diff --git a/Content.Client/_Crescent/PointCannons/TargetingConsoleBUI.cs b/Content.Client/_Crescent/PointCannons/TargetingConsoleBUI.cs
index 6ba5ce6dc5c..8c87540289d 100644
--- a/Content.Client/_Crescent/PointCannons/TargetingConsoleBUI.cs
+++ b/Content.Client/_Crescent/PointCannons/TargetingConsoleBUI.cs
@@ -60,6 +60,8 @@ protected override void Open()
_window.OpenCentered();
_window.OnClose += Close;
+ _window.OnServerRefresh += OnRefreshServer;
+
_window.Radar.OnRadarClick += (coords) =>
{
_coords = _formSys.ToMapCoordinates(coords).Position;
@@ -103,4 +105,9 @@ protected override void UpdateState(BoundUserInterfaceState state)
_controlled = consoleState.ControlledCannons;
_window?.UpdateState(consoleState);
}
+
+ private void OnRefreshServer()
+ {
+ SendMessage(new FireControlConsoleRefreshServerMessage());
+ }
}
diff --git a/Content.Client/_Crescent/PointCannons/TargetingConsoleWindow.xaml b/Content.Client/_Crescent/PointCannons/TargetingConsoleWindow.xaml
index 23ea68c323e..60369ef28c9 100644
--- a/Content.Client/_Crescent/PointCannons/TargetingConsoleWindow.xaml
+++ b/Content.Client/_Crescent/PointCannons/TargetingConsoleWindow.xaml
@@ -13,13 +13,29 @@
MaxWidth="300"
Margin="5 5 5 5"
Orientation="Vertical">
+
+
+
+
+
+
+
+
+
+
diff --git a/Content.Client/_Crescent/PointCannons/TargetingConsoleWindow.xaml.cs b/Content.Client/_Crescent/PointCannons/TargetingConsoleWindow.xaml.cs
index b566c0808f3..6d824c5a723 100644
--- a/Content.Client/_Crescent/PointCannons/TargetingConsoleWindow.xaml.cs
+++ b/Content.Client/_Crescent/PointCannons/TargetingConsoleWindow.xaml.cs
@@ -16,11 +16,14 @@ public sealed partial class TargetingConsoleWindow : FancyWindow, IComputerWindo
{
public ShuttleNavControl Radar => NavRadar;
public Action? OnCannonGroupChange;
+ public Action? OnServerRefresh;
public TargetingConsoleWindow()
{
RobustXamlLoader.Load(this);
IoCManager.InjectDependencies(this);
+
+ RefreshButton.OnPressed += _ => OnServerRefresh?.Invoke();
}
public void UpdateState(TargetingConsoleBoundUserInterfaceState state)
diff --git a/Content.Server/_Crescent/Hardpoint/HardpointSystem.cs b/Content.Server/_Crescent/Hardpoint/HardpointSystem.cs
index bf549984348..47edfd089c8 100644
--- a/Content.Server/_Crescent/Hardpoint/HardpointSystem.cs
+++ b/Content.Server/_Crescent/Hardpoint/HardpointSystem.cs
@@ -19,18 +19,11 @@ namespace Content.Server._Crescent.Hardpoint;
public sealed class HardpointSystem : SharedHardpointSystem
{
[Dependency] private readonly PointCannonSystem _cannonSystem = default!;
- [Dependency] private readonly IGameTiming _gameTiming = default!;
[Dependency] private readonly DeviceLinkSystem _signalSystem = default!;
[Dependency] private readonly SharedGunSystem _gun = default!;
- // Explosions can cause a lot of lookups and events to fire. So we time-limit it based on grids
- private const float UpdateDelay = 60f;
- private float InternalTimer = 0f;
- private HashSet QueuedGrids = new();
///
public override void Initialize()
{
- SubscribeLocalEvent(OnFixtureAnchor);
- SubscribeLocalEvent(OnCannonAnchor);
SubscribeLocalEvent(OnCannonDeanchor);
SubscribeLocalEvent(OnSignalReceived);
}
@@ -56,30 +49,6 @@ private void OnSignalReceived(EntityUid uid, HardpointFixedMountComponent compon
_gun.SetEnabled(hard.anchoring.Value, autoShoot, !autoShoot.Enabled);
}
- public void OnFixtureAnchor(EntityUid uid, FixturesComponent comp, ref AnchorStateChangedEvent args)
- {
- if (args.Transform.GridUid is null)
- return;
- QueueHardpointRefresh(args.Transform.GridUid.Value);
- }
-
- public void QueueHardpointRefresh(EntityUid grid)
- {
- if (QueuedGrids.Contains(grid))
- return;
- QueuedGrids.Add(grid);
- }
-
-
- public void OnCannonAnchor(EntityUid uid, HardpointComponent comp, ref HardpointCannonAnchoredEvent args)
- {
- // This is just for turret-cannons!
- if (!TryComp(args.cannonUid, out var compx))
- return;
- _cannonSystem.LinkCannonToAllConsoles(args.cannonUid);
- QueueHardpointRefresh(args.gridUid);
- }
-
public void OnCannonDeanchor(EntityUid uid, HardpointComponent comp, ref HardpointCannonDeanchoredEvent args)
{
// This is just for turret-cannons!
@@ -88,39 +57,4 @@ public void OnCannonDeanchor(EntityUid uid, HardpointComponent comp, ref Hardpoi
_cannonSystem.UnlinkCannon(args.CannonUid);
}
- public override void Update(float frameTime)
- {
- base.Update(frameTime);
-
- if (!_gameTiming.IsFirstTimePredicted)
- return;
-
- InternalTimer += frameTime;
- if (InternalTimer < UpdateDelay)
- return;
- InternalTimer = 0;
- EntityQuery hardpointQuery = GetEntityQuery();
- foreach(var grid in QueuedGrids)
- {
- if (TerminatingOrDeleted(grid))
- {
- QueuedGrids.Remove(grid);
- continue;
- }
- HashSet> lookupList = new();
- _lookupSystem.GetGridEntities(grid, lookupList);
- foreach (var entity in lookupList)
- {
- if (entity.Comp.anchoring is null)
- continue;
- if (TerminatingOrDeleted(entity.Comp.anchoring.Value))
- continue;
- // This is just for turret-cannons!
- if (!TryComp(entity.Comp.anchoring.Value, out var compx))
- continue;
- _cannonSystem.RefreshFiringRanges(entity.Comp.anchoring.Value, null, null, compx, entity.Comp.CannonRangeCheckRange);
- }
- }
- QueuedGrids.Clear();
- }
}
diff --git a/Content.Server/_Crescent/PointCannons/PointCannonSystem.cs b/Content.Server/_Crescent/PointCannons/PointCannonSystem.cs
index 888db5bc025..478f4f5331b 100644
--- a/Content.Server/_Crescent/PointCannons/PointCannonSystem.cs
+++ b/Content.Server/_Crescent/PointCannons/PointCannonSystem.cs
@@ -1,24 +1,20 @@
using System.Linq;
using System.Numerics;
+using System.Collections.Generic;
using Content.Server.Administration;
-using Content.Server.Construction.Conditions;
using Content.Server.Popups;
using Content.Server.Shuttles.Systems;
using Content.Server.Weapons.Ranged.Systems;
-using Content.Shared.Body.Components;
-using Content.Shared.Crescent.Radar;
using Content.Shared.Interaction;
using Content.Shared.Interaction.Events;
using Content.Shared.PointCannons;
-using Content.Shared.Popups;
using Content.Shared.Shuttles.BUIStates;
+using Content.Shared.Shuttles.Components;
using Content.Shared.UserInterface;
using Content.Shared.Weapons.Ranged.Components;
-using Content.Shared.Shuttles.Components;
using Robust.Server.GameObjects;
using Robust.Server.GameStates;
using Robust.Shared.Configuration;
-using Robust.Shared.Containers;
using Robust.Shared.Map;
using Robust.Shared.Map.Components;
using Robust.Shared.Physics;
@@ -29,12 +25,13 @@
using Content.Server.Power.Components;
using Content.Shared._Crescent.CCvars;
using Content.Shared._Crescent.Hardpoints;
-using Content.Shared.Communications;
using Content.Shared.Physics;
+using Content.Shared.Popups;
+using Content.Shared.Crescent.Radar;
namespace Content.Server.PointCannons;
-public class PointCannonSystem : EntitySystem
+public sealed class PointCannonSystem : EntitySystem
{
[Dependency] private readonly ISharedPlayerManager _playerMan = default!;
[Dependency] private readonly TransformSystem _formSys = default!;
@@ -46,13 +43,19 @@ public class PointCannonSystem : EntitySystem
[Dependency] private readonly PvsOverrideSystem _pvsSys = default!;
[Dependency] private readonly SharedTransformSystem _transform = default!;
[Dependency] private readonly EntityLookupSystem _lookup = default!;
- [Dependency] private readonly MapSystem _maps = default!;
[Dependency] private readonly HardpointSystem _hardpoint = default!;
[Dependency] private readonly IConfigurationManager _cfg = default!;
private float _accumulatedFrameTime;
private float _uiTps;
+ private readonly HashSet _activeConsoles = new();
+
+ private readonly Dictionary _gridUpdateCooldown = new();
+ private const float GridUpdateCooldownTime = 0.5f; // seconds
+ private int CannonCheckRange = 25;
+ private HashSet QueuedGrids = new();
+
public override void Initialize()
{
base.Initialize();
@@ -65,6 +68,7 @@ public override void Initialize()
SubscribeLocalEvent(OnConsoleClosed);
SubscribeLocalEvent(OnConsoleFire);
SubscribeLocalEvent(OnConsoleGroupChanged);
+ SubscribeLocalEvent(OnRefreshServer);
SubscribeLocalEvent(OnConsoleDelete);
SubscribeLocalEvent(OnConsoleAnchor);
@@ -72,62 +76,90 @@ public override void Initialize()
SubscribeLocalEvent(OnCannonDetach);
SubscribeLocalEvent(OnCannonDetach);
- SubscribeLocalEvent(OnGridShapeChange);
-
SubscribeLocalEvent(OnLinkToolHandUse);
- SubscribeLocalEvent(OnLinkToolUse);
}
+
public override void Update(float frameTime)
{
base.Update(frameTime);
_accumulatedFrameTime += frameTime;
-
float targetTime = _uiTps > 0 ? 1.0f / _uiTps : 1.0f;
-
- if (_accumulatedFrameTime < targetTime) // no update spam
+ if (_accumulatedFrameTime < targetTime)
return;
-
_accumulatedFrameTime -= targetTime;
- if (_accumulatedFrameTime > targetTime) // no lag-induced spam
+ if (_accumulatedFrameTime > targetTime)
_accumulatedFrameTime = 0;
- var query = EntityQueryEnumerator();
- while (query.MoveNext(out var uid, out var console))
+ foreach (var uid in _activeConsoles)
{
- if (!_uiSys.IsUiOpen(uid, TargetingConsoleUiKey.Key))
+ if (!TryComp(uid, out var console))
+ {
+ _activeConsoles.Remove(uid);
continue;
+ }
UpdateConsoleState(uid, console);
}
- }
- private void OnGridShapeChange(EntityUid gridUid, MapGridComponent grid, ref GridFixtureChangeEvent args)
- {
- //Logger.Error($"Running grid fixture change on {MetaData(gridUid).EntityName}, NUMBER {gridUid}");
- HashSet> targetingConsoles = new();
- _lookup.GetGridEntities(gridUid, targetingConsoles);
- foreach (var console in targetingConsoles)
+ var toRemove = new List();
+ foreach (var (uid, timer) in _gridUpdateCooldown)
{
- UnlinkAllCannonsFromConsole(console.Owner, console.Comp);
- LinkAllCannonsToConsole(console.Owner, console.Comp);
+ if (timer <= 0)
+ {
+ if (!TryComp(uid, out var consoleComp))
+ continue;
+ ProcessGridShapeChange(uid, consoleComp);
+ toRemove.Add(uid);
+ }
+ else
+ {
+ _gridUpdateCooldown[uid] = timer - frameTime;
+ }
+ }
+ foreach (var id in toRemove)
+ {
+ _gridUpdateCooldown.Remove(id);
}
- _hardpoint.QueueHardpointRefresh(gridUid);
+ }
+
+ private void ProcessGridShapeChange(EntityUid console, TargetingConsoleComponent component)
+ {
+ UnlinkAllCannonsFromConsole(console, component);
+ LinkAllCannonsToConsole(console, component);
+ }
+
+ private void OnRefreshServer(EntityUid console, TargetingConsoleComponent component, FireControlConsoleRefreshServerMessage args)
+ {
+ if (_gridUpdateCooldown.ContainsKey(console))
+ _gridUpdateCooldown[console] = GridUpdateCooldownTime; // reset timer
+ else
+ _gridUpdateCooldown[console] = GridUpdateCooldownTime;
}
private void UnlinkAllCannonsFromConsole(EntityUid console, TargetingConsoleComponent comp)
{
- // we need to create a copy of the dictionary else we modify the enumerable we act on
- foreach (var (group, cannons) in new Dictionary>(comp.CannonGroups))
+ // Create a complete snapshot of all cannons before unlinking anything
+ var allLinks = new List<(string group, EntityUid cannon)>();
+
+ foreach (var (group, cannons) in comp.CannonGroups)
{
- foreach (var cannon in new List(cannons))
+ foreach (var cannon in cannons)
{
- UnlinkConsole(cannon, console, comp);
+ allLinks.Add((group, cannon));
}
}
+
+ // Now unlink using the snapshot
+ foreach (var (group, cannon) in allLinks)
+ {
+ UnlinkConsole(cannon, console, comp);
+ }
}
+
private void OnConsoleDelete(EntityUid console, TargetingConsoleComponent comp, ref T args)
{
UnlinkAllCannonsFromConsole(console, comp);
+ _activeConsoles.Remove(console);
}
private void OnConsoleAnchor(EntityUid console, TargetingConsoleComponent comp, ref AnchorStateChangedEvent args)
@@ -137,8 +169,6 @@ private void OnConsoleAnchor(EntityUid console, TargetingConsoleComponent comp,
OnConsoleDelete(console, comp, ref args);
return;
}
-
- LinkAllCannonsToConsole(console, comp);
}
public void LinkAllCannonsToConsole(EntityUid console, TargetingConsoleComponent comp)
@@ -146,35 +176,21 @@ public void LinkAllCannonsToConsole(EntityUid console, TargetingConsoleComponent
var gridUid = Transform(console).GridUid;
if (gridUid is null)
return;
- HashSet> cannonList = new();
+ var cannonList = new HashSet>();
_lookup.GetGridEntities(gridUid.Value, cannonList);
foreach (var cannon in cannonList)
{
- if (Transform(cannon.Owner).Anchored == false)
+ if (!Transform(cannon.Owner).Anchored)
continue;
- LinkCannon(cannon.Owner, console, comp, MetaData(cannon.Owner).EntityName);
- }
- }
-
- public void LinkCannonToAllConsoles(EntityUid cannon)
- {
- var gridUid = Transform(cannon).GridUid;
- if (gridUid is null)
- return;
- HashSet> consoleList = new();
- _lookup.GetGridEntities(gridUid.Value, consoleList);
- foreach (var console in consoleList)
- {
- if (Transform(console.Owner).Anchored == false)
+ if (!TryComp(cannon.Owner, out var anchorComp) || anchorComp.anchoredTo is null)
continue;
- LinkCannon(cannon, console.Owner, console.Comp, MetaData(cannon).EntityName);
+ LinkCannon(cannon.Owner, console, comp, MetaData(cannon.Owner).EntityName);
}
}
private void OnConsoleOpenAttempt(EntityUid uid, TargetingConsoleComponent component, ActivatableUIOpenAttemptEvent args)
{
var uis = _uiSys.GetActorUis(args.User);
-
var ourGridUid = Transform(uid).GridUid;
if (ourGridUid is null)
{
@@ -184,10 +200,11 @@ private void OnConsoleOpenAttempt(EntityUid uid, TargetingConsoleComponent compo
foreach (var (_, key) in uis)
{
- if (key is ShuttleConsoleUiKey.Key)
+ if (key is ShuttleConsoleUiKey)
{
args.Cancel();
_popSys.PopupEntity(Loc.GetString("targeting-rejection-shuttle-console"), args.User, args.User, PopupType.LargeCaution);
+ return;
}
}
}
@@ -195,55 +212,32 @@ private void OnConsoleOpenAttempt(EntityUid uid, TargetingConsoleComponent compo
private void BUIValidation(EntityUid uid, TargetingConsoleComponent component, BoundUserInterfaceMessageAttempt args)
{
var uis = _uiSys.GetActorUis(args.Actor);
-
foreach (var (_, key) in uis)
{
- if (key is ShuttleConsoleUiKey.Key)
+ if (key is ShuttleConsoleUiKey)
{
args.Cancel();
+ return;
}
}
}
+
private void OnConsoleOpened(Entity uid, ref BoundUIOpenedEvent args)
{
uid.Comp.RegenerateCannons = true;
-
- if (_playerMan.TryGetSessionByEntity(args.Actor, out var session))
- TogglePvsOverride(uid.Comp.CurrentGroup, [session], true);
+ _activeConsoles.Add(uid.Owner);
}
private void OnConsoleClosed(Entity uid, ref BoundUIClosedEvent args)
{
- if (_playerMan.TryGetSessionByEntity(args.Actor, out var session))
- TogglePvsOverride(uid.Comp.CurrentGroup, [session], false);
+ _activeConsoles.Remove(uid.Owner);
}
- private void OnCannonDetach(Entity uid,ref T args)
+ private void OnCannonDetach(Entity uid, ref T args)
{
UnlinkCannon(uid);
}
-
-
- private void OnLinkToolUse(Entity uid, ref InteractUsingEvent args)
- {
- if (!TryComp(args.Used, out var linkTool))
- return;
-
- EntityUid? gridUid = Transform(uid).GridUid;
- if (gridUid == null)
- return;
-
- var query = EntityManager.AllEntityQueryEnumerator();
- while (query.MoveNext(out var consoleUid, out var form, out var console))
- {
- if (form.GridUid == gridUid)
- LinkCannon(uid, consoleUid, console, linkTool.GroupName);
- }
-
- _popSys.PopupEntity($"Added to {linkTool.GroupName}", args.User);
- }
-
private void OnLinkToolHandUse(Entity uid, ref UseInHandEvent args)
{
if (!_playerMan.TryGetSessionByEntity(args.User, out var session))
@@ -251,16 +245,16 @@ private void OnLinkToolHandUse(Entity uid, ref Use
_dialogSys.OpenDialog(session, "Group name", "Name (case insensitive)", (string name) =>
{
- uid.Comp.GroupName = name == "" ? "all" : name.ToLower();
+ uid.Comp.GroupName = string.IsNullOrEmpty(name) ? "all" : name.ToLower();
});
}
public void LinkCannon(EntityUid cannonUid, EntityUid consoleUid, TargetingConsoleComponent console, string group)
{
- if(!TryComp(cannonUid, out var cannonComponent))
+ if (!TryComp(cannonUid, out var cannonComponent))
return;
if (!console.CannonGroups.ContainsKey(group))
- console.CannonGroups[group] = [];
+ console.CannonGroups[group] = new List();
if (console.CannonGroups[group].Contains(cannonUid))
{
@@ -278,34 +272,41 @@ public void LinkCannon(EntityUid cannonUid, EntityUid consoleUid, TargetingConso
cannonComponent.LinkedConsoleId = consoleUid;
cannonComponent.LinkedConsoleIds.Add(consoleUid);
+ RefreshFiringRanges(cannonUid, null, null, cannonComponent, CannonCheckRange);
- if (group == console.CurrentGroupName)
- TogglePvsOverride([cannonUid], GetUiSessions(consoleUid, TargetingConsoleUiKey.Key), true);
+ //if (console.ActiveGroups.Contains(group))
+ //TogglePvsOverride(new[] { cannonUid }, GetUiSessions(consoleUid), true);
}
public void UnlinkCannon(EntityUid cannonUid)
{
if (!TryComp(cannonUid, out var cannonComp))
return;
- foreach (var consoleUid in cannonComp.LinkedConsoleIds)
+
+ var consoleIds = cannonComp.LinkedConsoleIds.ToList();
+
+ foreach (var consoleUid in consoleIds)
{
- var console = Comp(consoleUid);
- foreach (string group in console.CannonGroups.Keys.ToList())
+ if (!TryComp(consoleUid, out var console))
+ continue;
+
+ var groups = console.CannonGroups.Keys.ToList();
+
+ foreach (string group in groups)
{
- console.CannonGroups[group].Remove(cannonUid);
- if (console.CannonGroups[group].Count == 0 && group != "all")
+ if (console.CannonGroups.TryGetValue(group, out var cannons))
{
- console.CannonGroups.Remove(group);
- if (console.CurrentGroupName == group)
- console.CurrentGroupName = "all";
+ cannons.Remove(cannonUid);
+
+ if (cannons.Count == 0 && group != "all")
+ console.CannonGroups.Remove(group);
}
}
-
+
console.RegenerateCannons = true;
-
- TogglePvsOverride([cannonUid], GetUiSessions(consoleUid, TargetingConsoleUiKey.Key), false);
+ TogglePvsOverride(new[] { cannonUid }, GetUiSessions(consoleUid), false);
}
-
+
cannonComp.LinkedConsoleIds.Clear();
}
@@ -313,35 +314,43 @@ public void UnlinkConsole(EntityUid cannonUid, EntityUid consoleUid, TargetingCo
{
if (!TryComp(cannonUid, out var cannonComp))
return;
+
cannonComp.LinkedConsoleIds.Remove(consoleUid);
- var console = Comp(consoleUid);
- foreach (string group in console.CannonGroups.Keys.ToList())
+
+ if (!TryComp(consoleUid, out var console))
+ return;
+
+ // Get a snapshot of groups to iterate safely
+ var groups = console.CannonGroups.Keys.ToList();
+
+ foreach (string group in groups)
{
- console.CannonGroups[group].Remove(cannonUid);
- if (console.CannonGroups[group].Count == 0 && group != "all")
+ if (console.CannonGroups.TryGetValue(group, out var cannons))
{
- console.CannonGroups.Remove(group);
- if (console.CurrentGroupName == group)
- console.CurrentGroupName = "all";
+ cannons.Remove(cannonUid);
+
+ if (cannons.Count == 0 && group != "all")
+ console.CannonGroups.Remove(group);
}
}
-
+
console.RegenerateCannons = true;
-
- TogglePvsOverride([cannonUid], GetUiSessions(consoleUid, TargetingConsoleUiKey.Key), false);
+ TogglePvsOverride(new[] { cannonUid }, GetUiSessions(consoleUid), false);
}
public void UpdateConsoleState(EntityUid uid, TargetingConsoleComponent console)
{
NavInterfaceState navState = _shuttleConSys.GetNavState(uid, _shuttleConSys.GetAllDocks());
- IFFInterfaceState iffState = _shuttleConSys.GetIFFState(uid, console.RegenerateCannons ? null : console.PrevState?.IFFState.Turrets);
+ IFFInterfaceState iffState = _shuttleConSys.GetIFFState(uid,
+ console.RegenerateCannons ? null : console.PrevState?.IFFState.Turrets);
- TargetingConsoleBoundUserInterfaceState consoleState = new(
+ List? groups = console.RegenerateCannons ? console.CannonGroups.Keys.ToList() : null;
+
+ var consoleState = new TargetingConsoleBoundUserInterfaceState(
navState,
iffState,
- console.RegenerateCannons ? console.CannonGroups.Keys.ToList() : null,
+ groups,
GetNetEntityList(console.CurrentGroup));
-
console.RegenerateCannons = false;
console.PrevState = consoleState;
_uiSys.SetUiState(uid, TargetingConsoleUiKey.Key, consoleState);
@@ -355,6 +364,7 @@ private void OnConsoleFire(EntityUid uid, TargetingConsoleComponent console, Tar
if (Deleted(cannonUid))
{
console.CurrentGroup.RemoveAt(i);
+ TogglePvsOverride(new[] { cannonUid }, GetUiSessions(uid), false);
continue;
}
@@ -365,13 +375,36 @@ private void OnConsoleFire(EntityUid uid, TargetingConsoleComponent console, Tar
private void OnConsoleGroupChanged(Entity uid, ref TargetingConsoleGroupChangedMessage args)
{
- string prevGroup = uid.Comp.CurrentGroupName;
- uid.Comp.CurrentGroupName = args.GroupName;
- uid.Comp.RegenerateCannons = true;
+ var sessions = GetUiSessions(uid);
+
+ if (uid.Comp.ActiveGroups.Contains(args.GroupName))
+ {
+ if (args.GroupName == "all")
+ uid.Comp.ActiveGroups = new();
+ else
+ uid.Comp.ActiveGroups.Remove(args.GroupName);
+ TogglePvsOverride(uid.Comp.CannonGroups[args.GroupName], sessions, false);
+ }
+ else
+ {
+ if (args.GroupName == "all")
+ uid.Comp.ActiveGroups = new() { "all" };
+ else
+ uid.Comp.ActiveGroups.Add(args.GroupName);
+ TogglePvsOverride(uid.Comp.CannonGroups[args.GroupName], sessions, true);
+ }
+
+ var totalLength = 0;
- List sessions = GetUiSessions(uid, TargetingConsoleUiKey.Key);
- TogglePvsOverride(uid.Comp.CannonGroups[prevGroup], sessions, false);
- TogglePvsOverride(uid.Comp.CurrentGroup, sessions, true);
+ foreach (var group in uid.Comp.ActiveGroups)
+ totalLength += uid.Comp.CannonGroups[group].Count;
+
+ var selected = new List(totalLength);
+
+ foreach (var group in uid.Comp.ActiveGroups)
+ selected.AddRange(uid.Comp.CannonGroups[group]);
+
+ uid.Comp.CurrentGroup = selected;
}
public bool TryFireCannon(
@@ -386,36 +419,33 @@ public bool TryFireCannon(
if (form.MapUid == null || !_gunSys.CanShoot(gun))
return false;
- if (!TryComp(uid, out var anchorComp))
- return false;
- if (anchorComp.anchoredTo is null)
+ if (!TryComp(uid, out var anchorComp) || anchorComp.anchoredTo is null)
return false;
- if (!TryComp(anchorComp.anchoredTo, out var powerComp))
+ if (!TryComp(anchorComp.anchoredTo, out var powerComp) || !powerComp.Powered)
return false;
- if (!powerComp.Powered)
- return false;
- EntityCoordinates entPos = new EntityCoordinates(uid, new Vector2(0, -1));
- if (!TryComp(anchorComp.anchoredTo, out var fixedComp))
+
+ var entPos = new EntityCoordinates(uid, new Vector2(0, -1));
+ if (!HasComp(anchorComp.anchoredTo))
{
Vector2 cannonPos = _formSys.GetWorldPosition(form);
_formSys.SetWorldRotation(uid, Angle.FromWorldVec(pos - cannonPos));
- entPos = new(form.MapUid.Value, pos);
+ entPos = new EntityCoordinates(form.MapUid.Value, pos);
}
if (!SafetyCheck(form.LocalRotation - Math.PI / 2, cannon))
return false;
+
_gunSys.AttemptShoot(uid, uid, gun, entPos);
return true;
}
public bool SafetyCheck(Angle ang, PointCannonComponent cannon)
{
- foreach ((Angle start, Angle width) in cannon.ObstructedRanges)
+ foreach (var (start, width) in cannon.ObstructedRanges)
{
if (CrescentHelpers.AngInSector(ang, start, width))
return false;
}
-
return true;
}
@@ -423,7 +453,6 @@ public void RefreshFiringRanges(EntityUid uid, TransformComponent? form = null,
{
if (!Resolve(uid, ref form) || !Resolve(uid, ref gun) || !Resolve(uid, ref cannon))
return;
- // 10 meters the default if one is not provided
range ??= 10;
cannon.ObstructedRanges = CalculateFiringRanges(uid, form, gun, cannon, range.Value);
@@ -435,64 +464,74 @@ public void RefreshFiringRanges(EntityUid uid, TransformComponent? form = null,
if (form.GridUid == null)
return new();
- List<(Angle, Angle)> ranges = new();
- HashSet entities = _lookup.GetEntitiesInRange(uid, (float) range, LookupFlags.Static);
- foreach(var childUid in entities)
+ var gridUid = form.GridUid.Value;
+ var cannonPos = form.LocalPosition;
+
+ var entities = _lookup.GetEntitiesInRange(uid, range, LookupFlags.Static);
+ var sectors = new List<(Angle start, Angle width)>();
+
+ foreach (var childUid in entities)
{
- //checking if obstacle is not too far/close to the cannon
- TransformComponent otherForm = Transform(childUid);
- // dont care about other grids
- if (otherForm.GridUid != form.GridUid)
+ var otherForm = Transform(childUid);
+ if (otherForm.GridUid != gridUid)
+ continue;
+
+ var dir = otherForm.LocalPosition - cannonPos;
+ if (!otherForm.Anchored)
+ continue;
+
+ if (!TryComp(childUid, out var body) || !body.Hard)
continue;
- Vector2 dir = otherForm.LocalPosition - form.LocalPosition;
- //checking that obstacle is anchored and solid
- if (!otherForm.Anchored || !TryComp(childUid, out var body) || !body.Hard || (body.CollisionLayer & (int)CollisionGroup.BulletImpassable) == 0)
+ if ((body.CollisionLayer & (int)CollisionGroup.BulletImpassable) == 0)
continue;
- //calculating circular sector that obstacle occupies relative to the cannon
- (Angle start0, Angle width0) = GetObstacleSector(dir);
- ranges.Add((start0, width0));
+ var (start, width) = GetObstacleSector(dir);
+ sectors.Add((start, width));
+ }
+
+ // Merge overlapping sectors efficiently: O(n log n)
+ if (sectors.Count == 0)
+ return new();
- (Angle start2, Angle width2) = (start0, width0);
+ sectors.Sort((a, b) => a.start.Theta.CompareTo(b.start.Theta));
- //checking whether new sector overlaps with any existing ones and combining them if so
- List<(Angle, Angle)> overlaps = new();
- foreach ((Angle start1, Angle width1) in ranges)
+ var merged = new List<(Angle start, Angle width)>();
+ var current = sectors[0];
+
+ for (int i = 1; i < sectors.Count; i++)
+ {
+ var next = sectors[i];
+ if (CrescentHelpers.AngSectorsOverlap(current.start, current.width, next.start, next.width))
{
- if (CrescentHelpers.AngSectorsOverlap(start0, width0, start1, width1))
- {
- (start2, width2) = CrescentHelpers.AngCombinedSector(start2, width2, start1, width1);
- overlaps.Add((start1, width1));
- }
+ var (newStart, newWidth) = CrescentHelpers.AngCombinedSector(current.start, current.width, next.start, next.width);
+ current = (newStart, newWidth);
}
-
- foreach ((Angle start1, Angle width1) in overlaps)
+ else
{
- ranges.Remove((start1, width1));
+ merged.Add(current);
+ current = next;
}
- ranges.Add((start2, width2));
}
+ merged.Add(current);
- Angle maxSpread = gun.MaxAngle + Angle.FromDegrees(10);
- Angle clearance = maxSpread + cannon.ClearanceAngle;
+ var maxSpread = gun.MaxAngle + Angle.FromDegrees(10);
+ var clearance = maxSpread + cannon.ClearanceAngle;
- for (int i = 0; i < ranges.Count; i++)
+ var result = new List<(Angle, Angle)>(merged.Count);
+ foreach (var (start, width) in merged)
{
- ranges[i] = (CrescentHelpers.AngNormal(ranges[i].Item1 - clearance / 2), ranges[i].Item2 + clearance);
+ result.Add((CrescentHelpers.AngNormal(start - clearance / 2), width + clearance));
}
- return ranges;
+ return result;
}
- //delta between cannon's and obstacle's position
private (Angle, Angle) GetObstacleSector(Vector2 delta)
{
Angle dirAngle = CrescentHelpers.AngNormal(new Angle(delta));
Vector2 a, b;
- //this can be done without ugly conditional below, by rotating tile's square by delta's angle and finding left- and rightmost points,
- //but this certainly will be heavier and less clear
if (dirAngle % (Math.PI * 0.5) == 0)
{
switch (dirAngle.Theta)
@@ -541,10 +580,10 @@ public void RefreshFiringRanges(EntityUid uid, TransformComponent? form = null,
return (start, width);
}
- private List GetUiSessions(EntityUid uid, Enum key)
+ private List GetUiSessions(EntityUid uid)
{
- List sessions = new();
- foreach (EntityUid actorUid in _uiSys.GetActors(uid, TargetingConsoleUiKey.Key))
+ var sessions = new List();
+ foreach (var actorUid in _uiSys.GetActors(uid, TargetingConsoleUiKey.Key))
{
if (_playerMan.TryGetSessionByEntity(actorUid, out var session))
sessions.Add(session);
@@ -554,22 +593,18 @@ private List GetUiSessions(EntityUid uid, Enum key)
private void TogglePvsOverride(IEnumerable uids, IEnumerable sessions, bool enable)
{
- foreach (ICommonSession session in sessions)
+ foreach (var session in sessions)
{
- foreach (EntityUid uid in uids)
+ foreach (var uid in uids)
{
if (!Exists(uid))
continue;
if (enable)
- {
_pvsSys.AddSessionOverride(uid, session);
- }
else
- {
_pvsSys.RemoveSessionOverride(uid, session);
- }
}
}
}
-}
+}
\ No newline at end of file
diff --git a/Content.Server/_Crescent/PointCannons/TargetingConsoleComponent.cs b/Content.Server/_Crescent/PointCannons/TargetingConsoleComponent.cs
index f123a7e26cf..2c4d7e57f42 100644
--- a/Content.Server/_Crescent/PointCannons/TargetingConsoleComponent.cs
+++ b/Content.Server/_Crescent/PointCannons/TargetingConsoleComponent.cs
@@ -1,4 +1,5 @@
using Content.Shared.PointCannons;
+using Robust.Shared.Timing;
namespace Content.Server.PointCannons;
@@ -7,8 +8,11 @@ public sealed partial class TargetingConsoleComponent : Component
{
[DataField, ViewVariables(VVAccess.ReadWrite)]
public Dictionary> CannonGroups = new() { { "all", new() } };
- public string CurrentGroupName = "all";
- public List CurrentGroup => CannonGroups[CurrentGroupName];
+ public HashSet ActiveGroups = new();
+ public string CurrentGroupName = string.Empty;
+ //public List CurrentGroup => CannonGroups[CurrentGroupName];
+ [DataField, ViewVariables(VVAccess.ReadWrite)]
+ public List CurrentGroup = new();
public bool RegenerateCannons = true;
public TargetingConsoleBoundUserInterfaceState? PrevState;
diff --git a/Content.Shared/_Crescent/Hardpoints/SharedHardpointSystem.cs b/Content.Shared/_Crescent/Hardpoints/SharedHardpointSystem.cs
index 6d51938bdd6..39c90ac52fc 100644
--- a/Content.Shared/_Crescent/Hardpoints/SharedHardpointSystem.cs
+++ b/Content.Shared/_Crescent/Hardpoints/SharedHardpointSystem.cs
@@ -193,10 +193,6 @@ public void AnchorEntityToHardpoint(EntityUid target, EntityUid anchor, Hardpoin
hardpoint.anchoring = target;
targetComp.anchoredTo = anchor;
_transformSystem.SetLocalRotation(target, Transform(anchor).LocalRotation);
- HardpointCannonAnchoredEvent arg = new();
- arg.cannonUid = target;
- arg.gridUid = grid;
- RaiseLocalEvent(anchor, arg);
DirtyEntity(target);
DirtyEntity(anchor);
//Dirty(target, targetComp);
diff --git a/Content.Shared/_Crescent/PointCannons/TargetingConsoleBUIState.cs b/Content.Shared/_Crescent/PointCannons/TargetingConsoleBUIState.cs
index 9839752c431..3bae7f05b5c 100644
--- a/Content.Shared/_Crescent/PointCannons/TargetingConsoleBUIState.cs
+++ b/Content.Shared/_Crescent/PointCannons/TargetingConsoleBUIState.cs
@@ -37,6 +37,12 @@ public TargetingConsoleFireMessage(Vector2 coords)
}
}
+[Serializable, NetSerializable]
+public sealed class FireControlConsoleRefreshServerMessage : BoundUserInterfaceMessage
+{
+
+}
+
[Serializable, NetSerializable]
public sealed class TargetingConsoleGroupChangedMessage : BoundUserInterfaceMessage
{