start of persistence support (#20770)
Co-authored-by: deltanedas <@deltanedas:kde.org>
This commit is contained in:
@@ -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"));
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
{
|
||||
_log.Error($"Unknown map prototype {value} was selected!");
|
||||
}
|
||||
_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))
|
||||
{
|
||||
_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 =>
|
||||
|
||||
@@ -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
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
1
Resources/Locale/en-US/persistence/command.ftl
Normal file
1
Resources/Locale/en-US/persistence/command.ftl
Normal file
@@ -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.
|
||||
Reference in New Issue
Block a user