Beispiel #1
0
        /// <summary>
        /// Patches the specified assembly.
        /// </summary>
        /// <param name="args">Information about the assembly to patch.</param>
        public override void Patch(PatcherArguments args)
        {
            // Step 1: Get type definitions for the target type (specified in the configs) and Hooks from appropriate assemblies.
            TypeDefinition targetTypeDefinition = args.Assembly.MainModule.GetType(targetType);
            TypeDefinition hooksType            = hookAssembly.MainModule.GetType("ExMultiGame.Hook.Hooks");

            // Step 2: Get method definition for the target method (specified in the configs) and hook method (PrintHelloWorld).
            MethodDefinition targetMethodDefinition = targetTypeDefinition.Methods.FirstOrDefault(m => m.Name == targetMethod);
            MethodDefinition printHelloWorldMethod  = hooksType.Methods.FirstOrDefault(m => m.Name == "PrintHelloWorld");

            // Step 2.1: Import PrintHelloWorld method into the module where the target type is.
            // This is needed to ensure that the target assembly will know where to find PrintHelloWorld method.
            MethodReference printHelloWorldReference = targetMethodDefinition.Module.Import(printHelloWorldMethod);

            // Step 3: Perform patching.
            // Here we get the first instruction from the target method and an instance of ILProcessor to simplify IL manipulation.
            Instruction startInstruction = targetMethodDefinition.Body.Instructions[0];
            ILProcessor il = targetMethodDefinition.Body.GetILProcessor();

            // Insert a call to PrintHelloWorld. Since we don't need to pass any parameters, we don't need to add any more instructions.
            il.InsertBefore(startInstruction, il.Create(OpCodes.Call, printHelloWorldReference));

            // Step 4: Add pacher attribute.
            // Finally you must ALWAYS add the patcher tag to mark the asembly as patched.
            // This tag is used in CanPatch(PatcherArguments args) method above to check if the assembly requires patching.
            SetPatchedAttribute(args.Assembly, PATCHED_TAG);
        }
        public override void Patch(PatcherArguments args)
        {
            // Step 1: Get type definitions for SceneLogo and Hooks from appropriate assemblies.
            TypeDefinition maidType      = args.Assembly.MainModule.GetType("Maid");
            TypeDefinition maidParamType = args.Assembly.MainModule.GetType("MaidParam");
            TypeDefinition hooksType     = hookAssembly.MainModule.GetType("CM3D2.ExHelloWorld.Hook.Hooks");

            // Step 2: Get method definition for the target method (Start) and hook method (PrintHelloWorld).
            MethodDefinition crossFadeMethod    = maidType.Methods.FirstOrDefault(m => m.Name == "CrossFade");
            MethodDefinition setCurExciteMethod = maidParamType.Methods.FirstOrDefault(m => m.Name == "SetCurExcite");

            MethodDefinition crossFadeHookMethod   = hooksType.Methods.FirstOrDefault(m => m.Name == "CrossFadeHook");
            MethodDefinition setCurExciteMaxMethod = hooksType.Methods.FirstOrDefault(m => m.Name == "SetCurExciteMax");

            // Step 2.1: Import hook methods into the module where target types are.
            // This is needed to ensure that the target assembly (Assembly-CSharp) will know where to find the hook methods.
            MethodReference crossFadeHookReference   = crossFadeMethod.Module.Import(crossFadeHookMethod);
            MethodReference setCurExciteMaxReference = setCurExciteMethod.Module.Import(setCurExciteMaxMethod);

            // Step 3.1: Perform patching (CrossFade).
            // Here we get the first instruction from CrossFade method and an instance of ILProcessor to simplify IL manipulation.
            Instruction startInstruction = crossFadeMethod.Body.Instructions[0];
            ILProcessor il = crossFadeMethod.Body.GetILProcessor();

            // Firstly, push method's parameters onto the evaluation stack.
            // Since CrossFade is not static ldarg.0 will push the value of "this" onto the evaluation stack.
            // ldarg.1-6 will load method's other parameters.
            il.InsertBefore(startInstruction, il.Create(OpCodes.Ldarg_0));
            il.InsertBefore(startInstruction, il.Create(OpCodes.Ldarg_1));
            il.InsertBefore(startInstruction, il.Create(OpCodes.Ldarg_2));
            il.InsertBefore(startInstruction, il.Create(OpCodes.Ldarg_3));
            il.InsertBefore(startInstruction, il.Create(OpCodes.Ldarg_S, 4));
            il.InsertBefore(startInstruction, il.Create(OpCodes.Ldarg_S, 5));
            il.InsertBefore(startInstruction, il.Create(OpCodes.Ldarg_S, 6));
            // Finally, we insert the call to CrossFadeHook method
            il.InsertBefore(startInstruction, il.Create(OpCodes.Call, crossFadeHookReference));

            // Step 3.2: Perform patching (SetCurExcite).
            // Here we get the last instruction (ret) from SetCurExcite method and an instance of ILProcessor to simplify IL manipulation.
            startInstruction = setCurExciteMethod.Body.Instructions[setCurExciteMethod.Body.Instructions.Count - 1];
            il = setCurExciteMethod.Body.GetILProcessor();

            // Get reference to the status_ field defined in MaidParam. Since the field is defined in the same assembly as SetCurExcite, there is no need to explicitly import the field.
            FieldReference statusField = maidParamType.Fields.FirstOrDefault(f => f.Name == "status_");

            // Firstly we get the value of status_. Since it is an instance field, we first use ldarg.0 to get "this" and then ldfld to get the value of status_ for "this".
            il.InsertBefore(startInstruction, il.Create(OpCodes.Ldarg_0));
            il.InsertBefore(startInstruction, il.Create(OpCodes.Ldfld, statusField));
            // Finally we call SetCurExciteMax itself.
            il.InsertBefore(startInstruction, il.Create(OpCodes.Call, setCurExciteMaxReference));

            // Step 4: Add pacher attribute.
            // Finally you must ALWAYS add the patcher tag to mark the asembly as patched.
            // This tag is used in CanPatch(PatcherArguments args) method above to check if the assembly requires patching.
            SetPatchedAttribute(args.Assembly, PATCHED_TAG);
        }
        public override void Patch(PatcherArguments args)
        {
            var mod = args.Assembly.MainModule;

            var type = mod.GetType("GameUty");
            var meth = type.Methods.First(def => def.Name == ".cctor");

            meth.Body.Instructions.First(ins => ins.OpCode == OpCodes.Stsfld
                                                && ((FieldReference) ins.Operand).Name == "ModPriorityToModFolder")
                .Previous.OpCode = OpCodes.Ldc_I4_1; // Pop a true instead

            SetPatchedAttribute(args.Assembly, TOKEN);
        }
        public override bool CanPatch(PatcherArguments args)
        {
            if (args.Assembly.Name.Name != "Assembly-CSharp")
                return false;

            if (GetPatchedAttributes(args.Assembly).Any(attribute => attribute.Info == TOKEN))
            {
                Console.ForegroundColor = ConsoleColor.Yellow;
                Console.WriteLine("Assembly Already Patched");
                Console.ForegroundColor = ConsoleColor.Gray;
                return false;
            }
            return true;
        }
      public override void Patch( PatcherArguments args )
      {
         var PluginLoader = _hookAssembly.MainModule.GetType( "XUnity.AutoTranslator.Plugin.Core.PluginLoader" );
         var LoadThroughBootstrapper = PluginLoader.GetMethod( "LoadThroughBootstrapper" );

         var entryClasses = args.Assembly.MainModule.GetTypes().Where( x => EntryClasses.Contains( x.Name ) ).ToList();
         foreach( var entryClass in entryClasses )
         {
            var staticCtor = entryClass.Methods.FirstOrDefault( x => x.IsStatic && x.IsConstructor );
            if( staticCtor != null )
            {
               var injecctor = new InjectionDefinition( staticCtor, LoadThroughBootstrapper, InjectFlags.None );
               injecctor.Inject(
                  startCode: 0,
                  direction: InjectDirection.Before );
            }
         }

         SetPatchedAttribute( args.Assembly, "XUnity.AutoTranslator.Plugin.Core" );
      }
 public override bool CanPatch(PatcherArguments args)
 {
     return((args.Assembly.Name.Name == _assemblyName) && !HasAttribute(this, args.Assembly, "XUnity.AutoTranslator.Plugin.Core"));
 }
        public override void Patch(PatcherArguments args)
        {
            TypeDefinition gameMainType = args.Assembly.MainModule.GetType("GameMain");
            TypeDefinition maidParam = args.Assembly.MainModule.GetType("MaidParam");
            TypeDefinition maidType = args.Assembly.MainModule.GetType("Maid");
            TypeDefinition scheduleAPI = args.Assembly.MainModule.GetType("Schedule.ScheduleAPI");
            TypeDefinition daytimeTaskCtrl = args.Assembly.MainModule.GetType("DaytimeTaskCtrl");
            TypeDefinition nightTaskCtrl = args.Assembly.MainModule.GetType("NightTaskCtrl");
            TypeDefinition playerParam = args.Assembly.MainModule.GetType("PlayerParam");
            TypeDefinition yotogiPlayMgr = args.Assembly.MainModule.GetType("YotogiPlayManager");
            TypeDefinition wf = args.Assembly.MainModule.GetType("wf");
            TypeDefinition status = args.Assembly.MainModule.GetType("param.Status");
            TypeDefinition skillData =
            args.Assembly.MainModule.GetType("Yotogi").NestedTypes.FirstOrDefault(t => t.Name == "SkillData");

            TypeDefinition hookType = FiddlerAssembly.MainModule.GetType("CM3D2.MaidFiddler.Hook.FiddlerHooks");
            TypeDefinition maidHooks = FiddlerAssembly.MainModule.GetType(
            "CM3D2.MaidFiddler.Hook.MaidStatusChangeHooks");
            TypeDefinition playerHooks =
            FiddlerAssembly.MainModule.GetType("CM3D2.MaidFiddler.Hook.PlayerStatusChangeHooks");
            TypeDefinition valueLimitHooks = FiddlerAssembly.MainModule.GetType(
            "CM3D2.MaidFiddler.Hook.ValueLimitHooks");

            gameMainType.GetMethod("Deserialize")
                        .GetInjector(hookType, "OnSaveDeserialize", InjectFlags.PassParametersVal)
                        .Inject(-1);

            // Maid hooks
            MethodDefinition statusChangeHook = maidHooks.GetMethod(nameof(MaidStatusChangeHooks.OnStatusChanged));
            MethodDefinition propertyGetHook = maidHooks.GetMethod(nameof(MaidStatusChangeHooks.OnNewPropertyGet));
            MethodDefinition statusChangeIDHook1 = maidHooks.GetMethod(
            nameof(MaidStatusChangeHooks.OnStatusChangedID),
            typeof (int),
            typeof (Maid).MakeByRefType(),
            typeof (int));
            MethodDefinition statusChangeIDHook2 = maidHooks.GetMethod(
            nameof(MaidStatusChangeHooks.OnStatusChangedID),
            typeof (int),
            typeof (Maid).MakeByRefType(),
            typeof (int),
            typeof (int));
            MethodDefinition propertyRemovedHook = maidHooks.GetMethod(nameof(MaidStatusChangeHooks.OnPropertyRemoved));
            MethodDefinition statusUpdateHook = maidHooks.GetMethod(nameof(MaidStatusChangeHooks.OnStatusUpdate));
            MethodDefinition maidYotogiUpdateHook =
            maidHooks.GetMethod(nameof(MaidStatusChangeHooks.OnMaidClassAndYotogiUpdate));
            MethodDefinition classUpdateHook = maidHooks.GetMethod(nameof(MaidStatusChangeHooks.OnClassTypeUpdate));
            MethodDefinition skillExpAddedHook = maidHooks.GetMethod(nameof(MaidStatusChangeHooks.OnSkillExpAdded));
            MethodDefinition thumbnailChangedHook = maidHooks.GetMethod(
            nameof(MaidStatusChangeHooks.OnThumbnailChanged));
            MethodDefinition noonWorkEnableCheckHook =
            maidHooks.GetMethod(nameof(MaidStatusChangeHooks.OnNoonWorkEnableCheck));
            MethodDefinition nightWorkEnableCheckHook =
            maidHooks.GetMethod(nameof(MaidStatusChangeHooks.OnNightWorkEnableCheck));
            MethodDefinition reloadNoonWorkDataHook =
            maidHooks.GetMethod(nameof(MaidStatusChangeHooks.ReloadNoonWorkData));
            MethodDefinition reloadNightWorkDataHook =
            maidHooks.GetMethod(nameof(MaidStatusChangeHooks.ReloadNightWorkData));
            MethodDefinition featurePropensityUpdatedHook =
            maidHooks.GetMethod(nameof(MaidStatusChangeHooks.OnFeaturePropensityUpdated));
            MethodDefinition nightWorkVisCheckHook =
            maidHooks.GetMethod(nameof(MaidStatusChangeHooks.CheckNightWorkVisibility));
            MethodDefinition yotogiSkillVisCheckHook =
            maidHooks.GetMethod(nameof(MaidStatusChangeHooks.OnYotogiSkillVisibilityCheck));

            MethodDefinition onValueRoundInt1 = valueLimitHooks.GetMethod(
            nameof(ValueLimitHooks.OnValueRound),
            typeof (int).MakeByRefType(),
            typeof (int));
            MethodDefinition onValueRoundLong1 = valueLimitHooks.GetMethod(
            nameof(ValueLimitHooks.OnValueRound),
            typeof (long).MakeByRefType(),
            typeof (long));
            MethodDefinition onValueRoundInt3 = valueLimitHooks.GetMethod(
            nameof(ValueLimitHooks.OnValueRound),
            typeof (int).MakeByRefType(),
            typeof (int),
            typeof (int),
            typeof (int));
            MethodDefinition onValueRoundLong3 = valueLimitHooks.GetMethod(
            nameof(ValueLimitHooks.OnValueRound),
            typeof (long).MakeByRefType(),
            typeof (long),
            typeof (long),
            typeof (long));


            // Player hooks
            MethodDefinition playerStatChangeHook =
            playerHooks.GetMethod(nameof(PlayerStatusChangeHooks.OnPlayerStatChanged));

            const InjectFlags features1 = InjectFlags.PassTag | InjectFlags.PassFields | InjectFlags.ModifyReturn;
            const InjectFlags features2 = features1 | InjectFlags.PassParametersVal;
            const InjectFlags features3 = InjectFlags.PassFields | InjectFlags.PassTag;


            string[] typeNames = Enum.GetNames(typeof (MaidChangeType));

            Console.WriteLine("Pathichg basic Add/Set methods:");

            for (int i = (int) MaidChangeType.Care; i <= (int) MaidChangeType.TotalEvaluation; i++)
            {
                WritePreviousLine($"Add{typeNames[i]}");
                maidParam.GetMethod($"Add{typeNames[i]}")
                         .InjectWith(statusChangeHook, 0, i, features1, typeFields: new[] {maidParam.GetField("maid_")});

                WritePreviousLine($"Set{typeNames[i]}");
                maidParam.GetMethod($"Set{typeNames[i]}")
                         .InjectWith(statusChangeHook, 0, i, features1, typeFields: new[] {maidParam.GetField("maid_")});
            }

            for (int i = (int) MaidChangeType.FirstName; i <= (int) MaidChangeType.Seikeiken; i++)
            {
                WritePreviousLine($"Set{typeNames[i]}");
                maidParam.GetMethod($"Set{typeNames[i]}")
                         .InjectWith(statusChangeHook, 0, i, features1, typeFields: new[] {maidParam.GetField("maid_")});
            }

            for (int i = (int) MaidChangeType.MaidClassExp; i <= (int) MaidChangeType.YotogiClassExp; i++)
            {
                WritePreviousLine($"Add{typeNames[i]}");
                maidParam.GetMethod($"Add{typeNames[i]}", typeof (int))
                         .InjectWith(statusChangeHook, 0, i, features1, typeFields: new[] {maidParam.GetField("maid_")});
            }

            for (int i = (int) MaidChangeType.SkillPlayCount; i <= (int) MaidChangeType.WorkPlayCount; i++)
            {
                WritePreviousLine($"Add{typeNames[i]}");
                maidParam.GetMethod($"Add{typeNames[i]}")
                         .InjectWith(
                         statusChangeIDHook1,
                         0,
                         i,
                         features2,
                         typeFields: new[] {maidParam.GetField("maid_")});
            }

            WritePreviousLine("UpdateProfileComment");
            maidParam.GetMethod("UpdateProfileComment")
                     .InjectWith(
                     statusChangeHook,
                     0,
                     (int) MaidChangeType.Profile,
                     features1,
                     typeFields: new[] {maidParam.GetField("maid_")});

            WritePreviousLine($"Add{typeNames[(int) MaidChangeType.SkillExp]}");
            maidParam.GetMethod($"Add{typeNames[(int) MaidChangeType.SkillExp]}")
                     .InjectWith(
                     skillExpAddedHook,
                     0,
                     0,
                     InjectFlags.PassFields | InjectFlags.PassParametersVal,
                     typeFields: new[] {maidParam.GetField("maid_")});

            WritePreviousLine($"Set{typeNames[(int) MaidChangeType.WorkLevel]}");
            maidParam.GetMethod($"Set{typeNames[(int) MaidChangeType.WorkLevel]}")
                     .InjectWith(
                     statusChangeIDHook2,
                     0,
                     (int) MaidChangeType.WorkLevel,
                     features2,
                     typeFields: new[] {maidParam.GetField("maid_")});

            WritePreviousLine("SetPropensity");
            PatchFuncEnumBool(MaidChangeType.Propensity, maidParam.GetMethod("SetPropensity"), statusUpdateHook);

            WritePreviousLine("SetFeature");
            PatchFuncEnumBool(MaidChangeType.Feature, maidParam.GetMethod("SetFeature"), statusUpdateHook);

            for (int i = (int) MaidChangeType.NewGetSkill; i <= (int) MaidChangeType.NewGetWork; i++)
            {
                WritePreviousLine($"Set{typeNames[i]}");
                maidParam.GetMethod($"Set{typeNames[i]}")
                         .InjectWith(
                         propertyGetHook,
                         0,
                         i,
                         features3 | InjectFlags.PassParametersVal,
                         typeFields: new[] {maidParam.GetField("maid_")});
            }

            for (int i = (int) MaidChangeType.Skill; i <= (int) MaidChangeType.Work; i++)
            {
                WritePreviousLine($"Remove{typeNames[i]}");
                maidParam.GetMethod($"Remove{typeNames[i]}")
                         .InjectWith(
                         propertyRemovedHook,
                         0,
                         i,
                         features3 | InjectFlags.PassParametersVal,
                         typeFields: new[] {maidParam.GetField("maid_")});
            }

            WritePreviousLine("UpdatetAcquisitionMaidClassType");
            maidParam.GetMethod("UpdatetAcquisitionMaidClassType")
                     .InjectWith(
                     classUpdateHook,
                     0,
                     (int) MaidChangeType.MaidClassType,
                     features3,
                     typeFields: new[] {maidParam.GetField("maid_")});

            WritePreviousLine("UpdatetAcquisitionYotogiClassType");
            maidParam.GetMethod("UpdatetAcquisitionYotogiClassType")
                     .InjectWith(
                     classUpdateHook,
                     0,
                     (int) MaidChangeType.YotogiClassType,
                     features3,
                     typeFields: new[] {maidParam.GetField("maid_")});

            WritePreviousLine("UpdateMaidClassAndYotogiClassStatus");
            maidParam.GetMethod("UpdateMaidClassAndYotogiClassStatus")
                     .InjectWith(
                     maidYotogiUpdateHook,
                     0,
                     0,
                     InjectFlags.PassFields,
                     typeFields: new[] {maidParam.GetField("maid_")});

            WritePreviousLine("AddMaidClassExp");
            PatchFuncEnum(
            MaidChangeType.MaidClassType,
            maidParam.GetMethod("AddMaidClassExp", typeof (MaidClassType), typeof (int)),
            statusChangeIDHook1);

            WritePreviousLine("AddYotogiClassExp");
            PatchFuncEnum(
            MaidChangeType.YotogiClassType,
            maidParam.GetMethod("AddYotogiClassExp", typeof (YotogiClassType), typeof (int)),
            statusChangeIDHook1);

            WritePreviousLine("ThumShot");
            maidType.GetMethod("ThumShot").InjectWith(thumbnailChangedHook, -1, 0, InjectFlags.PassInvokingInstance);

            WritePreviousLine("EnableNoonWork");
            scheduleAPI.GetMethod("EnableNoonWork")
                       .InjectWith(
                       noonWorkEnableCheckHook,
                       0,
                       0,
                       InjectFlags.ModifyReturn | InjectFlags.PassParametersVal);

            WritePreviousLine("EnableNightWork");
            scheduleAPI.GetMethod("EnableNightWork")
                       .InjectWith(
                       nightWorkEnableCheckHook,
                       0,
                       0,
                       InjectFlags.ModifyReturn | InjectFlags.PassParametersVal);

            WritePreviousLine("DaytimeTaskCtrl.LoadData");
            daytimeTaskCtrl.GetMethod("LoadData")
                           .InjectWith(
                           reloadNoonWorkDataHook,
                           5,
                           flags: InjectFlags.PassFields | InjectFlags.PassParametersVal,
                           typeFields: new[] {daytimeTaskCtrl.GetField("m_scheduleApi")});

            WritePreviousLine("NightTaskCtrl.LoadData");
            nightTaskCtrl.GetMethod("LoadData")
                         .InjectWith(
                         reloadNightWorkDataHook,
                         5,
                         flags: InjectFlags.PassFields | InjectFlags.PassParametersVal,
                         typeFields: new[] {nightTaskCtrl.GetField("m_scheduleApi")});

            WritePreviousLine("VisibleNightWork");
            scheduleAPI.GetMethod("VisibleNightWork")
                       .InjectWith(
                       nightWorkVisCheckHook,
                       0,
                       0,
                       InjectFlags.ModifyReturn | InjectFlags.PassParametersVal);


            WritePreviousLine("UpdateFeatureAndPropensity");
            maidParam.GetMethod("UpdateFeatureAndPropensity")
                     .InjectWith(
                     featurePropensityUpdatedHook,
                     -1,
                     0,
                     InjectFlags.PassFields | InjectFlags.PassParametersVal,
                     typeFields: new[] {maidParam.GetField("maid_")});

            for (PlayerChangeType e = PlayerChangeType.Days; e <= PlayerChangeType.ShopUseMoney; e++)
            {
                string addMethod = $"Add{Enum.GetName(typeof (PlayerChangeType), e)}";
                string setMethod = $"Set{Enum.GetName(typeof (PlayerChangeType), e)}";
                WritePreviousLine(addMethod);
                playerParam.GetMethod(addMethod).InjectWith(playerStatChangeHook, 0, (int) e, InjectFlags.PassTag);

                WritePreviousLine(setMethod);
                playerParam.GetMethod(setMethod).InjectWith(playerStatChangeHook, 0, (int) e, InjectFlags.PassTag);
            }

            for (PlayerChangeType e = PlayerChangeType.BestSalonGrade; e <= PlayerChangeType.Name; e++)
            {
                string setMethod = $"Set{Enum.GetName(typeof (PlayerChangeType), e)}";

                WritePreviousLine(setMethod);
                playerParam.GetMethod(setMethod).InjectWith(playerStatChangeHook, 0, (int) e, InjectFlags.PassTag);
            }

            WritePreviousLine("UpdateCommand");
            yotogiPlayMgr.GetMethod("UpdateCommand")
                         .InjectWith(
                         maidHooks.GetMethod(nameof(MaidStatusChangeHooks.OnUpdateCommand)),
                         -1,
                         0,
                         InjectFlags.PassFields,
                         typeFields:
                         new[]
                         {
                             yotogiPlayMgr.GetField("player_state_"),
                             yotogiPlayMgr.GetField("valid_command_dic_"),
                             yotogiPlayMgr.GetField("command_factory_")
                         });

            WritePreviousLine("IsExecMaid");
            skillData.GetMethod("IsExecMaid").InjectWith(yotogiSkillVisCheckHook, 0, 0, InjectFlags.ModifyReturn);

            WritePreviousLine("IsExecStage");
            skillData.GetMethod("IsExecStage").InjectWith(yotogiSkillVisCheckHook, 0, 0, InjectFlags.ModifyReturn);

            WritePreviousLine("NumRound2");
            wf.GetMethod("NumRound2")
              .InjectWith(onValueRoundInt1, 0, 0, InjectFlags.ModifyReturn | InjectFlags.PassParametersVal);

            WritePreviousLine("NumRound3");
            wf.GetMethod("NumRound3")
              .InjectWith(onValueRoundInt1, 0, 0, InjectFlags.ModifyReturn | InjectFlags.PassParametersVal);

            WritePreviousLine("NumRound4(int)");
            wf.GetMethod("NumRound4", typeof (int))
              .InjectWith(onValueRoundInt1, 0, 0, InjectFlags.ModifyReturn | InjectFlags.PassParametersVal);

            WritePreviousLine("NumRound4(long)");
            wf.GetMethod("NumRound4", typeof (long))
              .InjectWith(onValueRoundLong1, 0, 0, InjectFlags.ModifyReturn | InjectFlags.PassParametersVal);

            WritePreviousLine("NumRound6");
            wf.GetMethod("NumRound6")
              .InjectWith(onValueRoundLong1, 0, 0, InjectFlags.ModifyReturn | InjectFlags.PassParametersVal);

            WritePreviousLine("RoundMinMax(int)");
            wf.GetMethod("RoundMinMax", typeof (int), typeof (int), typeof (int))
              .InjectWith(onValueRoundInt3, 0, 0, InjectFlags.ModifyReturn | InjectFlags.PassParametersVal);

            WritePreviousLine("RoundMinMax(long)");
            wf.GetMethod("RoundMinMax", typeof (long), typeof (long), typeof (long))
              .InjectWith(onValueRoundLong3, 0, 0, InjectFlags.ModifyReturn | InjectFlags.PassParametersVal);

            Console.WriteLine("Done. Patching class members:\n");
            WritePreviousLine("MaidParam.status_");
            maidParam.ChangeAccess("status_");

            WritePreviousLine("MaidParam.status_");
            playerParam.ChangeAccess("status_");

            WritePreviousLine("param.Status.kInitMaidPoint");
            status.ChangeAccess("kInitMaidPoint");

            SetPatchedAttribute(args.Assembly, TAG);
            Console.WriteLine("\nPatching complete.");
        }
 public override bool CanPatch(PatcherArguments args)
 {
     return args.Assembly.Name.Name == "Assembly-CSharp" && !HasAttribute(args.Assembly, TAG);
 }
Beispiel #9
0
        public override void Patch(PatcherArguments args)
        {
            TypeDefinition gameMainType    = args.Assembly.MainModule.GetType("GameMain");
            TypeDefinition maidParam       = args.Assembly.MainModule.GetType("MaidParam");
            TypeDefinition maidType        = args.Assembly.MainModule.GetType("Maid");
            TypeDefinition scheduleAPI     = args.Assembly.MainModule.GetType("Schedule.ScheduleAPI");
            TypeDefinition daytimeTaskCtrl = args.Assembly.MainModule.GetType("DaytimeTaskCtrl");
            TypeDefinition nightTaskCtrl   = args.Assembly.MainModule.GetType("NightTaskCtrl");
            TypeDefinition playerParam     = args.Assembly.MainModule.GetType("PlayerParam");
            TypeDefinition yotogiPlayMgr   = args.Assembly.MainModule.GetType("YotogiPlayManager");
            TypeDefinition wf        = args.Assembly.MainModule.GetType("wf");
            TypeDefinition status    = args.Assembly.MainModule.GetType("param.Status");
            TypeDefinition skillData =
                args.Assembly.MainModule.GetType("Yotogi").NestedTypes.FirstOrDefault(t => t.Name == "SkillData");
            TypeDefinition freeModeItemEveryday = args.Assembly.MainModule.GetType("FreeModeItemEveryday");
            TypeDefinition freeModeItemVip      = args.Assembly.MainModule.GetType("FreeModeItemVip");

            TypeDefinition hookType  = FiddlerAssembly.MainModule.GetType("CM3D2.MaidFiddler.Hook.FiddlerHooks");
            TypeDefinition maidHooks = FiddlerAssembly.MainModule.GetType(
                "CM3D2.MaidFiddler.Hook.MaidStatusChangeHooks");
            TypeDefinition playerHooks =
                FiddlerAssembly.MainModule.GetType("CM3D2.MaidFiddler.Hook.PlayerStatusChangeHooks");
            TypeDefinition valueLimitHooks = FiddlerAssembly.MainModule.GetType(
                "CM3D2.MaidFiddler.Hook.ValueLimitHooks");

            gameMainType.GetMethod("Deserialize")
            .GetInjector(hookType, "OnSaveDeserialize", InjectFlags.PassParametersVal)
            .Inject(-1);

            // Maid hooks
            MethodDefinition statusChangeHook         = maidHooks.GetMethod(nameof(MaidStatusChangeHooks.OnStatusChanged));
            MethodDefinition statusChangeCallbackHook =
                maidHooks.GetMethod(nameof(MaidStatusChangeHooks.OnStatusChangedCallback));
            MethodDefinition propertyGetHook     = maidHooks.GetMethod(nameof(MaidStatusChangeHooks.OnNewPropertyGet));
            MethodDefinition statusChangeIDHook1 = maidHooks.GetMethod(
                nameof(MaidStatusChangeHooks.OnStatusChangedID),
                typeof(int),
                typeof(Maid).MakeByRefType(),
                typeof(int));
            MethodDefinition statusChangeIDHook2 = maidHooks.GetMethod(
                nameof(MaidStatusChangeHooks.OnStatusChangedID),
                typeof(int),
                typeof(Maid).MakeByRefType(),
                typeof(int),
                typeof(int));
            MethodDefinition propertyRemovedHook  = maidHooks.GetMethod(nameof(MaidStatusChangeHooks.OnPropertyRemoved));
            MethodDefinition statusUpdateHook     = maidHooks.GetMethod(nameof(MaidStatusChangeHooks.OnStatusUpdate));
            MethodDefinition maidYotogiUpdateHook =
                maidHooks.GetMethod(nameof(MaidStatusChangeHooks.OnMaidClassAndYotogiUpdate));
            MethodDefinition classUpdateHook      = maidHooks.GetMethod(nameof(MaidStatusChangeHooks.OnClassTypeUpdate));
            MethodDefinition thumbnailChangedHook = maidHooks.GetMethod(
                nameof(MaidStatusChangeHooks.OnThumbnailChanged));
            MethodDefinition noonWorkEnableCheckHook =
                maidHooks.GetMethod(nameof(MaidStatusChangeHooks.OnNoonWorkEnableCheck));
            MethodDefinition nightWorkEnableCheckHook =
                maidHooks.GetMethod(nameof(MaidStatusChangeHooks.OnNightWorkEnableCheck));
            MethodDefinition reloadNoonWorkDataHook =
                maidHooks.GetMethod(nameof(MaidStatusChangeHooks.ReloadNoonWorkData));
            MethodDefinition reloadNightWorkDataHook =
                maidHooks.GetMethod(nameof(MaidStatusChangeHooks.ReloadNightWorkData));
            MethodDefinition featurePropensityUpdatedHook =
                maidHooks.GetMethod(nameof(MaidStatusChangeHooks.OnFeaturePropensityUpdated));
            MethodDefinition nightWorkVisCheckHook =
                maidHooks.GetMethod(nameof(MaidStatusChangeHooks.CheckNightWorkVisibility));
            MethodDefinition yotogiSkillVisCheckHook =
                maidHooks.GetMethod(nameof(MaidStatusChangeHooks.OnYotogiSkillVisibilityCheck));
            MethodDefinition postProcessFreeModeSceneHook =
                maidHooks.GetMethod(nameof(MaidStatusChangeHooks.PostProcessFreeModeScene));

            MethodDefinition onValueRoundInt1 = valueLimitHooks.GetMethod(
                nameof(ValueLimitHooks.OnValueRound),
                typeof(int).MakeByRefType(),
                typeof(int));
            MethodDefinition onValueRoundLong1 = valueLimitHooks.GetMethod(
                nameof(ValueLimitHooks.OnValueRound),
                typeof(long).MakeByRefType(),
                typeof(long));
            MethodDefinition onValueRoundInt3 = valueLimitHooks.GetMethod(
                nameof(ValueLimitHooks.OnValueRound),
                typeof(int).MakeByRefType(),
                typeof(int),
                typeof(int),
                typeof(int));
            MethodDefinition onValueRoundLong3 = valueLimitHooks.GetMethod(
                nameof(ValueLimitHooks.OnValueRound),
                typeof(long).MakeByRefType(),
                typeof(long),
                typeof(long),
                typeof(long));


            // Player hooks
            MethodDefinition playerStatChangeHook =
                playerHooks.GetMethod(nameof(PlayerStatusChangeHooks.OnPlayerStatChanged));

            const InjectFlags features1 = InjectFlags.PassTag | InjectFlags.PassFields | InjectFlags.ModifyReturn;
            const InjectFlags features2 = features1 | InjectFlags.PassParametersVal;
            const InjectFlags features3 = InjectFlags.PassFields | InjectFlags.PassTag;


            string[] typeNames = Enum.GetNames(typeof(MaidChangeType));

            Console.WriteLine("Patching basic Add/Set methods:");

            for (int i = (int)MaidChangeType.Care; i <= (int)MaidChangeType.TotalEvaluation; i++)
            {
                WritePreviousLine($"Add{typeNames[i]}");
                maidParam.GetMethod($"Add{typeNames[i]}")
                .InjectWith(statusChangeHook, 0, i, features1, typeFields: new[] { maidParam.GetField("maid_") });

                WritePreviousLine($"Set{typeNames[i]}");
                maidParam.GetMethod($"Set{typeNames[i]}")
                .InjectWith(statusChangeHook, 0, i, features1, typeFields: new[] { maidParam.GetField("maid_") });
            }

            MethodDefinition setSexual = maidParam.GetMethod("SetSexual");

            if (setSexual != null)
            {
                WritePreviousLine("SetSexual");
                maidParam.GetMethod("SetSexual")
                .InjectWith(
                    statusChangeHook,
                    -1,
                    (int)MaidChangeType.Sexual,
                    features1,
                    typeFields: new[] { maidParam.GetField("maid_") });
            }


            for (int i = (int)MaidChangeType.FirstName; i <= (int)MaidChangeType.Seikeiken; i++)
            {
                WritePreviousLine($"Set{typeNames[i]}");
                MethodDefinition setDefinition = maidParam.GetMethod($"Set{typeNames[i]}");
                if (setDefinition == null)
                {
                    Console.WriteLine("Method not found (probably older version of the game). Skipping...");
                    continue;
                }
                setDefinition.InjectWith(
                    statusChangeHook,
                    0,
                    i,
                    features1,
                    typeFields: new[] { maidParam.GetField("maid_") });
            }

            for (int i = (int)MaidChangeType.MaidClassExp; i <= (int)MaidChangeType.YotogiClassExp; i++)
            {
                WritePreviousLine($"Add{typeNames[i]}");
                maidParam.GetMethod($"Add{typeNames[i]}", typeof(int))
                .InjectWith(statusChangeHook, 0, i, features1, typeFields: new[] { maidParam.GetField("maid_") });
            }

            for (int i = (int)MaidChangeType.SkillPlayCount; i <= (int)MaidChangeType.WorkPlayCount; i++)
            {
                WritePreviousLine($"Add{typeNames[i]}");
                maidParam.GetMethod($"Add{typeNames[i]}")
                .InjectWith(
                    statusChangeIDHook1,
                    0,
                    i,
                    features2,
                    typeFields: new[] { maidParam.GetField("maid_") });
            }

            WritePreviousLine("UpdateProfileComment");
            maidParam.GetMethod("UpdateProfileComment")
            .InjectWith(
                statusChangeHook,
                0,
                (int)MaidChangeType.Profile,
                features1,
                typeFields: new[] { maidParam.GetField("maid_") });

            WritePreviousLine($"Add{typeNames[(int) MaidChangeType.SkillExp]}");
            maidParam.GetMethod($"Add{typeNames[(int) MaidChangeType.SkillExp]}")
            .InjectWith(
                statusChangeIDHook2,
                0,
                (int)MaidChangeType.SkillExp,
                InjectFlags.PassFields | InjectFlags.PassTag | InjectFlags.PassParametersVal,
                typeFields: new[] { maidParam.GetField("maid_") });

            WritePreviousLine($"Set{typeNames[(int) MaidChangeType.WorkLevel]}");
            maidParam.GetMethod($"Set{typeNames[(int) MaidChangeType.WorkLevel]}")
            .InjectWith(
                statusChangeIDHook2,
                0,
                (int)MaidChangeType.WorkLevel,
                features2,
                typeFields: new[] { maidParam.GetField("maid_") });

            WritePreviousLine("SetPropensity");
            PatchFuncEnumBool(MaidChangeType.Propensity, maidParam.GetMethod("SetPropensity"), statusUpdateHook);

            WritePreviousLine("SetFeature");
            PatchFuncEnumBool(MaidChangeType.Feature, maidParam.GetMethod("SetFeature"), statusUpdateHook);

            for (int i = (int)MaidChangeType.NewGetSkill; i <= (int)MaidChangeType.NewGetWork; i++)
            {
                WritePreviousLine($"Set{typeNames[i]}");
                maidParam.GetMethod($"Set{typeNames[i]}")
                .InjectWith(
                    propertyGetHook,
                    0,
                    i,
                    features3 | InjectFlags.PassParametersVal,
                    typeFields: new[] { maidParam.GetField("maid_") });
            }

            for (int i = (int)MaidChangeType.Skill; i <= (int)MaidChangeType.Work; i++)
            {
                WritePreviousLine($"Remove{typeNames[i]}");
                maidParam.GetMethod($"Remove{typeNames[i]}")
                .InjectWith(
                    propertyRemovedHook,
                    0,
                    i,
                    features3 | InjectFlags.PassParametersVal,
                    typeFields: new[] { maidParam.GetField("maid_") });
            }

            WritePreviousLine("UpdatetAcquisitionMaidClassType");
            maidParam.GetMethod("UpdatetAcquisitionMaidClassType")
            .InjectWith(
                classUpdateHook,
                0,
                (int)MaidChangeType.MaidClassType,
                features3,
                typeFields: new[] { maidParam.GetField("maid_") });

            WritePreviousLine("UpdatetAcquisitionYotogiClassType");
            maidParam.GetMethod("UpdatetAcquisitionYotogiClassType")
            .InjectWith(
                classUpdateHook,
                0,
                (int)MaidChangeType.YotogiClassType,
                features3,
                typeFields: new[] { maidParam.GetField("maid_") });

            WritePreviousLine("UpdateMaidClassAndYotogiClassStatus");
            maidParam.GetMethod("UpdateMaidClassAndYotogiClassStatus")
            .InjectWith(
                maidYotogiUpdateHook,
                0,
                0,
                InjectFlags.PassFields,
                typeFields: new[] { maidParam.GetField("maid_") });

            WritePreviousLine("AddMaidClassExp");
            PatchFuncEnum(
                MaidChangeType.MaidClassType,
                maidParam.GetMethods("AddMaidClassExp").FirstOrDefault(m => m.Parameters.Count == 2),
                statusChangeIDHook1);

            WritePreviousLine("AddYotogiClassExp");
            PatchFuncEnum(
                MaidChangeType.YotogiClassType,
                maidParam.GetMethods("AddYotogiClassExp").FirstOrDefault(m => m.Parameters.Count == 2),
                statusChangeIDHook1);

            WritePreviousLine("ThumShot");
            maidType.GetMethod("ThumShot").InjectWith(thumbnailChangedHook, -1, 0, InjectFlags.PassInvokingInstance);

            MethodDefinition setThumIcon = maidType.GetMethod("SetThumIcon");

            if (setThumIcon != null)
            {
                WritePreviousLine("SetThumIcon");
                setThumIcon.InjectWith(thumbnailChangedHook, -1, 0, InjectFlags.PassInvokingInstance);
            }
            WritePreviousLine("EnableNoonWork");
            scheduleAPI.GetMethod("EnableNoonWork")
            .InjectWith(
                noonWorkEnableCheckHook,
                0,
                0,
                InjectFlags.ModifyReturn | InjectFlags.PassParametersVal);

            WritePreviousLine("EnableNightWork");
            scheduleAPI.GetMethod("EnableNightWork")
            .InjectWith(
                nightWorkEnableCheckHook,
                0,
                0,
                InjectFlags.ModifyReturn | InjectFlags.PassParametersVal);

            WritePreviousLine("DaytimeTaskCtrl.LoadData");
            daytimeTaskCtrl.GetMethod("LoadData")
            .InjectWith(
                reloadNoonWorkDataHook,
                5,
                flags: InjectFlags.PassFields | InjectFlags.PassParametersVal,
                typeFields: new[] { daytimeTaskCtrl.GetField("m_scheduleApi") });

            WritePreviousLine("NightTaskCtrl.LoadData");
            nightTaskCtrl.GetMethod("LoadData")
            .InjectWith(
                reloadNightWorkDataHook,
                5,
                flags: InjectFlags.PassFields | InjectFlags.PassParametersVal,
                typeFields: new[] { nightTaskCtrl.GetField("m_scheduleApi") });

            WritePreviousLine("VisibleNightWork");
            scheduleAPI.GetMethod("VisibleNightWork")
            .InjectWith(
                nightWorkVisCheckHook,
                0,
                0,
                InjectFlags.ModifyReturn | InjectFlags.PassParametersVal);


            WritePreviousLine("UpdateFeatureAndPropensity");
            maidParam.GetMethod("UpdateFeatureAndPropensity")
            .InjectWith(
                featurePropensityUpdatedHook,
                -1,
                0,
                InjectFlags.PassFields | InjectFlags.PassParametersVal,
                typeFields: new[] { maidParam.GetField("maid_") });

            WritePreviousLine("SetFeature(HashSet)");
            maidParam.GetMethod("SetFeature", typeof(HashSet <>).MakeGenericType(typeof(Feature)))
            .InjectWith(
                statusChangeCallbackHook,
                -1,
                (int)MaidChangeType.FeatureHash,
                InjectFlags.PassTag | InjectFlags.PassFields,
                typeFields: new[] { maidParam.GetField("maid_") });

            WritePreviousLine("SetPropensity(HashSet)");
            maidParam.GetMethod("SetPropensity", typeof(HashSet <>).MakeGenericType(typeof(Propensity)))
            .InjectWith(
                statusChangeCallbackHook,
                -1,
                (int)MaidChangeType.PropensityHash,
                InjectFlags.PassTag | InjectFlags.PassFields,
                typeFields: new[] { maidParam.GetField("maid_") });

            for (PlayerChangeType e = PlayerChangeType.Days; e <= PlayerChangeType.ShopUseMoney; e++)
            {
                string addMethod = $"Add{Enum.GetName(typeof (PlayerChangeType), e)}";
                string setMethod = $"Set{Enum.GetName(typeof (PlayerChangeType), e)}";
                WritePreviousLine(addMethod);
                playerParam.GetMethod(addMethod)
                .InjectWith(playerStatChangeHook, 0, (int)e, InjectFlags.PassTag | InjectFlags.ModifyReturn);

                WritePreviousLine(setMethod);
                playerParam.GetMethod(setMethod)
                .InjectWith(playerStatChangeHook, 0, (int)e, InjectFlags.PassTag | InjectFlags.ModifyReturn);
            }

            for (PlayerChangeType e = PlayerChangeType.BestSalonGrade; e <= PlayerChangeType.Name; e++)
            {
                string setMethod = $"Set{Enum.GetName(typeof (PlayerChangeType), e)}";

                WritePreviousLine(setMethod);
                playerParam.GetMethod(setMethod)
                .InjectWith(playerStatChangeHook, 0, (int)e, InjectFlags.PassTag | InjectFlags.ModifyReturn);
            }

            WritePreviousLine("UpdateCommand");
            yotogiPlayMgr.GetMethod("UpdateCommand")
            .InjectWith(
                maidHooks.GetMethod(nameof(MaidStatusChangeHooks.OnUpdateCommand)),
                -1,
                0,
                InjectFlags.PassFields,
                typeFields:
                new[]
            {
                yotogiPlayMgr.GetField("player_state_"),
                yotogiPlayMgr.GetField("valid_command_dic_"),
                yotogiPlayMgr.GetField("command_factory_")
            });

            WritePreviousLine("IsExecMaid");
            skillData.GetMethod("IsExecMaid")
            .InjectWith(yotogiSkillVisCheckHook, 0, 0, InjectFlags.PassTag | InjectFlags.ModifyReturn);

            WritePreviousLine("IsExecStage");
            skillData.GetMethod("IsExecStage")
            .InjectWith(yotogiSkillVisCheckHook, 0, 1, InjectFlags.PassTag | InjectFlags.ModifyReturn);

            WritePreviousLine("NumRound2");
            wf.GetMethod("NumRound2")
            .InjectWith(onValueRoundInt1, 0, 0, InjectFlags.ModifyReturn | InjectFlags.PassParametersVal);

            WritePreviousLine("NumRound3");
            wf.GetMethod("NumRound3")
            .InjectWith(onValueRoundInt1, 0, 0, InjectFlags.ModifyReturn | InjectFlags.PassParametersVal);

            WritePreviousLine("NumRound4(int)");
            wf.GetMethod("NumRound4", typeof(int))
            .InjectWith(onValueRoundInt1, 0, 0, InjectFlags.ModifyReturn | InjectFlags.PassParametersVal);

            WritePreviousLine("NumRound4(long)");
            wf.GetMethod("NumRound4", typeof(long))
            .InjectWith(onValueRoundLong1, 0, 0, InjectFlags.ModifyReturn | InjectFlags.PassParametersVal);

            WritePreviousLine("NumRound6");
            wf.GetMethod("NumRound6")
            .InjectWith(onValueRoundLong1, 0, 0, InjectFlags.ModifyReturn | InjectFlags.PassParametersVal);

            WritePreviousLine("RoundMinMax(int)");
            wf.GetMethod("RoundMinMax", typeof(int), typeof(int), typeof(int))
            .InjectWith(onValueRoundInt3, 0, 0, InjectFlags.ModifyReturn | InjectFlags.PassParametersVal);

            WritePreviousLine("RoundMinMax(long)");
            wf.GetMethod("RoundMinMax", typeof(long), typeof(long), typeof(long))
            .InjectWith(onValueRoundLong3, 0, 0, InjectFlags.ModifyReturn | InjectFlags.PassParametersVal);

            if (freeModeItemEveryday != null)
            {
                WritePreviousLine("FreeModeItemEveryday.ctor");
                freeModeItemEveryday.GetMethod(".ctor")
                .InjectWith(
                    postProcessFreeModeSceneHook,
                    -1,
                    0,
                    InjectFlags.PassFields,
                    typeFields: new[] { freeModeItemEveryday.GetField("is_enabled_") });
            }

            if (freeModeItemVip != null)
            {
                WritePreviousLine("FreeModeItemVip.ctor");
                freeModeItemVip.GetMethod(".ctor")
                .InjectWith(
                    postProcessFreeModeSceneHook,
                    -1,
                    0,
                    InjectFlags.PassFields,
                    typeFields: new[] { freeModeItemVip.GetField("is_enabled_") });
            }

            Console.WriteLine("Done. Patching class members:\n");
            WritePreviousLine("MaidParam.status_");
            maidParam.ChangeAccess("status_");

            WritePreviousLine("MaidParam.status_");
            playerParam.ChangeAccess("status_");

            WritePreviousLine("param.Status.kInitMaidPoint");
            status.ChangeAccess("kInitMaidPoint");

            SetPatchedAttribute(args.Assembly, TAG);
            SetCustomPatchedAttribute(args.Assembly);
            Console.WriteLine("\nPatching complete.");
        }
Beispiel #10
0
 public override bool CanPatch(PatcherArguments args)
 {
     return(args.Assembly.Name.Name == "Assembly-CSharp" && !HasAttribute(args.Assembly, TAG));
 }
Beispiel #11
0
 /// <summary>
 /// Checks if the provided assembly should be patched with this patcher.
 /// </summary>
 /// <param name="args">Information about the assembly.</param>
 /// <returns>True, if the assembly specified in args should be patched with this patcher. Otherwise, false.</returns>
 public override bool CanPatch(PatcherArguments args)
 {
     // Check that the name of the assembly is the same as specified in the configuration and make sure the assembly wasn't already patched with this patcher.
     // The latter is done by looking at the assembly's attributes and finding the patched tag.
     return(args.Assembly.Name.Name == assembly && GetPatchedAttributes(args.Assembly).All(att => att.Info != PATCHED_TAG));
 }
        public override void Patch(PatcherArguments args)
        {
            //Debugger.Launch();
            var aMod = args.Assembly.MainModule;
            var eMod = EngineDefinition.MainModule;

            var ttBody = aMod.GetType("TBody");
            var mMulTex = ttBody.Methods.First(def => def.Name == "MulTexProc" && def.HasParameters);

            // Min
            var tInt = typeof(int);
            var mMin = aMod.Import(typeof(Math).GetMethods(BindingFlags.Public | BindingFlags.Static)
                                              .Where(info => info.Name == "Min")
                                              .First(
                                                     info =>
                                                     info.GetParameters().Length == 2
                                                     && info.GetParameters()[0].ParameterType == tInt
                                                     && info.GetParameters()[1].ParameterType == tInt));

            // Vector Variables
            var tVector = eMod.GetType("UnityEngine.Vector3");
            var tVectorRef = aMod.Import(tVector);

            var vVecPos = mMulTex.Body.Variables.First(def => def.VariableType.FullName == tVectorRef.FullName);
            var vVecScale = mMulTex.Body.Variables.Last(def => def.VariableType.FullName == tVectorRef.FullName);
            var vVecRatio = new VariableDefinition(tVectorRef);

            var mVectorCtor = aMod.Import(tVector.Methods.First(def => def.Name == ".ctor" && def.Parameters.Count == 3));
            var mVectorScale =
                aMod.Import(tVector.Methods.First(def => def.Name == "Scale"
                                                        && def.Parameters.All(def2 => def2.ParameterType.FullName == tVectorRef.FullName)));

            mMulTex.Body.Variables.Add(vVecRatio);

            // RenderTexture Methods
            var tRender = eMod.GetType("UnityEngine.RenderTexture");

            var mGetWd = tRender.Methods.First(def => def.Name == "get_width");
            var mGetHd = tRender.Methods.First(def => def.Name == "get_height");
            var mGetActived = tRender.Methods.First(def => def.Name == "get_active");
            var mSetActived = tRender.Methods.First(def => def.Name == "set_active");
            var mGetW = aMod.Import(mGetWd);
            var mGetH = aMod.Import(mGetHd);
            var mGetActive = aMod.Import(mGetActived);
            var mSetActive = aMod.Import(mSetActived);

            // First Point
            var pointOne =
                mMulTex.Body.Instructions.First(ins => ins.OpCode == OpCodes.Call
                                                       && ((MethodReference) ins.Operand).Name == mSetActive.Name).Next;

            // Second Point
            var pointTwo =
                mMulTex.Body.Instructions.First(ins => ins.OpCode == OpCodes.Call
                                                       && ((MethodReference) ins.Operand).Name == "PushMatrix");

            // Patching
            var ilp = mMulTex.Body.GetILProcessor();

            // Ratio calculated by Min(width,height) / 1024
            // Then matrix translation and scale XY are multiplied by it
            // This block Calculates the ratio, and insantiates a Vector3 with it as the xy components
            ilp.InsertBefore(pointOne, ilp.Create(OpCodes.Ldloca_S, vVecRatio)); // LDLOCA.S _vRATIO
            ilp.InsertBefore(pointOne, ilp.Create(OpCodes.Call, mGetActive)); //--- CALL [UnityEngine.RenderTexture].get_active
            ilp.InsertBefore(pointOne, ilp.Create(OpCodes.Callvirt, mGetW)); //---- CALLVIRT [UnityEngine.RenderTexture].get_width
            ilp.InsertBefore(pointOne, ilp.Create(OpCodes.Call, mGetActive)); //--- CALL [UnityEngine.RenderTexture].get_active
            ilp.InsertBefore(pointOne, ilp.Create(OpCodes.Callvirt, mGetH)); //---- CALLVIRT [UnityEngine.RenderTexture].get_height
            ilp.InsertBefore(pointOne, ilp.Create(OpCodes.Call, mMin)); //--------- CALL [System.Math].Min
            ilp.InsertBefore(pointOne, ilp.Create(OpCodes.Conv_R4)); //------------ CONV_R4
            ilp.InsertBefore(pointOne, ilp.Create(OpCodes.Ldc_R4, 1024f)); //------ LDC.R4 1024f
            ilp.InsertBefore(pointOne, ilp.Create(OpCodes.Div)); //---------------- DIV
            ilp.InsertBefore(pointOne, ilp.Create(OpCodes.Dup)); //---------------- DUP
            ilp.InsertBefore(pointOne, ilp.Create(OpCodes.Ldc_R4, 1f)); //--------- LDC.R4 1f
            ilp.InsertBefore(pointOne, ilp.Create(OpCodes.Call, mVectorCtor)); //-- CALL [UnityEngine.Vector3].ctor

            // Before calling PushMatrix
            // Scales the translation and position vectors by the ratio vector calculated above
            ilp.InsertBefore(pointTwo, ilp.Create(OpCodes.Ldloc_S, vVecPos)); //--- LDLOC.S _vPOS
            ilp.InsertBefore(pointTwo, ilp.Create(OpCodes.Ldloc_S, vVecRatio)); //- LDLOC.S _vRATIO
            ilp.InsertBefore(pointTwo, ilp.Create(OpCodes.Call, mVectorScale)); //- CALL [UnityEngine.Vector3].Scale
            ilp.InsertBefore(pointTwo, ilp.Create(OpCodes.Stloc_S, vVecPos)); //--- STLOC.S _vPOS

            ilp.InsertBefore(pointTwo, ilp.Create(OpCodes.Ldloc_S, vVecScale)); //- LDLOC.S _vSCALE
            ilp.InsertBefore(pointTwo, ilp.Create(OpCodes.Ldloc_S, vVecRatio)); //- LDLOC.S _vRATIO
            ilp.InsertBefore(pointTwo, ilp.Create(OpCodes.Call, mVectorScale)); //- CALL [UnityEngine.Vector3].Scale
            ilp.InsertBefore(pointTwo, ilp.Create(OpCodes.Stloc_S, vVecScale)); //- STLOC.S _vSCALE

            SetPatchedAttribute(args.Assembly, TOKEN);
        }