Restore the named-retail object update order across local, remote, static, projectile, animation, shadow, teleport, and effect lifetimes. Separate authoritative root commits from spatial rebucketing, preserve per-owner hook/FIFO ordering, and remove update-path allocations with exact lifecycle and residency gates. Add deterministic conformance, adversarial lifetime, GUID-reuse, pending-cell, quaternion, timestamp, and allocation coverage. Release build is warning-free and all 6,446 tests pass with five intentional skips; retail, architecture, and adversarial reviews are clean. Co-authored-by: OpenAI Codex <codex@openai.com>
109 lines
4.2 KiB
C#
109 lines
4.2 KiB
C#
using AcDream.Content.Vfx;
|
|
using AcDream.Content;
|
|
using AcDream.Core.Physics;
|
|
using AcDream.Core.Physics.Motion;
|
|
using AcDream.Core.Tests.Conformance;
|
|
using DatReaderWriter;
|
|
using DatReaderWriter.DBObjs;
|
|
using DatReaderWriter.Options;
|
|
using DatReaderWriter.Types;
|
|
|
|
namespace AcDream.Core.Tests.Physics;
|
|
|
|
/// <summary>
|
|
/// Pins the retail Humanoid motion table data consumed by CSequence root motion.
|
|
/// The packet-driven remote mover must use these values, not a velocity guessed
|
|
/// from the interpreted command.
|
|
/// </summary>
|
|
public sealed class HumanoidMotionTableRootMotionTests
|
|
{
|
|
private const uint HumanoidMotionTable = 0x09000001u;
|
|
private const uint HumanoidSetup = 0x02000001u;
|
|
private const uint NonCombatStyle = 0x8000003Du;
|
|
private const uint WalkForward = 0x40000005u;
|
|
private const uint RunForward = 0x40000007u;
|
|
private const uint Ready = 0x41000003u;
|
|
private const uint InterpretedWalkForward = 0x45000005u;
|
|
private const uint TurnRight = 0x6500000Du;
|
|
|
|
[Theory]
|
|
[InlineData(WalkForward)]
|
|
[InlineData(RunForward)]
|
|
public void RetailLocomotionCycle_ExposesItsLiteralMotionDataVelocity(uint motion)
|
|
{
|
|
string? datDir = ConformanceDats.ResolveDatDir();
|
|
if (datDir is null)
|
|
return;
|
|
|
|
using var dats = new DatCollection(datDir, DatAccessType.Read);
|
|
MotionTable table = Assert.IsType<MotionTable>(dats.Get<MotionTable>(HumanoidMotionTable));
|
|
int key = unchecked((int)((NonCombatStyle << 16) | (motion & 0x00FF_FFFFu)));
|
|
MotionData cycle = Assert.IsType<MotionData>(table.Cycles[key]);
|
|
|
|
Assert.Equal(System.Numerics.Vector3.Zero, cycle.Velocity);
|
|
}
|
|
|
|
[Fact]
|
|
public void RetailWalkSequence_ProducesAuthoredRootDisplacement()
|
|
{
|
|
string? datDir = ConformanceDats.ResolveDatDir();
|
|
if (datDir is null)
|
|
return;
|
|
|
|
using var dats = new DatCollection(datDir, DatAccessType.Read);
|
|
using var boundedDats = new DatCollectionAdapter(dats);
|
|
Setup setup = Assert.IsType<Setup>(dats.Get<Setup>(HumanoidSetup));
|
|
MotionTable table = Assert.IsType<MotionTable>(dats.Get<MotionTable>(HumanoidMotionTable));
|
|
var sequencer = new AnimationSequencer(
|
|
setup,
|
|
table,
|
|
new RetailAnimationLoader(boundedDats));
|
|
|
|
sequencer.SetCycle(NonCombatStyle, Ready);
|
|
sequencer.SetCycle(NonCombatStyle, InterpretedWalkForward);
|
|
|
|
float distance = 0f;
|
|
for (int i = 0; i < 120; i++)
|
|
{
|
|
var root = new Frame
|
|
{
|
|
Origin = System.Numerics.Vector3.Zero,
|
|
Orientation = System.Numerics.Quaternion.Identity,
|
|
};
|
|
sequencer.Advance(1f / 60f, root);
|
|
distance += root.Origin.Length();
|
|
}
|
|
|
|
Assert.True(
|
|
distance > 1f,
|
|
$"Installed retail WalkForward should author root travel; got {distance:F3} m over 2 s.");
|
|
}
|
|
|
|
[Fact]
|
|
public void RetailTurnRightModifier_ExposesLiteralSequenceOmega()
|
|
{
|
|
string? datDir = ConformanceDats.ResolveDatDir();
|
|
if (datDir is null)
|
|
return;
|
|
|
|
using var dats = new DatCollection(datDir, DatAccessType.Read);
|
|
MotionTable table = Assert.IsType<MotionTable>(dats.Get<MotionTable>(HumanoidMotionTable));
|
|
int styledKey = unchecked((int)((NonCombatStyle << 16) | (TurnRight & 0x00FF_FFFFu)));
|
|
int unstyledKey = unchecked((int)(TurnRight & 0x00FF_FFFFu));
|
|
bool found = table.Modifiers.TryGetValue(styledKey, out MotionData? modifier)
|
|
|| table.Modifiers.TryGetValue(unstyledKey, out modifier);
|
|
|
|
Assert.True(
|
|
found,
|
|
$"Retail Humanoid TurnRight modifier was absent at styled key 0x{styledKey:X8} "
|
|
+ $"and fallback key 0x{unstyledKey:X8}.");
|
|
Assert.NotNull(modifier);
|
|
|
|
Assert.True(
|
|
modifier!.Flags.HasFlag(DatReaderWriter.Enums.MotionDataFlags.HasOmega),
|
|
$"Retail Humanoid TurnRight must mark its literal omega present; "
|
|
+ $"flags={modifier.Flags}.");
|
|
Assert.Equal(System.Numerics.Vector3.Zero, modifier.Omega with { Z = 0f });
|
|
Assert.Equal(-1.5f, modifier.Omega.Z, 5);
|
|
}
|
|
}
|