From 176ca6c5784b3df2cea7a58031a77be3f369a189 Mon Sep 17 00:00:00 2001
From: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com>
Date: Sat, 20 Jul 2024 14:50:15 +1000
Subject: [PATCH] Add window helper for BUIs (#5183)
* Add window helper for BUIs
Automatically does OnClose and just makes content slightly nicer.
* more
* Add prototype reload helper
* Add Box2i Center
* weh
---
.../EntitySystems/UserInterfaceSystem.cs | 30 +++++++
.../UserInterface/BoundUserInterfaceExt.cs | 33 +++++++
Robust.Shared.Maths/UIBox2i.cs | 2 +
.../UserInterface/BoundUserInterface.cs | 27 ++++++
.../Systems/SharedUserInterfaceSystem.cs | 87 ++++++++++---------
5 files changed, 137 insertions(+), 42 deletions(-)
create mode 100644 Robust.Client/UserInterface/BoundUserInterfaceExt.cs
diff --git a/Robust.Client/GameObjects/EntitySystems/UserInterfaceSystem.cs b/Robust.Client/GameObjects/EntitySystems/UserInterfaceSystem.cs
index 20a0225a6..7c290cb4e 100644
--- a/Robust.Client/GameObjects/EntitySystems/UserInterfaceSystem.cs
+++ b/Robust.Client/GameObjects/EntitySystems/UserInterfaceSystem.cs
@@ -1,8 +1,38 @@
using Robust.Shared.GameObjects;
+using Robust.Shared.Prototypes;
namespace Robust.Client.GameObjects;
public sealed class UserInterfaceSystem : SharedUserInterfaceSystem
{
+ public override void Initialize()
+ {
+ base.Initialize();
+ ProtoManager.PrototypesReloaded += OnProtoReload;
+ }
+ public override void Shutdown()
+ {
+ base.Shutdown();
+ ProtoManager.PrototypesReloaded -= OnProtoReload;
+ }
+
+ private void OnProtoReload(PrototypesReloadedEventArgs obj)
+ {
+ var player = Player.LocalEntity;
+
+ if (!UserQuery.TryComp(player, out var userComp))
+ return;
+
+ foreach (var uid in userComp.OpenInterfaces.Keys)
+ {
+ if (!UIQuery.TryComp(uid, out var uiComp))
+ continue;
+
+ foreach (var bui in uiComp.ClientOpenInterfaces.Values)
+ {
+ bui.OnProtoReload(obj);
+ }
+ }
+ }
}
diff --git a/Robust.Client/UserInterface/BoundUserInterfaceExt.cs b/Robust.Client/UserInterface/BoundUserInterfaceExt.cs
new file mode 100644
index 000000000..eb59385a3
--- /dev/null
+++ b/Robust.Client/UserInterface/BoundUserInterfaceExt.cs
@@ -0,0 +1,33 @@
+using System;
+using Robust.Client.UserInterface.CustomControls;
+using Robust.Shared.GameObjects;
+
+namespace Robust.Client.UserInterface;
+
+public static class BoundUserInterfaceExt
+{
+ ///
+ /// Helper method to create a window and also handle closing the BUI when it's closed.
+ ///
+ public static T CreateWindow(this BoundUserInterface bui) where T : BaseWindow, new()
+ {
+ var window = bui.CreateDisposableControl();
+ window.OpenCentered();
+ window.OnClose += bui.Close;
+ return window;
+ }
+
+ ///
+ /// Creates a control for this BUI that will be disposed when it is disposed.
+ ///
+ ///
+ ///
+ ///
+ public static T CreateDisposableControl(this BoundUserInterface bui) where T : Control, IDisposable, new()
+ {
+ var control = new T();
+ bui.Disposals ??= [];
+ bui.Disposals.Add(control);
+ return control;
+ }
+}
diff --git a/Robust.Shared.Maths/UIBox2i.cs b/Robust.Shared.Maths/UIBox2i.cs
index 91db90dd6..353b9f6f0 100644
--- a/Robust.Shared.Maths/UIBox2i.cs
+++ b/Robust.Shared.Maths/UIBox2i.cs
@@ -1,4 +1,5 @@
using System;
+using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using Robust.Shared.Utility;
@@ -22,6 +23,7 @@ namespace Robust.Shared.Maths
public readonly int Width => Math.Abs(Right - Left);
public readonly int Height => Math.Abs(Top - Bottom);
public readonly Vector2i Size => new(Width, Height);
+ public readonly Vector2 Center => TopRight - BottomLeft / 2;
public UIBox2i(Vector2i topLeft, Vector2i bottomRight)
{
diff --git a/Robust.Shared/GameObjects/Components/UserInterface/BoundUserInterface.cs b/Robust.Shared/GameObjects/Components/UserInterface/BoundUserInterface.cs
index 3e09ae86c..c80debab8 100644
--- a/Robust.Shared/GameObjects/Components/UserInterface/BoundUserInterface.cs
+++ b/Robust.Shared/GameObjects/Components/UserInterface/BoundUserInterface.cs
@@ -1,6 +1,8 @@
using System;
+using System.Collections.Generic;
using Robust.Shared.IoC;
using Robust.Shared.Player;
+using Robust.Shared.Prototypes;
namespace Robust.Shared.GameObjects
{
@@ -16,6 +18,11 @@ namespace Robust.Shared.GameObjects
public readonly Enum UiKey;
public EntityUid Owner { get; }
+ ///
+ /// Additional controls to be disposed when this BUI is disposed.
+ ///
+ internal List? Disposals;
+
///
/// The last received state object sent from the server.
///
@@ -45,6 +52,14 @@ namespace Robust.Shared.GameObjects
{
}
+ ///
+ /// Helper method that gets called upon prototype reload.
+ ///
+ public virtual void OnProtoReload(PrototypesReloadedEventArgs args)
+ {
+
+ }
+
///
/// Invoked when the server sends an arbitrary message.
///
@@ -86,6 +101,18 @@ namespace Robust.Shared.GameObjects
protected virtual void Dispose(bool disposing)
{
+ if (disposing)
+ {
+ if (Disposals != null)
+ {
+ foreach (var control in Disposals)
+ {
+ control.Dispose();
+ }
+
+ Disposals = null;
+ }
+ }
}
}
}
diff --git a/Robust.Shared/GameObjects/Systems/SharedUserInterfaceSystem.cs b/Robust.Shared/GameObjects/Systems/SharedUserInterfaceSystem.cs
index b012c66df..5254a08a8 100644
--- a/Robust.Shared/GameObjects/Systems/SharedUserInterfaceSystem.cs
+++ b/Robust.Shared/GameObjects/Systems/SharedUserInterfaceSystem.cs
@@ -9,6 +9,7 @@ using Robust.Shared.GameStates;
using Robust.Shared.IoC;
using Robust.Shared.Network;
using Robust.Shared.Player;
+using Robust.Shared.Prototypes;
using Robust.Shared.Reflection;
using Robust.Shared.Threading;
using Robust.Shared.Timing;
@@ -18,18 +19,20 @@ namespace Robust.Shared.GameObjects;
public abstract class SharedUserInterfaceSystem : EntitySystem
{
- [Dependency] private readonly IDynamicTypeFactory _factory = default!;
- [Dependency] private readonly IGameTiming _timing = default!;
- [Dependency] private readonly INetManager _netManager = default!;
- [Dependency] private readonly IParallelManager _parallel = default!;
- [Dependency] private readonly IReflectionManager _reflection = default!;
+ [Dependency] private readonly IDynamicTypeFactory _factory = default!;
+ [Dependency] private readonly IGameTiming _timing = default!;
+ [Dependency] private readonly INetManager _netManager = default!;
+ [Dependency] private readonly IParallelManager _parallel = default!;
[Dependency] private readonly ISharedPlayerManager _player = default!;
- [Dependency] private readonly SharedTransformSystem _transforms = default!;
+ [Dependency] protected readonly IPrototypeManager ProtoManager = default!;
+ [Dependency] private readonly IReflectionManager _reflection = default!;
+ [Dependency] protected readonly ISharedPlayerManager Player = default!;
+ [Dependency] private readonly SharedTransformSystem _transforms = default!;
private EntityQuery _ignoreUIRangeQuery;
private EntityQuery _xformQuery;
- private EntityQuery _uiQuery;
- private EntityQuery _userQuery;
+ protected EntityQuery UIQuery;
+ protected EntityQuery UserQuery;
private ActorRangeCheckJob _rangeJob;
@@ -39,8 +42,8 @@ public abstract class SharedUserInterfaceSystem : EntitySystem
_ignoreUIRangeQuery = GetEntityQuery();
_xformQuery = GetEntityQuery();
- _uiQuery = GetEntityQuery();
- _userQuery = GetEntityQuery();
+ UIQuery = GetEntityQuery();
+ UserQuery = GetEntityQuery();
_rangeJob = new()
{
@@ -78,7 +81,7 @@ public abstract class SharedUserInterfaceSystem : EntitySystem
var uid = GetEntity(msg.Entity);
- if (!_uiQuery.TryComp(uid, out var uiComp))
+ if (!UIQuery.TryComp(uid, out var uiComp))
{
return;
}
@@ -134,13 +137,13 @@ public abstract class SharedUserInterfaceSystem : EntitySystem
private void OnPlayerAttached(PlayerAttachedEvent ev)
{
- if (!_userQuery.TryGetComponent(ev.Entity, out var actor))
+ if (!UserQuery.TryGetComponent(ev.Entity, out var actor))
return;
// Open BUIs upon attachment
foreach (var (uid, keys) in actor.OpenInterfaces)
{
- if (!_uiQuery.TryGetComponent(uid, out var uiComp))
+ if (!UIQuery.TryGetComponent(uid, out var uiComp))
continue;
// Player can now receive information about open UIs
@@ -158,13 +161,13 @@ public abstract class SharedUserInterfaceSystem : EntitySystem
private void OnPlayerDetached(PlayerDetachedEvent ev)
{
- if (!_userQuery.TryGetComponent(ev.Entity, out var actor))
+ if (!UserQuery.TryGetComponent(ev.Entity, out var actor))
return;
// Close BUIs open detachment.
foreach (var (uid, keys) in actor.OpenInterfaces)
{
- if (!_uiQuery.TryGetComponent(uid, out var uiComp))
+ if (!UIQuery.TryGetComponent(uid, out var uiComp))
continue;
// Player can no longer receive information about open UIs
@@ -187,7 +190,7 @@ public abstract class SharedUserInterfaceSystem : EntitySystem
private void CloseUiInternal(Entity ent, Enum key, EntityUid actor)
{
- if (!_uiQuery.Resolve(ent.Owner, ref ent.Comp, false))
+ if (!UIQuery.Resolve(ent.Owner, ref ent.Comp, false))
return;
if (!ent.Comp.Actors.TryGetValue(key, out var actors))
@@ -201,7 +204,7 @@ public abstract class SharedUserInterfaceSystem : EntitySystem
// If the actor is also deleting then don't worry about updating what they have open.
if (!TerminatingOrDeleted(actor)
- && _userQuery.TryComp(actor, out var actorComp)
+ && UserQuery.TryComp(actor, out var actorComp)
&& actorComp.OpenInterfaces.TryGetValue(ent.Owner, out var keys))
{
keys.Remove(key);
@@ -233,7 +236,7 @@ public abstract class SharedUserInterfaceSystem : EntitySystem
private void OpenUiInternal(Entity ent, Enum key, EntityUid actor)
{
- if (!_uiQuery.Resolve(ent.Owner, ref ent.Comp, false))
+ if (!UIQuery.Resolve(ent.Owner, ref ent.Comp, false))
return;
// Similar to the close method this handles actually opening a UI, it just gets relayed here
@@ -414,7 +417,7 @@ public abstract class SharedUserInterfaceSystem : EntitySystem
private void EnsureClientBui(Entity entity, Enum key, InterfaceData data, bool open = true)
{
// If it's out BUI open it up and apply the state, otherwise do nothing.
- var player = _player.LocalEntity;
+ var player = Player.LocalEntity;
if (player == null ||
!entity.Comp.Actors.TryGetValue(key, out var actors) ||
@@ -468,7 +471,7 @@ public abstract class SharedUserInterfaceSystem : EntitySystem
///
public IEnumerable<(EntityUid Entity, Enum Key)> GetActorUis(Entity entity)
{
- if (!_userQuery.Resolve(entity.Owner, ref entity.Comp, false))
+ if (!UserQuery.Resolve(entity.Owner, ref entity.Comp, false))
yield break;
foreach (var berry in entity.Comp.OpenInterfaces)
@@ -485,7 +488,7 @@ public abstract class SharedUserInterfaceSystem : EntitySystem
///
public IEnumerable GetActors(Entity entity, Enum key)
{
- if (!_uiQuery.Resolve(entity.Owner, ref entity.Comp, false) || !entity.Comp.Actors.TryGetValue(key, out var actors))
+ if (!UIQuery.Resolve(entity.Owner, ref entity.Comp, false) || !entity.Comp.Actors.TryGetValue(key, out var actors))
yield break;
foreach (var actorUid in actors)
@@ -499,7 +502,7 @@ public abstract class SharedUserInterfaceSystem : EntitySystem
///
public void CloseUi(Entity entity, Enum key)
{
- if (!_uiQuery.Resolve(entity.Owner, ref entity.Comp, false))
+ if (!UIQuery.Resolve(entity.Owner, ref entity.Comp, false))
return;
if (!entity.Comp.Actors.TryGetValue(key, out var actorSet))
@@ -533,7 +536,7 @@ public abstract class SharedUserInterfaceSystem : EntitySystem
if (actor == null)
return;
- if (!_uiQuery.Resolve(entity.Owner, ref entity.Comp, false))
+ if (!UIQuery.Resolve(entity.Owner, ref entity.Comp, false))
return;
// Short-circuit if no UI.
@@ -561,7 +564,7 @@ public abstract class SharedUserInterfaceSystem : EntitySystem
///
public bool TryOpenUi(Entity entity, Enum key, EntityUid actor, bool predicted = false)
{
- if (!_uiQuery.Resolve(entity.Owner, ref entity.Comp, false))
+ if (!UIQuery.Resolve(entity.Owner, ref entity.Comp, false))
return false;
OpenUi(entity, key, actor, predicted);
@@ -578,7 +581,7 @@ public abstract class SharedUserInterfaceSystem : EntitySystem
public void OpenUi(Entity entity, Enum key, EntityUid? actor, bool predicted = false)
{
- if (actor == null || !_uiQuery.Resolve(entity.Owner, ref entity.Comp, false))
+ if (actor == null || !UIQuery.Resolve(entity.Owner, ref entity.Comp, false))
return;
// No implementation for that UI key on this ent so short-circuit.
@@ -618,7 +621,7 @@ public abstract class SharedUserInterfaceSystem : EntitySystem
///
public void SetUiState(Entity entity, Enum key, BoundUserInterfaceState? state)
{
- if (!_uiQuery.Resolve(entity.Owner, ref entity.Comp, false))
+ if (!UIQuery.Resolve(entity.Owner, ref entity.Comp, false))
return;
if (!entity.Comp.Interfaces.ContainsKey(key))
@@ -662,7 +665,7 @@ public abstract class SharedUserInterfaceSystem : EntitySystem
///
public bool IsUiOpen(Entity entity, Enum uiKey)
{
- if (!_uiQuery.Resolve(entity.Owner, ref entity.Comp, false))
+ if (!UIQuery.Resolve(entity.Owner, ref entity.Comp, false))
return false;
if (!entity.Comp.Actors.TryGetValue(uiKey, out var actors))
@@ -674,7 +677,7 @@ public abstract class SharedUserInterfaceSystem : EntitySystem
public bool IsUiOpen(Entity entity, Enum uiKey, EntityUid actor)
{
- if (!_uiQuery.Resolve(entity.Owner, ref entity.Comp, false))
+ if (!UIQuery.Resolve(entity.Owner, ref entity.Comp, false))
return false;
if (!entity.Comp.Actors.TryGetValue(uiKey, out var actors))
@@ -689,7 +692,7 @@ public abstract class SharedUserInterfaceSystem : EntitySystem
[PublicAPI]
public void RaiseUiMessage(Entity entity, Enum key, BoundUserInterfaceMessage message)
{
- if (!_uiQuery.Resolve(entity.Owner, ref entity.Comp, false))
+ if (!UIQuery.Resolve(entity.Owner, ref entity.Comp, false))
return;
if (!entity.Comp.Actors.TryGetValue(key, out var actors))
@@ -705,7 +708,7 @@ public abstract class SharedUserInterfaceSystem : EntitySystem
///
public void ServerSendUiMessage(Entity entity, Enum key, BoundUserInterfaceMessage message)
{
- if (!_uiQuery.Resolve(entity.Owner, ref entity.Comp, false))
+ if (!UIQuery.Resolve(entity.Owner, ref entity.Comp, false))
return;
if (!entity.Comp.Actors.TryGetValue(key, out var actors))
@@ -720,7 +723,7 @@ public abstract class SharedUserInterfaceSystem : EntitySystem
///
public void ServerSendUiMessage(Entity entity, Enum key, BoundUserInterfaceMessage message, EntityUid actor)
{
- if (!_uiQuery.Resolve(entity.Owner, ref entity.Comp, false))
+ if (!UIQuery.Resolve(entity.Owner, ref entity.Comp, false))
return;
if (!entity.Comp.Actors.TryGetValue(key, out var actors) || !actors.Contains(actor))
@@ -737,7 +740,7 @@ public abstract class SharedUserInterfaceSystem : EntitySystem
if (!_netManager.IsClient)
return;
- if (!_uiQuery.Resolve(entity.Owner, ref entity.Comp, false) || actor.AttachedEntity is not { } attachedEntity)
+ if (!UIQuery.Resolve(entity.Owner, ref entity.Comp, false) || actor.AttachedEntity is not { } attachedEntity)
return;
if (!entity.Comp.Actors.TryGetValue(key, out var actors) || !actors.Contains(attachedEntity))
@@ -753,11 +756,11 @@ public abstract class SharedUserInterfaceSystem : EntitySystem
///
public void ClientSendUiMessage(Entity entity, Enum key, BoundUserInterfaceMessage message)
{
- var player = _player.LocalEntity;
+ var player = Player.LocalEntity;
// Don't send it if we're not a valid actor for it just in case.
if (player == null ||
- !_uiQuery.Resolve(entity.Owner, ref entity.Comp, false) ||
+ !UIQuery.Resolve(entity.Owner, ref entity.Comp, false) ||
!entity.Comp.Actors.TryGetValue(key, out var actors) ||
!actors.Contains(player.Value))
{
@@ -772,7 +775,7 @@ public abstract class SharedUserInterfaceSystem : EntitySystem
///
public void CloseUserUis(Entity actor)
{
- if (!_userQuery.Resolve(actor.Owner, ref actor.Comp, false))
+ if (!UserQuery.Resolve(actor.Owner, ref actor.Comp, false))
return;
if (actor.Comp.OpenInterfaces.Count == 0)
@@ -796,7 +799,7 @@ public abstract class SharedUserInterfaceSystem : EntitySystem
///
public void CloseUis(Entity entity)
{
- if (!_uiQuery.Resolve(entity.Owner, ref entity.Comp, false))
+ if (!UIQuery.Resolve(entity.Owner, ref entity.Comp, false))
return;
var toClose = new ValueList();
@@ -816,7 +819,7 @@ public abstract class SharedUserInterfaceSystem : EntitySystem
///
public void CloseUis(Entity entity, EntityUid actor)
{
- if (!_uiQuery.Resolve(entity.Owner, ref entity.Comp, false))
+ if (!UIQuery.Resolve(entity.Owner, ref entity.Comp, false))
return;
foreach (var key in entity.Comp.Interfaces.Keys)
@@ -830,7 +833,7 @@ public abstract class SharedUserInterfaceSystem : EntitySystem
///
public void CloseUis(Entity entity, ICommonSession actor)
{
- if (actor.AttachedEntity is not { } attachedEnt || !_uiQuery.Resolve(entity.Owner, ref entity.Comp, false))
+ if (actor.AttachedEntity is not { } attachedEnt || !UIQuery.Resolve(entity.Owner, ref entity.Comp, false))
return;
CloseUis(entity, attachedEnt);
@@ -843,7 +846,7 @@ public abstract class SharedUserInterfaceSystem : EntitySystem
{
bui = null;
- return _uiQuery.Resolve(entity.Owner, ref entity.Comp, false) && entity.Comp.ClientOpenInterfaces.TryGetValue(uiKey, out bui);
+ return UIQuery.Resolve(entity.Owner, ref entity.Comp, false) && entity.Comp.ClientOpenInterfaces.TryGetValue(uiKey, out bui);
}
///
@@ -851,7 +854,7 @@ public abstract class SharedUserInterfaceSystem : EntitySystem
///
public bool TryGetOpenUi(Entity entity, Enum uiKey, [NotNullWhen(true)] out T? bui) where T : BoundUserInterface
{
- if (!_uiQuery.Resolve(entity.Owner, ref entity.Comp, false) || !entity.Comp.ClientOpenInterfaces.TryGetValue(uiKey, out var cBui))
+ if (!UIQuery.Resolve(entity.Owner, ref entity.Comp, false) || !entity.Comp.ClientOpenInterfaces.TryGetValue(uiKey, out var cBui))
{
bui = null;
return false;
@@ -874,7 +877,7 @@ public abstract class SharedUserInterfaceSystem : EntitySystem
///
public bool TryToggleUi(Entity entity, Enum uiKey, EntityUid actor)
{
- if (!_uiQuery.Resolve(entity.Owner, ref entity.Comp, false) ||
+ if (!UIQuery.Resolve(entity.Owner, ref entity.Comp, false) ||
!entity.Comp.Interfaces.ContainsKey(uiKey))
{
return false;
@@ -954,7 +957,7 @@ public abstract class SharedUserInterfaceSystem : EntitySystem
var actor = data.Actor;
var key = data.Key;
- if (data.Result || Deleted(uid) || Deleted(actor) || !_uiQuery.TryComp(uid, out var uiComp))
+ if (data.Result || Deleted(uid) || Deleted(actor) || !UIQuery.TryComp(uid, out var uiComp))
continue;
CloseUi((uid, uiComp), key, actor);