mirror of
https://github.com/space-wizards/RobustToolbox.git
synced 2026-02-15 03:30:53 +01:00
Fix ordered subscriptions not working when targeting a parent system type (#5135)
* Fix ordered subscriptions not working when targeting a parent system type * Fix missing usages of expand ordering * Extract method
This commit is contained in:
@@ -167,7 +167,7 @@ namespace Robust.Shared.GameObjects
|
||||
if (eventHandler == null)
|
||||
throw new ArgumentNullException(nameof(eventHandler));
|
||||
|
||||
var order = new OrderingData(orderType, before ?? Array.Empty<Type>(), after ?? Array.Empty<Type>());
|
||||
var order = CreateOrderingData(orderType, before, after);
|
||||
|
||||
SubscribeEventCommon<T>(source, subscriber,
|
||||
(ref Unit ev) => eventHandler(Unsafe.As<Unit, T>(ref ev)), eventHandler, order, false);
|
||||
@@ -187,7 +187,7 @@ namespace Robust.Shared.GameObjects
|
||||
EntityEventRefHandler<T> eventHandler,
|
||||
Type orderType, Type[]? before = null, Type[]? after = null) where T : notnull
|
||||
{
|
||||
var order = new OrderingData(orderType, before ?? Array.Empty<Type>(), after ?? Array.Empty<Type>());
|
||||
var order = CreateOrderingData(orderType, before, after);
|
||||
|
||||
SubscribeEventCommon<T>(source, subscriber, (ref Unit ev) =>
|
||||
{
|
||||
|
||||
@@ -5,6 +5,7 @@ using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.Collections;
|
||||
using Robust.Shared.Reflection;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Robust.Shared.GameObjects;
|
||||
@@ -13,6 +14,7 @@ internal sealed partial class EntityEventBus : IEventBus
|
||||
{
|
||||
private IEntityManager _entMan;
|
||||
private IComponentFactory _comFac;
|
||||
private IReflectionManager _reflection;
|
||||
|
||||
// Data on individual events. Used to check ordering info and fire broadcast events.
|
||||
private FrozenDictionary<Type, EventData> _eventData = FrozenDictionary<Type, EventData>.Empty;
|
||||
@@ -57,6 +59,8 @@ internal sealed partial class EntityEventBus : IEventBus
|
||||
|
||||
public bool IgnoreUnregisteredComponents;
|
||||
|
||||
private readonly List<Type> _childrenTypesTemp = [];
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static ref Unit ExtractUnitRef(ref object obj, Type objType)
|
||||
{
|
||||
|
||||
@@ -6,6 +6,7 @@ using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using Robust.Shared.Collections;
|
||||
using Robust.Shared.Reflection;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Robust.Shared.GameObjects
|
||||
@@ -117,10 +118,12 @@ namespace Robust.Shared.GameObjects
|
||||
/// Constructs a new instance of <see cref="EntityEventBus"/>.
|
||||
/// </summary>
|
||||
/// <param name="entMan">The entity manager to watch for entity/component events.</param>
|
||||
public EntityEventBus(IEntityManager entMan)
|
||||
/// <param name="reflection">The reflection manager to use when finding derived types.</param>
|
||||
public EntityEventBus(IEntityManager entMan, IReflectionManager reflection)
|
||||
{
|
||||
_entMan = entMan;
|
||||
_comFac = entMan.ComponentFactory;
|
||||
_reflection = reflection;
|
||||
|
||||
// Dynamic handling of components is only for RobustUnitTest compatibility spaghetti.
|
||||
_comFac.ComponentsAdded += ComFacOnComponentsAdded;
|
||||
@@ -248,7 +251,7 @@ namespace Robust.Shared.GameObjects
|
||||
void EventHandler(EntityUid uid, IComponent comp, ref TEvent args)
|
||||
=> handler(uid, (TComp)comp, args);
|
||||
|
||||
var orderData = new OrderingData(orderType, before ?? Array.Empty<Type>(), after ?? Array.Empty<Type>());
|
||||
var orderData = CreateOrderingData(orderType, before, after);
|
||||
|
||||
EntSubscribe<TEvent>(
|
||||
CompIdx.Index<TComp>(),
|
||||
@@ -281,7 +284,7 @@ namespace Robust.Shared.GameObjects
|
||||
void EventHandler(EntityUid uid, IComponent comp, ref TEvent args)
|
||||
=> handler(uid, (TComp)comp, ref args);
|
||||
|
||||
var orderData = new OrderingData(orderType, before ?? Array.Empty<Type>(), after ?? Array.Empty<Type>());
|
||||
var orderData = CreateOrderingData(orderType, before, after);
|
||||
|
||||
EntSubscribe<TEvent>(
|
||||
CompIdx.Index<TComp>(),
|
||||
@@ -300,7 +303,7 @@ namespace Robust.Shared.GameObjects
|
||||
void EventHandler(EntityUid uid, IComponent comp, ref TEvent args)
|
||||
=> handler(new Entity<TComp>(uid, (TComp) comp), ref args);
|
||||
|
||||
var orderData = new OrderingData(orderType, before ?? Array.Empty<Type>(), after ?? Array.Empty<Type>());
|
||||
var orderData = CreateOrderingData(orderType, before, after);
|
||||
|
||||
EntSubscribe<TEvent>(
|
||||
CompIdx.Index<TComp>(),
|
||||
@@ -667,6 +670,7 @@ namespace Robust.Shared.GameObjects
|
||||
// punishment for use-after-free
|
||||
_entMan = null!;
|
||||
_comFac = null!;
|
||||
_reflection = null!;
|
||||
_entEventTables = null!;
|
||||
_compEventSubs = null!;
|
||||
_eventSubs = null!;
|
||||
|
||||
@@ -200,5 +200,33 @@ namespace Robust.Shared.GameObjects
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private OrderingData CreateOrderingData(Type orderType, Type[]? before, Type[]? after)
|
||||
{
|
||||
AddChildrenTypes(ref before);
|
||||
AddChildrenTypes(ref after);
|
||||
return new OrderingData(orderType, before ?? [], after ?? []);
|
||||
}
|
||||
|
||||
private void AddChildrenTypes(ref Type[]? original)
|
||||
{
|
||||
if (original == null || original.Length == 0)
|
||||
return;
|
||||
|
||||
_childrenTypesTemp.Clear();
|
||||
foreach (var beforeType in original)
|
||||
{
|
||||
foreach (var child in _reflection.GetAllChildren(beforeType))
|
||||
{
|
||||
_childrenTypesTemp.Add(child);
|
||||
}
|
||||
}
|
||||
|
||||
if (_childrenTypesTemp.Count > 0)
|
||||
{
|
||||
Array.Resize(ref original, original.Length + _childrenTypesTemp.Count);
|
||||
_childrenTypesTemp.CopyTo(original, original.Length - _childrenTypesTemp.Count);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ using Robust.Shared.Physics.Components;
|
||||
using Robust.Shared.Player;
|
||||
using Robust.Shared.Profiling;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Reflection;
|
||||
using Robust.Shared.Serialization.Manager;
|
||||
using Robust.Shared.Serialization.Markdown.Mapping;
|
||||
using Robust.Shared.Timing;
|
||||
@@ -40,6 +41,7 @@ namespace Robust.Shared.GameObjects
|
||||
[IoC.Dependency] private readonly ISerializationManager _serManager = default!;
|
||||
[IoC.Dependency] private readonly ProfManager _prof = default!;
|
||||
[IoC.Dependency] private readonly INetManager _netMan = default!;
|
||||
[IoC.Dependency] private readonly IReflectionManager _reflection = default!;
|
||||
|
||||
// I feel like PJB might shed me for putting a system dependency here, but its required for setting entity
|
||||
// positions on spawn....
|
||||
@@ -125,7 +127,7 @@ namespace Robust.Shared.GameObjects
|
||||
if (Initialized)
|
||||
throw new InvalidOperationException("Initialize() called multiple times");
|
||||
|
||||
_eventBus = new EntityEventBus(this);
|
||||
_eventBus = new EntityEventBus(this, _reflection);
|
||||
|
||||
InitializeComponents();
|
||||
_metaReg = _componentFactory.GetRegistration(typeof(MetaDataComponent));
|
||||
|
||||
@@ -109,6 +109,17 @@ namespace Robust.Shared.GameObjects
|
||||
_subscriptions.Add(new SubBroadcast<EntitySessionMessage<T>>(src));
|
||||
}
|
||||
|
||||
protected void SubscribeLocalEvent<TComp, TEvent>(
|
||||
EntityEventRefHandler<TComp, TEvent> handler,
|
||||
Type[]? before = null, Type[]? after = null)
|
||||
where TComp : IComponent
|
||||
where TEvent : notnull
|
||||
{
|
||||
EntityManager.EventBus.SubscribeLocalEvent(handler, GetType(), before, after);
|
||||
|
||||
_subscriptions.Add(new SubLocal<TComp, TEvent>());
|
||||
}
|
||||
|
||||
/// <seealso cref="SubscribeLocalEvent{TComp, TEvent}(ComponentEventRefHandler{TComp, TEvent}, Type[], Type[])"/>
|
||||
// [Obsolete("Subscribe to the event by ref instead (ComponentEventRefHandler)")]
|
||||
protected void SubscribeLocalEvent<TComp, TEvent>(
|
||||
@@ -133,17 +144,6 @@ namespace Robust.Shared.GameObjects
|
||||
_subscriptions.Add(new SubLocal<TComp, TEvent>());
|
||||
}
|
||||
|
||||
protected void SubscribeLocalEvent<TComp, TEvent>(
|
||||
EntityEventRefHandler<TComp, TEvent> handler,
|
||||
Type[]? before = null, Type[]? after = null)
|
||||
where TComp : IComponent
|
||||
where TEvent : notnull
|
||||
{
|
||||
EntityManager.EventBus.SubscribeLocalEvent(handler, GetType(), before, after);
|
||||
|
||||
_subscriptions.Add(new SubLocal<TComp, TEvent>());
|
||||
}
|
||||
|
||||
private void ShutdownSubscriptions()
|
||||
{
|
||||
foreach (var sub in _subscriptions)
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
using System;
|
||||
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.UnitTesting.Shared.Reflection;
|
||||
|
||||
namespace Robust.UnitTesting.Shared.GameObjects
|
||||
@@ -21,6 +21,7 @@ namespace Robust.UnitTesting.Shared.GameObjects
|
||||
var compInstance = new MetaDataComponent();
|
||||
|
||||
var entManMock = new Mock<IEntityManager>();
|
||||
var reflectMock = new Mock<IReflectionManager>();
|
||||
|
||||
compFactory.RegisterClass<MetaDataComponent>();
|
||||
entManMock.Setup(m => m.ComponentFactory).Returns(compFactory);
|
||||
@@ -35,7 +36,7 @@ namespace Robust.UnitTesting.Shared.GameObjects
|
||||
entManMock.Setup(m => m.GetComponentInternal(entUid, CompIdx.Index<MetaDataComponent>()))
|
||||
.Returns(compInstance);
|
||||
|
||||
var bus = new EntityEventBus(entManMock.Object);
|
||||
var bus = new EntityEventBus(entManMock.Object, reflectMock.Object);
|
||||
bus.OnlyCallOnRobustUnitTestISwearToGodPleaseSomebodyKillThisNightmare();
|
||||
|
||||
// Subscribe
|
||||
@@ -80,6 +81,7 @@ namespace Robust.UnitTesting.Shared.GameObjects
|
||||
CompIdx.Index<MetaDataComponent>());
|
||||
|
||||
var compFacMock = new Mock<IComponentFactory>();
|
||||
var reflectMock = new Mock<IReflectionManager>();
|
||||
|
||||
compFacMock.Setup(m => m.GetRegistration(CompIdx.Index<MetaDataComponent>())).Returns(compRegistration);
|
||||
compFacMock.Setup(m => m.GetAllRegistrations()).Returns(new[] { compRegistration });
|
||||
@@ -92,7 +94,7 @@ namespace Robust.UnitTesting.Shared.GameObjects
|
||||
entManMock.Setup(m => m.GetComponent(entUid, typeof(MetaDataComponent)))
|
||||
.Returns(compInstance);
|
||||
|
||||
var bus = new EntityEventBus(entManMock.Object);
|
||||
var bus = new EntityEventBus(entManMock.Object, reflectMock.Object);
|
||||
bus.OnlyCallOnRobustUnitTestISwearToGodPleaseSomebodyKillThisNightmare();
|
||||
|
||||
// Subscribe
|
||||
@@ -137,6 +139,7 @@ namespace Robust.UnitTesting.Shared.GameObjects
|
||||
CompIdx.Index<MetaDataComponent>());
|
||||
|
||||
var compFacMock = new Mock<IComponentFactory>();
|
||||
var reflectMock = new Mock<IReflectionManager>();
|
||||
|
||||
compFacMock.Setup(m => m.GetRegistration(CompIdx.Index<MetaDataComponent>())).Returns(compRegistration);
|
||||
compFacMock.Setup(m => m.GetAllRegistrations()).Returns(new[] { compRegistration });
|
||||
@@ -149,7 +152,7 @@ namespace Robust.UnitTesting.Shared.GameObjects
|
||||
entManMock.Setup(m => m.GetComponent(entUid, typeof(MetaDataComponent)))
|
||||
.Returns(compInstance);
|
||||
|
||||
var bus = new EntityEventBus(entManMock.Object);
|
||||
var bus = new EntityEventBus(entManMock.Object, reflectMock.Object);
|
||||
bus.OnlyCallOnRobustUnitTestISwearToGodPleaseSomebodyKillThisNightmare();
|
||||
|
||||
// Subscribe
|
||||
@@ -184,6 +187,7 @@ namespace Robust.UnitTesting.Shared.GameObjects
|
||||
|
||||
var entManMock = new Mock<IEntityManager>();
|
||||
var compFacMock = new Mock<IComponentFactory>();
|
||||
var reflectMock = new Mock<IReflectionManager>();
|
||||
|
||||
List<ComponentRegistration> allRefTypes = new();
|
||||
void Setup<T>(out T instance) where T : IComponent, new()
|
||||
@@ -208,7 +212,7 @@ namespace Robust.UnitTesting.Shared.GameObjects
|
||||
compFacMock.Setup(m => m.GetAllRegistrations()).Returns(allRefTypes.ToArray());
|
||||
|
||||
entManMock.Setup(m => m.ComponentFactory).Returns(compFacMock.Object);
|
||||
var bus = new EntityEventBus(entManMock.Object);
|
||||
var bus = new EntityEventBus(entManMock.Object, reflectMock.Object);
|
||||
bus.OnlyCallOnRobustUnitTestISwearToGodPleaseSomebodyKillThisNightmare();
|
||||
|
||||
// Subscribe
|
||||
|
||||
@@ -2,6 +2,7 @@ using System;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Reflection;
|
||||
|
||||
namespace Robust.UnitTesting.Shared.GameObjects
|
||||
{
|
||||
@@ -12,8 +13,9 @@ namespace Robust.UnitTesting.Shared.GameObjects
|
||||
{
|
||||
var compFacMock = new Mock<IComponentFactory>();
|
||||
var entManMock = new Mock<IEntityManager>();
|
||||
var reflectMock = new Mock<IReflectionManager>();
|
||||
entManMock.SetupGet(e => e.ComponentFactory).Returns(compFacMock.Object);
|
||||
var bus = new EntityEventBus(entManMock.Object);
|
||||
var bus = new EntityEventBus(entManMock.Object, reflectMock.Object);
|
||||
return bus;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user