using System; using Unity.Collections; namespace Unity.Netcode { /// /// This class is instantiated for types that we can't determine ahead of time are serializable - types /// that don't meet any of the constraints for methods that are available on FastBufferReader and /// FastBufferWriter. These types may or may not be serializable through extension methods. To ensure /// the user has time to pass in the delegates to UserNetworkVariableSerialization, the existence /// of user serialization isn't checked until it's used, so if no serialization is provided, this /// will throw an exception when an object containing the relevant NetworkVariable is spawned. /// /// internal class FallbackSerializer : INetworkVariableSerializer { public NetworkVariableType Type => NetworkVariableType.Unknown; public bool IsDistributedAuthorityOptimized => true; private void ThrowArgumentError() { throw new ArgumentException($"Serialization has not been generated for type {typeof(T).FullName}. This can be addressed by adding a [{nameof(GenerateSerializationForGenericParameterAttribute)}] to your generic class that serializes this value (if you are using one), adding [{nameof(GenerateSerializationForTypeAttribute)}(typeof({typeof(T).FullName})] to the class or method that is attempting to serialize it, or creating a field on a {nameof(NetworkBehaviour)} of type {nameof(NetworkVariable)}. If this error continues to appear after doing one of those things and this is a type you can change, then either implement {nameof(INetworkSerializable)} or mark it as serializable by memcpy by adding {nameof(INetworkSerializeByMemcpy)} to its interface list to enable automatic serialization generation. If not, assign serialization code to {nameof(UserNetworkVariableSerialization)}.{nameof(UserNetworkVariableSerialization.WriteValue)}, {nameof(UserNetworkVariableSerialization)}.{nameof(UserNetworkVariableSerialization.ReadValue)}, and {nameof(UserNetworkVariableSerialization)}.{nameof(UserNetworkVariableSerialization.DuplicateValue)}, or if it's serializable by memcpy (contains no pointers), wrap it in {typeof(ForceNetworkSerializeByMemcpy<>).Name}."); } public void Write(FastBufferWriter writer, ref T value) { if (UserNetworkVariableSerialization.ReadValue == null || UserNetworkVariableSerialization.WriteValue == null || UserNetworkVariableSerialization.DuplicateValue == null) { ThrowArgumentError(); } UserNetworkVariableSerialization.WriteValue(writer, value); } public void Read(FastBufferReader reader, ref T value) { if (UserNetworkVariableSerialization.ReadValue == null || UserNetworkVariableSerialization.WriteValue == null || UserNetworkVariableSerialization.DuplicateValue == null) { ThrowArgumentError(); } UserNetworkVariableSerialization.ReadValue(reader, out value); } public void WriteDelta(FastBufferWriter writer, ref T value, ref T previousValue) { if (UserNetworkVariableSerialization.ReadValue == null || UserNetworkVariableSerialization.WriteValue == null || UserNetworkVariableSerialization.DuplicateValue == null) { ThrowArgumentError(); } if (UserNetworkVariableSerialization.WriteDelta == null || UserNetworkVariableSerialization.ReadDelta == null) { UserNetworkVariableSerialization.WriteValue(writer, value); return; } UserNetworkVariableSerialization.WriteDelta(writer, value, previousValue); } public void ReadDelta(FastBufferReader reader, ref T value) { if (UserNetworkVariableSerialization.ReadValue == null || UserNetworkVariableSerialization.WriteValue == null || UserNetworkVariableSerialization.DuplicateValue == null) { ThrowArgumentError(); } if (UserNetworkVariableSerialization.WriteDelta == null || UserNetworkVariableSerialization.ReadDelta == null) { UserNetworkVariableSerialization.ReadValue(reader, out value); return; } UserNetworkVariableSerialization.ReadDelta(reader, ref value); } void INetworkVariableSerializer.ReadWithAllocator(FastBufferReader reader, out T value, Allocator allocator) { throw new NotImplementedException(); } public void Duplicate(in T value, ref T duplicatedValue) { if (UserNetworkVariableSerialization.ReadValue == null || UserNetworkVariableSerialization.WriteValue == null || UserNetworkVariableSerialization.DuplicateValue == null) { ThrowArgumentError(); } UserNetworkVariableSerialization.DuplicateValue(value, ref duplicatedValue); } public void WriteDistributedAuthority(FastBufferWriter writer, ref T value) => ThrowArgumentError(); public void ReadDistributedAuthority(FastBufferReader reader, ref T value) => ThrowArgumentError(); public void WriteDeltaDistributedAuthority(FastBufferWriter writer, ref T value, ref T previousValue) => ThrowArgumentError(); public void ReadDeltaDistributedAuthority(FastBufferReader reader, ref T value) => ThrowArgumentError(); } // RuntimeAccessModifiersILPP will make this `public` // This is just pass-through to NetworkVariableSerialization but is here because I could not get ILPP // to generate code that would successfully call Type.Method(T), but it has no problem calling Type.Method(T) internal class RpcFallbackSerialization { public static void Write(FastBufferWriter writer, ref T value) { NetworkVariableSerialization.Write(writer, ref value); } public static void Read(FastBufferReader reader, ref T value) { NetworkVariableSerialization.Read(reader, ref value); } } }