Refactor map loading & saving (#34020)
This commit is contained in:
@@ -9,13 +9,14 @@ using Content.IntegrationTests.Pair;
|
||||
using Content.Shared.Clothing.Components;
|
||||
using Content.Shared.Doors.Components;
|
||||
using Content.Shared.Item;
|
||||
using Robust.Server.GameObjects;
|
||||
using Robust.Shared;
|
||||
using Robust.Shared.Analyzers;
|
||||
using Robust.Shared.EntitySerialization;
|
||||
using Robust.Shared.EntitySerialization.Systems;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Map.Components;
|
||||
using Robust.Shared.Random;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Benchmarks;
|
||||
|
||||
@@ -32,7 +33,6 @@ public class ComponentQueryBenchmark
|
||||
|
||||
private TestPair _pair = default!;
|
||||
private IEntityManager _entMan = default!;
|
||||
private MapId _mapId = new(10);
|
||||
private EntityQuery<ItemComponent> _itemQuery;
|
||||
private EntityQuery<ClothingComponent> _clothingQuery;
|
||||
private EntityQuery<MapComponent> _mapQuery;
|
||||
@@ -54,10 +54,10 @@ public class ComponentQueryBenchmark
|
||||
_pair.Server.ResolveDependency<IRobustRandom>().SetSeed(42);
|
||||
_pair.Server.WaitPost(() =>
|
||||
{
|
||||
var success = _entMan.System<MapLoaderSystem>().TryLoad(_mapId, Map, out _);
|
||||
if (!success)
|
||||
var map = new ResPath(Map);
|
||||
var opts = DeserializationOptions.Default with {InitializeMaps = true};
|
||||
if (!_entMan.System<MapLoaderSystem>().TryLoadMap(map, out _, out _, opts))
|
||||
throw new Exception("Map load failed");
|
||||
_pair.Server.MapMan.DoMapInitialize(_mapId);
|
||||
}).GetAwaiter().GetResult();
|
||||
|
||||
_items = new EntityUid[_entMan.Count<ItemComponent>()];
|
||||
|
||||
@@ -6,12 +6,13 @@ using BenchmarkDotNet.Attributes;
|
||||
using Content.IntegrationTests;
|
||||
using Content.IntegrationTests.Pair;
|
||||
using Content.Server.Maps;
|
||||
using Robust.Server.GameObjects;
|
||||
using Robust.Shared;
|
||||
using Robust.Shared.Analyzers;
|
||||
using Robust.Shared.EntitySerialization.Systems;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Benchmarks;
|
||||
|
||||
@@ -20,7 +21,7 @@ public class MapLoadBenchmark
|
||||
{
|
||||
private TestPair _pair = default!;
|
||||
private MapLoaderSystem _mapLoader = default!;
|
||||
private IMapManager _mapManager = default!;
|
||||
private SharedMapSystem _mapSys = default!;
|
||||
|
||||
[GlobalSetup]
|
||||
public void Setup()
|
||||
@@ -36,7 +37,7 @@ public class MapLoadBenchmark
|
||||
.ToDictionary(x => x.ID, x => x.MapPath.ToString());
|
||||
|
||||
_mapLoader = server.ResolveDependency<IEntitySystemManager>().GetEntitySystem<MapLoaderSystem>();
|
||||
_mapManager = server.ResolveDependency<IMapManager>();
|
||||
_mapSys = server.ResolveDependency<IEntitySystemManager>().GetEntitySystem<SharedMapSystem>();
|
||||
}
|
||||
|
||||
[GlobalCleanup]
|
||||
@@ -52,17 +53,19 @@ public class MapLoadBenchmark
|
||||
public string Map;
|
||||
|
||||
public Dictionary<string, string> Paths;
|
||||
private MapId _mapId;
|
||||
|
||||
[Benchmark]
|
||||
public async Task LoadMap()
|
||||
{
|
||||
var mapPath = Paths[Map];
|
||||
var mapPath = new ResPath(Paths[Map]);
|
||||
var server = _pair.Server;
|
||||
await server.WaitPost(() =>
|
||||
{
|
||||
var success = _mapLoader.TryLoad(new MapId(10), mapPath, out _);
|
||||
var success = _mapLoader.TryLoadMap(mapPath, out var map, out _);
|
||||
if (!success)
|
||||
throw new Exception("Map load failed");
|
||||
_mapId = map.Value.Comp.MapId;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -70,9 +73,7 @@ public class MapLoadBenchmark
|
||||
public void IterationCleanup()
|
||||
{
|
||||
var server = _pair.Server;
|
||||
server.WaitPost(() =>
|
||||
{
|
||||
_mapManager.DeleteMap(new MapId(10));
|
||||
}).Wait();
|
||||
server.WaitPost(() => _mapSys.DeleteMap(_mapId))
|
||||
.Wait();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,13 +7,15 @@ using Content.IntegrationTests;
|
||||
using Content.IntegrationTests.Pair;
|
||||
using Content.Server.Mind;
|
||||
using Content.Server.Warps;
|
||||
using Robust.Server.GameObjects;
|
||||
using Robust.Shared;
|
||||
using Robust.Shared.Analyzers;
|
||||
using Robust.Shared.EntitySerialization;
|
||||
using Robust.Shared.EntitySerialization.Systems;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Player;
|
||||
using Robust.Shared.Random;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Benchmarks;
|
||||
|
||||
@@ -34,7 +36,6 @@ public class PvsBenchmark
|
||||
|
||||
private TestPair _pair = default!;
|
||||
private IEntityManager _entMan = default!;
|
||||
private MapId _mapId = new(10);
|
||||
private ICommonSession[] _players = default!;
|
||||
private EntityCoordinates[] _spawns = default!;
|
||||
public int _cycleOffset = 0;
|
||||
@@ -65,10 +66,10 @@ public class PvsBenchmark
|
||||
_pair.Server.ResolveDependency<IRobustRandom>().SetSeed(42);
|
||||
await _pair.Server.WaitPost(() =>
|
||||
{
|
||||
var success = _entMan.System<MapLoaderSystem>().TryLoad(_mapId, Map, out _);
|
||||
if (!success)
|
||||
var path = new ResPath(Map);
|
||||
var opts = DeserializationOptions.Default with {InitializeMaps = true};
|
||||
if (!_entMan.System<MapLoaderSystem>().TryLoadMap(path, out _, out _, opts))
|
||||
throw new Exception("Map load failed");
|
||||
_pair.Server.MapMan.DoMapInitialize(_mapId);
|
||||
});
|
||||
|
||||
// Get list of ghost warp positions
|
||||
|
||||
@@ -11,6 +11,8 @@ using Robust.Shared.Map;
|
||||
using Robust.Shared.Map.Components;
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
using Robust.Shared.EntitySerialization.Systems;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.IntegrationTests.Tests.Body
|
||||
{
|
||||
@@ -57,7 +59,6 @@ namespace Content.IntegrationTests.Tests.Body
|
||||
|
||||
await server.WaitIdleAsync();
|
||||
|
||||
var mapManager = server.ResolveDependency<IMapManager>();
|
||||
var entityManager = server.ResolveDependency<IEntityManager>();
|
||||
var mapLoader = entityManager.System<MapLoaderSystem>();
|
||||
var mapSys = entityManager.System<SharedMapSystem>();
|
||||
@@ -69,17 +70,13 @@ namespace Content.IntegrationTests.Tests.Body
|
||||
GridAtmosphereComponent relevantAtmos = default;
|
||||
var startingMoles = 0.0f;
|
||||
|
||||
var testMapName = "Maps/Test/Breathing/3by3-20oxy-80nit.yml";
|
||||
var testMapName = new ResPath("Maps/Test/Breathing/3by3-20oxy-80nit.yml");
|
||||
|
||||
await server.WaitPost(() =>
|
||||
{
|
||||
mapSys.CreateMap(out var mapId);
|
||||
Assert.That(mapLoader.TryLoad(mapId, testMapName, out var roots));
|
||||
|
||||
var query = entityManager.GetEntityQuery<MapGridComponent>();
|
||||
var grids = roots.Where(x => query.HasComponent(x));
|
||||
Assert.That(grids, Is.Not.Empty);
|
||||
grid = grids.First();
|
||||
Assert.That(mapLoader.TryLoadGrid(mapId, testMapName, out var gridEnt));
|
||||
grid = gridEnt!.Value.Owner;
|
||||
});
|
||||
|
||||
Assert.That(grid, Is.Not.Null, $"Test blueprint {testMapName} not found.");
|
||||
@@ -148,18 +145,13 @@ namespace Content.IntegrationTests.Tests.Body
|
||||
RespiratorComponent respirator = null;
|
||||
EntityUid human = default;
|
||||
|
||||
var testMapName = "Maps/Test/Breathing/3by3-20oxy-80nit.yml";
|
||||
var testMapName = new ResPath("Maps/Test/Breathing/3by3-20oxy-80nit.yml");
|
||||
|
||||
await server.WaitPost(() =>
|
||||
{
|
||||
mapSys.CreateMap(out var mapId);
|
||||
|
||||
Assert.That(mapLoader.TryLoad(mapId, testMapName, out var ents), Is.True);
|
||||
var query = entityManager.GetEntityQuery<MapGridComponent>();
|
||||
grid = ents
|
||||
.Select<EntityUid, EntityUid?>(x => x)
|
||||
.FirstOrDefault((uid) => uid.HasValue && query.HasComponent(uid.Value), null);
|
||||
Assert.That(grid, Is.Not.Null);
|
||||
Assert.That(mapLoader.TryLoadGrid(mapId, testMapName, out var gridEnt));
|
||||
grid = gridEnt!.Value.Owner;
|
||||
});
|
||||
|
||||
Assert.That(grid, Is.Not.Null, $"Test blueprint {testMapName} not found.");
|
||||
|
||||
@@ -2,10 +2,11 @@
|
||||
using System.Linq;
|
||||
using Content.Shared.Body.Components;
|
||||
using Content.Shared.Body.Systems;
|
||||
using Robust.Server.GameObjects;
|
||||
using Robust.Shared.Containers;
|
||||
using Robust.Shared.EntitySerialization.Systems;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.IntegrationTests.Tests.Body;
|
||||
|
||||
@@ -111,13 +112,12 @@ public sealed class SaveLoadReparentTest
|
||||
Is.Not.Empty
|
||||
);
|
||||
|
||||
const string mapPath = $"/{nameof(SaveLoadReparentTest)}{nameof(Test)}map.yml";
|
||||
var mapPath = new ResPath($"/{nameof(SaveLoadReparentTest)}{nameof(Test)}map.yml");
|
||||
|
||||
mapLoader.SaveMap(mapId, mapPath);
|
||||
maps.DeleteMap(mapId);
|
||||
Assert.That(mapLoader.TrySaveMap(mapId, mapPath));
|
||||
mapSys.DeleteMap(mapId);
|
||||
|
||||
mapSys.CreateMap(out mapId);
|
||||
Assert.That(mapLoader.TryLoad(mapId, mapPath, out _), Is.True);
|
||||
Assert.That(mapLoader.TryLoadMap(mapPath, out var map, out _), Is.True);
|
||||
|
||||
var query = EnumerateQueryEnumerator(
|
||||
entities.EntityQueryEnumerator<BodyComponent>()
|
||||
@@ -173,7 +173,7 @@ public sealed class SaveLoadReparentTest
|
||||
});
|
||||
}
|
||||
|
||||
maps.DeleteMap(mapId);
|
||||
entities.DeleteEntity(map);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#nullable enable
|
||||
using Robust.Shared.Console;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Map;
|
||||
|
||||
namespace Content.IntegrationTests.Tests.Minds;
|
||||
@@ -37,8 +38,8 @@ public sealed partial class MindTests
|
||||
Assert.That(pair.Client.EntMan.EntityCount, Is.EqualTo(0));
|
||||
|
||||
// Create a new map.
|
||||
int mapId = 1;
|
||||
await pair.Server.WaitPost(() => conHost.ExecuteCommand($"addmap {mapId}"));
|
||||
MapId mapId = default;
|
||||
await pair.Server.WaitPost(() => pair.Server.System<SharedMapSystem>().CreateMap(out mapId));
|
||||
await pair.RunTicksSync(5);
|
||||
|
||||
// Client is not attached to anything
|
||||
@@ -54,7 +55,7 @@ public sealed partial class MindTests
|
||||
Assert.That(pair.Client.EntMan.EntityExists(pair.Client.AttachedEntity));
|
||||
Assert.That(pair.Server.EntMan.EntityExists(pair.PlayerData?.Mind));
|
||||
var xform = pair.Client.Transform(pair.Client.AttachedEntity!.Value);
|
||||
Assert.That(xform.MapID, Is.EqualTo(new MapId(mapId)));
|
||||
Assert.That(xform.MapID, Is.EqualTo(mapId));
|
||||
|
||||
await pair.CleanReturnAsync();
|
||||
}
|
||||
|
||||
@@ -9,7 +9,6 @@ using Content.Server.Spawners.Components;
|
||||
using Content.Server.Station.Components;
|
||||
using Content.Shared.CCVar;
|
||||
using Content.Shared.Roles;
|
||||
using Robust.Server.GameObjects;
|
||||
using Robust.Shared.Configuration;
|
||||
using Robust.Shared.ContentPack;
|
||||
using Robust.Shared.GameObjects;
|
||||
@@ -17,6 +16,9 @@ using Robust.Shared.Map;
|
||||
using Robust.Shared.Map.Components;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Content.Shared.Station.Components;
|
||||
using Robust.Shared.EntitySerialization;
|
||||
using Robust.Shared.EntitySerialization.Systems;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Utility;
|
||||
using YamlDotNet.RepresentationModel;
|
||||
|
||||
@@ -36,10 +38,7 @@ namespace Content.IntegrationTests.Tests
|
||||
|
||||
private static readonly string[] Grids =
|
||||
{
|
||||
"/Maps/centcomm.yml",
|
||||
"/Maps/Shuttles/cargo.yml",
|
||||
"/Maps/Shuttles/emergency.yml",
|
||||
"/Maps/Shuttles/infiltrator.yml",
|
||||
"/Maps/centcomm.yml"
|
||||
};
|
||||
|
||||
private static readonly string[] GameMaps =
|
||||
@@ -81,33 +80,72 @@ namespace Content.IntegrationTests.Tests
|
||||
var entManager = server.ResolveDependency<IEntityManager>();
|
||||
var mapLoader = entManager.System<MapLoaderSystem>();
|
||||
var mapSystem = entManager.System<SharedMapSystem>();
|
||||
var mapManager = server.ResolveDependency<IMapManager>();
|
||||
var cfg = server.ResolveDependency<IConfigurationManager>();
|
||||
Assert.That(cfg.GetCVar(CCVars.GridFill), Is.False);
|
||||
var path = new ResPath(mapFile);
|
||||
|
||||
await server.WaitPost(() =>
|
||||
{
|
||||
mapSystem.CreateMap(out var mapId);
|
||||
try
|
||||
{
|
||||
#pragma warning disable NUnit2045
|
||||
Assert.That(mapLoader.TryLoad(mapId, mapFile, out var roots));
|
||||
Assert.That(roots.Where(uid => entManager.HasComponent<MapGridComponent>(uid)), Is.Not.Empty);
|
||||
#pragma warning restore NUnit2045
|
||||
Assert.That(mapLoader.TryLoadGrid(mapId, path, out var grid));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new Exception($"Failed to load map {mapFile}, was it saved as a map instead of a grid?", ex);
|
||||
}
|
||||
|
||||
mapSystem.DeleteMap(mapId);
|
||||
});
|
||||
await server.WaitRunTicks(1);
|
||||
|
||||
await pair.CleanReturnAsync();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Asserts that shuttles are loadable and have been saved as grids and not maps.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public async Task ShuttlesLoadableTest()
|
||||
{
|
||||
await using var pair = await PoolManager.GetServerClient();
|
||||
var server = pair.Server;
|
||||
|
||||
var entManager = server.ResolveDependency<IEntityManager>();
|
||||
var resMan = server.ResolveDependency<IResourceManager>();
|
||||
var mapLoader = entManager.System<MapLoaderSystem>();
|
||||
var mapSystem = entManager.System<SharedMapSystem>();
|
||||
var cfg = server.ResolveDependency<IConfigurationManager>();
|
||||
Assert.That(cfg.GetCVar(CCVars.GridFill), Is.False);
|
||||
|
||||
var shuttleFolder = new ResPath("/Maps/Shuttles");
|
||||
var shuttles = resMan
|
||||
.ContentFindFiles(shuttleFolder)
|
||||
.Where(filePath =>
|
||||
filePath.Extension == "yml" && !filePath.Filename.StartsWith(".", StringComparison.Ordinal))
|
||||
.ToArray();
|
||||
|
||||
await server.WaitPost(() =>
|
||||
{
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
foreach (var path in shuttles)
|
||||
{
|
||||
mapSystem.CreateMap(out var mapId);
|
||||
try
|
||||
{
|
||||
mapManager.DeleteMap(mapId);
|
||||
Assert.That(mapLoader.TryLoadGrid(mapId, path, out _),
|
||||
$"Failed to load shuttle {path}, was it saved as a map instead of a grid?");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new Exception($"Failed to delete map {mapFile}", ex);
|
||||
throw new Exception($"Failed to load shuttle {path}, was it saved as a map instead of a grid?",
|
||||
ex);
|
||||
}
|
||||
mapSystem.DeleteMap(mapId);
|
||||
}
|
||||
});
|
||||
});
|
||||
await server.WaitRunTicks(1);
|
||||
|
||||
@@ -121,12 +159,15 @@ namespace Content.IntegrationTests.Tests
|
||||
var server = pair.Server;
|
||||
|
||||
var resourceManager = server.ResolveDependency<IResourceManager>();
|
||||
var loader = server.System<MapLoaderSystem>();
|
||||
|
||||
var mapFolder = new ResPath("/Maps");
|
||||
var maps = resourceManager
|
||||
.ContentFindFiles(mapFolder)
|
||||
.Where(filePath => filePath.Extension == "yml" && !filePath.Filename.StartsWith(".", StringComparison.Ordinal))
|
||||
.ToArray();
|
||||
|
||||
var v7Maps = new List<ResPath>();
|
||||
foreach (var map in maps)
|
||||
{
|
||||
var rootedPath = map.ToRootedPath();
|
||||
@@ -149,13 +190,69 @@ namespace Content.IntegrationTests.Tests
|
||||
|
||||
var root = yamlStream.Documents[0].RootNode;
|
||||
var meta = root["meta"];
|
||||
var postMapInit = meta["postmapinit"].AsBool();
|
||||
var version = meta["format"].AsInt();
|
||||
|
||||
if (version >= 7)
|
||||
{
|
||||
v7Maps.Add(map);
|
||||
continue;
|
||||
}
|
||||
|
||||
var postMapInit = meta["postmapinit"].AsBool();
|
||||
Assert.That(postMapInit, Is.False, $"Map {map.Filename} was saved postmapinit");
|
||||
}
|
||||
|
||||
var deps = server.ResolveDependency<IEntitySystemManager>().DependencyCollection;
|
||||
foreach (var map in v7Maps)
|
||||
{
|
||||
Assert.That(IsPreInit(map, loader, deps));
|
||||
}
|
||||
|
||||
// Check that the test actually does manage to catch post-init maps and isn't just blindly passing everything.
|
||||
// To that end, create a new post-init map and try verify it.
|
||||
var mapSys = server.System<SharedMapSystem>();
|
||||
MapId id = default;
|
||||
await server.WaitPost(() => mapSys.CreateMap(out id, runMapInit: false));
|
||||
await server.WaitPost(() => server.EntMan.Spawn(null, new MapCoordinates(0, 0, id)));
|
||||
|
||||
// First check that a pre-init version passes
|
||||
var path = new ResPath($"{nameof(NoSavedPostMapInitTest)}.yml");
|
||||
Assert.That(loader.TrySaveMap(id, path));
|
||||
Assert.That(IsPreInit(path, loader, deps));
|
||||
|
||||
// and the post-init version fails.
|
||||
await server.WaitPost(() => mapSys.InitializeMap(id));
|
||||
Assert.That(loader.TrySaveMap(id, path));
|
||||
Assert.That(IsPreInit(path, loader, deps), Is.False);
|
||||
|
||||
await pair.CleanReturnAsync();
|
||||
}
|
||||
|
||||
private bool IsPreInit(ResPath map, MapLoaderSystem loader, IDependencyCollection deps)
|
||||
{
|
||||
if (!loader.TryReadFile(map, out var data))
|
||||
{
|
||||
Assert.Fail($"Failed to read {map}");
|
||||
return false;
|
||||
}
|
||||
|
||||
var reader = new EntityDeserializer(deps, data, DeserializationOptions.Default);
|
||||
if (!reader.TryProcessData())
|
||||
{
|
||||
Assert.Fail($"Failed to process {map}");
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach (var mapId in reader.MapYamlIds)
|
||||
{
|
||||
var mapData = reader.YamlEntities[mapId];
|
||||
if (mapData.PostInit)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
[Test, TestCaseSource(nameof(GameMaps))]
|
||||
public async Task GameMapsLoadableTest(string mapProto)
|
||||
{
|
||||
@@ -172,16 +269,16 @@ namespace Content.IntegrationTests.Tests
|
||||
var protoManager = server.ResolveDependency<IPrototypeManager>();
|
||||
var ticker = entManager.EntitySysManager.GetEntitySystem<GameTicker>();
|
||||
var shuttleSystem = entManager.EntitySysManager.GetEntitySystem<ShuttleSystem>();
|
||||
var xformQuery = entManager.GetEntityQuery<TransformComponent>();
|
||||
var cfg = server.ResolveDependency<IConfigurationManager>();
|
||||
Assert.That(cfg.GetCVar(CCVars.GridFill), Is.False);
|
||||
|
||||
await server.WaitPost(() =>
|
||||
{
|
||||
mapSystem.CreateMap(out var mapId);
|
||||
MapId mapId;
|
||||
try
|
||||
{
|
||||
ticker.LoadGameMap(protoManager.Index<GameMapPrototype>(mapProto), mapId, null);
|
||||
var opts = DeserializationOptions.Default with {InitializeMaps = true};
|
||||
ticker.LoadGameMap(protoManager.Index<GameMapPrototype>(mapProto), out mapId, opts);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -218,21 +315,17 @@ namespace Content.IntegrationTests.Tests
|
||||
if (entManager.TryGetComponent<StationEmergencyShuttleComponent>(station, out var stationEvac))
|
||||
{
|
||||
var shuttlePath = stationEvac.EmergencyShuttlePath;
|
||||
#pragma warning disable NUnit2045
|
||||
Assert.That(mapLoader.TryLoad(shuttleMap, shuttlePath.ToString(), out var roots));
|
||||
EntityUid shuttle = default!;
|
||||
Assert.DoesNotThrow(() =>
|
||||
{
|
||||
shuttle = roots.First(uid => entManager.HasComponent<MapGridComponent>(uid));
|
||||
}, $"Failed to load {shuttlePath}");
|
||||
Assert.That(mapLoader.TryLoadGrid(shuttleMap, shuttlePath, out var shuttle),
|
||||
$"Failed to load {shuttlePath}");
|
||||
|
||||
Assert.That(
|
||||
shuttleSystem.TryFTLDock(shuttle,
|
||||
entManager.GetComponent<ShuttleComponent>(shuttle), targetGrid.Value),
|
||||
shuttleSystem.TryFTLDock(shuttle!.Value.Owner,
|
||||
entManager.GetComponent<ShuttleComponent>(shuttle!.Value.Owner),
|
||||
targetGrid.Value),
|
||||
$"Unable to dock {shuttlePath} to {mapProto}");
|
||||
#pragma warning restore NUnit2045
|
||||
}
|
||||
|
||||
mapManager.DeleteMap(shuttleMap);
|
||||
mapSystem.DeleteMap(shuttleMap);
|
||||
|
||||
if (entManager.HasComponent<StationJobsComponent>(station))
|
||||
{
|
||||
@@ -269,7 +362,7 @@ namespace Content.IntegrationTests.Tests
|
||||
|
||||
try
|
||||
{
|
||||
mapManager.DeleteMap(mapId);
|
||||
mapSystem.DeleteMap(mapId);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -333,11 +426,9 @@ namespace Content.IntegrationTests.Tests
|
||||
var server = pair.Server;
|
||||
|
||||
var mapLoader = server.ResolveDependency<IEntitySystemManager>().GetEntitySystem<MapLoaderSystem>();
|
||||
var mapManager = server.ResolveDependency<IMapManager>();
|
||||
var resourceManager = server.ResolveDependency<IResourceManager>();
|
||||
var protoManager = server.ResolveDependency<IPrototypeManager>();
|
||||
var cfg = server.ResolveDependency<IConfigurationManager>();
|
||||
var mapSystem = server.System<SharedMapSystem>();
|
||||
Assert.That(cfg.GetCVar(CCVars.GridFill), Is.False);
|
||||
|
||||
var gameMaps = protoManager.EnumeratePrototypes<GameMapPrototype>().Select(o => o.MapPath).ToHashSet();
|
||||
@@ -348,7 +439,7 @@ namespace Content.IntegrationTests.Tests
|
||||
.Where(filePath => filePath.Extension == "yml" && !filePath.Filename.StartsWith(".", StringComparison.Ordinal))
|
||||
.ToArray();
|
||||
|
||||
var mapNames = new List<string>();
|
||||
var mapPaths = new List<ResPath>();
|
||||
foreach (var map in maps)
|
||||
{
|
||||
if (gameMaps.Contains(map))
|
||||
@@ -359,32 +450,46 @@ namespace Content.IntegrationTests.Tests
|
||||
{
|
||||
continue;
|
||||
}
|
||||
mapNames.Add(rootedPath.ToString());
|
||||
mapPaths.Add(rootedPath);
|
||||
}
|
||||
|
||||
await server.WaitPost(() =>
|
||||
{
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
foreach (var mapName in mapNames)
|
||||
// This bunch of files contains a random mixture of both map and grid files.
|
||||
// TODO MAPPING organize files
|
||||
var opts = MapLoadOptions.Default with
|
||||
{
|
||||
DeserializationOptions = DeserializationOptions.Default with
|
||||
{
|
||||
InitializeMaps = true,
|
||||
LogOrphanedGrids = false
|
||||
}
|
||||
};
|
||||
|
||||
HashSet<Entity<MapComponent>> maps;
|
||||
foreach (var path in mapPaths)
|
||||
{
|
||||
mapSystem.CreateMap(out var mapId);
|
||||
try
|
||||
{
|
||||
Assert.That(mapLoader.TryLoad(mapId, mapName, out _));
|
||||
Assert.That(mapLoader.TryLoadGeneric(path, out maps, out _, opts));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new Exception($"Failed to load map {mapName}", ex);
|
||||
throw new Exception($"Failed to load map {path}", ex);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
mapManager.DeleteMap(mapId);
|
||||
foreach (var map in maps)
|
||||
{
|
||||
server.EntMan.DeleteEntity(map);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new Exception($"Failed to delete map {mapName}", ex);
|
||||
throw new Exception($"Failed to delete map {path}", ex);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1,11 +1,8 @@
|
||||
using System.Linq;
|
||||
using Content.Shared.CCVar;
|
||||
using Content.Shared.CCVar;
|
||||
using Content.Shared.Salvage;
|
||||
using Robust.Server.GameObjects;
|
||||
using Robust.Shared.Configuration;
|
||||
using Robust.Shared.EntitySerialization.Systems;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Map.Components;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.IntegrationTests.Tests;
|
||||
@@ -24,7 +21,6 @@ public sealed class SalvageTest
|
||||
|
||||
var entManager = server.ResolveDependency<IEntityManager>();
|
||||
var mapLoader = entManager.System<MapLoaderSystem>();
|
||||
var mapManager = server.ResolveDependency<IMapManager>();
|
||||
var prototypeManager = server.ResolveDependency<IPrototypeManager>();
|
||||
var cfg = server.ResolveDependency<IConfigurationManager>();
|
||||
var mapSystem = entManager.System<SharedMapSystem>();
|
||||
@@ -34,13 +30,10 @@ public sealed class SalvageTest
|
||||
{
|
||||
foreach (var salvage in prototypeManager.EnumeratePrototypes<SalvageMapPrototype>())
|
||||
{
|
||||
var mapFile = salvage.MapPath;
|
||||
|
||||
mapSystem.CreateMap(out var mapId);
|
||||
try
|
||||
{
|
||||
Assert.That(mapLoader.TryLoad(mapId, mapFile.ToString(), out var roots));
|
||||
Assert.That(roots.Where(uid => entManager.HasComponent<MapGridComponent>(uid)), Is.Not.Empty);
|
||||
Assert.That(mapLoader.TryLoadGrid(mapId, salvage.MapPath, out var grid));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -49,7 +42,7 @@ public sealed class SalvageTest
|
||||
|
||||
try
|
||||
{
|
||||
mapManager.DeleteMap(mapId);
|
||||
mapSystem.DeleteMap(mapId);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
||||
@@ -3,6 +3,7 @@ using Content.Shared.CCVar;
|
||||
using Robust.Server.GameObjects;
|
||||
using Robust.Shared.Configuration;
|
||||
using Robust.Shared.ContentPack;
|
||||
using Robust.Shared.EntitySerialization.Systems;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Maths;
|
||||
@@ -16,7 +17,7 @@ namespace Content.IntegrationTests.Tests
|
||||
[Test]
|
||||
public async Task SaveLoadMultiGridMap()
|
||||
{
|
||||
const string mapPath = @"/Maps/Test/TestMap.yml";
|
||||
var mapPath = new ResPath("/Maps/Test/TestMap.yml");
|
||||
|
||||
await using var pair = await PoolManager.GetServerClient();
|
||||
var server = pair.Server;
|
||||
@@ -31,7 +32,7 @@ namespace Content.IntegrationTests.Tests
|
||||
|
||||
await server.WaitAssertion(() =>
|
||||
{
|
||||
var dir = new ResPath(mapPath).Directory;
|
||||
var dir = mapPath.Directory;
|
||||
resManager.UserData.CreateDir(dir);
|
||||
|
||||
mapSystem.CreateMap(out var mapId);
|
||||
@@ -47,15 +48,17 @@ namespace Content.IntegrationTests.Tests
|
||||
mapSystem.SetTile(mapGrid, new Vector2i(0, 0), new Tile(typeId: 2, flags: 1, variant: 254));
|
||||
}
|
||||
|
||||
Assert.Multiple(() => mapLoader.SaveMap(mapId, mapPath));
|
||||
Assert.Multiple(() => mapManager.DeleteMap(mapId));
|
||||
Assert.That(mapLoader.TrySaveMap(mapId, mapPath));
|
||||
mapSystem.DeleteMap(mapId);
|
||||
});
|
||||
|
||||
await server.WaitIdleAsync();
|
||||
|
||||
MapId newMap = default;
|
||||
await server.WaitAssertion(() =>
|
||||
{
|
||||
Assert.That(mapLoader.TryLoad(new MapId(10), mapPath, out _));
|
||||
Assert.That(mapLoader.TryLoadMap(mapPath, out var map, out _));
|
||||
newMap = map!.Value.Comp.MapId;
|
||||
});
|
||||
|
||||
await server.WaitIdleAsync();
|
||||
@@ -63,7 +66,7 @@ namespace Content.IntegrationTests.Tests
|
||||
await server.WaitAssertion(() =>
|
||||
{
|
||||
{
|
||||
if (!mapManager.TryFindGridAt(new MapId(10), new Vector2(10, 10), out var gridUid, out var mapGrid) ||
|
||||
if (!mapManager.TryFindGridAt(newMap, new Vector2(10, 10), out var gridUid, out var mapGrid) ||
|
||||
!sEntities.TryGetComponent<TransformComponent>(gridUid, out var gridXform))
|
||||
{
|
||||
Assert.Fail();
|
||||
@@ -77,7 +80,7 @@ namespace Content.IntegrationTests.Tests
|
||||
});
|
||||
}
|
||||
{
|
||||
if (!mapManager.TryFindGridAt(new MapId(10), new Vector2(-8, -8), out var gridUid, out var mapGrid) ||
|
||||
if (!mapManager.TryFindGridAt(newMap, new Vector2(-8, -8), out var gridUid, out var mapGrid) ||
|
||||
!sEntities.TryGetComponent<TransformComponent>(gridUid, out var gridXform))
|
||||
{
|
||||
Assert.Fail();
|
||||
|
||||
@@ -1,25 +1,25 @@
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Content.Shared.CCVar;
|
||||
using Robust.Server.GameObjects;
|
||||
using Robust.Server.Maps;
|
||||
using Robust.Shared.Configuration;
|
||||
using Robust.Shared.ContentPack;
|
||||
using Robust.Shared.EntitySerialization.Systems;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Map.Components;
|
||||
using Robust.Shared.Map.Events;
|
||||
using Robust.Shared.Serialization.Markdown.Mapping;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.IntegrationTests.Tests
|
||||
{
|
||||
/// <summary>
|
||||
/// Tests that a map's yaml does not change when saved consecutively.
|
||||
/// Tests that a grid's yaml does not change when saved consecutively.
|
||||
/// </summary>
|
||||
[TestFixture]
|
||||
public sealed class SaveLoadSaveTest
|
||||
{
|
||||
[Test]
|
||||
public async Task SaveLoadSave()
|
||||
public async Task CreateSaveLoadSaveGrid()
|
||||
{
|
||||
await using var pair = await PoolManager.GetServerClient();
|
||||
var server = pair.Server;
|
||||
@@ -30,22 +30,21 @@ namespace Content.IntegrationTests.Tests
|
||||
var cfg = server.ResolveDependency<IConfigurationManager>();
|
||||
Assert.That(cfg.GetCVar(CCVars.GridFill), Is.False);
|
||||
|
||||
var testSystem = server.System<SaveLoadSaveTestSystem>();
|
||||
testSystem.Enabled = true;
|
||||
|
||||
var rp1 = new ResPath("/save load save 1.yml");
|
||||
var rp2 = new ResPath("/save load save 2.yml");
|
||||
|
||||
await server.WaitPost(() =>
|
||||
{
|
||||
mapSystem.CreateMap(out var mapId0);
|
||||
// TODO: Properly find the "main" station grid.
|
||||
var grid0 = mapManager.CreateGridEntity(mapId0);
|
||||
mapLoader.Save(grid0.Owner, "save load save 1.yml");
|
||||
entManager.RunMapInit(grid0.Owner, entManager.GetComponent<MetaDataComponent>(grid0));
|
||||
Assert.That(mapLoader.TrySaveGrid(grid0.Owner, rp1));
|
||||
mapSystem.CreateMap(out var mapId1);
|
||||
EntityUid grid1 = default!;
|
||||
#pragma warning disable NUnit2045
|
||||
Assert.That(mapLoader.TryLoad(mapId1, "save load save 1.yml", out var roots, new MapLoadOptions() { LoadMap = false }), $"Failed to load test map {TestMap}");
|
||||
Assert.DoesNotThrow(() =>
|
||||
{
|
||||
grid1 = roots.First(uid => entManager.HasComponent<MapGridComponent>(uid));
|
||||
});
|
||||
#pragma warning restore NUnit2045
|
||||
mapLoader.Save(grid1, "save load save 2.yml");
|
||||
Assert.That(mapLoader.TryLoadGrid(mapId1, rp1, out var grid1));
|
||||
Assert.That(mapLoader.TrySaveGrid(grid1!.Value, rp2));
|
||||
});
|
||||
|
||||
await server.WaitIdleAsync();
|
||||
@@ -54,14 +53,12 @@ namespace Content.IntegrationTests.Tests
|
||||
string one;
|
||||
string two;
|
||||
|
||||
var rp1 = new ResPath("/save load save 1.yml");
|
||||
await using (var stream = userData.Open(rp1, FileMode.Open))
|
||||
using (var reader = new StreamReader(stream))
|
||||
{
|
||||
one = await reader.ReadToEndAsync();
|
||||
}
|
||||
|
||||
var rp2 = new ResPath("/save load save 2.yml");
|
||||
await using (var stream = userData.Open(rp2, FileMode.Open))
|
||||
using (var reader = new StreamReader(stream))
|
||||
{
|
||||
@@ -87,6 +84,7 @@ namespace Content.IntegrationTests.Tests
|
||||
TestContext.Error.WriteLine(twoTmp);
|
||||
}
|
||||
});
|
||||
testSystem.Enabled = false;
|
||||
await pair.CleanReturnAsync();
|
||||
}
|
||||
|
||||
@@ -101,8 +99,12 @@ namespace Content.IntegrationTests.Tests
|
||||
await using var pair = await PoolManager.GetServerClient();
|
||||
var server = pair.Server;
|
||||
var mapLoader = server.ResolveDependency<IEntitySystemManager>().GetEntitySystem<MapLoaderSystem>();
|
||||
var mapManager = server.ResolveDependency<IMapManager>();
|
||||
var mapSystem = server.System<SharedMapSystem>();
|
||||
var mapSys = server.System<SharedMapSystem>();
|
||||
var testSystem = server.System<SaveLoadSaveTestSystem>();
|
||||
testSystem.Enabled = true;
|
||||
|
||||
var rp1 = new ResPath("/load save ticks save 1.yml");
|
||||
var rp2 = new ResPath("/load save ticks save 2.yml");
|
||||
|
||||
MapId mapId = default;
|
||||
var cfg = server.ResolveDependency<IConfigurationManager>();
|
||||
@@ -111,10 +113,10 @@ namespace Content.IntegrationTests.Tests
|
||||
// Load bagel.yml as uninitialized map, and save it to ensure it's up to date.
|
||||
server.Post(() =>
|
||||
{
|
||||
mapSystem.CreateMap(out mapId, runMapInit: false);
|
||||
mapManager.SetMapPaused(mapId, true);
|
||||
Assert.That(mapLoader.TryLoad(mapId, TestMap, out _), $"Failed to load test map {TestMap}");
|
||||
mapLoader.SaveMap(mapId, "load save ticks save 1.yml");
|
||||
var path = new ResPath(TestMap);
|
||||
Assert.That(mapLoader.TryLoadMap(path, out var map, out _), $"Failed to load test map {TestMap}");
|
||||
mapId = map!.Value.Comp.MapId;
|
||||
Assert.That(mapLoader.TrySaveMap(mapId, rp1));
|
||||
});
|
||||
|
||||
// Run 5 ticks.
|
||||
@@ -122,7 +124,7 @@ namespace Content.IntegrationTests.Tests
|
||||
|
||||
await server.WaitPost(() =>
|
||||
{
|
||||
mapLoader.SaveMap(mapId, "/load save ticks save 2.yml");
|
||||
Assert.That(mapLoader.TrySaveMap(mapId, rp2));
|
||||
});
|
||||
|
||||
await server.WaitIdleAsync();
|
||||
@@ -131,13 +133,13 @@ namespace Content.IntegrationTests.Tests
|
||||
string one;
|
||||
string two;
|
||||
|
||||
await using (var stream = userData.Open(new ResPath("/load save ticks save 1.yml"), FileMode.Open))
|
||||
await using (var stream = userData.Open(rp1, FileMode.Open))
|
||||
using (var reader = new StreamReader(stream))
|
||||
{
|
||||
one = await reader.ReadToEndAsync();
|
||||
}
|
||||
|
||||
await using (var stream = userData.Open(new ResPath("/load save ticks save 2.yml"), FileMode.Open))
|
||||
await using (var stream = userData.Open(rp2, FileMode.Open))
|
||||
using (var reader = new StreamReader(stream))
|
||||
{
|
||||
two = await reader.ReadToEndAsync();
|
||||
@@ -163,7 +165,8 @@ namespace Content.IntegrationTests.Tests
|
||||
}
|
||||
});
|
||||
|
||||
await server.WaitPost(() => mapManager.DeleteMap(mapId));
|
||||
testSystem.Enabled = false;
|
||||
await server.WaitPost(() => mapSys.DeleteMap(mapId));
|
||||
await pair.CleanReturnAsync();
|
||||
}
|
||||
|
||||
@@ -184,29 +187,31 @@ namespace Content.IntegrationTests.Tests
|
||||
var server = pair.Server;
|
||||
|
||||
var mapLoader = server.System<MapLoaderSystem>();
|
||||
var mapSystem = server.System<SharedMapSystem>();
|
||||
var mapManager = server.ResolveDependency<IMapManager>();
|
||||
var mapSys = server.System<SharedMapSystem>();
|
||||
var userData = server.ResolveDependency<IResourceManager>().UserData;
|
||||
var cfg = server.ResolveDependency<IConfigurationManager>();
|
||||
Assert.That(cfg.GetCVar(CCVars.GridFill), Is.False);
|
||||
var testSystem = server.System<SaveLoadSaveTestSystem>();
|
||||
testSystem.Enabled = true;
|
||||
|
||||
MapId mapId = default;
|
||||
const string fileA = "/load tick load a.yml";
|
||||
const string fileB = "/load tick load b.yml";
|
||||
MapId mapId1 = default;
|
||||
MapId mapId2 = default;
|
||||
var fileA = new ResPath("/load tick load a.yml");
|
||||
var fileB = new ResPath("/load tick load b.yml");
|
||||
string yamlA;
|
||||
string yamlB;
|
||||
|
||||
// Load & save the first map
|
||||
server.Post(() =>
|
||||
{
|
||||
mapSystem.CreateMap(out mapId, runMapInit: false);
|
||||
mapManager.SetMapPaused(mapId, true);
|
||||
Assert.That(mapLoader.TryLoad(mapId, TestMap, out _), $"Failed to load test map {TestMap}");
|
||||
mapLoader.SaveMap(mapId, fileA);
|
||||
var path = new ResPath(TestMap);
|
||||
Assert.That(mapLoader.TryLoadMap(path, out var map, out _), $"Failed to load test map {TestMap}");
|
||||
mapId1 = map!.Value.Comp.MapId;
|
||||
Assert.That(mapLoader.TrySaveMap(mapId1, fileA));
|
||||
});
|
||||
|
||||
await server.WaitIdleAsync();
|
||||
await using (var stream = userData.Open(new ResPath(fileA), FileMode.Open))
|
||||
await using (var stream = userData.Open(fileA, FileMode.Open))
|
||||
using (var reader = new StreamReader(stream))
|
||||
{
|
||||
yamlA = await reader.ReadToEndAsync();
|
||||
@@ -217,16 +222,15 @@ namespace Content.IntegrationTests.Tests
|
||||
// Load & save the second map
|
||||
server.Post(() =>
|
||||
{
|
||||
mapManager.DeleteMap(mapId);
|
||||
mapSystem.CreateMap(out mapId, runMapInit: false);
|
||||
mapManager.SetMapPaused(mapId, true);
|
||||
Assert.That(mapLoader.TryLoad(mapId, TestMap, out _), $"Failed to load test map {TestMap}");
|
||||
mapLoader.SaveMap(mapId, fileB);
|
||||
var path = new ResPath(TestMap);
|
||||
Assert.That(mapLoader.TryLoadMap(path, out var map, out _), $"Failed to load test map {TestMap}");
|
||||
mapId2 = map!.Value.Comp.MapId;
|
||||
Assert.That(mapLoader.TrySaveMap(mapId2, fileB));
|
||||
});
|
||||
|
||||
await server.WaitIdleAsync();
|
||||
|
||||
await using (var stream = userData.Open(new ResPath(fileB), FileMode.Open))
|
||||
await using (var stream = userData.Open(fileB, FileMode.Open))
|
||||
using (var reader = new StreamReader(stream))
|
||||
{
|
||||
yamlB = await reader.ReadToEndAsync();
|
||||
@@ -234,8 +238,32 @@ namespace Content.IntegrationTests.Tests
|
||||
|
||||
Assert.That(yamlA, Is.EqualTo(yamlB));
|
||||
|
||||
await server.WaitPost(() => mapManager.DeleteMap(mapId));
|
||||
testSystem.Enabled = false;
|
||||
await server.WaitPost(() => mapSys.DeleteMap(mapId1));
|
||||
await server.WaitPost(() => mapSys.DeleteMap(mapId2));
|
||||
await pair.CleanReturnAsync();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Simple system that modifies the data saved to a yaml file by removing the timestamp.
|
||||
/// Required by some tests that validate that re-saving a map does not modify it.
|
||||
/// </summary>
|
||||
private sealed class SaveLoadSaveTestSystem : EntitySystem
|
||||
{
|
||||
public bool Enabled;
|
||||
public override void Initialize()
|
||||
{
|
||||
SubscribeLocalEvent<AfterSerializationEvent>(OnAfterSave);
|
||||
}
|
||||
|
||||
private void OnAfterSave(AfterSerializationEvent ev)
|
||||
{
|
||||
if (!Enabled)
|
||||
return;
|
||||
|
||||
// Remove timestamp.
|
||||
((MappingDataNode)ev.Node["meta"]).Remove("time");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,10 +4,12 @@ using System.Numerics;
|
||||
using Content.Server.Shuttles.Systems;
|
||||
using Content.Tests;
|
||||
using Robust.Server.GameObjects;
|
||||
using Robust.Shared.EntitySerialization.Systems;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Map.Components;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.IntegrationTests.Tests.Shuttle;
|
||||
|
||||
@@ -106,8 +108,9 @@ public sealed class DockTest : ContentUnitTest
|
||||
{
|
||||
mapGrid = entManager.AddComponent<MapGridComponent>(map.MapUid);
|
||||
entManager.DeleteEntity(map.Grid);
|
||||
Assert.That(entManager.System<MapLoaderSystem>().TryLoad(otherMap.MapId, "/Maps/Shuttles/emergency.yml", out var rootUids));
|
||||
shuttle = rootUids[0];
|
||||
var path = new ResPath("/Maps/Shuttles/emergency.yml");
|
||||
Assert.That(entManager.System<MapLoaderSystem>().TryLoadGrid(otherMap.MapId, path, out var grid));
|
||||
shuttle = grid!.Value.Owner;
|
||||
|
||||
var dockingConfig = dockingSystem.GetDockingConfig(shuttle, map.MapUid);
|
||||
Assert.That(dockingConfig, Is.EqualTo(null));
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
using Content.Server.GameTicking;
|
||||
using Content.Server.Maps;
|
||||
using Content.Shared.Administration;
|
||||
using Robust.Server.Maps;
|
||||
using Robust.Shared.Console;
|
||||
using Robust.Shared.ContentPack;
|
||||
using Robust.Shared.EntitySerialization;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
@@ -25,6 +23,7 @@ namespace Content.Server.Administration.Commands
|
||||
var prototypeManager = IoCManager.Resolve<IPrototypeManager>();
|
||||
var entityManager = IoCManager.Resolve<IEntityManager>();
|
||||
var gameTicker = entityManager.EntitySysManager.GetEntitySystem<GameTicker>();
|
||||
var mapSys = entityManager.EntitySysManager.GetEntitySystem<SharedMapSystem>();
|
||||
|
||||
if (args.Length is not (2 or 4 or 5))
|
||||
{
|
||||
@@ -32,30 +31,29 @@ namespace Content.Server.Administration.Commands
|
||||
return;
|
||||
}
|
||||
|
||||
if (prototypeManager.TryIndex<GameMapPrototype>(args[1], out var gameMap))
|
||||
if (!prototypeManager.TryIndex<GameMapPrototype>(args[1], out var gameMap))
|
||||
{
|
||||
shell.WriteError($"The given map prototype {args[0]} is invalid.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!int.TryParse(args[0], out var mapId))
|
||||
return;
|
||||
|
||||
var loadOptions = new MapLoadOptions()
|
||||
{
|
||||
LoadMap = false,
|
||||
};
|
||||
|
||||
var stationName = args.Length == 5 ? args[4] : null;
|
||||
|
||||
if (args.Length >= 4 && int.TryParse(args[2], out var x) && int.TryParse(args[3], out var y))
|
||||
{
|
||||
loadOptions.Offset = new Vector2(x, y);
|
||||
}
|
||||
var grids = gameTicker.LoadGameMap(gameMap, new MapId(mapId), loadOptions, stationName);
|
||||
Vector2? offset = null;
|
||||
if (args.Length >= 4)
|
||||
offset = new Vector2(int.Parse(args[2]), int.Parse(args[3]));
|
||||
|
||||
var id = new MapId(mapId);
|
||||
|
||||
var grids = mapSys.MapExists(id)
|
||||
? gameTicker.MergeGameMap(gameMap, id, stationName: stationName, offset: offset)
|
||||
: gameTicker.LoadGameMapWithId(gameMap, id, stationName: stationName, offset: offset);
|
||||
|
||||
shell.WriteLine($"Loaded {grids.Count} grids.");
|
||||
}
|
||||
else
|
||||
{
|
||||
shell.WriteError($"The given map prototype {args[0]} is invalid.");
|
||||
}
|
||||
}
|
||||
|
||||
public CompletionResult GetCompletion(IConsoleShell shell, string[] args)
|
||||
{
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
using Content.Shared.Administration;
|
||||
using Content.Shared.CCVar;
|
||||
using Robust.Server.GameObjects;
|
||||
using Robust.Shared.Configuration;
|
||||
using Robust.Shared.Console;
|
||||
using Robust.Shared.Map;
|
||||
using System.Linq;
|
||||
using Robust.Shared.EntitySerialization.Systems;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Server.Administration.Commands;
|
||||
|
||||
@@ -48,7 +48,7 @@ public sealed class PersistenceSave : IConsoleCommand
|
||||
}
|
||||
|
||||
var mapLoader = _system.GetEntitySystem<MapLoaderSystem>();
|
||||
mapLoader.SaveMap(mapId, saveFilePath);
|
||||
mapLoader.TrySaveMap(mapId, new ResPath(saveFilePath));
|
||||
shell.WriteLine(Loc.GetString("cmd-savemap-success"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
using Robust.Server.GameObjects;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Map.Components;
|
||||
using Robust.Shared.EntitySerialization.Systems;
|
||||
using Robust.Shared.Network;
|
||||
using Robust.Shared.Player;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Server.Administration.Systems;
|
||||
|
||||
@@ -11,8 +10,7 @@ namespace Content.Server.Administration.Systems;
|
||||
/// </summary>
|
||||
public sealed class AdminTestArenaSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly IMapManager _mapManager = default!;
|
||||
[Dependency] private readonly MapLoaderSystem _map = default!;
|
||||
[Dependency] private readonly MapLoaderSystem _loader = default!;
|
||||
[Dependency] private readonly MetaDataSystem _metaDataSystem = default!;
|
||||
|
||||
public const string ArenaMapPath = "/Maps/Test/admin_test_arena.yml";
|
||||
@@ -28,26 +26,24 @@ public sealed class AdminTestArenaSystem : EntitySystem
|
||||
{
|
||||
return (arenaMap, arenaGrid);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
|
||||
ArenaGrid[admin.UserId] = null;
|
||||
return (arenaMap, null);
|
||||
}
|
||||
}
|
||||
|
||||
ArenaMap[admin.UserId] = _mapManager.GetMapEntityId(_mapManager.CreateMap());
|
||||
_metaDataSystem.SetEntityName(ArenaMap[admin.UserId], $"ATAM-{admin.Name}");
|
||||
var grids = _map.LoadMap(Comp<MapComponent>(ArenaMap[admin.UserId]).MapId, ArenaMapPath);
|
||||
if (grids.Count != 0)
|
||||
{
|
||||
_metaDataSystem.SetEntityName(grids[0], $"ATAG-{admin.Name}");
|
||||
ArenaGrid[admin.UserId] = grids[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
ArenaGrid[admin.UserId] = null;
|
||||
}
|
||||
var path = new ResPath(ArenaMapPath);
|
||||
if (!_loader.TryLoadMap(path, out var map, out var grids))
|
||||
throw new Exception($"Failed to load admin arena");
|
||||
|
||||
return (ArenaMap[admin.UserId], ArenaGrid[admin.UserId]);
|
||||
ArenaMap[admin.UserId] = map.Value.Owner;
|
||||
_metaDataSystem.SetEntityName(map.Value.Owner, $"ATAM-{admin.Name}");
|
||||
|
||||
var grid = grids.FirstOrNull();
|
||||
ArenaGrid[admin.UserId] = grid?.Owner;
|
||||
if (grid != null)
|
||||
_metaDataSystem.SetEntityName(grid.Value.Owner, $"ATAG-{admin.Name}");
|
||||
|
||||
return (map.Value.Owner, grid?.Owner);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ public sealed class DeviceListSystem : SharedDeviceListSystem
|
||||
SubscribeLocalEvent<DeviceListComponent, ComponentShutdown>(OnShutdown);
|
||||
SubscribeLocalEvent<DeviceListComponent, BeforeBroadcastAttemptEvent>(OnBeforeBroadcast);
|
||||
SubscribeLocalEvent<DeviceListComponent, BeforePacketSentEvent>(OnBeforePacketSent);
|
||||
SubscribeLocalEvent<BeforeSaveEvent>(OnMapSave);
|
||||
SubscribeLocalEvent<BeforeSerializationEvent>(OnMapSave);
|
||||
}
|
||||
|
||||
private void OnShutdown(EntityUid uid, DeviceListComponent component, ComponentShutdown args)
|
||||
@@ -124,14 +124,14 @@ public sealed class DeviceListSystem : SharedDeviceListSystem
|
||||
Dirty(list);
|
||||
}
|
||||
|
||||
private void OnMapSave(BeforeSaveEvent ev)
|
||||
private void OnMapSave(BeforeSerializationEvent ev)
|
||||
{
|
||||
List<EntityUid> toRemove = new();
|
||||
var query = GetEntityQuery<TransformComponent>();
|
||||
var enumerator = AllEntityQuery<DeviceListComponent, TransformComponent>();
|
||||
while (enumerator.MoveNext(out var uid, out var device, out var xform))
|
||||
{
|
||||
if (xform.MapUid != ev.Map)
|
||||
if (!ev.MapIds.Contains(xform.MapID))
|
||||
continue;
|
||||
|
||||
foreach (var ent in device.Devices)
|
||||
@@ -144,7 +144,10 @@ public sealed class DeviceListSystem : SharedDeviceListSystem
|
||||
continue;
|
||||
}
|
||||
|
||||
if (linkedXform.MapUid == ev.Map)
|
||||
// This is assuming that **all** of the map is getting saved.
|
||||
// Which is not necessarily true.
|
||||
// AAAAAAAAAAAAAA
|
||||
if (ev.MapIds.Contains(linkedXform.MapID))
|
||||
continue;
|
||||
|
||||
toRemove.Add(ent);
|
||||
|
||||
@@ -67,15 +67,18 @@ public sealed class NetworkConfiguratorSystem : SharedNetworkConfiguratorSystem
|
||||
|
||||
SubscribeLocalEvent<DeviceListComponent, ComponentRemove>(OnComponentRemoved);
|
||||
|
||||
SubscribeLocalEvent<BeforeSaveEvent>(OnMapSave);
|
||||
SubscribeLocalEvent<BeforeSerializationEvent>(OnMapSave);
|
||||
}
|
||||
|
||||
private void OnMapSave(BeforeSaveEvent ev)
|
||||
private void OnMapSave(BeforeSerializationEvent ev)
|
||||
{
|
||||
var enumerator = AllEntityQuery<NetworkConfiguratorComponent>();
|
||||
while (enumerator.MoveNext(out var uid, out var conf))
|
||||
{
|
||||
if (CompOrNull<TransformComponent>(conf.ActiveDeviceList)?.MapUid != ev.Map)
|
||||
if (!TryComp(conf.ActiveDeviceList, out TransformComponent? listXform))
|
||||
continue;
|
||||
|
||||
if (!ev.MapIds.Contains(listXform.MapID))
|
||||
continue;
|
||||
|
||||
// The linked device list is (probably) being saved. Make sure that the configurator is also being saved
|
||||
@@ -83,9 +86,10 @@ public sealed class NetworkConfiguratorSystem : SharedNetworkConfiguratorSystem
|
||||
// containing a set of all entities that are about to be saved, which would make checking this much easier.
|
||||
// This is a shitty bandaid, and will force close the UI during auto-saves.
|
||||
// TODO Map serialization refactor
|
||||
// I'm refactoring it now and I still dont know what to do
|
||||
|
||||
var xform = Transform(uid);
|
||||
if (xform.MapUid == ev.Map && IsSaveable(uid))
|
||||
if (ev.MapIds.Contains(xform.MapID) && IsSaveable(uid))
|
||||
continue;
|
||||
|
||||
_uiSystem.CloseUi(uid, NetworkConfiguratorUiKey.Configure);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
using Content.Server.Announcements;
|
||||
using Content.Server.Discord;
|
||||
using Content.Server.GameTicking.Events;
|
||||
@@ -13,10 +14,12 @@ using Content.Shared.Players;
|
||||
using Content.Shared.Preferences;
|
||||
using JetBrains.Annotations;
|
||||
using Prometheus;
|
||||
using Robust.Server.Maps;
|
||||
using Robust.Shared.Asynchronous;
|
||||
using Robust.Shared.Audio;
|
||||
using Robust.Shared.EntitySerialization;
|
||||
using Robust.Shared.EntitySerialization.Systems;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Map.Components;
|
||||
using Robust.Shared.Network;
|
||||
using Robust.Shared.Player;
|
||||
using Robust.Shared.Random;
|
||||
@@ -92,9 +95,6 @@ namespace Content.Server.GameTicking
|
||||
|
||||
AddGamePresetRules();
|
||||
|
||||
DefaultMap = _mapManager.CreateMap();
|
||||
_mapManager.AddUninitializedMap(DefaultMap);
|
||||
|
||||
var maps = new List<GameMapPrototype>();
|
||||
|
||||
// the map might have been force-set by something
|
||||
@@ -132,52 +132,202 @@ namespace Content.Server.GameTicking
|
||||
// Let game rules dictate what maps we should load.
|
||||
RaiseLocalEvent(new LoadingMapsEvent(maps));
|
||||
|
||||
foreach (var map in maps)
|
||||
if (maps.Count == 0)
|
||||
{
|
||||
var toLoad = DefaultMap;
|
||||
if (maps[0] != map)
|
||||
{
|
||||
// Create other maps for the others since we need to.
|
||||
toLoad = _mapManager.CreateMap();
|
||||
_mapManager.AddUninitializedMap(toLoad);
|
||||
_map.CreateMap(out var mapId, runMapInit: false);
|
||||
DefaultMap = mapId;
|
||||
return;
|
||||
}
|
||||
|
||||
LoadGameMap(map, toLoad, null);
|
||||
for (var i = 0; i < maps.Count; i++)
|
||||
{
|
||||
LoadGameMap(maps[i], out var mapId);
|
||||
DebugTools.Assert(!_map.IsInitialized(mapId));
|
||||
|
||||
if (i == 0)
|
||||
DefaultMap = mapId;
|
||||
}
|
||||
}
|
||||
|
||||
public PreGameMapLoad RaisePreLoad(
|
||||
GameMapPrototype proto,
|
||||
DeserializationOptions? opts = null,
|
||||
Vector2? offset = null,
|
||||
Angle? rot = null)
|
||||
{
|
||||
offset ??= proto.MaxRandomOffset != 0f
|
||||
? _robustRandom.NextVector2(proto.MaxRandomOffset)
|
||||
: Vector2.Zero;
|
||||
|
||||
rot ??= proto.RandomRotation
|
||||
? _robustRandom.NextAngle()
|
||||
: Angle.Zero;
|
||||
|
||||
opts ??= DeserializationOptions.Default;
|
||||
var ev = new PreGameMapLoad(proto, opts.Value, offset.Value, rot.Value);
|
||||
RaiseLocalEvent(ev);
|
||||
return ev;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Loads a new map, allowing systems interested in it to handle loading events.
|
||||
/// In the base game, this is required to be used if you want to load a station.
|
||||
/// This does not initialze maps, unles specified via the <see cref="DeserializationOptions"/>.
|
||||
/// </summary>
|
||||
/// <param name="map">Game map prototype to load in.</param>
|
||||
/// <param name="targetMapId">Map to load into.</param>
|
||||
/// <param name="loadOptions">Map loading options, includes offset.</param>
|
||||
/// <remarks>
|
||||
/// This is basically a wrapper around a <see cref="MapLoaderSystem"/> method that auto generate
|
||||
/// some <see cref="MapLoadOptions"/> using information in a prototype, and raise some events to allow content
|
||||
/// to modify the options and react to the map creation.
|
||||
/// </remarks>
|
||||
/// <param name="proto">Game map prototype to load in.</param>
|
||||
/// <param name="mapId">The id of the map that was loaded.</param>
|
||||
/// <param name="options">Entity loading options, including whether the maps should be initialized.</param>
|
||||
/// <param name="stationName">Name to assign to the loaded station.</param>
|
||||
/// <returns>All loaded entities and grids.</returns>
|
||||
public IReadOnlyList<EntityUid> LoadGameMap(GameMapPrototype map, MapId targetMapId, MapLoadOptions? loadOptions, string? stationName = null)
|
||||
public IReadOnlyList<EntityUid> LoadGameMap(
|
||||
GameMapPrototype proto,
|
||||
out MapId mapId,
|
||||
DeserializationOptions? options = null,
|
||||
string? stationName = null,
|
||||
Vector2? offset = null,
|
||||
Angle? rot = null)
|
||||
{
|
||||
// Okay I specifically didn't set LoadMap here because this is typically called onto a new map.
|
||||
// whereas the command can also be used on an existing map.
|
||||
var loadOpts = loadOptions ?? new MapLoadOptions();
|
||||
var ev = RaisePreLoad(proto, options, offset, rot);
|
||||
|
||||
if (map.MaxRandomOffset != 0f)
|
||||
loadOpts.Offset = _robustRandom.NextVector2(map.MaxRandomOffset);
|
||||
if (ev.GameMap.IsGrid)
|
||||
{
|
||||
var mapUid = _map.CreateMap(out mapId);
|
||||
if (!_loader.TryLoadGrid(mapId,
|
||||
ev.GameMap.MapPath,
|
||||
out var grid,
|
||||
ev.Options,
|
||||
ev.Offset,
|
||||
ev.Rotation))
|
||||
{
|
||||
throw new Exception($"Failed to load game-map grid {ev.GameMap.ID}");
|
||||
}
|
||||
|
||||
if (map.RandomRotation)
|
||||
loadOpts.Rotation = _robustRandom.NextAngle();
|
||||
_metaData.SetEntityName(mapUid, proto.MapName);
|
||||
var g = new List<EntityUid> {grid.Value.Owner};
|
||||
RaiseLocalEvent(new PostGameMapLoad(proto, mapId, g, stationName));
|
||||
return g;
|
||||
}
|
||||
|
||||
var ev = new PreGameMapLoad(targetMapId, map, loadOpts);
|
||||
RaiseLocalEvent(ev);
|
||||
if (!_loader.TryLoadMap(ev.GameMap.MapPath,
|
||||
out var map,
|
||||
out var grids,
|
||||
ev.Options,
|
||||
ev.Offset,
|
||||
ev.Rotation))
|
||||
{
|
||||
throw new Exception($"Failed to load game map {ev.GameMap.ID}");
|
||||
}
|
||||
|
||||
var gridIds = _map.LoadMap(targetMapId, ev.GameMap.MapPath.ToString(), ev.Options);
|
||||
mapId = map.Value.Comp.MapId;
|
||||
_metaData.SetEntityName(map.Value.Owner, proto.MapName);
|
||||
var gridUids = grids.Select(x => x.Owner).ToList();
|
||||
RaiseLocalEvent(new PostGameMapLoad(proto, mapId, gridUids, stationName));
|
||||
return gridUids;
|
||||
}
|
||||
|
||||
_metaData.SetEntityName(_mapManager.GetMapEntityId(targetMapId), map.MapName);
|
||||
/// <summary>
|
||||
/// Variant of <see cref="LoadGameMap"/> that attempts to assign the provided <see cref="MapId"/> to the
|
||||
/// loaded map.
|
||||
/// </summary>
|
||||
public IReadOnlyList<EntityUid> LoadGameMapWithId(
|
||||
GameMapPrototype proto,
|
||||
MapId mapId,
|
||||
DeserializationOptions? opts = null,
|
||||
string? stationName = null,
|
||||
Vector2? offset = null,
|
||||
Angle? rot = null)
|
||||
{
|
||||
var ev = RaisePreLoad(proto, opts, offset, rot);
|
||||
|
||||
var gridUids = gridIds.ToList();
|
||||
RaiseLocalEvent(new PostGameMapLoad(map, targetMapId, gridUids, stationName));
|
||||
if (ev.GameMap.IsGrid)
|
||||
{
|
||||
var mapUid = _map.CreateMap(mapId);
|
||||
if (!_loader.TryLoadGrid(mapId,
|
||||
ev.GameMap.MapPath,
|
||||
out var grid,
|
||||
ev.Options,
|
||||
ev.Offset,
|
||||
ev.Rotation))
|
||||
{
|
||||
throw new Exception($"Failed to load game-map grid {ev.GameMap.ID}");
|
||||
}
|
||||
|
||||
_metaData.SetEntityName(mapUid, proto.MapName);
|
||||
var g = new List<EntityUid> {grid.Value.Owner};
|
||||
RaiseLocalEvent(new PostGameMapLoad(proto, mapId, g, stationName));
|
||||
return g;
|
||||
}
|
||||
|
||||
if (!_loader.TryLoadMapWithId(
|
||||
mapId,
|
||||
ev.GameMap.MapPath,
|
||||
out var map,
|
||||
out var grids,
|
||||
ev.Options,
|
||||
ev.Offset,
|
||||
ev.Rotation))
|
||||
{
|
||||
throw new Exception($"Failed to load map");
|
||||
}
|
||||
|
||||
_metaData.SetEntityName(map.Value.Owner, proto.MapName);
|
||||
var gridUids = grids.Select(x => x.Owner).ToList();
|
||||
RaiseLocalEvent(new PostGameMapLoad(proto, mapId, gridUids, stationName));
|
||||
return gridUids;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Variant of <see cref="LoadGameMap"/> that loads and then merges a game map onto an existing map.
|
||||
/// </summary>
|
||||
public IReadOnlyList<EntityUid> MergeGameMap(
|
||||
GameMapPrototype proto,
|
||||
MapId targetMap,
|
||||
DeserializationOptions? opts = null,
|
||||
string? stationName = null,
|
||||
Vector2? offset = null,
|
||||
Angle? rot = null)
|
||||
{
|
||||
// TODO MAP LOADING use a new event?
|
||||
// This is quite different from the other methods, which will actually create a **new** map.
|
||||
var ev = RaisePreLoad(proto, opts, offset, rot);
|
||||
|
||||
if (ev.GameMap.IsGrid)
|
||||
{
|
||||
if (!_loader.TryLoadGrid(targetMap,
|
||||
ev.GameMap.MapPath,
|
||||
out var grid,
|
||||
ev.Options,
|
||||
ev.Offset,
|
||||
ev.Rotation))
|
||||
{
|
||||
throw new Exception($"Failed to load game-map grid {ev.GameMap.ID}");
|
||||
}
|
||||
|
||||
var g = new List<EntityUid> {grid.Value.Owner};
|
||||
// TODO MAP LOADING use a new event?
|
||||
RaiseLocalEvent(new PostGameMapLoad(proto, targetMap, g, stationName));
|
||||
return g;
|
||||
}
|
||||
|
||||
if (!_loader.TryMergeMap(targetMap,
|
||||
ev.GameMap.MapPath,
|
||||
out var grids,
|
||||
ev.Options,
|
||||
ev.Offset,
|
||||
ev.Rotation))
|
||||
{
|
||||
throw new Exception($"Failed to load map");
|
||||
}
|
||||
|
||||
var gridUids = grids.Select(x => x.Owner).ToList();
|
||||
|
||||
// TODO MAP LOADING use a new event?
|
||||
RaiseLocalEvent(new PostGameMapLoad(proto, targetMap, gridUids, stationName));
|
||||
return gridUids;
|
||||
}
|
||||
|
||||
@@ -274,7 +424,7 @@ namespace Content.Server.GameTicking
|
||||
}
|
||||
|
||||
// MapInitialize *before* spawning players, our codebase is too shit to do it afterwards...
|
||||
_mapManager.DoMapInitialize(DefaultMap);
|
||||
_map.InitializeMap(DefaultMap);
|
||||
|
||||
SpawnPlayers(readyPlayers, readyPlayerProfiles, force);
|
||||
|
||||
@@ -714,20 +864,13 @@ namespace Content.Server.GameTicking
|
||||
/// You likely want to subscribe to this after StationSystem.
|
||||
/// </remarks>
|
||||
[PublicAPI]
|
||||
public sealed class PreGameMapLoad : EntityEventArgs
|
||||
public sealed class PreGameMapLoad(GameMapPrototype gameMap, DeserializationOptions options, Vector2 offset, Angle rotation) : EntityEventArgs
|
||||
{
|
||||
public readonly MapId Map;
|
||||
public GameMapPrototype GameMap;
|
||||
public MapLoadOptions Options;
|
||||
|
||||
public PreGameMapLoad(MapId map, GameMapPrototype gameMap, MapLoadOptions options)
|
||||
{
|
||||
Map = map;
|
||||
GameMap = gameMap;
|
||||
Options = options;
|
||||
public readonly GameMapPrototype GameMap = gameMap;
|
||||
public DeserializationOptions Options = options;
|
||||
public Vector2 Offset = offset;
|
||||
public Angle Rotation = rotation;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Event raised after the game loads a given map.
|
||||
|
||||
@@ -18,6 +18,7 @@ using Robust.Server.GameObjects;
|
||||
using Robust.Server.GameStates;
|
||||
using Robust.Shared.Audio.Systems;
|
||||
using Robust.Shared.Console;
|
||||
using Robust.Shared.EntitySerialization.Systems;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Random;
|
||||
@@ -48,7 +49,8 @@ namespace Content.Server.GameTicking
|
||||
[Dependency] private readonly IServerPreferencesManager _prefsManager = default!;
|
||||
[Dependency] private readonly IServerDbManager _db = default!;
|
||||
[Dependency] private readonly ChatSystem _chatSystem = default!;
|
||||
[Dependency] private readonly MapLoaderSystem _map = default!;
|
||||
[Dependency] private readonly MapLoaderSystem _loader = default!;
|
||||
[Dependency] private readonly SharedMapSystem _map = default!;
|
||||
[Dependency] private readonly GhostSystem _ghost = default!;
|
||||
[Dependency] private readonly SharedMindSystem _mind = default!;
|
||||
[Dependency] private readonly PlayTimeTrackingSystem _playTimeTrackings = default!;
|
||||
|
||||
@@ -20,11 +20,17 @@ public sealed partial class LoadMapRuleComponent : Component
|
||||
public ProtoId<GameMapPrototype>? GameMap;
|
||||
|
||||
/// <summary>
|
||||
/// A map path to load on a new map.
|
||||
/// A map to load.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public ResPath? MapPath;
|
||||
|
||||
/// <summary>
|
||||
/// A grid to load on a new map.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public ResPath? GridPath;
|
||||
|
||||
/// <summary>
|
||||
/// A <see cref="PreloadedGridPrototype"/> to move to a new map.
|
||||
/// If there are no instances left nothing is done.
|
||||
|
||||
@@ -1,10 +1,14 @@
|
||||
using System.Linq;
|
||||
using Content.Server.GameTicking.Rules.Components;
|
||||
using Content.Server.GridPreloader;
|
||||
using Content.Server.StationEvents.Events;
|
||||
using Content.Shared.GameTicking.Components;
|
||||
using Robust.Server.GameObjects;
|
||||
using Robust.Server.Maps;
|
||||
using Robust.Shared.EntitySerialization;
|
||||
using Robust.Shared.EntitySerialization.Systems;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Server.GameTicking.Rules;
|
||||
|
||||
@@ -26,29 +30,50 @@ public sealed class LoadMapRuleSystem : StationEventSystem<LoadMapRuleComponent>
|
||||
return;
|
||||
}
|
||||
|
||||
// grid preloading needs map to init after moving it
|
||||
var mapUid = _map.CreateMap(out var mapId, runMapInit: comp.PreloadedGrid == null);
|
||||
|
||||
Log.Info($"Created map {mapId} for {ToPrettyString(uid):rule}");
|
||||
|
||||
MapId mapId;
|
||||
IReadOnlyList<EntityUid> grids;
|
||||
if (comp.GameMap != null)
|
||||
{
|
||||
// Component has one of three modes, only one of the three fields should ever be populated.
|
||||
DebugTools.AssertNull(comp.MapPath);
|
||||
DebugTools.AssertNull(comp.GridPath);
|
||||
DebugTools.AssertNull(comp.PreloadedGrid);
|
||||
|
||||
var gameMap = _prototypeManager.Index(comp.GameMap.Value);
|
||||
grids = GameTicker.LoadGameMap(gameMap, mapId, new MapLoadOptions());
|
||||
grids = GameTicker.LoadGameMap(gameMap, out mapId, null);
|
||||
Log.Info($"Created map {mapId} for {ToPrettyString(uid):rule}");
|
||||
}
|
||||
else if (comp.MapPath is {} path)
|
||||
{
|
||||
var options = new MapLoadOptions { LoadMap = true };
|
||||
if (!_mapLoader.TryLoad(mapId, path.ToString(), out var roots, options))
|
||||
DebugTools.AssertNull(comp.GridPath);
|
||||
DebugTools.AssertNull(comp.PreloadedGrid);
|
||||
|
||||
var opts = DeserializationOptions.Default with {InitializeMaps = true};
|
||||
if (!_mapLoader.TryLoadMap(path, out var map, out var gridSet, opts))
|
||||
{
|
||||
Log.Error($"Failed to load map from {path}!");
|
||||
Del(mapUid);
|
||||
ForceEndSelf(uid, rule);
|
||||
return;
|
||||
}
|
||||
|
||||
grids = roots;
|
||||
grids = gridSet.Select( x => x.Owner).ToList();
|
||||
mapId = map.Value.Comp.MapId;
|
||||
}
|
||||
else if (comp.GridPath is { } gPath)
|
||||
{
|
||||
DebugTools.AssertNull(comp.PreloadedGrid);
|
||||
|
||||
// I fucking love it when "map paths" choses to ar
|
||||
_map.CreateMap(out mapId);
|
||||
var opts = DeserializationOptions.Default with {InitializeMaps = true};
|
||||
if (!_mapLoader.TryLoadGrid(mapId, gPath, out var grid, opts))
|
||||
{
|
||||
Log.Error($"Failed to load grid from {gPath}!");
|
||||
ForceEndSelf(uid, rule);
|
||||
return;
|
||||
}
|
||||
|
||||
grids = new List<EntityUid> {grid.Value.Owner};
|
||||
}
|
||||
else if (comp.PreloadedGrid is {} preloaded)
|
||||
{
|
||||
@@ -56,11 +81,11 @@ public sealed class LoadMapRuleSystem : StationEventSystem<LoadMapRuleComponent>
|
||||
if (!_gridPreloader.TryGetPreloadedGrid(preloaded, out var loadedShuttle))
|
||||
{
|
||||
Log.Error($"Failed to get a preloaded grid with {preloaded}!");
|
||||
Del(mapUid);
|
||||
ForceEndSelf(uid, rule);
|
||||
return;
|
||||
}
|
||||
|
||||
var mapUid = _map.CreateMap(out mapId, runMapInit: false);
|
||||
_transform.SetParent(loadedShuttle.Value, mapUid);
|
||||
grids = new List<EntityUid>() { loadedShuttle.Value };
|
||||
_map.InitializeMap(mapUid);
|
||||
@@ -68,7 +93,6 @@ public sealed class LoadMapRuleSystem : StationEventSystem<LoadMapRuleComponent>
|
||||
else
|
||||
{
|
||||
Log.Error($"No valid map prototype or map path associated with the rule {ToPrettyString(uid)}");
|
||||
Del(mapUid);
|
||||
ForceEndSelf(uid, rule);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ using Content.Shared.CCVar;
|
||||
using Content.Shared.GridPreloader.Prototypes;
|
||||
using Content.Shared.GridPreloader.Systems;
|
||||
using Robust.Server.GameObjects;
|
||||
using Robust.Server.Maps;
|
||||
using Robust.Shared.Configuration;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Map.Components;
|
||||
@@ -13,6 +12,7 @@ using System.Numerics;
|
||||
using Content.Server.GameTicking;
|
||||
using Content.Shared.GameTicking;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.EntitySerialization.Systems;
|
||||
|
||||
namespace Content.Server.GridPreloader;
|
||||
public sealed class GridPreloaderSystem : SharedGridPreloaderSystem
|
||||
@@ -72,23 +72,13 @@ public sealed class GridPreloaderSystem : SharedGridPreloaderSystem
|
||||
{
|
||||
for (var i = 0; i < proto.Copies; i++)
|
||||
{
|
||||
var options = new MapLoadOptions
|
||||
if (!_mapLoader.TryLoadGrid(mapId, proto.Path, out var grid))
|
||||
{
|
||||
LoadMap = false,
|
||||
};
|
||||
|
||||
if (!_mapLoader.TryLoad(mapId, proto.Path.ToString(), out var roots, options))
|
||||
Log.Error($"Failed to preload grid prototype {proto.ID}");
|
||||
continue;
|
||||
}
|
||||
|
||||
// only supports loading maps with one grid.
|
||||
if (roots.Count != 1)
|
||||
continue;
|
||||
|
||||
var gridUid = roots[0];
|
||||
|
||||
// gets grid + also confirms that the root we loaded is actually a grid
|
||||
if (!TryComp<MapGridComponent>(gridUid, out var mapGrid))
|
||||
continue;
|
||||
var (gridUid, mapGrid) = grid.Value;
|
||||
|
||||
if (!TryComp<PhysicsComponent>(gridUid, out var physics))
|
||||
continue;
|
||||
|
||||
@@ -3,12 +3,13 @@ using Content.Server.Administration;
|
||||
using Content.Server.GameTicking;
|
||||
using Content.Shared.Administration;
|
||||
using Content.Shared.CCVar;
|
||||
using Robust.Server.GameObjects;
|
||||
using Robust.Server.Maps;
|
||||
using Robust.Shared.Configuration;
|
||||
using Robust.Shared.Console;
|
||||
using Robust.Shared.ContentPack;
|
||||
using Robust.Shared.EntitySerialization;
|
||||
using Robust.Shared.EntitySerialization.Systems;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Server.Mapping
|
||||
{
|
||||
@@ -91,8 +92,9 @@ namespace Content.Server.Mapping
|
||||
}
|
||||
else
|
||||
{
|
||||
var loadOptions = new MapLoadOptions {StoreMapUids = true};
|
||||
_entities.System<MapLoaderSystem>().TryLoad(mapId, args[1], out _, loadOptions);
|
||||
var path = new ResPath(args[1]);
|
||||
var opts = new DeserializationOptions {StoreYamlUids = true};
|
||||
_entities.System<MapLoaderSystem>().TryLoadMapWithId(mapId, path, out _, out _, opts);
|
||||
}
|
||||
|
||||
// was the map actually created or did it fail somehow?
|
||||
|
||||
@@ -4,6 +4,8 @@ using Content.Shared.Administration;
|
||||
using Content.Shared.Mapping;
|
||||
using Robust.Server.GameObjects;
|
||||
using Robust.Server.Player;
|
||||
using Robust.Shared.EntitySerialization;
|
||||
using Robust.Shared.EntitySerialization.Systems;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Network;
|
||||
using Robust.Shared.Serialization;
|
||||
@@ -21,6 +23,7 @@ public sealed class MappingManager : IPostInjectInit
|
||||
[Dependency] private readonly IServerNetManager _net = default!;
|
||||
[Dependency] private readonly IPlayerManager _players = default!;
|
||||
[Dependency] private readonly IEntitySystemManager _systems = default!;
|
||||
[Dependency] private readonly IEntityManager _ent = default!;
|
||||
|
||||
private ISawmill _sawmill = default!;
|
||||
private ZStdCompressionContext _zstd = default!;
|
||||
@@ -45,14 +48,14 @@ public sealed class MappingManager : IPostInjectInit
|
||||
if (!_players.TryGetSessionByChannel(message.MsgChannel, out var session) ||
|
||||
!_admin.IsAdmin(session, true) ||
|
||||
!_admin.HasAdminFlag(session, AdminFlags.Host) ||
|
||||
session.AttachedEntity is not { } player)
|
||||
!_ent.TryGetComponent(session.AttachedEntity, out TransformComponent? xform) ||
|
||||
xform.MapUid is not {} mapUid)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var mapId = _systems.GetEntitySystem<TransformSystem>().GetMapCoordinates(player).MapId;
|
||||
var mapEntity = _map.GetMapEntityIdOrThrow(mapId);
|
||||
var data = _systems.GetEntitySystem<MapLoaderSystem>().GetSaveData(mapEntity);
|
||||
var sys = _systems.GetEntitySystem<MapLoaderSystem>();
|
||||
var data = sys.SerializeEntitiesRecursive([mapUid]).Node;
|
||||
var document = new YamlDocument(data.ToYaml());
|
||||
var stream = new YamlStream { document };
|
||||
var writer = new StringWriter();
|
||||
|
||||
@@ -3,10 +3,10 @@ using Content.Server.Administration;
|
||||
using Content.Shared.Administration;
|
||||
using Content.Shared.CCVar;
|
||||
using Robust.Server.GameObjects;
|
||||
using Robust.Server.Maps;
|
||||
using Robust.Shared.Configuration;
|
||||
using Robust.Shared.Console;
|
||||
using Robust.Shared.ContentPack;
|
||||
using Robust.Shared.EntitySerialization.Systems;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Timing;
|
||||
using Robust.Shared.Utility;
|
||||
@@ -23,7 +23,7 @@ public sealed class MappingSystem : EntitySystem
|
||||
[Dependency] private readonly IConfigurationManager _cfg = default!;
|
||||
[Dependency] private readonly IMapManager _mapManager = default!;
|
||||
[Dependency] private readonly IResourceManager _resMan = default!;
|
||||
[Dependency] private readonly MapLoaderSystem _map = default!;
|
||||
[Dependency] private readonly MapLoaderSystem _loader = default!;
|
||||
|
||||
// Not a comp because I don't want to deal with this getting saved onto maps ever
|
||||
/// <summary>
|
||||
@@ -78,7 +78,7 @@ public sealed class MappingSystem : EntitySystem
|
||||
var path = Path.Combine(saveDir, $"{DateTime.Now.ToString("yyyy-M-dd_HH.mm.ss")}-AUTO.yml");
|
||||
_currentlyAutosaving[map] = (CalculateNextTime(), name);
|
||||
Log.Info($"Autosaving map {name} ({map}) to {path}. Next save in {ReadableTimeLeft(map)} seconds.");
|
||||
_map.SaveMap(map, path);
|
||||
_loader.TrySaveMap(map, new ResPath(path));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -25,6 +25,11 @@ public sealed partial class GameMapPrototype : IPrototype
|
||||
[DataField]
|
||||
public float MaxRandomOffset = 1000f;
|
||||
|
||||
/// <summary>
|
||||
/// Turns out some of the map files are actually secretly grids. Excellent. I love map loading code.
|
||||
/// </summary>
|
||||
[DataField] public bool IsGrid;
|
||||
|
||||
[DataField]
|
||||
public bool RandomRotation = true;
|
||||
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Robust.Server.GameObjects;
|
||||
using Robust.Server.Maps;
|
||||
using Robust.Shared.ContentPack;
|
||||
using Robust.Shared.EntitySerialization.Systems;
|
||||
using Robust.Shared.Map.Events;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Serialization.Markdown;
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
using System.Linq;
|
||||
using Content.Server.Administration;
|
||||
using Content.Shared.Administration;
|
||||
using Robust.Server.GameObjects;
|
||||
using Robust.Server.Maps;
|
||||
using Robust.Shared.Console;
|
||||
using Robust.Shared.ContentPack;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.EntitySerialization;
|
||||
using Robust.Shared.EntitySerialization.Components;
|
||||
using Robust.Shared.EntitySerialization.Systems;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Server.Maps;
|
||||
@@ -17,8 +17,8 @@ namespace Content.Server.Maps;
|
||||
public sealed class ResaveCommand : LocalizedCommands
|
||||
{
|
||||
[Dependency] private readonly IEntityManager _entManager = default!;
|
||||
[Dependency] private readonly IMapManager _mapManager = default!;
|
||||
[Dependency] private readonly IResourceManager _res = default!;
|
||||
[Dependency] private readonly ILogManager _log = default!;
|
||||
|
||||
public override string Command => "resave";
|
||||
|
||||
@@ -26,32 +26,56 @@ public sealed class ResaveCommand : LocalizedCommands
|
||||
{
|
||||
var loader = _entManager.System<MapLoaderSystem>();
|
||||
|
||||
foreach (var fn in _res.ContentFindFiles(new ResPath("/Maps/")))
|
||||
var opts = MapLoadOptions.Default with
|
||||
{
|
||||
var mapId = _mapManager.CreateMap();
|
||||
_mapManager.AddUninitializedMap(mapId);
|
||||
loader.Load(mapId, fn.ToString(), new MapLoadOptions()
|
||||
|
||||
DeserializationOptions = DeserializationOptions.Default with
|
||||
{
|
||||
StoreMapUids = true,
|
||||
LoadMap = true,
|
||||
});
|
||||
StoreYamlUids = true,
|
||||
LogOrphanedGrids = false
|
||||
}
|
||||
};
|
||||
|
||||
var log = _log.GetSawmill(Command);
|
||||
var files = _res.ContentFindFiles(new ResPath("/Maps/")).ToList();
|
||||
|
||||
for (var i = 0; i < files.Count; i++)
|
||||
{
|
||||
var fn = files[i];
|
||||
log.Info($"Re-saving file {i}/{files.Count} : {fn}");
|
||||
|
||||
if (!loader.TryLoadGeneric(fn, out var result, opts))
|
||||
continue;
|
||||
|
||||
if (result.Maps.Count != 1)
|
||||
{
|
||||
shell.WriteError(
|
||||
$"Multi-map or multi-grid files like {fn} are not yet supported by the {Command} command");
|
||||
loader.Delete(result);
|
||||
continue;
|
||||
}
|
||||
|
||||
var map = result.Maps.First();
|
||||
|
||||
// Process deferred component removals.
|
||||
_entManager.CullRemovedComponents();
|
||||
|
||||
var mapUid = _mapManager.GetMapEntityId(mapId);
|
||||
var mapXform = _entManager.GetComponent<TransformComponent>(mapUid);
|
||||
|
||||
if (_entManager.HasComponent<LoadedMapComponent>(mapUid) || mapXform.ChildCount != 1)
|
||||
if (_entManager.HasComponent<LoadedMapComponent>(map))
|
||||
{
|
||||
loader.SaveMap(mapId, fn.ToString());
|
||||
loader.TrySaveMap(map.Comp.MapId, fn);
|
||||
}
|
||||
else if (mapXform.ChildEnumerator.MoveNext(out var child))
|
||||
else if (result.Grids.Count == 1)
|
||||
{
|
||||
loader.Save(child, fn.ToString());
|
||||
loader.TrySaveGrid(result.Grids.First(), fn);
|
||||
}
|
||||
else
|
||||
{
|
||||
shell.WriteError($"Failed to resave {fn}");
|
||||
}
|
||||
|
||||
_mapManager.DeleteMap(mapId);
|
||||
}
|
||||
loader.Delete(result);
|
||||
}
|
||||
|
||||
shell.WriteLine($"Resaved all maps");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,10 +15,13 @@ using Robust.Server.GameObjects;
|
||||
using Robust.Shared.Collections;
|
||||
using Robust.Shared.Configuration;
|
||||
using Robust.Shared.Console;
|
||||
using Robust.Shared.EntitySerialization;
|
||||
using Robust.Shared.EntitySerialization.Systems;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Map.Components;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Random;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Server.Procedural;
|
||||
|
||||
@@ -173,14 +176,18 @@ public sealed partial class DungeonSystem : SharedDungeonSystem
|
||||
return Transform(uid).MapID;
|
||||
}
|
||||
|
||||
var mapId = _mapManager.CreateMap();
|
||||
_mapManager.AddUninitializedMap(mapId);
|
||||
_loader.Load(mapId, proto.AtlasPath.ToString());
|
||||
var mapUid = _mapManager.GetMapEntityId(mapId);
|
||||
_mapManager.SetMapPaused(mapId, true);
|
||||
comp = AddComp<DungeonAtlasTemplateComponent>(mapUid);
|
||||
var opts = new MapLoadOptions
|
||||
{
|
||||
DeserializationOptions = DeserializationOptions.Default with {PauseMaps = true},
|
||||
ExpectedCategory = FileCategory.Map
|
||||
};
|
||||
|
||||
if (!_loader.TryLoadGeneric(proto.AtlasPath, out var res, opts) || !res.Maps.TryFirstOrNull(out var map))
|
||||
throw new Exception($"Failed to load dungeon template.");
|
||||
|
||||
comp = AddComp<DungeonAtlasTemplateComponent>(map.Value.Owner);
|
||||
comp.Path = proto.AtlasPath;
|
||||
return mapId;
|
||||
return map.Value.Comp.MapId;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -6,7 +6,6 @@ using Content.Shared.Mobs.Components;
|
||||
using Content.Shared.Procedural;
|
||||
using Content.Shared.Radio;
|
||||
using Content.Shared.Salvage.Magnet;
|
||||
using Robust.Server.Maps;
|
||||
using Robust.Shared.Exceptions;
|
||||
using Robust.Shared.Map;
|
||||
|
||||
@@ -291,15 +290,10 @@ public sealed partial class SalvageSystem
|
||||
case SalvageOffering wreck:
|
||||
var salvageProto = wreck.SalvageMap;
|
||||
|
||||
var opts = new MapLoadOptions
|
||||
{
|
||||
Offset = new Vector2(0, 0)
|
||||
};
|
||||
|
||||
if (!_map.TryLoad(salvMapXform.MapID, salvageProto.MapPath.ToString(), out _, opts))
|
||||
if (!_loader.TryLoadGrid(salvMapXform.MapID, salvageProto.MapPath, out _))
|
||||
{
|
||||
Report(magnet, MagnetChannel, "salvage-system-announcement-spawn-debris-disintegrated");
|
||||
_mapManager.DeleteMap(salvMapXform.MapID);
|
||||
_mapSystem.DeleteMap(salvMapXform.MapID);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,38 +1,23 @@
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
using Content.Server.Cargo.Systems;
|
||||
using Content.Server.Construction;
|
||||
using Content.Server.GameTicking;
|
||||
using Content.Server.Radio.EntitySystems;
|
||||
using Content.Shared.Examine;
|
||||
using Content.Shared.Interaction;
|
||||
using Content.Shared.Popups;
|
||||
using Content.Shared.Radio;
|
||||
using Content.Shared.Salvage;
|
||||
using Robust.Server.GameObjects;
|
||||
using Robust.Shared.Configuration;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Player;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Random;
|
||||
using Robust.Shared.Utility;
|
||||
using Content.Server.Chat.Managers;
|
||||
using Content.Server.Gravity;
|
||||
using Content.Server.Parallax;
|
||||
using Content.Server.Procedural;
|
||||
using Content.Server.Shuttles.Systems;
|
||||
using Content.Server.Station.Systems;
|
||||
using Content.Shared.CCVar;
|
||||
using Content.Shared.Construction.EntitySystems;
|
||||
using Content.Shared.Random;
|
||||
using Content.Shared.Random.Helpers;
|
||||
using Content.Shared.Tools.Components;
|
||||
using Robust.Server.Maps;
|
||||
using Robust.Shared.Audio;
|
||||
using Robust.Shared.Audio.Systems;
|
||||
using Robust.Shared.Map.Components;
|
||||
using Robust.Shared.Timing;
|
||||
using Content.Server.Labels;
|
||||
using Robust.Shared.EntitySerialization.Systems;
|
||||
|
||||
namespace Content.Server.Salvage
|
||||
{
|
||||
@@ -50,7 +35,7 @@ namespace Content.Server.Salvage
|
||||
[Dependency] private readonly DungeonSystem _dungeon = default!;
|
||||
[Dependency] private readonly GravitySystem _gravity = default!;
|
||||
[Dependency] private readonly LabelSystem _labelSystem = default!;
|
||||
[Dependency] private readonly MapLoaderSystem _map = default!;
|
||||
[Dependency] private readonly MapLoaderSystem _loader = default!;
|
||||
[Dependency] private readonly MetaDataSystem _metaData = default!;
|
||||
[Dependency] private readonly RadioSystem _radioSystem = default!;
|
||||
[Dependency] private readonly SharedAudioSystem _audio = default!;
|
||||
|
||||
@@ -30,11 +30,13 @@ using Robust.Server.GameObjects;
|
||||
using Robust.Shared.Collections;
|
||||
using Robust.Shared.Configuration;
|
||||
using Robust.Shared.Console;
|
||||
using Robust.Shared.EntitySerialization.Systems;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Player;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Random;
|
||||
using Robust.Shared.Timing;
|
||||
using Robust.Shared.Utility;
|
||||
using TimedDespawnComponent = Robust.Shared.Spawners.TimedDespawnComponent;
|
||||
|
||||
namespace Content.Server.Shuttles.Systems;
|
||||
@@ -512,15 +514,13 @@ public sealed class ArrivalsSystem : EntitySystem
|
||||
|
||||
private void SetupArrivalsStation()
|
||||
{
|
||||
var mapUid = _mapSystem.CreateMap(out var mapId, false);
|
||||
_metaData.SetEntityName(mapUid, Loc.GetString("map-name-terminal"));
|
||||
|
||||
if (!_loader.TryLoad(mapId, _cfgManager.GetCVar(CCVars.ArrivalsMap), out var uids))
|
||||
{
|
||||
var path = new ResPath(_cfgManager.GetCVar(CCVars.ArrivalsMap));
|
||||
if (!_loader.TryLoadMap(path, out var map, out var grids))
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var id in uids)
|
||||
_metaData.SetEntityName(map.Value, Loc.GetString("map-name-terminal"));
|
||||
|
||||
foreach (var id in grids)
|
||||
{
|
||||
EnsureComp<ArrivalsSourceComponent>(id);
|
||||
EnsureComp<ProtectedGridComponent>(id);
|
||||
@@ -531,15 +531,15 @@ public sealed class ArrivalsSystem : EntitySystem
|
||||
if (_cfgManager.GetCVar(CCVars.ArrivalsPlanet))
|
||||
{
|
||||
var template = _random.Pick(_arrivalsBiomeOptions);
|
||||
_biomes.EnsurePlanet(mapUid, _protoManager.Index(template));
|
||||
_biomes.EnsurePlanet(map.Value, _protoManager.Index(template));
|
||||
var restricted = new RestrictedRangeComponent
|
||||
{
|
||||
Range = 32f
|
||||
};
|
||||
AddComp(mapUid, restricted);
|
||||
AddComp(map.Value, restricted);
|
||||
}
|
||||
|
||||
_mapSystem.InitializeMap(mapId);
|
||||
_mapSystem.InitializeMap(map.Value.Comp.MapId);
|
||||
|
||||
// Handle roundstart stations.
|
||||
var query = AllEntityQuery<StationArrivalsComponent>();
|
||||
@@ -600,9 +600,9 @@ public sealed class ArrivalsSystem : EntitySystem
|
||||
var dummpMapEntity = _mapSystem.CreateMap(out var dummyMapId);
|
||||
|
||||
if (TryGetArrivals(out var arrivals) &&
|
||||
_loader.TryLoad(dummyMapId, component.ShuttlePath.ToString(), out var shuttleUids))
|
||||
_loader.TryLoadGrid(dummyMapId, component.ShuttlePath, out var shuttle))
|
||||
{
|
||||
component.Shuttle = shuttleUids[0];
|
||||
component.Shuttle = shuttle.Value;
|
||||
var shuttleComp = Comp<ShuttleComponent>(component.Shuttle);
|
||||
var arrivalsComp = EnsureComp<ArrivalsShuttleComponent>(component.Shuttle);
|
||||
arrivalsComp.Station = uid;
|
||||
|
||||
@@ -29,10 +29,9 @@ using Content.Shared.Shuttles.Events;
|
||||
using Content.Shared.Tag;
|
||||
using Content.Shared.Tiles;
|
||||
using Robust.Server.GameObjects;
|
||||
using Robust.Server.Maps;
|
||||
using Robust.Shared.Audio.Systems;
|
||||
using Robust.Shared.Configuration;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.EntitySerialization.Systems;
|
||||
using Robust.Shared.Map.Components;
|
||||
using Robust.Shared.Player;
|
||||
using Robust.Shared.Random;
|
||||
@@ -60,7 +59,7 @@ public sealed partial class EmergencyShuttleSystem : EntitySystem
|
||||
[Dependency] private readonly DockingSystem _dock = default!;
|
||||
[Dependency] private readonly IdCardSystem _idSystem = default!;
|
||||
[Dependency] private readonly NavMapSystem _navMap = default!;
|
||||
[Dependency] private readonly MapLoaderSystem _map = default!;
|
||||
[Dependency] private readonly MapLoaderSystem _loader = default!;
|
||||
[Dependency] private readonly MetaDataSystem _metaData = default!;
|
||||
[Dependency] private readonly PopupSystem _popup = default!;
|
||||
[Dependency] private readonly RoundEndSystem _roundEnd = default!;
|
||||
@@ -531,10 +530,11 @@ public sealed partial class EmergencyShuttleSystem : EntitySystem
|
||||
}
|
||||
|
||||
var map = _mapSystem.CreateMap(out var mapId);
|
||||
var grid = _map.LoadGrid(mapId, component.Map.ToString(), new MapLoadOptions()
|
||||
if (!_loader.TryLoadGrid(mapId, component.Map, out var grid))
|
||||
{
|
||||
LoadMap = false,
|
||||
});
|
||||
Log.Error($"Failed to set up centcomm grid!");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Exists(map))
|
||||
{
|
||||
@@ -608,15 +608,11 @@ public sealed partial class EmergencyShuttleSystem : EntitySystem
|
||||
|
||||
// Load escape shuttle
|
||||
var shuttlePath = ent.Comp1.EmergencyShuttlePath;
|
||||
var shuttle = _map.LoadGrid(map.MapId, shuttlePath.ToString(), new MapLoadOptions()
|
||||
{
|
||||
if (!_loader.TryLoadGrid(map.MapId,
|
||||
shuttlePath,
|
||||
out var shuttle,
|
||||
// Should be far enough... right? I'm too lazy to bounds check CentCom rn.
|
||||
Offset = new Vector2(500f + ent.Comp2.ShuttleIndex, 0f),
|
||||
// fun fact: if you just fucking yeet centcomm into nullspace anytime you try to spawn the shuttle, then any distance is far enough. so lets not do that
|
||||
LoadMap = false,
|
||||
});
|
||||
|
||||
if (shuttle == null)
|
||||
offset: new Vector2(500f + ent.Comp2.ShuttleIndex, 0f)))
|
||||
{
|
||||
Log.Error($"Unable to spawn emergency shuttle {shuttlePath} for {ToPrettyString(ent)}");
|
||||
return;
|
||||
|
||||
@@ -72,17 +72,15 @@ public sealed partial class ShuttleSystem
|
||||
|
||||
_mapSystem.CreateMap(out var mapId);
|
||||
|
||||
if (_loader.TryLoad(mapId, component.Path.ToString(), out var ent) && ent.Count > 0)
|
||||
if (_loader.TryLoadGrid(mapId, component.Path, out var ent))
|
||||
{
|
||||
if (HasComp<ShuttleComponent>(ent[0]))
|
||||
{
|
||||
TryFTLProximity(ent[0], targetGrid.Value);
|
||||
if (HasComp<ShuttleComponent>(ent))
|
||||
TryFTLProximity(ent.Value, targetGrid.Value);
|
||||
|
||||
_station.AddGridToStation(uid, ent.Value);
|
||||
}
|
||||
|
||||
_station.AddGridToStation(uid, ent[0]);
|
||||
}
|
||||
|
||||
_mapManager.DeleteMap(mapId);
|
||||
_mapSystem.DeleteMap(mapId);
|
||||
}
|
||||
|
||||
private bool TryDungeonSpawn(Entity<MapGridComponent?> targetGrid, DungeonSpawnGroup group, out EntityUid spawned)
|
||||
@@ -143,20 +141,18 @@ public sealed partial class ShuttleSystem
|
||||
var path = paths[^1];
|
||||
paths.RemoveAt(paths.Count - 1);
|
||||
|
||||
if (_loader.TryLoad(mapId, path.ToString(), out var ent) && ent.Count == 1)
|
||||
if (_loader.TryLoadGrid(mapId, path, out var grid))
|
||||
{
|
||||
if (HasComp<ShuttleComponent>(ent[0]))
|
||||
{
|
||||
TryFTLProximity(ent[0], targetGrid);
|
||||
}
|
||||
if (HasComp<ShuttleComponent>(grid))
|
||||
TryFTLProximity(grid.Value, targetGrid);
|
||||
|
||||
if (group.NameGrid)
|
||||
{
|
||||
var name = path.FilenameWithoutExtension;
|
||||
_metadata.SetEntityName(ent[0], name);
|
||||
_metadata.SetEntityName(grid.Value, name);
|
||||
}
|
||||
|
||||
spawned = ent[0];
|
||||
spawned = grid.Value;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -227,7 +223,7 @@ public sealed partial class ShuttleSystem
|
||||
}
|
||||
}
|
||||
|
||||
_mapManager.DeleteMap(mapId);
|
||||
_mapSystem.DeleteMap(mapId);
|
||||
}
|
||||
|
||||
private void OnGridFillMapInit(EntityUid uid, GridFillComponent component, MapInitEvent args)
|
||||
@@ -246,23 +242,22 @@ public sealed partial class ShuttleSystem
|
||||
_mapSystem.CreateMap(out var mapId);
|
||||
var valid = false;
|
||||
|
||||
if (_loader.TryLoad(mapId, component.Path.ToString(), out var ent) &&
|
||||
ent.Count == 1 &&
|
||||
TryComp(ent[0], out TransformComponent? shuttleXform))
|
||||
if (_loader.TryLoadGrid(mapId, component.Path, out var grid))
|
||||
{
|
||||
var escape = GetSingleDock(ent[0]);
|
||||
var escape = GetSingleDock(grid.Value);
|
||||
|
||||
if (escape != null)
|
||||
{
|
||||
var config = _dockSystem.GetDockingConfig(ent[0], xform.GridUid.Value, escape.Value.Entity, escape.Value.Component, uid, dock);
|
||||
var config = _dockSystem.GetDockingConfig(grid.Value, xform.GridUid.Value, escape.Value.Entity, escape.Value.Component, uid, dock);
|
||||
|
||||
if (config != null)
|
||||
{
|
||||
FTLDock((ent[0], shuttleXform), config);
|
||||
var shuttleXform = Transform(grid.Value);
|
||||
FTLDock((grid.Value, shuttleXform), config);
|
||||
|
||||
if (TryComp<StationMemberComponent>(xform.GridUid, out var stationMember))
|
||||
{
|
||||
_station.AddGridToStation(stationMember.Station, ent[0]);
|
||||
_station.AddGridToStation(stationMember.Station, grid.Value);
|
||||
}
|
||||
|
||||
valid = true;
|
||||
@@ -273,11 +268,11 @@ public sealed partial class ShuttleSystem
|
||||
{
|
||||
var compType = compReg.Component.GetType();
|
||||
|
||||
if (HasComp(ent[0], compType))
|
||||
if (HasComp(grid.Value, compType))
|
||||
continue;
|
||||
|
||||
var comp = _factory.GetComponent(compType);
|
||||
AddComp(ent[0], comp, true);
|
||||
AddComp(grid.Value, comp, true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -286,7 +281,7 @@ public sealed partial class ShuttleSystem
|
||||
Log.Error($"Error loading gridfill dock for {ToPrettyString(uid)} / {component.Path}");
|
||||
}
|
||||
|
||||
_mapManager.DeleteMap(mapId);
|
||||
_mapSystem.DeleteMap(mapId);
|
||||
}
|
||||
|
||||
private (EntityUid Entity, DockingComponent Component)? GetSingleDock(EntityUid uid)
|
||||
|
||||
@@ -17,6 +17,7 @@ using Robust.Server.GameStates;
|
||||
using Robust.Shared.Audio;
|
||||
using Robust.Shared.Audio.Systems;
|
||||
using Robust.Shared.Configuration;
|
||||
using Robust.Shared.EntitySerialization.Systems;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Map.Components;
|
||||
using Robust.Shared.Physics;
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
using Content.Shared.Administration.Managers;
|
||||
using Content.Shared.Database;
|
||||
@@ -44,8 +45,8 @@ public sealed class FollowerSystem : EntitySystem
|
||||
SubscribeLocalEvent<FollowedComponent, ComponentGetStateAttemptEvent>(OnFollowedAttempt);
|
||||
SubscribeLocalEvent<FollowerComponent, GotEquippedHandEvent>(OnGotEquippedHand);
|
||||
SubscribeLocalEvent<FollowedComponent, EntityTerminatingEvent>(OnFollowedTerminating);
|
||||
SubscribeLocalEvent<BeforeSerializationEvent>(OnBeforeSave);
|
||||
SubscribeLocalEvent<FollowedComponent, PolymorphedEvent>(OnFollowedPolymorphed);
|
||||
SubscribeLocalEvent<BeforeSaveEvent>(OnBeforeSave);
|
||||
}
|
||||
|
||||
private void OnFollowedAttempt(Entity<FollowedComponent> ent, ref ComponentGetStateAttemptEvent args)
|
||||
@@ -63,10 +64,16 @@ public sealed class FollowerSystem : EntitySystem
|
||||
}
|
||||
}
|
||||
|
||||
private void OnBeforeSave(BeforeSaveEvent ev)
|
||||
private void OnBeforeSave(BeforeSerializationEvent ev)
|
||||
{
|
||||
// Some followers will not be map savable. This ensures that maps don't get saved with empty/invalid
|
||||
// followers, but just stopping any following on the map being saved.
|
||||
// Some followers will not be map savable. This ensures that maps don't get saved with some entities that have
|
||||
// empty/invalid followers, by just stopping any following happening on the map being saved.
|
||||
// I hate this so much.
|
||||
// TODO WeakEntityReference
|
||||
// We need some way to store entity references in a way that doesn't imply that the entity still exists.
|
||||
// Then we wouldn't have to deal with this shit.
|
||||
|
||||
var maps = ev.Entities.Select(x => Transform(x).MapUid).ToHashSet();
|
||||
|
||||
var query = AllEntityQuery<FollowerComponent, TransformComponent, MetaDataComponent>();
|
||||
while (query.MoveNext(out var uid, out var follower, out var xform, out var meta))
|
||||
@@ -74,7 +81,7 @@ public sealed class FollowerSystem : EntitySystem
|
||||
if (meta.EntityPrototype == null || meta.EntityPrototype.MapSavable)
|
||||
continue;
|
||||
|
||||
if (xform.MapUid != ev.Map)
|
||||
if (!maps.Contains(xform.MapUid))
|
||||
continue;
|
||||
|
||||
StopFollowingEntity(uid, follower.Following);
|
||||
|
||||
@@ -8,6 +8,7 @@ using Content.Shared.Movement.Events;
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.Input;
|
||||
using Robust.Shared.Input.Binding;
|
||||
using Robust.Shared.Map.Components;
|
||||
using Robust.Shared.Player;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Serialization;
|
||||
@@ -207,7 +208,7 @@ namespace Content.Shared.Movement.Systems
|
||||
}
|
||||
|
||||
// If we went from grid -> map we'll preserve our worldrotation
|
||||
if (relative != null && _mapManager.IsMap(relative.Value))
|
||||
if (relative != null && HasComp<MapComponent>(relative.Value))
|
||||
{
|
||||
targetRotation = currentRotation.FlipPositive().Reduced();
|
||||
}
|
||||
|
||||
@@ -16,26 +16,11 @@ tilemap:
|
||||
entities:
|
||||
- proto: ""
|
||||
entities:
|
||||
- uid: 1
|
||||
components:
|
||||
- type: MetaData
|
||||
name: Map Entity
|
||||
- type: Transform
|
||||
- type: Map
|
||||
mapPaused: True
|
||||
- type: PhysicsMap
|
||||
- type: GridTree
|
||||
- type: MovedGrids
|
||||
- type: Broadphase
|
||||
- type: OccluderTree
|
||||
- type: LoadedMap
|
||||
- uid: 2
|
||||
components:
|
||||
- type: MetaData
|
||||
name: grid
|
||||
- type: Transform
|
||||
pos: -7.6484375,2.8046875
|
||||
parent: 1
|
||||
- type: MapGrid
|
||||
chunks:
|
||||
0,0:
|
||||
|
||||
@@ -454,7 +454,7 @@
|
||||
duration: 1
|
||||
- type: RuleGrids
|
||||
- type: LoadMapRule
|
||||
mapPath: /Maps/Shuttles/ShuttleEvent/striker.yml
|
||||
gridPath: /Maps/Shuttles/ShuttleEvent/striker.yml
|
||||
- type: NukeopsRule
|
||||
roundEndBehavior: Nothing
|
||||
- type: AntagSelection
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
- type: gameMap
|
||||
id: CentComm
|
||||
isGrid: true # Did you know that centcomm is the only "game map" that isn't actually a map? Send help.
|
||||
mapName: 'Central Command'
|
||||
mapPath: /Maps/centcomm.yml
|
||||
minPlayers: 10
|
||||
|
||||
Reference in New Issue
Block a user