mirror of
https://github.com/MirrorNetworking/Mirror.git
synced 2024-11-18 11:00:32 +00:00
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:
parent
3665a992d5
commit
030028d5c8
@ -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
|
||||
|
@ -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
|
@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3544c9f00f6e5443ea3c30873c5a06ef
|
||||
guid: e25c00c88fc134f6ea7ab00ae4db8083
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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()
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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]
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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]
|
||||
|
@ -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;
|
||||
}}
|
||||
|
@ -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]
|
||||
|
@ -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
|
||||
|
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: bbe7affc888ce1041a8d6752b0f3f94b
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -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]
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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]
|
||||
|
@ -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) {}
|
||||
}
|
||||
}
|
||||
|
@ -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) {}
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user