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
This commit is contained in:
metalgearsloth
2024-07-20 14:50:15 +10:00
committed by GitHub
parent 2664061993
commit 176ca6c578
5 changed files with 137 additions and 42 deletions

View File

@@ -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);
}
}
}
}

View File

@@ -0,0 +1,33 @@
using System;
using Robust.Client.UserInterface.CustomControls;
using Robust.Shared.GameObjects;
namespace Robust.Client.UserInterface;
public static class BoundUserInterfaceExt
{
/// <summary>
/// Helper method to create a window and also handle closing the BUI when it's closed.
/// </summary>
public static T CreateWindow<T>(this BoundUserInterface bui) where T : BaseWindow, new()
{
var window = bui.CreateDisposableControl<T>();
window.OpenCentered();
window.OnClose += bui.Close;
return window;
}
/// <summary>
/// Creates a control for this BUI that will be disposed when it is disposed.
/// </summary>
/// <param name="bui"></param>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public static T CreateDisposableControl<T>(this BoundUserInterface bui) where T : Control, IDisposable, new()
{
var control = new T();
bui.Disposals ??= [];
bui.Disposals.Add(control);
return control;
}
}

View File

@@ -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)
{

View File

@@ -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; }
/// <summary>
/// Additional controls to be disposed when this BUI is disposed.
/// </summary>
internal List<IDisposable>? Disposals;
/// <summary>
/// The last received state object sent from the server.
/// </summary>
@@ -45,6 +52,14 @@ namespace Robust.Shared.GameObjects
{
}
/// <summary>
/// Helper method that gets called upon prototype reload.
/// </summary>
public virtual void OnProtoReload(PrototypesReloadedEventArgs args)
{
}
/// <summary>
/// Invoked when the server sends an arbitrary message.
/// </summary>
@@ -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;
}
}
}
}
}

View File

@@ -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<IgnoreUIRangeComponent> _ignoreUIRangeQuery;
private EntityQuery<TransformComponent> _xformQuery;
private EntityQuery<UserInterfaceComponent> _uiQuery;
private EntityQuery<UserInterfaceUserComponent> _userQuery;
protected EntityQuery<UserInterfaceComponent> UIQuery;
protected EntityQuery<UserInterfaceUserComponent> UserQuery;
private ActorRangeCheckJob _rangeJob;
@@ -39,8 +42,8 @@ public abstract class SharedUserInterfaceSystem : EntitySystem
_ignoreUIRangeQuery = GetEntityQuery<IgnoreUIRangeComponent>();
_xformQuery = GetEntityQuery<TransformComponent>();
_uiQuery = GetEntityQuery<UserInterfaceComponent>();
_userQuery = GetEntityQuery<UserInterfaceUserComponent>();
UIQuery = GetEntityQuery<UserInterfaceComponent>();
UserQuery = GetEntityQuery<UserInterfaceUserComponent>();
_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<UserInterfaceComponent?> 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<UserInterfaceComponent?> 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<UserInterfaceComponent> 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
/// </summary>
public IEnumerable<(EntityUid Entity, Enum Key)> GetActorUis(Entity<UserInterfaceUserComponent?> 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
/// </summary>
public IEnumerable<EntityUid> GetActors(Entity<UserInterfaceComponent?> 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
/// </summary>
public void CloseUi(Entity<UserInterfaceComponent?> 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
/// </summary>
public bool TryOpenUi(Entity<UserInterfaceComponent?> 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<UserInterfaceComponent?> 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
/// </summary>
public void SetUiState(Entity<UserInterfaceComponent?> 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
/// </summary>
public bool IsUiOpen(Entity<UserInterfaceComponent?> 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<UserInterfaceComponent?> 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<UserInterfaceComponent?> 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
/// </summary>
public void ServerSendUiMessage(Entity<UserInterfaceComponent?> 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
/// </summary>
public void ServerSendUiMessage(Entity<UserInterfaceComponent?> 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
/// </summary>
public void ClientSendUiMessage(Entity<UserInterfaceComponent?> 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
/// </summary>
public void CloseUserUis(Entity<UserInterfaceUserComponent?> 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
/// </summary>
public void CloseUis(Entity<UserInterfaceComponent?> entity)
{
if (!_uiQuery.Resolve(entity.Owner, ref entity.Comp, false))
if (!UIQuery.Resolve(entity.Owner, ref entity.Comp, false))
return;
var toClose = new ValueList<EntityUid>();
@@ -816,7 +819,7 @@ public abstract class SharedUserInterfaceSystem : EntitySystem
/// </summary>
public void CloseUis(Entity<UserInterfaceComponent?> 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
/// </summary>
public void CloseUis(Entity<UserInterfaceComponent?> 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);
}
/// <summary>
@@ -851,7 +854,7 @@ public abstract class SharedUserInterfaceSystem : EntitySystem
/// </summary>
public bool TryGetOpenUi<T>(Entity<UserInterfaceComponent?> 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
/// </summary>
public bool TryToggleUi(Entity<UserInterfaceComponent?> 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);