From ee0e2ca9005bd1a0cc0695e41f22d328835c3ee9 Mon Sep 17 00:00:00 2001 From: rushiiMachine <33725716+rushiiMachine@users.noreply.github.com> Date: Wed, 27 Mar 2024 01:30:16 -0700 Subject: [PATCH] feat: PatchShowModsInGameplay --- .../Patches/PatchShowModsInGameplay.cs | 98 +++++++++++++++++++ Osu.Stubs/Player.cs | 20 ++++ 2 files changed, 118 insertions(+) create mode 100644 Osu.Patcher.Hook/Patches/PatchShowModsInGameplay.cs diff --git a/Osu.Patcher.Hook/Patches/PatchShowModsInGameplay.cs b/Osu.Patcher.Hook/Patches/PatchShowModsInGameplay.cs new file mode 100644 index 0000000..3512477 --- /dev/null +++ b/Osu.Patcher.Hook/Patches/PatchShowModsInGameplay.cs @@ -0,0 +1,98 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Reflection; +using HarmonyLib; +using JetBrains.Annotations; +using Osu.Stubs; +using static System.Reflection.Emit.OpCodes; + +namespace Osu.Patcher.Hook.Patches; + +/// +/// Makes the mods list overlay that is shown when entering play mode always show, like in a replay +/// but faded to a user customizable amount. +/// +[HarmonyPatch] +[UsedImplicitly] +public class PatchShowModsInGameplay +{ + // TODO: make this user configurable + private const float ModsNewAlpha = .2f; + + [UsedImplicitly] + [HarmonyTargetMethod] + private static MethodBase Target() => Player.OnLoadComplete.Reference; + + [UsedImplicitly] + [HarmonyTranspiler] + private static IEnumerable Transpiler(IEnumerable instructions) + { + // Replace a "0f" representing a fade target value after an arbitrary "94f" constant + // Also set the pSprite parameter "alwaysDraw" to true + + var replaceState = ReplaceState.Find; + + return instructions.Manipulator( + inst => + { + switch (replaceState) + { + case ReplaceState.Find when inst.Is(Ldc_R4, 94f): + replaceState = ReplaceState.ReplaceAlwaysDraw; + return false; + + // This is calling "InputManager.get_ReplayMode()" + case ReplaceState.ReplaceAlwaysDraw when inst.opcode == Call: + return true; + + // This is loading the transformation fade end value + case ReplaceState.ReplaceFadeEndValue when inst.Is(Ldc_R4, 0f): + return true; + + case ReplaceState.Finished: + default: + return false; + } + }, + inst => + { + switch (replaceState) + { + case ReplaceState.ReplaceAlwaysDraw: + inst.opcode = Ldc_I4_1; // Load "true" for the parameter "alwaysDraw" + inst.operand = null; + replaceState = ReplaceState.ReplaceFadeEndValue; + break; + case ReplaceState.ReplaceFadeEndValue: + inst.operand = ModsNewAlpha; + replaceState = ReplaceState.Finished; + break; + case ReplaceState.Find: + case ReplaceState.Finished: + default: + throw new Exception(); + } + } + ); + } + + [UsedImplicitly] + [HarmonyFinalizer] + [SuppressMessage("ReSharper", "InconsistentNaming")] + private static void Finalizer(Exception? __exception) + { + if (__exception != null) + { + Console.WriteLine($"Exception due to {nameof(PatchShowModsInGameplay)}: {__exception}"); + } + } + + private enum ReplaceState + { + Find, + ReplaceAlwaysDraw, + ReplaceFadeEndValue, + Finished, + } +} \ No newline at end of file diff --git a/Osu.Stubs/Player.cs b/Osu.Stubs/Player.cs index 8cb0041..85691d6 100644 --- a/Osu.Stubs/Player.cs +++ b/Osu.Stubs/Player.cs @@ -33,4 +33,24 @@ public static class Player Br_S, } ); + + /// + /// Original: OnLoadComplete(bool success) + /// b20240124: #=zXb_K4cZvV$uy + /// + [UsedImplicitly] + public static readonly LazyMethod OnLoadComplete = new( + "Player#OnLoadComplete(...)", + new[] + { + Br, + Ldloc_S, + Callvirt, + Unbox_Any, + Stloc_2, + Ldsfld, + Ldfld, + Call, + } + ); } \ No newline at end of file