Mirror/Unity-Technologies-networking/Weaver/MessageClassProcessor.cs

153 lines
5.5 KiB
C#
Raw Normal View History

using System;
using Mono.Cecil;
using Mono.Cecil.Cil;
namespace Unity.UNetWeaver
{
class MessageClassProcessor
{
TypeDefinition m_td;
public MessageClassProcessor(TypeDefinition td)
{
Weaver.DLog(td, "MessageClassProcessor for " + td.Name);
m_td = td;
}
public void Process()
{
Weaver.DLog(m_td, "MessageClassProcessor Start");
Weaver.ResetRecursionCount();
GenerateSerialization();
if (Weaver.fail)
{
return;
}
GenerateDeSerialization();
Weaver.DLog(m_td, "MessageClassProcessor Done");
}
void GenerateSerialization()
{
Weaver.DLog(m_td, " GenerateSerialization");
foreach (var m in m_td.Methods)
{
if (m.Name == "Serialize")
return;
}
if (m_td.Fields.Count == 0)
{
return;
}
// check for self-referencing types
foreach (var field in m_td.Fields)
{
if (field.FieldType.FullName == m_td.FullName)
{
Weaver.fail = true;
Log.Error("GenerateSerialization for " + m_td.Name + " [" + field.FullName + "]. [MessageBase] member cannot be self referencing.");
return;
}
}
MethodDefinition serializeFunc = new MethodDefinition("Serialize", MethodAttributes.Public |
MethodAttributes.Virtual |
MethodAttributes.HideBySig,
Weaver.voidType);
serializeFunc.Parameters.Add(new ParameterDefinition("writer", ParameterAttributes.None, Weaver.scriptDef.MainModule.ImportReference(Weaver.NetworkWriterType)));
ILProcessor serWorker = serializeFunc.Body.GetILProcessor();
foreach (var field in m_td.Fields)
{
if (field.IsStatic || field.IsPrivate || field.IsSpecialName)
continue;
if (field.FieldType.Resolve().HasGenericParameters)
{
Weaver.fail = true;
Log.Error("GenerateSerialization for " + m_td.Name + " [" + field.FieldType + "/" + field.FieldType.FullName + "]. [MessageBase] member cannot have generic parameters.");
return;
}
if (field.FieldType.Resolve().IsInterface)
{
Weaver.fail = true;
Log.Error("GenerateSerialization for " + m_td.Name + " [" + field.FieldType + "/" + field.FieldType.FullName + "]. [MessageBase] member cannot be an interface.");
return;
}
MethodReference writeFunc = Weaver.GetWriteFunc(field.FieldType);
if (writeFunc != null)
{
serWorker.Append(serWorker.Create(OpCodes.Ldarg_1));
serWorker.Append(serWorker.Create(OpCodes.Ldarg_0));
serWorker.Append(serWorker.Create(OpCodes.Ldfld, field));
serWorker.Append(serWorker.Create(OpCodes.Call, writeFunc));
}
else
{
Weaver.fail = true;
Log.Error("GenerateSerialization for " + m_td.Name + " unknown type [" + field.FieldType + "/" + field.FieldType.FullName + "]. [MessageBase] member variables must be basic types.");
return;
}
}
serWorker.Append(serWorker.Create(OpCodes.Ret));
m_td.Methods.Add(serializeFunc);
}
void GenerateDeSerialization()
{
Weaver.DLog(m_td, " GenerateDeserialization");
foreach (var m in m_td.Methods)
{
if (m.Name == "Deserialize")
return;
}
if (m_td.Fields.Count == 0)
{
return;
}
MethodDefinition serializeFunc = new MethodDefinition("Deserialize", MethodAttributes.Public |
MethodAttributes.Virtual |
MethodAttributes.HideBySig,
Weaver.voidType);
serializeFunc.Parameters.Add(new ParameterDefinition("reader", ParameterAttributes.None, Weaver.scriptDef.MainModule.ImportReference(Weaver.NetworkReaderType)));
ILProcessor serWorker = serializeFunc.Body.GetILProcessor();
foreach (var field in m_td.Fields)
{
if (field.IsStatic || field.IsPrivate || field.IsSpecialName)
continue;
MethodReference readerFunc = Weaver.GetReadFunc(field.FieldType);
if (readerFunc != null)
{
serWorker.Append(serWorker.Create(OpCodes.Ldarg_0));
serWorker.Append(serWorker.Create(OpCodes.Ldarg_1));
serWorker.Append(serWorker.Create(OpCodes.Call, readerFunc));
serWorker.Append(serWorker.Create(OpCodes.Stfld, field));
}
else
{
Weaver.fail = true;
Log.Error("GenerateDeSerialization for " + m_td.Name + " unknown type [" + field.FieldType + "]. [SyncVar] member variables must be basic types.");
return;
}
}
serWorker.Append(serWorker.Create(OpCodes.Ret));
m_td.Methods.Add(serializeFunc);
}
}
}