static MethodDefinition GenerateClassOrStructReadFunction(TypeReference variable, int recursionCount) { if (recursionCount > MaxRecursionCount) { Weaver.Error($"{variable} can't be deserialized because it references itself"); return(null); } if (!Weaver.IsValidTypeToGenerate(variable.Resolve())) { return(null); } string functionName = "_Read" + variable.Name + "_"; if (variable.DeclaringType != null) { functionName += variable.DeclaringType.Name; } else { functionName += "None"; } // create new reader for this type var readerFunc = new MethodDefinition(functionName, MethodAttributes.Public | MethodAttributes.Static | MethodAttributes.HideBySig, variable); // create local for return value readerFunc.Body.Variables.Add(new VariableDefinition(variable)); readerFunc.Body.InitLocals = true; readerFunc.Parameters.Add(new ParameterDefinition("reader", ParameterAttributes.None, Weaver.CurrentAssembly.MainModule.ImportReference(Weaver.NetworkReaderType))); ILProcessor worker = readerFunc.Body.GetILProcessor(); TypeDefinition td = variable.Resolve(); CreateNew(variable, worker, td); DeserializeFields(variable, recursionCount, worker); worker.Append(worker.Create(OpCodes.Ldloc_0)); worker.Append(worker.Create(OpCodes.Ret)); return(readerFunc); }
static MethodDefinition GenerateClassOrStructReadFunction(TypeReference variable, int recursionCount) { if (recursionCount > MaxRecursionCount) { Weaver.Error($"{variable} can't be deserialized because it references itself"); return(null); } if (!Weaver.IsValidTypeToGenerate(variable.Resolve())) { return(null); } string functionName = "_Read" + variable.Name + "_"; if (variable.DeclaringType != null) { functionName += variable.DeclaringType.Name; } else { functionName += "None"; } // create new reader for this type MethodDefinition readerFunc = new MethodDefinition(functionName, MethodAttributes.Public | MethodAttributes.Static | MethodAttributes.HideBySig, variable); // create local for return value readerFunc.Body.Variables.Add(new VariableDefinition(variable)); readerFunc.Body.InitLocals = true; readerFunc.Parameters.Add(new ParameterDefinition("reader", ParameterAttributes.None, Weaver.CurrentAssembly.MainModule.ImportReference(Weaver.NetworkReaderType))); ILProcessor worker = readerFunc.Body.GetILProcessor(); if (variable.IsValueType) { // structs are created with Initobj worker.Append(worker.Create(OpCodes.Ldloca, 0)); worker.Append(worker.Create(OpCodes.Initobj, variable)); } else { // classes are created with their constructor MethodDefinition ctor = Resolvers.ResolveDefaultPublicCtor(variable); if (ctor == null) { Weaver.Error($"{variable} can't be deserialized bcause i has no default constructor"); return(null); } worker.Append(worker.Create(OpCodes.Newobj, ctor)); worker.Append(worker.Create(OpCodes.Stloc_0)); } uint fields = 0; foreach (FieldDefinition field in variable.Resolve().Fields) { if (field.IsStatic || field.IsPrivate) { continue; } // mismatched ldloca/ldloc for struct/class combinations is invalid IL, which causes crash at runtime OpCode opcode = variable.IsValueType ? OpCodes.Ldloca : OpCodes.Ldloc; worker.Append(worker.Create(opcode, 0)); MethodReference readFunc = GetReadFunc(field.FieldType, recursionCount + 1); if (readFunc != null) { worker.Append(worker.Create(OpCodes.Ldarg_0)); worker.Append(worker.Create(OpCodes.Call, readFunc)); } else { Weaver.Error($"{field} has an unsupported type"); return(null); } worker.Append(worker.Create(OpCodes.Stfld, field)); fields++; } if (fields == 0) { Log.Warning($"{variable} has no public or non-static fields to deserialize"); } worker.Append(worker.Create(OpCodes.Ldloc_0)); worker.Append(worker.Create(OpCodes.Ret)); return(readerFunc); }
static MethodDefinition GenerateStructWriterFunction(TypeReference variable, int recursionCount) { if (recursionCount > MaxRecursionCount) { Weaver.Error($"{variable} can't be serialized because it references itself"); return(null); } if (!Weaver.IsValidTypeToGenerate(variable.Resolve())) { return(null); } string functionName = "_Write" + variable.Name + "_"; if (variable.DeclaringType != null) { functionName += variable.DeclaringType.Name; } else { functionName += "None"; } // create new writer for this type MethodDefinition writerFunc = new MethodDefinition(functionName, MethodAttributes.Public | MethodAttributes.Static | MethodAttributes.HideBySig, Weaver.voidType); writerFunc.Parameters.Add(new ParameterDefinition("writer", ParameterAttributes.None, Weaver.CurrentAssembly.MainModule.ImportReference(Weaver.NetworkWriterType))); writerFunc.Parameters.Add(new ParameterDefinition("value", ParameterAttributes.None, Weaver.CurrentAssembly.MainModule.ImportReference(variable))); ILProcessor worker = writerFunc.Body.GetILProcessor(); uint fields = 0; foreach (FieldDefinition field in variable.Resolve().Fields) { if (field.IsStatic || field.IsPrivate) { continue; } if (field.FieldType.Resolve().HasGenericParameters) { Weaver.Error($"{field} has unsupported type. Create a derived class instead of using generics"); return(null); } if (field.FieldType.Resolve().IsInterface) { Weaver.Error($"{field} has unsupported type. Use a concrete class instead of an interface"); return(null); } MethodReference writeFunc = GetWriteFunc(field.FieldType, recursionCount + 1); if (writeFunc != null) { fields++; worker.Append(worker.Create(OpCodes.Ldarg_0)); worker.Append(worker.Create(OpCodes.Ldarg_1)); worker.Append(worker.Create(OpCodes.Ldfld, field)); worker.Append(worker.Create(OpCodes.Call, writeFunc)); } else { Weaver.Error($"{field} has unsupported type. Use a type supported by Mirror instead"); return(null); } } if (fields == 0) { Log.Warning($" {variable} has no no public or non-static fields to serialize"); } worker.Append(worker.Create(OpCodes.Ret)); return(writerFunc); }
static MethodDefinition GenerateStructWriterFunction(TypeReference variable, int recursionCount) { if (!Weaver.IsValidTypeToGenerate(variable.Resolve())) { return(null); } string functionName = "_Write" + variable.Name + "_"; if (variable.DeclaringType != null) { functionName += variable.DeclaringType.Name; } else { functionName += "None"; } // create new writer for this type MethodDefinition writerFunc = new MethodDefinition(functionName, MethodAttributes.Public | MethodAttributes.Static | MethodAttributes.HideBySig, Weaver.voidType); writerFunc.Parameters.Add(new ParameterDefinition("writer", ParameterAttributes.None, Weaver.CurrentAssembly.MainModule.ImportReference(Weaver.NetworkWriterType))); writerFunc.Parameters.Add(new ParameterDefinition("value", ParameterAttributes.None, Weaver.CurrentAssembly.MainModule.ImportReference(variable))); ILProcessor worker = writerFunc.Body.GetILProcessor(); uint fields = 0; foreach (FieldDefinition field in variable.Resolve().Fields) { if (field.IsStatic || field.IsPrivate) { continue; } if (field.FieldType.Resolve().HasGenericParameters) { Weaver.Error("WriteReadFunc for " + field.Name + " [" + field.FieldType + "/" + field.FieldType.FullName + "]. Cannot have generic parameters."); return(null); } if (field.FieldType.Resolve().IsInterface) { Weaver.Error("WriteReadFunc for " + field.Name + " [" + field.FieldType + "/" + field.FieldType.FullName + "]. Cannot be an interface."); return(null); } MethodReference writeFunc = GetWriteFunc(field.FieldType, recursionCount + 1); if (writeFunc != null) { fields++; worker.Append(worker.Create(OpCodes.Ldarg_0)); worker.Append(worker.Create(OpCodes.Ldarg_1)); worker.Append(worker.Create(OpCodes.Ldfld, field)); worker.Append(worker.Create(OpCodes.Call, writeFunc)); } else { Weaver.Error("WriteReadFunc for " + field.Name + " type " + field.FieldType + " no supported"); return(null); } } if (fields == 0) { Log.Warning("The class / struct " + variable.Name + " has no public or non-static fields to serialize"); } worker.Append(worker.Create(OpCodes.Ret)); return(writerFunc); }