MethodDefinition GenerateSyncVarSetter(FoundSyncVar syncVar) { FieldDefinition fd = syncVar.FieldDefinition; TypeReference originalType = syncVar.OriginalType; string originalName = syncVar.OriginalName; //Create the set method MethodDefinition set = fd.DeclaringType.AddMethod("set_Network" + originalName, MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig); ParameterDefinition valueParam = set.AddParam(originalType, "value"); set.SemanticsAttributes = MethodSemanticsAttributes.Setter; ILProcessor worker = set.Body.GetILProcessor(); // if (!SyncVarEqual(value, ref playerData)) Instruction endOfMethod = worker.Create(OpCodes.Nop); // this worker.Append(worker.Create(OpCodes.Ldarg_0)); // new value to set worker.Append(worker.Create(OpCodes.Ldarg, valueParam)); // reference to field to set // make generic version of SetSyncVar with field type WriteLoadField(worker, syncVar); MethodReference syncVarEqual = module.ImportReference <NetworkBehaviour>(nb => nb.SyncVarEqual <object>(default, default));
void ProcessSyncVar(FoundSyncVar syncVar) { // process attributes first before creating setting, otherwise it wont know about hook syncVar.SetWrapType(); syncVar.ProcessAttributes(writers, readers); FieldDefinition fd = syncVar.FieldDefinition; string originalName = fd.Name; Weaver.DebugLog(fd.DeclaringType, $"Sync Var {fd.Name} {fd.FieldType}"); MethodDefinition get = GenerateSyncVarGetter(syncVar); MethodDefinition set = syncVar.InitialOnly ? GenerateSyncVarSetterInitialOnly(syncVar) : GenerateSyncVarSetter(syncVar); //NOTE: is property even needed? Could just use a setter function? //create the property var propertyDefinition = new PropertyDefinition("Network" + originalName, PropertyAttributes.None, syncVar.OriginalType) { GetMethod = get, SetMethod = set }; propertyDefinition.DeclaringType = fd.DeclaringType; //add the methods and property to the type. fd.DeclaringType.Properties.Add(propertyDefinition); propertySiteProcessor.Setters[fd] = set; if (syncVar.IsWrapped) { propertySiteProcessor.Getters[fd] = get; } }
public FoundSyncVar AddSyncVar(FieldDefinition fd) { int dirtyIndex = SyncVarInBase + SyncVars.Count; var syncVar = new FoundSyncVar(Module, this, fd, dirtyIndex); SyncVars.Add(syncVar); return(syncVar); }
public FoundSyncVar AddSyncVar(FieldDefinition fd) { var dirtyIndex = syncVarCounter.GetInBase() + SyncVars.Count; var syncVar = new FoundSyncVar(Module, this, fd, dirtyIndex); SyncVars.Add(syncVar); return(syncVar); }
internal void WriteIfSyncVarDirty(FoundSyncVar syncVar, Action body) { var endIf = worker.Create(OpCodes.Nop); // we dont shift read bits, so we have to shift dirty bit here var syncVarIndex = syncVar.DirtyBit >> behaviour.syncVarCounter.GetInBase(); // check if dirty bit is set worker.Append(worker.Create(OpCodes.Ldloc, DirtyBitsLocal)); worker.Append(worker.Create(OpCodes.Ldc_I8, syncVarIndex)); worker.Append(worker.Create(OpCodes.And)); worker.Append(worker.Create(OpCodes.Brfalse, endIf)); body.Invoke(); worker.Append(endIf); }
public void ProcessSyncVars(TypeDefinition td, IWeaverLogger logger) { behaviour = new FoundNetworkBehaviour(module, td); // the mapping of dirtybits to sync-vars is implicit in the order of the fields here. this order is recorded in m_replacementProperties. // start assigning syncvars at the place the base class stopped, if any // get numbers of syncvars in parent class, it will be added to syncvars in this class for total behaviour.GetSyncVarCountFromBase(); // find syncvars // use ToArray to create copy, ProcessSyncVar might add new fields foreach (FieldDefinition fd in td.Fields.ToArray()) { // try/catch for each field, and log once // we dont want to spam multiple logs for a single field try { if (IsValidSyncVar(fd)) { FoundSyncVar syncVar = behaviour.AddSyncVar(fd); ProcessSyncVar(syncVar); syncVar.HasProcessed = true; } } catch (ValueSerializerException e) { logger.Error(e.Message, fd); } catch (SyncVarException e) { logger.Error(e); } catch (SerializeFunctionException e) { // use field as member referecne logger.Error(e.Message, fd); } } behaviour.SetSyncVarCount(); GenerateSerialization(); GenerateDeserialization(); }
MethodDefinition GenerateSyncVarSetterInitialOnly(FoundSyncVar syncVar) { // todo reduce duplicate code with this and GenerateSyncVarSetter FieldDefinition fd = syncVar.FieldDefinition; TypeReference originalType = syncVar.OriginalType; string originalName = syncVar.OriginalName; //Create the set method MethodDefinition set = fd.DeclaringType.AddMethod("set_Network" + originalName, MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig); ParameterDefinition valueParam = set.AddParam(originalType, "value"); set.SemanticsAttributes = MethodSemanticsAttributes.Setter; ILProcessor worker = set.Body.GetILProcessor(); WriteStoreField(worker, valueParam, syncVar); worker.Append(worker.Create(OpCodes.Ret)); return(set); }
MethodDefinition GenerateSyncVarGetter(FoundSyncVar syncVar) { FieldDefinition fd = syncVar.FieldDefinition; TypeReference originalType = syncVar.OriginalType; string originalName = syncVar.OriginalName; //Create the get method MethodDefinition get = fd.DeclaringType.AddMethod( "get_Network" + originalName, MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig, originalType); ILProcessor worker = get.Body.GetILProcessor(); WriteLoadField(worker, syncVar); worker.Append(worker.Create(OpCodes.Ret)); get.SemanticsAttributes = MethodSemanticsAttributes.Getter; return(get); }
/// <summary> /// Generates: if ((dirtyBits & 1uL) != 0uL) /// <para>where 1uL is the syncvar's dirty bit</para> /// </summary> /// <param name="syncvar"></param> /// <param name="falseLabel"></param> public void WriteIfSyncVarDirty(FoundSyncVar syncvar, Action Body) { Instruction endIfLabel = worker.Create(OpCodes.Nop); // load dirtyBit // load syncvarIndex // AND operation // if zero, jump to label worker.Append(worker.Create(OpCodes.Ldloc, DirtyBitsLocal)); worker.Append(worker.Create(OpCodes.Ldc_I8, syncvar.DirtyBit)); worker.Append(worker.Create(OpCodes.And)); worker.Append(worker.Create(OpCodes.Brfalse, endIfLabel)); Body.Invoke(); // say that this NB is dirty worker.Append(worker.Create(OpCodes.Ldc_I4_1)); // set dirtyLocal to true worker.Append(worker.Create(OpCodes.Stloc, DirtyLocal)); worker.Append(endIfLabel); }
/// <exception cref="ValueSerializerException">Throws when attribute is used incorrectly</exception> /// <exception cref="SerializeFunctionException">Throws when can not generate read or write function</exception> public static ValueSerializer GetSerializer(FoundSyncVar syncVar, Writers writers, Readers readers) { return(GetSerializer(syncVar.Module, syncVar.Behaviour.TypeDefinition, syncVar.FieldDefinition, syncVar.FieldDefinition.FieldType, syncVar.FieldDefinition.Name, writers, readers)); }