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
|
|
@ -23,6 +23,7 @@ using AcDream.Core.Social;
|
|||
using AcDream.Core.Spells;
|
||||
using AcDream.Core.World;
|
||||
using AcDream.Content;
|
||||
using AcDream.Runtime;
|
||||
using AcDream.Runtime.Entities;
|
||||
using AcDream.Runtime.Gameplay;
|
||||
using AcDream.Runtime.Session;
|
||||
|
|
@ -39,6 +40,7 @@ internal sealed record LiveSessionPlayerRuntime(
|
|||
LiveWorldOriginState WorldOrigin);
|
||||
|
||||
internal sealed record LiveSessionDomainRuntime(
|
||||
GameRuntime Runtime,
|
||||
RuntimeEntityObjectLifetime EntityObjects,
|
||||
RuntimeCharacterState Character,
|
||||
RuntimeActionState Actions,
|
||||
|
|
@ -122,12 +124,18 @@ internal sealed class LiveSessionRuntimeFactory
|
|||
{
|
||||
ArgumentNullException.ThrowIfNull(controller);
|
||||
ArgumentNullException.ThrowIfNull(connectOptions);
|
||||
var resetHost = new GraphicalRuntimeGenerationResetHost(
|
||||
_world.LiveEntities,
|
||||
() => _world.RenderSceneShadow?.DrainUpdateBoundary());
|
||||
LiveSessionResetPlan reset =
|
||||
LiveSessionResetManifest.Create(
|
||||
CreateResetBindings(resetHost));
|
||||
return new LiveSessionHost(controller, new LiveSessionHostBindings(
|
||||
Routing: new(
|
||||
CreateEventRouter,
|
||||
session => _commands.Attach(new LiveSessionCommandRouter(
|
||||
CreateCommandBindings(session)))),
|
||||
Reset: LiveSessionResetManifest.Create(CreateResetBindings()).Execute,
|
||||
Reset: reset.Execute,
|
||||
Selection: new(
|
||||
SetPlayerIdentity: id => _player.Identity.ServerGuid = id,
|
||||
SetVitalsIdentity: id => _ui.Vitals?.SetLocalPlayerGuid(id),
|
||||
|
|
@ -152,37 +160,26 @@ internal sealed class LiveSessionRuntimeFactory
|
|||
connectOptions);
|
||||
}
|
||||
|
||||
private LiveSessionResetBindings CreateResetBindings() => new()
|
||||
private LiveSessionResetBindings CreateResetBindings(
|
||||
IRuntimeGenerationResetHost resetHost) => new()
|
||||
{
|
||||
MouseCapture = _interaction.GameplayInput.ResetSession,
|
||||
PlayerPresentation = ResetPlayerPresentation,
|
||||
TeleportTransit = _world.Teleport.ResetSession,
|
||||
TeleportPresentation =
|
||||
_world.Teleport.ResetGenerationPresentation,
|
||||
SessionDialogs = () => _ui.RetailUi?.ResetSessionTransientUi(),
|
||||
ChatCommandTargets = _domain.Communication.ResetCommandTargets,
|
||||
SettingsCharacterContext =
|
||||
_interaction.Settings.RestoreDefaultCharacterContext,
|
||||
EquippedChildren = _world.EquippedChildren.Clear,
|
||||
ExternalContainer = _domain.Inventory.ResetExternalContainer,
|
||||
InteractionAndSelection = _interaction.SelectionInteractions.ResetSession,
|
||||
InventoryTransactions = _domain.Inventory.ResetTransactions,
|
||||
InteractionPresentation =
|
||||
_interaction.SelectionInteractions.ResetGenerationPresentation,
|
||||
SelectionPresentation = _world.SelectionScene.Reset,
|
||||
ObjectTable = _domain.EntityObjects.ClearObjects,
|
||||
Spellbook = _domain.Character.ResetSpellbook,
|
||||
MagicRuntime = () => _ui.Magic?.Reset(),
|
||||
CombatAttack = _interaction.CombatAttack.ResetSession,
|
||||
CombatState = _domain.Actions.Combat.Clear,
|
||||
ItemMana = _domain.Inventory.ResetItemMana,
|
||||
LocalPlayer = _domain.Character.ResetLocalPlayer,
|
||||
Friends = _domain.Communication.ResetFriends,
|
||||
Squelch = _domain.Communication.ResetSquelch,
|
||||
TurbineChat = _domain.Communication.ResetNegotiatedChannels,
|
||||
ParticleVisibility = _world.ParticleVisibility.Reset,
|
||||
InboundEventFifo = _world.InboundEvents.Clear,
|
||||
LiveLiveness = _world.Liveness.Clear,
|
||||
LiveRuntime = ResetLiveRuntime,
|
||||
RenderSceneProjection =
|
||||
() => _world.RenderSceneShadow?.DrainUpdateBoundary(),
|
||||
SessionIdentity = ResetIdentity,
|
||||
RuntimeGeneration = generation =>
|
||||
_domain.Runtime.ResetGeneration(generation, resetHost),
|
||||
SessionIdentityPresentation = ResetIdentityPresentation,
|
||||
RemoteTeleport = _world.RemoteTeleport.Clear,
|
||||
NetworkEffects = _world.EntityEffects.ClearNetworkState,
|
||||
AnimationHookFrames = _world.AnimationHookFrames.Clear,
|
||||
|
|
@ -196,28 +193,28 @@ internal sealed class LiveSessionRuntimeFactory
|
|||
_world.SpawnClaims.Reset();
|
||||
}
|
||||
|
||||
private void ResetLiveRuntime() =>
|
||||
LiveSessionEntityRuntimeReset.ClearAndRequireConvergence(
|
||||
_world.LiveEntities);
|
||||
|
||||
private void ResetIdentity()
|
||||
private void ResetIdentityPresentation(
|
||||
RuntimeGenerationToken retiringGeneration)
|
||||
{
|
||||
LiveSessionEntityRuntimeReset.RequireConvergence(_world.LiveEntities);
|
||||
RuntimeGenerationResetSnapshot reset =
|
||||
_domain.Runtime.GenerationReset.CaptureSnapshot();
|
||||
if (reset.IsActive
|
||||
|| reset.LastCompletedGeneration != retiringGeneration)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
$"Runtime generation {retiringGeneration.Value} has not "
|
||||
+ "converged before App identity projection teardown.");
|
||||
}
|
||||
|
||||
// PlayerModule::Clear @ 0x005D48A0 clears shortcuts, desired
|
||||
// components, and character option objects. CPlayerSystem::Begin
|
||||
// @ 0x0055D410 resets player identity and session fields. The option
|
||||
// default comes from PlayerModule::PlayerModule @ 0x005D51F0.
|
||||
_player.Identity.ServerGuid = 0u;
|
||||
_ui.Vitals?.SetLocalPlayerGuid(0u);
|
||||
_domain.Communication.ResetChatIdentity();
|
||||
EntityVanishProbe.PlayerGuid = 0u;
|
||||
_interaction.Settings.ResetActiveCharacterKey();
|
||||
_domain.Character.Options.ResetSession();
|
||||
_domain.Character.MovementSkills.ResetSession();
|
||||
_world.NetworkUpdates.ResetSessionState();
|
||||
_world.Hydration.ResetSessionState();
|
||||
_domain.Inventory.ResetPlayerSnapshots();
|
||||
_ui.Paperdoll?.ResetSession();
|
||||
|
||||
// X/Y are ignored until the next logical player CreateObject claims a
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue