Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
using Content.Shared._Hullrot.FireControl;
using JetBrains.Annotations;
using Robust.Client.GameObjects;
using Robust.Client.UserInterface;
using Robust.Shared.Map;

namespace Content.Client._Hullrot.FireControl.UI;

[UsedImplicitly]
public sealed class FireControlConsoleBoundUserInterface : BoundUserInterface
{
[ViewVariables]
private FireControlWindow? _window;

public FireControlConsoleBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey)
{
}

protected override void Open()
{
base.Open();
_window = this.CreateWindow<FireControlWindow>();

_window.OnServerRefresh += OnRefreshServer;

_window.Radar.OnRadarClick += (coords) =>
{
var netCoords = EntMan.GetNetCoordinates(coords);
SendFireMessage(netCoords);
};

_window.Radar.DefaultCursorShape = Control.CursorShape.Crosshair;
}

private void OnRefreshServer()
{
SendMessage(new FireControlConsoleRefreshServerMessage());
}

private void SendFireMessage(NetCoordinates coordinates)
{
if (_window == null)
return;

var selected = new List<NetEntity>();
foreach (var button in _window.WeaponsList)
{
if (button.Value.Pressed)
selected.Add(button.Key);
}

if (selected.Count > 0)
SendMessage(new FireControlConsoleFireMessage(selected, coordinates));
}

protected override void UpdateState(BoundUserInterfaceState state)
{
base.UpdateState(state);

if (state is not FireControlConsoleBoundInterfaceState castState)
return;

_window?.UpdateStatus(castState);
}
}
21 changes: 21 additions & 0 deletions Content.Client/_Hullrot/FireControl/UI/FireControlWindow.xaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<controls:FancyWindow xmlns="https://spacestation14.io"
xmlns:gfx="clr-namespace:Robust.Client.Graphics;assembly=Robust.Client"
xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls"
xmlns:ui="clr-namespace:Content.Client.Shuttles.UI"
Title="{Loc 'fire-control-window-title'}"
SetSize="1000 800"
MinSize="1000 800">
<BoxContainer Name="RootBox" Orientation="Vertical">
<BoxContainer Name="StatusBox" Orientation="Vertical">
<Label Name="ServerStatus" Text="{Loc 'fire-control-window-disconnected'}"
StyleClasses="LabelKeyText" />
<Button Name="RefreshButton" Access="Public" Text="{Loc admin-logs-refresh}" StyleClasses="ButtonSquare"/>
<BoxContainer Name="ControllablesBox" Orientation="Horizontal">
</BoxContainer>
</BoxContainer>
<BoxContainer Name="RadarContainer" Orientation="Horizontal">
<ui:ShuttleNavControl
Name="NavRadar" />
</BoxContainer>
</BoxContainer>
</controls:FancyWindow>
52 changes: 52 additions & 0 deletions Content.Client/_Hullrot/FireControl/UI/FireControlWindow.xaml.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
using Content.Client.UserInterface.Controls;
using Content.Shared._Hullrot.FireControl;
using Robust.Client.AutoGenerated;
using Robust.Client.UserInterface.XAML;
using Robust.Client.UserInterface.Controls;
using Content.Client.Shuttles.UI;

namespace Content.Client._Hullrot.FireControl.UI;

[GenerateTypedNameReferences]
public sealed partial class FireControlWindow : FancyWindow
{
public ShuttleNavControl Radar => NavRadar;
public Action? OnServerRefresh;

// fun fact: readonly dictionaries are still mutable
public readonly Dictionary<NetEntity, Button> WeaponsList = new();

public FireControlWindow()
{
RobustXamlLoader.Load(this);
IoCManager.InjectDependencies(this);
RefreshButton.OnPressed += _ => OnServerRefresh?.Invoke();
}

public void UpdateStatus(FireControlConsoleBoundInterfaceState state)
{
NavRadar.UpdateState(state.NavState);

if (state.Connected)
{
// RefreshButton.Disabled = true;
ServerStatus.Text = Loc.GetString("fire-control-window-connected");
}
else
{
RefreshButton.Disabled = false;
ServerStatus.Text = Loc.GetString("fire-control-window-disconnected");
}

WeaponsList.Clear();
ControllablesBox.DisposeAllChildren();
foreach (var controllable in state.FireControllables)
{
var button = new Button();
button.ToggleMode = true;
button.Text = controllable.Name;
ControllablesBox.AddChild(button);
WeaponsList.Add(controllable.NetEntity, button);
}
}
}
11 changes: 11 additions & 0 deletions Content.Server/_Hullrot/FireControl/FireControlGridComponent.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/// Copyright Rane (elijahrane@gmail.com) 2025
/// All rights reserved.

namespace Content.Server._Hullrot.FireControl;

[RegisterComponent]
public sealed partial class FireControlGridComponent : Component
{
[ViewVariables]
public EntityUid? ControllingServer = null;
}
20 changes: 20 additions & 0 deletions Content.Server/_Hullrot/FireControl/FireControlServerComponent.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/// Copyright Rane (elijahrane@gmail.com) 2025
/// All rights reserved.

namespace Content.Server._Hullrot.FireControl;

[RegisterComponent]
public sealed partial class FireControlServerComponent : Component
{
[ViewVariables]
public EntityUid? ConnectedGrid = null;

[ViewVariables]
public HashSet<EntityUid> Controlled = new();

[ViewVariables]
public HashSet<EntityUid> Consoles = new();

[ViewVariables]
public Dictionary<EntityUid, EntityUid> Leases;
}
113 changes: 113 additions & 0 deletions Content.Server/_Hullrot/FireControl/FireControlSystem.Console.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
using Content.Server.Shuttles.Systems;
using Content.Shared._Hullrot.FireControl;
using Content.Shared.Power;
using Content.Shared.Shuttles.BUIStates;
using Robust.Server.GameObjects;

namespace Content.Server._Hullrot.FireControl;

public sealed partial class FireControlSystem : EntitySystem
{
[Dependency] private readonly UserInterfaceSystem _ui = default!;
[Dependency] private readonly ShuttleConsoleSystem _shuttleConsoleSystem = default!;
private void InitializeConsole()
{
SubscribeLocalEvent<FireControlConsoleComponent, PowerChangedEvent>(OnPowerChanged);
SubscribeLocalEvent<FireControlConsoleComponent, ComponentShutdown>(OnComponentShutdown);
SubscribeLocalEvent<FireControlConsoleComponent, FireControlConsoleRefreshServerMessage>(OnRefreshServer);
SubscribeLocalEvent<FireControlConsoleComponent, FireControlConsoleFireMessage>(OnFire);
SubscribeLocalEvent<FireControlConsoleComponent, BoundUIOpenedEvent>(OnUIOpened);
}

private void OnPowerChanged(EntityUid uid, FireControlConsoleComponent component, PowerChangedEvent args)
{
if (args.Powered)
TryRegisterConsole(uid, component);
else
UnregisterConsole(uid, component);
}

private void OnComponentShutdown(EntityUid uid, FireControlConsoleComponent component, ComponentShutdown args)
{
UnregisterConsole(uid, component);
}

private void OnRefreshServer(EntityUid uid, FireControlConsoleComponent component, FireControlConsoleRefreshServerMessage args)
{
TryRegisterConsole(uid, component);
}

private void OnFire(EntityUid uid, FireControlConsoleComponent component, FireControlConsoleFireMessage args)
{
if (component.ConnectedServer == null || !TryComp<FireControlServerComponent>(component.ConnectedServer, out var server))
return;

FireWeapons((EntityUid)component.ConnectedServer, args.Selected, args.Coordinates, server);
}

public void OnUIOpened(EntityUid uid, FireControlConsoleComponent component, BoundUIOpenedEvent args)
{
UpdateUi(uid, component);
}

private void UnregisterConsole(EntityUid console, FireControlConsoleComponent? component = null)
{
if (!Resolve(console, ref component))
return;

if (component.ConnectedServer == null || !TryComp<FireControlServerComponent>(component.ConnectedServer, out var server))
return;

server.Consoles.Remove(console);
component.ConnectedServer = null;
UpdateUi(console, component);
}
private bool TryRegisterConsole(EntityUid console, FireControlConsoleComponent? consoleComponent = null)
{
if (!Resolve(console, ref consoleComponent))
return false;

var gridServer = TryGetGridServer(console);

if (gridServer.ServerComponent == null)
return false;

if (gridServer.ServerComponent.Consoles.Add(console))
{
consoleComponent.ConnectedServer = gridServer.ServerUid;
UpdateUi(console, consoleComponent);
return true;
}
else
{
return false;
}
}

private void UpdateUi(EntityUid uid, FireControlConsoleComponent? component = null)
{
if (!Resolve(uid, ref component))
return;

NavInterfaceState navState = _shuttleConsoleSystem.GetNavState(uid, _shuttleConsoleSystem.GetAllDocks());

List<FireControllableEntry> controllables = new();
if (component.ConnectedServer != null && TryComp<FireControlServerComponent>(component.ConnectedServer, out var server))
{
foreach (var controllable in server.Controlled)
{
var controlled = new FireControllableEntry();
controlled.NetEntity = EntityManager.GetNetEntity(controllable);
controlled.Coordinates = GetNetCoordinates(Transform(controllable).Coordinates);
controlled.Name = MetaData(controllable).EntityName;

controllables.Add(controlled);
}
}

var array = controllables.ToArray();

var state = new FireControlConsoleBoundInterfaceState(component.ConnectedServer != null, array, navState);
_ui.SetUiState(uid, FireControlConsoleUiKey.Key, state);
}
}
Loading
Loading