mirror of https://github.com/hykilpikonna/AquaDX
Merge branch 'v1-dev' of https://github.com/hykilpikonna/AquaDX into v1-dev
commit
08a1595d3e
|
@ -298,14 +298,19 @@ DEBUG</DefineConstants>
|
||||||
<Compile Include="Fix\ExtendNotesPool.cs" />
|
<Compile Include="Fix\ExtendNotesPool.cs" />
|
||||||
<Compile Include="Fix\FixCharaCrash.cs" />
|
<Compile Include="Fix\FixCharaCrash.cs" />
|
||||||
<Compile Include="Fix\FixCheckAuth.cs" />
|
<Compile Include="Fix\FixCheckAuth.cs" />
|
||||||
|
<Compile Include="Fix\FixConnSlide.cs" />
|
||||||
|
<Compile Include="Fix\FixLevelDisplay.cs" />
|
||||||
<Compile Include="Fix\FontFix.cs" />
|
<Compile Include="Fix\FontFix.cs" />
|
||||||
<Compile Include="Fix\ForceAsServer.cs" />
|
<Compile Include="Fix\ForceAsServer.cs" />
|
||||||
<Compile Include="Fix\ForceFreePlay.cs" />
|
<Compile Include="Fix\ForceFreePlay.cs" />
|
||||||
<Compile Include="Fix\ForcePaidPlay.cs" />
|
<Compile Include="Fix\ForcePaidPlay.cs" />
|
||||||
<Compile Include="Fix\FrameRateLock.cs" />
|
<Compile Include="Fix\FrameRateLock.cs" />
|
||||||
|
<Compile Include="Fix\HanabiFix.cs" />
|
||||||
<Compile Include="Fix\I18nSingleAssemblyHook.cs" />
|
<Compile Include="Fix\I18nSingleAssemblyHook.cs" />
|
||||||
<Compile Include="Fix\RemoveEncryption.cs" />
|
<Compile Include="Fix\RemoveEncryption.cs" />
|
||||||
<Compile Include="Fix\SkipVersionCheck.cs" />
|
<Compile Include="Fix\SkipVersionCheck.cs" />
|
||||||
|
<Compile Include="Fix\SlideAutoPlayTweak.cs" />
|
||||||
|
<Compile Include="Fix\SlideJudgeTweak.cs" />
|
||||||
<Compile Include="Helpers\GuiSizes.cs" />
|
<Compile Include="Helpers\GuiSizes.cs" />
|
||||||
<Compile Include="Helpers\MessageHelper.cs" />
|
<Compile Include="Helpers\MessageHelper.cs" />
|
||||||
<Compile Include="Helpers\MusicDirHelper.cs" />
|
<Compile Include="Helpers\MusicDirHelper.cs" />
|
||||||
|
@ -334,10 +339,13 @@ DEBUG</DefineConstants>
|
||||||
<Compile Include="Utils\SelectionDetail.cs" />
|
<Compile Include="Utils\SelectionDetail.cs" />
|
||||||
<Compile Include="Utils\ShowNetErrorDetail.cs" />
|
<Compile Include="Utils\ShowNetErrorDetail.cs" />
|
||||||
<Compile Include="UX\CustomFont.cs" />
|
<Compile Include="UX\CustomFont.cs" />
|
||||||
|
<Compile Include="UX\CustomLogo.cs" />
|
||||||
|
<Compile Include="UX\CustomNoteSkin.cs" />
|
||||||
<Compile Include="UX\CustomPlaceName.cs" />
|
<Compile Include="UX\CustomPlaceName.cs" />
|
||||||
<Compile Include="UX\CustomVersionString.cs" />
|
<Compile Include="UX\CustomVersionString.cs" />
|
||||||
<Compile Include="UX\DemoMaster.cs" />
|
<Compile Include="UX\DemoMaster.cs" />
|
||||||
<Compile Include="UX\ExtendTimer.cs" />
|
<Compile Include="UX\ExtendTimer.cs" />
|
||||||
|
<Compile Include="UX\HideHanabi.cs" />
|
||||||
<Compile Include="UX\HideMask.cs" />
|
<Compile Include="UX\HideMask.cs" />
|
||||||
<Compile Include="UX\HideSelfMadeCharts.cs" />
|
<Compile Include="UX\HideSelfMadeCharts.cs" />
|
||||||
<Compile Include="UX\ImmediateSave.cs" />
|
<Compile Include="UX\ImmediateSave.cs" />
|
||||||
|
@ -349,6 +357,7 @@ DEBUG</DefineConstants>
|
||||||
<Compile Include="UX\RunCommandOnEvents.cs" />
|
<Compile Include="UX\RunCommandOnEvents.cs" />
|
||||||
<Compile Include="UX\SinglePlayer.cs" />
|
<Compile Include="UX\SinglePlayer.cs" />
|
||||||
<Compile Include="UX\TestProof.cs" />
|
<Compile Include="UX\TestProof.cs" />
|
||||||
|
<Compile Include="UX\TrackStartProcessTweak.cs" />
|
||||||
<Compile Include="WindowState\Enable.cs" />
|
<Compile Include="WindowState\Enable.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -369,9 +378,6 @@ DEBUG</DefineConstants>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Content Include="FodyWeavers.xml" />
|
<Content Include="FodyWeavers.xml" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
|
||||||
<Folder Include="Performance\" />
|
|
||||||
</ItemGroup>
|
|
||||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||||
<Import Project="packages\Fody.6.8.1\build\Fody.targets" Condition="Exists('packages\Fody.6.8.1\build\Fody.targets')" />
|
<Import Project="packages\Fody.6.8.1\build\Fody.targets" Condition="Exists('packages\Fody.6.8.1\build\Fody.targets')" />
|
||||||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||||
|
|
|
@ -53,6 +53,14 @@ HideSelfMadeCharts=true
|
||||||
# Place font.ttf in the LocalAssets directory to replace the game's global font
|
# Place font.ttf in the LocalAssets directory to replace the game's global font
|
||||||
# Cannot be used together with FontFix
|
# Cannot be used together with FontFix
|
||||||
CustomFont=false
|
CustomFont=false
|
||||||
|
# Provide the ability to use custom note skins (advanced feature)
|
||||||
|
CustomNoteSkin=false
|
||||||
|
# Delayed the animation of the song start screen
|
||||||
|
# Hide "TRACK X" text and DX/Standard chart display box
|
||||||
|
# For recording chart confirmation
|
||||||
|
TrackStartProcessTweak=false
|
||||||
|
# Cannot be used together with HanabiFix
|
||||||
|
HideHanabi=false
|
||||||
|
|
||||||
[Fix]
|
[Fix]
|
||||||
# Allow login with higher data version
|
# Allow login with higher data version
|
||||||
|
@ -70,6 +78,11 @@ FrameRateLock=false
|
||||||
# Use Microsoft YaHei Bold to display characters not in the font library
|
# Use Microsoft YaHei Bold to display characters not in the font library
|
||||||
# Cannot be used together with CustomFont
|
# Cannot be used together with CustomFont
|
||||||
FontFix=true
|
FontFix=true
|
||||||
|
# Make the Critical judgment of BreakSlide flash like BreakTap
|
||||||
|
# Align the judgment display of arc-shaped Slide with the judgment line accurately (it was slightly off before)
|
||||||
|
SlideJudgeTweak=true
|
||||||
|
# Cannot be used together with HideHanabi
|
||||||
|
HanabiFix=false
|
||||||
|
|
||||||
[Utils]
|
[Utils]
|
||||||
# Log user ID on login
|
# Log user ID on login
|
||||||
|
@ -80,16 +93,13 @@ JudgeAdjustA=0.0
|
||||||
JudgeAdjustB=0.0
|
JudgeAdjustB=0.0
|
||||||
# Touch screen delay, unit is milliseconds, one second = 1000 milliseconds. Must be an integer
|
# Touch screen delay, unit is milliseconds, one second = 1000 milliseconds. Must be an integer
|
||||||
TouchDelay=0
|
TouchDelay=0
|
||||||
# Window the game
|
|
||||||
Windowed=false
|
|
||||||
# Width and height for windowed mode, rendering resolution for fullscreen mode
|
|
||||||
# If set to 0, windowed mode will remember the user-set size, fullscreen mode will use the current display resolution
|
|
||||||
Width=0
|
|
||||||
Height=0
|
|
||||||
# Show detail of selected song in music selection screen
|
# Show detail of selected song in music selection screen
|
||||||
SelectionDetail=true
|
SelectionDetail=true
|
||||||
# Display framerate
|
# Display framerate
|
||||||
FrameRateDisplay=false
|
FrameRateDisplay=false
|
||||||
|
# Practice mode, activated by pressing Test in the game
|
||||||
|
# Must be used together with TestProof
|
||||||
|
PractiseMode=true
|
||||||
|
|
||||||
# ===================================
|
# ===================================
|
||||||
# Save some potentially unnecessary time
|
# Save some potentially unnecessary time
|
||||||
|
@ -111,6 +121,16 @@ SkipTrackStart=true
|
||||||
# Show reason when net icon is gray
|
# Show reason when net icon is gray
|
||||||
ShowNetErrorDetail=true
|
ShowNetErrorDetail=true
|
||||||
|
|
||||||
|
[WindowState]
|
||||||
|
# If not enabled, no operations will be performed on the game window
|
||||||
|
Enable=false
|
||||||
|
# Window the game
|
||||||
|
Windowed=false
|
||||||
|
# Width and height for windowed mode, rendering resolution for fullscreen mode
|
||||||
|
# If set to 0, windowed mode will remember the user-set size, fullscreen mode will use the current display resolution
|
||||||
|
Width=0
|
||||||
|
Height=0
|
||||||
|
|
||||||
[TouchSensitivity]
|
[TouchSensitivity]
|
||||||
# Enable custom sensitivity
|
# Enable custom sensitivity
|
||||||
# When enabled, the settings in Test mode will not take effect
|
# When enabled, the settings in Test mode will not take effect
|
||||||
|
@ -156,3 +176,27 @@ E5=20
|
||||||
E6=20
|
E6=20
|
||||||
E7=20
|
E7=20
|
||||||
E8=20
|
E8=20
|
||||||
|
|
||||||
|
[CustomKeyMap]
|
||||||
|
Enable = false
|
||||||
|
# These settings will work regardless of whether you have enabled segatools' io4 emulation
|
||||||
|
Test = "ScrollLock"
|
||||||
|
Service = "Pause"
|
||||||
|
Button1_1P = "W"
|
||||||
|
Button2_1P = "E"
|
||||||
|
Button3_1P = "D"
|
||||||
|
Button4_1P = "C"
|
||||||
|
Button5_1P = "X"
|
||||||
|
Button6_1P = "Z"
|
||||||
|
Button7_1P = "A"
|
||||||
|
Button8_1P = "Q"
|
||||||
|
Select_1P = "Alpha3"
|
||||||
|
Button1_2P = "Keypad8"
|
||||||
|
Button2_2P = "Keypad9"
|
||||||
|
Button3_2P = "Keypad6"
|
||||||
|
Button4_2P = "Keypad3"
|
||||||
|
Button5_2P = "Keypad2"
|
||||||
|
Button6_2P = "Keypad1"
|
||||||
|
Button7_2P = "Keypad4"
|
||||||
|
Button8_2P = "Keypad7"
|
||||||
|
Select_2P = "KeypadMultiply"
|
||||||
|
|
|
@ -62,6 +62,15 @@ HideSelfMadeCharts=true
|
||||||
# 在 LocalAssets 目录下放置 font.ttf 可以替换游戏的全局字体
|
# 在 LocalAssets 目录下放置 font.ttf 可以替换游戏的全局字体
|
||||||
# 不可以和 FontFix 一起使用
|
# 不可以和 FontFix 一起使用
|
||||||
CustomFont=false
|
CustomFont=false
|
||||||
|
# 提供自定义音符皮肤的能力(高级功能)
|
||||||
|
CustomNoteSkin=false
|
||||||
|
# 推迟了歌曲开始界面的动画
|
||||||
|
# 隐藏“TRACK X”字样和 DX/标准谱面的显示框
|
||||||
|
# 录制谱面确认用
|
||||||
|
TrackStartProcessTweak=false
|
||||||
|
# 完全隐藏烟花
|
||||||
|
# 不能和 HanabiFix 一起使用
|
||||||
|
HideHanabi=false
|
||||||
|
|
||||||
# ===================================
|
# ===================================
|
||||||
# 修复一些潜在的问题
|
# 修复一些潜在的问题
|
||||||
|
@ -86,6 +95,12 @@ FrameRateLock=false
|
||||||
# 在显示字库里没有的字时使用微软雅黑 Bold 显示
|
# 在显示字库里没有的字时使用微软雅黑 Bold 显示
|
||||||
# 不可以和 CustomFont 一起使用
|
# 不可以和 CustomFont 一起使用
|
||||||
FontFix=true
|
FontFix=true
|
||||||
|
# 让 BreakSlide 的 Critical 判定也可以像 BreakTap 一样闪烁
|
||||||
|
# 让圆弧形的 Slide 的判定显示与判定线精确对齐 (原本会有一点歪)
|
||||||
|
SlideJudgeTweak=true
|
||||||
|
# 修复 1p 模式下的烟花大小
|
||||||
|
# 不能和 HideHanabi 一起使用
|
||||||
|
HanabiFix=true
|
||||||
|
|
||||||
[Utils]
|
[Utils]
|
||||||
# 登录时将 UserID 输出到日志
|
# 登录时将 UserID 输出到日志
|
||||||
|
@ -96,18 +111,15 @@ JudgeAdjustA=0.0
|
||||||
JudgeAdjustB=0.0
|
JudgeAdjustB=0.0
|
||||||
# 触摸屏延迟,单位为毫秒,一秒 = 1000 毫秒。必须是整数
|
# 触摸屏延迟,单位为毫秒,一秒 = 1000 毫秒。必须是整数
|
||||||
TouchDelay=0
|
TouchDelay=0
|
||||||
# 窗口化游戏
|
|
||||||
Windowed=false
|
|
||||||
# 宽度和高度窗口化时为游戏窗口大小,全屏时为渲染分辨率
|
|
||||||
# 如果设为 0,窗口化将记住用户设定的大小,全屏时将使用当前显示器分辨率
|
|
||||||
Width=0
|
|
||||||
Height=0
|
|
||||||
# 选歌界面显示选择的歌曲的详情
|
# 选歌界面显示选择的歌曲的详情
|
||||||
SelectionDetail=true
|
SelectionDetail=true
|
||||||
# 出现灰网时显示原因
|
# 出现灰网时显示原因
|
||||||
ShowNetErrorDetail=true
|
ShowNetErrorDetail=true
|
||||||
# 显示帧率
|
# 显示帧率
|
||||||
FrameRateDisplay=false
|
FrameRateDisplay=false
|
||||||
|
# 练习模式,在游戏中按 Test 打开
|
||||||
|
# 必须和 TestProof 一起用
|
||||||
|
PractiseMode=true
|
||||||
|
|
||||||
# ===================================
|
# ===================================
|
||||||
# 节省一些不知道有用没用的时间
|
# 节省一些不知道有用没用的时间
|
||||||
|
@ -128,6 +140,16 @@ SkipGameOverScreen=true
|
||||||
# 跳过乐曲开始界面
|
# 跳过乐曲开始界面
|
||||||
SkipTrackStart=true
|
SkipTrackStart=true
|
||||||
|
|
||||||
|
[WindowState]
|
||||||
|
# 不启用的话,不会对游戏窗口做任何操作
|
||||||
|
Enable=false
|
||||||
|
# 窗口化游戏
|
||||||
|
Windowed=false
|
||||||
|
# 宽度和高度窗口化时为游戏窗口大小,全屏时为渲染分辨率
|
||||||
|
# 如果设为 0,窗口化将记住用户设定的大小,全屏时将使用当前显示器分辨率
|
||||||
|
Width=0
|
||||||
|
Height=0
|
||||||
|
|
||||||
[TouchSensitivity]
|
[TouchSensitivity]
|
||||||
# 是否启用自定义灵敏度
|
# 是否启用自定义灵敏度
|
||||||
# 这里启用之后 Test 里的就不再起作用了
|
# 这里启用之后 Test 里的就不再起作用了
|
||||||
|
@ -173,3 +195,27 @@ E5=20
|
||||||
E6=20
|
E6=20
|
||||||
E7=20
|
E7=20
|
||||||
E8=20
|
E8=20
|
||||||
|
|
||||||
|
[CustomKeyMap]
|
||||||
|
Enable = false
|
||||||
|
# 这里的设置无论你是否启用了 segatools 的 io4 模拟都会工作
|
||||||
|
Test = "ScrollLock"
|
||||||
|
Service = "Pause"
|
||||||
|
Button1_1P = "W"
|
||||||
|
Button2_1P = "E"
|
||||||
|
Button3_1P = "D"
|
||||||
|
Button4_1P = "C"
|
||||||
|
Button5_1P = "X"
|
||||||
|
Button6_1P = "Z"
|
||||||
|
Button7_1P = "A"
|
||||||
|
Button8_1P = "Q"
|
||||||
|
Select_1P = "Alpha3"
|
||||||
|
Button1_2P = "Keypad8"
|
||||||
|
Button2_2P = "Keypad9"
|
||||||
|
Button3_2P = "Keypad6"
|
||||||
|
Button4_2P = "Keypad3"
|
||||||
|
Button5_2P = "Keypad2"
|
||||||
|
Button6_2P = "Keypad1"
|
||||||
|
Button7_2P = "Keypad4"
|
||||||
|
Button8_2P = "Keypad7"
|
||||||
|
Select_2P = "KeypadMultiply"
|
||||||
|
|
|
@ -39,6 +39,9 @@ namespace AquaMai
|
||||||
public bool TestProof { get; set; }
|
public bool TestProof { get; set; }
|
||||||
public bool HideSelfMadeCharts { get; set; }
|
public bool HideSelfMadeCharts { get; set; }
|
||||||
public bool CustomFont { get; set; }
|
public bool CustomFont { get; set; }
|
||||||
|
public bool CustomNoteSkin { get; set; }
|
||||||
|
public bool TrackStartProcessTweak { get; set; }
|
||||||
|
public bool HideHanabi { get; set; }
|
||||||
public string CustomVersionString { get; set; } = "";
|
public string CustomVersionString { get; set; } = "";
|
||||||
public string CustomPlaceName { get; set; } = "";
|
public string CustomPlaceName { get; set; } = "";
|
||||||
public string ExecOnIdle { get; set; } = "";
|
public string ExecOnIdle { get; set; } = "";
|
||||||
|
@ -55,6 +58,8 @@ namespace AquaMai
|
||||||
public int ExtendNotesPool { get; set; }
|
public int ExtendNotesPool { get; set; }
|
||||||
public bool FrameRateLock { get; set; }
|
public bool FrameRateLock { get; set; }
|
||||||
public bool FontFix { get; set; }
|
public bool FontFix { get; set; }
|
||||||
|
public bool SlideJudgeTweak { get; set; }
|
||||||
|
public bool HanabiFix { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class UtilsConfig
|
public class UtilsConfig
|
||||||
|
|
|
@ -47,14 +47,6 @@ public class BasicFix
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
[HarmonyPrefix]
|
|
||||||
[HarmonyPatch(typeof(NetHttpClient), "CheckServerHash")]
|
|
||||||
private static bool CheckServerHash(ref bool __result)
|
|
||||||
{
|
|
||||||
__result = true;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
[HarmonyPrefix]
|
[HarmonyPrefix]
|
||||||
[HarmonyPatch(typeof(GameManager), "CalcSpecialNum")]
|
[HarmonyPatch(typeof(GameManager), "CalcSpecialNum")]
|
||||||
private static bool CalcSpecialNum(ref int __result)
|
private static bool CalcSpecialNum(ref int __result)
|
||||||
|
@ -63,22 +55,11 @@ public class BasicFix
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
[HarmonyPostfix]
|
[HarmonyPrefix]
|
||||||
[HarmonyPatch(typeof(MusicChainCardObejct), "SetLevel")]
|
[HarmonyPatch(typeof(NetHttpClient), "CheckServerHash")]
|
||||||
private static void FixLevelShift(MusicLevelID levelID, ref SpriteCounter ____digitLevel, ref SpriteCounter ____doubleDigitLevel)
|
private static bool CheckServerHash(ref bool __result)
|
||||||
{
|
{
|
||||||
switch (levelID)
|
__result = true;
|
||||||
{
|
return false;
|
||||||
case > MusicLevelID.Level9P:
|
|
||||||
____digitLevel.gameObject.SetActive(value: false);
|
|
||||||
____doubleDigitLevel.gameObject.SetActive(value: true);
|
|
||||||
____doubleDigitLevel.ChangeText(levelID.GetLevelNum().PadRight(3));
|
|
||||||
break;
|
|
||||||
case >= MusicLevelID.None:
|
|
||||||
____digitLevel.gameObject.SetActive(value: true);
|
|
||||||
____doubleDigitLevel.gameObject.SetActive(value: false);
|
|
||||||
____digitLevel.ChangeText(levelID.GetLevelNum().PadRight(2));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,64 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Reflection;
|
||||||
|
using HarmonyLib;
|
||||||
|
using Manager;
|
||||||
|
using MelonLoader;
|
||||||
|
using Monitor;
|
||||||
|
|
||||||
|
namespace AquaMai.Fix;
|
||||||
|
|
||||||
|
public class FixConnSlide
|
||||||
|
{
|
||||||
|
/* 这个 Patch 用于修复以下 bug:
|
||||||
|
* 非 ConnSlide 被错误解析为 ConnSlide (Fes 首日刹那旅程爆机 bug)
|
||||||
|
* 原 method 逻辑如下:
|
||||||
|
*
|
||||||
|
* if (this.IsSlideAll(noteData1.type) && (index1 + 1 < this._note._noteData.Count ? 1 : 0) != 0)
|
||||||
|
* {
|
||||||
|
* int targetNote = noteData1.slideData.targetNote;
|
||||||
|
* if (noteData1.slideData != null)
|
||||||
|
* targetNote = noteData1.slideData.targetNote;
|
||||||
|
* for (int index3 = index1; index3 < this._note._noteData.Count; ++index3)
|
||||||
|
* {
|
||||||
|
* NoteData noteData3 = this._note._noteData[index3];
|
||||||
|
* if (this.IsSlideAll(noteData3.type) && noteData3.time == noteData1.end && noteData3.startButtonPos == targetNote && noteData3.parent == null)
|
||||||
|
* {
|
||||||
|
* noteData3.parent = noteData1.parent;
|
||||||
|
* noteData1.child.Add(noteData3);
|
||||||
|
* noteData3.isUsed = true;
|
||||||
|
* noteData3.isJudged = true;
|
||||||
|
* break;
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* 修复 bug 需要把第二次调用 this.IsSlideAll() 更改为 this.IsConnectNote(), 这里使用 Transpiler 解决
|
||||||
|
*/
|
||||||
|
[HarmonyTranspiler]
|
||||||
|
[HarmonyPatch(typeof(NotesReader), "calcSlide")]
|
||||||
|
private static IEnumerable<CodeInstruction> Fix(IEnumerable<CodeInstruction> instructions)
|
||||||
|
{
|
||||||
|
List<CodeInstruction> instList = new List<CodeInstruction>(instructions);
|
||||||
|
bool found = false;
|
||||||
|
MethodInfo methodIsSlideAll = AccessTools.Method(typeof(NotesReader), "IsSlideAll");
|
||||||
|
MethodInfo methodIsConnectNote = AccessTools.Method(typeof(NotesReader), "IsConnectNote");
|
||||||
|
|
||||||
|
for (int i = 0; i < instList.Count; i++)
|
||||||
|
{
|
||||||
|
CodeInstruction inst = instList[i];
|
||||||
|
if (!found && inst.Calls(methodIsSlideAll))
|
||||||
|
{
|
||||||
|
found = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (found && inst.Calls(methodIsSlideAll))
|
||||||
|
{
|
||||||
|
inst.operand = methodIsConnectNote;
|
||||||
|
// MelonLogger.Msg($"[FixConnSlide] Successfully patched NotesReader::calcSlide");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return instList;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,73 @@
|
||||||
|
using HarmonyLib;
|
||||||
|
using MAI2.Util;
|
||||||
|
using Manager;
|
||||||
|
using Monitor;
|
||||||
|
using Monitor.MusicSelect.ChainList;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace AquaMai.Fix;
|
||||||
|
|
||||||
|
public class FixLevelDisplay
|
||||||
|
{
|
||||||
|
[HarmonyPostfix]
|
||||||
|
[HarmonyPatch(typeof(MusicChainCardObejct), "SetLevel")]
|
||||||
|
private static void FixLevelShiftMusicChainCardObejct(MusicLevelID levelID, SpriteCounter ____digitLevel, SpriteCounter ____doubleDigitLevel, bool utage, GameObject ____difficultyUtageQuesionMarkSingleDigit, GameObject ____difficultyUtageQuesionMarkDoubleDigit)
|
||||||
|
{
|
||||||
|
switch (levelID)
|
||||||
|
{
|
||||||
|
case > MusicLevelID.Level9P:
|
||||||
|
____digitLevel.gameObject.SetActive(value: false);
|
||||||
|
____doubleDigitLevel.gameObject.SetActive(value: true);
|
||||||
|
____doubleDigitLevel.ChangeText(levelID.GetLevelNum().PadRight(3));
|
||||||
|
break;
|
||||||
|
case >= MusicLevelID.None:
|
||||||
|
____digitLevel.gameObject.SetActive(value: true);
|
||||||
|
____doubleDigitLevel.gameObject.SetActive(value: false);
|
||||||
|
____digitLevel.ChangeText(levelID.GetLevelNum().PadRight(2));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!utage) return;
|
||||||
|
switch (levelID)
|
||||||
|
{
|
||||||
|
case > MusicLevelID.Level9P:
|
||||||
|
____difficultyUtageQuesionMarkSingleDigit.SetActive(value: false);
|
||||||
|
____difficultyUtageQuesionMarkDoubleDigit.SetActive(value: true);
|
||||||
|
break;
|
||||||
|
case >= MusicLevelID.None:
|
||||||
|
____difficultyUtageQuesionMarkSingleDigit.SetActive(value: true);
|
||||||
|
____difficultyUtageQuesionMarkDoubleDigit.SetActive(value: false);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[HarmonyPostfix]
|
||||||
|
[HarmonyPatch(typeof(SingleResultCardController), "SetLevel")]
|
||||||
|
private static void FixLevelShiftSingleResultCardController(MusicLevelID levelID, bool isUtage, ref SpriteCounter ____difficultySingle, ref SpriteCounter ____difficultyDouble, GameObject ____utageQuestionMarkSingleDigit, GameObject ____utageQuestionMarkDoubleDigit)
|
||||||
|
{
|
||||||
|
FixLevelShiftMusicChainCardObejct(levelID, ____difficultySingle, ____difficultyDouble, isUtage, ____utageQuestionMarkSingleDigit, ____utageQuestionMarkDoubleDigit);
|
||||||
|
}
|
||||||
|
|
||||||
|
[HarmonyPostfix]
|
||||||
|
[HarmonyPatch(typeof(TotalResultPlayer), "SetLevel")]
|
||||||
|
private static void FixLevelShiftTotalResultPlayer(MusicLevelID levelID, bool isUtage, ref SpriteCounter ____difficultySingle, ref SpriteCounter ____difficultyDouble, GameObject ____utageQuestionMarkSingleDigit, GameObject ____utageQuestionMarkDoubleDigit)
|
||||||
|
{
|
||||||
|
FixLevelShiftMusicChainCardObejct(levelID, ____difficultySingle, ____difficultyDouble, isUtage, ____utageQuestionMarkSingleDigit, ____utageQuestionMarkDoubleDigit);
|
||||||
|
}
|
||||||
|
|
||||||
|
[HarmonyPostfix]
|
||||||
|
[HarmonyPatch(typeof(ResultMonitor), "SetLevel")]
|
||||||
|
private static void FixLevelShiftTotalResultPlayer(MusicLevelID levelID, ref SpriteCounter ____difficultySingle, ref SpriteCounter ____difficultyDouble)
|
||||||
|
{
|
||||||
|
FixLevelShiftMusicChainCardObejct(levelID, ____difficultySingle, ____difficultyDouble, false, null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
[HarmonyPostfix]
|
||||||
|
[HarmonyPatch(typeof(TrackStartMonitor), "SetTrackStart")]
|
||||||
|
private static void FixLevelShiftTrackStartMonitor(int ___monitorIndex, ref SpriteCounter ____difficultySingle, ref SpriteCounter ____difficultyDouble, GameObject ____utageQuestionSingleDigit, GameObject ____utageQuestionDoubleDigit)
|
||||||
|
{
|
||||||
|
var music = Singleton<DataManager>.Instance.GetMusic(GameManager.SelectMusicID[___monitorIndex]);
|
||||||
|
var levelID = (MusicLevelID)music.notesData[GameManager.SelectDifficultyID[___monitorIndex]].musicLevelID;
|
||||||
|
FixLevelShiftMusicChainCardObejct(levelID, ____difficultySingle, ____difficultyDouble, music.name.id >= 100000, ____utageQuestionSingleDigit, ____utageQuestionDoubleDigit);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
using Fx;
|
||||||
|
using HarmonyLib;
|
||||||
|
using Monitor;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace AquaMai.Fix;
|
||||||
|
|
||||||
|
public class HanabiFix
|
||||||
|
{
|
||||||
|
[HarmonyPatch(typeof(TapCEffect), "SetUpParticle")]
|
||||||
|
[HarmonyPostfix]
|
||||||
|
public static void FixMaxSize(TapCEffect __instance, FX_Mai2_Note_Color ____particleControler)
|
||||||
|
{
|
||||||
|
var entities = ____particleControler.GetComponentsInChildren<ParticleSystemRenderer>(true);
|
||||||
|
foreach (var entity in entities)
|
||||||
|
{
|
||||||
|
entity.maxParticleSize = 1f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,102 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using HarmonyLib;
|
||||||
|
using Manager;
|
||||||
|
using Monitor;
|
||||||
|
|
||||||
|
namespace AquaMai.Fix;
|
||||||
|
|
||||||
|
public class SlideAutoPlayTweak
|
||||||
|
{
|
||||||
|
/* 这个 Patch 用于修复以下 bug:
|
||||||
|
* SlideFan 在 AutoPlay 时, 只有第一个箭头会消失
|
||||||
|
* 原 method 逻辑如下:
|
||||||
|
*
|
||||||
|
* if (this.IsNoteCheckTimeStartIgnoreJudgeWait())
|
||||||
|
* {
|
||||||
|
* // do something ...
|
||||||
|
* if (!GameManager.IsAutoPlay())
|
||||||
|
* {
|
||||||
|
* // do something ...
|
||||||
|
* for (int index = 0; index < this._arrowPrefubs.Length && (double) index < (double) num2 * 11.0; ++index)
|
||||||
|
* {
|
||||||
|
* // do something about displaying arrows ...
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
* else
|
||||||
|
* {
|
||||||
|
* float num4 = (currentMsec - this.StarLaunchMsec) / (this.StarArriveMsec - this.StarLaunchMsec - this.lastWaitTime);
|
||||||
|
* for (int index = 0; index < this._arrowPrefubs.Length && (double) index < (double) num4 * 1.0; ++index)
|
||||||
|
* {
|
||||||
|
* // do something about displaying arrows ...
|
||||||
|
* }
|
||||||
|
* if ((double) num4 > 1.0)
|
||||||
|
* num1 = 3;
|
||||||
|
* }
|
||||||
|
* // do something ...
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* 导致这个 bug 的原因是 else 分支的 for 循环终止条件写错了, 应该是 11.0 (因为有 11 个箭头), SBGA 写成了 1.0
|
||||||
|
* 这个 method 中一共只有 5 处 ldc.r4 的 IL Code, 依次为 10.0, 11.0, 1.0, 1.0, 0.0
|
||||||
|
* 修复 bug 需要把第三处的 1.0 更改为 11.0, 这里使用 Transpiler 解决
|
||||||
|
*/
|
||||||
|
[HarmonyTranspiler]
|
||||||
|
[HarmonyPatch(typeof(SlideFan), "NoteCheck")]
|
||||||
|
private static IEnumerable<CodeInstruction> FixFanAutoPlayArrow(IEnumerable<CodeInstruction> instructions)
|
||||||
|
{
|
||||||
|
List<CodeInstruction> instList = new List<CodeInstruction>(instructions);
|
||||||
|
bool found = false;
|
||||||
|
for (int i = 0; i < instList.Count; i++)
|
||||||
|
{
|
||||||
|
CodeInstruction inst = instList[i];
|
||||||
|
if (inst.LoadsConstant(11.0))
|
||||||
|
{
|
||||||
|
found = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (found && inst.LoadsConstant(1.0))
|
||||||
|
{
|
||||||
|
inst.operand = 11.0f;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return instList;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 这个 Patch 让 Slide 在 AutoPlay 的时候, 每个区仍然会分按下和松开两段进行推进 (加上 this._hitIn 的变化)
|
||||||
|
* 原 method 逻辑如下:
|
||||||
|
*
|
||||||
|
* if (!GameManager.IsAutoPlay())
|
||||||
|
* {
|
||||||
|
* // do somethings ...
|
||||||
|
* }
|
||||||
|
* else
|
||||||
|
* {
|
||||||
|
* float num1 = (currentMsec - this.StarLaunchMsec) / (this.StarArriveMsec - this.StarLaunchMsec - this.lastWaitTime);
|
||||||
|
* this._hitIndex = (int) ((double) this._hitAreaList.Count * (double) num1);
|
||||||
|
* if (this._hitIndex >= this._hitAreaList.Count)
|
||||||
|
* this._hitIndex = this._hitAreaList.Count - 1;
|
||||||
|
* if (this._hitIndex < 0)
|
||||||
|
* this._hitIndex = 0;
|
||||||
|
* int num2 = (int) ((double) this._dispLaneNum * this.GetDeleteArrowDistance());
|
||||||
|
* // do somethings ...
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* 现在要在 this.GetDeleteArrowDistance() 之前插入
|
||||||
|
* this._hitIn = ((float)this._hitAreaList.Count * num1 > (float)this._hitIndex + 0.5f);
|
||||||
|
* 这段代码, 可以采用 Prefix, GetDeleteArrowDistance() 只在两个地方调用过, 另一处就在上面的 if 分支中 (即非 AutoPlay 情况)
|
||||||
|
*/
|
||||||
|
[HarmonyPrefix]
|
||||||
|
[HarmonyPatch(typeof(SlideRoot), "GetDeleteArrowDistance")]
|
||||||
|
private static void FixSlideAutoPlayArrow(
|
||||||
|
SlideRoot __instance, ref bool ____hitIn, int ____hitIndex, List<SlideManager.HitArea> ____hitAreaList,
|
||||||
|
float ___StarLaunchMsec, float ___StarArriveMsec, float ___lastWaitTime
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if (GameManager.IsAutoPlay())
|
||||||
|
{
|
||||||
|
float prop = (NotesManager.GetCurrentMsec() - ___StarLaunchMsec) / (___StarArriveMsec - ___StarLaunchMsec - ___lastWaitTime);
|
||||||
|
____hitIn = ____hitAreaList.Count * prop > ____hitIndex + 0.5f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,89 @@
|
||||||
|
using System;
|
||||||
|
using HarmonyLib;
|
||||||
|
using Manager;
|
||||||
|
using Monitor;
|
||||||
|
using Process;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace AquaMai.Fix;
|
||||||
|
|
||||||
|
public class SlideJudgeTweak
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* 这个 Patch 让 BreakSlide 的 Critical 判定也可以像 BreakTap 一样闪烁
|
||||||
|
*/
|
||||||
|
[HarmonyPostfix]
|
||||||
|
[HarmonyPatch(typeof(SlideJudge), "UpdateBreakEffectAdd")]
|
||||||
|
private static void FixBreakSlideJudgeBlink(
|
||||||
|
SpriteRenderer ___SpriteRenderAdd, SpriteRenderer ___SpriteRender,
|
||||||
|
SlideJudge.SlideJudgeType ____judgeType, SlideJudge.SlideAngle ____angle
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if (!___SpriteRenderAdd.gameObject.activeSelf) return;
|
||||||
|
float num = ___SpriteRenderAdd.color.r;
|
||||||
|
___SpriteRenderAdd.color = new Color(num, num, num, 0.3f);
|
||||||
|
if (num > 0.9f)
|
||||||
|
{
|
||||||
|
___SpriteRender.sprite = GameNoteImageContainer.JudgeSlideCriticalBreak[(int) ____judgeType, (int) ____angle];
|
||||||
|
}
|
||||||
|
else if (num < 0.1f)
|
||||||
|
{
|
||||||
|
___SpriteRender.sprite = GameNoteImageContainer.JudgeSlideCritical[(int) ____judgeType, (int) ____angle];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 这个 Patch 让圆弧形的 Slide 的判定显示与判定线精确对齐 (原本会有一点歪), 就像 majdata 里那样
|
||||||
|
*/
|
||||||
|
[HarmonyPostfix]
|
||||||
|
[HarmonyPatch(typeof(SlideRoot), "Initialize")]
|
||||||
|
private static void FixCircleSlideJudgePosition(
|
||||||
|
SlideRoot __instance, SlideType ___EndSlideType, SlideJudge ___JudgeObj
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if (null != ___JudgeObj)
|
||||||
|
{
|
||||||
|
float z = ___JudgeObj.transform.localPosition.z;
|
||||||
|
if (___EndSlideType == SlideType.Slide_Circle_L)
|
||||||
|
{
|
||||||
|
float angle = -45.0f - 45.0f * __instance.EndButtonId;
|
||||||
|
double angleRad = Math.PI / 180.0 * (angle + 90 + 22.5 + 2.6415);
|
||||||
|
___JudgeObj.transform.localPosition = new Vector3(480f * (float)Math.Cos(angleRad), 480f * (float)Math.Sin(angleRad), z);
|
||||||
|
___JudgeObj.transform.localRotation = Quaternion.Euler(0.0f, 0.0f, angle);
|
||||||
|
}
|
||||||
|
else if (___EndSlideType == SlideType.Slide_Circle_R)
|
||||||
|
{
|
||||||
|
float angle = -45.0f * __instance.EndButtonId;
|
||||||
|
double angleRad = Math.PI / 180.0 * (angle + 90 - 22.5 - 2.6415);
|
||||||
|
___JudgeObj.transform.localPosition = new Vector3(480f * (float)Math.Cos(angleRad), 480f * (float)Math.Sin(angleRad), z);
|
||||||
|
___JudgeObj.transform.localRotation = Quaternion.Euler(0.0f, 0.0f, angle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 这个 Patch 让 Wifi Slide 的判定显示有上下的区别 (原本所有 Wifi 的判定显示都是朝向圆心的), 就像 majdata 里那样
|
||||||
|
* 这个 bug 产生的原因是 SBGA 忘记给 Wifi 的 EndButtonId 赋值了
|
||||||
|
* 不过需要注意的是, 考虑到圆弧形 Slide 的判定显示就是永远朝向圆心的, 我个人会觉得这个 Patch 关掉更好看一点
|
||||||
|
* 所以这里把 Patch 注释掉了
|
||||||
|
*/
|
||||||
|
// [HarmonyPostfix]
|
||||||
|
// [HarmonyPatch(typeof(SlideFan), "Initialize")]
|
||||||
|
private static void FixFanJudgeFilp(
|
||||||
|
int[] ___GoalButtonId, SlideJudge ___JudgeObj
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if (null != ___JudgeObj)
|
||||||
|
{
|
||||||
|
if (2 <= ___GoalButtonId[1] && ___GoalButtonId[1] <= 5)
|
||||||
|
{
|
||||||
|
___JudgeObj.Flip(false);
|
||||||
|
___JudgeObj.transform.Rotate(0.0f, 0.0f, 180f);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
___JudgeObj.Flip(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -158,10 +158,14 @@ namespace AquaMai
|
||||||
Patch(typeof(ExtendNotesPool));
|
Patch(typeof(ExtendNotesPool));
|
||||||
Patch(typeof(FixCheckAuth));
|
Patch(typeof(FixCheckAuth));
|
||||||
Patch(typeof(DebugFeature));
|
Patch(typeof(DebugFeature));
|
||||||
|
Patch(typeof(FixConnSlide));
|
||||||
|
Patch(typeof(SlideAutoPlayTweak));
|
||||||
|
Patch(typeof(FixLevelDisplay));
|
||||||
// UX
|
// UX
|
||||||
Patch(typeof(CustomVersionString));
|
Patch(typeof(CustomVersionString));
|
||||||
Patch(typeof(CustomPlaceName));
|
Patch(typeof(CustomPlaceName));
|
||||||
Patch(typeof(RunCommandOnEvents));
|
Patch(typeof(RunCommandOnEvents));
|
||||||
|
Patch(typeof(CustomLogo));
|
||||||
// Utils
|
// Utils
|
||||||
Patch(typeof(JudgeAdjust));
|
Patch(typeof(JudgeAdjust));
|
||||||
# if DEBUG
|
# if DEBUG
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
using HarmonyLib;
|
using HarmonyLib;
|
||||||
using MelonLoader;
|
using MelonLoader;
|
||||||
using TMPro;
|
using TMPro;
|
||||||
|
@ -10,6 +12,7 @@ namespace AquaMai.UX;
|
||||||
|
|
||||||
public class CustomFont
|
public class CustomFont
|
||||||
{
|
{
|
||||||
|
private static Font font;
|
||||||
private static TMP_FontAsset fontAsset;
|
private static TMP_FontAsset fontAsset;
|
||||||
|
|
||||||
public static void DoCustomPatch(HarmonyLib.Harmony h)
|
public static void DoCustomPatch(HarmonyLib.Harmony h)
|
||||||
|
@ -17,9 +20,7 @@ public class CustomFont
|
||||||
var fontPath = Path.Combine(Environment.CurrentDirectory, "LocalAssets", "font.ttf");
|
var fontPath = Path.Combine(Environment.CurrentDirectory, "LocalAssets", "font.ttf");
|
||||||
if (!File.Exists(fontPath)) return;
|
if (!File.Exists(fontPath)) return;
|
||||||
|
|
||||||
var font = new Font(fontPath);
|
font = new Font(fontPath);
|
||||||
|
|
||||||
// 不设置成 8192 的话,贴图会用完,剩下的字显示不出来
|
|
||||||
fontAsset = TMP_FontAsset.CreateFontAsset(font, 90, 9, GlyphRenderMode.SDFAA, 8192, 8192);
|
fontAsset = TMP_FontAsset.CreateFontAsset(font, 90, 9, GlyphRenderMode.SDFAA, 8192, 8192);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,10 +28,44 @@ public class CustomFont
|
||||||
[HarmonyPostfix]
|
[HarmonyPostfix]
|
||||||
public static void PostFix(TextMeshProUGUI __instance)
|
public static void PostFix(TextMeshProUGUI __instance)
|
||||||
{
|
{
|
||||||
if (fontAsset is null) return;
|
if (font is null) return;
|
||||||
# if DEBUG
|
# if DEBUG
|
||||||
MelonLogger.Msg($"{__instance.font.name} {__instance.text}");
|
MelonLogger.Msg($"{__instance.font.name} {__instance.text}");
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
|
var materialOrigin = __instance.fontMaterial;
|
||||||
|
var materialSharedOrigin = __instance.fontSharedMaterial;
|
||||||
__instance.font = fontAsset;
|
__instance.font = fontAsset;
|
||||||
|
# if DEBUG
|
||||||
|
MelonLogger.Msg($"shaderKeywords {materialOrigin.shaderKeywords.Join()} {__instance.fontMaterial.shaderKeywords.Join()}");
|
||||||
|
# endif
|
||||||
|
// __instance.fontSharedMaterial = materialSharedOrigin;
|
||||||
|
|
||||||
|
// 这样之后该有描边的地方整个字后面都是阴影,它不知道哪里是边
|
||||||
|
// materialOrigin.mainTexture = __instance.fontMaterial.mainTexture;
|
||||||
|
// materialOrigin.mainTextureOffset = __instance.fontMaterial.mainTextureOffset;
|
||||||
|
// materialOrigin.mainTextureScale = __instance.fontMaterial.mainTextureScale;
|
||||||
|
// __instance.fontMaterial.CopyPropertiesFromMaterial(materialOrigin);
|
||||||
|
|
||||||
|
// 这样了之后有描边了,但是描边很细
|
||||||
|
// __instance.fontMaterial.shader = materialOrigin.shader;
|
||||||
|
foreach (var keyword in materialOrigin.shaderKeywords)
|
||||||
|
{
|
||||||
|
__instance.fontMaterial.EnableKeyword(keyword);
|
||||||
|
}
|
||||||
|
// __instance.fontMaterial.globalIlluminationFlags = materialOrigin.globalIlluminationFlags;
|
||||||
|
|
||||||
|
// 原来是 underlay,但是复制这三个属性之后就又变成整个字后面都是阴影了
|
||||||
|
// __instance.fontMaterial.SetFloat(ShaderUtilities.ID_UnderlayOffsetY, materialOrigin.GetFloat(ShaderUtilities.ID_UnderlayOffsetY));
|
||||||
|
// __instance.fontMaterial.SetFloat(ShaderUtilities.ID_UnderlayOffsetX, materialOrigin.GetFloat(ShaderUtilities.ID_UnderlayOffsetX));
|
||||||
|
// __instance.fontMaterial.SetFloat(ShaderUtilities.ID_UnderlayDilate, materialOrigin.GetFloat(ShaderUtilities.ID_UnderlayDilate));
|
||||||
|
|
||||||
|
// if(materialOrigin.shaderKeywords.Contains(ShaderUtilities.Keyword_Underlay))
|
||||||
|
// {
|
||||||
|
// __instance.fontMaterial.EnableKeyword(ShaderUtilities.Keyword_Glow);
|
||||||
|
// __instance.fontMaterial.SetFloat(ShaderUtilities.ID_GlowOuter, .5f);
|
||||||
|
// // __instance.fontMaterial.SetFloat(ShaderUtilities.ID_UnderlayOffsetX, materialOrigin.GetFloat(ShaderUtilities.ID_UnderlayOffsetX));
|
||||||
|
// }
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,59 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using HarmonyLib;
|
||||||
|
using Monitor;
|
||||||
|
using Process;
|
||||||
|
using UnityEngine;
|
||||||
|
using UnityEngine.UI;
|
||||||
|
|
||||||
|
namespace AquaMai.UX;
|
||||||
|
|
||||||
|
public class CustomLogo
|
||||||
|
{
|
||||||
|
private static List<Sprite> segaLogo = new();
|
||||||
|
private static List<Sprite> allNetLogo = new();
|
||||||
|
|
||||||
|
public static void DoCustomPatch(HarmonyLib.Harmony h)
|
||||||
|
{
|
||||||
|
EnumSprite(segaLogo, Path.Combine(Environment.CurrentDirectory, "LocalAssets", "SegaLogo"));
|
||||||
|
EnumSprite(allNetLogo, Path.Combine(Environment.CurrentDirectory, "LocalAssets", "AllNetLogo"));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void EnumSprite(List<Sprite> collection, string path)
|
||||||
|
{
|
||||||
|
if (!Directory.Exists(path)) return;
|
||||||
|
foreach (var file in Directory.EnumerateFiles(path, "*.png"))
|
||||||
|
{
|
||||||
|
var data = File.ReadAllBytes(file);
|
||||||
|
var texture2D = new Texture2D(1, 1, TextureFormat.RGBA32, false);
|
||||||
|
if (texture2D.LoadImage(data))
|
||||||
|
{
|
||||||
|
collection.Add(Sprite.Create(texture2D, new Rect(0f, 0f, texture2D.width, texture2D.height), new Vector2(0.5f, 0.5f)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[HarmonyPatch(typeof(AdvertiseProcess), "OnStart")]
|
||||||
|
[HarmonyPostfix]
|
||||||
|
private static void AdvProcessPostFix(AdvertiseMonitor[] ____monitors)
|
||||||
|
{
|
||||||
|
if (segaLogo.Count > 0)
|
||||||
|
{
|
||||||
|
var logo = segaLogo[UnityEngine.Random.Range(0, segaLogo.Count)];
|
||||||
|
foreach (var monitor in ____monitors)
|
||||||
|
{
|
||||||
|
monitor.transform.Find("Canvas/Main/SegaAllNet_LOGO/NUL_ADT_SegaAllNet_LOGO/SegaLogo").GetComponent<Image>().sprite = logo;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (allNetLogo.Count > 0)
|
||||||
|
{
|
||||||
|
var logo = allNetLogo[UnityEngine.Random.Range(0, allNetLogo.Count)];
|
||||||
|
foreach (var monitor in ____monitors)
|
||||||
|
{
|
||||||
|
monitor.transform.Find("Canvas/Main/SegaAllNet_LOGO/NUL_ADT_SegaAllNet_LOGO/AllNetLogo").GetComponent<Image>().sprite = logo;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,321 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using HarmonyLib;
|
||||||
|
using MelonLoader;
|
||||||
|
using Monitor;
|
||||||
|
using Monitor.Game;
|
||||||
|
using Process;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace AquaMai.UX;
|
||||||
|
|
||||||
|
public class CustomNoteSkin
|
||||||
|
{
|
||||||
|
private static readonly List<string> ImageExts = [".png", ".jpg", ".jpeg"];
|
||||||
|
private static readonly List<string> SlideFanFields = ["_normalSlideFan", "_eachSlideFan", "_breakSlideFan", "_breakSlideFanEff"];
|
||||||
|
|
||||||
|
private static Sprite customOutline;
|
||||||
|
private static Sprite[,] customSlideFan = new Sprite[4, 11];
|
||||||
|
|
||||||
|
private static bool LoadIntoGameNoteImageContainer(string fieldName, int? idx1, int? idx2, Texture2D texture)
|
||||||
|
{
|
||||||
|
// 先确定确实有这个 Field, 如果没有的话可以直接跳过这个文件
|
||||||
|
var fieldTraverse = Traverse.Create(typeof(GameNoteImageContainer)).Field(fieldName);
|
||||||
|
if (!fieldTraverse.FieldExists())
|
||||||
|
{
|
||||||
|
MelonLogger.Msg($"[CustomNoteSkin] Cannot found field {fieldName}");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var fieldType = fieldTraverse.GetValueType();
|
||||||
|
if (!idx1.HasValue)
|
||||||
|
{
|
||||||
|
// 目标 Field 应当是单个 Sprite
|
||||||
|
if (fieldType != typeof(Sprite))
|
||||||
|
{
|
||||||
|
MelonLogger.Msg($"[CustomNoteSkin] Field {fieldName} is a {fieldType.Name}, not a Sprite");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var target = fieldTraverse.GetValue<Sprite>();
|
||||||
|
var pivot = new Vector2(target.pivot.x / target.rect.width, target.pivot.y / target.rect.height);
|
||||||
|
var custom = Sprite.Create(
|
||||||
|
texture, new Rect(0, 0, texture.width, texture.height), pivot, 1f,
|
||||||
|
0, SpriteMeshType.Tight, target.border
|
||||||
|
);
|
||||||
|
fieldTraverse.SetValue(custom);
|
||||||
|
}
|
||||||
|
else if (!idx2.HasValue)
|
||||||
|
{
|
||||||
|
// 目标 Field 是一维数组
|
||||||
|
if (fieldType != typeof(Sprite[]))
|
||||||
|
{
|
||||||
|
MelonLogger.Msg($"[CustomNoteSkin] Field {fieldName} is a {fieldType.Name}, not a Sprite[]");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var targetArray = fieldTraverse.GetValue<Sprite[]>();
|
||||||
|
var target = targetArray[idx1.Value];
|
||||||
|
var pivot = new Vector2(target.pivot.x / target.rect.width, target.pivot.y / target.rect.height);
|
||||||
|
var custom = Sprite.Create(
|
||||||
|
texture, new Rect(0, 0, texture.width, texture.height), pivot, 1f,
|
||||||
|
0, SpriteMeshType.Tight, target.border
|
||||||
|
);
|
||||||
|
targetArray[idx1.Value] = custom;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// 目标 Field 是二维数组
|
||||||
|
if (fieldType != typeof(Sprite[,]))
|
||||||
|
{
|
||||||
|
MelonLogger.Msg($"[CustomNoteSkin] Field {fieldName} is a {fieldType.Name}, not a Sprite[,]");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var targetArray = fieldTraverse.GetValue<Sprite[,]>();
|
||||||
|
var target = targetArray[idx1.Value, idx2.Value];
|
||||||
|
var pivot = new Vector2(target.pivot.x / target.rect.width, target.pivot.y / target.rect.height);
|
||||||
|
var custom = Sprite.Create(
|
||||||
|
texture, new Rect(0, 0, texture.width, texture.height), pivot, 1f,
|
||||||
|
0, SpriteMeshType.Tight, target.border
|
||||||
|
);
|
||||||
|
targetArray[idx1.Value, idx2.Value] = custom;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
[HarmonyPostfix]
|
||||||
|
[HarmonyPatch(typeof(GameNotePrefabContainer), "Initialize")]
|
||||||
|
private static void LoadNoteSkin()
|
||||||
|
{
|
||||||
|
if (!Directory.Exists(Path.Combine(Environment.CurrentDirectory, "LocalAssets", "Skins"))) return;
|
||||||
|
|
||||||
|
foreach (var laFile in Directory.EnumerateFiles(Path.Combine(Environment.CurrentDirectory, "LocalAssets", "Skins")))
|
||||||
|
{
|
||||||
|
if (!ImageExts.Contains(Path.GetExtension(laFile).ToLowerInvariant())) continue;
|
||||||
|
var texture = new Texture2D(1, 1, TextureFormat.RGBA32, false);
|
||||||
|
texture.LoadImage(File.ReadAllBytes(laFile));
|
||||||
|
|
||||||
|
var name = Path.GetFileNameWithoutExtension(laFile);
|
||||||
|
var args = name.Split('_');
|
||||||
|
// 文件名的格式是 XXXXXXXX_A_B 表示 GameNoteImageContainer._XXXXXXXX[A, B]
|
||||||
|
// 视具体情况, A, B 可能不存在
|
||||||
|
var fieldName = '_' + args[0];
|
||||||
|
int? idx1 = (args.Length < 2) ? null : (int.TryParse(args[1], out var temp) ? temp : null);
|
||||||
|
int? idx2 = (args.Length < 3) ? null : (int.TryParse(args[2], out temp) ? temp : null);
|
||||||
|
|
||||||
|
Traverse traverse;
|
||||||
|
|
||||||
|
if (fieldName == "_outline")
|
||||||
|
{
|
||||||
|
customOutline = Sprite.Create(texture, new Rect(0, 0, texture.width, texture.height), new Vector2(0.5f, 0.5f), 1f);
|
||||||
|
MelonLogger.Msg($"[CustomNoteSkin] Successfully loaded {name}");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SlideFanFields.Contains(fieldName))
|
||||||
|
{
|
||||||
|
if (!idx1.HasValue)
|
||||||
|
{
|
||||||
|
MelonLogger.Msg($"[CustomNoteSkin] Field {fieldName} needs a index");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var i = SlideFanFields.IndexOf(fieldName);
|
||||||
|
customSlideFan[i, idx1.Value] = Sprite.Create(texture, new Rect(0, 0, texture.width, texture.height), new Vector2(1f, 0.5f), 1f);
|
||||||
|
MelonLogger.Msg($"[CustomNoteSkin] Successfully loaded {name}");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fieldName == "_touchJust")
|
||||||
|
{
|
||||||
|
traverse = Traverse.Create(GameNotePrefabContainer.TouchTapB);
|
||||||
|
var noticeObject = traverse.Field<GameObject>("NoticeObject").Value;
|
||||||
|
var target = noticeObject.GetComponent<SpriteRenderer>();
|
||||||
|
var pivot = new Vector2(
|
||||||
|
target.sprite.pivot.x / target.sprite.rect.width,
|
||||||
|
target.sprite.pivot.y / target.sprite.rect.height
|
||||||
|
);
|
||||||
|
var custom = Sprite.Create(
|
||||||
|
texture, new Rect(0, 0, texture.width, texture.height), pivot, 1f,
|
||||||
|
0, SpriteMeshType.Tight, target.sprite.border
|
||||||
|
);
|
||||||
|
target.sprite = custom;
|
||||||
|
|
||||||
|
traverse = Traverse.Create(GameNotePrefabContainer.TouchTapC);
|
||||||
|
noticeObject = traverse.Field<GameObject>("NoticeObject").Value;
|
||||||
|
noticeObject.GetComponent<SpriteRenderer>().sprite = custom;
|
||||||
|
MelonLogger.Msg($"[CustomNoteSkin] Successfully loaded {name}");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fieldName == "_touchHold")
|
||||||
|
{
|
||||||
|
if (!idx1.HasValue)
|
||||||
|
{
|
||||||
|
MelonLogger.Msg($"[CustomNoteSkin] Field {fieldName} needs a index");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
traverse = Traverse.Create(GameNotePrefabContainer.TouchHoldC);
|
||||||
|
var target = traverse.Field<SpriteRenderer[]>("ColorsObject").Value;
|
||||||
|
var renderer = target[idx1.Value];
|
||||||
|
var pivot = new Vector2(
|
||||||
|
renderer.sprite.pivot.x / renderer.sprite.rect.width,
|
||||||
|
renderer.sprite.pivot.y / renderer.sprite.rect.height
|
||||||
|
);
|
||||||
|
var custom = Sprite.Create(
|
||||||
|
texture, new Rect(0, 0, texture.width, texture.height), pivot, 1f,
|
||||||
|
0, SpriteMeshType.Tight, renderer.sprite.border
|
||||||
|
);
|
||||||
|
renderer.sprite = custom;
|
||||||
|
MelonLogger.Msg($"[CustomNoteSkin] Successfully loaded {name}");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fieldName == "_normalTouchBorder")
|
||||||
|
{
|
||||||
|
if (!idx1.HasValue)
|
||||||
|
{
|
||||||
|
MelonLogger.Msg($"[CustomNoteSkin] Field {fieldName} needs a index");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
traverse = Traverse.Create(GameNotePrefabContainer.TouchReserve);
|
||||||
|
var target = traverse.Field<Sprite[]>("_reserveSingleSprite").Value;
|
||||||
|
var targetSprite = target[idx1.Value - 2];
|
||||||
|
var pivot = new Vector2(
|
||||||
|
targetSprite.pivot.x / targetSprite.rect.width,
|
||||||
|
targetSprite.pivot.y / targetSprite.rect.height
|
||||||
|
);
|
||||||
|
target[idx1.Value - 2] = Sprite.Create(
|
||||||
|
texture, new Rect(0, 0, texture.width, texture.height), pivot, 1f,
|
||||||
|
0, SpriteMeshType.Tight, targetSprite.border
|
||||||
|
);
|
||||||
|
MelonLogger.Msg($"[CustomNoteSkin] Successfully loaded {name}");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fieldName == "_eachTouchBorder")
|
||||||
|
{
|
||||||
|
if (!idx1.HasValue)
|
||||||
|
{
|
||||||
|
MelonLogger.Msg($"[CustomNoteSkin] Field {fieldName} needs a index");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
traverse = Traverse.Create(GameNotePrefabContainer.TouchReserve);
|
||||||
|
var target = traverse.Field<Sprite[]>("_reserveEachSprite").Value;
|
||||||
|
var targetSprite = target[idx1.Value - 2];
|
||||||
|
var pivot = new Vector2(
|
||||||
|
targetSprite.pivot.x / targetSprite.rect.width,
|
||||||
|
targetSprite.pivot.y / targetSprite.rect.height
|
||||||
|
);
|
||||||
|
target[idx1.Value - 2] = Sprite.Create(
|
||||||
|
texture, new Rect(0, 0, texture.width, texture.height), pivot, 1f,
|
||||||
|
0, SpriteMeshType.Tight, targetSprite.border
|
||||||
|
);
|
||||||
|
MelonLogger.Msg($"[CustomNoteSkin] Successfully loaded {name}");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (LoadIntoGameNoteImageContainer(fieldName, idx1, idx2, texture))
|
||||||
|
{
|
||||||
|
MelonLogger.Msg($"[CustomNoteSkin] Successfully loaded {name}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[HarmonyPostfix]
|
||||||
|
[HarmonyPatch(typeof(GameCtrl), "Initialize")]
|
||||||
|
private static void ChangeOutlineTexture(GameObject ____guideEndPointObj)
|
||||||
|
{
|
||||||
|
if (____guideEndPointObj != null && customOutline != null)
|
||||||
|
{
|
||||||
|
____guideEndPointObj.GetComponent<SpriteRenderer>().sprite = customOutline;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[HarmonyPostfix]
|
||||||
|
[HarmonyPatch(typeof(SlideFan), "Initialize")]
|
||||||
|
private static void ChangeFanTexture(
|
||||||
|
SpriteRenderer[] ____spriteLines, SpriteRenderer[] ____effectSprites, bool ___BreakFlag, bool ___EachFlag
|
||||||
|
)
|
||||||
|
{
|
||||||
|
Vector3 position;
|
||||||
|
Sprite sprite;
|
||||||
|
if (___BreakFlag)
|
||||||
|
{
|
||||||
|
for (var i = 0; i < 11; i++)
|
||||||
|
{
|
||||||
|
sprite = customSlideFan[2, i];
|
||||||
|
if (sprite != null)
|
||||||
|
{
|
||||||
|
____spriteLines[2 * i].sprite = sprite;
|
||||||
|
position = ____spriteLines[2 * i].transform.localPosition;
|
||||||
|
____spriteLines[2 * i].transform.localPosition = new Vector3(0, position.y, position.z);
|
||||||
|
____spriteLines[2 * i].color = Color.white;
|
||||||
|
|
||||||
|
____spriteLines[2 * i + 1].sprite = sprite;
|
||||||
|
position = ____spriteLines[2 * i + 1].transform.localPosition;
|
||||||
|
____spriteLines[2 * i + 1].transform.localPosition = new Vector3(0, position.y, position.z);
|
||||||
|
____spriteLines[2 * i + 1].color = Color.white;
|
||||||
|
}
|
||||||
|
|
||||||
|
sprite = customSlideFan[3, i];
|
||||||
|
if (sprite != null)
|
||||||
|
{
|
||||||
|
____effectSprites[2 * i].sprite = sprite;
|
||||||
|
position = ____effectSprites[2 * i].transform.localPosition;
|
||||||
|
____effectSprites[2 * i].transform.localPosition = new Vector3(0, position.y, position.z);
|
||||||
|
____effectSprites[2 * i].color = Color.white;
|
||||||
|
|
||||||
|
____effectSprites[2 * i + 1].sprite = sprite;
|
||||||
|
position = ____effectSprites[2 * i + 1].transform.localPosition;
|
||||||
|
____effectSprites[2 * i + 1].transform.localPosition = new Vector3(0, position.y, position.z);
|
||||||
|
____effectSprites[2 * i + 1].color = Color.white;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (___EachFlag)
|
||||||
|
{
|
||||||
|
for (var i = 0; i < 11; i++)
|
||||||
|
{
|
||||||
|
sprite = customSlideFan[1, i];
|
||||||
|
if (sprite != null)
|
||||||
|
{
|
||||||
|
____spriteLines[2 * i].sprite = sprite;
|
||||||
|
position = ____spriteLines[2 * i].transform.localPosition;
|
||||||
|
____spriteLines[2 * i].transform.localPosition = new Vector3(0, position.y, position.z);
|
||||||
|
____spriteLines[2 * i].color = Color.white;
|
||||||
|
|
||||||
|
____spriteLines[2 * i + 1].sprite = sprite;
|
||||||
|
position = ____spriteLines[2 * i + 1].transform.localPosition;
|
||||||
|
____spriteLines[2 * i + 1].transform.localPosition = new Vector3(0, position.y, position.z);
|
||||||
|
____spriteLines[2 * i + 1].color = Color.white;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (var i = 0; i < 11; i++)
|
||||||
|
{
|
||||||
|
sprite = customSlideFan[0, i];
|
||||||
|
if (sprite != null)
|
||||||
|
{
|
||||||
|
____spriteLines[2 * i].sprite = sprite;
|
||||||
|
position = ____spriteLines[2 * i].transform.localPosition;
|
||||||
|
____spriteLines[2 * i].transform.localPosition = new Vector3(0, position.y, position.z);
|
||||||
|
____spriteLines[2 * i].color = Color.white;
|
||||||
|
|
||||||
|
____spriteLines[2 * i + 1].sprite = sprite;
|
||||||
|
position = ____spriteLines[2 * i + 1].transform.localPosition;
|
||||||
|
____spriteLines[2 * i + 1].transform.localPosition = new Vector3(0, position.y, position.z);
|
||||||
|
____spriteLines[2 * i + 1].color = Color.white;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -16,6 +16,7 @@ namespace AquaMai.UX
|
||||||
{
|
{
|
||||||
var userOption = Singleton<GamePlayManager>.Instance.GetGameScore(i).UserOption;
|
var userOption = Singleton<GamePlayManager>.Instance.GetGameScore(i).UserOption;
|
||||||
userOption.NoteSpeed = OptionNotespeedID.Speed6_5;
|
userOption.NoteSpeed = OptionNotespeedID.Speed6_5;
|
||||||
|
userOption.TouchSpeed = OptionTouchspeedID.Speed7_0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
using Fx;
|
||||||
|
using HarmonyLib;
|
||||||
|
using Monitor;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace AquaMai.UX;
|
||||||
|
|
||||||
|
public class HideHanabi
|
||||||
|
{
|
||||||
|
[HarmonyPatch(typeof(TapCEffect), "SetUpParticle")]
|
||||||
|
[HarmonyPostfix]
|
||||||
|
public static void FixZeroSize(TapCEffect __instance, FX_Mai2_Note_Color ____particleControler)
|
||||||
|
{
|
||||||
|
var entities = ____particleControler.GetComponentsInChildren<ParticleSystemRenderer>(true);
|
||||||
|
foreach (var entity in entities)
|
||||||
|
{
|
||||||
|
entity.maxParticleSize = 0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -12,7 +12,6 @@ namespace AquaMai.UX
|
||||||
public class RandomBgm
|
public class RandomBgm
|
||||||
{
|
{
|
||||||
private static List<string> _acbs = new List<string>();
|
private static List<string> _acbs = new List<string>();
|
||||||
private static Random _rng = new Random();
|
|
||||||
|
|
||||||
[HarmonyPostfix]
|
[HarmonyPostfix]
|
||||||
[HarmonyPatch(typeof(SoundManager), "Initialize")]
|
[HarmonyPatch(typeof(SoundManager), "Initialize")]
|
||||||
|
@ -43,7 +42,7 @@ namespace AquaMai.UX
|
||||||
case Cue.BGM_COLLECTION:
|
case Cue.BGM_COLLECTION:
|
||||||
case Cue.BGM_RESULT_CLEAR:
|
case Cue.BGM_RESULT_CLEAR:
|
||||||
case Cue.BGM_RESULT:
|
case Cue.BGM_RESULT:
|
||||||
var acb = _acbs[_rng.Next(_acbs.Count)];
|
var acb = _acbs[UnityEngine.Random.Range(0, _acbs.Count)];
|
||||||
acbID = SoundManager.AcbID.Max;
|
acbID = SoundManager.AcbID.Max;
|
||||||
var result = Singleton<SoundCtrl>.Instance.LoadCueSheet((int)acbID, acb);
|
var result = Singleton<SoundCtrl>.Instance.LoadCueSheet((int)acbID, acb);
|
||||||
MelonLogger.Msg($"Picked {acb} for {cueIndex}, result: {result}");
|
MelonLogger.Msg($"Picked {acb} for {cueIndex}, result: {result}");
|
||||||
|
|
|
@ -20,6 +20,7 @@ namespace AquaMai.UX
|
||||||
{
|
{
|
||||||
left.transform.position = Vector3.zero;
|
left.transform.position = Vector3.zero;
|
||||||
right.localScale = Vector3.zero;
|
right.localScale = Vector3.zero;
|
||||||
|
GameObject.Find("Mask").transform.position = new Vector3(540f, 0f, 0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
[HarmonyPrefix]
|
[HarmonyPrefix]
|
||||||
|
|
|
@ -0,0 +1,83 @@
|
||||||
|
using HarmonyLib;
|
||||||
|
using Monitor;
|
||||||
|
using Process;
|
||||||
|
using UI;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace AquaMai.UX;
|
||||||
|
|
||||||
|
public class TrackStartProcessTweak
|
||||||
|
{
|
||||||
|
// 总之这个 Patch 没啥用, 是我个人用 sinmai 录谱面确认时用得到, 顺手也写进来了
|
||||||
|
// 具体而言就是推迟了歌曲开始界面的动画便于后期剪辑
|
||||||
|
// 然后把“TRACK X”字样和 DX/标准谱面的显示框隐藏掉, 让他看起来不那么 sinmai, 更像是 majdata
|
||||||
|
|
||||||
|
[HarmonyPrefix]
|
||||||
|
[HarmonyPatch(typeof(TrackStartProcess), "OnUpdate")]
|
||||||
|
private static bool DelayAnimation(
|
||||||
|
TrackStartProcess.TrackStartSequence ____state,
|
||||||
|
ref float ____timeCounter,
|
||||||
|
ProcessDataContainer ___container
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if (____state == TrackStartProcess.TrackStartSequence.Wait)
|
||||||
|
{
|
||||||
|
// 将开始动画(就是“噔噔, 噔 噔噔”)推迟
|
||||||
|
float temp = ____timeCounter + Time.deltaTime;
|
||||||
|
if (____timeCounter < 1.0f && temp >= 1.0f)
|
||||||
|
{
|
||||||
|
// 这是用来让转场动画继续播放的, 原本就是这个时候 notify 的同时开始播放开始动画
|
||||||
|
// 现在把开始动画往后延
|
||||||
|
___container.processManager.NotificationFadeIn();
|
||||||
|
}
|
||||||
|
____timeCounter = temp;
|
||||||
|
if (____timeCounter >= 3.0f)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
// 原 method 的逻辑是这样
|
||||||
|
// case TrackStartProcess.TrackStartSequence.Wait:
|
||||||
|
// this._timeCounter += Time.deltaTime;
|
||||||
|
// if ((double) this._timeCounter >= 1.0)
|
||||||
|
// {
|
||||||
|
// this._timeCounter = 0.0f;
|
||||||
|
// this._state = TrackStartProcess.TrackStartSequence.Disp;
|
||||||
|
// /* 一些开始播放开始动画的代码 */
|
||||||
|
// this.container.processManager.NotificationFadeIn();
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
// break;
|
||||||
|
// 所以只要在 prefix 里面等到 timeCounter 达到我们想要的值以后再执行原 method 就好
|
||||||
|
// 这里有个细节: NotificationFadeIn() 会被执行两遍, 这其实不好, 是个潜在 bug
|
||||||
|
// 不过由于此处把开始动画往后推了 2s, 转场动画已经结束把 Process 释放掉了, 所以第二遍会找不到 Process 就没效果
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else if (____state == TrackStartProcess.TrackStartSequence.DispEnd)
|
||||||
|
{
|
||||||
|
// 将开始动画结束以后的转场动画推迟
|
||||||
|
____timeCounter += Time.deltaTime; // timeCounter 会在先前由原本的 method 归零
|
||||||
|
if (____timeCounter >= 1.0f)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
[HarmonyPostfix]
|
||||||
|
[HarmonyPatch(typeof(TrackStartMonitor), "SetTrackStart")]
|
||||||
|
private static void DisableTabs(
|
||||||
|
SpriteCounter ____trackNumber, SpriteCounter ____bossTrackNumber, SpriteCounter ____utageTrackNumber,
|
||||||
|
MultipleImage ____musicTabImage, GameObject[] ____musicTabObj
|
||||||
|
)
|
||||||
|
{
|
||||||
|
____trackNumber.transform.parent.gameObject.SetActive(false);
|
||||||
|
____bossTrackNumber.transform.parent.gameObject.SetActive(false);
|
||||||
|
____utageTrackNumber.transform.parent.gameObject.SetActive(false);
|
||||||
|
____musicTabImage.gameObject.SetActive(false);
|
||||||
|
____musicTabObj[0].gameObject.SetActive(false);
|
||||||
|
____musicTabObj[1].gameObject.SetActive(false);
|
||||||
|
____musicTabObj[2].gameObject.SetActive(false);
|
||||||
|
}
|
||||||
|
}
|
|
@ -81,6 +81,9 @@ public class PractiseModeUI : MonoBehaviour
|
||||||
GUI.Label(GetButtonRect(1, 2), $"{Locale.Speed} {PractiseMode.speed * 100:000}%");
|
GUI.Label(GetButtonRect(1, 2), $"{Locale.Speed} {PractiseMode.speed * 100:000}%");
|
||||||
GUI.Button(GetButtonRect(2, 2), Locale.SpeedUp);
|
GUI.Button(GetButtonRect(2, 2), Locale.SpeedUp);
|
||||||
GUI.Button(GetButtonRect(1, 3), Locale.SpeedReset);
|
GUI.Button(GetButtonRect(1, 3), Locale.SpeedReset);
|
||||||
|
|
||||||
|
GUI.Label(GetButtonRect(0, 3), TimeSpan.FromMilliseconds(DebugFeature.CurrentPlayMsec).ToString(@"mm\:ss\.fff"));
|
||||||
|
GUI.Label(GetButtonRect(2, 3), TimeSpan.FromMilliseconds(NotesManager.Instance().getPlayFinalMsec()).ToString(@"mm\:ss\.fff"));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Update()
|
public void Update()
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
"@sveltejs/vite-plugin-svelte": "^3.1.0",
|
"@sveltejs/vite-plugin-svelte": "^3.1.0",
|
||||||
"@tsconfig/svelte": "^5.0.4",
|
"@tsconfig/svelte": "^5.0.4",
|
||||||
"@types/d3": "^7",
|
"@types/d3": "^7",
|
||||||
|
"@types/wicg-file-system-access": "^2023.10.5",
|
||||||
"@unocss/svelte-scoped": "^0.62.4",
|
"@unocss/svelte-scoped": "^0.62.4",
|
||||||
"chartjs-adapter-moment": "^1.0.1",
|
"chartjs-adapter-moment": "^1.0.1",
|
||||||
"eslint": "^8.57.0",
|
"eslint": "^8.57.0",
|
||||||
|
@ -39,7 +40,8 @@
|
||||||
"lxgw-wenkai-lite-webfont": "^1.7.0",
|
"lxgw-wenkai-lite-webfont": "^1.7.0",
|
||||||
"modern-normalize": "^2.0.0",
|
"modern-normalize": "^2.0.0",
|
||||||
"moment": "^2.30.1",
|
"moment": "^2.30.1",
|
||||||
|
"show-open-file-picker": "^0.2.2",
|
||||||
"svelte-chartjs": "^3.1.5"
|
"svelte-chartjs": "^3.1.5"
|
||||||
},
|
},
|
||||||
"packageManager": "yarn@4.1.1"
|
"packageManager": "pnpm@9.7.0+sha512.dc09430156b427f5ecfc79888899e1c39d2d690f004be70e05230b72cb173d96839587545d09429b55ac3c429c801b4dc3c0e002f653830a420fa2dd4e3cf9cf"
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -305,6 +305,8 @@ export const GAME = {
|
||||||
post(`/api/v2/game/${game}/export`),
|
post(`/api/v2/game/${game}/export`),
|
||||||
import: (game: GameName, data: any): Promise<Record<string, any>> =>
|
import: (game: GameName, data: any): Promise<Record<string, any>> =>
|
||||||
post(`/api/v2/game/${game}/import`, {}, { body: JSON.stringify(data) }),
|
post(`/api/v2/game/${game}/import`, {}, { body: JSON.stringify(data) }),
|
||||||
|
importMusicDetail: (game: GameName, data: any): Promise<Record<string, any>> =>
|
||||||
|
post(`/api/v2/game/${game}/import-music-detail`, {}, {body: JSON.stringify(data), headers: {'Content-Type': 'application/json'}}),
|
||||||
setRival: (game: GameName, rivalUserName: string, isAdd: boolean) =>
|
setRival: (game: GameName, rivalUserName: string, isAdd: boolean) =>
|
||||||
post(`/api/v2/game/${game}/set-rival`, { rivalUserName, isAdd }),
|
post(`/api/v2/game/${game}/set-rival`, { rivalUserName, isAdd }),
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
import StatusOverlays from "../../components/StatusOverlays.svelte";
|
import StatusOverlays from "../../components/StatusOverlays.svelte";
|
||||||
import { CARD, GAME, USER } from "../../libs/sdk";
|
import { CARD, GAME, USER } from "../../libs/sdk";
|
||||||
import Icon from "@iconify/svelte";
|
import Icon from "@iconify/svelte";
|
||||||
|
import { showOpenFilePicker } from 'show-open-file-picker'
|
||||||
|
|
||||||
let load = false;
|
let load = false;
|
||||||
let error = "";
|
let error = "";
|
||||||
|
@ -17,8 +18,8 @@
|
||||||
let confirmAction: (override: boolean) => void;
|
let confirmAction: (override: boolean) => void;
|
||||||
|
|
||||||
const startImport = async () => {
|
const startImport = async () => {
|
||||||
const [fileHandle] = await window.showOpenFilePicker({
|
const [fileHandle] = await (window.showOpenFilePicker || showOpenFilePicker)({
|
||||||
id: 'aquadx_import',
|
id: 'aquadx_import' as any,
|
||||||
startIn: 'downloads',
|
startIn: 'downloads',
|
||||||
types: [
|
types: [
|
||||||
{
|
{
|
||||||
|
@ -36,9 +37,17 @@
|
||||||
try {
|
try {
|
||||||
const file = await fileHandle.getFile();
|
const file = await fileHandle.getFile();
|
||||||
const data = JSON.parse(await file.text()) as any;
|
const data = JSON.parse(await file.text()) as any;
|
||||||
const game = getGameByCode(data.gameId);
|
|
||||||
|
|
||||||
const me = await USER.me();
|
const me = await USER.me();
|
||||||
|
|
||||||
|
const maybeUserMusicList = data?.userMusicList || data;
|
||||||
|
if (Array.isArray(maybeUserMusicList) && maybeUserMusicList.every(it => Array.isArray(it?.userMusicDetailList))) {
|
||||||
|
// Is music list array
|
||||||
|
await GAME.importMusicDetail("mai2", maybeUserMusicList.flatMap(it => it.userMusicDetailList));
|
||||||
|
location.href = `/u/${me.username}/mai2`;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const game = getGameByCode(data.gameId);
|
||||||
const userGames = await CARD.userGames(me.username);
|
const userGames = await CARD.userGames(me.username);
|
||||||
|
|
||||||
const existed = userGames[game];
|
const existed = userGames[game];
|
||||||
|
|
|
@ -0,0 +1,45 @@
|
||||||
|
package icu.samnyan.aqua.net.games.mai2
|
||||||
|
|
||||||
|
import ext.*
|
||||||
|
import icu.samnyan.aqua.net.db.AquaUserServices
|
||||||
|
import icu.samnyan.aqua.net.utils.SUCCESS
|
||||||
|
import icu.samnyan.aqua.sega.maimai2.model.Mai2Repos
|
||||||
|
import icu.samnyan.aqua.sega.maimai2.model.userdata.Mai2UserMusicDetail
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping
|
||||||
|
import org.springframework.web.bind.annotation.RestController
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@API("api/v2/game/mai2")
|
||||||
|
class Mai2MusicDetailImport(
|
||||||
|
val us: AquaUserServices,
|
||||||
|
val repos: Mai2Repos,
|
||||||
|
) {
|
||||||
|
@PostMapping("import-music-detail")
|
||||||
|
suspend fun importMusicDetail(@RP token: String, @RB data: List<Mai2UserMusicDetail>) = us.jwt.auth(token) { u ->
|
||||||
|
us.cardByName(u.username) { card ->
|
||||||
|
val user = repos.userData.findByCardExtId(card.extId).orElse(null) ?: (404 - "User not found")
|
||||||
|
data.forEach { newMusic ->
|
||||||
|
val musicRec = repos.userMusicDetail.findByUserAndMusicIdAndLevel(user, newMusic.musicId, newMusic.level)
|
||||||
|
if (musicRec.isPresent) {
|
||||||
|
val music = musicRec.get()
|
||||||
|
newMusic.apply {
|
||||||
|
id = music.id
|
||||||
|
this.user = user
|
||||||
|
achievement = achievement.coerceAtLeast(music.achievement)
|
||||||
|
scoreRank = scoreRank.coerceAtLeast(music.scoreRank)
|
||||||
|
comboStatus = comboStatus.coerceAtLeast(music.comboStatus)
|
||||||
|
syncStatus = syncStatus.coerceAtLeast(music.syncStatus)
|
||||||
|
deluxscoreMax = deluxscoreMax.coerceAtLeast(music.deluxscoreMax)
|
||||||
|
playCount = playCount.coerceAtLeast(music.playCount)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
newMusic.apply {
|
||||||
|
this.user = user
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
repos.userMusicDetail.saveAll(data)
|
||||||
|
SUCCESS
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue