refactor(runtime): expose canonical gameplay state

Move character options and movement skills into the Runtime-owned character graph, expose borrowed inventory, character, and social views, and route retained UI state commands through generation-gated typed Runtime contracts. Preserve the existing synchronous wire path while deleting the App-owned option and skill mirrors and extending normalized parity checkpoints.

Co-authored-by: Codex <codex@openai.com>
This commit is contained in:
Erik 2026-07-26 09:12:30 +02:00
parent 9d0d9b07e0
commit dcb61efb5a
34 changed files with 2076 additions and 103 deletions

View file

@ -21,6 +21,7 @@ public sealed class RuntimeInventoryState : IDisposable
ItemMana = new ItemManaState();
Shortcuts = new ShortcutState();
Transactions = new InventoryTransactionState(_entityObjects.Objects);
View = new InventoryStateView(this);
}
public ClientObjectTable Objects => _entityObjects.Objects;
@ -28,6 +29,7 @@ public sealed class RuntimeInventoryState : IDisposable
public ItemManaState ItemMana { get; }
public ShortcutState Shortcuts { get; }
public InventoryTransactionState Transactions { get; }
public IRuntimeInventoryStateView View { get; }
public bool IsDisposed => _disposed;
public void ResetExternalContainer() => ExternalContainers.Reset();
@ -66,6 +68,61 @@ public sealed class RuntimeInventoryState : IDisposable
(failures ??= []).Add(error);
}
}
private sealed class InventoryStateView(RuntimeInventoryState owner)
: IRuntimeInventoryStateView
{
public RuntimeInventoryStateSnapshot Snapshot
{
get
{
RuntimePendingInventoryRequestSnapshot? pending = null;
if (owner.Transactions.TryGetPending(
out PendingInventoryRequest request))
{
pending = new RuntimePendingInventoryRequestSnapshot(
request.Token,
(int)request.Kind,
request.ItemId,
request.Dispatched);
}
return new RuntimeInventoryStateSnapshot(
owner.ExternalContainers.RequestedContainerId,
owner.ExternalContainers.CurrentContainerId,
owner.Transactions.BusyCount,
owner.Transactions.CanBeginRequest,
pending,
owner.Shortcuts.Items.Count,
owner.Shortcuts.Revision,
owner.ItemMana.Count,
owner.ItemMana.Revision);
}
}
public bool TryGetShortcut(
int index,
out RuntimeShortcutSnapshot shortcut)
{
IReadOnlyList<ShortcutEntry> shortcuts = owner.Shortcuts.Items;
for (int i = 0; i < shortcuts.Count; i++)
{
if (shortcuts[i].Index != index)
continue;
ShortcutEntry current = shortcuts[i];
shortcut = new RuntimeShortcutSnapshot(
current.Index,
current.ObjectId,
current.SpellId);
return true;
}
shortcut = default;
return false;
}
public bool TryGetItemMana(uint objectId, out float fraction) =>
owner.ItemMana.TryGetManaPercent(objectId, out fraction);
}
}
public sealed class ShortcutState