예제 #1
0
            private static IEnumerable <CodeInstruction> UpdateExplore_Transpiler(IEnumerable <CodeInstruction> instructions)
            {
                TranspilerState state = TranspilerState.Searching;

                CodeInstruction previous = null;

                foreach (CodeInstruction instruction in instructions)
                {
                    switch (state)
                    {
                    case TranspilerState.Searching:
                        if (instruction.opcode == OpCodes.Ldarg_0)
                        {
                            previous = instruction;
                            state    = TranspilerState.Checking;
                        }
                        else
                        {
                            yield return(instruction);
                        }
                        break;

                    case TranspilerState.Checking:
                        if (instruction.opcode == OpCodes.Ldfld && ((FieldInfo)instruction.operand).Name == nameof(Minimap.m_exploreRadius))
                        {
                            yield return(new CodeInstruction(OpCodes.Ldarg_2));    // player

                            yield return(new CodeInstruction(OpCodes.Call, typeof(Minimap_Patches).GetMethod(nameof(GetExploreRadius), BindingFlags.Static | BindingFlags.NonPublic)));

                            state = TranspilerState.Finishing;
                        }
                        else
                        {
                            yield return(previous);

                            yield return(instruction);

                            state = TranspilerState.Searching;
                        }
                        previous = null;
                        break;

                    case TranspilerState.Finishing:
                        yield return(instruction);

                        break;
                    }
                }
            }
예제 #2
0
            private static IEnumerable <CodeInstruction> ApplyToHeightmap_Transpiler(IEnumerable <CodeInstruction> instructions)
            {
                TranspilerState state = TranspilerState.Searching;

                CodeInstruction valueInstruction = null;

                foreach (CodeInstruction instruction in instructions)
                {
                    switch (state)
                    {
                    case TranspilerState.Searching:
                        if (instruction.opcode == OpCodes.Ldc_R4 && (float)instruction.operand == 8.0f)
                        {
                            valueInstruction = instruction;
                            state            = TranspilerState.Replacing;
                        }
                        else
                        {
                            yield return(instruction);
                        }
                        break;

                    case TranspilerState.Replacing:
                        if (instruction.opcode == OpCodes.Sub)
                        {
                            valueInstruction.operand = MaximumDepth.Value;
                        }
                        else if (instruction.opcode == OpCodes.Add)
                        {
                            valueInstruction.operand = MaximumHeight.Value;
                        }
                        yield return(valueInstruction);

                        yield return(instruction);

                        valueInstruction = null;
                        state            = TranspilerState.Searching;
                        break;
                    }
                }
            }
예제 #3
0
            private static IEnumerable <CodeInstruction> Update_Transpiler(IEnumerable <CodeInstruction> instructions, ILGenerator generator)
            {
                LocalBuilder isSlashPressed = generator.DeclareLocal(typeof(bool));

                isSlashPressed.SetLocalSymInfo(nameof(isSlashPressed));

                Label label1 = generator.DefineLabel();
                Label label2 = generator.DefineLabel();

                yield return(new CodeInstruction(OpCodes.Ldc_I4_0));

                yield return(new CodeInstruction(OpCodes.Stloc, isSlashPressed.LocalIndex));

                TranspilerState state = TranspilerState.Searching;

                foreach (CodeInstruction instruction in instructions)
                {
                    if (state == TranspilerState.Inserting)
                    {
                        if (instruction.opcode != OpCodes.Brfalse)
                        {
                            throw new InvalidOperationException($"[BetterChat] {nameof(Chat_Slash_Patches)} encountered unexpected IL code. Unable to patch. This is most likely due to a game update changing the target code. Disable {nameof(SlashOpensChat)} in the config as a workaround until the mod can be fixed.");
                        }

                        // Previous instruction was checking if enter is pressed. If so, skip the slash key check (boolean OR).
                        yield return(new CodeInstruction(OpCodes.Brtrue, label1));

                        // Check for slash key if enter is not pressed. Also store the result of the check.
                        yield return(new CodeInstruction(OpCodes.Ldc_I4, (int)KeyCode.Slash));

                        yield return(new CodeInstruction(OpCodes.Call, typeof(Input).GetMethod(nameof(Input.GetKeyDown), new[] { typeof(KeyCode) })));

                        yield return(new CodeInstruction(OpCodes.Stloc, isSlashPressed.LocalIndex));

                        yield return(new CodeInstruction(OpCodes.Ldloc, isSlashPressed.LocalIndex));

                        state = TranspilerState.Labeling;
                    }
                    else if (state == TranspilerState.Labeling)
                    {
                        // Label this instruction as the one to jump to if the enter key is pressed (to skip the slash check).
                        instruction.labels.Add(label1);
                        state = TranspilerState.Searching2;
                    }
                    else if (state == TranspilerState.Labeling2)
                    {
                        // Label this instruction as the one to jump to when skipping the slash insertion code.
                        instruction.labels.Add(label2);
                        state = TranspilerState.Finishing;
                    }

                    yield return(instruction);

                    if (state == TranspilerState.Searching && instruction.opcode == OpCodes.Call)
                    {
                        MethodBase method = (MethodBase)instruction.operand;
                        if (method.Name == nameof(Input.GetKeyDown))
                        {
                            state = TranspilerState.Inserting;
                        }
                    }
                    else if (state == TranspilerState.Searching2 && instruction.opcode == OpCodes.Callvirt)
                    {
                        MethodBase method = (MethodBase)instruction.operand;
                        if (method.Name == nameof(InputField.ActivateInputField))
                        {
                            // If slash was not pressed (meaning enter was), then skip the block below
                            yield return(new CodeInstruction(OpCodes.Ldloc, isSlashPressed.LocalIndex));

                            yield return(new CodeInstruction(OpCodes.Brfalse, label2));

                            // If slash was pressed, replace current chat input string with a / character
                            yield return(new CodeInstruction(OpCodes.Ldarg_0));

                            yield return(new CodeInstruction(OpCodes.Ldfld, typeof(Chat).GetField(nameof(Chat.m_input))));

                            yield return(new CodeInstruction(OpCodes.Ldstr, "/"));

                            yield return(new CodeInstruction(OpCodes.Callvirt, typeof(InputField).GetMethod("set_text")));

                            // Move caret to end (after slash) in LateUpdate
                            yield return(new CodeInstruction(OpCodes.Ldc_I4_1));

                            yield return(new CodeInstruction(OpCodes.Stsfld, typeof(BetterChatPlugin).GetField(nameof(sMoveCaretToEnd), BindingFlags.Static | BindingFlags.NonPublic)));

                            state = TranspilerState.Labeling2;
                        }
                    }
                }
            }