From da3640fe2bc4c1f0bedaeb9257807396201b4041 Mon Sep 17 00:00:00 2001 From: beerpsi <92439990+beer-psi@users.noreply.github.com> Date: Thu, 29 May 2025 10:32:04 +0700 Subject: [PATCH 1/8] feat: FixLocaleIssues --- AquaMai.Mods/Fix/FixLocaleIssues.cs | 77 +++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) create mode 100644 AquaMai.Mods/Fix/FixLocaleIssues.cs diff --git a/AquaMai.Mods/Fix/FixLocaleIssues.cs b/AquaMai.Mods/Fix/FixLocaleIssues.cs new file mode 100644 index 00000000..9a68819e --- /dev/null +++ b/AquaMai.Mods/Fix/FixLocaleIssues.cs @@ -0,0 +1,77 @@ +using System; +using System.Globalization; +using AquaMai.Config.Attributes; +using HarmonyLib; +using JetBrains.Annotations; +using Manager; + +namespace AquaMai.Mods.Fix; + +// Fixes various locale issues that pop up if the game runs in a different locale than ja-JP. +[ConfigSection(exampleHidden: true, defaultOn: true)] +public class FixLocaleIssues +{ + private static readonly CultureInfo JapanCultureInfo = new CultureInfo("ja-JP"); + [CanBeNull] private static TimeZoneInfo _tokyoStandardTime; + + [HarmonyPrefix] + [HarmonyPatch(typeof(int), "Parse", typeof(string))] + private static bool int_Parse(ref int __result, string s) + { + __result = int.Parse(s, JapanCultureInfo); + return false; + } + + [HarmonyPrefix] + [HarmonyPatch(typeof(float), "Parse", typeof(string))] + private static bool float_Parse(ref float __result, string s) + { + __result = float.Parse(s, JapanCultureInfo); + return false; + } + + // Forces local timezone to be UTC+9, since segatools didn't patch it properly until recent versions, + // which doesn't actually work well with maimai. + [HarmonyPrefix] + [HarmonyPatch(typeof(DateTime), "get_Now")] + private static bool DateTime_get_Now(ref DateTime __result) + { + if (_tokyoStandardTime == null) + { + try + { + _tokyoStandardTime = TimeZoneInfo.FindSystemTimeZoneById("Tokyo Standard Time"); + } + catch (Exception e) when (e is TimeZoneNotFoundException or InvalidTimeZoneException) + { + _tokyoStandardTime = TimeZoneInfo.CreateCustomTimeZone( + "Tokyo Standard Time", + TimeManager.JpTime, + "(UTC+09:00) Osaka, Sapporo, Tokyo", + "Tokyo Standard Time", + "Tokyo Daylight Time", + null, + true); + } + } + + __result = TimeZoneInfo.ConvertTimeFromUtc(DateTime.UtcNow, _tokyoStandardTime!); + return false; + } + + [HarmonyPrefix] + [HarmonyPatch(typeof(DateTime), "Parse")] + private static bool DateTime_Parse(ref DateTime __result, string s) + { + __result = DateTime.Parse(s, JapanCultureInfo); + return false; + } + + [HarmonyPrefix] + [HarmonyPatch(typeof(DateTime), "ToShortDateString")] + private static bool DateTime_ToShortDateString(DateTime __instance, ref string __result) + { + __result = __instance.ToString("d", JapanCultureInfo); + return false; + } +} From c4ccf67f71d1b2dd7d83b377a0ff47f28621b965 Mon Sep 17 00:00:00 2001 From: beerpsi <92439990+beer-psi@users.noreply.github.com> Date: Thu, 29 May 2025 10:34:33 +0700 Subject: [PATCH 2/8] fix: resolve ambiguity for DateTime.Parse --- AquaMai.Mods/Fix/FixLocaleIssues.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AquaMai.Mods/Fix/FixLocaleIssues.cs b/AquaMai.Mods/Fix/FixLocaleIssues.cs index 9a68819e..2b593a95 100644 --- a/AquaMai.Mods/Fix/FixLocaleIssues.cs +++ b/AquaMai.Mods/Fix/FixLocaleIssues.cs @@ -60,7 +60,7 @@ private static bool DateTime_get_Now(ref DateTime __result) } [HarmonyPrefix] - [HarmonyPatch(typeof(DateTime), "Parse")] + [HarmonyPatch(typeof(DateTime), "Parse", typeof(string))] private static bool DateTime_Parse(ref DateTime __result, string s) { __result = DateTime.Parse(s, JapanCultureInfo); From 8e3a5712a2f2c2ce4f78de9299af76c9740bd988 Mon Sep 17 00:00:00 2001 From: beerpsi <92439990+beer-psi@users.noreply.github.com> Date: Thu, 29 May 2025 10:48:26 +0700 Subject: [PATCH 3/8] Update FixLocaleIssues.cs --- AquaMai.Mods/Fix/FixLocaleIssues.cs | 69 +++++++++++------------------ 1 file changed, 25 insertions(+), 44 deletions(-) diff --git a/AquaMai.Mods/Fix/FixLocaleIssues.cs b/AquaMai.Mods/Fix/FixLocaleIssues.cs index 2b593a95..1dfac18d 100644 --- a/AquaMai.Mods/Fix/FixLocaleIssues.cs +++ b/AquaMai.Mods/Fix/FixLocaleIssues.cs @@ -4,6 +4,7 @@ using HarmonyLib; using JetBrains.Annotations; using Manager; +using MelonLoader; namespace AquaMai.Mods.Fix; @@ -11,23 +12,33 @@ namespace AquaMai.Mods.Fix; [ConfigSection(exampleHidden: true, defaultOn: true)] public class FixLocaleIssues { - private static readonly CultureInfo JapanCultureInfo = new CultureInfo("ja-JP"); + private static readonly CultureInfo JapanCultureInfo = CultureInfo.GetCultureInfo("ja-JP"); [CanBeNull] private static TimeZoneInfo _tokyoStandardTime; - [HarmonyPrefix] - [HarmonyPatch(typeof(int), "Parse", typeof(string))] - private static bool int_Parse(ref int __result, string s) + public static void OnBeforePatch() { - __result = int.Parse(s, JapanCultureInfo); - return false; - } + CultureInfo.DefaultThreadCurrentCulture = JapanCultureInfo; + CultureInfo.DefaultThreadCurrentUICulture = JapanCultureInfo; - [HarmonyPrefix] - [HarmonyPatch(typeof(float), "Parse", typeof(string))] - private static bool float_Parse(ref float __result, string s) - { - __result = float.Parse(s, JapanCultureInfo); - return false; + try + { + _tokyoStandardTime = TimeZoneInfo.FindSystemTimeZoneById("Tokyo Standard Time"); + } + catch (Exception e) when (e is TimeZoneNotFoundException or InvalidTimeZoneException) + { + _tokyoStandardTime = TimeZoneInfo.CreateCustomTimeZone( + "Tokyo Standard Time", + TimeManager.JpTime, + "(UTC+09:00) Osaka, Sapporo, Tokyo", + "Tokyo Standard Time", + "Tokyo Daylight Time", + null, + true); + } + catch (Exception e) + { + MelonLogger.Warning($"Could not get JST timezone, DateTime.Now patch will not work: {e.StackTrace}"); + } } // Forces local timezone to be UTC+9, since segatools didn't patch it properly until recent versions, @@ -38,40 +49,10 @@ private static bool DateTime_get_Now(ref DateTime __result) { if (_tokyoStandardTime == null) { - try - { - _tokyoStandardTime = TimeZoneInfo.FindSystemTimeZoneById("Tokyo Standard Time"); - } - catch (Exception e) when (e is TimeZoneNotFoundException or InvalidTimeZoneException) - { - _tokyoStandardTime = TimeZoneInfo.CreateCustomTimeZone( - "Tokyo Standard Time", - TimeManager.JpTime, - "(UTC+09:00) Osaka, Sapporo, Tokyo", - "Tokyo Standard Time", - "Tokyo Daylight Time", - null, - true); - } + return true; } __result = TimeZoneInfo.ConvertTimeFromUtc(DateTime.UtcNow, _tokyoStandardTime!); return false; } - - [HarmonyPrefix] - [HarmonyPatch(typeof(DateTime), "Parse", typeof(string))] - private static bool DateTime_Parse(ref DateTime __result, string s) - { - __result = DateTime.Parse(s, JapanCultureInfo); - return false; - } - - [HarmonyPrefix] - [HarmonyPatch(typeof(DateTime), "ToShortDateString")] - private static bool DateTime_ToShortDateString(DateTime __instance, ref string __result) - { - __result = __instance.ToString("d", JapanCultureInfo); - return false; - } } From 75ae6c7c142a8062d2760157c3b631796a95554f Mon Sep 17 00:00:00 2001 From: beerpsi <92439990+beer-psi@users.noreply.github.com> Date: Thu, 29 May 2025 10:51:50 +0700 Subject: [PATCH 4/8] also sets culture for current thread --- AquaMai.Mods/Fix/FixLocaleIssues.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/AquaMai.Mods/Fix/FixLocaleIssues.cs b/AquaMai.Mods/Fix/FixLocaleIssues.cs index 1dfac18d..b0d321a4 100644 --- a/AquaMai.Mods/Fix/FixLocaleIssues.cs +++ b/AquaMai.Mods/Fix/FixLocaleIssues.cs @@ -1,5 +1,6 @@ using System; using System.Globalization; +using System.Threading; using AquaMai.Config.Attributes; using HarmonyLib; using JetBrains.Annotations; @@ -19,6 +20,8 @@ public static void OnBeforePatch() { CultureInfo.DefaultThreadCurrentCulture = JapanCultureInfo; CultureInfo.DefaultThreadCurrentUICulture = JapanCultureInfo; + Thread.CurrentThread.CurrentCulture = JapanCultureInfo; + Thread.CurrentThread.CurrentUICulture = JapanCultureInfo; try { From 6e7cc56926df20db2edee2311b06a8da62cf8522 Mon Sep 17 00:00:00 2001 From: beerpsi <92439990+beer-psi@users.noreply.github.com> Date: Thu, 29 May 2025 10:58:01 +0700 Subject: [PATCH 5/8] fix: revert setting default thread locale doesn't actually work, thanks AI for nothing --- AquaMai.Mods/Fix/FixLocaleIssues.cs | 38 ++++++++++++++++++++++++----- 1 file changed, 32 insertions(+), 6 deletions(-) diff --git a/AquaMai.Mods/Fix/FixLocaleIssues.cs b/AquaMai.Mods/Fix/FixLocaleIssues.cs index b0d321a4..5a29a656 100644 --- a/AquaMai.Mods/Fix/FixLocaleIssues.cs +++ b/AquaMai.Mods/Fix/FixLocaleIssues.cs @@ -1,6 +1,5 @@ using System; using System.Globalization; -using System.Threading; using AquaMai.Config.Attributes; using HarmonyLib; using JetBrains.Annotations; @@ -18,11 +17,6 @@ public class FixLocaleIssues public static void OnBeforePatch() { - CultureInfo.DefaultThreadCurrentCulture = JapanCultureInfo; - CultureInfo.DefaultThreadCurrentUICulture = JapanCultureInfo; - Thread.CurrentThread.CurrentCulture = JapanCultureInfo; - Thread.CurrentThread.CurrentUICulture = JapanCultureInfo; - try { _tokyoStandardTime = TimeZoneInfo.FindSystemTimeZoneById("Tokyo Standard Time"); @@ -43,6 +37,22 @@ public static void OnBeforePatch() MelonLogger.Warning($"Could not get JST timezone, DateTime.Now patch will not work: {e.StackTrace}"); } } + + [HarmonyPrefix] + [HarmonyPatch(typeof(int), "Parse", typeof(string))] + private static bool int_Parse(ref int __result, string s) + { + __result = int.Parse(s, JapanCultureInfo); + return false; + } + + [HarmonyPrefix] + [HarmonyPatch(typeof(float), "Parse", typeof(string))] + private static bool float_Parse(ref float __result, string s) + { + __result = float.Parse(s, JapanCultureInfo); + return false; + } // Forces local timezone to be UTC+9, since segatools didn't patch it properly until recent versions, // which doesn't actually work well with maimai. @@ -58,4 +68,20 @@ private static bool DateTime_get_Now(ref DateTime __result) __result = TimeZoneInfo.ConvertTimeFromUtc(DateTime.UtcNow, _tokyoStandardTime!); return false; } + + [HarmonyPrefix] + [HarmonyPatch(typeof(DateTime), "Parse", typeof(string))] + private static bool DateTime_Parse(ref DateTime __result, string s) + { + __result = DateTime.Parse(s, JapanCultureInfo); + return false; + } + + [HarmonyPrefix] + [HarmonyPatch(typeof(DateTime), "ToShortDateString")] + private static bool DateTime_ToShortDateString(DateTime __instance, ref string __result) + { + __result = __instance.ToString("d", JapanCultureInfo); + return false; + } } From 111881c517141d99a71a1166542a908b9a3c946e Mon Sep 17 00:00:00 2001 From: beerpsi <92439990+beer-psi@users.noreply.github.com> Date: Thu, 29 May 2025 13:46:34 +0700 Subject: [PATCH 6/8] Add in locale overrides anyways, just in case --- AquaMai.Mods/Fix/FixLocaleIssues.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/AquaMai.Mods/Fix/FixLocaleIssues.cs b/AquaMai.Mods/Fix/FixLocaleIssues.cs index 5a29a656..eda21c26 100644 --- a/AquaMai.Mods/Fix/FixLocaleIssues.cs +++ b/AquaMai.Mods/Fix/FixLocaleIssues.cs @@ -1,5 +1,6 @@ using System; using System.Globalization; +using System.Threading; using AquaMai.Config.Attributes; using HarmonyLib; using JetBrains.Annotations; @@ -17,6 +18,11 @@ public class FixLocaleIssues public static void OnBeforePatch() { + Thread.CurrentThread.CurrentCulture = JapanCultureInfo; + Thread.CurrentThread.CurrentUICulture = JapanCultureInfo; + CultureInfo.DefaultThreadCurrentCulture = JapanCultureInfo; + CultureInfo.DefaultThreadCurrentUICulture = JapanCultureInfo; + try { _tokyoStandardTime = TimeZoneInfo.FindSystemTimeZoneById("Tokyo Standard Time"); From 98a722d9520f5cdbca6b8a5094e7455048d3df3a Mon Sep 17 00:00:00 2001 From: beerpsi <92439990+beer-psi@users.noreply.github.com> Date: Fri, 30 May 2025 22:10:29 +0700 Subject: [PATCH 7/8] fix: Patch straight at the root of this problem --- AquaMai.Mods/Fix/FixLocaleIssues.cs | 37 +++++++++++------------------ 1 file changed, 14 insertions(+), 23 deletions(-) diff --git a/AquaMai.Mods/Fix/FixLocaleIssues.cs b/AquaMai.Mods/Fix/FixLocaleIssues.cs index eda21c26..604b2474 100644 --- a/AquaMai.Mods/Fix/FixLocaleIssues.cs +++ b/AquaMai.Mods/Fix/FixLocaleIssues.cs @@ -13,7 +13,7 @@ namespace AquaMai.Mods.Fix; [ConfigSection(exampleHidden: true, defaultOn: true)] public class FixLocaleIssues { - private static readonly CultureInfo JapanCultureInfo = CultureInfo.GetCultureInfo("ja-JP"); + private static readonly CultureInfo JapanCultureInfo = new("ja-JP"); [CanBeNull] private static TimeZoneInfo _tokyoStandardTime; public static void OnBeforePatch() @@ -44,19 +44,26 @@ public static void OnBeforePatch() } } + // This covers all calls to T.Parse(String) or T.Parse(String, NumberStyles) + // where T is a number. Sets the current thread's culture to Japan before calling + // the original getter, since that's what the original getter depends on. + // + // While we already set the thread's culture on the OnBeforePatch lifecycle hook, + // it seems to not apply to the game at all for some reason. [HarmonyPrefix] - [HarmonyPatch(typeof(int), "Parse", typeof(string))] - private static bool int_Parse(ref int __result, string s) + [HarmonyPatch(typeof(NumberFormatInfo), "get_CurrentInfo")] + public static bool NumberFormatInfo_get_CurrentInfo(ref NumberFormatInfo __result) { - __result = int.Parse(s, JapanCultureInfo); + __result = (NumberFormatInfo)JapanCultureInfo.GetFormat(typeof(NumberFormatInfo)); return false; } + // Same for datetimes. [HarmonyPrefix] - [HarmonyPatch(typeof(float), "Parse", typeof(string))] - private static bool float_Parse(ref float __result, string s) + [HarmonyPatch(typeof(DateTimeFormatInfo), "get_CurrentInfo")] + public static bool DateTimeFormatInfo_get_CurrentInfo(ref DateTimeFormatInfo __result) { - __result = float.Parse(s, JapanCultureInfo); + __result = (DateTimeFormatInfo)JapanCultureInfo.GetFormat(typeof(DateTimeFormatInfo)); return false; } @@ -74,20 +81,4 @@ private static bool DateTime_get_Now(ref DateTime __result) __result = TimeZoneInfo.ConvertTimeFromUtc(DateTime.UtcNow, _tokyoStandardTime!); return false; } - - [HarmonyPrefix] - [HarmonyPatch(typeof(DateTime), "Parse", typeof(string))] - private static bool DateTime_Parse(ref DateTime __result, string s) - { - __result = DateTime.Parse(s, JapanCultureInfo); - return false; - } - - [HarmonyPrefix] - [HarmonyPatch(typeof(DateTime), "ToShortDateString")] - private static bool DateTime_ToShortDateString(DateTime __instance, ref string __result) - { - __result = __instance.ToString("d", JapanCultureInfo); - return false; - } } From 0a5fddf57494c0acae54c9e27bd445c751c9f020 Mon Sep 17 00:00:00 2001 From: beerpsi <92439990+beer-psi@users.noreply.github.com> Date: Fri, 30 May 2025 22:15:54 +0700 Subject: [PATCH 8/8] Update FixLocaleIssues.cs --- AquaMai.Mods/Fix/FixLocaleIssues.cs | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/AquaMai.Mods/Fix/FixLocaleIssues.cs b/AquaMai.Mods/Fix/FixLocaleIssues.cs index 604b2474..b02c4ac1 100644 --- a/AquaMai.Mods/Fix/FixLocaleIssues.cs +++ b/AquaMai.Mods/Fix/FixLocaleIssues.cs @@ -18,11 +18,6 @@ public class FixLocaleIssues public static void OnBeforePatch() { - Thread.CurrentThread.CurrentCulture = JapanCultureInfo; - Thread.CurrentThread.CurrentUICulture = JapanCultureInfo; - CultureInfo.DefaultThreadCurrentCulture = JapanCultureInfo; - CultureInfo.DefaultThreadCurrentUICulture = JapanCultureInfo; - try { _tokyoStandardTime = TimeZoneInfo.FindSystemTimeZoneById("Tokyo Standard Time"); @@ -54,7 +49,7 @@ public static void OnBeforePatch() [HarmonyPatch(typeof(NumberFormatInfo), "get_CurrentInfo")] public static bool NumberFormatInfo_get_CurrentInfo(ref NumberFormatInfo __result) { - __result = (NumberFormatInfo)JapanCultureInfo.GetFormat(typeof(NumberFormatInfo)); + __result = JapanCultureInfo.NumberFormat; return false; } @@ -63,7 +58,7 @@ public static bool NumberFormatInfo_get_CurrentInfo(ref NumberFormatInfo __resul [HarmonyPatch(typeof(DateTimeFormatInfo), "get_CurrentInfo")] public static bool DateTimeFormatInfo_get_CurrentInfo(ref DateTimeFormatInfo __result) { - __result = (DateTimeFormatInfo)JapanCultureInfo.GetFormat(typeof(DateTimeFormatInfo)); + __result = JapanCultureInfo.DateTimeFormat; return false; }