// Initialize the local variable with a new instance static void CreateNew(TypeReference variable, ILProcessor worker, TypeDefinition td) { if (variable.IsValueType) { // structs are created with Initobj worker.Append(worker.Create(OpCodes.Ldloca, 0)); worker.Append(worker.Create(OpCodes.Initobj, variable)); } else if (td.IsDerivedFrom <UnityEngine.ScriptableObject>()) { GenericInstanceMethod genericInstanceMethod = new GenericInstanceMethod(WeaverTypes.ScriptableObjectCreateInstanceMethod); genericInstanceMethod.GenericArguments.Add(variable); worker.Append(worker.Create(OpCodes.Call, genericInstanceMethod)); worker.Append(worker.Create(OpCodes.Stloc_0)); } else { // classes are created with their constructor MethodDefinition ctor = Resolvers.ResolveDefaultPublicCtor(variable); if (ctor == null) { Weaver.Error($"{variable.Name} can't be deserialized because it has no default constructor", variable); return; } MethodReference ctorRef = Weaver.CurrentAssembly.MainModule.ImportReference(ctor); worker.Append(worker.Create(OpCodes.Newobj, ctorRef)); worker.Append(worker.Create(OpCodes.Stloc_0)); } }
// Initialize the local variable with a new instance void CreateNew(TypeReference variable, ILProcessor worker, TypeDefinition td, ref bool WeavingFailed) { if (variable.IsValueType) { // structs are created with Initobj worker.Emit(OpCodes.Ldloca, 0); worker.Emit(OpCodes.Initobj, variable); } else if (td.IsDerivedFrom <UnityEngine.ScriptableObject>()) { GenericInstanceMethod genericInstanceMethod = new GenericInstanceMethod(weaverTypes.ScriptableObjectCreateInstanceMethod); genericInstanceMethod.GenericArguments.Add(variable); worker.Emit(OpCodes.Call, genericInstanceMethod); worker.Emit(OpCodes.Stloc_0); } else { // classes are created with their constructor MethodDefinition ctor = Resolvers.ResolveDefaultPublicCtor(variable); if (ctor == null) { Log.Error($"{variable.Name} can't be deserialized because it has no default constructor. Don't use {variable.Name} in [SyncVar]s, Rpcs, Cmds, etc.", variable); WeavingFailed = true; return; } MethodReference ctorRef = assembly.MainModule.ImportReference(ctor); worker.Emit(OpCodes.Newobj, ctorRef); worker.Emit(OpCodes.Stloc_0); } }
// Initialize the local variable with a new instance private static void CreateNew(TypeReference variable, ILProcessor worker, TypeDefinition td) { if (variable.IsValueType) { // structs are created with Initobj worker.Append(worker.Create(OpCodes.Ldloca, 0)); worker.Append(worker.Create(OpCodes.Initobj, variable)); } else if (td.IsDerivedFrom(Weaver.ScriptableObjectType)) { var genericInstanceMethod = new GenericInstanceMethod(Weaver.ScriptableObjectCreateInstanceMethod); genericInstanceMethod.GenericArguments.Add(variable); worker.Append(worker.Create(OpCodes.Call, genericInstanceMethod)); worker.Append(worker.Create(OpCodes.Stloc_0)); } else { // classes are created with their constructor MethodDefinition ctor = Resolvers.ResolveDefaultPublicCtor(variable); if (ctor == null) { Weaver.Error($"{variable} can't be deserialized because i has no default constructor"); } worker.Append(worker.Create(OpCodes.Newobj, ctor)); worker.Append(worker.Create(OpCodes.Stloc_0)); } }
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); }