Skip to content

Commit

Permalink
feat: restructure base patch & harmony finalizers
Browse files Browse the repository at this point in the history
- All patches now extend a base OsuPatch
- Custom patch processor automatically handles adding patch finalizers to catch exceptions
  • Loading branch information
rushiiMachine committed Mar 30, 2024
1 parent 5430185 commit bdcf92f
Show file tree
Hide file tree
Showing 23 changed files with 260 additions and 268 deletions.
10 changes: 8 additions & 2 deletions Osu.Patcher.Hook/Hook.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using System.Runtime.InteropServices;
using HarmonyLib;
using JetBrains.Annotations;
using Osu.Patcher.Hook.Patches;
using Osu.Performance;
using Osu.Stubs.Wrappers;

Expand Down Expand Up @@ -66,10 +67,15 @@ private static void InitializePatches(Harmony harmony)
{
foreach (var type in AccessTools.GetTypesFromAssembly(typeof(Hook).Assembly))
{
// Check if the type extends OsuPatch
if (!type.IsSubclassOf(typeof(OsuPatch)))
continue;

Debug.WriteLine($"Processing Patch {type.Name}", "Hook");

try
{
// This executes for every type and ignores if no [HarmonyPatch] is present
harmony.CreateClassProcessor(type).Patch();
new OsuPatchProcessor(harmony, type).Patch();
}
catch (Exception e)
{
Expand Down
21 changes: 6 additions & 15 deletions Osu.Patcher.Hook/Patches/BeatmapMirror/EnableOsuDirect.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Reflection;
using System.Reflection.Emit;
using HarmonyLib;
using JetBrains.Annotations;
using Osu.Stubs;
using Osu.Utils.Extensions;
using static System.Reflection.Emit.OpCodes;

namespace Osu.Patcher.Hook.Patches.BeatmapMirror;
Expand All @@ -28,7 +27,7 @@ namespace Osu.Patcher.Hook.Patches.BeatmapMirror;
/// </summary>
[HarmonyPatch]
[UsedImplicitly]
public class EnableOsuDirect : BasePatch
internal class EnableOsuDirect : OsuPatch
{
private static readonly OpCode[] Signature =
{
Expand All @@ -49,9 +48,9 @@ public class EnableOsuDirect : BasePatch

[UsedImplicitly]
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions) =>
InsertBeforeSignature(
instructions,
private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
{
instructions = instructions.InsertBeforeSignature(
Signature,
new CodeInstruction[]
{
Expand All @@ -61,14 +60,6 @@ private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstructi
}
);

[UsedImplicitly]
[HarmonyFinalizer]
[SuppressMessage("ReSharper", "InconsistentNaming")]
private static void Finalizer(Exception? __exception)
{
if (__exception != null)
{
Console.WriteLine($"Exception due to {nameof(EnableOsuDirect)}: {__exception}");
}
return instructions;
}
}
14 changes: 1 addition & 13 deletions Osu.Patcher.Hook/Patches/LivePerformance/AddPerformanceToUi.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
using System;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
Expand All @@ -17,7 +16,7 @@ namespace Osu.Patcher.Hook.Patches.LivePerformance;
/// </summary>
[HarmonyPatch]
[UsedImplicitly]
public class AddPerformanceToUi
internal class AddPerformanceToUi : OsuPatch
{
[UsedImplicitly]
[HarmonyTargetMethod]
Expand Down Expand Up @@ -73,17 +72,6 @@ private static void After(
Debug.WriteLine("Added Performance Counter to ScoreDisplay", nameof(AddPerformanceToUi));
}

[UsedImplicitly]
[HarmonyFinalizer]
[SuppressMessage("ReSharper", "InconsistentNaming")]
private static void Finalizer(Exception? __exception)
{
if (__exception != null)
{
Console.WriteLine($"Exception due to {nameof(AddPerformanceToUi)}: {__exception}");
}
}

private static float GetYOffset(float baseYPosition, float scale, object scoreDisplay)
{
// Read the heights of both pSpriteTexts: s_Score, s_Accuracy
Expand Down
14 changes: 1 addition & 13 deletions Osu.Patcher.Hook/Patches/LivePerformance/TrackOnScoreHit.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
using System;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Reflection;
Expand All @@ -16,7 +15,7 @@ namespace Osu.Patcher.Hook.Patches.LivePerformance;
/// </summary>
[HarmonyPatch]
[UsedImplicitly]
public static class TrackOnScoreHit
internal class TrackOnScoreHit : OsuPatch
{
[UsedImplicitly]
[HarmonyTargetMethod]
Expand Down Expand Up @@ -56,15 +55,4 @@ private static void After(

Task.Run(() => PerformanceCalculator.Calculator?.AddJudgement(judgement, (uint)MaxCombo));
}

[UsedImplicitly]
[HarmonyFinalizer]
[SuppressMessage("ReSharper", "InconsistentNaming")]
private static void Finalizer(Exception? __exception)
{
if (__exception != null)
{
Console.WriteLine($"Exception due to {nameof(TrackOnScoreHit)}: {__exception}");
}
}
}
15 changes: 1 addition & 14 deletions Osu.Patcher.Hook/Patches/LivePerformance/TrackResetScore.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
using System;
using System.Diagnostics.CodeAnalysis;
using System.Reflection;
using HarmonyLib;
using JetBrains.Annotations;
Expand All @@ -12,7 +10,7 @@ namespace Osu.Patcher.Hook.Patches.LivePerformance;
/// </summary>
[HarmonyPatch]
[UsedImplicitly]
internal class TrackResetScore
internal class TrackResetScore : OsuPatch
{
[UsedImplicitly]
[HarmonyTargetMethod]
Expand All @@ -21,15 +19,4 @@ internal class TrackResetScore
[UsedImplicitly]
[HarmonyPostfix]
private static void After() => PerformanceCalculator.ResetCalculator();

[UsedImplicitly]
[HarmonyFinalizer]
[SuppressMessage("ReSharper", "InconsistentNaming")]
private static void Finalizer(Exception? __exception)
{
if (__exception != null)
{
Console.WriteLine($"Exception due to {nameof(TrackResetScore)}: {__exception}");
}
}
}
12 changes: 8 additions & 4 deletions Osu.Patcher.Hook/Patches/Misc/AllowPlayModeReload.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using JetBrains.Annotations;
using Osu.Patcher.Hook.Patches.UI;
using Osu.Stubs;
using Osu.Utils.Extensions;
using static System.Reflection.Emit.OpCodes;

namespace Osu.Patcher.Hook.Patches.Misc;
Expand All @@ -28,17 +29,17 @@ namespace Osu.Patcher.Hook.Patches.Misc;
/// </summary>
[HarmonyPatch]
[UsedImplicitly]
public class AllowPlayModeReload : BasePatch
internal class AllowPlayModeReload : OsuPatch
{
[UsedImplicitly]
[HarmonyTargetMethod]
private static MethodBase Target() => GameBase.GetModeCanReload.Reference;

[UsedImplicitly]
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions) =>
InsertBeforeSignature(
instructions,
private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
{
instructions = instructions.InsertBeforeSignature(
new[]
{
// Ldsfld, // Loads the ReplayScore to check if it's null
Expand All @@ -55,4 +56,7 @@ private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstructi
new(Ret),
}
);

return instructions;
}
}
2 changes: 1 addition & 1 deletion Osu.Patcher.Hook/Patches/Misc/DisableErrorReporting.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ namespace Osu.Patcher.Hook.Patches.Misc;
/// </summary>
[HarmonyPatch]
[UsedImplicitly]
internal class DisableErrorReporting : BasePatch
internal class DisableErrorReporting : OsuPatch
{
[UsedImplicitly]
[HarmonyTargetMethod]
Expand Down
17 changes: 5 additions & 12 deletions Osu.Patcher.Hook/Patches/Misc/FixDoubleSkipping.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ namespace Osu.Patcher.Hook.Patches.Misc;
/// </summary>
[HarmonyPatch]
[UsedImplicitly]
internal class FixDoubleSkipping : BasePatch
internal class FixDoubleSkipping : OsuPatch
{
[UsedImplicitly]
[HarmonyTargetMethod]
Expand All @@ -48,20 +48,13 @@ private static bool Before(ref bool __result)
/// </summary>
[UsedImplicitly]
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions) =>
instructions.Manipulator(
private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
{
instructions = instructions.Manipulator(
inst => inst.OperandIs(10000),
inst => inst.operand = 0
);

[UsedImplicitly]
[HarmonyFinalizer]
[SuppressMessage("ReSharper", "InconsistentNaming")]
private static void Finalizer(Exception? __exception)
{
if (__exception != null)
{
Console.WriteLine($"Exception due to {nameof(FixDoubleSkipping)}: {__exception}");
}
return instructions;
}
}
2 changes: 1 addition & 1 deletion Osu.Patcher.Hook/Patches/Misc/LogOsuLogger.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ namespace Osu.Patcher.Hook.Patches.Misc;
/// </summary>
[HarmonyPatch]
[UsedImplicitly]
public static class LogOsuLogger
internal class LogOsuLogger : OsuPatch
{
[UsedImplicitly]
[HarmonyTargetMethod]
Expand Down
2 changes: 1 addition & 1 deletion Osu.Patcher.Hook/Patches/Misc/LogSoftErrors.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ namespace Osu.Patcher.Hook.Patches.Misc;
/// </summary>
[HarmonyPatch]
[UsedImplicitly]
public class LogSoftErrors
internal class LogSoftErrors : OsuPatch
{
[UsedImplicitly]
[HarmonyTargetMethod]
Expand Down
15 changes: 1 addition & 14 deletions Osu.Patcher.Hook/Patches/Mods/PatchSuddenDeathAutoRetry.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Reflection;
using HarmonyLib;
using JetBrains.Annotations;
Expand All @@ -25,7 +23,7 @@ namespace Osu.Patcher.Hook.Patches.Mods;
/// </summary>
[HarmonyPatch]
[UsedImplicitly]
public class PatchSuddenDeathAutoRetry
internal class PatchSuddenDeathAutoRetry : OsuPatch
{
private const int ModPerfect = 1 << 14;
private const int ModSuddenDeath = 1 << 5;
Expand All @@ -45,15 +43,4 @@ private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstructi
inst => inst.opcode == Ldc_I4 && inst.OperandIs(ModPerfect),
inst => inst.operand = ModPerfect | ModSuddenDeath
);

[UsedImplicitly]
[HarmonyFinalizer]
[SuppressMessage("ReSharper", "InconsistentNaming")]
private static void Finalizer(Exception? __exception)
{
if (__exception != null)
{
Console.WriteLine($"Exception due to {nameof(PatchSuddenDeathAutoRetry)}: {__exception}");
}
}
}
6 changes: 6 additions & 0 deletions Osu.Patcher.Hook/Patches/OsuPatch.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
namespace Osu.Patcher.Hook.Patches;

/// <summary>
/// A base patch that provides utility methods for signature-based patching.
/// </summary>
public abstract class OsuPatch;
64 changes: 64 additions & 0 deletions Osu.Patcher.Hook/Patches/OsuPatchProcessor.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Reflection;
using HarmonyLib;
using JetBrains.Annotations;
using Osu.Utils.Extensions;

namespace Osu.Patcher.Hook.Patches;

/// <summary>
/// Custom patch processor to automatically add additional things to the target patches.
/// </summary>
public class OsuPatchProcessor : PatchClassProcessor
{
// List<AttributePatch> HarmonyLib.PatchClassProcessor::patchMethods
private static readonly FieldInfo FieldPatchMethods = typeof(PatchClassProcessor)
.GetField("patchMethods", AccessTools.all)!;

// AttributePatch HarmonyLib.AttributePatch::Create(MethodInfo)
private static readonly MethodInfo MethodCreateAttributePatch =
AccessTools.Method("HarmonyLib.AttributePatch:Create");

// void OsuPatchProcessor::BaseFinalizer(Exception?)
private static readonly MethodInfo GenericMethodBaseFinalizer = typeof(OsuPatchProcessor)
.GetMethod("BaseFinalizer", AccessTools.all)!;

// void List<HarmonyLib.AttributePatch>::Add(HarmonyLib.AttributePatch)
private static readonly MethodInfo ListAttributePatchAdd = typeof(List<>)
.MakeGenericType([AccessTools.TypeByName("HarmonyLib.AttributePatch")])
.GetMethod("Add")!;

/// <summary>
/// Create a new class patch processor that adds extra attribute patches to the patch.
/// </summary>
public OsuPatchProcessor(Harmony instance, Type type) : base(instance, type)
{
AddFinalizerPatch(type);
}

/// <summary>
/// Adds a new <see cref="HarmonyFinalizer" /> attribute patch to the
/// current patch processor targeting a specific <paramref name="type" />.
/// </summary>
private void AddFinalizerPatch(Type type)
{
var boundMethod = GenericMethodBaseFinalizer.MakeGenericMethod([type]);
var attributePatch = MethodCreateAttributePatch.Invoke<object>(null, [boundMethod]);

var attributePatches = FieldPatchMethods.GetValue(this)!;
ListAttributePatchAdd.Invoke(attributePatches, [attributePatch]);
}

[UsedImplicitly]
[HarmonyFinalizer]
[SuppressMessage("ReSharper", "InconsistentNaming")]
private static void BaseFinalizer<P>(Exception? __exception) where P : OsuPatch
{
if (__exception == null)
return;

Console.WriteLine($"[F] [Patch{typeof(P).Name}]: {__exception}");
}
}
Loading

0 comments on commit bdcf92f

Please sign in to comment.