diff --git a/UXAssist/Common/PatchImpl.cs b/UXAssist/Common/PatchImpl.cs index b43f5a0..37c8601 100644 --- a/UXAssist/Common/PatchImpl.cs +++ b/UXAssist/Common/PatchImpl.cs @@ -13,9 +13,9 @@ public class PatchGuidAttribute(string guid) : Attribute public enum PatchCallbackFlag { - // OnEnable() is called After patch is applied by default, set this flag to call it before patch is applied + // By default, OnEnable() is called After patch applied, set this flag to call it before patch is applied CallOnEnableBeforePatch, - // OnDisable() is called Before patch is removed by default, set this flag to call it after patch is removed + // By default, OnDisable() is called Before patch removed, set this flag to call it after patch is removed CallOnDisableAfterUnpatch, } diff --git a/UXAssist/Functions/WindowFunctions.cs b/UXAssist/Functions/WindowFunctions.cs index f5cd34c..18170f1 100644 --- a/UXAssist/Functions/WindowFunctions.cs +++ b/UXAssist/Functions/WindowFunctions.cs @@ -221,7 +221,8 @@ public static class WindowFunctions var args = Environment.GetCommandLineArgs(); for (var i = 0; i < args.Length - 1; i++) { - if (args[i] != "--doorstop-target") continue; + // Doorstop 3.x and 4.x use different arguments to pass the target assembly path + if (args[i] != "--doorstop-target" && args[i] != "--doorstop-target-assembly") continue; var arg = args[i + 1]; const string doorstopPathSuffix = @"\BepInEx\core\BepInEx.Preloader.dll"; if (!arg.EndsWith(doorstopPathSuffix, StringComparison.OrdinalIgnoreCase)) diff --git a/UXAssist/Patches/GamePatch.cs b/UXAssist/Patches/GamePatch.cs index a113639..075879a 100644 --- a/UXAssist/Patches/GamePatch.cs +++ b/UXAssist/Patches/GamePatch.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.IO; using System.Reflection.Emit; +using System.Xml; using BepInEx.Configuration; using CommonAPI.Systems; using HarmonyLib; @@ -86,7 +87,7 @@ public class GamePatch : PatchImpl // AutoSaveOptEnabled.SettingChanged += (_, _) => AutoSaveOpt.Enable(AutoSaveOptEnabled.Value); ConvertSavesFromPeaceEnabled.SettingChanged += (_, _) => ConvertSavesFromPeace.Enable(ConvertSavesFromPeaceEnabled.Value); ProfileBasedSaveFolderEnabled.SettingChanged += (_, _) => RefreshSavePath(); - ProfileBasedOptionEnabled.SettingChanged += (_, _) => RefreshSavePath(); + ProfileBasedOptionEnabled.SettingChanged += (_, _) => ProfileBasedOption.Enable(ProfileBasedOptionEnabled.Value); DefaultProfileName.SettingChanged += (_, _) => RefreshSavePath(); GameUpsFactor.SettingChanged += (_, _) => { @@ -99,11 +100,12 @@ public class GamePatch : PatchImpl FPSController.SetFixUPS(GameMain.tickPerSec * GameUpsFactor.Value); }; - RefreshSavePath(); + ProfileBasedOption.Enable(ProfileBasedOptionEnabled.Value); } public static void Start() { + RefreshSavePath(); EnableWindowResize.Enable(EnableWindowResizeEnabled.Value); LoadLastWindowRect.Enable(LoadLastWindowRectEnabled.Value); MouseCursorScaleUp.NeedReloadCursors = false; @@ -172,21 +174,6 @@ public class GamePatch : PatchImpl { Directory.CreateDirectory(GameConfig.gameSavePath); } - - string optionPath; - if (ProfileBasedOptionEnabled.Value && string.Compare(DefaultProfileName.Value, profileName, StringComparison.OrdinalIgnoreCase) != 0) - { - var path = $"{GameConfig.gameDocumentFolder}Option"; - if (!Directory.Exists(path)) - { - Directory.CreateDirectory(path); - } - optionPath = $"{path}/{profileName}.xml"; - } - else - optionPath = $"{GameConfig.gameDocumentFolder}options.xml"; - if (string.Compare(GameConfig.gameXMLOption, optionPath, StringComparison.OrdinalIgnoreCase) == 0) return; - GameConfig.gameXMLOption = optionPath; } [HarmonyPrefix, HarmonyPatch(typeof(GameMain), nameof(GameMain.HandleApplicationQuit))] @@ -554,6 +541,80 @@ public class GamePatch : PatchImpl } } + private class ProfileBasedOption : PatchImpl + { + [HarmonyPrefix] + [HarmonyPatch(typeof(GameOption), nameof(GameOption.LoadGlobal))] + private static bool GameOption_LoadGlobal_Prefix(ref GameOption __instance) + { + UXAssist.Logger.LogDebug("Loading global option"); + var profileName = WindowFunctions.ProfileName; + if (profileName == null) + { + // We should initialize WindowFunctions before using WindowFunctions.ProfileName + WindowFunctions.Init(); + profileName = WindowFunctions.ProfileName; + if (profileName == null) return true; + } + if (string.Compare(DefaultProfileName.Value, profileName, StringComparison.OrdinalIgnoreCase) == 0) return true; + var optionPath = $"{GameConfig.gameDocumentFolder}Option/{profileName}.xml"; + if (File.Exists(optionPath)) + { + try + { + __instance.ImportXML(optionPath); + return false; + } + catch + { + } + } + var gameXMLOptionPath = GameConfig.gameXMLOptionPath; + if (File.Exists(gameXMLOptionPath)) + { + try + { + __instance.ImportXML(gameXMLOptionPath); + return false; + } + catch (Exception ex) + { + Debug.LogException(ex); + } + } + GameOption.newlyCreated = true; + __instance.SetDefault(); + return false; + } + + [HarmonyPrefix] + [HarmonyPatch(typeof(GameOption), nameof(GameOption.SaveGlobal))] + private static bool GameOption_SaveGlobal_Prefix(ref GameOption __instance) + { + var profileName = WindowFunctions.ProfileName; + if (profileName == null) return true; + if (string.Compare(DefaultProfileName.Value, profileName, StringComparison.OrdinalIgnoreCase) == 0) return true; + var path = $"{GameConfig.gameDocumentFolder}Option"; + if (!Directory.Exists(path)) + { + Directory.CreateDirectory(path); + } + try + { + using FileStream fileStream = new($"{path}/{profileName}.xml", FileMode.Create, FileAccess.Write, FileShare.None); + using XmlTextWriter xmlTextWriter = new(fileStream, Console.OutputEncoding); + xmlTextWriter.Formatting = Formatting.Indented; + __instance.ExportXML(xmlTextWriter); + xmlTextWriter.Close(); + } + catch (Exception ex) + { + Debug.LogException(ex); + } + return false; + } + } + [PatchSetCallbackFlag(PatchCallbackFlag.CallOnDisableAfterUnpatch)] private class MouseCursorScaleUp : PatchImpl { diff --git a/UXAssist/UIConfigWindow.cs b/UXAssist/UIConfigWindow.cs index bad0ec2..1a15aae 100644 --- a/UXAssist/UIConfigWindow.cs +++ b/UXAssist/UIConfigWindow.cs @@ -35,8 +35,8 @@ public static class UIConfigWindow I18N.Add("Profile-based save folder tips", "Save files are stored in 'Save\\' folder.\nWill use original save location if matching default profile name", "存档文件会存储在'Save\\'文件夹中\n如果匹配默认配置档案名则使用原始存档位置"); I18N.Add("Profile-based option", "Mod manager profile based option", "基于mod管理器配置档案名的选项设置"); - I18N.Add("Profile-based option tips", "Options are stored in 'Option\\.xml'.\nWill use original save location if matching default profile name", - "配置选项会存储在'Option\\.xml'里\n如果匹配默认配置档案名则使用原始存档位置"); + I18N.Add("Profile-based option tips", "Options are stored in 'Option\\.xml'.\nWill use original location if matching default profile name", + "配置选项会存储在'Option\\.xml'里\n如果匹配默认配置档案名则使用原始位置"); I18N.Add("Default profile name", "Default profile name", "默认配置档案名"); I18N.Add("Logical Frame Rate", "Logical Frame Rate", "逻辑帧倍率"); I18N.Add("Reset", "Reset", "重置");