Prototype load parallelization (#3502)

This commit is contained in:
Pieter-Jan Briers
2022-12-20 22:46:30 +01:00
committed by GitHub
parent 2aafb21772
commit 84733a335c
94 changed files with 2140 additions and 1249 deletions

View File

@@ -35,7 +35,8 @@ END TEMPLATE-->
### Breaking changes
*None yet*
* `ITypeReader<,>.Read(...)` and `ITypeCopier<>.Copy(...)` have had their `bool skipHook` parameter replaced with a `SerializationHookContext` to facilitate multithreaded prototype loading.
* Prototypes are now loaded in parallel across multiple threads. Type serializers, property setters, etc... must be thread safe and not rely on an active IoC instance.
### New features
@@ -43,16 +44,21 @@ END TEMPLATE-->
### Bugfixes
*None yet*
* Mapped string serializer once again is initialized with prototype strongs, reducing bandwidth usage.
### Other
*None yet*
* Drastically improved startup time by running prototype loading in parallel.
* `AfterDeserialization` hooks are still ran on the main thread during load to avoid issues.
* Various systems in the serialization system such as `SerializationManager` or `ReflectionManager` have had various methods made thread safe.
* `TileAliasPrototype` no longer has a load priority set.
* Straightened out terminology in prototypes: to refer to the type of a prototype (e.g. `EntityPrototype` itself), use "kind".
* This was previously mixed between "type" and "variant".
### Internal
*None yet*
* `SpanSplitExtensions` has been taken behind the shed for being horrifically wrong unsafe code that should never have been entered into a keyboard ever. A simpler helper method replaces its use in `Box2Serializer`.
* `PrototypeManager.cs` has been split apart into multiple files.
## 0.73.0.0

View File

@@ -1,5 +1,6 @@
using System.Globalization;
using Robust.Shared.IoC;
using Robust.Shared.Serialization;
using Robust.Shared.Serialization.Manager;
using Robust.Shared.Serialization.Markdown;
using Robust.Shared.Serialization.Markdown.Validation;
@@ -19,7 +20,7 @@ namespace Robust.Benchmarks.Serialization
}
public int Read(ISerializationManager serializationManager, ValueDataNode node,
IDependencyCollection dependencies, bool skipHook, ISerializationContext? context = null,
IDependencyCollection dependencies, SerializationHookContext hookCtx, ISerializationContext? context = null,
ISerializationManager.InstantiationDelegate<int>? instanceProvider = null)
{
return int.Parse(node.Value, CultureInfo.InvariantCulture);
@@ -32,7 +33,7 @@ namespace Robust.Benchmarks.Serialization
return new ValueDataNode(value.ToString(CultureInfo.InvariantCulture));
}
public int CreateCopy(ISerializationManager serializationManager, int source, bool skipHook,
public int CreateCopy(ISerializationManager serializationManager, int source, SerializationHookContext hookCtx,
ISerializationContext? context = null)
{
return source;

View File

@@ -48,6 +48,7 @@ namespace Robust.Client
deps.Register<IGameTiming, ClientGameTiming>();
deps.Register<IClientGameTiming, ClientGameTiming>();
deps.Register<IPrototypeManager, ClientPrototypeManager>();
deps.Register<IPrototypeManagerInternal, ClientPrototypeManager>();
deps.Register<IMapManager, NetworkedMapManager>();
deps.Register<IMapManagerInternal, NetworkedMapManager>();
deps.Register<INetworkedMapManager, NetworkedMapManager>();

View File

@@ -157,7 +157,9 @@ namespace Robust.Client.Graphics.Clyde
{
FullMode = BoundedChannelFullMode.Wait,
SingleReader = true,
SingleWriter = true
SingleWriter = true,
// For unblocking continuations.
AllowSynchronousContinuations = true
});
_eventReader = eventChannel.Reader;

View File

@@ -150,7 +150,9 @@ internal partial class Clyde
{
FullMode = BoundedChannelFullMode.Wait,
SingleReader = true,
SingleWriter = true
SingleWriter = true,
// For unblocking continuations.
AllowSynchronousContinuations = true
});
_eventReader = eventChannel.Reader;

View File

@@ -18,7 +18,7 @@ namespace Robust.Client.Serialization
{
public AppearanceVisualizer Read(ISerializationManager serializationManager, MappingDataNode node,
IDependencyCollection dependencies,
bool skipHook,
SerializationHookContext hookCtx,
ISerializationContext? context = null, ISerializationManager.InstantiationDelegate<AppearanceVisualizer>? instanceProvider = null)
{
Type? type = null;
@@ -38,7 +38,7 @@ namespace Robust.Client.Serialization
var newNode = node.Copy();
newNode.Remove("type");
return (AppearanceVisualizer) serializationManager.Read(type, newNode, context, skipHook)!;
return (AppearanceVisualizer) serializationManager.Read(type, newNode, hookCtx, context)!;
}
public ValidationNode Validate(ISerializationManager serializationManager, MappingDataNode node,

View File

@@ -8,6 +8,7 @@ using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.CustomControls;
using Robust.Shared.Enums;
using Robust.Shared.IoC;
using Robust.Shared.Localization;
using Robust.Shared.Map;
using Robust.Shared.Utility;
using static Robust.Client.UserInterface.Controls.BaseButton;
@@ -133,11 +134,11 @@ public sealed class TileSpawningUIController : UIController
if (!string.IsNullOrEmpty(searchStr))
{
tileDefs = tileDefs.Where(s =>
s.Name.Contains(searchStr, StringComparison.InvariantCultureIgnoreCase) ||
Loc.GetString(s.Name).Contains(searchStr, StringComparison.CurrentCultureIgnoreCase) ||
s.ID.Contains(searchStr, StringComparison.OrdinalIgnoreCase));
}
tileDefs = tileDefs.OrderBy(d => d.Name);
tileDefs = tileDefs.OrderBy(d => Loc.GetString(d.Name));
_shownTiles.Clear();
_shownTiles.AddRange(tileDefs);
@@ -151,7 +152,7 @@ public sealed class TileSpawningUIController : UIController
{
texture = _resources.GetResource<TextureResource>(path);
}
_window.TileList.AddItem(entry.Name, texture);
_window.TileList.AddItem(Loc.GetString(entry.Name), texture);
}
}
}

View File

@@ -90,7 +90,7 @@ namespace Robust.Server
[Dependency] private readonly IServerConsoleHost _consoleHost = default!;
[Dependency] private readonly IParallelManagerInternal _parallelMgr = default!;
[Dependency] private readonly ProfManager _prof = default!;
[Dependency] private readonly IPrototypeManager _prototype = default!;
[Dependency] private readonly IPrototypeManagerInternal _prototype = default!;
[Dependency] private readonly IPlacementManager _placement = default!;
[Dependency] private readonly IServerViewVariablesInternal _viewVariables = default!;
[Dependency] private readonly ISerializationManager _serialization = default!;
@@ -317,11 +317,11 @@ namespace Robust.Server
//IoCManager.Resolve<IMapLoader>().LoadedMapData +=
// IoCManager.Resolve<IRobustMappedStringSerializer>().AddStrings;
_prototype.LoadedData += (yaml, name) =>
_prototype.LoadedData += data =>
{
if (!_stringSerializer.Locked)
{
_stringSerializer.AddStrings(yaml);
_stringSerializer.AddStrings(data.Root);
}
};

View File

@@ -5,6 +5,7 @@ using Robust.Server.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.Map;
using Robust.Shared.Maths;
using Robust.Shared.Serialization;
using Robust.Shared.Serialization.Manager;
using Robust.Shared.Serialization.Manager.Attributes;
using Robust.Shared.Serialization.Markdown;
@@ -25,9 +26,9 @@ internal sealed class MapChunkSerializer : ITypeSerializer<MapChunk, MappingData
}
public MapChunk Read(ISerializationManager serializationManager, MappingDataNode node,
IDependencyCollection dependencies, bool skipHook, ISerializationContext? context = null, ISerializationManager.InstantiationDelegate<MapChunk>? instantiationDelegate = null)
IDependencyCollection dependencies, SerializationHookContext hookCtx, ISerializationContext? context = null, ISerializationManager.InstantiationDelegate<MapChunk>? instantiationDelegate = null)
{
var ind = (Vector2i) serializationManager.Read(typeof(Vector2i), node["ind"], context, skipHook)!;
var ind = (Vector2i) serializationManager.Read(typeof(Vector2i), node["ind"], hookCtx, context)!;
var tileNode = (ValueDataNode)node["tiles"];
var tileBytes = Convert.FromBase64String(tileNode.Value);
@@ -128,7 +129,7 @@ internal sealed class MapChunkSerializer : ITypeSerializer<MapChunk, MappingData
return Convert.ToBase64String(barr);
}
public MapChunk CreateCopy(ISerializationManager serializationManager, MapChunk source, bool skipHook,
public MapChunk CreateCopy(ISerializationManager serializationManager, MapChunk source, SerializationHookContext hookCtx,
ISerializationContext? context = null)
{
var mapManager = ((SerializationManager)serializationManager).DependencyCollection.Resolve<IMapManager>();

View File

@@ -59,6 +59,7 @@ namespace Robust.Server
deps.Register<IPlayerManager, PlayerManager>();
deps.Register<ISharedPlayerManager, PlayerManager>();
deps.Register<IPrototypeManager, ServerPrototypeManager>();
deps.Register<IPrototypeManagerInternal, ServerPrototypeManager>();
deps.Register<IResourceManager, ResourceManager>();
deps.Register<IResourceManagerInternal, ResourceManager>();
deps.Register<EntityManager, ServerEntityManager>();

View File

@@ -19,7 +19,9 @@ namespace Robust.Shared.Asynchronous
var channel = Channel.CreateUnbounded<Mail>(new UnboundedChannelOptions
{
SingleReader = true,
SingleWriter = false
SingleWriter = false,
// For unblocking continuations.
AllowSynchronousContinuations = true
});
_channelReader = channel.Reader;

View File

@@ -1,5 +1,6 @@
using System;
using Robust.Shared.IoC;
using Robust.Shared.Serialization;
using Robust.Shared.Serialization.Manager;
using Robust.Shared.Serialization.Manager.Attributes;
using Robust.Shared.Serialization.Markdown.Mapping;
@@ -30,15 +31,15 @@ public sealed class SoundSpecifierTypeSerializer :
}
public SoundSpecifier Read(ISerializationManager serializationManager, MappingDataNode node,
IDependencyCollection dependencies, bool skipHook, ISerializationContext? context = null,
IDependencyCollection dependencies, SerializationHookContext hookCtx, ISerializationContext? context = null,
ISerializationManager.InstantiationDelegate<SoundSpecifier>? instanceProvider = null)
{
var type = GetType(node);
return (SoundSpecifier)serializationManager.Read(type, node, context, skipHook)!;
return (SoundSpecifier)serializationManager.Read(type, node, hookCtx, context)!;
}
public SoundSpecifier Read(ISerializationManager serializationManager, ValueDataNode node,
IDependencyCollection dependencies, bool skipHook, ISerializationContext? context = null,
IDependencyCollection dependencies, SerializationHookContext hookCtx, ISerializationContext? context = null,
ISerializationManager.InstantiationDelegate<SoundSpecifier>? instanceProvider = null)
{
return new SoundPathSpecifier(node.Value);

View File

@@ -6,6 +6,7 @@ using JetBrains.Annotations;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.Log;
using Robust.Shared.Serialization;
using Robust.Shared.Serialization.Manager;
using Robust.Shared.Serialization.Markdown;
using Robust.Shared.Serialization.Markdown.Validation;
@@ -108,7 +109,7 @@ internal sealed class MapSerializationContext : ISerializationContext, IEntityLo
EntityUid ITypeReader<EntityUid, ValueDataNode>.Read(ISerializationManager serializationManager,
ValueDataNode node,
IDependencyCollection dependencies,
bool skipHook,
SerializationHookContext hookCtx,
ISerializationContext? context, ISerializationManager.InstantiationDelegate<EntityUid>? _)
{
if (node.Value == "invalid")

View File

@@ -4,6 +4,7 @@ using Robust.Shared.IoC;
using Robust.Shared.Map;
using Robust.Shared.Map.Components;
using Robust.Shared.Physics.Dynamics;
using Robust.Shared.Serialization;
using Robust.Shared.Serialization.Manager;
using Robust.Shared.Serialization.Markdown;
using Robust.Shared.Serialization.Markdown.Sequence;
@@ -31,13 +32,13 @@ public sealed class FixtureSerializer : ITypeSerializer<List<Fixture>, SequenceD
}
public List<Fixture> Read(ISerializationManager serializationManager, SequenceDataNode node, IDependencyCollection dependencies,
bool skipHook, ISerializationContext? context = null, ISerializationManager.InstantiationDelegate<List<Fixture>>? instantiation = default)
SerializationHookContext hookCtx, ISerializationContext? context = null, ISerializationManager.InstantiationDelegate<List<Fixture>>? instantiation = default)
{
var value = instantiation != null ? instantiation() : new List<Fixture>(node.Count);
foreach (var subNode in node)
{
var fixture = serializationManager.Read<Fixture>(subNode, context, skipHook);
var fixture = serializationManager.Read<Fixture>(subNode, hookCtx, context);
value.Add(fixture);
}

View File

@@ -0,0 +1,40 @@
using System;
using JetBrains.Annotations;
using Robust.Shared.Serialization.Manager.Attributes;
namespace Robust.Shared.Prototypes;
/// <summary>
/// Quick attribute to give the prototype its type string.
/// To prevent needing to instantiate it because interfaces can't declare statics.
/// </summary>
[AttributeUsage(AttributeTargets.Class, Inherited = false)]
[BaseTypeRequired(typeof(IPrototype))]
[MeansImplicitUse]
[MeansDataDefinition]
[Virtual]
public class PrototypeAttribute : Attribute
{
private readonly string type;
public string Type => type;
public readonly int LoadPriority = 1;
public PrototypeAttribute(string type, int loadPriority = 1)
{
this.type = type;
LoadPriority = loadPriority;
}
}
[AttributeUsage(AttributeTargets.Class, Inherited = false)]
[BaseTypeRequired(typeof(IPrototype))]
[MeansImplicitUse]
[MeansDataDefinition]
[MeansDataRecord]
public sealed class PrototypeRecordAttribute : PrototypeAttribute
{
public PrototypeRecordAttribute(string type, int loadPriority = 1) : base(type, loadPriority)
{
}
}

View File

@@ -0,0 +1,49 @@
using System;
using System.Runtime.Serialization;
namespace Robust.Shared.Prototypes;
[Serializable]
[Virtual]
public class PrototypeLoadException : Exception
{
public PrototypeLoadException()
{
}
public PrototypeLoadException(string message) : base(message)
{
}
public PrototypeLoadException(string message, Exception inner) : base(message, inner)
{
}
public PrototypeLoadException(SerializationInfo info, StreamingContext context) : base(info, context)
{
}
}
[Serializable]
[Virtual]
public class UnknownPrototypeException : Exception
{
public override string Message => "Unknown prototype: " + Prototype;
public readonly string? Prototype;
public UnknownPrototypeException(string prototype)
{
Prototype = prototype;
}
public UnknownPrototypeException(SerializationInfo info, StreamingContext context) : base(info, context)
{
Prototype = (string?) info.GetValue("prototype", typeof(string));
}
public override void GetObjectData(SerializationInfo info, StreamingContext context)
{
base.GetObjectData(info, context);
info.AddValue("prototype", Prototype, typeof(string));
}
}

View File

@@ -0,0 +1,265 @@
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using Robust.Shared.Serialization.Markdown;
using Robust.Shared.Serialization.Markdown.Mapping;
using Robust.Shared.Serialization.Markdown.Validation;
using Robust.Shared.Utility;
using YamlDotNet.RepresentationModel;
namespace Robust.Shared.Prototypes;
/// <summary>
/// Handle storage and loading of YAML prototypes.
/// </summary>
/// <remarks>
/// Terminology:
/// "Kinds" are the types of prototypes there are, like <see cref="EntityPrototype"/>.
/// "Prototypes" are simply filled-in prototypes from YAML.
/// </remarks>
public interface IPrototypeManager
{
void Initialize();
/// <summary>
/// Returns an <see cref="IEnumerable{T}"/> of all registered prototype kinds by their ID.
/// </summary>
IEnumerable<string> GetPrototypeKinds();
/// <summary>
/// Return an <see cref="IEnumerable{T}"/> of all prototypes of a certain kind.
/// </summary>
/// <exception cref="KeyNotFoundException">
/// Thrown if the type of prototype is not registered.
/// </exception>
IEnumerable<T> EnumeratePrototypes<T>() where T : class, IPrototype;
/// <summary>
/// Return an <see cref="IEnumerable{T}"/> of all prototypes of a certain kind.
/// </summary>
/// <exception cref="KeyNotFoundException">
/// Thrown if the kind of prototype is not registered.
/// </exception>
IEnumerable<IPrototype> EnumeratePrototypes(Type kind);
/// <summary>
/// Return an <see cref="IEnumerable{T}"/> of all prototypes of a certain kind.
/// </summary>
/// <exception cref="KeyNotFoundException">
/// Thrown if the kind of prototype is not registered.
/// </exception>
IEnumerable<IPrototype> EnumeratePrototypes(string variant);
/// <summary>
/// Returns an <see cref="IEnumerable{T}"/> of all parents of a prototype of a certain kind.
/// </summary>
IEnumerable<T> EnumerateParents<T>(string kind, bool includeSelf = false)
where T : class, IPrototype, IInheritingPrototype;
/// <summary>
/// Returns an <see cref="IEnumerable{T}"/> of parents of a prototype of a certain kind.
/// </summary>
IEnumerable<IPrototype> EnumerateParents(Type kind, string id, bool includeSelf = false);
/// <summary>
/// Index for a <see cref="IPrototype"/> by ID.
/// </summary>
/// <exception cref="KeyNotFoundException">
/// Thrown if the type of prototype is not registered.
/// </exception>
T Index<T>(string id) where T : class, IPrototype;
/// <summary>
/// Index for a <see cref="IPrototype"/> by ID.
/// </summary>
/// <exception cref="KeyNotFoundException">
/// Thrown if the ID does not exist or the kind of prototype is not registered.
/// </exception>
IPrototype Index(Type kind, string id);
/// <summary>
/// Returns whether a prototype of type <typeparamref name="T"/> with the specified <param name="id"/> exists.
/// </summary>
bool HasIndex<T>(string id) where T : class, IPrototype;
bool TryIndex<T>(string id, [NotNullWhen(true)] out T? prototype) where T : class, IPrototype;
bool TryIndex(Type kind, string id, [NotNullWhen(true)] out IPrototype? prototype);
bool HasMapping<T>(string id);
bool TryGetMapping(Type kind, string id, [NotNullWhen(true)] out MappingDataNode? mappings);
/// <summary>
/// Returns whether a prototype variant <param name="variant"/> exists.
/// </summary>
/// <param name="variant">Identifier for the prototype variant.</param>
/// <returns>Whether the prototype variant exists.</returns>
[Obsolete("Variant is outdated naming, use *kind* functions instead")]
bool HasVariant(string variant);
/// <summary>
/// Returns the Type for a prototype variant.
/// </summary>
/// <param name="variant">Identifier for the prototype variant.</param>
/// <returns>The specified prototype Type.</returns>
/// <exception cref="KeyNotFoundException">
/// Thrown when the specified prototype variant isn't registered or doesn't exist.
/// </exception>
[Obsolete("Variant is outdated naming, use *kind* functions instead")]
Type GetVariantType(string variant);
/// <summary>
/// Attempts to get the Type for a prototype variant.
/// </summary>
/// <param name="variant">Identifier for the prototype variant.</param>
/// <param name="prototype">The specified prototype Type, or null.</param>
/// <returns>Whether the prototype type was found and <see cref="prototype"/> isn't null.</returns>
[Obsolete("Variant is outdated naming, use *kind* functions instead")]
bool TryGetVariantType(string variant, [NotNullWhen(true)] out Type? prototype);
/// <summary>
/// Attempts to get a prototype's variant.
/// </summary>
/// <param name="type"></param>
/// <param name="variant"></param>
/// <returns></returns>
[Obsolete("Variant is outdated naming, use *kind* functions instead")]
bool TryGetVariantFrom(Type type, [NotNullWhen(true)] out string? variant);
/// <summary>
/// Attempts to get a prototype's variant.
/// </summary>
/// <param name="prototype">The prototype in question.</param>
/// <param name="variant">Identifier for the prototype variant, or null.</param>
/// <returns>Whether the prototype variant was successfully retrieved.</returns>
[Obsolete("Variant is outdated naming, use *kind* functions instead")]
bool TryGetVariantFrom(IPrototype prototype, [NotNullWhen(true)] out string? variant);
/// <summary>
/// Attempts to get a prototype's variant.
/// </summary>
/// <param name="variant">Identifier for the prototype variant, or null.</param>
/// <typeparam name="T">The prototype in question.</typeparam>
/// <returns>Whether the prototype variant was successfully retrieved.</returns>
[Obsolete("Variant is outdated naming, use *kind* functions instead")]
bool TryGetVariantFrom<T>([NotNullWhen(true)] out string? variant) where T : class, IPrototype;
/// <summary>
/// Returns whether a prototype kind <param name="kind"/> exists.
/// </summary>
/// <param name="kind">Identifier for the prototype kind.</param>
/// <returns>Whether the prototype kind exists.</returns>
bool HasKind(string kind);
/// <summary>
/// Returns the Type for a prototype kind.
/// </summary>
/// <param name="kind">Identifier for the prototype kind.</param>
/// <returns>The specified prototype Type.</returns>
/// <exception cref="KeyNotFoundException">
/// Thrown when the specified prototype kind isn't registered or doesn't exist.
/// </exception>
Type GetKindType(string kind);
/// <summary>
/// Attempts to get the Type for a prototype kind.
/// </summary>
/// <param name="kind">Identifier for the prototype kind.</param>
/// <param name="prototype">The specified prototype Type, or null.</param>
/// <returns>Whether the prototype type was found and <see cref="prototype"/> isn't null.</returns>
bool TryGetKindType(string kind, [NotNullWhen(true)] out Type? prototype);
/// <summary>
/// Attempts to get a prototype's kind.
/// </summary>
/// <param name="type"></param>
/// <param name="kind"></param>
/// <returns></returns>
bool TryGetKindFrom(Type type, [NotNullWhen(true)] out string? kind);
/// <summary>
/// Attempts to get a prototype's kind.
/// </summary>
/// <param name="prototype">The prototype in question.</param>
/// <param name="kind">Identifier for the prototype kind, or null.</param>
/// <returns>Whether the prototype kind was successfully retrieved.</returns>
bool TryGetKindFrom(IPrototype prototype, [NotNullWhen(true)] out string? kind);
/// <summary>
/// Attempts to get a prototype's kind.
/// </summary>
/// <param name="kind">Identifier for the prototype kind, or null.</param>
/// <typeparam name="T">The prototype in question.</typeparam>
/// <returns>Whether the prototype kind was successfully retrieved.</returns>
bool TryGetKindFrom<T>([NotNullWhen(true)] out string? kind) where T : class, IPrototype;
/// <summary>
/// Load prototypes from files in a directory, recursively.
/// </summary>
void LoadDirectory(ResourcePath path, bool overwrite = false, Dictionary<Type, HashSet<string>>? changed = null);
Dictionary<string, HashSet<ErrorNode>> ValidateDirectory(ResourcePath path);
void LoadFromStream(TextReader stream, bool overwrite = false, Dictionary<Type, HashSet<string>>? changed = null);
void LoadString(string str, bool overwrite = false, Dictionary<Type, HashSet<string>>? changed = null);
void RemoveString(string prototypes);
/// <summary>
/// Clear out all prototypes and reset to a blank slate.
/// </summary>
void Clear();
/// <summary>
/// Syncs all inter-prototype data. Call this when operations adding new prototypes are done.
/// </summary>
void ResolveResults();
/// <summary>
/// Reload the changes from LoadString
/// </summary>
/// <param name="prototypes">Changes from load string</param>
void ReloadPrototypes(Dictionary<Type, HashSet<string>> prototypes);
/// <summary>
/// Registers a specific prototype name to be ignored.
/// </summary>
void RegisterIgnore(string name);
/// <summary>
/// Loads a single prototype class type into the manager.
/// </summary>
/// <param name="protoClass">A prototype class type that implements IPrototype. This type also
/// requires a <see cref="PrototypeAttribute"/> with a non-empty class string.</param>
[Obsolete("Prototype type is outdated naming, use *king* functions instead")]
void RegisterType(Type protoClass);
/// <summary>
/// Loads a single prototype kind into the manager.
/// </summary>
/// <param name="kind">
/// The type of the prototype kind that implements <see cref="IPrototype"/>. This type also
/// requires a <see cref="PrototypeAttribute"/> with a non-empty class string.
/// </param>
void RegisterKind(Type kind);
/// <summary>
/// Fired when prototype are reloaded. The event args contain the modified prototypes.
/// </summary>
/// <remarks>
/// This does NOT fire on initial prototype load.
/// </remarks>
event Action<PrototypesReloadedEventArgs> PrototypesReloaded;
}
internal interface IPrototypeManagerInternal : IPrototypeManager
{
event Action<DataNodeDocument>? LoadedData;
}
public sealed record PrototypesReloadedEventArgs(
IReadOnlyDictionary<Type, PrototypesReloadedEventArgs.PrototypeChangeSet> ByType)
{
public sealed record PrototypeChangeSet(IReadOnlyDictionary<string, IPrototype> Modified);
}

View File

@@ -25,6 +25,7 @@ public sealed class MultiRootInheritanceGraph<T> where T : notnull
}
public T[]? GetParents(T id) => _parents.GetValueOrDefault(id);
public int GetParentsCount(T id) => _parents.GetValueOrDefault(id)?.Length ?? 0;
public bool TryGetParents(T id, [NotNullWhen(true)] out T[]? parents)
{

View File

@@ -0,0 +1,337 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading;
using Robust.Shared.Random;
using Robust.Shared.Serialization.Markdown;
using Robust.Shared.Serialization.Markdown.Mapping;
using Robust.Shared.Serialization.Markdown.Sequence;
using Robust.Shared.Serialization.Markdown.Validation;
using Robust.Shared.Serialization.Markdown.Value;
using Robust.Shared.Utility;
using YamlDotNet.RepresentationModel;
namespace Robust.Shared.Prototypes;
public partial class PrototypeManager
{
public event Action<DataNodeDocument>? LoadedData;
/// <inheritdoc />
public void LoadDirectory(ResourcePath path, bool overwrite = false,
Dictionary<Type, HashSet<string>>? changed = null)
{
_hasEverBeenReloaded = true;
var streams = Resources.ContentFindFiles(path)
.Where(filePath => filePath.Extension == "yml" && !filePath.Filename.StartsWith("."))
.ToArray();
// Shuffle to avoid input data patterns causing uneven thread workloads.
RandomExtensions.Shuffle(streams.AsSpan(), new System.Random());
var sawmill = _logManager.GetSawmill("eng");
var results = streams.AsParallel()
.Select<ResourcePath, (ResourcePath, IEnumerable<ExtractedMappingData>)>(file =>
{
try
{
using var reader = ReadFile(file, !overwrite);
if (reader == null)
return (file, Array.Empty<ExtractedMappingData>());
var extractedList = new List<ExtractedMappingData>();
foreach (var document in DataNodeParser.ParseYamlStream(reader))
{
LoadedData?.Invoke(document);
var seq = (SequenceDataNode)document.Root;
foreach (var mapping in seq.Sequence)
{
var data = ExtractMapping((MappingDataNode)mapping);
if (data != null)
extractedList.Add(data);
}
}
return (file, extractedList);
}
catch (Exception e)
{
sawmill.Error($"Exception whilst loading prototypes from {file}:\n{e}");
return (file, Array.Empty<ExtractedMappingData>());
}
});
foreach (var (file, result) in results)
{
foreach (var mapping in result)
{
try
{
MergeMapping(mapping, overwrite, changed);
}
catch (Exception e)
{
sawmill.Error($"Exception whilst loading prototypes from {file}:\n{e}");
}
}
}
}
public Dictionary<string, HashSet<ErrorNode>> ValidateDirectory(ResourcePath path)
{
var streams = Resources.ContentFindFiles(path).ToList().AsParallel()
.Where(filePath => filePath.Extension == "yml" && !filePath.Filename.StartsWith("."));
var dict = new Dictionary<string, HashSet<ErrorNode>>();
foreach (var resourcePath in streams)
{
using var reader = ReadFile(resourcePath);
if (reader == null)
{
continue;
}
var yamlStream = new YamlStream();
yamlStream.Load(reader);
for (var i = 0; i < yamlStream.Documents.Count; i++)
{
var rootNode = (YamlSequenceNode)yamlStream.Documents[i].RootNode;
foreach (YamlMappingNode node in rootNode.Cast<YamlMappingNode>())
{
var type = node.GetNode("type").AsString();
if (!_kindNames.ContainsKey(type))
{
if (_ignoredPrototypeTypes.Contains(type))
{
continue;
}
throw new PrototypeLoadException($"Unknown prototype type: '{type}'");
}
var mapping = node.ToDataNodeCast<MappingDataNode>();
mapping.Remove("type");
var errorNodes = _serializationManager.ValidateNode(_kindNames[type], mapping).GetErrors()
.ToHashSet();
if (errorNodes.Count == 0) continue;
if (!dict.TryGetValue(resourcePath.ToString(), out var hashSet))
dict[resourcePath.ToString()] = new HashSet<ErrorNode>();
dict[resourcePath.ToString()].UnionWith(errorNodes);
}
}
}
return dict;
}
private StreamReader? ReadFile(ResourcePath file, bool @throw = true)
{
var retries = 0;
// This might be shit-code, but its pjb-responded-idk-when-asked shit-code.
while (true)
{
try
{
var reader = new StreamReader(Resources.ContentFileRead(file), EncodingHelpers.UTF8);
return reader;
}
catch (IOException e)
{
if (retries > 10)
{
if (@throw)
{
throw;
}
_sawmill.Error($"Error reloading prototypes in file {file}:\n{e}");
return null;
}
retries++;
Thread.Sleep(10);
}
}
}
public void LoadFile(ResourcePath file, bool overwrite = false, Dictionary<Type, HashSet<string>>? changed = null)
{
try
{
using var reader = ReadFile(file, !overwrite);
if (reader == null)
return;
var i = 0;
foreach (var document in DataNodeParser.ParseYamlStream(reader))
{
LoadedData?.Invoke(document);
try
{
var seq = (SequenceDataNode)document.Root;
foreach (var mapping in seq.Sequence)
{
var extracted = ExtractMapping((MappingDataNode) mapping);
if (extracted == null)
continue;
MergeMapping(extracted, overwrite, changed);
}
}
catch (Exception e)
{
_sawmill.Error($"Exception whilst loading prototypes from {file}#{i}:\n{e}");
}
i += 1;
}
}
catch (Exception e)
{
_sawmill.Error("YamlException whilst loading prototypes from {0}: {1}", file, e.Message);
}
}
private ExtractedMappingData? ExtractMapping(MappingDataNode dataNode)
{
var type = dataNode.Get<ValueDataNode>("type").Value;
if (!_kindNames.TryGetValue(type, out var kind))
{
if (_ignoredPrototypeTypes.Contains(type))
return null;
throw new PrototypeLoadException($"Unknown prototype type: '{type}'");
}
var kindData = _kinds[kind];
if (!dataNode.TryGet<ValueDataNode>(IdDataFieldAttribute.Name, out var idNode))
throw new PrototypeLoadException($"Prototype type {type} is missing an 'id' datafield.");
var id = idNode.Value;
string[]? parents = null;
if (kindData.Inheritance != null)
{
if (dataNode.TryGet(ParentDataFieldAttribute.Name, out var parentNode))
{
parents = _serializationManager.Read<string[]>(parentNode);
}
}
return new ExtractedMappingData(kind, id, parents, dataNode);
}
private void MergeMapping(
ExtractedMappingData mapping,
bool overwrite,
Dictionary<Type, HashSet<string>>? changed)
{
var (kind, id, parents, data) = mapping;
var kindData = _kinds[kind];
if (!overwrite && kindData.Results.ContainsKey(id))
throw new PrototypeLoadException($"Duplicate ID: '{id}' for kind '{kind}");
kindData.Results[id] = data;
if (kindData.Inheritance is { } inheritance)
{
if (parents != null)
{
inheritance.Add(id, parents);
}
else
{
inheritance.Add(id);
}
}
if (changed == null)
return;
var set = changed.GetOrNew(kind);
set.Add(id);
}
public void LoadFromStream(TextReader stream, bool overwrite = false,
Dictionary<Type, HashSet<string>>? changed = null)
{
_hasEverBeenReloaded = true;
var i = 0;
foreach (var document in DataNodeParser.ParseYamlStream(stream))
{
LoadedData?.Invoke(document);
try
{
var rootNode = (SequenceDataNode)document.Root;
foreach (var node in rootNode.Cast<MappingDataNode>())
{
var extracted = ExtractMapping(node);
if (extracted == null)
continue;
MergeMapping(extracted, overwrite, changed);
}
i += 1;
}
catch (Exception e)
{
throw new PrototypeLoadException($"Failed to load prototypes from document#{i}", e);
}
}
}
public void LoadString(string str, bool overwrite = false, Dictionary<Type, HashSet<string>>? changed = null)
{
LoadFromStream(new StringReader(str), overwrite, changed);
}
public void RemoveString(string prototypes)
{
var reader = new StringReader(prototypes);
foreach (var document in DataNodeParser.ParseYamlStream(reader))
{
var root = (SequenceDataNode)document.Root;
foreach (var node in root.Cast<MappingDataNode>())
{
var typeString = node.Get<ValueDataNode>("type").Value;
if (!_kindNames.TryGetValue(typeString, out var kind))
{
continue;
}
var kindData = _kinds[kind];
var id = node.Get<ValueDataNode>("id").Value;
if (kindData.Inheritance is { } tree)
tree.Remove(id, true);
kindData.Instances.Remove(id);
kindData.Results.Remove(id);
}
}
}
// All these fields can be null in case the
private sealed record ExtractedMappingData(
Type Kind,
string Id,
string[]? Parents,
MappingDataNode Data);
}

File diff suppressed because it is too large Load Diff

View File

@@ -7,7 +7,7 @@ namespace Robust.Shared.Prototypes;
/// Prototype that represents an alias from one tile ID to another.
/// Tile alias prototypes, unlike tile prototypes, are implemented here, as they're really just fed to TileDefinitionManager.
/// </summary>
[Prototype("tileAlias", -1)]
[Prototype("tileAlias")]
public sealed class TileAliasPrototype : IPrototype
{
/// <summary>

View File

@@ -80,5 +80,17 @@ namespace Robust.Shared.Random
return random.NextDouble() <= chance;
}
internal static void Shuffle<T>(Span<T> array, System.Random random)
{
var n = array.Length;
while (n > 1)
{
n--;
var k = random.Next(n + 1);
(array[k], array[n]) =
(array[n], array[k]);
}
}
}
}

View File

@@ -3,8 +3,10 @@ using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Reflection;
using System.Threading;
using Robust.Shared.Log;
using Robust.Shared.Serialization;
using Robust.Shared.Utility;
using Robust.Shared.ViewVariables;
namespace Robust.Shared.Reflection
@@ -24,8 +26,7 @@ namespace Robust.Shared.Reflection
public event EventHandler<ReflectionUpdateEventArgs>? OnAssemblyAdded;
[ViewVariables]
public IReadOnlyList<Assembly> Assemblies => assemblies;
[ViewVariables] public IReadOnlyList<Assembly> Assemblies => assemblies;
private readonly Dictionary<(Type baseType, string typeName), Type?> _yamlTypeTagCache = new();
@@ -34,6 +35,9 @@ namespace Robust.Shared.Reflection
private readonly Dictionary<string, Enum> _enumCache = new();
private readonly Dictionary<Enum, string> _reverseEnumCache = new();
private readonly ReaderWriterLockSlim _enumCacheLock = new();
private readonly ReaderWriterLockSlim _yamlTypeTagCacheLock = new();
private readonly List<Type> _getAllTypesCache = new();
/// <inheritdoc />
@@ -80,7 +84,7 @@ namespace Robust.Shared.Reflection
{
foreach (var type in typeSet)
{
var attribute = (ReflectAttribute?) Attribute.GetCustomAttribute(type, typeof(ReflectAttribute));
var attribute = (ReflectAttribute?)Attribute.GetCustomAttribute(type, typeof(ReflectAttribute));
if (!(attribute?.Discoverable ?? ReflectAttribute.DEFAULT_DISCOVERABLE))
continue;
@@ -133,53 +137,56 @@ namespace Robust.Shared.Reflection
public bool TryLooseGetType(string name, [NotNullWhen(true)] out Type? type)
{
if (_looseTypeCache.TryGetValue(name, out type))
return true;
// Check standard types first.
switch (name)
lock (_looseTypeCache)
{
case "Byte":
type = typeof(byte);
_looseTypeCache[name] = type;
if (_looseTypeCache.TryGetValue(name, out type))
return true;
case "Bool":
type = typeof(bool);
_looseTypeCache[name] = type;
return true;
case "Double":
type = typeof(double);
_looseTypeCache[name] = type;
return true;
case "SByte":
type = typeof(sbyte);
_looseTypeCache[name] = type;
return true;
case "Single":
type = typeof(float);
_looseTypeCache[name] = type;
return true;
case "String":
type = typeof(string);
_looseTypeCache[name] = type;
return true;
}
foreach (var assembly in assemblies)
{
foreach (var tryType in assembly.DefinedTypes)
// Check standard types first.
switch (name)
{
if (tryType.FullName!.EndsWith(name))
{
type = tryType;
case "Byte":
type = typeof(byte);
_looseTypeCache[name] = type;
return true;
case "Bool":
type = typeof(bool);
_looseTypeCache[name] = type;
return true;
case "Double":
type = typeof(double);
_looseTypeCache[name] = type;
return true;
case "SByte":
type = typeof(sbyte);
_looseTypeCache[name] = type;
return true;
case "Single":
type = typeof(float);
_looseTypeCache[name] = type;
return true;
case "String":
type = typeof(string);
_looseTypeCache[name] = type;
return true;
}
foreach (var assembly in assemblies)
{
foreach (var tryType in assembly.DefinedTypes)
{
if (tryType.FullName!.EndsWith(name))
{
type = tryType;
_looseTypeCache[name] = type;
return true;
}
}
}
}
type = default;
return false;
type = default;
return false;
}
}
/// <inheritdoc />
@@ -204,35 +211,46 @@ namespace Robust.Shared.Reflection
/// <inheritdoc />
public string GetEnumReference(Enum @enum)
{
if (_reverseEnumCache.TryGetValue(@enum, out var reference))
return reference;
// if there is more than one enum with the same basic name, the reference may need to be the fully qualified name.
// but if possible we want to avoid that and use a shorter string.
var fullName = @enum.GetType().FullName!;
var dotIndex = fullName.LastIndexOf('.');
if (dotIndex > 0 && dotIndex != fullName.Length)
using (_enumCacheLock.ReadGuard())
{
var name = fullName.Substring(dotIndex + 1);
reference = $"enum.{name}.{@enum}";
if (TryParseEnumReference(reference, out var resolvedEnum, false) && resolvedEnum == @enum)
{
// TryParse will have filled in the cache already.
if (_reverseEnumCache.TryGetValue(@enum, out var reference))
return reference;
}
}
// If that failed, just use the full name.
reference = $"enum.{fullName}.{@enum}";
_reverseEnumCache[@enum] = reference;
_enumCache[reference] = @enum;
return reference;
using (_enumCacheLock.WriteGuard())
{
if (_reverseEnumCache.TryGetValue(@enum, out var reference))
return reference;
// if there is more than one enum with the same basic name, the reference may need to be the fully qualified name.
// but if possible we want to avoid that and use a shorter string.
var fullName = @enum.GetType().FullName!;
var dotIndex = fullName.LastIndexOf('.');
if (dotIndex > 0 && dotIndex != fullName.Length)
{
var name = fullName.Substring(dotIndex + 1);
reference = $"enum.{name}.{@enum}";
if (TryParseEnumReference(reference, out var resolvedEnum, false) && resolvedEnum == @enum)
{
// TryParse will have filled in the cache already.
return reference;
}
}
// If that failed, just use the full name.
reference = $"enum.{fullName}.{@enum}";
_reverseEnumCache[@enum] = reference;
_enumCache[reference] = @enum;
return reference;
}
}
/// <inheritdoc />
public bool TryParseEnumReference(string reference, [NotNullWhen(true)] out Enum? @enum, bool shouldThrow = true)
public bool TryParseEnumReference(string reference, [NotNullWhen(true)] out Enum? @enum,
bool shouldThrow = true)
{
if (!reference.StartsWith("enum."))
{
@@ -242,9 +260,13 @@ namespace Robust.Shared.Reflection
reference = reference.Substring(5);
if (_enumCache.TryGetValue(reference, out @enum))
return true;
using (_enumCacheLock.ReadGuard())
{
if (_enumCache.TryGetValue(reference, out @enum))
return true;
}
// Doesn't exist, add it.
var dotIndex = reference.LastIndexOf('.');
var typeName = reference.Substring(0, dotIndex);
@@ -262,9 +284,13 @@ namespace Robust.Shared.Reflection
continue;
}
@enum = (Enum) Enum.Parse(type, value);
_enumCache[reference] = @enum;
_reverseEnumCache[@enum] = reference;
using (_enumCacheLock.WriteGuard())
{
@enum = (Enum)Enum.Parse(type, value);
_enumCache[reference] = @enum;
_reverseEnumCache[@enum] = reference;
}
return true;
}
}
@@ -276,47 +302,53 @@ namespace Robust.Shared.Reflection
public Type? YamlTypeTagLookup(Type baseType, string typeName)
{
if (_yamlTypeTagCache.TryGetValue((baseType, typeName), out var type))
using (_yamlTypeTagCacheLock.ReadGuard())
{
return type;
if (_yamlTypeTagCache.TryGetValue((baseType, typeName), out var type))
return type;
}
Type? found = null;
foreach (var derivedType in GetAllChildren(baseType))
using (_yamlTypeTagCacheLock.WriteGuard())
{
if (!derivedType.IsPublic)
if (_yamlTypeTagCache.TryGetValue((baseType, typeName), out var type))
return type;
Type? found = null;
foreach (var derivedType in GetAllChildren(baseType))
{
continue;
if (!derivedType.IsPublic)
{
continue;
}
if (derivedType.Name == typeName)
{
found = derivedType;
break;
}
var serializedAttribute = derivedType.GetCustomAttribute<SerializedTypeAttribute>();
if (serializedAttribute != null &&
serializedAttribute.SerializeName == typeName)
{
found = derivedType;
break;
}
}
if (derivedType.Name == typeName)
// Fallback
if (found == null)
{
found = derivedType;
break;
TryLooseGetType(typeName, out found);
// If we may have gotten the type but it's still abstract then don't return it.
if (found == null || found.IsAbstract || !found.IsAssignableTo(baseType))
found = null;
}
var serializedAttribute = derivedType.GetCustomAttribute<SerializedTypeAttribute>();
if (serializedAttribute != null &&
serializedAttribute.SerializeName == typeName)
{
found = derivedType;
break;
}
_yamlTypeTagCache.Add((baseType, typeName), found);
return found;
}
// Fallback
if (found == null)
{
TryLooseGetType(typeName, out found);
// If we may have gotten the type but it's still abstract then don't return it.
if (found == null || found.IsAbstract || !found.IsAssignableTo(baseType))
found = null;
}
_yamlTypeTagCache.Add((baseType, typeName), found);
return found;
}
}
}

View File

@@ -6,6 +6,8 @@ using JetBrains.Annotations;
using NetSerializer;
using Robust.Shared.Network;
using Robust.Shared.Network.Messages;
using Robust.Shared.Serialization.Markdown;
using Robust.Shared.Serialization.Markdown.Mapping;
using YamlDotNet.RepresentationModel;
namespace Robust.Shared.Serialization
@@ -78,6 +80,8 @@ namespace Robust.Shared.Serialization
/// <param name="yaml">The YAML to collect strings from.</param>
void AddStrings(YamlStream yaml);
void AddStrings(DataNode dataNode);
/// <summary>
/// Add strings from the given enumeration to the mapping.
/// </summary>

View File

@@ -10,8 +10,8 @@ namespace Robust.Shared.Serialization.Manager.Definition
public delegate void PopulateDelegateSignature(
ref T target,
MappingDataNode mappingDataNode,
ISerializationContext? context,
bool skipHook);
SerializationHookContext hookCtx,
ISerializationContext? context);
public delegate MappingDataNode SerializeDelegateSignature(
T obj,
@@ -21,8 +21,8 @@ namespace Robust.Shared.Serialization.Manager.Definition
public delegate void CopyDelegateSignature(
T source,
ref T target,
ISerializationContext? context,
bool skipHook);
SerializationHookContext hookCtx,
ISerializationContext? context);
private delegate ValidationNode ValidateFieldDelegate(
DataNode node,

View File

@@ -22,8 +22,8 @@ namespace Robust.Shared.Serialization.Manager.Definition
var targetParam = Expression.Parameter(typeof(T).MakeByRefType());
var mappingDataParam = Expression.Parameter(typeof(MappingDataNode));
var hookCtxParam = Expression.Parameter(typeof(SerializationHookContext));
var contextParam = Expression.Parameter(typeof(ISerializationContext));
var skipHookParam = Expression.Parameter(typeof(bool));
var expressions = new List<BlockExpression>();
@@ -57,8 +57,8 @@ namespace Robust.Shared.Serialization.Manager.Definition
"Read",
new []{fieldType, typeof(ValueDataNode), fieldDefinition.Attribute.CustomTypeSerializer},
Expression.Convert(nodeVariable, typeof(ValueDataNode)),
hookCtxParam,
contextParam,
skipHookParam,
Expression.Constant(null, typeof(ISerializationManager.InstantiationDelegate<>).MakeGenericType(fieldType)),
Expression.Constant(!isNullable)), nullable))),
Expression.Constant(typeof(ValueDataNode))));
@@ -72,8 +72,8 @@ namespace Robust.Shared.Serialization.Manager.Definition
"Read",
new []{fieldType, typeof(SequenceDataNode), fieldDefinition.Attribute.CustomTypeSerializer},
Expression.Convert(nodeVariable, typeof(SequenceDataNode)),
hookCtxParam,
contextParam,
skipHookParam,
Expression.Constant(null, typeof(ISerializationManager.InstantiationDelegate<>).MakeGenericType(fieldType)),
Expression.Constant(!isNullable)), nullable))),
Expression.Constant(typeof(SequenceDataNode))));
@@ -87,8 +87,8 @@ namespace Robust.Shared.Serialization.Manager.Definition
"Read",
new []{fieldType, typeof(MappingDataNode), fieldDefinition.Attribute.CustomTypeSerializer},
Expression.Convert(nodeVariable, typeof(MappingDataNode)),
hookCtxParam,
contextParam,
skipHookParam,
Expression.Constant(null, typeof(ISerializationManager.InstantiationDelegate<>).MakeGenericType(fieldType)),
Expression.Constant(!isNullable)), nullable))),
Expression.Constant(typeof(MappingDataNode))));
@@ -114,8 +114,8 @@ namespace Robust.Shared.Serialization.Manager.Definition
"Read",
new[] { fieldDefinition.FieldType },
nodeVariable,
hookCtxParam,
contextParam,
skipHookParam,
Expression.Constant(null, typeof(ISerializationManager.InstantiationDelegate<>).MakeGenericType(fieldDefinition.FieldType)),
Expression.Constant(!isNullable)));
}
@@ -158,8 +158,8 @@ namespace Robust.Shared.Serialization.Manager.Definition
Expression.Block(expressions),
targetParam,
mappingDataParam,
contextParam,
skipHookParam).Compile();
hookCtxParam,
contextParam).Compile();
}
private SerializeDelegateSignature EmitSerializeDelegate(SerializationManager manager)
@@ -315,7 +315,7 @@ namespace Robust.Shared.Serialization.Manager.Definition
var sourceParam = Expression.Parameter(typeof(T));
var targetParam = Expression.Parameter(typeof(T).MakeByRefType());
var contextParam = Expression.Parameter(typeof(ISerializationContext));
var skipHookParam = Expression.Parameter(typeof(bool));
var hookCtxParam = Expression.Parameter(typeof(SerializationHookContext));
var expressions = new List<Expression>();
@@ -348,8 +348,8 @@ namespace Robust.Shared.Serialization.Manager.Definition
new[]{fieldType, fieldDefinition.Attribute.CustomTypeSerializer},
sourceAccess,
targetValue,
hookCtxParam,
contextParam,
skipHookParam,
Expression.Constant(!isNullable)),
Expression.Assign(finalTargetValue, Expression.Convert(targetValue, fieldDefinition.FieldType)));
@@ -381,8 +381,8 @@ namespace Robust.Shared.Serialization.Manager.Definition
"CreateCopy",
new []{fieldDefinition.FieldType, fieldDefinition.Attribute.CustomTypeSerializer},
AccessExpression(i, sourceParam),
hookCtxParam,
contextParam,
skipHookParam,
Expression.Constant(!isNullable));
}
else
@@ -392,8 +392,8 @@ namespace Robust.Shared.Serialization.Manager.Definition
"CreateCopy",
new[] { fieldDefinition.FieldType },
AccessExpression(i, sourceParam),
hookCtxParam,
contextParam,
skipHookParam,
Expression.Constant(!isNullable));
}
@@ -404,8 +404,8 @@ namespace Robust.Shared.Serialization.Manager.Definition
Expression.Block(expressions),
sourceParam,
targetParam,
contextParam,
skipHookParam).Compile();
hookCtxParam,
contextParam).Compile();
}
private ValidateFieldDelegate EmitFieldValidationDelegate(SerializationManager manager, int i)

View File

@@ -87,6 +87,12 @@ namespace Robust.Shared.Serialization.Manager
/// <param name="notNullableOverride">Set true if a reference Type should not allow null. Not necessary for value types.</param>
/// <returns>The deserialized object or null.</returns>
public object? Read(Type type, DataNode node, ISerializationContext? context = null, bool skipHook = false, bool notNullableOverride = false);
public object? Read(
Type type,
DataNode node,
SerializationHookContext hookCtx,
ISerializationContext? context = null,
bool notNullableOverride = false);
/// <summary>
/// Deserializes a node into a populated object of the given generic type <see cref="T"/>
@@ -99,6 +105,12 @@ namespace Robust.Shared.Serialization.Manager
/// <typeparam name="T">The type of object to create and populate.</typeparam>
/// <returns>The deserialized object, or null.</returns>
T Read<T>(DataNode node, ISerializationContext? context = null, bool skipHook = false, InstantiationDelegate<T>? instanceProvider = null, bool notNullableOverride = false);
T Read<T>(
DataNode node,
SerializationHookContext hookCtx,
ISerializationContext? context = null,
InstantiationDelegate<T>? instanceProvider = null,
bool notNullableOverride = false);
/// <summary>
@@ -116,6 +128,15 @@ namespace Robust.Shared.Serialization.Manager
T Read<T, TNode>(ITypeReader<T, TNode> reader, TNode node, ISerializationContext? context = null,
bool skipHook = false, InstantiationDelegate<T>? instanceProvider = null, bool notNullableOverride = false) where TNode : DataNode;
T Read<T, TNode>(
ITypeReader<T, TNode> reader,
TNode node,
SerializationHookContext hookCtx,
ISerializationContext? context = null,
InstantiationDelegate<T>? instanceProvider = null,
bool notNullableOverride = false)
where TNode : DataNode;
/// <summary>
/// Deserializes a node into a populated object of the given generic type <see cref="T"/> using the provided <see cref="ITypeReader{TType,TNode}"/> type.
/// </summary>
@@ -131,6 +152,15 @@ namespace Robust.Shared.Serialization.Manager
T Read<T, TNode, TReader>(TNode node, ISerializationContext? context = null,
bool skipHook = false, InstantiationDelegate<T>? instanceProvider = null, bool notNullableOverride = false) where TNode : DataNode where TReader : ITypeReader<T, TNode>;
T Read<T, TNode, TReader>(
TNode node,
SerializationHookContext hookCtx,
ISerializationContext? context = null,
InstantiationDelegate<T>? instanceProvider = null,
bool notNullableOverride = false)
where TNode : DataNode
where TReader : ITypeReader<T, TNode>;
#endregion
#region Write
@@ -226,6 +256,12 @@ namespace Robust.Shared.Serialization.Manager
/// <param name="skipHook">Whether or not to skip running <see cref="ISerializationHooks"/></param>
/// <param name="notNullableOverride">Set true if a reference Type should not allow null. Not necessary for value types.</param>
void CopyTo(object source, ref object? target, ISerializationContext? context = null, bool skipHook = false, bool notNullableOverride = false);
void CopyTo(
object source,
ref object? target,
SerializationHookContext hookCtx,
ISerializationContext? context = null,
bool notNullableOverride = false);
/// <summary>
/// Copies the values of one object into another.
@@ -239,6 +275,12 @@ namespace Robust.Shared.Serialization.Manager
/// <param name="notNullableOverride">Set true if a reference Type should not allow null. Not necessary for value types.</param>
/// <typeparam name="T">The type of the objects to copy from and into.</typeparam>
void CopyTo<T>(T source, ref T? target, ISerializationContext? context = null, bool skipHook = false, bool notNullableOverride = false);
void CopyTo<T>(
T source,
ref T? target,
SerializationHookContext hookCtx,
ISerializationContext? context = null,
bool notNullableOverride = false);
/// <summary>
/// Copies the values of one object into another using a specified <see cref="ITypeCopier{TType}"/> instance.
@@ -253,6 +295,13 @@ namespace Robust.Shared.Serialization.Manager
/// <param name="notNullableOverride">Set true if a reference Type should not allow null. Not necessary for value types.</param>
/// <typeparam name="T">The type of the objects to copy from and into.</typeparam>
void CopyTo<T>(ITypeCopier<T> copier, T source, ref T? target, ISerializationContext? context = null, bool skipHook = false, bool notNullableOverride = false);
void CopyTo<T>(
ITypeCopier<T> copier,
T source,
ref T? target,
SerializationHookContext hookCtx,
ISerializationContext? context = null,
bool notNullableOverride = false);
/// <summary>
/// Copies the values of one object into another using a specified <see cref="ITypeCopier{TType}"/> type.
@@ -267,6 +316,13 @@ namespace Robust.Shared.Serialization.Manager
/// <typeparam name="T">The type of the objects to copy from and into.</typeparam>
/// <typeparam name="TCopier">The type of the <see cref="ITypeCopier{TType}"/>.</typeparam>
void CopyTo<T, TCopier>(T source, ref T? target, ISerializationContext? context = null, bool skipHook = false, bool notNullableOverride = false) where TCopier : ITypeCopier<T>;
void CopyTo<T, TCopier>(
T source,
ref T? target,
SerializationHookContext hookCtx,
ISerializationContext? context = null,
bool notNullableOverride = false)
where TCopier : ITypeCopier<T>;
/// <summary>
/// Creates a copy of the given object.
@@ -279,6 +335,13 @@ namespace Robust.Shared.Serialization.Manager
[MustUseReturnValue]
object? CreateCopy(object? source, ISerializationContext? context = null, bool skipHook = false, bool notNullableOverride = false);
[MustUseReturnValue]
object? CreateCopy(
object? source,
SerializationHookContext hookCtx,
ISerializationContext? context = null,
bool notNullableOverride = false);
/// <summary>
/// Creates a copy of the given object.
/// </summary>
@@ -291,6 +354,13 @@ namespace Robust.Shared.Serialization.Manager
[MustUseReturnValue]
T CreateCopy<T>(T source, ISerializationContext? context = null, bool skipHook = false, bool notNullableOverride = false);
[MustUseReturnValue]
T CreateCopy<T>(
T source,
SerializationHookContext hookCtx,
ISerializationContext? context = null,
bool notNullableOverride = false);
/// <summary>
/// Creates a copy of the given object using a specified <see cref="ITypeCopyCreator{TType}"/> instance.
/// </summary>
@@ -304,6 +374,14 @@ namespace Robust.Shared.Serialization.Manager
[MustUseReturnValue]
T CreateCopy<T>(ITypeCopyCreator<T> copyCreator, T source, ISerializationContext? context = null, bool skipHook = false, bool notNullableOverride = false);
[MustUseReturnValue]
T CreateCopy<T>(
ITypeCopyCreator<T> copyCreator,
T source,
SerializationHookContext hookCtx,
ISerializationContext? context = null,
bool notNullableOverride = false);
/// <summary>
/// Creates a copy of the given object using a specified <see cref="ITypeCopyCreator{TType}"/> type.
/// </summary>
@@ -317,6 +395,14 @@ namespace Robust.Shared.Serialization.Manager
[MustUseReturnValue]
T CreateCopy<T, TCopyCreator>(T source, ISerializationContext? context = null, bool skipHook = false, bool notNullableOverride = false) where TCopyCreator : ITypeCopyCreator<T>;
[MustUseReturnValue]
T CreateCopy<T, TCopyCreator>(
T source,
SerializationHookContext hookCtx,
ISerializationContext? context = null,
bool notNullableOverride = false)
where TCopyCreator : ITypeCopyCreator<T>;
#endregion
#region Flags And Constants

View File

@@ -7,6 +7,9 @@ using Robust.Shared.Serialization.Markdown;
using Robust.Shared.Serialization.TypeSerializers.Interfaces;
using Robust.Shared.Utility;
// Avoid accidentally mixing up overloads.
// ReSharper disable RedundantTypeArgumentsOfMethod
namespace Robust.Shared.Serialization.Manager;
public sealed partial class SerializationManager
@@ -14,14 +17,14 @@ public sealed partial class SerializationManager
private delegate void CopyToBoxingDelegate(
object source,
ref object target,
bool skipHook,
SerializationHookContext hookCtx,
ISerializationContext? context = null);
private delegate bool CopyToGenericDelegate<T>(
T source,
ref T target,
ISerializationContext? context = null,
bool skipHook = false);
SerializationHookContext hookCtx,
ISerializationContext? context = null);
private readonly ConcurrentDictionary<Type, object> _copyToGenericDelegates = new();
private readonly ConcurrentDictionary<(Type baseType, Type actualType), object> _copyToGenericBaseDelegates = new();
@@ -34,7 +37,7 @@ public sealed partial class SerializationManager
var managerConst = Expression.Constant(manager);
var sourceParam = Expression.Parameter(typeof(object), "source");
var targetParam = Expression.Parameter(typeof(object).MakeByRefType(), "target");
var skipHookParam = Expression.Parameter(typeof(bool), "skipHook");
var hookCtxParam = Expression.Parameter(typeof(SerializationHookContext), "hookCtx");
var contextParam = Expression.Parameter(typeof(ISerializationContext), "context");
var targetVar = Expression.Variable(type);
@@ -48,8 +51,8 @@ public sealed partial class SerializationManager
new[] { type },
Expression.Convert(sourceParam, type),
targetVar,
hookCtxParam,
contextParam,
skipHookParam,
Expression.Constant(false)), //we already handled the override before calling this
Expression.Assign(targetParam, Expression.Convert(targetVar, typeof(object))));
@@ -57,7 +60,7 @@ public sealed partial class SerializationManager
block,
sourceParam,
targetParam,
skipHookParam,
hookCtxParam,
contextParam).Compile();
}, this);
}
@@ -69,7 +72,7 @@ public sealed partial class SerializationManager
var instanceParam = Expression.Constant(manager);
var sourceParam = Expression.Parameter(baseType, "source");
var targetParam = Expression.Parameter(baseType.MakeByRefType(), "target");
var skipHookParam = Expression.Parameter(typeof(bool), "skipHook");
var hookCtxParam = Expression.Parameter(typeof(SerializationHookContext), "hookCtx");
var contextParam = Expression.Parameter(typeof(ISerializationContext), "context");
Expression call;
@@ -90,8 +93,8 @@ public sealed partial class SerializationManager
copierConstant,
sourceVar,
targetVar,
hookCtxParam,
contextParam,
skipHookParam,
Expression.Constant(false)),
Expression.Constant(true));
}
@@ -99,7 +102,7 @@ public sealed partial class SerializationManager
{
call = Expression.Call(instanceParam, nameof(CopyToInternal), new[] { actualType }, sourceVar, targetVar,
Expression.Constant(manager.GetDefinition(actualType), typeof(DataDefinition<>).MakeGenericType(actualType)),
instanceParam, skipHookParam, contextParam);
instanceParam, hookCtxParam, contextParam);
}
if (!sameType)
@@ -113,7 +116,13 @@ public sealed partial class SerializationManager
returnVar);
}
return Expression.Lambda<CopyToGenericDelegate<T>>(call, sourceParam, targetParam, contextParam, skipHookParam).Compile();
return Expression.Lambda<CopyToGenericDelegate<T>>(
call,
sourceParam,
targetParam,
hookCtxParam,
contextParam)
.Compile();
}
var type = typeof(T);
@@ -129,12 +138,12 @@ public sealed partial class SerializationManager
private delegate object CreateCopyBoxingDelegate(
object source,
bool skipHook,
SerializationHookContext hookCtx,
ISerializationContext? context = null);
private delegate T CreateCopyGenericDelegate<T>(
T source,
bool skipHook,
SerializationHookContext hookCtx,
ISerializationContext? context = null);
private readonly ConcurrentDictionary<Type, object> _createCopyGenericDelegates = new();
@@ -146,7 +155,7 @@ public sealed partial class SerializationManager
{
var managerConst = Expression.Constant(manager);
var sourceParam = Expression.Parameter(typeof(object), "source");
var skipHookParam = Expression.Parameter(typeof(bool), "skipHook");
var hookCtxParam = Expression.Parameter(typeof(SerializationHookContext), "hookCtx");
var contextParam = Expression.Parameter(typeof(ISerializationContext), "context");
return Expression.Lambda<CreateCopyBoxingDelegate>(
@@ -155,11 +164,11 @@ public sealed partial class SerializationManager
nameof(CreateCopy),
new[] { type },
Expression.Convert(sourceParam, type),
hookCtxParam,
contextParam,
skipHookParam,
Expression.Constant(false)), typeof(object)),
sourceParam,
skipHookParam,
hookCtxParam,
contextParam).Compile();
}, this);
}
@@ -171,7 +180,7 @@ public sealed partial class SerializationManager
{
var instanceParam = Expression.Constant(manager);
var sourceParam = Expression.Parameter(type, "source");
var skipHookParam = Expression.Parameter(typeof(bool), "skipHook");
var hookCtxParam = Expression.Parameter(typeof(SerializationHookContext), "hookCtx");
var contextParam = Expression.Parameter(typeof(ISerializationContext), "context");
var actualType = type;
@@ -188,8 +197,8 @@ public sealed partial class SerializationManager
new []{type},
copierConst,
sourceParamAccess,
hookCtxParam,
contextParam,
skipHookParam,
Expression.Constant(false));
}
else if (type.IsArray)
@@ -199,8 +208,8 @@ public sealed partial class SerializationManager
nameof(CreateArrayCopy),
new[]{type.GetElementType()!},
sourceParamAccess,
contextParam,
skipHookParam);
hookCtxParam,
contextParam);
}
else
{
@@ -211,8 +220,8 @@ public sealed partial class SerializationManager
nameof(CreateCopy),
Type.EmptyTypes,
Expression.Convert(sourceParam, typeof(object)),
hookCtxParam,
contextParam,
skipHookParam,
Expression.Constant(false)), type);
}
else
@@ -222,8 +231,8 @@ public sealed partial class SerializationManager
nameof(CreateCopyInternal),
new[] {type},
sourceParamAccess,
hookCtxParam,
contextParam,
skipHookParam,
Expression.Constant(manager.GetDefinition(type), typeof(DataDefinition<>).MakeGenericType(type)));
}
}
@@ -231,7 +240,7 @@ public sealed partial class SerializationManager
return Expression.Lambda<CreateCopyGenericDelegate<T>>(
Expression.Convert(call, actualType),
sourceParam,
skipHookParam,
hookCtxParam,
contextParam).Compile();
}, this);
}
@@ -249,7 +258,7 @@ public sealed partial class SerializationManager
ref TCommon target,
DataDefinition<TCommon>? definition,
ISerializationManager serializationManager,
bool skipHook,
SerializationHookContext hookCtx,
ISerializationContext? context)
where TCommon : notnull
{
@@ -257,7 +266,7 @@ public sealed partial class SerializationManager
context.SerializerProvider.TryGetTypeSerializer<ITypeCopier<TCommon>, TCommon>(out var copier))
{
var commonTarget = target;
copier.CopyTo(this, source, ref commonTarget, skipHook, context);
copier.CopyTo(this, source, ref commonTarget, hookCtx, context);
}
if (ShouldReturnSource(typeof(TCommon))) //todo paul can be precomputed
@@ -289,7 +298,7 @@ public sealed partial class SerializationManager
for (var i = 0; i < sourceArray.Length; i++)
{
newArray.SetValue(CreateCopy(sourceArray.GetValue(i), context, skipHook), i);
newArray.SetValue(CreateCopy(sourceArray.GetValue(i), hookCtx, context), i);
}
//todo paul serv3 fix
@@ -303,22 +312,22 @@ public sealed partial class SerializationManager
return false;
}
definition.CopyTo(source, ref target, context, skipHook);
definition.CopyTo(source, ref target, hookCtx, context);
return true;
}
private T[] CreateArrayCopy<T>(T[] source, ISerializationContext context, bool skipHook)
private T[] CreateArrayCopy<T>(T[] source, SerializationHookContext hookCtx, ISerializationContext context)
{
var copy = new T[source.Length];
for (int i = 0; i < source.Length; i++)
{
copy[i] = CreateCopy(source[i], context, skipHook);
copy[i] = CreateCopy(source[i], hookCtx, context);
}
return copy;
}
private T CreateCopyInternal<T>(T source, ISerializationContext context, bool skipHook, DataDefinition<T>? definition) where T : notnull
private T CreateCopyInternal<T>(T source, SerializationHookContext hookCtx, ISerializationContext context, DataDefinition<T>? definition) where T : notnull
{
if (ShouldReturnSource(typeof(T)))
return source;
@@ -329,7 +338,7 @@ public sealed partial class SerializationManager
var isRecord = definition?.IsRecord ?? false;
var target = GetOrCreateInstantiator<T>(isRecord)();
if (!GetOrCreateCopyToGenericDelegate<T>(source)(source, ref target, context, skipHook))
if (!GetOrCreateCopyToGenericDelegate<T>(source)(source, ref target, hookCtx, context))
{
throw new CopyToFailedException<T>();
}
@@ -342,6 +351,16 @@ public sealed partial class SerializationManager
}
public void CopyTo(object? source, ref object? target, ISerializationContext? context = null, bool skipHook = false, bool notNullableOverride = false)
{
CopyTo(source, ref target, SerializationHookContext.ForSkipHooks(skipHook), context, notNullableOverride);
}
public void CopyTo(
object? source,
ref object? target,
SerializationHookContext hookCtx,
ISerializationContext? context = null,
bool notNullableOverride = false)
{
if (source == null)
{
@@ -352,7 +371,7 @@ public sealed partial class SerializationManager
if (target == null)
{
target = CreateCopy(source, context, skipHook);
target = CreateCopy(source, hookCtx, context);
return;
}
@@ -361,10 +380,20 @@ public sealed partial class SerializationManager
throw new InvalidOperationException($"Could not find common type in Copy for types {source.GetType()} and {target.GetType()}!");
}
GetOrCreateCopyToBoxingDelegate(commonType)(source, ref target, skipHook, context);
GetOrCreateCopyToBoxingDelegate(commonType)(source, ref target, hookCtx, context);
}
public void CopyTo<T>(T source, ref T? target, ISerializationContext? context = null, bool skipHook = false, bool notNullableOverride = false)
{
CopyTo<T>(source, ref target, SerializationHookContext.ForSkipHooks(skipHook), context, notNullableOverride);
}
public void CopyTo<T>(
T source,
ref T? target,
SerializationHookContext hookCtx,
ISerializationContext? context = null,
bool notNullableOverride = false)
{
if (source == null)
{
@@ -375,21 +404,37 @@ public sealed partial class SerializationManager
if (target == null)
{
target = CreateCopy(source, context, skipHook)!;
target = CreateCopy(source, hookCtx, context)!;
return;
}
if (!GetOrCreateCopyToGenericDelegate<T>(source)(source, ref target, context))
if (!GetOrCreateCopyToGenericDelegate<T>(source)(source, ref target, hookCtx, context))
{
target = CreateCopy(source, context);
target = CreateCopy(source, hookCtx, context);
}
if(!skipHook && target is ISerializationHooks hookres)
hookres.AfterDeserialization();
RunAfterHook(target, hookCtx);
}
public void CopyTo<T>(ITypeCopier<T> copier, T source, ref T? target, ISerializationContext? context = null,
bool skipHook = false, bool notNullableOverride = false)
{
CopyTo<T>(
copier,
source,
ref target,
SerializationHookContext.ForSkipHooks(skipHook),
context,
notNullableOverride);
}
public void CopyTo<T>(
ITypeCopier<T> copier,
T source,
ref T? target,
SerializationHookContext hookCtx,
ISerializationContext? context = null,
bool notNullableOverride = false)
{
if (source == null)
{
@@ -400,19 +445,43 @@ public sealed partial class SerializationManager
target ??= GetOrCreateInstantiator<T>(false)();
copier.CopyTo(this, source, ref target, skipHook, context);
copier.CopyTo(this, source, ref target, hookCtx, context);
if(!skipHook && target is ISerializationHooks hookres)
hookres.AfterDeserialization();
RunAfterHook(target, hookCtx);
}
public void CopyTo<T, TCopier>(T source, ref T? target, ISerializationContext? context = null, bool skipHook = false, bool notNullableOverride = false)
where TCopier : ITypeCopier<T>
{
CopyTo(GetOrCreateCustomTypeSerializer<TCopier>(), source, ref target, context, skipHook, notNullableOverride);
CopyTo<T, TCopier>(
source,
ref target,
SerializationHookContext.ForSkipHooks(skipHook),
context,
notNullableOverride);
}
public void CopyTo<T, TCopier>(
T source,
ref T? target,
SerializationHookContext hookCtx,
ISerializationContext? context = null,
bool notNullableOverride = false)
where TCopier : ITypeCopier<T>
{
CopyTo(GetOrCreateCustomTypeSerializer<TCopier>(), source, ref target, hookCtx, context, notNullableOverride);
}
public object? CreateCopy(object? source, ISerializationContext? context = null, bool skipHook = false, bool notNullableOverride = false)
{
return CreateCopy(source, SerializationHookContext.ForSkipHooks(skipHook), context, notNullableOverride);
}
public object? CreateCopy(
object? source,
SerializationHookContext hookCtx,
ISerializationContext? context = null,
bool notNullableOverride = false)
{
if (source == null)
{
@@ -420,10 +489,19 @@ public sealed partial class SerializationManager
return null;
}
return GetOrCreateCreateCopyBoxingDelegate(source.GetType())(source, skipHook, context);
return GetOrCreateCreateCopyBoxingDelegate(source.GetType())(source, hookCtx, context);
}
public T CreateCopy<T>(T source, ISerializationContext? context = null, bool skipHook = false, bool notNullableOverride = false)
{
return CreateCopy(source, SerializationHookContext.ForSkipHooks(skipHook), context, notNullableOverride);
}
public T CreateCopy<T>(
T source,
SerializationHookContext hookCtx,
ISerializationContext? context = null,
bool notNullableOverride = false)
{
if (source == null)
{
@@ -431,17 +509,29 @@ public sealed partial class SerializationManager
return default!;
}
var res = GetOrCreateCreateCopyGenericDelegate<T>()(source, skipHook, context);
if (!skipHook && res is ISerializationHooks hooks)
{
hooks.AfterDeserialization();
}
var res = GetOrCreateCreateCopyGenericDelegate<T>()(source, hookCtx, context);
RunAfterHook(res, hookCtx);
return res;
}
public T CreateCopy<T>(ITypeCopyCreator<T> copyCreator, T source, ISerializationContext? context = null,
bool skipHook = false, bool notNullableOverride = false)
{
return CreateCopy<T>(
copyCreator,
source,
SerializationHookContext.ForSkipHooks(skipHook),
context,
notNullableOverride);
}
public T CreateCopy<T>(
ITypeCopyCreator<T> copyCreator,
T source,
SerializationHookContext hookCtx,
ISerializationContext? context = null,
bool notNullableOverride = false)
{
if (source == null)
{
@@ -449,11 +539,8 @@ public sealed partial class SerializationManager
return default!;
}
var res = copyCreator.CreateCopy(this, source, skipHook, context);
if (!skipHook && res is ISerializationHooks hooks)
{
hooks.AfterDeserialization();
}
var res = copyCreator.CreateCopy(this, source, hookCtx, context);
RunAfterHook(res, hookCtx);
return res;
}
@@ -461,6 +548,19 @@ public sealed partial class SerializationManager
public T CreateCopy<T, TCopyCreator>(T source, ISerializationContext? context = null, bool skipHook = false, bool notNullableOverride = false)
where TCopyCreator : ITypeCopyCreator<T>
{
return CreateCopy(GetOrCreateCustomTypeSerializer<TCopyCreator>(), source, context, skipHook, notNullableOverride);
return CreateCopy<T, TCopyCreator>(
source,
SerializationHookContext.ForSkipHooks(skipHook),
context,
notNullableOverride);
}
public T CreateCopy<T, TCopyCreator>(
T source, SerializationHookContext hookCtx,
ISerializationContext? context = null,
bool notNullableOverride = false)
where TCopyCreator : ITypeCopyCreator<T>
{
return CreateCopy(GetOrCreateCustomTypeSerializer<TCopyCreator>(), source, hookCtx, context, notNullableOverride);
}
}

View File

@@ -12,19 +12,22 @@ using Robust.Shared.Serialization.Markdown.Value;
using Robust.Shared.Serialization.TypeSerializers.Interfaces;
using Robust.Shared.Utility;
// Avoid accidentally mixing up overloads.
// ReSharper disable RedundantTypeArgumentsOfMethod
namespace Robust.Shared.Serialization.Manager
{
public partial class SerializationManager
{
private delegate object? ReadBoxingDelegate(
DataNode node,
ISerializationContext? context = null,
bool skipHook = false);
SerializationHookContext hookCtx,
ISerializationContext? context = null);
private delegate T ReadGenericDelegate<T>(
DataNode node,
SerializationHookContext hookCtx,
ISerializationContext? context = null,
bool skipHook = false,
ISerializationManager.InstantiationDelegate<T>? instanceProvider = null);
private readonly ConcurrentDictionary<(Type type, bool notNullableOverride), ReadBoxingDelegate> _readBoxingDelegates = new();
@@ -32,6 +35,21 @@ namespace Robust.Shared.Serialization.Manager
private readonly ConcurrentDictionary<(Type value, Type node, bool notNullableOverride), object> _readGenericDelegates = new();
public T Read<T>(DataNode node, ISerializationContext? context = null, bool skipHook = false, ISerializationManager.InstantiationDelegate<T>? instanceProvider = null, bool notNullableOverride = false)
{
return Read<T>(
node,
SerializationHookContext.ForSkipHooks(skipHook),
context,
instanceProvider,
notNullableOverride);
}
public T Read<T>(
DataNode node,
SerializationHookContext hookCtx,
ISerializationContext? context = null,
ISerializationManager.InstantiationDelegate<T>? instanceProvider = null,
bool notNullableOverride = false)
{
if (node.Tag?.StartsWith("!type:") ?? false)
{
@@ -58,19 +76,40 @@ namespace Robust.Shared.Serialization.Manager
return ((ReadGenericDelegate<T>)_readGenericBaseDelegates.GetOrAdd(
(typeof(T), type, node.GetType()!, notNullableOverride),
static (tuple, manager) => ReadDelegateValueFactory(tuple.baseType, tuple.actualType, tuple.node, tuple.notNullableOverride, manager),
this))(node, context, skipHook, instanceProvider);
this))(node, hookCtx, context, instanceProvider);
}
return ((ReadGenericDelegate<T>)_readGenericDelegates.GetOrAdd((typeof(T), node.GetType()!, notNullableOverride),
static (tuple, manager) => ReadDelegateValueFactory(tuple.value, tuple.value, tuple.node, tuple.notNullableOverride, manager), this))(node, context, skipHook, instanceProvider);
static (tuple, manager) => ReadDelegateValueFactory(tuple.value, tuple.value, tuple.node, tuple.notNullableOverride, manager), this))(node, hookCtx, context, instanceProvider);
}
public T Read<T, TNode>(ITypeReader<T, TNode> reader, TNode node, ISerializationContext? context = null,
bool skipHook = false, ISerializationManager.InstantiationDelegate<T>? instanceProvider = null, bool notNullableOverride = false)
where TNode : DataNode
{
var val = reader.Read(this, node, DependencyCollection, skipHook, context, instanceProvider);
if(notNullableOverride) Debug.Assert(val != null, "Reader call returned null value! Forbidden!");
return Read<T, TNode>(
reader,
node,
SerializationHookContext.ForSkipHooks(skipHook),
context,
instanceProvider,
notNullableOverride);
}
public T Read<T, TNode>(
ITypeReader<T, TNode> reader,
TNode node,
SerializationHookContext hookCtx,
ISerializationContext? context = null,
ISerializationManager.InstantiationDelegate<T>? instanceProvider = null,
bool notNullableOverride = false)
where TNode : DataNode
{
var val = reader.Read(this, node, DependencyCollection, hookCtx, context, instanceProvider);
if (notNullableOverride)
Debug.Assert(val != null, "Reader call returned null value! Forbidden!");
return val;
}
@@ -78,13 +117,45 @@ namespace Robust.Shared.Serialization.Manager
bool skipHook = false, ISerializationManager.InstantiationDelegate<T>? instanceProvider = null, bool notNullableOverride = false) where TNode : DataNode
where TReader : ITypeReader<T, TNode>
{
return Read(GetOrCreateCustomTypeSerializer<TReader>(), node, context, skipHook,
instanceProvider, notNullableOverride);
return Read<T, TNode, TReader>(
node,
SerializationHookContext.ForSkipHooks(skipHook),
context,
instanceProvider,
notNullableOverride);
}
public T Read<T, TNode, TReader>(
TNode node,
SerializationHookContext hookCtx,
ISerializationContext? context = null,
ISerializationManager.InstantiationDelegate<T>? instanceProvider = null,
bool notNullableOverride = false)
where TNode : DataNode
where TReader : ITypeReader<T, TNode>
{
return Read(
GetOrCreateCustomTypeSerializer<TReader>(),
node,
hookCtx,
context,
instanceProvider,
notNullableOverride);
}
public object? Read(Type type, DataNode node, ISerializationContext? context = null, bool skipHook = false, bool notNullableOverride = false)
{
return GetOrCreateBoxingReadDelegate(type, notNullableOverride)(node, context, skipHook);
return Read(type, node, SerializationHookContext.ForSkipHooks(skipHook), context, notNullableOverride);
}
public object? Read(
Type type,
DataNode node,
SerializationHookContext hookCtx,
ISerializationContext? context = null,
bool notNullableOverride = false)
{
return GetOrCreateBoxingReadDelegate(type, notNullableOverride)(node, hookCtx, context);
}
private ReadBoxingDelegate GetOrCreateBoxingReadDelegate(Type type, bool notNullableOverride = false)
@@ -96,23 +167,23 @@ namespace Robust.Shared.Serialization.Manager
var nodeParam = Expression.Variable(typeof(DataNode));
var contextParam = Expression.Variable(typeof(ISerializationContext));
var skipHookParam = Expression.Variable(typeof(bool));
var hookCtxParam = Expression.Variable(typeof(SerializationHookContext));
var call = Expression.Convert(Expression.Call(
managerConst,
nameof(Read),
new[] { type },
nodeParam,
hookCtxParam,
contextParam,
skipHookParam,
Expression.Constant(null, typeof(ISerializationManager.InstantiationDelegate<>).MakeGenericType(type)),
Expression.Constant(tuple.notNullableOverride)), typeof(object));
return Expression.Lambda<ReadBoxingDelegate>(
call,
nodeParam,
contextParam,
skipHookParam).Compile();
hookCtxParam,
contextParam).Compile();
}, this);
}
@@ -124,7 +195,7 @@ namespace Robust.Shared.Serialization.Manager
var nodeParam = Expression.Parameter(typeof(DataNode), "node");
var contextParam = Expression.Parameter(typeof(ISerializationContext), "context");
var skipHookParam = Expression.Parameter(typeof(bool), "skipHook");
var hookCtxParam = Expression.Parameter(typeof(SerializationHookContext), "hookCtx");
var instantiatorParam = Expression.Parameter(typeof(ISerializationManager.InstantiationDelegate<>).MakeGenericType(baseType), "instanceProvider");
actualType = actualType.EnsureNotNullableType();
@@ -171,8 +242,8 @@ namespace Robust.Shared.Serialization.Manager
new[] { actualType, nodeType },
readerConst,
Expression.Convert(nodeParam, nodeType),
hookCtxParam,
contextParam,
skipHookParam,
BaseInstantiatorToActual(),
Expression.Constant(notNullableOverride));
}
@@ -182,13 +253,23 @@ namespace Robust.Shared.Serialization.Manager
if (nodeType == typeof(ValueDataNode))
{
call = Expression.Call(managerConst, nameof(ReadArrayValue), new[] { elementType },
Expression.Convert(nodeParam, typeof(ValueDataNode)), contextParam, skipHookParam);
call = Expression.Call(
managerConst,
nameof(ReadArrayValue),
new[] { elementType },
Expression.Convert(nodeParam, typeof(ValueDataNode)),
hookCtxParam,
contextParam);
}
else if (nodeType == typeof(SequenceDataNode))
{
call = Expression.Call(managerConst, nameof(ReadArraySequence), new[] { elementType },
Expression.Convert(nodeParam, typeof(SequenceDataNode)), contextParam, skipHookParam);
call = Expression.Call(
managerConst,
nameof(ReadArraySequence),
new[] { elementType },
Expression.Convert(nodeParam, typeof(SequenceDataNode)),
hookCtxParam,
contextParam);
}
else
{
@@ -231,12 +312,14 @@ namespace Robust.Shared.Serialization.Manager
}
else
{
var hooksConst = Expression.Constant(actualType.IsAssignableTo(typeof(ISerializationHooks)));
if (nodeType == typeof(ValueDataNode))
{
call = Expression.Call(managerConst, nameof(ReadGenericValue), new[] { actualType },
Expression.Convert(nodeParam, typeof(ValueDataNode)), hooksConst, skipHookParam,
call = Expression.Call(
managerConst,
nameof(ReadGenericValue),
new[] { actualType },
Expression.Convert(nodeParam, typeof(ValueDataNode)),
hookCtxParam,
instantiatorVariable);
}
else if (nodeType == typeof(MappingDataNode))
@@ -244,9 +327,14 @@ namespace Robust.Shared.Serialization.Manager
var definition = manager.GetDefinition(actualType);
var definitionConst = Expression.Constant(definition, typeof(DataDefinition<>).MakeGenericType(actualType));
call = Expression.Call(managerConst, nameof(ReadGenericMapping), new[] { actualType },
Expression.Convert(nodeParam, typeof(MappingDataNode)), definitionConst, hooksConst,
contextParam, skipHookParam,
call = Expression.Call(
managerConst,
nameof(ReadGenericMapping),
new[] { actualType },
Expression.Convert(nodeParam, typeof(MappingDataNode)),
definitionConst,
hookCtxParam,
contextParam,
instantiatorVariable);
}
else
@@ -276,8 +364,8 @@ namespace Robust.Shared.Serialization.Manager
new []{actualType, nodeType},
serializerVar,
Expression.Convert(nodeParam, nodeType),
hookCtxParam,
contextParam,
skipHookParam,
BaseInstantiatorToActual(),
Expression.Constant(notNullableOverride)),
call));
@@ -311,8 +399,14 @@ namespace Robust.Shared.Serialization.Manager
finalValue);
}
return Expression.Lambda(typeof(ReadGenericDelegate<>).MakeGenericType(baseType), call, nodeParam,
contextParam, skipHookParam, instantiatorParam).Compile();
return Expression.Lambda(
typeof(ReadGenericDelegate<>).MakeGenericType(baseType),
call,
nodeParam,
hookCtxParam,
contextParam,
instantiatorParam)
.Compile();
}
private ISerializationManager.InstantiationDelegate<T>? UnwrapInstantiationDelegate<T>(
@@ -344,24 +438,24 @@ namespace Robust.Shared.Serialization.Manager
private T[] ReadArrayValue<T>(
ValueDataNode value,
ISerializationContext? context = null,
bool skipHook = false)
SerializationHookContext hookCtx,
ISerializationContext? context = null)
{
var array = new T[1];
array[0] = Read<T>(value, context, skipHook);
array[0] = Read<T>(value, hookCtx, context);
return array;
}
private T[] ReadArraySequence<T>(
SequenceDataNode node,
ISerializationContext? context = null,
bool skipHook = false)
SerializationHookContext hookCtx,
ISerializationContext? context = null)
{
var array = new T[node.Sequence.Count];
for (var i = 0; i < node.Sequence.Count; i++)
{
array[i] = Read<T>(node.Sequence[i], context, skipHook);
array[i] = Read<T>(node.Sequence[i], hookCtx, context);
}
return array;
@@ -387,8 +481,7 @@ namespace Robust.Shared.Serialization.Manager
private TValue ReadGenericValue<TValue>(
ValueDataNode node,
bool hooks,
bool skipHook,
SerializationHookContext hookCtx,
ISerializationManager.InstantiationDelegate<TValue> instanceProvider)
where TValue : notnull
{
@@ -400,10 +493,7 @@ namespace Robust.Shared.Serialization.Manager
throw new ArgumentException($"No mapping node provided for type {type} at line: {node.Start.Line}");
}
if (!skipHook && hooks)
{
((ISerializationHooks) instance).AfterDeserialization();
}
RunAfterHook(instance, hookCtx);
return instance;
}
@@ -411,9 +501,8 @@ namespace Robust.Shared.Serialization.Manager
private TValue ReadGenericMapping<TValue>(
MappingDataNode node,
DataDefinition<TValue>? definition,
bool hooks,
SerializationHookContext hookCtx,
ISerializationContext? context,
bool skipHook,
ISerializationManager.InstantiationDelegate<TValue> instanceProvider)
where TValue : notnull
{
@@ -424,12 +513,9 @@ namespace Robust.Shared.Serialization.Manager
var instance = instanceProvider();
definition.Populate(ref instance, node, context, skipHook);
definition.Populate(ref instance, node, hookCtx, context);
if (!skipHook && hooks)
{
((ISerializationHooks) instance).AfterDeserialization();
}
RunAfterHook(instance, hookCtx);
return instance;
}

View File

@@ -66,6 +66,8 @@ public sealed partial class SerializationManager
private List<Type> _typeNodeInterfaces = new();
private List<Type> _typeInterfaces = new();
private readonly object _lock = new();
#region GetSerializerMethods
public bool TryGetTypeNodeSerializer<TInterface, TType, TNode>([NotNullWhen(true)] out TInterface? serializer)
@@ -82,26 +84,30 @@ public sealed partial class SerializationManager
public bool TryGetTypeNodeSerializer(Type interfaceType, Type objectType, Type nodeType, [NotNullWhen(true)] out object? serializer)
{
if (_typeNodeSerializers.TryGetValue(interfaceType, out var typeNodeSerializers) &&
typeNodeSerializers.TryGetValue((objectType, nodeType), out serializer))
return true;
if (_genericTypeNodeSerializers.TryGetValue(interfaceType, out var genericTypeNodeSerializers) && objectType.IsGenericType)
lock (_lock)
{
var typeDef = objectType.GetGenericTypeDefinition();
foreach (var (key, val) in genericTypeNodeSerializers)
if (_typeNodeSerializers.TryGetValue(interfaceType, out var typeNodeSerializers) &&
typeNodeSerializers.TryGetValue((objectType, nodeType), out serializer))
return true;
if (_genericTypeNodeSerializers.TryGetValue(interfaceType, out var genericTypeNodeSerializers) &&
objectType.IsGenericType)
{
if (typeDef.HasSameMetadataDefinitionAs(key.ObjectType) && nodeType == key.NodeType)
var typeDef = objectType.GetGenericTypeDefinition();
foreach (var (key, val) in genericTypeNodeSerializers)
{
var serializerType = val.MakeGenericType(objectType.GetGenericArguments());
serializer = RegisterSerializer(serializerType)!;
return true;
if (typeDef.HasSameMetadataDefinitionAs(key.ObjectType) && nodeType == key.NodeType)
{
var serializerType = val.MakeGenericType(objectType.GetGenericArguments());
serializer = RegisterSerializer(serializerType)!;
return true;
}
}
}
}
serializer = null;
return false;
serializer = null;
return false;
}
}
public TInterface GetTypeNodeSerializer<TInterface, TType, TNode>()
@@ -135,26 +141,30 @@ public sealed partial class SerializationManager
public bool TryGetTypeSerializer(Type interfaceType, Type objectType, [NotNullWhen(true)] out object? serializer)
{
if (_typeSerializers.TryGetValue(interfaceType, out var typeSerializers) &&
typeSerializers.TryGetValue(objectType, out serializer))
return true;
if (_genericTypeSerializers.TryGetValue(interfaceType, out var genericTypeSerializers) && objectType.IsGenericType)
lock (_lock)
{
var typeDef = objectType.GetGenericTypeDefinition();
foreach (var (key, val) in genericTypeSerializers)
if (_typeSerializers.TryGetValue(interfaceType, out var typeSerializers) &&
typeSerializers.TryGetValue(objectType, out serializer))
return true;
if (_genericTypeSerializers.TryGetValue(interfaceType, out var genericTypeSerializers) &&
objectType.IsGenericType)
{
if (typeDef.HasSameMetadataDefinitionAs(key))
var typeDef = objectType.GetGenericTypeDefinition();
foreach (var (key, val) in genericTypeSerializers)
{
var serializerType = val.MakeGenericType(objectType.GetGenericArguments());
serializer = RegisterSerializer(serializerType)!;
return true;
if (typeDef.HasSameMetadataDefinitionAs(key))
{
var serializerType = val.MakeGenericType(objectType.GetGenericArguments());
serializer = RegisterSerializer(serializerType)!;
return true;
}
}
}
}
serializer = null;
return false;
serializer = null;
return false;
}
}
public TInterface GetTypeSerializer<TInterface, TType>()
@@ -182,45 +192,12 @@ public sealed partial class SerializationManager
private object RegisterSerializer(Type type, object obj)
{
foreach (var @interface in type.GetInterfaces())
lock (_lock)
{
if(!@interface.IsGenericType) continue;
foreach (var typeInterface in _typeInterfaces)
{
if (@interface.GetGenericTypeDefinition().HasSameMetadataDefinitionAs(typeInterface))
{
var arguments = @interface.GetGenericArguments();
if (arguments.Length != 1)
throw new InvalidGenericParameterCountException();
_typeSerializers.GetOrNew(typeInterface).Add(arguments[0], obj);
}
}
foreach (var typeInterface in _typeNodeInterfaces)
{
if (@interface.GetGenericTypeDefinition().HasSameMetadataDefinitionAs(typeInterface))
{
var arguments = @interface.GetGenericArguments();
if (arguments.Length != 2)
throw new InvalidGenericParameterCountException();
_typeNodeSerializers.GetOrNew(typeInterface).Add((arguments[0], arguments[1]), obj);
}
}
}
return obj;
}
public T? RegisterSerializer<T>() => (T?)RegisterSerializer(typeof(T));
public object? RegisterSerializer(Type type)
{
if (type.IsGenericTypeDefinition)
{
var typeArguments = type.GetGenericArguments();
foreach (var @interface in type.GetInterfaces())
{
if (!@interface.IsGenericType) continue;
foreach (var typeInterface in _typeInterfaces)
{
if (@interface.GetGenericTypeDefinition().HasSameMetadataDefinitionAs(typeInterface))
@@ -228,14 +205,7 @@ public sealed partial class SerializationManager
var arguments = @interface.GetGenericArguments();
if (arguments.Length != 1)
throw new InvalidGenericParameterCountException();
var objArguments = arguments[0].GetGenericArguments();
for (int i = 0; i < typeArguments.Length; i++)
{
if (typeArguments[i] != objArguments[i])
throw new GenericParameterMismatchException();
}
_genericTypeSerializers.GetOrNew(typeInterface).Add(arguments[0], type);
_typeSerializers.GetOrNew(typeInterface).Add(arguments[0], obj);
}
}
@@ -246,22 +216,69 @@ public sealed partial class SerializationManager
var arguments = @interface.GetGenericArguments();
if (arguments.Length != 2)
throw new InvalidGenericParameterCountException();
var objArguments = arguments[0].GetGenericArguments();
for (int i = 0; i < typeArguments.Length; i++)
{
if (typeArguments[i] != objArguments[i])
throw new GenericParameterMismatchException();
}
_genericTypeNodeSerializers.GetOrNew(typeInterface).Add((arguments[0], arguments[1]), type);
_typeNodeSerializers.GetOrNew(typeInterface).Add((arguments[0], arguments[1]), obj);
}
}
}
return null;
return obj;
}
}
return RegisterSerializer(type, CreateSerializer(type));
public T? RegisterSerializer<T>() => (T?)RegisterSerializer(typeof(T));
public object? RegisterSerializer(Type type)
{
lock (_lock)
{
if (type.IsGenericTypeDefinition)
{
var typeArguments = type.GetGenericArguments();
foreach (var @interface in type.GetInterfaces())
{
foreach (var typeInterface in _typeInterfaces)
{
if (@interface.GetGenericTypeDefinition().HasSameMetadataDefinitionAs(typeInterface))
{
var arguments = @interface.GetGenericArguments();
if (arguments.Length != 1)
throw new InvalidGenericParameterCountException();
var objArguments = arguments[0].GetGenericArguments();
for (int i = 0; i < typeArguments.Length; i++)
{
if (typeArguments[i] != objArguments[i])
throw new GenericParameterMismatchException();
}
_genericTypeSerializers.GetOrNew(typeInterface).Add(arguments[0], type);
}
}
foreach (var typeInterface in _typeNodeInterfaces)
{
if (@interface.GetGenericTypeDefinition().HasSameMetadataDefinitionAs(typeInterface))
{
var arguments = @interface.GetGenericArguments();
if (arguments.Length != 2)
throw new InvalidGenericParameterCountException();
var objArguments = arguments[0].GetGenericArguments();
for (int i = 0; i < typeArguments.Length; i++)
{
if (typeArguments[i] != objArguments[i])
throw new GenericParameterMismatchException();
}
_genericTypeNodeSerializers.GetOrNew(typeInterface)
.Add((arguments[0], arguments[1]), type);
}
}
}
return null;
}
return RegisterSerializer(type, CreateSerializer(type));
}
}
//todo paul serv3 is there a better way than comparing names here?
@@ -269,31 +286,38 @@ public sealed partial class SerializationManager
{
if (!type.IsGenericTypeDefinition)
throw new ArgumentException("Only generic type definitions can be signed up as interfaces", nameof(type));
var genericTypeNode = typeof(BaseSerializerInterfaces.ITypeNodeInterface<,>);
var genericType = typeof(BaseSerializerInterfaces.ITypeInterface<>);
var genericParams = type.GetGenericArguments();
foreach (var @interface in type.GetInterfaces())
// Note: lock is entered recursively.
lock (_lock)
{
var genericInterface = @interface.GetGenericTypeDefinition();
if (genericInterface.HasSameMetadataDefinitionAs(genericTypeNode))
var genericTypeNode = typeof(BaseSerializerInterfaces.ITypeNodeInterface<,>);
var genericType = typeof(BaseSerializerInterfaces.ITypeInterface<>);
var genericParams = type.GetGenericArguments();
foreach (var @interface in type.GetInterfaces())
{
var genericInterfaceParams = genericInterface.GetGenericArguments();
for (int i = 0; i < genericParams.Length; i++)
var genericInterface = @interface.GetGenericTypeDefinition();
if (genericInterface.HasSameMetadataDefinitionAs(genericTypeNode))
{
if (genericParams[i].Name != genericInterfaceParams[i].Name)
throw new GenericParameterMismatchException();
var genericInterfaceParams = genericInterface.GetGenericArguments();
for (int i = 0; i < genericParams.Length; i++)
{
if (genericParams[i].Name != genericInterfaceParams[i].Name)
throw new GenericParameterMismatchException();
}
_typeNodeInterfaces.Add(type);
}
_typeNodeInterfaces.Add(type);
}
else if (genericInterface.HasSameMetadataDefinitionAs(genericType))
{
var genericInterfaceParams = genericInterface.GetGenericArguments();
for (int i = 0; i < genericParams.Length; i++)
else if (genericInterface.HasSameMetadataDefinitionAs(genericType))
{
if (genericParams[i].Name != genericInterfaceParams[i].Name)
throw new GenericParameterMismatchException();
var genericInterfaceParams = genericInterface.GetGenericArguments();
for (int i = 0; i < genericParams.Length; i++)
{
if (genericParams[i].Name != genericInterfaceParams[i].Name)
throw new GenericParameterMismatchException();
}
_typeInterfaces.Add(type);
}
_typeInterfaces.Add(type);
}
}
}

View File

@@ -271,5 +271,20 @@ namespace Robust.Shared.Serialization.Manager
return type;
}
private static void RunAfterHook<TValue>(TValue instance, SerializationHookContext ctx)
{
#pragma warning disable CS0618
if (ctx.SkipHooks || instance is not ISerializationHooks hooks)
#pragma warning restore CS0618
return;
DebugTools.Assert(!typeof(TValue).IsValueType, "ISerializationHooks must only be used on reference types");
if (ctx.DeferQueue != null)
ctx.DeferQueue.TryWrite(hooks);
else
hooks.AfterDeserialization();
}
}
}

View File

@@ -0,0 +1,57 @@
using System;
using System.Collections.Generic;
using Robust.Shared.Serialization.Markdown.Mapping;
using Robust.Shared.Serialization.Markdown.Sequence;
using Robust.Shared.Serialization.Markdown.Value;
namespace Robust.Shared.Serialization.Markdown;
public static class DataNodeHelpers
{
public static IEnumerable<DataNode> GetAllNodes(DataNode node)
{
return node switch
{
MappingDataNode mapping => GetAllNodes(mapping),
SequenceDataNode sequence => GetAllNodes(sequence),
ValueDataNode value => GetAllNodes(value),
_ => throw new ArgumentOutOfRangeException(nameof(node))
};
}
private static IEnumerable<DataNode> GetAllNodes(MappingDataNode node)
{
yield return node;
foreach (var (k, v) in node)
{
foreach (var child in GetAllNodes(k))
{
yield return child;
}
foreach (var child in GetAllNodes(v))
{
yield return child;
}
}
}
private static IEnumerable<DataNode> GetAllNodes(SequenceDataNode node)
{
yield return node;
foreach (var s in node)
{
foreach (var child in GetAllNodes(s))
{
yield return child;
}
}
}
private static IEnumerable<DataNode> GetAllNodes(ValueDataNode node)
{
yield return node;
}
}

View File

@@ -10,6 +10,9 @@ using System.Runtime.CompilerServices;
using System.Text;
using NetSerializer;
using Robust.Shared.Log;
using Robust.Shared.Serialization.Markdown;
using Robust.Shared.Serialization.Markdown.Mapping;
using Robust.Shared.Serialization.Markdown.Value;
using Robust.Shared.Utility;
using YamlDotNet.RepresentationModel;
@@ -346,6 +349,30 @@ namespace Robust.Shared.Serialization
}
}
public void AddStrings(DataNode dataNode)
{
if (Locked)
{
throw new InvalidOperationException("Mapped strings are locked, will not add.");
}
foreach (var node in DataNodeHelpers.GetAllNodes(dataNode))
{
var t = node.Tag;
if (!string.IsNullOrEmpty(t))
AddString(t);
if (node is not ValueDataNode value)
continue;
var v = value.Value;
if (string.IsNullOrEmpty(v))
continue;
AddString(v);
}
}
/// <summary>
/// Add strings from the given enumeration to the mapping.
/// </summary>

View File

@@ -15,6 +15,8 @@ using Robust.Shared.IoC;
using Robust.Shared.Log;
using Robust.Shared.Network;
using Robust.Shared.Network.Messages;
using Robust.Shared.Serialization.Markdown;
using Robust.Shared.Serialization.Markdown.Mapping;
using Robust.Shared.Utility;
using YamlDotNet.RepresentationModel;
using static Robust.Shared.Utility.Base64Helpers;
@@ -540,6 +542,14 @@ namespace Robust.Shared.Serialization
}
}
public void AddStrings(DataNode dataNode)
{
if (!_net.IsClient)
{
_dict.AddStrings(dataNode);
}
}
/// <summary>
/// Add strings from the given enumeration to the mapping.
/// </summary>

View File

@@ -0,0 +1,22 @@
using System.Threading.Channels;
namespace Robust.Shared.Serialization;
public sealed class SerializationHookContext
{
public static readonly SerializationHookContext DoSkipHooks = new(null, true);
public static readonly SerializationHookContext DontSkipHooks = new(null, false);
#pragma warning disable CS0618
public readonly ChannelWriter<ISerializationHooks>? DeferQueue;
public readonly bool SkipHooks;
public SerializationHookContext(ChannelWriter<ISerializationHooks>? deferQueue, bool skipHooks)
{
DeferQueue = deferQueue;
SkipHooks = skipHooks;
}
public static SerializationHookContext ForSkipHooks(bool skip) => skip ? DoSkipHooks : DontSkipHooks;
#pragma warning restore CS0618
}

View File

@@ -16,7 +16,7 @@ namespace Robust.Shared.Serialization.TypeSerializers.Implementations
{
public Angle Read(ISerializationManager serializationManager, ValueDataNode node,
IDependencyCollection dependencies,
bool skipHook,
SerializationHookContext hookCtx,
ISerializationContext? context = null,
ISerializationManager.InstantiationDelegate<Angle>? instanceProvider = null)
{
@@ -49,7 +49,7 @@ namespace Robust.Shared.Serialization.TypeSerializers.Implementations
[MustUseReturnValue]
public Angle CreateCopy(ISerializationManager serializationManager, Angle source,
bool skipHook,
SerializationHookContext hookCtx,
ISerializationContext? context = null)
{
return new(source);

View File

@@ -16,32 +16,34 @@ namespace Robust.Shared.Serialization.TypeSerializers.Implementations
[TypeSerializer]
public sealed class Box2Serializer : ITypeSerializer<Box2, ValueDataNode>, ITypeCopyCreator<Box2>
{
private static void NextOrThrow(ref SpanSplitExtensions.Enumerator<char> enumerator, string value)
private static void NextOrThrow(
ref ReadOnlySpan<char> source,
out ReadOnlySpan<char> splitValue,
string errValue)
{
if (!enumerator.MoveNext())
throw new InvalidMappingException($"Could not parse {nameof(Box2)}: '{value}'");
if (!SpanSplitExtensions.SplitFindNext(ref source, ',', out splitValue))
throw new InvalidMappingException($"Could not parse {nameof(Box2)}: '{errValue}'");
}
public Box2 Read(ISerializationManager serializationManager, ValueDataNode node,
IDependencyCollection dependencies,
bool skipHook,
SerializationHookContext hookCtx,
ISerializationContext? context = null,
ISerializationManager.InstantiationDelegate<Box2>? instanceProvider = null)
{
var nodeValue = node.Value;
var args = nodeValue.AsSpan().Split(',').GetEnumerator();
NextOrThrow(ref args, nodeValue);
var nodeValue = node.Value.AsSpan();
NextOrThrow(ref nodeValue, out var current, node.Value);
var l = Parse.Float(args.Current);
NextOrThrow(ref args, nodeValue);
var l = Parse.Float(current);
NextOrThrow(ref nodeValue, out current, node.Value);
var b = Parse.Float(args.Current);
NextOrThrow(ref args, nodeValue);
var b = Parse.Float(current);
NextOrThrow(ref nodeValue, out current, node.Value);
var r = Parse.Float(args.Current);
NextOrThrow(ref args, nodeValue);
var r = Parse.Float(current);
NextOrThrow(ref nodeValue, out current, node.Value);
var t = Parse.Float(args.Current);
var t = Parse.Float(current);
return new Box2(l, b, r, t);
}
@@ -80,7 +82,7 @@ namespace Robust.Shared.Serialization.TypeSerializers.Implementations
[MustUseReturnValue]
public Box2 CreateCopy(ISerializationManager serializationManager, Box2 source,
bool skipHook,
SerializationHookContext hookCtx,
ISerializationContext? context = null)
{
return new(source.Left, source.Bottom, source.Right, source.Top);

View File

@@ -15,7 +15,7 @@ namespace Robust.Shared.Serialization.TypeSerializers.Implementations
{
public Color Read(ISerializationManager serializationManager, ValueDataNode node,
IDependencyCollection dependencies,
bool skipHook,
SerializationHookContext hookCtx,
ISerializationContext? context = null,
ISerializationManager.InstantiationDelegate<Color>? instanceProvider = null)
{
@@ -44,7 +44,7 @@ namespace Robust.Shared.Serialization.TypeSerializers.Implementations
[MustUseReturnValue]
public Color CreateCopy(ISerializationManager serializationManager, Color source,
bool skipHook,
SerializationHookContext hookCtx,
ISerializationContext? context = null)
{
return new(source.R, source.G, source.B, source.A);

View File

@@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.Log;
@@ -23,15 +22,16 @@ namespace Robust.Shared.Serialization.TypeSerializers.Implementations
public ComponentRegistry Read(ISerializationManager serializationManager,
SequenceDataNode node,
IDependencyCollection dependencies,
bool skipHook,
SerializationHookContext hookCtx,
ISerializationContext? context = null,
ISerializationManager.InstantiationDelegate<ComponentRegistry>? instanceProvider = null)
{
var factory = dependencies.Resolve<IComponentFactory>();
var components = instanceProvider != null ? instanceProvider() : new ComponentRegistry();
foreach (var componentMapping in node.Sequence.Cast<MappingDataNode>())
foreach (var sequenceEntry in node.Sequence)
{
var componentMapping = (MappingDataNode)sequenceEntry;
string compType = ((ValueDataNode) componentMapping.Get("type")).Value;
// See if type exists to detect errors.
switch (factory.GetComponentAvailability(compType))
@@ -48,7 +48,7 @@ namespace Robust.Shared.Serialization.TypeSerializers.Implementations
}
// Has this type already been added?
if (components.Keys.Contains(compType))
if (components.ContainsKey(compType))
{
Logger.ErrorS(SerializationManager.LogCategory, $"Component of type '{compType}' defined twice in prototype!");
continue;
@@ -58,7 +58,7 @@ namespace Robust.Shared.Serialization.TypeSerializers.Implementations
copy.Remove("type");
var type = factory.GetRegistration(compType).Type;
var read = (IComponent)serializationManager.Read(type, copy, skipHook: skipHook)!;
var read = (IComponent)serializationManager.Read(type, copy, hookCtx)!;
components[compType] = new ComponentRegistryEntry(read, copy);
}
@@ -92,8 +92,9 @@ namespace Robust.Shared.Serialization.TypeSerializers.Implementations
var components = new ComponentRegistry();
var list = new List<ValidationNode>();
foreach (var componentMapping in node.Sequence.Cast<MappingDataNode>())
foreach (var sequenceEntry in node.Sequence)
{
var componentMapping = (MappingDataNode)sequenceEntry;
string compType = ((ValueDataNode) componentMapping.Get("type")).Value;
// See if type exists to detect errors.
switch (factory.GetComponentAvailability(compType))
@@ -111,7 +112,7 @@ namespace Robust.Shared.Serialization.TypeSerializers.Implementations
}
// Has this type already been added?
if (components.Keys.Contains(compType))
if (components.ContainsKey(compType))
{
list.Add(new ErrorNode(componentMapping, "Duplicate Component."));
continue;
@@ -170,7 +171,7 @@ namespace Robust.Shared.Serialization.TypeSerializers.Implementations
}
public void CopyTo(ISerializationManager serializationManager, ComponentRegistry source, ref ComponentRegistry target,
bool skipHook, ISerializationContext? context = null)
SerializationHookContext hookCtx, ISerializationContext? context = null)
{
target.Clear();
target.EnsureCapacity(source.Count);
@@ -192,16 +193,29 @@ namespace Robust.Shared.Serialization.TypeSerializers.Implementations
foreach (var (reg, mapping) in parentDict)
{
if (newCompRegDict.TryFirstOrNull(childReg => reg.References.Any(x => childReg.Key.References.Contains(x)), out var entry))
foreach (var (childReg, idx) in newCompRegDict)
{
newCompReg[entry.Value.Value] = serializationManager.PushCompositionWithGenericNode(reg.Type,
new[] { parent[mapping] }, newCompReg[entry.Value.Value], context);
}
else
{
newCompReg.Add(parent[mapping]);
newCompRegDict[reg] = newCompReg.Count-1;
foreach (var x in reg.References)
{
if (childReg.References.Contains(x))
{
newCompReg[idx] = serializationManager.PushCompositionWithGenericNode(
reg.Type,
new[] { parent[mapping] },
newCompReg[idx],
context);
goto found;
}
}
}
// Not found.
newCompReg.Add(parent[mapping]);
newCompRegDict[reg] = newCompReg.Count-1;
found: ;
}
return newCompReg;

View File

@@ -18,7 +18,7 @@ namespace Robust.Shared.Serialization.TypeSerializers.Implementations.Custom
}
public int Read(ISerializationManager serializationManager, ValueDataNode node,
IDependencyCollection dependencies, bool skipHook, ISerializationContext? context = null,
IDependencyCollection dependencies, SerializationHookContext hookCtx, ISerializationContext? context = null,
ISerializationManager.InstantiationDelegate<int>? instanceProvider = null)
{
var constType = serializationManager.GetConstantTypeFromTag(typeof(TTag));

View File

@@ -19,7 +19,7 @@ namespace Robust.Shared.Serialization.TypeSerializers.Implementations.Custom
}
public int Read(ISerializationManager serializationManager, ValueDataNode node,
IDependencyCollection dependencies, bool skipHook, ISerializationContext? context = null,
IDependencyCollection dependencies, SerializationHookContext hookCtx, ISerializationContext? context = null,
ISerializationManager.InstantiationDelegate<int>? instanceProvider = null)
{
var flagType = serializationManager.GetFlagTypeFromTag(typeof(TTag));
@@ -76,7 +76,7 @@ namespace Robust.Shared.Serialization.TypeSerializers.Implementations.Custom
}
public int Read(ISerializationManager serializationManager, SequenceDataNode node,
IDependencyCollection dependencies, bool skipHook, ISerializationContext? context = null,
IDependencyCollection dependencies, SerializationHookContext hookCtx, ISerializationContext? context = null,
ISerializationManager.InstantiationDelegate<int>? instanceProvider = null)
{
var flagType = serializationManager.GetFlagTypeFromTag(typeof(TTag));
@@ -91,7 +91,7 @@ namespace Robust.Shared.Serialization.TypeSerializers.Implementations.Custom
return flags;
}
public int CreateCopy(ISerializationManager serializationManager, int source, bool skipHook,
public int CreateCopy(ISerializationManager serializationManager, int source, SerializationHookContext hookCtx,
ISerializationContext? context = null)
{
return source;

View File

@@ -42,7 +42,7 @@ namespace Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Pro
}
public PrototypeFlags<T> Read(ISerializationManager serializationManager, SequenceDataNode node,
IDependencyCollection dependencies, bool skipHook, ISerializationContext? context = null,
IDependencyCollection dependencies, SerializationHookContext hookCtx, ISerializationContext? context = null,
ISerializationManager.InstantiationDelegate<PrototypeFlags<T>>? instanceProvider = null)
{
if(instanceProvider != null)
@@ -75,7 +75,7 @@ namespace Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Pro
}
public PrototypeFlags<T> Read(ISerializationManager serializationManager, ValueDataNode node,
IDependencyCollection dependencies, bool skipHook, ISerializationContext? context = null,
IDependencyCollection dependencies, SerializationHookContext hookCtx, ISerializationContext? context = null,
ISerializationManager.InstantiationDelegate<PrototypeFlags<T>>? instanceProvider = null)
{
if(instanceProvider != null)
@@ -85,12 +85,12 @@ namespace Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Pro
}
public PrototypeFlags<T> CreateCopy(ISerializationManager serializationManager, PrototypeFlags<T> source,
bool skipHook, ISerializationContext? context = null)
SerializationHookContext hookCtx, ISerializationContext? context = null)
{
return new PrototypeFlags<T>(source);
}
public void CopyTo(ISerializationManager serializationManager, PrototypeFlags<T> source, ref PrototypeFlags<T> target, bool skipHook,
public void CopyTo(ISerializationManager serializationManager, PrototypeFlags<T> source, ref PrototypeFlags<T> target, SerializationHookContext hookCtx,
ISerializationContext? context = null)
{
target.Clear();

View File

@@ -20,7 +20,7 @@ public sealed class TimeOffsetSerializer : ITypeSerializer<TimeSpan, ValueDataNo
{
public TimeSpan Read(ISerializationManager serializationManager, ValueDataNode node,
IDependencyCollection dependencies,
bool skipHook,
SerializationHookContext hookCtx,
ISerializationContext? context = null,
ISerializationManager.InstantiationDelegate<TimeSpan>? instanceProvider = null)
{

View File

@@ -26,7 +26,7 @@ public sealed class EnumSerializer : ITypeSerializer<Enum, ValueDataNode>
}
public Enum Read(ISerializationManager serializationManager, ValueDataNode node,
IDependencyCollection dependencies, bool skipHook, ISerializationContext? context = null,
IDependencyCollection dependencies, SerializationHookContext hookCtx, ISerializationContext? context = null,
ISerializationManager.InstantiationDelegate<Enum>? instanceProvider = null)
{
if (serializationManager.ReflectionManager.TryParseEnumReference(node.Value, out var @enum))

View File

@@ -14,7 +14,7 @@ namespace Robust.Shared.Serialization.TypeSerializers.Implementations
public sealed class FormattedMessageSerializer : ITypeSerializer<FormattedMessage, ValueDataNode>, ITypeCopyCreator<FormattedMessage>
{
public FormattedMessage Read(ISerializationManager serializationManager,
ValueDataNode node, IDependencyCollection dependencies, bool skipHook,
ValueDataNode node, IDependencyCollection dependencies, SerializationHookContext hookCtx,
ISerializationContext? context = null,
ISerializationManager.InstantiationDelegate<FormattedMessage>? instanceProvider = null)
{
@@ -40,7 +40,7 @@ namespace Robust.Shared.Serialization.TypeSerializers.Implementations
[MustUseReturnValue]
public FormattedMessage CreateCopy(ISerializationManager serializationManager, FormattedMessage source,
bool skipHook, ISerializationContext? context = null)
SerializationHookContext hookCtx, ISerializationContext? context = null)
{
return new(source);
}

View File

@@ -20,14 +20,14 @@ public sealed class CustomHashSetSerializer<T, TCustomSerializer>
HashSet<T> ITypeReader<HashSet<T>, SequenceDataNode>.Read(ISerializationManager serializationManager,
SequenceDataNode node,
IDependencyCollection dependencies,
bool skipHook,
SerializationHookContext hookCtx,
ISerializationContext? context, ISerializationManager.InstantiationDelegate<HashSet<T>>? instanceProvider = null)
{
var set = instanceProvider != null ? instanceProvider() : new HashSet<T>();
foreach (var dataNode in node.Sequence)
{
var value = serializationManager.Read<T, ValueDataNode, TCustomSerializer>((ValueDataNode)dataNode, context, skipHook);
var value = serializationManager.Read<T, ValueDataNode, TCustomSerializer>((ValueDataNode)dataNode, hookCtx, context);
if (value == null)
throw new InvalidOperationException($"{nameof(TCustomSerializer)} returned a null value when reading using a custom hashset serializer.");

View File

@@ -20,14 +20,14 @@ public sealed class CustomQueueSerializer<T, TCustomSerializer>
Queue<T> ITypeReader<Queue<T>, SequenceDataNode>.Read(ISerializationManager serializationManager,
SequenceDataNode node,
IDependencyCollection dependencies,
bool skipHook,
SerializationHookContext hookCtx,
ISerializationContext? context, ISerializationManager.InstantiationDelegate<Queue<T>>? instanceProvider = null)
{
var queue = instanceProvider != null ? instanceProvider() : new Queue<T>();
foreach (var dataNode in node.Sequence)
{
var value = serializationManager.Read<T, ValueDataNode, TCustomSerializer>((ValueDataNode)dataNode, context, skipHook);
var value = serializationManager.Read<T, ValueDataNode, TCustomSerializer>((ValueDataNode)dataNode, hookCtx, context);
if (value == null)
throw new InvalidOperationException($"{nameof(TCustomSerializer)} returned a null value when reading using a custom hashset serializer.");

View File

@@ -40,15 +40,15 @@ public sealed class DictionarySerializer<TKey, TValue> :
}
public Dictionary<TKey, TValue> Read(ISerializationManager serializationManager,
MappingDataNode node, IDependencyCollection dependencies, bool skipHook, ISerializationContext? context,
MappingDataNode node, IDependencyCollection dependencies, SerializationHookContext hookCtx, ISerializationContext? context,
ISerializationManager.InstantiationDelegate<Dictionary<TKey, TValue>>? instanceProvider)
{
var dict = instanceProvider != null ? instanceProvider() : new Dictionary<TKey, TValue>();
foreach (var (key, value) in node.Children)
{
dict.Add(serializationManager.Read<TKey>(key, context, skipHook),
serializationManager.Read<TValue>(value, context, skipHook));
dict.Add(serializationManager.Read<TKey>(key, hookCtx, context),
serializationManager.Read<TValue>(value, hookCtx, context));
}
return dict;
@@ -115,7 +115,7 @@ public sealed class DictionarySerializer<TKey, TValue> :
IReadOnlyDictionary<TKey, TValue> ITypeReader<IReadOnlyDictionary<TKey, TValue>, MappingDataNode>.Read(
ISerializationManager serializationManager, MappingDataNode node,
IDependencyCollection dependencies,
bool skipHook, ISerializationContext? context,
SerializationHookContext hookCtx, ISerializationContext? context,
ISerializationManager.InstantiationDelegate<IReadOnlyDictionary<TKey, TValue>>? instanceProvider)
{
if (instanceProvider != null)
@@ -128,8 +128,8 @@ public sealed class DictionarySerializer<TKey, TValue> :
foreach (var (key, value) in node.Children)
{
dict.Add(serializationManager.Read<TKey>(key, context, skipHook),
serializationManager.Read<TValue>(value, context, skipHook));
dict.Add(serializationManager.Read<TKey>(key, hookCtx, context),
serializationManager.Read<TValue>(value, hookCtx, context));
}
return dict;
@@ -138,21 +138,21 @@ public sealed class DictionarySerializer<TKey, TValue> :
SortedDictionary<TKey, TValue> ITypeReader<SortedDictionary<TKey, TValue>, MappingDataNode>.Read(
ISerializationManager serializationManager, MappingDataNode node,
IDependencyCollection dependencies,
bool skipHook, ISerializationContext? context,
SerializationHookContext hookCtx, ISerializationContext? context,
ISerializationManager.InstantiationDelegate<SortedDictionary<TKey, TValue>>? instanceProvider)
{
var dict = instanceProvider != null ? instanceProvider() : new SortedDictionary<TKey, TValue>();
foreach (var (key, value) in node.Children)
{
dict.Add(serializationManager.Read<TKey>(key, context, skipHook),
serializationManager.Read<TValue>(value, context, skipHook));
dict.Add(serializationManager.Read<TKey>(key, hookCtx, context),
serializationManager.Read<TValue>(value, hookCtx, context));
}
return dict;
}
public void CopyTo(ISerializationManager serializationManager, Dictionary<TKey, TValue> source, ref Dictionary<TKey, TValue> target, bool skipHook,
public void CopyTo(ISerializationManager serializationManager, Dictionary<TKey, TValue> source, ref Dictionary<TKey, TValue> target, SerializationHookContext hookCtx,
ISerializationContext? context = null)
{
target.Clear();
@@ -160,24 +160,24 @@ public sealed class DictionarySerializer<TKey, TValue> :
foreach (var value in source)
{
target.Add(
serializationManager.CreateCopy(value.Key, context, skipHook),
serializationManager.CreateCopy(value.Value, context, skipHook));
serializationManager.CreateCopy(value.Key, hookCtx, context),
serializationManager.CreateCopy(value.Value, hookCtx, context));
}
}
public void CopyTo(ISerializationManager serializationManager, SortedDictionary<TKey, TValue> source, ref SortedDictionary<TKey, TValue> target,
bool skipHook, ISerializationContext? context = null)
SerializationHookContext hookCtx, ISerializationContext? context = null)
{
target.Clear();
foreach (var value in source)
{
target.Add(
serializationManager.CreateCopy(value.Key, context, skipHook),
serializationManager.CreateCopy(value.Value, context, skipHook));
serializationManager.CreateCopy(value.Key, hookCtx, context),
serializationManager.CreateCopy(value.Value, hookCtx, context));
}
}
public IReadOnlyDictionary<TKey, TValue> CreateCopy(ISerializationManager serializationManager, IReadOnlyDictionary<TKey, TValue> source, bool skipHook,
public IReadOnlyDictionary<TKey, TValue> CreateCopy(ISerializationManager serializationManager, IReadOnlyDictionary<TKey, TValue> source, SerializationHookContext hookCtx,
ISerializationContext? context = null)
{
var target = new Dictionary<TKey, TValue>();
@@ -185,8 +185,8 @@ public sealed class DictionarySerializer<TKey, TValue> :
foreach (var value in source)
{
target.Add(
serializationManager.CreateCopy(value.Key, context, skipHook),
serializationManager.CreateCopy(value.Value, context, skipHook));
serializationManager.CreateCopy(value.Key, hookCtx, context),
serializationManager.CreateCopy(value.Value, hookCtx, context));
}
return target;

View File

@@ -22,14 +22,14 @@ namespace Robust.Shared.Serialization.TypeSerializers.Implementations.Generic
HashSet<T> ITypeReader<HashSet<T>, SequenceDataNode>.Read(ISerializationManager serializationManager,
SequenceDataNode node,
IDependencyCollection dependencies,
bool skipHook,
SerializationHookContext hookCtx,
ISerializationContext? context, ISerializationManager.InstantiationDelegate<HashSet<T>>? instanceProvider = null)
{
var set = instanceProvider != null ? instanceProvider() : new HashSet<T>();
foreach (var dataNode in node.Sequence)
{
set.Add(serializationManager.Read<T>(dataNode, context, skipHook));
set.Add(serializationManager.Read<T>(dataNode, hookCtx, context));
}
return set;
@@ -85,7 +85,7 @@ namespace Robust.Shared.Serialization.TypeSerializers.Implementations.Generic
ISerializationManager serializationManager,
SequenceDataNode node,
IDependencyCollection dependencies,
bool skipHook,
SerializationHookContext hookCtx,
ISerializationContext? context,
ISerializationManager.InstantiationDelegate<ImmutableHashSet<T>>? instanceProvider = null)
{
@@ -95,13 +95,13 @@ namespace Robust.Shared.Serialization.TypeSerializers.Implementations.Generic
foreach (var dataNode in node.Sequence)
{
set.Add(serializationManager.Read<T>(dataNode, context, skipHook));
set.Add(serializationManager.Read<T>(dataNode, hookCtx, context));
}
return set.ToImmutable();
}
public void CopyTo(ISerializationManager serializationManager, HashSet<T> source, ref HashSet<T> target, bool skipHook,
public void CopyTo(ISerializationManager serializationManager, HashSet<T> source, ref HashSet<T> target, SerializationHookContext hookCtx,
ISerializationContext? context = null)
{
target.Clear();
@@ -109,11 +109,11 @@ namespace Robust.Shared.Serialization.TypeSerializers.Implementations.Generic
foreach (var val in source)
{
target.Add(serializationManager.CreateCopy(val, context, skipHook));
target.Add(serializationManager.CreateCopy(val, hookCtx, context));
}
}
public ImmutableHashSet<T> CreateCopy(ISerializationManager serializationManager, ImmutableHashSet<T> source, bool skipHook,
public ImmutableHashSet<T> CreateCopy(ISerializationManager serializationManager, ImmutableHashSet<T> source, SerializationHookContext hookCtx,
ISerializationContext? context = null)
{
var target = new HashSet<T>();
@@ -121,7 +121,7 @@ namespace Robust.Shared.Serialization.TypeSerializers.Implementations.Generic
foreach (var val in source)
{
target.Add(serializationManager.CreateCopy(val, context, skipHook));
target.Add(serializationManager.CreateCopy(val, hookCtx, context));
}
return target.ToImmutableHashSet();

View File

@@ -70,14 +70,14 @@ namespace Robust.Shared.Serialization.TypeSerializers.Implementations.Generic
List<T> ITypeReader<List<T>, SequenceDataNode>.Read(ISerializationManager serializationManager,
SequenceDataNode node,
IDependencyCollection dependencies,
bool skipHook,
SerializationHookContext hookCtx,
ISerializationContext? context, ISerializationManager.InstantiationDelegate<List<T>>? instanceProvider = null)
{
var list = instanceProvider != null ? instanceProvider() : new List<T>();
foreach (var dataNode in node.Sequence)
{
list.Add(serializationManager.Read<T>(dataNode, context, skipHook));
list.Add(serializationManager.Read<T>(dataNode, hookCtx, context));
}
return list;
@@ -124,7 +124,7 @@ namespace Robust.Shared.Serialization.TypeSerializers.Implementations.Generic
IReadOnlyList<T> ITypeReader<IReadOnlyList<T>, SequenceDataNode>.Read(
ISerializationManager serializationManager, SequenceDataNode node,
IDependencyCollection dependencies,
bool skipHook, ISerializationContext? context,
SerializationHookContext hookCtx, ISerializationContext? context,
ISerializationManager.InstantiationDelegate<IReadOnlyList<T>>? instanceProvider = null)
{
if(instanceProvider != null)
@@ -134,7 +134,7 @@ namespace Robust.Shared.Serialization.TypeSerializers.Implementations.Generic
foreach (var dataNode in node.Sequence)
{
list.Add(serializationManager.Read<T>(dataNode, context, skipHook));
list.Add(serializationManager.Read<T>(dataNode, hookCtx, context));
}
return list;
@@ -143,7 +143,7 @@ namespace Robust.Shared.Serialization.TypeSerializers.Implementations.Generic
IReadOnlyCollection<T> ITypeReader<IReadOnlyCollection<T>, SequenceDataNode>.Read(
ISerializationManager serializationManager, SequenceDataNode node,
IDependencyCollection dependencies,
bool skipHook, ISerializationContext? context,
SerializationHookContext hookCtx, ISerializationContext? context,
ISerializationManager.InstantiationDelegate<IReadOnlyCollection<T>>? instanceProvider = null)
{
if(instanceProvider != null)
@@ -153,7 +153,7 @@ namespace Robust.Shared.Serialization.TypeSerializers.Implementations.Generic
foreach (var dataNode in node.Sequence)
{
list.Add(serializationManager.Read<T>(dataNode, context, skipHook));
list.Add(serializationManager.Read<T>(dataNode, hookCtx, context));
}
return list;
@@ -162,7 +162,7 @@ namespace Robust.Shared.Serialization.TypeSerializers.Implementations.Generic
ImmutableList<T> ITypeReader<ImmutableList<T>, SequenceDataNode>.Read(
ISerializationManager serializationManager, SequenceDataNode node,
IDependencyCollection dependencies,
bool skipHook, ISerializationContext? context,
SerializationHookContext hookCtx, ISerializationContext? context,
ISerializationManager.InstantiationDelegate<ImmutableList<T>>? instanceProvider = null)
{
if(instanceProvider != null)
@@ -172,13 +172,13 @@ namespace Robust.Shared.Serialization.TypeSerializers.Implementations.Generic
foreach (var dataNode in node.Sequence)
{
list.Add(serializationManager.Read<T>(dataNode, context, skipHook));
list.Add(serializationManager.Read<T>(dataNode, hookCtx, context));
}
return list.ToImmutable();
}
public void CopyTo(ISerializationManager serializationManager, List<T> source, ref List<T> target, bool skipHook,
public void CopyTo(ISerializationManager serializationManager, List<T> source, ref List<T> target, SerializationHookContext hookCtx,
ISerializationContext? context = null)
{
target.Clear();
@@ -188,45 +188,45 @@ namespace Robust.Shared.Serialization.TypeSerializers.Implementations.Generic
for (var i = 0; i < sourceSpan.Length; i++)
{
ref var val = ref sourceSpan[i];
target.Add(serializationManager.CreateCopy(val, context, skipHook));
target.Add(serializationManager.CreateCopy(val, hookCtx, context));
}
}
public IReadOnlyList<T> CreateCopy(ISerializationManager serializationManager, IReadOnlyList<T> source,
bool skipHook,
SerializationHookContext hookCtx,
ISerializationContext? context = null)
{
var target = new List<T>(source.Count);
foreach (var val in source)
{
target.Add(serializationManager.CreateCopy(val, context, skipHook));
target.Add(serializationManager.CreateCopy(val, hookCtx, context));
}
return target;
}
public IReadOnlyCollection<T> CreateCopy(ISerializationManager serializationManager, IReadOnlyCollection<T> source, bool skipHook,
public IReadOnlyCollection<T> CreateCopy(ISerializationManager serializationManager, IReadOnlyCollection<T> source, SerializationHookContext hookCtx,
ISerializationContext? context = null)
{
var target = new List<T>(source.Count);
foreach (var val in source)
{
target.Add(serializationManager.CreateCopy(val, context, skipHook));
target.Add(serializationManager.CreateCopy(val, hookCtx, context));
}
return target;
}
public ImmutableList<T> CreateCopy(ISerializationManager serializationManager, ImmutableList<T> source, bool skipHook,
public ImmutableList<T> CreateCopy(ISerializationManager serializationManager, ImmutableList<T> source, SerializationHookContext hookCtx,
ISerializationContext? context = null)
{
var target = new List<T>(source.Count);
foreach (var val in source)
{
target.Add(serializationManager.CreateCopy(val, context, skipHook));
target.Add(serializationManager.CreateCopy(val, hookCtx, context));
}
return target.ToImmutableList();

View File

@@ -15,14 +15,14 @@ public sealed class QueueSerializer<T> : ITypeSerializer<Queue<T>, SequenceDataN
Queue<T> ITypeReader<Queue<T>, SequenceDataNode>.Read(ISerializationManager serializationManager,
SequenceDataNode node,
IDependencyCollection dependencies,
bool skipHook,
SerializationHookContext hookCtx,
ISerializationContext? context, ISerializationManager.InstantiationDelegate<Queue<T>>? instanceProvider = null)
{
var queue = instanceProvider != null ? instanceProvider() : new Queue<T>();
foreach (var dataNode in node.Sequence)
{
queue.Enqueue(serializationManager.Read<T>(dataNode, context, skipHook));
queue.Enqueue(serializationManager.Read<T>(dataNode, hookCtx, context));
}
return queue;
@@ -55,14 +55,14 @@ public sealed class QueueSerializer<T> : ITypeSerializer<Queue<T>, SequenceDataN
return sequence;
}
public void CopyTo(ISerializationManager serializationManager, Queue<T> source, ref Queue<T> target, bool skipHook, ISerializationContext? context = null)
public void CopyTo(ISerializationManager serializationManager, Queue<T> source, ref Queue<T> target, SerializationHookContext hookCtx, ISerializationContext? context = null)
{
target.Clear();
target.EnsureCapacity(source.Count);
foreach (var val in source)
{
target.Enqueue(serializationManager.CreateCopy(val, context, skipHook));
target.Enqueue(serializationManager.CreateCopy(val, hookCtx, context));
}
}
}

View File

@@ -16,15 +16,15 @@ namespace Robust.Shared.Serialization.TypeSerializers.Implementations.Generic
{
public (T1, T2) Read(ISerializationManager serializationManager, MappingDataNode node,
IDependencyCollection dependencies,
bool skipHook,
SerializationHookContext hookCtx,
ISerializationContext? context = null, ISerializationManager.InstantiationDelegate<(T1, T2)>? val = null)
{
if (node.Children.Count != 1)
throw new InvalidMappingException("Less than or more than 1 mappings provided to ValueTupleSerializer");
var entry = node.Children.First();
var v1 = serializationManager.Read<T1>(entry.Key, context, skipHook);
var v2 = serializationManager.Read<T2>(entry.Value, context, skipHook);
var v1 = serializationManager.Read<T1>(entry.Key, hookCtx, context);
var v2 = serializationManager.Read<T2>(entry.Value, hookCtx, context);
return (v1, v2);
}
@@ -62,11 +62,11 @@ namespace Robust.Shared.Serialization.TypeSerializers.Implementations.Generic
}
public (T1, T2) CreateCopy(ISerializationManager serializationManager, (T1, T2) source,
bool skipHook,
SerializationHookContext hookCtx,
ISerializationContext? context = null)
{
return (serializationManager.CreateCopy(source.Item1, context, skipHook),
serializationManager.CreateCopy(source.Item2, context, skipHook));
return (serializationManager.CreateCopy(source.Item1, hookCtx, context),
serializationManager.CreateCopy(source.Item2, hookCtx, context));
}
}
}

View File

@@ -16,7 +16,7 @@ namespace Robust.Shared.Serialization.TypeSerializers.Implementations
{
public MapId Read(ISerializationManager serializationManager, ValueDataNode node,
IDependencyCollection dependencies,
bool skipHook,
SerializationHookContext hookCtx,
ISerializationContext? context = null,
ISerializationManager.InstantiationDelegate<MapId>? instanceProvider = null)
{
@@ -43,7 +43,7 @@ namespace Robust.Shared.Serialization.TypeSerializers.Implementations
[MustUseReturnValue]
public MapId CreateCopy(ISerializationManager serializationManager, MapId source,
bool skipHook,
SerializationHookContext hookCtx,
ISerializationContext? context = null)
{
return new(source.Value);

View File

@@ -21,7 +21,7 @@ namespace Robust.Shared.Serialization.TypeSerializers.Implementations.Primitive
}
public bool Read(ISerializationManager serializationManager, ValueDataNode node,
IDependencyCollection dependencies, bool skipHook, ISerializationContext? context = null,
IDependencyCollection dependencies, SerializationHookContext hookCtx, ISerializationContext? context = null,
ISerializationManager.InstantiationDelegate<bool>? instanceProvider = null)
{
return bool.Parse(node.Value);

View File

@@ -21,7 +21,7 @@ namespace Robust.Shared.Serialization.TypeSerializers.Implementations.Primitive
}
public byte Read(ISerializationManager serializationManager, ValueDataNode node,
IDependencyCollection dependencies, bool skipHook, ISerializationContext? context = null,
IDependencyCollection dependencies, SerializationHookContext hookCtx, ISerializationContext? context = null,
ISerializationManager.InstantiationDelegate<byte>? instanceProvider = null)
{
return byte.Parse(node.Value, CultureInfo.InvariantCulture);

View File

@@ -21,7 +21,7 @@ namespace Robust.Shared.Serialization.TypeSerializers.Implementations.Primitive
}
public char Read(ISerializationManager serializationManager, ValueDataNode node,
IDependencyCollection dependencies, bool skipHook, ISerializationContext? context = null,
IDependencyCollection dependencies, SerializationHookContext hookCtx, ISerializationContext? context = null,
ISerializationManager.InstantiationDelegate<char>? instanceProvider = null)
{
return char.Parse(node.Value);
@@ -33,5 +33,11 @@ namespace Robust.Shared.Serialization.TypeSerializers.Implementations.Primitive
{
return new ValueDataNode(value.ToString(CultureInfo.InvariantCulture));
}
public char Copy(ISerializationManager serializationManager, char source, char target, bool skipHook,
ISerializationContext? context = null)
{
return source;
}
}
}

View File

@@ -22,7 +22,7 @@ namespace Robust.Shared.Serialization.TypeSerializers.Implementations.Primitive
}
public decimal Read(ISerializationManager serializationManager, ValueDataNode node,
IDependencyCollection dependencies, bool skipHook, ISerializationContext? context = null,
IDependencyCollection dependencies, SerializationHookContext hookCtx, ISerializationContext? context = null,
ISerializationManager.InstantiationDelegate<decimal>? instanceProvider = null)
{
return Parse.Decimal(node.Value);

View File

@@ -22,7 +22,7 @@ namespace Robust.Shared.Serialization.TypeSerializers.Implementations.Primitive
}
public double Read(ISerializationManager serializationManager, ValueDataNode node,
IDependencyCollection dependencies, bool skipHook, ISerializationContext? context = null,
IDependencyCollection dependencies, SerializationHookContext hookCtx, ISerializationContext? context = null,
ISerializationManager.InstantiationDelegate<double>? instanceProvider = null)
{
return Parse.Double(node.Value);

View File

@@ -21,7 +21,7 @@ namespace Robust.Shared.Serialization.TypeSerializers.Implementations.Primitive
}
public float Read(ISerializationManager serializationManager, ValueDataNode node,
IDependencyCollection dependencies, bool skipHook, ISerializationContext? context = null,
IDependencyCollection dependencies, SerializationHookContext hookCtx, ISerializationContext? context = null,
ISerializationManager.InstantiationDelegate<float>? instanceProvider = null)
{
return float.Parse(node.Value, CultureInfo.InvariantCulture);

View File

@@ -22,7 +22,7 @@ namespace Robust.Shared.Serialization.TypeSerializers.Implementations.Primitive
}
public int Read(ISerializationManager serializationManager, ValueDataNode node,
IDependencyCollection dependencies, bool skipHook, ISerializationContext? context = null,
IDependencyCollection dependencies, SerializationHookContext hookCtx, ISerializationContext? context = null,
ISerializationManager.InstantiationDelegate<int>? instanceProvider = null)
{
return Parse.Int32(node.Value);

View File

@@ -22,7 +22,7 @@ namespace Robust.Shared.Serialization.TypeSerializers.Implementations.Primitive
}
public long Read(ISerializationManager serializationManager, ValueDataNode node,
IDependencyCollection dependencies, bool skipHook, ISerializationContext? context = null,
IDependencyCollection dependencies, SerializationHookContext hookCtx, ISerializationContext? context = null,
ISerializationManager.InstantiationDelegate<long>? instanceProvider = null)
{
return Parse.Int64(node.Value);
@@ -34,5 +34,11 @@ namespace Robust.Shared.Serialization.TypeSerializers.Implementations.Primitive
{
return new ValueDataNode(value.ToString(CultureInfo.InvariantCulture));
}
public long Copy(ISerializationManager serializationManager, long source, long target, bool skipHook,
ISerializationContext? context = null)
{
return source;
}
}
}

View File

@@ -21,7 +21,7 @@ namespace Robust.Shared.Serialization.TypeSerializers.Implementations.Primitive
}
public sbyte Read(ISerializationManager serializationManager, ValueDataNode node,
IDependencyCollection dependencies, bool skipHook, ISerializationContext? context = null,
IDependencyCollection dependencies, SerializationHookContext hookCtx, ISerializationContext? context = null,
ISerializationManager.InstantiationDelegate<sbyte>? instanceProvider = null)
{
return sbyte.Parse(node.Value, CultureInfo.InvariantCulture);

View File

@@ -22,7 +22,7 @@ namespace Robust.Shared.Serialization.TypeSerializers.Implementations.Primitive
}
public short Read(ISerializationManager serializationManager, ValueDataNode node,
IDependencyCollection dependencies, bool skipHook, ISerializationContext? context = null,
IDependencyCollection dependencies, SerializationHookContext hookCtx, ISerializationContext? context = null,
ISerializationManager.InstantiationDelegate<short>? instanceProvider = null)
{
return Parse.Int16(node.Value);

View File

@@ -22,7 +22,7 @@ namespace Robust.Shared.Serialization.TypeSerializers.Implementations.Primitive
}
public uint Read(ISerializationManager serializationManager, ValueDataNode node,
IDependencyCollection dependencies, bool skipHook, ISerializationContext? context = null,
IDependencyCollection dependencies, SerializationHookContext hookCtx, ISerializationContext? context = null,
ISerializationManager.InstantiationDelegate<uint>? instanceProvider = null)
{
return Parse.UInt32(node.Value);

View File

@@ -22,7 +22,7 @@ namespace Robust.Shared.Serialization.TypeSerializers.Implementations.Primitive
}
public ulong Read(ISerializationManager serializationManager, ValueDataNode node,
IDependencyCollection dependencies, bool skipHook, ISerializationContext? context = null,
IDependencyCollection dependencies, SerializationHookContext hookCtx, ISerializationContext? context = null,
ISerializationManager.InstantiationDelegate<ulong>? instanceProvider = null)
{
return Parse.UInt64(node.ToString());

View File

@@ -22,7 +22,7 @@ namespace Robust.Shared.Serialization.TypeSerializers.Implementations.Primitive
}
public ushort Read(ISerializationManager serializationManager, ValueDataNode node,
IDependencyCollection dependencies, bool skipHook, ISerializationContext? context = null,
IDependencyCollection dependencies, SerializationHookContext hookCtx, ISerializationContext? context = null,
ISerializationManager.InstantiationDelegate<ushort>? instanceProvider = null)
{
return Parse.UInt16(node.Value);

View File

@@ -16,7 +16,7 @@ namespace Robust.Shared.Serialization.TypeSerializers.Implementations
{
public Regex Read(ISerializationManager serializationManager, ValueDataNode node,
IDependencyCollection dependencies,
bool skipHook,
SerializationHookContext hookCtx,
ISerializationContext? context = null,
ISerializationManager.InstantiationDelegate<Regex>? instanceProvider = null)
{
@@ -48,7 +48,7 @@ namespace Robust.Shared.Serialization.TypeSerializers.Implementations
[MustUseReturnValue]
public Regex CreateCopy(ISerializationManager serializationManager, Regex source,
bool skipHook,
SerializationHookContext hookCtx,
ISerializationContext? context = null)
{
return new(source.ToString(), source.Options, source.MatchTimeout);

View File

@@ -19,7 +19,7 @@ namespace Robust.Shared.Serialization.TypeSerializers.Implementations
{
public ResourcePath Read(ISerializationManager serializationManager, ValueDataNode node,
IDependencyCollection dependencies,
bool skipHook,
SerializationHookContext hookCtx,
ISerializationContext? context = null,
ISerializationManager.InstantiationDelegate<ResourcePath>? instanceProvider = null)
{
@@ -76,7 +76,7 @@ namespace Robust.Shared.Serialization.TypeSerializers.Implementations
[MustUseReturnValue]
public ResourcePath CreateCopy(ISerializationManager serializationManager, ResourcePath source,
bool skipHook,
SerializationHookContext hookCtx,
ISerializationContext? context = null)
{
return new(source.ToString());

View File

@@ -28,26 +28,26 @@ namespace Robust.Shared.Serialization.TypeSerializers.Implementations
Texture ITypeReader<Texture, ValueDataNode>.Read(ISerializationManager serializationManager,
ValueDataNode node,
IDependencyCollection dependencies,
bool skipHook, ISerializationContext? context,
SerializationHookContext hookCtx, ISerializationContext? context,
ISerializationManager.InstantiationDelegate<Texture>? instanceProvider = null)
{
var path = serializationManager.Read<ResourcePath>(node, context, skipHook);
var path = serializationManager.Read<ResourcePath>(node, hookCtx, context);
return new Texture(path);
}
SpriteSpecifier ITypeReader<SpriteSpecifier, ValueDataNode>.Read(ISerializationManager serializationManager,
ValueDataNode node,
IDependencyCollection dependencies,
bool skipHook, ISerializationContext? context,
SerializationHookContext hookCtx, ISerializationContext? context,
ISerializationManager.InstantiationDelegate<SpriteSpecifier>? instanceProvider = null)
{
return ((ITypeReader<Texture, ValueDataNode>)this).Read(serializationManager, node, dependencies, skipHook, context, (ISerializationManager.InstantiationDelegate<Texture>?)instanceProvider);
return ((ITypeReader<Texture, ValueDataNode>)this).Read(serializationManager, node, dependencies, hookCtx, context, (ISerializationManager.InstantiationDelegate<Texture>?)instanceProvider);
}
EntityPrototype ITypeReader<EntityPrototype, ValueDataNode>.Read(ISerializationManager serializationManager,
ValueDataNode node,
IDependencyCollection dependencies,
bool skipHook, ISerializationContext? context,
SerializationHookContext hookCtx, ISerializationContext? context,
ISerializationManager.InstantiationDelegate<EntityPrototype>? instanceProvider = null)
{
return new EntityPrototype(node.Value);
@@ -56,7 +56,7 @@ namespace Robust.Shared.Serialization.TypeSerializers.Implementations
Rsi ITypeReader<Rsi, MappingDataNode>.Read(ISerializationManager serializationManager,
MappingDataNode node,
IDependencyCollection dependencies,
bool skipHook, ISerializationContext? context,
SerializationHookContext hookCtx, ISerializationContext? context,
ISerializationManager.InstantiationDelegate<Rsi>? instanceProvider = null)
{
if (!node.TryGet("sprite", out var pathNode))
@@ -69,20 +69,20 @@ namespace Robust.Shared.Serialization.TypeSerializers.Implementations
throw new InvalidMappingException("Expected state-node as a valuenode");
}
var path = serializationManager.Read<ResourcePath>(pathNode, context, skipHook);
var path = serializationManager.Read<ResourcePath>(pathNode, hookCtx, context);
return new Rsi(path, valueDataNode.Value);
}
SpriteSpecifier ITypeReader<SpriteSpecifier, MappingDataNode>.Read(ISerializationManager serializationManager,
MappingDataNode node,
IDependencyCollection dependencies,
bool skipHook, ISerializationContext? context,
SerializationHookContext hookCtx, ISerializationContext? context,
ISerializationManager.InstantiationDelegate<SpriteSpecifier>? instanceProvider = null)
{
if (node.TryGet("entity", out var entityNode) && entityNode is ValueDataNode entityValueNode)
return ((ITypeReader<EntityPrototype, ValueDataNode>)this).Read(serializationManager, entityValueNode, dependencies, skipHook, context, (ISerializationManager.InstantiationDelegate<EntityPrototype>?)instanceProvider);
return ((ITypeReader<EntityPrototype, ValueDataNode>)this).Read(serializationManager, entityValueNode, dependencies, hookCtx, context, (ISerializationManager.InstantiationDelegate<EntityPrototype>?)instanceProvider);
return ((ITypeReader<Rsi, MappingDataNode>) this).Read(serializationManager, node, dependencies, skipHook, context, (ISerializationManager.InstantiationDelegate<Rsi>?)instanceProvider);
return ((ITypeReader<Rsi, MappingDataNode>) this).Read(serializationManager, node, dependencies, hookCtx, context, (ISerializationManager.InstantiationDelegate<Rsi>?)instanceProvider);
}
ValidationNode ITypeValidator<SpriteSpecifier, ValueDataNode>.Validate(ISerializationManager serializationManager,
@@ -167,19 +167,19 @@ namespace Robust.Shared.Serialization.TypeSerializers.Implementations
return mapping;
}
public Texture CreateCopy(ISerializationManager serializationManager, Texture source, bool skipHook,
public Texture CreateCopy(ISerializationManager serializationManager, Texture source, SerializationHookContext hookCtx,
ISerializationContext? context = null)
{
return new(source.TexturePath);
}
public EntityPrototype CreateCopy(ISerializationManager serializationManager, EntityPrototype source,
bool skipHook, ISerializationContext? context = null)
SerializationHookContext hookCtx, ISerializationContext? context = null)
{
return new(source.EntityPrototypeId);
}
public Rsi CreateCopy(ISerializationManager serializationManager, Rsi source, bool skipHook,
public Rsi CreateCopy(ISerializationManager serializationManager, Rsi source, SerializationHookContext hookCtx,
ISerializationContext? context = null)
{
return new(source.RsiPath, source.RsiState);
@@ -205,31 +205,31 @@ namespace Robust.Shared.Serialization.TypeSerializers.Implementations
}
public SpriteSpecifier CreateCopy(ISerializationManager serializationManager, SpriteSpecifier source,
bool skipHook, ISerializationContext? context = null)
SerializationHookContext hookCtx, ISerializationContext? context = null)
{
return source switch
{
Rsi rsi
=> CreateCopy(serializationManager, rsi, skipHook, context),
=> CreateCopy(serializationManager, rsi, hookCtx, context),
Texture texture
=> CreateCopy(serializationManager, texture, skipHook, context),
=> CreateCopy(serializationManager, texture, hookCtx, context),
EntityPrototype entityPrototype
=> CreateCopy(serializationManager, entityPrototype, skipHook, context),
=> CreateCopy(serializationManager, entityPrototype, hookCtx, context),
_ => throw new InvalidOperationException("Invalid SpriteSpecifier specified!")
};
}
public void CopyTo(ISerializationManager serializationManager, Rsi source, ref Rsi target, bool skipHook,
public void CopyTo(ISerializationManager serializationManager, Rsi source, ref Rsi target, SerializationHookContext hookCtx,
ISerializationContext? context = null)
{
target.RsiPath = source.RsiPath;
target.RsiState = source.RsiState;
}
public void CopyTo(ISerializationManager serializationManager, Texture source, ref Texture target, bool skipHook,
public void CopyTo(ISerializationManager serializationManager, Texture source, ref Texture target, SerializationHookContext hookCtx,
ISerializationContext? context = null)
{
target.TexturePath = source.TexturePath;

View File

@@ -13,7 +13,7 @@ namespace Robust.Shared.Serialization.TypeSerializers.Implementations
{
public string Read(ISerializationManager serializationManager, ValueDataNode node,
IDependencyCollection dependencies,
bool skipHook,
SerializationHookContext hookCtx,
ISerializationContext? context = null,
ISerializationManager.InstantiationDelegate<string>? instanceProvider = null)
{

View File

@@ -16,7 +16,7 @@ namespace Robust.Shared.Serialization.TypeSerializers.Implementations
{
public TimeSpan Read(ISerializationManager serializationManager, ValueDataNode node,
IDependencyCollection dependencies,
bool skipHook,
SerializationHookContext hookCtx,
ISerializationContext? context = null,
ISerializationManager.InstantiationDelegate<TimeSpan>? instanceProvider = null)
{
@@ -42,7 +42,7 @@ namespace Robust.Shared.Serialization.TypeSerializers.Implementations
[MustUseReturnValue]
public TimeSpan CreateCopy(ISerializationManager serializationManager, TimeSpan source,
bool skipHook,
SerializationHookContext hookCtx,
ISerializationContext? context = null)
{
return source;

View File

@@ -31,7 +31,7 @@ namespace Robust.Shared.Serialization.TypeSerializers.Implementations
}
public Type Read(ISerializationManager serializationManager, ValueDataNode node,
IDependencyCollection dependencies, bool skipHook, ISerializationContext? context = null,
IDependencyCollection dependencies, SerializationHookContext hookCtx, ISerializationContext? context = null,
ISerializationManager.InstantiationDelegate<Type>? instanceProvider = null)
{
if (Shortcuts.TryGetValue(node.Value, out var shortcutType))
@@ -51,7 +51,7 @@ namespace Robust.Shared.Serialization.TypeSerializers.Implementations
return new ValueDataNode(value.FullName ?? value.Name);
}
public Type CreateCopy(ISerializationManager serializationManager, Type source, bool skipHook,
public Type CreateCopy(ISerializationManager serializationManager, Type source, SerializationHookContext hookCtx,
ISerializationContext? context = null)
{
return source;

View File

@@ -16,7 +16,7 @@ namespace Robust.Shared.Serialization.TypeSerializers.Implementations
{
public UIBox2 Read(ISerializationManager serializationManager, ValueDataNode node,
IDependencyCollection dependencies,
bool skipHook,
SerializationHookContext hookCtx,
ISerializationContext? context = null,
ISerializationManager.InstantiationDelegate<UIBox2>? instanceProvider = null)
{
@@ -67,7 +67,7 @@ namespace Robust.Shared.Serialization.TypeSerializers.Implementations
[MustUseReturnValue]
public UIBox2 CreateCopy(ISerializationManager serializationManager, UIBox2 source,
bool skipHook,
SerializationHookContext hookCtx,
ISerializationContext? context = null)
{
return new(source.Left, source.Top, source.Right, source.Bottom);

View File

@@ -16,7 +16,7 @@ namespace Robust.Shared.Serialization.TypeSerializers.Implementations
{
public Vector2 Read(ISerializationManager serializationManager, ValueDataNode node,
IDependencyCollection dependencies,
bool skipHook,
SerializationHookContext hookCtx,
ISerializationContext? context = null,
ISerializationManager.InstantiationDelegate<Vector2>? instanceProvider = null)
{
@@ -54,7 +54,7 @@ namespace Robust.Shared.Serialization.TypeSerializers.Implementations
}
public Vector2 CreateCopy(ISerializationManager serializationManager, Vector2 source,
bool skipHook,
SerializationHookContext hookCtx,
ISerializationContext? context = null)
{
return new(source.X, source.Y);

View File

@@ -16,7 +16,7 @@ namespace Robust.Shared.Serialization.TypeSerializers.Implementations
{
public Vector2i Read(ISerializationManager serializationManager, ValueDataNode node,
IDependencyCollection dependencies,
bool skipHook,
SerializationHookContext hookCtx,
ISerializationContext? context = null,
ISerializationManager.InstantiationDelegate<Vector2i>? instanceProvider = null)
{
@@ -54,7 +54,7 @@ namespace Robust.Shared.Serialization.TypeSerializers.Implementations
}
public Vector2i CreateCopy(ISerializationManager serializationManager, Vector2i source,
bool skipHook,
SerializationHookContext hookCtx,
ISerializationContext? context = null)
{
return new(source.X, source.Y);

View File

@@ -16,7 +16,7 @@ namespace Robust.Shared.Serialization.TypeSerializers.Implementations
{
public Vector3 Read(ISerializationManager serializationManager, ValueDataNode node,
IDependencyCollection dependencies,
bool skipHook,
SerializationHookContext hookCtx,
ISerializationContext? context = null,
ISerializationManager.InstantiationDelegate<Vector3>? instanceProvider = null)
{
@@ -57,7 +57,7 @@ namespace Robust.Shared.Serialization.TypeSerializers.Implementations
}
public Vector3 CreateCopy(ISerializationManager serializationManager, Vector3 source,
bool skipHook,
SerializationHookContext hookCtx,
ISerializationContext? context = null)
{
return new(source);

View File

@@ -16,7 +16,7 @@ namespace Robust.Shared.Serialization.TypeSerializers.Implementations
{
public Vector4 Read(ISerializationManager serializationManager, ValueDataNode node,
IDependencyCollection dependencies,
bool skipHook,
SerializationHookContext hookCtx,
ISerializationContext? context = null,
ISerializationManager.InstantiationDelegate<Vector4>? instanceProvider = null)
{
@@ -61,7 +61,7 @@ namespace Robust.Shared.Serialization.TypeSerializers.Implementations
}
public Vector4 CreateCopy(ISerializationManager serializationManager, Vector4 source,
bool skipHook,
SerializationHookContext hookCtx,
ISerializationContext? context = null)
{
return new(source);

View File

@@ -4,8 +4,11 @@ namespace Robust.Shared.Serialization.TypeSerializers.Interfaces;
public interface ITypeCopier<TType> : BaseSerializerInterfaces.ITypeInterface<TType>
{
void CopyTo(ISerializationManager serializationManager, TType source, ref TType target,
bool skipHook,
void CopyTo(
ISerializationManager serializationManager,
TType source,
ref TType target,
SerializationHookContext hookCtx,
ISerializationContext? context = null);
}

View File

@@ -6,7 +6,9 @@ namespace Robust.Shared.Serialization.TypeSerializers.Interfaces;
public interface ITypeCopyCreator<TType> : BaseSerializerInterfaces.ITypeInterface<TType>
{
[MustUseReturnValue]
TType CreateCopy(ISerializationManager serializationManager, TType source,
bool skipHook,
TType CreateCopy(
ISerializationManager serializationManager,
TType source,
SerializationHookContext hookCtx,
ISerializationContext? context = null);
}

View File

@@ -9,7 +9,7 @@ namespace Robust.Shared.Serialization.TypeSerializers.Interfaces
TType Read(ISerializationManager serializationManager,
TNode node,
IDependencyCollection dependencies,
bool skipHook,
SerializationHookContext hookCtx,
ISerializationContext? context = null,
ISerializationManager.InstantiationDelegate<TType>? instanceProvider = null);
}

View File

@@ -4,86 +4,33 @@ using JetBrains.Annotations;
namespace Robust.Shared.Utility;
// https://github.com/dotnet/runtime/issues/934
// https://gist.github.com/LordJZ/92b7decebe52178a445a0b82f63e585a
internal static class SpanSplitExtensions
{
public ref struct Enumerable<T> where T : IEquatable<T>
public static bool SplitFindNext<T>(
ref ReadOnlySpan<T> source,
T splitOn,
out ReadOnlySpan<T> splitValue)
where T : IEquatable<T>
{
public Enumerable(ReadOnlySpan<T> span, T separator)
if (source.IsEmpty)
{
Span = span;
Separator = separator;
splitValue = ReadOnlySpan<T>.Empty;
return false;
}
private ReadOnlySpan<T> Span { get; }
private T Separator { get; }
public Enumerator<T> GetEnumerator() => new(Span, Separator);
}
internal ref struct Enumerator<T> where T : IEquatable<T>
{
internal Enumerator(ReadOnlySpan<T> span, T separator)
var idx = source.IndexOf(splitOn);
if (idx == -1)
{
Span = span;
Separator = separator;
Current = default;
if (Span.IsEmpty)
TrailingEmptyItem = true;
// Take rest of remaining span.
splitValue = source;
source = ReadOnlySpan<T>.Empty;
}
else
{
splitValue = source[..idx];
source = source[(idx + 1)..];
}
private ReadOnlySpan<T> Span { get; set; }
private T Separator { get; }
private static int SeparatorLength => 1;
private ReadOnlySpan<T> TrailingEmptyItemSentinel => Unsafe.As<T[]>(nameof(TrailingEmptyItemSentinel)).AsSpan();
private bool TrailingEmptyItem
{
get => Span == TrailingEmptyItemSentinel;
set => Span = value ? TrailingEmptyItemSentinel : default;
}
public bool MoveNext()
{
if (TrailingEmptyItem)
{
TrailingEmptyItem = false;
Current = default;
return true;
}
if (Span.IsEmpty)
{
Span = Current = default;
return false;
}
var idx = Span.IndexOf(Separator);
if (idx < 0)
{
Current = Span;
Span = default;
}
else
{
Current = Span[..idx];
Span = Span[(idx + SeparatorLength)..];
if (Span.IsEmpty)
TrailingEmptyItem = true;
}
return true;
}
public ReadOnlySpan<T> Current { get; private set; }
}
[Pure]
internal static Enumerable<T> Split<T>(this ReadOnlySpan<T> span, T separator) where T : IEquatable<T>
{
return new Enumerable<T>(span, separator);
return true;
}
}

View File

@@ -0,0 +1,24 @@
using System.Threading;
using System.Threading.Tasks;
namespace Robust.Shared.Utility;
internal static class WaitHandleHelpers
{
// https://learn.microsoft.com/en-us/dotnet/standard/asynchronous-programming-patterns/interop-with-other-asynchronous-patterns-and-types?redirectedfrom=MSDN#from-wait-handles-to-tap
public static Task WaitOneAsync(WaitHandle handle)
{
var tcs = new TaskCompletionSource();
var rwh = ThreadPool.RegisterWaitForSingleObject(
handle,
delegate { tcs.TrySetResult(); },
null,
-1,
true);
var t = tcs.Task;
t.ContinueWith(_ => rwh.Unregister(null));
return t;
}
}

View File

@@ -7,6 +7,7 @@ using Robust.Shared.IoC;
using Robust.Shared.Network;
using Robust.Shared.Network.Messages;
using Robust.Shared.Serialization;
using Robust.Shared.Serialization.Markdown;
using YamlDotNet.RepresentationModel;
namespace Robust.UnitTesting
@@ -48,6 +49,11 @@ namespace Robust.UnitTesting
// Nada.
}
public void AddStrings(DataNode dataNode)
{
// Nada.
}
public void AddStrings(IEnumerable<string> strings)
{
// Nada.

View File

@@ -62,7 +62,7 @@ namespace Robust.UnitTesting.Server.GameObjects.Components
IoCManager.Resolve<ISerializationManager>().Initialize();
var manager = IoCManager.Resolve<IPrototypeManager>();
manager.RegisterType(typeof(EntityPrototype));
manager.RegisterKind(typeof(EntityPrototype));
manager.LoadFromStream(new StringReader(PROTOTYPES));
manager.ResolveResults();

View File

@@ -77,7 +77,7 @@ entities:
resourceManager.MountString("/EnginePrototypes/TestMapEntity.yml", Prototype);
var protoMan = IoCManager.Resolve<IPrototypeManager>();
protoMan.RegisterType(typeof(EntityPrototype));
protoMan.RegisterKind(typeof(EntityPrototype));
protoMan.LoadDirectory(new ResourcePath("/EnginePrototypes"));
protoMan.LoadDirectory(new ResourcePath("/Prototypes"));

View File

@@ -308,7 +308,7 @@ namespace Robust.UnitTesting.Server
container.Resolve<ISerializationManager>().Initialize();
var protoMan = container.Resolve<IPrototypeManager>();
protoMan.RegisterType(typeof(EntityPrototype));
protoMan.RegisterKind(typeof(EntityPrototype));
_protoDelegate?.Invoke(protoMan);
protoMan.ResolveResults();

View File

@@ -31,7 +31,7 @@ namespace Robust.UnitTesting.Shared.Localization
var protoMan = IoCManager.Resolve<IPrototypeManager>();
protoMan.RegisterType(typeof(EntityPrototype));
protoMan.RegisterKind(typeof(EntityPrototype));
protoMan.LoadDirectory(new ResourcePath("/EnginePrototypes"));
protoMan.ResolveResults();

View File

@@ -30,7 +30,7 @@ namespace Robust.UnitTesting.Shared.Map
{
IoCManager.Resolve<ISerializationManager>().Initialize();
var prototypeManager = IoCManager.Resolve<IPrototypeManager>();
prototypeManager.RegisterType(typeof(EntityPrototype));
prototypeManager.RegisterKind(typeof(EntityPrototype));
prototypeManager.LoadFromStream(new StringReader(PROTOTYPES));
prototypeManager.ResolveResults();

View File

@@ -47,7 +47,7 @@ namespace Robust.UnitTesting.Shared.Prototypes
IoCManager.Resolve<ISerializationManager>().Initialize();
_prototypes = (PrototypeManager) IoCManager.Resolve<IPrototypeManager>();
_prototypes.RegisterType(typeof(EntityPrototype));
_prototypes.RegisterKind(typeof(EntityPrototype));
_prototypes.LoadString(InitialPrototypes);
_prototypes.ResolveResults();

View File

@@ -28,7 +28,7 @@ namespace Robust.UnitTesting.Shared.Prototypes
IoCManager.Resolve<ISerializationManager>().Initialize();
manager = IoCManager.Resolve<IPrototypeManager>();
manager.RegisterType(typeof(EntityPrototype));
manager.RegisterKind(typeof(EntityPrototype));
manager.LoadString(DOCUMENT);
manager.ResolveResults();
}
@@ -126,7 +126,7 @@ namespace Robust.UnitTesting.Shared.Prototypes
parent: {parent}";
}
manager.RegisterType(typeof(CircleTestPrototype));
manager.RegisterKind(typeof(CircleTestPrototype));
var directCircle = $@"{GenerateCircleTestPrototype("1", "2")}
{GenerateCircleTestPrototype("2", "1")}";

View File

@@ -58,7 +58,7 @@ namespace Robust.UnitTesting.Shared.Serialization
var prototypeManager = IoCManager.Resolve<IPrototypeManager>();
prototypeManager.RegisterType(typeof(EntityPrototype));
prototypeManager.RegisterKind(typeof(EntityPrototype));
prototypeManager.LoadString(Prototypes);
prototypeManager.ResolveResults();

View File

@@ -49,7 +49,7 @@ public sealed partial class DataDefinitionTests
}
public int Read(ISerializationManager serializationManager, ValueDataNode node, IDependencyCollection dependencies,
bool skipHook, ISerializationContext? context = null, ISerializationManager.InstantiationDelegate<int>? instanceProvider = null)
SerializationHookContext hookCtx, ISerializationContext? context = null, ISerializationManager.InstantiationDelegate<int>? instanceProvider = null)
{
return SerializerReturnInt;
}
@@ -61,7 +61,7 @@ public sealed partial class DataDefinitionTests
}
public DataDummyStruct Read(ISerializationManager serializationManager, ValueDataNode node, IDependencyCollection dependencies,
bool skipHook, ISerializationContext? context = null, ISerializationManager.InstantiationDelegate<DataDummyStruct>? instanceProvider = null)
SerializationHookContext hookCtx, ISerializationContext? context = null, ISerializationManager.InstantiationDelegate<DataDummyStruct>? instanceProvider = null)
{
return SerializerReturnStruct;
}
@@ -73,7 +73,7 @@ public sealed partial class DataDefinitionTests
}
public DataDummyClass Read(ISerializationManager serializationManager, ValueDataNode node, IDependencyCollection dependencies,
bool skipHook, ISerializationContext? context = null, ISerializationManager.InstantiationDelegate<DataDummyClass>? instanceProvider = null)
SerializationHookContext hookCtx, ISerializationContext? context = null, ISerializationManager.InstantiationDelegate<DataDummyClass>? instanceProvider = null)
{
return SerializerReturnClass;
}
@@ -84,37 +84,37 @@ public sealed partial class DataDefinitionTests
return SerializerValueDataNode;
}
public void CopyTo(ISerializationManager serializationManager, int source, ref int target, bool skipHook,
public void CopyTo(ISerializationManager serializationManager, int source, ref int target, SerializationHookContext hookCtx,
ISerializationContext? context = null)
{
target = SerializerReturnInt;
}
public int CreateCopy(ISerializationManager serializationManager, int source, bool skipHook,
public int CreateCopy(ISerializationManager serializationManager, int source, SerializationHookContext hookCtx,
ISerializationContext? context = null)
{
return SerializerReturnInt;
}
public void CopyTo(ISerializationManager serializationManager, DataDummyStruct source, ref DataDummyStruct target,
bool skipHook, ISerializationContext? context = null)
SerializationHookContext hookCtx, ISerializationContext? context = null)
{
target = SerializerReturnStruct;
}
public DataDummyStruct CreateCopy(ISerializationManager serializationManager, DataDummyStruct source, bool skipHook,
public DataDummyStruct CreateCopy(ISerializationManager serializationManager, DataDummyStruct source, SerializationHookContext hookCtx,
ISerializationContext? context = null)
{
return SerializerReturnStruct;
}
public void CopyTo(ISerializationManager serializationManager, DataDummyClass source, ref DataDummyClass target, bool skipHook,
public void CopyTo(ISerializationManager serializationManager, DataDummyClass source, ref DataDummyClass target, SerializationHookContext hookCtx,
ISerializationContext? context = null)
{
target = SerializerReturnClass;
}
public DataDummyClass CreateCopy(ISerializationManager serializationManager, DataDummyClass source, bool skipHook,
public DataDummyClass CreateCopy(ISerializationManager serializationManager, DataDummyClass source, SerializationHookContext hookCtx,
ISerializationContext? context = null)
{
return SerializerReturnClass;
@@ -148,7 +148,7 @@ public sealed partial class DataDefinitionTests
}
public int Read(ISerializationManager serializationManager, SequenceDataNode node, IDependencyCollection dependencies,
bool skipHook, ISerializationContext? context = null, ISerializationManager.InstantiationDelegate<int>? instanceProvider = null)
SerializationHookContext hookCtx, ISerializationContext? context = null, ISerializationManager.InstantiationDelegate<int>? instanceProvider = null)
{
return SerializerReturnInt;
}
@@ -161,7 +161,7 @@ public sealed partial class DataDefinitionTests
public DataDummyStruct Read(ISerializationManager serializationManager, SequenceDataNode node,
IDependencyCollection dependencies, bool skipHook, ISerializationContext? context = null, ISerializationManager.InstantiationDelegate<DataDummyStruct>? instanceProvider = null)
IDependencyCollection dependencies, SerializationHookContext hookCtx, ISerializationContext? context = null, ISerializationManager.InstantiationDelegate<DataDummyStruct>? instanceProvider = null)
{
return SerializerReturnStruct;
}
@@ -173,7 +173,7 @@ public sealed partial class DataDefinitionTests
}
public DataDummyClass Read(ISerializationManager serializationManager, SequenceDataNode node,
IDependencyCollection dependencies, bool skipHook, ISerializationContext? context = null, ISerializationManager.InstantiationDelegate<DataDummyClass>? instanceProvider = null)
IDependencyCollection dependencies, SerializationHookContext hookCtx, ISerializationContext? context = null, ISerializationManager.InstantiationDelegate<DataDummyClass>? instanceProvider = null)
{
return SerializerReturnClass;
}
@@ -184,37 +184,37 @@ public sealed partial class DataDefinitionTests
return SerializerSequenceDataNode;
}
public void CopyTo(ISerializationManager serializationManager, int source, ref int target, bool skipHook,
public void CopyTo(ISerializationManager serializationManager, int source, ref int target, SerializationHookContext hookCtx,
ISerializationContext? context = null)
{
target = SerializerReturnInt;
}
public int CreateCopy(ISerializationManager serializationManager, int source, bool skipHook,
public int CreateCopy(ISerializationManager serializationManager, int source, SerializationHookContext hookCtx,
ISerializationContext? context = null)
{
return SerializerReturnInt;
}
public void CopyTo(ISerializationManager serializationManager, DataDummyStruct source, ref DataDummyStruct target,
bool skipHook, ISerializationContext? context = null)
SerializationHookContext hookCtx, ISerializationContext? context = null)
{
target = SerializerReturnStruct;
}
public DataDummyStruct CreateCopy(ISerializationManager serializationManager, DataDummyStruct source, bool skipHook,
public DataDummyStruct CreateCopy(ISerializationManager serializationManager, DataDummyStruct source, SerializationHookContext hookCtx,
ISerializationContext? context = null)
{
return SerializerReturnStruct;
}
public void CopyTo(ISerializationManager serializationManager, DataDummyClass source, ref DataDummyClass target, bool skipHook,
public void CopyTo(ISerializationManager serializationManager, DataDummyClass source, ref DataDummyClass target, SerializationHookContext hookCtx,
ISerializationContext? context = null)
{
target = SerializerReturnClass;
}
public DataDummyClass CreateCopy(ISerializationManager serializationManager, DataDummyClass source, bool skipHook,
public DataDummyClass CreateCopy(ISerializationManager serializationManager, DataDummyClass source, SerializationHookContext hookCtx,
ISerializationContext? context = null)
{
return SerializerReturnClass;
@@ -248,7 +248,7 @@ public sealed partial class DataDefinitionTests
}
public int Read(ISerializationManager serializationManager, MappingDataNode node, IDependencyCollection dependencies,
bool skipHook, ISerializationContext? context = null, ISerializationManager.InstantiationDelegate<int>? instanceProvider = null)
SerializationHookContext hookCtx, ISerializationContext? context = null, ISerializationManager.InstantiationDelegate<int>? instanceProvider = null)
{
return SerializerReturnInt;
}
@@ -260,7 +260,7 @@ public sealed partial class DataDefinitionTests
}
public DataDummyStruct Read(ISerializationManager serializationManager, MappingDataNode node,
IDependencyCollection dependencies, bool skipHook, ISerializationContext? context = null, ISerializationManager.InstantiationDelegate<DataDummyStruct>? instanceProvider = null)
IDependencyCollection dependencies, SerializationHookContext hookCtx, ISerializationContext? context = null, ISerializationManager.InstantiationDelegate<DataDummyStruct>? instanceProvider = null)
{
return SerializerReturnStruct;
}
@@ -272,7 +272,7 @@ public sealed partial class DataDefinitionTests
}
public DataDummyClass Read(ISerializationManager serializationManager, MappingDataNode node,
IDependencyCollection dependencies, bool skipHook, ISerializationContext? context = null, ISerializationManager.InstantiationDelegate<DataDummyClass>? instanceProvider = null)
IDependencyCollection dependencies, SerializationHookContext hookCtx, ISerializationContext? context = null, ISerializationManager.InstantiationDelegate<DataDummyClass>? instanceProvider = null)
{
return SerializerReturnClass;
}
@@ -283,37 +283,37 @@ public sealed partial class DataDefinitionTests
return SerializerMappingDataNode;
}
public void CopyTo(ISerializationManager serializationManager, int source, ref int target, bool skipHook,
public void CopyTo(ISerializationManager serializationManager, int source, ref int target, SerializationHookContext hookCtx,
ISerializationContext? context = null)
{
target = SerializerReturnInt;
}
public int CreateCopy(ISerializationManager serializationManager, int source, bool skipHook,
public int CreateCopy(ISerializationManager serializationManager, int source, SerializationHookContext hookCtx,
ISerializationContext? context = null)
{
return SerializerReturnInt;
}
public void CopyTo(ISerializationManager serializationManager, DataDummyStruct source, ref DataDummyStruct target,
bool skipHook, ISerializationContext? context = null)
SerializationHookContext hookCtx, ISerializationContext? context = null)
{
target = SerializerReturnStruct;
}
public DataDummyStruct CreateCopy(ISerializationManager serializationManager, DataDummyStruct source, bool skipHook,
public DataDummyStruct CreateCopy(ISerializationManager serializationManager, DataDummyStruct source, SerializationHookContext hookCtx,
ISerializationContext? context = null)
{
return SerializerReturnStruct;
}
public void CopyTo(ISerializationManager serializationManager, DataDummyClass source, ref DataDummyClass target, bool skipHook,
public void CopyTo(ISerializationManager serializationManager, DataDummyClass source, ref DataDummyClass target, SerializationHookContext hookCtx,
ISerializationContext? context = null)
{
target = SerializerReturnClass;
}
public DataDummyClass CreateCopy(ISerializationManager serializationManager, DataDummyClass source, bool skipHook,
public DataDummyClass CreateCopy(ISerializationManager serializationManager, DataDummyClass source, SerializationHookContext hookCtx,
ISerializationContext? context = null)
{
return SerializerReturnClass;

View File

@@ -49,7 +49,7 @@ public sealed partial class ManagerTests : ISerializationContext
}
public SerializerStruct Read(ISerializationManager serializationManager, ValueDataNode node,
IDependencyCollection dependencies, bool skipHook, ISerializationContext? context = null, ISerializationManager.InstantiationDelegate<SerializerStruct>? instanceProvider = null)
IDependencyCollection dependencies, SerializationHookContext hookCtx, ISerializationContext? context = null, ISerializationManager.InstantiationDelegate<SerializerStruct>? instanceProvider = null)
{
Assert.That(node, Is.EqualTo(SerializerRanDataNode));
return SerializerStruct.SerializerReturn();
@@ -62,13 +62,13 @@ public sealed partial class ManagerTests : ISerializationContext
}
public void CopyTo(ISerializationManager serializationManager, SerializerStruct source, ref SerializerStruct target,
bool skipHook, ISerializationContext? context = null)
SerializationHookContext hookCtx, ISerializationContext? context = null)
{
target.OneValue = source.OneValue;
target.TwoValue = source.TwoValue;
}
public SerializerStruct CreateCopy(ISerializationManager serializationManager, SerializerStruct source, bool skipHook,
public SerializerStruct CreateCopy(ISerializationManager serializationManager, SerializerStruct source, SerializationHookContext hookCtx,
ISerializationContext? context = null)
{
return new SerializerStruct(source.OneValue, source.TwoValue);
@@ -84,7 +84,7 @@ public sealed partial class ManagerTests : ISerializationContext
}
public SerializerStruct Read(ISerializationManager serializationManager, ValueDataNode node,
IDependencyCollection dependencies, bool skipHook, ISerializationContext? context = null, ISerializationManager.InstantiationDelegate<SerializerStruct>? instanceProvider = null)
IDependencyCollection dependencies, SerializationHookContext hookCtx, ISerializationContext? context = null, ISerializationManager.InstantiationDelegate<SerializerStruct>? instanceProvider = null)
{
Assert.That(node, Is.EqualTo(SerializerRanCustomDataNode));
return SerializerStruct.SerializerCustomReturn();
@@ -97,13 +97,13 @@ public sealed partial class ManagerTests : ISerializationContext
}
public void CopyTo(ISerializationManager serializationManager, SerializerStruct source, ref SerializerStruct target,
bool skipHook, ISerializationContext? context = null)
SerializationHookContext hookCtx, ISerializationContext? context = null)
{
target.OneValue = source.OneValue;
target.TwoValue = source.TwoValue;
}
public SerializerStruct CreateCopy(ISerializationManager serializationManager, SerializerStruct source, bool skipHook,
public SerializerStruct CreateCopy(ISerializationManager serializationManager, SerializerStruct source, SerializationHookContext hookCtx,
ISerializationContext? context = null)
{
return new SerializerStruct(source.OneValue, source.TwoValue);
@@ -132,7 +132,7 @@ public sealed partial class ManagerTests : ISerializationContext
}
public SerializerClass Read(ISerializationManager serializationManager, ValueDataNode node,
IDependencyCollection dependencies, bool skipHook, ISerializationContext? context = null, ISerializationManager.InstantiationDelegate<SerializerClass>? instanceProvider = null)
IDependencyCollection dependencies, SerializationHookContext hookCtx, ISerializationContext? context = null, ISerializationManager.InstantiationDelegate<SerializerClass>? instanceProvider = null)
{
Assert.That(node, Is.EqualTo(SerializerRanDataNode));
return SerializerClass.SerializerReturn();
@@ -144,7 +144,7 @@ public sealed partial class ManagerTests : ISerializationContext
return SerializerRanDataNode;
}
public SerializerClass CreateCopy(ISerializationManager serializationManager, SerializerClass source, bool skipHook,
public SerializerClass CreateCopy(ISerializationManager serializationManager, SerializerClass source, SerializationHookContext hookCtx,
ISerializationContext? context = null)
{
return new SerializerClass(source.OneValue, source.TwoValue);
@@ -160,7 +160,7 @@ public sealed partial class ManagerTests : ISerializationContext
}
public SerializerClass Read(ISerializationManager serializationManager, ValueDataNode node,
IDependencyCollection dependencies, bool skipHook, ISerializationContext? context = null, ISerializationManager.InstantiationDelegate<SerializerClass>? instanceProvider = null)
IDependencyCollection dependencies, SerializationHookContext hookCtx, ISerializationContext? context = null, ISerializationManager.InstantiationDelegate<SerializerClass>? instanceProvider = null)
{
Assert.That(node, Is.EqualTo(SerializerRanCustomDataNode));
return SerializerClass.SerializerCustomReturn();
@@ -172,7 +172,7 @@ public sealed partial class ManagerTests : ISerializationContext
return SerializerRanCustomDataNode;
}
public SerializerClass CreateCopy(ISerializationManager serializationManager, SerializerClass source, bool skipHook,
public SerializerClass CreateCopy(ISerializationManager serializationManager, SerializerClass source, SerializationHookContext hookCtx,
ISerializationContext? context = null)
{
return new SerializerClass(source.OneValue, source.TwoValue);

View File

@@ -45,7 +45,7 @@ entitiesImmutableList:
{
var protoMan = IoCManager.Resolve<IPrototypeManager>();
protoMan.RegisterType(typeof(EntityPrototype));
protoMan.RegisterKind(typeof(EntityPrototype));
protoMan.LoadString(Prototypes);
protoMan.ResolveResults();
}