Beispiel #1
0
        static IEnumerable <CodeInstruction> Transpiler(IEnumerable <CodeInstruction> instructions)
        {
            var original = new List <CodeInstruction>(instructions);
            var patched  = new List <CodeInstruction>();

            for (int i = 0; i < original.Count; i++)
            {
                var instruction = original[i];
                if (instruction.Calls(screenGetHeight))
                {
                    patched.Add(new CodeInstruction(OpCodes.Ldarg_0));
                    patched.Add(CodeInstruction.LoadField(typeof(WBOIT), "camera"));
                    patched.Add(CodeInstruction.Call(typeof(Camera), "get_pixelHeight"));
                }
                else if (instruction.Calls(screenGetWidth))
                {
                    patched.Add(new CodeInstruction(OpCodes.Ldarg_0));
                    patched.Add(CodeInstruction.LoadField(typeof(WBOIT), "camera"));
                    patched.Add(CodeInstruction.Call(typeof(Camera), "get_pixelWidth"));
                }
                else
                {
                    patched.Add(instruction);
                }
            }
            return(patched);
        }
Beispiel #2
0
        public static IEnumerable <CodeInstruction> SetControlsTranspiler(IEnumerable <CodeInstruction> instructions)
        {
            bool            foundCancelCrouch           = false;
            bool            foundAutoRunCondition       = false;
            bool            foundMoveDirCondition       = false;
            bool            foundCancelAutorunCondition = false;
            bool            foundMoveDirAssignment      = false;
            CodeInstruction branchEndAutoRun            = null;

            List <CodeInstruction> codes = new List <CodeInstruction>(instructions);

            //DumpIL(codes);
            for (int i = 0; i < codes.Count(); i++)
            {
                CodeInstruction code = codes[i];

                if (!foundCancelCrouch &&
                    codes[i + 0].opcode == OpCodes.Ldarg_0 &&
                    codes[i + 1].opcode == OpCodes.Ldc_I4_0 &&
                    codes[i + 2].Calls(AccessTools.Method(typeof(Character), nameof(Character.SetCrouch))))
                {
                    //Debug.Log("foundit0 " + i);
                    // Nop out the call to "this.SetCrouch(false)"
                    codes[i + 0].opcode = OpCodes.Nop; codes[i + 0].operand = null;
                    codes[i + 1].opcode = OpCodes.Nop; codes[i + 1].operand = null;
                    codes[i + 2].opcode = OpCodes.Nop; codes[i + 2].operand = null;

                    foundCancelCrouch = true;
                }

                // We're looking for a ldfld of m_autoRun followed by a brfalse: "if(this.m_autoRun)"
                if (!foundAutoRunCondition &&
                    code.opcode == OpCodes.Ldfld &&
                    code.LoadsField(AccessTools.DeclaredField(typeof(Player), nameof(Player.m_autoRun))) &&
                    codes[i + 1].opcode == OpCodes.Brfalse)
                {
                    //Debug.Log("foundit1 " + i);
                    foundAutoRunCondition = true;
                }

                // Nop out the "jump || crouch || movedir != Vector3.zero" conditions
                if (foundAutoRunCondition &&
                    codes[i - 5].opcode == OpCodes.Ldarg_S &&
                    codes[i - 4].opcode == OpCodes.Or &&
                    codes[i - 3].opcode == OpCodes.Ldarg_S &&
                    codes[i - 2].opcode == OpCodes.Or &&
                    codes[i - 1].Branches(out Label? asdfasdfasdsa) &&
                    codes[i + 0].opcode == OpCodes.Ldarg_1 &&
                    codes[i + 1].opcode == OpCodes.Call)
                {
                    //Debug.Log("foundit3 " + i);
                    codes[i - 5].opcode = OpCodes.Nop; codes[i - 5].operand = null;
                    codes[i - 4].opcode = OpCodes.Nop; codes[i - 4].operand = null;
                    codes[i - 3].opcode = OpCodes.Nop; codes[i - 3].operand = null;
                    codes[i - 2].opcode = OpCodes.Nop; codes[i - 2].operand = null;
                    // Leave codes[i - 1] alone since it's the branching instruction for the very first condition
                    codes[i + 0].opcode = OpCodes.Nop; codes[i + 0].operand = null;
                    codes[i + 1].opcode = OpCodes.Nop; codes[i + 1].operand = null;
                    codes[i + 2].opcode = OpCodes.Nop; codes[i + 2].operand = null;
                    codes[i + 3].opcode = OpCodes.Nop; codes[i + 3].operand = null;

                    // Add in our own autorun canceling conditions: if either forwards or backwards are pressed.
                    branchEndAutoRun = codes[i - 1];
                    codes.InsertRange(i, new List <CodeInstruction>()
                    {
                        new CodeInstruction(OpCodes.Ldstr, "Forward"),
                        CodeInstruction.Call(typeof(ZInput), nameof(ZInput.GetButton)),
                        branchEndAutoRun.Clone(),
                        new CodeInstruction(OpCodes.Ldstr, "Backward"),
                        CodeInstruction.Call(typeof(ZInput), nameof(ZInput.GetButton)),
                        branchEndAutoRun.Clone()
                    });

                    foundCancelAutorunCondition = true;
                }

                // Convert "else if (autoRun || blockHold)" into "else"
                if (foundCancelAutorunCondition &&
                    codes[i + 0].opcode == OpCodes.Ldarg_S && //&& codes[i + 0].operand as string == "10"
                    codes[i + 1].opcode == OpCodes.Ldarg_S && //&& codes[i + 1].operand as string == "6"
                    codes[i + 2].opcode == OpCodes.Or &&
                    codes[i + 3].Branches(out Label? asdfasdfsad))
                {
                    //Debug.Log("foundit4 " + i);
                    codes[i + 0].opcode = OpCodes.Nop; codes[i + 0].operand = null;
                    codes[i + 1].opcode = OpCodes.Nop; codes[i + 1].operand = null;
                    codes[i + 2].opcode = OpCodes.Nop; codes[i + 2].operand = null;
                    codes[i + 3].opcode = OpCodes.Nop; codes[i + 3].operand = null;

                    foundMoveDirCondition = true;
                }

                // Lastly, add "movedir.x * Vector3.Cross(Vector3.up, this.m_lookDir)" to the player's movedir so that they can strafe while autorunning
                if (foundMoveDirCondition &&
                    codes[i - 3].opcode == OpCodes.Ldarg_0 &&
                    codes[i - 2].opcode == OpCodes.Ldarg_0 &&
                    codes[i - 1].LoadsField(AccessTools.Field(typeof(Character), nameof(Character.m_lookDir))) &&
                    codes[i - 0].StoresField(AccessTools.Field(typeof(Character), nameof(Character.m_moveDir))))
                {
                    //Debug.Log("foundit5 " + i);
                    codes.InsertRange(i, new List <CodeInstruction>()
                    {
                        new CodeInstruction(OpCodes.Ldarg_1),
                        CodeInstruction.LoadField(typeof(Vector3), nameof(Vector3.x)),
                        new CodeInstruction(OpCodes.Call, AccessTools.PropertyGetter(typeof(Vector3), nameof(Vector3.up))),
                        new CodeInstruction(OpCodes.Ldarg_0),
                        CodeInstruction.LoadField(typeof(Player), nameof(Player.m_lookDir)),
                        CodeInstruction.Call(typeof(Vector3), nameof(Vector3.Cross)),
                        new CodeInstruction(OpCodes.Call, AccessTools.Method(typeof(Vector3), "op_Multiply", new Type[] { typeof(float), typeof(Vector3) })),
                        new CodeInstruction(OpCodes.Call, AccessTools.Method(typeof(Vector3), "op_Addition", new Type[] { typeof(Vector3), typeof(Vector3) }))
                    });

                    foundMoveDirAssignment = true;
                    break; // we done
                }
            }

            //DumpIL(codes);

            //Debug.Log(string.Format("{0} {1} {2} {3} {4}", foundAutoRunCondition, branchEndAutoRun != null, foundCancelAutorunCondition, foundMoveDirCondition, foundMoveDirAssignment));
            if (!foundAutoRunCondition || branchEndAutoRun == null || !foundCancelAutorunCondition || !foundMoveDirCondition || !foundMoveDirAssignment)
            {
                throw new Exception("BetterAutoRun injection point NOT found!! Game has most likely updated and broken this mod!");
            }

            if (!foundCancelCrouch)
            {
                Main.log.LogWarning("One of the BetterAutoRun injection points were not found, game has most likely updated and broken this mod.");
                Main.log.LogWarning("Autorun while crouching will not work but everything else should be fine.");
            }

            return(codes.AsEnumerable());
        }