Try improve RaiseEvent performance (#5925)

* IEventBus -> EventBus

* Fix CompIdx.RefArray

* IEntityManager -> EntityManager

* Remove double delegate

* Add GetNetCompEventHandlers()

* release notes & cleanup

* Make PVS use GetNetCompEventHandlers

* I love event bus tests

* also fix pvs pause test

* dont trimm

---------

Co-authored-by: PJB3005 <pieterjan.briers+git@gmail.com>
Co-authored-by: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com>
This commit is contained in:
Leon Friedrich
2025-11-13 23:32:40 +13:00
committed by GitHub
parent cd59027089
commit b15d960c69
16 changed files with 275 additions and 385 deletions

View File

@@ -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
/// <returns>New entity State for the given entity.</returns>
private EntityState GetEntityState(ICommonSession? player, EntityUid entityUid, GameTick fromTick, MetaDataComponent meta)
{
var bus = EntityManager.EventBus;
var changed = new List<ComponentChange>();
bool sendCompList = meta.LastComponentRemoved > fromTick;
HashSet<ushort>? 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<ComponentGetState, EntityEventBus.Unit>(ref stateEv));
var state = stateEv.State;
return state;
}
/// <summary>
/// Variant of <see cref="GetEntityState"/> that includes all entity data, including data that can be inferred implicitly from the entity prototype.
/// </summary>
private EntityState GetFullEntityState(ICommonSession player, EntityUid entityUid, MetaDataComponent meta)
{
var bus = EntityManager.EventBus;
var bus = EntityManager.EventBusInternal;
var changed = new List<ComponentChange>();
var stateEv = new ComponentGetState(player, GameTick.Zero);
HashSet<ushort> 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);

View File

@@ -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<PvsThreadResources> _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
/// </summary>
internal void SendGameStates(ICommonSession[] players)
{
_getStateHandlers ??= EntityManager.EventBusInternal.GetNetCompEventHandlers<ComponentGetState>();
// Wait for pending jobs and process disconnected players
ProcessDisconnections();