From 66bb4c8573855fa8d3762167902dbed2dfd088a6 Mon Sep 17 00:00:00 2001 From: ScaredKurufinve Date: Tue, 7 Mar 2023 01:40:42 +0300 Subject: [PATCH 01/35] Added a publicization for Owlcat.UI Please, fix my ugly formatting. --- ModMenu/ModMenu.csproj | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/ModMenu/ModMenu.csproj b/ModMenu/ModMenu.csproj index 6bd1eff..4eb70e4 100644 --- a/ModMenu/ModMenu.csproj +++ b/ModMenu/ModMenu.csproj @@ -52,7 +52,7 @@ $(WrathPath)\Wrath_Data\Managed\Assembly-CSharp-firstpass.dll - $(WrathPath)\Wrath_Data\Managed\Owlcat.Runtime.UI.dll + $(SolutionDir)lib\Owlcat.Runtime.UI_public.dll $(WrathPath)\Wrath_Data\Managed\Owlcat.Runtime.Validation.dll @@ -104,6 +104,23 @@ + + + + + + + + + + + + + + + + + From c27560939582a9ee605afe5556912c2eaf5db4b2 Mon Sep 17 00:00:00 2001 From: ScaredKurufinve Date: Tue, 7 Mar 2023 01:41:33 +0300 Subject: [PATCH 02/35] Changed the access modifier to an overriden method due to the publicization --- ModMenu/NewTypes/SettingsEntitySubHeader.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ModMenu/NewTypes/SettingsEntitySubHeader.cs b/ModMenu/NewTypes/SettingsEntitySubHeader.cs index aca4943..a199ae1 100644 --- a/ModMenu/NewTypes/SettingsEntitySubHeader.cs +++ b/ModMenu/NewTypes/SettingsEntitySubHeader.cs @@ -51,7 +51,7 @@ public override VirtualListLayoutElementSettings LayoutSettings } private VirtualListLayoutElementSettings m_LayoutSettings; - protected override int GetFontSize() + public override int GetFontSize() { return 110; } From 7d399f34f085630800210dd2198bd56b802824e2 Mon Sep 17 00:00:00 2001 From: ScaredKurufinve Date: Tue, 7 Mar 2023 01:41:41 +0300 Subject: [PATCH 03/35] Changed the access modifier to an overriden method due to the publicization --- ModMenu/NewTypes/SettingsEntityCollapsibleHeader.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ModMenu/NewTypes/SettingsEntityCollapsibleHeader.cs b/ModMenu/NewTypes/SettingsEntityCollapsibleHeader.cs index 09df7b9..f72b4d5 100644 --- a/ModMenu/NewTypes/SettingsEntityCollapsibleHeader.cs +++ b/ModMenu/NewTypes/SettingsEntityCollapsibleHeader.cs @@ -100,7 +100,7 @@ public override VirtualListLayoutElementSettings LayoutSettings public OwlcatMultiButton Button; public ExpandableCollapseMultiButtonPC ButtonPC; - protected override void BindViewImplementation() + public override void BindViewImplementation() { Title.text = UIUtility.GetSaberBookFormat(ViewModel.Tittle, size: GetFontSize()); Button.OnLeftClick.RemoveAllListeners(); @@ -108,8 +108,8 @@ protected override void BindViewImplementation() ViewModel.Init(ButtonPC); } - protected virtual int GetFontSize() { return 140; } + public virtual int GetFontSize() { return 140; } - protected override void DestroyViewImplementation() { } + public override void DestroyViewImplementation() { } } } From 9d78ab35ecb62d33224894c1d16730ea4999fe28 Mon Sep 17 00:00:00 2001 From: ScaredKurufinve Date: Tue, 7 Mar 2023 01:41:49 +0300 Subject: [PATCH 04/35] Changed the access modifier to an overriden method due to the publicization --- ModMenu/NewTypes/SettingsEntityImage.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ModMenu/NewTypes/SettingsEntityImage.cs b/ModMenu/NewTypes/SettingsEntityImage.cs index bd2cbdd..da07839 100644 --- a/ModMenu/NewTypes/SettingsEntityImage.cs +++ b/ModMenu/NewTypes/SettingsEntityImage.cs @@ -37,7 +37,7 @@ internal SettingsEntityImageVM(UISettingsEntityImage imageEntity) ImageScale = imageEntity.ImageScale; } - protected override void DisposeImplementation() { } + public override void DisposeImplementation() { } } internal class SettingsEntityImageView : VirtualListElementViewBase @@ -81,7 +81,7 @@ private void SetHeight(float height) public Image Icon; public GameObject TopBorder; - protected override void BindViewImplementation() + public override void BindViewImplementation() { Icon.sprite = ViewModel.Sprite; @@ -114,7 +114,7 @@ protected override void BindViewImplementation() SetHeight(height); } - protected override void DestroyViewImplementation() { } + public override void DestroyViewImplementation() { } } } From b72a53a96b7d820dc6186250d3e137f7416b80fc Mon Sep 17 00:00:00 2001 From: ScaredKurufinve Date: Tue, 7 Mar 2023 01:42:19 +0300 Subject: [PATCH 05/35] Added an empty Localized string to be used on several occasions --- ModMenu/Helpers.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/ModMenu/Helpers.cs b/ModMenu/Helpers.cs index e5d5c3a..4d4b911 100644 --- a/ModMenu/Helpers.cs +++ b/ModMenu/Helpers.cs @@ -14,6 +14,7 @@ namespace ModMenu internal static class Helpers { private static readonly List Strings = new(); + internal static LocalizedString EmptyString = CreateString("", ""); internal static LocalizedString CreateString(string key, string enGB, string ruRU = "") { From ec231c30a7b5a527120421efb9c980d129b10625 Mon Sep 17 00:00:00 2001 From: ScaredKurufinve Date: Tue, 7 Mar 2023 01:44:51 +0300 Subject: [PATCH 06/35] New wrapper ckass which contains UI Setting Groups and mod info to generate the description which will be displayed when you hover over the entry in the dropdown. Info may be auto-generate out of a Mod Entry or set manually. --- ModMenu/Settings/ModsMenuEntry.cs | 260 ++++++++++++++++++++++++++++++ 1 file changed, 260 insertions(+) create mode 100644 ModMenu/Settings/ModsMenuEntry.cs diff --git a/ModMenu/Settings/ModsMenuEntry.cs b/ModMenu/Settings/ModsMenuEntry.cs new file mode 100644 index 0000000..e861401 --- /dev/null +++ b/ModMenu/Settings/ModsMenuEntry.cs @@ -0,0 +1,260 @@ +using JetBrains.Annotations; +using Kingmaker.Designers; +using Kingmaker.Localization; +using Kingmaker.Localization.Shared; +using Kingmaker.Modding; +using Kingmaker.UI.SettingsUI; +using Kingmaker.UnitLogic.Abilities.Components.TargetCheckers; +using Kingmaker.Utility; +using Steamworks; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.Serialization; +using System.Text; +using System.Threading.Tasks; +using System.Xml.Linq; +using UnityEngine; +using UnityEngine.Rendering; + +namespace ModMenu.Settings +{ + public class ModsMenuEntry + { +#pragma warning disable CS1291 // stupid documentation requests +#pragma warning disable CS0618 // Method is obolete. I know! I made it obsolete! + internal static ModsMenuEntry EmptyInstance = new(new UISettingsGroup() { Title = new() { m_Key = "" }, SettingsList = Array.Empty() }); + + internal readonly IEnumerable ModSettings; + internal readonly Info ModInfo; + + internal ModsMenuEntry() => ModInfo = new(Helpers.EmptyString, Helpers.EmptyString); + + + [Obsolete("Please, use ModsMenuEntry(Info modInfo, UISettingsGroup settingGroup) instead. You will not be able to change ModInfo later.")] + public ModsMenuEntry([NotNull]UISettingsGroup settingGroup) + { + if (settingGroup is null) + { + throw new ModMenu_EmptySettingsGroupException(message: $"A null UISettingsGroup is trying to create a ModsMenuEntry out of itself without any additional mod info provided."); + } + + if (settingGroup.SettingsList.Length == 0) + { + string name = ("titled " + settingGroup.Title) ?? "without a title"; + throw new ModMenu_EmptySettingsGroupException(message: $"UISettingsGroup {name} is trying to create a ModsMenuEntry out of itself without any additional mod info provided."); + } + + + ModSettings = new UISettingsGroup[1] {settingGroup}; + ModInfo = new(settingGroup.Title); + AddToTheEntityList(); + } + + [Obsolete("Please, use ModsMenuEntry(Info modInfo, IEnumerable settingGroups) instead. You will not be able to change ModInfo later.")] + public ModsMenuEntry(IEnumerable settingGroups) + { + if (settingGroups is null || settingGroups.Count() == 0) + { + throw new ModMenu_EmptySettingsGroupException(message: $"A null list of UISettingsGroups is trying to create a ModsMenuEntry out of itself without any additional mod info provided."); + } + UISettingsGroup firstGroup = settingGroups.ElementAt(0); + + if (firstGroup is null) + { + throw new ModMenu_EmptySettingsGroupException(message: $"A null UISettingsGroup is trying to create a ModsMenuEntry out of itself without any additional mod info provided."); + } + + if (firstGroup.SettingsList.Length == 0) + { + string name = ("titled " + firstGroup.Title) ?? "without a title"; + throw new ModMenu_EmptySettingsGroupException(message: $"UISettingsGroup {name} is trying to create a ModsMenuEntry out of itself without any additional mod info provided."); + } + + + ModSettings = new UISettingsGroup[1] { firstGroup }; + ModInfo = new(firstGroup.Title); + AddToTheEntityList(); + } + + public ModsMenuEntry(Info modInfo, UISettingsGroup settingGroup) : this(settingGroup) + { + ModInfo = modInfo; + } + public ModsMenuEntry(Info modInfo, IEnumerable settingGroups) : this(settingGroups) + { + ModInfo = modInfo; + } + + public ModsMenuEntry(LocalizedString ModName, UISettingsGroup settingGroup) : this(settingGroup) + { + ModInfo = new(ModName); + } + + + + private void AddToTheEntityList() + { + ModsMenuEntity.ModEntries.Add(this); + } + + private class ModMenu_EmptySettingsGroupException : Exception + { + + internal ModMenu_EmptySettingsGroupException() + { + } + + internal ModMenu_EmptySettingsGroupException(string message) : base(message) + { + } + + internal ModMenu_EmptySettingsGroupException(string message, Exception inner) : base(message, inner) + { + } + + internal ModMenu_EmptySettingsGroupException(SerializationInfo info, StreamingContext context) : base(info, context) + { + } + } + + public struct Info + { + private static readonly LocalizedString AnonymousMod = Helpers.CreateString("ModsMenu.AnonymousMod", "Anonymous Mod", ruRU: "Безымянный мод"); + private static readonly LocalizedString stringAuthor = Helpers.CreateString("ModsMenu.stringAuthor", "Author", ruRU: "Создатель"); + private static readonly LocalizedString stringVer = Helpers.CreateString("ModsMenu.stringVer", "Version", ruRU: "Версия"); + private const string anonMod = "AnonymousMod"; + private static int AnonymousCounter = 0; + + public Info(LocalizedString Name, LocalizedString Description = null, string version = "", string author = "", Sprite image = null) + { + if (Name is null) ModName = AnonymousMod; + else ModName = Name; + VersionNumber = version; + AuthorName = author; + ModImage = image; + ModDescription = Description; + } + + public Info(string Name, string version = "", string author = "", Sprite image = null) : this((Name.IsNullOrEmpty() ? AnonymousMod : Helpers.CreateString($"ModsMenu.{Name}.Name", Name)), null, version, author, image) + { + + } + public Info(string Name, string Description, string version = "", string author = "", Sprite image = null) : this(Name, version, author, image) + { + if (Name.IsNullOrEmpty()) + { + Name = anonMod + AnonymousCounter; + AnonymousCounter++; + } + ModDescription = Helpers.CreateString($"ModsMenu.{Name}.Description", Description); + } + + public Info(OwlcatModification owlcatModification, bool allowModDisabling, LocalizedString LocalizedModName = null, LocalizedString LocalizedModDescription = null, Sprite image = null) + { + if (owlcatModification is null) + throw new ModMenu_EmptyModException("Attempt to create ModInfo out of a null OwlcatModification"); + OwlMod = owlcatModification; + AllowModDisabling = allowModDisabling; + OwlcatModificationManifest manifest = owlcatModification.Manifest; + AuthorName = manifest.Author; + VersionNumber = manifest.Version; + string uniqueName = manifest.UniqueName; + if (uniqueName.IsNullOrEmpty()) + { + uniqueName = "AnonymousMod" + AnonymousCounter; + AnonymousCounter++; + } + AuthorName = manifest.Author; + + if (LocalizedModName is not null && LocalizedModName.ToString().IsNullOrEmpty() is false) + ModName = LocalizedModName; + else if (manifest.DisplayName.IsNullOrEmpty() is false) + { + ModName = Helpers.CreateString($"ModsMenu.{uniqueName}.ModName", manifest.DisplayName); + } + else ModName = AnonymousMod; + if (LocalizedModDescription is not null && LocalizedModDescription.ToString().IsNullOrEmpty() is false) + ModDescription = LocalizedModDescription; + else if (manifest.Description.IsNullOrEmpty() is false) + { + ModDescription = Helpers.CreateString($"ModsMenu.{uniqueName}.Description", manifest.DisplayName); + } + + ModImage = image; + } + public Info(UnityModManagerNet.UnityModManager.ModEntry UMM_Mod, bool allowModDisabling, LocalizedString LocalizedModName = null, LocalizedString LocalizedModDescription = null, Sprite image = null) + { + if (UMM_Mod is null) + throw new ModMenu_EmptyModException("Attempt to create ModInfo out of a null UMM mod"); + UMMMod = UMM_Mod; + AllowModDisabling = allowModDisabling; + UnityModManagerNet.UnityModManager.ModInfo info = UMM_Mod.Info; + AuthorName = info.Author; + VersionNumber = info.Version; + string uniqueName = info.Id; + if (uniqueName.IsNullOrEmpty()) + { + uniqueName = "AnonymousMod" + AnonymousCounter; + AnonymousCounter++; + } + AuthorName = info.Author; + + if (LocalizedModName is not null && LocalizedModName.ToString().IsNullOrEmpty() is false) + ModName = LocalizedModName; + else if (info.DisplayName.IsNullOrEmpty() is false) + { + ModName = Helpers.CreateString($"ModsMenu.{uniqueName}.ModName", info.DisplayName); + } + else ModName = AnonymousMod; + if (LocalizedModDescription is not null && LocalizedModDescription.ToString().IsNullOrEmpty() is false) + ModDescription = LocalizedModDescription; + + ModImage = image; + } + + public Sprite ModImage { get; private set; } + public LocalizedString ModName { get; private set; } + public string VersionNumber { get; private set; } + public string AuthorName { get; private set; } + public LocalizedString ModDescription { get; private set; } + internal bool AllowModDisabling { get; set; } + internal OwlcatModification OwlMod { get; } + internal UnityModManagerNet.UnityModManager.ModEntry UMMMod { get; } + + internal string GenerateName() + { + string result = ModName; + if (!string.IsNullOrEmpty(VersionNumber)) result = $"{result} ({stringVer}: {VersionNumber})"; + result = $"{result}\n"; + if (!string.IsNullOrEmpty(AuthorName)) result = string.Concat(result, $"{stringAuthor}: {AuthorName}\n"); + string.Concat(result, ModDescription); + + return result; + } + + + private class ModMenu_EmptyModException : Exception + { + + internal ModMenu_EmptyModException() + { + } + + internal ModMenu_EmptyModException(string message) : base(message) + { + } + + internal ModMenu_EmptyModException(string message, Exception inner) : base(message, inner) + { + } + + internal ModMenu_EmptyModException(SerializationInfo info, StreamingContext context) : base(info, context) + { + } + } + + } + + } +} From 8c77f2a93044cbdd6a5e7ccc669d538d2eb810c8 Mon Sep 17 00:00:00 2001 From: ScaredKurufinve Date: Tue, 7 Mar 2023 01:48:17 +0300 Subject: [PATCH 07/35] New Setting Entity class with a ModsmenuEntry as a possible setting - on value changed redraws the setting screen to display settings of the chosen mod. --- .../NewTypes/SettingsEntityModsmenuEntry.cs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 ModMenu/NewTypes/SettingsEntityModsmenuEntry.cs diff --git a/ModMenu/NewTypes/SettingsEntityModsmenuEntry.cs b/ModMenu/NewTypes/SettingsEntityModsmenuEntry.cs new file mode 100644 index 0000000..9b37f1e --- /dev/null +++ b/ModMenu/NewTypes/SettingsEntityModsmenuEntry.cs @@ -0,0 +1,18 @@ +using Kingmaker.Settings; +using ModMenu.Settings; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ModMenu.NewTypes +{ + internal class SettingsEntityModsmenuEntry : SettingsEntity + { + internal static SettingsEntityModsmenuEntry instance = new("modsmenu.entrystaticinstance", ModsMenuEntry.EmptyInstance); + + public SettingsEntityModsmenuEntry(string key, ModsMenuEntry defaultValue) : base(key, defaultValue, false, false, false) + => OnTempValueChanged += new(() => { ModsMenuEntity.settingVM.SwitchSettingsScreen(ModsMenuEntity.SettingsScreenId); return true; }); + } +} From 4860f08325dd39916921ce78ccd503a49655e390 Mon Sep 17 00:00:00 2001 From: ScaredKurufinve Date: Tue, 7 Mar 2023 01:50:41 +0300 Subject: [PATCH 08/35] Changed a postfix of the Switch Settings Screen to a boolean Prefix returning false. I intended to add a toggle setting allowing to disable the mod at run-time (there's a field in mod info for that), but then realized it won't be possible to properly enable it back after reloading. --- ModMenu/NewTypes/SettingsEntityPatches.cs | 44 +++++++++++++++++++++-- 1 file changed, 42 insertions(+), 2 deletions(-) diff --git a/ModMenu/NewTypes/SettingsEntityPatches.cs b/ModMenu/NewTypes/SettingsEntityPatches.cs index 7527315..35c228a 100644 --- a/ModMenu/NewTypes/SettingsEntityPatches.cs +++ b/ModMenu/NewTypes/SettingsEntityPatches.cs @@ -72,7 +72,47 @@ static bool Prefix( return true; } - [HarmonyPatch(nameof(SettingsVM.SwitchSettingsScreen)), HarmonyPostfix] + [HarmonyPatch(nameof(SettingsVM.SwitchSettingsScreen)), HarmonyPrefix] + static bool Prefix(UISettingsManager.SettingsScreen settingsScreen, SettingsVM __instance) + { + if (settingsScreen != ModsMenuEntity.SettingsScreenId) return true; + try + { + Main.Logger.NativeLog("Collecting setting entities."); + + __instance.m_SettingEntities.Clear(); + __instance.m_SettingEntities.Add(__instance.AddDisposableAndReturn(SettingsVM.GetVMForSettingsItem(UISettingsEntityDropdownModsmenuEntry.instance))); + __instance.m_SettingEntities.Add(__instance.AddDisposableAndReturn(SettingsVM.GetVMForSettingsItem(new UISettingsEntitySeparator()))); + + //Here should be a toggle for mod disabling, but do we need it? + SettingsEntitySubHeaderVM subheader; + foreach (var uisettingsGroup in ModsMenuEntity.CollectSettingGroups) + { + __instance.m_SettingEntities.Add(__instance.AddDisposableAndReturn(new SettingsEntityCollapsibleHeaderVM(uisettingsGroup.Title))); + subheader = null; + foreach (UISettingsEntityBase uisettingsEntityBase in uisettingsGroup.VisibleSettingsList) + { + if (uisettingsEntityBase is UISettingsEntitySubHeader sub) + { + subheader = new SettingsEntitySubHeaderVM(sub); + __instance.m_SettingEntities.Add(__instance.AddDisposableAndReturn(subheader)); + continue; + } + VirtualListElementVMBase element = __instance.AddDisposableAndReturn(SettingsVM.GetVMForSettingsItem(uisettingsEntityBase)); + __instance.m_SettingEntities.Add(element); + subheader?.SettingsInGroup.Add(element); + } + } + + } + catch (Exception e) + { + Main.Logger.LogException("SettingsVM.SwitchSettingsScreen", e); + } + return false; + } + + /*[HarmonyPatch(nameof(SettingsVM.SwitchSettingsScreen)), HarmonyPostfix] static void Postfix(UISettingsManager.SettingsScreen settingsScreen, SettingsVM __instance) { try @@ -111,7 +151,7 @@ static void Postfix(UISettingsManager.SettingsScreen settingsScreen, SettingsVM { Main.Logger.LogException("SettingsVM.SwitchSettingsScreen", e); } - } + }*/ } /// From 84ca27ab9e1cee0c4351b6a7de2a4b9a61dcb204 Mon Sep 17 00:00:00 2001 From: ScaredKurufinve Date: Tue, 7 Mar 2023 01:55:23 +0300 Subject: [PATCH 09/35] New UI Settings Dropdown - the main feature of the PR. I did not add any new VM and expect it to work correctly with the default dropdown. --- .../UISettingsEntityDropDownModsmenuEntry.cs | 45 +++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 ModMenu/NewTypes/UISettingsEntityDropDownModsmenuEntry.cs diff --git a/ModMenu/NewTypes/UISettingsEntityDropDownModsmenuEntry.cs b/ModMenu/NewTypes/UISettingsEntityDropDownModsmenuEntry.cs new file mode 100644 index 0000000..3e5ab32 --- /dev/null +++ b/ModMenu/NewTypes/UISettingsEntityDropDownModsmenuEntry.cs @@ -0,0 +1,45 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Kingmaker.UI.SettingsUI; +using ModMenu.Settings; +using UnityEngine; + +namespace ModMenu.NewTypes +{ + internal class UISettingsEntityDropdownModsmenuEntry : UISettingsEntityDropdown + { + static UISettingsEntityDropdownModsmenuEntry() + { + instance.LinkSetting(SettingsEntityModsmenuEntry.instance); + } + internal static UISettingsEntityDropdownModsmenuEntry instance = ScriptableObject.CreateInstance(); + public override List LocalizedValues + { + get + { + return ModsMenuEntity.ModEntries.Select(entry => entry.ModInfo.GenerateName()).ToList(); + } + } + + public override int GetIndexTempValue() + { + return ModsMenuEntity.ModEntries.IndexOf(Setting.GetTempValue()); + } + + + public override void SetIndexTempValue(int value) + { + if (value is < 0 && value > ModsMenuEntity.ModEntries.Count()) + { + Main.Logger.Error($"Value {value} is given to UISettingsEntityDropdownModsmenuEntry when there're only {ModsMenuEntity.ModEntries.Count()} entries in the list"); + SetTempValue(ModsMenuEntity.ModEntries[0]); + } + + SetTempValue(ModsMenuEntity.ModEntries[value]); + } + + } +} From 3548809fcc83529a3411fe0162c8b6e858ef6a5d Mon Sep 17 00:00:00 2001 From: ScaredKurufinve Date: Tue, 7 Mar 2023 01:56:29 +0300 Subject: [PATCH 10/35] Updated the Builder to add new functionality. ATTENTION - Build() function gotthe signature changed, it now returns generated mod info among other things --- ModMenu/Settings/SettingsBuilder.cs | 152 ++++++++++++++++++++++++++-- 1 file changed, 145 insertions(+), 7 deletions(-) diff --git a/ModMenu/Settings/SettingsBuilder.cs b/ModMenu/Settings/SettingsBuilder.cs index 254c2f1..18808e1 100644 --- a/ModMenu/Settings/SettingsBuilder.cs +++ b/ModMenu/Settings/SettingsBuilder.cs @@ -1,5 +1,6 @@ using Kingmaker; using Kingmaker.Localization; +using Kingmaker.Modding; using Kingmaker.PubSubSystem; using Kingmaker.Settings; using Kingmaker.UI; @@ -70,7 +71,15 @@ namespace ModMenu.Settings /// public class SettingsBuilder { - private readonly UISettingsGroup Group = ScriptableObject.CreateInstance(); + private object mod; + private bool allowDisabling; + private LocalizedString modName; + private LocalizedString modDescription; + private string Author = ""; + private string Version = ""; + private Sprite modIllustration; + private readonly List GroupList = new(); + private UISettingsGroup Group; // it will be now initialized by the instance constructor through a call to AddAnotherSettingsGroup. private readonly List Settings = new(); private readonly Dictionary SettingsEntities = new(); private Action OnDefaultsApplied; @@ -81,13 +90,99 @@ public class SettingsBuilder /// Title of the settings group, displayed on the settings page public static SettingsBuilder New(string key, LocalizedString title) { - return new(key, title); + return new SettingsBuilder(key, title); } - public SettingsBuilder(string key, LocalizedString title) + /// + /// Globally unique key / name for the settings group. Use only lowercase letters, numbers, '-', and '.' + /// + /// Title of the settings group, displayed on the settings page + public SettingsBuilder(string key, LocalizedString title) : this() + { + AddAnotherSettingsGroup(key, title); + } + + private SettingsBuilder() + { + + } + + + /// + /// Creates a new group of settings. + /// + /// + /// Globally unique key / name for the settings group. Use only lowercase letters, numbers, '-', and '.' + /// + /// Title of the settings group, displayed on the settings page + public SettingsBuilder AddAnotherSettingsGroup(string key, LocalizedString title) + { + if (GroupList.Any() && GroupList.Any(g => g.name.Equals(key))) + Main.Logger.Warning("An attempt to create a new Settings group with an existing key"); + + var group = ScriptableObject.CreateInstance(); + group.name = key; + group.Title= title; + if (Settings?.Count > 0) Group.SettingsList = Settings.ToArray(); + GroupList.Add(group); + Group = group; + return this; + } + + /// + /// Set a source mod for your settings. Information from the manifest / info will be displayed when selecting the mod in the menu dropdown. + /// If you don't set Mod name and Mod description separately, the information from the manifest / info will be used instead. + /// Providing the source mod is necessary if you want to allow disabling from the ModMenu. + /// + /// + /// Your mod + /// + /// Set to true if you want to create a button to disable it + /// + public SettingsBuilder SetMod(OwlcatModification modEntry, bool AllowDisabling = false) + { + mod = modEntry; + allowDisabling = AllowDisabling; + return this; + } + + /// + /// Set a source mod for your settings. Information from the manifest / info will be displayed when selecting the mod in the menu dropdown. + /// If you don't set Mod name and Mod description separately, the information from the manifest / info will be used instead. + /// Providing the source mod is necessary if you want to allow disabling from the ModMenu. + /// + /// + /// Your mod + /// + /// Set to true if you want to create a button to disable it + /// + public SettingsBuilder SetMod(UnityModManagerNet.UnityModManager.ModEntry modEntry, bool AllowDisabling = false) + { + mod = modEntry; + allowDisabling = AllowDisabling; + return this; + } + + /// + /// The name of your mod to be displayed in the ModMenu dropdown. + /// + /// - a Localized string containing the mod name. + /// + public SettingsBuilder SetModName(LocalizedString name) + { + modName = name; + return this; + } + + /// + /// Sets the description for your mod which will be visible when hovering the mouse over the mod entry in the ModMenu dropdown. + /// + /// - a Localized string containing the description. + /// + public SettingsBuilder SetModDescription(LocalizedString description) { - Group.name = key.ToLower(); - Group.Title = title; + modDescription = description; + return this; } /// @@ -108,6 +203,44 @@ public SettingsBuilder AddImage(Sprite sprite, int height, float imageScale) return AddImageInternal(sprite, height, imageScale); } + /// + /// Adds mod's version to the mod description shown when you hover the mouse over the mod entry in the ModMenu dropdown + /// + /// + /// Will be displayed only if you at least provided a Localized mod name with . + /// Mod version from the source mod info (if set with + /// or with ) will have higher precedence + public SettingsBuilder SetModVersion(string version) + { + Version = version; + return this; + } + + /// + /// Adds author's name mod description shown when you hover the mouse over the mod entry in the ModMenu dropdown + /// + /// + /// Will be displayed only if you at least provided a Localized mod name with . + /// Author's name from the source mod info (if set with + /// or with ) will have higher precedence. + public SettingsBuilder SetModAuthor(string author) + { + Author = author; + return this; + } + + /// + /// Adds an image to the mod description shown when you hover the mouse over the mod entry in the ModMenu dropdown + /// + /// + /// Will be displayed only if you have a source mod info (if set with + /// or with ) or at least provided a Localized mod name with . + public SettingsBuilder SetModIllustration(Sprite image) + { + modIllustration = image; + return this; + } + /// /// Adds a row containing an image. There is no setting tied to this, it is just for decoration. /// @@ -278,10 +411,15 @@ private SettingsBuilder Add(string key, ISettingsEntity entity, UISettingsEntity return this; } - internal (UISettingsGroup group, Dictionary settings) Build() + internal (List groups, Dictionary settings, ModsMenuEntry.Info info) Build() { Group.SettingsList = Settings.ToArray(); - return (Group, SettingsEntities); + ModsMenuEntry.Info Info; + if (mod is OwlcatModification OwlMod) Info = new(OwlMod, allowDisabling, modName, modDescription, modIllustration); + else if (mod is UnityModManagerNet.UnityModManager.ModEntry UMMmod) Info = new(UMMmod, allowDisabling, modName, modDescription, modIllustration); + else if (modName is not null) Info = new(modName, modDescription, Version, Author, modIllustration); + else Info = default; + return (GroupList, SettingsEntities, Info); } private void OpenDefaultSettingsDialog() From d07416d88d73ad9261e5bdd58706863c56681f58 Mon Sep 17 00:00:00 2001 From: ScaredKurufinve Date: Tue, 7 Mar 2023 01:57:26 +0300 Subject: [PATCH 11/35] Changed the AddSettings functions to fit the new reality --- ModMenu/Settings/ModsMenuEntity.cs | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/ModMenu/Settings/ModsMenuEntity.cs b/ModMenu/Settings/ModsMenuEntity.cs index 7cd78e8..e91f418 100644 --- a/ModMenu/Settings/ModsMenuEntity.cs +++ b/ModMenu/Settings/ModsMenuEntity.cs @@ -4,8 +4,10 @@ using Kingmaker.UI.MVVM._VM.Settings; using Kingmaker.UI.SettingsUI; using Kingmaker.Utility; +using ModMenu.NewTypes; using System; using System.Collections.Generic; +using System.Linq; using System.Reflection; using System.Reflection.Emit; @@ -20,6 +22,7 @@ internal class ModsMenuEntity private const int SettingsScreenValue = 17; internal static readonly UISettingsManager.SettingsScreen SettingsScreenId = (UISettingsManager.SettingsScreen)SettingsScreenValue; + internal static SettingsVM settingVM; private static LocalizedString _menuTitleString; private static LocalizedString MenuTitleString @@ -33,12 +36,29 @@ private static LocalizedString MenuTitleString } private static readonly List ModSettings = new(); + internal static readonly List ModEntries = new(); +#pragma warning disable CS0618 // Obsolete method which I myself marked as obsolete >_> internal static void Add(UISettingsGroup uiSettingsGroup) { - ModSettings.Add(uiSettingsGroup); + ModEntries.Add(new(uiSettingsGroup)); } + internal static void Add(List uiSettingsGroup) + { + ModEntries.Add(new(uiSettingsGroup)); + } +#pragma warning restore CS0618 // Тип или член устарел + + internal static void Add(ModsMenuEntry modEntry) + { + ModEntries.Add(modEntry); + } + + + internal static IEnumerable CollectSettingGroups => UISettingsEntityDropdownModsmenuEntry.instance.Setting.m_CurrentValue.ModSettings; + + /// /// Patch to create the Mods Menu ViewModel. /// @@ -85,6 +105,7 @@ private static void AddMenuEntity(SettingsVM settings) try { settings.CreateMenuEntity(MenuTitleString, SettingsScreenId); + settingVM = settings; Main.Logger.NativeLog("Added Mods Menu ViewModel."); } catch (Exception e) @@ -137,7 +158,7 @@ static void Postfix(UISettingsManager.SettingsScreen? screenId, ref List Date: Tue, 7 Mar 2023 01:58:20 +0300 Subject: [PATCH 12/35] added a local variable to store the modEntry so that it can be used to auto-generate ModInfo in TestSettings --- ModMenu/Main.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/ModMenu/Main.cs b/ModMenu/Main.cs index 665ae0f..9c5c256 100644 --- a/ModMenu/Main.cs +++ b/ModMenu/Main.cs @@ -10,6 +10,7 @@ namespace ModMenu public static class Main { internal static ModLogger Logger; + internal static ModEntry Entry; private static Harmony Harmony; public static bool Load(ModEntry modEntry) From 106f6d8668ab5d73307e0152e1c4eb6ef9304e9d Mon Sep 17 00:00:00 2001 From: ScaredKurufinve Date: Tue, 7 Mar 2023 01:59:20 +0300 Subject: [PATCH 13/35] Changed the whole AddSettings stuff to fit the new reality --- ModMenu/ModMenu.cs | 59 +++++++++++++++++++++++++++++++++++++++------- 1 file changed, 50 insertions(+), 9 deletions(-) diff --git a/ModMenu/ModMenu.cs b/ModMenu/ModMenu.cs index 3f1c4fd..4c1b6b4 100644 --- a/ModMenu/ModMenu.cs +++ b/ModMenu/ModMenu.cs @@ -1,4 +1,5 @@ using Kingmaker.Settings; +using Kingmaker.UI.SaveLoadWindow; using Kingmaker.UI.SettingsUI; using ModMenu.Settings; using System; @@ -25,8 +26,8 @@ public static class ModMenu /// public static void AddSettings(SettingsBuilder settings) { - var settingsGroup = settings.Build(); - foreach (var setting in settingsGroup.settings) + var result = settings.Build(); + foreach (var setting in result.settings) { if (Settings.ContainsKey(setting.Key)) { @@ -35,17 +36,18 @@ public static void AddSettings(SettingsBuilder settings) } Settings.Add(setting.Key, setting.Value); } - ModsMenuEntity.Add(settingsGroup.group); + ModsMenuEntity.Add(new ModsMenuEntry(result.info, result.groups)); } /// - /// Adds a new group of settings to the Mods menu page. + /// Adds a new entry containing the group of settings to the Mods menu dropdown. + /// Group's title will be displayed instead of the mod name. /// /// /// /// /// Using is recommended. If you prefer to construct the settings - /// on your own you can use this method. + /// on your own you can use this method, but better choose a less deprecated overload using ModsMenuEntry. /// /// /// @@ -53,10 +55,49 @@ public static void AddSettings(SettingsBuilder settings) /// . /// /// - public static void AddSettings(UISettingsGroup settingsGroup) - { - ModsMenuEntity.Add(settingsGroup); - } + [Obsolete("Please, use AddSettings(ModsMenuEntry entry) instead")] + public static void AddSettings(UISettingsGroup settingsGroup) => ModsMenuEntity.Add(settingsGroup); + + + + /// + /// Adds a new entry containing groups of settings to the Mods menu dropdown. + /// The title of the first group will displayed instead of the mod name + /// + /// + /// + /// + /// Using is recommended. If you prefer to construct the settings + /// on your own you can use this method, but better choose a less deprecated overload using ModsMenuEntry. + /// + /// + /// + /// Settings added in this way cannot be retrieved using or + /// . + /// + /// + [Obsolete("Please, use AddSettings(ModsMenuEntry entry) instead")] + public static void AddSettings(List settingsGroup) => ModsMenuEntity.Add(settingsGroup); + + + /// + /// Adds a new entry containing groups of settings to the Mods menu page. + /// + /// + /// + /// + /// Use this method if you prefer to construct settings on your own you can use this method + /// instead of using the recommended . + /// + /// + /// + /// Settings added in this way cannot be retrieved using or + /// . + /// + /// + public static void AddSetting(ModsMenuEntry entry) => ModsMenuEntity.Add(entry); + + /// /// The setting with the specified , or null if it does not exist or has the wrong type. From 6f75187f4aa48ae218e354e125825ca7f96be672 Mon Sep 17 00:00:00 2001 From: ScaredKurufinve Date: Tue, 7 Mar 2023 02:00:23 +0300 Subject: [PATCH 14/35] Added new methods to Test Settings. In particualar, concatenate test settings and extra settings into a single mod entry thhrough AddAnotherGroup --- ModMenu/Settings/TestSettings.cs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/ModMenu/Settings/TestSettings.cs b/ModMenu/Settings/TestSettings.cs index 9a99bfe..cf4b6a8 100644 --- a/ModMenu/Settings/TestSettings.cs +++ b/ModMenu/Settings/TestSettings.cs @@ -27,6 +27,7 @@ internal void Initialize() { ModMenu.AddSettings( SettingsBuilder.New(RootKey, CreateString("title", "Testing settings")) + .SetMod(Main.Entry) .AddImage(Helpers.CreateSprite("ModMenu.WittleWolfie.png"), 250) .AddDefaultButton(OnDefaultsApplied) .AddButton( @@ -83,10 +84,8 @@ internal void Initialize() CreateString("int-desc", "This is a custom int slider"), minValue: 1, maxValue: 6) - .HideValueText())); - - ModMenu.AddSettings( - SettingsBuilder.New(GetKey("extra"), CreateString("extra-title", "More Test Settings")) + .HideValueText()) + .AddAnotherSettingsGroup(GetKey("extra"), CreateString("extra-title", "More Test Settings")) .AddDefaultButton() .AddToggle( Toggle.New( From fe892a588bc0538d09e0d5e6403ca93c88697e2c Mon Sep 17 00:00:00 2001 From: ScaredKurufinve Date: Thu, 9 Mar 2023 23:13:54 +0300 Subject: [PATCH 15/35] Some changes. Realized I was giving the mod description instead of the mod name to the dropdown. Moved the call to redraw the screen from the setting itself to the UISetting. Deleted a duplicated call to add a ModEntry to the list of entries. Added a bunch of summaries --- .../NewTypes/SettingsEntityModsmenuEntry.cs | 4 +- .../UISettingsEntityDropDownModsmenuEntry.cs | 3 +- ModMenu/Settings/ModsMenuEntry.cs | 155 +++++++++++------- 3 files changed, 95 insertions(+), 67 deletions(-) diff --git a/ModMenu/NewTypes/SettingsEntityModsmenuEntry.cs b/ModMenu/NewTypes/SettingsEntityModsmenuEntry.cs index 9b37f1e..b4b1cd0 100644 --- a/ModMenu/NewTypes/SettingsEntityModsmenuEntry.cs +++ b/ModMenu/NewTypes/SettingsEntityModsmenuEntry.cs @@ -11,8 +11,6 @@ namespace ModMenu.NewTypes internal class SettingsEntityModsmenuEntry : SettingsEntity { internal static SettingsEntityModsmenuEntry instance = new("modsmenu.entrystaticinstance", ModsMenuEntry.EmptyInstance); - - public SettingsEntityModsmenuEntry(string key, ModsMenuEntry defaultValue) : base(key, defaultValue, false, false, false) - => OnTempValueChanged += new(() => { ModsMenuEntity.settingVM.SwitchSettingsScreen(ModsMenuEntity.SettingsScreenId); return true; }); + public SettingsEntityModsmenuEntry(string key, ModsMenuEntry defaultValue) : base(key, defaultValue, false, false, false) {} } } diff --git a/ModMenu/NewTypes/UISettingsEntityDropDownModsmenuEntry.cs b/ModMenu/NewTypes/UISettingsEntityDropDownModsmenuEntry.cs index 3e5ab32..0ce263c 100644 --- a/ModMenu/NewTypes/UISettingsEntityDropDownModsmenuEntry.cs +++ b/ModMenu/NewTypes/UISettingsEntityDropDownModsmenuEntry.cs @@ -13,6 +13,7 @@ internal class UISettingsEntityDropdownModsmenuEntry : UISettingsEntityDropdown< { static UISettingsEntityDropdownModsmenuEntry() { + instance.OnTempIndexValueChanged += new Action(ModIndex => ModsMenuEntity.settingVM.SwitchSettingsScreen(ModsMenuEntity.SettingsScreenId)); instance.LinkSetting(SettingsEntityModsmenuEntry.instance); } internal static UISettingsEntityDropdownModsmenuEntry instance = ScriptableObject.CreateInstance(); @@ -20,7 +21,7 @@ public override List LocalizedValues { get { - return ModsMenuEntity.ModEntries.Select(entry => entry.ModInfo.GenerateName()).ToList(); + return ModsMenuEntity.ModEntries.Select(entry => entry.ModInfo.ModName.ToString()).ToList(); } } diff --git a/ModMenu/Settings/ModsMenuEntry.cs b/ModMenu/Settings/ModsMenuEntry.cs index e861401..4019517 100644 --- a/ModMenu/Settings/ModsMenuEntry.cs +++ b/ModMenu/Settings/ModsMenuEntry.cs @@ -1,12 +1,8 @@ using JetBrains.Annotations; -using Kingmaker.Designers; using Kingmaker.Localization; -using Kingmaker.Localization.Shared; using Kingmaker.Modding; using Kingmaker.UI.SettingsUI; -using Kingmaker.UnitLogic.Abilities.Components.TargetCheckers; using Kingmaker.Utility; -using Steamworks; using System; using System.Collections.Generic; using System.Linq; @@ -15,13 +11,15 @@ using System.Threading.Tasks; using System.Xml.Linq; using UnityEngine; -using UnityEngine.Rendering; namespace ModMenu.Settings { + /// + /// Wrapper class used to display mod's settings in the ModMenu dropdown. Contains a list of UI Setting Groups and modification's info such as name + /// public class ModsMenuEntry { -#pragma warning disable CS1291 // stupid documentation requests +#pragma warning disable CS1591 // stupid documentation requests #pragma warning disable CS0618 // Method is obolete. I know! I made it obsolete! internal static ModsMenuEntry EmptyInstance = new(new UISettingsGroup() { Title = new() { m_Key = "" }, SettingsList = Array.Empty() }); @@ -29,8 +27,13 @@ public class ModsMenuEntry internal readonly Info ModInfo; internal ModsMenuEntry() => ModInfo = new(Helpers.EmptyString, Helpers.EmptyString); - + + /// + /// Creates a simpliest ModEntry out of a single UI setting group. + /// Mod entry will use the group's title as displayed name or will be called anonymous if title is empty + /// + /// You can't create a ModEntry out of a null settings group ¯\_(ツ)_/¯ [Obsolete("Please, use ModsMenuEntry(Info modInfo, UISettingsGroup settingGroup) instead. You will not be able to change ModInfo later.")] public ModsMenuEntry([NotNull]UISettingsGroup settingGroup) { @@ -48,9 +51,13 @@ public ModsMenuEntry([NotNull]UISettingsGroup settingGroup) ModSettings = new UISettingsGroup[1] {settingGroup}; ModInfo = new(settingGroup.Title); - AddToTheEntityList(); } + /// + /// Creates a ModEntry out of a several UI setting group. + /// Mod entry will use the first group's title as displayed name or will be called anonymous if title is empty + /// + /// settingGroups argument must not be null, have at least 1 group in it and none of groups can be null [Obsolete("Please, use ModsMenuEntry(Info modInfo, IEnumerable settingGroups) instead. You will not be able to change ModInfo later.")] public ModsMenuEntry(IEnumerable settingGroups) { @@ -58,12 +65,12 @@ public ModsMenuEntry(IEnumerable settingGroups) { throw new ModMenu_EmptySettingsGroupException(message: $"A null list of UISettingsGroups is trying to create a ModsMenuEntry out of itself without any additional mod info provided."); } - UISettingsGroup firstGroup = settingGroups.ElementAt(0); - - if (firstGroup is null) + if (settingGroups.Any(g => g is null)) { - throw new ModMenu_EmptySettingsGroupException(message: $"A null UISettingsGroup is trying to create a ModsMenuEntry out of itself without any additional mod info provided."); + throw new ModMenu_EmptySettingsGroupException(message: $"A list of UISettingsGroups is trying to create a ModsMenuEntry out of itself, but contains a null group."); } + UISettingsGroup firstGroup = settingGroups.ElementAt(0); + if (firstGroup.SettingsList.Length == 0) { @@ -74,7 +81,6 @@ public ModsMenuEntry(IEnumerable settingGroups) ModSettings = new UISettingsGroup[1] { firstGroup }; ModInfo = new(firstGroup.Title); - AddToTheEntityList(); } public ModsMenuEntry(Info modInfo, UISettingsGroup settingGroup) : this(settingGroup) @@ -86,18 +92,17 @@ public ModsMenuEntry(Info modInfo, IEnumerable settingGroups) : ModInfo = modInfo; } - public ModsMenuEntry(LocalizedString ModName, UISettingsGroup settingGroup) : this(settingGroup) + /// + /// Creates a simple ModEntry out of a single UI setting group. + /// > + /// Name of your mod which will be displayed in the ModMenu dropdown. If you don't provide any, it will displayed as Anonymous + /// + /// You can't create a ModEntry out of a null settings group ¯\_(ツ)_/¯ + public ModsMenuEntry( LocalizedString ModName, [NotNull]UISettingsGroup settingGroup) : this(settingGroup) { ModInfo = new(ModName); } - - - private void AddToTheEntityList() - { - ModsMenuEntity.ModEntries.Add(this); - } - private class ModMenu_EmptySettingsGroupException : Exception { @@ -118,6 +123,9 @@ internal ModMenu_EmptySettingsGroupException(SerializationInfo info, StreamingCo } } + /// + /// Structure containing information required to display the ModEntry in the ModMenu dropdown (such as mod's info) + /// public struct Info { private static readonly LocalizedString AnonymousMod = Helpers.CreateString("ModsMenu.AnonymousMod", "Anonymous Mod", ruRU: "Безымянный мод"); @@ -126,6 +134,25 @@ public struct Info private const string anonMod = "AnonymousMod"; private static int AnonymousCounter = 0; + public Sprite ModImage { get; private set; } + public LocalizedString ModName { get; private set; } + public string VersionNumber { get; private set; } + public string AuthorName { get; private set; } + public LocalizedString LocalizedModDescription { get; private set; } + public string NonLocalizedModDescription { get; private set; } + internal bool AllowModDisabling { get; set; } + internal OwlcatModification OwlMod { get; } + internal UnityModManagerNet.UnityModManager.ModEntry UMMMod { get; } + + + + /// + /// + /// Name of your mod which will be displayed in the ModMenu dropdown. If you don't provide any, it will displayed as Anonymous + /// Description which will be displayed when user selects your mod in ModMenu dropdown + /// Mod version to be displayed alongside the description + /// Mod author's name to be displayed alongside the description + /// Mod's icon to be displayed alongside the description public Info(LocalizedString Name, LocalizedString Description = null, string version = "", string author = "", Sprite image = null) { if (Name is null) ModName = AnonymousMod; @@ -133,24 +160,36 @@ public Info(LocalizedString Name, LocalizedString Description = null, string ver VersionNumber = version; AuthorName = author; ModImage = image; - ModDescription = Description; + LocalizedModDescription = Description; } - public Info(string Name, string version = "", string author = "", Sprite image = null) : this((Name.IsNullOrEmpty() ? AnonymousMod : Helpers.CreateString($"ModsMenu.{Name}.Name", Name)), null, version, author, image) - { - - } - public Info(string Name, string Description, string version = "", string author = "", Sprite image = null) : this(Name, version, author, image) + /// + /// + /// Name of your mod which will be displayed in the ModMenu dropdown. If you don't provide any, it will displayed as Anonymous + /// Description which will be displayed when user selects your mod in ModMenu dropdown + /// Mod version to be displayed alongside the description + /// Mod author's name to be displayed alongside the description + /// Mod's icon to be displayed alongside the description + public Info(string Name, string Description = "", string version = "", string author = "", Sprite image = null) : this(Helpers.CreateString($"ModsMenu.{Name}.Name", Name), null, version, author, image) { if (Name.IsNullOrEmpty()) { Name = anonMod + AnonymousCounter; AnonymousCounter++; } - ModDescription = Helpers.CreateString($"ModsMenu.{Name}.Description", Description); + NonLocalizedModDescription = Description; } - public Info(OwlcatModification owlcatModification, bool allowModDisabling, LocalizedString LocalizedModName = null, LocalizedString LocalizedModDescription = null, Sprite image = null) + /// + /// + /// if your mod is an OwlcatModification, you may provide a link to it + /// in this case the constructor will use the information from manifest to set mod's name, description, author and version. + /// Set to true if you want to have a button in the ModMenu to disable your mod + /// Localized name for your mod if you are mot satisfied with the non localized name taken from the mod manifest + /// Localized description for your mod if you are mot satisfied with the non localized description taken from the mod manifest + /// Mod's icon to be displayed alongside the description + /// You are not allowed to provide a null OwlcatModification when using this constructor + public Info([NotNull]OwlcatModification owlcatModification, bool allowModDisabling, LocalizedString LocalizedModName = null, LocalizedString LocalizedModDescription = null, Sprite image = null) { if (owlcatModification is null) throw new ModMenu_EmptyModException("Attempt to create ModInfo out of a null OwlcatModification"); @@ -165,25 +204,35 @@ public Info(OwlcatModification owlcatModification, bool allowModDisabling, Local uniqueName = "AnonymousMod" + AnonymousCounter; AnonymousCounter++; } - AuthorName = manifest.Author; if (LocalizedModName is not null && LocalizedModName.ToString().IsNullOrEmpty() is false) ModName = LocalizedModName; - else if (manifest.DisplayName.IsNullOrEmpty() is false) + else { - ModName = Helpers.CreateString($"ModsMenu.{uniqueName}.ModName", manifest.DisplayName); + ModName = manifest.DisplayName.IsNullOrEmpty() is false + ? Helpers.CreateString($"ModsMenu.{uniqueName}.ModName", manifest.DisplayName) + : AnonymousMod; } - else ModName = AnonymousMod; if (LocalizedModDescription is not null && LocalizedModDescription.ToString().IsNullOrEmpty() is false) - ModDescription = LocalizedModDescription; + this.LocalizedModDescription = LocalizedModDescription; else if (manifest.Description.IsNullOrEmpty() is false) { - ModDescription = Helpers.CreateString($"ModsMenu.{uniqueName}.Description", manifest.DisplayName); + NonLocalizedModDescription = Helpers.CreateString($"ModsMenu.{uniqueName}.Description", manifest.DisplayName); } ModImage = image; } - public Info(UnityModManagerNet.UnityModManager.ModEntry UMM_Mod, bool allowModDisabling, LocalizedString LocalizedModName = null, LocalizedString LocalizedModDescription = null, Sprite image = null) + + /// + /// + /// if your mod is an UMM mod, you may provide a link to it + /// in this case the constructor will use the information from manifest to set mod's name, author and version. + /// Set to true if you want to have a button in the ModMenu to disable your mod + /// Localized name for your mod if you are mot satisfied with the non localized name taken from the mod manifest + /// Localized description for your mod + /// Mod's icon to be displayed alongside the description + /// You are not allowed to provide a null UnityModManager.ModEntry when using this constructor + public Info([NotNull] UnityModManagerNet.UnityModManager.ModEntry UMM_Mod, bool allowModDisabling, LocalizedString LocalizedModName = null, LocalizedString LocalizedModDescription = null, Sprite image = null) { if (UMM_Mod is null) throw new ModMenu_EmptyModException("Attempt to create ModInfo out of a null UMM mod"); @@ -208,27 +257,19 @@ public Info(UnityModManagerNet.UnityModManager.ModEntry UMM_Mod, bool allowModDi } else ModName = AnonymousMod; if (LocalizedModDescription is not null && LocalizedModDescription.ToString().IsNullOrEmpty() is false) - ModDescription = LocalizedModDescription; + this.LocalizedModDescription = LocalizedModDescription; ModImage = image; } - public Sprite ModImage { get; private set; } - public LocalizedString ModName { get; private set; } - public string VersionNumber { get; private set; } - public string AuthorName { get; private set; } - public LocalizedString ModDescription { get; private set; } - internal bool AllowModDisabling { get; set; } - internal OwlcatModification OwlMod { get; } - internal UnityModManagerNet.UnityModManager.ModEntry UMMMod { get; } - internal string GenerateName() + internal string GenerateDescription() { string result = ModName; if (!string.IsNullOrEmpty(VersionNumber)) result = $"{result} ({stringVer}: {VersionNumber})"; result = $"{result}\n"; if (!string.IsNullOrEmpty(AuthorName)) result = string.Concat(result, $"{stringAuthor}: {AuthorName}\n"); - string.Concat(result, ModDescription); + string.Concat(result, LocalizedModDescription); return result; } @@ -236,22 +277,10 @@ internal string GenerateName() private class ModMenu_EmptyModException : Exception { - - internal ModMenu_EmptyModException() - { - } - - internal ModMenu_EmptyModException(string message) : base(message) - { - } - - internal ModMenu_EmptyModException(string message, Exception inner) : base(message, inner) - { - } - - internal ModMenu_EmptyModException(SerializationInfo info, StreamingContext context) : base(info, context) - { - } + internal ModMenu_EmptyModException() { } + internal ModMenu_EmptyModException(string message) : base(message) { } + internal ModMenu_EmptyModException(string message, Exception inner) : base(message, inner) { } + internal ModMenu_EmptyModException(SerializationInfo info, StreamingContext context) : base(info, context) { } } } From 4a25e62623a760ff98f546bfcbb472a555c52a5b Mon Sep 17 00:00:00 2001 From: ScaredKurufinve Date: Thu, 9 Mar 2023 23:14:52 +0300 Subject: [PATCH 16/35] Visual studio is crazy and did not fixate one change --- ModMenu/Settings/ModsMenuEntry.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ModMenu/Settings/ModsMenuEntry.cs b/ModMenu/Settings/ModsMenuEntry.cs index 4019517..d452ec5 100644 --- a/ModMenu/Settings/ModsMenuEntry.cs +++ b/ModMenu/Settings/ModsMenuEntry.cs @@ -140,6 +140,7 @@ public struct Info public string AuthorName { get; private set; } public LocalizedString LocalizedModDescription { get; private set; } public string NonLocalizedModDescription { get; private set; } + private string ModDescription { get { return LocalizedModDescription ?? NonLocalizedModDescription; } } internal bool AllowModDisabling { get; set; } internal OwlcatModification OwlMod { get; } internal UnityModManagerNet.UnityModManager.ModEntry UMMMod { get; } @@ -265,7 +266,7 @@ public Info([NotNull] UnityModManagerNet.UnityModManager.ModEntry UMM_Mod, bool internal string GenerateDescription() { - string result = ModName; + string result = ModDescription; if (!string.IsNullOrEmpty(VersionNumber)) result = $"{result} ({stringVer}: {VersionNumber})"; result = $"{result}\n"; if (!string.IsNullOrEmpty(AuthorName)) result = string.Concat(result, $"{stringAuthor}: {AuthorName}\n"); From 0bbd4415bfd83d0073de815ae65a3ffecaf644dd Mon Sep 17 00:00:00 2001 From: TylerGoeringer Date: Fri, 10 Mar 2023 08:06:12 -0800 Subject: [PATCH 17/35] Basic cleanup - Unify publicize task - Remove imports --- ModMenu/Main.cs | 2 - ModMenu/ModMenu.cs | 1 - ModMenu/ModMenu.csproj | 37 +++++-------------- .../NewTypes/SettingsEntityDropdownButton.cs | 2 +- .../NewTypes/SettingsEntityModsmenuEntry.cs | 5 --- .../UISettingsEntityDropDownModsmenuEntry.cs | 8 ++-- ModMenu/Settings/KeyBinding.cs | 16 ++++---- ModMenu/Settings/ModsMenuEntry.cs | 3 -- ModMenu/Settings/TestSettings.cs | 8 +--- 9 files changed, 21 insertions(+), 61 deletions(-) diff --git a/ModMenu/Main.cs b/ModMenu/Main.cs index 9c5c256..51fb334 100644 --- a/ModMenu/Main.cs +++ b/ModMenu/Main.cs @@ -1,6 +1,4 @@ using HarmonyLib; -using Kingmaker.Blueprints.JsonSystem; -using ModMenu.Settings; using System; using static UnityModManagerNet.UnityModManager; using static UnityModManagerNet.UnityModManager.ModEntry; diff --git a/ModMenu/ModMenu.cs b/ModMenu/ModMenu.cs index 4c1b6b4..4791f2f 100644 --- a/ModMenu/ModMenu.cs +++ b/ModMenu/ModMenu.cs @@ -1,5 +1,4 @@ using Kingmaker.Settings; -using Kingmaker.UI.SaveLoadWindow; using Kingmaker.UI.SettingsUI; using ModMenu.Settings; using System; diff --git a/ModMenu/ModMenu.csproj b/ModMenu/ModMenu.csproj index 4eb70e4..08a7506 100644 --- a/ModMenu/ModMenu.csproj +++ b/ModMenu/ModMenu.csproj @@ -44,16 +44,16 @@ - $(SolutionDir)lib\Assembly-CSharp.dll + $(SolutionDir)lib\Assembly-CSharp_public.dll + + + $(SolutionDir)lib\Owlcat.Runtime.UI_public.dll $(WrathPath)\Wrath_Data\Managed\Assembly-CSharp-firstpass.dll - - $(SolutionDir)lib\Owlcat.Runtime.UI_public.dll - $(WrathPath)\Wrath_Data\Managed\Owlcat.Runtime.Validation.dll @@ -92,35 +92,16 @@ - - - + + + + - - - - + - - - - - - - - - - - - - - - - - diff --git a/ModMenu/NewTypes/SettingsEntityDropdownButton.cs b/ModMenu/NewTypes/SettingsEntityDropdownButton.cs index 3792378..082acc6 100644 --- a/ModMenu/NewTypes/SettingsEntityDropdownButton.cs +++ b/ModMenu/NewTypes/SettingsEntityDropdownButton.cs @@ -7,8 +7,8 @@ using Owlcat.Runtime.UI.VirtualListSystem.ElementSettings; using System; using TMPro; -using UnityEngine.EventSystems; using UnityEngine; +using UnityEngine.EventSystems; using UnityEngine.UI; namespace ModMenu.NewTypes diff --git a/ModMenu/NewTypes/SettingsEntityModsmenuEntry.cs b/ModMenu/NewTypes/SettingsEntityModsmenuEntry.cs index b4b1cd0..ba36be3 100644 --- a/ModMenu/NewTypes/SettingsEntityModsmenuEntry.cs +++ b/ModMenu/NewTypes/SettingsEntityModsmenuEntry.cs @@ -1,10 +1,5 @@ using Kingmaker.Settings; using ModMenu.Settings; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; namespace ModMenu.NewTypes { diff --git a/ModMenu/NewTypes/UISettingsEntityDropDownModsmenuEntry.cs b/ModMenu/NewTypes/UISettingsEntityDropDownModsmenuEntry.cs index 0ce263c..3aa21a2 100644 --- a/ModMenu/NewTypes/UISettingsEntityDropDownModsmenuEntry.cs +++ b/ModMenu/NewTypes/UISettingsEntityDropDownModsmenuEntry.cs @@ -1,10 +1,8 @@ -using System; +using Kingmaker.UI.SettingsUI; +using ModMenu.Settings; +using System; using System.Collections.Generic; using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Kingmaker.UI.SettingsUI; -using ModMenu.Settings; using UnityEngine; namespace ModMenu.NewTypes diff --git a/ModMenu/Settings/KeyBinding.cs b/ModMenu/Settings/KeyBinding.cs index 9ca04c9..f6f3e33 100644 --- a/ModMenu/Settings/KeyBinding.cs +++ b/ModMenu/Settings/KeyBinding.cs @@ -1,16 +1,14 @@ -using Kingmaker.Localization; +using HarmonyLib; +using Kingmaker; +using Kingmaker.Localization; using Kingmaker.Settings; -using Kingmaker.UI.SettingsUI; -using System.Text; -using static Kingmaker.UI.KeyboardAccess; -using UnityEngine; -using HarmonyLib; using Kingmaker.UI; -using Kingmaker; +using Kingmaker.UI.SettingsUI; using System; using System.Collections.Generic; -using System.Security.Principal; -using Kingmaker.GameModes; +using System.Text; +using UnityEngine; +using static Kingmaker.UI.KeyboardAccess; namespace ModMenu.Settings { diff --git a/ModMenu/Settings/ModsMenuEntry.cs b/ModMenu/Settings/ModsMenuEntry.cs index d452ec5..cd2c629 100644 --- a/ModMenu/Settings/ModsMenuEntry.cs +++ b/ModMenu/Settings/ModsMenuEntry.cs @@ -7,9 +7,6 @@ using System.Collections.Generic; using System.Linq; using System.Runtime.Serialization; -using System.Text; -using System.Threading.Tasks; -using System.Xml.Linq; using UnityEngine; namespace ModMenu.Settings diff --git a/ModMenu/Settings/TestSettings.cs b/ModMenu/Settings/TestSettings.cs index cf4b6a8..a7f989d 100644 --- a/ModMenu/Settings/TestSettings.cs +++ b/ModMenu/Settings/TestSettings.cs @@ -1,10 +1,4 @@ -using Kingmaker.Localization; -using Kingmaker.UI.SettingsUI; -using System.Text; -using UnityEngine; -using static Kingmaker.UI.KeyboardAccess; - -namespace ModMenu.Settings +namespace ModMenu.Settings { #if DEBUG /// From 6b5da80737de893dd0cbb75344f06c1a4636a34c Mon Sep 17 00:00:00 2001 From: TylerGoeringer Date: Fri, 10 Mar 2023 08:10:29 -0800 Subject: [PATCH 18/35] Rename --- ModMenu/NewTypes/SettingsEntityPatches.cs | 2 +- ...menuEntry.cs => UISettingsEntityDropDownModMenuEntry.cs} | 6 +++--- ModMenu/Settings/ModsMenuEntity.cs | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) rename ModMenu/NewTypes/{UISettingsEntityDropDownModsmenuEntry.cs => UISettingsEntityDropDownModMenuEntry.cs} (79%) diff --git a/ModMenu/NewTypes/SettingsEntityPatches.cs b/ModMenu/NewTypes/SettingsEntityPatches.cs index 35c228a..7f93045 100644 --- a/ModMenu/NewTypes/SettingsEntityPatches.cs +++ b/ModMenu/NewTypes/SettingsEntityPatches.cs @@ -81,7 +81,7 @@ static bool Prefix(UISettingsManager.SettingsScreen settingsScreen, SettingsVM _ Main.Logger.NativeLog("Collecting setting entities."); __instance.m_SettingEntities.Clear(); - __instance.m_SettingEntities.Add(__instance.AddDisposableAndReturn(SettingsVM.GetVMForSettingsItem(UISettingsEntityDropdownModsmenuEntry.instance))); + __instance.m_SettingEntities.Add(__instance.AddDisposableAndReturn(SettingsVM.GetVMForSettingsItem(UISettingsEntityDropdownModMenuEntry.instance))); __instance.m_SettingEntities.Add(__instance.AddDisposableAndReturn(SettingsVM.GetVMForSettingsItem(new UISettingsEntitySeparator()))); //Here should be a toggle for mod disabling, but do we need it? diff --git a/ModMenu/NewTypes/UISettingsEntityDropDownModsmenuEntry.cs b/ModMenu/NewTypes/UISettingsEntityDropDownModMenuEntry.cs similarity index 79% rename from ModMenu/NewTypes/UISettingsEntityDropDownModsmenuEntry.cs rename to ModMenu/NewTypes/UISettingsEntityDropDownModMenuEntry.cs index 3aa21a2..e0476f0 100644 --- a/ModMenu/NewTypes/UISettingsEntityDropDownModsmenuEntry.cs +++ b/ModMenu/NewTypes/UISettingsEntityDropDownModMenuEntry.cs @@ -7,14 +7,14 @@ namespace ModMenu.NewTypes { - internal class UISettingsEntityDropdownModsmenuEntry : UISettingsEntityDropdown + internal class UISettingsEntityDropdownModMenuEntry : UISettingsEntityDropdown { - static UISettingsEntityDropdownModsmenuEntry() + static UISettingsEntityDropdownModMenuEntry() { instance.OnTempIndexValueChanged += new Action(ModIndex => ModsMenuEntity.settingVM.SwitchSettingsScreen(ModsMenuEntity.SettingsScreenId)); instance.LinkSetting(SettingsEntityModsmenuEntry.instance); } - internal static UISettingsEntityDropdownModsmenuEntry instance = ScriptableObject.CreateInstance(); + internal static UISettingsEntityDropdownModMenuEntry instance = ScriptableObject.CreateInstance(); public override List LocalizedValues { get diff --git a/ModMenu/Settings/ModsMenuEntity.cs b/ModMenu/Settings/ModsMenuEntity.cs index e91f418..04531fc 100644 --- a/ModMenu/Settings/ModsMenuEntity.cs +++ b/ModMenu/Settings/ModsMenuEntity.cs @@ -56,7 +56,7 @@ internal static void Add(ModsMenuEntry modEntry) } - internal static IEnumerable CollectSettingGroups => UISettingsEntityDropdownModsmenuEntry.instance.Setting.m_CurrentValue.ModSettings; + internal static IEnumerable CollectSettingGroups => UISettingsEntityDropdownModMenuEntry.instance.Setting.m_CurrentValue.ModSettings; /// From 519f07ddca169506c7824dfa65ee0da04949b036 Mon Sep 17 00:00:00 2001 From: TylerGoeringer Date: Fri, 10 Mar 2023 08:18:31 -0800 Subject: [PATCH 19/35] Resolve ambiguity error --- ModMenu/NewTypes/UISettingsEntityDropDownModMenuEntry.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ModMenu/NewTypes/UISettingsEntityDropDownModMenuEntry.cs b/ModMenu/NewTypes/UISettingsEntityDropDownModMenuEntry.cs index e0476f0..fbc0e1c 100644 --- a/ModMenu/NewTypes/UISettingsEntityDropDownModMenuEntry.cs +++ b/ModMenu/NewTypes/UISettingsEntityDropDownModMenuEntry.cs @@ -11,7 +11,7 @@ internal class UISettingsEntityDropdownModMenuEntry : UISettingsEntityDropdown(ModIndex => ModsMenuEntity.settingVM.SwitchSettingsScreen(ModsMenuEntity.SettingsScreenId)); + ((IUISettingsEntityDropdown) instance).OnTempIndexValueChanged += new Action(ModIndex => ModsMenuEntity.settingVM.SwitchSettingsScreen(ModsMenuEntity.SettingsScreenId)); instance.LinkSetting(SettingsEntityModsmenuEntry.instance); } internal static UISettingsEntityDropdownModMenuEntry instance = ScriptableObject.CreateInstance(); @@ -33,7 +33,7 @@ public override void SetIndexTempValue(int value) { if (value is < 0 && value > ModsMenuEntity.ModEntries.Count()) { - Main.Logger.Error($"Value {value} is given to UISettingsEntityDropdownModsmenuEntry when there're only {ModsMenuEntity.ModEntries.Count()} entries in the list"); + Main.Logger.Error($"Value {value} is given to UISettingsEntityDropdownModMenuEntry when there're only {ModsMenuEntity.ModEntries.Count()} entries in the list"); SetTempValue(ModsMenuEntity.ModEntries[0]); } From 439f213b67bcd562abfa78c6fec31315852e273d Mon Sep 17 00:00:00 2001 From: TylerGoeringer Date: Fri, 10 Mar 2023 08:18:54 -0800 Subject: [PATCH 20/35] Update UISettingsEntityDropDownModMenuEntry.cs --- ModMenu/NewTypes/UISettingsEntityDropDownModMenuEntry.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/ModMenu/NewTypes/UISettingsEntityDropDownModMenuEntry.cs b/ModMenu/NewTypes/UISettingsEntityDropDownModMenuEntry.cs index fbc0e1c..fa3a2e2 100644 --- a/ModMenu/NewTypes/UISettingsEntityDropDownModMenuEntry.cs +++ b/ModMenu/NewTypes/UISettingsEntityDropDownModMenuEntry.cs @@ -14,6 +14,7 @@ static UISettingsEntityDropdownModMenuEntry() ((IUISettingsEntityDropdown) instance).OnTempIndexValueChanged += new Action(ModIndex => ModsMenuEntity.settingVM.SwitchSettingsScreen(ModsMenuEntity.SettingsScreenId)); instance.LinkSetting(SettingsEntityModsmenuEntry.instance); } + internal static UISettingsEntityDropdownModMenuEntry instance = ScriptableObject.CreateInstance(); public override List LocalizedValues { From 0b347a43d01b9c9671b2292f27771f648f8c4d4e Mon Sep 17 00:00:00 2001 From: TylerGoeringer Date: Fri, 10 Mar 2023 08:19:09 -0800 Subject: [PATCH 21/35] Update UISettingsEntityDropDownModMenuEntry.cs --- ModMenu/NewTypes/UISettingsEntityDropDownModMenuEntry.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/ModMenu/NewTypes/UISettingsEntityDropDownModMenuEntry.cs b/ModMenu/NewTypes/UISettingsEntityDropDownModMenuEntry.cs index fa3a2e2..b9c8e88 100644 --- a/ModMenu/NewTypes/UISettingsEntityDropDownModMenuEntry.cs +++ b/ModMenu/NewTypes/UISettingsEntityDropDownModMenuEntry.cs @@ -29,7 +29,6 @@ public override int GetIndexTempValue() return ModsMenuEntity.ModEntries.IndexOf(Setting.GetTempValue()); } - public override void SetIndexTempValue(int value) { if (value is < 0 && value > ModsMenuEntity.ModEntries.Count()) @@ -40,6 +39,5 @@ public override void SetIndexTempValue(int value) SetTempValue(ModsMenuEntity.ModEntries[value]); } - } } From 28ccd99b1606341f61153607c99c634c3d819412 Mon Sep 17 00:00:00 2001 From: TylerGoeringer Date: Fri, 10 Mar 2023 08:20:10 -0800 Subject: [PATCH 22/35] Rename / cleanup --- ModMenu/NewTypes/SettingsEntityModMenuEntry.cs | 11 +++++++++++ ModMenu/NewTypes/SettingsEntityModsmenuEntry.cs | 11 ----------- .../NewTypes/UISettingsEntityDropDownModMenuEntry.cs | 6 ++++-- 3 files changed, 15 insertions(+), 13 deletions(-) create mode 100644 ModMenu/NewTypes/SettingsEntityModMenuEntry.cs delete mode 100644 ModMenu/NewTypes/SettingsEntityModsmenuEntry.cs diff --git a/ModMenu/NewTypes/SettingsEntityModMenuEntry.cs b/ModMenu/NewTypes/SettingsEntityModMenuEntry.cs new file mode 100644 index 0000000..e734c5a --- /dev/null +++ b/ModMenu/NewTypes/SettingsEntityModMenuEntry.cs @@ -0,0 +1,11 @@ +using Kingmaker.Settings; +using ModMenu.Settings; + +namespace ModMenu.NewTypes +{ + internal class SettingsEntityModMenuEntry : SettingsEntity + { + internal static SettingsEntityModMenuEntry instance = new("modsmenu.entrystaticinstance", ModsMenuEntry.EmptyInstance); + public SettingsEntityModMenuEntry(string key, ModsMenuEntry defaultValue) : base(key, defaultValue, false, false, false) {} + } +} diff --git a/ModMenu/NewTypes/SettingsEntityModsmenuEntry.cs b/ModMenu/NewTypes/SettingsEntityModsmenuEntry.cs deleted file mode 100644 index ba36be3..0000000 --- a/ModMenu/NewTypes/SettingsEntityModsmenuEntry.cs +++ /dev/null @@ -1,11 +0,0 @@ -using Kingmaker.Settings; -using ModMenu.Settings; - -namespace ModMenu.NewTypes -{ - internal class SettingsEntityModsmenuEntry : SettingsEntity - { - internal static SettingsEntityModsmenuEntry instance = new("modsmenu.entrystaticinstance", ModsMenuEntry.EmptyInstance); - public SettingsEntityModsmenuEntry(string key, ModsMenuEntry defaultValue) : base(key, defaultValue, false, false, false) {} - } -} diff --git a/ModMenu/NewTypes/UISettingsEntityDropDownModMenuEntry.cs b/ModMenu/NewTypes/UISettingsEntityDropDownModMenuEntry.cs index b9c8e88..ca688d2 100644 --- a/ModMenu/NewTypes/UISettingsEntityDropDownModMenuEntry.cs +++ b/ModMenu/NewTypes/UISettingsEntityDropDownModMenuEntry.cs @@ -11,11 +11,13 @@ internal class UISettingsEntityDropdownModMenuEntry : UISettingsEntityDropdown(ModIndex => ModsMenuEntity.settingVM.SwitchSettingsScreen(ModsMenuEntity.SettingsScreenId)); + ((IUISettingsEntityDropdown) instance).OnTempIndexValueChanged += + new Action(ModIndex => ModsMenuEntity.settingVM.SwitchSettingsScreen(ModsMenuEntity.SettingsScreenId)); instance.LinkSetting(SettingsEntityModsmenuEntry.instance); } - internal static UISettingsEntityDropdownModMenuEntry instance = ScriptableObject.CreateInstance(); + internal static UISettingsEntityDropdownModMenuEntry instance = + ScriptableObject.CreateInstance(); public override List LocalizedValues { get From 6f57e309dded0e4316364fefdb0bc4cd163d146c Mon Sep 17 00:00:00 2001 From: TylerGoeringer Date: Fri, 10 Mar 2023 08:21:39 -0800 Subject: [PATCH 23/35] Update UISettingsEntityDropDownModMenuEntry.cs --- ModMenu/NewTypes/UISettingsEntityDropDownModMenuEntry.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ModMenu/NewTypes/UISettingsEntityDropDownModMenuEntry.cs b/ModMenu/NewTypes/UISettingsEntityDropDownModMenuEntry.cs index ca688d2..503a53a 100644 --- a/ModMenu/NewTypes/UISettingsEntityDropDownModMenuEntry.cs +++ b/ModMenu/NewTypes/UISettingsEntityDropDownModMenuEntry.cs @@ -13,7 +13,7 @@ static UISettingsEntityDropdownModMenuEntry() { ((IUISettingsEntityDropdown) instance).OnTempIndexValueChanged += new Action(ModIndex => ModsMenuEntity.settingVM.SwitchSettingsScreen(ModsMenuEntity.SettingsScreenId)); - instance.LinkSetting(SettingsEntityModsmenuEntry.instance); + instance.LinkSetting(SettingsEntityModMenuEntry.instance); } internal static UISettingsEntityDropdownModMenuEntry instance = From 314e7718a9c11393b2f36fb35c78722202c252d7 Mon Sep 17 00:00:00 2001 From: TylerGoeringer Date: Fri, 10 Mar 2023 08:40:03 -0800 Subject: [PATCH 24/35] More cleanup --- ModMenu/Settings/ModsMenuEntity.cs | 5 +- ModMenu/Settings/ModsMenuEntry.cs | 261 +++++++++++++++-------------- 2 files changed, 139 insertions(+), 127 deletions(-) diff --git a/ModMenu/Settings/ModsMenuEntity.cs b/ModMenu/Settings/ModsMenuEntity.cs index 04531fc..c9e64d1 100644 --- a/ModMenu/Settings/ModsMenuEntity.cs +++ b/ModMenu/Settings/ModsMenuEntity.cs @@ -55,9 +55,8 @@ internal static void Add(ModsMenuEntry modEntry) ModEntries.Add(modEntry); } - - internal static IEnumerable CollectSettingGroups => UISettingsEntityDropdownModMenuEntry.instance.Setting.m_CurrentValue.ModSettings; - + internal static IEnumerable CollectSettingGroups => + UISettingsEntityDropdownModMenuEntry.instance.Setting.m_CurrentValue.ModSettings; /// /// Patch to create the Mods Menu ViewModel. diff --git a/ModMenu/Settings/ModsMenuEntry.cs b/ModMenu/Settings/ModsMenuEntry.cs index cd2c629..22acd85 100644 --- a/ModMenu/Settings/ModsMenuEntry.cs +++ b/ModMenu/Settings/ModsMenuEntry.cs @@ -6,46 +6,48 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Runtime.Serialization; using UnityEngine; +using UnityModManagerNet; namespace ModMenu.Settings { /// - /// Wrapper class used to display mod's settings in the ModMenu dropdown. Contains a list of UI Setting Groups and modification's info such as name + /// Wrapper class used to display mod's settings in the ModMenu dropdown. Contains a list of UI Setting Groups and + /// modification's info such as name. /// public class ModsMenuEntry { #pragma warning disable CS1591 // stupid documentation requests #pragma warning disable CS0618 // Method is obolete. I know! I made it obsolete! - internal static ModsMenuEntry EmptyInstance = new(new UISettingsGroup() { Title = new() { m_Key = "" }, SettingsList = Array.Empty() }); + internal static ModsMenuEntry EmptyInstance = + new(new UISettingsGroup() { Title = new() { m_Key = "" }, SettingsList = Array.Empty() }); internal readonly IEnumerable ModSettings; internal readonly Info ModInfo; internal ModsMenuEntry() => ModInfo = new(Helpers.EmptyString, Helpers.EmptyString); - /// /// Creates a simpliest ModEntry out of a single UI setting group. /// Mod entry will use the group's title as displayed name or will be called anonymous if title is empty /// - /// You can't create a ModEntry out of a null settings group ¯\_(ツ)_/¯ + /// + /// You can't create a ModEntry out of a null settings group ¯\_(ツ)_/¯ + /// [Obsolete("Please, use ModsMenuEntry(Info modInfo, UISettingsGroup settingGroup) instead. You will not be able to change ModInfo later.")] public ModsMenuEntry([NotNull]UISettingsGroup settingGroup) { if (settingGroup is null) { - throw new ModMenu_EmptySettingsGroupException(message: $"A null UISettingsGroup is trying to create a ModsMenuEntry out of itself without any additional mod info provided."); + throw new ArgumentException("Cannot create ModsMenuEntry with a null settingsGroup."); } if (settingGroup.SettingsList.Length == 0) { string name = ("titled " + settingGroup.Title) ?? "without a title"; - throw new ModMenu_EmptySettingsGroupException(message: $"UISettingsGroup {name} is trying to create a ModsMenuEntry out of itself without any additional mod info provided."); + throw new ArgumentException($"UISettingsGroup {name} is trying to create a ModsMenuEntry without mod info."); } - ModSettings = new UISettingsGroup[1] {settingGroup}; ModInfo = new(settingGroup.Title); } @@ -54,28 +56,28 @@ public ModsMenuEntry([NotNull]UISettingsGroup settingGroup) /// Creates a ModEntry out of a several UI setting group. /// Mod entry will use the first group's title as displayed name or will be called anonymous if title is empty /// - /// settingGroups argument must not be null, have at least 1 group in it and none of groups can be null - [Obsolete("Please, use ModsMenuEntry(Info modInfo, IEnumerable settingGroups) instead. You will not be able to change ModInfo later.")] + /// + /// settingGroups argument must not be null, have at least 1 group in it and none can be null + /// + [Obsolete("Use ModsMenuEntry(Info modInfo, IEnumerable settingGroups). You will not be able to change ModInfo later.")] public ModsMenuEntry(IEnumerable settingGroups) { if (settingGroups is null || settingGroups.Count() == 0) { - throw new ModMenu_EmptySettingsGroupException(message: $"A null list of UISettingsGroups is trying to create a ModsMenuEntry out of itself without any additional mod info provided."); + throw new ArgumentException("Cannot create ModsMenuEntry without any settingsGroups."); } if (settingGroups.Any(g => g is null)) { - throw new ModMenu_EmptySettingsGroupException(message: $"A list of UISettingsGroups is trying to create a ModsMenuEntry out of itself, but contains a null group."); + throw new ArgumentException("Cannot create ModsMenuEntry with a null settingsGroup."); } - UISettingsGroup firstGroup = settingGroups.ElementAt(0); - + UISettingsGroup firstGroup = settingGroups.ElementAt(0); if (firstGroup.SettingsList.Length == 0) { string name = ("titled " + firstGroup.Title) ?? "without a title"; - throw new ModMenu_EmptySettingsGroupException(message: $"UISettingsGroup {name} is trying to create a ModsMenuEntry out of itself without any additional mod info provided."); + throw new ArgumentException($"UISettingsGroup {name} is trying to create a ModsMenuEntry without mod info."); } - ModSettings = new UISettingsGroup[1] { firstGroup }; ModInfo = new(firstGroup.Title); } @@ -84,6 +86,7 @@ public ModsMenuEntry(Info modInfo, UISettingsGroup settingGroup) : this(settingG { ModInfo = modInfo; } + public ModsMenuEntry(Info modInfo, IEnumerable settingGroups) : this(settingGroups) { ModInfo = modInfo; @@ -91,33 +94,16 @@ public ModsMenuEntry(Info modInfo, IEnumerable settingGroups) : /// /// Creates a simple ModEntry out of a single UI setting group. - /// > - /// Name of your mod which will be displayed in the ModMenu dropdown. If you don't provide any, it will displayed as Anonymous - /// - /// You can't create a ModEntry out of a null settings group ¯\_(ツ)_/¯ - public ModsMenuEntry( LocalizedString ModName, [NotNull]UISettingsGroup settingGroup) : this(settingGroup) + /// + /// + /// Name of your mod displayed in the ModMenu dropdown. If you don't provide any, it will be Anonymous + /// + /// + /// You can't create a ModEntry out of a null settings group ¯\_(ツ)_/¯ + /// + public ModsMenuEntry(LocalizedString modName, [NotNull]UISettingsGroup settingGroup) : this(settingGroup) { - ModInfo = new(ModName); - } - - private class ModMenu_EmptySettingsGroupException : Exception - { - - internal ModMenu_EmptySettingsGroupException() - { - } - - internal ModMenu_EmptySettingsGroupException(string message) : base(message) - { - } - - internal ModMenu_EmptySettingsGroupException(string message, Exception inner) : base(message, inner) - { - } - - internal ModMenu_EmptySettingsGroupException(SerializationInfo info, StreamingContext context) : base(info, context) - { - } + ModInfo = new(modName); } /// @@ -125,10 +111,12 @@ internal ModMenu_EmptySettingsGroupException(SerializationInfo info, StreamingCo /// public struct Info { - private static readonly LocalizedString AnonymousMod = Helpers.CreateString("ModsMenu.AnonymousMod", "Anonymous Mod", ruRU: "Безымянный мод"); - private static readonly LocalizedString stringAuthor = Helpers.CreateString("ModsMenu.stringAuthor", "Author", ruRU: "Создатель"); - private static readonly LocalizedString stringVer = Helpers.CreateString("ModsMenu.stringVer", "Version", ruRU: "Версия"); - private const string anonMod = "AnonymousMod"; + private static readonly LocalizedString AnonymousMod = + Helpers.CreateString("ModsMenu.AnonymousMod", "Anonymous Mod", ruRU: "Безымянный мод"); + private static readonly LocalizedString stringAuthor = + Helpers.CreateString("ModsMenu.stringAuthor", "Author", ruRU: "Создатель"); + private static readonly LocalizedString stringVer = + Helpers.CreateString("ModsMenu.stringVer", "Version", ruRU: "Версия"); private static int AnonymousCounter = 0; public Sprite ModImage { get; private set; } @@ -140,62 +128,92 @@ public struct Info private string ModDescription { get { return LocalizedModDescription ?? NonLocalizedModDescription; } } internal bool AllowModDisabling { get; set; } internal OwlcatModification OwlMod { get; } - internal UnityModManagerNet.UnityModManager.ModEntry UMMMod { get; } - - - - /// - /// - /// Name of your mod which will be displayed in the ModMenu dropdown. If you don't provide any, it will displayed as Anonymous - /// Description which will be displayed when user selects your mod in ModMenu dropdown - /// Mod version to be displayed alongside the description - /// Mod author's name to be displayed alongside the description - /// Mod's icon to be displayed alongside the description - public Info(LocalizedString Name, LocalizedString Description = null, string version = "", string author = "", Sprite image = null) + internal UnityModManager.ModEntry UMMMod { get; } + + /// + /// Name of your mod displayed in the ModMenu dropdown. If you don't provide any, it will be Anonymous + /// + /// + /// Description which will be displayed when user selects your mod in ModMenu dropdown + /// + /// + /// Mod version to be displayed alongside the description + /// + /// + /// Mod author's name to be displayed alongside the description + /// + /// + /// Mod's icon to be displayed alongside the description + /// + public Info( + LocalizedString name, + LocalizedString description = null, + string version = "", + string author = "", + Sprite image = null) { - if (Name is null) ModName = AnonymousMod; - else ModName = Name; + if (name is null) ModName = AnonymousMod; + else ModName = name; VersionNumber = version; AuthorName = author; ModImage = image; - LocalizedModDescription = Description; + LocalizedModDescription = description; } - /// - /// - /// Name of your mod which will be displayed in the ModMenu dropdown. If you don't provide any, it will displayed as Anonymous - /// Description which will be displayed when user selects your mod in ModMenu dropdown - /// Mod version to be displayed alongside the description - /// Mod author's name to be displayed alongside the description - /// Mod's icon to be displayed alongside the description - public Info(string Name, string Description = "", string version = "", string author = "", Sprite image = null) : this(Helpers.CreateString($"ModsMenu.{Name}.Name", Name), null, version, author, image) + /// + /// Name of your mod which will be displayed in the ModMenu dropdown. If you don't provide any, it will displayed + /// as Anonymous + /// + /// + /// Description which will be displayed when user selects your mod in ModMenu dropdown + /// + /// Mod version to be displayed alongside the description + /// Mod author's name to be displayed alongside the description + /// Mod's icon to be displayed alongside the description + public Info( + string name, string description = "", string version = "", string author = "", Sprite image = null) : + this(Helpers.CreateString($"ModsMenu.{name}.Name", name), null, version, author, image) { - if (Name.IsNullOrEmpty()) - { - Name = anonMod + AnonymousCounter; + if (name.IsNullOrEmpty()) AnonymousCounter++; - } - NonLocalizedModDescription = Description; + + NonLocalizedModDescription = description; } - /// - /// - /// if your mod is an OwlcatModification, you may provide a link to it - /// in this case the constructor will use the information from manifest to set mod's name, description, author and version. - /// Set to true if you want to have a button in the ModMenu to disable your mod - /// Localized name for your mod if you are mot satisfied with the non localized name taken from the mod manifest - /// Localized description for your mod if you are mot satisfied with the non localized description taken from the mod manifest - /// Mod's icon to be displayed alongside the description - /// You are not allowed to provide a null OwlcatModification when using this constructor - public Info([NotNull]OwlcatModification owlcatModification, bool allowModDisabling, LocalizedString LocalizedModName = null, LocalizedString LocalizedModDescription = null, Sprite image = null) + /// + /// If your mod is an OwlcatModification, you may provide a link to it in this case the constructor will use the + /// information from manifest to set mod's name, description, author and version. + /// + /// + /// Set to true if you want to have a button in the ModMenu to disable your mod + /// + /// + /// Localized name for your mod if you are not satisfied with the non localized name taken from the mod manifest + /// + /// + /// Localized description for your mod if you are mot satisfied with the non localized description taken from the + /// mod manifest + /// + /// Mod's icon to be displayed alongside the description + /// + /// You are not allowed to provide a null OwlcatModification when using this constructor + /// + public Info( + OwlcatModification owlcatModification, + bool allowModDisabling, + LocalizedString localizedModName = null, + LocalizedString localizedModDescription = null, + Sprite image = null) { if (owlcatModification is null) - throw new ModMenu_EmptyModException("Attempt to create ModInfo out of a null OwlcatModification"); + throw new ArgumentException("Attempt to create ModInfo out of a null OwlcatModification"); + OwlMod = owlcatModification; AllowModDisabling = allowModDisabling; OwlcatModificationManifest manifest = owlcatModification.Manifest; AuthorName = manifest.Author; VersionNumber = manifest.Version; + string uniqueName = manifest.UniqueName; if (uniqueName.IsNullOrEmpty()) { @@ -203,42 +221,46 @@ public Info([NotNull]OwlcatModification owlcatModification, bool allowModDisabli AnonymousCounter++; } - if (LocalizedModName is not null && LocalizedModName.ToString().IsNullOrEmpty() is false) - ModName = LocalizedModName; + if (localizedModName is not null && localizedModName.ToString().IsNullOrEmpty() is false) + ModName = localizedModName; else { ModName = manifest.DisplayName.IsNullOrEmpty() is false ? Helpers.CreateString($"ModsMenu.{uniqueName}.ModName", manifest.DisplayName) : AnonymousMod; } - if (LocalizedModDescription is not null && LocalizedModDescription.ToString().IsNullOrEmpty() is false) - this.LocalizedModDescription = LocalizedModDescription; + + if (localizedModDescription is not null && localizedModDescription.ToString().IsNullOrEmpty() is false) + LocalizedModDescription = localizedModDescription; else if (manifest.Description.IsNullOrEmpty() is false) - { NonLocalizedModDescription = Helpers.CreateString($"ModsMenu.{uniqueName}.Description", manifest.DisplayName); - } ModImage = image; } - /// - /// - /// if your mod is an UMM mod, you may provide a link to it + /// if your mod is an UMM mod, you may provide a link to it /// in this case the constructor will use the information from manifest to set mod's name, author and version. /// Set to true if you want to have a button in the ModMenu to disable your mod - /// Localized name for your mod if you are mot satisfied with the non localized name taken from the mod manifest - /// Localized description for your mod + /// Localized name for your mod if you are mot satisfied with the non localized name taken from the mod manifest + /// Localized description for your mod /// Mod's icon to be displayed alongside the description - /// You are not allowed to provide a null UnityModManager.ModEntry when using this constructor - public Info([NotNull] UnityModManagerNet.UnityModManager.ModEntry UMM_Mod, bool allowModDisabling, LocalizedString LocalizedModName = null, LocalizedString LocalizedModDescription = null, Sprite image = null) + /// You are not allowed to provide a null UnityModManager.ModEntry when using this constructor + public Info( + UnityModManager.ModEntry ummMod, + bool allowModDisabling, + LocalizedString localizedModName = null, + LocalizedString localizedModDescription = null, + Sprite image = null) { - if (UMM_Mod is null) - throw new ModMenu_EmptyModException("Attempt to create ModInfo out of a null UMM mod"); - UMMMod = UMM_Mod; + if (ummMod is null) + throw new ArgumentException("Attempt to create ModInfo out of a null UMM mod"); + + UMMMod = ummMod; AllowModDisabling = allowModDisabling; - UnityModManagerNet.UnityModManager.ModInfo info = UMM_Mod.Info; + UnityModManager.ModInfo info = ummMod.Info; AuthorName = info.Author; VersionNumber = info.Version; + string uniqueName = info.Id; if (uniqueName.IsNullOrEmpty()) { @@ -247,41 +269,32 @@ public Info([NotNull] UnityModManagerNet.UnityModManager.ModEntry UMM_Mod, bool } AuthorName = info.Author; - if (LocalizedModName is not null && LocalizedModName.ToString().IsNullOrEmpty() is false) - ModName = LocalizedModName; + if (localizedModName is not null && localizedModName.ToString().IsNullOrEmpty() is false) + ModName = localizedModName; else if (info.DisplayName.IsNullOrEmpty() is false) - { ModName = Helpers.CreateString($"ModsMenu.{uniqueName}.ModName", info.DisplayName); - } - else ModName = AnonymousMod; - if (LocalizedModDescription is not null && LocalizedModDescription.ToString().IsNullOrEmpty() is false) - this.LocalizedModDescription = LocalizedModDescription; + else + ModName = AnonymousMod; + + if (localizedModDescription is not null && localizedModDescription.ToString().IsNullOrEmpty() is false) + LocalizedModDescription = localizedModDescription; ModImage = image; } - internal string GenerateDescription() { string result = ModDescription; - if (!string.IsNullOrEmpty(VersionNumber)) result = $"{result} ({stringVer}: {VersionNumber})"; + if (!string.IsNullOrEmpty(VersionNumber)) + result = $"{result} ({stringVer}: {VersionNumber})"; + result = $"{result}\n"; - if (!string.IsNullOrEmpty(AuthorName)) result = string.Concat(result, $"{stringAuthor}: {AuthorName}\n"); + if (!string.IsNullOrEmpty(AuthorName)) + result = string.Concat(result, $"{stringAuthor}: {AuthorName}\n"); + string.Concat(result, LocalizedModDescription); - return result; } - - - private class ModMenu_EmptyModException : Exception - { - internal ModMenu_EmptyModException() { } - internal ModMenu_EmptyModException(string message) : base(message) { } - internal ModMenu_EmptyModException(string message, Exception inner) : base(message, inner) { } - internal ModMenu_EmptyModException(SerializationInfo info, StreamingContext context) : base(info, context) { } - } - } - } } From 855d2079c348861e3076b2d4222f4a0cd471af09 Mon Sep 17 00:00:00 2001 From: TylerGoeringer Date: Fri, 10 Mar 2023 08:46:30 -0800 Subject: [PATCH 25/35] More cleanup --- ModMenu/ModMenu.csproj | 4 -- ModMenu/Settings/SettingsBuilder.cs | 93 +++++++++++++++-------------- 2 files changed, 47 insertions(+), 50 deletions(-) diff --git a/ModMenu/ModMenu.csproj b/ModMenu/ModMenu.csproj index 08a7506..ad97a5d 100644 --- a/ModMenu/ModMenu.csproj +++ b/ModMenu/ModMenu.csproj @@ -88,10 +88,6 @@ - - - - diff --git a/ModMenu/Settings/SettingsBuilder.cs b/ModMenu/Settings/SettingsBuilder.cs index 18808e1..220d798 100644 --- a/ModMenu/Settings/SettingsBuilder.cs +++ b/ModMenu/Settings/SettingsBuilder.cs @@ -10,6 +10,7 @@ using System.Collections.Generic; using System.Linq; using UnityEngine; +using UnityModManagerNet; namespace ModMenu.Settings { @@ -71,10 +72,10 @@ namespace ModMenu.Settings /// public class SettingsBuilder { - private object mod; - private bool allowDisabling; - private LocalizedString modName; - private LocalizedString modDescription; + private object Mod; + private bool AllowDisabling; + private LocalizedString ModName; + private LocalizedString ModDescription; private string Author = ""; private string Version = ""; private Sprite modIllustration; @@ -102,11 +103,7 @@ public SettingsBuilder(string key, LocalizedString title) : this() AddAnotherSettingsGroup(key, title); } - private SettingsBuilder() - { - - } - + private SettingsBuilder() { } /// /// Creates a new group of settings. @@ -130,58 +127,54 @@ public SettingsBuilder AddAnotherSettingsGroup(string key, LocalizedString title } /// - /// Set a source mod for your settings. Information from the manifest / info will be displayed when selecting the mod in the menu dropdown. - /// If you don't set Mod name and Mod description separately, the information from the manifest / info will be used instead. - /// Providing the source mod is necessary if you want to allow disabling from the ModMenu. + /// Set a source mod for your settings. Information from the manifest / info will be displayed when selecting the + /// mod in the menu dropdown. If you don't set Mod name and Mod description separately, the information from the + /// manifest / info will be used instead. Providing the source mod is necessary if you want to allow disabling from + /// the ModMenu. /// - /// - /// Your mod - /// - /// Set to true if you want to create a button to disable it - /// - public SettingsBuilder SetMod(OwlcatModification modEntry, bool AllowDisabling = false) - { - mod = modEntry; - allowDisabling = AllowDisabling; + /// + /// Your mod + /// Set to true if you want to create a button to disable it + public SettingsBuilder SetMod(OwlcatModification modEntry, bool allowDisabling = false) + { + Mod = modEntry; + AllowDisabling = allowDisabling; return this; } /// - /// Set a source mod for your settings. Information from the manifest / info will be displayed when selecting the mod in the menu dropdown. - /// If you don't set Mod name and Mod description separately, the information from the manifest / info will be used instead. - /// Providing the source mod is necessary if you want to allow disabling from the ModMenu. + /// Set a source mod for your settings. Information from the manifest / info will be displayed when selecting the + /// mod in the menu dropdown. If you don't set Mod name and Mod description separately, the information from the + /// manifest / info will be used instead. Providing the source mod is necessary if you want to allow disabling from + /// the ModMenu. /// - /// - /// Your mod - /// - /// Set to true if you want to create a button to disable it - /// - public SettingsBuilder SetMod(UnityModManagerNet.UnityModManager.ModEntry modEntry, bool AllowDisabling = false) - { - mod = modEntry; - allowDisabling = AllowDisabling; + /// + /// Your mod + /// Set to true if you want to create a button to disable it + public SettingsBuilder SetMod(UnityModManager.ModEntry modEntry, bool allowDisabling = false) + { + Mod = modEntry; + AllowDisabling = allowDisabling; return this; } /// /// The name of your mod to be displayed in the ModMenu dropdown. /// - /// - a Localized string containing the mod name. - /// + /// A Localized string containing the mod name. public SettingsBuilder SetModName(LocalizedString name) { - modName = name; + ModName = name; return this; } /// /// Sets the description for your mod which will be visible when hovering the mouse over the mod entry in the ModMenu dropdown. /// - /// - a Localized string containing the description. - /// + /// A Localized string containing the description. public SettingsBuilder SetModDescription(LocalizedString description) { - modDescription = description; + ModDescription = description; return this; } @@ -207,7 +200,8 @@ public SettingsBuilder AddImage(Sprite sprite, int height, float imageScale) /// Adds mod's version to the mod description shown when you hover the mouse over the mod entry in the ModMenu dropdown /// /// - /// Will be displayed only if you at least provided a Localized mod name with . + /// + /// Will be displayed only if you at least provided a Localized mod name with . /// Mod version from the source mod info (if set with /// or with ) will have higher precedence public SettingsBuilder SetModVersion(string version) @@ -233,8 +227,10 @@ public SettingsBuilder SetModAuthor(string author) /// Adds an image to the mod description shown when you hover the mouse over the mod entry in the ModMenu dropdown /// /// - /// Will be displayed only if you have a source mod info (if set with - /// or with ) or at least provided a Localized mod name with . + /// + /// Will be displayed only if you have a source mod info (if set with + /// or with ) or at least provided a Localized mod name with . + /// public SettingsBuilder SetModIllustration(Sprite image) { modIllustration = image; @@ -415,10 +411,14 @@ private SettingsBuilder Add(string key, ISettingsEntity entity, UISettingsEntity { Group.SettingsList = Settings.ToArray(); ModsMenuEntry.Info Info; - if (mod is OwlcatModification OwlMod) Info = new(OwlMod, allowDisabling, modName, modDescription, modIllustration); - else if (mod is UnityModManagerNet.UnityModManager.ModEntry UMMmod) Info = new(UMMmod, allowDisabling, modName, modDescription, modIllustration); - else if (modName is not null) Info = new(modName, modDescription, Version, Author, modIllustration); - else Info = default; + if (Mod is OwlcatModification OwlMod) + Info = new(OwlMod, AllowDisabling, ModName, ModDescription, modIllustration); + else if (Mod is UnityModManager.ModEntry UMMmod) + Info = new(UMMmod, AllowDisabling, ModName, ModDescription, modIllustration); + else if (ModName is not null) + Info = new(ModName, ModDescription, Version, Author, modIllustration); + else + Info = default; return (GroupList, SettingsEntities, Info); } @@ -583,6 +583,7 @@ public abstract class BaseSettingWithValue protected readonly string Key; protected readonly T DefaultValue; + /// /// Currently this is unused but I might add some kind of special handling later so the code is here. /// From a2dc6174ec6fa9c716d9a3faa672115c4df1b862 Mon Sep 17 00:00:00 2001 From: TylerGoeringer Date: Fri, 10 Mar 2023 08:49:06 -0800 Subject: [PATCH 26/35] More cleanup --- ModMenu/ModMenu.cs | 5 ----- ModMenu/Settings/ModsMenuEntity.cs | 1 - 2 files changed, 6 deletions(-) diff --git a/ModMenu/ModMenu.cs b/ModMenu/ModMenu.cs index 4791f2f..53ef291 100644 --- a/ModMenu/ModMenu.cs +++ b/ModMenu/ModMenu.cs @@ -56,8 +56,6 @@ public static void AddSettings(SettingsBuilder settings) /// [Obsolete("Please, use AddSettings(ModsMenuEntry entry) instead")] public static void AddSettings(UISettingsGroup settingsGroup) => ModsMenuEntity.Add(settingsGroup); - - /// /// Adds a new entry containing groups of settings to the Mods menu dropdown. @@ -78,7 +76,6 @@ public static void AddSettings(SettingsBuilder settings) [Obsolete("Please, use AddSettings(ModsMenuEntry entry) instead")] public static void AddSettings(List settingsGroup) => ModsMenuEntity.Add(settingsGroup); - /// /// Adds a new entry containing groups of settings to the Mods menu page. /// @@ -95,8 +92,6 @@ public static void AddSettings(SettingsBuilder settings) /// /// public static void AddSetting(ModsMenuEntry entry) => ModsMenuEntity.Add(entry); - - /// /// The setting with the specified , or null if it does not exist or has the wrong type. diff --git a/ModMenu/Settings/ModsMenuEntity.cs b/ModMenu/Settings/ModsMenuEntity.cs index c9e64d1..b8bb4fd 100644 --- a/ModMenu/Settings/ModsMenuEntity.cs +++ b/ModMenu/Settings/ModsMenuEntity.cs @@ -35,7 +35,6 @@ private static LocalizedString MenuTitleString } } - private static readonly List ModSettings = new(); internal static readonly List ModEntries = new(); #pragma warning disable CS0618 // Obsolete method which I myself marked as obsolete >_> From 43a11af22c3ca12dcbe18ed3446c2397804e6d59 Mon Sep 17 00:00:00 2001 From: ScaredKurufinve Date: Thu, 19 Oct 2023 02:24:24 +0300 Subject: [PATCH 27/35] All sorts of changes --- ModMenu/Main.cs | 14 +- ModMenu/ModMenu.csproj | 11 +- .../DropdownItemWithHighlightCallback.cs | 56 ++++ ModMenu/NewTypes/SettingsEntityPatches.cs | 258 +++++++++++++++++- .../UISettingsEntityDropDownModMenuEntry.cs | 25 +- ModMenu/Settings/ModsMenuEntity.cs | 12 +- ModMenu/Settings/ModsMenuEntry.cs | 149 +++++++++- ModMenu/Settings/SettingsBuilder.cs | 2 +- ModMenu/Settings/TestSettings.cs | 9 +- 9 files changed, 506 insertions(+), 30 deletions(-) create mode 100644 ModMenu/NewTypes/DropdownItemWithHighlightCallback.cs diff --git a/ModMenu/Main.cs b/ModMenu/Main.cs index 51fb334..43f988a 100644 --- a/ModMenu/Main.cs +++ b/ModMenu/Main.cs @@ -1,26 +1,33 @@ using HarmonyLib; +using Kingmaker.Blueprints.Classes.Spells; +using Kingmaker.Blueprints.JsonSystem; +using Kingmaker.Utility; +using ModMenu.Settings; using System; +using System.Linq; +using System.Reflection; using static UnityModManagerNet.UnityModManager; using static UnityModManagerNet.UnityModManager.ModEntry; namespace ModMenu { - public static class Main + internal static class Main { internal static ModLogger Logger; internal static ModEntry Entry; - private static Harmony Harmony; + internal static Harmony Harmony; public static bool Load(ModEntry modEntry) { try { + Entry = modEntry; Logger = modEntry.Logger; modEntry.OnUnload = OnUnload; Harmony = new(modEntry.Info.Id); + Harmony.DEBUG = true; Harmony.PatchAll(); - Logger.Log("Finished loading."); } catch (Exception e) @@ -55,6 +62,7 @@ static void Postfix() Logger.LogException("BlueprintsCache.Init", e); } } + } #endif } diff --git a/ModMenu/ModMenu.csproj b/ModMenu/ModMenu.csproj index ad97a5d..27009eb 100644 --- a/ModMenu/ModMenu.csproj +++ b/ModMenu/ModMenu.csproj @@ -46,9 +46,15 @@ $(SolutionDir)lib\Assembly-CSharp_public.dll + + ..\..\..\..\..\..\Program Files (x86)\Steam\steamapps\common\Pathfinder Second Adventure\Wrath_Data\Managed\Newtonsoft.Json.dll + $(SolutionDir)lib\Owlcat.Runtime.UI_public.dll + + $(SolutionDir)lib\Unity.TextMeshPro_public.dll + @@ -57,9 +63,6 @@ $(WrathPath)\Wrath_Data\Managed\Owlcat.Runtime.Validation.dll - - $(WrathPath)\Wrath_Data\Managed\Unity.TextMeshPro.dll - $(WrathPath)\Wrath_Data\Managed\UnityEngine.CoreModule.dll @@ -93,6 +96,8 @@ + + diff --git a/ModMenu/NewTypes/DropdownItemWithHighlightCallback.cs b/ModMenu/NewTypes/DropdownItemWithHighlightCallback.cs new file mode 100644 index 0000000..8e36222 --- /dev/null +++ b/ModMenu/NewTypes/DropdownItemWithHighlightCallback.cs @@ -0,0 +1,56 @@ +using Owlcat.Runtime.UI.MVVM; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using TMPro; +using UniRx.Triggers; +using UniRx; +using HarmonyLib; +using Epic.OnlineServices; +using UnityEngine.EventSystems; +using Steamworks; + +namespace ModMenu.NewTypes +{ + [HarmonyPatch] + internal class DropdownOptionWithHighlightCallback : TMP_Dropdown.OptionData + { + public List> OnMouseEnter = new(); + public List> OnMouseExit = new(); + + + [HarmonyPatch(typeof(TMP_Dropdown), nameof(TMP_Dropdown.AddItem))] + [HarmonyPostfix] + static void TMP_Dropdown_AddItem_Patch(TMP_Dropdown.OptionData data, TMP_Dropdown __instance, TMP_Dropdown.DropdownItem __result) + { + if (data is not DropdownOptionWithHighlightCallback workaround) + return; + else + { + var observer = __result.gameObject.AddComponent(); + foreach (var action in workaround.OnMouseEnter) + observer.PointerEnter += action; + foreach (var action in workaround.OnMouseExit) + observer.PointerExit += action; + } + } + + + class PointerObserverWorkaround : UIBehaviour, IPointerEnterHandler, IPointerExitHandler + { + internal event Action PointerEnter; + internal event Action PointerExit; + + public void OnPointerEnter(PointerEventData eventData) + { + PointerEnter?.Invoke(GetComponent()); + } + public void OnPointerExit(PointerEventData eventData) + { + PointerExit?.Invoke(GetComponent()); + } + } + } +} diff --git a/ModMenu/NewTypes/SettingsEntityPatches.cs b/ModMenu/NewTypes/SettingsEntityPatches.cs index 7f93045..dd0cdc8 100644 --- a/ModMenu/NewTypes/SettingsEntityPatches.cs +++ b/ModMenu/NewTypes/SettingsEntityPatches.cs @@ -1,4 +1,11 @@ using HarmonyLib; +using Kingmaker; +using Kingmaker.Blueprints.Root; +using Kingmaker.Blueprints.Root.Strings; +using Kingmaker.Localization; +using Kingmaker.Settings; +using Kingmaker.UI.Common; +using Kingmaker.UI.MVVM; using Kingmaker.UI.MVVM._PCView.ServiceWindows.Journal; using Kingmaker.UI.MVVM._PCView.Settings; using Kingmaker.UI.MVVM._PCView.Settings.Entities; @@ -15,10 +22,16 @@ using Owlcat.Runtime.UI.VirtualListSystem; using Owlcat.Runtime.UI.VirtualListSystem.ElementSettings; using System; +using System.CodeDom; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; using System.Reflection; +using System.Reflection.Emit; using TMPro; using UnityEngine; using UnityEngine.UI; +using static Kingmaker.UI.SettingsUI.UISettingsManager; using Object = UnityEngine.Object; namespace ModMenu.NewTypes @@ -28,6 +41,70 @@ internal class SettingsEntityPatches internal static readonly FieldInfo OverrideType = AccessTools.Field(typeof(VirtualListLayoutElementSettings), "m_OverrideType"); + /// + /// Patch to prevent exceptions on deserializing settings + /// + [HarmonyPatch] + static class DictionarySettingsProviderPatcher + { + [HarmonyTargetMethod] + static MethodInfo TargetMethod() + { + return typeof(DictionarySettingsProvider) + .GetMethod(nameof(DictionarySettingsProvider.GetValue)) + .MakeGenericMethod(typeof(ModsMenuEntry)); + } + + [HarmonyPrefix] + public static bool DeserializeSettingEntry(string key, ref ModsMenuEntry __result) + { + if (key.Equals(SettingsEntityModMenuEntry.instance.Key)) + { + __result = ModsMenuEntry.EmptyInstance; + return false; + } + return true; + } + } + + /// + /// Patch to change the way dropdown options are generated so that the settings description would show individual mod descriptions. + /// + [HarmonyPatch] + static class SettingsEntityDropdownPCView_Patch + { + [HarmonyPatch(typeof(SettingsEntityDropdownPCView), nameof(SettingsEntityDropdownPCView.SetupDropdown))] + static bool Prefix(SettingsEntityDropdownPCView __instance) + { + if (__instance.ViewModel.m_UISettingsEntity is not UISettingsEntityDropdownModMenuEntry) return true; + + else + __instance.Dropdown.gameObject.SetActive(true); + __instance.Dropdown.ClearOptions(); + + List options = new(); + var vm = GameObject.Find("CommonPCView(Clone)/Canvas/SettingsView/")?.GetComponent()?.ViewModel; + foreach (var modEntry in ModsMenuEntity.ModEntries) + { + options.Add( + new DropdownOptionWithHighlightCallback() + { + m_Text = modEntry.ModInfo.ModName, + OnMouseEnter = new() { new(_ => { + if (vm is null) + Main.Logger.Warning("SettingsEntityDropdownPCView_Patch - settings VM is null!"); + else + vm.HandleShowSettingsDescription( + title: UIUtility.GetSaberBookFormat(modEntry.ModInfo.ModName, default(Color), 140, null, 0f), + description: modEntry.ModInfo.GenerateDescription()); + })} + }); + } + __instance.Dropdown.AddOptions(options); + return false; + } + } + /// /// Patch to return the correct view model for /// @@ -82,9 +159,11 @@ static bool Prefix(UISettingsManager.SettingsScreen settingsScreen, SettingsVM _ __instance.m_SettingEntities.Clear(); __instance.m_SettingEntities.Add(__instance.AddDisposableAndReturn(SettingsVM.GetVMForSettingsItem(UISettingsEntityDropdownModMenuEntry.instance))); - __instance.m_SettingEntities.Add(__instance.AddDisposableAndReturn(SettingsVM.GetVMForSettingsItem(new UISettingsEntitySeparator()))); + if (UISettingsEntityDropdownModMenuEntry.instance.Setting.GetTempValue() == ModsMenuEntry.EmptyInstance) + return false; + //__instance.m_SettingEntities.Add(__instance.AddDisposableAndReturn(SettingsVM.GetVMForSettingsItem(separator))); - //Here should be a toggle for mod disabling, but do we need it? + //Here should be a toggle for mod disabling, but do we need it? SettingsEntitySubHeaderVM subheader; foreach (var uisettingsGroup in ModsMenuEntity.CollectSettingGroups) { @@ -369,6 +448,181 @@ private static SettingsEntityDropdownButtonView CreateDropdownButtonTemplate( return templatePrefab; } + + } + + [HarmonyPatch] + internal static class DefaultButtonPatcher + { + [HarmonyPatch(typeof(SettingsVM), nameof(SettingsVM.SetSettingsList))] + [HarmonyTranspiler] + static IEnumerable SettingsVM_SetSettingsList_Transpiler_ToEnableDefaultButtonOnModsTab(IEnumerable instructions) + { + var _inst = instructions.ToList(); + int length = _inst.Count; + int index = -1; + for (int i = 0; i < length; i++) + { + if ( + _inst[i + 0].opcode == OpCodes.Ldloc_0 && + _inst[i + 1].opcode == OpCodes.Ldfld && _inst[i + 1].operand is FieldInfo fi && fi.Name.Contains("settingsScreen") && + _inst[i + 2].opcode == OpCodes.Ldc_I4_4 && + _inst[i + 3].opcode == OpCodes.Beq_S || _inst[i + 3].opcode == OpCodes.Beq) + { + index = i; + break; + } + } + + if (index == -1) + { + Main.Logger.Error("DefaultButtonPatcher - failed to find the index when transpile SettingsVM.SetSettingsList. Default button will not be enabled on the Mods tab of settings screen."); + return instructions; + } + + _inst.InsertRange(index + 4, new CodeInstruction[4] { + new (_inst[index + 0]), + new (_inst[index + 1]), + new (OpCodes.Ldc_I4, ModsMenuEntity.SettingsScreenValue), + new (_inst[index + 3]), + }); + + return _inst; + } + + /// + /// Will make Default button affect the mod selected on the Mod tab + /// + /// + [HarmonyPatch(typeof(SettingsController), nameof(SettingsController.ResetToDefault))] + [HarmonyTranspiler] + static IEnumerable SettingsController_ResetToDefault_Transpiler_ToCollectModSettings(IEnumerable instructions, ILGenerator gen) + { + var _inst = instructions.ToList(); + int length = _inst.Count; + int index = -1; + FieldInfo settingsManagerInfo = typeof(Kingmaker.Game).GetField(nameof(Kingmaker.Game.UISettingsManager)); + MethodInfo gameGetter = typeof(Kingmaker.Game).GetProperty(nameof(Kingmaker.Game.Instance)).GetMethod; + + + for (int i = 0; i < length; i++) + { + if ( + ((_inst[i + 0].opcode == OpCodes.Call || _inst[i + 0].opcode == OpCodes.Callvirt) && _inst[i + 0].operand is MethodInfo mi1 && mi1 == gameGetter) && + (_inst[i + 1].opcode == OpCodes.Ldfld && _inst[i + 1].operand is FieldInfo fi && fi == settingsManagerInfo) && + _inst[i + 2].opcode == OpCodes.Ldarg_0 && + _inst[i + 3].opcode == OpCodes.Newobj && + ((_inst[i + 4].opcode == OpCodes.Call || _inst[i + 4].opcode == OpCodes.Callvirt) && _inst[i + 4].operand is MethodInfo mi2 && mi2.Name.Contains("GetSettingsList"))) + { + index = i; + break; + } + } + + if (index == -1) + { + Main.Logger.Error("DefaultButtonPatcher - failed to find the index when transpile SettingsController.ResetToDefault. Default button will do nothing on the Mods tab."); + return instructions; + } + + Label labelNotMods = gen.DefineLabel(); + _inst[index].labels.Add(labelNotMods); + + Label labelIsMods = gen.DefineLabel(); + _inst[index+5].labels.Add(labelIsMods); + + MethodInfo mi = typeof(Enumerable).GetMethod(nameof(Enumerable.ToList)).MakeGenericMethod(typeof(UISettingsGroup)); + + _inst.InsertRange(index, new CodeInstruction[] { + new CodeInstruction(OpCodes.Ldarg_0), + //CodeInstruction.Call((UISettingsManager.SettingsScreen e) => Convert.ToInt32(e)), //WHY DOES IT NOT WORK?!?!?!?!?! + //new CodeInstruction(OpCodes.Ldc_I4, ModsMenuEntity.SettingsScreenValue), + //new CodeInstruction(OpCodes.Ceq), + CodeInstruction.Call((UISettingsManager.SettingsScreen e) => AnotherScreenCheck(e)), + new CodeInstruction(OpCodes.Brfalse_S, labelNotMods), + new CodeInstruction(OpCodes.Call, typeof(ModsMenuEntity).GetProperty(nameof(ModsMenuEntity.CollectSettingGroups), BindingFlags.Static | BindingFlags.NonPublic).GetMethod), + new CodeInstruction(OpCodes.Callvirt, mi), + new CodeInstruction(OpCodes.Br_S, labelIsMods) + });; + + return _inst; + } + + static bool AnotherScreenCheck(UISettingsManager.SettingsScreen e) => e == (UISettingsManager.SettingsScreen)ModsMenuEntity.SettingsScreenValue; + + [HarmonyPatch(typeof(SettingsVM), nameof(SettingsVM.OpenDefaultSettingsDialog))] + [HarmonyTranspiler] + static IEnumerable SettingsVM_OpenDefaultSettingsDialog_Transpiler_ToChangeDefaultDialogMessage(IEnumerable instructions, ILGenerator gen) + { + var _inst = instructions.ToList(); + int length = _inst.Count; + int indexStart = -1; + int indexEnd = -1; + //var newDefaultMessage = Helpers.CreateString("ModsMenu_NewDefaultButtonMessage", "this is a message for {0}"); + string newDefaultMessage = "Revert all settings of the mod \"{0}\" to their default values?"; + + for (int i = 0; i < length; i++) + { + if ( + _inst[i].Calls(typeof(Kingmaker.Game).GetProperty(nameof(Kingmaker.Game.Instance)).GetMethod) && + _inst[i + 1].Calls(typeof(Kingmaker.Game).GetProperty(nameof(Kingmaker.Game.BlueprintRoot)).GetMethod) && + _inst[i + 2].opcode == OpCodes.Ldfld && _inst[i + 2].operand is FieldInfo fi1 && fi1 == AccessTools.Field(typeof(BlueprintRoot), nameof(BlueprintRoot.LocalizedTexts)) && + _inst[i + 3].opcode == OpCodes.Ldfld && _inst[i + 3].operand is FieldInfo fi2 && fi2 == AccessTools.Field(typeof(LocalizedTexts), nameof(LocalizedTexts.UserInterfacesText)) && + _inst[i + 4].opcode == OpCodes.Ldfld && _inst[i + 4].operand is FieldInfo fi3 && fi3 == AccessTools.Field(typeof(UIStrings), nameof(UIStrings.SettingsUI)) && + _inst[i + 5].opcode == OpCodes.Ldfld && _inst[i + 5].operand is FieldInfo fi4 && fi4 == AccessTools.Field(typeof(UITextSettingsUI), nameof(UITextSettingsUI.RestoreAllDefaultsMessage)) + ) + { + indexStart = i; + break; + } + } + + if (indexStart == -1) + { + Main.Logger.Error("DefaultButtonPatcher - failed to find the starting index when transpile SettingsVM.OpenDefaultSettingsDialog. Default button message will not be altered."); + return instructions; + } + + for (int i = indexStart + 6; i < length; i++) + { + if ( + _inst[i].opcode == OpCodes.Call && _inst[i].operand is MethodInfo { Name: nameof(string.Format)} && + _inst[i + 1].opcode == OpCodes.Stfld && _inst[i + 1].operand is FieldInfo { Name: "text" } + ) + { + indexEnd = i; + break; + } + } + + if (indexEnd == -1) + { + Main.Logger.Error("DefaultButtonPatcher - failed to find the ending index when transpile SettingsVM.OpenDefaultSettingsDialog. Default button message will not be altered."); + return instructions; + } + + Label labelNotMod = gen.DefineLabel(); + _inst[indexStart].labels.Add(labelNotMod); + + Label labelIsMod = gen.DefineLabel(); + _inst[indexEnd +1].labels.Add(labelIsMod); + + _inst.InsertRange(indexStart, new CodeInstruction[] + { + CodeInstruction.Call(() => CheckForSelectedSettingsScreenType()), + new CodeInstruction(OpCodes.Brfalse_S, labelNotMod), + new CodeInstruction(OpCodes.Ldstr, newDefaultMessage), + CodeInstruction.Call(() => GiveMeName()), + CodeInstruction.Call(() => string.Format(newDefaultMessage, SettingsEntityModMenuEntry.instance.m_TempValue.ModInfo.ModName)), + new CodeInstruction(OpCodes.Br_S, labelIsMod) + }); + + return _inst; + + } + static bool CheckForSelectedSettingsScreenType() => RootUIContext.Instance?.CommonVM.SettingsVM.Value?.SelectedMenuEntity.Value?.SettingsScreenType == (UISettingsManager.SettingsScreen)ModsMenuEntity.SettingsScreenValue; + + static string GiveMeName() => SettingsEntityModMenuEntry.instance.m_TempValue.ModInfo.ModName; } } } \ No newline at end of file diff --git a/ModMenu/NewTypes/UISettingsEntityDropDownModMenuEntry.cs b/ModMenu/NewTypes/UISettingsEntityDropDownModMenuEntry.cs index 503a53a..0c74394 100644 --- a/ModMenu/NewTypes/UISettingsEntityDropDownModMenuEntry.cs +++ b/ModMenu/NewTypes/UISettingsEntityDropDownModMenuEntry.cs @@ -1,4 +1,9 @@ -using Kingmaker.UI.SettingsUI; +using HarmonyLib; +using Kingmaker.Localization; +using Kingmaker.Settings; +using Kingmaker.UI.MVVM._VM.Settings; +using Kingmaker.UI.MVVM._VM.Settings.Entities; +using Kingmaker.UI.SettingsUI; using ModMenu.Settings; using System; using System.Collections.Generic; @@ -7,17 +12,29 @@ namespace ModMenu.NewTypes { + [HarmonyLib.HarmonyPatch] internal class UISettingsEntityDropdownModMenuEntry : UISettingsEntityDropdown { static UISettingsEntityDropdownModMenuEntry() { - ((IUISettingsEntityDropdown) instance).OnTempIndexValueChanged += - new Action(ModIndex => ModsMenuEntity.settingVM.SwitchSettingsScreen(ModsMenuEntity.SettingsScreenId)); + instance.m_Description = Helpers.CreateString("UISettingsEntityDropdownModMenuEntry.Description", "Choose your mod", ruRU: "Выберите мод"); instance.LinkSetting(SettingsEntityModMenuEntry.instance); + + ((IUISettingsEntityDropdown) instance).OnTempIndexValueChanged += + new (ModIndex => ModsMenuEntity.settingVM.SwitchSettingsScreen(ModsMenuEntity.SettingsScreenId)); + + ((IUISettingsEntityDropdown) instance).OnTempIndexValueChanged += + new (_ => + { + SettingsController.RemoveFromConfirmationList(instance.SettingsEntity, false); + SettingsEntityModMenuEntry.instance.TempValueIsConfirmed = true; + }); + } internal static UISettingsEntityDropdownModMenuEntry instance = ScriptableObject.CreateInstance(); + public override List LocalizedValues { get @@ -41,5 +58,7 @@ public override void SetIndexTempValue(int value) SetTempValue(ModsMenuEntity.ModEntries[value]); } + + } } diff --git a/ModMenu/Settings/ModsMenuEntity.cs b/ModMenu/Settings/ModsMenuEntity.cs index b8bb4fd..f2fc4b2 100644 --- a/ModMenu/Settings/ModsMenuEntity.cs +++ b/ModMenu/Settings/ModsMenuEntity.cs @@ -19,9 +19,10 @@ namespace ModMenu.Settings internal class ModsMenuEntity { // Random magic number representing our fake enum for UiSettingsManager.SettingsScreen - private const int SettingsScreenValue = 17; + internal const int SettingsScreenValue = 17; internal static readonly UISettingsManager.SettingsScreen SettingsScreenId = (UISettingsManager.SettingsScreen)SettingsScreenValue; + internal static SettingsVM settingVM; private static LocalizedString _menuTitleString; @@ -41,21 +42,27 @@ private static LocalizedString MenuTitleString internal static void Add(UISettingsGroup uiSettingsGroup) { ModEntries.Add(new(uiSettingsGroup)); + //if (ModEntries.Contains(ModsMenuEntry.EmptyInstance)) + // ModEntries.Remove(ModsMenuEntry.EmptyInstance); } internal static void Add(List uiSettingsGroup) { ModEntries.Add(new(uiSettingsGroup)); + //if (ModEntries.Contains(ModsMenuEntry.EmptyInstance)) + // ModEntries.Remove(ModsMenuEntry.EmptyInstance); } #pragma warning restore CS0618 // Тип или член устарел internal static void Add(ModsMenuEntry modEntry) { ModEntries.Add(modEntry); + //if (ModEntries.Contains(ModsMenuEntry.EmptyInstance)) + // ModEntries.Remove(ModsMenuEntry.EmptyInstance); } internal static IEnumerable CollectSettingGroups => - UISettingsEntityDropdownModMenuEntry.instance.Setting.m_CurrentValue.ModSettings; + UISettingsEntityDropdownModMenuEntry.instance.Setting.m_TempValue.ModSettings; /// /// Patch to create the Mods Menu ViewModel. @@ -113,6 +120,7 @@ private static void AddMenuEntity(SettingsVM settings) } } + /// /// Patch to create the Mods Menu View. Needed to show the menu in-game. /// diff --git a/ModMenu/Settings/ModsMenuEntry.cs b/ModMenu/Settings/ModsMenuEntry.cs index 22acd85..a3d0a4a 100644 --- a/ModMenu/Settings/ModsMenuEntry.cs +++ b/ModMenu/Settings/ModsMenuEntry.cs @@ -1,9 +1,11 @@ using JetBrains.Annotations; using Kingmaker.Localization; +using Kingmaker.Localization.Shared; using Kingmaker.Modding; using Kingmaker.UI.SettingsUI; using Kingmaker.Utility; using System; +using System.CodeDom; using System.Collections.Generic; using System.Linq; using UnityEngine; @@ -15,17 +17,116 @@ namespace ModMenu.Settings /// Wrapper class used to display mod's settings in the ModMenu dropdown. Contains a list of UI Setting Groups and /// modification's info such as name. /// - public class ModsMenuEntry + public class ModsMenuEntry : IConvertible { #pragma warning disable CS1591 // stupid documentation requests + #region Conversion + public TypeCode GetTypeCode() + { + return TypeCode.Int32; + } + + public bool ToBoolean(IFormatProvider provider) + { + return false; + } + + public char ToChar(IFormatProvider provider) + { + return (char)0; + } + + public sbyte ToSByte(IFormatProvider provider) + { + return 0; + } + + public byte ToByte(IFormatProvider provider) + { + return 0; + } + + public short ToInt16(IFormatProvider provider) + { + return 0; + } + + public ushort ToUInt16(IFormatProvider provider) + { + return 0; + } + + public int ToInt32(IFormatProvider provider) + { + return 0; + } + + public uint ToUInt32(IFormatProvider provider) + { + return 0; + } + + public long ToInt64(IFormatProvider provider) + { + return 0; + } + + public ulong ToUInt64(IFormatProvider provider) + { + return 0; + } + + public float ToSingle(IFormatProvider provider) + { + return 0; + } + + public double ToDouble(IFormatProvider provider) + { + return 0; + } + + public decimal ToDecimal(IFormatProvider provider) + { + return 0; + } + + public DateTime ToDateTime(IFormatProvider provider) + { + throw new NotImplementedException(); + } + + public string ToString(IFormatProvider provider) + { + return "0"; + } + + public object ToType(Type conversionType, IFormatProvider provider) + { + if (conversionType == typeof(int)) + return 0; + throw new NotImplementedException(); + } + #endregion #pragma warning disable CS0618 // Method is obolete. I know! I made it obsolete! - internal static ModsMenuEntry EmptyInstance = - new(new UISettingsGroup() { Title = new() { m_Key = "" }, SettingsList = Array.Empty() }); + static ModsMenuEntry() + { + ModsMenuEntity.Add(EmptyInstance); + } + + internal static ModsMenuEntry EmptyInstance = new(); internal readonly IEnumerable ModSettings; internal readonly Info ModInfo; - internal ModsMenuEntry() => ModInfo = new(Helpers.EmptyString, Helpers.EmptyString); + internal ModsMenuEntry() + { + ModInfo = new(Helpers.EmptyString, Helpers.EmptyString); + UISettingsGroup pseudoGroup = ScriptableObject.CreateInstance(); + pseudoGroup.Title = Helpers.EmptyString; + ModSettings = new UISettingsGroup[1]{ pseudoGroup }; + + } /// /// Creates a simpliest ModEntry out of a single UI setting group. @@ -49,7 +150,7 @@ public ModsMenuEntry([NotNull]UISettingsGroup settingGroup) } ModSettings = new UISettingsGroup[1] {settingGroup}; - ModInfo = new(settingGroup.Title); + ModInfo = new(settingGroup.Title); } /// @@ -126,6 +227,8 @@ public struct Info public LocalizedString LocalizedModDescription { get; private set; } public string NonLocalizedModDescription { get; private set; } private string ModDescription { get { return LocalizedModDescription ?? NonLocalizedModDescription; } } + private string m_CachedDescription; + private Locale m_LastLocale; internal bool AllowModDisabling { get; set; } internal OwlcatModification OwlMod { get; } internal UnityModManager.ModEntry UMMMod { get; } @@ -284,16 +387,32 @@ public Info( internal string GenerateDescription() { - string result = ModDescription; - if (!string.IsNullOrEmpty(VersionNumber)) - result = $"{result} ({stringVer}: {VersionNumber})"; - - result = $"{result}\n"; - if (!string.IsNullOrEmpty(AuthorName)) - result = string.Concat(result, $"{stringAuthor}: {AuthorName}\n"); - - string.Concat(result, LocalizedModDescription); - return result; + if (!m_CachedDescription.IsNullOrEmpty() && m_LastLocale == LocalizationManager.CurrentLocale) + return m_CachedDescription; + + else + try + { + string result = ""; + if (!string.IsNullOrEmpty(AuthorName)) + result += $"{stringAuthor}: {AuthorName}\n"; + + if (!string.IsNullOrEmpty(VersionNumber)) + result += $"({stringVer}: {VersionNumber})\n"; + + //result = $"{result}\n"; + result += "\n"; + result += $"{ModDescription}"; + m_CachedDescription= result; + m_LastLocale = LocalizationManager.CurrentLocale; + return result; + } + catch(Exception ex) + { + Main.Logger.Log("We fucked up generating description!"); + Main.Logger.LogException(ex); + return "We fucked up generating description!"; + } } } } diff --git a/ModMenu/Settings/SettingsBuilder.cs b/ModMenu/Settings/SettingsBuilder.cs index 220d798..1c2cedd 100644 --- a/ModMenu/Settings/SettingsBuilder.cs +++ b/ModMenu/Settings/SettingsBuilder.cs @@ -418,7 +418,7 @@ private SettingsBuilder Add(string key, ISettingsEntity entity, UISettingsEntity else if (ModName is not null) Info = new(ModName, ModDescription, Version, Author, modIllustration); else - Info = default; + Info = new(GroupList.ElementAt(0)?.Title ?? ""); return (GroupList, SettingsEntities, Info); } diff --git a/ModMenu/Settings/TestSettings.cs b/ModMenu/Settings/TestSettings.cs index a7f989d..8c8948f 100644 --- a/ModMenu/Settings/TestSettings.cs +++ b/ModMenu/Settings/TestSettings.cs @@ -1,4 +1,10 @@ -namespace ModMenu.Settings +using Kingmaker.Localization; +using Kingmaker.UI.SettingsUI; +using System.Text; +using UnityEngine; +using static Kingmaker.UI.KeyboardAccess; + +namespace ModMenu.Settings { #if DEBUG /// @@ -22,6 +28,7 @@ internal void Initialize() ModMenu.AddSettings( SettingsBuilder.New(RootKey, CreateString("title", "Testing settings")) .SetMod(Main.Entry) + .SetModDescription(Helpers.CreateString("test-settings-desc", "This is a test description for mod and let's make it a bit longer to take several lines.")) .AddImage(Helpers.CreateSprite("ModMenu.WittleWolfie.png"), 250) .AddDefaultButton(OnDefaultsApplied) .AddButton( From af7e54a923356b7d51e53527fca879d2da57c5d3 Mon Sep 17 00:00:00 2001 From: ScaredKurufinve Date: Sat, 21 Oct 2023 01:28:37 +0300 Subject: [PATCH 28/35] Added a safety check for Localization Manager initialized state to avoid any possible NRE when accessing CurrentPack during when calling CreateString. strings will be registered later anyway when the first pack is loaded. Added another check for a -returned value from Localized string in the Register method (just in case). And just generally formatted it more to my liking. Sorry :( --- ModMenu/Helpers.cs | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/ModMenu/Helpers.cs b/ModMenu/Helpers.cs index 4d4b911..5ce76d0 100644 --- a/ModMenu/Helpers.cs +++ b/ModMenu/Helpers.cs @@ -1,6 +1,7 @@ using HarmonyLib; using Kingmaker.Localization; using Kingmaker.Localization.Shared; +using Kingmaker.Utility; using System; using System.Collections.Generic; using System.Reflection; @@ -16,11 +17,12 @@ internal static class Helpers private static readonly List Strings = new(); internal static LocalizedString EmptyString = CreateString("", ""); - internal static LocalizedString CreateString(string key, string enGB, string ruRU = "") + internal static LocalizedString CreateString(string key, string enGB, string ruRU = null) { var localString = new LocalString(key, enGB, ruRU); Strings.Add(localString); - localString.Register(); + if (LocalizationManager.Initialized) + localString.Register(); return localString.LocalizedString; } @@ -41,6 +43,7 @@ private class LocalString public readonly LocalizedString LocalizedString; private readonly string enGB; private readonly string ruRU; + const string NullString = ""; public LocalString(string key, string enGB, string ruRU) { @@ -51,14 +54,23 @@ public LocalString(string key, string enGB, string ruRU) public void Register() { - var localized = enGB; - switch (LocalizationManager.CurrentPack.Locale) + string localized; + if (LocalizationManager.CurrentPack.Locale == Locale.enGB) { - case Locale.ruRU: - if (!string.IsNullOrEmpty(ruRU)) - localized = ruRU; - break; + localized = enGB; + goto putString; } + + localized = (LocalizationManager.CurrentPack.Locale) switch + { + Locale.ruRU => ruRU, + _ => "" + }; + + if (localized.IsNullOrEmpty() || localized == NullString) + localized = enGB; + + ;putString: LocalizationManager.CurrentPack.PutString(LocalizedString.m_Key, localized); } } From 436e1fa22b899b18569bc7bbe0f5d26a0775af92 Mon Sep 17 00:00:00 2001 From: ScaredKurufinve Date: Sat, 21 Oct 2023 01:32:18 +0300 Subject: [PATCH 29/35] Fixed the constructor of SettingsEntityModMenuEntry to be properly private, because it is meant to be used only internally for creation of the static instance. --- ModMenu/NewTypes/SettingsEntityModMenuEntry.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ModMenu/NewTypes/SettingsEntityModMenuEntry.cs b/ModMenu/NewTypes/SettingsEntityModMenuEntry.cs index e734c5a..09cb1c1 100644 --- a/ModMenu/NewTypes/SettingsEntityModMenuEntry.cs +++ b/ModMenu/NewTypes/SettingsEntityModMenuEntry.cs @@ -6,6 +6,6 @@ namespace ModMenu.NewTypes internal class SettingsEntityModMenuEntry : SettingsEntity { internal static SettingsEntityModMenuEntry instance = new("modsmenu.entrystaticinstance", ModsMenuEntry.EmptyInstance); - public SettingsEntityModMenuEntry(string key, ModsMenuEntry defaultValue) : base(key, defaultValue, false, false, false) {} + private SettingsEntityModMenuEntry(string key, ModsMenuEntry defaultValue) : base(key, defaultValue, false, false, false) {} } } From 91d13d96508f18325c56f5fcdbac40bc66d041ca Mon Sep 17 00:00:00 2001 From: ScaredKurufinve Date: Sat, 21 Oct 2023 01:35:59 +0300 Subject: [PATCH 30/35] Made it so that former Collapsible Headers VMs return regular Header Views for the sake of backward compatibility (their place now is taken by former Collapsible Subheaders). Also made a couple of Default Button transpilers prettier. --- ModMenu/NewTypes/SettingsEntityPatches.cs | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/ModMenu/NewTypes/SettingsEntityPatches.cs b/ModMenu/NewTypes/SettingsEntityPatches.cs index dd0cdc8..bb02196 100644 --- a/ModMenu/NewTypes/SettingsEntityPatches.cs +++ b/ModMenu/NewTypes/SettingsEntityPatches.cs @@ -167,7 +167,7 @@ static bool Prefix(UISettingsManager.SettingsScreen settingsScreen, SettingsVM _ SettingsEntitySubHeaderVM subheader; foreach (var uisettingsGroup in ModsMenuEntity.CollectSettingGroups) { - __instance.m_SettingEntities.Add(__instance.AddDisposableAndReturn(new SettingsEntityCollapsibleHeaderVM(uisettingsGroup.Title))); + __instance.m_SettingEntities.Add(__instance.AddDisposableAndReturn(new SettingsEntityHeaderVM(uisettingsGroup.Title))); subheader = null; foreach (UISettingsEntityBase uisettingsEntityBase in uisettingsGroup.VisibleSettingsList) { @@ -552,14 +552,16 @@ static IEnumerable SettingsController_ResetToDefault_Transpiler [HarmonyPatch(typeof(SettingsVM), nameof(SettingsVM.OpenDefaultSettingsDialog))] [HarmonyTranspiler] - static IEnumerable SettingsVM_OpenDefaultSettingsDialog_Transpiler_ToChangeDefaultDialogMessage(IEnumerable instructions, ILGenerator gen) + static internal IEnumerable SettingsVM_OpenDefaultSettingsDialog_Transpiler_ToChangeDefaultDialogMessage(IEnumerable instructions, ILGenerator gen) { var _inst = instructions.ToList(); int length = _inst.Count; int indexStart = -1; int indexEnd = -1; - //var newDefaultMessage = Helpers.CreateString("ModsMenu_NewDefaultButtonMessage", "this is a message for {0}"); - string newDefaultMessage = "Revert all settings of the mod \"{0}\" to their default values?"; + newDefaultMessage = Helpers.CreateString( + key: "ModsMenuNewDefaultButtonMessage", + enGB: "Revert all settings of the mod {0} to their default values?", + ruRU: "Вернуть все настройки для мода {0} к их значениям по-умолчанию?"); for (int i = 0; i < length; i++) { @@ -611,18 +613,19 @@ static IEnumerable SettingsVM_OpenDefaultSettingsDialog_Transpi { CodeInstruction.Call(() => CheckForSelectedSettingsScreenType()), new CodeInstruction(OpCodes.Brfalse_S, labelNotMod), - new CodeInstruction(OpCodes.Ldstr, newDefaultMessage), - CodeInstruction.Call(() => GiveMeName()), - CodeInstruction.Call(() => string.Format(newDefaultMessage, SettingsEntityModMenuEntry.instance.m_TempValue.ModInfo.ModName)), + CodeInstruction.Call(() => MakeMeDefaultButtonMessage()), new CodeInstruction(OpCodes.Br_S, labelIsMod) }); return _inst; - } + static LocalizedString newDefaultMessage; static bool CheckForSelectedSettingsScreenType() => RootUIContext.Instance?.CommonVM.SettingsVM.Value?.SelectedMenuEntity.Value?.SettingsScreenType == (UISettingsManager.SettingsScreen)ModsMenuEntity.SettingsScreenValue; - static string GiveMeName() => SettingsEntityModMenuEntry.instance.m_TempValue.ModInfo.ModName; + static string MakeMeDefaultButtonMessage() + { + return string.Format(newDefaultMessage, SettingsEntityModMenuEntry.instance.m_TempValue.ModInfo.ModName); + } } } } \ No newline at end of file From c553ede45083f87037ef47c4f1c1ec9322d8d317 Mon Sep 17 00:00:00 2001 From: ScaredKurufinve Date: Sat, 21 Oct 2023 01:38:49 +0300 Subject: [PATCH 31/35] Added a missing empty tooltip description to the Empty instance (so that the description view not show ). Also moved the creation of the instance inside the actual static constructor to make it prettier. (Is it?) --- ModMenu/NewTypes/UISettingsEntityDropDownModMenuEntry.cs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/ModMenu/NewTypes/UISettingsEntityDropDownModMenuEntry.cs b/ModMenu/NewTypes/UISettingsEntityDropDownModMenuEntry.cs index 0c74394..ca598c6 100644 --- a/ModMenu/NewTypes/UISettingsEntityDropDownModMenuEntry.cs +++ b/ModMenu/NewTypes/UISettingsEntityDropDownModMenuEntry.cs @@ -17,7 +17,11 @@ internal class UISettingsEntityDropdownModMenuEntry : UISettingsEntityDropdown(); + internal static UISettingsEntityDropdownModMenuEntry instance; public override List LocalizedValues { From 14fa201753c0f3abbb333a286be43b8b2ffa6fc8 Mon Sep 17 00:00:00 2001 From: ScaredKurufinve Date: Sat, 21 Oct 2023 01:40:45 +0300 Subject: [PATCH 32/35] Fixed a horrible bug where the builder would not clean the settings buffer after a new settings group has been declared. --- ModMenu/Settings/SettingsBuilder.cs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/ModMenu/Settings/SettingsBuilder.cs b/ModMenu/Settings/SettingsBuilder.cs index 1c2cedd..6c2e083 100644 --- a/ModMenu/Settings/SettingsBuilder.cs +++ b/ModMenu/Settings/SettingsBuilder.cs @@ -14,6 +14,7 @@ namespace ModMenu.Settings { +#pragma warning disable CS1591 // stupid documentation requests /// /// Builder API for constructing settings. /// @@ -120,7 +121,11 @@ public SettingsBuilder AddAnotherSettingsGroup(string key, LocalizedString title var group = ScriptableObject.CreateInstance(); group.name = key; group.Title= title; - if (Settings?.Count > 0) Group.SettingsList = Settings.ToArray(); + if (Settings?.Count > 0) + { + Group.SettingsList = Settings.ToArray(); + Settings.RemoveRange(0, Settings.Count - 1); + } GroupList.Add(group); Group = group; return this; From 69440f4717e69755d79c091a053506a96197fc70 Mon Sep 17 00:00:00 2001 From: ScaredKurufinve Date: Sat, 21 Oct 2023 01:42:03 +0300 Subject: [PATCH 33/35] Fixed a stupid bug with the order of ModEntry constructor calls causing only the first settings group passed to the constructor was actually stored. --- ModMenu/Settings/ModsMenuEntry.cs | 65 ++++++++++++++++--------------- 1 file changed, 33 insertions(+), 32 deletions(-) diff --git a/ModMenu/Settings/ModsMenuEntry.cs b/ModMenu/Settings/ModsMenuEntry.cs index a3d0a4a..1dcefae 100644 --- a/ModMenu/Settings/ModsMenuEntry.cs +++ b/ModMenu/Settings/ModsMenuEntry.cs @@ -1,4 +1,5 @@ -using JetBrains.Annotations; +using Epic.OnlineServices.Mods; +using JetBrains.Annotations; using Kingmaker.Localization; using Kingmaker.Localization.Shared; using Kingmaker.Modding; @@ -10,6 +11,7 @@ using System.Linq; using UnityEngine; using UnityModManagerNet; +using static UnityModManagerNet.UnityModManager; namespace ModMenu.Settings { @@ -108,26 +110,20 @@ public object ToType(Type conversionType, IFormatProvider provider) throw new NotImplementedException(); } #endregion -#pragma warning disable CS0618 // Method is obolete. I know! I made it obsolete! static ModsMenuEntry() { + Info info = new(Helpers.EmptyString, Helpers.EmptyString); + UISettingsGroup pseudoGroup = ScriptableObject.CreateInstance(); + pseudoGroup.Title = Helpers.EmptyString; + EmptyInstance = new(info, pseudoGroup); ModsMenuEntity.Add(EmptyInstance); } - internal static ModsMenuEntry EmptyInstance = new(); + internal static ModsMenuEntry EmptyInstance; internal readonly IEnumerable ModSettings; internal readonly Info ModInfo; - internal ModsMenuEntry() - { - ModInfo = new(Helpers.EmptyString, Helpers.EmptyString); - UISettingsGroup pseudoGroup = ScriptableObject.CreateInstance(); - pseudoGroup.Title = Helpers.EmptyString; - ModSettings = new UISettingsGroup[1]{ pseudoGroup }; - - } - /// /// Creates a simpliest ModEntry out of a single UI setting group. /// Mod entry will use the group's title as displayed name or will be called anonymous if title is empty @@ -161,7 +157,22 @@ public ModsMenuEntry([NotNull]UISettingsGroup settingGroup) /// settingGroups argument must not be null, have at least 1 group in it and none can be null /// [Obsolete("Use ModsMenuEntry(Info modInfo, IEnumerable settingGroups). You will not be able to change ModInfo later.")] - public ModsMenuEntry(IEnumerable settingGroups) + public ModsMenuEntry(IEnumerable settingGroups) : this(default(Info), settingGroups) + { + } + + /// + /// settingGroups argument must not be null, have at least 1 group in it and none can be null + /// + public ModsMenuEntry(Info modInfo, [NotNull]UISettingsGroup settingGroup) : this(modInfo, new UISettingsGroup[] { settingGroup }) + { + + } + + /// + /// settingGroups argument must not be null, have at least 1 group in it and none can be null + /// + public ModsMenuEntry(Info modInfo, [NotNull] IEnumerable settingGroups) { if (settingGroups is null || settingGroups.Count() == 0) { @@ -172,25 +183,16 @@ public ModsMenuEntry(IEnumerable settingGroups) throw new ArgumentException("Cannot create ModsMenuEntry with a null settingsGroup."); } - UISettingsGroup firstGroup = settingGroups.ElementAt(0); - if (firstGroup.SettingsList.Length == 0) + ModSettings = settingGroups; + + if (!modInfo.Equals(default(Info))) + ModInfo = modInfo; + else { - string name = ("titled " + firstGroup.Title) ?? "without a title"; - throw new ArgumentException($"UISettingsGroup {name} is trying to create a ModsMenuEntry without mod info."); + string title = settingGroups.ElementAt(0)?.Title; + if (title.IsNullOrEmpty()) + ModInfo = new(title); } - - ModSettings = new UISettingsGroup[1] { firstGroup }; - ModInfo = new(firstGroup.Title); - } - - public ModsMenuEntry(Info modInfo, UISettingsGroup settingGroup) : this(settingGroup) - { - ModInfo = modInfo; - } - - public ModsMenuEntry(Info modInfo, IEnumerable settingGroups) : this(settingGroups) - { - ModInfo = modInfo; } /// @@ -202,9 +204,8 @@ public ModsMenuEntry(Info modInfo, IEnumerable settingGroups) : /// /// You can't create a ModEntry out of a null settings group ¯\_(ツ)_/¯ /// - public ModsMenuEntry(LocalizedString modName, [NotNull]UISettingsGroup settingGroup) : this(settingGroup) + public ModsMenuEntry(LocalizedString modName, [NotNull]UISettingsGroup settingGroup) : this(new Info(modName), settingGroup) { - ModInfo = new(modName); } /// From 2e431ea5bcd3f69a7f95054950e77fbd97ef6fef Mon Sep 17 00:00:00 2001 From: ScaredKurufinve Date: Sat, 21 Oct 2023 01:42:03 +0300 Subject: [PATCH 34/35] deleted a couple random usings (Vs be VS) --- ModMenu/Settings/ModsMenuEntry.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/ModMenu/Settings/ModsMenuEntry.cs b/ModMenu/Settings/ModsMenuEntry.cs index 1dcefae..7ff1331 100644 --- a/ModMenu/Settings/ModsMenuEntry.cs +++ b/ModMenu/Settings/ModsMenuEntry.cs @@ -1,4 +1,4 @@ -using Epic.OnlineServices.Mods; + using JetBrains.Annotations; using Kingmaker.Localization; using Kingmaker.Localization.Shared; @@ -6,7 +6,6 @@ using Kingmaker.UI.SettingsUI; using Kingmaker.Utility; using System; -using System.CodeDom; using System.Collections.Generic; using System.Linq; using UnityEngine; From 8b89099c90fc9edfcc42e3deb9e708571bd82ce5 Mon Sep 17 00:00:00 2001 From: ScaredKurufinve Date: Tue, 7 Nov 2023 23:18:14 +0300 Subject: [PATCH 35/35] Decided to make ModsMenuEntry internal. Removed all its constructors' overloads and added several overloads of ModMenu.AddSettings in their stead. Extracted ModInfo structure from inside ModsMenuEntry. Added Chinese, German and French localization. Changed the construction of static UISettingsEntityDropdownModMenuEntry instance into unity's ScriptableObject CreateInstance to remove the warning in the log. --- ModMenu/Helpers.cs | 15 +++- ModMenu/ModMenu.cs | 67 ++++++++++++-- ModMenu/NewTypes/SettingsEntityPatches.cs | 5 +- .../UISettingsEntityDropDownModMenuEntry.cs | 37 +++----- ModMenu/Settings/ModsMenuEntity.cs | 28 ++---- ModMenu/Settings/ModsMenuEntry.cs | 88 +++---------------- ModMenu/Settings/SettingsBuilder.cs | 24 +++-- ModMenu/Settings/TestSettings.cs | 7 +- 8 files changed, 129 insertions(+), 142 deletions(-) diff --git a/ModMenu/Helpers.cs b/ModMenu/Helpers.cs index 5ce76d0..a58a33f 100644 --- a/ModMenu/Helpers.cs +++ b/ModMenu/Helpers.cs @@ -17,9 +17,9 @@ internal static class Helpers private static readonly List Strings = new(); internal static LocalizedString EmptyString = CreateString("", ""); - internal static LocalizedString CreateString(string key, string enGB, string ruRU = null) + internal static LocalizedString CreateString(string key, string enGB, string ruRU = null, string zhCN = null, string deDE = null, string frFR = null) { - var localString = new LocalString(key, enGB, ruRU); + var localString = new LocalString(key, enGB, ruRU, zhCN, deDE, frFR); Strings.Add(localString); if (LocalizationManager.Initialized) localString.Register(); @@ -43,13 +43,19 @@ private class LocalString public readonly LocalizedString LocalizedString; private readonly string enGB; private readonly string ruRU; + private readonly string zhCN; + private readonly string deDE; + private readonly string frFR; const string NullString = ""; - public LocalString(string key, string enGB, string ruRU) + public LocalString(string key, string enGB, string ruRU, string zhCN, string deDE, string frFR) { LocalizedString = new LocalizedString() { m_Key = key }; this.enGB = enGB; this.ruRU = ruRU; + this.zhCN = zhCN; + this.deDE = deDE; + this.frFR = frFR; } public void Register() @@ -64,6 +70,9 @@ public void Register() localized = (LocalizationManager.CurrentPack.Locale) switch { Locale.ruRU => ruRU, + Locale.zhCN => zhCN, + Locale.deDE => deDE, + Locale.frFR => frFR, _ => "" }; diff --git a/ModMenu/ModMenu.cs b/ModMenu/ModMenu.cs index 53ef291..9b8ad5f 100644 --- a/ModMenu/ModMenu.cs +++ b/ModMenu/ModMenu.cs @@ -1,4 +1,5 @@ -using Kingmaker.Settings; +using JetBrains.Annotations; +using Kingmaker.Settings; using Kingmaker.UI.SettingsUI; using ModMenu.Settings; using System; @@ -35,7 +36,7 @@ public static void AddSettings(SettingsBuilder settings) } Settings.Add(setting.Key, setting.Value); } - ModsMenuEntity.Add(new ModsMenuEntry(result.info, result.groups)); + ModsMenuEntity.Add(result.info, result.groups); } /// @@ -47,6 +48,7 @@ public static void AddSettings(SettingsBuilder settings) /// /// Using is recommended. If you prefer to construct the settings /// on your own you can use this method, but better choose a less deprecated overload using ModsMenuEntry. + /// The name of the settings group will be used as the display name for the mod in the selection dropdown . /// /// /// @@ -54,8 +56,12 @@ public static void AddSettings(SettingsBuilder settings) /// . /// /// - [Obsolete("Please, use AddSettings(ModsMenuEntry entry) instead")] - public static void AddSettings(UISettingsGroup settingsGroup) => ModsMenuEntity.Add(settingsGroup); + /// + /// settingGroups argument must not be null, have at least 1 group in it and none can be null + /// + [Obsolete("Please, use AddSettings(ModsMenuEntry modInfo) instead")] + public static void AddSettings([NotNull] UISettingsGroup settingsGroup) + => ModsMenuEntity.Add(default, new UISettingsGroup[1] { settingsGroup }); /// /// Adds a new entry containing groups of settings to the Mods menu dropdown. @@ -66,6 +72,7 @@ public static void AddSettings(SettingsBuilder settings) /// /// Using is recommended. If you prefer to construct the settings /// on your own you can use this method, but better choose a less deprecated overload using ModsMenuEntry. + /// The name of the first settings group from the list will be used as the display name for the mod in the selection dropdown . /// /// /// @@ -73,25 +80,67 @@ public static void AddSettings(SettingsBuilder settings) /// . /// /// - [Obsolete("Please, use AddSettings(ModsMenuEntry entry) instead")] - public static void AddSettings(List settingsGroup) => ModsMenuEntity.Add(settingsGroup); - + /// + /// settingGroups argument must not be null, have at least 1 group in it and none can be null + /// + [Obsolete("Please, use AddSettings(ModsMenuEntry modInfo) instead")] + public static void AddSettings([NotNull] List settingsGroups) + => ModsMenuEntity.Add(default, settingsGroups); + /// /// Adds a new entry containing groups of settings to the Mods menu page. /// /// /// /// - /// Use this method if you prefer to construct settings on your own you can use this method + /// Use this method if you prefer to construct settings on your own; you can use this method /// instead of using the recommended . /// /// + /// Structure containing basic info about the mod - name, version, description, author name et cetera. + /// This information will be displayed when user is choosing the mod from the dropdown + /// + /// Group of settings created with original Owlcat API. If you did not set any mod name inside the modInfo structure, + /// name of this settings group will be instead used as the display name of the mod. + /// + /// /// /// Settings added in this way cannot be retrieved using or /// . /// /// - public static void AddSetting(ModsMenuEntry entry) => ModsMenuEntity.Add(entry); + /// + /// settingGroups argument must not be null, have at least 1 group in it and none can be null + /// + /// + public static void AddSettings(Info modInfo, [NotNull] UISettingsGroup group) + => ModsMenuEntity.Add(modInfo, new UISettingsGroup[1] { group }); + + /// + /// Adds a new entry containing groups of settings to the Mods menu page. + /// + /// + /// + /// + /// Use this method if you prefer to construct settings on your own; you can use this method + /// instead of using the recommended . + /// + /// Settings added in this way cannot be retrieved using or + /// . + /// + /// + /// + /// Structure containing basic info about the mod - name, version, description, author name et cetera. + /// This information will be displayed when user is choosing the mod from the dropdown + /// param> + /// Groups of settings created with original Owlcat API. If you did not set any mod name inside the modInfo structure, + /// name of the first settings group from the list will be instead used as the display name of the mod. + /// param> + /// + /// settingGroups argument must not be null, have at least 1 group in it and none can be null + /// + public static void AddSettings(Info modInfo, [NotNull] List groups) + => ModsMenuEntity.Add(modInfo, groups); /// /// The setting with the specified , or null if it does not exist or has the wrong type. diff --git a/ModMenu/NewTypes/SettingsEntityPatches.cs b/ModMenu/NewTypes/SettingsEntityPatches.cs index bb02196..16d9ce4 100644 --- a/ModMenu/NewTypes/SettingsEntityPatches.cs +++ b/ModMenu/NewTypes/SettingsEntityPatches.cs @@ -561,7 +561,10 @@ static internal IEnumerable SettingsVM_OpenDefaultSettingsDialo newDefaultMessage = Helpers.CreateString( key: "ModsMenuNewDefaultButtonMessage", enGB: "Revert all settings of the mod {0} to their default values?", - ruRU: "Вернуть все настройки для мода {0} к их значениям по-умолчанию?"); + ruRU: "Вернуть все настройки для мода {0} к их значениям по-умолчанию?", + zhCN: "还原所有{0}模组设置到默认值?", + deDE: "Alle Einstellungen des Mods {0} auf ihre Standardwerte zurücksetzen?", + frFR: "Rétablir les valeurs par défaut de tous les paramètres du mod {0}?"); for (int i = 0; i < length; i++) { diff --git a/ModMenu/NewTypes/UISettingsEntityDropDownModMenuEntry.cs b/ModMenu/NewTypes/UISettingsEntityDropDownModMenuEntry.cs index ca598c6..5786a1f 100644 --- a/ModMenu/NewTypes/UISettingsEntityDropDownModMenuEntry.cs +++ b/ModMenu/NewTypes/UISettingsEntityDropDownModMenuEntry.cs @@ -1,27 +1,27 @@ using HarmonyLib; -using Kingmaker.Localization; using Kingmaker.Settings; -using Kingmaker.UI.MVVM._VM.Settings; -using Kingmaker.UI.MVVM._VM.Settings.Entities; using Kingmaker.UI.SettingsUI; using ModMenu.Settings; using System; using System.Collections.Generic; using System.Linq; -using UnityEngine; namespace ModMenu.NewTypes { - [HarmonyLib.HarmonyPatch] + [HarmonyPatch] internal class UISettingsEntityDropdownModMenuEntry : UISettingsEntityDropdown { static UISettingsEntityDropdownModMenuEntry() { - instance = new() - { - m_Description = Helpers.CreateString("UISettingsEntityDropdownModMenuEntry.Description", "Choose your mod", ruRU: "Выберите мод"), - m_TooltipDescription = Helpers.EmptyString, - }; + instance = CreateInstance(); + instance.m_Description = Helpers.CreateString("UISettingsEntityDropdownModMenuEntry.Description", + enGB:"Select a mod", + ruRU: "Выберите мод", + zhCN: "选择一个模组", + deDE: "Wähle einen Mod aus", + frFR: "Choisir un mod"); + instance.m_TooltipDescription = Helpers.EmptyString; + instance.LinkSetting(SettingsEntityModMenuEntry.instance); ((IUISettingsEntityDropdown) instance).OnTempIndexValueChanged += @@ -38,18 +38,11 @@ static UISettingsEntityDropdownModMenuEntry() internal static UISettingsEntityDropdownModMenuEntry instance; - public override List LocalizedValues - { - get - { - return ModsMenuEntity.ModEntries.Select(entry => entry.ModInfo.ModName.ToString()).ToList(); - } - } - + public override List LocalizedValues + => ModsMenuEntity.ModEntries.Select(entry => entry.ModInfo.ModName.ToString()).ToList(); public override int GetIndexTempValue() - { - return ModsMenuEntity.ModEntries.IndexOf(Setting.GetTempValue()); - } + => ModsMenuEntity.ModEntries.IndexOf(Setting.GetTempValue()); + public override void SetIndexTempValue(int value) { @@ -61,7 +54,5 @@ public override void SetIndexTempValue(int value) SetTempValue(ModsMenuEntity.ModEntries[value]); } - - } } diff --git a/ModMenu/Settings/ModsMenuEntity.cs b/ModMenu/Settings/ModsMenuEntity.cs index f2fc4b2..303b822 100644 --- a/ModMenu/Settings/ModsMenuEntity.cs +++ b/ModMenu/Settings/ModsMenuEntity.cs @@ -1,4 +1,5 @@ using HarmonyLib; +using JetBrains.Annotations; using Kingmaker.Localization; using Kingmaker.UI.MVVM._PCView.Settings.Menu; using Kingmaker.UI.MVVM._VM.Settings; @@ -31,35 +32,20 @@ private static LocalizedString MenuTitleString get { _menuTitleString ??= Helpers.CreateString( - "ModsMenu.Title", "Mods", ruRU: "Моды"); + "ModsMenu.Title", "Mods", ruRU: "Моды", zhCN: "模组", deDE: "Mods", frFR: "Mods"); return _menuTitleString; } } internal static readonly List ModEntries = new(); -#pragma warning disable CS0618 // Obsolete method which I myself marked as obsolete >_> - internal static void Add(UISettingsGroup uiSettingsGroup) - { - ModEntries.Add(new(uiSettingsGroup)); - //if (ModEntries.Contains(ModsMenuEntry.EmptyInstance)) - // ModEntries.Remove(ModsMenuEntry.EmptyInstance); - } - - internal static void Add(List uiSettingsGroup) - { - ModEntries.Add(new(uiSettingsGroup)); - //if (ModEntries.Contains(ModsMenuEntry.EmptyInstance)) - // ModEntries.Remove(ModsMenuEntry.EmptyInstance); - } -#pragma warning restore CS0618 // Тип или член устарел + + internal static void Add(Info modInfo, [NotNull] IEnumerable settingGroups) + => ModEntries.Add(new(modInfo, settingGroups)); internal static void Add(ModsMenuEntry modEntry) - { - ModEntries.Add(modEntry); - //if (ModEntries.Contains(ModsMenuEntry.EmptyInstance)) - // ModEntries.Remove(ModsMenuEntry.EmptyInstance); - } + => ModEntries.Add(modEntry); + internal static IEnumerable CollectSettingGroups => UISettingsEntityDropdownModMenuEntry.instance.Setting.m_TempValue.ModSettings; diff --git a/ModMenu/Settings/ModsMenuEntry.cs b/ModMenu/Settings/ModsMenuEntry.cs index 7ff1331..099a342 100644 --- a/ModMenu/Settings/ModsMenuEntry.cs +++ b/ModMenu/Settings/ModsMenuEntry.cs @@ -1,5 +1,4 @@ - -using JetBrains.Annotations; +using JetBrains.Annotations; using Kingmaker.Localization; using Kingmaker.Localization.Shared; using Kingmaker.Modding; @@ -18,7 +17,7 @@ namespace ModMenu.Settings /// Wrapper class used to display mod's settings in the ModMenu dropdown. Contains a list of UI Setting Groups and /// modification's info such as name. /// - public class ModsMenuEntry : IConvertible + internal class ModsMenuEntry : IConvertible { #pragma warning disable CS1591 // stupid documentation requests #region Conversion @@ -114,7 +113,7 @@ static ModsMenuEntry() Info info = new(Helpers.EmptyString, Helpers.EmptyString); UISettingsGroup pseudoGroup = ScriptableObject.CreateInstance(); pseudoGroup.Title = Helpers.EmptyString; - EmptyInstance = new(info, pseudoGroup); + EmptyInstance = new(info, new UISettingsGroup[1] { pseudoGroup }); ModsMenuEntity.Add(EmptyInstance); } @@ -123,101 +122,37 @@ static ModsMenuEntry() internal readonly IEnumerable ModSettings; internal readonly Info ModInfo; - /// - /// Creates a simpliest ModEntry out of a single UI setting group. - /// Mod entry will use the group's title as displayed name or will be called anonymous if title is empty - /// - /// - /// You can't create a ModEntry out of a null settings group ¯\_(ツ)_/¯ - /// - [Obsolete("Please, use ModsMenuEntry(Info modInfo, UISettingsGroup settingGroup) instead. You will not be able to change ModInfo later.")] - public ModsMenuEntry([NotNull]UISettingsGroup settingGroup) - { - if (settingGroup is null) - { - throw new ArgumentException("Cannot create ModsMenuEntry with a null settingsGroup."); - } - - if (settingGroup.SettingsList.Length == 0) - { - string name = ("titled " + settingGroup.Title) ?? "without a title"; - throw new ArgumentException($"UISettingsGroup {name} is trying to create a ModsMenuEntry without mod info."); - } - - ModSettings = new UISettingsGroup[1] {settingGroup}; - ModInfo = new(settingGroup.Title); - } - - /// - /// Creates a ModEntry out of a several UI setting group. - /// Mod entry will use the first group's title as displayed name or will be called anonymous if title is empty - /// - /// - /// settingGroups argument must not be null, have at least 1 group in it and none can be null - /// - [Obsolete("Use ModsMenuEntry(Info modInfo, IEnumerable settingGroups). You will not be able to change ModInfo later.")] - public ModsMenuEntry(IEnumerable settingGroups) : this(default(Info), settingGroups) - { - } - /// /// settingGroups argument must not be null, have at least 1 group in it and none can be null /// - public ModsMenuEntry(Info modInfo, [NotNull]UISettingsGroup settingGroup) : this(modInfo, new UISettingsGroup[] { settingGroup }) - { - - } - - /// - /// settingGroups argument must not be null, have at least 1 group in it and none can be null - /// - public ModsMenuEntry(Info modInfo, [NotNull] IEnumerable settingGroups) + internal ModsMenuEntry(Info modInfo, [NotNull] IEnumerable settingGroups) { if (settingGroups is null || settingGroups.Count() == 0) - { throw new ArgumentException("Cannot create ModsMenuEntry without any settingsGroups."); - } + if (settingGroups.Any(g => g is null)) - { throw new ArgumentException("Cannot create ModsMenuEntry with a null settingsGroup."); - } ModSettings = settingGroups; - if (!modInfo.Equals(default(Info))) ModInfo = modInfo; else - { - string title = settingGroups.ElementAt(0)?.Title; - if (title.IsNullOrEmpty()) - ModInfo = new(title); - } - } + ModInfo = new(settingGroups.ElementAt(0)?.Title); - /// - /// Creates a simple ModEntry out of a single UI setting group. - /// - /// - /// Name of your mod displayed in the ModMenu dropdown. If you don't provide any, it will be Anonymous - /// - /// - /// You can't create a ModEntry out of a null settings group ¯\_(ツ)_/¯ - /// - public ModsMenuEntry(LocalizedString modName, [NotNull]UISettingsGroup settingGroup) : this(new Info(modName), settingGroup) - { } + } /// /// Structure containing information required to display the ModEntry in the ModMenu dropdown (such as mod's info) /// public struct Info { private static readonly LocalizedString AnonymousMod = - Helpers.CreateString("ModsMenu.AnonymousMod", "Anonymous Mod", ruRU: "Безымянный мод"); + Helpers.CreateString("ModsMenu.AnonymousMod", "Anonymous Mod", ruRU: "Безымянный мод", zhCN: "匿名模组", deDE: "Anonymer Mod", frFR: "Mod anonyme"); private static readonly LocalizedString stringAuthor = - Helpers.CreateString("ModsMenu.stringAuthor", "Author", ruRU: "Создатель"); + Helpers.CreateString("ModsMenu.stringAuthor", "Author", ruRU: "Создатель", zhCN: "作者", deDE: "Autor", frFR: "Créateur"); private static readonly LocalizedString stringVer = - Helpers.CreateString("ModsMenu.stringVer", "Version", ruRU: "Версия"); + Helpers.CreateString("ModsMenu.stringVer", "Version", ruRU: "Версия", zhCN: "版本", deDE: "Version", frFR: "Version"); private static int AnonymousCounter = 0; public Sprite ModImage { get; private set; } @@ -349,7 +284,7 @@ public Info( /// Mod's icon to be displayed alongside the description /// You are not allowed to provide a null UnityModManager.ModEntry when using this constructor public Info( - UnityModManager.ModEntry ummMod, + ModEntry ummMod, bool allowModDisabling, LocalizedString localizedModName = null, LocalizedString localizedModDescription = null, @@ -415,5 +350,4 @@ internal string GenerateDescription() } } } - } } diff --git a/ModMenu/Settings/SettingsBuilder.cs b/ModMenu/Settings/SettingsBuilder.cs index 6c2e083..27e26ae 100644 --- a/ModMenu/Settings/SettingsBuilder.cs +++ b/ModMenu/Settings/SettingsBuilder.cs @@ -412,10 +412,10 @@ private SettingsBuilder Add(string key, ISettingsEntity entity, UISettingsEntity return this; } - internal (List groups, Dictionary settings, ModsMenuEntry.Info info) Build() + internal (List groups, Dictionary settings, Info info) Build() { Group.SettingsList = Settings.ToArray(); - ModsMenuEntry.Info Info; + Info Info; if (Mod is OwlcatModification OwlMod) Info = new(OwlMod, AllowDisabling, ModName, ModDescription, modIllustration); else if (Mod is UnityModManager.ModEntry UMMmod) @@ -459,8 +459,11 @@ private LocalizedString DefaultDescription() return Helpers.CreateString( $"mod-menu.default-description.{Group.name}", - $"Restore all settings in {Group.Title} to their defaults", - ruRU: $"Вернуть все настройки в группе {Group.Title} к значениям по умолчанию"); + enGB: $"Restore all settings in {Group.Title} to their defaults", + ruRU: $"Вернуть все настройки в группе {Group.Title} к значениям по умолчанию", + zhCN: $"还原所有{Group.Title}中的设置到默认值", + deDE: $"Setze alle Einstellungen in {Group.Title} auf ihre Standardwerte zurück", + frFR: "Rétablir les valeurs par défaut de tous les paramètres sous {Group.Title}"); } private LocalizedString DefaultDescriptionLong() @@ -468,13 +471,20 @@ private LocalizedString DefaultDescriptionLong() return Helpers.CreateString( $"mod-menu.default-description-long.{Group.name}", - $"Sets each settings under {Group.Title} to its default value. Your current settings will be lost." + enGB: $"Sets each settings under {Group.Title} to its default value. Your current settings will be lost." + $" Settings in other groups are not affected. Keep in mind this will apply to sub-groups under" + $" {Group.Title} as well (anything that is hidden when the group is collapsed).", ruRU: $"При нажатии на кнопку все настройки в группе {Group.Title} примут значения по умолчанию." + $" Ваши текущие настройки будут потеряны. Настройки из других групп затронуты не будут. Обратите внимание," + $" что изменения коснутся в том числе настроек из подгрупп, вложенных в {Group.Title}" + - $" (т.е. все те настройки, которые оказываются скрыты, когда вы сворачиваете группу)."); + $" (т.е. все те настройки, которые оказываются скрыты, когда вы сворачиваете группу).", + zhCN: $"{Group.Title}之中每一项设置的值都会变成各自的默认值。你的当前设置会丢失。其它分组的设置不受影响。" + + $"注意这也会影响{Group.Title}内部的小分组(只要是折叠之后看不见的都会影响.", + deDE: "Setzt alle Einstellungen unter {Group.Title} auf ihre Standardwerte zurück. Die aktuellen Einstellungen gehen dabei verloren. " + + "Einstellungen in anderen Gruppen werden nicht beeinflusst. Beachte, dass dies auch die Untergruppen von {Group.Title} betrifft.", + frFR: "Rétablit la valeur par défaut pour tous les paramètres sous {Group.Title}. Vos paramètres actuels vont être perdus. " + + "Les paramètres des autres sections ne seront pas affectés. Gardez en tête que cela va s'appliquer aussi aux sous-sections de {Group.Title} " + + "(tout ce qui est caché quand la section est réduite)"); } private static LocalizedString _defaultButtonLabel; @@ -483,7 +493,7 @@ private static LocalizedString DefaultButtonLabel get { _defaultButtonLabel ??= Helpers.CreateString( - "mod-menu.default-button-label", "Default", ruRU: "По умолчанию"); + "mod-menu.default-button-label", "Default", ruRU: "По умолчанию", zhCN: "默认值", deDE: "Standard", frFR: "Défaut"); return _defaultButtonLabel; } } diff --git a/ModMenu/Settings/TestSettings.cs b/ModMenu/Settings/TestSettings.cs index 8c8948f..95cdce8 100644 --- a/ModMenu/Settings/TestSettings.cs +++ b/ModMenu/Settings/TestSettings.cs @@ -28,7 +28,12 @@ internal void Initialize() ModMenu.AddSettings( SettingsBuilder.New(RootKey, CreateString("title", "Testing settings")) .SetMod(Main.Entry) - .SetModDescription(Helpers.CreateString("test-settings-desc", "This is a test description for mod and let's make it a bit longer to take several lines.")) + .SetModDescription(Helpers.CreateString("test-settings-desc", + enGB:"This is a test description for mod and let's make it a bit longer to take several lines.", + ruRU: "Здесь описание для тестового мода и пусть оно будь достаточно длинным, чтобы занимать пару строчек", + zhCN: "这是模组描述的一个测试案例,现在让我们多水一点字数吧,这样的话描述就能有好几行了", + deDE: "Dies ist eine Testbeschreibung für einen Mod, und sie ist noch ein wenig länger, damit sie mehrere Zeilen benötigt.", + frFR: "Ceci est un exemple de description de mod qui doit être assez long pour prendre deux lignes mais on n'a pas dit au traducteur quelle est la taille des lignes, j'imagine que c'est assez long maintenant. ")) .AddImage(Helpers.CreateSprite("ModMenu.WittleWolfie.png"), 250) .AddDefaultButton(OnDefaultsApplied) .AddButton(