Skip to content

Commit

Permalink
Refactor map loading & saving (#5572)
Browse files Browse the repository at this point in the history
* Refactor map loading & saving

* test fixes

* ISerializationManager tweaks

* Fix component composition

* Try fix entity deserialization component composition

* comments

* CL

* error preinit

* a

* cleanup

* error if version is too new

* Add AlwaysPushSerializationTest

* Add auto-inclusion test

* Better categorization

* Combine test components

* Save -> TrySave

Also better handling for saving multiple entities individually

* Create new partial class for map loading

* Add OrphanSerializationTest

* Include MapIds in BeforeSerializationEvent

* Addd LifetimeSerializationTest

* Add TestMixedLifetimeSerialization

* Add CategorizationTest

* explicitly serialize list of nullspace entities

* Add backwards compatibility test

* Version comments

also fixes wrong v4 format

* add MapMergeTest

* Add NetEntity support

* Optimize EntityDeserializer

Avoid unnecessary component deserialization

* fix assert & other bugs

* fucking containers strike again

* Fix deletion of pre-init entities

* fix release note merge conflict

* Update Robust.Shared/Map/MapManager.GridCollection.cs

Co-authored-by: metalgearsloth <[email protected]>

* VV

---------

Co-authored-by: metalgearsloth <[email protected]>
  • Loading branch information
ElectroJr and metalgearsloth authored Feb 16, 2025
1 parent 9d1b15a commit fbc706f
Show file tree
Hide file tree
Showing 79 changed files with 6,943 additions and 2,186 deletions.
19 changes: 15 additions & 4 deletions RELEASE-NOTES.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,19 +35,30 @@ END TEMPLATE-->

### Breaking changes

*None yet*
* `ITileDefinitionManager.AssignAlias` and general tile alias functionality has been removed. `TileAliasPrototype` still exist, but are only used during entity deserialization.
* `IMapManager.AddUninitializedMap` has been removed. Use the map-init options on `CreateMap()` instead.
* Re-using a MapId will now log a warning. This may cause some integration tests to fail if they are configured to fail
when warnings are logged.
* The minimum supported map format / version has been increased from 2 to 3.
* The server-side `MapLoaderSystem` and associated classes & structs has been moved to `Robust.Shared`, and has been significantly modified.
* The`TryLoad` and `Save` methods have been replaced with grid, map, generic entity variants. I.e, `SaveGrid`, `SaveMap`, and `SaveEntities`.
* Most of the serialization logic and methods have been moved out of `MapLoaderSystem` and into new `EntitySerializer`
and `EntityDeserializer` classes, which also replace the old `MapSerializationContext`.
* The `MapLoadOptions` class has been split into `MapLoadOptions`, `SerializationOptions`, and `DeserializationOptions`
structs.

### New features

*None yet*
* The current map format/version has increased from 6 to 7 and now contains more information to try support serialization of maps with null-space entities and full game saves.
* `IEntitySystemManager` now provides access to the system `IDependencyCollection`.

### Bugfixes

*None yet*
* Fixed entity deserialization for components with a data fields that have a AlwaysPushInheritance Attribute

### Other

*None yet*
* `MapChangedEvent` has been marked as obsolete, and should be replaced with `MapCreatedEvent` and `MapRemovedEvent.

### Internal

Expand Down
2 changes: 1 addition & 1 deletion Robust.Client/GameObjects/EntitySystems/MapSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ protected override MapId GetNextMapId()
{
// Client-side map entities use negative map Ids to avoid conflict with server-side maps.
var id = new MapId(--LastMapId);
while (MapManager.MapExists(id))
while (MapExists(id) || UsedIds.Contains(id))
{
id = new MapId(--LastMapId);
}
Expand Down
95 changes: 43 additions & 52 deletions Robust.Server/Console/Commands/MapCommands.cs
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
using System.Linq;
using System.Numerics;
using Robust.Server.GameObjects;
using Robust.Server.Maps;
using Robust.Shared.Console;
using Robust.Shared.ContentPack;
using Robust.Shared.EntitySerialization;
using Robust.Shared.EntitySerialization.Systems;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.Localization;
using Robust.Shared.Map;
using Robust.Shared.Maths;
using Robust.Shared.Utility;

namespace Robust.Server.Console.Commands
{
Expand Down Expand Up @@ -42,7 +43,7 @@ public override void Execute(IConsoleShell shell, string argStr, string[] args)
return;
}

_ent.System<MapLoaderSystem>().Save(uid, args[1]);
_ent.System<MapLoaderSystem>().TrySaveGrid(uid, new ResPath(args[1]));
shell.WriteLine("Save successful. Look in the user data directory.");
}

Expand All @@ -63,7 +64,6 @@ public override CompletionResult GetCompletion(IConsoleShell shell, string[] arg
public sealed class LoadGridCommand : LocalizedCommands
{
[Dependency] private readonly IEntitySystemManager _system = default!;
[Dependency] private readonly IMapManager _map = default!;
[Dependency] private readonly IResourceManager _resource = default!;

public override string Command => "loadgrid";
Expand Down Expand Up @@ -91,13 +91,14 @@ public override void Execute(IConsoleShell shell, string argStr, string[] args)
return;
}

if (!_map.MapExists(mapId))
var sys = _system.GetEntitySystem<SharedMapSystem>();
if (!sys.MapExists(mapId))
{
shell.WriteError("Target map does not exist.");
return;
}

var loadOptions = new MapLoadOptions();
Vector2 offset = default;
if (args.Length >= 4)
{
if (!float.TryParse(args[2], out var x))
Expand All @@ -112,9 +113,10 @@ public override void Execute(IConsoleShell shell, string argStr, string[] args)
return;
}

loadOptions.Offset = new Vector2(x, y);
offset = new Vector2(x, y);
}

Angle rot = default;
if (args.Length >= 5)
{
if (!float.TryParse(args[4], out var rotation))
Expand All @@ -123,9 +125,10 @@ public override void Execute(IConsoleShell shell, string argStr, string[] args)
return;
}

loadOptions.Rotation = Angle.FromDegrees(rotation);
rot = Angle.FromDegrees(rotation);
}

var opts = DeserializationOptions.Default;
if (args.Length >= 6)
{
if (!bool.TryParse(args[5], out var storeUids))
Expand All @@ -134,10 +137,11 @@ public override void Execute(IConsoleShell shell, string argStr, string[] args)
return;
}

loadOptions.StoreMapUids = storeUids;
opts.StoreYamlUids = storeUids;
}

_system.GetEntitySystem<MapLoaderSystem>().Load(mapId, args[1], loadOptions);
var path = new ResPath(args[1]);
_system.GetEntitySystem<MapLoaderSystem>().TryLoadGrid(mapId, path, out _, opts, offset, rot);
}

public override CompletionResult GetCompletion(IConsoleShell shell, string[] args)
Expand All @@ -149,7 +153,6 @@ public override CompletionResult GetCompletion(IConsoleShell shell, string[] arg
public sealed class SaveMap : LocalizedCommands
{
[Dependency] private readonly IEntitySystemManager _system = default!;
[Dependency] private readonly IMapManager _map = default!;
[Dependency] private readonly IResourceManager _resource = default!;

public override string Command => "savemap";
Expand Down Expand Up @@ -189,29 +192,29 @@ public override void Execute(IConsoleShell shell, string argStr, string[] args)
if (mapId == MapId.Nullspace)
return;

if (!_map.MapExists(mapId))
var sys = _system.GetEntitySystem<SharedMapSystem>();
if (!sys.MapExists(mapId))
{
shell.WriteError(Loc.GetString("cmd-savemap-not-exist"));
return;
}

if (_map.IsMapInitialized(mapId) &&
if (sys.IsInitialized(mapId) &&
( args.Length < 3 || !bool.TryParse(args[2], out var force) || !force))
{
shell.WriteError(Loc.GetString("cmd-savemap-init-warning"));
return;
}

shell.WriteLine(Loc.GetString("cmd-savemap-attempt", ("mapId", mapId), ("path", args[1])));
_system.GetEntitySystem<MapLoaderSystem>().SaveMap(mapId, args[1]);
_system.GetEntitySystem<MapLoaderSystem>().TrySaveMap(mapId, new ResPath(args[1]));
shell.WriteLine(Loc.GetString("cmd-savemap-success"));
}
}

public sealed class LoadMap : LocalizedCommands
{
[Dependency] private readonly IEntitySystemManager _system = default!;
[Dependency] private readonly IMapManager _map = default!;
[Dependency] private readonly IResourceManager _resource = default!;

public override string Command => "loadmap";
Expand Down Expand Up @@ -267,61 +270,49 @@ public override void Execute(IConsoleShell shell, string argStr, string[] args)
return;
}

if (_map.MapExists(mapId))
var sys = _system.GetEntitySystem<SharedMapSystem>();
if (sys.MapExists(mapId))
{
shell.WriteError(Loc.GetString("cmd-loadmap-exists", ("mapId", mapId)));
return;
}

var loadOptions = new MapLoadOptions();

float x = 0, y = 0;
if (args.Length >= 3)
float x = 0;
if (args.Length >= 3 && !float.TryParse(args[2], out x))
{
if (!float.TryParse(args[2], out x))
{
shell.WriteError(Loc.GetString("cmd-parse-failure-float", ("arg", args[2])));
return;
}
shell.WriteError(Loc.GetString("cmd-parse-failure-float", ("arg", args[2])));
return;
}

if (args.Length >= 4)
float y = 0;
if (args.Length >= 4 && !float.TryParse(args[3], out y))
{

if (!float.TryParse(args[3], out y))
{
shell.WriteError(Loc.GetString("cmd-parse-failure-float", ("arg", args[3])));
return;
}
shell.WriteError(Loc.GetString("cmd-parse-failure-float", ("arg", args[3])));
return;
}
var offset = new Vector2(x, y);

loadOptions.Offset = new Vector2(x, y);

if (args.Length >= 5)
float rotation = 0;
if (args.Length >= 5 && !float.TryParse(args[4], out rotation))
{
if (!float.TryParse(args[4], out var rotation))
{
shell.WriteError(Loc.GetString("cmd-parse-failure-float", ("arg", args[4])));
return;
}

loadOptions.Rotation = new Angle(rotation);
shell.WriteError(Loc.GetString("cmd-parse-failure-float", ("arg", args[4])));
return;
}
var rot = new Angle(rotation);

if (args.Length >= 6)
bool storeUids = false;
if (args.Length >= 6 && !bool.TryParse(args[5], out storeUids))
{
if (!bool.TryParse(args[5], out var storeUids))
{
shell.WriteError(Loc.GetString("cmd-parse-failure-bool", ("arg", args[5])));
return;
}

loadOptions.StoreMapUids = storeUids;
shell.WriteError(Loc.GetString("cmd-parse-failure-bool", ("arg", args[5])));
return;
}

_system.GetEntitySystem<MapLoaderSystem>().TryLoad(mapId, args[1], out _, loadOptions);
var opts = new DeserializationOptions {StoreYamlUids = storeUids};

var path = new ResPath(args[1]);
_system.GetEntitySystem<MapLoaderSystem>().TryLoadMapWithId(mapId, path, out _, out _, opts, offset, rot);

if (_map.MapExists(mapId))
if (sys.MapExists(mapId))
shell.WriteLine(Loc.GetString("cmd-loadmap-success", ("mapId", mapId), ("path", args[1])));
else
shell.WriteLine(Loc.GetString("cmd-loadmap-error", ("path", args[1])));
Expand Down
Loading

0 comments on commit fbc706f

Please sign in to comment.