diff --git a/.github/workflows/test-full.yml b/.github/workflows/test-full.yml index 4a576d9a..9dbc7dce 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.1.22 + uses: danielpalme/ReportGenerator-GitHub-Action@5.1.23 with: reports: '*.xml' targetdir: 'coveragereport' diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 71dcfe18..866cbd41 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.1.22 + uses: danielpalme/ReportGenerator-GitHub-Action@5.1.23 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' diff --git a/build/common.props b/build/common.props index af1fb72c..59859f38 100644 --- a/build/common.props +++ b/build/common.props @@ -4,7 +4,7 @@ - 2.8.3 + 2.8.4 2.2.2 3.2.0.77 @@ -15,7 +15,7 @@ 2.0.0 1.1.0.102 - 3.0.0.136 + 3.0.0.137 5.0.209 diff --git a/changelog.txt b/changelog.txt index 958226c9..5d7122f0 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,4 +1,9 @@ --------------------------------------------------------------------------------------------------- +Version: 2.8.4 +Game Versions: v1.0.0,v1.0.1,v1.0.2,v1.0.3,v1.1.0,v1.1.1,v1.1.2,v1.1.3,v1.1.4,v1.1.5,v1.2.0 +* ButterLib is not able to disable v1.2.0 Watchdog, BLSE is required +* Added integration with BLSE's better exception intercepter +--------------------------------------------------------------------------------------------------- Version: 2.8.3 Game Versions: v1.0.0,v1.0.1,v1.0.2,v1.0.3,v1.1.0,v1.1.1,v1.1.2,v1.1.3,v1.1.4,v1.1.5,v1.2.0 * The UseVanillaCrashHandler setting wasn't set correctly diff --git a/src/Bannerlord.ButterLib.Implementation/DistanceMatrix/DistanceMatrixSubSystem.cs b/src/Bannerlord.ButterLib.Implementation/DistanceMatrix/DistanceMatrixSubSystem.cs index a6b7b823..ded711cc 100644 --- a/src/Bannerlord.ButterLib.Implementation/DistanceMatrix/DistanceMatrixSubSystem.cs +++ b/src/Bannerlord.ButterLib.Implementation/DistanceMatrix/DistanceMatrixSubSystem.cs @@ -9,7 +9,8 @@ internal class DistanceMatrixSubSystem : ISubSystem public static DistanceMatrixSubSystem? Instance { get; private set; } public string Id => "Distance Matrix"; - public string Description => "Mod Developer feature! Provides helpers to calculate distance between objects on map."; + public string Name => "{=Ox6uK8fZWs}Distance Matrix"; + public string Description => "{=WQ4r2n0mYj}Mod Developer feature! Provides helpers to calculate distance between objects on map."; public bool IsEnabled { get; private set; } = false; public bool CanBeDisabled => true; public bool CanBeSwitchedAtRuntime => false; diff --git a/src/Bannerlord.ButterLib.Implementation/HotKeys/HotKeySubSystem.cs b/src/Bannerlord.ButterLib.Implementation/HotKeys/HotKeySubSystem.cs index 841b42ec..2cd0cada 100644 --- a/src/Bannerlord.ButterLib.Implementation/HotKeys/HotKeySubSystem.cs +++ b/src/Bannerlord.ButterLib.Implementation/HotKeys/HotKeySubSystem.cs @@ -18,8 +18,9 @@ internal sealed class HotKeySubSystem : ISubSystem public static HotKeySubSystem? Instance { get; private set; } public string Id => "Hot Keys"; + public string Name => "{=jvV6QDc7AJ}Hot Keys"; public bool IsEnabled { get; private set; } - public string Description => "Mod Developer feature! Provides a better way for mods to create hotkeys"; + public string Description => "{=wNNYwgUeus}Mod Developer feature! Provides a better way for mods to create hotkeys"; public bool CanBeDisabled => true; public bool CanBeSwitchedAtRuntime => false; diff --git a/src/Bannerlord.ButterLib.Implementation/MBSubModuleBaseExtended/MBSubModuleBaseExSubSystem.cs b/src/Bannerlord.ButterLib.Implementation/MBSubModuleBaseExtended/MBSubModuleBaseExSubSystem.cs index 7047c4b6..748c78a1 100644 --- a/src/Bannerlord.ButterLib.Implementation/MBSubModuleBaseExtended/MBSubModuleBaseExSubSystem.cs +++ b/src/Bannerlord.ButterLib.Implementation/MBSubModuleBaseExtended/MBSubModuleBaseExSubSystem.cs @@ -15,7 +15,8 @@ internal class MBSubModuleBaseExSubSystem : ISubSystem { public static MBSubModuleBaseExSubSystem? Instance { get; private set; } public string Id => "MBSubModuleBase extended"; - public string Description => "Mod Developer feature! Introduces a MBSubModuleBase-derived abstract class, that provides new SubModule events."; + public string Name => "{=JGylAT3SrB}MBSubModuleBase Extended"; + public string Description => "{=XfveBQYVWH}Mod Developer feature! Introduces a MBSubModuleBase-derived abstract class, that provides new SubModule events."; public bool IsEnabled { get; private set; } public bool CanBeDisabled => true; public bool CanBeSwitchedAtRuntime => false; diff --git a/src/Bannerlord.ButterLib.Implementation/ObjectSystem/ObjectSystemSubSystem.cs b/src/Bannerlord.ButterLib.Implementation/ObjectSystem/ObjectSystemSubSystem.cs index 79e71d3a..45185174 100644 --- a/src/Bannerlord.ButterLib.Implementation/ObjectSystem/ObjectSystemSubSystem.cs +++ b/src/Bannerlord.ButterLib.Implementation/ObjectSystem/ObjectSystemSubSystem.cs @@ -10,7 +10,8 @@ internal class ObjectSystemSubSystem : ISubSystem public static ObjectSystemSubSystem? Instance { get; private set; } public string Id => "Object System"; - public string Description => "Mod Developer feature!"; + public string Name => "{=IA0mVgHJgo}Object System"; + public string Description => "{=mFZTv1nwOx}Mod Developer feature!"; public bool IsEnabled { get; private set; } public bool CanBeDisabled => true; public bool CanBeSwitchedAtRuntime => false; diff --git a/src/Bannerlord.ButterLib.Implementation/SaveSystem/SaveSystemSubSystem.cs b/src/Bannerlord.ButterLib.Implementation/SaveSystem/SaveSystemSubSystem.cs index 5eff2df2..ac24ca40 100644 --- a/src/Bannerlord.ButterLib.Implementation/SaveSystem/SaveSystemSubSystem.cs +++ b/src/Bannerlord.ButterLib.Implementation/SaveSystem/SaveSystemSubSystem.cs @@ -10,10 +10,11 @@ internal class SaveSystemSubSystem : ISubSystem public static SaveSystemSubSystem? Instance { get; private set; } public string Id => "Save System"; - public string Description => @"Extends and fixes the game's save system: -* Fixes possible collision with save names; -* Fixes save corruption & crashes when duplicate types are defined; -* Adds support for saving many more container types; + public string Name => "{=66A5N9278w}Save System"; + public string Description => @"{=9ybOxGpWb5}Extends and fixes the game's save system:{NL} +* Fixes possible collision with save names;{NL} +* Fixes save corruption & crashes when duplicate types are defined;{NL} +* Adds support for saving many more container types;{NL} This might alter the save file, disabling the feature might render the save file unloadable!"; public bool IsEnabled { get; private set; } public bool CanBeDisabled => true; diff --git a/src/Bannerlord.ButterLib.Implementation/_Module/ModuleData/Languages/EN/sta_strings.xml b/src/Bannerlord.ButterLib.Implementation/_Module/ModuleData/Languages/EN/sta_strings.xml index 701703f1..f2f7e691 100644 --- a/src/Bannerlord.ButterLib.Implementation/_Module/ModuleData/Languages/EN/sta_strings.xml +++ b/src/Bannerlord.ButterLib.Implementation/_Module/ModuleData/Languages/EN/sta_strings.xml @@ -23,5 +23,24 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Bannerlord.ButterLib/CrashUploader/CrashUploaderSubSystem.cs b/src/Bannerlord.ButterLib/CrashUploader/CrashUploaderSubSystem.cs index 26fec625..d942ad9c 100644 --- a/src/Bannerlord.ButterLib/CrashUploader/CrashUploaderSubSystem.cs +++ b/src/Bannerlord.ButterLib/CrashUploader/CrashUploaderSubSystem.cs @@ -7,7 +7,8 @@ internal sealed class CrashUploaderSubSystem : ISubSystem public static CrashUploaderSubSystem? Instance { get; private set; } public string Id => "CrashUploader"; - public string Description => "Uploads the crash reports to BUTR for an easy file hosting."; + public string Name => "{=UsLlrwMTjJ}Crash Uploader"; + public string Description => "{=hjeoN9NwZm}Uploads the crash reports to BUTR for an easy file hosting."; public bool IsEnabled { get; private set; } public bool CanBeDisabled => true; public bool CanBeSwitchedAtRuntime => true; diff --git a/src/Bannerlord.ButterLib/DelayedSubModule/DelayedSubModuleSubSystem.cs b/src/Bannerlord.ButterLib/DelayedSubModule/DelayedSubModuleSubSystem.cs index eb6d2b08..2acc88f6 100644 --- a/src/Bannerlord.ButterLib/DelayedSubModule/DelayedSubModuleSubSystem.cs +++ b/src/Bannerlord.ButterLib/DelayedSubModule/DelayedSubModuleSubSystem.cs @@ -5,7 +5,8 @@ namespace Bannerlord.ButterLib.DelayedSubModule internal class DelayedSubModuleSubSystem : ISubSystem { public string Id => "Delayed SubModule"; - public string Description => "Mod Developer feature! Provides helpers to run methods after SubModule events."; + 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; diff --git a/src/Bannerlord.ButterLib/ExceptionHandler/BEWPatch.cs b/src/Bannerlord.ButterLib/ExceptionHandler/BEWPatch.cs index 7f76cfba..ced6b8a7 100644 --- a/src/Bannerlord.ButterLib/ExceptionHandler/BEWPatch.cs +++ b/src/Bannerlord.ButterLib/ExceptionHandler/BEWPatch.cs @@ -1,17 +1,12 @@ -using Bannerlord.BLSE; -using Bannerlord.ButterLib.Common.Extensions; -using Bannerlord.ButterLib.ExceptionHandler.DebuggerDetection; +using Bannerlord.ButterLib.ExceptionHandler.DebuggerDetection; using HarmonyLib; using HarmonyLib.BUTR.Extensions; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Logging.Abstractions; - using System; using System.Collections.Generic; using System.Diagnostics; +using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -28,7 +23,6 @@ namespace Bannerlord.ButterLib.ExceptionHandler // TaleWorlds.MountAndBlade.MissionBehaviour:OnMissionTick -> Called by TaleWorlds.MountAndBlade.Mission:Tick // TaleWorlds.MountAndBlade.MBSubModuleBase:OnSubModuleLoad -> Replicated - [BLSELoaderInterceptor] internal sealed class BEWPatch { public static bool IsDebuggerAttached() @@ -37,9 +31,7 @@ public static bool IsDebuggerAttached() return true; if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { return ProcessDebug.CheckProcessDebugObjectHandle(); - } return false; } @@ -54,8 +46,6 @@ internal record ExceptionIdentifier(Type Type, string? StackTrace, string Messag private static readonly string[] BEW = { "org.calradia.admiralnelson.betterexceptionwindow" }; - //private static readonly Assembly[] AutoGeneratedAssemblies = AccessTools2.AllAssemblies().Where(x => x.GetName().Name.EndsWith(".AutoGeneratedAssemblies")).ToArray(); - private static readonly MethodInfo? ManagedApplicationTickMethod = AccessTools2.Method("TaleWorlds.DotNet.Managed:ApplicationTick"); private static readonly MethodInfo? ModuleOnApplicationTickMethod = AccessTools2.Method("TaleWorlds.MountAndBlade.Module:OnApplicationTick"); private static readonly MethodInfo? ScreenManagerTickMethod = AccessTools2.Method("TaleWorlds.ScreenSystem.ScreenManager:Tick"); @@ -63,13 +53,6 @@ internal record ExceptionIdentifier(Type Type, string? StackTrace, string Messag private static readonly MethodInfo? MissionTickMethod = AccessTools2.Method("TaleWorlds.MountAndBlade.Mission:Tick"); public static readonly MethodInfo? FinalizerMethod = AccessTools2.Method(typeof(BEWPatch), nameof(Finalizer)); - private static readonly AccessTools.FieldRef>? LoadedSubModuleTypes = - AccessTools2.FieldRefAccess>("_loadedSubmoduleTypes"); - - private static ILogger _log = default!; - - private static bool _wasButrLoaderInterceptorCalled = false; - private static void Finalizer(Exception? __exception) { if (ExceptionHandlerSubSystem.Instance?.DisableWhenDebuggerIsAttached == true && IsDebuggerAttached()) @@ -81,9 +64,6 @@ private static void Finalizer(Exception? __exception) internal static void Enable(Harmony harmony) { - _log = ButterLibSubModule.Instance?.GetServiceProvider()?.GetRequiredService>() - ?? NullLogger.Instance; - harmony.Patch(ManagedApplicationTickMethod, finalizer: new HarmonyMethod(FinalizerMethod, before: BEW)); harmony.Patch(ModuleOnApplicationTickMethod, finalizer: new HarmonyMethod(FinalizerMethod, before: BEW)); harmony.Patch(ScreenManagerTickMethod, finalizer: new HarmonyMethod(FinalizerMethod, before: BEW)); @@ -114,79 +94,32 @@ internal static void Enable(Harmony harmony) transpiler: AccessTools2.Method(typeof(BEWPatch), nameof(BlankTranspiler))); } - internal static void Disable(Harmony harmony) - { - harmony.Unpatch(ManagedApplicationTickMethod, FinalizerMethod); - harmony.Unpatch(ModuleOnApplicationTickMethod, FinalizerMethod); - harmony.Unpatch(ScreenManagerTickMethod, FinalizerMethod); - harmony.Unpatch(ManagedScriptHolderTickComponentsMethod, FinalizerMethod); - harmony.Unpatch(MissionTickMethod, FinalizerMethod); - } - - /* - internal static void EnableWithDebug(Harmony harmony) + internal static void EnableAutoGenCatch(Harmony harmony) { - _log = ButterLibSubModule.Instance?.GetServiceProvider()?.GetRequiredService>() - ?? NullLogger.Instance; - - harmony.Patch(ModuleOnApplicationTickMethod, finalizer: new HarmonyMethod(FinalizerMethod, before: BEW)); - harmony.Patch(MissionTickMethod, finalizer: new HarmonyMethod(FinalizerMethod, before: BEW)); - - var callbacksGeneratedTypes = AutoGeneratedAssemblies.SelectMany(x => x.GetTypes().Where(y => y.Name.EndsWith("CallbacksGenerated"))); + var callbacksGeneratedTypes = AccessTools2.AllAssemblies().SelectMany(x => x.GetTypes().Where(y => y.Name.EndsWith("CallbacksGenerated"))); var callbackGeneratedMethods = callbacksGeneratedTypes.SelectMany(AccessTools.GetDeclaredMethods); foreach (var method in callbackGeneratedMethods.Where(x => x.GetCustomAttributesData().Any(y => y.AttributeType.Name == "MonoPInvokeCallbackAttribute"))) harmony.Patch(method, finalizer: new HarmonyMethod(FinalizerMethod, before: BEW)); - - if (!_wasButrLoaderInterceptorCalled) - PatchSubModules(harmony); } - internal static void DisableWithDebug(Harmony harmony) + internal static void Disable(Harmony harmony) { + harmony.Unpatch(ManagedApplicationTickMethod, FinalizerMethod); harmony.Unpatch(ModuleOnApplicationTickMethod, FinalizerMethod); + harmony.Unpatch(ScreenManagerTickMethod, FinalizerMethod); + harmony.Unpatch(ManagedScriptHolderTickComponentsMethod, FinalizerMethod); harmony.Unpatch(MissionTickMethod, FinalizerMethod); + } - var callbacksGeneratedTypes = AutoGeneratedAssemblies.SelectMany(x => x.GetTypes().Where(y => y.Name.EndsWith("CallbacksGenerated"))); + internal static void DisableAutoGenCatch(Harmony harmony) + { + var callbacksGeneratedTypes = AccessTools2.AllAssemblies().SelectMany(x => x.GetTypes().Where(y => y.Name.EndsWith("CallbacksGenerated"))); var callbackGeneratedMethods = callbacksGeneratedTypes.SelectMany(AccessTools.GetDeclaredMethods); foreach (var method in callbackGeneratedMethods.Where(x => x.GetCustomAttributesData().Any(y => y.AttributeType.Name == "MonoPInvokeCallbackAttribute"))) harmony.Unpatch(method, FinalizerMethod); } - */ [MethodImpl(MethodImplOptions.NoInlining)] private static IEnumerable BlankTranspiler(IEnumerable instructions) => instructions; - - /// - /// We need to patch MBSubModuleBase.OnSubModuleLoad because they generally can't be catched. - /// The reason is, Harmony can't patch a method it's running in. - /// The exception handling (this one) is started within the - /// Module.Initialize() -> Module.LoadSubModules() -> Module.InitializeSubModules() -> MBSubModuleBase.OnSubModuleLoad() - /// We start the exception interception within this scope, so if anything is throwing while within Module.Initialize(), - /// we will lose that. It's easier to intercept every exception in MBSubModuleBase.OnSubModuleLoad() instead. - /// - private static bool PatchSubModules(Harmony harmony) - { - /* - if (LoadedSubModuleTypes is null) - return false; - - foreach (var (_, type) in LoadedSubModuleTypes(Module.CurrentModule)) - { - if (AccessTools2.Method(type, "OnSubModuleLoad") is not { } method || method.DeclaringType == typeof(MBSubModuleBase)) - continue; - - harmony.Patch(method, finalizer: new HarmonyMethod(FinalizerMethod, before: BEW)); - } - */ - return true; - } - - // BUTRLoader gives un the ability to intercept every exception call. - // We will use the earlier entrypoint instead - private static void OnInitializeSubModulesPrefix() - { - _wasButrLoaderInterceptorCalled = true; - PatchSubModules(new Harmony("Bannerlord.ButterLib.ExceptionHandler.BUTRLoadingInterceptor")); - } } } \ No newline at end of file diff --git a/src/Bannerlord.ButterLib/ExceptionHandler/DebuggerDetection/CloseHandleTrick.cs b/src/Bannerlord.ButterLib/ExceptionHandler/DebuggerDetection/CloseHandleTrick.cs deleted file mode 100644 index 5924daf6..00000000 --- a/src/Bannerlord.ButterLib/ExceptionHandler/DebuggerDetection/CloseHandleTrick.cs +++ /dev/null @@ -1,37 +0,0 @@ -/* -using System; -using System.Runtime.InteropServices; - -namespace Bannerlord.ButterLib.ExceptionHandler.DebuggerDetection -{ - /// - /// Starting with Windows XP, Windows systems have had a mechanism for kernel object handle tracing. - /// When the tracing mode is on, all operations with handlers are saved to the circular buffer, also, - /// when trying to use a nonexistent handler, for instance to close it using the CloseHandle function, - /// the EXCEPTION_INVALID_HANDLE exception will be generated. If a process is started not from the debugger, - /// the CloseHandle function will return FALSE. - /// It was originally published on https://www.apriorit.com/ - /// - internal static class CloseHandleTrick - { - [DllImport("kernel32.dll", SetLastError = true)] - private static extern bool CloseHandle(IntPtr hObject); - - public static bool Check() - { - try - { - if (IntPtr.Size == 8) - CloseHandle((IntPtr) 0xDEADBEEF); - else - CloseHandle((IntPtr) 0xDEADBEE); - return false; - } - catch - { - return true; - } - } - } -} -*/ \ No newline at end of file diff --git a/src/Bannerlord.ButterLib/ExceptionHandler/DebuggerDetection/PEBBeingDebugged.cs b/src/Bannerlord.ButterLib/ExceptionHandler/DebuggerDetection/PEBBeingDebugged.cs deleted file mode 100644 index ad16cc7c..00000000 --- a/src/Bannerlord.ButterLib/ExceptionHandler/DebuggerDetection/PEBBeingDebugged.cs +++ /dev/null @@ -1,45 +0,0 @@ -/* -using System; -using System.Diagnostics; -using System.Runtime.InteropServices; - -namespace Bannerlord.ButterLib.ExceptionHandler.DebuggerDetection -{ - internal static class PEBBeingDebugged - { - private delegate IntPtr PebAddress(); - - [DllImport("kernel32.dll")] - private static extern bool VirtualProtectEx(IntPtr hProcess, IntPtr lpAddress, UIntPtr dwSize, uint flNewProtect, out uint lpflOldProtect); - - public static unsafe bool CheckPeb() - { - byte[] assembledCode; - if (IntPtr.Size == 8) - assembledCode = new byte[] - { - 0x65, 0x48, 0x8B, 0x04, 0x25, 0x60, 0x00, // mov rax,QWORD PTR gs:0x60 - 0x00, 0x00, 0xC2, 0x00, 0x00 // ret 0x0 - }; - else - assembledCode = new byte[] - { - 0x64, 0xA1, 0x30, 0x00, 0x00, 0x00, // mov eax,fs:0x30 - 0xC2, 0x00, 0x00 // ret 0x0 - }; - - fixed (byte* ptr = assembledCode) - { - var memoryAddress = (IntPtr) ptr; - - if (!VirtualProtectEx(Process.GetCurrentProcess().Handle, memoryAddress, (UIntPtr) assembledCode.Length, 0x40, out _)) // EXECUTE_READWRITE - return false; - - var pebAddress = Marshal.GetDelegateForFunctionPointer(memoryAddress); - var isDebuggerPresent = Convert.ToBoolean(Marshal.ReadByte(pebAddress(), 2)); - return isDebuggerPresent; - } - } - } -} -*/ \ No newline at end of file diff --git a/src/Bannerlord.ButterLib/ExceptionHandler/DebuggerDetection/ProcessDebug.cs b/src/Bannerlord.ButterLib/ExceptionHandler/DebuggerDetection/ProcessDebug.cs index 4c262c8f..b284baed 100644 --- a/src/Bannerlord.ButterLib/ExceptionHandler/DebuggerDetection/ProcessDebug.cs +++ b/src/Bannerlord.ButterLib/ExceptionHandler/DebuggerDetection/ProcessDebug.cs @@ -7,7 +7,6 @@ namespace Bannerlord.ButterLib.ExceptionHandler.DebuggerDetection internal static class ProcessDebug { private const int PROCESS_DEBUG_OBJECT_HANDLE = 30; - private const int PROCESS_DEBUG_PORT = 7; [DllImport("ntdll.dll", SetLastError = true)] private static extern int NtQueryInformationProcess(IntPtr processHandle, int processInformationClass, @@ -31,26 +30,5 @@ public static bool CheckProcessDebugObjectHandle() ); return status == 0 && (IntPtr) 0 != flProcessDebugObject; } - - /* - /// - /// The CheckRemoteDebuggerPresent function is assigned the DebugPort value, - /// as the ProcessInformationClass parameter value (the second one) is 7. - /// It was originally published on https://www.apriorit.com/ - /// - /// - public static bool CheckProcessDebugPort() - { - var status = NtQueryInformationProcess - ( - Process.GetCurrentProcess().Handle, - PROCESS_DEBUG_PORT, - out var flProcessDebugPort, - IntPtr.Size, - IntPtr.Zero - ); - return status == 0 && (IntPtr) (-1) == flProcessDebugPort; - } - */ } } \ No newline at end of file diff --git a/src/Bannerlord.ButterLib/ExceptionHandler/DebuggerDetection/RaiseExceptionTrick.cs b/src/Bannerlord.ButterLib/ExceptionHandler/DebuggerDetection/RaiseExceptionTrick.cs deleted file mode 100644 index 0302a4e3..00000000 --- a/src/Bannerlord.ButterLib/ExceptionHandler/DebuggerDetection/RaiseExceptionTrick.cs +++ /dev/null @@ -1,40 +0,0 @@ -/* -using System; -using System.Runtime.InteropServices; - -namespace Bannerlord.ButterLib.ExceptionHandler.DebuggerDetection -{ - /// - /// Since Windows 10, the implementation of the OutputDebugString function has changed to a - /// simple RaiseException call with the specific parameters. So, debug output exception must be now handled by the debugger. - /// There are two exception types: DBG_PRINTEXCEPTION_C (0x40010006) and DBG_PRINTEXCEPTION_W(0x4001000A), - /// which can be used to detect the debugger presence. - /// It was originally published on https://www.apriorit.com/ - /// - internal static class RaiseExceptionTrick - { - private const uint DBG_PRINTEXCEPTION_C = 0x40010006; - private const uint DBG_PRINTEXCEPTION_W = 0x4001000A; - - [DllImport("kernel32.dll")] - private static extern bool RaiseException(uint dwExceptionCode, uint dwExceptionFlags, uint nNumberOfArguments, IntPtr lpArguments); - - [DllImport("kernel32.dll")] - private static extern uint GetLastError(); - - public static bool Check() - { - try - { - RaiseException(DBG_PRINTEXCEPTION_C, 0, 0, IntPtr.Zero); - } - catch - { - return GetLastError() == DBG_PRINTEXCEPTION_C; - } - - return true; - } - } -} -*/ \ No newline at end of file diff --git a/src/Bannerlord.ButterLib/ExceptionHandler/ExceptionHandlerSubSystem.cs b/src/Bannerlord.ButterLib/ExceptionHandler/ExceptionHandlerSubSystem.cs index dfb943c2..5fe6ee20 100644 --- a/src/Bannerlord.ButterLib/ExceptionHandler/ExceptionHandlerSubSystem.cs +++ b/src/Bannerlord.ButterLib/ExceptionHandler/ExceptionHandlerSubSystem.cs @@ -1,4 +1,5 @@ -using Bannerlord.ButterLib.SubSystems; +using Bannerlord.BLSE; +using Bannerlord.ButterLib.SubSystems; using Bannerlord.ButterLib.SubSystems.Settings; using HarmonyLib; @@ -6,9 +7,12 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Runtime.ExceptionServices; +using System.Security; namespace Bannerlord.ButterLib.ExceptionHandler { + [BLSEInterceptor] internal sealed class ExceptionHandlerSubSystem : ISubSystem, ISubSystemSettings { public static ExceptionHandlerSubSystem? Instance { get; private set; } @@ -16,7 +20,8 @@ internal sealed class ExceptionHandlerSubSystem : ISubSystem, ISubSystemSettings internal readonly Harmony Harmony = new("Bannerlord.ButterLib.ExceptionHandler.BEW"); public string Id => "ExceptionHandler"; - public string Description => "Captures game crashes and creates reports out of them."; + public string Name => "{=ZypQtNNcVN}Exception Handler"; + public string Description => "{=UreeIeLQYS}Captures game crashes and creates reports out of them."; public bool IsEnabled { get; private set; } public bool CanBeDisabled => true; public bool CanBeSwitchedAtRuntime => true; @@ -56,50 +61,20 @@ private set { _catchAutoGenExceptions = value; - /* if (_catchAutoGenExceptions) { if (IsEnabled) { - BEWPatch.Disable(Harmony); - BEWPatch.EnableWithDebug(Harmony); + //BEWPatch.Disable(Harmony); + BEWPatch.EnableAutoGenCatch(Harmony); } } else { if (IsEnabled) { - BEWPatch.DisableWithDebug(Harmony); - BEWPatch.Enable(Harmony); - } - } - */ - } - } - } - - private bool _useVanillaCrashHandler = false; - public bool UseVanillaCrashHandler - { - get => _useVanillaCrashHandler; - private set - { - if (_useVanillaCrashHandler != value) - { - _useVanillaCrashHandler = value; - - if (_useVanillaCrashHandler) - { - if (IsEnabled) - { - WatchdogHandler.EnableTWWatchdog(); - } - } - else - { - if (IsEnabled) - { - WatchdogHandler.DisableTWWatchdog(); + //BEWPatch.Enable(Harmony); + BEWPatch.DisableAutoGenCatch(Harmony); } } } @@ -117,10 +92,6 @@ private set "{=jorWb502pD} Catch AutoGenerated Code Exceptions (Lower Performance) (DISABLED)", "{=ji1brrsEZz} Catch every Native->Managed call. Should catch every exception not catched the standard way. Might decrease the overall performance a bit.", x => x.CatchAutoGenExceptions), - new SubSystemSettingsPropertyBool( - "{=ZD69h3IpF5} Use Vanilla Crash Handler", - "{=o0DgSNv5V1} Disables ButterLib's and BEW's Crash Handlers with the new Watchdog Crash Handler. Do not enable if not sure.", - x => x.UseVanillaCrashHandler), }; @@ -135,10 +106,12 @@ public void Enable() if (!BEWPatch.IsDebuggerAttached()) SubscribeToUnhandledException(); - - BEWPatch.Enable(Harmony); - - WatchdogHandler.DisableTWWatchdog(); + + if (!_wasButrLoaderInterceptorCalled) + { + BEWPatch.Enable(Harmony); + BEWPatch.EnableAutoGenCatch(Harmony); + } } public void Disable() @@ -151,14 +124,14 @@ public void Disable() { BEWPatch.Disable(Harmony); } - - WatchdogHandler.EnableTWWatchdog(); } private static bool _isSubscribedToUnhandledException; + private static bool _wasButrLoaderInterceptorCalled; + private static void SubscribeToUnhandledException() { - if (!_isSubscribedToUnhandledException) + if (!_isSubscribedToUnhandledException && !_wasButrLoaderInterceptorCalled) { _isSubscribedToUnhandledException = true; AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException; @@ -166,13 +139,14 @@ private static void SubscribeToUnhandledException() } private static void UnsubscribeToUnhandledException() { - if (_isSubscribedToUnhandledException) + if (_isSubscribedToUnhandledException && !_wasButrLoaderInterceptorCalled) { _isSubscribedToUnhandledException = false; AppDomain.CurrentDomain.UnhandledException -= CurrentDomain_UnhandledException; } } + [HandleProcessCorruptedStateExceptions, SecurityCritical] private static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e) { if (e.ExceptionObject is Exception exception) @@ -180,5 +154,11 @@ private static void CurrentDomain_UnhandledException(object sender, UnhandledExc ExceptionReporter.Show(exception); } } + + // BLSE Duck typed method + private static void OnInitializeSubModulesPrefix() + { + _wasButrLoaderInterceptorCalled = true; + } } } \ No newline at end of file diff --git a/src/Bannerlord.ButterLib/ExceptionHandler/ExceptionReporter.cs b/src/Bannerlord.ButterLib/ExceptionHandler/ExceptionReporter.cs index 242cc614..a1fc64be 100644 --- a/src/Bannerlord.ButterLib/ExceptionHandler/ExceptionReporter.cs +++ b/src/Bannerlord.ButterLib/ExceptionHandler/ExceptionReporter.cs @@ -1,10 +1,15 @@ -using System; +using Bannerlord.BLSE; + +using System; using System.Diagnostics; namespace Bannerlord.ButterLib.ExceptionHandler { + [BLSEExceptionHandler] public static class ExceptionReporter { + private static void OnException(Exception exception) => Show(exception); + public static void Show(Exception exception) { if (BEWPatch.SuppressedExceptions.Contains(BEWPatch.ExceptionIdentifier.FromException(exception))) diff --git a/src/Bannerlord.ButterLib/ExceptionHandler/HtmlBuilder.cs b/src/Bannerlord.ButterLib/ExceptionHandler/HtmlBuilder.cs index 95432dc5..1c077099 100644 --- a/src/Bannerlord.ButterLib/ExceptionHandler/HtmlBuilder.cs +++ b/src/Bannerlord.ButterLib/ExceptionHandler/HtmlBuilder.cs @@ -747,7 +747,7 @@ private static string GetLogFilesListHtml(CrashReport crashReport) var sb = new StringBuilder(); sb.AppendLine("
    "); - foreach (var logSource in ButterLibSubModule.Instance?.GetServiceProvider().GetRequiredService>() ?? Enumerable.Empty()) + foreach (var logSource in ButterLibSubModule.Instance?.GetServiceProvider()?.GetRequiredService>() ?? Enumerable.Empty()) { sb.Append("
  • ").Append("").Append(logSource.Name).Append("
    ").Append("
      "); diff --git a/src/Bannerlord.ButterLib/ExceptionHandler/WatchdogHandler.cs b/src/Bannerlord.ButterLib/ExceptionHandler/WatchdogHandler.cs deleted file mode 100644 index 6e696d44..00000000 --- a/src/Bannerlord.ButterLib/ExceptionHandler/WatchdogHandler.cs +++ /dev/null @@ -1,76 +0,0 @@ -using System; -using System.IO; -using System.Runtime.InteropServices; - -namespace Bannerlord.ButterLib.ExceptionHandler -{ - internal static unsafe class WatchdogHandler - { - [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)] - private static extern byte* LoadLibrary(string libname); - - [DllImport("kernel32.dll", SetLastError = true)] - private static extern bool VirtualProtect(byte* address, nint dwSize, int newProtect, out int oldProtect); - - private static readonly int PAGE_EXECUTE_READWRITE = 0x40; - - private static readonly string WatchdogLibraryName = "TaleWorlds.Native.dll"; - private static readonly byte[] WatchdogOriginal = "Watchdog.exe"u8.ToArray(); - private static readonly byte[] WatchdogReplacement = "Wetchdog.exe"u8.ToArray(); - - // Disable Watchdog by renaming it, thus performing a soft delete in it's eyes - public static void DisableTWWatchdog() - { - var watchdogLibraryFile = new FileInfo(WatchdogLibraryName); - if (!watchdogLibraryFile.Exists) return; - - var libraryPtr = LoadLibrary(WatchdogLibraryName); - // Don't like the fact that I can't get the concrete memory size - var size = (int) watchdogLibraryFile.Length; - - var librarySpan = new ReadOnlySpan(libraryPtr, size); - - var searchSpan = librarySpan; - var searchSpanOffset = 0; - while (searchSpan.IndexOf(WatchdogOriginal) is var idx and not -1) - { - var watchdogLocationPtr = libraryPtr + searchSpanOffset + idx; - var watchdogLocationSpan = new Span(watchdogLocationPtr, WatchdogOriginal.Length); - - VirtualProtect(watchdogLocationPtr, watchdogLocationSpan.Length, PAGE_EXECUTE_READWRITE, out var old); - WatchdogReplacement.CopyTo(watchdogLocationSpan); - VirtualProtect(watchdogLocationPtr, watchdogLocationSpan.Length, old, out _); - - searchSpanOffset = idx; - searchSpan = searchSpan.Slice(searchSpanOffset); - } - } - - public static void EnableTWWatchdog() - { - var watchdogLibraryFile = new FileInfo(WatchdogLibraryName); - if (!watchdogLibraryFile.Exists) return; - - var libraryPtr = LoadLibrary(WatchdogLibraryName); - // Don't like the fact that I can't get the concrete memory size - var size = (int) watchdogLibraryFile.Length; - - var librarySpan = new ReadOnlySpan(libraryPtr, size); - - var searchSpan = librarySpan; - var searchSpanOffset = 0; - while (searchSpan.IndexOf(WatchdogReplacement) is var idx and not -1) - { - var watchdogLocationPtr = libraryPtr + searchSpanOffset + idx; - var watchdogLocationSpan = new Span(watchdogLocationPtr, WatchdogOriginal.Length); - - VirtualProtect(watchdogLocationPtr, watchdogLocationSpan.Length, PAGE_EXECUTE_READWRITE, out var old); - WatchdogOriginal.CopyTo(watchdogLocationSpan); - VirtualProtect(watchdogLocationPtr, watchdogLocationSpan.Length, old, out _); - - searchSpanOffset = idx; - searchSpan = searchSpan.Slice(searchSpanOffset); - } - } - } -} \ No newline at end of file diff --git a/src/Bannerlord.ButterLib/Helpers/BLSEExceptionHandlerAttribute.cs b/src/Bannerlord.ButterLib/Helpers/BLSEExceptionHandlerAttribute.cs new file mode 100644 index 00000000..16047210 --- /dev/null +++ b/src/Bannerlord.ButterLib/Helpers/BLSEExceptionHandlerAttribute.cs @@ -0,0 +1,7 @@ +using System; + +namespace Bannerlord.BLSE +{ + [AttributeUsage(AttributeTargets.Class)] + public sealed class BLSEExceptionHandlerAttribute : Attribute { } +} \ No newline at end of file diff --git a/src/Bannerlord.ButterLib/Helpers/BLSELoaderInterceptorAttribute.cs b/src/Bannerlord.ButterLib/Helpers/BLSEInterceptorAttribute.cs similarity index 64% rename from src/Bannerlord.ButterLib/Helpers/BLSELoaderInterceptorAttribute.cs rename to src/Bannerlord.ButterLib/Helpers/BLSEInterceptorAttribute.cs index 0aec301b..67416b08 100644 --- a/src/Bannerlord.ButterLib/Helpers/BLSELoaderInterceptorAttribute.cs +++ b/src/Bannerlord.ButterLib/Helpers/BLSEInterceptorAttribute.cs @@ -4,5 +4,5 @@ namespace Bannerlord.BLSE { [AttributeUsage(AttributeTargets.Class)] - internal sealed class BLSELoaderInterceptorAttribute : Attribute { } + internal sealed class BLSEInterceptorAttribute : Attribute { } } \ No newline at end of file diff --git a/src/Bannerlord.ButterLib/SubModuleWrappers2/SubModuleWrappers2SubSystem.cs b/src/Bannerlord.ButterLib/SubModuleWrappers2/SubModuleWrappers2SubSystem.cs index 8dcf3199..8de2cdaa 100644 --- a/src/Bannerlord.ButterLib/SubModuleWrappers2/SubModuleWrappers2SubSystem.cs +++ b/src/Bannerlord.ButterLib/SubModuleWrappers2/SubModuleWrappers2SubSystem.cs @@ -12,7 +12,8 @@ internal sealed class SubModuleWrappers2SubSystem : ISubSystem private readonly Harmony Harmony = new("Bannerlord.ButterLib.SubModuleWrappers2"); public string Id => "SubModuleWrappers2"; - public string Description => "Mod Developer feature! A wrapper for MBSubModuleBase based on Harmony patches."; + public string Name => "{=NkAAB8EEu2}SubModule Wrappers"; + public string Description => "{=izmKJPjkjN}Mod Developer feature! A wrapper for MBSubModuleBase based on Harmony patches."; public bool IsEnabled => true; public bool CanBeDisabled => false; public bool CanBeSwitchedAtRuntime => false; diff --git a/src/Bannerlord.ButterLib/SubSystems/ISubSystem.cs b/src/Bannerlord.ButterLib/SubSystems/ISubSystem.cs index f9f37df7..62cbf87f 100644 --- a/src/Bannerlord.ButterLib/SubSystems/ISubSystem.cs +++ b/src/Bannerlord.ButterLib/SubSystems/ISubSystem.cs @@ -3,6 +3,7 @@ public interface ISubSystem { string Id { get; } + string Name { get; } string Description { get; } bool IsEnabled { get; } bool CanBeDisabled { get; }