fix(runtime): close Campaign LA7b review findings
This commit is contained in:
parent
0e82cbf700
commit
1b9e7e41f9
11 changed files with 700 additions and 28 deletions
|
|
@ -376,14 +376,17 @@ public sealed class LiveSessionController
|
|||
private Action<WorldSession>? _preLogoffFlushHook;
|
||||
|
||||
public LiveSessionController()
|
||||
: this(ProductionLiveSessionOperations.Instance)
|
||||
: this(ProductionLiveSessionOperations.Instance, null)
|
||||
{
|
||||
}
|
||||
|
||||
public LiveSessionController(ILiveSessionOperations operations)
|
||||
public LiveSessionController(
|
||||
ILiveSessionOperations operations,
|
||||
TimeProvider? timeProvider = null)
|
||||
{
|
||||
_operations = operations ?? throw new ArgumentNullException(nameof(operations));
|
||||
CharacterSelectionState = new RuntimeCharacterSelectionState();
|
||||
CharacterSelectionState = new RuntimeCharacterSelectionState(
|
||||
timeProvider);
|
||||
}
|
||||
|
||||
public RuntimeCharacterSelectionState CharacterSelectionState { get; }
|
||||
|
|
@ -583,6 +586,7 @@ public sealed class LiveSessionController
|
|||
_operations.Tick(scope.Session);
|
||||
if (!IsCurrent(scope, generation))
|
||||
return;
|
||||
CharacterSelectionState.SweepRestoreCorrelation();
|
||||
}
|
||||
catch (Exception tickError)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ public enum RuntimeCharacterSelectionDeltaKind
|
|||
DeleteAcknowledged,
|
||||
RestoreRequested,
|
||||
RestoreCompleted,
|
||||
RestoreCorrelationExpired,
|
||||
ErrorChanged,
|
||||
EnteringWorld,
|
||||
EnteredWorld,
|
||||
|
|
@ -165,6 +166,9 @@ public interface IRuntimeCharacterSelectionCommands
|
|||
/// </summary>
|
||||
public sealed class RuntimeCharacterSelectionState : IDisposable
|
||||
{
|
||||
internal static readonly TimeSpan RestoreCorrelationTimeout =
|
||||
TimeSpan.FromSeconds(5);
|
||||
|
||||
private sealed class ViewProjection(RuntimeCharacterSelectionState owner)
|
||||
: IRuntimeCharacterSelectionView
|
||||
{
|
||||
|
|
@ -191,6 +195,7 @@ public sealed class RuntimeCharacterSelectionState : IDisposable
|
|||
private readonly object _gate = new();
|
||||
private readonly RuntimeCharacterSelectionEventStream _events = new();
|
||||
private readonly ViewProjection _view;
|
||||
private readonly TimeProvider _timeProvider;
|
||||
private RuntimeCharacterSelectionEntry[] _entries = [];
|
||||
private RuntimeGenerationToken _generation;
|
||||
private RuntimeCharacterSelectionLifecycle _lifecycle;
|
||||
|
|
@ -201,12 +206,15 @@ public sealed class RuntimeCharacterSelectionState : IDisposable
|
|||
private uint _pendingDeleteCharacterId;
|
||||
private uint _lastRestoreRequestedCharacterId;
|
||||
private bool _restoreResponseArmed;
|
||||
private long _restoreCorrelationStartedTimestamp;
|
||||
private bool _flagOnlyRestoreResponseAmbiguous;
|
||||
private RuntimeCharacterSelectionOperation _operation;
|
||||
private RuntimeCharacterSelectionError? _error;
|
||||
private bool _disposed;
|
||||
|
||||
public RuntimeCharacterSelectionState()
|
||||
public RuntimeCharacterSelectionState(TimeProvider? timeProvider = null)
|
||||
{
|
||||
_timeProvider = timeProvider ?? TimeProvider.System;
|
||||
_view = new ViewProjection(this);
|
||||
}
|
||||
|
||||
|
|
@ -303,6 +311,8 @@ public sealed class RuntimeCharacterSelectionState : IDisposable
|
|||
_pendingDeleteCharacterId = 0u;
|
||||
_lastRestoreRequestedCharacterId = 0u;
|
||||
_restoreResponseArmed = false;
|
||||
_restoreCorrelationStartedTimestamp = 0;
|
||||
_flagOnlyRestoreResponseAmbiguous = false;
|
||||
_operation = RuntimeCharacterSelectionOperation.None;
|
||||
_error = null;
|
||||
_highlightedCharacterId = Contains(previous)
|
||||
|
|
@ -408,6 +418,7 @@ public sealed class RuntimeCharacterSelectionState : IDisposable
|
|||
if (_disposed
|
||||
|| _lifecycle != RuntimeCharacterSelectionLifecycle.AwaitingSelection
|
||||
|| HasDeleteModalOrRequest()
|
||||
|| _restoreResponseArmed
|
||||
|| index < 0
|
||||
|| !_entries[index].IsPendingDelete)
|
||||
{
|
||||
|
|
@ -419,6 +430,8 @@ public sealed class RuntimeCharacterSelectionState : IDisposable
|
|||
_pendingDeleteCharacterId = 0u;
|
||||
_lastRestoreRequestedCharacterId = character.CharacterId;
|
||||
_restoreResponseArmed = true;
|
||||
_restoreCorrelationStartedTimestamp =
|
||||
_timeProvider.GetTimestamp();
|
||||
_operation = RuntimeCharacterSelectionOperation.RestoreRequested;
|
||||
_error = null;
|
||||
_revision++;
|
||||
|
|
@ -429,6 +442,39 @@ public sealed class RuntimeCharacterSelectionState : IDisposable
|
|||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Releases the one outstanding restore correlation after a bounded local
|
||||
/// window. ACE can intentionally send no response for an unknown GUID;
|
||||
/// later flag-only responses carry no GUID, so once a request expires
|
||||
/// they remain ambiguous and are never attributed to a newer request.
|
||||
/// </summary>
|
||||
internal bool SweepRestoreCorrelation()
|
||||
{
|
||||
uint characterId;
|
||||
lock (_gate)
|
||||
{
|
||||
if (_disposed
|
||||
|| !_restoreResponseArmed
|
||||
|| _timeProvider.GetElapsedTime(
|
||||
_restoreCorrelationStartedTimestamp)
|
||||
< RestoreCorrelationTimeout)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
characterId = _lastRestoreRequestedCharacterId;
|
||||
_restoreResponseArmed = false;
|
||||
_restoreCorrelationStartedTimestamp = 0;
|
||||
_flagOnlyRestoreResponseAmbiguous = true;
|
||||
_operation = RuntimeCharacterSelectionOperation.None;
|
||||
_revision++;
|
||||
}
|
||||
Publish(
|
||||
RuntimeCharacterSelectionDeltaKind.RestoreCorrelationExpired,
|
||||
characterId);
|
||||
return true;
|
||||
}
|
||||
|
||||
internal bool Cancel()
|
||||
{
|
||||
RuntimeCharacterSelectionDeltaKind kind;
|
||||
|
|
@ -493,12 +539,18 @@ public sealed class RuntimeCharacterSelectionState : IDisposable
|
|||
|| _lifecycle != RuntimeCharacterSelectionLifecycle.AwaitingSelection
|
||||
|| !_restoreResponseArmed)
|
||||
return;
|
||||
if (response.Guid is null
|
||||
&& _flagOnlyRestoreResponseAmbiguous)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (response.Guid is { } responseGuid
|
||||
&& responseGuid != _lastRestoreRequestedCharacterId)
|
||||
{
|
||||
return;
|
||||
}
|
||||
_restoreResponseArmed = false;
|
||||
_restoreCorrelationStartedTimestamp = 0;
|
||||
characterId = response.Guid
|
||||
?? _lastRestoreRequestedCharacterId;
|
||||
|
||||
|
|
@ -555,7 +607,10 @@ public sealed class RuntimeCharacterSelectionState : IDisposable
|
|||
or RuntimeCharacterSelectionLifecycle.EnteringWorld))
|
||||
return;
|
||||
_pendingDeleteCharacterId = 0u;
|
||||
if (_restoreResponseArmed)
|
||||
_flagOnlyRestoreResponseAmbiguous = true;
|
||||
_restoreResponseArmed = false;
|
||||
_restoreCorrelationStartedTimestamp = 0;
|
||||
_operation = RuntimeCharacterSelectionOperation.None;
|
||||
_error = new RuntimeCharacterSelectionError(
|
||||
error.RawErrorCode,
|
||||
|
|
@ -588,6 +643,8 @@ public sealed class RuntimeCharacterSelectionState : IDisposable
|
|||
_pendingDeleteCharacterId = 0u;
|
||||
_lastRestoreRequestedCharacterId = 0u;
|
||||
_restoreResponseArmed = false;
|
||||
_restoreCorrelationStartedTimestamp = 0;
|
||||
_flagOnlyRestoreResponseAmbiguous = false;
|
||||
_operation = RuntimeCharacterSelectionOperation.None;
|
||||
_error = null;
|
||||
_lifecycle = RuntimeCharacterSelectionLifecycle.EnteringWorld;
|
||||
|
|
@ -717,7 +774,7 @@ public sealed class RuntimeCharacterSelectionState : IDisposable
|
|||
return new RuntimeCharacterSelectionButtons(
|
||||
CanEnter: false,
|
||||
CanDelete: false,
|
||||
CanRestore: true,
|
||||
CanRestore: !_restoreResponseArmed,
|
||||
DeleteVisible: false,
|
||||
RestoreVisible: true);
|
||||
}
|
||||
|
|
@ -833,6 +890,8 @@ public sealed class RuntimeCharacterSelectionState : IDisposable
|
|||
_pendingDeleteCharacterId = 0u;
|
||||
_lastRestoreRequestedCharacterId = 0u;
|
||||
_restoreResponseArmed = false;
|
||||
_restoreCorrelationStartedTimestamp = 0;
|
||||
_flagOnlyRestoreResponseAmbiguous = false;
|
||||
_operation = RuntimeCharacterSelectionOperation.None;
|
||||
_error = null;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue