From f93c47eb20b4c1a37ecaf5b908681179c27ab7c5 Mon Sep 17 00:00:00 2001 From: Eoin Mcloughlin Date: Fri, 19 Jun 2026 19:11:30 +0100 Subject: [PATCH] Defer UI operations until UI system runs frame update --- .../Systems/SharedUserInterfaceSystem.cs | 42 ++++++++++++------- 1 file changed, 27 insertions(+), 15 deletions(-) diff --git a/Robust.Shared/GameObjects/Systems/SharedUserInterfaceSystem.cs b/Robust.Shared/GameObjects/Systems/SharedUserInterfaceSystem.cs index 7012d65c7..2f1fcdd3d 100644 --- a/Robust.Shared/GameObjects/Systems/SharedUserInterfaceSystem.cs +++ b/Robust.Shared/GameObjects/Systems/SharedUserInterfaceSystem.cs @@ -36,10 +36,21 @@ public abstract partial class SharedUserInterfaceSystem : EntitySystem private ActorRangeCheckJob _rangeJob; + /// Update type to apply + private enum QueuedUpdate + { + /// Upen a UI + Open, + /// Apply new state to the UI + ApplyState, + /// Close the UI + Close + }; + /// /// Defer BUIs during state handling so client doesn't spam a BUI constantly during prediction. /// - private readonly List<(BoundUserInterface Bui, bool value)> _queuedBuis = new(); + private readonly List<(BoundUserInterface bui, QueuedUpdate updateType)> _queuedBuis = new(); public override void Initialize() { @@ -82,9 +93,9 @@ public override void Initialize() SubscribeLocalEvent(OnActorShutdown); } - private void AddQueued(BoundUserInterface bui, bool value) + private void AddQueued(BoundUserInterface bui, QueuedUpdate type) { - _queuedBuis.Add((bui, value)); + _queuedBuis.Add((bui, type)); } /// @@ -238,7 +249,7 @@ private void CloseUiInternal(Entity ent, Enum key, Enti if (ent.Comp.ClientOpenInterfaces.TryGetValue(key, out var cBui)) { - AddQueued(cBui, false); + AddQueued(cBui, QueuedUpdate.Close); } if (ent.Comp.Actors.Count == 0) @@ -280,7 +291,7 @@ private void OnUserInterfaceStartup(Entity ent, ref Comp // PlayerAttachedEvent will catch some of these. foreach (var (key, bui) in ent.Comp.ClientOpenInterfaces) { - AddQueued(bui, true); + AddQueued(bui, QueuedUpdate.Open); } } @@ -300,7 +311,7 @@ protected void OnUserInterfaceShutdown(Entity ent, ref C DebugTools.Assert(!ent.Comp.Actors.ContainsKey(key)); } - DebugTools.Assert(ent.Comp.ClientOpenInterfaces.Values.All(x => _queuedBuis.Contains((x, false)))); + DebugTools.Assert(ent.Comp.ClientOpenInterfaces.Values.All(x => _queuedBuis.Contains((x, QueuedUpdate.Close)))); } private void OnUserInterfaceGetState(Entity ent, ref ComponentGetState args) @@ -462,7 +473,7 @@ private void OnUserInterfaceHandleState(Entity ent, ref } var bui = ent.Comp.ClientOpenInterfaces[key]; - AddQueued(bui, false); + AddQueued(bui, QueuedUpdate.Close); } } @@ -489,9 +500,7 @@ private void OnUserInterfaceHandleState(Entity ent, ref if (!ent.Comp.ClientOpenInterfaces.TryGetValue(key, out var cBui) || !cBui.IsOpened) continue; - cBui.State = buiState; - cBui.UpdateState(buiState); - cBui.Update(); + AddQueued(cBui, QueuedUpdate.ApplyState); } } @@ -519,7 +528,7 @@ private void EnsureClientBui(Entity entity, Enum key, In // Existing BUI just keep it. if (entity.Comp.ClientOpenInterfaces.TryGetValue(key, out var existing)) { - _queuedBuis.Remove((existing, false)); + _queuedBuis.Remove((existing, QueuedUpdate.Close)); return; } @@ -544,7 +553,7 @@ private void EnsureClientBui(Entity entity, Enum key, In if (!open) return; - AddQueued(boundUserInterface, true); + AddQueued(boundUserInterface, QueuedUpdate.Open); } /// @@ -1101,15 +1110,18 @@ public override void Update(float frameTime) { if (_timing.IsFirstTimePredicted) { - foreach (var (bui, open) in _queuedBuis) + foreach (var (bui, updateType) in _queuedBuis) { - if (open) + if (updateType == QueuedUpdate.Open || updateType == QueuedUpdate.ApplyState) { #if EXCEPTION_TOLERANCE try { #endif - bui.Open(); + if (updateType == QueuedUpdate.Open) + { + bui.Open(); + } if (UIQuery.TryComp(bui.Owner, out var uiComp)) {