diff --git a/README.md b/README.md index 212ffcb6..acbf1b41 100644 --- a/README.md +++ b/README.md @@ -1,52 +1,52 @@ # Bannerlord.UIExtenderEx

- - + + Logo -
- - +
+
+ Lines Of Code - CodeFactor + CodeFactor Code Climate maintainability - - + + Documentation - + Crowdin -
+
GitHub Workflow Status (event) - + CodeCov -
- - +
+
+ NuGet Bannerlord.UIExtenderEx -
- - +
+
+ NexusMods UIExtenderEx - - + + NexusMods UIExtenderEx - - + + NexusMods UIExtenderEx - - + + NexusMods UIExtenderEx - - + + NexusMods UIExtenderEx -
+
Steam Mod Configuration Menu @@ -62,7 +62,7 @@ Steam Favorites -
+

A library that enables multiple mods to alter standard game interface. @@ -72,7 +72,7 @@ Previously, a fork of [UIExtenderLib](https://github.com/shdwp/UIExtenderLib) th This module should be one of the highest in loading order. Ideally, it should be loaded after ``Bannerlord.Harmony`` or ``Bannerlord.ButterLib``. ## For Players -This mod is a dependency mod that does not provide anything by itself. You need to additionaly install mods that use it. +This mod is a dependency mod that does not provide anything by itself. You need to additionally install mods that use it. ## Usage Check the [``Articles``](https://butr.github.io/Bannerlord.UIExtenderEx/articles/v2/Overview.html) section of our documentation! diff --git a/build/common.props b/build/common.props index 4770de8c..92165722 100644 --- a/build/common.props +++ b/build/common.props @@ -4,7 +4,7 @@ - 2.9.0 + 2.10.0 2.2.2 3.2.0.77 diff --git a/changelog.txt b/changelog.txt index 96ebb7df..73a074c8 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,4 +1,9 @@ --------------------------------------------------------------------------------------------------- +Version: 2.10.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.1.6,v1.2.8 +* BETA! Might cause issues with the UI in specific cases! +* UIExtender now only disables AutoGens that are patched, should increase the game's performance +--------------------------------------------------------------------------------------------------- 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.1.6,v1.2.8 * Added the ability to disable specific Prefabs and Mixins, also to deregister a mods UIExtender diff --git a/docs/articles/general/InteractingWithOtherMods.md b/docs/articles/general/InteractingWithOtherMods.md new file mode 100644 index 00000000..5878e1ae --- /dev/null +++ b/docs/articles/general/InteractingWithOtherMods.md @@ -0,0 +1,17 @@ +# Interacting with Other Mods + +You can access another mod's `UIExtender` and modify it to your liking. +At the moment you are able to disable the UIExtender, deregister it (meaning fully disabling it without the ability to enable it back) and enable. +You are able to disable a specific Prefab or Mixin. +```csharp +// Get Mod Configuration Menu's UIExtender +var mcm = UIExtender.GetUIExtenderFor("MCM.UI"); + +// Disable a prefab +var mcmPrefab = AccessTools.TypeByName("MCM.UI.UIExtenderEx.OptionsPrefabExtension1"); +mcm.Disable(mcmPrefab); + +// Disable a Mixin +var mcmMixin = AccessTools.TypeByName("MCM.UI.UIExtenderEx.OptionsVMMixin"); +mcm.Disable(mcmMixin); +``` \ No newline at end of file diff --git a/docs/articles/general/Overview.md b/docs/articles/general/Overview.md new file mode 100644 index 00000000..8316c31a --- /dev/null +++ b/docs/articles/general/Overview.md @@ -0,0 +1,3 @@ +# Overview + +Check the specific articles. \ No newline at end of file diff --git a/docs/articles/general/toc.yml b/docs/articles/general/toc.yml new file mode 100644 index 00000000..9831a478 --- /dev/null +++ b/docs/articles/general/toc.yml @@ -0,0 +1,6 @@ +- name: Overview + href: Overview.md +- name: Prefab + href: Prefab.md +- name: Interacting With Other Mods + href: InteractingWithOtherMods.md diff --git a/docs/articles/interface/toc.yml b/docs/articles/interface/toc.yml index 7018247e..e8fbca11 100644 --- a/docs/articles/interface/toc.yml +++ b/docs/articles/interface/toc.yml @@ -2,5 +2,5 @@ href: Overview.md - name: Prefab href: Prefab.md -- name: ViewModelMixin +- name: ViewModel Mixin href: ViewModelMixin.md diff --git a/docs/articles/runtime/toc.yml b/docs/articles/runtime/toc.yml index 80d02a8c..ca802cec 100644 --- a/docs/articles/runtime/toc.yml +++ b/docs/articles/runtime/toc.yml @@ -2,7 +2,7 @@ href: Overview.md - name: Registration href: Registration.md -- name: PrefabPatching +- name: Prefab Patching href: PrefabPatching.md -- name: ViewModelPatching +- name: ViewModel Patching href: ViewModelPatching.md diff --git a/docs/articles/toc.yml b/docs/articles/toc.yml index dd8ebace..022ced4e 100644 --- a/docs/articles/toc.yml +++ b/docs/articles/toc.yml @@ -1,4 +1,7 @@ items: +- name: General + href: general/toc.yml + homepage: general/Overview.md - name: APIv2 href: v2/toc.yml homepage: v2/Overview.md diff --git a/docs/articles/v2/toc.yml b/docs/articles/v2/toc.yml index 581ec6b6..df13d403 100644 --- a/docs/articles/v2/toc.yml +++ b/docs/articles/v2/toc.yml @@ -4,7 +4,7 @@ href: PrefabExtensionSetAttributePatch.md - name: PrefabExtensionInsertPatch href: PrefabExtensionInsertPatch.md -- name: ViewModelMixin +- name: ViewModel Mixin href: ViewModelMixin.md - name: Examples href: Examples.md diff --git a/src/Bannerlord.UIExtenderEx.sln b/src/Bannerlord.UIExtenderEx.sln index dbd0fc86..7eec80dc 100644 --- a/src/Bannerlord.UIExtenderEx.sln +++ b/src/Bannerlord.UIExtenderEx.sln @@ -31,8 +31,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Bannerlord.UIExtenderEx.Tes EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "docs", "docs", "{6A6FB1BE-5426-4835-A308-0E74E66299D5}" ProjectSection(SolutionItems) = preProject - ..\docs\articles\toc.yml = ..\docs\articles\toc.yml ..\docs\docfx.json = ..\docs\docfx.json + ..\docs\toc.yml = ..\docs\toc.yml EndProjectSection EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "v1", "v1", "{395402D4-28B5-4974-943D-04B7D5F6673D}" @@ -53,33 +53,38 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "v2", "v2", "{B4D6A888-2D8F- EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "interface", "interface", "{252A68C5-9E10-4E28-AF49-37E6DF1E62F0}" ProjectSection(SolutionItems) = preProject - ..\docs\articles\Interface\Overview.png = ..\docs\articles\Interface\Overview.png - ..\docs\articles\Interface\Overview.puml = ..\docs\articles\Interface\Overview.puml - ..\docs\articles\Interface\Prefab.png = ..\docs\articles\Interface\Prefab.png - ..\docs\articles\Interface\Prefab.puml = ..\docs\articles\Interface\Prefab.puml - ..\docs\articles\Interface\ViewModelMixin.png = ..\docs\articles\Interface\ViewModelMixin.png - ..\docs\articles\Interface\ViewModelMixin.puml = ..\docs\articles\Interface\ViewModelMixin.puml - ..\docs\articles\Interface\Overview.md = ..\docs\articles\Interface\Overview.md - ..\docs\articles\Interface\Prefab.md = ..\docs\articles\Interface\Prefab.md - ..\docs\articles\Interface\ViewModelMixin.md = ..\docs\articles\Interface\ViewModelMixin.md - ..\docs\articles\Interface\toc.yml = ..\docs\articles\Interface\toc.yml + ..\docs\articles\interface\Overview.svg = ..\docs\articles\interface\Overview.svg + ..\docs\articles\interface\Overview.puml = ..\docs\articles\interface\Overview.puml + ..\docs\articles\interface\Overview.md = ..\docs\articles\interface\Overview.md + ..\docs\articles\interface\Prefab.svg = ..\docs\articles\interface\Prefab.svg + ..\docs\articles\interface\Prefab.puml = ..\docs\articles\interface\Prefab.puml + ..\docs\articles\interface\Prefab.md = ..\docs\articles\interface\Prefab.md + ..\docs\articles\interface\ViewModelMixin.svg = ..\docs\articles\interface\ViewModelMixin.svg + ..\docs\articles\interface\ViewModelMixin.puml = ..\docs\articles\interface\ViewModelMixin.puml + ..\docs\articles\interface\ViewModelMixin.md = ..\docs\articles\interface\ViewModelMixin.md + ..\docs\articles\interface\toc.yml = ..\docs\articles\interface\toc.yml EndProjectSection EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "runtime", "runtime", "{8969A5E2-BC12-46F8-BF4A-E8F73771E4E5}" ProjectSection(SolutionItems) = preProject - ..\docs\articles\Runtime\ViewModelPatching.png = ..\docs\articles\Runtime\ViewModelPatching.png - ..\docs\articles\Runtime\ViewModelPatching.puml = ..\docs\articles\Runtime\ViewModelPatching.puml - ..\docs\articles\Runtime\Overview.png = ..\docs\articles\Runtime\Overview.png - ..\docs\articles\Runtime\Overview.puml = ..\docs\articles\Runtime\Overview.puml - ..\docs\articles\Runtime\PrefabPatching.png = ..\docs\articles\Runtime\PrefabPatching.png - ..\docs\articles\Runtime\PrefabPatching.puml = ..\docs\articles\Runtime\PrefabPatching.puml - ..\docs\articles\Runtime\Registration.png = ..\docs\articles\Runtime\Registration.png - ..\docs\articles\Runtime\Registration.puml = ..\docs\articles\Runtime\Registration.puml - ..\docs\articles\Runtime\Overview.md = ..\docs\articles\Runtime\Overview.md - ..\docs\articles\Runtime\PrefabPatching.md = ..\docs\articles\Runtime\PrefabPatching.md - ..\docs\articles\Runtime\Registration.md = ..\docs\articles\Runtime\Registration.md - ..\docs\articles\Runtime\ViewModelPatching.md = ..\docs\articles\Runtime\ViewModelPatching.md - ..\docs\articles\Runtime\toc.yml = ..\docs\articles\Runtime\toc.yml + ..\docs\articles\runtime\ViewModelPatching.svg = ..\docs\articles\runtime\ViewModelPatching.svg + ..\docs\articles\runtime\ViewModelPatching.puml = ..\docs\articles\runtime\ViewModelPatching.puml + ..\docs\articles\runtime\ViewModelPatching.md = ..\docs\articles\runtime\ViewModelPatching.md + ..\docs\articles\runtime\Overview.svg = ..\docs\articles\runtime\Overview.svg + ..\docs\articles\runtime\Overview.puml = ..\docs\articles\runtime\Overview.puml + ..\docs\articles\runtime\Overview.md = ..\docs\articles\runtime\Overview.md + ..\docs\articles\runtime\PrefabPatching.svg = ..\docs\articles\runtime\PrefabPatching.svg + ..\docs\articles\runtime\PrefabPatching.puml = ..\docs\articles\runtime\PrefabPatching.puml + ..\docs\articles\runtime\PrefabPatching.md = ..\docs\articles\runtime\PrefabPatching.md + ..\docs\articles\runtime\Registration.svg = ..\docs\articles\runtime\Registration.svg + ..\docs\articles\runtime\Registration.puml = ..\docs\articles\runtime\Registration.puml + ..\docs\articles\runtime\Registration.md = ..\docs\articles\runtime\Registration.md + ..\docs\articles\runtime\toc.yml = ..\docs\articles\runtime\toc.yml + EndProjectSection +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "articles", "articles", "{8034BC17-4282-4A4B-942B-80EEC315C1C2}" + ProjectSection(SolutionItems) = preProject + ..\docs\articles\toc.yml = ..\docs\articles\toc.yml EndProjectSection EndProject Global @@ -118,10 +123,11 @@ Global {74E13D44-2846-49A3-A5AC-D432AD83C9F0} = {9D2C61D6-D1B6-4C89-80B2-6DAE2D5FCEE4} {7C6449DA-635E-4BD9-AAFE-CF2C4B2FB988} = {74E13D44-2846-49A3-A5AC-D432AD83C9F0} {6A6FB1BE-5426-4835-A308-0E74E66299D5} = {9D2C61D6-D1B6-4C89-80B2-6DAE2D5FCEE4} - {395402D4-28B5-4974-943D-04B7D5F6673D} = {6A6FB1BE-5426-4835-A308-0E74E66299D5} - {B4D6A888-2D8F-49A4-87C5-6CD18D8F818B} = {6A6FB1BE-5426-4835-A308-0E74E66299D5} - {252A68C5-9E10-4E28-AF49-37E6DF1E62F0} = {6A6FB1BE-5426-4835-A308-0E74E66299D5} - {8969A5E2-BC12-46F8-BF4A-E8F73771E4E5} = {6A6FB1BE-5426-4835-A308-0E74E66299D5} + {8034BC17-4282-4A4B-942B-80EEC315C1C2} = {6A6FB1BE-5426-4835-A308-0E74E66299D5} + {252A68C5-9E10-4E28-AF49-37E6DF1E62F0} = {8034BC17-4282-4A4B-942B-80EEC315C1C2} + {8969A5E2-BC12-46F8-BF4A-E8F73771E4E5} = {8034BC17-4282-4A4B-942B-80EEC315C1C2} + {395402D4-28B5-4974-943D-04B7D5F6673D} = {8034BC17-4282-4A4B-942B-80EEC315C1C2} + {B4D6A888-2D8F-49A4-87C5-6CD18D8F818B} = {8034BC17-4282-4A4B-942B-80EEC315C1C2} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {31629F18-48B4-4C3E-87C3-BDCB9BBF1BBD} diff --git a/src/Bannerlord.UIExtenderEx/Components/PrefabComponent.cs b/src/Bannerlord.UIExtenderEx/Components/PrefabComponent.cs index 2346df92..cb334cab 100644 --- a/src/Bannerlord.UIExtenderEx/Components/PrefabComponent.cs +++ b/src/Bannerlord.UIExtenderEx/Components/PrefabComponent.cs @@ -1,4 +1,5 @@ -using Bannerlord.BUTR.Shared.Helpers; +using Bannerlord.BUTR.Shared.Extensions; +using Bannerlord.BUTR.Shared.Helpers; using Bannerlord.UIExtenderEx.Utils; using HarmonyLib.BUTR.Extensions; @@ -21,7 +22,7 @@ namespace Bannerlord.UIExtenderEx.Components; /// internal partial class PrefabComponent { - private sealed record PrefabPatch(Type Type, Action Patcher); + internal sealed record PrefabPatch(Type Type, Action Patcher); private delegate Dictionary GetPrefabNamesAndPathsFromCurrentPathDelegate(object instance); private static readonly GetPrefabNamesAndPathsFromCurrentPathDelegate? PrefabNamesMethod = @@ -36,7 +37,7 @@ private sealed record PrefabPatch(Type Type, Action Patcher); /// /// Registered movie patches /// - private readonly ConcurrentDictionary> _moviePatches = new(); + internal readonly ConcurrentDictionary> MoviePatches = new(); private readonly ConcurrentDictionary _enabledPatches = new(); public PrefabComponent(string moduleName) @@ -44,6 +45,15 @@ public PrefabComponent(string moduleName) _moduleName = moduleName; } + public IEnumerable GetMoviesToPatch() + { + foreach (var (movie, patches) in MoviePatches) + { + if (patches.Any(x => _enabledPatches.TryGetValue(x.Type, out var enabled) && enabled)) + yield return movie; + } + } + /// /// Enables all Prefabs. /// @@ -96,7 +106,7 @@ public void RegisterPatch(string movie, Type prefabType, Action pat return; } - _moviePatches.GetOrAdd(movie, _ => new List()).Add(new(prefabType, patcher)); + MoviePatches.GetOrAdd(movie, _ => new List()).Add(new(prefabType, patcher)); _enabledPatches[prefabType] = false; } @@ -115,7 +125,7 @@ public void RegisterPatch(string movie, Type prefabType, Action patcher return; } - _moviePatches.GetOrAdd(movie, _ => new List()).Add(new(prefabType, patcher)); + MoviePatches.GetOrAdd(movie, _ => new List()).Add(new(prefabType, patcher)); _enabledPatches[prefabType] = false; } @@ -140,7 +150,7 @@ public void RegisterPatch(string movie, string? xpath, Type prefabType, Action public void ProcessMovieIfNeeded(string movie, XmlDocument document) { - if (!_moviePatches.TryGetValue(movie, out var patches)) + if (!MoviePatches.TryGetValue(movie, out var patches)) return; if (_enabledPatches.Values.All(x => !x)) diff --git a/src/Bannerlord.UIExtenderEx/Patches/GauntletMoviePatch.cs b/src/Bannerlord.UIExtenderEx/Patches/GauntletMoviePatch.cs index d72f851d..7aa00fbc 100644 --- a/src/Bannerlord.UIExtenderEx/Patches/GauntletMoviePatch.cs +++ b/src/Bannerlord.UIExtenderEx/Patches/GauntletMoviePatch.cs @@ -1,22 +1,30 @@ using HarmonyLib; using HarmonyLib.BUTR.Extensions; +using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; +using TaleWorlds.GauntletUI.BaseTypes; +using TaleWorlds.GauntletUI.PrefabSystem; +using TaleWorlds.Library; + namespace Bannerlord.UIExtenderEx.Patches; internal static class GauntletMoviePatch { - private static readonly ConcurrentDictionary> WidgetNames = new(); - + private static readonly ConcurrentDictionary> _widgetNames = new(); + private static readonly ConcurrentDictionary _widgetChildCache = new(); + private static readonly AccessTools.FieldRef>>? _generatedPrefabs = + AccessTools2.FieldRefAccess>>("_generatedPrefabs"); + public static void Register(UIExtenderRuntime runtime, string? autoGenWidgetName) { if (string.IsNullOrEmpty(autoGenWidgetName)) return; - WidgetNames.AddOrUpdate(runtime, _ => [autoGenWidgetName], (_, list) => + _widgetNames.AddOrUpdate(runtime, _ => [autoGenWidgetName], (_, list) => { list.Add(autoGenWidgetName!); return list; @@ -25,25 +33,73 @@ public static void Register(UIExtenderRuntime runtime, string? autoGenWidgetName public static void Deregister(UIExtenderRuntime runtime) { - WidgetNames.TryRemove(runtime, out var _); + _widgetNames.TryRemove(runtime, out var _); } public static void Patch(Harmony harmony) { - if (AccessTools2.DeclaredMethod("TaleWorlds.GauntletUI.Data.GauntletMovie:Load") is { } methodInfo && - methodInfo.GetParameters() is { } @params && - @params.Any(p => p.Name == "doNotUseGeneratedPrefabs")) + if (AccessTools2.DeclaredMethod("TaleWorlds.GauntletUI.Data.GauntletMovie:Load") is { } mi && mi.GetParameters() is { } p && p.Any(x => x.Name == "doNotUseGeneratedPrefabs")) { harmony.Patch( - methodInfo, + mi, prefix: new HarmonyMethod(typeof(GauntletMoviePatch), nameof(LoadPrefix))); } } - private static void LoadPrefix(string movieName, ref bool doNotUseGeneratedPrefabs) + private static void LoadPrefix(WidgetFactory widgetFactory, string movieName, IViewModel? datasource, ref bool doNotUseGeneratedPrefabs) { - var movies = WidgetNames.SelectMany(kv => kv.Value); - if (movies.Contains(movieName)) + static IEnumerable GetAllInvolvedAutoGenNames(WidgetFactory widgetFactory, string movieName, IViewModel? datasource) + { + static IEnumerable GetChildWidgets(Type widgetType) + { + var children = _widgetChildCache.GetOrAdd(widgetType, static x => x.GetFields(AccessTools.all).Select(x => x.FieldType).Where(x => x.IsSubclassOf(typeof(Widget))).Distinct().ToArray()); + foreach (var childWidgetType in children.Where(x => x != widgetType)) + { + foreach (var childChildWidgetType in GetChildWidgets(childWidgetType).Where(x => x != widgetType && x != childWidgetType)) + { + yield return childChildWidgetType; + } + } + } + + if (_generatedPrefabs?.Invoke(widgetFactory.GeneratedPrefabContext) is { } generatedPrefabs) + { + const string create = "Create"; + var variantName = datasource != null ? datasource.GetType().FullName : "Default"; + if (generatedPrefabs.TryGetValue(movieName, out var dict2) && dict2.TryGetValue(variantName, out var creator) && AccessTools2.TypeByName(creator.Method.Name.Remove(0, create.Length)) is { } type) + { + var widgets = new List { type }.Concat(GetChildWidgets(type)); + var widgetNames = widgets.Select(x => x.Name); + var autoGenNames = widgetNames.Where(x => x.Contains("__")); + return autoGenNames.Select(x => x.Split(["__"], StringSplitOptions.None)[0]); + } + } + /* This implementation actually created the Widget, but it seems that game didn't intend for that + var variantName = datasource == null ? "Default" : datasource.GetType().FullName; + var data = datasource == null ? new Dictionary() : new() { {"DataSource", datasource} }; + if (widgetFactory.GeneratedPrefabContext.InstantiatePrefab(context, movieName, variantName, data) is { } autogenResult) + { + var autoGen = autogenResult.Root; + autoGen.DisableRender = true; + autoGen.IsVisible = false; + autoGen.UpdateChildrenStates = false; + var widgetNames = new HashSet { autoGen.GetType().Name }; + CheckChildrenAutoGens(ref widgetNames, autoGen); + var autoGenNames = widgetNames.Where(x => x.Contains("__")).ToArray(); + return autoGenNames.Select(x => x.Split(["__"], StringSplitOptions.None)[0]); + } + */ + + return Enumerable.Empty(); + } + + var moviesPatched = new HashSet(UIExtender.GetAllRuntimes().SelectMany(x => x.PrefabComponent.GetMoviesToPatch())); + var moviesInvolved = new HashSet(GetAllInvolvedAutoGenNames(widgetFactory, movieName, datasource)); + if (moviesInvolved.Overlaps(moviesPatched)) + doNotUseGeneratedPrefabs = true; + + var moviesBlacklisted = _widgetNames.SelectMany(kv => kv.Value); + if (moviesBlacklisted.Contains(movieName)) doNotUseGeneratedPrefabs = true; } } \ No newline at end of file diff --git a/src/Bannerlord.UIExtenderEx/Patches/UIConfigPatch.cs b/src/Bannerlord.UIExtenderEx/Patches/UIConfigPatch.cs deleted file mode 100644 index 40ec37ae..00000000 --- a/src/Bannerlord.UIExtenderEx/Patches/UIConfigPatch.cs +++ /dev/null @@ -1,17 +0,0 @@ -using HarmonyLib; -using HarmonyLib.BUTR.Extensions; - -namespace Bannerlord.UIExtenderEx.Patches; - -internal static class UIConfigPatch -{ - public static void Patch(Harmony harmony) - { - harmony.TryPatch( - AccessTools2.DeclaredPropertySetter("TaleWorlds.Engine.GauntletUI.UIConfig:DoNotUseGeneratedPrefabs"), - prefix: AccessTools2.DeclaredMethod("Bannerlord.UIExtenderEx.Patches.UIConfigPatch:Prefix")); - } - - // Disable setting a value to DoNotUseGeneratedPrefabs - private static bool Prefix() => false; -} \ No newline at end of file diff --git a/src/Bannerlord.UIExtenderEx/SubModule.cs b/src/Bannerlord.UIExtenderEx/SubModule.cs index 9d960c30..8d3f843c 100644 --- a/src/Bannerlord.UIExtenderEx/SubModule.cs +++ b/src/Bannerlord.UIExtenderEx/SubModule.cs @@ -1,14 +1,10 @@ using Bannerlord.BUTR.Shared.Helpers; -using Bannerlord.UIExtenderEx.Utils; - using BUTR.MessageBoxPInvoke.Helpers; using System; using System.Linq; -using System.Reflection; using System.Text; -using TaleWorlds.Engine.GauntletUI; using TaleWorlds.Localization; using TaleWorlds.MountAndBlade; @@ -16,22 +12,6 @@ namespace Bannerlord.UIExtenderEx; public class SubModule : MBSubModuleBase { - static SubModule() - { - // Disable AutoGens as early as possible - try - { - // Force load TaleWorlds.Engine.GauntletUI as it might not be loaded yet! - Assembly.Load("TaleWorlds.Engine.GauntletUI"); - } - catch (Exception e) - { - MessageUtils.Fail($"Failed to load 'TaleWorlds.Engine.GauntletUI'! Exception: {e}"); - } - - UIConfig.DoNotUseGeneratedPrefabs = true; - } - // We can't rely on EN since the game assumes that the default locale is always English private const string SWarningTitle = @"{=eySpdc25EE}Warning from Bannerlord.UIExtenderEx!"; diff --git a/src/Bannerlord.UIExtenderEx/UIExtender.cs b/src/Bannerlord.UIExtenderEx/UIExtender.cs index 958d621b..01724e73 100644 --- a/src/Bannerlord.UIExtenderEx/UIExtender.cs +++ b/src/Bannerlord.UIExtenderEx/UIExtender.cs @@ -19,7 +19,7 @@ namespace Bannerlord.UIExtenderEx; public class UIExtender { public static UIExtender Create(string moduleName) => new(moduleName, false); - public static UIExtender GetUIExtenderFor(string moduleName) => Instances[moduleName]; + public static UIExtender? GetUIExtenderFor(string moduleName) => Instances.TryGetValue(moduleName, out var uiExtender) ? uiExtender : null; internal static UIExtenderRuntime? GetRuntimeFor(string moduleName) => Instances[moduleName]._runtime; internal static IReadOnlyList GetAllRuntimes() => Instances.Select(x => x.Value._runtime).OfType().ToList(); @@ -29,10 +29,8 @@ public class UIExtender static UIExtender() { - // AutoGens are globally disabled for now. When the game will be released on Linux/OSX we'll reuse this property again. - //GauntletMoviePatch.Patch(Harmony); + GauntletMoviePatch.Patch(Harmony); ViewModelPatch.Patch(Harmony); - UIConfigPatch.Patch(Harmony); WidgetPrefabPatch.Patch(Harmony); BrushFactoryManager.Patch(Harmony); WidgetFactoryManager.Patch(Harmony); diff --git a/tests/Bannerlord.UIExtenderEx.Tests/Prefabs/IntegrationTests/PrefabsTests.cs b/tests/Bannerlord.UIExtenderEx.Tests/Prefabs/IntegrationTests/PrefabsTests.cs index 62e7b48d..119ac6af 100644 --- a/tests/Bannerlord.UIExtenderEx.Tests/Prefabs/IntegrationTests/PrefabsTests.cs +++ b/tests/Bannerlord.UIExtenderEx.Tests/Prefabs/IntegrationTests/PrefabsTests.cs @@ -34,7 +34,7 @@ public void Finalization() { _uiExtender?.Deregister(); } - + [Test] public void PrefabsInsertTest() { diff --git a/tests/Bannerlord.UIExtenderEx.Tests/Prefabs2/UnitTests/PrefabComponentPrefabs2Tests.cs b/tests/Bannerlord.UIExtenderEx.Tests/Prefabs2/UnitTests/PrefabComponentPrefabs2Tests.cs index e83dfefd..51b1090e 100644 --- a/tests/Bannerlord.UIExtenderEx.Tests/Prefabs2/UnitTests/PrefabComponentPrefabs2Tests.cs +++ b/tests/Bannerlord.UIExtenderEx.Tests/Prefabs2/UnitTests/PrefabComponentPrefabs2Tests.cs @@ -68,7 +68,7 @@ public void RegisterPatch_XmlDocument_InsertAsFirstChild() Assert.AreEqual("Children", validRootNode!.ParentNode!.Name); Assert.AreEqual("SomeChild", validRootNode.FirstChild.Name); Assert.AreEqual(validRootNode, validRootNode.ParentNode.FirstChild, $"First child should be ValidRoot. Was {validRootNode.ParentNode.FirstChild.Name}"); - + prefabComponent.Deregister(); } @@ -96,7 +96,7 @@ public void RegisterPatch_XmlNode_InsertAsMiddleChild() Assert.AreEqual("Children", validRootNode!.ParentNode!.Name); Assert.AreEqual("SomeChild", validRootNode.FirstChild.Name); Assert.AreEqual(validRootNode, validRootNode.ParentNode.ChildNodes[2], $"Third child should be ValidRoot. Was {validRootNode.ParentNode.FirstChild.Name}"); - + prefabComponent.Deregister(); } @@ -124,7 +124,7 @@ public void RegisterPatch_XmlNode_PassXmlDocumentAsXmlNode() Assert.AreEqual("Children", validRootNode!.ParentNode!.Name); Assert.AreEqual("SomeChild", validRootNode.FirstChild.Name); Assert.AreEqual(validRootNode, validRootNode.ParentNode.ChildNodes[2], $"Third child should be ValidRoot. Was {validRootNode.ParentNode.FirstChild.Name}"); - + prefabComponent.Deregister(); } @@ -150,7 +150,7 @@ public void RegisterPatch_Text_InsertAsLastChild() Assert.AreEqual("Children", validRootNode!.ParentNode!.Name); Assert.AreEqual("SomeChild", validRootNode.FirstChild.Name); Assert.AreEqual(validRootNode, validRootNode.ParentNode.ChildNodes[validRootNode.ParentNode.ChildNodes.Count - 1], $"Last child should be ValidRoot. Was {validRootNode.ParentNode.FirstChild.Name}"); - + prefabComponent.Deregister(); } @@ -177,7 +177,7 @@ public void RegisterPatch_Text_ReplaceRemoveRootNode() Assert.AreEqual(4, someChild1Node!.ParentNode!.ChildNodes.Count); Assert.AreEqual("SomeChild1", someChild1Node!.ParentNode!.ChildNodes[0].Name); Assert.AreEqual("SomeChild2", someChild1Node!.ParentNode!.ChildNodes[1].Name); - + prefabComponent.Deregister(); } @@ -203,7 +203,7 @@ public void RegisterPatch_FileName_InsertAsLastChild() Assert.AreEqual("Children", validRootNode!.ParentNode!.Name); Assert.AreEqual("SomeChild", validRootNode.FirstChild.Name); Assert.AreEqual(validRootNode, validRootNode.ParentNode.ChildNodes[validRootNode.ParentNode.ChildNodes.Count - 1], $"Last child should be ValidRoot. Was {validRootNode.ParentNode.FirstChild.Name}"); - + prefabComponent.Deregister(); } @@ -230,7 +230,7 @@ public void RegisterPatch_FileName_ReplaceRemoveRootNode() Assert.AreEqual(4, someChild1Node!.ParentNode!.ChildNodes.Count); Assert.AreEqual("SomeChild1", someChild1Node!.ParentNode!.ChildNodes[0].Name); Assert.AreEqual("SomeChild2", someChild1Node!.ParentNode!.ChildNodes[1].Name); - + prefabComponent.Deregister(); } @@ -260,7 +260,7 @@ public void RegisterPatch_XmlNodes_InsertMultipleChildren() Assert.AreEqual("Child1", child1Node.ParentNode.ChildNodes[0].Name, $"First child should be Child1. Was {child1Node.ParentNode.FirstChild.Name}"); Assert.AreEqual("Child2", child1Node.ParentNode.ChildNodes[1].Name, $"Second child should be Child2. Was {child1Node.ParentNode.FirstChild.Name}"); Assert.AreEqual("Child3", child1Node.ParentNode.ChildNodes[2].Name, $"Third child should be Child3. Was {child1Node.ParentNode.FirstChild.Name}"); - + prefabComponent.Deregister(); } @@ -294,7 +294,7 @@ public void RegisterPatch_XmlNodes_PassXmlDocumentsAsXmlNodes() Assert.AreEqual("Child1", child1Node.ParentNode.ChildNodes[0].Name, $"First child should be Child1. Was {child1Node.ParentNode.FirstChild.Name}"); Assert.AreEqual("Child2", child1Node.ParentNode.ChildNodes[1].Name, $"Second child should be Child2. Was {child1Node.ParentNode.FirstChild.Name}"); Assert.AreEqual("Child3", child1Node.ParentNode.ChildNodes[2].Name, $"Third child should be Child3. Was {child1Node.ParentNode.FirstChild.Name}"); - + prefabComponent.Deregister(); } @@ -325,7 +325,7 @@ public void RegisterPatch_RemoveComments_ChildComments() Assert.AreEqual("Children", validRootNode!.ParentNode!.Name); Assert.AreEqual("SomeChild", validRootNode.FirstChild.Name); Assert.AreEqual(validRootNode, validRootNode.ParentNode.FirstChild, $"First child should be ValidRoot. Was {validRootNode.ParentNode.FirstChild.Name}"); - + prefabComponent.Deregister(); } @@ -356,7 +356,7 @@ public void RegisterPatch_RemoveComments_RootComment() Assert.AreEqual("Children", validRootNode!.ParentNode!.Name); Assert.AreEqual("SomeChild", validRootNode.FirstChild.Name); Assert.AreEqual(validRootNode, validRootNode.ParentNode.FirstChild, $"First child should be ValidRoot. Was {validRootNode.ParentNode.FirstChild.Name}"); - + prefabComponent.Deregister(); } @@ -387,7 +387,7 @@ public void RegisterPatch_RemoveComments_FirstNodeRootComment() Assert.AreEqual("Children", validRootNode!.ParentNode!.Name); Assert.AreEqual("SomeChild", validRootNode.FirstChild.Name); Assert.AreEqual(validRootNode, validRootNode.ParentNode.FirstChild, $"First child should be ValidRoot. Was {validRootNode.ParentNode.FirstChild.Name}"); - + prefabComponent.Deregister(); } @@ -410,7 +410,7 @@ public void RegisterPatch_Remove() // Assert var removedNode = movieDocument.SelectSingleNode("descendant::OptionsScreenWidget[@Id='Options']"); Assert.IsNull(removedNode); - + prefabComponent.Deregister(); } } \ No newline at end of file diff --git a/tests/Bannerlord.UIExtenderEx.Tests/SharedTests.cs b/tests/Bannerlord.UIExtenderEx.Tests/SharedTests.cs index 751da2d2..c2c6c631 100644 --- a/tests/Bannerlord.UIExtenderEx.Tests/SharedTests.cs +++ b/tests/Bannerlord.UIExtenderEx.Tests/SharedTests.cs @@ -1,4 +1,4 @@ -using Bannerlord.UIExtenderEx.Tests.Prefabs2; +using Bannerlord.UIExtenderEx.Tests.Prefabs2; using HarmonyLib; using HarmonyLib.BUTR.Extensions; @@ -21,26 +21,26 @@ private static bool MockedGetBasePathPath(ref string __result) __result = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Assets"); return false; } - + private Harmony _harmony; - + [OneTimeSetUp] public void SharedOneTimeSetUp() { Trace.Listeners.Add(new ConsoleTraceListener()); - + _harmony = new Harmony($"{nameof(PrefabComponentPrefabs2Tests)}"); _harmony.Patch(SymbolExtensions2.GetMethodInfo(() => TaleWorlds.Engine.Utilities.GetBasePath()), prefix: new HarmonyMethod(typeof(PrefabComponentPrefabs2Tests), nameof(MockedGetBasePathPath))); _harmony.Patch(SymbolExtensions2.GetPropertyGetter(() => TaleWorlds.Library.BasePath.Name), prefix: new HarmonyMethod(typeof(PrefabComponentPrefabs2Tests), nameof(MockedGetBasePathPath))); } - + [OneTimeTearDown] public void SharedOneTimeTearDown() { Trace.Flush(); - + foreach (var patchedMethod in _harmony.GetPatchedMethods()) { if (patchedMethod is not MethodInfo patchedMethodInfo)