sinmai-mods/UnlockFrameRate/PatchFrameTime.cs

98 lines
4.2 KiB
C#

// ReSharper disable InconsistentNaming
using HarmonyLib;
using Manager;
using Manager.UserDatas;
using Monitor;
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Reflection.Emit;
namespace UnlockFrameRate;
[HarmonyPatch]
internal class PatchFrameTime
{
private const float OriginalFrameRate = 60f;
private const float OriginalFrameTime = 1000f / OriginalFrameRate;
private const float OriginalFramePerMilliseconds = OriginalFrameRate / 1000;
private static IEnumerable<MethodBase> TargetMethods()
{
// This shouldn't be patched, because they make the judgements
// harder or easier depending on your frame rate.
// var noteJudge = AccessTools.TypeByName("NoteJudge");
// var juggeTiming = AccessTools.Inner(noteJudge, "JuggeTiming"); // lol
// yield return AccessTools.Constructor(juggeTiming);
// This changes the effect of judgement timing based on the set FPS,
// so +2.0 at 120Hz will only add 17ms instead of 33ms.
if (FrameRatePlugin.Instance.PatchJudgementTiming)
{
yield return AccessTools.Method(typeof(NoteJudge), nameof(NoteJudge.GetJudgeTiming));
yield return AccessTools.Method(typeof(NoteJudge), nameof(NoteJudge.GetSlideJudgeTiming));
yield return AccessTools.Method(typeof(UserOption), nameof(UserOption.GetAdjustMSec));
}
yield return AccessTools.Method(typeof(NoteBase), "IsNoteCheckTimeStart");
yield return AccessTools.Method(typeof(TouchNoteB), "GetNoteYPosition");
yield return AccessTools.Method(typeof(SlideRoot), "IsNoteCheckTimeStart");
yield return AccessTools.Method(typeof(SlideJudge), nameof(SlideJudge.Initialize));
yield return AccessTools.Method(typeof(JudgeGrade), nameof(JudgeGrade.Initialize));
yield return AccessTools.Method(typeof(NotesManager), nameof(NotesManager.getPlayFirstMsec));
yield return AccessTools.Method(typeof(NotesManager), nameof(NotesManager.getPlayFinalMsec));
yield return AccessTools.Method(typeof(NotesManager), nameof(NotesManager.getCurrentDrawFrame));
yield return AccessTools.Method(typeof(NotesReader), nameof(NotesReader.calcFrame));
yield return AccessTools.Method(typeof(NotesReader), nameof(NotesReader.GetBPM_Frame));
yield return AccessTools.Method(typeof(NotesReader), nameof(NotesReader.getMeter_Frame));
yield return AccessTools.Method(typeof(NoteData), nameof(NoteData.getLengthFrame));
yield return AccessTools.Method(typeof(GameManager), nameof(GameManager.UpdateGameTimer));
yield return AccessTools.PropertyGetter(typeof(NotesTime), nameof(NotesTime.frame));
}
private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions, MethodBase __originalMethod)
{
var targetFrameTime = 1000f / FrameRatePlugin.Instance.TargetFrameRate;
var targetFramePerMs = (float)FrameRatePlugin.Instance.TargetFrameRate / 1000;
var i = 0;
foreach (var instruction in instructions)
{
if (instruction.opcode != OpCodes.Ldc_R4 || instruction.operand is not float operand)
{
yield return instruction;
i++;
continue;
}
var overridden = false;
if (Math.Abs(operand - OriginalFrameTime) < float.Epsilon)
{
instruction.operand = targetFrameTime;
overridden = true;
}
else if (Math.Abs(operand - OriginalFramePerMilliseconds) < float.Epsilon)
{
instruction.operand = targetFramePerMs;
overridden = true;
}
if (overridden)
{
FrameRatePlugin.Logger.LogDebug(
"Overrode constant at opcode index {0} in {1}: {2} => {3}",
i,
__originalMethod.Name,
operand,
instruction.operand);
}
yield return instruction;
i++;
}
}
}