]> git.smokeofanarchy.ru Git - space-station-14.git/commitdiff
start of persistence support (#20770)
authordeltanedas <39013340+deltanedas@users.noreply.github.com>
Sun, 17 Dec 2023 03:55:19 +0000 (03:55 +0000)
committerGitHub <noreply@github.com>
Sun, 17 Dec 2023 03:55:19 +0000 (19:55 -0800)
Co-authored-by: deltanedas <@deltanedas:kde.org>
Content.Server/Administration/Commands/PersistenceSaveCommand.cs [new file with mode: 0644]
Content.Server/Maps/GameMapManager.cs
Content.Server/Maps/GameMapPrototype.cs
Content.Server/Station/Components/StationMemberComponent.cs
Content.Server/Station/Systems/StationSystem.cs
Content.Shared/CCVar/CCVars.cs
Resources/Locale/en-US/persistence/command.ftl [new file with mode: 0644]

diff --git a/Content.Server/Administration/Commands/PersistenceSaveCommand.cs b/Content.Server/Administration/Commands/PersistenceSaveCommand.cs
new file mode 100644 (file)
index 0000000..2684e85
--- /dev/null
@@ -0,0 +1,60 @@
+using Content.Server.GameTicking;
+using Content.Server.Ghost.Components;
+using Content.Server.Players;
+using Content.Shared.Administration;
+using Content.Shared.CCVar;
+using Content.Shared.Ghost;
+using Robust.Server.GameObjects;
+using Robust.Server.Player;
+using Robust.Shared.Configuration;
+using Robust.Shared.Console;
+using Robust.Shared.Map;
+using System.Linq;
+
+namespace Content.Server.Administration.Commands;
+
+[AdminCommand(AdminFlags.Server)]
+public sealed class PersistenceSave : IConsoleCommand
+{
+    [Dependency] private readonly IConfigurationManager _config = default!;
+    [Dependency] private readonly IEntityManager _entities = default!;
+    [Dependency] private readonly IEntitySystemManager _system = default!;
+    [Dependency] private readonly IMapManager _map = default!;
+
+    public string Command => "persistencesave";
+    public string Description => "Saves server data to a persistence file to be loaded later.";
+    public string Help => "persistencesave [mapId] [filePath - default: game.map (CCVar) ]";
+
+    public void Execute(IConsoleShell shell, string argStr, string[] args)
+    {
+        if (args.Length < 1 || args.Length > 2)
+        {
+            shell.WriteError(Loc.GetString("shell-wrong-arguments-number"));
+            return;
+        }
+
+        if (!int.TryParse(args[0], out var intMapId))
+        {
+            shell.WriteError(Loc.GetString("cmd-parse-failure-integer", ("arg", args[0])));
+            return;
+        }
+
+        var mapId = new MapId(intMapId);
+        if (!_map.MapExists(mapId))
+        {
+            shell.WriteError(Loc.GetString("cmd-savemap-not-exist"));
+            return;
+        }
+
+        var saveFilePath = (args.Length > 1 ? args[1] : null) ?? _config.GetCVar(CCVars.GameMap);
+        if (string.IsNullOrWhiteSpace(saveFilePath))
+        {
+            shell.WriteError(Loc.GetString("cmd-persistencesave-no-path", ("cvar", nameof(CCVars.GameMap))));
+            return;
+        }
+
+        var mapLoader = _system.GetEntitySystem<MapLoaderSystem>();
+        mapLoader.SaveMap(mapId, saveFilePath);
+        shell.WriteLine(Loc.GetString("cmd-savemap-success"));
+    }
+}
index 69f732151f8ef8b448726e3da17ce54a8188c9b8..9638dffaa7c4cf879419064b6cd49f0d2cf88cec 100644 (file)
@@ -5,8 +5,10 @@ using Content.Server.GameTicking;
 using Content.Shared.CCVar;
 using Robust.Server.Player;
 using Robust.Shared.Configuration;
+using Robust.Shared.ContentPack;
 using Robust.Shared.Prototypes;
 using Robust.Shared.Random;
+using Robust.Shared.Utility;
 
 namespace Content.Server.Maps;
 
@@ -16,6 +18,7 @@ public sealed class GameMapManager : IGameMapManager
     [Dependency] private readonly IPrototypeManager _prototypeManager = default!;
     [Dependency] private readonly IConfigurationManager _configurationManager = default!;
     [Dependency] private readonly IPlayerManager _playerManager = default!;
+    [Dependency] private readonly IResourceManager _resMan = default!;
     [Dependency] private readonly IRobustRandom _random = default!;
 
     [ViewVariables(VVAccess.ReadOnly)]
@@ -40,18 +43,34 @@ public sealed class GameMapManager : IGameMapManager
             if (TryLookupMap(value, out GameMapPrototype? map))
             {
                 _configSelectedMap = map;
+                return;
             }
-            else
+
+            if (string.IsNullOrEmpty(value))
             {
-                if (string.IsNullOrEmpty(value))
-                {
-                    _configSelectedMap = default!;
-                }
-                else
+                _configSelectedMap = default!;
+                return;
+            }
+
+            if (_configurationManager.GetCVar<bool>(CCVars.UsePersistence))
+            {
+                var startMap = _configurationManager.GetCVar<string>(CCVars.PersistenceMap);
+                _configSelectedMap = _prototypeManager.Index<GameMapPrototype>(startMap);
+
+                var mapPath = new ResPath(value);
+                if (_resMan.UserData.Exists(mapPath))
                 {
-                    _log.Error($"Unknown map prototype {value} was selected!");
+                    _configSelectedMap = _configSelectedMap.Persistence(mapPath);
+                    _log.Info($"Using persistence map from {value}");
+                    return;
                 }
+
+                // persistence save path doesn't exist so we just use the start map
+                _log.Warning($"Using persistence start map {startMap} as {value} doesn't exist");
+                return;
             }
+
+            _log.Error($"Unknown map prototype {value} was selected!");
         }, true);
         _configurationManager.OnValueChanged(CCVars.GameMapRotation, value => _mapRotationEnabled = value, true);
         _configurationManager.OnValueChanged(CCVars.GameMapMemoryDepth, value =>
index 837e838290a8d4035b967141f4da51e27162b2d5..bd15194495ecd498c807931731d3bd58e6eb1a0f 100644 (file)
@@ -40,4 +40,18 @@ public sealed partial class GameMapPrototype : IPrototype
     /// The stations this map contains. The names should match with the BecomesStation components.
     /// </summary>
     public IReadOnlyDictionary<string, StationConfig> Stations => _stations;
+
+    /// <summary>
+    /// Performs a shallow clone of this map prototype, replacing <c>MapPath</c> with the argument.
+    /// </summary>
+    public GameMapPrototype Persistence(ResPath mapPath)
+    {
+        return new()
+        {
+            ID = ID,
+            MapName = MapName,
+            MapPath = mapPath,
+            _stations = _stations
+        };
+    }
 }
index 7213d2549e5c6cbde050a147978cba76f7616a94..2100c20c55d338d79fba8a89e2975f878d05c1f3 100644 (file)
@@ -11,6 +11,6 @@ public sealed partial class StationMemberComponent : Component
     /// <summary>
     /// Station that this grid is a part of.
     /// </summary>
-    [ViewVariables]
+    [DataField]
     public EntityUid Station = EntityUid.Invalid;
 }
index 65eabd819006e139008268dc04bec3d3e20443e0..8f9e634c098dce7b0eeed6b685aba5f4cd0a6499 100644 (file)
@@ -331,7 +331,7 @@ public sealed class StationSystem : EntitySystem
         if (!string.IsNullOrEmpty(name))
             _metaData.SetEntityName(mapGrid, name);
 
-        var stationMember = AddComp<StationMemberComponent>(mapGrid);
+        var stationMember = EnsureComp<StationMemberComponent>(mapGrid);
         stationMember.Station = station;
         stationData.Grids.Add(mapGrid);
 
index b29e2273509b3597cdc0e9eb7356083527ddab4e..2e1589a7e9c1aea92f8b10dbcf1e4978bb3a665e 100644 (file)
@@ -179,6 +179,19 @@ namespace Content.Shared.CCVar
         public static readonly CVarDef<string>
             GameMap = CVarDef.Create("game.map", string.Empty, CVar.SERVERONLY);
 
+        /// <summary>
+        ///     Controls whether to use world persistence or not.
+        /// </summary>
+        public static readonly CVarDef<bool>
+            UsePersistence = CVarDef.Create("game.usepersistence", false, CVar.ARCHIVE);
+
+        /// <summary>
+        ///     If world persistence is used, what map prototype should be initially loaded.
+        ///     If the save file exists, it replaces MapPath but everything else stays the same (station name and such).
+        /// </summary>
+        public static readonly CVarDef<string>
+            PersistenceMap = CVarDef.Create("game.persistencemap", "Empty", CVar.ARCHIVE);
+
         /// <summary>
         ///     Prototype to use for map pool.
         /// </summary>
diff --git a/Resources/Locale/en-US/persistence/command.ftl b/Resources/Locale/en-US/persistence/command.ftl
new file mode 100644 (file)
index 0000000..b070aee
--- /dev/null
@@ -0,0 +1 @@
+cmd-persistencesave-no-path = filePath was not specified and CCVar {$cvar} is not set. Manually set the filePath param in order to save the map.