diff --git a/RELEASE-NOTES.md b/RELEASE-NOTES.md
index 73aad122d..a97461095 100644
--- a/RELEASE-NOTES.md
+++ b/RELEASE-NOTES.md
@@ -35,6 +35,8 @@ END TEMPLATE-->
### Breaking changes
+* Events that are raised via `IEventBus.RaiseComponentEvent()` now **must** be annotated with the `ComponentEventAttribute`.
+ * By default, events annotated with this attribute can **only** be raised via `IEventBus.RaiseComponentEvent()`. This can be configured via `ComponentEventAttribute.Exclusive`
* StartCollide and EndCollide events are now buffered until the end of physics substeps instead of being raised during the CollideContacts step. EndCollide events are double-buffered and any new ones raised while the events are being dispatched will now go out on the next tick / substep.
### New features
diff --git a/Robust.Server/GameStates/PvsSystem.GetStates.cs b/Robust.Server/GameStates/PvsSystem.GetStates.cs
index 04afedeb2..87786ceac 100644
--- a/Robust.Server/GameStates/PvsSystem.GetStates.cs
+++ b/Robust.Server/GameStates/PvsSystem.GetStates.cs
@@ -1,6 +1,8 @@
using System;
using System.Collections.Generic;
+using System.Runtime.CompilerServices;
using Robust.Shared.GameObjects;
+using Robust.Shared.GameStates;
using Robust.Shared.Player;
using Robust.Shared.Timing;
using Robust.Shared.Utility;
@@ -20,11 +22,11 @@ internal sealed partial class PvsSystem
/// New entity State for the given entity.
private EntityState GetEntityState(ICommonSession? player, EntityUid entityUid, GameTick fromTick, MetaDataComponent meta)
{
- var bus = EntityManager.EventBus;
var changed = new List();
bool sendCompList = meta.LastComponentRemoved > fromTick;
HashSet? netComps = sendCompList ? new() : null;
+ var stateEv = new ComponentGetState(player, fromTick);
foreach (var (netId, component) in meta.NetComponents)
{
@@ -41,15 +43,15 @@ internal sealed partial class PvsSystem
if (component.LastModifiedTick <= fromTick)
{
- if (sendCompList && (!component.SessionSpecific || player == null || EntityManager.CanGetComponentState(bus, component, player)))
+ if (sendCompList && (!component.SessionSpecific || player == null || EntityManager.CanGetComponentState(component, player)))
netComps!.Add(netId);
continue;
}
- if (component.SessionSpecific && player != null && !EntityManager.CanGetComponentState(bus, component, player))
+ if (component.SessionSpecific && player != null && !EntityManager.CanGetComponentState(component, player))
continue;
- var state = EntityManager.GetComponentState(bus, component, player, fromTick);
+ var state = ComponentState(entityUid, component, netId, ref stateEv);
changed.Add(new ComponentChange(netId, state, component.LastModifiedTick));
if (state != null)
@@ -66,13 +68,23 @@ internal sealed partial class PvsSystem
return entState;
}
+ private IComponentState? ComponentState(EntityUid uid, IComponent comp, ushort netId, ref ComponentGetState stateEv)
+ {
+ DebugTools.Assert(comp.NetSyncEnabled, $"Attempting to get component state for an un-synced component: {comp.GetType()}");
+ stateEv.State = null;
+ _getStateHandlers![netId]?.Invoke(uid, comp, ref Unsafe.As(ref stateEv));
+ var state = stateEv.State;
+ return state;
+ }
+
///
/// Variant of that includes all entity data, including data that can be inferred implicitly from the entity prototype.
///
private EntityState GetFullEntityState(ICommonSession player, EntityUid entityUid, MetaDataComponent meta)
{
- var bus = EntityManager.EventBus;
+ var bus = EntityManager.EventBusInternal;
var changed = new List();
+ var stateEv = new ComponentGetState(player, GameTick.Zero);
HashSet netComps = new();
@@ -86,7 +98,7 @@ internal sealed partial class PvsSystem
if (component.SessionSpecific && !EntityManager.CanGetComponentState(bus, component, player))
continue;
- var state = EntityManager.GetComponentState(bus, component, player, GameTick.Zero);
+ var state = ComponentState(entityUid, component, netId, ref stateEv);
DebugTools.Assert(state is not IComponentDeltaState);
changed.Add(new ComponentChange(netId, state, component.LastModifiedTick));
netComps.Add(netId);
diff --git a/Robust.Server/GameStates/PvsSystem.cs b/Robust.Server/GameStates/PvsSystem.cs
index e68ff17e2..26ca25493 100644
--- a/Robust.Server/GameStates/PvsSystem.cs
+++ b/Robust.Server/GameStates/PvsSystem.cs
@@ -14,6 +14,7 @@ using Robust.Server.Replays;
using Robust.Shared;
using Robust.Shared.Configuration;
using Robust.Shared.GameObjects;
+using Robust.Shared.GameStates;
using Robust.Shared.Map;
using Robust.Shared.Network;
using Robust.Shared.Player;
@@ -105,6 +106,7 @@ internal sealed partial class PvsSystem : EntitySystem
private bool _async;
private DefaultObjectPool _threadResourcesPool = default!;
+ private EntityEventBus.DirectedEventHandler?[]? _getStateHandlers;
private static readonly Histogram Histogram = Metrics.CreateHistogram("robust_game_state_update_usage",
"Amount of time spent processing different parts of the game state update", new HistogramConfiguration
@@ -173,6 +175,7 @@ internal sealed partial class PvsSystem : EntitySystem
ClearPvsData();
ShutdownDirty();
+ _getStateHandlers = null;
}
public override void Update(float frameTime)
@@ -185,6 +188,8 @@ internal sealed partial class PvsSystem : EntitySystem
///
internal void SendGameStates(ICommonSession[] players)
{
+ _getStateHandlers ??= EntityManager.EventBusInternal.GetNetCompEventHandlers();
+
// Wait for pending jobs and process disconnected players
ProcessDisconnections();
diff --git a/Robust.Shared/GameObjects/CompIdx.cs b/Robust.Shared/GameObjects/CompIdx.cs
index 136f45bb2..ab7d537c9 100644
--- a/Robust.Shared/GameObjects/CompIdx.cs
+++ b/Robust.Shared/GameObjects/CompIdx.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
using System.Reflection;
using System.Threading;
using Robust.Shared.Maths;
@@ -33,7 +34,7 @@ public readonly struct CompIdx : IEquatable
var curLength = array.Length;
if (curLength <= idx.Value)
{
- var newLength = MathHelper.NextPowerOfTwo(Math.Max(8, idx.Value));
+ var newLength = MathHelper.NextPowerOfTwo(Math.Max(8, idx.Value + 1));
Array.Resize(ref array, newLength);
}
diff --git a/Robust.Shared/GameObjects/EntityEventBus.Common.cs b/Robust.Shared/GameObjects/EntityEventBus.Common.cs
index 1d8c22859..55ef2dc0c 100644
--- a/Robust.Shared/GameObjects/EntityEventBus.Common.cs
+++ b/Robust.Shared/GameObjects/EntityEventBus.Common.cs
@@ -12,7 +12,7 @@ namespace Robust.Shared.GameObjects;
internal sealed partial class EntityEventBus : IEventBus
{
- private IEntityManager _entMan;
+ private EntityManager _entMan;
private IComponentFactory _comFac;
private IReflectionManager _reflection;
@@ -34,18 +34,18 @@ internal sealed partial class EntityEventBus : IEventBus
///
/// Array of component events and their handlers. The array is indexed by a component's
/// , while the dictionary is indexed by the event type. This does not include events
- /// with the
+ /// with the , unless is false.
///
- internal FrozenDictionary[] _eventSubs = default!;
+ private FrozenDictionary[] _eventSubs = default!;
///
- /// Variant of that also includes events with the
+ /// Variant of that only includes events with the
///
- internal FrozenDictionary[] _compEventSubs = default!;
+ private FrozenDictionary[] _compEventSubs = default!;
// pre-freeze event subscription data
- internal Dictionary?[] _eventSubsUnfrozen =
- Array.Empty>();
+ private Dictionary?[] _eventSubsUnfrozen = [];
+ private Dictionary?[] _compEventSubsUnfrozen = [];
///
/// Inverse of , mapping event types to sets of components.
diff --git a/Robust.Shared/GameObjects/EntityEventBus.Directed.cs b/Robust.Shared/GameObjects/EntityEventBus.Directed.cs
index e20e72603..f9e97bcd2 100644
--- a/Robust.Shared/GameObjects/EntityEventBus.Directed.cs
+++ b/Robust.Shared/GameObjects/EntityEventBus.Directed.cs
@@ -1,8 +1,8 @@
using System;
using System.Collections.Frozen;
using System.Collections.Generic;
-using System.Diagnostics.CodeAnalysis;
using System.Linq;
+using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using Robust.Shared.Collections;
@@ -101,9 +101,6 @@ namespace Robust.Shared.GameObjects
{
internal delegate void DirectedEventHandler(EntityUid uid, IComponent comp, ref Unit args);
- private delegate void DirectedEventHandler(EntityUid uid, IComponent comp, ref TEvent args)
- where TEvent : notnull;
-
///
/// Max size of a components event subscription linked list.
/// Used to limit the stackalloc in
@@ -118,7 +115,7 @@ namespace Robust.Shared.GameObjects
///
/// The entity manager to watch for entity/component events.
/// The reflection manager to use when finding derived types.
- public EntityEventBus(IEntityManager entMan, IReflectionManager reflection)
+ public EntityEventBus(EntityManager entMan, IReflectionManager reflection)
{
_entMan = entMan;
_comFac = entMan.ComponentFactory;
@@ -176,13 +173,8 @@ namespace Robust.Shared.GameObjects
public void RaiseComponentEvent(EntityUid uid, IComponent component, CompIdx type, ref TEvent args)
where TEvent : notnull
{
- ref var unitRef = ref Unsafe.As(ref args);
-
- DispatchComponent(
- uid,
- component,
- type,
- ref unitRef);
+ if (_compEventSubs[type.Value].TryGetValue(typeof(TEvent), out var handler))
+ handler(uid, component, ref Unsafe.As(ref args));
}
public void OnlyCallOnRobustUnitTestISwearToGodPleaseSomebodyKillThisNightmare()
@@ -249,15 +241,13 @@ namespace Robust.Shared.GameObjects
where TComp : IComponent
where TEvent : notnull
{
- void EventHandler(EntityUid uid, IComponent comp, ref TEvent args)
- => handler(uid, (TComp)comp, args);
+ void EventHandler(EntityUid uid, IComponent comp, ref Unit ev)
+ {
+ ref var tev = ref Unsafe.As(ref ev);
+ handler(uid, (TComp) comp, tev);
+ }
- EntSubscribe(
- CompIdx.Index(),
- typeof(TComp),
- typeof(TEvent),
- EventHandler,
- null);
+ EntAddSubscription(CompIdx.Index(), typeof(TComp), typeof(TEvent), EventHandler);
}
public void SubscribeLocalEvent(
@@ -268,71 +258,51 @@ namespace Robust.Shared.GameObjects
where TComp : IComponent
where TEvent : notnull
{
- void EventHandler(EntityUid uid, IComponent comp, ref TEvent args)
- => handler(uid, (TComp)comp, args);
+ void EventHandler(EntityUid uid, IComponent comp, ref Unit ev)
+ {
+ ref var tev = ref Unsafe.As(ref ev);
+ handler(uid, (TComp) comp, tev);
+ }
- var orderData = CreateOrderingData(orderType, before, after);
-
- EntSubscribe(
- CompIdx.Index(),
- typeof(TComp),
- typeof(TEvent),
- EventHandler,
- orderData);
-
- RegisterCommon(typeof(TEvent), orderData, out _);
+ EntAddSubscription(CompIdx.Index(), typeof(TComp), typeof(TEvent), EventHandler, orderType, before, after);
}
public void SubscribeLocalEvent(ComponentEventRefHandler handler)
where TComp : IComponent where TEvent : notnull
{
- void EventHandler(EntityUid uid, IComponent comp, ref TEvent args)
- => handler(uid, (TComp)comp, ref args);
+ void EventHandler(EntityUid uid, IComponent comp, ref Unit ev)
+ {
+ ref var tev = ref Unsafe.As(ref ev);
+ handler(uid, (TComp) comp, ref tev);
+ }
- EntSubscribe(
- CompIdx.Index(),
- typeof(TComp),
- typeof(TEvent),
- EventHandler,
- null);
+ EntAddSubscription(CompIdx.Index(), typeof(TComp), typeof(TEvent), EventHandler);
}
public void SubscribeLocalEvent(ComponentEventRefHandler handler, Type orderType,
Type[]? before = null,
Type[]? after = null) where TComp : IComponent where TEvent : notnull
{
- void EventHandler(EntityUid uid, IComponent comp, ref TEvent args)
- => handler(uid, (TComp)comp, ref args);
+ void EventHandler(EntityUid uid, IComponent comp, ref Unit ev)
+ {
+ ref var tev = ref Unsafe.As(ref ev);
+ handler(uid, (TComp) comp, ref tev);
+ }
- var orderData = CreateOrderingData(orderType, before, after);
-
- EntSubscribe(
- CompIdx.Index(),
- typeof(TComp),
- typeof(TEvent),
- EventHandler,
- orderData);
-
- RegisterCommon(typeof(TEvent), orderData, out _);
+ EntAddSubscription(CompIdx.Index(), typeof(TComp), typeof(TEvent), EventHandler, orderType, before, after);
}
public void SubscribeLocalEvent(EntityEventRefHandler handler, Type orderType,
Type[]? before = null,
Type[]? after = null) where TComp : IComponent where TEvent : notnull
{
- void EventHandler(EntityUid uid, IComponent comp, ref TEvent args)
- => handler(new Entity(uid, (TComp) comp), ref args);
+ void EventHandler(EntityUid uid, IComponent comp, ref Unit ev)
+ {
+ ref var tev = ref Unsafe.As(ref ev);
+ handler(new Entity(uid, (TComp) comp), ref tev);
+ }
- var orderData = CreateOrderingData(orderType, before, after);
-
- EntSubscribe(
- CompIdx.Index(),
- typeof(TComp),
- typeof(TEvent),
- EventHandler,
- orderData);
-
- RegisterCommon(typeof(TEvent), orderData, out _);
+ EntAddSubscription(CompIdx.Index(), typeof(TComp), typeof(TEvent), EventHandler, orderType, before, after);
}
///
@@ -340,7 +310,24 @@ namespace Robust.Shared.GameObjects
where TComp : IComponent
where TEvent : notnull
{
- EntUnsubscribe(CompIdx.Index(), typeof(TEvent));
+ if (!_comFac.TryGetRegistration(typeof(TComp), out _))
+ {
+ if (!IgnoreUnregisteredComponents)
+ throw new InvalidOperationException($"Component is not a valid reference type: {typeof(TComp).Name}");
+
+ return;
+ }
+
+ if (_subscriptionLock)
+ throw new InvalidOperationException("Subscription locked.");
+
+ var i = CompIdx.ArrayIndex();
+
+ _eventSubsUnfrozen[i]!.Remove(typeof(TEvent));
+ _compEventSubsUnfrozen[i]!.Remove(typeof(TEvent));
+
+ if (_eventSubsInv.TryGetValue(typeof(TEvent), out var t))
+ t.Remove(CompIdx.Index());
}
private void ComFacOnComponentsAdded(ComponentRegistration[] regs)
@@ -351,6 +338,7 @@ namespace Robust.Shared.GameObjects
foreach (var reg in regs)
{
CompIdx.RefArray(ref _eventSubsUnfrozen, reg.Idx) ??= new();
+ CompIdx.RefArray(ref _compEventSubsUnfrozen, reg.Idx) ??= new();
}
}
@@ -374,40 +362,17 @@ namespace Robust.Shared.GameObjects
_subscriptionLock = true;
_eventData = _eventDataUnfrozen.ToFrozenDictionary();
- // Find last non-null entry.
- var last = 0;
- for (var i = 0; i < _eventSubsUnfrozen.Length; i++)
- {
- var entry = _eventSubsUnfrozen[i];
- if (entry != null)
- last = i;
- }
-
- // TODO PERFORMANCE
- // make this only contain events that actually use comp-events
- // Assuming it makes the frozen dictionaries more specialized and thus faster.
- // AFAIK currently only MapInit is both a comp-event and a general event.
- // It should probably be changed to just be a comp event.
- _compEventSubs = _eventSubsUnfrozen
- .Take(last+1)
+ _eventSubs = TrimNull(_eventSubsUnfrozen)
.Select(dict => dict?.ToFrozenDictionary()!)
.ToArray();
- _eventSubs = _eventSubsUnfrozen
- .Take(last+1)
- .Select(dict => dict?.Where(x => !IsComponentEvent(x.Key)).ToFrozenDictionary()!)
+ _compEventSubs = TrimNull(_compEventSubsUnfrozen)
+ .Select(dict => dict?.ToFrozenDictionary()!)
.ToArray();
CalcOrdering();
}
- private bool IsComponentEvent(Type t)
- {
- var isCompEv = _eventData[t].ComponentEvent;
- DebugTools.Assert(isCompEv == t.HasCustomAttribute());
- return isCompEv;
- }
-
public void OnComponentRemoved(in RemovedComponentEventArgs e)
{
EntRemoveComponent(e.BaseArgs.Owner, e.Idx);
@@ -417,13 +382,15 @@ namespace Robust.Shared.GameObjects
CompIdx compType,
Type compTypeObj,
Type eventType,
- DirectedRegistration registration)
+ DirectedEventHandler handler,
+ Type? orderType = null,
+ Type[]? before = null,
+ Type[]? after = null)
{
if (_subscriptionLock)
throw new InvalidOperationException("Subscription locked.");
- if (compType.Value >= _eventSubsUnfrozen.Length
- || _eventSubsUnfrozen[compType.Value] is not { } compSubs)
+ if (!_comFac.TryGetRegistration(compTypeObj, out _))
{
if (IgnoreUnregisteredComponents)
return;
@@ -431,53 +398,25 @@ namespace Robust.Shared.GameObjects
throw new InvalidOperationException($"Component is not a valid reference type: {compTypeObj.Name}");
}
- if (compSubs.ContainsKey(eventType))
+ if (eventType.GetCustomAttribute() is { } attr)
{
- throw new InvalidOperationException(
- $"Duplicate Subscriptions for comp={compTypeObj}, event={eventType.Name}");
- }
+ if (!_compEventSubsUnfrozen[compType.Value]!.TryAdd(eventType, handler))
+ throw new InvalidOperationException($"Duplicate Subscriptions for comp={compTypeObj}, event={eventType.Name}");
- compSubs.Add(eventType, registration);
-
- RegisterCommon(eventType, registration.Ordering, out var data);
- data.ComponentEvent = eventType.HasCustomAttribute();
- if (!data.ComponentEvent)
- _eventSubsInv.GetOrNew(eventType).Add(compType);
- }
-
- private void EntSubscribe(
- CompIdx compType,
- Type compTypeObj,
- Type eventType,
- DirectedEventHandler handler,
- OrderingData? order)
- where TEvent : notnull
- {
- EntAddSubscription(compType, compTypeObj, eventType, new DirectedRegistration(handler, order,
- (EntityUid uid, IComponent comp, ref Unit ev) =>
- {
- ref var tev = ref Unsafe.As(ref ev);
- handler(uid, comp, ref tev);
- }));
- }
-
- private void EntUnsubscribe(CompIdx compType, Type eventType)
- {
- if (_subscriptionLock)
- throw new InvalidOperationException("Subscription locked.");
-
- if (compType.Value >= _eventSubsUnfrozen.Length
- || _eventSubsUnfrozen[compType.Value] is not { } compSubs)
- {
- if (IgnoreUnregisteredComponents)
+ // An exclusive component-event is only raised via RaiseComponentEvent, hence it don't need a normal
+ // directed event subscription
+ if (attr.Exclusive)
return;
-
- throw new InvalidOperationException("Trying to unsubscribe from unregistered component!");
}
- var removed = compSubs.Remove(eventType);
- if (removed)
- _eventSubsInv[eventType].Remove(compType);
+ var orderData = orderType == null ? null : CreateOrderingData(orderType, before, after);
+ var reg = new DirectedRegistration(orderData, handler);
+
+ if (!_eventSubsUnfrozen[compType.Value]!.TryAdd(eventType, reg))
+ throw new InvalidOperationException($"Duplicate Subscriptions for comp={compTypeObj}, event={eventType.Name}");
+
+ RegisterCommon(eventType, reg.Ordering, out _);
+ _eventSubsInv.GetOrNew(eventType).Add(compType);
}
private void EntAddEntity(EntityUid euid)
@@ -501,8 +440,6 @@ namespace Robust.Shared.GameObjects
foreach (var evType in compSubs.Keys)
{
- DebugTools.Assert(!_eventData[evType].ComponentEvent);
-
if (eventTable.Free < 0)
GrowEventTable(eventTable);
@@ -563,7 +500,6 @@ namespace Robust.Shared.GameObjects
foreach (var evType in compSubs.Keys)
{
- DebugTools.Assert(!_eventData[evType].ComponentEvent);
ref var indices = ref CollectionsMarshal.GetValueRefOrNullRef(eventTable.EventIndices, evType);
if (Unsafe.IsNullRef(ref indices))
{
@@ -667,17 +603,6 @@ namespace Robust.Shared.GameObjects
}
}
- private void DispatchComponent(
- EntityUid euid,
- IComponent component,
- CompIdx baseType,
- ref Unit args)
- where TEvent : notnull
- {
- if (_compEventSubs[baseType.Value].TryGetValue(typeof(TEvent), out var reg))
- reg.Handler(euid, component, ref args);
- }
-
public void ClearSubscriptions()
{
_subscriptionLock = false;
@@ -691,6 +616,10 @@ namespace Robust.Shared.GameObjects
{
sub?.Clear();
}
+ foreach (var sub in _compEventSubsUnfrozen)
+ {
+ sub?.Clear();
+ }
}
public void Dispose()
@@ -705,22 +634,14 @@ namespace Robust.Shared.GameObjects
_compEventSubs = null!;
_eventSubs = null!;
_eventSubsUnfrozen = null!;
+ _compEventSubsUnfrozen = null!;
_eventSubsInv = null!;
}
- internal sealed class DirectedRegistration : OrderedRegistration
+ internal sealed class DirectedRegistration(OrderingData? ordering, DirectedEventHandler handler)
+ : OrderedRegistration(ordering)
{
- public readonly Delegate Original;
- public readonly DirectedEventHandler Handler;
-
- public DirectedRegistration(
- Delegate original,
- OrderingData? ordering,
- DirectedEventHandler handler) : base(ordering)
- {
- Original = original;
- Handler = handler;
- }
+ public readonly DirectedEventHandler Handler = handler;
public void SetOrder(int order)
{
@@ -753,6 +674,48 @@ namespace Robust.Shared.GameObjects
public int Next;
public CompIdx Component;
}
+
+ ///
+ /// Return a new array with any trailing null entries removed.
+ ///
+ public static T[] TrimNull(T[] input)
+ {
+ // Find last non-null entry.
+ var last = 0;
+ for (var i = 0; i < input.Length; i++)
+ {
+ var entry = input[i];
+ if (entry != null)
+ last = i;
+ }
+
+ return input[..(last + 1)];
+ }
+
+ ///
+ /// Get an array of event handlers for a given component event, indexed by the component's net-id.
+ ///
+ ///
+ /// For most events, this will generally be a pretty sparse array, with most entries being null. However, for
+ /// the get and handle state events, this array will be relatively dense and helps save PVS a lot of save a
+ /// FrozenDictionary lookups.
+ ///
+ internal DirectedEventHandler?[] GetNetCompEventHandlers()
+ {
+ DebugTools.Assert(_subscriptionLock);
+ DebugTools.Assert(typeof(TEvent).HasCustomAttribute());
+
+ var netComps = _comFac.NetworkedComponents!;
+ var result = new DirectedEventHandler?[netComps.Count];
+
+ for (var i = 0; i < netComps.Count; i++)
+ {
+ var reg = netComps[i];
+ result[i] = _compEventSubs[reg.Idx.Value].GetValueOrDefault(typeof(TEvent));
+ }
+
+ return result;
+ }
}
///
diff --git a/Robust.Shared/GameObjects/EntityManager.Components.cs b/Robust.Shared/GameObjects/EntityManager.Components.cs
index bb0dfe520..3d7323717 100644
--- a/Robust.Shared/GameObjects/EntityManager.Components.cs
+++ b/Robust.Shared/GameObjects/EntityManager.Components.cs
@@ -406,7 +406,7 @@ namespace Robust.Shared.GameObjects
var eventArgs = new AddedComponentEventArgs(new ComponentEventArgs(component, uid), reg);
ComponentAdded?.Invoke(eventArgs);
- _eventBus.OnComponentAdded(eventArgs);
+ EventBusInternal.OnComponentAdded(eventArgs);
LifeAddToEntity(uid, component, reg.Idx);
@@ -427,7 +427,7 @@ namespace Robust.Shared.GameObjects
LifeStartup(uid, component, reg.Idx);
if (metadata.EntityLifeStage >= EntityLifeStage.MapInitialized)
- EventBus.RaiseComponentEvent(uid, component, reg.Idx, MapInitEventInstance);
+ EventBusInternal.RaiseComponentEvent(uid, component, reg.Idx, MapInitEventInstance);
}
///
@@ -717,7 +717,7 @@ namespace Robust.Shared.GameObjects
var eventArgs = new RemovedComponentEventArgs(new ComponentEventArgs(component, entityUid), false, metadata, idx);
ComponentRemoved?.Invoke(eventArgs);
- _eventBus.OnComponentRemoved(eventArgs);
+ EventBusInternal.OnComponentRemoved(eventArgs);
if (!terminating)
{
@@ -1708,9 +1708,12 @@ namespace Robust.Shared.GameObjects
}
public bool CanGetComponentState(IEventBus eventBus, IComponent component, ICommonSession player)
+ => CanGetComponentState(component, player);
+
+ public bool CanGetComponentState(IComponent component, ICommonSession player)
{
var attempt = new ComponentGetStateAttemptEvent(player);
- eventBus.RaiseComponentEvent(component.Owner, component, ref attempt);
+ EventBusInternal.RaiseComponentEvent(component.Owner, component, ref attempt);
return !attempt.Cancelled;
}
diff --git a/Robust.Shared/GameObjects/EntityManager.LifeCycle.cs b/Robust.Shared/GameObjects/EntityManager.LifeCycle.cs
index 84ed16f03..f569636f0 100644
--- a/Robust.Shared/GameObjects/EntityManager.LifeCycle.cs
+++ b/Robust.Shared/GameObjects/EntityManager.LifeCycle.cs
@@ -24,7 +24,7 @@ public partial class EntityManager
component.CreationTick = CurrentTick;
// networked components are assumed to be dirty when added to entities. See also: ClearTicks()
component.LastModifiedTick = CurrentTick;
- EventBus.RaiseComponentEvent(uid, component, idx, CompAddInstance);
+ EventBusInternal.RaiseComponentEvent(uid, component, idx, CompAddInstance);
component.LifeStage = ComponentLifeStage.Added;
#pragma warning restore CS0618 // Type or member is obsolete
}
@@ -39,7 +39,7 @@ public partial class EntityManager
DebugTools.Assert(component.LifeStage == ComponentLifeStage.Added);
component.LifeStage = ComponentLifeStage.Initializing;
- EventBus.RaiseComponentEvent(uid, component, idx, CompInitInstance);
+ EventBusInternal.RaiseComponentEvent(uid, component, idx, CompInitInstance);
component.LifeStage = ComponentLifeStage.Initialized;
}
@@ -53,7 +53,7 @@ public partial class EntityManager
DebugTools.Assert(component.LifeStage == ComponentLifeStage.Initialized);
component.LifeStage = ComponentLifeStage.Starting;
- EventBus.RaiseComponentEvent(uid, component, idx, CompStartupInstance);
+ EventBusInternal.RaiseComponentEvent(uid, component, idx, CompStartupInstance);
component.LifeStage = ComponentLifeStage.Running;
}
@@ -76,7 +76,7 @@ public partial class EntityManager
}
component.LifeStage = ComponentLifeStage.Stopping;
- EventBus.RaiseComponentEvent(uid, component, idx, CompShutdownInstance);
+ EventBusInternal.RaiseComponentEvent(uid, component, idx, CompShutdownInstance);
component.LifeStage = ComponentLifeStage.Stopped;
}
@@ -90,7 +90,7 @@ public partial class EntityManager
DebugTools.Assert(component.LifeStage != ComponentLifeStage.PreAdd);
component.LifeStage = ComponentLifeStage.Removing;
- EventBus.RaiseComponentEvent(uid, component, idx, CompRemoveInstance);
+ EventBusInternal.RaiseComponentEvent(uid, component, idx, CompRemoveInstance);
component.LifeStage = ComponentLifeStage.Deleted;
}
diff --git a/Robust.Shared/GameObjects/EntityManager.cs b/Robust.Shared/GameObjects/EntityManager.cs
index bf2d802bb..680d24ef5 100644
--- a/Robust.Shared/GameObjects/EntityManager.cs
+++ b/Robust.Shared/GameObjects/EntityManager.cs
@@ -81,14 +81,14 @@ namespace Robust.Shared.GameObjects
///
protected readonly HashSet Entities = new();
- private EntityEventBus _eventBus = null!;
+ internal EntityEventBus EventBusInternal = null!;
protected int NextEntityUid = (int) EntityUid.FirstUid;
protected int NextNetworkId = (int) NetEntity.First;
///
- public IEventBus EventBus => _eventBus;
+ public IEventBus EventBus => EventBusInternal;
public event Action>? EntityAdded;
public event Action>? EntityInitialized;
@@ -142,7 +142,7 @@ namespace Robust.Shared.GameObjects
if (Initialized)
throw new InvalidOperationException("Initialize() called multiple times");
- _eventBus = new EntityEventBus(this, _reflection);
+ EventBusInternal = new EntityEventBus(this, _reflection);
InitializeComponents();
_metaReg = _componentFactory.GetRegistration(typeof(MetaDataComponent));
@@ -233,7 +233,7 @@ namespace Robust.Shared.GameObjects
// TODO: Probably better to call this on its own given it's so infrequent.
_entitySystemManager.Initialize();
Started = true;
- _eventBus.LockSubscriptions();
+ EventBusInternal.LockSubscriptions();
_mapSystem = System();
_xforms = System();
_containers = System();
@@ -248,7 +248,7 @@ namespace Robust.Shared.GameObjects
{
ShuttingDown = true;
FlushEntities();
- _eventBus.ClearSubscriptions();
+ EventBusInternal.ClearSubscriptions();
_entitySystemManager.Shutdown();
ClearComponents();
ShuttingDown = false;
@@ -262,8 +262,8 @@ namespace Robust.Shared.GameObjects
ShuttingDown = true;
FlushEntities();
_entitySystemManager.Clear();
- _eventBus.Dispose();
- _eventBus = null!;
+ EventBusInternal.Dispose();
+ EventBusInternal = null!;
ClearComponents();
ShuttingDown = false;
@@ -282,7 +282,7 @@ namespace Robust.Shared.GameObjects
using (histogram?.WithLabels("EntityEventBus").NewTimer())
using (_prof.Group("Events"))
{
- _eventBus.ProcessEventQueue();
+ EventBusInternal.ProcessEventQueue();
}
using (histogram?.WithLabels("QueuedDeletion").NewTimer())
@@ -604,7 +604,7 @@ namespace Robust.Shared.GameObjects
{
var ev = new EntityTerminatingEvent((uid, metadata));
BeforeEntityTerminating?.Invoke(ref ev);
- EventBus.RaiseLocalEvent(uid, ref ev, true);
+ EventBusInternal.RaiseLocalEvent(uid, ref ev, true);
}
catch (Exception e)
{
@@ -698,7 +698,7 @@ namespace Robust.Shared.GameObjects
#endif
}
- _eventBus.OnEntityDeleted(uid);
+ EventBusInternal.OnEntityDeleted(uid);
Entities.Remove(uid);
// Need to get the ID above before MetadataComponent shutdown but only remove it after everything else is done.
NetEntityLookup.Remove(metadata.NetEntity);
@@ -932,7 +932,7 @@ namespace Robust.Shared.GameObjects
// we want this called before adding components
EntityAdded?.Invoke((uid, metadata));
- _eventBus.OnEntityAdded(uid);
+ EventBusInternal.OnEntityAdded(uid);
Entities.Add(uid);
// add the required MetaDataComponent directly.
@@ -1049,7 +1049,7 @@ namespace Robust.Shared.GameObjects
DebugTools.Assert(meta.EntityLifeStage == EntityLifeStage.Initialized, $"Expected entity {ToPrettyString(entity)} to be initialized, was {meta.EntityLifeStage}");
SetLifeStage(meta, EntityLifeStage.MapInitialized);
- EventBus.RaiseLocalEvent(entity, MapInitEventInstance);
+ EventBusInternal.RaiseLocalEvent(entity, MapInitEventInstance);
}
///
diff --git a/Robust.Shared/GameObjects/EntitySystem.Subscriptions.cs b/Robust.Shared/GameObjects/EntitySystem.Subscriptions.cs
index 35764cb80..a38259d92 100644
--- a/Robust.Shared/GameObjects/EntitySystem.Subscriptions.cs
+++ b/Robust.Shared/GameObjects/EntitySystem.Subscriptions.cs
@@ -148,7 +148,7 @@ namespace Robust.Shared.GameObjects
{
foreach (var sub in _subscriptions)
{
- sub.Unsubscribe(this, EntityManager.EventBus);
+ sub.Unsubscribe(this, EntityManager.EventBusInternal);
}
_subscriptions = default;
diff --git a/Robust.Shared/GameObjects/EntitySystem.cs b/Robust.Shared/GameObjects/EntitySystem.cs
index c923cddd9..12aaa8ce0 100644
--- a/Robust.Shared/GameObjects/EntitySystem.cs
+++ b/Robust.Shared/GameObjects/EntitySystem.cs
@@ -99,22 +99,22 @@ namespace Robust.Shared.GameObjects
protected void RaiseLocalEvent(T message) where T : notnull
{
- EntityManager.EventBus.RaiseEvent(EventSource.Local, message);
+ EntityManager.EventBusInternal.RaiseEvent(EventSource.Local, message);
}
protected void RaiseLocalEvent(ref T message) where T : notnull
{
- EntityManager.EventBus.RaiseEvent(EventSource.Local, ref message);
+ EntityManager.EventBusInternal.RaiseEvent(EventSource.Local, ref message);
}
protected void RaiseLocalEvent(object message)
{
- EntityManager.EventBus.RaiseEvent(EventSource.Local, message);
+ EntityManager.EventBusInternal.RaiseEvent(EventSource.Local, message);
}
protected void QueueLocalEvent(EntityEventArgs message)
{
- EntityManager.EventBus.QueueEvent(EventSource.Local, message);
+ EntityManager.EventBusInternal.QueueEvent(EventSource.Local, message);
}
protected void RaiseNetworkEvent(EntityEventArgs message)
@@ -158,23 +158,36 @@ namespace Robust.Shared.GameObjects
protected void RaiseLocalEvent(EntityUid uid, TEvent args, bool broadcast = false)
where TEvent : notnull
{
- EntityManager.EventBus.RaiseLocalEvent(uid, args, broadcast);
+ EntityManager.EventBusInternal.RaiseLocalEvent(uid, args, broadcast);
}
protected void RaiseLocalEvent(EntityUid uid, object args, bool broadcast = false)
{
- EntityManager.EventBus.RaiseLocalEvent(uid, args, broadcast);
+ EntityManager.EventBusInternal.RaiseLocalEvent(uid, args, broadcast);
}
protected void RaiseLocalEvent(EntityUid uid, ref TEvent args, bool broadcast = false)
where TEvent : notnull
{
- EntityManager.EventBus.RaiseLocalEvent(uid, ref args, broadcast);
+ EntityManager.EventBusInternal.RaiseLocalEvent(uid, ref args, broadcast);
}
protected void RaiseLocalEvent(EntityUid uid, ref object args, bool broadcast = false)
{
- EntityManager.EventBus.RaiseLocalEvent(uid, ref args, broadcast);
+ EntityManager.EventBusInternal.RaiseLocalEvent(uid, ref args, broadcast);
+ }
+
+ protected void RaiseComponentEvent(EntityUid uid, TComp comp, ref TEvent args)
+ where TEvent : notnull
+ where TComp : IComponent
+ {
+ EntityManager.EventBusInternal.RaiseComponentEvent(uid, comp, ref args);
+ }
+
+ public void RaiseComponentEvent(EntityUid uid, IComponent component, ref TEvent args)
+ where TEvent : notnull
+ {
+ EntityManager.EventBusInternal.RaiseComponentEvent(uid, component, ref args);
}
#endregion
diff --git a/Robust.Shared/GameObjects/EventBusAttributes.cs b/Robust.Shared/GameObjects/EventBusAttributes.cs
index 54848a892..13aa55d30 100644
--- a/Robust.Shared/GameObjects/EventBusAttributes.cs
+++ b/Robust.Shared/GameObjects/EventBusAttributes.cs
@@ -3,15 +3,17 @@ using System;
namespace Robust.Shared.GameObjects;
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct)]
-public sealed class ByRefEventAttribute : Attribute
-{
-}
+public sealed class ByRefEventAttribute : Attribute;
///
-/// Indicates that an eventbus event should only ever be raised through .
-/// This allows extra optimizations.
+/// This attribute enables an event to be raised as a "component event" via .
///
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct)]
internal sealed class ComponentEventAttribute : Attribute
{
+ ///
+ /// If true, this event may **only** be raised via as a "component event", as any subscriptions will not be
+ /// included in the normal event tables.
+ ///
+ public bool Exclusive = true;
}
diff --git a/Robust.Shared/GameObjects/IMapInit.cs b/Robust.Shared/GameObjects/IMapInit.cs
index 194535788..8762ae83f 100644
--- a/Robust.Shared/GameObjects/IMapInit.cs
+++ b/Robust.Shared/GameObjects/IMapInit.cs
@@ -3,6 +3,7 @@ namespace Robust.Shared.GameObjects
///
/// Raised directed on an entity when the map is initialized.
///
+ [ComponentEvent(Exclusive = false)]
public sealed class MapInitEvent : EntityEventArgs
{
}
diff --git a/Robust.UnitTesting/Server/GameStates/PvsPauseTest.cs b/Robust.UnitTesting/Server/GameStates/PvsPauseTest.cs
index 4bd6432b9..12e4d6759 100644
--- a/Robust.UnitTesting/Server/GameStates/PvsPauseTest.cs
+++ b/Robust.UnitTesting/Server/GameStates/PvsPauseTest.cs
@@ -166,9 +166,8 @@ public sealed class PvsPauseTest : RobustIntegrationTest
AssertEnt(paused: true, detached: false, clientPaused: true);
}
- await client.WaitPost(() => netMan.ClientDisconnect(""));
- await server.WaitRunTicks(5);
- await client.WaitRunTicks(5);
+ client.Post(() => netMan.ClientDisconnect(""));
+ await RunTicks();
}
}
diff --git a/Robust.UnitTesting/Shared/GameObjects/EntityEventBusTests.ComponentEvent.cs b/Robust.UnitTesting/Shared/GameObjects/EntityEventBusTests.ComponentEvent.cs
index 1a76bc500..5ce870211 100644
--- a/Robust.UnitTesting/Shared/GameObjects/EntityEventBusTests.ComponentEvent.cs
+++ b/Robust.UnitTesting/Shared/GameObjects/EntityEventBusTests.ComponentEvent.cs
@@ -2,11 +2,8 @@ using System.Collections.Generic;
using Moq;
using NUnit.Framework;
using Robust.Shared.GameObjects;
-using Robust.Shared.IoC;
-using Robust.Shared.Log;
using Robust.Shared.Reflection;
-using Robust.Shared.Serialization.Manager;
-using Robust.UnitTesting.Shared.Reflection;
+using Robust.UnitTesting.Server;
namespace Robust.UnitTesting.Shared.GameObjects
{
@@ -15,30 +12,8 @@ namespace Robust.UnitTesting.Shared.GameObjects
[Test]
public void SubscribeCompEvent()
{
- var compFactory = new ComponentFactory(new DynamicTypeFactory(), new ReflectionManagerTest(), new SerializationManager(), new LogManager());
-
- // Arrange
- var entUid = new EntityUid(7);
- var compInstance = new MetaDataComponent();
-
- var entManMock = new Mock();
- var reflectMock = new Mock();
-
- compFactory.RegisterClass();
- entManMock.Setup(m => m.ComponentFactory).Returns(compFactory);
-
- IComponent? outIComponent = compInstance;
- entManMock.Setup(m => m.TryGetComponent(entUid, CompIdx.Index(), out outIComponent))
- .Returns(true);
-
- entManMock.Setup(m => m.GetComponent(entUid, CompIdx.Index()))
- .Returns(compInstance);
-
- entManMock.Setup(m => m.GetComponentInternal(entUid, CompIdx.Index()))
- .Returns(compInstance);
-
- var bus = new EntityEventBus(entManMock.Object, reflectMock.Object);
- bus.OnlyCallOnRobustUnitTestISwearToGodPleaseSomebodyKillThisNightmare();
+ var (bus, sim, entUid, compInstance) = EntFactory();
+ var compFactory = sim.Resolve();
// Subscribe
int calledCount = 0;
@@ -70,34 +45,8 @@ namespace Robust.UnitTesting.Shared.GameObjects
[Test]
public void UnsubscribeCompEvent()
{
- // Arrange
- var entUid = new EntityUid(7);
- var compInstance = new MetaDataComponent();
-
- var entManMock = new Mock();
-
- var compRegistration = new ComponentRegistration(
- "MetaData",
- typeof(MetaDataComponent),
- CompIdx.Index());
-
- var compFacMock = new Mock();
- var reflectMock = new Mock();
-
- compFacMock.Setup(m => m.GetRegistration(CompIdx.Index())).Returns(compRegistration);
- compFacMock.Setup(m => m.GetAllRegistrations()).Returns(new[] { compRegistration });
- compFacMock.Setup(m => m.GetIndex(typeof(MetaDataComponent))).Returns(CompIdx.Index());
- entManMock.Setup(m => m.ComponentFactory).Returns(compFacMock.Object);
-
- IComponent? outIComponent = compInstance;
- entManMock.Setup(m => m.TryGetComponent(entUid, typeof(MetaDataComponent), out outIComponent))
- .Returns(true);
-
- entManMock.Setup(m => m.GetComponent(entUid, typeof(MetaDataComponent)))
- .Returns(compInstance);
-
- var bus = new EntityEventBus(entManMock.Object, reflectMock.Object);
- bus.OnlyCallOnRobustUnitTestISwearToGodPleaseSomebodyKillThisNightmare();
+ var (bus, sim, entUid, compInstance) = EntFactory();
+ var compFactory = sim.Resolve();
// Subscribe
int calledCount = 0;
@@ -108,7 +57,7 @@ namespace Robust.UnitTesting.Shared.GameObjects
// add a component to the system
bus.OnEntityAdded(entUid);
- var reg = compFacMock.Object.GetRegistration(CompIdx.Index());
+ var reg = compFactory.GetRegistration(CompIdx.Index());
bus.OnComponentAdded(new AddedComponentEventArgs(new ComponentEventArgs(compInstance, entUid), reg));
// Raise
@@ -121,58 +70,22 @@ namespace Robust.UnitTesting.Shared.GameObjects
{
calledCount++;
}
-
}
[Test]
public void SubscribeCompLifeEvent()
{
- // Arrange
- var entUid = new EntityUid(7);
- var compInstance = new MetaDataComponent();
-
- var entManMock = new Mock();
-
-#pragma warning disable CS0618 // Type or member is obsolete
- compInstance.Owner = entUid;
-#pragma warning restore CS0618 // Type or member is obsolete
-
- var compRegistration = new ComponentRegistration(
- "MetaData",
- typeof(MetaDataComponent),
- CompIdx.Index());
-
- var compFacMock = new Mock();
- var reflectMock = new Mock();
-
- compFacMock.Setup(m => m.GetRegistration(CompIdx.Index())).Returns(compRegistration);
- compFacMock.Setup(m => m.GetAllRegistrations()).Returns(new[] { compRegistration });
- compFacMock.Setup(m => m.GetIndex(typeof(MetaDataComponent))).Returns(CompIdx.Index());
- entManMock.Setup(m => m.ComponentFactory).Returns(compFacMock.Object);
-
- IComponent? outIComponent = compInstance;
- entManMock.Setup(m => m.TryGetComponent(entUid, typeof(MetaDataComponent), out outIComponent))
- .Returns(true);
-
- entManMock.Setup(m => m.GetComponent(entUid, typeof(MetaDataComponent)))
- .Returns(compInstance);
-
- var bus = new EntityEventBus(entManMock.Object, reflectMock.Object);
- bus.OnlyCallOnRobustUnitTestISwearToGodPleaseSomebodyKillThisNightmare();
+ var (bus, sim, entUid, compInstance) = EntFactory();
+ var entMan = sim.Resolve();
+ var fact = sim.Resolve();
// Subscribe
int calledCount = 0;
bus.SubscribeLocalEvent(HandleTestEvent);
bus.LockSubscriptions();
- // add a component to the system
- entManMock.Raise(m => m.EntityAdded += null, entUid);
-
- var reg = compFacMock.Object.GetRegistration();
- entManMock.Raise(m => m.ComponentAdded += null, new AddedComponentEventArgs(new ComponentEventArgs(compInstance, entUid), reg));
-
// Raise
- ((IEventBus)bus).RaiseComponentEvent(entUid, compInstance, new ComponentInit());
+ bus.RaiseComponentEvent(entUid, compInstance, new ComponentInit());
// Assert
Assert.That(calledCount, Is.EqualTo(1));
@@ -187,39 +100,25 @@ namespace Robust.UnitTesting.Shared.GameObjects
[Test]
public void CompEventOrdered()
{
- // Arrange
- var entUid = new EntityUid(7);
+ var sim = RobustServerSimulation
+ .NewSimulation()
+ .RegisterComponents(f =>
+ {
+ f.RegisterClass();
+ f.RegisterClass();
+ f.RegisterClass();
+ })
+ .InitializeInstance();
- var entManMock = new Mock();
- var compFacMock = new Mock();
- var reflectMock = new Mock();
+ var entMan = sim.Resolve();
+ var entUid = entMan.Spawn();
+ var instA = entMan.AddComponent(entUid);
+ var instB = entMan.AddComponent(entUid);
+ var instC = entMan.AddComponent(entUid);
+ var bus = entMan.EventBusInternal;
+ bus.ClearSubscriptions();
- List allRefTypes = new();
- void Setup(out T instance) where T : IComponent, new()
- {
- IComponent? inst = instance = new T();
- var reg = new ComponentRegistration(
- typeof(T).Name,
- typeof(T),
- CompIdx.Index());
-
- compFacMock.Setup(m => m.GetRegistration(CompIdx.Index())).Returns(reg);
- compFacMock.Setup(m => m.GetIndex(typeof(T))).Returns(CompIdx.Index());
- entManMock.Setup(m => m.TryGetComponent(entUid, CompIdx.Index(), out inst)).Returns(true);
- entManMock.Setup(m => m.GetComponent(entUid, CompIdx.Index())).Returns(inst);
- entManMock.Setup(m => m.GetComponentInternal(entUid, CompIdx.Index())).Returns(inst);
- allRefTypes.Add(reg);
- }
-
- Setup(out var instA);
- Setup(out var instB);
- Setup(out var instC);
-
- compFacMock.Setup(m => m.GetAllRegistrations()).Returns(allRefTypes.ToArray());
-
- entManMock.Setup(m => m.ComponentFactory).Returns(compFacMock.Object);
- var bus = new EntityEventBus(entManMock.Object, reflectMock.Object);
- bus.OnlyCallOnRobustUnitTestISwearToGodPleaseSomebodyKillThisNightmare();
+ var fact = sim.Resolve();
// Subscribe
var a = false;
@@ -250,9 +149,9 @@ namespace Robust.UnitTesting.Shared.GameObjects
// add a component to the system
bus.OnEntityAdded(entUid);
- var regA = compFacMock.Object.GetRegistration(CompIdx.Index());
- var regB = compFacMock.Object.GetRegistration(CompIdx.Index());
- var regC = compFacMock.Object.GetRegistration(CompIdx.Index());
+ var regA = fact.GetRegistration(CompIdx.Index());
+ var regB = fact.GetRegistration(CompIdx.Index());
+ var regC = fact.GetRegistration(CompIdx.Index());
bus.OnComponentAdded(new AddedComponentEventArgs(new ComponentEventArgs(instA, entUid), regA));
bus.OnComponentAdded(new AddedComponentEventArgs(new ComponentEventArgs(instB, entUid), regB));
@@ -271,40 +170,25 @@ namespace Robust.UnitTesting.Shared.GameObjects
[Test]
public void CompEventLoop()
{
- var entUid = new EntityUid(7);
+ var sim = RobustServerSimulation
+ .NewSimulation()
+ .RegisterComponents(f =>
+ {
+ f.RegisterClass();
+ f.RegisterClass();
+ })
+ .InitializeInstance();
- var entManMock = new Mock();
- var compFacMock = new Mock();
- var reflectMock = new Mock();
+ var entMan = sim.Resolve();
+ var entUid = entMan.Spawn();
+ var instA = entMan.AddComponent(entUid);
+ var instB = entMan.AddComponent(entUid);
+ var bus = entMan.EventBusInternal;
+ bus.ClearSubscriptions();
- List allRefTypes = new();
- void Setup(out T instance) where T : IComponent, new()
- {
- IComponent? inst = instance = new T();
- var reg = new ComponentRegistration(
- typeof(T).Name,
- typeof(T),
- CompIdx.Index());
-
- compFacMock.Setup(m => m.GetRegistration(CompIdx.Index())).Returns(reg);
- compFacMock.Setup(m => m.GetIndex(typeof(T))).Returns(CompIdx.Index());
- entManMock.Setup(m => m.TryGetComponent(entUid, CompIdx.Index(), out inst)).Returns(true);
- entManMock.Setup(m => m.GetComponent(entUid, CompIdx.Index())).Returns(inst);
- entManMock.Setup(m => m.GetComponentInternal(entUid, CompIdx.Index())).Returns(inst);
- allRefTypes.Add(reg);
- }
-
- Setup(out var instA);
- Setup(out var instB);
-
- compFacMock.Setup(m => m.GetAllRegistrations()).Returns(allRefTypes.ToArray());
-
- entManMock.Setup(m => m.ComponentFactory).Returns(compFacMock.Object);
- var bus = new EntityEventBus(entManMock.Object, reflectMock.Object);
- bus.OnlyCallOnRobustUnitTestISwearToGodPleaseSomebodyKillThisNightmare();
-
- var regA = compFacMock.Object.GetRegistration(CompIdx.Index());
- var regB = compFacMock.Object.GetRegistration(CompIdx.Index());
+ var fact = sim.Resolve();
+ var regA = fact.GetRegistration(CompIdx.Index());
+ var regB = fact.GetRegistration(CompIdx.Index());
var handlerACount = 0;
void HandlerA(EntityUid uid, Component comp, TestEvent ev)
diff --git a/Robust.UnitTesting/Shared/GameObjects/EntityEventBusTests.SystemEvent.cs b/Robust.UnitTesting/Shared/GameObjects/EntityEventBusTests.SystemEvent.cs
index 6dd43e6fe..eb21d0bcf 100644
--- a/Robust.UnitTesting/Shared/GameObjects/EntityEventBusTests.SystemEvent.cs
+++ b/Robust.UnitTesting/Shared/GameObjects/EntityEventBusTests.SystemEvent.cs
@@ -1,22 +1,27 @@
using System;
-using Moq;
using NUnit.Framework;
using Robust.Shared.GameObjects;
-using Robust.Shared.Reflection;
+using Robust.UnitTesting.Server;
namespace Robust.UnitTesting.Shared.GameObjects
{
[TestFixture, Parallelizable, TestOf(typeof(EntityEventBus))]
public partial class EntityEventBusTests
{
+ private static (EntityEventBus Bus, ISimulation Sim, EntityUid Uid, MetaDataComponent Comp) EntFactory()
+ {
+ var sim = RobustServerSimulation.NewSimulation().InitializeInstance();
+ var entMan = sim.Resolve();
+ var uid = entMan.Spawn();
+ var comp = entMan.MetaQuery.Comp(uid);
+ var bus = entMan.EventBusInternal;
+ bus.ClearSubscriptions();
+ return (bus, sim, uid, comp);
+ }
+
private static EntityEventBus BusFactory()
{
- var compFacMock = new Mock();
- var entManMock = new Mock();
- var reflectMock = new Mock();
- entManMock.SetupGet(e => e.ComponentFactory).Returns(compFacMock.Object);
- var bus = new EntityEventBus(entManMock.Object, reflectMock.Object);
- return bus;
+ return EntFactory().Bus;
}
///