using System.IO;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
using BenchmarkDotNet.Attributes;
using Content.IntegrationTests;
using Content.IntegrationTests.Pair;
using Content.Shared.EntityEffects;
using Robust.Shared;
using Robust.Shared.Analyzers;
using Robust.Shared.GameObjects;
namespace Content.Benchmarks;
///
/// Benchmark comparing EntityEffect dispatch strategies.
/// Old: event bus SubscribeLocalEvent + RaiseLocalEvent
/// New: static Dictionary{{Type, IEntityEffectHandler}} + direct interface call
///
[Virtual]
public partial class EffectDispatchBenchmark
{
private TestPair _pair = default!;
private BenchSystem _sys = default!;
[GlobalSetup]
public void Setup()
{
ProgramShared.PathOffset = "../../../../";
PoolManager.Startup(typeof(BenchSystem).Assembly);
_pair = PoolManager.GetServerClient(testContext: new ExternalTestContext("Benchmark", StreamWriter.Null)).GetAwaiter().GetResult();
var entMan = _pair.Server.EntMan;
_sys = entMan.System();
_pair.Server.WaitPost(() =>
{
var hitUid = entMan.Spawn();
entMan.AddComponent(hitUid);
_sys.HitTarget = new(hitUid, entMan.GetComponent(hitUid));
var missUid = entMan.Spawn();
_sys.MissTarget = new(missUid, entMan.GetComponent(missUid));
})
.GetAwaiter()
.GetResult();
}
[GlobalCleanup]
public async Task Cleanup()
{
await _pair.DisposeAsync();
PoolManager.Shutdown();
}
[Benchmark(Baseline = true)]
public int EventBusDispatch_Hit()
{
return _sys.RaiseViaEventBusHit();
}
[Benchmark]
public int EventBusDispatch_Miss()
{
return _sys.RaiseViaEventBusMiss();
}
[Benchmark]
public int CurrentImplementation_Hit()
{
return _sys.RaiseViaCurrentImplementation();
}
[Benchmark]
public int CurrentImplementation_Miss()
{
return _sys.RaiseViaCurrentImplementationMiss();
}
[Benchmark]
public int CSharpEventDispatch_Hit()
{
return _sys.RaiseViaCSharpEventHit();
}
[Benchmark]
public int CSharpEventDispatch_Miss()
{
return _sys.RaiseViaCSharpEventHit();
}
public sealed partial class BenchSystem : EntitySystem
{
private SharedEntityEffectsSystem _effectsSystem = default!;
public Entity HitTarget;
public Entity MissTarget;
private EntityEffect _effect = new TestEffect();
private int _counter;
public delegate void EffectHandler(EntityUid uid);
public event EffectHandler OnEffect;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent(OnEventBus);
OnEffect += OnCSharpEvent;
_effectsSystem = EntityManager.System();
}
[MethodImpl(MethodImplOptions.NoInlining)]
private void OnEventBus(Entity entity, ref TestEffectEvent args)
{
_counter++;
}
[MethodImpl(MethodImplOptions.NoInlining)]
private void OnCSharpEvent(EntityUid uid)
{
TryComp(uid, out _);
_counter++;
}
public int RaiseViaEventBusHit()
{
_counter = 0;
var ev = new TestEffectEvent();
RaiseLocalEvent(HitTarget.Owner, ref ev);
return _counter;
}
public int RaiseViaEventBusMiss()
{
_counter = 0;
var ev = new TestEffectEvent();
RaiseLocalEvent(MissTarget.Owner, ref ev);
return _counter;
}
public int RaiseViaCurrentImplementation()
{
_counter = 0;
_effectsSystem.ApplyEffect(HitTarget, _effect);
return _counter;
}
public int RaiseViaCurrentImplementationMiss()
{
_counter = 0;
_effectsSystem.ApplyEffect(MissTarget, _effect);
return _counter;
}
public int RaiseViaCSharpEventHit()
{
_counter = 0;
OnEffect?.Invoke(HitTarget.Owner);
return _counter;
}
public int RaiseViaCSharpEventMiss()
{
_counter = 0;
OnEffect?.Invoke(MissTarget.Owner);
return _counter;
}
}
[ByRefEvent]
public struct TestEffectEvent
{
}
public sealed partial class TestEffectSystem : EntityEffectSystem
{
protected override void Effect(Entity entity, ref EntityEffectEvent args)
{
}
}
public sealed partial class TestEffect : EntityEffectBase
{
}
[RegisterComponent]
public sealed partial class DummyComponent : Component
{
}
}