From dcadd34389dd025d5e0b6b93f2dbdcf09f30d0d1 Mon Sep 17 00:00:00 2001
From: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com>
Date: Thu, 9 Jul 2026 00:08:10 +1000
Subject: [PATCH] Serv5 fixes (#6761)
---
Robust.Serialization.Generator/Generator.cs | 30 +++++++++----------
Robust.Serialization.Generator/Types.cs | 6 ++++
Robust.Shared/Prototypes/ProtoId.cs | 2 ++
.../Custom/TimeOffsetSerializer.cs | 12 +++++++-
4 files changed, 34 insertions(+), 16 deletions(-)
diff --git a/Robust.Serialization.Generator/Generator.cs b/Robust.Serialization.Generator/Generator.cs
index b94f70dc6b..ec9c3f9e7d 100644
--- a/Robust.Serialization.Generator/Generator.cs
+++ b/Robust.Serialization.Generator/Generator.cs
@@ -1140,21 +1140,7 @@ public class Generator : IIncrementalGenerator
var nullableValue = isNullableValueType ? ".Value" : string.Empty;
var nullNotAllowed = isClass && !isNullable;
- if (CanBeCopiedByValue(field.Symbol, field.Type))
- {
- if (nullNotAllowed)
- {
- builder.AppendLine($$"""
- if (source.{{name}} == null)
- {
- throw new NullNotAllowedException();
- }
- """);
- }
-
- builder.AppendLine($"{targetName} = source.{name};");
- }
- else if (field.CustomSerializer is { Serializer: var serializer, Type: var serializerType } &&
+ if (field.CustomSerializer is { Serializer: var serializer, Type: var serializerType } &&
((serializerType & Copier) != 0 || (serializerType & CopyCreator) != 0))
{
if (nullNotAllowed)
@@ -1201,6 +1187,20 @@ public class Generator : IIncrementalGenerator
if (isNullable || isNullableValueType)
builder.AppendLine("}");
}
+ else if (CanBeCopiedByValue(field.Symbol, field.Type))
+ {
+ if (nullNotAllowed)
+ {
+ builder.AppendLine($$"""
+ if (source.{{name}} == null)
+ {
+ throw new NullNotAllowedException();
+ }
+ """);
+ }
+
+ builder.AppendLine($"{targetName} = source.{name};");
+ }
else
{
if (nullNotAllowed)
diff --git a/Robust.Serialization.Generator/Types.cs b/Robust.Serialization.Generator/Types.cs
index 7e7b782a26..e029835a33 100644
--- a/Robust.Serialization.Generator/Types.cs
+++ b/Robust.Serialization.Generator/Types.cs
@@ -78,6 +78,12 @@ internal static class Types
if (HasAttribute(type, CopyByRefNamespace))
return true;
+ if (type is INamedTypeSymbol named &&
+ HasAttribute(named.OriginalDefinition, CopyByRefNamespace))
+ {
+ return true;
+ }
+
if (type.TypeKind == TypeKind.Enum)
return true;
diff --git a/Robust.Shared/Prototypes/ProtoId.cs b/Robust.Shared/Prototypes/ProtoId.cs
index 8d69ad02b1..1b7fb85a17 100644
--- a/Robust.Shared/Prototypes/ProtoId.cs
+++ b/Robust.Shared/Prototypes/ProtoId.cs
@@ -1,4 +1,5 @@
using System;
+using Robust.Shared.Serialization.Manager.Attributes;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Generic;
using Robust.Shared.Toolshed.TypeParsers;
@@ -14,6 +15,7 @@ namespace Robust.Shared.Prototypes;
///
/// for an alias.
[Serializable]
+[CopyByRef]
[PreferOtherType(typeof(EntityPrototype), typeof(EntProtoId))]
public readonly record struct ProtoId(string Id) :
IEquatable,
diff --git a/Robust.Shared/Serialization/TypeSerializers/Implementations/Custom/TimeOffsetSerializer.cs b/Robust.Shared/Serialization/TypeSerializers/Implementations/Custom/TimeOffsetSerializer.cs
index 0c8c4ac2ce..63394f8256 100644
--- a/Robust.Shared/Serialization/TypeSerializers/Implementations/Custom/TimeOffsetSerializer.cs
+++ b/Robust.Shared/Serialization/TypeSerializers/Implementations/Custom/TimeOffsetSerializer.cs
@@ -21,7 +21,7 @@ namespace Robust.Shared.Serialization.TypeSerializers.Implementations.Custom;
/// to prevent time-offsets from being unintentionally saved to maps while mapping. If an entity must have an initial
/// non-zero time, then that time should just be configured during map-init.
///
-public sealed class TimeOffsetSerializer : ITypeSerializer
+public sealed class TimeOffsetSerializer : ITypeSerializer, ITypeCopyCreator
{
public TimeSpan Read(ISerializationManager serializationManager, ValueDataNode node,
IDependencyCollection dependencies,
@@ -81,4 +81,14 @@ public sealed class TimeOffsetSerializer : ITypeSerializer