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:
Erik 2026-07-27 00:43:26 +02:00
parent 7818494116
commit a9a822f206
28 changed files with 2707 additions and 345 deletions

View file

@ -968,15 +968,55 @@ public sealed class RuntimeEntityObjectLifetime : IDisposable
_sessionClearInProgress = true;
Entities.BeginSessionClear();
RuntimeEntityRecord[] retired = Entities.ActiveRecords.ToArray();
foreach (RuntimeEntityRecord canonical in retired)
RuntimeEntityRecord[] active = Entities.ActiveRecords.ToArray();
foreach (RuntimeEntityRecord canonical in active)
{
if (!Entities.RemoveActive(canonical))
continue;
Entities.RetainTeardown(canonical);
PublishEntity(RuntimeEntityChange.Deleted, canonical);
}
return retired;
return active;
}
public IReadOnlyList<RuntimeEntityRecord>
CaptureSessionClearRetirements()
{
EnsureNotDisposed();
if (!_sessionClearInProgress)
{
throw new InvalidOperationException(
"Session-clear retirements are only available while the "
+ "canonical clear transaction is active.");
}
return Entities.TeardownRecords.ToArray();
}
/// <summary>
/// Completes one exact incarnation retained by
/// <see cref="BeginSessionClear"/> after the borrowed host has retired its
/// presentation projection. Failure keeps the tombstone and local
/// identity intact so the same transaction cursor can retry this exact
/// record without reconstructing the retirement set.
/// </summary>
public void CompleteSessionEntityRetirement(
RuntimeEntityRecord canonical)
{
EnsureNotDisposed();
ArgumentNullException.ThrowIfNull(canonical);
if (!_sessionClearInProgress
|| !Entities.TryGetTeardown(
canonical.ServerGuid,
canonical.Incarnation,
out RuntimeEntityRecord retained)
|| !ReferenceEquals(retained, canonical))
{
throw new InvalidOperationException(
$"Live entity 0x{canonical.ServerGuid:X8}/{canonical.Incarnation} is not retained by the active session-clear transaction.");
}
CompleteProjectionRetirement(canonical);
Entities.ReleaseTeardown(canonical);
}
public bool CompleteSessionClearIfConverged()