Move some Station methods into shared (#38976)

This commit is contained in:
Nemanja
2025-08-08 11:22:34 -04:00
committed by GitHub
parent 3d9e1f64a9
commit 1374ceea47
41 changed files with 298 additions and 351 deletions

View File

@@ -76,7 +76,7 @@ public sealed partial class ObjectsTab : Control
switch (selection)
{
case ObjectsTabSelection.Stations:
entities.AddRange(_entityManager.EntitySysManager.GetEntitySystem<StationSystem>().Stations);
entities.AddRange(_entityManager.EntitySysManager.GetEntitySystem<StationSystem>().GetStationNames());
break;
case ObjectsTabSelection.Grids:
{

View File

@@ -2,34 +2,5 @@
namespace Content.Client.Station;
/// <summary>
/// This handles letting the client know stations are a thing. Only really used by an admin menu.
/// </summary>
public sealed partial class StationSystem : SharedStationSystem
{
private readonly List<(string Name, NetEntity Entity)> _stations = new();
/// <summary>
/// All stations that currently exist.
/// </summary>
/// <remarks>
/// I'd have this just invoke an entity query, but we're on the client and the client barely knows about stations.
/// </remarks>
// TODO: Stations have a global PVS override now, this can probably be changed into a query.
public IReadOnlyList<(string Name, NetEntity Entity)> Stations => _stations;
/// <inheritdoc/>
public override void Initialize()
{
base.Initialize();
SubscribeNetworkEvent<StationsUpdatedEvent>(StationsUpdated);
}
private void StationsUpdated(StationsUpdatedEvent ev)
{
_stations.Clear();
// TODO this needs to be done in component states and with the Ensure() methods
_stations.AddRange(ev.Stations);
}
}
/// <inheritdoc/>
public sealed partial class StationSystem : SharedStationSystem;

View File

@@ -2,9 +2,9 @@ using System.Linq;
using Content.Server.GameTicking;
using Content.Server.Shuttles.Components;
using Content.Server.Shuttles.Systems;
using Content.Server.Station.Components;
using Content.Shared.CCVar;
using Content.Shared.Shuttles.Components;
using Content.Shared.Station.Components;
using Robust.Shared.GameObjects;
using Robust.Shared.Map.Components;

View File

@@ -2,15 +2,12 @@ using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Numerics;
using Content.Server.Administration.Components;
using Content.Server.Atmos;
using Content.Server.Atmos.Components;
using Content.Server.Cargo.Components;
using Content.Server.Doors.Systems;
using Content.Server.Hands.Systems;
using Content.Server.Power.Components;
using Content.Server.Power.EntitySystems;
using Content.Server.Stack;
using Content.Server.Station.Components;
using Content.Server.Station.Systems;
using Content.Server.Weapons.Ranged.Systems;
using Content.Shared.Access;
@@ -28,6 +25,7 @@ using Content.Shared.Hands.Components;
using Content.Shared.Inventory;
using Content.Shared.PDA;
using Content.Shared.Stacks;
using Content.Shared.Station.Components;
using Content.Shared.Verbs;
using Content.Shared.Weapons.Ranged.Components;
using Robust.Server.Physics;

View File

@@ -1,6 +1,5 @@
using Content.Server.Anomaly.Components;
using Content.Server.Power.EntitySystems;
using Content.Server.Station.Components;
using Content.Shared.Anomaly;
using Content.Shared.CCVar;
using Content.Shared.Materials;
@@ -164,8 +163,7 @@ public sealed partial class AnomalySystem
var xform = Transform(uid);
if (_station.GetStationInMap(xform.MapID) is not { } station ||
!TryComp<StationDataComponent>(station, out var data) ||
_station.GetLargestGrid(data) is not { } grid)
_station.GetLargestGrid(station) is not { } grid)
{
if (xform.GridUid == null)
return;

View File

@@ -1,8 +1,8 @@
using System.Linq;
using Content.Server.Station.Components;
using Content.Shared.Cargo;
using Content.Shared.Cargo.Components;
using Content.Shared.Cargo.Prototypes;
using Content.Shared.Station.Components;
using Robust.Shared.Prototypes;
namespace Content.Server.Cargo.Components;

View File

@@ -1,7 +1,6 @@
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using Content.Server.Cargo.Components;
using Content.Server.Station.Components;
using Content.Shared.Cargo;
using Content.Shared.Cargo.BUI;
using Content.Shared.Cargo.Components;
@@ -13,8 +12,8 @@ using Content.Shared.IdentityManagement;
using Content.Shared.Interaction;
using Content.Shared.Labels.Components;
using Content.Shared.Paper;
using Content.Shared.Station.Components;
using JetBrains.Annotations;
using Robust.Shared.Audio;
using Robust.Shared.Map;
using Robust.Shared.Prototypes;
using Robust.Shared.Timing;

View File

@@ -3,11 +3,11 @@ using System.Linq;
using Content.Server.Cargo.Components;
using Content.Server.Power.Components;
using Content.Server.Power.EntitySystems;
using Content.Server.Station.Components;
using Content.Shared.Cargo;
using Content.Shared.Cargo.Components;
using Content.Shared.DeviceLinking;
using Content.Shared.Power;
using Content.Shared.Station.Components;
using Robust.Shared.Audio;
using Robust.Shared.Random;
using Robust.Shared.Utility;

View File

@@ -7,7 +7,6 @@ using Content.Server.Chat.Managers;
using Content.Server.GameTicking;
using Content.Server.Speech.EntitySystems;
using Content.Server.Speech.Prototypes;
using Content.Server.Station.Components;
using Content.Server.Station.Systems;
using Content.Shared.ActionBlocker;
using Content.Shared.Administration;
@@ -21,6 +20,7 @@ using Content.Shared.Mobs.Systems;
using Content.Shared.Players;
using Content.Shared.Players.RateLimiting;
using Content.Shared.Radio;
using Content.Shared.Station.Components;
using Content.Shared.Whitelist;
using Robust.Server.Player;
using Robust.Shared.Audio;

View File

@@ -1,4 +1,4 @@
using Content.Server.Station.Components;
using Content.Shared.Station.Components;
using Robust.Shared.Console;
namespace Content.Server.Commands;

View File

@@ -1,7 +1,6 @@
using System.Linq;
using Content.Server.Administration;
using Content.Server.EUI;
using Content.Server.Station.Components;
using Content.Server.Station.Systems;
using Content.Server.StationRecords;
using Content.Server.StationRecords.Systems;
@@ -10,12 +9,12 @@ using Content.Shared.CCVar;
using Content.Shared.CrewManifest;
using Content.Shared.GameTicking;
using Content.Shared.Roles;
using Content.Shared.Station.Components;
using Content.Shared.StationRecords;
using Robust.Shared.Configuration;
using Robust.Shared.Console;
using Robust.Shared.Player;
using Robust.Shared.Prototypes;
using Robust.Shared.Utility;
namespace Content.Server.CrewManifest;

View File

@@ -1,11 +1,8 @@
using Content.Server.Antag;
using Content.Server.Dragon;
using Content.Server.GameTicking.Rules.Components;
using Content.Server.Mind;
using Content.Server.Roles;
using Content.Server.Station.Components;
using Content.Server.Station.Systems;
using Content.Shared.CharacterInfo;
using Content.Shared.Localizations;
using Robust.Server.GameObjects;
@@ -56,10 +53,9 @@ public sealed class DragonRuleSystem : GameRuleSystem<DragonRuleComponent>
var dragonXform = Transform(dragon);
var station = _station.GetStationInMap(dragonXform.MapID);
EntityUid? stationGrid = null;
if (TryComp<StationDataComponent>(station, out var stationData))
stationGrid = _station.GetLargestGrid(stationData);
if (_station.GetStationInMap(dragonXform.MapID) is { } station)
stationGrid = _station.GetLargestGrid(station);
if (stationGrid is not null)
{

View File

@@ -1,14 +1,12 @@
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using Content.Server.GameTicking.Rules.Components;
using Content.Server.Station.Components;
using Content.Shared.GameTicking.Components;
using Content.Shared.Random.Helpers;
using Robust.Server.GameObjects;
using Content.Shared.Station.Components;
using Robust.Shared.Collections;
using Robust.Shared.Map;
using Robust.Shared.Map.Components;
using Robust.Shared.Random;
namespace Content.Server.GameTicking.Rules;

View File

@@ -24,6 +24,7 @@ using Robust.Shared.Map;
using Robust.Shared.Random;
using Robust.Shared.Utility;
using System.Linq;
using Content.Shared.Station.Components;
using Content.Shared.Store.Components;
using Robust.Shared.Prototypes;

View File

@@ -1,11 +1,10 @@
using System.Linq;
using Content.Server.GameTicking.Rules.Components;
using Content.Server.GameTicking.Rules.Components;
using Content.Server.Shuttles.Systems;
using Content.Server.Station.Components;
using Content.Server.Station.Events;
using Content.Shared.GameTicking.Components;
using Content.Shared.Station.Components;
using Content.Shared.Storage;
using Robust.Shared.Prototypes;
using Robust.Shared.Random;
namespace Content.Server.GameTicking.Rules;

View File

@@ -58,7 +58,7 @@ public abstract class BaseEntityReplaceVariationPassSystem<TEntComp, TGameRuleCo
Transform(newEnt).LocalRotation = rot;
}
Log.Debug($"Entity replacement took {stopwatch.Elapsed} with {Stations.GetTileCount(args.Station)} tiles");
Log.Debug($"Entity replacement took {stopwatch.Elapsed} with {Stations.GetTileCount(args.Station.AsNullable())} tiles");
}
private void QueueReplace(Entity<TransformComponent> ent, List<EntitySpawnEntry> replacements)

View File

@@ -9,7 +9,7 @@ public sealed class EntitySpawnVariationPassSystem : VariationPassSystem<EntityS
{
protected override void ApplyVariation(Entity<EntitySpawnVariationPassComponent> ent, ref StationVariationPassEvent args)
{
var totalTiles = Stations.GetTileCount(args.Station);
var totalTiles = Stations.GetTileCount(args.Station.AsNullable());
var dirtyMod = Random.NextGaussian(ent.Comp.TilesPerEntityAverage, ent.Comp.TilesPerEntityStdDev);
var trashTiles = Math.Max((int) (totalTiles * (1 / dirtyMod)), 0);

View File

@@ -15,7 +15,7 @@ public sealed class PuddleMessVariationPassSystem : VariationPassSystem<PuddleMe
protected override void ApplyVariation(Entity<PuddleMessVariationPassComponent> ent, ref StationVariationPassEvent args)
{
var totalTiles = Stations.GetTileCount(args.Station);
var totalTiles = Stations.GetTileCount(args.Station.AsNullable());
if (!_proto.TryIndex(ent.Comp.RandomPuddleSolutionFill, out var proto))
return;

View File

@@ -4,7 +4,6 @@ using Content.Server.GameTicking.Rules.Components;
using Content.Server.Popups;
using Content.Server.Roles;
using Content.Server.RoundEnd;
using Content.Server.Station.Components;
using Content.Server.Station.Systems;
using Content.Server.Zombies;
using Content.Shared.GameTicking.Components;
@@ -190,7 +189,7 @@ public sealed class ZombieRuleSystem : GameRuleSystem<ZombieRuleComponent>
{
foreach (var station in _station.GetStationsSet())
{
if (TryComp<StationDataComponent>(station, out var data) && _station.GetLargestGrid(data) is { } grid)
if (_station.GetLargestGrid(station) is { } grid)
stationGrids.Add(grid);
}
}

View File

@@ -1,9 +1,8 @@
using Content.Server.Station;
using JetBrains.Annotations;
using Robust.Shared.Prototypes;
using Robust.Shared.Utility;
using System.Diagnostics;
using System.Numerics;
using Content.Shared.Station;
namespace Content.Server.Maps;

View File

@@ -1,6 +1,6 @@
using Content.Server.Administration;
using Content.Server.Station.Components;
using Content.Shared.Administration;
using Content.Shared.Station.Components;
using Robust.Shared.Console;
namespace Content.Server.Nuke.Commands;

View File

@@ -2,9 +2,9 @@ using System.Diagnostics.CodeAnalysis;
using Content.Server.Chat.Systems;
using Content.Server.Fax;
using Content.Shared.Fax.Components;
using Content.Server.Station.Components;
using Content.Server.Station.Systems;
using Content.Shared.Paper;
using Content.Shared.Station.Components;
using Robust.Shared.Random;
using Robust.Shared.Utility;

View File

@@ -9,7 +9,6 @@ using Content.Server.GameTicking;
using Content.Server.Screens.Components;
using Content.Server.Shuttles.Components;
using Content.Server.Shuttles.Systems;
using Content.Server.Station.Components;
using Content.Server.Station.Systems;
using Content.Shared.Database;
using Content.Shared.DeviceNetwork;
@@ -20,6 +19,7 @@ using Robust.Shared.Player;
using Robust.Shared.Prototypes;
using Robust.Shared.Timing;
using Content.Shared.DeviceNetwork.Components;
using Content.Shared.Station.Components;
using Timer = Robust.Shared.Timing.Timer;
namespace Content.Server.RoundEnd
@@ -97,10 +97,10 @@ namespace Content.Server.RoundEnd
/// </summary>
public EntityUid? GetStation()
{
AllEntityQuery<StationEmergencyShuttleComponent, StationDataComponent>().MoveNext(out _, out _, out var data);
AllEntityQuery<StationEmergencyShuttleComponent, StationDataComponent>().MoveNext(out var uid, out _, out var data);
if (data == null)
return null;
var targetGrid = _stationSystem.GetLargestGrid(data);
var targetGrid = _stationSystem.GetLargestGrid((uid, data));
return targetGrid == null ? null : Transform(targetGrid.Value).MapUid;
}

View File

@@ -2,7 +2,6 @@ using System.Numerics;
using Content.Server.Salvage.Expeditions;
using Content.Server.Shuttles.Components;
using Content.Server.Shuttles.Events;
using Content.Server.Station.Components;
using Content.Shared.Chat;
using Content.Shared.Humanoid;
using Content.Shared.Mobs.Components;
@@ -10,6 +9,7 @@ using Content.Shared.Mobs.Systems;
using Content.Shared.Salvage.Expeditions;
using Content.Shared.Shuttles.Components;
using Content.Shared.Localizations;
using Content.Shared.Station.Components;
using Robust.Shared.Map.Components;
using Robust.Shared.Player;

View File

@@ -11,7 +11,6 @@ using Content.Server.Shuttles.Components;
using Content.Server.Shuttles.Events;
using Content.Server.Spawners.Components;
using Content.Server.Spawners.EntitySystems;
using Content.Server.Station.Components;
using Content.Server.Station.Events;
using Content.Server.Station.Systems;
using Content.Shared.Administration;
@@ -224,7 +223,7 @@ public sealed class ArrivalsSystem : EntitySystem
if (component.FirstRun)
{
var station = _station.GetLargestGrid(Comp<StationDataComponent>(component.Station));
var station = _station.GetLargestGrid(component.Station);
sourceMap = station == null ? null : Transform(station.Value)?.MapUid;
arrivalsDelay += RoundStartFTLDuration;
component.FirstRun = false;
@@ -470,7 +469,7 @@ public sealed class ArrivalsSystem : EntitySystem
{
while (query.MoveNext(out var uid, out var comp, out var shuttle, out var xform))
{
if (comp.NextTransfer > curTime || !TryComp<StationDataComponent>(comp.Station, out var data))
if (comp.NextTransfer > curTime)
continue;
var tripTime = _shuttles.DefaultTravelTime + _shuttles.DefaultStartupTime;
@@ -486,7 +485,7 @@ public sealed class ArrivalsSystem : EntitySystem
// Go to station
else
{
var targetGrid = _station.GetLargestGrid(data);
var targetGrid = _station.GetLargestGrid(comp.Station);
if (targetGrid != null)
_shuttles.FTLToDock(uid, shuttle, targetGrid.Value);

View File

@@ -14,7 +14,6 @@ using Content.Server.RoundEnd;
using Content.Server.Screens.Components;
using Content.Server.Shuttles.Components;
using Content.Server.Shuttles.Events;
using Content.Server.Station.Components;
using Content.Server.Station.Events;
using Content.Server.Station.Systems;
using Content.Shared.Access.Systems;
@@ -181,7 +180,7 @@ public sealed partial class EmergencyShuttleSystem : EntitySystem
return;
}
var targetGrid = _station.GetLargestGrid(Comp<StationDataComponent>(station.Value));
var targetGrid = _station.GetLargestGrid(station.Value);
if (targetGrid == null)
return;
@@ -270,7 +269,7 @@ public sealed partial class EmergencyShuttleSystem : EntitySystem
return null;
}
var targetGrid = _station.GetLargestGrid(Comp<StationDataComponent>(stationUid));
var targetGrid = _station.GetLargestGrid(stationUid);
// UHH GOOD LUCK
if (targetGrid == null)

View File

@@ -1,9 +1,7 @@
using System.Numerics;
using Content.Server.Shuttles.Components;
using Content.Server.Station.Components;
using Content.Server.Station.Events;
using Content.Shared.CCVar;
using Content.Shared.Salvage;
using Content.Shared.Shuttles.Components;
using Content.Shared.Station.Components;
using Robust.Shared.Collections;
@@ -62,10 +60,7 @@ public sealed partial class ShuttleSystem
if (!_cfg.GetCVar(CCVars.GridFill))
return;
if (!TryComp(uid, out StationDataComponent? dataComp))
return;
var targetGrid = _station.GetLargestGrid(dataComp);
var targetGrid = _station.GetLargestGrid(uid);
if (targetGrid == null)
return;
@@ -165,12 +160,7 @@ public sealed partial class ShuttleSystem
if (!_cfg.GetCVar(CCVars.GridFill))
return;
if (!TryComp<StationDataComponent>(uid, out var data))
{
return;
}
var targetGrid = _station.GetLargestGrid(data);
var targetGrid = _station.GetLargestGrid(uid);
if (targetGrid == null)
return;

View File

@@ -1,15 +1,13 @@
using System.Numerics;
using Content.Server.Administration.Logs;
using Content.Server.Singularity.Events;
using Content.Server.Station.Components;
using Content.Shared.Database;
using Content.Shared.Ghost;
using Content.Shared.Mind.Components;
using Content.Shared.Singularity.Components;
using Content.Shared.Singularity.EntitySystems;
using Content.Shared.Station.Components;
using Content.Shared.Tag;
using Robust.Shared.Containers;
using Robust.Shared.GameObjects;
using Robust.Shared.Map;
using Robust.Shared.Map.Components;
using Robust.Shared.Physics.Components;

View File

@@ -2,12 +2,12 @@ using System.Diagnostics;
using System.Linq;
using Content.Server.Administration;
using Content.Server.Cargo.Systems;
using Content.Server.Station.Components;
using Content.Server.Station.Systems;
using Content.Shared.Administration;
using Content.Shared.Station;
using Content.Shared.Station.Components;
using Robust.Shared.Toolshed;
using Robust.Shared.Toolshed.Errors;
using Robust.Shared.Toolshed.Syntax;
using Robust.Shared.Utility;
namespace Content.Server.Station.Commands;
@@ -54,7 +54,7 @@ public sealed class StationsCommand : ToolshedCommand
public EntityUid? LargestGrid([PipedArgument] EntityUid input)
{
_station ??= GetSys<StationSystem>();
return _station.GetLargestGrid(Comp<StationDataComponent>(input));
return _station.GetLargestGrid(input);
}
[CommandImplementation("largestgrid")]

View File

@@ -1,4 +1,4 @@
using Content.Server.Station.Components;
using Content.Shared.Station.Components;
namespace Content.Server.Station.Events;

View File

@@ -20,12 +20,10 @@ public sealed partial class StationBiomeSystem : EntitySystem
private void OnStationPostInit(Entity<StationBiomeComponent> map, ref StationPostInitEvent args)
{
if (!TryComp(map, out StationDataComponent? dataComp))
var station = _station.GetLargestGrid(map.Owner);
if (station == null)
return;
var station = _station.GetLargestGrid(dataComp);
if (station == null) return;
var mapId = Transform(station.Value).MapID;
var mapUid = _map.GetMapOrInvalid(mapId);

View File

@@ -1,4 +1,5 @@
using Content.Server.Station.Components;
using Content.Shared.Station.Components;
namespace Content.Server.Station.Systems;

View File

@@ -3,20 +3,16 @@ using Content.Server.Chat.Systems;
using Content.Server.GameTicking;
using Content.Server.Station.Components;
using Content.Server.Station.Events;
using Content.Shared.CCVar;
using Content.Shared.Station;
using Content.Shared.Station.Components;
using JetBrains.Annotations;
using Robust.Server.GameObjects;
using Robust.Server.GameStates;
using Robust.Server.Player;
using Robust.Shared.Collections;
using Robust.Shared.Configuration;
using Robust.Shared.Enums;
using Robust.Shared.Map;
using Robust.Shared.Map.Components;
using Robust.Shared.Player;
using Robust.Shared.Random;
using Robust.Shared.Utility;
namespace Content.Server.Station.Systems;
@@ -34,7 +30,6 @@ public sealed partial class StationSystem : SharedStationSystem
[Dependency] private readonly ChatSystem _chatSystem = default!;
[Dependency] private readonly SharedTransformSystem _transform = default!;
[Dependency] private readonly MetaDataSystem _metaData = default!;
[Dependency] private readonly MapSystem _map = default!;
[Dependency] private readonly PvsOverrideSystem _pvsOverride = default!;
private ISawmill _sawmill = default!;
@@ -42,8 +37,8 @@ public sealed partial class StationSystem : SharedStationSystem
private EntityQuery<MapGridComponent> _gridQuery;
private EntityQuery<TransformComponent> _xformQuery;
private ValueList<MapId> _mapIds = new();
private ValueList<(Box2Rotated Bounds, MapId MapId)> _gridBounds = new();
private ValueList<MapId> _mapIds;
private ValueList<(Box2Rotated Bounds, MapId MapId)> _gridBounds;
/// <inheritdoc/>
public override void Initialize()
@@ -79,6 +74,7 @@ public sealed partial class StationSystem : SharedStationSystem
return;
stationData.Grids.Remove(uid);
Dirty(uid, component);
}
public override void Shutdown()
@@ -193,44 +189,6 @@ public sealed partial class StationSystem : SharedStationSystem
#endregion Event handlers
/// <summary>
/// Gets the largest member grid from a station.
/// </summary>
public EntityUid? GetLargestGrid(StationDataComponent component)
{
EntityUid? largestGrid = null;
Box2 largestBounds = new Box2();
foreach (var gridUid in component.Grids)
{
if (!TryComp<MapGridComponent>(gridUid, out var grid) ||
grid.LocalAABB.Size.LengthSquared() < largestBounds.Size.LengthSquared())
continue;
largestBounds = grid.LocalAABB;
largestGrid = gridUid;
}
return largestGrid;
}
/// <summary>
/// Returns the total number of tiles contained in the station's grids.
/// </summary>
public int GetTileCount(StationDataComponent component)
{
var count = 0;
foreach (var gridUid in component.Grids)
{
if (!TryComp<MapGridComponent>(gridUid, out var grid))
continue;
count += _map.GetAllTiles(gridUid, grid).Count();
}
return count;
}
/// <summary>
/// Tries to retrieve a filter for everything in the station the source is on.
/// </summary>
@@ -384,6 +342,7 @@ public sealed partial class StationSystem : SharedStationSystem
var stationMember = EnsureComp<StationMemberComponent>(mapGrid);
stationMember.Station = station;
stationData.Grids.Add(mapGrid);
Dirty(station, stationData);
RaiseLocalEvent(station, new StationGridAddedEvent(mapGrid, station, false), true);
@@ -407,6 +366,7 @@ public sealed partial class StationSystem : SharedStationSystem
RemComp<StationMemberComponent>(mapGrid);
stationData.Grids.Remove(mapGrid);
Dirty(station, stationData);
RaiseLocalEvent(station, new StationGridRemovedEvent(mapGrid, station), true);
_sawmill.Info($"Removing grid {mapGrid} from station {Name(station)} ({station})");
@@ -450,110 +410,6 @@ public sealed partial class StationSystem : SharedStationSystem
QueueDel(station);
}
public EntityUid? GetOwningStation(EntityUid? entity, TransformComponent? xform = null)
{
if (entity == null)
return null;
return GetOwningStation(entity.Value, xform);
}
/// <summary>
/// Gets the station that "owns" the given entity (essentially, the station the grid it's on is attached to)
/// </summary>
/// <param name="entity">Entity to find the owner of.</param>
/// <param name="xform">Resolve pattern, transform of the entity.</param>
/// <returns>The owning station, if any.</returns>
/// <remarks>
/// This does not remember what station an entity started on, it simply checks where it is currently located.
/// </remarks>
public EntityUid? GetOwningStation(EntityUid entity, TransformComponent? xform = null)
{
if (!Resolve(entity, ref xform))
throw new ArgumentException("Tried to use an abstract entity!", nameof(entity));
if (TryComp<StationDataComponent>(entity, out _))
{
// We are the station, just return ourselves.
return entity;
}
if (TryComp<MapGridComponent>(entity, out _))
{
// We are the station, just check ourselves.
return CompOrNull<StationMemberComponent>(entity)?.Station;
}
if (xform.GridUid == EntityUid.Invalid)
{
Log.Debug("Unable to get owning station - GridUid invalid.");
return null;
}
return CompOrNull<StationMemberComponent>(xform.GridUid)?.Station;
}
public List<EntityUid> GetStations()
{
var stations = new List<EntityUid>();
var query = EntityQueryEnumerator<StationDataComponent>();
while (query.MoveNext(out var uid, out _))
{
stations.Add(uid);
}
return stations;
}
public HashSet<EntityUid> GetStationsSet()
{
var stations = new HashSet<EntityUid>();
var query = EntityQueryEnumerator<StationDataComponent>();
while (query.MoveNext(out var uid, out _))
{
stations.Add(uid);
}
return stations;
}
public List<(string Name, NetEntity Entity)> GetStationNames()
{
var stations = GetStationsSet();
var stats = new List<(string Name, NetEntity Station)>();
foreach (var weh in stations)
{
stats.Add((MetaData(weh).EntityName, GetNetEntity(weh)));
}
return stats;
}
/// <summary>
/// Returns the first station that has a grid in a certain map.
/// If the map has no stations, null is returned instead.
/// </summary>
/// <remarks>
/// If there are multiple stations on a map it is probably arbitrary which one is returned.
/// </remarks>
public EntityUid? GetStationInMap(MapId map)
{
var query = EntityQueryEnumerator<StationDataComponent>();
while (query.MoveNext(out var uid, out var data))
{
foreach (var gridUid in data.Grids)
{
if (Transform(gridUid).MapID == map)
{
return uid;
}
}
}
return null;
}
}
/// <summary>

View File

@@ -1,7 +1,7 @@
using Content.Server.Anomaly;
using Content.Server.Station.Components;
using Content.Server.StationEvents.Components;
using Content.Shared.GameTicking.Components;
using Content.Shared.GameTicking.Components;
using Content.Shared.Station.Components;
namespace Content.Server.StationEvents.Events;
@@ -31,7 +31,7 @@ public sealed class AnomalySpawnRule : StationEventSystem<AnomalySpawnRuleCompon
if (!TryComp<StationDataComponent>(chosenStation, out var stationData))
return;
var grid = StationSystem.GetLargestGrid(stationData);
var grid = StationSystem.GetLargestGrid((chosenStation.Value, stationData));
if (grid is null)
return;

View File

@@ -2,9 +2,9 @@ using System.Linq;
using Content.Server.Cargo.Components;
using Content.Server.Cargo.Systems;
using Content.Server.GameTicking;
using Content.Server.Station.Components;
using Content.Server.StationEvents.Components;
using Content.Shared.GameTicking.Components;
using Content.Shared.Station.Components;
using Robust.Shared.Prototypes;
namespace Content.Server.StationEvents.Events;

View File

@@ -1,7 +1,6 @@
using System.Numerics;
using Content.Server.Chat.Systems;
using Content.Server.GameTicking.Rules;
using Content.Server.Station.Components;
using Content.Server.Station.Systems;
using Content.Server.StationEvents.Components;
using Content.Shared.GameTicking.Components;
@@ -49,7 +48,7 @@ public sealed class MeteorSwarmSystem : GameRuleSystem<MeteorSwarmComponent>
return;
var station = RobustRandom.Pick(_station.GetStations());
if (_station.GetLargestGrid(Comp<StationDataComponent>(station)) is not { } grid)
if (_station.GetLargestGrid(station) is not { } grid)
return;
var mapId = Transform(grid).MapID;

View File

@@ -1,6 +1,4 @@
using Content.Server.Antag;
using Content.Server.GameTicking.Rules.Components;
using Content.Server.Station.Components;
using Content.Server.StationEvents.Components;
using Content.Shared.GameTicking.Components;
using Robust.Shared.Map;
@@ -32,10 +30,8 @@ public sealed class SpaceSpawnRule : StationEventSystem<SpaceSpawnRuleComponent>
return;
}
var stationData = Comp<StationDataComponent>(station.Value);
// find a station grid
var gridUid = StationSystem.GetLargestGrid(stationData);
var gridUid = StationSystem.GetLargestGrid(station.Value);
if (gridUid == null || !TryComp<MapGridComponent>(gridUid, out var grid))
{
Sawmill.Warning("Chosen station has no grids, cannot pick location for {ToPrettyString(uid):rule}");

View File

@@ -1,26 +1,23 @@
using Content.Server.Shuttles.Systems;
using Content.Server.Station.Systems;
using Robust.Shared.Serialization.TypeSerializers.Implementations;
using Robust.Shared.Utility;
using Robust.Shared.GameStates;
namespace Content.Server.Station.Components;
namespace Content.Shared.Station.Components;
/// <summary>
/// Stores core information about a station, namely its config and associated grids.
/// All station entities will have this component.
/// </summary>
[RegisterComponent, Access(typeof(StationSystem))]
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState, Access(typeof(SharedStationSystem))]
public sealed partial class StationDataComponent : Component
{
/// <summary>
/// The game map prototype, if any, associated with this station.
/// </summary>
[DataField("stationConfig")]
public StationConfig? StationConfig = null;
[DataField]
public StationConfig? StationConfig;
/// <summary>
/// List of all grids this station is part of.
/// </summary>
[DataField("grids")]
[DataField, AutoNetworkedField]
public HashSet<EntityUid> Grids = new();
}

View File

@@ -0,0 +1,88 @@
using Content.Shared.Station.Components;
using JetBrains.Annotations;
using Robust.Shared.Map;
namespace Content.Shared.Station;
public abstract partial class SharedStationSystem
{
private void InitializeTracker()
{
SubscribeLocalEvent<StationTrackerComponent, MapInitEvent>(OnTrackerMapInit);
SubscribeLocalEvent<StationTrackerComponent, ComponentRemove>(OnTrackerRemove);
SubscribeLocalEvent<StationTrackerComponent, GridUidChangedEvent>(OnTrackerGridChanged);
SubscribeLocalEvent<StationTrackerComponent, MetaFlagRemoveAttemptEvent>(OnMetaFlagRemoveAttempt);
}
private void OnTrackerMapInit(Entity<StationTrackerComponent> ent, ref MapInitEvent args)
{
_meta.AddFlag(ent, MetaDataFlags.ExtraTransformEvents);
UpdateStationTracker(ent.AsNullable());
}
private void OnTrackerRemove(Entity<StationTrackerComponent> ent, ref ComponentRemove args)
{
_meta.RemoveFlag(ent, MetaDataFlags.ExtraTransformEvents);
}
private void OnTrackerGridChanged(Entity<StationTrackerComponent> ent, ref GridUidChangedEvent args)
{
UpdateStationTracker((ent, ent.Comp, args.Transform));
}
private void OnMetaFlagRemoveAttempt(Entity<StationTrackerComponent> ent, ref MetaFlagRemoveAttemptEvent args)
{
if ((args.ToRemove & MetaDataFlags.ExtraTransformEvents) != 0 &&
ent.Comp.LifeStage <= ComponentLifeStage.Running)
{
args.ToRemove &= ~MetaDataFlags.ExtraTransformEvents;
}
}
/// <summary>
/// Updates the station tracker component based on entity's current location.
/// </summary>
[PublicAPI]
public void UpdateStationTracker(Entity<StationTrackerComponent?, TransformComponent?> ent)
{
if (!Resolve(ent, ref ent.Comp1))
return;
var xform = ent.Comp2;
if (!_xformQuery.Resolve(ent, ref xform))
return;
// Entity is in nullspace or not on a grid
if (xform.MapID == MapId.Nullspace || xform.GridUid == null)
{
SetStation(ent, null);
return;
}
// Check if the grid is part of a station
if (!_stationMemberQuery.TryGetComponent(xform.GridUid.Value, out var stationMember))
{
SetStation(ent, null);
return;
}
SetStation(ent, stationMember.Station);
}
/// <summary>
/// Sets the station for a StationTrackerComponent.
/// </summary>
[PublicAPI]
public void SetStation(Entity<StationTrackerComponent?> ent, EntityUid? station)
{
if (!Resolve(ent, ref ent.Comp))
return;
if (ent.Comp.Station == station)
return;
ent.Comp.Station = station;
Dirty(ent);
}
}

View File

@@ -1,11 +1,14 @@
using System.Linq;
using Content.Shared.Station.Components;
using JetBrains.Annotations;
using Robust.Shared.Map;
using Robust.Shared.Map.Components;
namespace Content.Shared.Station;
public abstract partial class SharedStationSystem : EntitySystem
{
[Dependency] private readonly SharedMapSystem _map = default!;
[Dependency] private readonly MetaDataSystem _meta = default!;
private EntityQuery<TransformComponent> _xformQuery;
@@ -16,96 +19,164 @@ public abstract partial class SharedStationSystem : EntitySystem
{
base.Initialize();
InitializeTracker();
_xformQuery = GetEntityQuery<TransformComponent>();
_stationMemberQuery = GetEntityQuery<StationMemberComponent>();
SubscribeLocalEvent<StationTrackerComponent, MapInitEvent>(OnTrackerMapInit);
SubscribeLocalEvent<StationTrackerComponent, ComponentRemove>(OnTrackerRemove);
SubscribeLocalEvent<StationTrackerComponent, GridUidChangedEvent>(OnTrackerGridChanged);
SubscribeLocalEvent<StationTrackerComponent, MetaFlagRemoveAttemptEvent>(OnMetaFlagRemoveAttempt);
}
private void OnTrackerMapInit(Entity<StationTrackerComponent> ent, ref MapInitEvent args)
{
_meta.AddFlag(ent, MetaDataFlags.ExtraTransformEvents);
UpdateStationTracker(ent.AsNullable());
}
private void OnTrackerRemove(Entity<StationTrackerComponent> ent, ref ComponentRemove args)
{
_meta.RemoveFlag(ent, MetaDataFlags.ExtraTransformEvents);
}
private void OnTrackerGridChanged(Entity<StationTrackerComponent> ent, ref GridUidChangedEvent args)
{
UpdateStationTracker((ent, ent.Comp, args.Transform));
}
private void OnMetaFlagRemoveAttempt(Entity<StationTrackerComponent> ent, ref MetaFlagRemoveAttemptEvent args)
{
if ((args.ToRemove & MetaDataFlags.ExtraTransformEvents) != 0 &&
ent.Comp.LifeStage <= ComponentLifeStage.Running)
{
args.ToRemove &= ~MetaDataFlags.ExtraTransformEvents;
}
}
/// <summary>
/// Updates the station tracker component based on entity's current location.
/// Gets the largest member grid from a station.
/// </summary>
[PublicAPI]
public void UpdateStationTracker(Entity<StationTrackerComponent?, TransformComponent?> ent)
{
if (!Resolve(ent, ref ent.Comp1))
return;
var xform = ent.Comp2;
if (!_xformQuery.Resolve(ent, ref xform))
return;
// Entity is in nullspace or not on a grid
if (xform.MapID == MapId.Nullspace || xform.GridUid == null)
{
SetStation(ent, null);
return;
}
// Check if the grid is part of a station
if (!_stationMemberQuery.TryGetComponent(xform.GridUid.Value, out var stationMember))
{
SetStation(ent, null);
return;
}
SetStation(ent, stationMember.Station);
}
/// <summary>
/// Sets the station for a StationTrackerComponent.
/// </summary>
[PublicAPI]
public void SetStation(Entity<StationTrackerComponent?> ent, EntityUid? station)
public EntityUid? GetLargestGrid(Entity<StationDataComponent?> ent)
{
if (!Resolve(ent, ref ent.Comp))
return;
return null;
if (ent.Comp.Station == station)
return;
EntityUid? largestGrid = null;
Box2 largestBounds = new Box2();
ent.Comp.Station = station;
Dirty(ent);
foreach (var gridUid in ent.Comp.Grids)
{
if (!TryComp<MapGridComponent>(gridUid, out var grid) ||
grid.LocalAABB.Size.LengthSquared() < largestBounds.Size.LengthSquared())
continue;
largestBounds = grid.LocalAABB;
largestGrid = gridUid;
}
return largestGrid;
}
/// <summary>
/// Gets the station an entity is currently on, if any.
/// Returns the total number of tiles contained in the station's grids.
/// </summary>
[PublicAPI]
public EntityUid? GetCurrentStation(Entity<StationTrackerComponent?> ent)
public int GetTileCount(Entity<StationDataComponent?> ent)
{
if (!Resolve(ent, ref ent.Comp, logMissing: false))
if (!Resolve(ent, ref ent.Comp))
return 0;
var count = 0;
foreach (var gridUid in ent.Comp.Grids)
{
if (!TryComp<MapGridComponent>(gridUid, out var grid))
continue;
count += _map.GetAllTiles(gridUid, grid).Count();
}
return count;
}
[PublicAPI]
public EntityUid? GetOwningStation(EntityUid? entity, TransformComponent? xform = null)
{
if (entity == null)
return null;
return ent.Comp.Station;
return GetOwningStation(entity.Value, xform);
}
/// <summary>
/// Gets the station that "owns" the given entity (essentially, the station the grid it's on is attached to)
/// </summary>
/// <param name="entity">Entity to find the owner of.</param>
/// <param name="xform">Resolve pattern, transform of the entity.</param>
/// <returns>The owning station, if any.</returns>
/// <remarks>
/// This does not remember what station an entity started on, it simply checks where it is currently located.
/// </remarks>
public EntityUid? GetOwningStation(EntityUid entity, TransformComponent? xform = null)
{
if (!Resolve(entity, ref xform))
throw new ArgumentException("Tried to use an abstract entity!", nameof(entity));
if (TryComp<StationTrackerComponent>(entity, out var stationTracker))
{
// We have a specific station we are tracking and are tethered to.
return stationTracker.Station;
}
if (HasComp<StationDataComponent>(entity))
{
// We are the station, just return ourselves.
return entity;
}
if (HasComp<MapGridComponent>(entity))
{
// We are the station, just check ourselves.
return CompOrNull<StationMemberComponent>(entity)?.Station;
}
if (xform.GridUid == EntityUid.Invalid)
{
Log.Debug("Unable to get owning station - GridUid invalid.");
return null;
}
return CompOrNull<StationMemberComponent>(xform.GridUid)?.Station;
}
public List<EntityUid> GetStations()
{
var stations = new List<EntityUid>();
var query = EntityQueryEnumerator<StationDataComponent>();
while (query.MoveNext(out var uid, out _))
{
stations.Add(uid);
}
return stations;
}
public HashSet<EntityUid> GetStationsSet()
{
var stations = new HashSet<EntityUid>();
var query = EntityQueryEnumerator<StationDataComponent>();
while (query.MoveNext(out var uid, out _))
{
stations.Add(uid);
}
return stations;
}
public List<(string Name, NetEntity Entity)> GetStationNames()
{
var stations = GetStationsSet();
var stats = new List<(string Name, NetEntity Station)>();
foreach (var weh in stations)
{
stats.Add((MetaData(weh).EntityName, GetNetEntity(weh)));
}
return stats;
}
/// <summary>
/// Returns the first station that has a grid in a certain map.
/// If the map has no stations, null is returned instead.
/// </summary>
/// <remarks>
/// If there are multiple stations on a map it is probably arbitrary which one is returned.
/// </remarks>
public EntityUid? GetStationInMap(MapId map)
{
var query = EntityQueryEnumerator<StationDataComponent>();
while (query.MoveNext(out var uid, out var data))
{
foreach (var gridUid in data.Grids)
{
if (Transform(gridUid).MapID == map)
{
return uid;
}
}
}
return null;
}
}

View File

@@ -1,17 +1,15 @@
using Content.Server.Maps.NameGenerators;
using JetBrains.Annotations;
using Robust.Shared.Prototypes;
using Robust.Shared.Prototypes;
namespace Content.Server.Station;
namespace Content.Shared.Station;
/// <summary>
/// A config for a station. Specifies name and component modifications.
/// </summary>
[DataDefinition, PublicAPI]
[DataDefinition]
public sealed partial class StationConfig
{
[DataField("stationProto", required: true)]
public string StationPrototype = default!;
public EntProtoId StationPrototype;
[DataField("components", required: true)]
public ComponentRegistry StationComponentOverrides = default!;