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:
Erik 2026-07-21 16:17:03 +02:00
parent c87bac31a0
commit 69a2ca0c6d
26 changed files with 4172 additions and 430 deletions

View file

@ -931,6 +931,38 @@ public sealed class LiveEntityRuntime
return true;
}
/// <summary>
/// Exact-incarnation withdrawal used after App leave-world callbacks. A
/// callback may accept a newer INSTANCE_TS for the same GUID; that newer
/// projection must never be withdrawn by the displaced operation.
/// </summary>
public bool WithdrawLiveEntityProjection(LiveEntityRecord expectedRecord)
{
ArgumentNullException.ThrowIfNull(expectedRecord);
return WithdrawLiveEntityProjection(
expectedRecord,
expectedRecord.PositionAuthorityVersion,
expectedRecord.ProjectionMutationVersion);
}
/// <summary>
/// Exact-operation withdrawal used across arbitrary App callbacks. Both
/// the accepted Position authority and projection mutation token are
/// pinned so a same-incarnation re-entry cannot be removed by an older
/// parent/pickup/leave-world operation.
/// </summary>
internal bool WithdrawLiveEntityProjection(
LiveEntityRecord expectedRecord,
ulong expectedPositionAuthorityVersion,
ulong expectedProjectionMutationVersion)
{
ArgumentNullException.ThrowIfNull(expectedRecord);
return IsCurrentRecord(expectedRecord)
&& expectedRecord.PositionAuthorityVersion == expectedPositionAuthorityVersion
&& expectedRecord.ProjectionMutationVersion == expectedProjectionMutationVersion
&& WithdrawLiveEntityProjection(expectedRecord.ServerGuid);
}
/// <summary>
/// Withdraws a still-live projection whose authoritative rollback frame
/// is outside every world cell. Logical owners remain registered.
@ -1515,7 +1547,6 @@ public sealed class LiveEntityRuntime
RefreshRecord(update.ChildGuid, accepted);
if (_recordsByGuid.TryGetValue(update.ChildGuid, out LiveEntityRecord? record))
record.AdvancePositionAuthority();
ClearWorldCell(update.ChildGuid);
}
return applied;
}
@ -1528,11 +1559,43 @@ public sealed class LiveEntityRuntime
RefreshRecord(update.ChildGuid, accepted);
if (_recordsByGuid.TryGetValue(update.ChildGuid, out LiveEntityRecord? record))
record.AdvancePositionAuthority();
ClearWorldCell(update.ChildGuid);
}
return applied;
}
internal bool CommitStagedParent(
ParentAttachmentRelation relation,
out WorldSession.EntitySpawn accepted)
{
bool committed = _inbound.TryCommitParent(
relation.ChildGuid,
relation.ParentGuid,
relation.ParentLocation,
relation.PlacementId,
relation.ChildPositionSequence,
out accepted);
if (committed)
RefreshRecord(relation.ChildGuid, accepted);
return committed;
}
/// <summary>
/// Commits retail <c>CPhysicsObj::set_parent</c>'s cell-less edge only
/// after the parent accepted the child (PartArray + holding-location
/// validation). The POSITION_TS is consumed before this step, matching
/// retail; invalid parent relationships retain the old world projection.
/// </summary>
internal bool CommitAcceptedParentCellless(
LiveEntityRecord record,
ulong positionAuthorityVersion)
{
ArgumentNullException.ThrowIfNull(record);
if (!IsCurrentPositionAuthority(record, positionAuthorityVersion))
return false;
ClearWorldCell(record.ServerGuid);
return IsCurrentPositionAuthority(record, positionAuthorityVersion);
}
public bool TryApplyMotion(
WorldSession.EntityMotionUpdate update,
bool retainPayload,
@ -2154,7 +2217,7 @@ public sealed class LiveEntityRuntime
RefreshSpatialRuntimeIndexes(record);
}
private bool IsCurrentRecord(LiveEntityRecord record) =>
internal bool IsCurrentRecord(LiveEntityRecord record) =>
_recordsByGuid.TryGetValue(record.ServerGuid, out LiveEntityRecord? current)
&& ReferenceEquals(current, record);