Add saved BUI positions (#5650)

This commit is contained in:
metalgearsloth
2025-02-04 00:19:22 +11:00
committed by GitHub
parent 2719b9f0c8
commit fc55c8e0d3
6 changed files with 156 additions and 16 deletions

View File

@@ -35,11 +35,11 @@ END TEMPLATE-->
### Breaking changes
*None yet*
* RemoveChild is called after OnClose for BaseWindow.
### New features
*None yet*
* BUIs now have their positions saved when closed and re-used when opened when using the `CreateWindow<T>` helper or via manually registering it via RegisterControl.
### Bugfixes

View File

@@ -1,10 +1,18 @@
using System;
using System.Collections.Generic;
using System.Numerics;
using Robust.Client.UserInterface;
using Robust.Shared.GameObjects;
using Robust.Shared.Prototypes;
using Robust.Shared.Utility;
namespace Robust.Client.GameObjects;
public sealed class UserInterfaceSystem : SharedUserInterfaceSystem
{
private Dictionary<EntityUid, Dictionary<Enum, Vector2>> _savedPositions = new();
private Dictionary<BoundUserInterface, Control> _registeredControls = new();
public override void Initialize()
{
base.Initialize();
@@ -17,6 +25,59 @@ public sealed class UserInterfaceSystem : SharedUserInterfaceSystem
ProtoManager.PrototypesReloaded -= OnProtoReload;
}
protected override void OnUserInterfaceShutdown(Entity<UserInterfaceComponent> ent, ref ComponentShutdown args)
{
base.OnUserInterfaceShutdown(ent, ref args);
_savedPositions.Remove(ent.Owner);
}
/// <inheritdoc />
public override void OpenUi(Entity<UserInterfaceComponent?> entity, Enum key, bool predicted = false)
{
var player = Player.LocalEntity;
if (player == null)
return;
OpenUi(entity, key, player.Value, predicted);
}
protected override void SavePosition(BoundUserInterface bui)
{
if (!_registeredControls.Remove(bui, out var control))
return;
var keyed = _savedPositions[bui.Owner];
keyed[bui.UiKey] = control.Position;
}
/// <summary>
/// Registers a control so it will later have its position stored by <see cref="SavePosition"/> when the BUI is closed.
/// </summary>
public void RegisterControl(BoundUserInterface bui, Control control)
{
DebugTools.Assert(!_registeredControls.ContainsKey(bui));
_registeredControls[bui] = control;
_savedPositions.GetOrNew(bui.Owner);
}
public override bool TryGetPosition(Entity<UserInterfaceComponent?> entity, Enum key, out Vector2 position)
{
position = default;
if (!_savedPositions.TryGetValue(entity.Owner, out var keyed))
{
return false;
}
if (!keyed.TryGetValue(key, out position))
{
return false;
}
return true;
}
private void OnProtoReload(PrototypesReloadedEventArgs obj)
{
var player = Player.LocalEntity;

View File

@@ -1,4 +1,5 @@
using System;
using Robust.Client.GameObjects;
using Robust.Client.UserInterface.CustomControls;
using Robust.Shared.GameObjects;
@@ -6,14 +7,47 @@ namespace Robust.Client.UserInterface;
public static class BoundUserInterfaceExt
{
private static T GetWindow<T>(BoundUserInterface bui) where T : BaseWindow, new()
{
var window = bui.CreateDisposableControl<T>();
window.OnClose += bui.Close;
var system = bui.EntMan.System<UserInterfaceSystem>();
system.RegisterControl(bui, window);
return window;
}
/// <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;
var window = GetWindow<T>(bui);
if (bui.EntMan.System<UserInterfaceSystem>().TryGetPosition(bui.Owner, bui.UiKey, out var position))
{
window.Open(position);
}
else
{
window.OpenCentered();
}
return window;
}
public static T CreateWindowCenteredLeft<T>(this BoundUserInterface bui) where T : BaseWindow, new()
{
var window = GetWindow<T>(bui);
if (bui.EntMan.System<UserInterfaceSystem>().TryGetPosition(bui.Owner, bui.UiKey, out var position))
{
window.Open(position);
}
else
{
window.OpenCenteredLeft();
}
return window;
}

View File

@@ -5,6 +5,7 @@ using Robust.Client.UserInterface.Controls;
using Robust.Shared.Input;
using Robust.Shared.IoC;
using Robust.Shared.Log;
using Robust.Shared.Map;
using Robust.Shared.Maths;
using Robust.Shared.Timing;
@@ -36,8 +37,8 @@ namespace Robust.Client.UserInterface.CustomControls
return;
}
Parent.RemoveChild(this);
OnClose?.Invoke();
Parent.RemoveChild(this);
}
protected internal override void KeyBindDown(GUIBoundKeyEventArgs args)
@@ -229,6 +230,16 @@ namespace Robust.Client.UserInterface.CustomControls
OnOpen?.Invoke();
}
/// <summary>
/// Opens the window and places it at the specified position.
/// </summary>
public void Open(Vector2 position)
{
Measure(Vector2Helpers.Infinity);
Open();
LayoutContainer.SetPosition(this, position);
}
public void OpenCentered() => OpenCenteredAt(new Vector2(0.5f, 0.5f));
public void OpenToLeft() => OpenCenteredAt(new Vector2(0, 0.5f));

View File

@@ -11,7 +11,7 @@ namespace Robust.Shared.GameObjects
/// </summary>
public abstract class BoundUserInterface : IDisposable
{
[Dependency] protected readonly IEntityManager EntMan = default!;
[Dependency] protected internal readonly IEntityManager EntMan = default!;
[Dependency] protected readonly ISharedPlayerManager PlayerManager = default!;
protected readonly SharedUserInterfaceSystem UiSystem;

View File

@@ -2,6 +2,7 @@ using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Numerics;
using System.Runtime.InteropServices;
using JetBrains.Annotations;
using Robust.Shared.Collections;
@@ -45,6 +46,8 @@ public abstract class SharedUserInterfaceSystem : EntitySystem
/// </summary>
private ValueList<Enum> _keys = new();
private ValueList<EntityUid> _entList = new();
public override void Initialize()
{
base.Initialize();
@@ -86,6 +89,11 @@ public abstract class SharedUserInterfaceSystem : EntitySystem
SubscribeLocalEvent<UserInterfaceUserComponent, ComponentShutdown>(OnActorShutdown);
}
private void AddQueued(BoundUserInterface bui, bool value)
{
_queuedBuis.Add((bui, value));
}
/// <summary>
/// Validates the received message, and then pass it onto systems/components
/// </summary>
@@ -232,7 +240,7 @@ public abstract class SharedUserInterfaceSystem : EntitySystem
if (ent.Comp.ClientOpenInterfaces.TryGetValue(key, out var cBui))
{
_queuedBuis.Add((cBui, false));
AddQueued(cBui, false);
}
if (ent.Comp.Actors.Count == 0)
@@ -274,18 +282,17 @@ public abstract class SharedUserInterfaceSystem : EntitySystem
// PlayerAttachedEvent will catch some of these.
foreach (var (key, bui) in ent.Comp.ClientOpenInterfaces)
{
_queuedBuis.Add((bui, true));
AddQueued(bui, true);
}
}
private void OnUserInterfaceShutdown(Entity<UserInterfaceComponent> ent, ref ComponentShutdown args)
protected virtual void OnUserInterfaceShutdown(Entity<UserInterfaceComponent> ent, ref ComponentShutdown args)
{
var actors = new List<EntityUid>();
foreach (var (key, acts) in ent.Comp.Actors)
{
actors.Clear();
actors.AddRange(acts);
foreach (var actor in actors)
_entList.Clear();
_entList.AddRange(acts);
foreach (var actor in _entList)
{
CloseUiInternal(ent!, key, actor);
DebugTools.Assert(!acts.Contains(actor));
@@ -456,7 +463,7 @@ public abstract class SharedUserInterfaceSystem : EntitySystem
}
var bui = ent.Comp.ClientOpenInterfaces[key];
_queuedBuis.Add((bui, false));
AddQueued(bui, false);
}
}
@@ -537,7 +544,7 @@ public abstract class SharedUserInterfaceSystem : EntitySystem
if (!open)
return;
_queuedBuis.Add((boundUserInterface, true));
AddQueued(boundUserInterface, true);
}
/// <summary>
@@ -653,6 +660,14 @@ public abstract class SharedUserInterfaceSystem : EntitySystem
return true;
}
/// <summary>
/// Opens the UI for the local client. Does nothing on server.
/// </summary>
public virtual void OpenUi(Entity<UserInterfaceComponent?> entity, Enum key, bool predicted = false)
{
}
public void OpenUi(Entity<UserInterfaceComponent?> entity, Enum key, EntityUid? actor, bool predicted = false)
{
if (actor == null || !UIQuery.Resolve(entity.Owner, ref entity.Comp, false))
@@ -690,6 +705,23 @@ public abstract class SharedUserInterfaceSystem : EntitySystem
OpenUi(entity, key, actorEnt.Value, predicted);
}
/// <summary>
/// Tries to return the saved position of a user interface.
/// </summary>
public virtual bool TryGetPosition(Entity<UserInterfaceComponent?> entity, Enum key, out Vector2 position)
{
position = Vector2.Zero;
return false;
}
/// <summary>
/// Saves a position for the BUI.
/// </summary>
protected virtual void SavePosition(BoundUserInterface bui)
{
}
/// <summary>
/// Sets a BUI state and networks it to all clients.
/// </summary>
@@ -1056,6 +1088,7 @@ public abstract class SharedUserInterfaceSystem : EntitySystem
}
#endif
}
// Close BUI
else
{
if (UIQuery.TryComp(bui.Owner, out var uiComp))
@@ -1063,6 +1096,7 @@ public abstract class SharedUserInterfaceSystem : EntitySystem
uiComp.ClientOpenInterfaces.Remove(bui.UiKey);
}
SavePosition(bui);
bui.Dispose();
}
}