diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 90e0373e2..76038ec21 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -55,7 +55,7 @@ jobs: - name: pack run: dotnet pack -o . src\OWML.ModHelper\OWML.ModHelper.csproj -p:NuspecFile=OWML.ModHelper.nuspec -p:NuspecProperties="version=${{ steps.version.outputs.prop }};" - name: upload nuget - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 with: name: owml-nuget path: OWML.*.nupkg @@ -67,7 +67,7 @@ jobs: mkdir Mods 7z a OWML.zip * - name: upload zip - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 with: name: owml-zip path: src\OWML.Launcher\bin\Debug\net48\OWML.zip diff --git a/src/OWML.Abstractions/GameObjectHelper.cs b/src/OWML.Abstractions/GameObjectHelper.cs index 95c40065d..e59bfc98d 100644 --- a/src/OWML.Abstractions/GameObjectHelper.cs +++ b/src/OWML.Abstractions/GameObjectHelper.cs @@ -13,6 +13,6 @@ public TBehaviour CreateAndAdd(string name = null) => CreateAndAdd(typeof(TBehaviour), name); public TBehaviour CreateAndAdd(Type type, string name = null) => - (TBehaviour)(object)new GameObject(name).AddComponent(type); + (TBehaviour)(object)new GameObject(name ?? type.Name).AddComponent(type); } } diff --git a/src/OWML.Common/Interfaces/Menus/IMenuManager.cs b/src/OWML.Common/Interfaces/Menus/IMenuManager.cs index 0899dfcd4..14cd46b41 100644 --- a/src/OWML.Common/Interfaces/Menus/IMenuManager.cs +++ b/src/OWML.Common/Interfaces/Menus/IMenuManager.cs @@ -10,5 +10,11 @@ public interface IMenuManager public IPopupMenuManager PopupMenuManager { get; } internal IList ModList { get; set; } + + /// + /// Keeps the Mod Options tab open, since it is ephemeral. + /// Otherwise, a popup opening in the tab would close it. + /// + public void ForceModOptionsOpen(bool force); } } diff --git a/src/OWML.Common/Interfaces/Menus/IOWMLPopupInputMenu.cs b/src/OWML.Common/Interfaces/Menus/IOWMLPopupInputMenu.cs index dc27beb3a..4ba6edf92 100644 --- a/src/OWML.Common/Interfaces/Menus/IOWMLPopupInputMenu.cs +++ b/src/OWML.Common/Interfaces/Menus/IOWMLPopupInputMenu.cs @@ -1,11 +1,16 @@ -using UnityEngine.UI; +using System; +using UnityEngine.UI; namespace OWML.Common.Interfaces.Menus { public interface IOWMLPopupInputMenu { + [Obsolete("Use OnValidateChar instead.")] public event PopupInputMenu.InputPopupValidateCharEvent OnInputPopupValidateChar; + public delegate bool InputPopupValidateCharEvent(string input, int charIndex, char addedChar); + public event InputPopupValidateCharEvent OnValidateChar; + public void EnableMenu(bool value); public string GetInputText(); diff --git a/src/OWML.Common/Interfaces/Menus/IOWMLTextEntryElement.cs b/src/OWML.Common/Interfaces/Menus/IOWMLTextEntryElement.cs index 3764ce257..3bb3492be 100644 --- a/src/OWML.Common/Interfaces/Menus/IOWMLTextEntryElement.cs +++ b/src/OWML.Common/Interfaces/Menus/IOWMLTextEntryElement.cs @@ -7,5 +7,15 @@ public interface IOWMLTextEntryElement : IOWMLMenuValueOption public event TextEntryConfirmEvent OnConfirmEntry; public string GetInputText(); + + /// + /// Sets the text that is displayed without updating the underlying option value. + /// + public void SetText(string text); + + /// + /// Sets the underlying option value to the text, and updates the displayed text. + /// + public void SetCurrentValue(string text); } } diff --git a/src/OWML.Launcher/OWML.Manifest.json b/src/OWML.Launcher/OWML.Manifest.json index 181e65195..2884e88a4 100644 --- a/src/OWML.Launcher/OWML.Manifest.json +++ b/src/OWML.Launcher/OWML.Manifest.json @@ -3,7 +3,7 @@ "author": "Alek", "name": "OWML", "uniqueName": "Alek.OWML", - "version": "2.13.0", + "version": "2.14.0", "minGameVersion": "1.1.15.1018", "maxGameVersion": "1.1.15.1018" } diff --git a/src/OWML.ModHelper.Menus/CustomInputs/OWMLPopupInputMenu.cs b/src/OWML.ModHelper.Menus/CustomInputs/OWMLPopupInputMenu.cs index 09f77af30..8a58beb12 100644 --- a/src/OWML.ModHelper.Menus/CustomInputs/OWMLPopupInputMenu.cs +++ b/src/OWML.ModHelper.Menus/CustomInputs/OWMLPopupInputMenu.cs @@ -15,6 +15,9 @@ public class OWMLPopupInputMenu : PopupMenu, IOWMLPopupInputMenu protected bool _virtualKeyboardOpen; public event PopupInputMenu.InputPopupTextChangedEvent OnInputPopupTextChanged; + public event IOWMLPopupInputMenu.InputPopupValidateCharEvent OnValidateChar; + + [Obsolete("Use OnValidateChar instead.")] public event PopupInputMenu.InputPopupValidateCharEvent OnInputPopupValidateChar; public override void Awake() @@ -152,20 +155,32 @@ private void OnTextFieldChanged() private char OnValidateInput(string input, int charIndex, char addedChar) { - bool flag = true; - if (this.OnInputPopupValidateChar != null) + var isValidCharacter = true; + if (OnInputPopupValidateChar != null) + { + var invocationList = OnInputPopupValidateChar.GetInvocationList(); + for (var i = 0; i < invocationList.Length; i++) + { + var flag2 = (bool)invocationList[i].DynamicInvoke(new object[] { addedChar }); + isValidCharacter = isValidCharacter && flag2; + } + } + + if (OnValidateChar != null && isValidCharacter) { - Delegate[] invocationList = this.OnInputPopupValidateChar.GetInvocationList(); - for (int i = 0; i < invocationList.Length; i++) + var invocationList = OnValidateChar.GetInvocationList(); + for (var i = 0; i < invocationList.Length; i++) { - bool flag2 = (bool)invocationList[i].DynamicInvoke(new object[] { addedChar }); - flag = flag && flag2; + var flag2 = (bool)invocationList[i].DynamicInvoke(new object[] { input, charIndex, addedChar }); + isValidCharacter = isValidCharacter && flag2; } } - if (flag) + + if (isValidCharacter) { return addedChar; } + return '\0'; } diff --git a/src/OWML.ModHelper.Menus/CustomInputs/OWMLTextEntryElement.cs b/src/OWML.ModHelper.Menus/CustomInputs/OWMLTextEntryElement.cs index ecc06789d..3e2ceb6f8 100644 --- a/src/OWML.ModHelper.Menus/CustomInputs/OWMLTextEntryElement.cs +++ b/src/OWML.ModHelper.Menus/CustomInputs/OWMLTextEntryElement.cs @@ -23,9 +23,14 @@ public string GetInputText() return _popup.GetInputText(); } - public void SetCurrentValue(string text) + public void SetText(string text) { gameObject.GetComponentsInChildren().First(x => x != this)._label.text = text; + } + + public void SetCurrentValue(string text) + { + SetText(text); _popup.GetInputField().text = text; OnConfirmEntry(); } diff --git a/src/OWML.ModHelper.Menus/ModInputMenu.cs b/src/OWML.ModHelper.Menus/ModInputMenu.cs index 5bff28165..8ed10e155 100644 --- a/src/OWML.ModHelper.Menus/ModInputMenu.cs +++ b/src/OWML.ModHelper.Menus/ModInputMenu.cs @@ -75,7 +75,7 @@ private bool OnValidateNumber() => float.TryParse(_inputMenu.GetInputText(), out _); private bool OnValidateCharNumber(char c) => - "0123456789.".Contains("" + c); + "0123456789.-".Contains(c.ToString()); protected override void OnPopupConfirm() { diff --git a/src/OWML.ModHelper.Menus/NewMenuSystem/MenuManager.cs b/src/OWML.ModHelper.Menus/NewMenuSystem/MenuManager.cs index b95bc7990..5b058d071 100644 --- a/src/OWML.ModHelper.Menus/NewMenuSystem/MenuManager.cs +++ b/src/OWML.ModHelper.Menus/NewMenuSystem/MenuManager.cs @@ -39,6 +39,7 @@ enum SettingType internal static List<(IModBehaviour behaviour, Menu modMenu)> ModSettingsMenus = new(); private bool _hasSetupMenusThisScene = false; + private bool _forceModOptionsOpen; public MenuManager( IModConsole console, @@ -52,7 +53,7 @@ public MenuManager( _unityEvents = unityEvents; TitleMenuManager = new TitleMenuManager(); PopupMenuManager = new PopupMenuManager(console, harmony, this); - OptionsMenuManager = new OptionsMenuManager(console, unityEvents, PopupMenuManager); + OptionsMenuManager = new OptionsMenuManager(console, unityEvents, PopupMenuManager, this); PauseMenuManager = new PauseMenuManager(console); var harmonyInstance = harmony.GetValue("_harmony"); @@ -85,6 +86,11 @@ public MenuManager( }; } + public void ForceModOptionsOpen(bool force) + { + _forceModOptionsOpen = force; + } + internal void SetupMenus(IList modList) { if (_hasSetupMenusThisScene) @@ -103,8 +109,8 @@ void SaveConfig() // Create menus and submenus var (modsMenu, modsMenuButton) = OptionsMenuManager.CreateTabWithSubTabs("MODS"); - var (owmlSubTab, owmlSubTabButton) = OptionsMenuManager.AddSubTab(modsMenu, "OWML"); var (modsSubTab, modsSubTabButton) = OptionsMenuManager.AddSubTab(modsMenu, "MODS"); + var (owmlSubTab, owmlSubTabButton) = OptionsMenuManager.AddSubTab(modsMenu, "OWML"); OWMLSettingsMenu = owmlSubTab; @@ -210,7 +216,20 @@ void SaveConfig() newModTab.OnDeactivateMenu += () => { - OptionsMenuManager.RemoveTab(newModTab); + if (_forceModOptionsOpen) + { + return; + } + + // Fixes tab dissapearing when you click on it again + // Clicking on a tab closes and opens it again + _unityEvents.FireOnNextUpdate(() => + { + if (!newModTab._isActivated) + { + OptionsMenuManager.RemoveTab(newModTab); + } + }); }; foreach (var (name, setting) in mod.ModHelper.Config.Settings) @@ -307,6 +326,7 @@ void SaveConfig() mod.ModHelper.Config.SetSettingsValue(name, newValue); mod.ModHelper.Storage.Save(mod.ModHelper.Config, Constants.ModConfigFileName); mod.Configure(mod.ModHelper.Config); + textInput.SetText(newValue); }; break; case SettingType.NUMBER: @@ -319,6 +339,7 @@ void SaveConfig() mod.ModHelper.Config.SetSettingsValue(name, newValue); mod.ModHelper.Storage.Save(mod.ModHelper.Config, Constants.ModConfigFileName); mod.Configure(mod.ModHelper.Config); + numberInput.SetText(newValue.ToString()); }; break; default: @@ -387,6 +408,12 @@ private void EditExistingMenus() { var text = item.GetComponent()._textItems[0]; text.horizontalOverflow = HorizontalWrapMode.Wrap; + + // Give a little bit of margin to account for the dividing lines + // (as otherwise it can look like the text is on top of them when in mouse mode) + float margin = 0.03f; + text.rectTransform.anchorMin = new Vector2(margin, 0.0f); + text.rectTransform.anchorMax = new Vector2(1f - margin, 1.0f); } } diff --git a/src/OWML.ModHelper.Menus/NewMenuSystem/OptionsMenuManager.cs b/src/OWML.ModHelper.Menus/NewMenuSystem/OptionsMenuManager.cs index b3191800e..f1d3c7628 100644 --- a/src/OWML.ModHelper.Menus/NewMenuSystem/OptionsMenuManager.cs +++ b/src/OWML.ModHelper.Menus/NewMenuSystem/OptionsMenuManager.cs @@ -14,12 +14,14 @@ internal class OptionsMenuManager : IOptionsMenuManager private readonly IModConsole _console; private readonly IModUnityEvents _unityEvents; private readonly IPopupMenuManager _popupMenuManager; + private readonly IMenuManager _menuManager; - public OptionsMenuManager(IModConsole console, IModUnityEvents unityEvents, IPopupMenuManager popupMenuManager) + public OptionsMenuManager(IModConsole console, IModUnityEvents unityEvents, IPopupMenuManager popupMenuManager, IMenuManager menuManager) { _console = console; _unityEvents = unityEvents; _popupMenuManager = popupMenuManager; + _menuManager = menuManager; } public (Menu menu, TabButton button) CreateStandardTab(string name) @@ -31,6 +33,7 @@ public OptionsMenuManager(IModConsole console, IModUnityEvents unityEvents, IPop newMenu.transform.localScale = Vector3.one; newMenu.transform.localPosition = Vector3.zero; newMenu.transform.localRotation = Quaternion.identity; + newMenu.name = $"Menu-{name}"; var rt = newMenu.GetComponent(); var ert = existingMenu.GetComponent(); rt.anchorMin = ert.anchorMin; @@ -84,6 +87,7 @@ public OptionsMenuManager(IModConsole console, IModUnityEvents unityEvents, IPop newSubMenu.transform.localScale = Vector3.one; newSubMenu.transform.localPosition = Vector3.zero; newSubMenu.transform.localRotation = Quaternion.identity; + newSubMenu.name = $"Menu-{name}"; var rectTransform = newSubMenu.GetComponent(); rectTransform.anchorMin = existingTabbedSubMenu.GetComponent().anchorMin; rectTransform.anchorMax = existingTabbedSubMenu.GetComponent().anchorMax; @@ -169,7 +173,7 @@ public void RemoveTab(Menu tab) newSubMenuTabButton.transform.localScale = Vector3.one; newSubMenuTabButton.transform.localPosition = Vector3.zero; newSubMenuTabButton.transform.localRotation = Quaternion.identity; - newSubMenuTabButton.transform.SetSiblingIndex(newSubMenuTabButton.transform.parent.childCount - 2); + newSubMenuTabButton.transform.SetSiblingIndex(newSubMenuTabButton.transform.parent.childCount - 3); newSubMenuTabButton.name = $"Button-{name}Tab"; Object.Destroy(newSubMenuTabButton.GetComponentInChildren()); newSubMenuTabButton.GetComponentInChildren().text = name; @@ -190,6 +194,9 @@ public void RemoveTab(Menu tab) rt.offsetMax = ert.offsetMax; rt.sizeDelta = ert.sizeDelta; + var viewportRect = newSubMenu.GetComponentInChildren().GetComponent(); + viewportRect.anchoredPosition3D = Vector3.zero; + if (menu._selectOnActivate == null) { menu._selectOnActivate = newSubMenuTabButton.GetComponent