Separate logical ownership, render publication, and GPU retirement across live entities, landblocks, particles, textures, mesh arenas, portal/UI teardown, and per-frame scratch storage. Add bounded DAT/texture caches, upload budgets, three-frame fence retirement, exact-incarnation appearance reconciliation, frame pacing, and extensive lifetime conformance coverage.\n\nThe seven-destination connected route now cuts peak working/private memory roughly in half, returns Caul to 125-153 FPS locally, and produces no WER or AMD reset.\n\nCo-authored-by: OpenAI Codex <codex@openai.com>
78 lines
2.3 KiB
C#
78 lines
2.3 KiB
C#
namespace AcDream.App.World;
|
|
|
|
/// <summary>
|
|
/// Runs the independent owners that participate in one live incarnation's
|
|
/// teardown without letting an earlier callback strand later state. Retail's
|
|
/// object destruction drains these owners as separate lifecycle steps; the App
|
|
/// composition callback must preserve that symmetry even when a plugin,
|
|
/// renderer, or effect sink throws.
|
|
/// </summary>
|
|
internal static class LiveEntityTeardown
|
|
{
|
|
internal static void Run(IEnumerable<Action> cleanups)
|
|
{
|
|
ArgumentNullException.ThrowIfNull(cleanups);
|
|
List<Exception>? failures = null;
|
|
foreach (Action cleanup in cleanups)
|
|
{
|
|
try
|
|
{
|
|
cleanup();
|
|
}
|
|
catch (Exception error)
|
|
{
|
|
(failures ??= []).Add(error);
|
|
}
|
|
}
|
|
|
|
if (failures is not null)
|
|
throw new AggregateException(
|
|
"One or more live-entity component teardown steps failed.",
|
|
failures);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// A stable teardown plan whose successful steps are committed individually.
|
|
/// The plan itself stays on the live-record tombstone, so retrying a later
|
|
/// failed owner never replays an earlier ExitWorld notification or release.
|
|
/// </summary>
|
|
internal sealed class LiveEntityTeardownPlan
|
|
{
|
|
private readonly Action[] _steps;
|
|
private readonly bool[] _completed;
|
|
|
|
public LiveEntityTeardownPlan(IEnumerable<Action> steps)
|
|
{
|
|
ArgumentNullException.ThrowIfNull(steps);
|
|
_steps = [.. steps];
|
|
_completed = new bool[_steps.Length];
|
|
}
|
|
|
|
internal int CompletedCount => _completed.Count(static completed => completed);
|
|
internal bool IsComplete => CompletedCount == _steps.Length;
|
|
|
|
public void Advance()
|
|
{
|
|
List<Exception>? failures = null;
|
|
for (int i = 0; i < _steps.Length; i++)
|
|
{
|
|
if (_completed[i])
|
|
continue;
|
|
try
|
|
{
|
|
_steps[i]();
|
|
_completed[i] = true;
|
|
}
|
|
catch (Exception error)
|
|
{
|
|
(failures ??= []).Add(error);
|
|
}
|
|
}
|
|
|
|
if (failures is not null)
|
|
throw new AggregateException(
|
|
"One or more live-entity component teardown steps failed.",
|
|
failures);
|
|
}
|
|
}
|