From dcbe0505dce7e98252e8802c0547052becadc87d Mon Sep 17 00:00:00 2001 From: Pieter-Jan Briers Date: Tue, 29 Jul 2025 18:22:17 +0200 Subject: [PATCH] Revert "Add WeakEntityReference (#5577)" (#6112) This reverts commit c3489d4ded3e10067116b208785783ef262d1dc8. --- RELEASE-NOTES.md | 2 +- .../EntitySerialization/EntityDeserializer.cs | 44 +------- .../EntitySerialization/EntitySerializer.cs | 66 ++--------- .../GameObjects/EntityManager.Components.cs | 88 --------------- .../GameObjects/EntityManager.Network.cs | 4 +- Robust.Shared/GameObjects/EntityManager.cs | 13 --- .../GameObjects/EntitySystem.Proxy.cs | 88 --------------- .../GameObjects/IEntityManager.Components.cs | 48 +------- Robust.Shared/GameObjects/IEntityManager.cs | 11 -- .../GameObjects/WeakEntityReference.cs | 68 ----------- Robust.Shared/Prototypes/EntProtoId.cs | 5 +- Robust.Shared/Prototypes/ProtoId.cs | 3 +- .../Prototypes/YamlValidationContext.cs | 71 ++++-------- .../Exceptions/CopyToFailedException.cs | 5 +- .../Implementations/EntProtoIdSerializer.cs | 14 ++- .../Generic/ProtoIdSerializer.cs | 7 +- .../Generic/WeakEntityReferenceSerializer.cs | 60 ---------- .../EntitySerialization/TestComponents.cs | 9 -- .../WeakEntityReferenceTest.cs | 106 ------------------ 19 files changed, 61 insertions(+), 651 deletions(-) delete mode 100644 Robust.Shared/GameObjects/WeakEntityReference.cs delete mode 100644 Robust.Shared/Serialization/TypeSerializers/Implementations/Generic/WeakEntityReferenceSerializer.cs delete mode 100644 Robust.UnitTesting/Shared/EntitySerialization/WeakEntityReferenceTest.cs diff --git a/RELEASE-NOTES.md b/RELEASE-NOTES.md index 18fa308ef2..3951ba4a06 100644 --- a/RELEASE-NOTES.md +++ b/RELEASE-NOTES.md @@ -39,7 +39,7 @@ END TEMPLATE--> ### New features -* Added a new `WeakEntityReference` struct that is intended to be used by component data-fields to refer to entities that may or may not still exist. +*None yet* ### Bugfixes diff --git a/Robust.Shared/EntitySerialization/EntityDeserializer.cs b/Robust.Shared/EntitySerialization/EntityDeserializer.cs index 0e0cc60242..ad7eb21adc 100644 --- a/Robust.Shared/EntitySerialization/EntityDeserializer.cs +++ b/Robust.Shared/EntitySerialization/EntityDeserializer.cs @@ -33,8 +33,7 @@ namespace Robust.Shared.EntitySerialization; public sealed class EntityDeserializer : ISerializationContext, ITypeSerializer, - ITypeSerializer, - ITypeSerializer + ITypeSerializer { // See the comments around EntitySerializer's version const for information about the different versions. // TBH version three isn't even really fully supported anymore, simply due to changes in engine component serialization. @@ -1219,46 +1218,5 @@ public sealed class EntityDeserializer : : new ValueDataNode("invalid"); } - WeakEntityReference ITypeReader.Read( - ISerializationManager serializationManager, - ValueDataNode node, - IDependencyCollection dependencies, - SerializationHookContext hookCtx, - ISerializationContext? context, - ISerializationManager.InstantiationDelegate? instanceProvider) - { - var uid = serializationManager.Read(node, context); - return EntMan.TryGetNetEntity(uid, out var nent) - ? new(nent.Value) - : WeakEntityReference.Invalid; - } - - DataNode ITypeWriter.Write( - ISerializationManager serializationManager, - WeakEntityReference value, - IDependencyCollection dependencies, - bool alwaysWrite, - ISerializationContext? context) - { - return value != WeakEntityReference.Invalid - ? new ValueDataNode(value.Entity.Id.ToString(CultureInfo.InvariantCulture)) - : new ValueDataNode("invalid"); - } - - ValidationNode ITypeValidator.Validate( - ISerializationManager serializationManager, - ValueDataNode node, - IDependencyCollection dependencies, - ISerializationContext? context) - { - if (node.Value is "invalid") - return new ValidatedValueNode(node); - - if (!int.TryParse(node.Value, out _)) - return new ErrorNode(node, "Invalid NetEntity"); - - return new ValidatedValueNode(node); - } - #endregion } diff --git a/Robust.Shared/EntitySerialization/EntitySerializer.cs b/Robust.Shared/EntitySerialization/EntitySerializer.cs index c65af0e481..2b9b6fa124 100644 --- a/Robust.Shared/EntitySerialization/EntitySerializer.cs +++ b/Robust.Shared/EntitySerialization/EntitySerializer.cs @@ -38,8 +38,7 @@ namespace Robust.Shared.EntitySerialization; /// public sealed class EntitySerializer : ISerializationContext, ITypeSerializer, - ITypeSerializer, - ITypeSerializer + ITypeSerializer { public const int MapFormatVersion = 7; // v6->v7: PR #5572 - Added more metadata, List maps/grids/orphans, include some life-stage information @@ -869,12 +868,12 @@ public sealed class EntitySerializer : ISerializationContext, return new ValidatedValueNode(node); } - DataNode ITypeWriter.Write( + public DataNode Write( ISerializationManager serializationManager, EntityUid value, IDependencyCollection dependencies, - bool alwaysWrite, - ISerializationContext? context) + bool alwaysWrite = false, + ISerializationContext? context = null) { if (YamlUidMap.TryGetValue(value, out var yamlId)) return new ValueDataNode(yamlId.ToString(CultureInfo.InvariantCulture)); @@ -948,11 +947,11 @@ public sealed class EntitySerializer : ISerializationContext, return node.Value == "invalid" ? EntityUid.Invalid : EntityUid.Parse(node.Value); } - ValidationNode ITypeValidator.Validate( + public ValidationNode Validate( ISerializationManager serializationManager, ValueDataNode node, IDependencyCollection dependencies, - ISerializationContext? context) + ISerializationContext? context = null) { if (node.Value == "invalid") return new ValidatedValueNode(node); @@ -963,68 +962,27 @@ public sealed class EntitySerializer : ISerializationContext, return new ValidatedValueNode(node); } - NetEntity ITypeReader.Read( + public NetEntity Read( ISerializationManager serializationManager, ValueDataNode node, IDependencyCollection dependencies, SerializationHookContext hookCtx, - ISerializationContext? context, - ISerializationManager.InstantiationDelegate? instanceProvider) + ISerializationContext? context = null, + ISerializationManager.InstantiationDelegate? instanceProvider = null) { return node.Value == "invalid" ? NetEntity.Invalid : NetEntity.Parse(node.Value); } - DataNode ITypeWriter.Write( + public DataNode Write( ISerializationManager serializationManager, NetEntity value, IDependencyCollection dependencies, - bool alwaysWrite, - ISerializationContext? context) + bool alwaysWrite = false, + ISerializationContext? context = null) { var uid = EntMan.GetEntity(value); return serializationManager.WriteValue(uid, alwaysWrite, context); } - ValidationNode ITypeValidator.Validate( - ISerializationManager serializationManager, - ValueDataNode node, - IDependencyCollection dependencies, - ISerializationContext? context) - { - if (node.Value == "invalid") - return new ValidatedValueNode(node); - - if (!int.TryParse(node.Value, out _)) - return new ErrorNode(node, "Invalid NetEntity"); - - return new ValidatedValueNode(node); - } - - WeakEntityReference ITypeReader.Read( - ISerializationManager serializationManager, - ValueDataNode node, - IDependencyCollection dependencies, - SerializationHookContext hookCtx, - ISerializationContext? context, - ISerializationManager.InstantiationDelegate? instanceProvider) - { - return node.Value == "invalid" - ? WeakEntityReference.Invalid - : new(NetEntity.Parse(node.Value)); - } - - DataNode ITypeWriter.Write( - ISerializationManager serializationManager, - WeakEntityReference value, - IDependencyCollection dependencies, - bool alwaysWrite, - ISerializationContext? context) - { - if (EntMan.TryGetEntity(value.Entity, out var uid) && YamlUidMap.TryGetValue(uid.Value, out var yamlId)) - return new ValueDataNode(yamlId.ToString(CultureInfo.InvariantCulture)); - - return new ValueDataNode("invalid"); - } - #endregion } diff --git a/Robust.Shared/GameObjects/EntityManager.Components.cs b/Robust.Shared/GameObjects/EntityManager.Components.cs index e291baade3..bb0dfe5201 100644 --- a/Robust.Shared/GameObjects/EntityManager.Components.cs +++ b/Robust.Shared/GameObjects/EntityManager.Components.cs @@ -1391,94 +1391,6 @@ namespace Robust.Shared.GameObjects return new CompRegistryEntityEnumerator(this, trait1, registry); } - #region WeakEntityReference - - public WeakEntityReference GetWeakReference(EntityUid uid, MetaDataComponent? meta = null) - { - return new WeakEntityReference(GetNetEntity(uid, meta)); - } - - public WeakEntityReference? GetWeakReference(EntityUid? uid, MetaDataComponent? meta = null) - { - if (uid == null) - return null; - - return new WeakEntityReference(GetNetEntity(uid.Value, meta)); - } - - /// - public EntityUid? Resolve(WeakEntityReference weakRef) - { - if (weakRef.Entity != NetEntity.Invalid - && TryGetEntity(weakRef.Entity, out var ent)) - { - return ent.Value; - } - - return null; - } - - /// - public EntityUid? Resolve(WeakEntityReference? weakRef) - { - return weakRef == null ? null : Resolve(weakRef.Value); - } - - /// - public Entity? Resolve(WeakEntityReference weakRef) where T : IComponent - { - if (weakRef.Entity != NetEntity.Invalid - && TryGetEntity(weakRef.Entity, out var ent) - && TryGetComponent(ent.Value, out T? comp)) - { - return new(ent.Value, comp); - } - - return null; - } - - /// - public Entity? Resolve(WeakEntityReference? weakRef) where T : IComponent - { - return weakRef == null ? null : Resolve(weakRef.Value); - } - - public bool TryGetEntity(WeakEntityReference weakRef, [NotNullWhen(true)] out EntityUid? entity) - { - return TryGetEntity(weakRef.Entity, out entity); - } - - public bool TryGetEntity([NotNullWhen(true)] WeakEntityReference? weakRef, [NotNullWhen(true)] out EntityUid? entity) - { - return TryGetEntity(weakRef?.Entity, out entity); - } - - public bool TryGetEntity(WeakEntityReference weakRef, [NotNullWhen(true)] out Entity? entity) - where T : IComponent - { - if (!TryGetEntity(weakRef.Entity, out var uid) - || !TryGetComponent(uid.Value, out T? component)) - { - entity = null; - return false; - } - - entity = new(uid.Value, component); - return true; - } - - public bool TryGetEntity([NotNullWhen(true)] WeakEntityReference? weakRef, [NotNullWhen(true)] out Entity? entity) - where T : IComponent - { - if (weakRef != null) - return TryGetEntity(weakRef.Value, out entity); - - entity = null; - return false; - } - - #endregion - public AllEntityQueryEnumerator AllEntityQueryEnumerator(Type comp) { DebugTools.Assert(comp.IsAssignableTo(typeof(IComponent))); diff --git a/Robust.Shared/GameObjects/EntityManager.Network.cs b/Robust.Shared/GameObjects/EntityManager.Network.cs index 46ecc1d8fb..370d43269a 100644 --- a/Robust.Shared/GameObjects/EntityManager.Network.cs +++ b/Robust.Shared/GameObjects/EntityManager.Network.cs @@ -88,7 +88,7 @@ public partial class EntityManager } /// - public bool TryGetEntity([NotNullWhen(true)] NetEntity? nEntity, [NotNullWhen(true)] out EntityUid? entity) + public bool TryGetEntity(NetEntity? nEntity, [NotNullWhen(true)] out EntityUid? entity) { if (nEntity == null) { @@ -121,7 +121,7 @@ public partial class EntityManager } /// - public bool TryGetNetEntity([NotNullWhen(true)] EntityUid? uid, [NotNullWhen(true)] out NetEntity? netEntity, MetaDataComponent? metadata = null) + public bool TryGetNetEntity(EntityUid? uid, [NotNullWhen(true)] out NetEntity? netEntity, MetaDataComponent? metadata = null) { if (uid == null) { diff --git a/Robust.Shared/GameObjects/EntityManager.cs b/Robust.Shared/GameObjects/EntityManager.cs index 42e9b1f9a1..e6b000d2f8 100644 --- a/Robust.Shared/GameObjects/EntityManager.cs +++ b/Robust.Shared/GameObjects/EntityManager.cs @@ -1040,19 +1040,6 @@ namespace Robust.Shared.GameObjects return ToPrettyString(uid.Value, meta); } - /// - [return: NotNullIfNotNull(nameof(weakRef))] - public EntityStringRepresentation? ToPrettyString(WeakEntityReference? weakRef) - { - return weakRef == null ? null : ToPrettyString(weakRef.Value); - } - - /// - public EntityStringRepresentation ToPrettyString(WeakEntityReference weakRef) - { - return ToPrettyString(weakRef.Entity); - } - #endregion Entity Management public virtual void RaisePredictiveEvent(T msg) where T : EntityEventArgs diff --git a/Robust.Shared/GameObjects/EntitySystem.Proxy.cs b/Robust.Shared/GameObjects/EntitySystem.Proxy.cs index 9173edd814..a9edfa791b 100644 --- a/Robust.Shared/GameObjects/EntitySystem.Proxy.cs +++ b/Robust.Shared/GameObjects/EntitySystem.Proxy.cs @@ -423,22 +423,6 @@ public partial class EntitySystem return EntityManager.ToPrettyString(netEntity); } - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - [return: NotNullIfNotNull(nameof(weakRef))] - protected EntityStringRepresentation ToPrettyString(WeakEntityReference weakRef) - { - return EntityManager.ToPrettyString(weakRef); - } - /// [MethodImpl(MethodImplOptions.AggressiveInlining)] protected EntityStringRepresentation ToPrettyString(EntityUid uid, MetaDataComponent? metadata) @@ -1622,76 +1606,4 @@ public partial class EntitySystem } #endregion - - #region WeakEntityReference - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - protected WeakEntityReference GetWeakReference(EntityUid uid, MetaDataComponent? meta = null) - { - return EntityManager.GetWeakReference(uid, meta); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - protected WeakEntityReference? GetWeakReference(EntityUid? uid, MetaDataComponent? meta = null) - { - return EntityManager.GetWeakReference(uid, meta); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - protected EntityUid? Resolve(WeakEntityReference weakRef) - { - return EntityManager.Resolve(weakRef); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - protected EntityUid? Resolve(WeakEntityReference? weakRef) - { - return EntityManager.Resolve(weakRef); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - protected Entity? Resolve(WeakEntityReference weakRef) where T : IComponent - { - return EntityManager.Resolve(weakRef); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - protected Entity? Resolve(WeakEntityReference? weakRef) where T : IComponent - { - return EntityManager.Resolve(weakRef); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - protected bool TryGetEntity(WeakEntityReference weakRef, [NotNullWhen(true)] out EntityUid? entity) - { - return EntityManager.TryGetEntity(weakRef, out entity); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - protected bool TryGetEntity(WeakEntityReference? weakRef, [NotNullWhen(true)] out EntityUid? entity) - { - return EntityManager.TryGetEntity(weakRef, out entity); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - protected bool TryGetEntity(WeakEntityReference weakRef, [NotNullWhen(true)] out Entity? entity) - where T : IComponent - { - return EntityManager.TryGetEntity(weakRef, out entity); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - protected bool TryGetEntity(WeakEntityReference? weakRef, [NotNullWhen(true)] out Entity? entity) - where T : IComponent - { - return EntityManager.TryGetEntity(weakRef, out entity); - } - #endregion - } diff --git a/Robust.Shared/GameObjects/IEntityManager.Components.cs b/Robust.Shared/GameObjects/IEntityManager.Components.cs index 38fdb6a54f..aae524d1ae 100644 --- a/Robust.Shared/GameObjects/IEntityManager.Components.cs +++ b/Robust.Shared/GameObjects/IEntityManager.Components.cs @@ -505,56 +505,12 @@ namespace Robust.Shared.GameObjects /// /// /// - ComponentQueryEnumerator ComponentQueryEnumerator(ComponentRegistry registry); + public ComponentQueryEnumerator ComponentQueryEnumerator(ComponentRegistry registry); /// /// /// - CompRegistryEntityEnumerator CompRegistryQueryEnumerator(ComponentRegistry registry); - - /// - /// Returns a pointing to the local entity. - /// - WeakEntityReference GetWeakReference(EntityUid uid, MetaDataComponent? meta = null); - - /// - /// Returns a pointing to the local entity. - /// - WeakEntityReference? GetWeakReference(EntityUid? uid, MetaDataComponent? meta = null); - - /// - /// Attempts to resolve the given into an that - /// corresponds to an existing entity. If this fails, the entity has either been deleted, or for clients, the - /// entity may not yet have been sent to them. - /// - EntityUid? Resolve(WeakEntityReference weakRef); - - /// - EntityUid? Resolve(WeakEntityReference? weakRef); - - bool TryGetEntity(WeakEntityReference weakRef, [NotNullWhen(true)] out EntityUid? entity); - - bool TryGetEntity( - [NotNullWhen(true)] WeakEntityReference? weakRef, - [NotNullWhen(true)] out EntityUid? entity); - - bool TryGetEntity(WeakEntityReference weakRef, [NotNullWhen(true)] out Entity? entity) - where T : IComponent; - - bool TryGetEntity( - [NotNullWhen(true)] WeakEntityReference? weakRef, - [NotNullWhen(true)] out Entity? entity) - where T : IComponent; - - /// - /// Attempts to resolve the given into an existing entity with the specified - /// component and return the . If this fails, the entity has either been deleted, doesn't - /// have the component, or for clients the entity may not yet have been sent to them. - /// - public Entity? Resolve(WeakEntityReference weakRef) where T : IComponent; - - /// - public Entity? Resolve(WeakEntityReference? weakRef) where T : IComponent; + public CompRegistryEntityEnumerator CompRegistryQueryEnumerator(ComponentRegistry registry); AllEntityQueryEnumerator AllEntityQueryEnumerator(Type comp); diff --git a/Robust.Shared/GameObjects/IEntityManager.cs b/Robust.Shared/GameObjects/IEntityManager.cs index 8530eb30ac..225086f76d 100644 --- a/Robust.Shared/GameObjects/IEntityManager.cs +++ b/Robust.Shared/GameObjects/IEntityManager.cs @@ -235,11 +235,6 @@ namespace Robust.Shared.GameObjects /// EntityStringRepresentation ToPrettyString(NetEntity netEntity); - /// - /// Returns a string representation of an entity with various information regarding it. - /// - EntityStringRepresentation ToPrettyString(WeakEntityReference weakRef); - /// /// Returns a string representation of an entity with various information regarding it. /// @@ -252,12 +247,6 @@ namespace Robust.Shared.GameObjects [return: NotNullIfNotNull("netEntity")] EntityStringRepresentation? ToPrettyString(NetEntity? netEntity); - /// - /// Returns a string representation of an entity with various information regarding it. - /// - [return: NotNullIfNotNull(nameof(weakRef))] - EntityStringRepresentation? ToPrettyString(WeakEntityReference? weakRef); - #endregion Entity Management /// diff --git a/Robust.Shared/GameObjects/WeakEntityReference.cs b/Robust.Shared/GameObjects/WeakEntityReference.cs deleted file mode 100644 index 39e26f53f1..0000000000 --- a/Robust.Shared/GameObjects/WeakEntityReference.cs +++ /dev/null @@ -1,68 +0,0 @@ -using System; -using Robust.Shared.Serialization; -using Robust.Shared.Serialization.Manager.Attributes; - -namespace Robust.Shared.GameObjects; - -/// -/// This struct is just a wrapper around a that is intended to be used to store references to -/// entities in a context where there is no expectation that the entity still exists (has not been deleted). -/// -/// -/// The current convention is that a non-null EntityUid stored on a component should correspond to an -/// existing entity. Generally, if such an entity has since been deleted or had a relevant component removed, the -/// references to that entity should have been cleaned up by the component shutdown logic. If this is not done, this -/// generally results in errors being logged when an invalid EntityUid is passed around. This struct exists to for -/// cases where you want to store an entity reference, while making it clear that there is no expectation that it -/// should continue to be valid, which also means you do not need to clean up any references upon deletion or -/// component removal. -/// -/// -/// When saving a map, any weak references to entities that are not being included in the save file are automatically -/// ignored. -/// -[CopyByRef, Serializable, NetSerializable] -public record struct WeakEntityReference(NetEntity Entity) -{ - public override int GetHashCode() => Entity.GetHashCode(); - public static readonly WeakEntityReference Invalid = new(NetEntity.Invalid); - - public static WeakEntityReference Parse(ReadOnlySpan uid) => new(NetEntity.Parse(uid)); - - public static bool TryParse(ReadOnlySpan uid, out WeakEntityReference entity) - { - if (NetEntity.TryParse(uid, out var nent)) - { - entity = new(nent); - return true; - } - - entity = Invalid; - return false; - } -} - -/// -/// Variant of that is only considered valid if the entity exists and still has the -/// specified component. -/// -[CopyByRef, Serializable] -public record struct WeakEntityReference(NetEntity Entity) where T : IComponent -{ - public override int GetHashCode() => Entity.GetHashCode(); - public static readonly WeakEntityReference Invalid = new(NetEntity.Invalid); - - public static WeakEntityReference Parse(ReadOnlySpan uid) => new(NetEntity.Parse(uid)); - - public static bool TryParse(ReadOnlySpan uid, out WeakEntityReference entity) - { - if (NetEntity.TryParse(uid, out var nent)) - { - entity = new(nent); - return true; - } - - entity = Invalid; - return false; - } -} diff --git a/Robust.Shared/Prototypes/EntProtoId.cs b/Robust.Shared/Prototypes/EntProtoId.cs index 96dc417f06..5944ccf07f 100644 --- a/Robust.Shared/Prototypes/EntProtoId.cs +++ b/Robust.Shared/Prototypes/EntProtoId.cs @@ -3,7 +3,6 @@ using System.Diagnostics.CodeAnalysis; using Robust.Shared.GameObjects; using Robust.Shared.IoC; using Robust.Shared.Serialization; -using Robust.Shared.Serialization.Manager.Attributes; using Robust.Shared.Serialization.TypeSerializers.Implementations; using Robust.Shared.Toolshed.TypeParsers; @@ -17,7 +16,7 @@ namespace Robust.Shared.Prototypes; /// This will be automatically validated by if used in data fields. /// /// for a wrapper of other prototype kinds. -[Serializable, NetSerializable, CopyByRef] +[Serializable, NetSerializable] public readonly record struct EntProtoId(string Id) : IEquatable, IComparable, IAsType, IAsType> { @@ -59,7 +58,7 @@ public readonly record struct EntProtoId(string Id) : IEquatable, ICompa } /// -[Serializable, CopyByRef] +[Serializable] public readonly record struct EntProtoId(string Id) : IEquatable, IComparable where T : IComponent, new() { public static implicit operator string(EntProtoId protoId) diff --git a/Robust.Shared/Prototypes/ProtoId.cs b/Robust.Shared/Prototypes/ProtoId.cs index 2be07ad2ce..8d69ad02b1 100644 --- a/Robust.Shared/Prototypes/ProtoId.cs +++ b/Robust.Shared/Prototypes/ProtoId.cs @@ -1,5 +1,4 @@ using System; -using Robust.Shared.Serialization.Manager.Attributes; using Robust.Shared.Serialization.TypeSerializers.Implementations.Generic; using Robust.Shared.Toolshed.TypeParsers; @@ -14,7 +13,7 @@ namespace Robust.Shared.Prototypes; /// This will be automatically validated by if used in data fields. /// /// for an alias. -[Serializable, CopyByRef] +[Serializable] [PreferOtherType(typeof(EntityPrototype), typeof(EntProtoId))] public readonly record struct ProtoId(string Id) : IEquatable, diff --git a/Robust.Shared/Prototypes/YamlValidationContext.cs b/Robust.Shared/Prototypes/YamlValidationContext.cs index 35e27072be..eb87bf3d61 100644 --- a/Robust.Shared/Prototypes/YamlValidationContext.cs +++ b/Robust.Shared/Prototypes/YamlValidationContext.cs @@ -1,4 +1,5 @@ using System.Globalization; +using JetBrains.Annotations; using Robust.Shared.GameObjects; using Robust.Shared.IoC; using Robust.Shared.Serialization; @@ -13,8 +14,7 @@ namespace Robust.Shared.Prototypes; internal sealed class YamlValidationContext : ISerializationContext, ITypeSerializer, - ITypeSerializer, - ITypeSerializer + ITypeSerializer { public SerializationManager.SerializerProvider SerializerProvider { get; } = new(); public bool WritingReadingPrototypes => true; @@ -55,71 +55,42 @@ internal sealed class YamlValidationContext : return EntityUid.Parse(node.Value); } - ValidationNode ITypeValidator.Validate( + public ValidationNode Validate( ISerializationManager serializationManager, ValueDataNode node, IDependencyCollection dependencies, - ISerializationContext? context) + ISerializationContext? context = null) { - return node.Value == "invalid" - ? new ValidatedValueNode(node) - : new ErrorNode(node, "Prototypes should not contain NetEntities"); + if (node.Value == "invalid") + return new ValidatedValueNode(node); + + return new ErrorNode(node, "Prototypes should not contain NetEntities"); } - NetEntity ITypeReader.Read( + public NetEntity Read( ISerializationManager serializationManager, ValueDataNode node, IDependencyCollection dependencies, SerializationHookContext hookCtx, - ISerializationContext? context, - ISerializationManager.InstantiationDelegate? instanceProvider) + ISerializationContext? context = null, + ISerializationManager.InstantiationDelegate? instanceProvider = null) { - return node.Value == "invalid" ? NetEntity.Invalid : NetEntity.Parse(node.Value); + if (node.Value == "invalid") + return NetEntity.Invalid; + + return NetEntity.Parse(node.Value); } - DataNode ITypeWriter.Write( + public DataNode Write( ISerializationManager serializationManager, NetEntity value, IDependencyCollection dependencies, - bool alwaysWrite, - ISerializationContext? context) + bool alwaysWrite = false, + ISerializationContext? context = null) { - return value.Valid - ? new ValueDataNode(value.Id.ToString(CultureInfo.InvariantCulture)) - : new ValueDataNode("invalid"); - } + if (!value.Valid) + return new ValueDataNode("invalid"); - ValidationNode ITypeValidator.Validate( - ISerializationManager serializationManager, - ValueDataNode node, - IDependencyCollection dependencies, - ISerializationContext? context) - { - return node.Value == "invalid" - ? new ValidatedValueNode(node) - : new ErrorNode(node, "Prototypes should not contain WeakEntityReferences"); - } - - WeakEntityReference ITypeReader.Read( - ISerializationManager serializationManager, - ValueDataNode node, - IDependencyCollection dependencies, - SerializationHookContext hookCtx, - ISerializationContext? context, - ISerializationManager.InstantiationDelegate? instanceProvider) - { - return node.Value == "invalid" ? WeakEntityReference.Invalid : new(NetEntity.Parse(node.Value)); - } - - DataNode ITypeWriter.Write( - ISerializationManager serializationManager, - WeakEntityReference value, - IDependencyCollection dependencies, - bool alwaysWrite, - ISerializationContext? context) - { - return !value.Entity.Valid - ? new ValueDataNode("invalid") - : new ValueDataNode(value.Entity.Id.ToString(CultureInfo.InvariantCulture)); + return new ValueDataNode(value.Id.ToString(CultureInfo.InvariantCulture)); } } diff --git a/Robust.Shared/Serialization/Manager/Exceptions/CopyToFailedException.cs b/Robust.Shared/Serialization/Manager/Exceptions/CopyToFailedException.cs index f552b90fb9..edbb06b964 100644 --- a/Robust.Shared/Serialization/Manager/Exceptions/CopyToFailedException.cs +++ b/Robust.Shared/Serialization/Manager/Exceptions/CopyToFailedException.cs @@ -1,11 +1,8 @@ using System; -using Robust.Shared.Serialization.Manager.Attributes; -using Robust.Shared.Serialization.TypeSerializers.Interfaces; namespace Robust.Shared.Serialization.Manager.Exceptions; public sealed class CopyToFailedException : Exception { - public override string Message - => $"Failed performing CopyTo for Type {typeof(T)}. Did you forget to create a {nameof(ITypeCopier)} implementation? Or maybe {typeof(T)} should have the {nameof(CopyByRefAttribute)}?"; + public override string Message => $"Failed performing CopyTo for Type {typeof(T)}"; } diff --git a/Robust.Shared/Serialization/TypeSerializers/Implementations/EntProtoIdSerializer.cs b/Robust.Shared/Serialization/TypeSerializers/Implementations/EntProtoIdSerializer.cs index 1f6c0036e6..37dfd6ef54 100644 --- a/Robust.Shared/Serialization/TypeSerializers/Implementations/EntProtoIdSerializer.cs +++ b/Robust.Shared/Serialization/TypeSerializers/Implementations/EntProtoIdSerializer.cs @@ -17,7 +17,7 @@ namespace Robust.Shared.Serialization.TypeSerializers.Implementations; /// Serializer used automatically for types. /// [TypeSerializer] -public sealed class EntProtoIdSerializer : ITypeSerializer +public sealed class EntProtoIdSerializer : ITypeSerializer, ITypeCopyCreator { public ValidationNode Validate(ISerializationManager serialization, ValueDataNode node, IDependencyCollection dependencies, ISerializationContext? context = null) { @@ -37,13 +37,18 @@ public sealed class EntProtoIdSerializer : ITypeSerializer /// Serializer used automatically for types. /// [TypeSerializer] -public sealed class EntProtoIdSerializer : ITypeSerializer, ValueDataNode> where T : IComponent, new() +public sealed class EntProtoIdSerializer : ITypeSerializer, ValueDataNode>, ITypeCopyCreator> where T : IComponent, new() { public ValidationNode Validate(ISerializationManager serialization, ValueDataNode node, IDependencyCollection dependencies, ISerializationContext? context = null) { @@ -78,4 +83,9 @@ public sealed class EntProtoIdSerializer : ITypeSerializer, Val { return new ValueDataNode(value.Id); } + + public EntProtoId CreateCopy(ISerializationManager serializationManager, EntProtoId source, IDependencyCollection dependencies, SerializationHookContext hookCtx, ISerializationContext? context = null) + { + return source; + } } diff --git a/Robust.Shared/Serialization/TypeSerializers/Implementations/Generic/ProtoIdSerializer.cs b/Robust.Shared/Serialization/TypeSerializers/Implementations/Generic/ProtoIdSerializer.cs index 58a1baef7d..cf383bb352 100644 --- a/Robust.Shared/Serialization/TypeSerializers/Implementations/Generic/ProtoIdSerializer.cs +++ b/Robust.Shared/Serialization/TypeSerializers/Implementations/Generic/ProtoIdSerializer.cs @@ -15,7 +15,7 @@ namespace Robust.Shared.Serialization.TypeSerializers.Implementations.Generic; /// /// The type of the prototype for which the id is stored. [TypeSerializer] -public sealed class ProtoIdSerializer : ITypeSerializer, ValueDataNode> where T : class, IPrototype +public sealed class ProtoIdSerializer : ITypeSerializer, ValueDataNode>, ITypeCopyCreator> where T : class, IPrototype { public ValidationNode Validate(ISerializationManager serialization, ValueDataNode node, IDependencyCollection dependencies, ISerializationContext? context = null) { @@ -46,4 +46,9 @@ public sealed class ProtoIdSerializer : ITypeSerializer, ValueData { return new ValueDataNode(value.Id); } + + public ProtoId CreateCopy(ISerializationManager serializationManager, ProtoId source, IDependencyCollection dependencies, SerializationHookContext hookCtx, ISerializationContext? context = null) + { + return source; + } } diff --git a/Robust.Shared/Serialization/TypeSerializers/Implementations/Generic/WeakEntityReferenceSerializer.cs b/Robust.Shared/Serialization/TypeSerializers/Implementations/Generic/WeakEntityReferenceSerializer.cs deleted file mode 100644 index 34db4f424a..0000000000 --- a/Robust.Shared/Serialization/TypeSerializers/Implementations/Generic/WeakEntityReferenceSerializer.cs +++ /dev/null @@ -1,60 +0,0 @@ -using Robust.Shared.EntitySerialization; -using Robust.Shared.GameObjects; -using Robust.Shared.IoC; -using Robust.Shared.Serialization.Manager; -using Robust.Shared.Serialization.Manager.Attributes; -using Robust.Shared.Serialization.Markdown; -using Robust.Shared.Serialization.Markdown.Validation; -using Robust.Shared.Serialization.Markdown.Value; -using Robust.Shared.Serialization.TypeSerializers.Interfaces; -using static Robust.Shared.Serialization.Manager.ISerializationManager; - -namespace Robust.Shared.Serialization.TypeSerializers.Implementations.Generic; - -// This specifically implements WeakEntityReference, but not WeakEntityReference for the same reason that there is no -// EntityUid serializer: So that it can be implemented by the entity (de)serialization context. -// Ideally I'd also leave that there instead of here, but it needs generics... -[TypeSerializer] -public sealed class WeakEntityReferenceSerializer : - ITypeSerializer, ValueDataNode> - where T : class, IComponent -{ - public WeakEntityReference Read( - ISerializationManager serializationManager, - ValueDataNode node, - IDependencyCollection dependencies, - SerializationHookContext hookCtx, - ISerializationContext? context = null, - InstantiationDelegate>? instanceProvider = null) - { - var val = serializationManager.Read(node, hookCtx, context); - return new(val.Entity); - } - - public DataNode Write( - ISerializationManager serializationManager, - WeakEntityReference value, - IDependencyCollection dependencies, - bool alwaysWrite = false, - ISerializationContext? context = null) - { - NetEntity val = value.Entity; - - if (context is EntitySerializer seri) - { - if (!seri.EntMan.TryGetEntity(val, out var uid) || !seri.EntMan.HasComponent(uid)) - val = NetEntity.Invalid; - } - - return serializationManager.WriteValue(new WeakEntityReference(val), alwaysWrite, context); - } - - public ValidationNode Validate( - ISerializationManager serializationManager, - ValueDataNode node, - IDependencyCollection dependencies, - ISerializationContext? context) - { - return serializationManager.ValidateNode(node, context); - } -} diff --git a/Robust.UnitTesting/Shared/EntitySerialization/TestComponents.cs b/Robust.UnitTesting/Shared/EntitySerialization/TestComponents.cs index b69c2249d9..685a939d55 100644 --- a/Robust.UnitTesting/Shared/EntitySerialization/TestComponents.cs +++ b/Robust.UnitTesting/Shared/EntitySerialization/TestComponents.cs @@ -2,7 +2,6 @@ using System.Collections.Generic; using System.Linq; using NUnit.Framework; using Robust.Shared.GameObjects; -using Robust.Shared.GameStates; using Robust.Shared.Map; using Robust.Shared.Maths; using Robust.Shared.Prototypes; @@ -43,14 +42,6 @@ public sealed partial class EntitySaveTestComponent : Component } } -[RegisterComponent] -[NetworkedComponent, AutoGenerateComponentState] -public sealed partial class WeakEntityReferenceTestComponent : Component -{ - [DataField, AutoNetworkedField] - public WeakEntityReference Entity; -} - /// /// Dummy tile definition for serializing grids. /// diff --git a/Robust.UnitTesting/Shared/EntitySerialization/WeakEntityReferenceTest.cs b/Robust.UnitTesting/Shared/EntitySerialization/WeakEntityReferenceTest.cs deleted file mode 100644 index 12dbe46f34..0000000000 --- a/Robust.UnitTesting/Shared/EntitySerialization/WeakEntityReferenceTest.cs +++ /dev/null @@ -1,106 +0,0 @@ -using System.Linq; -using System.Threading.Tasks; -using NUnit.Framework; -using Robust.Shared; -using Robust.Shared.GameObjects; -using Robust.Shared.Network; -using Robust.Shared.Player; - -namespace Robust.UnitTesting.Shared.EntitySerialization; - -public sealed partial class WeakEntityReferenceTest : RobustIntegrationTest -{ - [Test] - public async Task TestWeakEntityReference() - { - var server = StartServer(); - var client = StartClient(); - - await Task.WhenAll(server.WaitIdleAsync(), client.WaitIdleAsync()); - - var sEntMan = server.EntMan; - var sPlayerMan = server.ResolveDependency(); - var cEntMan = client.EntMan; - var cNetMan = client.ResolveDependency(); - - NetEntity netEntA = default; - NetEntity netEntB = default; - - // Set up entities - await server.WaitPost(() => - { - var entA = sEntMan.Spawn(); - var entB = sEntMan.Spawn(); - netEntA = sEntMan.GetNetEntity(entA); - netEntB = sEntMan.GetNetEntity(entB); - - // Give A a weak reference to B - var comp = sEntMan.AddComponent(entA); - comp.Entity = new WeakEntityReference(sEntMan.GetNetEntity(entB)); - }); - - // Connect client. - Assert.DoesNotThrow(() => client.SetConnectTarget(server)); - await client.WaitPost(() => cNetMan.ClientConnect(null!, 0, null!)); - // Disable PVS so everything gets networked - server.Post(() => server.CfgMan.SetCVar(CVars.NetPVS, false)); - - async Task RunTicks() - { - for (int i = 0; i < 10; i++) - { - await server.WaitRunTicks(1); - await client.WaitRunTicks(1); - } - } - await RunTicks(); - - // Put the player into the game so they get entity data - await server.WaitAssertion(() => - { - var session = sPlayerMan.Sessions.First(); - sPlayerMan.JoinGame(session); - }); - - await RunTicks(); - - // Make sure the client got entity data - await client.WaitAssertion(() => - { - Assert.That(cNetMan.IsConnected); - Assert.That(cEntMan.TryGetEntity(netEntA, out var entA)); - Assert.That(cEntMan.TryGetEntity(netEntB, out var entB)); - - Assert.That(cEntMan.TryGetComponent(entA, out var comp)); - var referencedEnt = cEntMan.Resolve(comp!.Entity); - Assert.That(referencedEnt, Is.EqualTo(entB)); - }); - - // Delete the referenced entity on the server - await server.WaitAssertion(() => - { - var entB = sEntMan.GetEntity(netEntB); - sEntMan.DeleteEntity(entB); - }); - - await RunTicks(); - - // Make sure the client now resolves the reference to null - await client.WaitAssertion(() => - { - Assert.That(cEntMan.TryGetEntity(netEntA, out var entA)); - Assert.That(cEntMan.TryGetComponent(entA, out var comp)); - var referencedEnt = cEntMan.Resolve(comp!.Entity); - Assert.That(referencedEnt, Is.Null); - }); - - // Disconnect client - await client.WaitPost(() => cNetMan.ClientDisconnect("")); - await server.WaitRunTicks(5); - await client.WaitRunTicks(5); - - // Reset cvar - // I love engine tests - server.Post(() => server.CfgMan.SetCVar(CVars.NetPVS, true)); - } -}