diff --git a/Directory.Build.props b/Directory.Build.props index d7583c7..171b240 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -11,6 +11,6 @@ It should follow the format major.minor.patch (semantic versioning). If you publish your mod as a library to NuGet, this version will also be used as the package version. --> - 0.4.1 + 0.4.2 diff --git a/Elements/LocalizedTextExtensions.cs b/Elements/LocalizedTextExtensions.cs index 59974f6..f5e991e 100644 --- a/Elements/LocalizedTextExtensions.cs +++ b/Elements/LocalizedTextExtensions.cs @@ -1,4 +1,5 @@ -using UnityEngine.UI; +using Silksong.ModMenu.Internal; +using UnityEngine.UI; namespace Silksong.ModMenu.Elements; @@ -27,8 +28,11 @@ public LocalizedText LocalizedText { if (!self.TryGetComponent(out var auto)) { - auto = self.gameObject.AddComponent(); - auto.textField = self; + using (self.gameObject.TempInactive()) + { + auto = self.gameObject.AddComponent(); + auto.textField = self; + } } auto.text = value.Localized; diff --git a/Internal/CustomMappableKey.cs b/Internal/CustomMappableKey.cs index f81f891..c32af58 100644 --- a/Internal/CustomMappableKey.cs +++ b/Internal/CustomMappableKey.cs @@ -49,25 +49,26 @@ internal static CustomMappableKey Replace(MappableKey src) var obj = src.gameObject; DestroyImmediate(src); // We cannot wait 1 frame to add a new Selectable component. - var wasActive = obj.activeSelf; - obj.SetActive(false); - CustomMappableKey dest = obj.AddComponent(); - dest.animationTriggers = animationTriggers; - dest.buttonType = MenuButtonType.Proceed; - dest.cancelAction = CancelAction.DoNothing; - dest.colors = colors; - dest.DontPlaySelectSound = true; - dest.KeymapImage = keymapImage; - dest.KeymapText = keymapText; - dest.leftCursor = leftCursor; - dest.menuCancelVibration = menuCancelVibration; - dest.menuSubmitVibration = menuSubmitVibration; - dest.playSubmitSound = true; - dest.prevSelectedObject = obj; - dest.rightCursor = rightCursor; - dest.transition = Transition.None; - dest.uiAudioPlayer = UIManager.instance.uiAudioPlayer; - obj.SetActive(wasActive); + CustomMappableKey dest; + using (obj.TempInactive()) + { + dest = obj.AddComponent(); + dest.animationTriggers = animationTriggers; + dest.buttonType = MenuButtonType.Proceed; + dest.cancelAction = CancelAction.DoNothing; + dest.colors = colors; + dest.DontPlaySelectSound = true; + dest.KeymapImage = keymapImage; + dest.KeymapText = keymapText; + dest.leftCursor = leftCursor; + dest.menuCancelVibration = menuCancelVibration; + dest.menuSubmitVibration = menuSubmitVibration; + dest.playSubmitSound = true; + dest.prevSelectedObject = obj; + dest.rightCursor = rightCursor; + dest.transition = Transition.None; + dest.uiAudioPlayer = UIManager.instance.uiAudioPlayer; + } return dest; } diff --git a/Internal/EnumUtil.cs b/Internal/EnumUtil.cs index b5bfae2..13dd665 100644 --- a/Internal/EnumUtil.cs +++ b/Internal/EnumUtil.cs @@ -50,7 +50,7 @@ internal static ReadOnlyDictionary StringsForType(Type enumType) fieldName ??= StringUtil.UnCamelCase(field.Name); } - if (fieldName == null) + if (customName == null && fieldName == null) continue; names[value] = customName ?? fieldName!; diff --git a/Internal/GameObjectUtil.cs b/Internal/GameObjectUtil.cs index ba30e88..3ea20d9 100644 --- a/Internal/GameObjectUtil.cs +++ b/Internal/GameObjectUtil.cs @@ -13,4 +13,22 @@ internal static void DestroyAllChildren(this GameObject self) Object.Destroy(obj); } } + + private class InactiveScope : System.IDisposable + { + private readonly bool prevActiveSelf; + private readonly GameObject gameObject; + + internal InactiveScope(GameObject gameObject) + { + prevActiveSelf = gameObject.activeSelf; + this.gameObject = gameObject; + gameObject.SetActive(false); + } + + public void Dispose() => gameObject.SetActive(prevActiveSelf); + } + + internal static System.IDisposable TempInactive(this GameObject self) => + new InactiveScope(self); } diff --git a/Internal/IEnumeratorUtil.cs b/Internal/IEnumeratorUtil.cs index 70bbd09..d8834f7 100644 --- a/Internal/IEnumeratorUtil.cs +++ b/Internal/IEnumeratorUtil.cs @@ -33,6 +33,9 @@ IEnumerator Modified() return Modified(); } + internal static IEnumerator PropagateContext(this IEnumerator self) + where T : class => ThreadLocalContext.Get(out var ctx) ? self.WithContext(ctx) : self; + internal static IEnumerator Append(this IEnumerator self, Action action) { IEnumerator Modified() diff --git a/Screens/AbstractMenuScreen.cs b/Screens/AbstractMenuScreen.cs index da35691..56b8c08 100644 --- a/Screens/AbstractMenuScreen.cs +++ b/Screens/AbstractMenuScreen.cs @@ -187,7 +187,6 @@ internal void InvokeOnGoBack() internal void InvokeOnHide(MenuScreenNavigation.NavigationType navigationType) { - ModMenuPlugin.LogError($"{Container.name}{nameof(InvokeOnHide)}: {navigationType}"); OnHide?.Invoke(navigationType); visibility.VisibleSelf = false; } diff --git a/Screens/BasicMenuScreen.cs b/Screens/BasicMenuScreen.cs index d380327..76e1c74 100644 --- a/Screens/BasicMenuScreen.cs +++ b/Screens/BasicMenuScreen.cs @@ -9,8 +9,14 @@ namespace Silksong.ModMenu.Screens; /// /// A simple menu screen with a single content entity. /// -public class BasicMenuScreen(string title, INavigableMenuEntity content) : AbstractMenuScreen(title) +public class BasicMenuScreen : AbstractMenuScreen { + /// + /// Construct a basic menu screen with a single content entity. + /// + public BasicMenuScreen(string title, INavigableMenuEntity content) + : base(title) => Content = content; + /// /// The content displayed by this menu screen, minus the back button. /// @@ -23,12 +29,12 @@ public INavigableMenuEntity Content throw new ArgumentNullException(nameof(Content)); if (field != value) - field.ClearParents(); + field?.ClearParents(); field = value; AddChild(field); } - } = content; + } /// /// Remove the content pane for this menu, showing nothing instead. diff --git a/Screens/MenuScreenNavigation.cs b/Screens/MenuScreenNavigation.cs index ac8f768..dc6ed12 100644 --- a/Screens/MenuScreenNavigation.cs +++ b/Screens/MenuScreenNavigation.cs @@ -210,7 +210,9 @@ IEnumerator Routine() { var ui = UIManager.instance; ui.isFadingMenu = true; - yield return ui.StartCoroutine(ui.HideMenu(screen.MenuScreen)); + yield return ui.StartCoroutine( + ui.HideMenu(screen.MenuScreen).PropagateContext() + ); ui.isFadingMenu = false; }