Files
RobustToolbox/Robust.Shared/EntitySerialization/Systems/MapLoaderSystem.cs
83c2a1be11 [Dependency] source generator part 2 (#6550)
* [Dependency] source generator

No more reflection, no more codegen at runtime

Also various changes to Roslyn helpers to make this easier to write.

Requires all types with dependencies to be partial and not have readonly dependency fields. An analyzer enforces this at warning level, the previous injection strategies have remained in the code *for now* as a fallback.

No fallback is available for [field: Dependency] properties, due to a Roslyn bug.

Code Fixes exist. We love Roslyn

* Apply dependencies generator changes to all code

* Release notes

* Preprocessor got hands

* Handle nullable dependencies

These are bad but gotta deal with it.

* Apply suggestions from code review

Co-authored-by: Moony <moony@hellomouse.net>

* Fine, let's not use collection expressions

---------

Co-authored-by: Moony <moony@hellomouse.net>
2026-05-08 12:38:33 +02:00

153 lines
4.8 KiB
C#

using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Linq;
using Robust.Shared.ContentPack;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.Map.Components;
using Robust.Shared.Serialization;
using Robust.Shared.Serialization.Markdown;
using Robust.Shared.Serialization.Markdown.Mapping;
using Robust.Shared.Timing;
using Robust.Shared.Utility;
using YamlDotNet.Core;
using YamlDotNet.RepresentationModel;
namespace Robust.Shared.EntitySerialization.Systems;
/// <summary>
/// This class provides methods for saving and loading maps and grids.
/// </summary>
/// <remarks>
/// The save & load methods are basically wrappers around <see cref="EntitySerializer"/> and
/// <see cref="EntityDeserializer"/>, which can be used for more control over serialization.
/// </remarks>
public sealed partial class MapLoaderSystem : EntitySystem
{
[Dependency] private IResourceManager _resourceManager = default!;
[Dependency] private SharedMapSystem _mapSystem = default!;
[Dependency] private SharedTransformSystem _xform = default!;
[Dependency] private IDependencyCollection _dependency = default!;
private Stopwatch _stopwatch = new();
private EntityQuery<MapComponent> _mapQuery;
private EntityQuery<MapGridComponent> _gridQuery;
public override void Initialize()
{
base.Initialize();
_gridQuery = GetEntityQuery<MapGridComponent>();
_mapQuery = GetEntityQuery<MapComponent>();
_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)
{
Log.Info($"Saving serialized results to {path}");
path = path.ToRootedPath();
_resourceManager.UserData.CreateDir(path.Directory);
using var writer = _resourceManager.UserData.OpenWriteText(path);
Write(writer, data);
}
public bool TryReadFile(ResPath file, [NotNullWhen(true)] out MappingDataNode? data)
{
var resPath = file.ToRootedPath();
data = null;
if (!TryGetReader(resPath, out var reader))
return false;
Log.Info($"Loading file: {resPath}");
return TryReadFile(reader, out data);
}
private bool TryReadFile(TextReader reader, [NotNullWhen(true)] out MappingDataNode? data)
{
data = null;
_stopwatch.Restart();
using var textReader = reader;
var documents = DataNodeParser.ParseYamlStream(reader).ToArray();
Log.Debug($"Loaded yml stream in {_stopwatch.Elapsed}");
// Yes, logging errors in a "try" method is kinda shit, but it was throwing exceptions when I found it and it does
// make sense to at least provide some kind of feedback for why it failed.
switch (documents.Length)
{
case < 1:
Log.Error("Stream has no YAML documents.");
return false;
case > 1:
Log.Error("Stream too many YAML documents. Map files store exactly one.");
return false;
default:
data = (MappingDataNode) documents[0].Root;
return true;
}
}
private bool TryGetReader(ResPath resPath, [NotNullWhen(true)] out TextReader? reader)
{
if (_resourceManager.UserData.Exists(resPath))
{
// Log warning if file exists in both user and content data.
if (_resourceManager.ContentFileExists(resPath))
Log.Warning("Reading map user data instead of content");
reader = _resourceManager.UserData.OpenText(resPath);
return true;
}
if (_resourceManager.TryContentFileRead(resPath, out var contentReader))
{
reader = new StreamReader(contentReader);
return true;
}
Log.Error($"File not found: {resPath}");
reader = null;
return false;
}
/// <summary>
/// Helper method for deleting all loaded entities.
/// </summary>
public void Delete(LoadResult result)
{
foreach (var uid in result.Maps)
{
Del(uid);
}
foreach (var uid in result.Orphans)
{
Del(uid);
}
foreach (var uid in result.Entities)
{
Del(uid);
}
}
}