refactor(world): separate live lifetime from spatial buckets

Introduce LiveEntityRuntime as the canonical owner of each accepted server-object incarnation, stable local identity, timestamped state, parent relations, runtime components, and exactly-once teardown. Split logical registration from rebucketing so pending landblocks, equipment attachment, pickup re-entry, and GUID replacement reuse the same entity and effect owners.

Keep canonical materialized and visible target/radar views distinct, preserve retail leave_world versus exit_world semantics, gate root simulation while cell-less, and track transitional pre-Create F754 owners through delete and session reset. Remove stale-spawn rehydration and make GpuWorldState spatial-only for live objects.

Add lifecycle, generation, pending, unload, attachment, event-publication, local-ID, rollback, and effect-cleanup coverage; update architecture, milestones, memory, and the divergence register.

Co-Authored-By: Codex <noreply@openai.com>
This commit is contained in:
Erik 2026-07-14 07:47:03 +02:00
parent 8a5d77f7f4
commit 8dd996053d
24 changed files with 2449 additions and 631 deletions

View file

@ -37,6 +37,32 @@ public class GpuWorldStateTwoTierTests
Assert.True(state.IsLoaded(0xAAAAFFFFu)); // landblock still resident
}
[Fact]
public void RemoveEntitiesFromLandblock_DropsStaticLayerButRetainsLiveProjection()
{
var state = new GpuWorldState();
WorldEntity staticEntity = MakeStubEntity(1);
var liveEntity = new WorldEntity
{
Id = 2,
ServerGuid = 0x70000002u,
SourceGfxObjOrSetupId = 0x01000001u,
Position = System.Numerics.Vector3.Zero,
Rotation = System.Numerics.Quaternion.Identity,
MeshRefs = System.Array.Empty<MeshRef>(),
};
state.AddLandblock(MakeStubLandblock(
0xAAAAFFFFu,
staticEntity,
liveEntity));
state.RemoveEntitiesFromLandblock(0xAAAAFFFFu);
Assert.Same(liveEntity, Assert.Single(state.Entities));
Assert.DoesNotContain(staticEntity, state.Entities);
Assert.True(state.IsLoaded(0xAAAAFFFFu));
}
[Fact]
public void AddEntitiesToExistingLandblock_MergesIntoExistingRecord()
{
@ -118,7 +144,6 @@ public class GpuWorldStateTwoTierTests
int callCount = 0;
var state = new GpuWorldState(
wbSpawnAdapter: null,
wbEntitySpawnAdapter: null,
onLandblockUnloaded: id => { observed = id; callCount++; });
state.AddLandblock(MakeStubLandblock(0xA9B4FFFFu, MakeStubEntity(1)));
@ -144,7 +169,6 @@ public class GpuWorldStateTwoTierTests
int callCount = 0;
var state = new GpuWorldState(
wbSpawnAdapter: null,
wbEntitySpawnAdapter: null,
onLandblockUnloaded: _ => callCount++);
// Landblock never loaded.