Add more MapLoaderSystem TextReader/TextWriter overloads

Co-authored-by: kaylie <moony@hellomouse.net>
This commit is contained in:
PJB3005
2026-02-08 14:04:09 +01:00
parent fe1648d290
commit fd27f315cb
5 changed files with 342 additions and 78 deletions

View File

@@ -41,6 +41,7 @@ END TEMPLATE-->
* If a sandbox error is caused by a compiler-generated method, the engine will now attempt to point out which using code is responsible. * If a sandbox error is caused by a compiler-generated method, the engine will now attempt to point out which using code is responsible.
* Added `OrderedDictionary<TKey, TValue>` and `System.StringComparer` to the sandbox whitelist. * Added `OrderedDictionary<TKey, TValue>` and `System.StringComparer` to the sandbox whitelist.
* Added more overloads to `MapLoaderSystem` taking `TextReader`/`TextWriter` where appropriate.
### Bugfixes ### Bugfixes

View File

@@ -19,8 +19,8 @@ namespace Robust.Shared.EntitySerialization.Systems;
public sealed partial class MapLoaderSystem public sealed partial class MapLoaderSystem
{ {
/// <summary> /// <summary>
/// Tries to load entities from a yaml file. Whenever possible, you should try to use <see cref="TryLoadMap"/>, /// Tries to load entities from a YAML file. Whenever possible, you should try to use <see cref="TryLoadMap"/>,
/// <see cref="TryLoadGrid"/>, or <see cref="TryLoadEntity"/> instead. /// <see cref="TryLoadGrid"/>, or <see cref="TryLoadEntity"/> instead.
/// </summary> /// </summary>
public bool TryLoadGeneric( public bool TryLoadGeneric(
ResPath file, ResPath file,
@@ -30,6 +30,7 @@ public sealed partial class MapLoaderSystem
{ {
grids = null; grids = null;
maps = null; maps = null;
if (!TryLoadGeneric(file, out var data, options)) if (!TryLoadGeneric(file, out var data, options))
return false; return false;
@@ -39,33 +40,29 @@ public sealed partial class MapLoaderSystem
} }
/// <summary> /// <summary>
/// Tries to load entities from a YAML file, taking in a raw byte stream. /// Tries to load entities from a YAML text stream. Whenever possible, you should try to use <see cref="TryLoadMap"/>,
/// <see cref="TryLoadGrid"/>, or <see cref="TryLoadEntity"/> instead.
/// </summary> /// </summary>
/// <param name="file">The file contents to load from.</param>
/// <param name="fileName">
/// The name of the file being loaded. This is used purely for logging/informational purposes.
/// </param>
/// <param name="result">The result of the load operation.</param>
/// <param name="options">Options for the load operation.</param>
/// <returns>True if the load succeeded, false otherwise.</returns>
/// <seealso cref="M:Robust.Shared.EntitySerialization.Systems.MapLoaderSystem.TryLoadGeneric(Robust.Shared.Utility.ResPath,Robust.Shared.EntitySerialization.LoadResult@,System.Nullable{Robust.Shared.EntitySerialization.MapLoadOptions})"/>
public bool TryLoadGeneric( public bool TryLoadGeneric(
Stream file, TextReader reader,
string fileName, string source,
[NotNullWhen(true)] out LoadResult? result, [NotNullWhen(true)] out HashSet<Entity<MapComponent>>? maps,
[NotNullWhen(true)] out HashSet<Entity<MapGridComponent>>? grids,
MapLoadOptions? options = null) MapLoadOptions? options = null)
{ {
result = null; grids = null;
maps = null;
if (!TryReadFile(new StreamReader(file), out var data)) if (!TryLoadGeneric(reader, source, out var data, options))
return false; return false;
return TryLoadGeneric(data, fileName, out result, options); maps = data.Maps;
grids = data.Grids;
return true;
} }
/// <summary> /// <summary>
/// Tries to load entities from a yaml file. Whenever possible, you should try to use <see cref="TryLoadMap"/>, /// Tries to load entities from a YAML file. Whenever possible, you should try to use <see cref="TryLoadMap"/>,
/// <see cref="TryLoadGrid"/>, or <see cref="TryLoadEntity"/> instead. /// <see cref="TryLoadGrid"/>, or <see cref="TryLoadEntity"/> instead.
/// </summary> /// </summary>
/// <param name="file">The file to load.</param> /// <param name="file">The file to load.</param>
/// <param name="result">Data class containing information about the loaded entities</param> /// <param name="result">Data class containing information about the loaded entities</param>
@@ -80,9 +77,45 @@ public sealed partial class MapLoaderSystem
return TryLoadGeneric(data, file.ToString(), out result, options); return TryLoadGeneric(data, file.ToString(), out result, options);
} }
private bool TryLoadGeneric( /// <summary>
/// Tries to load entities from a YAML text stream. Whenever possible, you should try to use <see cref="TryLoadMap"/>,
/// <see cref="TryLoadGrid"/>, or <see cref="TryLoadEntity"/> instead.
/// </summary>
/// <param name="reader">The text to load.</param>
/// <param name="source">The name of the source, if any. This should be your file path (for example)</param>
/// <param name="result">Data class containing information about the loaded entities</param>
/// <param name="options">Optional Options for configuring loading behaviour.</param>
public bool TryLoadGeneric(TextReader reader, string source, [NotNullWhen(true)] out LoadResult? result, MapLoadOptions? options = null)
{
result = null;
if (!TryReadFile(reader, out var data))
return false;
return TryLoadGeneric(data, source, out result, options);
}
/// <summary>
/// Tries to load entities from a YAML text stream. Whenever possible, you should try to use <see cref="TryLoadMap"/>,
/// <see cref="TryLoadGrid"/>, or <see cref="TryLoadEntity"/> instead.
/// </summary>
/// <param name="stream">The stream containing the text to load.</param>
/// <param name="source">The name of the source, if any. This should be your file path (for example)</param>
/// <param name="result">Data class containing information about the loaded entities</param>
/// <param name="options">Optional Options for configuring loading behaviour.</param>
public bool TryLoadGeneric(Stream stream, string source, [NotNullWhen(true)] out LoadResult? result, MapLoadOptions? options = null)
{
result = null;
if (!TryReadFile(new StreamReader(stream, leaveOpen: true), out var data))
return false;
return TryLoadGeneric(data, source, out result, options);
}
public bool TryLoadGeneric(
MappingDataNode data, MappingDataNode data,
string fileName, string source,
[NotNullWhen(true)] out LoadResult? result, [NotNullWhen(true)] out LoadResult? result,
MapLoadOptions? options = null) MapLoadOptions? options = null)
{ {
@@ -118,7 +151,7 @@ public sealed partial class MapLoaderSystem
if (!deserializer.TryProcessData()) if (!deserializer.TryProcessData())
{ {
Log.Debug($"Failed to process entity data in {fileName}"); Log.Debug($"Failed to process entity data in {source}");
return false; return false;
} }
@@ -128,7 +161,7 @@ public sealed partial class MapLoaderSystem
&& deserializer.Result.Category != FileCategory.Unknown) && deserializer.Result.Category != FileCategory.Unknown)
{ {
// Did someone try to load a map file as a grid or vice versa? // Did someone try to load a map file as a grid or vice versa?
Log.Error($"Map {fileName} does not contain the expected data. Expected {expected} but got {deserializer.Result.Category}"); Log.Error($"Map {source} does not contain the expected data. Expected {expected} but got {deserializer.Result.Category}");
Delete(deserializer.Result); Delete(deserializer.Result);
return false; return false;
} }
@@ -139,7 +172,7 @@ public sealed partial class MapLoaderSystem
} }
catch (Exception e) catch (Exception e)
{ {
Log.Error($"Caught exception while creating entities for map {fileName}: {e}"); Log.Error($"Caught exception while creating entities for map {source}: {e}");
Delete(deserializer.Result); Delete(deserializer.Result);
throw; throw;
} }
@@ -149,7 +182,7 @@ public sealed partial class MapLoaderSystem
if (opts.ExpectedCategory is { } exp && exp != deserializer.Result.Category) if (opts.ExpectedCategory is { } exp && exp != deserializer.Result.Category)
{ {
// Did someone try to load a map file as a grid or vice versa? // Did someone try to load a map file as a grid or vice versa?
Log.Error($"Map {fileName} does not contain the expected data. Expected {exp} but got {deserializer.Result.Category}"); Log.Error($"Map {source} does not contain the expected data. Expected {exp} but got {deserializer.Result.Category}");
Delete(deserializer.Result); Delete(deserializer.Result);
return false; return false;
} }
@@ -184,12 +217,33 @@ public sealed partial class MapLoaderSystem
} }
/// <summary> /// <summary>
/// Tries to load a regular (non-map, non-grid) entity from a file. /// Tries to load a regular (non-map, non-grid) entity from a YAML file.
/// The loaded entity will initially be in null-space. /// The loaded entity will initially be in null-space.
/// If the file does not contain exactly one orphaned entity, this will return false and delete loaded entities. /// If the file does not contain exactly one orphaned entity, this will return false and delete loaded entities.
/// </summary> /// </summary>
public bool TryLoadEntity( public bool TryLoadEntity(
ResPath path, ResPath file,
[NotNullWhen(true)] out Entity<TransformComponent>? entity,
DeserializationOptions? options = null)
{
entity = null;
if (!TryGetReader(file, out var reader))
return false;
using (reader)
{
return TryLoadEntity(reader, file.ToString(), out entity, options);
}
}
/// <summary>
/// Tries to load a regular (non-map, non-grid) entity from a YAML text stream.
/// The loaded entity will initially be in null-space.
/// If the file does not contain exactly one orphaned entity, this will return false and delete loaded entities.
/// </summary>
public bool TryLoadEntity(
TextReader reader,
string source,
[NotNullWhen(true)] out Entity<TransformComponent>? entity, [NotNullWhen(true)] out Entity<TransformComponent>? entity,
DeserializationOptions? options = null) DeserializationOptions? options = null)
{ {
@@ -200,7 +254,7 @@ public sealed partial class MapLoaderSystem
}; };
entity = null; entity = null;
if (!TryLoadGeneric(path, out var result, opts)) if (!TryLoadGeneric(reader, source, out var result, opts))
return false; return false;
if (result.Orphans.Count == 1) if (result.Orphans.Count == 1)
@@ -215,12 +269,35 @@ public sealed partial class MapLoaderSystem
} }
/// <summary> /// <summary>
/// Tries to load a grid entity from a file and parent it to the given map. /// Tries to load a grid entity from a YAML file and parent it to the given map.
/// If the file does not contain exactly one grid, this will return false and delete loaded entities. /// If the file does not contain exactly one grid, this will return false and delete loaded entities.
/// </summary> /// </summary>
public bool TryLoadGrid( public bool TryLoadGrid(
MapId map, MapId map,
ResPath path, ResPath file,
[NotNullWhen(true)] out Entity<MapGridComponent>? grid,
DeserializationOptions? options = null,
Vector2 offset = default,
Angle rot = default)
{
grid = null;
if (!TryGetReader(file, out var reader))
return false;
using (reader)
{
return TryLoadGrid(map, reader, file.ToString(), out grid, options, offset, rot);
}
}
/// <summary>
/// Tries to load a grid entity from a YAML text stream and parent it to the given map.
/// If the file does not contain exactly one grid, this will return false and delete loaded entities.
/// </summary>
public bool TryLoadGrid(
MapId map,
TextReader reader,
string source,
[NotNullWhen(true)] out Entity<MapGridComponent>? grid, [NotNullWhen(true)] out Entity<MapGridComponent>? grid,
DeserializationOptions? options = null, DeserializationOptions? options = null,
Vector2 offset = default, Vector2 offset = default,
@@ -236,7 +313,7 @@ public sealed partial class MapLoaderSystem
}; };
grid = null; grid = null;
if (!TryLoadGeneric(path, out var result, opts)) if (!TryLoadGeneric(reader, source, out var result, opts))
return false; return false;
if (result.Grids.Count == 1) if (result.Grids.Count == 1)
@@ -250,11 +327,35 @@ public sealed partial class MapLoaderSystem
} }
/// <summary> /// <summary>
/// Tries to load a grid entity from a file and parent it to a newly created map. /// Tries to load a grid entity from a YAML file and parent it to a newly created map.
/// If the file does not contain exactly one grid, this will return false and delete loaded entities. /// If the file does not contain exactly one grid, this will return false and delete loaded entities.
/// </summary> /// </summary>
public bool TryLoadGrid( public bool TryLoadGrid(
ResPath path, ResPath file,
[NotNullWhen(true)] out Entity<MapComponent>? map,
[NotNullWhen(true)] out Entity<MapGridComponent>? grid,
DeserializationOptions? options = null,
Vector2 offset = default,
Angle rot = default)
{
grid = null;
map = null;
if (!TryGetReader(file, out var reader))
return false;
using (reader)
{
return TryLoadGrid(reader, file.ToString(), out map, out grid, options, offset, rot);
}
}
/// <summary>
/// Tries to load a grid entity from a YAML text stream and parent it to a newly created map.
/// If the file does not contain exactly one grid, this will return false and delete loaded entities.
/// </summary>
public bool TryLoadGrid(
TextReader reader,
string source,
[NotNullWhen(true)] out Entity<MapComponent>? map, [NotNullWhen(true)] out Entity<MapComponent>? map,
[NotNullWhen(true)] out Entity<MapGridComponent>? grid, [NotNullWhen(true)] out Entity<MapGridComponent>? grid,
DeserializationOptions? options = null, DeserializationOptions? options = null,
@@ -267,7 +368,7 @@ public sealed partial class MapLoaderSystem
if (opts.PauseMaps) if (opts.PauseMaps)
_mapSystem.SetPaused(mapUid, true); _mapSystem.SetPaused(mapUid, true);
if (!TryLoadGrid(mapId, path, out grid, options, offset, rot)) if (!TryLoadGrid(mapId, reader, source, out grid, options, offset, rot))
{ {
Del(mapUid); Del(mapUid);
map = null; map = null;

View File

@@ -1,6 +1,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis; using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Linq; using System.Linq;
using System.Numerics; using System.Numerics;
using Robust.Shared.GameObjects; using Robust.Shared.GameObjects;
@@ -15,14 +16,41 @@ namespace Robust.Shared.EntitySerialization.Systems;
public sealed partial class MapLoaderSystem public sealed partial class MapLoaderSystem
{ {
/// <summary> /// <summary>
/// Attempts to load a file containing a single map. /// Attempts to load a YAML file containing a single map.
/// If the file does not contain exactly one map, this will return false and delete all loaded entities. /// If the file does not contain exactly one map, this will return false and delete all loaded entities.
/// </summary> /// </summary>
/// <remarks> /// <remarks>
/// Note that this will not automatically initialize the map, unless specified via the <see cref="DeserializationOptions"/>. /// Note that this will not automatically initialize the map, unless specified via the <see cref="DeserializationOptions"/>.
/// </remarks> /// </remarks>
public bool TryLoadMap( public bool TryLoadMap(
ResPath path, ResPath file,
[NotNullWhen(true)] out Entity<MapComponent>? map,
[NotNullWhen(true)] out HashSet<Entity<MapGridComponent>>? grids,
DeserializationOptions? options = null,
Vector2 offset = default,
Angle rot = default)
{
map = null;
grids = null;
if (!TryGetReader(file, out var reader))
return false;
using (reader)
{
return TryLoadMap(reader, file.ToString(), out map, out grids, options, offset, rot);
}
}
/// <summary>
/// Attempts to load a YAML stream containing a single map.
/// If the file does not contain exactly one map, this will return false and delete all loaded entities.
/// </summary>
/// <remarks>
/// Note that this will not automatically initialize the map, unless specified via the <see cref="DeserializationOptions"/>.
/// </remarks>
public bool TryLoadMap(
TextReader reader,
string source,
[NotNullWhen(true)] out Entity<MapComponent>? map, [NotNullWhen(true)] out Entity<MapComponent>? map,
[NotNullWhen(true)] out HashSet<Entity<MapGridComponent>>? grids, [NotNullWhen(true)] out HashSet<Entity<MapGridComponent>>? grids,
DeserializationOptions? options = null, DeserializationOptions? options = null,
@@ -39,7 +67,7 @@ public sealed partial class MapLoaderSystem
map = null; map = null;
grids = null; grids = null;
if (!TryLoadGeneric(path, out var result, opts)) if (!TryLoadGeneric(reader, source, out var result, opts))
return false; return false;
if (result.Maps.Count == 1) if (result.Maps.Count == 1)
@@ -54,17 +82,47 @@ public sealed partial class MapLoaderSystem
} }
/// <summary> /// <summary>
/// Attempts to load a file containing a single map, assign it the given map id. /// Attempts to load a YAML file containing a single map, assign it the given map id.
/// </summary> /// </summary>
/// <remarks> /// <remarks>
/// If possible, it is better to use <see cref="TryLoadMap"/> which automatically assigns a <see cref="MapId"/>. /// If possible, it is better to use <see cref="TryLoadMap"/> which automatically assigns a <see cref="MapId"/>.
/// </remarks> /// </remarks>
/// <remarks> /// <remarks>
/// Note that this will not automatically initialize the map, unless specified via the <see cref="DeserializationOptions"/>. /// Note that this will not automatically initialize the map, unless specified via the <see cref="DeserializationOptions"/>.
/// </remarks> /// </remarks>
public bool TryLoadMapWithId( public bool TryLoadMapWithId(
MapId mapId, MapId mapId,
ResPath path, ResPath file,
[NotNullWhen(true)] out Entity<MapComponent>? map,
[NotNullWhen(true)] out HashSet<Entity<MapGridComponent>>? grids,
DeserializationOptions? options = null,
Vector2 offset = default,
Angle rot = default)
{
map = null;
grids = null;
if (!TryGetReader(file, out var reader))
return false;
using (reader)
{
return TryLoadMapWithId(mapId, reader, file.ToString(), out map, out grids, options, offset, rot);
}
}
/// <summary>
/// Attempts to load a YAML text stream containing a single map, assign it the given map id.
/// </summary>
/// <remarks>
/// If possible, it is better to use <see cref="TryLoadMap"/> which automatically assigns a <see cref="MapId"/>.
/// </remarks>
/// <remarks>
/// Note that this will not automatically initialize the map, unless specified via the <see cref="DeserializationOptions"/>.
/// </remarks>
public bool TryLoadMapWithId(
MapId mapId,
TextReader reader,
string source,
[NotNullWhen(true)] out Entity<MapComponent>? map, [NotNullWhen(true)] out Entity<MapComponent>? map,
[NotNullWhen(true)] out HashSet<Entity<MapGridComponent>>? grids, [NotNullWhen(true)] out HashSet<Entity<MapGridComponent>>? grids,
DeserializationOptions? options = null, DeserializationOptions? options = null,
@@ -86,7 +144,7 @@ public sealed partial class MapLoaderSystem
throw new Exception($"Target map already exists"); throw new Exception($"Target map already exists");
opts.ForceMapId = mapId; opts.ForceMapId = mapId;
if (!TryLoadGeneric(path, out var result, opts)) if (!TryLoadGeneric(reader, source, out var result, opts))
return false; return false;
if (!_mapSystem.TryGetMap(mapId, out var uid) || !TryComp(uid, out MapComponent? comp)) if (!_mapSystem.TryGetMap(mapId, out var uid) || !TryComp(uid, out MapComponent? comp))
@@ -98,12 +156,35 @@ public sealed partial class MapLoaderSystem
} }
/// <summary> /// <summary>
/// Attempts to load a file containing a single map, and merge its children onto another map. After which the /// Attempts to load a YAML text stream containing a single map, and merge its children onto another map. After which
/// loaded map gets deleted. /// the loaded map gets deleted.
/// </summary> /// </summary>
public bool TryMergeMap( public bool TryMergeMap(
MapId mapId, MapId mapId,
ResPath path, ResPath file,
[NotNullWhen(true)] out HashSet<Entity<MapGridComponent>>? grids,
DeserializationOptions? options = null,
Vector2 offset = default,
Angle rot = default)
{
grids = null;
if (!TryGetReader(file, out var reader))
return false;
using (reader)
{
return TryMergeMap(mapId, reader, file.ToString(), out grids, options, offset, rot);
}
}
/// <summary>
/// Attempts to load a YAML file containing a single map, and merge its children onto another map. After which
/// the loaded map gets deleted.
/// </summary>
public bool TryMergeMap(
MapId mapId,
TextReader reader,
string source,
[NotNullWhen(true)] out HashSet<Entity<MapGridComponent>>? grids, [NotNullWhen(true)] out HashSet<Entity<MapGridComponent>>? grids,
DeserializationOptions? options = null, DeserializationOptions? options = null,
Vector2 offset = default, Vector2 offset = default,
@@ -123,7 +204,7 @@ public sealed partial class MapLoaderSystem
throw new Exception($"Target map {mapId} does not exist"); throw new Exception($"Target map {mapId} does not exist");
opts.MergeMap = mapId; opts.MergeMap = mapId;
if (!TryLoadGeneric(path, out var result, opts)) if (!TryLoadGeneric(reader, source, out var result, opts))
return false; return false;
if (!_mapSystem.TryGetMap(mapId, out var uid) || !TryComp(uid, out MapComponent? comp)) if (!_mapSystem.TryGetMap(mapId, out var uid) || !TryComp(uid, out MapComponent? comp))

View File

@@ -1,6 +1,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis; using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Linq; using System.Linq;
using Robust.Shared.GameObjects; using Robust.Shared.GameObjects;
using Robust.Shared.Map; using Robust.Shared.Map;
@@ -59,10 +60,19 @@ public sealed partial class MapLoaderSystem
} }
/// <summary> /// <summary>
/// Serialize a standard (non-grid, non-map) entity and all of its children and write the result to a /// Serialize a standard (non-grid, non-map) entity and all of its children and write the result to a YAML file.
/// yaml file.
/// </summary> /// </summary>
public bool TrySaveEntity(EntityUid entity, ResPath path, SerializationOptions? options = null) public bool TrySaveEntity(EntityUid entity, ResPath target, SerializationOptions? options = null)
{
using var writer = GetWriterForPath(target);
return TrySaveEntity(entity, writer, options);
}
/// <summary>
/// Serialize a standard (non-grid, non-map) entity and all of its children and write the result to a YAML text
/// stream.
/// </summary>
public bool TrySaveEntity(EntityUid entity, TextWriter target, SerializationOptions? options = null)
{ {
if (_mapQuery.HasComp(entity)) if (_mapQuery.HasComp(entity))
{ {
@@ -97,12 +107,12 @@ public sealed partial class MapLoaderSystem
return false; return false;
} }
Write(path, data); Write(target, data);
return true; return true;
} }
/// <summary> /// <summary>
/// Serialize a map and all of its children and write the result to a yaml file. /// Serialize a map and all of its children and write the result to a YAML file.
/// </summary> /// </summary>
public bool TrySaveMap(MapId mapId, ResPath path, SerializationOptions? options = null) public bool TrySaveMap(MapId mapId, ResPath path, SerializationOptions? options = null)
{ {
@@ -114,9 +124,18 @@ public sealed partial class MapLoaderSystem
} }
/// <summary> /// <summary>
/// Serialize a map and all of its children and write the result to a yaml file. /// Serialize a map and all of its children and write the result to a YAML file.
/// </summary> /// </summary>
public bool TrySaveMap(EntityUid map, ResPath path, SerializationOptions? options = null) public bool TrySaveMap(EntityUid map, ResPath target, SerializationOptions? options = null)
{
using var writer = GetWriterForPath(target);
return TrySaveMap(map, writer, options);
}
/// <summary>
/// Serialize a map and all of its children and write the result to a YAML text stream.
/// </summary>
public bool TrySaveMap(EntityUid map, TextWriter target, SerializationOptions? options = null)
{ {
if (!_mapQuery.HasComp(map)) if (!_mapQuery.HasComp(map))
{ {
@@ -145,14 +164,23 @@ public sealed partial class MapLoaderSystem
return false; return false;
} }
Write(path, data); Write(target, data);
return true; return true;
} }
/// <summary> /// <summary>
/// Serialize a grid and all of its children and write the result to a yaml file. /// Serialize a grid and all of its children and write the result to a YAML file.
/// </summary> /// </summary>
public bool TrySaveGrid(EntityUid grid, ResPath path, SerializationOptions? options = null) public bool TrySaveGrid(EntityUid map, ResPath target, SerializationOptions? options = null)
{
using var writer = GetWriterForPath(target);
return TrySaveGrid(map, writer, options);
}
/// <summary>
/// Serialize a grid and all of its children and write the result to a YAML text stream.
/// </summary>
public bool TrySaveGrid(EntityUid grid, TextWriter target, SerializationOptions? options = null)
{ {
if (!_gridQuery.HasComp(grid)) if (!_gridQuery.HasComp(grid))
{ {
@@ -187,32 +215,62 @@ public sealed partial class MapLoaderSystem
return false; return false;
} }
Write(path, data); Write(target, data);
return true; return true;
} }
/// <summary> /// <summary>
/// Serialize an entities and all of their children to a yaml file. /// Serialize an entity and all of their children to a YAML file.
/// This makes no assumptions about the expected entity or resulting file category. /// This makes no assumptions about the expected entity or resulting file category.
/// If possible, use the map/grid specific variants instead. /// If possible, use the map/grid specific variants instead.
/// </summary> /// </summary>
public bool TrySaveGeneric( public bool TrySaveGeneric(
EntityUid uid, EntityUid uid,
ResPath path, ResPath target,
out FileCategory category, out FileCategory category,
SerializationOptions? options = null) SerializationOptions? options = null)
{ {
return TrySaveGeneric([uid], path, out category, options); using var writer = GetWriterForPath(target);
return TrySaveGeneric(uid, writer, out category, options);
} }
/// <summary> /// <summary>
/// Serialize one or more entities and all of their children to a yaml file. /// Serialize an entity and all of their children to a YAML text stream.
/// This makes no assumptions about the expected entity or resulting file category. /// This makes no assumptions about the expected entity or resulting file category.
/// If possible, use the map/grid specific variants instead. /// If possible, use the map/grid specific variants instead.
/// </summary>
public bool TrySaveGeneric(
EntityUid uid,
TextWriter target,
out FileCategory category,
SerializationOptions? options = null)
{
return TrySaveGeneric([uid], target, out category, options);
}
/// <summary>
/// Serialize one or more entities and all of their children to a YAML file.
/// This makes no assumptions about the expected entity or resulting file category.
/// If possible, use the map/grid specific variants instead.
/// </summary>
public bool TrySaveGeneric(
HashSet<EntityUid> uid,
ResPath target,
out FileCategory category,
SerializationOptions? options = null)
{
using var writer = GetWriterForPath(target);
return TrySaveGeneric(uid, writer, out category, options);
}
/// <summary>
/// Serialize one or more entities and all of their children to a YAML text stream.
/// This makes no assumptions about the expected entity or resulting file category.
/// If possible, use the map/grid specific variants instead.
/// </summary> /// </summary>
public bool TrySaveGeneric( public bool TrySaveGeneric(
HashSet<EntityUid> entities, HashSet<EntityUid> entities,
ResPath path, TextWriter target,
out FileCategory category, out FileCategory category,
SerializationOptions? options = null) SerializationOptions? options = null)
{ {
@@ -233,10 +291,21 @@ public sealed partial class MapLoaderSystem
return false; return false;
} }
Write(path, data); Write(target, data);
return true; return true;
} }
/// <inheritdoc cref="TrySerializeAllEntities(out MappingDataNode, SerializationOptions?)"/>
public bool TrySaveAllEntities(TextWriter target, SerializationOptions? options = null)
{
if (!TrySerializeAllEntities(out var data, options))
return false;
Write(target, data);
return true;
}
/// <inheritdoc cref="TrySerializeAllEntities(out MappingDataNode, SerializationOptions?)"/> /// <inheritdoc cref="TrySerializeAllEntities(out MappingDataNode, SerializationOptions?)"/>
public bool TrySaveAllEntities(ResPath path, SerializationOptions? options = null) public bool TrySaveAllEntities(ResPath path, SerializationOptions? options = null)
{ {

View File

@@ -42,17 +42,29 @@ public sealed partial class MapLoaderSystem : EntitySystem
_gridQuery = GetEntityQuery<MapGridComponent>(); _gridQuery = GetEntityQuery<MapGridComponent>();
} }
private void Write(TextWriter target, MappingDataNode data)
{
var document = new YamlDocument(data.ToYaml());
var stream = new YamlStream {document};
stream.Save(new YamlMappingFix(new Emitter(target)), false);
}
private StreamWriter GetWriterForPath(ResPath path)
{
Log.Info($"Saving serialized results to {path}");
path = path.ToRootedPath();
_resourceManager.UserData.CreateDir(path.Directory);
return _resourceManager.UserData.OpenWriteText(path);
}
private void Write(ResPath path, MappingDataNode data) private void Write(ResPath path, MappingDataNode data)
{ {
Log.Info($"Saving serialized results to {path}"); Log.Info($"Saving serialized results to {path}");
path = path.ToRootedPath(); path = path.ToRootedPath();
var document = new YamlDocument(data.ToYaml());
_resourceManager.UserData.CreateDir(path.Directory); _resourceManager.UserData.CreateDir(path.Directory);
using var writer = _resourceManager.UserData.OpenWriteText(path); using var writer = _resourceManager.UserData.OpenWriteText(path);
{
var stream = new YamlStream {document}; Write(writer, data);
stream.Save(new YamlMappingFix(new Emitter(writer)), false);
}
} }
public bool TryReadFile(ResPath file, [NotNullWhen(true)] out MappingDataNode? data) public bool TryReadFile(ResPath file, [NotNullWhen(true)] out MappingDataNode? data)