breaking: no need to override Serialize/Deserialize in messages (#2317)

* breaking: no need to override Serialize/Deserialize in messages

Messages no longer serilize themselves.  This has been decoupled.  Serializing a message is now done
via readers and writers, which can be either generated or user provided.

This lifts some restrictions,
* you no longer need to have a default constructor in messages
* Messages types can be recursive
* struct Messages don't need to provide an empty Serialize and Deserialize method

Before:
```cs
public struct ReadyMessage : IMessageBase
{
    public void Deserialize(NetworkReader reader) { }

    public void Serialize(NetworkWriter writer) { }
}
```

After:
```cs
public struct ReadyMessage : IMessageBase
{
}
```

BREAKING CHANGE: Messages must be public
BREAKING CHANGE: Use custom reader and writer instead of Serialize/Deserialize methods

* Remove unused method

* remove unused methods

* remove unused methods

* make all messages struct

* Fix test code generator

* Get rid of MessageBase

* Rename IMessageBase -> NetworkMessage

* add MessageBase as obsolete

* Use a default request

* Empty file to make asset store happy

* Apply suggestions from code review

Co-authored-by: James Frowen <jamesfrowendev@gmail.com>

Co-authored-by: James Frowen <jamesfrowendev@gmail.com>
This commit is contained in:
Paul Pacheco 2020-10-06 02:31:02 -05:00 committed by vis2k
parent 3665a992d5
commit 030028d5c8
24 changed files with 47 additions and 675 deletions

View File

@ -190,14 +190,6 @@ public static MethodDefinition GetMethod(this TypeDefinition td, string methodNa
return td.Methods.FirstOrDefault(method => method.Name == methodName);
}
public static MethodDefinition GetMethodWith1Arg(this TypeDefinition tr, string methodName, TypeReference argType)
{
return tr.GetMethods(methodName).Where(m =>
m.Parameters.Count == 1
&& m.Parameters[0].ParameterType.FullName == argType.FullName
).FirstOrDefault();
}
public static List<MethodDefinition> GetMethods(this TypeDefinition td, string methodName)
{
// Linq allocations don't matter in weaver

View File

@ -1,199 +1 @@
using System.Linq;
using Mono.CecilX;
using Mono.CecilX.Cil;
namespace Mirror.Weaver
{
/// <summary>
/// generates OnSerialize/OnDeserialize when inheriting from MessageBase
/// </summary>
static class MessageClassProcessor
{
static bool IsEmptyDefault(this MethodBody body)
{
return body.Instructions.All(instruction => instruction.OpCode == OpCodes.Nop || instruction.OpCode == OpCodes.Ret);
}
public static void Process(TypeDefinition td)
{
Weaver.DLog(td, "MessageClassProcessor Start");
GenerateSerialization(td);
if (Weaver.WeavingFailed)
{
return;
}
GenerateDeSerialization(td);
Weaver.DLog(td, "MessageClassProcessor Done");
}
static void GenerateSerialization(TypeDefinition td)
{
Weaver.DLog(td, " GenerateSerialization");
MethodDefinition existingMethod = td.GetMethodWith1Arg("Serialize", WeaverTypes.Import<NetworkWriter>());
// do nothing if method exists and is abstract or not empty
if (existingMethod != null && (existingMethod.IsAbstract || !existingMethod.Body.IsEmptyDefault()))
{
return;
}
if (td.Fields.Count == 0)
{
return;
}
// check for self-referencing types
foreach (FieldDefinition field in td.Fields)
{
if (field.FieldType.FullName == td.FullName)
{
Weaver.Error($"{td.Name} has field {field.Name} that references itself", field);
return;
}
}
MethodDefinition serializeFunc = existingMethod ?? new MethodDefinition("Serialize",
MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.HideBySig,
WeaverTypes.Import(typeof(void)));
//only add to new method
if (existingMethod == null)
{
serializeFunc.Parameters.Add(new ParameterDefinition("writer", ParameterAttributes.None, WeaverTypes.Import<NetworkWriter>()));
}
ILProcessor worker = serializeFunc.Body.GetILProcessor();
if (existingMethod != null)
{
//remove default nop&ret from existing empty interface method
worker.Body.Instructions.Clear();
}
// if it is not a struct, call base
if (!td.IsValueType)
{
// call base
CallBase(td, worker, "Serialize");
}
foreach (FieldDefinition field in td.Fields)
{
if (field.IsStatic || field.IsPrivate || field.IsSpecialName)
continue;
CallWriter(worker, field);
}
worker.Append(worker.Create(OpCodes.Ret));
//only add if not just replaced body
if (existingMethod == null)
{
td.Methods.Add(serializeFunc);
}
}
static void CallWriter(ILProcessor worker, FieldDefinition field)
{
MethodReference writeFunc = Writers.GetWriteFunc(field.FieldType);
if (writeFunc != null)
{
worker.Append(worker.Create(OpCodes.Ldarg_1));
worker.Append(worker.Create(OpCodes.Ldarg_0));
worker.Append(worker.Create(OpCodes.Ldfld, field));
worker.Append(worker.Create(OpCodes.Call, writeFunc));
}
else
{
Weaver.Error($"{field.Name} has unsupported type", field);
}
}
static void CallBase(TypeDefinition td, ILProcessor worker, string name)
{
MethodReference method = Resolvers.TryResolveMethodInParents(td.BaseType, Weaver.CurrentAssembly, name);
// dont call method if it is null or abstract
if (method == null || method.Resolve().IsAbstract)
{
return;
}
// base
worker.Append(worker.Create(OpCodes.Ldarg_0));
// writer
worker.Append(worker.Create(OpCodes.Ldarg_1));
worker.Append(worker.Create(OpCodes.Call, method));
}
static void GenerateDeSerialization(TypeDefinition td)
{
Weaver.DLog(td, " GenerateDeserialization");
MethodDefinition existingMethod = td.GetMethodWith1Arg("Deserialize", WeaverTypes.Import<NetworkReader>());
// do nothing if method exists and is abstract or not empty
if (existingMethod != null && (existingMethod.IsAbstract || !existingMethod.Body.IsEmptyDefault()))
{
return;
}
if (td.Fields.Count == 0)
{
return;
}
MethodDefinition serializeFunc = existingMethod ?? new MethodDefinition("Deserialize",
MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.HideBySig,
WeaverTypes.Import(typeof(void)));
//only add to new method
if (existingMethod == null)
{
serializeFunc.Parameters.Add(new ParameterDefinition("reader", ParameterAttributes.None, WeaverTypes.Import<NetworkReader>()));
}
ILProcessor worker = serializeFunc.Body.GetILProcessor();
if (existingMethod != null)
{
//remove default nop&ret from existing empty interface method
worker.Body.Instructions.Clear();
}
// if not value type, call base
if (!td.IsValueType)
{
CallBase(td, worker, "Deserialize");
}
foreach (FieldDefinition field in td.Fields)
{
if (field.IsStatic || field.IsPrivate || field.IsSpecialName)
continue;
CallReader(worker, field);
}
worker.Append(worker.Create(OpCodes.Ret));
//only add if not just replaced body
if (existingMethod == null)
{
td.Methods.Add(serializeFunc);
}
}
static void CallReader(ILProcessor worker, FieldDefinition field)
{
MethodReference readerFunc = Readers.GetReadFunc(field.FieldType);
if (readerFunc != null)
{
worker.Append(worker.Create(OpCodes.Ldarg_0));
worker.Append(worker.Create(OpCodes.Ldarg_1));
worker.Append(worker.Create(OpCodes.Call, readerFunc));
worker.Append(worker.Create(OpCodes.Stfld, field));
}
else
{
Weaver.Error($"{field.Name} has unsupported type", field);
}
}
}
}
// removed Oct 5 2020

View File

@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 3544c9f00f6e5443ea3c30873c5a06ef
guid: e25c00c88fc134f6ea7ab00ae4db8083
MonoImporter:
externalObjects: {}
serializedVersion: 2

View File

@ -43,6 +43,25 @@ static void ProcessAssemblyClasses(AssemblyDefinition CurrentAssembly, AssemblyD
LoadDeclaredReaders(CurrentAssembly, klass);
}
}
foreach (TypeDefinition klass in assembly.MainModule.Types)
{
LoadMessageReadWriter(CurrentAssembly.MainModule, klass);
}
}
private static void LoadMessageReadWriter(ModuleDefinition module, TypeDefinition klass)
{
if (!klass.IsAbstract && !klass.IsInterface && klass.ImplementsInterface<NetworkMessage>())
{
Readers.GetReadFunc(module.ImportReference(klass));
Writers.GetWriteFunc(module.ImportReference(klass));
}
foreach (TypeDefinition td in klass.NestedTypes)
{
LoadMessageReadWriter(module, td);
}
}
static void LoadDeclaredWriters(AssemblyDefinition currentAssembly, TypeDefinition klass)

View File

@ -18,9 +18,6 @@ class WeaverLists
// amount of SyncVars per class. dict<className, amount>
public Dictionary<string, int> numSyncVars = new Dictionary<string, int>();
public HashSet<string> ProcessedMessages = new HashSet<string>();
public int GetSyncVarStart(string className)
{
return numSyncVars.ContainsKey(className)
@ -136,48 +133,6 @@ static bool WeaveNetworkBehavior(TypeDefinition td)
return modified;
}
static bool WeaveMessage(TypeDefinition td)
{
if (!td.IsClass)
return false;
// already processed
if (WeaveLists.ProcessedMessages.Contains(td.FullName))
return false;
bool modified = false;
if (td.ImplementsInterface<NetworkMessage>())
{
// process this and base classes from parent to child order
try
{
TypeDefinition parent = td.BaseType.Resolve();
// process parent
WeaveMessage(parent);
}
catch (AssemblyResolutionException)
{
// this can happen for plugins.
//Console.WriteLine("AssemblyResolutionException: "+ ex.ToString());
}
// process this
MessageClassProcessor.Process(td);
WeaveLists.ProcessedMessages.Add(td.FullName);
modified = true;
}
// check for embedded types
// inner classes should be processed after outter class to avoid StackOverflowException
foreach (TypeDefinition embedded in td.NestedTypes)
{
modified |= WeaveMessage(embedded);
}
return modified;
}
static bool WeaveModule(ModuleDefinition moduleDefinition)
{
try
@ -192,7 +147,6 @@ static bool WeaveModule(ModuleDefinition moduleDefinition)
if (td.IsClass && td.BaseType.CanBeResolved())
{
modified |= WeaveNetworkBehavior(td);
modified |= WeaveMessage(td);
modified |= ServerClientAttributeProcessor.Process(td);
}
}

View File

@ -17,10 +17,6 @@ public void SetHostname(string hostname)
public struct CreatePlayerMessage : NetworkMessage
{
public string name;
// Weaver will generate serialization
public void Serialize(NetworkWriter writer) {}
public void Deserialize(NetworkReader reader) {}
}
public override void OnStartServer()

View File

@ -38,13 +38,13 @@ public static void Pack<T>(T message, NetworkWriter writer)
{
// if it is a value type, just use typeof(T) to avoid boxing
// this works because value types cannot be derived
// if it is a reference type (for example IMessageBase),
// if it is a reference type (for example NetworkMessage),
// ask the message for the real type
int msgType = GetId(typeof(T));
writer.WriteUInt16((ushort)msgType);
// serialize message into writer
message.Serialize(writer);
writer.Write(message);
}
// unpack a message we received
@ -59,10 +59,7 @@ public static T Unpack<T>(byte[] data)
if (id != msgType)
throw new FormatException("Invalid message, could not unpack " + typeof(T).FullName);
T message = new T();
message.Deserialize(networkReader);
return message;
return networkReader.Read<T>();
}
}
@ -110,8 +107,7 @@ internal static NetworkMessageDelegate WrapHandler<T, C>(Action<C, T> handler, b
if (!requireAuthenication || conn.isAuthenticated)
{
// deserialize
T message = default;
message.Deserialize(reader);
T message = reader.Read<T>();
// call it
handler((C)conn, message);

View File

@ -3,12 +3,7 @@
namespace Mirror
{
public interface NetworkMessage
{
void Deserialize(NetworkReader reader);
void Serialize(NetworkWriter writer);
}
public interface NetworkMessage {}
#region Public System Messages
public struct ErrorMessage : NetworkMessage
@ -19,52 +14,17 @@ public ErrorMessage(byte v)
{
value = v;
}
public void Deserialize(NetworkReader reader)
{
value = reader.ReadByte();
}
public void Serialize(NetworkWriter writer)
{
writer.WriteByte(value);
}
}
public struct ReadyMessage : NetworkMessage
{
public void Deserialize(NetworkReader reader) { }
public struct ReadyMessage : NetworkMessage {}
public void Serialize(NetworkWriter writer) { }
}
public struct NotReadyMessage : NetworkMessage {}
public struct NotReadyMessage : NetworkMessage
{
public void Deserialize(NetworkReader reader) { }
public struct AddPlayerMessage : NetworkMessage {}
public void Serialize(NetworkWriter writer) { }
}
public struct DisconnectMessage : NetworkMessage {}
public struct AddPlayerMessage : NetworkMessage
{
public void Deserialize(NetworkReader reader) { }
public void Serialize(NetworkWriter writer) { }
}
public struct DisconnectMessage : NetworkMessage
{
public void Deserialize(NetworkReader reader) { }
public void Serialize(NetworkWriter writer) { }
}
public struct ConnectMessage : NetworkMessage
{
public void Deserialize(NetworkReader reader) { }
public void Serialize(NetworkWriter writer) { }
}
public struct ConnectMessage : NetworkMessage {}
public enum SceneOperation : byte
{
@ -84,23 +44,6 @@ public struct CommandMessage : NetworkMessage
// the parameters for the Cmd function
// -> ArraySegment to avoid unnecessary allocations
public ArraySegment<byte> payload;
public void Deserialize(NetworkReader reader)
{
netId = reader.ReadUInt32();
componentIndex = (int)reader.ReadUInt32();
// hash is always 4 full bytes, WritePackedInt would send 1 extra byte here
functionHash = reader.ReadInt32();
payload = reader.ReadBytesAndSizeSegment();
}
public void Serialize(NetworkWriter writer)
{
writer.WriteUInt32(netId);
writer.WriteUInt32((uint)componentIndex);
writer.WriteInt32(functionHash);
writer.WriteBytesAndSizeSegment(payload);
}
}
public struct RpcMessage : NetworkMessage
@ -111,23 +54,6 @@ public struct RpcMessage : NetworkMessage
// the parameters for the Cmd function
// -> ArraySegment to avoid unnecessary allocations
public ArraySegment<byte> payload;
public void Deserialize(NetworkReader reader)
{
netId = reader.ReadUInt32();
componentIndex = (int)reader.ReadUInt32();
// hash is always 4 full bytes, WritePackedInt would send 1 extra byte here
functionHash = reader.ReadInt32();
payload = reader.ReadBytesAndSizeSegment();
}
public void Serialize(NetworkWriter writer)
{
writer.WriteUInt32(netId);
writer.WriteUInt32((uint)componentIndex);
writer.WriteInt32(functionHash);
writer.WriteBytesAndSizeSegment(payload);
}
}
#endregion
@ -172,68 +98,16 @@ public struct SpawnMessage : NetworkMessage
/// <remark>ArraySegment to avoid unnecessary allocations</remark>
/// </summary>
public ArraySegment<byte> payload;
public void Deserialize(NetworkReader reader)
{
netId = reader.ReadUInt32();
isLocalPlayer = reader.ReadBoolean();
isOwner = reader.ReadBoolean();
sceneId = reader.ReadUInt64();
if (sceneId == 0)
{
assetId = reader.ReadGuid();
}
position = reader.ReadVector3();
rotation = reader.ReadQuaternion();
scale = reader.ReadVector3();
payload = reader.ReadBytesAndSizeSegment();
}
public void Serialize(NetworkWriter writer)
{
writer.WriteUInt32(netId);
writer.WriteBoolean(isLocalPlayer);
writer.WriteBoolean(isOwner);
writer.WriteUInt64(sceneId);
if (sceneId == 0)
{
writer.WriteGuid(assetId);
}
writer.WriteVector3(position);
writer.WriteQuaternion(rotation);
writer.WriteVector3(scale);
writer.WriteBytesAndSizeSegment(payload);
}
}
public struct ObjectDestroyMessage : NetworkMessage
{
public uint netId;
public void Deserialize(NetworkReader reader)
{
netId = reader.ReadUInt32();
}
public void Serialize(NetworkWriter writer)
{
writer.WriteUInt32(netId);
}
}
public struct ObjectHideMessage : NetworkMessage
{
public uint netId;
public void Deserialize(NetworkReader reader)
{
netId = reader.ReadUInt32();
}
public void Serialize(NetworkWriter writer)
{
writer.WriteUInt32(netId);
}
}
public struct UpdateVarsMessage : NetworkMessage
@ -242,18 +116,6 @@ public struct UpdateVarsMessage : NetworkMessage
// the serialized component data
// -> ArraySegment to avoid unnecessary allocations
public ArraySegment<byte> payload;
public void Deserialize(NetworkReader reader)
{
netId = reader.ReadUInt32();
payload = reader.ReadBytesAndSizeSegment();
}
public void Serialize(NetworkWriter writer)
{
writer.WriteUInt32(netId);
writer.WriteBytesAndSizeSegment(payload);
}
}
// A client sends this message to the server
@ -266,16 +128,6 @@ public NetworkPingMessage(double value)
{
clientTime = value;
}
public void Deserialize(NetworkReader reader)
{
clientTime = reader.ReadDouble();
}
public void Serialize(NetworkWriter writer)
{
writer.WriteDouble(clientTime);
}
}
// The server responds with this message
@ -284,18 +136,6 @@ public struct NetworkPongMessage : NetworkMessage
{
public double clientTime;
public double serverTime;
public void Deserialize(NetworkReader reader)
{
clientTime = reader.ReadDouble();
serverTime = reader.ReadDouble();
}
public void Serialize(NetworkWriter writer)
{
writer.WriteDouble(clientTime);
writer.WriteDouble(serverTime);
}
}
#endregion
}

View File

@ -235,10 +235,5 @@ public static NetworkIdentity ReadNetworkIdentity(this NetworkReader reader)
// logger.LogFormat(LogType.Warning, "ReadNetworkIdentity netId:{0} not found in spawned", netId);
return null;
}
public static void ReadMessage<T>(this NetworkReader reader, T msg) where T : NetworkMessage
{
msg.Deserialize(reader);
}
}
}

View File

@ -293,10 +293,5 @@ public static void WriteNetworkIdentity(this NetworkWriter writer, NetworkIdenti
}
writer.WriteUInt32(value.netId);
}
public static void WriteMessage<T>(this NetworkWriter writer, T msg) where T : NetworkMessage
{
msg.Serialize(writer);
}
}
}

View File

@ -36,10 +36,6 @@ public class CustomRWTest
struct QuestMessage : NetworkMessage
{
public MockQuest quest;
// Weaver will generate serialization
public void Serialize(NetworkWriter writer) {}
public void Deserialize(NetworkReader reader) {}
}
[Test]

View File

@ -26,10 +26,6 @@ public class EnumReadWriteTests
public struct ByteMessage : NetworkMessage
{
public MyByteEnum byteEnum;
// Weaver auto generates serialization
public void Deserialize(NetworkReader reader) {}
public void Serialize(NetworkWriter writer) {}
}
public enum MyByteEnum : byte
{
@ -39,10 +35,6 @@ public enum MyByteEnum : byte
public struct ShortMessage : NetworkMessage
{
public MyShortEnum shortEnum;
// Weaver auto generates serialization
public void Deserialize(NetworkReader reader) {}
public void Serialize(NetworkWriter writer) {}
}
public enum MyShortEnum : short
{
@ -52,10 +44,6 @@ public enum MyShortEnum : short
public struct CustomMessage : NetworkMessage
{
public MyCustomEnum customEnum;
// Weaver auto generates serialization
public void Deserialize(NetworkReader reader) {}
public void Serialize(NetworkWriter writer) {}
}
public enum MyCustomEnum
@ -70,7 +58,7 @@ public void ByteIsSentForByteEnum()
ByteMessage msg = new ByteMessage() { byteEnum = MyByteEnum.B };
NetworkWriter writer = new NetworkWriter();
msg.Serialize(writer);
writer.Write(msg);
// should only be 1 byte
Assert.That(writer.Length, Is.EqualTo(1));
@ -82,7 +70,7 @@ public void ShortIsSentForShortEnum()
ShortMessage msg = new ShortMessage() { shortEnum = MyShortEnum.G };
NetworkWriter writer = new NetworkWriter();
msg.Serialize(writer);
writer.Write(msg);
// should only be 1 byte
Assert.That(writer.Length, Is.EqualTo(2));
@ -101,12 +89,11 @@ public void CustomWriterIsUsedForEnum()
{
NetworkWriter writer = new NetworkWriter();
msg.Serialize(writer);
writer.Write(msg);
NetworkReader reader = new NetworkReader(writer.ToArraySegment());
T msg2 = new T();
msg2.Deserialize(reader);
T msg2 = reader.Read<T>();
return msg2;
}
}

View File

@ -13,10 +13,6 @@ public class Array_int_Test
struct Message : NetworkMessage
{
public int[] collection;
// Weaver will generate serialization
public void Serialize(NetworkWriter writer) {}
public void Deserialize(NetworkReader reader) {}
}
[Test]
@ -81,10 +77,6 @@ public class Array_string_Test
struct Message : NetworkMessage
{
public string[] collection;
// Weaver will generate serialization
public void Serialize(NetworkWriter writer) {}
public void Deserialize(NetworkReader reader) {}
}
[Test]
@ -149,10 +141,6 @@ public class Array_Vector3_Test
struct Message : NetworkMessage
{
public Vector3[] collection;
// Weaver will generate serialization
public void Serialize(NetworkWriter writer) {}
public void Deserialize(NetworkReader reader) {}
}
[Test]
@ -217,10 +205,6 @@ public class Array_FloatStringStruct_Test
struct Message : NetworkMessage
{
public FloatStringStruct[] collection;
// Weaver will generate serialization
public void Serialize(NetworkWriter writer) {}
public void Deserialize(NetworkReader reader) {}
}
[Test]
@ -285,10 +269,6 @@ public class Array_ClassWithNoConstructor_Test
struct Message : NetworkMessage
{
public ClassWithNoConstructor[] collection;
// Weaver will generate serialization
public void Serialize(NetworkWriter writer) {}
public void Deserialize(NetworkReader reader) {}
}
[Test]
@ -353,10 +333,6 @@ public class ArraySegment_int_Test
struct Message : NetworkMessage
{
public ArraySegment<int> collection;
// Weaver will generate serialization
public void Serialize(NetworkWriter writer) {}
public void Deserialize(NetworkReader reader) {}
}
[Test]
@ -435,10 +411,6 @@ public class ArraySegment_string_Test
struct Message : NetworkMessage
{
public ArraySegment<string> collection;
// Weaver will generate serialization
public void Serialize(NetworkWriter writer) {}
public void Deserialize(NetworkReader reader) {}
}
[Test]
@ -517,10 +489,6 @@ public class ArraySegment_Vector3_Test
struct Message : NetworkMessage
{
public ArraySegment<Vector3> collection;
// Weaver will generate serialization
public void Serialize(NetworkWriter writer) {}
public void Deserialize(NetworkReader reader) {}
}
[Test]
@ -599,10 +567,6 @@ public class ArraySegment_FloatStringStruct_Test
struct Message : NetworkMessage
{
public ArraySegment<FloatStringStruct> collection;
// Weaver will generate serialization
public void Serialize(NetworkWriter writer) {}
public void Deserialize(NetworkReader reader) {}
}
[Test]
@ -681,10 +645,6 @@ public class ArraySegment_ClassWithNoConstructor_Test
struct Message : NetworkMessage
{
public ArraySegment<ClassWithNoConstructor> collection;
// Weaver will generate serialization
public void Serialize(NetworkWriter writer) {}
public void Deserialize(NetworkReader reader) {}
}
[Test]
@ -763,10 +723,6 @@ public class List_int_Test
struct Message : NetworkMessage
{
public List<int> collection;
// Weaver will generate serialization
public void Serialize(NetworkWriter writer) {}
public void Deserialize(NetworkReader reader) {}
}
[Test]
@ -831,10 +787,6 @@ public class List_string_Test
struct Message : NetworkMessage
{
public List<string> collection;
// Weaver will generate serialization
public void Serialize(NetworkWriter writer) {}
public void Deserialize(NetworkReader reader) {}
}
[Test]
@ -899,10 +851,6 @@ public class List_Vector3_Test
struct Message : NetworkMessage
{
public List<Vector3> collection;
// Weaver will generate serialization
public void Serialize(NetworkWriter writer) {}
public void Deserialize(NetworkReader reader) {}
}
[Test]
@ -967,10 +915,6 @@ public class List_FloatStringStruct_Test
struct Message : NetworkMessage
{
public List<FloatStringStruct> collection;
// Weaver will generate serialization
public void Serialize(NetworkWriter writer) {}
public void Deserialize(NetworkReader reader) {}
}
[Test]
@ -1035,10 +979,6 @@ public class List_ClassWithNoConstructor_Test
struct Message : NetworkMessage
{
public List<ClassWithNoConstructor> collection;
// Weaver will generate serialization
public void Serialize(NetworkWriter writer) {}
public void Deserialize(NetworkReader reader) {}
}
[Test]

View File

@ -121,7 +121,7 @@ static string Classes(string elementType, string collectionType, IEnumerable<str
return $@"
public class {collectionType}_{elementType}_Test
{{
class Message : MessageBase
public class Message : NetworkMessage
{{
public {messageField} collection;
}}

View File

@ -8,20 +8,6 @@ struct TestMessage : NetworkMessage
// Normal = 0, LoadAdditive = 1, UnloadAdditive = 2
public SceneOperation sceneOperation;
public bool customHandling;
public void Deserialize(NetworkReader reader)
{
sceneName = reader.ReadString();
sceneOperation = (SceneOperation)reader.ReadByte();
customHandling = reader.ReadBoolean();
}
public void Serialize(NetworkWriter writer)
{
writer.WriteString(sceneName);
writer.WriteByte((byte)sceneOperation);
writer.WriteBoolean(customHandling);
}
}
[TestFixture]

View File

@ -17,20 +17,6 @@ public TestMessage1(int i, string s, double d)
StringValue = s;
DoubleValue = d;
}
public void Deserialize(NetworkReader reader)
{
IntValue = reader.ReadInt32();
StringValue = reader.ReadString();
DoubleValue = reader.ReadDouble();
}
public void Serialize(NetworkWriter writer)
{
writer.WriteInt32(IntValue);
writer.WriteString(StringValue);
writer.WriteDouble(DoubleValue);
}
}
struct TestMessage2 : NetworkMessage
@ -40,10 +26,6 @@ struct TestMessage2 : NetworkMessage
public string StringValue;
public double DoubleValue;
#pragma warning restore CS0649 // Field is never assigned to
// Mirror will fill out these empty methods
public void Deserialize(NetworkReader reader) { }
public void Serialize(NetworkWriter writer) { }
}
public class CommandTestNetworkBehaviour : NetworkBehaviour

View File

@ -1,66 +0,0 @@
using NUnit.Framework;
namespace Mirror.Tests.MessageTests
{
struct NoArgMethodMessage : NetworkMessage
{
public int someValue;
// Weaver should ignore these methods because they have no args
public void Serialize() { /* method with no arg */ }
public void Deserialize() { /* method with no arg */ }
// Mirror will fill out these empty methods
public void Serialize(NetworkWriter writer) { }
public void Deserialize(NetworkReader reader) { }
}
struct TwoArgMethodMessage : NetworkMessage
{
public int someValue;
// Weaver should ignore these methods because they have two args
public void Serialize(NetworkWriter writer, int AnotherValue) { /* method with 2 args */ }
public void Deserialize(NetworkReader reader, int AnotherValue) { /* method with 2 args */ }
// Mirror will fill out these empty methods
public void Serialize(NetworkWriter writer) { }
public void Deserialize(NetworkReader reader) { }
}
public class OverloadMethodTest
{
[Test]
public void MethodsWithNoArgs()
{
const int value = 10;
NoArgMethodMessage intMessage = new NoArgMethodMessage
{
someValue = value
};
byte[] data = MessagePackerTest.PackToByteArray(intMessage);
NoArgMethodMessage unpacked = MessagePacker.Unpack<NoArgMethodMessage>(data);
Assert.That(unpacked.someValue, Is.EqualTo(value));
}
[Test]
public void MethodsWithTwoArgs()
{
const int value = 10;
TwoArgMethodMessage intMessage = new TwoArgMethodMessage
{
someValue = value
};
byte[] data = MessagePackerTest.PackToByteArray(intMessage);
TwoArgMethodMessage unpacked = MessagePacker.Unpack<TwoArgMethodMessage>(data);
Assert.That(unpacked.someValue, Is.EqualTo(value));
}
}
}

View File

@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: bbe7affc888ce1041a8d6752b0f3f94b
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -3,7 +3,7 @@
namespace Mirror.Tests
{
internal class MyScriptableObject : ScriptableObject
public class MyScriptableObject : ScriptableObject
{
public int someData;
}
@ -19,10 +19,6 @@ public class ScriptableObjectWriterTest
struct ScriptableObjectMessage : NetworkMessage
{
public MyScriptableObject scriptableObject;
// Weaver auto generates serialization
public void Deserialize(NetworkReader reader) {}
public void Serialize(NetworkWriter writer) {}
}
[Test]

View File

@ -5,10 +5,6 @@ namespace Mirror.Tests.StructMessages
public struct SomeStructMessage : NetworkMessage
{
public int someValue;
// Weaver will generate serialization
public void Serialize(NetworkWriter writer) { }
public void Deserialize(NetworkReader reader) { }
}
[TestFixture]
@ -20,7 +16,7 @@ public void SerializeAreAddedWhenEmptyInStruct()
NetworkWriter writer = new NetworkWriter();
const int someValue = 3;
writer.WriteMessage(new SomeStructMessage
writer.Write(new SomeStructMessage
{
someValue = someValue,
});
@ -28,8 +24,7 @@ public void SerializeAreAddedWhenEmptyInStruct()
byte[] arr = writer.ToArray();
NetworkReader reader = new NetworkReader(arr);
SomeStructMessage received = new SomeStructMessage();
received.Deserialize(reader);
SomeStructMessage received = reader.Read<SomeStructMessage>();
Assert.AreEqual(someValue, received.someValue);

View File

@ -13,19 +13,23 @@ public void MessageValid()
[Test]
public void MessageMemberGeneric()
{
HasError("Cannot generate reader for generic variable HasGeneric`1. Use a supported type or provide a custom reader",
"WeaverMessageTests.MessageMemberGeneric.HasGeneric`1<System.Int32>");
HasError("invalidField has an unsupported type",
"WeaverMessageTests.MessageMemberGeneric.HasGeneric`1<System.Int32> WeaverMessageTests.MessageMemberGeneric.MessageMemberGeneric::invalidField");
HasError("Cannot generate writer for generic type HasGeneric`1. Use a supported type or provide a custom writer",
"WeaverMessageTests.MessageMemberGeneric.HasGeneric`1<System.Int32>");
HasError("invalidField has unsupported type",
"WeaverMessageTests.MessageMemberGeneric.HasGeneric`1<System.Int32> WeaverMessageTests.MessageMemberGeneric.MessageMemberGeneric::invalidField");
}
[Test]
public void MessageMemberInterface()
{
HasError("Cannot generate reader for interface SuperCoolInterface. Use a supported type or provide a custom reader",
"WeaverMessageTests.MessageMemberInterface.SuperCoolInterface");
HasError("invalidField has an unsupported type",
"WeaverMessageTests.MessageMemberInterface.SuperCoolInterface WeaverMessageTests.MessageMemberInterface.MessageMemberInterface::invalidField");
HasError("Cannot generate writer for interface SuperCoolInterface. Use a supported type or provide a custom writer",
"WeaverMessageTests.MessageMemberInterface.SuperCoolInterface");
HasError("invalidField has unsupported type",
"WeaverMessageTests.MessageMemberInterface.SuperCoolInterface WeaverMessageTests.MessageMemberInterface.MessageMemberInterface::invalidField");
}
[Test]

View File

@ -14,9 +14,5 @@ struct MessageMemberGeneric : NetworkMessage
public Quaternion rotation;
public HasGeneric<int> invalidField;
public byte[] payload;
// Weaver will generate serialization
public void Serialize(NetworkWriter writer) {}
public void Deserialize(NetworkReader reader) {}
}
}

View File

@ -14,9 +14,5 @@ struct MessageMemberInterface : NetworkMessage
public Quaternion rotation;
public SuperCoolInterface invalidField;
public byte[] payload;
// Weaver will generate serialization
public void Serialize(NetworkWriter writer) {}
public void Deserialize(NetworkReader reader) {}
}
}

View File

@ -11,23 +11,5 @@ struct MessageValid : NetworkMessage
public Vector3 position;
public Quaternion rotation;
public byte[] payload;
public void Deserialize(NetworkReader reader)
{
netId = reader.ReadUInt32();
assetId = reader.ReadGuid();
position = reader.ReadVector3();
rotation = reader.ReadQuaternion();
payload = reader.ReadBytesAndSize();
}
public void Serialize(NetworkWriter writer)
{
writer.WriteUInt32(netId);
writer.WriteGuid(assetId);
writer.WriteVector3(position);
writer.WriteQuaternion(rotation);
writer.WriteBytesAndSize(payload);
}
}
}