acdream/tests/AcDream.Core.Tests/Meshing/EquippedChildAttachmentTests.cs
Erik ab6d96d113 feat(combat): port retail held weapon parenting
Select the default combat mode from ordered equipped objects so bows request missile stance. Parse CreateObject parent metadata and ParentEvent, then render held objects as separate children composed from setup holding locations and placement frames each animation tick.
2026-07-11 13:02:26 +02:00

108 lines
3.1 KiB
C#

using System.Numerics;
using AcDream.Core.Meshing;
using AcDream.Core.World;
using DatReaderWriter.DBObjs;
using DatReaderWriter.Enums;
using DatReaderWriter.Types;
namespace AcDream.Core.Tests.Meshing;
public sealed class EquippedChildAttachmentTests
{
[Fact]
public void TryCompose_CombinesChildPlacementHoldingFrameAndAnimatedHandPart()
{
var parent = new Setup
{
HoldingLocations =
{
[ParentLocation.LeftHand] = new LocationType
{
PartId = 1,
Frame = FrameAt(2, 0, 0),
},
},
};
var parentPose = new[]
{
new MeshRef(1, Matrix4x4.Identity),
new MeshRef(2, Matrix4x4.CreateTranslation(10, 0, 0)),
};
var child = new Setup
{
Parts = { 0x01000001u },
DefaultScale = { Vector3.One },
PlacementFrames =
{
[Placement.LeftHand] = new AnimationFrame(1)
{
Frames = { FrameAt(3, 0, 0) },
},
},
};
var template = new[] { new MeshRef(0x01000001u, Matrix4x4.Identity) };
bool ok = EquippedChildAttachment.TryCompose(
parent, parentPose, child, ParentLocation.LeftHand,
Placement.LeftHand, template, 1.0f, out var result);
Assert.True(ok);
Assert.Equal(15f, Assert.Single(result).PartTransform.Translation.X);
}
[Fact]
public void TryCompose_MissingRequestedPlacementFallsBackToDefault()
{
var parent = ParentWithRightHand(partId: -1, FrameAt(4, 0, 0));
var child = new Setup
{
Parts = { 0x01000001u },
PlacementFrames =
{
[Placement.Default] = new AnimationFrame(1)
{
Frames = { FrameAt(6, 0, 0) },
},
},
};
bool ok = EquippedChildAttachment.TryCompose(
parent, [], child, ParentLocation.RightHand,
Placement.RightHandCombat,
[new MeshRef(0x01000001u, Matrix4x4.Identity)],
1.0f,
out var result);
Assert.True(ok);
Assert.Equal(10f, Assert.Single(result).PartTransform.Translation.X);
}
[Fact]
public void TryCompose_MissingHoldingLocationRejectsAttachment()
{
bool ok = EquippedChildAttachment.TryCompose(
new Setup(), [], new Setup(), ParentLocation.RightHand,
Placement.RightHandCombat, [], 1.0f, out var result);
Assert.False(ok);
Assert.Empty(result);
}
private static Setup ParentWithRightHand(int partId, Frame frame) => new()
{
HoldingLocations =
{
[ParentLocation.RightHand] = new LocationType
{
PartId = partId,
Frame = frame,
},
},
};
private static Frame FrameAt(float x, float y, float z) => new()
{
Origin = new Vector3(x, y, z),
Orientation = Quaternion.Identity,
};
}