Files
RobustToolbox/Robust.Shared/Serialization/Manager/ISerializationManager.cs
Leon Friedrich fbc706f37b Refactor map loading & saving (#5572)
* Refactor map loading & saving

* test fixes

* ISerializationManager tweaks

* Fix component composition

* Try fix entity deserialization component composition

* comments

* CL

* error preinit

* a

* cleanup

* error if version is too new

* Add AlwaysPushSerializationTest

* Add auto-inclusion test

* Better categorization

* Combine test components

* Save -> TrySave

Also better handling for saving multiple entities individually

* Create new partial class for map loading

* Add OrphanSerializationTest

* Include MapIds in BeforeSerializationEvent

* Addd LifetimeSerializationTest

* Add TestMixedLifetimeSerialization

* Add CategorizationTest

* explicitly serialize list of nullspace entities

* Add backwards compatibility test

* Version comments

also fixes wrong v4 format

* add MapMergeTest

* Add NetEntity support

* Optimize EntityDeserializer

Avoid unnecessary component deserialization

* fix assert & other bugs

* fucking containers strike again

* Fix deletion of pre-init entities

* fix release note merge conflict

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

Co-authored-by: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com>

* VV

---------

Co-authored-by: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com>
2025-02-16 21:25:07 +11:00

455 lines
25 KiB
C#

using System;
using System.Diagnostics.CodeAnalysis;
using JetBrains.Annotations;
using Robust.Shared.Reflection;
using Robust.Shared.Serialization.Markdown;
using Robust.Shared.Serialization.Markdown.Mapping;
using Robust.Shared.Serialization.Markdown.Validation;
using Robust.Shared.Serialization.TypeSerializers.Interfaces;
namespace Robust.Shared.Serialization.Manager
{
public interface ISerializationManager
{
public delegate T InstantiationDelegate<out T>();
/// <summary>
/// Initializes the serialization manager.
/// </summary>
void Initialize();
/// <summary>
/// Shuts down the serialization manager.
/// </summary>
void Shutdown();
IReflectionManager ReflectionManager { get; }
#region Validation
/// <summary>
/// Validates that a node has all the properties required by a certain type.
/// </summary>
/// <param name="type">The type to check for.</param>
/// <param name="node">The node to check.</param>
/// <param name="context">The context to use, if any.</param>
/// <returns>
/// A node with whether or not <see cref="node"/> is valid and which of its fields
/// are invalid, if any.
/// </returns>
[PreferGenericVariant]
ValidationNode ValidateNode(Type type, DataNode node, ISerializationContext? context = null);
/// <summary>
/// Validates that a node has all the properties required by a certain type.
/// </summary>
/// <param name="node">The node to check.</param>
/// <param name="context">The context to use, if any.</param>
/// <typeparam name="T">The type this node should be able to be read into.</typeparam>
/// <returns>
/// A node with whether or not <see cref="node"/> is valid and which of its fields
/// are invalid, if any.
/// </returns>
ValidationNode ValidateNode<T>(DataNode node, ISerializationContext? context = null);
/// <summary>
/// Validates that a node has all the properties required by a certain type using a specified <see cref="ITypeValidator{TType,TNode}"/> instance.
/// </summary>
/// <param name="typeValidator">The <see cref="ITypeValidator{TType,TNode}"/> instance to use.</param>
/// <param name="node">The node to check.</param>
/// <param name="context">The context to use, if any.</param>
/// <typeparam name="T">The type this node should be able to be read into.</typeparam>
/// <typeparam name="TNode">The node type</typeparam>
/// <returns></returns>
ValidationNode ValidateNode<T, TNode>(ITypeValidator<T, TNode> typeValidator, TNode node,
ISerializationContext? context = null) where TNode : DataNode;
/// <summary>
/// Validates that a node has all the properties required by a certain type using a specified <see cref="ITypeValidator{TType,TNode}"/> type.
/// </summary>
/// <param name="node">The node to check.</param>
/// <param name="context">The context to use, if any.</param>
/// <typeparam name="T">The type this node should be able to be read into.</typeparam>
/// <typeparam name="TNode">The node type</typeparam>
/// <typeparam name="TValidator">The type of the <see cref="ITypeValidator{TType,TNode}"/>.</typeparam>
/// <returns></returns>
ValidationNode ValidateNode<T, TNode, TValidator>(TNode node,
ISerializationContext? context = null) where TNode : DataNode where TValidator : ITypeValidator<T, TNode>;
#endregion
#region Read
/// <summary>
/// Deserializes a node into an object, populating it.
/// </summary>
/// <param name="type">The type of object to deserialize into.</param>
/// <param name="node">The node to deserialize.</param>
/// <param name="context">The context to use, if any.</param>
/// <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>
/// <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"/>
/// </summary>
/// <param name="node">The node to deserialize.</param>
/// <param name="context">The context to use, if any.</param>
/// <param name="skipHook">Whether or not to skip running <see cref="ISerializationHooks"/></param>
/// <param name="instanceProvider">The valueProvider which can provide a value to read into. If none is supplied, a new object will be created.</param>
/// <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 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, [NotNullableFlag(nameof(T))] bool notNullableOverride = false);
T Read<T>(
DataNode node,
SerializationHookContext hookCtx,
ISerializationContext? context = null,
InstantiationDelegate<T>? instanceProvider = null,
[NotNullableFlag(nameof(T))] bool notNullableOverride = false);
/// <summary>
/// Deserializes a node into a populated object of the given generic type <see cref="T"/> using the provided <see cref="ITypeReader{TType,TNode}"/> instance.
/// </summary>
/// <param name="reader">The <see cref="ITypeReader{TType,TNode}"/> instance to use.</param>
/// <param name="node">The node to deserialize.</param>
/// <param name="context">The context to use, if any.</param>
/// <param name="skipHook">Whether or not to skip running <see cref="ISerializationHooks"/></param>
/// <param name="instanceProvider">The valueProvider which can provide a value to read into. If none is supplied, a new object will be created.</param>
/// <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 object to create and populate.</typeparam>
/// <typeparam name="TNode">The node type that will be returned by the <see cref="ITypeReader{TType,TNode}"/></typeparam>
/// <returns>The deserialized object, or null.</returns>
T Read<T, TNode>(ITypeReader<T, TNode> reader, TNode node, ISerializationContext? context = null,
bool skipHook = false, InstantiationDelegate<T>? instanceProvider = null, [NotNullableFlag(nameof(T))] 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>
/// <param name="node">The node to deserialize.</param>
/// <param name="context">The context to use, if any.</param>
/// <param name="skipHook">Whether or not to skip running <see cref="ISerializationHooks"/></param>
/// <param name="instanceProvider">The valueProvider which can provide a value to read into. If none is supplied, a new object will be created.</param>
/// <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 object to create and populate.</typeparam>
/// <typeparam name="TNode">The node type that will be returned by the <see cref="ITypeReader{TType,TNode}"/></typeparam>
/// <typeparam name="TReader">The type of the <see cref="ITypeReader{TType,TNode}"/>.</typeparam>
/// <returns>The deserialized object, or null.</returns>
T Read<T, TNode, TReader>(TNode node, ISerializationContext? context = null,
bool skipHook = false, InstantiationDelegate<T>? instanceProvider = null, [NotNullableFlag(nameof(T))] 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
/// <summary>
/// Serializes a value into a node.
/// </summary>
/// <param name="value">The value to serialize.</param>
/// <param name="alwaysWrite">
/// Whether or not to always write the given values into the resulting node,
/// even if they are the default.
/// </param>
/// <param name="context">The context to use, if any.</param>
/// <param name="notNullableOverride">Set true if a reference Type should not allow null. Not necessary for value types.</param>
/// <typeparam name="T">The type to serialize.</typeparam>
/// <returns>A <see cref="DataNode"/> created from the given <see cref="value"/>.</returns>
DataNode WriteValue<T>(T value, bool alwaysWrite = false, ISerializationContext? context = null, [NotNullableFlag(nameof(T))] bool notNullableOverride = false);
/// <summary>
/// Serializes a value into a node using a <see cref="ITypeWriter{TType}"/> instance.
/// </summary>
/// <param name="writer">The <see cref="ITypeWriter{TType}"/> to use for serializing the value.</param>
/// <param name="value">The value to serialize.</param>
/// <param name="alwaysWrite">
/// Whether or not to always write the given values into the resulting node,
/// even if they are the default.
/// </param>
/// <param name="context">The context to use, if any.</param>
/// <param name="notNullableOverride">Set true if a reference Type should not allow null. Not necessary for value types.</param>
/// <typeparam name="T">The type to serialize.</typeparam>
/// <returns>A serialized datanode created from the given <see cref="value"/> by using the typewriter.</returns>
DataNode WriteValue<T>(ITypeWriter<T> writer, T value, bool alwaysWrite = false, ISerializationContext? context = null, [NotNullableFlag(nameof(T))] bool notNullableOverride = false);
/// <summary>
/// Serializes a value into a node using a <see cref="ITypeWriter{TType}"/> type.
/// </summary>
/// <param name="value">The value to serialize.</param>
/// <param name="alwaysWrite">
/// Whether or not to always write the given values into the resulting node,
/// even if they are the default.
/// </param>
/// <param name="context">The context to use, if any.</param>
/// <param name="notNullableOverride">Set true if a reference Type should not allow null. Not necessary for value types.</param>
/// <typeparam name="T">The type to serialize.</typeparam>
/// <typeparam name="TWriter">The type of the <see cref="ITypeWriter{TType}"/>.</typeparam>
/// <returns>A serialized datanode created from the given <see cref="value"/> by using the typewriter.</returns>
DataNode WriteValue<T, TWriter>(T value, bool alwaysWrite = false, ISerializationContext? context = null, [NotNullableFlag(nameof(T))] bool notNullableOverride = false) where TWriter : ITypeWriter<T>;
/// <summary>
/// Serializes a value into a node.
/// </summary>
/// <param name="type">The type of the <see cref="value"/> to serialize as.</param>
/// <param name="value">The value to serialize.</param>
/// <param name="alwaysWrite">
/// Whether or not to always write the given values into the resulting node,
/// even if they are the default.
/// </param>
/// <param name="context">The context to use, if any.</param>
/// <param name="notNullableOverride">Set true if a reference Type should not allow null. Not necessary for value types.</param>
/// <returns>
/// A serialized datanode created from the given <see cref="value"/>
/// of type <see cref="type"/>.
/// </returns>
[PreferGenericVariant]
DataNode WriteValue(Type type, object? value, bool alwaysWrite = false, ISerializationContext? context = null, bool notNullableOverride = false);
#endregion
#region Copy
/// <summary>
/// Copies the values of one object into another.
/// This does not guarantee that the object passed as <see cref="target"/>
/// is actually mutated.
/// </summary>
/// <param name="source">The object to copy values from.</param>
/// <param name="target">The object to copy values into.</param>
/// <param name="context">The context to use, if any.</param>
/// <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.
/// This does not guarantee that the object passed as <see cref="target"/>
/// is actually mutated.
/// </summary>
/// <param name="source">The object to copy values from.</param>
/// <param name="target">The object to copy values into.</param>
/// <param name="context">The context to use, if any.</param>
/// <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>
/// <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, [NotNullableFlag(nameof(T))] bool notNullableOverride = false);
void CopyTo<T>(
T source,
ref T target,
SerializationHookContext hookCtx,
ISerializationContext? context = null,
[NotNullableFlag(nameof(T))] bool notNullableOverride = false);
/// <summary>
/// Copies the values of one object into another using a specified <see cref="ITypeCopier{TType}"/> instance.
/// This does not guarantee that the object passed as <see cref="target"/>
/// is actually mutated.
/// </summary>
/// <param name="copier">the <see cref="ITypeCopier{TType}"/> instance to use</param>
/// <param name="source">The object to copy values from.</param>
/// <param name="target">The object to copy values into.</param>
/// <param name="context">The context to use, if any.</param>
/// <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>
/// <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, [NotNullableFlag(nameof(T))] bool notNullableOverride = false);
void CopyTo<T>(
ITypeCopier<T> copier,
T source,
ref T target,
SerializationHookContext hookCtx,
ISerializationContext? context = null,
[NotNullableFlag(nameof(T))] bool notNullableOverride = false);
/// <summary>
/// Copies the values of one object into another using a specified <see cref="ITypeCopier{TType}"/> type.
/// This does not guarantee that the object passed as <see cref="target"/>
/// is actually mutated.
/// </summary>
/// <param name="source">The object to copy values from.</param>
/// <param name="target">The object to copy values into.</param>
/// <param name="context">The context to use, if any.</param>
/// <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>
/// <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, [NotNullableFlag(nameof(T))] bool notNullableOverride = false) where TCopier : ITypeCopier<T>;
void CopyTo<T, TCopier>(
T source,
ref T target,
SerializationHookContext hookCtx,
ISerializationContext? context = null,
[NotNullableFlag(nameof(T))] bool notNullableOverride = false)
where TCopier : ITypeCopier<T>;
/// <summary>
/// Creates a copy of the given object.
/// </summary>
/// <param name="source">The object to copy.</param>
/// <param name="context">The context to use, if any.</param>
/// <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>
/// <returns>A copy of the given object.</returns>
[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>
/// <param name="source">The object to copy.</param>
/// <param name="context">The context to use, if any.</param>
/// <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>
/// <typeparam name="T">The type of the object to copy.</typeparam>
/// <returns>A copy of the given object.</returns>
[MustUseReturnValue]
T CreateCopy<T>(T source, ISerializationContext? context = null, bool skipHook = false, [NotNullableFlag(nameof(T))] 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>
/// <param name="copyCreator">The <see cref="ITypeCopyCreator{TType}"/> instance.</param>
/// <param name="source">The object to copy.</param>
/// <param name="context">The context to use, if any.</param>
/// <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>
/// <typeparam name="T">The type of the object to copy.</typeparam>
/// <returns>A copy of the given object.</returns>
[MustUseReturnValue]
T CreateCopy<T>(ITypeCopyCreator<T> copyCreator, T source, ISerializationContext? context = null, bool skipHook = false, [NotNullableFlag(nameof(T))] 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>
/// <param name="source">The object to copy.</param>
/// <param name="context">The context to use, if any.</param>
/// <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>
/// <typeparam name="T">The type of the object to copy.</typeparam>
/// <typeparam name="TCopyCreator">The type of the <see cref="ITypeCopier{TType}"/> to use.</typeparam>
/// <returns>A copy of the given object.</returns>
[MustUseReturnValue]
T CreateCopy<T, TCopyCreator>(T source, ISerializationContext? context = null, bool skipHook = false, [NotNullableFlag(nameof(T))] 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>;
[Obsolete]
bool TryGetCopierOrCreator<TType>(
out ITypeCopier<TType>? copier,
out ITypeCopyCreator<TType>? copyCreator,
ISerializationContext? context = null);
[Obsolete]
bool TryCustomCopy<T>(
T source,
ref T target,
SerializationHookContext hookCtx,
bool hasHooks,
ISerializationContext? context = null);
#endregion
#region Flags And Constants
Type GetFlagTypeFromTag(Type tagType);
int GetFlagHighestBit(Type tagType);
Type GetConstantTypeFromTag(Type tagType);
#endregion
#region Composition
DataNode PushComposition(Type type, DataNode[] parents, DataNode child, ISerializationContext? context = null);
public TNode PushComposition<TType, TNode>(TNode[] parents, TNode child, ISerializationContext? context = null) where TNode : DataNode
{
// ReSharper disable once CoVariantArrayConversion
return (TNode)PushComposition(typeof(TType), parents, child, context);
}
TNode PushInheritance<TType, TNode>(ITypeInheritanceHandler<TType, TNode> inheritanceHandler, TNode parent, TNode child,
ISerializationContext? context = null) where TNode : DataNode;
TNode PushInheritance<TType, TNode, TInheritanceHandler>(TNode parent, TNode child,
ISerializationContext? context = null) where TNode : DataNode
where TInheritanceHandler : ITypeInheritanceHandler<TType, TNode>;
public TNode PushCompositionWithGenericNode<TNode>(Type type, TNode[] parents, TNode child, ISerializationContext? context = null) where TNode : DataNode
{
// ReSharper disable once CoVariantArrayConversion
return (TNode) PushComposition(type, parents, child, context);
}
/// <summary>
/// Simple <see cref="MappingDataNode"/> inheritance pusher clones data and overrides a parent's values with
/// the child's.
/// </summary>
MappingDataNode CombineMappings(MappingDataNode child, MappingDataNode parent);
#endregion
public bool TryGetVariableType(Type type, string variableName, [NotNullWhen(true)] out Type? variableType);
}
}