229 lines
8.3 KiB
C#
229 lines
8.3 KiB
C#
// SPDX-FileCopyrightText: 2025 Ark
|
|
// SPDX-FileCopyrightText: 2025 ark1368
|
|
// SPDX-FileCopyrightText: 2025 sleepyyapril
|
|
//
|
|
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|
|
|
// Copyright Rane (elijahrane@gmail.com) 2025
|
|
// All rights reserved. Relicensed under AGPL with permission
|
|
|
|
using Content.Server.Shuttles.Components;
|
|
using Content.Server.Shuttles.Systems;
|
|
using Content.Shared._Mono.FireControl;
|
|
using Content.Shared.GameTicking;
|
|
using Content.Shared.Popups;
|
|
using Content.Shared.Power;
|
|
using Content.Shared.Shuttles.BUIStates;
|
|
using Content.Shared.UserInterface;
|
|
using Robust.Server.GameObjects;
|
|
|
|
namespace Content.Server._Mono.FireControl;
|
|
|
|
public sealed partial class FireControlSystem : EntitySystem
|
|
{
|
|
[Dependency] private readonly UserInterfaceSystem _ui = default!;
|
|
[Dependency] private readonly ShuttleConsoleSystem _shuttleConsoleSystem = default!;
|
|
[Dependency] private readonly TransformSystem _transform = default!;
|
|
[Dependency] private readonly SharedPopupSystem _popup = default!;
|
|
|
|
private bool _completedCheck = false;
|
|
|
|
private void InitializeConsole()
|
|
{
|
|
SubscribeLocalEvent<PlayerSpawnCompleteEvent>(OnSpawnComplete);
|
|
|
|
SubscribeLocalEvent<FireControlConsoleComponent, PowerChangedEvent>(OnPowerChanged);
|
|
SubscribeLocalEvent<FireControlConsoleComponent, ComponentShutdown>(OnComponentShutdown);
|
|
SubscribeLocalEvent<FireControlConsoleComponent, FireControlConsoleRefreshServerMessage>(OnRefreshServer);
|
|
SubscribeLocalEvent<FireControlConsoleComponent, FireControlConsoleFireMessage>(OnFire);
|
|
SubscribeLocalEvent<FireControlConsoleComponent, BoundUIOpenedEvent>(OnUIOpened);
|
|
}
|
|
|
|
// scuffed one-time check of all station control consoles to ensure they're already refreshed
|
|
// given this only happens once, we can assume all refreshed are things like Camelot's gunnery server.
|
|
private void OnSpawnComplete(PlayerSpawnCompleteEvent ev)
|
|
{
|
|
if (_completedCheck)
|
|
return;
|
|
|
|
var query = EntityQueryEnumerator<FireControlConsoleComponent>();
|
|
|
|
while (query.MoveNext(out var uid, out var console))
|
|
{
|
|
DoRefreshServer(uid, console);
|
|
}
|
|
|
|
_completedCheck = true;
|
|
}
|
|
|
|
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 DoRefreshServer(EntityUid uid, FireControlConsoleComponent component)
|
|
{
|
|
// First, clean up any invalid server references across all grids
|
|
CleanupInvalidServerReferences();
|
|
|
|
// Get the console's grid to force server reconnection on it
|
|
var consoleGrid = _xform.GetGrid(uid);
|
|
if (consoleGrid != null)
|
|
{
|
|
// Force all servers on this grid to attempt reconnection
|
|
ForceServerReconnectionOnGrid((EntityUid)consoleGrid);
|
|
}
|
|
|
|
// Check if the current connected server is still valid
|
|
if (component.ConnectedServer != null)
|
|
{
|
|
if (!Exists(component.ConnectedServer) || !TryComp<FireControlServerComponent>(component.ConnectedServer, out _))
|
|
{
|
|
// Server no longer exists, clear the connection
|
|
component.ConnectedServer = null;
|
|
}
|
|
}
|
|
|
|
// Try to register console if not connected or if connection was cleared
|
|
if (component.ConnectedServer == null)
|
|
{
|
|
TryRegisterConsole(uid, component);
|
|
}
|
|
|
|
// Refresh controllables if we have a valid server connection
|
|
if (component.ConnectedServer != null &&
|
|
TryComp<FireControlServerComponent>(component.ConnectedServer, out var server) &&
|
|
server.ConnectedGrid != null)
|
|
{
|
|
RefreshControllables((EntityUid)server.ConnectedGrid);
|
|
}
|
|
|
|
// Always update UI to reflect current state
|
|
UpdateUi(uid, component);
|
|
}
|
|
|
|
private void OnRefreshServer(EntityUid uid, FireControlConsoleComponent component, FireControlConsoleRefreshServerMessage args)
|
|
{
|
|
DoRefreshServer(uid, component);
|
|
}
|
|
|
|
private void OnFire(EntityUid uid, FireControlConsoleComponent component, FireControlConsoleFireMessage args)
|
|
{
|
|
if (component.ConnectedServer == null
|
|
|| !TryComp<FireControlServerComponent>(component.ConnectedServer, out var server)
|
|
|| !server.Consoles.Contains(uid))
|
|
return;
|
|
|
|
// Fire the actual weapons
|
|
FireWeapons((EntityUid)component.ConnectedServer, args.Selected, args.Coordinates, server);
|
|
|
|
// Raise an event to track the cursor position even when not firing
|
|
var fireEvent = new FireControlConsoleFireEvent(args.Coordinates, args.Selected);
|
|
RaiseLocalEvent(uid, fireEvent);
|
|
}
|
|
|
|
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)
|
|
return;
|
|
|
|
// Check if server still exists before trying to unregister
|
|
if (Exists(component.ConnectedServer) && TryComp<FireControlServerComponent>(component.ConnectedServer, out var server))
|
|
{
|
|
server.Consoles.Remove(console);
|
|
}
|
|
|
|
component.ConnectedServer = null;
|
|
UpdateUi(console, component);
|
|
}
|
|
|
|
private bool CanRegister((EntityUid? ServerUid, FireControlServerComponent? ServerComponent) gridServer)
|
|
{
|
|
if (gridServer.ServerComponent == null)
|
|
return false;
|
|
|
|
if (gridServer.ServerComponent.EnforceMaxConsoles
|
|
&& gridServer.ServerComponent.Consoles.Count >= gridServer.ServerComponent.MaxConsoles)
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
private bool TryRegisterConsole(EntityUid console, FireControlConsoleComponent? consoleComponent = null)
|
|
{
|
|
if (!Resolve(console, ref consoleComponent))
|
|
return false;
|
|
|
|
// Clear any existing invalid connection first
|
|
if (consoleComponent.ConnectedServer != null)
|
|
{
|
|
if (!Exists(consoleComponent.ConnectedServer) || !TryComp<FireControlServerComponent>(consoleComponent.ConnectedServer, out _))
|
|
{
|
|
consoleComponent.ConnectedServer = null;
|
|
}
|
|
}
|
|
|
|
var gridServer = TryGetGridServer(console);
|
|
|
|
if (gridServer.ServerUid == null || gridServer.ServerComponent == null)
|
|
return false;
|
|
|
|
var canRegister = CanRegister(gridServer);
|
|
|
|
if (canRegister && gridServer.ServerComponent.Consoles.Add(console))
|
|
{
|
|
consoleComponent.ConnectedServer = gridServer.ServerUid;
|
|
UpdateUi(console, consoleComponent);
|
|
return true;
|
|
}
|
|
|
|
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))
|
|
{
|
|
if (!server.Consoles.Contains(uid))
|
|
return;
|
|
|
|
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);
|
|
}
|
|
}
|