public static bool WriteArguments(ILProcessor worker, MethodDefinition md, string errString, bool skipFirst) { // write each argument short argNum = 1; foreach (ParameterDefinition pd in md.Parameters) { if (argNum == 1 && skipFirst) { argNum += 1; continue; } MethodReference writeFunc = Weaver.GetWriteFunc(pd.ParameterType); if (writeFunc == null) { Log.Error("WriteArguments for " + md.Name + " type " + pd.ParameterType + " not supported"); Weaver.fail = true; return(false); } // use built-in writer func on writer object worker.Append(worker.Create(OpCodes.Ldloc_0)); // writer object worker.Append(worker.Create(OpCodes.Ldarg, argNum)); // argument worker.Append(worker.Create(OpCodes.Call, writeFunc)); // call writer func on writer object argNum += 1; } return(true); }
// 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); }
void GenerateSerialization() { Weaver.DLog(m_td, " GenerateSerialization"); foreach (MethodDefinition m in m_td.Methods) { if (m.Name == "OnSerialize") { return; } } if (m_SyncVars.Count == 0) { // no synvars, no need for custom OnSerialize return; } MethodDefinition serialize = new MethodDefinition("OnSerialize", MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.HideBySig, Weaver.boolType); serialize.Parameters.Add(new ParameterDefinition("writer", ParameterAttributes.None, Weaver.scriptDef.MainModule.ImportReference(Weaver.NetworkWriterType))); serialize.Parameters.Add(new ParameterDefinition("forceAll", ParameterAttributes.None, Weaver.boolType)); ILProcessor serWorker = serialize.Body.GetILProcessor(); serialize.Body.InitLocals = true; // loc_0, this local variable is to determine if any variable was dirty VariableDefinition dirtyLocal = new VariableDefinition(Weaver.boolType); serialize.Body.Variables.Add(dirtyLocal); MethodReference baseSerialize = Resolvers.ResolveMethodInParents(m_td.BaseType, Weaver.scriptDef, "OnSerialize"); if (baseSerialize != null) { serWorker.Append(serWorker.Create(OpCodes.Ldarg_0)); // base serWorker.Append(serWorker.Create(OpCodes.Ldarg_1)); // writer serWorker.Append(serWorker.Create(OpCodes.Ldarg_2)); // forceAll serWorker.Append(serWorker.Create(OpCodes.Call, baseSerialize)); serWorker.Append(serWorker.Create(OpCodes.Stloc_0)); // set dirtyLocal to result of base.OnSerialize() } // Generates: if (forceAll); Instruction initialStateLabel = serWorker.Create(OpCodes.Nop); serWorker.Append(serWorker.Create(OpCodes.Ldarg_2)); // forceAll serWorker.Append(serWorker.Create(OpCodes.Brfalse, initialStateLabel)); foreach (FieldDefinition syncVar in m_SyncVars) { // Generates a writer call for each sync variable serWorker.Append(serWorker.Create(OpCodes.Ldarg_1)); // writer serWorker.Append(serWorker.Create(OpCodes.Ldarg_0)); // this serWorker.Append(serWorker.Create(OpCodes.Ldfld, syncVar)); MethodReference writeFunc = Weaver.GetWriteFunc(syncVar.FieldType); if (writeFunc != null) { serWorker.Append(serWorker.Create(OpCodes.Call, writeFunc)); } else { Weaver.fail = true; Log.Error("GenerateSerialization for " + m_td.Name + " unknown type [" + syncVar.FieldType + "]. UNet [SyncVar] member variables must be basic types."); return; } } // always return true if forceAll // Generates: return true serWorker.Append(serWorker.Create(OpCodes.Ldc_I4_1)); serWorker.Append(serWorker.Create(OpCodes.Ret)); // Generates: end if (forceAll); serWorker.Append(initialStateLabel); // write dirty bits before the data fields // Generates: writer.WritePackedUInt64 (base.get_syncVarDirtyBits ()); serWorker.Append(serWorker.Create(OpCodes.Ldarg_1)); // writer serWorker.Append(serWorker.Create(OpCodes.Ldarg_0)); // base serWorker.Append(serWorker.Create(OpCodes.Call, Weaver.NetworkBehaviourDirtyBitsReference)); serWorker.Append(serWorker.Create(OpCodes.Callvirt, Weaver.NetworkWriterWritePacked64)); // generate a writer call for any dirty variable in this class // start at number of syncvars in parent int dirtyBit = Weaver.GetSyncVarStart(m_td.BaseType.FullName); foreach (FieldDefinition syncVar in m_SyncVars) { Instruction varLabel = serWorker.Create(OpCodes.Nop); // Generates: if ((base.get_syncVarDirtyBits() & 1uL) != 0uL) serWorker.Append(serWorker.Create(OpCodes.Ldarg_0)); // base serWorker.Append(serWorker.Create(OpCodes.Call, Weaver.NetworkBehaviourDirtyBitsReference)); serWorker.Append(serWorker.Create(OpCodes.Ldc_I8, 1L << dirtyBit)); // 8 bytes = long serWorker.Append(serWorker.Create(OpCodes.And)); serWorker.Append(serWorker.Create(OpCodes.Brfalse, varLabel)); // Generates a call to the writer for that field serWorker.Append(serWorker.Create(OpCodes.Ldarg_1)); // writer serWorker.Append(serWorker.Create(OpCodes.Ldarg_0)); // base serWorker.Append(serWorker.Create(OpCodes.Ldfld, syncVar)); MethodReference writeFunc = Weaver.GetWriteFunc(syncVar.FieldType); if (writeFunc != null) { serWorker.Append(serWorker.Create(OpCodes.Call, writeFunc)); } else { Log.Error("GenerateSerialization for " + m_td.Name + " unknown type [" + syncVar.FieldType + "]. UNet [SyncVar] member variables must be basic types."); Weaver.fail = true; return; } // something was dirty serWorker.Append(serWorker.Create(OpCodes.Ldc_I4_1)); serWorker.Append(serWorker.Create(OpCodes.Stloc_0)); // set dirtyLocal to true serWorker.Append(varLabel); dirtyBit += 1; } if (Weaver.generateLogErrors) { serWorker.Append(serWorker.Create(OpCodes.Ldstr, "Injected Serialize " + m_td.Name)); serWorker.Append(serWorker.Create(OpCodes.Call, Weaver.logErrorReference)); } // generate: return dirtyLocal serWorker.Append(serWorker.Create(OpCodes.Ldloc_0)); serWorker.Append(serWorker.Create(OpCodes.Ret)); m_td.Methods.Add(serialize); }
// serialization of individual element MethodReference GenerateSerialization() { Weaver.DLog(m_TypeDef, " GenerateSerialization"); foreach (var m in m_TypeDef.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.scriptDef.MainModule.ImportReference(Weaver.NetworkWriterType))); serializeFunc.Parameters.Add(new ParameterDefinition("item", ParameterAttributes.None, m_ItemType)); ILProcessor serWorker = serializeFunc.Body.GetILProcessor(); if (m_ItemType.IsGenericInstance) { Weaver.fail = true; Log.Error("GenerateSerialization for " + Helpers.PrettyPrintType(m_ItemType) + " failed. Struct passed into SyncListStruct<T> can't have generic parameters"); return(null); } foreach (var field in m_ItemType.Resolve().Fields) { if (field.IsStatic || field.IsPrivate || field.IsSpecialName) { continue; } var importedField = Weaver.scriptDef.MainModule.ImportReference(field); var ft = importedField.FieldType.Resolve(); if (ft.HasGenericParameters) { Weaver.fail = true; Log.Error("GenerateSerialization for " + m_TypeDef.Name + " [" + ft + "/" + ft.FullName + "]. UNet [MessageBase] member cannot have generic parameters."); return(null); } if (ft.IsInterface) { Weaver.fail = true; Log.Error("GenerateSerialization for " + m_TypeDef.Name + " [" + ft + "/" + ft.FullName + "]. UNet [MessageBase] member cannot be an interface."); return(null); } MethodReference writeFunc = Weaver.GetWriteFunc(field.FieldType); if (writeFunc != null) { serWorker.Append(serWorker.Create(OpCodes.Ldarg_1)); serWorker.Append(serWorker.Create(OpCodes.Ldarg_2)); serWorker.Append(serWorker.Create(OpCodes.Ldfld, importedField)); serWorker.Append(serWorker.Create(OpCodes.Call, writeFunc)); } else { Weaver.fail = true; Log.Error("GenerateSerialization for " + m_TypeDef.Name + " unknown type [" + ft + "/" + ft.FullName + "]. UNet [MessageBase] member variables must be basic types."); return(null); } } serWorker.Append(serWorker.Create(OpCodes.Ret)); m_TypeDef.Methods.Add(serializeFunc); return(serializeFunc); }
static void GenerateSerialization(TypeDefinition td) { Weaver.DLog(td, " GenerateSerialization"); foreach (MethodDefinition m in td.Methods) { if (m.Name == "Serialize") { return; } } if (td.Fields.Count == 0) { return; } // check for self-referencing types foreach (FieldDefinition field in td.Fields) { if (field.FieldType.FullName == td.FullName) { Weaver.Error("GenerateSerialization for " + 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.CurrentAssembly.MainModule.ImportReference(Weaver.NetworkWriterType))); ILProcessor serWorker = serializeFunc.Body.GetILProcessor(); foreach (FieldDefinition field in td.Fields) { if (field.IsStatic || field.IsPrivate || field.IsSpecialName) { continue; } if (field.FieldType.Resolve().HasGenericParameters) { Weaver.Error("GenerateSerialization for " + td.Name + " [" + field.FieldType + "/" + field.FieldType.FullName + "]. [MessageBase] member cannot have generic parameters."); return; } if (field.FieldType.Resolve().IsInterface) { Weaver.Error("GenerateSerialization for " + 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.Error("GenerateSerialization for " + td.Name + " unknown type [" + field.FieldType + "/" + field.FieldType.FullName + "]. [MessageBase] member variables must be basic types."); return; } } serWorker.Append(serWorker.Create(OpCodes.Ret)); td.Methods.Add(serializeFunc); }