mirror of
https://github.com/MewoLab/AquaDX.git
synced 2026-02-15 15:07:28 +08:00
[RF] AquaMai configuration refactor (#82)
更新了配置文件格式,原有的配置文件将被自动无缝迁移,详情请见新的配置文件中的注释(例外:`SlideJudgeTweak` 不再默认启用) 旧配置文件将被重命名备份,如果更新到此版本遇到 Bug 请联系我们 Updated configuration file schema. The old config file will be migrated automatically and seamlessly. See the comments in the new configuration file for details. (Except for `SlideJudgeTweak` is no longer enabled by default) Your old configuration file will be renamed as a backup. If you encounter any bug with this version, please contact us.
This commit is contained in:
151
AquaMai/AquaMai.Mods/UX/PracticeMode/Libs/PractiseModeUI.cs
Normal file
151
AquaMai/AquaMai.Mods/UX/PracticeMode/Libs/PractiseModeUI.cs
Normal file
@@ -0,0 +1,151 @@
|
||||
using System;
|
||||
using AquaMai.Mods.Fix;
|
||||
using AquaMai.Core.Helpers;
|
||||
using AquaMai.Core.Resources;
|
||||
using Manager;
|
||||
using UnityEngine;
|
||||
|
||||
namespace AquaMai.Mods.UX.PracticeMode.Libs;
|
||||
|
||||
public class PracticeModeUI : MonoBehaviour
|
||||
{
|
||||
private static float windowTop => Screen.height - GuiSizes.PlayerWidth + GuiSizes.PlayerWidth * .22f;
|
||||
private static float controlHeight => GuiSizes.PlayerWidth * .13f;
|
||||
private static float sideButtonWidth => GuiSizes.PlayerWidth * .1f;
|
||||
private static float centerButtonWidth => GuiSizes.PlayerWidth * .28f;
|
||||
private static int fontSize => (int)(GuiSizes.PlayerWidth * .02f);
|
||||
|
||||
private static Rect GetButtonRect(int pos, int row)
|
||||
{
|
||||
float x;
|
||||
float width;
|
||||
switch (pos)
|
||||
{
|
||||
case 0:
|
||||
x = GuiSizes.PlayerCenter - centerButtonWidth / 2 - sideButtonWidth - GuiSizes.Margin;
|
||||
width = sideButtonWidth;
|
||||
break;
|
||||
case 1:
|
||||
x = GuiSizes.PlayerCenter - centerButtonWidth / 2;
|
||||
width = centerButtonWidth;
|
||||
break;
|
||||
case 2:
|
||||
x = GuiSizes.PlayerCenter + centerButtonWidth / 2 + GuiSizes.Margin;
|
||||
width = sideButtonWidth;
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException(nameof(pos), pos, null);
|
||||
}
|
||||
|
||||
return new Rect(x, windowTop + (GuiSizes.Margin + controlHeight) * row + GuiSizes.Margin, width, controlHeight);
|
||||
}
|
||||
|
||||
public void OnGUI()
|
||||
{
|
||||
var labelStyle = GUI.skin.GetStyle("label");
|
||||
labelStyle.fontSize = fontSize;
|
||||
labelStyle.alignment = TextAnchor.MiddleCenter;
|
||||
|
||||
var buttonStyle = GUI.skin.GetStyle("button");
|
||||
buttonStyle.fontSize = fontSize;
|
||||
|
||||
GUI.Box(new Rect(
|
||||
GuiSizes.PlayerCenter - centerButtonWidth / 2 - sideButtonWidth - GuiSizes.Margin * 2,
|
||||
windowTop,
|
||||
centerButtonWidth + sideButtonWidth * 2 + GuiSizes.Margin * 4,
|
||||
controlHeight * 4 + GuiSizes.Margin * 5
|
||||
), "");
|
||||
|
||||
GUI.Button(GetButtonRect(0, 0), Locale.SeekBackward);
|
||||
GUI.Button(GetButtonRect(1, 0), Locale.Pause);
|
||||
GUI.Button(GetButtonRect(2, 0), Locale.SeekForward);
|
||||
|
||||
if (PracticeMode.repeatStart == -1)
|
||||
{
|
||||
GUI.Button(GetButtonRect(0, 1), Locale.MarkRepeatStart);
|
||||
GUI.Label(GetButtonRect(1, 1), Locale.RepeatNotSet);
|
||||
}
|
||||
else if (PracticeMode.repeatEnd == -1)
|
||||
{
|
||||
GUI.Button(GetButtonRect(0, 1), Locale.MarkRepeatEnd);
|
||||
GUI.Label(GetButtonRect(1, 1), Locale.RepeatStartSet);
|
||||
GUI.Button(GetButtonRect(2, 1), Locale.RepeatReset);
|
||||
}
|
||||
else
|
||||
{
|
||||
GUI.Label(GetButtonRect(1, 1), Locale.RepeatStartEndSet);
|
||||
GUI.Button(GetButtonRect(2, 1), Locale.RepeatReset);
|
||||
}
|
||||
|
||||
GUI.Button(GetButtonRect(0, 2), Locale.SpeedDown);
|
||||
GUI.Label(GetButtonRect(1, 2), $"{Locale.Speed} {PracticeMode.speed * 100:000}%");
|
||||
GUI.Button(GetButtonRect(2, 2), Locale.SpeedUp);
|
||||
GUI.Button(GetButtonRect(1, 3), Locale.SpeedReset);
|
||||
|
||||
GUI.Label(GetButtonRect(0, 3), $"{TimeSpan.FromMilliseconds(PracticeMode.CurrentPlayMsec):mm\\:ss\\.fff}\n{TimeSpan.FromMilliseconds(NotesManager.Instance().getPlayFinalMsec()):mm\\:ss\\.fff}");
|
||||
GUI.Button(GetButtonRect(2, 3), $"保持流速\n{(PracticeMode.keepNoteSpeed ? "ON" : "OFF")}");
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
if (InputManager.GetTouchPanelAreaDown(InputManager.TouchPanelArea.E8))
|
||||
{
|
||||
PracticeMode.Seek(-1000);
|
||||
}
|
||||
else if (InputManager.GetTouchPanelAreaDown(InputManager.TouchPanelArea.E2))
|
||||
{
|
||||
PracticeMode.Seek(1000);
|
||||
}
|
||||
else if (InputManager.GetTouchPanelAreaDown(InputManager.TouchPanelArea.B8) || InputManager.GetTouchPanelAreaDown(InputManager.TouchPanelArea.B1))
|
||||
{
|
||||
DebugFeature.Pause = !DebugFeature.Pause;
|
||||
if (!DebugFeature.Pause)
|
||||
{
|
||||
PracticeMode.Seek(0);
|
||||
}
|
||||
}
|
||||
else if (InputManager.GetTouchPanelAreaDown(InputManager.TouchPanelArea.B7) && PracticeMode.repeatStart == -1)
|
||||
{
|
||||
PracticeMode.repeatStart = PracticeMode.CurrentPlayMsec;
|
||||
}
|
||||
else if (InputManager.GetTouchPanelAreaDown(InputManager.TouchPanelArea.B7) && PracticeMode.repeatEnd == -1)
|
||||
{
|
||||
PracticeMode.SetRepeatEnd(PracticeMode.CurrentPlayMsec);
|
||||
}
|
||||
else if (InputManager.GetTouchPanelAreaDown(InputManager.TouchPanelArea.B2))
|
||||
{
|
||||
PracticeMode.ClearRepeat();
|
||||
}
|
||||
else if (InputManager.GetTouchPanelAreaDown(InputManager.TouchPanelArea.B6))
|
||||
{
|
||||
PracticeMode.SpeedDown();
|
||||
}
|
||||
else if (InputManager.GetTouchPanelAreaDown(InputManager.TouchPanelArea.B3))
|
||||
{
|
||||
PracticeMode.SpeedUp();
|
||||
}
|
||||
else if (InputManager.GetTouchPanelAreaDown(InputManager.TouchPanelArea.B5) || InputManager.GetTouchPanelAreaDown(InputManager.TouchPanelArea.B4))
|
||||
{
|
||||
PracticeMode.SpeedReset();
|
||||
}
|
||||
else if (InputManager.GetTouchPanelAreaDown(InputManager.TouchPanelArea.E4))
|
||||
{
|
||||
PracticeMode.keepNoteSpeed = !PracticeMode.keepNoteSpeed;
|
||||
PracticeMode.gameCtrl?.ResetOptionSpeed();
|
||||
}
|
||||
else if (
|
||||
InputManager.GetTouchPanelAreaDown(InputManager.TouchPanelArea.A1) ||
|
||||
InputManager.GetTouchPanelAreaDown(InputManager.TouchPanelArea.A2) ||
|
||||
InputManager.GetTouchPanelAreaDown(InputManager.TouchPanelArea.A3) ||
|
||||
InputManager.GetTouchPanelAreaDown(InputManager.TouchPanelArea.A4) ||
|
||||
InputManager.GetTouchPanelAreaDown(InputManager.TouchPanelArea.A5) ||
|
||||
InputManager.GetTouchPanelAreaDown(InputManager.TouchPanelArea.A6) ||
|
||||
InputManager.GetTouchPanelAreaDown(InputManager.TouchPanelArea.A7) ||
|
||||
InputManager.GetTouchPanelAreaDown(InputManager.TouchPanelArea.A8)
|
||||
)
|
||||
{
|
||||
PracticeMode.ui = null;
|
||||
Destroy(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
282
AquaMai/AquaMai.Mods/UX/PracticeMode/PracticeMode.cs
Normal file
282
AquaMai/AquaMai.Mods/UX/PracticeMode/PracticeMode.cs
Normal file
@@ -0,0 +1,282 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using AquaMai.Mods.Fix;
|
||||
using AquaMai.Core.Helpers;
|
||||
using AquaMai.Core.Resources;
|
||||
using AquaMai.Mods.UX.PracticeMode.Libs;
|
||||
using HarmonyLib;
|
||||
using Manager;
|
||||
using Monitor;
|
||||
using Monitor.Game;
|
||||
using Process;
|
||||
using UnityEngine;
|
||||
using AquaMai.Config.Attributes;
|
||||
using AquaMai.Config.Types;
|
||||
|
||||
namespace AquaMai.Mods.UX.PracticeMode;
|
||||
|
||||
[ConfigCollapseNamespace]
|
||||
[ConfigSection(
|
||||
en: "Practice Mode.",
|
||||
zh: "练习模式")]
|
||||
public class PracticeMode
|
||||
{
|
||||
[ConfigEntry(
|
||||
en: "Key to show Practice Mode UI.",
|
||||
zh: "显示练习模式 UI 的按键")]
|
||||
public static readonly KeyCodeOrName key = KeyCodeOrName.Test;
|
||||
|
||||
[ConfigEntry]
|
||||
public static readonly bool longPress = false;
|
||||
|
||||
public static double repeatStart = -1;
|
||||
public static double repeatEnd = -1;
|
||||
public static float speed = 1;
|
||||
private static CriAtomExPlayer player;
|
||||
private static MovieMaterialMai2 movie;
|
||||
public static GameCtrl gameCtrl;
|
||||
public static bool keepNoteSpeed = false;
|
||||
|
||||
public static void SetRepeatEnd(double time)
|
||||
{
|
||||
if (repeatStart == -1)
|
||||
{
|
||||
MessageHelper.ShowMessage(Locale.RepeatStartTimeNotSet);
|
||||
return;
|
||||
}
|
||||
|
||||
if (time < repeatStart)
|
||||
{
|
||||
MessageHelper.ShowMessage(Locale.RepeatEndTimeLessThenStartTime);
|
||||
return;
|
||||
}
|
||||
|
||||
repeatEnd = time;
|
||||
}
|
||||
|
||||
public static void ClearRepeat()
|
||||
{
|
||||
repeatStart = -1;
|
||||
repeatEnd = -1;
|
||||
}
|
||||
|
||||
public static void SetSpeed()
|
||||
{
|
||||
player.SetPitch((float)(1200 * Math.Log(speed, 2)));
|
||||
// player.SetDspTimeStretchRatio(1 / speed);
|
||||
player.UpdateAll();
|
||||
|
||||
movie.player.SetSpeed(speed);
|
||||
gameCtrl?.ResetOptionSpeed();
|
||||
}
|
||||
|
||||
private static IEnumerator SetSpeedCoroutineInner()
|
||||
{
|
||||
yield return null;
|
||||
SetSpeed();
|
||||
}
|
||||
|
||||
public static void SetSpeedCoroutine()
|
||||
{
|
||||
SharedInstances.GameMainObject.StartCoroutine(SetSpeedCoroutineInner());
|
||||
}
|
||||
|
||||
public static void SpeedUp()
|
||||
{
|
||||
speed += .05f;
|
||||
if (speed > 2)
|
||||
{
|
||||
speed = 2;
|
||||
}
|
||||
|
||||
SetSpeed();
|
||||
}
|
||||
|
||||
public static void SpeedDown()
|
||||
{
|
||||
speed -= .05f;
|
||||
if (speed < 0.05)
|
||||
{
|
||||
speed = 0.05f;
|
||||
}
|
||||
|
||||
SetSpeed();
|
||||
}
|
||||
|
||||
public static void SpeedReset()
|
||||
{
|
||||
speed = 1;
|
||||
SetSpeed();
|
||||
}
|
||||
|
||||
public static void Seek(int addMsec)
|
||||
{
|
||||
// Debug feature 里面那个 timer 不能感知变速
|
||||
// 为了和魔改版本统一,polyfill 里面不修这个
|
||||
// 这里重新实现一个能感知变速的 Seek
|
||||
var msec = CurrentPlayMsec + addMsec;
|
||||
if (msec < 0)
|
||||
{
|
||||
msec = 0;
|
||||
}
|
||||
|
||||
CurrentPlayMsec = msec;
|
||||
}
|
||||
|
||||
public static double CurrentPlayMsec
|
||||
{
|
||||
get => NotesManager.GetCurrentMsec() - 91;
|
||||
set
|
||||
{
|
||||
DebugFeature.CurrentPlayMsec = value;
|
||||
SetSpeedCoroutine();
|
||||
}
|
||||
}
|
||||
|
||||
public static PracticeModeUI ui;
|
||||
|
||||
[HarmonyPatch]
|
||||
public class PatchNoteSpeed
|
||||
{
|
||||
public static IEnumerable<MethodBase> TargetMethods()
|
||||
{
|
||||
yield return AccessTools.Method(typeof(GameManager), "GetNoteSpeed");
|
||||
yield return AccessTools.Method(typeof(GameManager), "GetTouchSpeed");
|
||||
}
|
||||
|
||||
public static void Postfix(ref float __result)
|
||||
{
|
||||
if (!keepNoteSpeed) return;
|
||||
__result /= speed;
|
||||
}
|
||||
}
|
||||
|
||||
[HarmonyPatch(typeof(GameProcess), "OnStart")]
|
||||
[HarmonyPostfix]
|
||||
public static void GameProcessPostStart()
|
||||
{
|
||||
repeatStart = -1;
|
||||
repeatEnd = -1;
|
||||
speed = 1;
|
||||
ui = null;
|
||||
}
|
||||
|
||||
[HarmonyPatch(typeof(GameProcess), "OnRelease")]
|
||||
[HarmonyPostfix]
|
||||
public static void GameProcessPostRelease()
|
||||
{
|
||||
repeatStart = -1;
|
||||
repeatEnd = -1;
|
||||
speed = 1;
|
||||
ui = null;
|
||||
}
|
||||
|
||||
[HarmonyPatch(typeof(GameCtrl), "Initialize")]
|
||||
[HarmonyPostfix]
|
||||
public static void GameCtrlPostInitialize(GameCtrl __instance)
|
||||
{
|
||||
gameCtrl = __instance;
|
||||
}
|
||||
|
||||
# if DEBUG
|
||||
[HarmonyPrefix]
|
||||
[HarmonyPatch(typeof(GenericProcess), "OnUpdate")]
|
||||
public static void OnGenericProcessUpdate(GenericMonitor[] ____monitors)
|
||||
{
|
||||
if (Input.GetKeyDown(KeyCode.F11))
|
||||
{
|
||||
____monitors[0].gameObject.AddComponent<PracticeModeUI>();
|
||||
}
|
||||
}
|
||||
# endif
|
||||
|
||||
[HarmonyPatch(typeof(GameProcess), "OnUpdate")]
|
||||
[HarmonyPostfix]
|
||||
public static void GameProcessPostUpdate(GameProcess __instance, GameMonitor[] ____monitors)
|
||||
{
|
||||
if (KeyListener.GetKeyDownOrLongPress(key, longPress) && ui is null)
|
||||
{
|
||||
ui = ____monitors[0].gameObject.AddComponent<PracticeModeUI>();
|
||||
}
|
||||
|
||||
if (repeatStart >= 0 && repeatEnd >= 0)
|
||||
{
|
||||
if (CurrentPlayMsec >= repeatEnd)
|
||||
{
|
||||
CurrentPlayMsec = repeatStart;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static float startGap = -1f;
|
||||
|
||||
[HarmonyPatch(typeof(NotesManager), "StartPlay")]
|
||||
[HarmonyPostfix]
|
||||
public static void NotesManagerPostUpdateTimer(float msecStartGap)
|
||||
{
|
||||
startGap = msecStartGap;
|
||||
}
|
||||
|
||||
[HarmonyPatch(typeof(NotesManager), "UpdateTimer")]
|
||||
[HarmonyPrefix]
|
||||
public static bool NotesManagerPostUpdateTimer(bool ____isPlaying, Stopwatch ____stopwatch, ref float ____curMSec, ref float ____curMSecPre, float ____msecStartGap)
|
||||
{
|
||||
var stackTrace = new StackTrace(); // get call stack
|
||||
var stackFrames = stackTrace.GetFrames(); // get method calls (frames)
|
||||
if(stackFrames.Select(it => it.GetMethod().DeclaringType.Name).Contains("AdvDemoProcess"))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (startGap != -1f)
|
||||
{
|
||||
____curMSec = startGap;
|
||||
____curMSecPre = startGap;
|
||||
____stopwatch?.Reset();
|
||||
startGap = -1f;
|
||||
}
|
||||
else
|
||||
{
|
||||
____curMSecPre = ____curMSec;
|
||||
if (____isPlaying && ____stopwatch != null && !DebugFeature.Pause)
|
||||
{
|
||||
var num = (double)____stopwatch.ElapsedTicks / Stopwatch.Frequency * 1000.0 * speed;
|
||||
____curMSec += (float)num;
|
||||
____stopwatch.Reset();
|
||||
____stopwatch.Start();
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
[HarmonyPatch(typeof(SoundCtrl), "Initialize")]
|
||||
[HarmonyPostfix]
|
||||
public static void SoundCtrlPostInitialize(SoundCtrl.InitParam param, Dictionary<int, object> ____players)
|
||||
{
|
||||
var wrapper = ____players[2];
|
||||
player = (CriAtomExPlayer)wrapper.GetType().GetField("Player").GetValue(wrapper);
|
||||
// var pool = new CriAtomExStandardVoicePool(1, 8, 96000, true, 2);
|
||||
// pool.AttachDspTimeStretch();
|
||||
// player.SetVoicePoolIdentifier(pool.identifier);
|
||||
|
||||
// debug
|
||||
// var wrapper1 = ____players[7];
|
||||
// var player1 = (CriAtomExPlayer)wrapper1.GetType().GetField("Player").GetValue(wrapper1);
|
||||
// var pool = new CriAtomExStandardVoicePool(1, 8, 96000, true, 2);
|
||||
// pool.AttachDspTimeStretch();
|
||||
// player1.SetVoicePoolIdentifier(pool.identifier);
|
||||
// player1.SetDspTimeStretchRatio(2);
|
||||
}
|
||||
|
||||
[HarmonyPatch(typeof(MovieController), "Awake")]
|
||||
[HarmonyPostfix]
|
||||
public static void MovieControllerPostAwake(MovieMaterialMai2 ____moviePlayers)
|
||||
{
|
||||
movie = ____moviePlayers;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user