예제 #1
0
        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));
예제 #2
0
        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;
            }
        }
예제 #3
0
        public FoundSyncVar AddSyncVar(FieldDefinition fd)
        {
            int dirtyIndex = SyncVarInBase + SyncVars.Count;
            var syncVar    = new FoundSyncVar(Module, this, fd, dirtyIndex);

            SyncVars.Add(syncVar);
            return(syncVar);
        }
예제 #4
0
        public FoundSyncVar AddSyncVar(FieldDefinition fd)
        {
            var dirtyIndex = syncVarCounter.GetInBase() + SyncVars.Count;
            var syncVar    = new FoundSyncVar(Module, this, fd, dirtyIndex);

            SyncVars.Add(syncVar);
            return(syncVar);
        }
예제 #5
0
        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);
        }
예제 #6
0
        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();
        }
예제 #7
0
        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);
        }
예제 #8
0
        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);
        }
예제 #9
0
        /// <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);
        }
예제 #10
0
 /// <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));
 }