From 61c8c58c2967f0e2b7baab63e9387a59de29a988 Mon Sep 17 00:00:00 2001
From: Vitalii Mikhailov
Date: Mon, 26 Jun 2023 10:28:42 +0300
Subject: [PATCH 01/12] Update README.md
---
README.md | 16 ++++++++++++++++
1 file changed, 16 insertions(+)
diff --git a/README.md b/README.md
index 57f7d9cf..88460a58 100644
--- a/README.md
+++ b/README.md
@@ -50,6 +50,22 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Extension library for Mount & Blade II: Bannerlord.
From 8f60e539bc75d8a447d2e2a656ac7a7e8e43f20f Mon Sep 17 00:00:00 2001
From: Vitalii Mikhailov
Date: Wed, 28 Jun 2023 12:39:56 +0300
Subject: [PATCH 02/12] Some formatting and nullable fixes
---
.../MBSubModuleBaseExSubSystem.cs | 2 +-
.../ObjectSystem/MBObjectExtensionDataStore.cs | 4 ++--
.../Patches/CampaignBehaviorManagerPatch.cs | 4 ++--
.../SaveSystem/Patches/BehaviourNamePatch.cs | 2 +-
.../SaveSystem/Patches/DefinitionContextPatch.cs | 4 ++--
.../SaveSystem/Patches/TypeExtensionsPatch.cs | 2 +-
.../CrashUploader/BUTRCrashUploader.cs | 2 ++
.../CrashUploader/CrashUploaderResult.cs | 1 +
.../CrashUploader/CrashUploaderStatus.cs | 1 +
.../DynamicAPI/DynamicApiProvider.cs | 8 ++++----
.../ExceptionHandler/BEWPatch.cs | 2 +-
.../ExceptionHandler/CrashReport.cs | 14 +++++++-------
.../DebuggerDetection/ProcessDebug.cs | 2 +-
.../WinForms/HtmlCrashReportForm.cs | 13 ++++++++-----
.../SaveSystem/DictionaryToArrayConverter.cs | 6 +++---
.../SaveSystem/Extensions/IDataStoreExtensions.cs | 4 ++--
.../SaveSystem/MBGUIDConverter.cs | 2 +-
.../SaveSystem/MBObjectBaseConverter.cs | 2 +-
.../Settings/SubSystemSettingsProperty.cs | 4 +++-
.../Settings/SubSystemSettingsPropertyDropdown.cs | 2 +-
20 files changed, 45 insertions(+), 36 deletions(-)
diff --git a/src/Bannerlord.ButterLib.Implementation/MBSubModuleBaseExtended/MBSubModuleBaseExSubSystem.cs b/src/Bannerlord.ButterLib.Implementation/MBSubModuleBaseExtended/MBSubModuleBaseExSubSystem.cs
index ecc2bc24..7047c4b6 100644
--- a/src/Bannerlord.ButterLib.Implementation/MBSubModuleBaseExtended/MBSubModuleBaseExSubSystem.cs
+++ b/src/Bannerlord.ButterLib.Implementation/MBSubModuleBaseExtended/MBSubModuleBaseExSubSystem.cs
@@ -45,7 +45,7 @@ public void Disable()
// Think about DelayedSubModuleManager.Unregister
}
- internal static void LogNoHooksIssue(ILogger logger, int originalCallIndex, int finallyIndex, List codes, MethodBase currentMethod)
+ internal static void LogNoHooksIssue(ILogger logger, int originalCallIndex, int finallyIndex, List codes, MethodBase? currentMethod)
{
var issueInfo = new StringBuilder("Indexes: ");
issueInfo.Append($"\n\toriginalCallIndex = {originalCallIndex}.\n\tfinallyIndex={finallyIndex}.");
diff --git a/src/Bannerlord.ButterLib.Implementation/ObjectSystem/MBObjectExtensionDataStore.cs b/src/Bannerlord.ButterLib.Implementation/ObjectSystem/MBObjectExtensionDataStore.cs
index 30b0b11c..7aeafafb 100755
--- a/src/Bannerlord.ButterLib.Implementation/ObjectSystem/MBObjectExtensionDataStore.cs
+++ b/src/Bannerlord.ButterLib.Implementation/ObjectSystem/MBObjectExtensionDataStore.cs
@@ -107,13 +107,13 @@ private sealed class DataKey : IEquatable
internal readonly MBGUID ObjectId;
[SaveableField(1)]
- internal readonly string Key;
+ internal readonly string? Key;
private DataKey(MBGUID objectId, string key) => (ObjectId, Key) = (objectId, key);
internal static DataKey Make(MBObjectBase obj, string key) => new(obj.Id, key);
- public bool Equals(DataKey other) => ObjectId == other.ObjectId && !(Key is null || other.Key is null) && Key.Equals(other.Key);
+ public bool Equals(DataKey? other) => ObjectId == other?.ObjectId && !(Key is null || other.Key is null) && Key.Equals(other.Key);
public override bool Equals(object? obj) => obj is DataKey k && Equals(k);
diff --git a/src/Bannerlord.ButterLib.Implementation/ObjectSystem/Patches/CampaignBehaviorManagerPatch.cs b/src/Bannerlord.ButterLib.Implementation/ObjectSystem/Patches/CampaignBehaviorManagerPatch.cs
index 05077fb0..f38c9cc7 100755
--- a/src/Bannerlord.ButterLib.Implementation/ObjectSystem/Patches/CampaignBehaviorManagerPatch.cs
+++ b/src/Bannerlord.ButterLib.Implementation/ObjectSystem/Patches/CampaignBehaviorManagerPatch.cs
@@ -78,9 +78,9 @@ internal static void Disable(Harmony harmony) { }
private static readonly Type? CampaignBehaviorDataStoreT =
typeof(Campaign).Assembly.GetType("TaleWorlds.CampaignSystem.CampaignBehaviorDataStore");
- private static readonly MethodInfo? LoadBehaviorDataMI = AccessTools2.Method(CampaignBehaviorDataStoreT, "LoadBehaviorData");
+ private static readonly MethodInfo? LoadBehaviorDataMI = AccessTools2.Method(CampaignBehaviorDataStoreT!, "LoadBehaviorData");
- private static readonly MethodInfo? SaveBehaviorDataMI = AccessTools2.Method(CampaignBehaviorDataStoreT, "SaveBehaviorData");
+ private static readonly MethodInfo? SaveBehaviorDataMI = AccessTools2.Method(CampaignBehaviorDataStoreT!, "SaveBehaviorData");
// Patch implementation:
diff --git a/src/Bannerlord.ButterLib.Implementation/SaveSystem/Patches/BehaviourNamePatch.cs b/src/Bannerlord.ButterLib.Implementation/SaveSystem/Patches/BehaviourNamePatch.cs
index 7fe75ae9..1e0e6b4c 100644
--- a/src/Bannerlord.ButterLib.Implementation/SaveSystem/Patches/BehaviourNamePatch.cs
+++ b/src/Bannerlord.ButterLib.Implementation/SaveSystem/Patches/BehaviourNamePatch.cs
@@ -29,7 +29,7 @@ internal static bool Disable(Harmony harmony)
return true;
}
- private static void CampaignBehaviorBaseCtorPostfix(CampaignBehaviorBase __instance, ref string ___StringId)
+ private static void CampaignBehaviorBaseCtorPostfix(CampaignBehaviorBase __instance, ref string? ___StringId)
{
var module = ModuleInfoHelper.GetModuleByType(__instance.GetType());
if (module is null) // A non-module dll
diff --git a/src/Bannerlord.ButterLib.Implementation/SaveSystem/Patches/DefinitionContextPatch.cs b/src/Bannerlord.ButterLib.Implementation/SaveSystem/Patches/DefinitionContextPatch.cs
index c386b9c5..1c5c849d 100644
--- a/src/Bannerlord.ButterLib.Implementation/SaveSystem/Patches/DefinitionContextPatch.cs
+++ b/src/Bannerlord.ButterLib.Implementation/SaveSystem/Patches/DefinitionContextPatch.cs
@@ -144,7 +144,7 @@ private static bool NotNull(T obj, string name, string? errPrefix = null) whe
if (obj is null)
{
var prefix = errPrefix ?? string.Empty;
- _log.LogError($"{prefix}{name} is null!");
+ _log.LogError("{Prefix}{Name} is null!", prefix, name);
return false;
}
@@ -168,7 +168,7 @@ protected Patch(string patchMethodName, MethodInfo? targetMethod)
internal virtual bool IsReady => ThisNotNull(PatchMethod, nameof(PatchMethod)) & ThisNotNull(TargetMethod, nameof(TargetMethod));
- private MethodInfo? ResolvePatchMethod() => AccessTools2.Method(GetType().DeclaringType, PatchMethodName);
+ private MethodInfo? ResolvePatchMethod() => AccessTools2.Method(GetType().DeclaringType!, PatchMethodName);
protected bool ThisNotNull(object? obj, string objName) => NotNull(obj, objName, $"Patch {PatchMethodName}: ");
}
diff --git a/src/Bannerlord.ButterLib.Implementation/SaveSystem/Patches/TypeExtensionsPatch.cs b/src/Bannerlord.ButterLib.Implementation/SaveSystem/Patches/TypeExtensionsPatch.cs
index 3db6fff7..b8705114 100644
--- a/src/Bannerlord.ButterLib.Implementation/SaveSystem/Patches/TypeExtensionsPatch.cs
+++ b/src/Bannerlord.ButterLib.Implementation/SaveSystem/Patches/TypeExtensionsPatch.cs
@@ -52,7 +52,7 @@ internal static bool Disable(Harmony harmony)
private static readonly Type? TargetType = typeof(MetaData).Assembly.GetType("TaleWorlds.SaveSystem.TypeExtensions");
private static readonly Type[] TargetMethodParams = { typeof(Type), typeof(ContainerType).MakeByRefType() };
- private static readonly MethodInfo? TargetMethod = AccessTools2.Method(TargetType, "IsContainer", TargetMethodParams);
+ private static readonly MethodInfo? TargetMethod = AccessTools2.Method(TargetType!, "IsContainer", TargetMethodParams);
private static readonly MethodInfo? PatchMethod = AccessTools2.Method("Bannerlord.ButterLib.Implementation.SaveSystem.Patches.TypeExtensionsPatch:IsContainerPrefix");
// ReSharper disable once RedundantAssignment
diff --git a/src/Bannerlord.ButterLib/CrashUploader/BUTRCrashUploader.cs b/src/Bannerlord.ButterLib/CrashUploader/BUTRCrashUploader.cs
index 56ed8619..fa931f72 100644
--- a/src/Bannerlord.ButterLib/CrashUploader/BUTRCrashUploader.cs
+++ b/src/Bannerlord.ButterLib/CrashUploader/BUTRCrashUploader.cs
@@ -47,6 +47,8 @@ public async Task UploadAsync(CrashReport crashReport)
using var responseReader = new StreamReader(stream);
var result = await responseReader.ReadLineAsync().ConfigureAwait(false);
+ if (string.IsNullOrEmpty(result))
+ return CrashUploaderResult.ResponseUrlIsNullOrEmpty();
return CrashUploaderResult.Success(result);
}
catch (Exception e)
diff --git a/src/Bannerlord.ButterLib/CrashUploader/CrashUploaderResult.cs b/src/Bannerlord.ButterLib/CrashUploader/CrashUploaderResult.cs
index 26260614..1969be5a 100644
--- a/src/Bannerlord.ButterLib/CrashUploader/CrashUploaderResult.cs
+++ b/src/Bannerlord.ButterLib/CrashUploader/CrashUploaderResult.cs
@@ -7,6 +7,7 @@ internal record CrashUploaderResult
public static CrashUploaderResult ResponseIsNotHttpWebResponse() => new(CrashUploaderStatus.ResponseIsNotHttpWebResponse);
public static CrashUploaderResult WrongStatusCode(string statusCode) => new(CrashUploaderStatus.WrongStatusCode) { StatusCode = statusCode };
public static CrashUploaderResult ResponseStreamIsNull() => new(CrashUploaderStatus.ResponseStreamIsNull);
+ public static CrashUploaderResult ResponseUrlIsNullOrEmpty() => new(CrashUploaderStatus.UrlIsNullOrEmpty);
public static CrashUploaderResult FailedWithException(string exception) => new(CrashUploaderStatus.FailedWithException) { Exception = exception };
public CrashUploaderStatus Status { get; }
diff --git a/src/Bannerlord.ButterLib/CrashUploader/CrashUploaderStatus.cs b/src/Bannerlord.ButterLib/CrashUploader/CrashUploaderStatus.cs
index 044ed7cb..554687ee 100644
--- a/src/Bannerlord.ButterLib/CrashUploader/CrashUploaderStatus.cs
+++ b/src/Bannerlord.ButterLib/CrashUploader/CrashUploaderStatus.cs
@@ -8,5 +8,6 @@ internal enum CrashUploaderStatus
WrongStatusCode,
ResponseStreamIsNull,
FailedWithException,
+ UrlIsNullOrEmpty,
}
}
\ No newline at end of file
diff --git a/src/Bannerlord.ButterLib/DynamicAPI/DynamicApiProvider.cs b/src/Bannerlord.ButterLib/DynamicAPI/DynamicApiProvider.cs
index a1200375..4871323b 100644
--- a/src/Bannerlord.ButterLib/DynamicAPI/DynamicApiProvider.cs
+++ b/src/Bannerlord.ButterLib/DynamicAPI/DynamicApiProvider.cs
@@ -42,7 +42,7 @@ private record MethodInfoWithAttribute(MethodInfo MethodInfo, CustomAttributeDat
private static TypeWithAttribute? GetDynamicAPIClass(Type? type)
{
bool Predicate(CustomAttributeData x) =>
- PossibleClassNames.Contains(x.AttributeType.FullName) && x.ConstructorArguments.Count == 1 && x.ConstructorArguments[0].ArgumentType == typeof(string);
+ PossibleClassNames.Contains(x.AttributeType.FullName!) && x.ConstructorArguments.Count == 1 && x.ConstructorArguments[0].ArgumentType == typeof(string);
if (type is null)
return null;
@@ -59,7 +59,7 @@ bool Predicate(CustomAttributeData x) =>
private static MethodInfoWithAttribute? GetDynamicAPIMethod(MethodInfo? methodInfo)
{
bool Predicate(CustomAttributeData x) =>
- PossibleMethodNames.Contains(x.AttributeType.FullName) && x.ConstructorArguments.Count == 1 && x.ConstructorArguments[0].ArgumentType == typeof(string);
+ PossibleMethodNames.Contains(x.AttributeType.FullName!) && x.ConstructorArguments.Count == 1 && x.ConstructorArguments[0].ArgumentType == typeof(string);
if (methodInfo is null)
return null;
@@ -71,11 +71,11 @@ bool Predicate(CustomAttributeData x) =>
}
private static string DynamicAPIClassAttributeName(TypeWithAttribute typeWithAttribute) =>
- (string) typeWithAttribute.CustomAttributeData.ConstructorArguments[0].Value;
+ (string) typeWithAttribute.CustomAttributeData.ConstructorArguments[0].Value!;
private static string DynamicAPIMethodAttributeName(MethodInfoWithAttribute methodInfoWithAttribute)
{
- var name = (string) methodInfoWithAttribute.CustomAttributeData.ConstructorArguments[0].Value;
+ var name = (string) methodInfoWithAttribute.CustomAttributeData.ConstructorArguments[0].Value!;
return $"{(methodInfoWithAttribute.MethodInfo.IsStatic ? "0static" : "0instance")}_{name}";
}
diff --git a/src/Bannerlord.ButterLib/ExceptionHandler/BEWPatch.cs b/src/Bannerlord.ButterLib/ExceptionHandler/BEWPatch.cs
index 8fb59738..416d56d5 100644
--- a/src/Bannerlord.ButterLib/ExceptionHandler/BEWPatch.cs
+++ b/src/Bannerlord.ButterLib/ExceptionHandler/BEWPatch.cs
@@ -44,7 +44,7 @@ public static bool IsDebuggerAttached()
return false;
}
- internal record ExceptionIdentifier(Type Type, string StackTrace, string Message)
+ internal record ExceptionIdentifier(Type Type, string? StackTrace, string Message)
{
public static ExceptionIdentifier FromException(Exception e) => new(e.GetType(), e.StackTrace, e.Message);
}
diff --git a/src/Bannerlord.ButterLib/ExceptionHandler/CrashReport.cs b/src/Bannerlord.ButterLib/ExceptionHandler/CrashReport.cs
index 9e0d8f00..6b80a5b4 100644
--- a/src/Bannerlord.ButterLib/ExceptionHandler/CrashReport.cs
+++ b/src/Bannerlord.ButterLib/ExceptionHandler/CrashReport.cs
@@ -35,11 +35,11 @@ public CrashReport(Exception exception)
foreach (var subModule in LoadedModules.SelectMany(module => module.SubModules))
{
moduleAssemblies.Add(Path.GetFileNameWithoutExtension(subModule.DLLName));
- moduleAssemblies.AddRange(subModule.Assemblies.Select(Path.GetFileNameWithoutExtension));
+ moduleAssemblies.AddRange(subModule.Assemblies.Select(Path.GetFileNameWithoutExtension).OfType());
}
- ModuleLoadedAssemblies.AddRange(AccessTools2.AllAssemblies().Where(a => moduleAssemblies.Contains(a.GetName().Name)));
- ExternalLoadedAssemblies.AddRange(AccessTools2.AllAssemblies().Where(a => !moduleAssemblies.Contains(a.GetName().Name)));
+ ModuleLoadedAssemblies.AddRange(AccessTools2.AllAssemblies().Where(a => moduleAssemblies.Contains(a.GetName().Name!)));
+ ExternalLoadedAssemblies.AddRange(AccessTools2.AllAssemblies().Where(a => !moduleAssemblies.Contains(a.GetName().Name!)));
foreach (var originalMethod in Harmony.GetAllPatchedMethods())
{
@@ -101,7 +101,7 @@ private static IEnumerable GetAllInvolvedModules(Exception ex)
{
if (!frame.HasMethod()) continue;
- MethodBase? method;
+ MethodBase method;
var methodFromStackframeIssue = false;
try
{
@@ -110,15 +110,15 @@ private static IEnumerable GetAllInvolvedModules(Exception ex)
// NullReferenceException means the method was not found. Harmony doesn't handle this case gracefully
catch (NullReferenceException)
{
- method = frame.GetMethod();
+ method = frame.GetMethod()!;
}
// The given generic instantiation was invalid.
// From what I understand, this will occur with generic methods
// Also when static constructors throw errors, Harmony resolution will fail
- catch (Exception e)
+ catch (Exception)
{
methodFromStackframeIssue = true;
- method = frame.GetMethod();
+ method = frame.GetMethod()!;
}
var frameDesc = $"{frame} (IL Offset: {frame.GetILOffset()})";
diff --git a/src/Bannerlord.ButterLib/ExceptionHandler/DebuggerDetection/ProcessDebug.cs b/src/Bannerlord.ButterLib/ExceptionHandler/DebuggerDetection/ProcessDebug.cs
index 9dc3de96..4c262c8f 100644
--- a/src/Bannerlord.ButterLib/ExceptionHandler/DebuggerDetection/ProcessDebug.cs
+++ b/src/Bannerlord.ButterLib/ExceptionHandler/DebuggerDetection/ProcessDebug.cs
@@ -6,7 +6,7 @@ namespace Bannerlord.ButterLib.ExceptionHandler.DebuggerDetection
{
internal static class ProcessDebug
{
- private const int PROCESS_DEBUG_OBJECT_HANDLE = 0x1E;
+ private const int PROCESS_DEBUG_OBJECT_HANDLE = 30;
private const int PROCESS_DEBUG_PORT = 7;
[DllImport("ntdll.dll", SetLastError = true)]
diff --git a/src/Bannerlord.ButterLib/ExceptionHandler/WinForms/HtmlCrashReportForm.cs b/src/Bannerlord.ButterLib/ExceptionHandler/WinForms/HtmlCrashReportForm.cs
index a6458664..8ea51eff 100644
--- a/src/Bannerlord.ButterLib/ExceptionHandler/WinForms/HtmlCrashReportForm.cs
+++ b/src/Bannerlord.ButterLib/ExceptionHandler/WinForms/HtmlCrashReportForm.cs
@@ -134,7 +134,7 @@ function handleIncludeScreenshot(cb) {
}
";
- private static string TableText = @$"
+ private static string TableText = $"""
Clicking 'Close Report' will continue with the Game's error report mechanism.
-
";
+
+""";
private CrashReport CrashReport { get; }
private string ReportInHtml { get; }
diff --git a/src/Bannerlord.ButterLib/SaveSystem/DictionaryToArrayConverter.cs b/src/Bannerlord.ButterLib/SaveSystem/DictionaryToArrayConverter.cs
index d07fe319..48d0ca08 100644
--- a/src/Bannerlord.ButterLib/SaveSystem/DictionaryToArrayConverter.cs
+++ b/src/Bannerlord.ButterLib/SaveSystem/DictionaryToArrayConverter.cs
@@ -13,7 +13,7 @@ public sealed class DictionaryToArrayConverter : JsonConverter
private static bool TypeImplementsGenericInterface(Type concreteType, Type interfaceType) => concreteType.GetInterfaces().Any(i => i.IsGenericType && i.GetGenericTypeDefinition() == interfaceType);
- public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
+ public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer)
{
if (value is IDictionary dictionary)
{
@@ -33,12 +33,12 @@ public override void WriteJson(JsonWriter writer, object value, JsonSerializer s
}
}
- public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
+ public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer)
{
if (existingValue is not IDictionary dict)
{
var contract = serializer.ContractResolver.ResolveContract(objectType);
- dict = (IDictionary) contract.DefaultCreator();
+ dict = (IDictionary) contract.DefaultCreator!();
}
if (reader.TokenType == JsonToken.StartArray)
diff --git a/src/Bannerlord.ButterLib/SaveSystem/Extensions/IDataStoreExtensions.cs b/src/Bannerlord.ButterLib/SaveSystem/Extensions/IDataStoreExtensions.cs
index 3b420711..224bd6a6 100644
--- a/src/Bannerlord.ButterLib/SaveSystem/Extensions/IDataStoreExtensions.cs
+++ b/src/Bannerlord.ButterLib/SaveSystem/Extensions/IDataStoreExtensions.cs
@@ -28,7 +28,7 @@ private static string ChunksToString(IReadOnlyList chunks)
return strBuilder.ToString();
}
- public static bool SyncDataAsJson(this IDataStore dataStore, string key, ref T data, JsonSerializerSettings? settings = null)
+ public static bool SyncDataAsJson(this IDataStore dataStore, string key, ref T? data, JsonSerializerSettings? settings = null)
{
// If the type we're synchronizing is a string or string array, then it's ambiguous
// with our own internal storage types, which imply that the strings contain valid
@@ -63,7 +63,7 @@ public static bool SyncDataAsJson(this IDataStore dataStore, string key, ref
var jsonDataChunks = Array.Empty();
if (dataStore.SyncData(key, ref jsonDataChunks))
{
- var (format, jsonData) = JsonConvert.DeserializeObject(ChunksToString(jsonDataChunks ?? Array.Empty()), settings);
+ var (format, jsonData) = JsonConvert.DeserializeObject(ChunksToString(jsonDataChunks ?? Array.Empty()), settings) ?? new(-1, string.Empty);
data = format switch
{
2 => JsonConvert.DeserializeObject(jsonData, settings),
diff --git a/src/Bannerlord.ButterLib/SaveSystem/MBGUIDConverter.cs b/src/Bannerlord.ButterLib/SaveSystem/MBGUIDConverter.cs
index 314d4ad1..770e2955 100644
--- a/src/Bannerlord.ButterLib/SaveSystem/MBGUIDConverter.cs
+++ b/src/Bannerlord.ButterLib/SaveSystem/MBGUIDConverter.cs
@@ -21,7 +21,7 @@ public override void WriteJson(JsonWriter writer, object? value, JsonSerializer
serializer.Serialize(writer, null);
}
- public override object? ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
+ public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer)
{
if (serializer.Deserialize(reader) is { } id)
{
diff --git a/src/Bannerlord.ButterLib/SaveSystem/MBObjectBaseConverter.cs b/src/Bannerlord.ButterLib/SaveSystem/MBObjectBaseConverter.cs
index 759ef592..21e40f44 100644
--- a/src/Bannerlord.ButterLib/SaveSystem/MBObjectBaseConverter.cs
+++ b/src/Bannerlord.ButterLib/SaveSystem/MBObjectBaseConverter.cs
@@ -29,7 +29,7 @@ public override void WriteJson(JsonWriter writer, object? value, JsonSerializer
serializer.Serialize(writer, null);
}
- public override object? ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
+ public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer)
{
if (serializer.Deserialize(reader) is { } mbguid)
{
diff --git a/src/Bannerlord.ButterLib/SubSystems/Settings/SubSystemSettingsProperty.cs b/src/Bannerlord.ButterLib/SubSystems/Settings/SubSystemSettingsProperty.cs
index af5f378f..9721384b 100644
--- a/src/Bannerlord.ButterLib/SubSystems/Settings/SubSystemSettingsProperty.cs
+++ b/src/Bannerlord.ButterLib/SubSystems/Settings/SubSystemSettingsProperty.cs
@@ -3,11 +3,13 @@
namespace Bannerlord.ButterLib.SubSystems.Settings
{
- ///
///
/// A property based declaration.
///
+ /// The name of the settings entry.
+ /// The description of the settings entry.
/// And expression that references the property.
+ /// The that exposes the settings.
/// Type of the property.
public abstract record SubSystemSettingsProperty(string Name, string Description, Expression> Property) :
SubSystemSettingsDeclaration(Name, Description) where TSubSystem : ISubSystem;
diff --git a/src/Bannerlord.ButterLib/SubSystems/Settings/SubSystemSettingsPropertyDropdown.cs b/src/Bannerlord.ButterLib/SubSystems/Settings/SubSystemSettingsPropertyDropdown.cs
index 7df38979..c7ae1f1f 100644
--- a/src/Bannerlord.ButterLib/SubSystems/Settings/SubSystemSettingsPropertyDropdown.cs
+++ b/src/Bannerlord.ButterLib/SubSystems/Settings/SubSystemSettingsPropertyDropdown.cs
@@ -6,7 +6,7 @@ namespace Bannerlord.ButterLib.SubSystems.Settings
{
///
///
- /// A switch based on a property.
+ /// IList<>
///
public record SubSystemSettingsPropertyDropdown(string Name, string Description, Expression>> Property, int SelectedIndex) :
SubSystemSettingsProperty>(Name, Description, Property) where TSubSystem : ISubSystem;
From 08c8d5b05d7181b3a2863bbca31bc32d8bc8d01b Mon Sep 17 00:00:00 2001
From: Vitalii Mikhailov
Date: Wed, 28 Jun 2023 16:36:00 +0300
Subject: [PATCH 03/12] Added CIL code for methods
Added AsmResolver dependency
---
build/common.props | 9 ++--
changelog.txt | 5 ++
...Bannerlord.ButterLib.Implementation.csproj | 4 +-
.../Properties/launchSettings.json | 12 ++---
.../_Module/SubModule.xml | 3 ++
.../Bannerlord.ButterLib.csproj | 9 +++-
.../DynamicAPI/DynamicApiProvider.cs | 2 +-
.../ExceptionHandler/CrashReport.cs | 39 ++++++++++----
.../ExceptionHandler/HtmlBuilder.cs | 52 ++++++-------------
9 files changed, 77 insertions(+), 58 deletions(-)
diff --git a/build/common.props b/build/common.props
index 1fcbb887..8416f527 100644
--- a/build/common.props
+++ b/build/common.props
@@ -4,13 +4,14 @@
- 2.8.1
+ 2.9.0
- 2.2.2
+ 2.3.0
3.2.0.77
1.0.1.44
-
+
+
2.0.0
1.1.0.102
@@ -20,12 +21,12 @@
BUTR Team
-
ButterLib Library for Bannerlord
+
diff --git a/changelog.txt b/changelog.txt
index b8b78aa7..98c1e114 100644
--- a/changelog.txt
+++ b/changelog.txt
@@ -1,4 +1,9 @@
---------------------------------------------------------------------------------------------------
+Version: 2.9.0
+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
+* Show the whole CIL code of the patched method in enhanced stacktrace
+* Requires Lib.Harmony 2.3.0 and higher
+---------------------------------------------------------------------------------------------------
Version: 2.8.1
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
* Added support for v1.2.0
diff --git a/src/Bannerlord.ButterLib.Implementation/Bannerlord.ButterLib.Implementation.csproj b/src/Bannerlord.ButterLib.Implementation/Bannerlord.ButterLib.Implementation.csproj
index 6df46153..105ddd33 100644
--- a/src/Bannerlord.ButterLib.Implementation/Bannerlord.ButterLib.Implementation.csproj
+++ b/src/Bannerlord.ButterLib.Implementation/Bannerlord.ButterLib.Implementation.csproj
@@ -35,7 +35,9 @@
-
+
+
+
diff --git a/src/Bannerlord.ButterLib.Implementation/Properties/launchSettings.json b/src/Bannerlord.ButterLib.Implementation/Properties/launchSettings.json
index 9af5d7cf..65805984 100644
--- a/src/Bannerlord.ButterLib.Implementation/Properties/launchSettings.json
+++ b/src/Bannerlord.ButterLib.Implementation/Properties/launchSettings.json
@@ -18,21 +18,21 @@
"commandLineArgs": "/singleplayer _MODULES_*Bannerlord.Harmony*Bannerlord.ButterLib*Native*SandBoxCore*Sandbox*StoryMode*CustomBattle*Bannerlord.ButterLib.HotKeys.Test*_MODULES_",
"workingDirectory": "$(GameFolder)\\bin\\Win64_Shipping_Client"
},
- "MBSE Bannerlord": {
+ "BLSE Bannerlord": {
"commandName": "Executable",
- "executablePath": "$(GameFolder)\\bin\\Win64_Shipping_Client\\Bannerlord.MBSE.exe",
+ "executablePath": "$(GameFolder)\\bin\\Win64_Shipping_Client\\Bannerlord.BLSE.Standalone.exe",
"commandLineArgs": "/singleplayer _MODULES_*Bannerlord.Harmony*Bannerlord.ButterLib*Native*SandBoxCore*Sandbox*StoryMode*CustomBattle*_MODULES_",
"workingDirectory": "$(GameFolder)\\bin\\Win64_Shipping_Client"
},
- "MBSE BannerlordWithMCM": {
+ "BLSE BannerlordWithMCM": {
"commandName": "Executable",
- "executablePath": "$(GameFolder)\\bin\\Win64_Shipping_Client\\Bannerlord.MBSE.exe",
+ "executablePath": "$(GameFolder)\\bin\\Win64_Shipping_Client\\Bannerlord.BLSE.Standalone.exe",
"commandLineArgs": "/singleplayer _MODULES_*Bannerlord.Harmony*Bannerlord.ButterLib*Bannerlord.UIExtenderEx*Bannerlord.MBOptionScreen*Native*SandBoxCore*Sandbox*StoryMode*CustomBattle*_MODULES_",
"workingDirectory": "$(GameFolder)\\bin\\Win64_Shipping_Client"
},
- "MBSE BannerlordWithTests": {
+ "BLSE BannerlordWithTests": {
"commandName": "Executable",
- "executablePath": "$(GameFolder)\\bin\\Win64_Shipping_Client\\Bannerlord.MBSE.exe",
+ "executablePath": "$(GameFolder)\\bin\\Win64_Shipping_Client\\Bannerlord.BLSE.Standalone.exe",
"commandLineArgs": "/singleplayer _MODULES_*Bannerlord.Harmony*Bannerlord.ButterLib*Native*SandBoxCore*Sandbox*StoryMode*CustomBattle*Bannerlord.ButterLib.HotKeys.Test*_MODULES_",
"workingDirectory": "$(GameFolder)\\bin\\Win64_Shipping_Client"
}
diff --git a/src/Bannerlord.ButterLib.Implementation/_Module/SubModule.xml b/src/Bannerlord.ButterLib.Implementation/_Module/SubModule.xml
index 04b0d361..b2dc20bb 100644
--- a/src/Bannerlord.ButterLib.Implementation/_Module/SubModule.xml
+++ b/src/Bannerlord.ButterLib.Implementation/_Module/SubModule.xml
@@ -9,6 +9,9 @@
+
diff --git a/src/Bannerlord.ButterLib/Bannerlord.ButterLib.csproj b/src/Bannerlord.ButterLib/Bannerlord.ButterLib.csproj
index bbec774f..37cce132 100644
--- a/src/Bannerlord.ButterLib/Bannerlord.ButterLib.csproj
+++ b/src/Bannerlord.ButterLib/Bannerlord.ButterLib.csproj
@@ -33,10 +33,12 @@
+
-
+
+
@@ -46,6 +48,11 @@
+
diff --git a/src/Bannerlord.ButterLib/DynamicAPI/DynamicApiProvider.cs b/src/Bannerlord.ButterLib/DynamicAPI/DynamicApiProvider.cs
index 4871323b..03b2682b 100644
--- a/src/Bannerlord.ButterLib/DynamicAPI/DynamicApiProvider.cs
+++ b/src/Bannerlord.ButterLib/DynamicAPI/DynamicApiProvider.cs
@@ -81,7 +81,7 @@ private static string DynamicAPIMethodAttributeName(MethodInfoWithAttribute meth
private static IEnumerable GetAssembliesToScan()
{
- var loadedModules = ModuleInfoHelper.GetLoadedModules().OfType().ToList();
+ var loadedModules = ModuleInfoHelper.GetLoadedModules().Where(x => x is not null).ToList();
foreach (var assembly in AccessTools2.AllAssemblies().Where(x => !x.IsDynamic && !string.IsNullOrEmpty(x.Location)))
{
if (loadedModules.Any(loadedModule => ModuleInfoHelper.IsModuleAssembly(loadedModule, assembly)))
diff --git a/src/Bannerlord.ButterLib/ExceptionHandler/CrashReport.cs b/src/Bannerlord.ButterLib/ExceptionHandler/CrashReport.cs
index 6b80a5b4..13841e5e 100644
--- a/src/Bannerlord.ButterLib/ExceptionHandler/CrashReport.cs
+++ b/src/Bannerlord.ButterLib/ExceptionHandler/CrashReport.cs
@@ -1,9 +1,13 @@
-using Bannerlord.BUTR.Shared.Helpers;
+using AsmResolver.DotNet.Code.Cil;
+
+using Bannerlord.BUTR.Shared.Helpers;
using Bannerlord.ModuleManager;
using HarmonyLib;
using HarmonyLib.BUTR.Extensions;
+using MonoMod.Core.Platforms;
+
using System;
using System.Collections.Generic;
using System.Diagnostics;
@@ -13,7 +17,7 @@
namespace Bannerlord.ButterLib.ExceptionHandler
{
- internal record StacktraceEntry(MethodBase Method, bool MethodFromStackframeIssue, ModuleInfoExtended? ModuleInfo, string StackFrameDescription);
+ internal record StacktraceEntry(MethodBase Method, bool MethodFromStackframeIssue, ModuleInfoExtended? ModuleInfo, string StackFrameDescription, CilInstructionCollection? CilInstructions);
internal class CrashReport
{
@@ -35,7 +39,7 @@ public CrashReport(Exception exception)
foreach (var subModule in LoadedModules.SelectMany(module => module.SubModules))
{
moduleAssemblies.Add(Path.GetFileNameWithoutExtension(subModule.DLLName));
- moduleAssemblies.AddRange(subModule.Assemblies.Select(Path.GetFileNameWithoutExtension).OfType());
+ moduleAssemblies.AddRange(subModule.Assemblies.Select(Path.GetFileNameWithoutExtension).Where(x => x is not null));
}
ModuleLoadedAssemblies.AddRange(AccessTools2.AllAssemblies().Where(a => moduleAssemblies.Contains(a.GetName().Name!)));
@@ -126,27 +130,42 @@ private static IEnumerable GetAllInvolvedModules(Exception ex)
var patches = FindPatches(method);
foreach (var (methodBase, extendedModuleInfo) in GetFinalizers(patches))
{
- yield return new(methodBase, methodFromStackframeIssue, extendedModuleInfo, frameDesc);
+ yield return new(methodBase, methodFromStackframeIssue, extendedModuleInfo, frameDesc, null);
}
foreach (var (methodBase, extendedModuleInfo) in GetPostfixes(patches))
{
- yield return new(methodBase, methodFromStackframeIssue, extendedModuleInfo, frameDesc);
+ yield return new(methodBase, methodFromStackframeIssue, extendedModuleInfo, frameDesc, null);
}
foreach (var (methodBase, extendedModuleInfo) in GetPrefixes(patches))
{
- yield return new(methodBase, methodFromStackframeIssue, extendedModuleInfo, frameDesc);
+ yield return new(methodBase, methodFromStackframeIssue, extendedModuleInfo, frameDesc, null);
}
foreach (var (methodBase, extendedModuleInfo) in GetTranspilers(patches))
{
- yield return new(methodBase, methodFromStackframeIssue, extendedModuleInfo, frameDesc);
+ yield return new(methodBase, methodFromStackframeIssue, extendedModuleInfo, frameDesc, null);
}
var moduleInfo = GetModuleInfoIfMod(method);
- yield return new(method, methodFromStackframeIssue, moduleInfo, frameDesc);
+ yield return new(method, methodFromStackframeIssue, moduleInfo, frameDesc, null);
- if (method is MethodInfo methodInfo && Harmony.GetOriginalMethod(methodInfo) is { } original)
- yield return new(original, methodFromStackframeIssue, moduleInfo, frameDesc);
+ // Further versions of Harmony will do `PlatformTriple.Current.GetIdentifiable(method) is MethodInfo identifiableMethod` themselves
+ if (method is MethodInfo && PlatformTriple.Current.GetIdentifiable(method) is MethodInfo identifiableMethod && Harmony.GetOriginalMethod(identifiableMethod) is { } original)
+ {
+ CilInstructionCollection? instructions;
+ try
+ {
+ var module = AsmResolver.DotNet.ModuleDefinition.FromModule(identifiableMethod.Module);
+ var dynamicMethodDefinition = new AsmResolver.DotNet.Dynamic.DynamicMethodDefinition(module, identifiableMethod);
+ var cilMethodBody = dynamicMethodDefinition.MethodBody as CilMethodBody;
+ instructions = cilMethodBody?.Instructions;
+ }
+ catch (Exception)
+ {
+ instructions = null;
+ }
+ yield return new(original, methodFromStackframeIssue, moduleInfo, frameDesc, instructions);
+ }
}
}
}
diff --git a/src/Bannerlord.ButterLib/ExceptionHandler/HtmlBuilder.cs b/src/Bannerlord.ButterLib/ExceptionHandler/HtmlBuilder.cs
index 1a511e19..13b3bb7a 100644
--- a/src/Bannerlord.ButterLib/ExceptionHandler/HtmlBuilder.cs
+++ b/src/Bannerlord.ButterLib/ExceptionHandler/HtmlBuilder.cs
@@ -1,6 +1,7 @@
using Bannerlord.BUTR.Shared.Extensions;
using Bannerlord.BUTR.Shared.Helpers;
using Bannerlord.ButterLib.Common.Extensions;
+using Bannerlord.ButterLib.Helpers;
using Bannerlord.ButterLib.Logger;
using Bannerlord.ModuleManager;
@@ -26,7 +27,7 @@ namespace Bannerlord.ButterLib.ExceptionHandler
{
internal static class HtmlBuilder
{
- private static readonly int Version = 10;
+ private static readonly int Version = 11;
private static readonly string NL = Environment.NewLine;
public static readonly string MiniDumpTag = "";
@@ -315,10 +316,10 @@ function screenshot(element) {{