refactor(runtime): unify generation reset for direct hosts
Move canonical per-session teardown into one retryable Runtime transaction, reduce App reset to projection acknowledgements, and prove the same GameRuntime graph through deterministic no-window lifecycle, gameplay, portal, fault, reconnect, and isolation gates.\n\nCo-authored-by: Codex <noreply@openai.com>
This commit is contained in:
parent
7818494116
commit
a9a822f206
28 changed files with 2707 additions and 345 deletions
|
|
@ -2230,6 +2230,76 @@ public sealed class LiveEntityRuntime : ILiveEntityRadarSource
|
|||
IsCurrentRecord(expectedRecord)
|
||||
&& expectedRecord.CreateIntegrationVersion == expectedCreateIntegrationVersion;
|
||||
|
||||
/// <summary>
|
||||
/// Retires only the graphical sidecar for an exact Runtime-owned
|
||||
/// incarnation. The Runtime generation-reset transaction retains and
|
||||
/// completes the canonical tombstone after this acknowledgement returns.
|
||||
/// </summary>
|
||||
internal void RetireGenerationProjection(
|
||||
RuntimeEntityRecord canonical)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(canonical);
|
||||
if (_isClearing || _isRegisteringResources)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
_isClearing
|
||||
? "Live entity projection teardown is already in progress."
|
||||
: "Live entity projection teardown cannot begin inside atomic resource registration.");
|
||||
}
|
||||
|
||||
LiveEntityRecord? record = null;
|
||||
if (_projections.TryGet(canonical, out LiveEntityRecord active))
|
||||
{
|
||||
if (!_projections.RemoveActive(active))
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
$"Exact App projection for 0x{canonical.ServerGuid:X8}/{canonical.Incarnation} could not be retired during generation reset.");
|
||||
}
|
||||
_projections.RetainTeardown(active);
|
||||
record = active;
|
||||
}
|
||||
else if (_projections.TryGetTeardown(
|
||||
canonical,
|
||||
out LiveEntityRecord retained))
|
||||
{
|
||||
record = retained;
|
||||
}
|
||||
|
||||
if (record is null)
|
||||
return;
|
||||
|
||||
_isClearing = true;
|
||||
try
|
||||
{
|
||||
TearDownRecord(record, completeCanonical: false);
|
||||
_projections.ReleaseTeardown(record);
|
||||
}
|
||||
finally
|
||||
{
|
||||
_isClearing = false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Completes the App-only projection boundary after Runtime has retired
|
||||
/// every exact canonical incarnation. No canonical owner is mutated here.
|
||||
/// </summary>
|
||||
internal void CompleteGenerationProjectionRetirement()
|
||||
{
|
||||
if (_projections.ActiveCount != 0
|
||||
|| _projections.TeardownCount != 0)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
"Live entity projection storage has not converged at the generation-reset boundary.");
|
||||
}
|
||||
|
||||
_spatialAnimations.Clear();
|
||||
_physics.ClearSpatialWorksets();
|
||||
_projections.ClearConverged();
|
||||
_spatial.ClearLiveEntityLifetimeState();
|
||||
_sessionClearPendingFinalization = false;
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
if (_isClearing || _isRegisteringResources)
|
||||
|
|
@ -2670,7 +2740,9 @@ public sealed class LiveEntityRuntime : ILiveEntityRadarSource
|
|||
_sessionClearPendingFinalization = false;
|
||||
}
|
||||
|
||||
private void TearDownRecord(LiveEntityRecord record)
|
||||
private void TearDownRecord(
|
||||
LiveEntityRecord record,
|
||||
bool completeCanonical = true)
|
||||
{
|
||||
if (record.TeardownInProgress)
|
||||
throw new InvalidOperationException(
|
||||
|
|
@ -2730,8 +2802,11 @@ public sealed class LiveEntityRuntime : ILiveEntityRadarSource
|
|||
|
||||
if (record.WorldEntity is not null)
|
||||
_ = RequireProjectionKey(record);
|
||||
_entityObjects.CompleteProjectionRetirement(
|
||||
record.Canonical);
|
||||
if (completeCanonical)
|
||||
{
|
||||
_entityObjects.CompleteProjectionRetirement(
|
||||
record.Canonical);
|
||||
}
|
||||
|
||||
record.AnimationRuntime = null;
|
||||
record.EffectProfile = null;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue