mirror of
https://github.com/MirrorNetworking/Mirror.git
synced 2024-11-18 19:10:32 +00:00
synclist code generator is now reusable (#624)
* refactor: Made serializer generation reusable * refactor: SyncList code generator is reusable for other structs
This commit is contained in:
parent
1d166c699a
commit
b7e977a7a3
@ -6,112 +6,13 @@ namespace Mirror.Weaver
|
|||||||
{
|
{
|
||||||
static class SyncListProcessor
|
static class SyncListProcessor
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Generates serialization methods for synclists
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="td">The synclist class</param>
|
||||||
public static void Process(TypeDefinition td)
|
public static void Process(TypeDefinition td)
|
||||||
{
|
{
|
||||||
// find item type
|
SyncObjectProcessor.GenerateSerialization(td, 0, "SerializeItem", "DeserializeItem");
|
||||||
GenericInstanceType gt = (GenericInstanceType)td.BaseType;
|
|
||||||
if (gt.GenericArguments.Count == 0)
|
|
||||||
{
|
|
||||||
Weaver.Error("SyncListProcessor no generic args");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
TypeReference itemType = Weaver.CurrentAssembly.MainModule.ImportReference(gt.GenericArguments[0]);
|
|
||||||
|
|
||||||
Weaver.DLog(td, "SyncListProcessor Start item:" + itemType.FullName);
|
|
||||||
|
|
||||||
Weaver.ResetRecursionCount();
|
|
||||||
MethodReference writeItemFunc = GenerateSerialization(td, itemType);
|
|
||||||
if (Weaver.WeavingFailed)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
MethodReference readItemFunc = GenerateDeserialization(td, itemType);
|
|
||||||
|
|
||||||
if (readItemFunc == null || writeItemFunc == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
Weaver.DLog(td, "SyncListProcessor Done");
|
|
||||||
}
|
|
||||||
|
|
||||||
// serialization of individual element
|
|
||||||
static MethodReference GenerateSerialization(TypeDefinition td, TypeReference itemType)
|
|
||||||
{
|
|
||||||
Weaver.DLog(td, " GenerateSerialization");
|
|
||||||
foreach (var m in td.Methods)
|
|
||||||
{
|
|
||||||
if (m.Name == "SerializeItem")
|
|
||||||
return m;
|
|
||||||
}
|
|
||||||
|
|
||||||
MethodDefinition serializeFunc = new MethodDefinition("SerializeItem", MethodAttributes.Public |
|
|
||||||
MethodAttributes.Virtual |
|
|
||||||
MethodAttributes.Public |
|
|
||||||
MethodAttributes.HideBySig,
|
|
||||||
Weaver.voidType);
|
|
||||||
|
|
||||||
serializeFunc.Parameters.Add(new ParameterDefinition("writer", ParameterAttributes.None, Weaver.CurrentAssembly.MainModule.ImportReference(Weaver.NetworkWriterType)));
|
|
||||||
serializeFunc.Parameters.Add(new ParameterDefinition("item", ParameterAttributes.None, itemType));
|
|
||||||
ILProcessor serWorker = serializeFunc.Body.GetILProcessor();
|
|
||||||
|
|
||||||
if (itemType.IsGenericInstance)
|
|
||||||
{
|
|
||||||
Weaver.Error("GenerateSerialization for " + Helpers.PrettyPrintType(itemType) + " failed. Struct passed into SyncList<T> can't have generic parameters");
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
MethodReference writeFunc = Weaver.GetWriteFunc(itemType);
|
|
||||||
if (writeFunc != null)
|
|
||||||
{
|
|
||||||
serWorker.Append(serWorker.Create(OpCodes.Ldarg_1));
|
|
||||||
serWorker.Append(serWorker.Create(OpCodes.Ldarg_2));
|
|
||||||
serWorker.Append(serWorker.Create(OpCodes.Call, writeFunc));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Weaver.Error("GenerateSerialization for " + td.Name + " unknown type [" + itemType + "/" + itemType.FullName + "]. [SyncList] member variables must be basic types.");
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
serWorker.Append(serWorker.Create(OpCodes.Ret));
|
|
||||||
|
|
||||||
td.Methods.Add(serializeFunc);
|
|
||||||
return serializeFunc;
|
|
||||||
}
|
|
||||||
|
|
||||||
static MethodReference GenerateDeserialization(TypeDefinition td, TypeReference itemType)
|
|
||||||
{
|
|
||||||
Weaver.DLog(td, " GenerateDeserialization");
|
|
||||||
foreach (var m in td.Methods)
|
|
||||||
{
|
|
||||||
if (m.Name == "DeserializeItem")
|
|
||||||
return m;
|
|
||||||
}
|
|
||||||
|
|
||||||
MethodDefinition deserializeFunction = new MethodDefinition("DeserializeItem", MethodAttributes.Public |
|
|
||||||
MethodAttributes.Virtual |
|
|
||||||
MethodAttributes.Public |
|
|
||||||
MethodAttributes.HideBySig,
|
|
||||||
itemType);
|
|
||||||
|
|
||||||
deserializeFunction.Parameters.Add(new ParameterDefinition("reader", ParameterAttributes.None, Weaver.CurrentAssembly.MainModule.ImportReference(Weaver.NetworkReaderType)));
|
|
||||||
|
|
||||||
ILProcessor serWorker = deserializeFunction.Body.GetILProcessor();
|
|
||||||
|
|
||||||
MethodReference readerFunc = Weaver.GetReadFunc(itemType);
|
|
||||||
if (readerFunc != null)
|
|
||||||
{
|
|
||||||
serWorker.Append(serWorker.Create(OpCodes.Ldarg_1));
|
|
||||||
serWorker.Append(serWorker.Create(OpCodes.Call, readerFunc));
|
|
||||||
serWorker.Append(serWorker.Create(OpCodes.Ret));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Weaver.Error("GenerateDeserialization for " + td.Name + " unknown type [" + itemType + "]. [SyncList] member variables must be basic types.");
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
td.Methods.Add(deserializeFunction);
|
|
||||||
return deserializeFunction;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
124
Assets/Mirror/Editor/Weaver/Processors/SyncObjectProcessor.cs
Normal file
124
Assets/Mirror/Editor/Weaver/Processors/SyncObjectProcessor.cs
Normal file
@ -0,0 +1,124 @@
|
|||||||
|
using System;
|
||||||
|
using Mono.Cecil;
|
||||||
|
using Mono.Cecil.Cil;
|
||||||
|
|
||||||
|
namespace Mirror.Weaver
|
||||||
|
{
|
||||||
|
public static class SyncObjectProcessor
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Generates the serialization and deserialization methods for a specified generic argument
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="td">The type of the class that needs serialization methods</param>
|
||||||
|
/// <param name="genericArgument">Which generic argument to serialize, 0 is the first one</param>
|
||||||
|
/// <param name="serializeMethod">The name of the serialize method</param>
|
||||||
|
/// <param name="deserializeMethod">The name of the deserialize method</param>
|
||||||
|
public static void GenerateSerialization(TypeDefinition td, int genericArgument, string serializeMethod, string deserializeMethod)
|
||||||
|
{
|
||||||
|
// find item type
|
||||||
|
GenericInstanceType gt = (GenericInstanceType)td.BaseType;
|
||||||
|
if (gt.GenericArguments.Count <= genericArgument)
|
||||||
|
{
|
||||||
|
Weaver.Error("SyncObjectProcessor no generic args");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
TypeReference itemType = Weaver.CurrentAssembly.MainModule.ImportReference(gt.GenericArguments[genericArgument]);
|
||||||
|
|
||||||
|
Weaver.DLog(td, "SyncObjectProcessor Start item:" + itemType.FullName);
|
||||||
|
|
||||||
|
Weaver.ResetRecursionCount();
|
||||||
|
MethodReference writeItemFunc = GenerateSerialization(serializeMethod, td, itemType);
|
||||||
|
if (Weaver.WeavingFailed)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
MethodReference readItemFunc = GenerateDeserialization(deserializeMethod, td, itemType);
|
||||||
|
|
||||||
|
if (readItemFunc == null || writeItemFunc == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Weaver.DLog(td, "SyncObjectProcessor Done");
|
||||||
|
}
|
||||||
|
|
||||||
|
// serialization of individual element
|
||||||
|
static MethodReference GenerateSerialization(string methodName, TypeDefinition td, TypeReference itemType)
|
||||||
|
{
|
||||||
|
Weaver.DLog(td, " GenerateSerialization");
|
||||||
|
foreach (var m in td.Methods)
|
||||||
|
{
|
||||||
|
if (m.Name == methodName)
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
|
MethodDefinition serializeFunc = new MethodDefinition(methodName, MethodAttributes.Public |
|
||||||
|
MethodAttributes.Virtual |
|
||||||
|
MethodAttributes.Public |
|
||||||
|
MethodAttributes.HideBySig,
|
||||||
|
Weaver.voidType);
|
||||||
|
|
||||||
|
serializeFunc.Parameters.Add(new ParameterDefinition("writer", ParameterAttributes.None, Weaver.CurrentAssembly.MainModule.ImportReference(Weaver.NetworkWriterType)));
|
||||||
|
serializeFunc.Parameters.Add(new ParameterDefinition("item", ParameterAttributes.None, itemType));
|
||||||
|
ILProcessor serWorker = serializeFunc.Body.GetILProcessor();
|
||||||
|
|
||||||
|
if (itemType.IsGenericInstance)
|
||||||
|
{
|
||||||
|
Weaver.Error("GenerateSerialization for " + Helpers.PrettyPrintType(itemType) + " failed. Can't have generic parameters");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
MethodReference writeFunc = Weaver.GetWriteFunc(itemType);
|
||||||
|
if (writeFunc != null)
|
||||||
|
{
|
||||||
|
serWorker.Append(serWorker.Create(OpCodes.Ldarg_1));
|
||||||
|
serWorker.Append(serWorker.Create(OpCodes.Ldarg_2));
|
||||||
|
serWorker.Append(serWorker.Create(OpCodes.Call, writeFunc));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Weaver.Error("GenerateSerialization for " + td.Name + " unknown type [" + itemType + "/" + itemType.FullName + "]. Member variables must be basic types.");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
serWorker.Append(serWorker.Create(OpCodes.Ret));
|
||||||
|
|
||||||
|
td.Methods.Add(serializeFunc);
|
||||||
|
return serializeFunc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static MethodReference GenerateDeserialization(string methodName, TypeDefinition td, TypeReference itemType)
|
||||||
|
{
|
||||||
|
Weaver.DLog(td, " GenerateDeserialization");
|
||||||
|
foreach (var m in td.Methods)
|
||||||
|
{
|
||||||
|
if (m.Name == methodName)
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
|
MethodDefinition deserializeFunction = new MethodDefinition(methodName, MethodAttributes.Public |
|
||||||
|
MethodAttributes.Virtual |
|
||||||
|
MethodAttributes.Public |
|
||||||
|
MethodAttributes.HideBySig,
|
||||||
|
itemType);
|
||||||
|
|
||||||
|
deserializeFunction.Parameters.Add(new ParameterDefinition("reader", ParameterAttributes.None, Weaver.CurrentAssembly.MainModule.ImportReference(Weaver.NetworkReaderType)));
|
||||||
|
|
||||||
|
ILProcessor serWorker = deserializeFunction.Body.GetILProcessor();
|
||||||
|
|
||||||
|
MethodReference readerFunc = Weaver.GetReadFunc(itemType);
|
||||||
|
if (readerFunc != null)
|
||||||
|
{
|
||||||
|
serWorker.Append(serWorker.Create(OpCodes.Ldarg_1));
|
||||||
|
serWorker.Append(serWorker.Create(OpCodes.Call, readerFunc));
|
||||||
|
serWorker.Append(serWorker.Create(OpCodes.Ret));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Weaver.Error("GenerateDeserialization for " + td.Name + " unknown type [" + itemType + "]. Member variables must be basic types.");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
td.Methods.Add(deserializeFunction);
|
||||||
|
return deserializeFunction;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 78f71efc83cde4917b7d21efa90bcc9a
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
@ -285,7 +285,7 @@ public void SyncListStructGenericGeneric()
|
|||||||
{
|
{
|
||||||
Assert.That(CompilationFinishedHook.WeaveFailed, Is.True);
|
Assert.That(CompilationFinishedHook.WeaveFailed, Is.True);
|
||||||
Assert.That(m_weaverErrors.Count, Is.EqualTo(1));
|
Assert.That(m_weaverErrors.Count, Is.EqualTo(1));
|
||||||
Assert.That(m_weaverErrors[0], Does.Match("Struct passed into SyncList<T> can't have generic parameters"));
|
Assert.That(m_weaverErrors[0], Is.EqualTo("Mirror.Weaver error: GenerateSerialization for MyGenericStruct<Single> failed. Can't have generic parameters"));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
|
Loading…
Reference in New Issue
Block a user