Exemplo n.º 1
0
 public static Instruction ParseInstruction(ILProcessor processor, TypeDefinition type, XElement instrXML)
 {
     return(processor.Create(OpCodes.Stloc_0));
 }
Exemplo n.º 2
0
        /// <summary>
        /// Patches the Method.
        /// </summary>
        /// <param name="Method">The Method.</param>
        Boolean PatchMethod(MethodDefinition Method)
        {
            Boolean IsSharpJit = false;
            List<String> Attributes = this.GetSharpDXAttributes(Method);

            if (Attributes.Contains("SharpDX.ModuleInit"))
            {
                CreateModuleInit(Method);
            }

            if (Method.DeclaringType.Name == "Interop")
            {
                if (Method.Name == "memcpy")
                {
                    CreateMemcpy(Method);
                }
                else if (Method.Name == "memset")
                {
                    CreateMemset(Method);
                }
                else if ((Method.Name == "Cast") || (Method.Name == "CastOut"))
                {
                    CreateCastMethod(Method);
                }
                else if (Method.Name == "CastArray")
                {
                    CreateCastArrayMethod(Method);
                }
                else if (Method.Name == "Read" || (Method.Name == "ReadOut") || (Method.Name == "Read2D"))
                {
                    if (Method.Parameters.Count == 2)
                        CreateReadMethod(Method);
                    else
                        CreateReadRangeMethod(Method);
                }
                else if (Method.Name == "Write" || (Method.Name == "Write2D"))
                {
                    if (Method.Parameters.Count == 2)
                        CreateWriteMethod(Method);
                    else
                        CreateWriteRangeMethod(Method);
                }
            }
            else if (Method.HasBody)
            {
                ILProcessor IlProcessor = Method.Body.GetILProcessor();
                Collection<Instruction> instructions = Method.Body.Instructions;
                Instruction Instruction = null;
                Instruction previousInstruction;

                for (Int32 Index = 0; Index < instructions.Count; Index++)
                {
                    previousInstruction = Instruction;
                    Instruction = instructions[Index];

                    if (Instruction.OpCode != OpCodes.Call || !(Instruction.Operand is MethodReference))
                        continue;

                    MethodReference MethodDescription = (MethodReference)Instruction.Operand;

                    if (MethodDescription is MethodDefinition)
                    {
                        foreach (CustomAttribute CustomAttribute in ((MethodDefinition)MethodDescription).CustomAttributes)
                        {
                            if (CustomAttribute.AttributeType.FullName == typeof(ObfuscationAttribute).FullName)
                            {
                                foreach (Mono.Cecil.CustomAttributeNamedArgument Arg in CustomAttribute.Properties)
                                {
                                    if (Arg.Name == "Feature" && Arg.Argument.Value != null)
                                    {
                                        var customValue = Arg.Argument.Value.ToString();
                                        if (customValue.StartsWith("SharpJit."))
                                        {
                                            IsSharpJit = true;
                                            break;
                                        }
                                    }
                                }
                            }
                            if (IsSharpJit) break;
                        }
                    }

                    if (!IsSharpJit)
                    {
                        if (MethodDescription.Name.StartsWith("Calli") && MethodDescription.DeclaringType.Name == "LocalInterop")
                        {
                            CallSite CallSite = new CallSite(MethodDescription.ReturnType) { CallingConvention = MethodCallingConvention.StdCall };

                            // Last parameter is the function ptr, so we don't add it as a parameter for calli
                            // as it is already an implicit parameter for calli
                            for (Int32 ParameterIndex = 0; ParameterIndex < MethodDescription.Parameters.Count - 1; ParameterIndex++)
                            {
                                ParameterDefinition ParameterDefinition = MethodDescription.Parameters[ParameterIndex];
                                CallSite.Parameters.Add(ParameterDefinition);
                            }

                            // Create calli Instruction
                            Instruction CallIInstruction = IlProcessor.Create(OpCodes.Calli, CallSite);

                            // Replace instruction
                            IlProcessor.Replace(Instruction, CallIInstruction);
                        }
                        else if (MethodDescription.DeclaringType.Name == "Interop")
                        {
                            if (MethodDescription.FullName.Contains("Fixed"))
                            {
                                if (MethodDescription.Parameters[0].ParameterType.IsArray)
                                {
                                    ReplaceFixedArrayStatement(Method, IlProcessor, Instruction);
                                }
                                else
                                {
                                    ReplaceFixedStatement(Method, IlProcessor, Instruction);
                                }
                            }
                            else if (MethodDescription.Name.StartsWith("ReadInline"))
                            {
                                this.ReplaceReadInline(Method, IlProcessor, Instruction);
                            }
                            else if (MethodDescription.Name.StartsWith("CopyInline") || MethodDescription.Name.StartsWith("WriteInline"))
                            {
                                this.ReplaceCopyInline(Method, IlProcessor, Instruction);
                            }
                            else if (MethodDescription.Name.StartsWith("SizeOf"))
                            {
                                this.ReplaceSizeOfStructGeneric(Method, IlProcessor, Instruction);
                            }
                        }
                    }
                }
            }

            return IsSharpJit;
        }
Exemplo n.º 3
0
        // todo add documentation
        public static Instruction Create <T, TR>(this ILProcessor worker, OpCode code, Expression <Func <T, TR> > expression)
        {
            MethodReference typeref = worker.Body.Method.Module.ImportReference(expression);

            return(worker.Create(code, typeref));
        }
        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));

            CheckForHookFunction(td, fd, out MethodDefinition hookFunctionMethod);

            if (hookFunctionMethod != 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
                setWorker.Append(setWorker.Create(OpCodes.Ldarg_0));
                setWorker.Append(setWorker.Create(OpCodes.Ldarg_1));
                setWorker.Append(setWorker.Create(OpCodes.Call, hookFunctionMethod));

                // 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);
            }

            // 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
            setWorker.Append(setWorker.Create(OpCodes.Ldc_I8, dirtyBit)); // 8 byte integer aka long

            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));
            }

            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);
        }
Exemplo n.º 5
0
 public override Instruction CreateInstruction(ILProcessor worker, OpCode opcode)
 {
     return(worker.Create(opcode, SelectedOperand));
 }
Exemplo n.º 6
0
    /// <summary>
    /// Transfuses an instruction into a target method.
    /// </summary>
    /// <param name="inst">Instruction to transfuse</param>
    /// <param name="offset">Start offset</param>
    /// <param name="targetAssembly">Target assembly</param>
    /// <param name="targetMethod">Target method</param>
    /// <param name="importToAssembly">Assembly to import to</param>
    /// <param name="verbose">Whether to print verbose messages to the console</param>
    /// <returns></returns>
    public static Instruction TransfuseInstruction(Instruction inst, int offset, AssemblyDefinition targetAssembly, MethodDefinition targetMethod, AssemblyDefinition importToAssembly, bool verbose)
    {
        Instruction newInst = null;
        ILProcessor proc    = targetMethod.Body.GetILProcessor();

        if (inst.Operand == null)
        {
            newInst = proc.Create(inst.OpCode);
        }
        else if (inst.Operand is byte)
        {
            newInst = proc.Create(inst.OpCode, (byte)inst.Operand);
        }
        else if (inst.Operand is sbyte)
        {
            newInst = proc.Create(inst.OpCode, (sbyte)inst.Operand);
        }
        else if (inst.Operand is short)
        {
            newInst = proc.Create(inst.OpCode, (short)inst.Operand);
        }
        else if (inst.Operand is int)
        {
            newInst = proc.Create(inst.OpCode, (int)inst.Operand);
        }
        else if (inst.Operand is long)
        {
            newInst = proc.Create(inst.OpCode, (long)inst.Operand);
        }
        else if (inst.Operand is float)
        {
            newInst = proc.Create(inst.OpCode, (float)inst.Operand);
        }
        else if (inst.Operand is double)
        {
            newInst = proc.Create(inst.OpCode, (double)inst.Operand);
        }
        else if (inst.Operand is string)
        {
            newInst = proc.Create(inst.OpCode, (string)inst.Operand);
        }
        else if (inst.Operand is Instruction)
        {
            newInst = proc.Create(inst.OpCode, TransfuseInstruction(inst.Operand as Instruction, offset, targetAssembly, targetMethod, importToAssembly, verbose));
        }
        else if (inst.Operand is Instruction[])
        {
            Instruction[] insts = inst.Operand as Instruction[];
            for (var i = 0; i < insts.Length; i++)
            {
                insts[i] = TransfuseInstruction(insts[i], offset, targetAssembly, targetMethod, importToAssembly, verbose);
            }
            newInst = proc.Create(inst.OpCode, insts);
        }
        else if (inst.Operand is VariableReference)
        {
            VariableDefinition def = (inst.Operand as VariableReference).Resolve();
            newInst = proc.Create(inst.OpCode, new VariableDefinition(def.Name, importToAssembly.MainModule.Import(def.VariableType)));
        }
        else if (inst.Operand is TypeReference)
        {
            TypeDefinition def = (inst.Operand as TypeReference).Resolve();
            if (def != null)
            {
                if (verbose)
                {
                    Console.WriteLine("< import " + def);
                }
                newInst = proc.Create(inst.OpCode, importToAssembly.MainModule.Import(def));
            }
            else
            {
                throw new Exception("Unresolved TypeReference: " + inst.Operand);
            }
        }
        else if (inst.Operand is FieldReference)
        {
            FieldDefinition def = (inst.Operand as FieldReference).Resolve();
            if (def != null)
            {
                if (verbose)
                {
                    Console.WriteLine("< import " + def);
                }
                newInst = proc.Create(inst.OpCode, importToAssembly.MainModule.Import(def));
            }
            else
            {
                throw new Exception("Unresolved FieldReference: " + inst.Operand);
            }
        }
        else if (inst.Operand is MethodReference)
        {
            MethodDefinition def = (inst.Operand as MethodReference).Resolve();
            if (def != null)
            {
                if (verbose)
                {
                    Console.WriteLine("< import " + def);
                }
                newInst = proc.Create(inst.OpCode, importToAssembly.MainModule.Import(def));
            }
            else
            {
                throw new Exception("Unresolved MethodReference: " + inst.Operand);
            }
        }
        else
        {
            throw new Exception("Unknown Operand type: " + inst.Operand.GetType());
        }
        newInst.Offset = offset + inst.Offset;
        return(newInst);
    }
Exemplo n.º 7
0
        public static void EmitPointerToObject(this ILProcessor body, TypeReference originalReturnType, TypeReference convertedReturnType, TypeRewriteContext enclosingType, Instruction loadPointer, bool extraDerefForNonValueTypes, bool unboxValueType)
        {
            // input stack: not used
            // output stack: converted result

            if (originalReturnType is GenericParameter)
            {
                EmitPointerToObjectGeneric(body, originalReturnType, convertedReturnType, enclosingType, loadPointer, extraDerefForNonValueTypes, unboxValueType);
                return;
            }

            var imports = enclosingType.AssemblyContext.Imports;

            if (originalReturnType.FullName == "System.Void")
            {
                // do nothing
            }
            else if (originalReturnType.IsValueType)
            {
                if (convertedReturnType.IsValueType)
                {
                    body.Append(loadPointer);
                    if (unboxValueType)
                    {
                        body.Emit(OpCodes.Call, imports.ObjectUnbox);
                    }
                    body.Emit(OpCodes.Ldobj, convertedReturnType);
                }
                else
                {
                    if (!unboxValueType)
                    {
                        var classPointerTypeRef = new GenericInstanceType(imports.Il2CppClassPointerStore)
                        {
                            GenericArguments = { convertedReturnType }
                        };
                        var classPointerFieldRef =
                            new FieldReference(nameof(Il2CppClassPointerStore <int> .NativeClassPtr), imports.IntPtr,
                                               classPointerTypeRef);
                        body.Emit(OpCodes.Ldsfld, enclosingType.NewType.Module.ImportReference(classPointerFieldRef));
                        body.Append(loadPointer);
                        body.Emit(OpCodes.Call, imports.ObjectBox);
                    }
                    else // already boxed
                    {
                        body.Append(loadPointer);
                    }

                    body.Emit(OpCodes.Newobj,
                              new MethodReference(".ctor", imports.Void, convertedReturnType)
                    {
                        Parameters = { new ParameterDefinition(imports.IntPtr) }, HasThis = true
                    });
                }
            }
            else if (originalReturnType.FullName == "System.String")
            {
                body.Append(loadPointer);
                if (extraDerefForNonValueTypes)
                {
                    body.Emit(OpCodes.Ldind_I);
                }
                body.Emit(OpCodes.Call, imports.StringFromNative);
            }
            else if (originalReturnType.IsArray && originalReturnType.GetElementType().IsGenericParameter)
            {
                body.Append(loadPointer);
                var actualReturnType = imports.Il2CppArrayBaseSelfSubst;
                var methodRef        = new MethodReference(nameof(Il2CppArrayBase <int> .WrapNativeGenericArrayPointer),
                                                           actualReturnType,
                                                           convertedReturnType)
                {
                    HasThis = false, Parameters = { new ParameterDefinition(imports.IntPtr) }
                };
                body.Emit(OpCodes.Call, methodRef);
            }
            else
            {
                var createRealObject = body.Create(OpCodes.Newobj,
                                                   new MethodReference(".ctor", imports.Void, convertedReturnType)
                {
                    Parameters = { new ParameterDefinition(imports.IntPtr) }, HasThis = true
                });
                var endNop = body.Create(OpCodes.Nop);

                body.Append(loadPointer);
                if (extraDerefForNonValueTypes)
                {
                    body.Emit(OpCodes.Ldind_I);
                }
                body.Emit(OpCodes.Dup);
                body.Emit(OpCodes.Brtrue_S, createRealObject);
                body.Emit(OpCodes.Pop);
                body.Emit(OpCodes.Ldnull);
                body.Emit(OpCodes.Br, endNop);

                body.Append(createRealObject);
                body.Append(endNop);
            }
        }
Exemplo n.º 8
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("InvokeSyncEvent" + ed.Name, MethodAttributes.Family |
                                                        MethodAttributes.Static |
                                                        MethodAttributes.HideBySig,
                                                        Weaver.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);
        }
Exemplo n.º 9
0
        static MethodDefinition GenerateArrayReadFunc(TypeReference variable)
        {
            if (!variable.IsArrayType())
            {
                Weaver.Error($"{variable.Name} is an unsupported type. Jagged and multidimensional arrays are not supported", variable);
                return(null);
            }

            MethodDefinition readerFunc      = GenerateReaderFunction(variable);
            TypeReference    elementType     = variable.GetElementType();
            MethodReference  elementReadFunc = GetReadFunc(elementType);

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

            // int lengh
            readerFunc.Body.Variables.Add(new VariableDefinition(WeaverTypes.Import <int>()));
            // T[] array
            readerFunc.Body.Variables.Add(new VariableDefinition(variable));
            // int i;
            readerFunc.Body.Variables.Add(new VariableDefinition(WeaverTypes.Import <int>()));

            ILProcessor worker = readerFunc.Body.GetILProcessor();

            // int length = reader.ReadPackedInt32();
            GenerateReadLength(worker);

            GenerateNullLengthCheck(worker);

            // 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++) {
            GenerateFor(worker, () =>
            {
                // 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()));
            });

            // return value;
            worker.Append(worker.Create(OpCodes.Ldloc_1));
            worker.Append(worker.Create(OpCodes.Ret));
            return(readerFunc);
        }
Exemplo n.º 10
0
        static int EmitParameters(MethodDefinition method, MethodDefinition native, MethodBody body, ILProcessor il)
        {
            int i;

            for (i = 0; i < method.Parameters.Count; i++)
            {
                var parameter = method.Parameters[i];
                var p         = method.Module.Import(method.Parameters[i].ParameterType);
                il.Emit(OpCodes.Ldarg, i);

                if (p.Name.Contains("Int32") && native.Parameters[i].ParameterType.Name.Contains("IntPtr"))
                {
                    // This is a convenience Int32 overload for an IntPtr (size_t) parameter.
                    // We need to convert the loaded argument to IntPtr.
                    il.Emit(OpCodes.Conv_I);
                }
                else if (p.Name == "StringBuilder")
                {
                    EmitStringBuilderParameter(method, parameter, body, il);
                }
                else if (p.Name == "String" && !p.IsArray)
                {
                    EmitStringParameter(method, parameter, body, il);
                }
                else if (p.IsByReference)
                {
                    body.Variables.Add(new VariableDefinition(new PinnedType(p)));
                    var index = body.Variables.Count - 1;
                    il.Emit(OpCodes.Stloc, index);
                    il.Emit(OpCodes.Ldloc, index);
                    il.Emit(OpCodes.Conv_I);
                }
                else if (p.IsArray)
                {
                    if (p.Name != method.Module.Import(typeof(string[])).Name)
                    {
                        // .Net treats 1d arrays differently than higher rank arrays.
                        // 1d arrays are directly supported by instructions such as ldlen and ldelema.
                        // Higher rank arrays must be accessed through System.Array methods such as get_Length.
                        // 1d array:
                        //    check array is not null
                        //    check ldlen array > 0
                        //    ldc.i4.0
                        //    ldelema
                        // 2d array:
                        //    check array is not null
                        //    check array.get_Length() > 0
                        //    ldc.i4.0
                        //    ldc.i4.0
                        //    call instance T& T[0..., 0...]::Address(int32, int32)
                        // Mono treats everything as a 1d array.
                        // Interestingly, the .Net approach works on both Mono and .Net.
                        // The Mono approach fails when using high-rank arrays on .Net.
                        // We should report a bug to http://bugzilla.xamarin.com

                        // Pin the array and pass the address
                        // of its first element.
                        var array        = (ArrayType)p;
                        var element_type = p.GetElementType();
                        body.Variables.Add(new VariableDefinition(new PinnedType(new ByReferenceType(element_type))));
                        int pinned_index = body.Variables.Count - 1;

                        var empty = il.Create(OpCodes.Ldc_I4, 0);
                        var pin   = il.Create(OpCodes.Ldarg, i);
                        var end   = il.Create(OpCodes.Stloc, pinned_index);

                        // if (array == null) goto empty
                        il.Emit(OpCodes.Brfalse, empty);

                        // else if (array.Length != 0) goto pin
                        il.Emit(OpCodes.Ldarg, i);
                        if (array.Rank == 1)
                        {
                            il.Emit(OpCodes.Ldlen);
                            il.Emit(OpCodes.Conv_I4);
                        }
                        else
                        {
                            var get_length = method.Module.Import(
                                mscorlib.MainModule.GetType("System.Array").Methods.First(m => m.Name == "get_Length"));
                            il.Emit(OpCodes.Callvirt, get_length);
                        }
                        il.Emit(OpCodes.Brtrue, pin);

                        // empty: IntPtr ptr = IntPtr.Zero
                        il.Append(empty);
                        il.Emit(OpCodes.Conv_U);
                        il.Emit(OpCodes.Br, end);

                        // pin: &array[0]
                        il.Append(pin);
                        if (array.Rank == 1)
                        {
                            // 1d array (vector), address is taken by ldelema
                            il.Emit(OpCodes.Ldc_I4, 0);
                            il.Emit(OpCodes.Ldelema, element_type);
                        }
                        else
                        {
                            // 2d-3d array, address must be taken as follows:
                            // call instance T& T[0..., 0..., 0...]::Address(int, int, int)
                            ByReferenceType t_ref       = array.ElementType.MakeByReferenceType();
                            MethodReference get_address = new MethodReference("Address", t_ref, array);
                            for (int r = 0; r < array.Rank; r++)
                            {
                                get_address.Parameters.Add(new ParameterDefinition(TypeInt32));
                            }
                            get_address.HasThis = true;

                            // emit the get_address call
                            for (int r = 0; r < array.Rank; r++)
                            {
                                il.Emit(OpCodes.Ldc_I4, 0);
                            }
                            il.Emit(OpCodes.Call, get_address);
                        }

                        // end: fixed (IntPtr ptr = &array[0])
                        il.Append(end);
                        il.Emit(OpCodes.Ldloc, pinned_index);
                        il.Emit(OpCodes.Conv_I);
                    }
                    else
                    {
                        EmitStringArrayParameter(method, parameter, body, il);
                    }
                }
            }
            return(i);
        }
Exemplo n.º 11
0
        private void InstrumentInstruction(int instructionId, Instruction instruction,
                                           MethodReference hitMethodReference, MethodDefinition method, ILProcessor ilProcessor)
        {
            var pathParamLoadInstruction = ilProcessor.Create(OpCodes.Ldstr, hitsFile);
            var lineParamLoadInstruction = ilProcessor.Create(OpCodes.Ldc_I4, instructionId);
            var registerInstruction      = ilProcessor.Create(OpCodes.Call, hitMethodReference);

            ilProcessor.InsertBefore(instruction, registerInstruction);
            ilProcessor.InsertBefore(registerInstruction, lineParamLoadInstruction);
            ilProcessor.InsertBefore(lineParamLoadInstruction, pathParamLoadInstruction);

            var newFirstInstruction = pathParamLoadInstruction;

            //change try/finally etc to point to our first instruction if they referenced the one we inserted before
            foreach (var handler in method.Body.ExceptionHandlers)
            {
                if (handler.FilterStart == instruction)
                {
                    handler.FilterStart = newFirstInstruction;
                }

                if (handler.TryStart == instruction)
                {
                    handler.TryStart = newFirstInstruction;
                }
                if (handler.TryEnd == instruction)
                {
                    handler.TryEnd = newFirstInstruction;
                }

                if (handler.HandlerStart == instruction)
                {
                    handler.HandlerStart = newFirstInstruction;
                }
                if (handler.HandlerEnd == instruction)
                {
                    handler.HandlerEnd = newFirstInstruction;
                }
            }

            //change instructions with a target instruction if they referenced the one we inserted before to be our first instruction
            foreach (var iteratedInstruction in method.Body.Instructions)
            {
                var operand = iteratedInstruction.Operand;
                if (operand == instruction)
                {
                    iteratedInstruction.Operand = newFirstInstruction;
                    continue;
                }

                if (!(operand is Instruction[]))
                {
                    continue;
                }

                var operands = (Instruction[])operand;
                for (var i = 0; i < operands.Length; ++i)
                {
                    if (operands[i] == instruction)
                    {
                        operands[i] = newFirstInstruction;
                    }
                }
            }
        }
 public Instruction CreateInstruction(ILProcessor worker, OpCode opcode)
 {
     return(worker.Create(opcode, _selectedInstructions.ToArray()));
 }
        private static void InjectIL(TypeDefinition type, ModuleDefinition module)
        {
            const string targetMethod = "Load";

            // From class -> JsonLoadRequest -> StringDataLoadRequest
            TypeDefinition   baseType = type.BaseType.Resolve().BaseType.Resolve();
            MethodDefinition method   =
                baseType.GetMethods().FirstOrDefault(m => m.Name == targetMethod);

            if (method == null)
            {
                CecilManager.WriteError($"Can't find method: {targetMethod}\n");
                return;
            }

            ILProcessor ilProcessor = method.Body.GetILProcessor();

            // Add a enew reference to an importable method call for AsyncJsonLoadRequest.Load()
            TypeReference ajlr_TR = module.ImportReference(typeof(AsyncJsonLoadRequest));
            TypeReference taskTR  = module.ImportReference(typeof(Task));

            MethodReference ajlr_lr_MR = new MethodReference("LoadResource", taskTR, ajlr_TR);
            TypeReference   stringTR   = module.ImportReference(typeof(string));

            ajlr_lr_MR.Parameters.Add(new ParameterDefinition(stringTR));

            TypeReference actionStringTR = module.ImportReference(typeof(Action <string>));

            ajlr_lr_MR.Parameters.Add(new ParameterDefinition(actionStringTR));
            ajlr_lr_MR.ReturnType = taskTR;

            MethodReference ajlr_lr_Imported_MR = module.ImportReference(ajlr_lr_MR);

            // Walk the instructions to find the target. Don't mutate as we go, so we can use insertAfter later.
            int targetIdx = -1;

            for (int i = 0; i < method.Body.Instructions.Count - 1; i++)
            {
                Instruction instruction = method.Body.Instructions[i];
                if (instruction.OpCode == OpCodes.Callvirt &&
                    instruction.Operand is MethodDefinition methodDef)
                {
                    //CecilManager.WriteLog($"Found methodDef: {methodDef.FullName}");

                    if (methodDef.FullName.StartsWith("System.Void HBS.Data.DataLoader::LoadResource"))
                    {
                        CecilManager.WriteLog($"Found injection point: {methodDef.FullName}\n");
                        targetIdx = i;
                    }
                }
            }
            if (targetIdx != -1)
            {
                // Replace callvirt for dataManager.dataLoader.LoadResource with call to AsyncJsonLoadRequest
                method.Body.Instructions[targetIdx] = ilProcessor.Create(OpCodes.Call, ajlr_lr_Imported_MR);

                // Elminate references to dataLoader (no longer used)
                method.Body.Instructions[targetIdx - 9].OpCode  = OpCodes.Nop;
                method.Body.Instructions[targetIdx - 9].Operand = null;

                method.Body.Instructions[targetIdx - 8].OpCode  = OpCodes.Nop;
                method.Body.Instructions[targetIdx - 8].Operand = null;

                method.Body.Instructions[targetIdx - 7].OpCode  = OpCodes.Nop;
                method.Body.Instructions[targetIdx - 7].Operand = null;

                // Add a pop to remove the async Task (to eliminate dnSpy decompile err)
                Instruction popInst = ilProcessor.Create(OpCodes.Pop);
                ilProcessor.InsertAfter(method.Body.Instructions[targetIdx], popInst);
            }
        }
Exemplo n.º 14
0
        public InstructionBlock CreateThisVariable(VariableDefinition instanceVariable,
                                                   TypeReference objectTypeReference)
        {
            if (_method.IsStatic)
            {
                return(new InstructionBlock("Static method call: " + _method.Name, _processor.Create(OpCodes.Nop)));
            }

            var loadThisInstruction  = _processor.Create(OpCodes.Ldarg_0);
            var castInstruction      = _processor.Create(OpCodes.Castclass, objectTypeReference);
            var storeThisInstruction = _processor.Create(OpCodes.Stloc, instanceVariable);

            return(new InstructionBlock(
                       "Store instance for: " + _method.Name,
                       loadThisInstruction,
                       castInstruction,
                       storeThisInstruction));
        }
Exemplo n.º 15
0
        void GenerateDeSerialization()
        {
            Weaver.DLog(netBehaviourSubclass, "  GenerateDeSerialization");

            foreach (MethodDefinition m in netBehaviourSubclass.Methods)
            {
                if (m.Name == "OnDeserialize")
                {
                    return;
                }
            }

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

            MethodDefinition 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;
            VariableDefinition dirtyBitsLocal = new VariableDefinition(Weaver.int64Type);

            serialize.Body.Variables.Add(dirtyBitsLocal);

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

            if (baseDeserialize != null)
            {
                serWorker.Append(serWorker.Create(OpCodes.Ldarg_0)); // base
                serWorker.Append(serWorker.Create(OpCodes.Ldarg_1)); // reader
                serWorker.Append(serWorker.Create(OpCodes.Ldarg_2)); // initialState
                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.Callvirt, Weaver.NetworkReaderReadPackedUInt64));
            serWorker.Append(serWorker.Create(OpCodes.Stloc_0));

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

            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);
        }
Exemplo n.º 16
0
 private static void GenerateReadLength(ILProcessor worker)
 {
     worker.Append(worker.Create(OpCodes.Ldarg_0));
     worker.Append(worker.Create(OpCodes.Call, GetReadFunc(WeaverTypes.Import <int>())));
     worker.Append(worker.Create(OpCodes.Stloc_0));
 }
Exemplo n.º 17
0
        public override Instruction CreateInstruction(ILProcessor worker, OpCode opcode)
        {
            var mdef = Context as MethodDefinition;

            return(mdef != null?worker.Create(opcode, CecilImporter.Import(mdef.DeclaringType.Module, SelectedOperand, mdef)) : null);
        }
Exemplo n.º 18
0
        private static void GenerateFor(ILProcessor worker, Action body)
        {
            // loop through array and deserialize each element
            // generates code like this
            // for (int i=0; i< length ; i++)
            // {
            //     <body>
            // }
            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);

            body();

            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));
        }
Exemplo n.º 19
0
        public static MethodDefinition GenerateSyncVarSetter(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,
                                                        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(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(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);

            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);
        }
Exemplo n.º 20
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);
        }
Exemplo n.º 21
0
        private static void EmitObjectStoreGeneric(ILProcessor body, TypeReference originalType, TypeReference newType, TypeRewriteContext enclosingType, int argumentIndex)
        {
            // input stack: object address, target address
            // output: nothing

            var imports = enclosingType.AssemblyContext.Imports;

            body.Emit(OpCodes.Ldtoken, newType);
            body.Emit(OpCodes.Call, enclosingType.NewType.Module.ImportReference(imports.Type.Methods.Single(it => it.Name == nameof(Type.GetTypeFromHandle))));
            body.Emit(OpCodes.Dup);
            body.Emit(OpCodes.Callvirt, enclosingType.NewType.Module.ImportReference(imports.Type.Methods.Single(it => it.Name == typeof(Type).GetProperty(nameof(Type.IsValueType)) !.GetMethod !.Name)));

            var finalNop        = body.Create(OpCodes.Nop);
            var stringNop       = body.Create(OpCodes.Nop);
            var valueTypeNop    = body.Create(OpCodes.Nop);
            var storePointerNop = body.Create(OpCodes.Nop);

            body.Emit(OpCodes.Brtrue, valueTypeNop);

            body.Emit(OpCodes.Callvirt, enclosingType.NewType.Module.ImportReference(imports.Type.Methods.Single(it => it.Name == typeof(Type).GetProperty(nameof(Type.FullName)) !.GetMethod !.Name)));
            body.Emit(OpCodes.Ldstr, "System.String");
            body.Emit(OpCodes.Call, enclosingType.NewType.Module.ImportReference(TargetTypeSystemHandler.String.Methods.Single(it => it.Name == nameof(String.Equals) && it.IsStatic && it.Parameters.Count == 2)));
            body.Emit(OpCodes.Brtrue_S, stringNop);

            body.Emit(OpCodes.Ldarg, argumentIndex);
            body.Emit(OpCodes.Box, newType);
            body.Emit(OpCodes.Isinst, imports.Il2CppObjectBase);
            body.Emit(OpCodes.Call, imports.Il2CppObjectBaseToPointer);
            body.Emit(OpCodes.Dup);
            body.Emit(OpCodes.Brfalse_S, storePointerNop);

            body.Emit(OpCodes.Dup);
            body.Emit(OpCodes.Call, imports.ObjectGetClass);
            body.Emit(OpCodes.Call, imports.ClassIsValueType);
            body.Emit(OpCodes.Brfalse_S, storePointerNop);

            body.Emit(OpCodes.Dup);
            var tempLocal = new VariableDefinition(imports.IntPtr);

            body.Body.Variables.Add(tempLocal);
            body.Emit(OpCodes.Stloc, tempLocal);
            body.Emit(OpCodes.Call, imports.ObjectUnbox);
            body.Emit(OpCodes.Ldloc, tempLocal);
            body.Emit(OpCodes.Call, imports.ObjectGetClass);
            body.Emit(OpCodes.Ldc_I4_0);
            body.Emit(OpCodes.Conv_U);
            body.Emit(OpCodes.Call, imports.ValueSizeGet);
            body.Emit(OpCodes.Cpblk);
            body.Emit(OpCodes.Pop);
            body.Emit(OpCodes.Br_S, finalNop);

            body.Append(storePointerNop);
            body.Emit(OpCodes.Call, imports.WriteFieldWBarrier);
            body.Emit(OpCodes.Br_S, finalNop);

            body.Append(stringNop);
            body.Emit(OpCodes.Ldarg, argumentIndex);
            body.Emit(OpCodes.Box, newType);
            body.Emit(OpCodes.Isinst, imports.String);
            body.Emit(OpCodes.Call, imports.StringToNative);
            body.Emit(OpCodes.Call, imports.WriteFieldWBarrier);
            body.Emit(OpCodes.Br_S, finalNop);

            body.Append(valueTypeNop);
            body.Emit(OpCodes.Pop); // pop extra typeof(T)
            body.Emit(OpCodes.Ldarg, argumentIndex);
            body.Emit(OpCodes.Stobj, newType);
            body.Emit(OpCodes.Pop);

            body.Append(finalNop);
        }
Exemplo n.º 22
0
 public static void WriteCreateWriter(ILProcessor worker)
 {
     // create writer
     worker.Append(worker.Create(OpCodes.Newobj, Weaver.NetworkWriterCtor));
     worker.Append(worker.Create(OpCodes.Stloc_0));
 }
Exemplo n.º 23
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);
                getWorker.Append(getWorker.Create(OpCodes.Ldarg_0)); // this.
                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);
                getWorker.Append(getWorker.Create(OpCodes.Ldarg_0)); // this.
                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);
        }
Exemplo n.º 24
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      = null;
            bool             cctorFound = false;

            foreach (MethodDefinition md in netBehaviourSubclass.Methods)
            {
                if (md.Name == ".cctor")
                {
                    cctor      = md;
                    cctorFound = true;
                }
            }
            if (cctor != null)
            {
                // remove the return opcode from end of function. will add our own later.
                if (cctor.Body.Instructions.Count != 0)
                {
                    Instruction ret = cctor.Body.Instructions[cctor.Body.Instructions.Count - 1];
                    if (ret.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 = null;

            foreach (MethodDefinition md in netBehaviourSubclass.Methods)
            {
                if (md.Name == ".ctor")
                {
                    ctor = md;

                    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;
                    }

                    break;
                }
            }

            if (ctor == null)
            {
                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;
        }
Exemplo n.º 25
0
        private void ReplaceFixedArrayStatement(MethodDefinition Method, ILProcessor IlProcessor, Instruction fixedtoPatch)
        {
            TypeReference ParamT = ((GenericInstanceMethod)fixedtoPatch.Operand).GenericArguments[0];

            // Preparing locals
            // local(0) T*
            Method.Body.Variables.Add(new VariableDefinition("pin", new PinnedType(new ByReferenceType(ParamT))));

            Int32 Index = Method.Body.Variables.Count - 1;

            Instruction LdlocFixed;
            Instruction StlocFixed;

            switch (Index)
            {
                case 0:
                    StlocFixed = IlProcessor.Create(OpCodes.Stloc_0);
                    LdlocFixed = IlProcessor.Create(OpCodes.Ldloc_0);
                    break;
                case 1:
                    StlocFixed = IlProcessor.Create(OpCodes.Stloc_1);
                    LdlocFixed = IlProcessor.Create(OpCodes.Ldloc_1);
                    break;
                case 2:
                    StlocFixed = IlProcessor.Create(OpCodes.Stloc_2);
                    LdlocFixed = IlProcessor.Create(OpCodes.Ldloc_2);
                    break;
                case 3:
                    StlocFixed = IlProcessor.Create(OpCodes.Stloc_3);
                    LdlocFixed = IlProcessor.Create(OpCodes.Ldloc_3);
                    break;
                default:
                    StlocFixed = IlProcessor.Create(OpCodes.Stloc, Index);
                    LdlocFixed = IlProcessor.Create(OpCodes.Ldloc, Index);
                    break;
            }

            Instruction InstructionLdci40 = IlProcessor.Create(OpCodes.Ldc_I4_0);
            IlProcessor.InsertBefore(fixedtoPatch, InstructionLdci40);

            Instruction InstructionLdElema = IlProcessor.Create(OpCodes.Ldelema, ParamT);
            IlProcessor.InsertBefore(fixedtoPatch, InstructionLdElema);
            IlProcessor.InsertBefore(fixedtoPatch, StlocFixed);
            IlProcessor.Replace(fixedtoPatch, LdlocFixed);
        }
Exemplo n.º 26
0
        void GenerateSerialization()
        {
            Weaver.DLog(netBehaviourSubclass, "  GenerateSerialization");

            foreach (MethodDefinition m in netBehaviourSubclass.Methods)
            {
                if (m.Name == "OnSerialize")
                {
                    return;
                }
            }

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

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

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

            serialize.Body.Variables.Add(dirtyLocal);

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

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

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

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

            foreach (FieldDefinition syncVar in syncVars)
            {
                // Generates a writer call for each sync variable
                serWorker.Append(serWorker.Create(OpCodes.Ldarg_1)); // writer
                serWorker.Append(serWorker.Create(OpCodes.Ldarg_0)); // this
                serWorker.Append(serWorker.Create(OpCodes.Ldfld, syncVar));
                MethodReference writeFunc = 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 ());
            serWorker.Append(serWorker.Create(OpCodes.Ldarg_1)); // writer
            serWorker.Append(serWorker.Create(OpCodes.Ldarg_0)); // base
            serWorker.Append(serWorker.Create(OpCodes.Call, Weaver.NetworkBehaviourDirtyBitsReference));
            serWorker.Append(serWorker.Create(OpCodes.Callvirt, Weaver.NetworkWriterWritePackedUInt64));

            // 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)
                serWorker.Append(serWorker.Create(OpCodes.Ldarg_0));                // base
                serWorker.Append(serWorker.Create(OpCodes.Call, Weaver.NetworkBehaviourDirtyBitsReference));
                serWorker.Append(serWorker.Create(OpCodes.Ldc_I8, 1L << dirtyBit)); // 8 bytes = long
                serWorker.Append(serWorker.Create(OpCodes.And));
                serWorker.Append(serWorker.Create(OpCodes.Brfalse, varLabel));

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

                MethodReference writeFunc = 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));
                serWorker.Append(serWorker.Create(OpCodes.Stloc_0)); // set dirtyLocal to true

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

            if (Weaver.GenerateLogErrors)
            {
                serWorker.Append(serWorker.Create(OpCodes.Ldstr, "Injected Serialize " + 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);
        }
Exemplo n.º 27
0
        static void GenerateSerialization(TypeDefinition td)
        {
            Weaver.DLog(td, "  GenerateSerialization");
            MethodDefinition existingMethod = td.GetMethodWith1Arg("Serialize", WeaverTypes.Import <NetworkWriter>());

            // do nothing if method exists and is abstract or not empty
            if (existingMethod != null && (existingMethod.IsAbstract || !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.Name} has field {field.Name} that references itself", field);
                    return;
                }
            }

            MethodDefinition serializeFunc = existingMethod ?? new MethodDefinition("Serialize",
                                                                                    MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.HideBySig,
                                                                                    WeaverTypes.Import(typeof(void)));

            //only add to new method
            if (existingMethod == null)
            {
                serializeFunc.Parameters.Add(new ParameterDefinition("writer", ParameterAttributes.None, WeaverTypes.Import <NetworkWriter>()));
            }
            ILProcessor worker = serializeFunc.Body.GetILProcessor();

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

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

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

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

            //only add if not just replaced body
            if (existingMethod == null)
            {
                td.Methods.Add(serializeFunc);
            }
        }
Exemplo n.º 28
0
        void DeserializeField(FieldDefinition syncVar, ILProcessor serWorker, MethodDefinition deserialize)
        {
            // check for Hook function
            if (!SyncVarProcessor.CheckForHookFunction(netBehaviourSubclass, syncVar, out MethodDefinition foundMethod))
            {
                return;
            }

            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];

                VariableDefinition tmpValue = new VariableDefinition(Weaver.uint32Type);
                deserialize.Body.Variables.Add(tmpValue);

                // read id and store in a local variable
                serWorker.Append(serWorker.Create(OpCodes.Ldarg_1));
                serWorker.Append(serWorker.Create(OpCodes.Call, Weaver.NetworkReaderReadPackedUInt32));
                serWorker.Append(serWorker.Create(OpCodes.Stloc, tmpValue));

                if (foundMethod != null)
                {
                    // call Hook(this.GetSyncVarGameObject/NetworkIdentity(reader.ReadPackedUInt32()))
                    // because we send/receive the netID, not the GameObject/NetworkIdentity
                    serWorker.Append(serWorker.Create(OpCodes.Ldarg_0)); // this.
                    serWorker.Append(serWorker.Create(OpCodes.Ldarg_0));
                    serWorker.Append(serWorker.Create(OpCodes.Ldloc, tmpValue));
                    serWorker.Append(serWorker.Create(OpCodes.Ldarg_0));
                    serWorker.Append(serWorker.Create(OpCodes.Ldflda, syncVar));
                    if (syncVar.FieldType.FullName == Weaver.gameObjectType.FullName)
                    {
                        serWorker.Append(serWorker.Create(OpCodes.Callvirt, Weaver.getSyncVarGameObjectReference));
                    }
                    else if (syncVar.FieldType.FullName == Weaver.NetworkIdentityType.FullName)
                    {
                        serWorker.Append(serWorker.Create(OpCodes.Callvirt, Weaver.getSyncVarNetworkIdentityReference));
                    }
                    serWorker.Append(serWorker.Create(OpCodes.Call, foundMethod));
                }
                // set the netid field
                serWorker.Append(serWorker.Create(OpCodes.Ldarg_0));
                serWorker.Append(serWorker.Create(OpCodes.Ldloc, tmpValue));
                serWorker.Append(serWorker.Create(OpCodes.Stfld, netIdField));
            }
            else
            {
                MethodReference readFunc = Readers.GetReadFunc(syncVar.FieldType);
                if (readFunc == null)
                {
                    Weaver.Error($"{syncVar} has unsupported type. Use a supported Mirror type instead");
                    return;
                }
                VariableDefinition tmpValue = new VariableDefinition(syncVar.FieldType);
                deserialize.Body.Variables.Add(tmpValue);

                // read value and put it in a local variable
                serWorker.Append(serWorker.Create(OpCodes.Ldarg_1));
                serWorker.Append(serWorker.Create(OpCodes.Call, readFunc));
                serWorker.Append(serWorker.Create(OpCodes.Stloc, tmpValue));

                if (foundMethod != null)
                {
                    // call hook
                    serWorker.Append(serWorker.Create(OpCodes.Ldarg_0));
                    serWorker.Append(serWorker.Create(OpCodes.Ldloc, tmpValue));
                    serWorker.Append(serWorker.Create(OpCodes.Call, foundMethod));
                }
                // set the property
                serWorker.Append(serWorker.Create(OpCodes.Ldarg_0));
                serWorker.Append(serWorker.Create(OpCodes.Ldloc, tmpValue));
                serWorker.Append(serWorker.Create(OpCodes.Stfld, syncVar));
            }
        }
Exemplo n.º 29
0
        static MethodDefinition GenerateArrayReadFunc(TypeReference variable, int recursionCount)
        {
            if (!variable.IsArrayType())
            {
                Weaver.Error($"{variable} is an unsupported type. Jagged and multidimensional arrays are not supported");
                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);
        }
Exemplo n.º 30
0
        public static void Weave(ModuleDefinition module, Dictionary <ushort, MethodDefinition> methods, TypeDefinition protocol)
        {
            if (module == null || methods.Count == 0 || protocol == null)
            {
                return;
            }

            FieldReference connectionField = module.ImportReference(ResolveHelper.ResolveField(protocol.BaseType, "m_Connection"));
            {
                //public void Register();
                MethodDefinition registerMethod = ResolveHelper.ResolveMethod(protocol, "Register");
                registerMethod.Body.Variables.Clear();
                registerMethod.Body.Instructions.Clear();

                ILProcessor registerProcessor = registerMethod.Body.GetILProcessor();
                registerProcessor.Append(registerProcessor.Create(OpCodes.Nop));

                foreach (ushort key in methods.Keys)
                {
                    MethodDefinition method = methods[key];

                    if (!CheckHelper.CheckMethodFirstParams(WeaverProgram.Server, method))
                    {
                        continue;
                    }

                    MethodDefinition protoMethodImpl = MethodFactory.CreateMethod(module, protocol, "OnProtocol_" + key, MethodAttributes.Private | MethodAttributes.HideBySig, true);
                    protoMethodImpl.Parameters.Add(new ParameterDefinition("msg", ParameterAttributes.None, module.ImportReference(WeaverProgram.ChannelMessageType)));
                    protoMethodImpl.Body.Variables.Add(new VariableDefinition(module.ImportReference(WeaverProgram.ByteBufferType)));

                    {
                        ILProcessor processor = protoMethodImpl.Body.GetILProcessor();
                        processor.Append(processor.Create(OpCodes.Nop));
                        processor.Append(processor.Create(OpCodes.Ldarg_1));
                        processor.Append(processor.Create(OpCodes.Ldfld, module.ImportReference(WeaverProgram.ChannelMessageBufferField)));
                        processor.Append(processor.Create(OpCodes.Stloc_0));

                        List <int> indexs = new List <int>();
                        Collection <ParameterDefinition> parms = method.Parameters;
                        for (int i = 0; i < parms.Count; ++i)
                        {
                            if (i > 0)
                            {
                                ParameterDefinition parm     = parms[i];
                                TypeDefinition      parmType = parm.ParameterType.Resolve();
                                protoMethodImpl.Body.Variables.Add(new VariableDefinition(module.ImportReference(parm.ParameterType)));

                                int index = protoMethodImpl.Body.Variables.Count - 1;
                                indexs.Add(index);

                                if (parm.ParameterType.FullName == typeof(byte[]).FullName)
                                {
                                    processor.Append(processor.Create(OpCodes.Ldloc_0));
                                    processor.Append(processor.Create(OpCodes.Call, module.ImportReference(WeaverProgram.ByteUtilsReadMethod)));
                                    processor.Append(processor.Create(OpCodes.Stloc, index));
                                    continue;
                                }

                                if (parm.ParameterType.FullName == typeof(ByteBuffer).FullName)
                                {
                                    processor.Append(processor.Create(OpCodes.Ldloc_0));
                                    processor.Append(processor.Create(OpCodes.Call, module.ImportReference(WeaverProgram.ByteBufferUtilsReadMethod)));
                                    processor.Append(processor.Create(OpCodes.Stloc, index));
                                    continue;
                                }

                                if (parm.ParameterType.IsArray)
                                {
                                    ArrayReadFactory.CreateMethodVariableReadInstruction(module, protoMethodImpl, processor, parmType);
                                    continue;
                                }

                                if (BaseTypeFactory.IsBaseType(parmType))
                                {
                                    processor.Append(processor.Create(OpCodes.Ldloc_0));
                                    processor.Append(BaseTypeFactory.CreateReadInstruction(module, processor, parmType));
                                    processor.Append(processor.Create(OpCodes.Stloc, index));
                                    continue;
                                }

                                if (parmType.IsValueType)
                                {
                                    MethodDefinition deserialize = StructMethodFactory.CreateDeserialize(module, parmType);
                                    processor.Append(processor.Create(OpCodes.Ldloca, index));
                                    processor.Append(processor.Create(OpCodes.Initobj, module.ImportReference(parmType)));
                                    processor.Append(processor.Create(OpCodes.Ldloca, index));
                                    processor.Append(processor.Create(OpCodes.Ldloc_0));
                                    processor.Append(processor.Create(OpCodes.Call, module.ImportReference(deserialize)));
                                }
                            }
                        }

                        processor.Append(processor.Create(OpCodes.Ldarg_0));
                        processor.Append(processor.Create(OpCodes.Ldfld, connectionField));

                        for (int i = 0; i < indexs.Count; ++i)
                        {
                            processor.Append(processor.Create(OpCodes.Ldloc, indexs[i]));
                        }

                        processor.Append(processor.Create(OpCodes.Call, method));
                        processor.Append(processor.Create(OpCodes.Nop));
                        processor.Append(processor.Create(OpCodes.Ret));
                    }

                    registerProcessor.Append(registerProcessor.Create(OpCodes.Ldarg_0));
                    registerProcessor.Append(registerProcessor.Create(OpCodes.Ldfld, connectionField));
                    registerProcessor.Append(registerProcessor.Create(OpCodes.Ldc_I4, key));
                    registerProcessor.Append(registerProcessor.Create(OpCodes.Ldarg_0));
                    registerProcessor.Append(registerProcessor.Create(OpCodes.Ldftn, protoMethodImpl));
                    registerProcessor.Append(registerProcessor.Create(OpCodes.Newobj, module.ImportReference(typeof(ChannelMessageDelegate).GetConstructor(new Type[] { typeof(object), typeof(IntPtr) }))));
                    registerProcessor.Append(registerProcessor.Create(OpCodes.Callvirt, module.ImportReference(WeaverProgram.IConnectionRegisterHandlerMethod)));
                }

                registerProcessor.Append(registerProcessor.Create(OpCodes.Ret));
            }

            {
                //public void Unregister();
                MethodDefinition unregisterMethod = ResolveHelper.ResolveMethod(protocol, "UnRegister");
                unregisterMethod.Body.Variables.Clear();
                unregisterMethod.Body.Instructions.Clear();

                ILProcessor unregisterProcessor = unregisterMethod.Body.GetILProcessor();
                unregisterProcessor.Append(unregisterProcessor.Create(OpCodes.Nop));
                foreach (short key in methods.Keys)
                {
                    unregisterProcessor.Append(unregisterProcessor.Create(OpCodes.Ldarg_0));
                    unregisterProcessor.Append(unregisterProcessor.Create(OpCodes.Ldfld, connectionField));
                    unregisterProcessor.Append(unregisterProcessor.Create(OpCodes.Ldc_I4, key));
                    unregisterProcessor.Append(unregisterProcessor.Create(OpCodes.Callvirt, module.ImportReference(WeaverProgram.IConnectionUnregisterHandlerMethod)));
                }
                unregisterProcessor.Append(unregisterProcessor.Create(OpCodes.Ret));
            }
        }