diff --git a/Content.Server/Administration/AdminCommandAttribute.cs b/Content.Server/Administration/AdminCommandAttribute.cs
index 0c9730df82..b7e17c9c4d 100644
--- a/Content.Server/Administration/AdminCommandAttribute.cs
+++ b/Content.Server/Administration/AdminCommandAttribute.cs
@@ -12,7 +12,7 @@ namespace Content.Server.Administration
/// If this attribute is used multiple times, either attribute's flag sets can be used to get access.
///
///
- [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
+ [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true)]
[BaseTypeRequired(typeof(IConsoleCommand))]
[MeansImplicitUse]
public sealed class AdminCommandAttribute : Attribute
diff --git a/Content.Server/Administration/Managers/AdminManager.cs b/Content.Server/Administration/Managers/AdminManager.cs
index cd88ac315f..c554750371 100644
--- a/Content.Server/Administration/Managers/AdminManager.cs
+++ b/Content.Server/Administration/Managers/AdminManager.cs
@@ -436,7 +436,13 @@ namespace Content.Server.Administration.Managers
private static (bool isAvail, AdminFlags[] flagsReq) GetRequiredFlag(IConsoleCommand cmd)
{
- var type = cmd.GetType();
+ MemberInfo type = cmd.GetType();
+
+ if (cmd is ConsoleHost.RegisteredCommand registered)
+ {
+ type = registered.Callback.Method;
+ }
+
if (Attribute.IsDefined(type, typeof(AnyCommandAttribute)))
{
// Available to everybody.
diff --git a/Content.Server/Atmos/Commands/FixGridAtmos.cs b/Content.Server/Atmos/Commands/FixGridAtmos.cs
deleted file mode 100644
index b0a6fee2ac..0000000000
--- a/Content.Server/Atmos/Commands/FixGridAtmos.cs
+++ /dev/null
@@ -1,103 +0,0 @@
-using Content.Server.Administration;
-using Content.Server.Atmos.EntitySystems;
-using Content.Server.Atmos.Components;
-using Content.Shared.Administration;
-using Content.Shared.Atmos;
-using Content.Shared.Tag;
-using Robust.Shared.Console;
-using Robust.Shared.GameObjects;
-using Robust.Shared.IoC;
-using Robust.Shared.Map;
-
-namespace Content.Server.Atmos.Commands
-{
- [AdminCommand(AdminFlags.Debug)]
- public class FixGridAtmos : IConsoleCommand
- {
- public string Command => "fixgridatmos";
- public string Description => "Makes every tile on a grid have a roundstart gas mix.";
- public string Help => $"{Command} ";
- public void Execute(IConsoleShell shell, string argStr, string[] args)
- {
- if (args.Length == 0)
- {
- shell.WriteError("Not enough arguments.");
- return;
- }
-
- var mapManager = IoCManager.Resolve();
- var entityManager = IoCManager.Resolve();
- var atmosphereSystem = EntitySystem.Get();
-
- var mixtures = new GasMixture[6];
- for (var i = 0; i < mixtures.Length; i++)
- mixtures[i] = new GasMixture(Atmospherics.CellVolume) { Temperature = Atmospherics.T20C };
-
- // 0: Air
- mixtures[0].AdjustMoles(Gas.Oxygen, Atmospherics.OxygenMolesStandard);
- mixtures[0].AdjustMoles(Gas.Nitrogen, Atmospherics.NitrogenMolesStandard);
-
- // 1: Vaccum
-
- // 2: Oxygen (GM)
- mixtures[2].AdjustMoles(Gas.Oxygen, Atmospherics.MolesCellGasMiner);
-
- // 3: Nitrogen (GM)
- mixtures[3].AdjustMoles(Gas.Nitrogen, Atmospherics.MolesCellGasMiner);
-
- // 4: Plasma (GM)
- mixtures[4].AdjustMoles(Gas.Plasma, Atmospherics.MolesCellGasMiner);
-
- // 5: Instant Plasmafire (r)
- mixtures[5].AdjustMoles(Gas.Oxygen, Atmospherics.MolesCellGasMiner);
- mixtures[5].AdjustMoles(Gas.Plasma, Atmospherics.MolesCellGasMiner);
- mixtures[5].Temperature = 5000f;
-
- foreach (var gid in args)
- {
- // I like offering detailed error messages, that's why I don't use one of the extension methods.
- if (!int.TryParse(gid, out var i) || i <= 0)
- {
- shell.WriteError($"Invalid grid ID \"{gid}\".");
- continue;
- }
-
- var gridId = new GridId(i);
-
- if (!mapManager.TryGetGrid(gridId, out var mapGrid))
- {
- shell.WriteError($"Grid \"{i}\" doesn't exist.");
- continue;
- }
-
- if (!entityManager.TryGetComponent(mapGrid.GridEntityId, out GridAtmosphereComponent? gridAtmosphere))
- {
- shell.WriteError($"Grid \"{i}\" has no atmosphere component, try addatmos.");
- continue;
- }
-
- foreach (var (indices, tileMain) in gridAtmosphere.Tiles)
- {
- var tile = tileMain.Air;
- if (tile == null)
- continue;
-
- tile.Clear();
- var mixtureId = 0;
- foreach (var entUid in mapGrid.GetAnchoredEntities(indices))
- {
- if (!entityManager.TryGetComponent(entUid, out AtmosFixMarkerComponent? afm))
- continue;
- mixtureId = afm.Mode;
- break;
- }
- var mixture = mixtures[mixtureId];
- atmosphereSystem.Merge(tile, mixture);
- tile.Temperature = mixture.Temperature;
-
- atmosphereSystem.InvalidateTile(gridAtmosphere, indices);
- }
- }
- }
- }
-}
diff --git a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Commands.cs b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Commands.cs
new file mode 100644
index 0000000000..9219aa3a1b
--- /dev/null
+++ b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Commands.cs
@@ -0,0 +1,107 @@
+using Content.Server.Administration;
+using Content.Server.Atmos.Components;
+using Content.Shared.Administration;
+using Content.Shared.Atmos;
+using Robust.Shared.Console;
+using Robust.Shared.IoC;
+using Robust.Shared.Map;
+
+namespace Content.Server.Atmos.EntitySystems;
+
+public partial class AtmosphereSystem
+{
+ [Dependency] private readonly IConsoleHost _consoleHost = default!;
+
+ private void InitializeCommands()
+ {
+ // Fix Grid Atmos command.
+ _consoleHost.RegisterCommand("fixgridatmos",
+ "Makes every tile on a grid have a roundstart gas mix.",
+ "fixgridatmos ", FixGridAtmosCommand);
+ }
+
+ private void ShutdownCommands()
+ {
+ _consoleHost.UnregisterCommand("fixgridatmos");
+ }
+
+ [AdminCommand(AdminFlags.Debug)]
+ private void FixGridAtmosCommand(IConsoleShell shell, string argstr, string[] args)
+ {
+ if (args.Length == 0)
+ {
+ shell.WriteError("Not enough arguments.");
+ return;
+ }
+
+ var mixtures = new GasMixture[6];
+ for (var i = 0; i < mixtures.Length; i++)
+ mixtures[i] = new GasMixture(Atmospherics.CellVolume) { Temperature = Atmospherics.T20C };
+
+ // 0: Air
+ mixtures[0].AdjustMoles(Gas.Oxygen, Atmospherics.OxygenMolesStandard);
+ mixtures[0].AdjustMoles(Gas.Nitrogen, Atmospherics.NitrogenMolesStandard);
+
+ // 1: Vaccum
+
+ // 2: Oxygen (GM)
+ mixtures[2].AdjustMoles(Gas.Oxygen, Atmospherics.MolesCellGasMiner);
+
+ // 3: Nitrogen (GM)
+ mixtures[3].AdjustMoles(Gas.Nitrogen, Atmospherics.MolesCellGasMiner);
+
+ // 4: Plasma (GM)
+ mixtures[4].AdjustMoles(Gas.Plasma, Atmospherics.MolesCellGasMiner);
+
+ // 5: Instant Plasmafire (r)
+ mixtures[5].AdjustMoles(Gas.Oxygen, Atmospherics.MolesCellGasMiner);
+ mixtures[5].AdjustMoles(Gas.Plasma, Atmospherics.MolesCellGasMiner);
+ mixtures[5].Temperature = 5000f;
+
+ foreach (var gid in args)
+ {
+ // I like offering detailed error messages, that's why I don't use one of the extension methods.
+ if (!int.TryParse(gid, out var i) || i <= 0)
+ {
+ shell.WriteError($"Invalid grid ID \"{gid}\".");
+ continue;
+ }
+
+ var gridId = new GridId(i);
+
+ if (!_mapManager.TryGetGrid(gridId, out var mapGrid))
+ {
+ shell.WriteError($"Grid \"{i}\" doesn't exist.");
+ continue;
+ }
+
+ if (!TryComp(mapGrid.GridEntityId, out GridAtmosphereComponent? gridAtmosphere))
+ {
+ shell.WriteError($"Grid \"{i}\" has no atmosphere component, try addatmos.");
+ continue;
+ }
+
+ foreach (var (indices, tileMain) in gridAtmosphere.Tiles)
+ {
+ var tile = tileMain.Air;
+ if (tile == null)
+ continue;
+
+ tile.Clear();
+ var mixtureId = 0;
+ foreach (var entUid in mapGrid.GetAnchoredEntities(indices))
+ {
+ if (!TryComp(entUid, out AtmosFixMarkerComponent? afm))
+ continue;
+ mixtureId = afm.Mode;
+ break;
+ }
+ var mixture = mixtures[mixtureId];
+ Merge(tile, mixture);
+ tile.Temperature = mixture.Temperature;
+
+ InvalidateTile(gridAtmosphere, indices);
+ }
+ }
+ }
+}
diff --git a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.cs b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.cs
index ad497a64ec..0231049cde 100644
--- a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.cs
+++ b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.cs
@@ -1,11 +1,15 @@
+using Content.Server.Administration;
using Content.Server.Administration.Logs;
using Content.Server.Atmos.Components;
+using Content.Server.Database;
using Content.Server.NodeContainer.EntitySystems;
using Content.Server.Temperature.Components;
using Content.Server.Temperature.Systems;
+using Content.Shared.Administration;
using Content.Shared.Atmos.EntitySystems;
using Content.Shared.Maps;
using JetBrains.Annotations;
+using Robust.Shared.Console;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.Map;
@@ -31,6 +35,7 @@ namespace Content.Server.Atmos.EntitySystems
UpdatesAfter.Add(typeof(NodeGroupSystem));
InitializeGases();
+ InitializeCommands();
InitializeCVars();
InitializeGrid();
@@ -47,6 +52,8 @@ namespace Content.Server.Atmos.EntitySystems
base.Shutdown();
_mapManager.TileChanged -= OnTileChanged;
+
+ ShutdownCommands();
}
private void OnTileChanged(object? sender, TileChangedEventArgs eventArgs)
diff --git a/Content.Shared/Administration/AnyCommandAttribute.cs b/Content.Shared/Administration/AnyCommandAttribute.cs
index 426389b4e3..a98ec7da95 100644
--- a/Content.Shared/Administration/AnyCommandAttribute.cs
+++ b/Content.Shared/Administration/AnyCommandAttribute.cs
@@ -7,7 +7,7 @@ namespace Content.Shared.Administration
///
/// Specifies that a command can be executed by any player.
///
- [AttributeUsage(AttributeTargets.Class)]
+ [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
[BaseTypeRequired(typeof(IConsoleCommand))]
[MeansImplicitUse]
public sealed class AnyCommandAttribute : Attribute