Skip to content

Commit

Permalink
[+] Configurable mod key map manager
Browse files Browse the repository at this point in the history
  • Loading branch information
clansty committed Nov 1, 2024
1 parent ac4db91 commit fb96e93
Show file tree
Hide file tree
Showing 14 changed files with 331 additions and 136 deletions.
4 changes: 4 additions & 0 deletions AquaMai/Config.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@ 试试使用 MaiChartManager 图形化配置 AquaMai 吧!
zh: "音符和判定表示以及一些其他贴图的视觉效果调整")]
public Visual.Config Visual { get; set; } = new();

[ConfigComment(
zh: "Mod 内功能的按键设置")]
public ModKeyMap.Config ModKeyMap { get; set; } = new();

[ConfigComment(
zh: "窗口相关设置")]
public WindowState.Config WindowState { get; set; } = new();
Expand Down
28 changes: 28 additions & 0 deletions AquaMai/Fix/FestivalQuickRetryFix.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
using AquaMai.Attributes;
using HarmonyLib;
using Manager;

namespace AquaMai.Fix;

[GameVersion(23000, 23499)]
public class FestivalQuickRetryFix
{
// Fix for the game not resetting Fast and Late counts when quick retrying
// For game version < 1.35.0
[HarmonyPostfix]
[HarmonyPatch(typeof(GamePlayManager), "SetQuickRetryFrag")]
public static void PostGamePlayManagerSetQuickRetryFrag(GamePlayManager __instance, bool flag)
{
// Since 1.35.0, `GameScoreList.Initialize()` resets the Fast and Late counts
if (flag && !Traverse.Create(typeof(GameScoreList)).Methods().Contains("Initialize"))
{
for (int i = 0; i < 4; i++)
{
var gameScoreList = __instance.GetGameScore(i);
var traverse = Traverse.Create(gameScoreList);
traverse.Property("Fast").SetValue((uint)0);
traverse.Property("Late").SetValue((uint)0);
}
}
}
}
9 changes: 9 additions & 0 deletions AquaMai/Main.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using AquaMai.Attributes;
using AquaMai.Fix;
using AquaMai.Helpers;
using AquaMai.ModKeyMap;
using AquaMai.Resources;
using AquaMai.Utils;
using AquaMai.UX;
Expand Down Expand Up @@ -167,6 +168,7 @@ public override void OnInitializeMelon()
Patch(typeof(FixCheckAuth));
Patch(typeof(DebugFeature));
Patch(typeof(FixConnSlide));
Patch(typeof(FestivalQuickRetryFix));
// Visual
Patch(typeof(FixSlideAutoPlay)); // Rename: SlideAutoPlayTweak -> FixSlideAutoPlay, 不过这个应该无副作用所以不需要改配置文件
Patch(typeof(FixCircleSlideJudge)); // 这个我觉得算无副作用, 可以常开
Expand All @@ -179,6 +181,13 @@ public override void OnInitializeMelon()
// Utils
Patch(typeof(JudgeAdjust));
Patch(typeof(TouchPanelBaudRate));
// ModKeyMap
// TODO: Make it configurable
Patch(typeof(ModKeyListener));
Patch(typeof(QuickSkip));
Patch(typeof(TestProof));
Patch(typeof(PractiseMode));
Patch(typeof(HideSelfMadeCharts));

// Apply patches based on the settings
ApplyPatches();
Expand Down
54 changes: 54 additions & 0 deletions AquaMai/ModKeyMap/Config.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
using AquaMai.Attributes;

namespace AquaMai.ModKeyMap;

public class Config
{
[ConfigComment(
en: "Skip to next step",
zh: """
跳过登录过程中的界面直接进入选歌界面
在选歌界面直接结束游戏
""")]
public ModKeyCode QuickSkip { get; set; } = ModKeyCode.None;

public bool QuickSkipLongPress { get; set; }

[ConfigComment(
en: "Quick retry in-game",
zh: "游戏内快速重试")]
public ModKeyCode InGameRetry { get; set; } = ModKeyCode.None;

public bool InGameRetryLongPress { get; set; }

[ConfigComment(
en: "Quick skip in-game",
zh: "游戏内快速跳过")]
public ModKeyCode InGameSkip { get; set; } = ModKeyCode.None;

public bool InGameSkipLongPress { get; set; }

[ConfigComment(
en: "Enter game test mode",
zh: "进入游戏测试模式")]
public ModKeyCode TestMode { get; set; } = ModKeyCode.Test;

public bool TestModeLongPress { get; set; }

[ConfigComment(
zh: "练习模式")]
public ModKeyCode PractiseMode { get; set; } = ModKeyCode.None;

public bool PractiseModeLongPress { get; set; }

[ConfigComment(
zh: "选歌界面隐藏所有自制谱")]
public ModKeyCode HideSelfMadeCharts { get; set; } = ModKeyCode.None;

public bool HideSelfMadeChartsLongPress { get; set; }

[ConfigComment(
en: "Hold the bottom four buttons (3456) for official quick retry (non-utage only)",
zh: "按住下方四个按钮(3456)使用官方快速重开(仅对非宴谱有效)")]
public bool EnableNativeQuickRetry { get; set; }
}
19 changes: 19 additions & 0 deletions AquaMai/ModKeyMap/EnableNativeQuickRetry.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
using AquaMai.Attributes;
using HarmonyLib;
using Manager;
using Monitor;

namespace AquaMai.ModKeyMap;

[GameVersion(23000)]
public class EnableNativeQuickRetry
{
[HarmonyPrefix]
[HarmonyPatch(typeof(QuickRetry), "IsQuickRetryEnable")]
public static bool OnQuickRetryIsQuickRetryEnable(ref bool __result)
{
var isUtageProperty = Traverse.Create(typeof(GameManager)).Property("IsUtage");
__result = !isUtageProperty.PropertyExists() || !isUtageProperty.GetValue<bool>();
return false;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
using UnityEngine;
using Util;

namespace AquaMai.UX;
namespace AquaMai.ModKeyMap;

public class HideSelfMadeCharts
{
Expand Down Expand Up @@ -53,33 +53,20 @@ public static void GetMusics(ref Safe.ReadonlySortedDictionary<int, Manager.MaiS
__result = _musicsNoneSelfMade;
}

private static int _keyPressFrames;

[HarmonyPostfix]
[HarmonyPatch(typeof(MusicSelectProcess), "OnUpdate")]
public static void MusicSelectProcessOnUpdate(ref MusicSelectProcess __instance)
{
if (isForceDisable) return;
if (Input.GetKey(KeyCode.Alpha7) || InputManager.GetSystemInputPush(InputManager.SystemButtonSetting.ButtonService))
{
_keyPressFrames++;
}
else if (_keyPressFrames is > 0 and < 30 && !Input.GetKey(KeyCode.Alpha7) && !InputManager.GetSystemInputPush(InputManager.SystemButtonSetting.ButtonService))
if (!ModKeyListener.GetKeyDownOrLongPress(AquaMai.AppConfig.ModKeyMap.HideSelfMadeCharts, AquaMai.AppConfig.ModKeyMap.HideSelfMadeChartsLongPress)) return;
isShowSelfMadeCharts = !isShowSelfMadeCharts;
MelonLogger.Msg($"[HideSelfMadeCharts] isShowSelfMadeCharts: {isShowSelfMadeCharts}");
SharedInstances.ProcessDataContainer.processManager.AddProcess(new FadeProcess(SharedInstances.ProcessDataContainer, __instance, new MusicSelectProcess(SharedInstances.ProcessDataContainer)));
Task.Run(async () =>
{
_keyPressFrames = 0;
isShowSelfMadeCharts = !isShowSelfMadeCharts;
MelonLogger.Msg($"[HideSelfMadeCharts] isShowSelfMadeCharts: {isShowSelfMadeCharts}");
SharedInstances.ProcessDataContainer.processManager.AddProcess(new FadeProcess(SharedInstances.ProcessDataContainer, __instance, new MusicSelectProcess(SharedInstances.ProcessDataContainer)));
Task.Run(async () =>
{
await Task.Delay(1000);
MessageHelper.ShowMessage($"{(isShowSelfMadeCharts ? "Show" : "Hide")} Self-Made Charts");
});
}
else
{
_keyPressFrames = 0;
}
await Task.Delay(1000);
MessageHelper.ShowMessage($"{(isShowSelfMadeCharts ? "Show" : "Hide")} Self-Made Charts");
});
}

[HarmonyPrefix]
Expand Down
53 changes: 53 additions & 0 deletions AquaMai/ModKeyMap/ModKeyCode.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
namespace AquaMai.ModKeyMap;

public enum ModKeyCode
{
None,
Alpha0,
Alpha1,
Alpha2,
Alpha3,
Alpha4,
Alpha5,
Alpha6,
Alpha7,
Alpha8,
Alpha9,
Keypad0,
Keypad1,
Keypad2,
Keypad3,
Keypad4,
Keypad5,
Keypad6,
Keypad7,
Keypad8,
Keypad9,
F1,
F2,
F3,
F4,
F5,
F6,
F7,
F8,
F9,
F10,
F11,
F12,
Insert,
Delete,
Home,
End,
PageUp,
PageDown,
UpArrow,
DownArrow,
LeftArrow,
RightArrow,

Select1P,
Select2P,
Service,
Test,
}
145 changes: 145 additions & 0 deletions AquaMai/ModKeyMap/ModKeyListener.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using HarmonyLib;
using Main;
using Manager;
using MelonLoader;
using UnityEngine;

namespace AquaMai.ModKeyMap;

public static class ModKeyListener
{
private static readonly Dictionary<ModKeyCode, int> _keyPressFrames = new();
private static readonly Dictionary<ModKeyCode, int> _keyPressFramesPrev = new();

static ModKeyListener()
{
foreach (ModKeyCode key in Enum.GetValues(typeof(ModKeyCode)))
{
_keyPressFrames[key] = 0;
_keyPressFramesPrev[key] = 0;
}
}

[HarmonyPostfix]
[HarmonyPatch(typeof(GameMainObject), "Update")]
public static void CheckLongPush()
{
foreach (ModKeyCode key in Enum.GetValues(typeof(ModKeyCode)))
{
_keyPressFramesPrev[key] = _keyPressFrames[key];
if (GetKeyPush(key))
{
# if DEBUG
MelonLogger.Msg($"CheckLongPush {key} is push {_keyPressFrames[key]}");
# endif
_keyPressFrames[key]++;
}
else
{
_keyPressFrames[key] = 0;
}
}
}

public static bool GetKeyPush(ModKeyCode key) =>
key switch
{
ModKeyCode.None => false,
< ModKeyCode.Select1P => Input.GetKey(key.GetKeyCode()),
ModKeyCode.Test => InputManager.GetSystemInputPush(InputManager.SystemButtonSetting.ButtonTest),
ModKeyCode.Service => InputManager.GetSystemInputPush(InputManager.SystemButtonSetting.ButtonService),
ModKeyCode.Select1P => InputManager.GetButtonPush(0, InputManager.ButtonSetting.Select),
ModKeyCode.Select2P => InputManager.GetButtonPush(1, InputManager.ButtonSetting.Select),
_ => throw new ArgumentOutOfRangeException(nameof(key), key, "我也不知道这是什么键")
};

public static bool GetKeyDown(ModKeyCode key)
{
// return key switch
// {
// ModKeyCode.None => false,
// < ModKeyCode.Select1P => Input.GetKeyDown(key.GetKeyCode()),
// ModKeyCode.Test => InputManager.GetSystemInputDown(InputManager.SystemButtonSetting.ButtonTest),
// ModKeyCode.Service => InputManager.GetSystemInputDown(InputManager.SystemButtonSetting.ButtonService),
// ModKeyCode.Select1P => InputManager.GetButtonDown(0, InputManager.ButtonSetting.Select),
// ModKeyCode.Select2P => InputManager.GetButtonDown(1, InputManager.ButtonSetting.Select),
// _ => throw new ArgumentOutOfRangeException(nameof(key), key, "我也不知道这是什么键")
// };

// 不用这个,我们检测按键是否弹起以及弹起之前按下的时间是否小于 30,这样可以防止要长按时按下的时候就触发
return _keyPressFrames[key] == 0 && 0 < _keyPressFramesPrev[key] && _keyPressFramesPrev[key] < 30;
}

public static bool GetKeyDownOrLongPress(ModKeyCode key, bool isLongPress)
{
bool ret;
if (isLongPress)
{
ret = _keyPressFrames[key] == 60;
}
else
{
ret = GetKeyDown(key);
}

# if DEBUG
if (ret)
{
MelonLogger.Msg($"Key {key} is pressed");
MelonLogger.Msg(new StackTrace());
}
# endif
return ret;
}

private static KeyCode GetKeyCode(this ModKeyCode modKeyCode) =>
modKeyCode switch
{
ModKeyCode.Alpha0 => KeyCode.Alpha0,
ModKeyCode.Alpha1 => KeyCode.Alpha1,
ModKeyCode.Alpha2 => KeyCode.Alpha2,
ModKeyCode.Alpha3 => KeyCode.Alpha3,
ModKeyCode.Alpha4 => KeyCode.Alpha4,
ModKeyCode.Alpha5 => KeyCode.Alpha5,
ModKeyCode.Alpha6 => KeyCode.Alpha6,
ModKeyCode.Alpha7 => KeyCode.Alpha7,
ModKeyCode.Alpha8 => KeyCode.Alpha8,
ModKeyCode.Alpha9 => KeyCode.Alpha9,
ModKeyCode.Keypad0 => KeyCode.Keypad0,
ModKeyCode.Keypad1 => KeyCode.Keypad1,
ModKeyCode.Keypad2 => KeyCode.Keypad2,
ModKeyCode.Keypad3 => KeyCode.Keypad3,
ModKeyCode.Keypad4 => KeyCode.Keypad4,
ModKeyCode.Keypad5 => KeyCode.Keypad5,
ModKeyCode.Keypad6 => KeyCode.Keypad6,
ModKeyCode.Keypad7 => KeyCode.Keypad7,
ModKeyCode.Keypad8 => KeyCode.Keypad8,
ModKeyCode.Keypad9 => KeyCode.Keypad9,
ModKeyCode.F1 => KeyCode.F1,
ModKeyCode.F2 => KeyCode.F2,
ModKeyCode.F3 => KeyCode.F3,
ModKeyCode.F4 => KeyCode.F4,
ModKeyCode.F5 => KeyCode.F5,
ModKeyCode.F6 => KeyCode.F6,
ModKeyCode.F7 => KeyCode.F7,
ModKeyCode.F8 => KeyCode.F8,
ModKeyCode.F9 => KeyCode.F9,
ModKeyCode.F10 => KeyCode.F10,
ModKeyCode.F11 => KeyCode.F11,
ModKeyCode.F12 => KeyCode.F12,
ModKeyCode.Insert => KeyCode.Insert,
ModKeyCode.Delete => KeyCode.Delete,
ModKeyCode.Home => KeyCode.Home,
ModKeyCode.End => KeyCode.End,
ModKeyCode.PageUp => KeyCode.PageUp,
ModKeyCode.PageDown => KeyCode.PageDown,
ModKeyCode.UpArrow => KeyCode.UpArrow,
ModKeyCode.DownArrow => KeyCode.DownArrow,
ModKeyCode.LeftArrow => KeyCode.LeftArrow,
ModKeyCode.RightArrow => KeyCode.RightArrow,
_ => throw new ArgumentOutOfRangeException(nameof(modKeyCode), modKeyCode, "游戏功能键需要单独处理")
};
}
Loading

0 comments on commit fb96e93

Please sign in to comment.