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
|
|
@ -20,6 +20,7 @@ internal sealed class CurrentGameRuntimeAdapter
|
|||
{
|
||||
private readonly GameRuntime _runtime;
|
||||
private readonly CurrentGameRuntimeCommandAdapter _commands;
|
||||
private readonly CharacterSelectionProjection _characterSelection;
|
||||
private readonly IDisposable _hostLease;
|
||||
private readonly object _subscriptionGate = new();
|
||||
private readonly HashSet<AdapterSubscription> _subscriptions = [];
|
||||
|
|
@ -40,6 +41,7 @@ internal sealed class CurrentGameRuntimeAdapter
|
|||
"graphical game-runtime command adapter");
|
||||
try
|
||||
{
|
||||
_characterSelection = new CharacterSelectionProjection(this);
|
||||
_commands = new CurrentGameRuntimeCommandAdapter(
|
||||
runtime.Session,
|
||||
sessionHost,
|
||||
|
|
@ -61,7 +63,7 @@ internal sealed class CurrentGameRuntimeAdapter
|
|||
}
|
||||
|
||||
private bool IsActive =>
|
||||
!_disposed
|
||||
!Volatile.Read(ref _disposed)
|
||||
&& !_runtime.Session.IsDisposalComplete;
|
||||
|
||||
public RuntimeGenerationToken Generation => _runtime.Generation;
|
||||
|
|
@ -90,7 +92,7 @@ internal sealed class CurrentGameRuntimeAdapter
|
|||
public IRuntimeSocialView Social => _runtime.Social;
|
||||
public IRuntimeChatView Chat => _runtime.Chat;
|
||||
public IRuntimeCharacterSelectionView CharacterSelection =>
|
||||
_runtime.CharacterSelection;
|
||||
_characterSelection;
|
||||
public IRuntimeFellowshipView Fellowship => _runtime.Fellowship;
|
||||
public IRuntimeAllegianceView Allegiance => _runtime.Allegiance;
|
||||
public IRuntimeActionView Actions => _runtime.Actions;
|
||||
|
|
@ -100,9 +102,9 @@ internal sealed class CurrentGameRuntimeAdapter
|
|||
|
||||
public IRuntimeSessionCommands Session => _commands;
|
||||
public IRuntimeCharacterSelectionCommands CharacterSelectionCommands =>
|
||||
_runtime.Session;
|
||||
_characterSelection;
|
||||
IRuntimeCharacterSelectionCommands IGameRuntimeCommands.CharacterSelection =>
|
||||
_runtime.Session;
|
||||
_characterSelection;
|
||||
public IRuntimeSelectionCommands Selection => _commands;
|
||||
public IRuntimeCombatCommands Combat => _commands;
|
||||
public IRuntimeMagicCommands Magic => _commands;
|
||||
|
|
@ -166,6 +168,187 @@ internal sealed class CurrentGameRuntimeAdapter
|
|||
_subscriptions.Remove(subscription);
|
||||
}
|
||||
|
||||
private RuntimeCharacterSelectionSnapshot CharacterSelectionSnapshot()
|
||||
{
|
||||
lock (_subscriptionGate)
|
||||
{
|
||||
if (IsActive)
|
||||
return _runtime.CharacterSelection.Snapshot;
|
||||
return new RuntimeCharacterSelectionSnapshot(
|
||||
_runtime.Generation,
|
||||
RuntimeCharacterSelectionLifecycle.Inactive,
|
||||
Revision: 0,
|
||||
AccountName: string.Empty,
|
||||
SlotCount: 0,
|
||||
RosterCount: 0,
|
||||
HighlightedCharacterId: 0u,
|
||||
HighlightedDisplayIndex: -1,
|
||||
PendingDeleteCharacterId: 0u,
|
||||
LastRestoreRequestedCharacterId: 0u,
|
||||
Operation: RuntimeCharacterSelectionOperation.None,
|
||||
Error: null,
|
||||
Buttons: RuntimeCharacterSelectionButtons.None);
|
||||
}
|
||||
}
|
||||
|
||||
private bool TryGetCharacterSelectionAt(
|
||||
int displayIndex,
|
||||
out RuntimeCharacterSelectionEntry character)
|
||||
{
|
||||
lock (_subscriptionGate)
|
||||
{
|
||||
if (IsActive)
|
||||
{
|
||||
return _runtime.CharacterSelection.TryGetAt(
|
||||
displayIndex,
|
||||
out character);
|
||||
}
|
||||
character = default;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private bool TryGetCharacterSelection(
|
||||
uint characterId,
|
||||
out RuntimeCharacterSelectionEntry character)
|
||||
{
|
||||
lock (_subscriptionGate)
|
||||
{
|
||||
if (IsActive)
|
||||
{
|
||||
return _runtime.CharacterSelection.TryGet(
|
||||
characterId,
|
||||
out character);
|
||||
}
|
||||
character = default;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private void VisitCharacterSelection(
|
||||
IRuntimeCharacterSelectionVisitor visitor)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(visitor);
|
||||
lock (_subscriptionGate)
|
||||
{
|
||||
if (IsActive)
|
||||
_runtime.CharacterSelection.Visit(visitor);
|
||||
}
|
||||
}
|
||||
|
||||
private IDisposable SubscribeCharacterSelection(
|
||||
IRuntimeCharacterSelectionObserver observer)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(observer);
|
||||
lock (_subscriptionGate)
|
||||
{
|
||||
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||
var gated = new AdapterCharacterSelectionObserver(this, observer);
|
||||
IDisposable runtimeSubscription =
|
||||
_runtime.CharacterSelection.Subscribe(gated);
|
||||
var subscription = new AdapterSubscription(
|
||||
this,
|
||||
runtimeSubscription);
|
||||
_subscriptions.Add(subscription);
|
||||
return subscription;
|
||||
}
|
||||
}
|
||||
|
||||
private RuntimeCommandResult ExecuteCharacterSelection(
|
||||
Func<IRuntimeCharacterSelectionCommands, RuntimeCommandResult> execute)
|
||||
{
|
||||
lock (_subscriptionGate)
|
||||
{
|
||||
if (!IsActive)
|
||||
{
|
||||
return new RuntimeCommandResult(
|
||||
RuntimeCommandStatus.Inactive,
|
||||
_runtime.Generation);
|
||||
}
|
||||
return execute(_runtime.Session);
|
||||
}
|
||||
}
|
||||
|
||||
private void ForwardCharacterSelection(
|
||||
IRuntimeCharacterSelectionObserver observer,
|
||||
in RuntimeCharacterSelectionDelta delta)
|
||||
{
|
||||
lock (_subscriptionGate)
|
||||
{
|
||||
if (IsActive)
|
||||
observer.OnCharacterSelectionChanged(in delta);
|
||||
}
|
||||
}
|
||||
|
||||
private sealed class CharacterSelectionProjection(
|
||||
CurrentGameRuntimeAdapter owner)
|
||||
: IRuntimeCharacterSelectionView,
|
||||
IRuntimeCharacterSelectionCommands
|
||||
{
|
||||
public RuntimeCharacterSelectionSnapshot Snapshot =>
|
||||
owner.CharacterSelectionSnapshot();
|
||||
|
||||
public bool TryGetAt(
|
||||
int displayIndex,
|
||||
out RuntimeCharacterSelectionEntry character) =>
|
||||
owner.TryGetCharacterSelectionAt(displayIndex, out character);
|
||||
|
||||
public bool TryGet(
|
||||
uint characterId,
|
||||
out RuntimeCharacterSelectionEntry character) =>
|
||||
owner.TryGetCharacterSelection(characterId, out character);
|
||||
|
||||
public void Visit(IRuntimeCharacterSelectionVisitor visitor) =>
|
||||
owner.VisitCharacterSelection(visitor);
|
||||
|
||||
public IDisposable Subscribe(
|
||||
IRuntimeCharacterSelectionObserver observer) =>
|
||||
owner.SubscribeCharacterSelection(observer);
|
||||
|
||||
public RuntimeCommandResult Highlight(
|
||||
RuntimeGenerationToken expectedGeneration,
|
||||
uint characterId) =>
|
||||
owner.ExecuteCharacterSelection(
|
||||
commands => commands.Highlight(
|
||||
expectedGeneration,
|
||||
characterId));
|
||||
|
||||
public RuntimeCommandResult Enter(
|
||||
RuntimeGenerationToken expectedGeneration) =>
|
||||
owner.ExecuteCharacterSelection(
|
||||
commands => commands.Enter(expectedGeneration));
|
||||
|
||||
public RuntimeCommandResult RequestDelete(
|
||||
RuntimeGenerationToken expectedGeneration) =>
|
||||
owner.ExecuteCharacterSelection(
|
||||
commands => commands.RequestDelete(expectedGeneration));
|
||||
|
||||
public RuntimeCommandResult ConfirmDelete(
|
||||
RuntimeGenerationToken expectedGeneration) =>
|
||||
owner.ExecuteCharacterSelection(
|
||||
commands => commands.ConfirmDelete(expectedGeneration));
|
||||
|
||||
public RuntimeCommandResult Restore(
|
||||
RuntimeGenerationToken expectedGeneration) =>
|
||||
owner.ExecuteCharacterSelection(
|
||||
commands => commands.Restore(expectedGeneration));
|
||||
|
||||
public RuntimeCommandResult Cancel(
|
||||
RuntimeGenerationToken expectedGeneration) =>
|
||||
owner.ExecuteCharacterSelection(
|
||||
commands => commands.Cancel(expectedGeneration));
|
||||
}
|
||||
|
||||
private sealed class AdapterCharacterSelectionObserver(
|
||||
CurrentGameRuntimeAdapter owner,
|
||||
IRuntimeCharacterSelectionObserver observer)
|
||||
: IRuntimeCharacterSelectionObserver
|
||||
{
|
||||
public void OnCharacterSelectionChanged(
|
||||
in RuntimeCharacterSelectionDelta delta) =>
|
||||
owner.ForwardCharacterSelection(observer, in delta);
|
||||
}
|
||||
|
||||
private sealed class AdapterSubscription(
|
||||
CurrentGameRuntimeAdapter owner,
|
||||
IDisposable runtimeSubscription) : IDisposable
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue