6
2026-01-13 18:31:02 +02:00

310 lines
9.5 KiB
C#

using System.Linq;
using System.Numerics;
using System.Text;
using Content.Shared.Shuttles.BUIStates;
using Content.Shared.Shuttles.Components;
using Content.Shared.Shuttles.Systems;
using Robust.Client.AutoGenerated;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.XAML;
using Robust.Shared.Log;
using Robust.Shared.Utility;
namespace Content.Client.Shuttles.UI;
[GenerateTypedNameReferences]
public sealed partial class DockingScreen : BoxContainer
{
[Dependency] private readonly IEntityManager _entManager = default!;
private readonly SharedShuttleSystem _shuttles;
/// <summary>
/// Stored by GridID then by docks
/// </summary>
public Dictionary<NetEntity, List<DockingPortState>> Docks = new();
/// <summary>
/// Store the dock buttons for the side buttons.
/// </summary>
private readonly Dictionary<NetEntity, Button> _ourDockButtons = new();
public event Action<NetEntity, NetEntity>? DockRequest;
public event Action<NetEntity>? UndockRequest;
public event Action<List<NetEntity>>? UndockAllRequest;
public DockingScreen()
{
RobustXamlLoader.Load(this);
IoCManager.InjectDependencies(this);
_shuttles = _entManager.System<SharedShuttleSystem>();
DockingControl.OnViewDock += OnView;
DockingControl.DockRequest += (entity, netEntity) =>
{
DockRequest?.Invoke(entity, netEntity);
};
DockingControl.UndockRequest += entity =>
{
UndockRequest?.Invoke(entity);
};
UndockAllButton.OnPressed += _ => OnUndockAllPressed();
}
private void OnUndockAllPressed()
{
if (UndockAllRequest == null)
return;
// Find all docks that belong to the current shuttle and are docked
var netEntity = _entManager.GetNetEntity(DockingControl.GridEntity!.Value);
if (!Docks.TryGetValue(netEntity, out var shuttleDocks))
return;
var dockedPorts = new List<NetEntity>();
foreach (var dock in shuttleDocks)
{
if (dock.Connected)
{
dockedPorts.Add(dock.Entity);
}
}
if (dockedPorts.Count > 0)
{
UndockAllRequest.Invoke(dockedPorts);
}
}
private void OnView(NetEntity obj)
{
if (_ourDockButtons.TryGetValue(obj, out var viewed))
{
viewed.Pressed = true;
}
}
public void UpdateState(EntityUid? shuttle, DockingInterfaceState state)
{
Docks = state.Docks;
DockingControl.DockState = state;
DockingControl.GridEntity = shuttle;
BuildDocks(shuttle);
// Enable the undock all button only if there are docked ports
var hasDockedPorts = false;
if (shuttle != null)
{
var netEntity = _entManager.GetNetEntity(shuttle.Value);
if (Docks.TryGetValue(netEntity, out var shuttleDocks))
{
hasDockedPorts = shuttleDocks.Any(d => d.Connected);
}
}
UndockAllButton.Disabled = !hasDockedPorts;
// Update lock status indicators on all dock buttons
UpdateDockLockIndicators(shuttle);
}
private void UpdateDockLockIndicators(EntityUid? shuttle)
{
if (shuttle == null)
return;
var netEntity = _entManager.GetNetEntity(shuttle.Value);
if (!Docks.TryGetValue(netEntity, out var shuttleDocks))
return;
foreach (var dock in shuttleDocks)
{
if (!_ourDockButtons.TryGetValue(dock.Entity, out var button))
continue;
// Find the lock indicator label in the button's children
if (button.ChildCount == 0)
continue;
var buttonContainer = button.GetChild(0) as BoxContainer;
if (buttonContainer == null)
continue;
// Only update if connected to another grid
if (!dock.Connected || dock.GridDockedWith == null)
{
// If there's a lock indicator but no connection anymore, remove it
if (buttonContainer.ChildCount > 1)
{
var existingIndicator = buttonContainer.GetChild(1);
if (existingIndicator != null)
{
buttonContainer.RemoveChild(existingIndicator);
}
}
continue;
}
var dockedEntity = _entManager.GetEntity(dock.GridDockedWith.Value);
// Get or create lock indicator
Label? lockIndicator = null;
if (buttonContainer.ChildCount > 1)
{
lockIndicator = buttonContainer.GetChild(1) as Label;
}
if (lockIndicator == null)
{
// Create new lock indicator if it doesn't exist
lockIndicator = new Label
{
HorizontalAlignment = Control.HAlignment.Right,
VerticalAlignment = Control.VAlignment.Center,
Margin = new Thickness(2f, 0f),
MinWidth = 70
};
buttonContainer.AddChild(lockIndicator);
}
}
}
private void BuildDocks(EntityUid? shuttle)
{
DockingControl.BuildDocks(shuttle);
var currentDock = DockingControl.ViewedDock;
// DockedWith.DisposeAllChildren();
DockPorts.DisposeAllChildren();
_ourDockButtons.Clear();
if (shuttle == null)
{
DockingControl.SetViewedDock(null);
return;
}
var shuttleNent = _entManager.GetNetEntity(shuttle.Value);
if (!Docks.TryGetValue(shuttleNent, out var shuttleDocks) || shuttleDocks.Count <= 0)
return;
var dockText = new StringBuilder();
var buttonGroup = new ButtonGroup();
var idx = 0;
var selected = false;
DockingPortState? firstState = null; // Frontier
// Build the dock buttons for our docks.
foreach (var dock in shuttleDocks.OrderBy(x => x.LabelName ?? x.Name)) // Frontier: order by name
{
if (idx == 0) // Frontier: get first element
firstState = dock; // Frontier: get first element
idx++;
dockText.Clear();
dockText.Append(dock.LabelName ?? dock.Name);
// Create a BoxContainer to hold button text and lock indicator
var buttonContainer = new BoxContainer
{
Orientation = BoxContainer.LayoutOrientation.Horizontal,
HorizontalExpand = true,
VerticalAlignment = Control.VAlignment.Center,
Margin = new Thickness(3f),
};
// The text label
var textLabel = new Label
{
Text = dockText.ToString(),
HorizontalExpand = true,
Margin = new Thickness(4f, 0f),
};
buttonContainer.AddChild(textLabel);
var button = new Button()
{
Text = dockText.ToString(),
ToggleMode = true,
Group = buttonGroup,
Margin = new Thickness(0f, 3f),
HorizontalExpand = true
};
// Add the container with text and lock indicator to the button
button.AddChild(buttonContainer);
button.OnMouseEntered += args =>
{
DockingControl.HighlightedDock = dock.Entity;
};
button.OnMouseExited += args =>
{
DockingControl.HighlightedDock = null;
};
if (currentDock == dock.Entity)
{
selected = true;
button.Pressed = true;
}
button.OnPressed += args =>
{
OnDockPress(dock);
};
_ourDockButtons[dock.Entity] = button;
DockPorts.AddChild(button);
}
// Button group needs one selected so just show the first one.
if (!selected)
{
// Frontier: press first button in alphabetical order
// var buttonOne = shuttleDocks[0];
// OnDockPress(buttonOne);
OnDockPress(firstState!);
// End Frontier
}
var shuttleContainers = new Dictionary<NetEntity, DockObject>();
foreach (var dock in shuttleDocks.OrderBy(x => x.GridDockedWith))
{
if (dock.GridDockedWith == null)
continue;
DockObject? dockContainer;
if (!shuttleContainers.TryGetValue(dock.GridDockedWith.Value, out dockContainer))
{
dockContainer = new DockObject();
shuttleContainers[dock.GridDockedWith.Value] = dockContainer;
var dockGrid = _entManager.GetEntity(dock.GridDockedWith);
string? iffLabel = null;
if (_entManager.EntityExists(dockGrid))
{
iffLabel = _shuttles.GetIFFLabel(dockGrid.Value);
}
iffLabel ??= Loc.GetString("shuttle-console-unknown");
dockContainer.SetName(iffLabel);
// DockedWith.AddChild(dockContainer);
}
dockContainer.AddDock(dock, DockingControl);
}
}
private void OnDockPress(DockingPortState state)
{
DockingControl.SetViewedDock(state);
}
}