feat(headless): complete deterministic bot command parity
This commit is contained in:
parent
7e8acb74dd
commit
38e83640d9
37 changed files with 2805 additions and 295 deletions
|
|
@ -48,21 +48,26 @@ internal sealed class GameRuntimeEventHub
|
|||
{
|
||||
private readonly RuntimeEntityObjectLifetime _entityObjects;
|
||||
private readonly RuntimeCommunicationState _communication;
|
||||
private readonly RuntimeActionState _actions;
|
||||
private readonly object _observerGate = new();
|
||||
private IRuntimeEventObserver[] _observers = [];
|
||||
private IDisposable? _entityObjectSubscription;
|
||||
private IDisposable? _communicationSubscription;
|
||||
private bool _actionEventsAttached;
|
||||
private bool _disposeRequested;
|
||||
private bool _disposed;
|
||||
|
||||
public GameRuntimeEventHub(
|
||||
RuntimeEntityObjectLifetime entityObjects,
|
||||
RuntimeCommunicationState communication)
|
||||
RuntimeCommunicationState communication,
|
||||
RuntimeActionState actions)
|
||||
{
|
||||
_entityObjects = entityObjects
|
||||
?? throw new ArgumentNullException(nameof(entityObjects));
|
||||
_communication = communication
|
||||
?? throw new ArgumentNullException(nameof(communication));
|
||||
_actions = actions
|
||||
?? throw new ArgumentNullException(nameof(actions));
|
||||
}
|
||||
|
||||
public long DispatchFailureCount { get; private set; }
|
||||
|
|
@ -127,6 +132,7 @@ internal sealed class GameRuntimeEventHub
|
|||
ref _entityObjectSubscription,
|
||||
"entity/object event subscription",
|
||||
ref failures);
|
||||
DetachActionEvents();
|
||||
_disposed = !OwnerEventsAttached;
|
||||
|
||||
if (failures is not null)
|
||||
|
|
@ -284,7 +290,8 @@ internal sealed class GameRuntimeEventHub
|
|||
|
||||
private bool OwnerEventsAttached =>
|
||||
_entityObjectSubscription is not null
|
||||
|| _communicationSubscription is not null;
|
||||
|| _communicationSubscription is not null
|
||||
|| _actionEventsAttached;
|
||||
|
||||
private void AttachOwnerEvents()
|
||||
{
|
||||
|
|
@ -294,11 +301,14 @@ internal sealed class GameRuntimeEventHub
|
|||
{
|
||||
entity = _entityObjects.Events.Subscribe(this);
|
||||
communication = _communication.Events.Subscribe(this);
|
||||
_actions.CombatChanged += OnCombatChanged;
|
||||
_actionEventsAttached = true;
|
||||
_entityObjectSubscription = entity;
|
||||
_communicationSubscription = communication;
|
||||
}
|
||||
catch
|
||||
{
|
||||
DetachActionEvents();
|
||||
communication?.Dispose();
|
||||
entity?.Dispose();
|
||||
throw;
|
||||
|
|
@ -347,6 +357,7 @@ internal sealed class GameRuntimeEventHub
|
|||
ref _entityObjectSubscription,
|
||||
"entity/object event subscription",
|
||||
ref failures);
|
||||
DetachActionEvents();
|
||||
if (failures is not null)
|
||||
{
|
||||
throw new AggregateException(
|
||||
|
|
@ -378,6 +389,37 @@ internal sealed class GameRuntimeEventHub
|
|||
private RuntimeEventStamp NextStamp() =>
|
||||
_entityObjects.Events.NextStamp();
|
||||
|
||||
private void OnCombatChanged()
|
||||
{
|
||||
if (!TryObservers(out IRuntimeEventObserver[] observers))
|
||||
return;
|
||||
RuntimeActionSnapshot actions = _actions.View.Snapshot;
|
||||
var delta = new RuntimeCombatDelta(
|
||||
NextStamp(),
|
||||
actions.CombatMode,
|
||||
actions.TrackedTargetHealthCount,
|
||||
actions.CombatAttack);
|
||||
foreach (IRuntimeEventObserver observer in observers)
|
||||
{
|
||||
try
|
||||
{
|
||||
observer.OnCombat(in delta);
|
||||
}
|
||||
catch (Exception error)
|
||||
{
|
||||
RecordDispatchFailure(error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void DetachActionEvents()
|
||||
{
|
||||
if (!_actionEventsAttached)
|
||||
return;
|
||||
_actions.CombatChanged -= OnCombatChanged;
|
||||
_actionEventsAttached = false;
|
||||
}
|
||||
|
||||
private bool TryObservers(out IRuntimeEventObserver[] observers)
|
||||
{
|
||||
observers = Volatile.Read(ref _observers);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue