Exemple #1
0
            private static IEnumerable <CodeInstruction> TryPlayCustomTopicAdvTpl(IEnumerable <CodeInstruction> instructions)
            {
                var matcher = new CodeMatcher(instructions)
                              .MatchForward(true, new CodeMatch(OpCodes.Ldstr, "話題を振る"))
                              .MatchForward(true, new CodeMatch(OpCodes.Call, AccessTools.PropertyGetter(typeof(TalkScene), nameof(TalkScene.isNPC))))
                              .Advance(1)
                              .ThrowIfNotMatch("Brtrue not found", new CodeMatch(OpCodes.Brtrue));

                var startPos = matcher.Pos;

                // Figure out where the if else ends so we can jump there if we want to skip it
                // First go to the start of else, then step back and get the label at the end of if that skips over the else
                var elseLabel = ((Label)matcher.Operand);

                matcher.MatchForward(false, new CodeMatch(instruction => instruction.labels.Contains(elseLabel)))
                .Advance(-1)
                .ThrowIfNotMatch("Br not found", new CodeMatch(OpCodes.Br));
                var skipIfelseLabel = matcher.Operand;

                // Go back to the start of the if
                matcher.Advance(startPos - matcher.Pos).ThrowIfNotMatch("Brtrue not found 2", new CodeMatch(OpCodes.Brtrue));

                // Go back to the first if, then insert our if before it
                // Copy the `this` load instead of hardcoding it just in case (isNPC takes it)
                matcher.Advance(-2);
                var loadInstrCopy = new CodeInstruction(matcher.Opcode, matcher.Operand);

                matcher.Advance(1).Insert(
                    new CodeInstruction(OpCodes.Call, AccessTools.Method(typeof(TopicHooks), nameof(TryPlayCustomTopicAdvHook))),
                    new CodeInstruction(OpCodes.Brtrue, skipIfelseLabel),
                    loadInstrCopy);

                return(matcher.Instructions());
            }
        public static IEnumerable <CodeInstruction> ChaControl_SetShapeBodyValue_RemoveHeightLock(IEnumerable <CodeInstruction> instructions)
        {
            var cm = new CodeMatcher(instructions);

            // find branch that overrides the male height
            cm.MatchForward(false, new CodeMatch(OpCodes.Call, AccessTools.PropertyGetter(typeof(ChaInfo), nameof(ChaInfo.sex))))
            .MatchForward(false, new CodeMatch(c => c.Branches(out _)));
            // turn it into an unconditional jump
            cm.InsertAndAdvance(new CodeInstruction(OpCodes.Pop))
            .SetOpcodeAndAdvance(OpCodes.Br);
            return(cm.Instructions());
        }
        public static IEnumerable <CodeInstruction> ChaControl_Initialize_RemoveHeightLock(IEnumerable <CodeInstruction> instructions)
        {
            var cm = new CodeMatcher(instructions);

            // find branch that overrides the male height
            cm.MatchForward(false, new CodeMatch(OpCodes.Ldc_R4, 0.6f))
            .MatchBack(false, new CodeMatch(OpCodes.Call))
            .MatchBack(false, new CodeMatch(c => c.Branches(out _)));
            // turn it into an unconditional jump
            cm.InsertAndAdvance(new CodeInstruction(OpCodes.Pop))
            .SetOpcodeAndAdvance(OpCodes.Br);
            return(cm.Instructions());
        }
            private static IEnumerable <CodeInstruction> PhPluginSceneInfoSaveTranspiler(IEnumerable <CodeInstruction> instructions)
            {
                var matcher = new CodeMatcher(instructions);

                matcher.MatchForward(false, new CodeMatch(OpCodes.Ldstr, "【PHStudio】"));
                var getWriterInstr = matcher.InstructionAt(-1);

                matcher.Advance(2);
                matcher.InsertAndAdvance(
                    new CodeInstruction(OpCodes.Ldarg_0),
                    getWriterInstr,
                    CodeInstruction.Call(typeof(Hooks), nameof(SceneInfoSaveHook)));

                if (matcher.Instruction.opcode != OpCodes.Leave && matcher.Instruction.opcode != OpCodes.Leave_S)
                {
                    throw new Exception("Failed to patch SceneInfo.Save");
                }

                return(matcher.Instructions());
            }