refactor(world): extract live projection mechanics
Move appearance rebinding, collision construction, default-pose resolution, local shadow ownership, and exact leave-world presentation into focused owners. Preserve retail parent ordering with staged validation, committed recovery, recursive attached-subtree withdrawal, and retryable exact teardown across parent, pickup, position, unwield, and pose-loss edges. Co-Authored-By: OpenAI Codex <codex@openai.com>
This commit is contained in:
parent
c87bac31a0
commit
69a2ca0c6d
26 changed files with 4172 additions and 430 deletions
|
|
@ -453,6 +453,78 @@ public sealed class EntitySpawnAdapterLifetimeTests
|
|||
Assert.Equal(0, meshes.TotalReferenceCount);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AppearanceChange_AfterPublicationRunsBeforeOldRetirement()
|
||||
{
|
||||
const uint guid = 0x7400C100u;
|
||||
const ulong oldMesh = 0x01000A10u;
|
||||
const ulong newMesh = 0x01000A11u;
|
||||
var meshes = new CallbackMeshAdapter();
|
||||
var adapter = new EntitySpawnAdapter(
|
||||
new RecordingTextureLifetime(), _ => MakeSequencer(), meshes);
|
||||
WorldEntity entity = MakeEntity(152u, guid);
|
||||
entity.MeshRefs = [new MeshRef((uint)oldMesh, Matrix4x4.Identity)];
|
||||
adapter.OnCreate(entity);
|
||||
Assert.True(adapter.SetPresentationResident(entity, resident: true));
|
||||
meshes.Operations.Clear();
|
||||
MeshRef[] replacement = [new MeshRef((uint)newMesh, Matrix4x4.Identity)];
|
||||
|
||||
Assert.True(adapter.OnAppearanceChanged(
|
||||
entity,
|
||||
replacement,
|
||||
[],
|
||||
() =>
|
||||
{
|
||||
meshes.Operations.Add("publish");
|
||||
entity.ApplyAppearance(replacement, paletteOverride: null, []);
|
||||
},
|
||||
() =>
|
||||
{
|
||||
Assert.Same(replacement, entity.MeshRefs);
|
||||
Assert.Equal(1, meshes.ReferenceCounts[oldMesh]);
|
||||
Assert.Equal(1, meshes.ReferenceCounts[newMesh]);
|
||||
meshes.Operations.Add("after-publication");
|
||||
}));
|
||||
|
||||
int afterPublication = meshes.Operations.IndexOf("after-publication");
|
||||
Assert.True(meshes.Operations.IndexOf("publish") < afterPublication);
|
||||
Assert.True(meshes.Operations.IndexOf($"decrement:{oldMesh:X8}") > afterPublication);
|
||||
Assert.True(adapter.OnRemove(entity));
|
||||
Assert.Equal(0, meshes.TotalReferenceCount);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AppearanceChange_AfterPublicationFailureKeepsCommittedSetAndRetryRetiresOld()
|
||||
{
|
||||
const uint guid = 0x7400C200u;
|
||||
const ulong oldMesh = 0x01000A20u;
|
||||
const ulong newMesh = 0x01000A21u;
|
||||
var meshes = new RefCountingMeshAdapter();
|
||||
var adapter = new EntitySpawnAdapter(
|
||||
new RecordingTextureLifetime(), _ => MakeSequencer(), meshes);
|
||||
WorldEntity entity = MakeEntity(153u, guid);
|
||||
entity.MeshRefs = [new MeshRef((uint)oldMesh, Matrix4x4.Identity)];
|
||||
adapter.OnCreate(entity);
|
||||
Assert.True(adapter.SetPresentationResident(entity, resident: true));
|
||||
MeshRef[] replacement = [new MeshRef((uint)newMesh, Matrix4x4.Identity)];
|
||||
|
||||
Assert.Throws<InvalidOperationException>(() => adapter.OnAppearanceChanged(
|
||||
entity,
|
||||
replacement,
|
||||
[],
|
||||
() => entity.ApplyAppearance(replacement, paletteOverride: null, []),
|
||||
() => throw new InvalidOperationException("injected dependent publication failure")));
|
||||
|
||||
Assert.Same(replacement, entity.MeshRefs);
|
||||
Assert.Equal(1, meshes.ReferenceCounts[oldMesh]);
|
||||
Assert.Equal(1, meshes.ReferenceCounts[newMesh]);
|
||||
Assert.True(adapter.SetPresentationResident(entity, resident: true));
|
||||
Assert.False(meshes.ReferenceCounts.ContainsKey(oldMesh));
|
||||
Assert.Equal(1, meshes.ReferenceCounts[newMesh]);
|
||||
Assert.True(adapter.OnRemove(entity));
|
||||
Assert.Equal(0, meshes.TotalReferenceCount);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AppearanceChange_WhileSuspended_OnlyReplacementSetIsAcquiredOnResume()
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue