Files
RobustToolbox/Robust.UnitTesting/Shared/GameObjects/EntityEventBusTests.RefDirectedEvents.cs
T
e5013d9e3f Add support for struct directed events, add by-ref directed/broadcast events. (#1931)
* Add support for struct directed events.
- Turn transform events into readonly structs

* TransformComponent events have readonly fields.

* Reduce boxing allocations, add DirectedRegistration readonly struct.

* Use typeof in a few places instead of GetType

* Add overloads to allow passing directed events by ref.

* Raise transform events by ref.

* Fix occluder AnchorStateChangedEvent subscription

* Fix broadphase subscriptions

* Fix bug oops

* Fix transform system raising moveevents by value

* Don't reflect the test entity systems.

* Directed EventBus uses ref everywhere, internally
Deduplicates a bunch of code. Whoo!

* Add broadcast by-ref events

* Fix by-ref events bug using Unsafe, add new tests for sorted by-ref events.

* Port broadcast events to by-ref.

* Speed, more correctness, reduce generics bloat.

* Clean up subscription code some.

* Remove bad test.

Co-authored-by: Pieter-Jan Briers <pieterjan.briers+git@gmail.com>
2021-08-21 11:37:02 +02:00

188 lines
6.5 KiB
C#

using System;
using NUnit.Framework;
using Robust.Shared.GameObjects;
using Robust.Shared.Map;
using Robust.Shared.Reflection;
using Robust.Shared.Utility;
using Robust.UnitTesting.Server;
namespace Robust.UnitTesting.Shared.GameObjects
{
public partial class EntityEventBusTests
{
[Test]
public void SubscribeCompRefDirectedEvent()
{
// Arrange.
var simulation = RobustServerSimulation
.NewSimulation()
.RegisterComponents(factory => factory.RegisterClass<DummyComponent>())
.RegisterEntitySystems(factory => factory.LoadExtraSystemType<SubscribeCompRefDirectedEventSystem>())
.InitializeInstance();
var map = new MapId(1);
simulation.AddMap(map);
var entity = simulation.SpawnEntity(null, new MapCoordinates(0, 0, map));
entity.AddComponent<DummyComponent>();
// Act.
var testEvent = new TestStructEvent {TestNumber = 5};
var eventBus = simulation.Resolve<IEntityManager>().EventBus;
eventBus.RaiseLocalEvent(entity.Uid, ref testEvent);
// Check that the entity system changed the value correctly
Assert.That(testEvent.TestNumber, Is.EqualTo(10));
}
[Reflect(false)]
private class SubscribeCompRefDirectedEventSystem : EntitySystem
{
public override void Initialize()
{
SubscribeLocalEvent<DummyComponent, TestStructEvent>(MyRefHandler);
}
private void MyRefHandler(EntityUid uid, DummyComponent component, ref TestStructEvent args)
{
Assert.That(args.TestNumber, Is.EqualTo(5));
args.TestNumber = 10;
}
}
[Test]
public void SubscriptionNoMixedRefValueDirectedEvent()
{
// Arrange.
var simulation = RobustServerSimulation
.NewSimulation()
.RegisterComponents(factory =>
{
factory.RegisterClass<DummyComponent>();
factory.RegisterClass<DummyTwoComponent>();
})
.RegisterEntitySystems(factory =>
factory.LoadExtraSystemType<SubscriptionNoMixedRefValueDirectedEventSystem>());
// Act. No mixed ref and value subscriptions are allowed.
Assert.Throws(typeof(InvalidOperationException), () => simulation.InitializeInstance());
}
[Reflect(false)]
private class SubscriptionNoMixedRefValueDirectedEventSystem : EntitySystem
{
public override void Initialize()
{
// The below is not allowed, as you're subscribing by-ref and by-value to the same event...
SubscribeLocalEvent<DummyComponent, TestStructEvent>(MyRefHandler);
SubscribeLocalEvent<DummyTwoComponent, TestStructEvent>(MyValueHandler);
}
private void MyValueHandler(EntityUid uid, DummyTwoComponent component, TestStructEvent args) { }
private void MyRefHandler(EntityUid uid, DummyComponent component, ref TestStructEvent args) { }
}
[Test]
public void SortedDirectedRefEvents()
{
// Arrange.
var simulation = RobustServerSimulation
.NewSimulation()
.RegisterComponents(factory =>
{
factory.RegisterClass<OrderComponentA>();
factory.RegisterClass<OrderComponentB>();
factory.RegisterClass<OrderComponentC>();
})
.RegisterEntitySystems(factory =>
{
factory.LoadExtraSystemType<OrderASystem>();
factory.LoadExtraSystemType<OrderBSystem>();
factory.LoadExtraSystemType<OrderCSystem>();
})
.InitializeInstance();
var map = new MapId(1);
simulation.AddMap(map);
var entity = simulation.SpawnEntity(null, new MapCoordinates(0, 0, map));
entity.AddComponent<OrderComponentA>();
entity.AddComponent<OrderComponentB>();
entity.AddComponent<OrderComponentC>();
// Act.
var testEvent = new TestStructEvent {TestNumber = 5};
var eventBus = simulation.Resolve<IEntityManager>().EventBus;
eventBus.RaiseLocalEvent(entity.Uid, ref testEvent);
// Check that the entity systems changed the value correctly
Assert.That(testEvent.TestNumber, Is.EqualTo(15));
}
[Reflect(false)]
private class OrderASystem : EntitySystem
{
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<OrderComponentA, TestStructEvent>(OnA, new[]{typeof(OrderBSystem)}, new[]{typeof(OrderCSystem)});
}
private void OnA(EntityUid uid, OrderComponentA component, ref TestStructEvent args)
{
// Second handler being ran.
Assert.That(args.TestNumber, Is.EqualTo(0));
args.TestNumber = 10;
}
}
[Reflect(false)]
private class OrderBSystem : EntitySystem
{
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<OrderComponentB, TestStructEvent>(OnB, null, new []{typeof(OrderASystem)});
}
private void OnB(EntityUid uid, OrderComponentB component, ref TestStructEvent args)
{
// Last handler being ran.
Assert.That(args.TestNumber, Is.EqualTo(10));
args.TestNumber = 15;
}
}
[Reflect(false)]
private class OrderCSystem : EntitySystem
{
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<OrderComponentC, TestStructEvent>(OnC);
}
private void OnC(EntityUid uid, OrderComponentC component, ref TestStructEvent args)
{
// First handler being ran.
Assert.That(args.TestNumber, Is.EqualTo(5));
args.TestNumber = 0;
}
}
private class DummyTwoComponent : Component
{
public override string Name => "DummyTwo";
}
private struct TestStructEvent
{
public int TestNumber;
}
}
}