fix(streaming): preserve portal destination ownership
Detach old-world spatial ownership atomically, prioritize destination retirement dependencies, and reveal the viewport at the retail transition edge. Give private paperdoll views independent mesh ownership and retain dormant ACE entities so portal revisits preserve server objects without extending active GPU lifetimes.
This commit is contained in:
parent
2c848d4167
commit
823936ec31
57 changed files with 2551 additions and 324 deletions
|
|
@ -20,6 +20,7 @@ internal sealed class LiveEntityDeletionController : ILiveEntityPruneSink
|
|||
private readonly ClientObjectTable _objects;
|
||||
private readonly ILiveEntityTeardownCoordinator _teardown;
|
||||
private readonly ILocalPlayerIdentitySource _identity;
|
||||
private readonly DormantLiveEntityStore _dormant;
|
||||
private readonly Action<string>? _diagnostic;
|
||||
|
||||
public LiveEntityDeletionController(
|
||||
|
|
@ -27,12 +28,14 @@ internal sealed class LiveEntityDeletionController : ILiveEntityPruneSink
|
|||
ClientObjectTable objects,
|
||||
ILiveEntityTeardownCoordinator teardown,
|
||||
ILocalPlayerIdentitySource identity,
|
||||
DormantLiveEntityStore? dormant = null,
|
||||
Action<string>? diagnostic = null)
|
||||
{
|
||||
_runtime = runtime ?? throw new ArgumentNullException(nameof(runtime));
|
||||
_objects = objects ?? throw new ArgumentNullException(nameof(objects));
|
||||
_teardown = teardown ?? throw new ArgumentNullException(nameof(teardown));
|
||||
_identity = identity ?? throw new ArgumentNullException(nameof(identity));
|
||||
_dormant = dormant ?? new DormantLiveEntityStore();
|
||||
_diagnostic = diagnostic;
|
||||
}
|
||||
|
||||
|
|
@ -46,7 +49,8 @@ internal sealed class LiveEntityDeletionController : ILiveEntityPruneSink
|
|||
if (delete.Guid == _identity.ServerGuid)
|
||||
return false;
|
||||
|
||||
if (!_runtime.TryGetRecord(delete.Guid, out _))
|
||||
bool hasActiveRecord = _runtime.TryGetRecord(delete.Guid, out _);
|
||||
if (!hasActiveRecord)
|
||||
_teardown.ForgetUnknownOwner(delete.Guid);
|
||||
|
||||
bool removed = _runtime.UnregisterLiveEntity(
|
||||
|
|
@ -54,16 +58,45 @@ internal sealed class LiveEntityDeletionController : ILiveEntityPruneSink
|
|||
isLocalPlayer: false,
|
||||
beforeTeardown: () =>
|
||||
ObjectTableWiring.ApplyEntityDelete(_objects, delete));
|
||||
bool removedDormant = _dormant.RemoveExact(delete);
|
||||
if (!removed && removedDormant)
|
||||
ObjectTableWiring.ApplyEntityDelete(_objects, delete);
|
||||
if (removed)
|
||||
{
|
||||
_dormant.RemoveExact(delete);
|
||||
_diagnostic?.Invoke(
|
||||
$"live: delete guid=0x{delete.Guid:X8} instSeq={delete.InstanceSequence}");
|
||||
}
|
||||
return removed;
|
||||
else if (removedDormant)
|
||||
{
|
||||
_diagnostic?.Invoke(
|
||||
$"live: delete dormant guid=0x{delete.Guid:X8} instSeq={delete.InstanceSequence}");
|
||||
}
|
||||
return removed || removedDormant;
|
||||
}
|
||||
|
||||
public bool Prune(LiveEntityPruneCandidate candidate) =>
|
||||
Delete(new DeleteObject.Parsed(
|
||||
candidate.ServerGuid,
|
||||
candidate.Generation));
|
||||
public bool Prune(LiveEntityPruneCandidate candidate)
|
||||
{
|
||||
if (!_runtime.TryGetRecord(
|
||||
candidate.ServerGuid,
|
||||
out LiveEntityRecord record)
|
||||
|| record.Generation != candidate.Generation)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
WorldSession.EntitySpawn snapshot = record.Snapshot;
|
||||
bool removed = _runtime.UnregisterLiveEntity(
|
||||
new DeleteObject.Parsed(
|
||||
candidate.ServerGuid,
|
||||
candidate.Generation),
|
||||
isLocalPlayer: false);
|
||||
if (!removed)
|
||||
return false;
|
||||
|
||||
_dormant.Retain(snapshot);
|
||||
_diagnostic?.Invoke(
|
||||
$"live: dormant guid=0x{candidate.ServerGuid:X8} instSeq={candidate.Generation}");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue