using Mono.Cecil; using Mono.Cecil.Cil; namespace QNetWeaver { internal class MessageClassProcessor { public MessageClassProcessor(TypeDefinition td) { Weaver.DLog(td, "MessageClassProcessor for " + td.Name, new object[0]); m_td = td; } public void Process() { Weaver.DLog(m_td, "MessageClassProcessor Start", new object[0]); Weaver.ResetRecursionCount(); GenerateSerialization(); if (!Weaver.fail) { GenerateDeSerialization(); Weaver.DLog(m_td, "MessageClassProcessor Done", new object[0]); } } private void GenerateSerialization() { Weaver.DLog(m_td, " MessageClass GenerateSerialization", new object[0]); foreach (var methodDefinition in m_td.Methods) { if (methodDefinition.Name == "Serialize") { Weaver.DLog(m_td, " Abort - is Serialize", new object[0]); return; } } if (m_td.Fields.Count != 0) { foreach (var fieldDefinition in m_td.Fields) { if (fieldDefinition.FieldType.FullName == m_td.FullName) { Weaver.fail = true; Log.Error(string.Concat(new string[] { "GenerateSerialization for ", m_td.Name, " [", fieldDefinition.FullName, "]. [MessageBase] member cannot be self referencing." })); return; } } var methodDefinition2 = new MethodDefinition("Serialize", MethodAttributes.FamANDAssem | MethodAttributes.Family | MethodAttributes.Virtual | MethodAttributes.HideBySig, Weaver.voidType); methodDefinition2.Parameters.Add(new ParameterDefinition("writer", ParameterAttributes.None, Weaver.scriptDef.MainModule.ImportReference(Weaver.NetworkWriterType))); var ilprocessor = methodDefinition2.Body.GetILProcessor(); foreach (var fieldDefinition2 in m_td.Fields) { if (!fieldDefinition2.IsStatic && !fieldDefinition2.IsPrivate && !fieldDefinition2.IsSpecialName) { if (fieldDefinition2.FieldType.Resolve().HasGenericParameters) { Weaver.fail = true; Log.Error(string.Concat(new object[] { "GenerateSerialization for ", m_td.Name, " [", fieldDefinition2.FieldType, "/", fieldDefinition2.FieldType.FullName, "]. [MessageBase] member cannot have generic parameters." })); return; } if (fieldDefinition2.FieldType.Resolve().IsInterface) { Weaver.fail = true; Log.Error(string.Concat(new object[] { "GenerateSerialization for ", m_td.Name, " [", fieldDefinition2.FieldType, "/", fieldDefinition2.FieldType.FullName, "]. [MessageBase] member cannot be an interface." })); return; } var writeFunc = Weaver.GetWriteFunc(fieldDefinition2.FieldType); if (writeFunc == null) { Weaver.fail = true; Log.Error(string.Concat(new object[] { "GenerateSerialization for ", m_td.Name, " unknown type [", fieldDefinition2.FieldType, "/", fieldDefinition2.FieldType.FullName, "]. [MessageBase] member variables must be basic types." })); return; } ilprocessor.Append(ilprocessor.Create(OpCodes.Ldarg_1)); ilprocessor.Append(ilprocessor.Create(OpCodes.Ldarg_0)); ilprocessor.Append(ilprocessor.Create(OpCodes.Ldfld, fieldDefinition2)); ilprocessor.Append(ilprocessor.Create(OpCodes.Call, writeFunc)); } } ilprocessor.Append(ilprocessor.Create(OpCodes.Ret)); m_td.Methods.Add(methodDefinition2); } } private void GenerateDeSerialization() { Weaver.DLog(m_td, " GenerateDeserialization", new object[0]); foreach (var methodDefinition in m_td.Methods) { if (methodDefinition.Name == "Deserialize") { return; } } if (m_td.Fields.Count != 0) { var methodDefinition2 = new MethodDefinition("Deserialize", MethodAttributes.FamANDAssem | MethodAttributes.Family | MethodAttributes.Virtual | MethodAttributes.HideBySig, Weaver.voidType); methodDefinition2.Parameters.Add(new ParameterDefinition("reader", ParameterAttributes.None, Weaver.scriptDef.MainModule.ImportReference(Weaver.NetworkReaderType))); var ilprocessor = methodDefinition2.Body.GetILProcessor(); foreach (var fieldDefinition in m_td.Fields) { if (!fieldDefinition.IsStatic && !fieldDefinition.IsPrivate && !fieldDefinition.IsSpecialName) { var readFunc = Weaver.GetReadFunc(fieldDefinition.FieldType); if (readFunc == null) { Weaver.fail = true; Log.Error(string.Concat(new object[] { "GenerateDeSerialization for ", m_td.Name, " unknown type [", fieldDefinition.FieldType, "]. [SyncVar] member variables must be basic types." })); return; } ilprocessor.Append(ilprocessor.Create(OpCodes.Ldarg_0)); ilprocessor.Append(ilprocessor.Create(OpCodes.Ldarg_1)); ilprocessor.Append(ilprocessor.Create(OpCodes.Call, readFunc)); ilprocessor.Append(ilprocessor.Create(OpCodes.Stfld, fieldDefinition)); } } ilprocessor.Append(ilprocessor.Create(OpCodes.Ret)); m_td.Methods.Add(methodDefinition2); } } private TypeDefinition m_td; } }