refactor(net): converge live session state reset
This commit is contained in:
parent
78a9223b65
commit
4f31a5085f
35 changed files with 1460 additions and 83 deletions
|
|
@ -66,10 +66,14 @@ public sealed class CameraController
|
|||
|
||||
public void ExitChaseMode()
|
||||
{
|
||||
bool wasChaseMode = IsChaseMode;
|
||||
Chase = null;
|
||||
RetailChase = null;
|
||||
if (_mode == Mode.Orbit)
|
||||
return;
|
||||
_mode = Mode.Fly;
|
||||
ModeChanged?.Invoke(IsFlyMode);
|
||||
if (wasChaseMode)
|
||||
ModeChanged?.Invoke(IsFlyMode);
|
||||
}
|
||||
|
||||
public void SetAspect(float aspect)
|
||||
|
|
|
|||
|
|
@ -817,6 +817,7 @@ public sealed class GameWindow : IDisposable, ILiveAnimationPresentationContext
|
|||
// an ICommandBus and becomes inert before the displaced socket closes.
|
||||
private AcDream.App.Net.LiveSessionEventRouter? _liveSessionEvents;
|
||||
private AcDream.App.Net.LiveSessionCommandRouter? _liveSessionCommands;
|
||||
private AcDream.App.Net.LiveSessionResetPlan? _liveSessionResetPlan;
|
||||
|
||||
// Phase G.1-G.2 world lighting/time state.
|
||||
public readonly AcDream.Core.World.WorldTimeService WorldTime =
|
||||
|
|
@ -1785,6 +1786,13 @@ public sealed class GameWindow : IDisposable, ILiveAnimationPresentationContext
|
|||
// writes under the chosen character's
|
||||
// name (or "default" pre-login).
|
||||
settingsStore.SaveCharacter(_activeToonKey, character);
|
||||
if (string.Equals(
|
||||
_activeToonKey,
|
||||
"default",
|
||||
StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
_persistedCharacter = character;
|
||||
}
|
||||
Console.WriteLine(
|
||||
$"settings: character[{_activeToonKey}] saved to "
|
||||
+ AcDream.UI.Abstractions.Panels.Settings.SettingsStore.DefaultPath());
|
||||
|
|
@ -2946,23 +2954,125 @@ public sealed class GameWindow : IDisposable, ILiveAnimationPresentationContext
|
|||
|
||||
private void ClearInboundEntityState()
|
||||
{
|
||||
EndMouseLookAndRestoreCursor();
|
||||
ResetTeleportTransitState(clearSession: true);
|
||||
if (_playerController is not null)
|
||||
_playerController.State = AcDream.App.Input.PlayerState.InWorld;
|
||||
(_liveSessionResetPlan ??= CreateLiveSessionResetPlan()).Execute();
|
||||
}
|
||||
|
||||
// Session-scoped origin readiness. A reconnect's first logical player
|
||||
// CreateObject must initialize the render/streaming center anew;
|
||||
// projection recovery inside one session never crosses this boundary.
|
||||
private AcDream.App.Net.LiveSessionResetPlan CreateLiveSessionResetPlan() =>
|
||||
AcDream.App.Net.LiveSessionResetManifest.Create(new()
|
||||
{
|
||||
MouseCapture = ResetSessionMouseCapture,
|
||||
PlayerPresentation = ResetSessionPlayerPresentation,
|
||||
TeleportTransit = () => ResetTeleportTransitState(clearSession: true),
|
||||
SessionDialogs = () => _retailUiRuntime?.ResetSessionDialogs(),
|
||||
ChatCommandTargets = () => _retailChatVm?.ResetSessionTargets(),
|
||||
SettingsCharacterContext = () =>
|
||||
_settingsVm?.LoadCharacterContext(_persistedCharacter),
|
||||
EquippedChildren = () => _equippedChildRenderer?.Clear(),
|
||||
ExternalContainer = () => _externalContainers.Reset(),
|
||||
InteractionAndSelection = ResetSessionInteraction,
|
||||
SelectionPresentation = () => _retailSelectionScene?.Reset(),
|
||||
ObjectTable = Objects.Clear,
|
||||
Spellbook = SpellBook.Clear,
|
||||
MagicRuntime = () => _magicRuntime?.Reset(),
|
||||
CombatAttack = () => _combatAttackController?.ResetSession(),
|
||||
CombatState = Combat.Clear,
|
||||
ItemMana = ItemMana.Clear,
|
||||
LocalPlayer = LocalPlayer.Clear,
|
||||
Friends = Friends.Clear,
|
||||
Squelch = Squelch.Clear,
|
||||
TurbineChat = TurbineChat.Reset,
|
||||
ParticleVisibility = _particleVisibility.Reset,
|
||||
InboundEventFifo = _inboundEntityEvents.Clear,
|
||||
LiveLiveness = () => _liveEntityLiveness?.Clear(),
|
||||
LiveRuntime = ResetSessionLiveRuntime,
|
||||
SessionIdentity = ResetSessionIdentity,
|
||||
RemoteTeleport = () => _remoteTeleportController?.Clear(),
|
||||
NetworkEffects = () => _entityEffects?.ClearNetworkState(),
|
||||
AnimationHookFrames = () => _animationHookFrames?.Clear(),
|
||||
LivePresentation = () => _liveEntityPresentation?.Clear(),
|
||||
RemoteMovementDiagnostics = _remoteLastMove.Clear,
|
||||
PhysicsHostIndex = _physicsHosts.Clear,
|
||||
});
|
||||
|
||||
private void ResetSessionMouseCapture()
|
||||
{
|
||||
bool wasActive = _mouseLook?.Active == true;
|
||||
_mouseLook?.Release();
|
||||
if (wasActive || _mouseLookSavedCursorMode.HasValue)
|
||||
RestoreCursorAfterMouseLook();
|
||||
}
|
||||
|
||||
private void ResetSessionPlayerPresentation()
|
||||
{
|
||||
_playerModeAutoEntry?.Cancel();
|
||||
try
|
||||
{
|
||||
_cameraController?.ExitChaseMode();
|
||||
}
|
||||
finally
|
||||
{
|
||||
_playerMode = false;
|
||||
_playerController = null;
|
||||
_playerHost = null;
|
||||
_chaseCamera = null;
|
||||
_retailChaseCamera = null;
|
||||
_playerMouseDeltaX = 0f;
|
||||
_rmbHeld = false;
|
||||
_autoRunActive = false;
|
||||
_chaseModeEverEntered = false;
|
||||
_lastMovementTruthOutbound = null;
|
||||
_lastLocalPlayerShadow = null;
|
||||
_spawnClaimRangeMemo = null;
|
||||
}
|
||||
}
|
||||
|
||||
private void ResetSessionIdentity()
|
||||
{
|
||||
AcDream.App.Net.LiveSessionEntityRuntimeReset.RequireConvergence(_liveEntities);
|
||||
|
||||
// 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.
|
||||
_playerServerGuid = 0u;
|
||||
_vitalsVm?.SetLocalPlayerGuid(0u);
|
||||
Chat.ResetSessionIdentity();
|
||||
AcDream.App.Streaming.EntityVanishProbe.PlayerGuid = 0u;
|
||||
_activeToonKey = "default";
|
||||
_characterOptions1 =
|
||||
AcDream.Core.Net.Messages.PlayerDescriptionParser.CharacterOptions1.Default;
|
||||
_playerMotionTableId = null;
|
||||
_lastSeenRunSkill = -1;
|
||||
_lastSeenJumpSkill = -1;
|
||||
_lastLivePlayerLandblockId = null;
|
||||
_liveSpawnReceived = 0;
|
||||
_liveSpawnHydrated = 0;
|
||||
_liveDropReasonNoPos = 0;
|
||||
_liveDropReasonNoSetup = 0;
|
||||
_liveDropReasonSetupDatMissing = 0;
|
||||
_liveDropReasonNoMeshRefs = 0;
|
||||
_liveAnimRejectNoCycle = 0;
|
||||
_liveAnimRejectFramerate = 0;
|
||||
_liveAnimRejectSingleFrame = 0;
|
||||
_liveAnimRejectPartFrames = 0;
|
||||
Shortcuts = Array.Empty<AcDream.Core.Items.ShortcutEntry>();
|
||||
DesiredComponents = Array.Empty<(uint Id, uint Amount)>();
|
||||
_paperdollDollDirty = true;
|
||||
|
||||
// X/Y are ignored until the next logical player CreateObject claims a
|
||||
// new origin. Keeping the last values avoids inventing a synthetic
|
||||
// landblock while still forcing first-spawn initialization.
|
||||
_liveCenterKnown = false;
|
||||
}
|
||||
|
||||
// Attachment projections own GL-backed world registrations, so tear
|
||||
// them down before dropping the canonical GUID/timestamp snapshots.
|
||||
_equippedChildRenderer?.Clear();
|
||||
_externalContainers.Reset();
|
||||
Objects.Clear();
|
||||
SpellBook.Clear();
|
||||
_magicRuntime?.Reset();
|
||||
private void ResetSessionLiveRuntime()
|
||||
{
|
||||
AcDream.App.Net.LiveSessionEntityRuntimeReset.ClearAndRequireConvergence(
|
||||
_liveEntities);
|
||||
}
|
||||
|
||||
private void ResetSessionInteraction()
|
||||
{
|
||||
if (_selectionInteractions is { } interactions)
|
||||
interactions.ResetSession();
|
||||
else
|
||||
|
|
@ -2970,36 +3080,6 @@ public sealed class GameWindow : IDisposable, ILiveAnimationPresentationContext
|
|||
_itemInteractionController?.ResetSession();
|
||||
_selection.Reset();
|
||||
}
|
||||
_retailSelectionScene?.Reset();
|
||||
_particleVisibility.Reset();
|
||||
try
|
||||
{
|
||||
_liveEntityLiveness?.Clear();
|
||||
_liveEntities?.Clear();
|
||||
}
|
||||
finally
|
||||
{
|
||||
try
|
||||
{
|
||||
// A pending teleport is operational state outside the live
|
||||
// record. Clear it independently even if a resource callback
|
||||
// failed while the canonical runtime was draining.
|
||||
_remoteTeleportController?.Clear();
|
||||
}
|
||||
finally
|
||||
{
|
||||
try
|
||||
{
|
||||
// F754/F755 can precede CreateObject, so the mixed pending FIFO
|
||||
// may contain owners with no LiveEntityRecord to tear down.
|
||||
_entityEffects?.ClearNetworkState();
|
||||
}
|
||||
finally
|
||||
{
|
||||
_animationHookFrames?.Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue