From eb141caa0f8fcbe877bc7a092521140d644c79b4 Mon Sep 17 00:00:00 2001 From: Cephas369 Date: Wed, 7 Aug 2024 12:01:23 -0400 Subject: [PATCH 1/7] Fixed exception handler preventing debuggers from catching exceptions --- src/Bannerlord.ButterLib/ExceptionHandler/BEWPatch.cs | 3 --- .../ExceptionHandler/ExceptionHandlerSubSystem.cs | 2 ++ 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/Bannerlord.ButterLib/ExceptionHandler/BEWPatch.cs b/src/Bannerlord.ButterLib/ExceptionHandler/BEWPatch.cs index a9a3097a..fd960880 100644 --- a/src/Bannerlord.ButterLib/ExceptionHandler/BEWPatch.cs +++ b/src/Bannerlord.ButterLib/ExceptionHandler/BEWPatch.cs @@ -65,9 +65,6 @@ private static void Finalizer(Exception? __exception) { if (__exception is not null) { - if (ExceptionHandlerSubSystem.Instance?.DisableWhenDebuggerIsAttached == true && IsDebuggerAttached()) - return; - ExceptionReporter.Show(__exception); } } diff --git a/src/Bannerlord.ButterLib/ExceptionHandler/ExceptionHandlerSubSystem.cs b/src/Bannerlord.ButterLib/ExceptionHandler/ExceptionHandlerSubSystem.cs index 2cbd2ff1..412c822f 100644 --- a/src/Bannerlord.ButterLib/ExceptionHandler/ExceptionHandlerSubSystem.cs +++ b/src/Bannerlord.ButterLib/ExceptionHandler/ExceptionHandlerSubSystem.cs @@ -78,6 +78,8 @@ public void Enable() if (!BEWPatch.IsDebuggerAttached()) SubscribeToUnhandledException(); + else if (Instance?.DisableWhenDebuggerIsAttached == true) + return; if (!_wasButrLoaderInterceptorCalled) { From b4828429cd46b26a777412b1a2d8ec693e093aa0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 4 Sep 2024 04:48:42 +0000 Subject: [PATCH 2/7] Bump danielpalme/ReportGenerator-GitHub-Action from 5.3.7 to 5.3.9 Bumps [danielpalme/ReportGenerator-GitHub-Action](https://github.com/danielpalme/reportgenerator-github-action) from 5.3.7 to 5.3.9. - [Release notes](https://github.com/danielpalme/reportgenerator-github-action/releases) - [Commits](https://github.com/danielpalme/reportgenerator-github-action/compare/5.3.7...5.3.9) --- updated-dependencies: - dependency-name: danielpalme/ReportGenerator-GitHub-Action dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- .github/workflows/test-full.yml | 2 +- .github/workflows/test.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test-full.yml b/.github/workflows/test-full.yml index c946da38..f7d3d590 100644 --- a/.github/workflows/test-full.yml +++ b/.github/workflows/test-full.yml @@ -71,7 +71,7 @@ jobs: shell: pwsh - name: ReportGenerator - uses: danielpalme/ReportGenerator-GitHub-Action@5.3.7 + uses: danielpalme/ReportGenerator-GitHub-Action@5.3.9 with: reports: '*.xml' targetdir: 'coveragereport' diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index c4fb1334..a63de68e 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -77,7 +77,7 @@ jobs: shell: pwsh - name: ReportGenerator - uses: danielpalme/ReportGenerator-GitHub-Action@5.3.7 + uses: danielpalme/ReportGenerator-GitHub-Action@5.3.9 with: reports: 'coverage_butterlib_stable_debug.xml;coverage_butterlib_stable_release.xml;coverage_butterlib_impl_stable_debug.xml;coverage_butterlib_impl_stable_release.xml;coverage_butterlib_impl_beta_debug.xml;coverage_butterlib_impl_beta_release.xml;' targetdir: 'coveragereport' From 7dbbfe50d9a8784f6df7dc79d3559f02040dbe1d Mon Sep 17 00:00:00 2001 From: Vitalii Mikhailov Date: Mon, 23 Sep 2024 20:16:47 +0300 Subject: [PATCH 3/7] Updated Crash Reporter to v14 --- build/common.props | 8 ++++---- changelog.txt | 5 +++++ .../DelayedSubModule/DelayedSubModuleTest.cs | 14 +++++++------- .../DelayedSubModule/TestHelper.cs | 12 ++++++------ tests/Bannerlord.ButterLib.Tests/DelegateHelper.cs | 4 ++-- 5 files changed, 24 insertions(+), 19 deletions(-) diff --git a/build/common.props b/build/common.props index 58d92ec7..5b35fdee 100644 --- a/build/common.props +++ b/build/common.props @@ -5,7 +5,7 @@ 1.0.0 - 2.9.10 + 2.9.11 2.2.2 3.2.0.77 @@ -16,9 +16,9 @@ 2.0.0 1.1.0.104 - 3.0.0.138 - 5.0.222 - 13.0.0.81 + 3.0.0.142 + 5.0.226 + 14.0.0.84 diff --git a/changelog.txt b/changelog.txt index 200a5f47..17bdc78a 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,4 +1,9 @@ --------------------------------------------------------------------------------------------------- +Version: 2.9.11 +Game Versions: v1.0.x,v1.1.x,v1.2.x +* Updated Crash Reporter to v14 +* OS Type/Version and loaded Native Modules are now saved in the crash report +--------------------------------------------------------------------------------------------------- Version: 2.9.10 Game Versions: v1.0.x,v1.1.x,v1.2.x * Fixed double key press issue diff --git a/tests/Bannerlord.ButterLib.Tests/DelayedSubModule/DelayedSubModuleTest.cs b/tests/Bannerlord.ButterLib.Tests/DelayedSubModule/DelayedSubModuleTest.cs index ab50b04e..81dda834 100644 --- a/tests/Bannerlord.ButterLib.Tests/DelayedSubModule/DelayedSubModuleTest.cs +++ b/tests/Bannerlord.ButterLib.Tests/DelayedSubModule/DelayedSubModuleTest.cs @@ -15,7 +15,7 @@ namespace Bannerlord.ButterLib.Tests.DelayedSubModule; public class DelayedSubModuleTest { [MethodImpl(MethodImplOptions.NoInlining)] - private static bool MockedGetModuleInfo(Type type, ref ModuleInfoExtendedWithMetadata? __result) + private static bool MockedGetModuleInfo(Type type, ref ModuleInfoExtendedHelper? __result) { if (type == typeof(TestSubModuleCaller)) { @@ -44,9 +44,9 @@ public void Setup() public void SubscribeBeforeTargetLoad_Test() { [MethodImpl(MethodImplOptions.NoInlining)] - static bool MockedGetLoadedModules(ref IEnumerable __result) + static bool MockedGetLoadedModules(ref IEnumerable __result) { - __result = new List { TestHelper.ModuleInfoCaller, TestHelper.ModuleInfoTarget }; + __result = new List { TestHelper.ModuleInfoCaller, TestHelper.ModuleInfoTarget }; return false; } @@ -66,9 +66,9 @@ static bool MockedGetLoadedModules(ref IEnumerable __result) + static bool MockedGetLoadedModules(ref IEnumerable __result) { - __result = new List { TestHelper.ModuleInfoCaller, TestHelper.ModuleInfoTarget }; + __result = new List { TestHelper.ModuleInfoCaller, TestHelper.ModuleInfoTarget }; return false; } @@ -93,9 +93,9 @@ static bool MockedGetLoadedModules(ref IEnumerable __result) + static bool MockedGetLoadedModules(ref IEnumerable __result) { - __result = new List { TestHelper.ModuleInfoTarget, TestHelper.ModuleInfoCaller }; + __result = new List { TestHelper.ModuleInfoTarget, TestHelper.ModuleInfoCaller }; return false; } diff --git a/tests/Bannerlord.ButterLib.Tests/DelayedSubModule/TestHelper.cs b/tests/Bannerlord.ButterLib.Tests/DelayedSubModule/TestHelper.cs index 08ea0e57..3d2941f0 100644 --- a/tests/Bannerlord.ButterLib.Tests/DelayedSubModule/TestHelper.cs +++ b/tests/Bannerlord.ButterLib.Tests/DelayedSubModule/TestHelper.cs @@ -11,14 +11,14 @@ internal static class TestHelper { public static readonly Type? ModuleInfoType = AccessTools2.TypeByName("TaleWorlds.ModuleManager.ModuleInfo"); - private static ModuleInfoExtendedWithMetadata? _moduleInfoCaller; - public static ModuleInfoExtendedWithMetadata ModuleInfoCaller + private static ModuleInfoExtendedHelper? _moduleInfoCaller; + public static ModuleInfoExtendedHelper ModuleInfoCaller { get { if (_moduleInfoCaller is null) { - _moduleInfoCaller = new ModuleInfoExtendedWithMetadata(new ModuleInfoExtended(), false, ""); + _moduleInfoCaller = new ModuleInfoExtendedHelper(new ModuleInfoExtended(), false, ""); AccessTools2.Property("Bannerlord.ModuleManager.ModuleInfoExtended:Id")?.SetValue(_moduleInfoCaller, nameof(TestSubModuleCaller)); AccessTools2.Property("Bannerlord.ModuleManager.ModuleInfoExtended:Name")?.SetValue(_moduleInfoCaller, nameof(TestSubModuleCaller)); } @@ -27,14 +27,14 @@ public static ModuleInfoExtendedWithMetadata ModuleInfoCaller } } - private static ModuleInfoExtendedWithMetadata? _moduleInfoTarget; - public static ModuleInfoExtendedWithMetadata ModuleInfoTarget + private static ModuleInfoExtendedHelper? _moduleInfoTarget; + public static ModuleInfoExtendedHelper ModuleInfoTarget { get { if (_moduleInfoTarget is null) { - _moduleInfoTarget = new ModuleInfoExtendedWithMetadata(new ModuleInfoExtended(), false, ""); + _moduleInfoTarget = new ModuleInfoExtendedHelper(new ModuleInfoExtended(), false, ""); AccessTools2.Property("Bannerlord.ModuleManager.ModuleInfoExtended:Id")?.SetValue(_moduleInfoTarget, nameof(TestSubModuleTarget)); AccessTools2.Property("Bannerlord.ModuleManager.ModuleInfoExtended:Name")?.SetValue(_moduleInfoTarget, nameof(TestSubModuleTarget)); } diff --git a/tests/Bannerlord.ButterLib.Tests/DelegateHelper.cs b/tests/Bannerlord.ButterLib.Tests/DelegateHelper.cs index 7a6031f4..26c1a511 100644 --- a/tests/Bannerlord.ButterLib.Tests/DelegateHelper.cs +++ b/tests/Bannerlord.ButterLib.Tests/DelegateHelper.cs @@ -8,12 +8,12 @@ namespace Bannerlord.ButterLib.Tests; internal static class DelegateHelper { - public delegate bool MockedGetModuleInfoDelegate(Type type, ref ModuleInfoExtendedWithMetadata? __result); + public delegate bool MockedGetModuleInfoDelegate(Type type, ref ModuleInfoExtendedHelper? __result); public static MethodInfo GetMethodInfo(MockedGetModuleInfoDelegate @delegate) => @delegate.Method; public delegate bool MockedGetBasePathDelegate(ref string __result); public static MethodInfo GetMethodInfo(this MockedGetBasePathDelegate @delegate) => @delegate.Method; - public delegate bool MockedGetLoadedModulesDelegate(ref IEnumerable __result); + public delegate bool MockedGetLoadedModulesDelegate(ref IEnumerable __result); public static MethodInfo GetMethodInfo(MockedGetLoadedModulesDelegate @delegate) => @delegate.Method; } \ No newline at end of file From e6662baebce8a93ec13a56f155f98f84f3171403 Mon Sep 17 00:00:00 2001 From: Vitalii Mikhailov Date: Mon, 23 Sep 2024 20:24:42 +0300 Subject: [PATCH 4/7] Fix --- .github/workflows/test.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index c4fb1334..71d77d62 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -92,7 +92,8 @@ jobs: path: coveragereport - name: Upload ReportGenerator to CodeCov - uses: codecov/codecov-action@v4.5.0 + uses: codecov/codecov-action@v4 + continue-on-error: true with: token: ${{secrets.CODECOV_TOKEN}} file: coveragereport/Cobertura.xml From 0679f7ed37358643107709af2e6180000aea0770 Mon Sep 17 00:00:00 2001 From: Vitalii Mikhailov Date: Tue, 24 Sep 2024 16:50:01 +0300 Subject: [PATCH 5/7] Update changelog.txt --- changelog.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/changelog.txt b/changelog.txt index 17bdc78a..35275c23 100644 --- a/changelog.txt +++ b/changelog.txt @@ -3,6 +3,7 @@ Version: 2.9.11 Game Versions: v1.0.x,v1.1.x,v1.2.x * Updated Crash Reporter to v14 * OS Type/Version and loaded Native Modules are now saved in the crash report +* Fixed methods not being debuggable when Debugger is attached by Cephas369 --------------------------------------------------------------------------------------------------- Version: 2.9.10 Game Versions: v1.0.x,v1.1.x,v1.2.x From ede8ac92a48c6cab890f26846f63beae64624f3d Mon Sep 17 00:00:00 2001 From: Vitalii Mikhailov Date: Wed, 25 Sep 2024 13:12:10 +0300 Subject: [PATCH 6/7] ButterLib now properly reads settings and will not enable a SubSystem if disabled Otherwise we will always create Harmony patches for method, which is not reversible by disabling them --- changelog.txt | 2 +- .../DistanceMatrix/DistanceMatrixSubSystem.cs | 12 +- .../HotKeys/HotKeySubSystem.cs | 10 ++ .../MBSubModuleBaseExSubSystem.cs | 10 ++ .../SaveSystem/SaveSystemSubSystem.cs | 10 ++ .../SubModule.cs | 1 + .../ButterLibSubModule.cs | 12 +- .../CrashUploader/CrashUploaderSubSystem.cs | 11 +- .../DelayedSubModuleSubSystem.cs | 8 ++ .../ExceptionHandler/BEWPatch.cs | 3 + .../ExceptionHandlerSubSystem.cs | 37 ++++-- .../Options/ButterLibOptions.cs | 6 +- .../Options/JsonButterLibOptionsModel.cs | 62 --------- .../Options/SettingsProvider.cs | 119 ++++++++++++++++++ .../SubSystemSettingsPropertyDropdown.cs | 5 +- 15 files changed, 221 insertions(+), 87 deletions(-) delete mode 100644 src/Bannerlord.ButterLib/Options/JsonButterLibOptionsModel.cs create mode 100644 src/Bannerlord.ButterLib/Options/SettingsProvider.cs diff --git a/changelog.txt b/changelog.txt index 35275c23..1fc52d31 100644 --- a/changelog.txt +++ b/changelog.txt @@ -3,7 +3,7 @@ Version: 2.9.11 Game Versions: v1.0.x,v1.1.x,v1.2.x * Updated Crash Reporter to v14 * OS Type/Version and loaded Native Modules are now saved in the crash report -* Fixed methods not being debuggable when Debugger is attached by Cephas369 +* Fixed methods not being debuggable when Debugger is attached (Thanks Cephas369) --------------------------------------------------------------------------------------------------- Version: 2.9.10 Game Versions: v1.0.x,v1.1.x,v1.2.x diff --git a/src/Bannerlord.ButterLib.Implementation/DistanceMatrix/DistanceMatrixSubSystem.cs b/src/Bannerlord.ButterLib.Implementation/DistanceMatrix/DistanceMatrixSubSystem.cs index 8ddf23f7..36f89a3f 100644 --- a/src/Bannerlord.ButterLib.Implementation/DistanceMatrix/DistanceMatrixSubSystem.cs +++ b/src/Bannerlord.ButterLib.Implementation/DistanceMatrix/DistanceMatrixSubSystem.cs @@ -1,4 +1,5 @@ -using Bannerlord.ButterLib.SubSystems; +using Bannerlord.ButterLib.Options; +using Bannerlord.ButterLib.SubSystems; using Bannerlord.ButterLib.SubSystems.Settings; using System.Collections.Generic; @@ -18,6 +19,8 @@ internal class DistanceMatrixSubSystem : ISubSystem, ISubSystemSettings()); + DistanceMatrixSubSystem.Instance?.Enable(); HotKeySubSystem.Instance?.Enable(); MBSubModuleBaseExSubSystem.Instance?.Enable(); SaveSystemSubSystem.Instance?.Enable(); diff --git a/src/Bannerlord.ButterLib/ButterLibSubModule.cs b/src/Bannerlord.ButterLib/ButterLibSubModule.cs index f094d8a2..995f3ba8 100644 --- a/src/Bannerlord.ButterLib/ButterLibSubModule.cs +++ b/src/Bannerlord.ButterLib/ButterLibSubModule.cs @@ -4,7 +4,6 @@ using Bannerlord.ButterLib.DelayedSubModule; using Bannerlord.ButterLib.DynamicAPI; using Bannerlord.ButterLib.ExceptionHandler; -using Bannerlord.ButterLib.Extensions; using Bannerlord.ButterLib.ObjectSystem.Extensions; using Bannerlord.ButterLib.Options; using Bannerlord.ButterLib.SubModuleWrappers2; @@ -21,12 +20,9 @@ using TaleWorlds.CampaignSystem; using TaleWorlds.Core; -using TaleWorlds.Engine; using TaleWorlds.Localization; using TaleWorlds.MountAndBlade; -using Path = System.IO.Path; - namespace Bannerlord.ButterLib; /// @@ -66,7 +62,7 @@ public void OnServiceRegistration() Services.AddOptions(); Services.Configure(o => { - var defaultJsonOptions = new JsonButterLibOptionsModel(); + var defaultJsonOptions = SettingsProvider.GetSettings(); o.MinLogLevel = defaultJsonOptions.MinLogLevel; }); @@ -74,8 +70,8 @@ public void OnServiceRegistration() action?.Invoke(Services); this.AddDefaultSerilogLogger(); - this.AddSerilogLoggerProvider("butterlib.txt", new[] { "Bannerlord.ButterLib.*" }); - this.AddSerilogLoggerProvider("trace.txt", new[] { "System.Diagnostics.Logger.*" }); + this.AddSerilogLoggerProvider("butterlib.txt", ["Bannerlord.ButterLib.*"]); + this.AddSerilogLoggerProvider("trace.txt", ["System.Diagnostics.Logger.*"]); //this.AddSteamWriterLogger("harmony.txt", out var harmonyStreamWriter); //HarmonyLib.FileLog.LogWriter = harmonyStreamWriter; @@ -110,6 +106,8 @@ protected override void OnSubModuleLoad() if (!DelayedServiceCreation) InitializeServices(); + DelayedSubModuleSubSystem.Instance?.Enable(); + SubModuleWrappers2SubSystem.Instance?.Enable(); ExceptionHandlerSubSystem.Instance?.Enable(); CrashUploaderSubSystem.Instance?.Enable(); diff --git a/src/Bannerlord.ButterLib/CrashUploader/CrashUploaderSubSystem.cs b/src/Bannerlord.ButterLib/CrashUploader/CrashUploaderSubSystem.cs index 73cdb9cb..10f8d320 100644 --- a/src/Bannerlord.ButterLib/CrashUploader/CrashUploaderSubSystem.cs +++ b/src/Bannerlord.ButterLib/CrashUploader/CrashUploaderSubSystem.cs @@ -1,4 +1,5 @@ -using Bannerlord.ButterLib.SubSystems; +using Bannerlord.ButterLib.Options; +using Bannerlord.ButterLib.SubSystems; namespace Bannerlord.ButterLib.CrashUploader; @@ -13,6 +14,7 @@ internal sealed class CrashUploaderSubSystem : ISubSystem public bool CanBeDisabled => true; public bool CanBeSwitchedAtRuntime => true; + private bool _wasInitialized; public CrashUploaderSubSystem() { @@ -21,6 +23,13 @@ public CrashUploaderSubSystem() public void Enable() { + if (!_wasInitialized) + { + _wasInitialized = true; + var isEnabledViaSettings = SettingsProvider.PopulateSubSystemSettings(this) ?? true; + if (!isEnabledViaSettings) return; + } + if (IsEnabled) return; IsEnabled = true; } diff --git a/src/Bannerlord.ButterLib/DelayedSubModule/DelayedSubModuleSubSystem.cs b/src/Bannerlord.ButterLib/DelayedSubModule/DelayedSubModuleSubSystem.cs index d526e531..7cbb105d 100644 --- a/src/Bannerlord.ButterLib/DelayedSubModule/DelayedSubModuleSubSystem.cs +++ b/src/Bannerlord.ButterLib/DelayedSubModule/DelayedSubModuleSubSystem.cs @@ -4,12 +4,20 @@ namespace Bannerlord.ButterLib.DelayedSubModule; internal class DelayedSubModuleSubSystem : ISubSystem { + public static DelayedSubModuleSubSystem? Instance { get; private set; } + public string Id => "Delayed SubModule"; public string Name => "{=joCJ9xpDvM}Delayed SubModule"; public string Description => "{=Gznum6kuzv}Mod Developer feature! Provides helpers to run methods after SubModule events."; public bool IsEnabled => true; public bool CanBeDisabled => false; public bool CanBeSwitchedAtRuntime => false; + + public DelayedSubModuleSubSystem() + { + Instance = this; + } + public void Enable() { } public void Disable() { } } \ No newline at end of file diff --git a/src/Bannerlord.ButterLib/ExceptionHandler/BEWPatch.cs b/src/Bannerlord.ButterLib/ExceptionHandler/BEWPatch.cs index fd960880..a9a3097a 100644 --- a/src/Bannerlord.ButterLib/ExceptionHandler/BEWPatch.cs +++ b/src/Bannerlord.ButterLib/ExceptionHandler/BEWPatch.cs @@ -65,6 +65,9 @@ private static void Finalizer(Exception? __exception) { if (__exception is not null) { + if (ExceptionHandlerSubSystem.Instance?.DisableWhenDebuggerIsAttached == true && IsDebuggerAttached()) + return; + ExceptionReporter.Show(__exception); } } diff --git a/src/Bannerlord.ButterLib/ExceptionHandler/ExceptionHandlerSubSystem.cs b/src/Bannerlord.ButterLib/ExceptionHandler/ExceptionHandlerSubSystem.cs index 412c822f..3af620f8 100644 --- a/src/Bannerlord.ButterLib/ExceptionHandler/ExceptionHandlerSubSystem.cs +++ b/src/Bannerlord.ButterLib/ExceptionHandler/ExceptionHandlerSubSystem.cs @@ -1,4 +1,5 @@ using Bannerlord.BLSE; +using Bannerlord.ButterLib.Options; using Bannerlord.ButterLib.SubSystems; using Bannerlord.ButterLib.SubSystems.Settings; @@ -37,33 +38,38 @@ public bool DisableWhenDebuggerIsAttached get => _disableWhenDebuggerIsAttached; private set { - if (_disableWhenDebuggerIsAttached != value) - { - _disableWhenDebuggerIsAttached = value; + if (_disableWhenDebuggerIsAttached == value) return; + + _disableWhenDebuggerIsAttached = value; - if (BEWPatch.IsDebuggerAttached()) + if (BEWPatch.IsDebuggerAttached()) + { + if (_disableWhenDebuggerIsAttached) { - if (_disableWhenDebuggerIsAttached) - UnsubscribeToUnhandledException(); - else - SubscribeToUnhandledException(); + Disable(); } else { SubscribeToUnhandledException(); } } + else + { + SubscribeToUnhandledException(); + } } } + private bool _wasInitialized; + /// - public IReadOnlyCollection> Declarations { get; } = new SubSystemSettingsDeclaration[] - { + public IReadOnlyCollection> Declarations { get; } = + [ new SubSystemSettingsPropertyBool( "{=B7bfrDNzIk} Disable when Debugger is Attached", "{=r3ktQzFMRz} Stops the Exception Handler when a debugger is attached.", x => x.DisableWhenDebuggerIsAttached), - }; + ]; public ExceptionHandlerSubSystem() @@ -73,12 +79,19 @@ public ExceptionHandlerSubSystem() public void Enable() { + if (!_wasInitialized) + { + _wasInitialized = true; + var isEnabledViaSettings = SettingsProvider.PopulateSubSystemSettings(this) ?? true; + if (!isEnabledViaSettings) return; + } + if (IsEnabled) return; IsEnabled = true; if (!BEWPatch.IsDebuggerAttached()) SubscribeToUnhandledException(); - else if (Instance?.DisableWhenDebuggerIsAttached == true) + else if (_disableWhenDebuggerIsAttached) return; if (!_wasButrLoaderInterceptorCalled) diff --git a/src/Bannerlord.ButterLib/Options/ButterLibOptions.cs b/src/Bannerlord.ButterLib/Options/ButterLibOptions.cs index ca4a2d50..87ee755f 100644 --- a/src/Bannerlord.ButterLib/Options/ButterLibOptions.cs +++ b/src/Bannerlord.ButterLib/Options/ButterLibOptions.cs @@ -1,6 +1,8 @@ -namespace Bannerlord.ButterLib.Options; +using Microsoft.Extensions.Logging; + +namespace Bannerlord.ButterLib.Options; public sealed class ButterLibOptions { - public int MinLogLevel { get; set; } + public int MinLogLevel { get; set; } = (int) LogLevel.Information; } \ No newline at end of file diff --git a/src/Bannerlord.ButterLib/Options/JsonButterLibOptionsModel.cs b/src/Bannerlord.ButterLib/Options/JsonButterLibOptionsModel.cs deleted file mode 100644 index 0384065d..00000000 --- a/src/Bannerlord.ButterLib/Options/JsonButterLibOptionsModel.cs +++ /dev/null @@ -1,62 +0,0 @@ -using Microsoft.Extensions.Logging; - -using Newtonsoft.Json; - -using System; - -using TaleWorlds.Engine; -using TaleWorlds.Library; - -namespace Bannerlord.ButterLib.Options; - -[JsonObject(MemberSerialization.OptIn)] -internal sealed class JsonButterLibOptionsModel -{ - //private static readonly string Path = System.IO.Path.Combine(Utilities.GetConfigsPath(), "ModSettings/Global/ButterLib/ButterLib_v1.json"); - private static readonly PlatformDirectoryPath BasePath = EngineFilePaths.ConfigsPath + "/ModSettings/ButterLib"; - - [JsonProperty("MinLogLevel", DefaultValueHandling = DefaultValueHandling.Populate)] - public int MinLogLevel { get; private set; } = (int) LogLevel.Information; - - public JsonButterLibOptionsModel() - { - var filePath = new PlatformFilePath(BasePath, "Options.json"); - - if (FileHelper.FileExists(filePath)) - { - try - { - JsonConvert.PopulateObject(FileHelper.GetFileContentString(filePath), this); - } - catch (Exception e) when (e is JsonSerializationException) - { - FileHelper.SaveFileString(filePath, JsonConvert.SerializeObject(this)); - } - catch - { - return; - } - } - else - { - FileHelper.SaveFileString(filePath, JsonConvert.SerializeObject(this)); - } - } - - private static void TryCreate(PlatformFilePath filePath, JsonButterLibOptionsModel model) - { - try - { - } - catch { } - } - - private static void TryOverwrite(PlatformFilePath filePath, JsonButterLibOptionsModel model) - { - try - { - FileHelper.SaveFileString(filePath, JsonConvert.SerializeObject(model)); - } - catch { } - } -} \ No newline at end of file diff --git a/src/Bannerlord.ButterLib/Options/SettingsProvider.cs b/src/Bannerlord.ButterLib/Options/SettingsProvider.cs new file mode 100644 index 00000000..f322bbae --- /dev/null +++ b/src/Bannerlord.ButterLib/Options/SettingsProvider.cs @@ -0,0 +1,119 @@ +using Bannerlord.ButterLib.SubSystems; +using Bannerlord.ButterLib.SubSystems.Settings; + +using JetBrains.Annotations; + +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; + +using System; +using System.Linq.Expressions; +using System.Reflection; + +using TaleWorlds.Engine; +using TaleWorlds.Library; + +namespace Bannerlord.ButterLib.Options; + +internal class SettingsProvider +{ + private static PropertyInfo? GetPropertyInfo(Expression> expression) => + expression is LambdaExpression { Body: MemberExpression { Member: PropertyInfo propertyInfo } } ? propertyInfo : null; + + private static bool Read(TSubSystem subSystem, JsonReader reader) where TSubSystem : ISubSystem + { + var jo = JObject.Load(reader); + + var isEnabled = true; + var enabledId = $"{typeof(TSubSystem).Name} Enabled"; + if (jo.TryGetValue(enabledId, out var isEnabledValue)) + isEnabled = isEnabledValue.ToObject(); + + if (subSystem is not ISubSystemSettings settings) + return isEnabled; + + + foreach (var declaration in settings.Declarations) + { + var func = declaration switch + { + SubSystemSettingsPropertyBool sp when GetPropertyInfo(sp.Property) is { } pi => () => + { + var id = $"{typeof(TSubSystem).Name}_{pi.Name}"; + if (jo.TryGetValue(id, out var value)) + pi.SetValue(subSystem, value.ToObject(pi.PropertyType)); + } + , + SubSystemSettingsPropertyDropdown sp when GetPropertyInfo(sp.Property) is { } pi => () => + { + var id = $"{typeof(TSubSystem).Name}_{pi.Name}"; + if (jo.TryGetValue(id, out var value)) + sp.SelectedIndex = value.ToObject(); + } + , + SubSystemSettingsPropertyFloat sp when GetPropertyInfo(sp.Property) is { } pi => () => + { + var id = $"{typeof(TSubSystem).Name}_{pi.Name}"; + if (jo.TryGetValue(id, out var value)) + pi.SetValue(subSystem, value.ToObject(pi.PropertyType)); + } + , + SubSystemSettingsPropertyInt sp when GetPropertyInfo(sp.Property) is { } pi => () => + { + var id = $"{typeof(TSubSystem).Name}_{pi.Name}"; + if (jo.TryGetValue(id, out var value)) + pi.SetValue(subSystem, value.ToObject(pi.PropertyType)); + } + , + SubSystemSettingsPropertyText sp when GetPropertyInfo(sp.Property) is { } pi => () => + { + var id = $"{typeof(TSubSystem).Name}_{pi.Name}"; + if (jo.TryGetValue(id, out var value)) + pi.SetValue(subSystem, value.ToObject(pi.PropertyType)); + } + , + _ => (Action?) null, + }; + func?.Invoke(); + } + + return isEnabled; + } + + + private static readonly PlatformDirectoryPath BasePath = EngineFilePaths.ConfigsPath + "/ModSettings/ButterLib"; + private static readonly PlatformFilePath optionsFilePath = new(BasePath, "Options.json"); + public static bool? PopulateSubSystemSettings(TSubSystem subSystem) where TSubSystem : ISubSystem + { + if (!FileHelper.FileExists(optionsFilePath)) + return null; + + var json = FileHelper.GetFileContentString(optionsFilePath); + + var reader = new JsonTextReader(new System.IO.StringReader(json)); + + return Read(subSystem, reader); + } + + public static ButterLibOptions GetSettings() + { + if (FileHelper.FileExists(optionsFilePath)) + { + try + { + return JsonConvert.DeserializeObject(FileHelper.GetFileContentString(optionsFilePath)) ?? new(); + } + catch (Exception e) when (e is JsonSerializationException) + { + FileHelper.SaveFileString(optionsFilePath, JsonConvert.SerializeObject(new())); + } + catch { /* ignore */ } + } + else + { + FileHelper.SaveFileString(optionsFilePath, JsonConvert.SerializeObject(new())); + } + + return new(); + } +} \ No newline at end of file diff --git a/src/Bannerlord.ButterLib/SubSystems/Settings/SubSystemSettingsPropertyDropdown.cs b/src/Bannerlord.ButterLib/SubSystems/Settings/SubSystemSettingsPropertyDropdown.cs index 7ae3f84a..b30bcfe6 100644 --- a/src/Bannerlord.ButterLib/SubSystems/Settings/SubSystemSettingsPropertyDropdown.cs +++ b/src/Bannerlord.ButterLib/SubSystems/Settings/SubSystemSettingsPropertyDropdown.cs @@ -9,4 +9,7 @@ namespace Bannerlord.ButterLib.SubSystems.Settings; /// IList<> /// public record SubSystemSettingsPropertyDropdown(string Name, string Description, Expression>> Property, int SelectedIndex) : - SubSystemSettingsProperty>(Name, Description, Property) where TSubSystem : ISubSystem; \ No newline at end of file + SubSystemSettingsProperty>(Name, Description, Property) where TSubSystem : ISubSystem +{ + public int SelectedIndex { get; set; } = SelectedIndex; +} \ No newline at end of file From 6fc3ba8549f57ac7c3cf66d13b78f4ee918c29a7 Mon Sep 17 00:00:00 2001 From: Vitalii Mikhailov Date: Wed, 25 Sep 2024 22:38:01 +0300 Subject: [PATCH 7/7] Update test.yml --- .github/workflows/test.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 4505627b..f2f70613 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -38,7 +38,8 @@ jobs: runs-on: windows-latest steps: - name: Tests Setup - uses: butr/actions-tests-setup@v1 + #uses: butr/actions-tests-setup@v1 + uses: butr/actions-tests-setup@master with: github-token: ${{secrets.GITHUB_TOKEN}} steam-login: ${{secrets.STEAM_LOGIN}}