diff --git a/CoroutineUtils.cs b/CoroutineUtils.cs index a8f88ce..a91c31c 100644 --- a/CoroutineUtils.cs +++ b/CoroutineUtils.cs @@ -27,6 +27,7 @@ namespace NEG.Utils action?.Invoke(); } + public static void ActionAfterEndOfFrame(this MonoBehaviour mono, Action action) => mono.StartCoroutine(ActionAtNextFrame(action)); public static IEnumerator ActionAfterEndOfFrame(Action action) { yield return WaitForEndOfFrame; diff --git a/Editor/BuildingUtils.cs b/Editor/BuildingUtils.cs index b2acc8d..a95774f 100644 --- a/Editor/BuildingUtils.cs +++ b/Editor/BuildingUtils.cs @@ -55,7 +55,18 @@ public static class BuildingUtils BuildDevelopment(); UploadSteam(); } - + + + [MenuItem("Tools/Build/Steam/Demo")] + public static void SteamDemo() + { + if(!CanBuild()) + return; + + IncreaseBuildNumber(); + BuildDemo(); + UploadSteam(true); + } [MenuItem("Tools/Build/All Release")] public static void BuildRelease() @@ -63,6 +74,7 @@ public static class BuildingUtils if(!CanBuild()) return; BuildWindowsRelease(); + BuildLinuxRelease(); } [MenuItem("Tools/Build/All Development")] @@ -72,6 +84,15 @@ public static class BuildingUtils return; BuildWindowsDevelopment(); } + + [MenuItem("Tools/Build/All Demo")] + public static void BuildDemo() + { + if(!CanBuild()) + return; + BuildWindows(true, new[] {"DEMO"}); + BuildLinux(true, new[] {"DEMO"}); + } [MenuItem("Tools/Build/Platform/Windows/x64-Development")] public static void BuildWindowsDevelopment() @@ -88,6 +109,15 @@ public static class BuildingUtils return; BuildWindows(true); } + + [MenuItem("Tools/Build/Platform/Linux/x64-Release")] + public static void BuildLinuxRelease() + { + if(!CanBuild()) + return; + BuildLinux(true); + } + [MenuItem("Tools/Build/Platform/Android/GooglePlay")] public static void BuildGooglePlay() @@ -109,7 +139,7 @@ public static class BuildingUtils BuildPipeline.BuildPlayer(buildPlayerOptions); } - private static void BuildWindows(bool release) + private static void BuildWindows(bool release, string[] additionalDefines = default) { var buildPlayerOptions = new BuildPlayerOptions { scenes = new string[EditorBuildSettings.scenes.Length] }; for (int i = 0; i < EditorBuildSettings.scenes.Length; i++) @@ -117,12 +147,31 @@ public static class BuildingUtils buildPlayerOptions.scenes[i] = EditorBuildSettings.scenes[i].path; } + buildPlayerOptions.extraScriptingDefines = additionalDefines; + buildPlayerOptions.target = BuildTarget.StandaloneWindows64; buildPlayerOptions.options = release ? BuildOptions.None : BuildOptions.Development; buildPlayerOptions.locationPathName = Application.dataPath + $"/../../{Application.productName}-Steam/ContentBuilder/content/windows/{Application.productName}.exe"; BuildPipeline.BuildPlayer(buildPlayerOptions); } + + private static void BuildLinux(bool release, string[] additionalDefines = default) + { + var buildPlayerOptions = new BuildPlayerOptions { scenes = new string[EditorBuildSettings.scenes.Length] }; + for (int i = 0; i < EditorBuildSettings.scenes.Length; i++) + { + buildPlayerOptions.scenes[i] = EditorBuildSettings.scenes[i].path; + } + + buildPlayerOptions.extraScriptingDefines = additionalDefines; + + buildPlayerOptions.target = BuildTarget.StandaloneLinux64; + buildPlayerOptions.options = release ? BuildOptions.None : BuildOptions.Development; + buildPlayerOptions.locationPathName = Application.dataPath + + $"/../../{Application.productName}-Steam/ContentBuilder/content/linux/{Application.productName}.x86_64"; + BuildPipeline.BuildPlayer(buildPlayerOptions); + } private static void IncreaseBuildNumber() { @@ -135,9 +184,13 @@ public static class BuildingUtils PlayerSettings.bundleVersion = string.Join(".", versionParts); } - private static void UploadSteam() + private static void UploadSteam(bool demo = false) { - string command = $"cd {Application.dataPath}/../../{Application.productName}-Steam/ContentBuilder && run_build.bat"; + string command = $"cd {Application.dataPath}/../../{Application.productName}-Steam/ContentBuilder && push_build.bat"; + if (demo) + { + command = $"cd {Application.dataPath}/../../{Application.productName}-Steam/ContentBuilder && push_demo.bat"; + } var processInfo = new ProcessStartInfo("cmd.exe", $"/c {command}") { diff --git a/NEG/UI/UiManager.cs b/NEG/UI/UiManager.cs index c25e4b3..f55b0da 100644 --- a/NEG/UI/UiManager.cs +++ b/NEG/UI/UiManager.cs @@ -6,6 +6,7 @@ using NEG.Utils; using NegUtils.NEG.UI; using System; using System.Collections.Generic; +using System.Linq; using UnityEngine; namespace NEG.UI @@ -34,7 +35,7 @@ namespace NEG.UI /// /// Current window that is considered main (focused, lastly opened). Can be null. /// - public IWindow CurrentMainWindow { get; protected set; } + public IWindow CurrentMainWindow => mainWindows.LastOrDefault(); public PopupData CurrentPopup => currentShownPopup.data; @@ -47,6 +48,8 @@ namespace NEG.UI //TODO: localize private string localizedYes = "Yes", localizedNo = "No", localizedOk = "Ok"; + private List mainWindows; + protected UiManager(IArea startArea) { if (Instance != null) @@ -58,6 +61,7 @@ namespace NEG.UI Instance = this; CurrentArea = startArea; + mainWindows = new List(); } /// @@ -146,16 +150,13 @@ namespace NEG.UI public virtual void Dispose() => Instance = null; - public void SetMainWindow(IWindow window) => CurrentMainWindow = window; + public void SetMainWindow(IWindow window) => mainWindows.Add(window); - public void OnWindowClosed(IWindow window) - { - if(CurrentMainWindow != window) - return; - - //TODO: select new main window - } + public void MainWindowClosed(IWindow window) => mainWindows.Remove(window); + public void OnWindowClosed(IWindow window) => MainWindowClosed(window); + + //TODO: select new main window protected void PopupClosed(PopupData data) { if (currentShownPopup.data != data) @@ -169,7 +170,7 @@ namespace NEG.UI protected void SetDefaultPopup(IDefaultPopup popup) => currentDefaultPopup = popup; - private void UpdatePopupsState(bool forceShow, int priority = 0, PopupData data = null) + protected virtual void UpdatePopupsState(bool forceShow, int priority = 0, PopupData data = null) { if (forceShow) { @@ -183,6 +184,8 @@ namespace NEG.UI while (popupsToShow.TryDequeue(out var d, out int p)) { + if(d == null) + continue; if(!d.IsValid) continue; if(d == currentShownPopup.data) diff --git a/NEG/UI/UnityUi/Area/AutoOpenWindowWhenNoOther.cs b/NEG/UI/UnityUi/Area/AutoOpenWindowWhenNoOther.cs new file mode 100644 index 0000000..c9ba380 --- /dev/null +++ b/NEG/UI/UnityUi/Area/AutoOpenWindowWhenNoOther.cs @@ -0,0 +1,17 @@ +using NEG.UI.UnityUi.Window; +using NEG.UI.Window; +using UnityEngine; + +namespace NEG.UI.Area +{ + public class AutoOpenWindowWhenNoOther : MonoBehaviour + { + [SerializeField] private MonoWindow window; + + private void Start() + { + if(UiManager.Instance.CurrentMainWindow == null) + window.Open(); + } + } +} \ No newline at end of file diff --git a/NEG/UI/UnityUi/Area/AutoOpenWindowWhenNoOther.cs.meta b/NEG/UI/UnityUi/Area/AutoOpenWindowWhenNoOther.cs.meta new file mode 100644 index 0000000..14ed8c2 --- /dev/null +++ b/NEG/UI/UnityUi/Area/AutoOpenWindowWhenNoOther.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 473c065573984067a824ebf3b605c3ab +timeCreated: 1695048071 \ No newline at end of file diff --git a/NEG/UI/UnityUi/Area/CloseMainWindowOnBack.cs b/NEG/UI/UnityUi/Area/CloseMainWindowOnBack.cs index 1334558..b7211c5 100644 --- a/NEG/UI/UnityUi/Area/CloseMainWindowOnBack.cs +++ b/NEG/UI/UnityUi/Area/CloseMainWindowOnBack.cs @@ -12,7 +12,7 @@ namespace NEG.UI.Area protected override void OnBackUsed(IControllable.BackUsed backUsed) { base.OnBackUsed(backUsed); - UiManager.Instance.CurrentMainWindow.Close(); + UiManager.Instance.CurrentMainWindow?.Close(); backUsed.Used = true; } } diff --git a/NEG/UI/UnityUi/Area/MonoArea.cs b/NEG/UI/UnityUi/Area/MonoArea.cs index 2829582..535489a 100644 --- a/NEG/UI/UnityUi/Area/MonoArea.cs +++ b/NEG/UI/UnityUi/Area/MonoArea.cs @@ -36,7 +36,7 @@ namespace NEG.UI.Area public void OpenWindow(IWindow window, object data = null) => DefaultWindowSlot.AttachWindow(window, data); - private void Awake() + protected virtual void Awake() { if (setAsDefaultArea) UiManager.Instance.CurrentArea = this; diff --git a/NEG/UI/UnityUi/Area/MonoArea.cs.meta b/NEG/UI/UnityUi/Area/MonoArea.cs.meta index 958b733..883d00d 100644 --- a/NEG/UI/UnityUi/Area/MonoArea.cs.meta +++ b/NEG/UI/UnityUi/Area/MonoArea.cs.meta @@ -1,3 +1,11 @@ -fileFormatVersion: 2 +fileFormatVersion: 2 guid: 39eb59ca1ef60934abb3f0c64169be65 -timeCreated: 1670707479 \ No newline at end of file +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 10 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/NEG/UI/UnityUi/MonoController.cs b/NEG/UI/UnityUi/MonoController.cs index 7c4afdb..e6c9a7b 100644 --- a/NEG/UI/UnityUi/MonoController.cs +++ b/NEG/UI/UnityUi/MonoController.cs @@ -1,4 +1,5 @@ using KBCore.Refs; +using NEG.UI.UnityUi.Window; using NegUtils.NEG.UI; using System; using UnityEngine; @@ -11,6 +12,8 @@ namespace NEG.UI.UnityUi [SerializeField, Self] protected InterfaceRef controllable; + protected MonoWindow ControllableAsWindow => (MonoWindow)controllable.Value; + protected virtual void Awake() { controllable.Value.OnOpened += OnOpened; diff --git a/NEG/UI/UnityUi/MonoUiInputManger.cs b/NEG/UI/UnityUi/MonoUiInputManger.cs index 22cd060..4aac796 100644 --- a/NEG/UI/UnityUi/MonoUiInputManger.cs +++ b/NEG/UI/UnityUi/MonoUiInputManger.cs @@ -1,4 +1,5 @@ -using UnityEngine; +using NEG.UI.UnityUi.Window; +using UnityEngine; using UnityEngine.EventSystems; using UnityEngine.InputSystem; using UnityEngine.InputSystem.UI; @@ -11,16 +12,16 @@ namespace NEG.UI.UnityUi Direction } - public class UiInputModule { } + public class UiInputModule { public SelectionSource CurrentSelectionSource { get; protected set; }} public class DefaultInputModule : UiInputModule { - public SelectionSource CurrentSelectionSource { get; private set; } - public DefaultInputModule() { var defaultActions = new DefaultInputActions(); InputActionReference.Create(defaultActions.UI.Navigate).action.performed += (ctx) => OnSelectionChangeStarted(); + InputActionReference.Create(defaultActions.UI.Cancel).action.performed += + (_) => UiManager.Instance.UseBack(); defaultActions.Enable(); if (Gamepad.current != null) @@ -31,9 +32,9 @@ namespace NEG.UI.UnityUi //var keyboardAction = new InputAction(binding: "//*"); //keyboardAction.performed += (context) => CurrentInputSource = EInputSource.Keyboard; //keyboardAction.Enable(); - var gamepadAction = new InputAction(binding: "//*"); - gamepadAction.performed += (context) => OnSelectionChangeStarted(); - gamepadAction.Enable(); + //var gamepadAction = new InputAction(binding: "//*"); + //gamepadAction.performed += (context) => OnSelectionChangeStarted(); + //gamepadAction.Enable(); var mouseAction = new InputAction(binding: "//*"); mouseAction.performed += (context) => @@ -47,15 +48,37 @@ namespace NEG.UI.UnityUi private void OnSelectionChangeStarted() { - if(CurrentSelectionSource == SelectionSource.Direction) + if(CurrentSelectionSource == SelectionSource.Direction && EventSystem.current.currentSelectedGameObject != null) return; SetDirectionInput(); } private void SetDirectionInput() { + if (EventSystem.current == null || MonoUiManager.Instance == null ) + { + return; + } CurrentSelectionSource = SelectionSource.Direction; Cursor.visible = false; + if (EventSystem.current.currentSelectedGameObject == null && MonoUiManager.Instance.CurrentMainWindow != null) + { + EventSystem.current.SetSelectedGameObject(((MonoWindow)MonoUiManager.Instance.CurrentMainWindow).DefaultSelectedItem); + return; + } + var data = new PointerEventData(EventSystem.current); + var currentSelected = EventSystem.current.currentSelectedGameObject; + if (currentSelected != null) + { + for (var current = EventSystem.current.currentSelectedGameObject.transform; + current != null; + current = current.parent) + { + ExecuteEvents.Execute(current.gameObject, data, ExecuteEvents.pointerExitHandler); + } + } + + EventSystem.current.SetSelectedGameObject(currentSelected); } private void SetPointerInput() @@ -72,6 +95,8 @@ namespace NEG.UI.UnityUi if (EventSystem.current.currentInputModule == null) return; + EventSystem.current.SetSelectedGameObject(null); + var module = (InputSystemUIInputModule)EventSystem.current.currentInputModule; var result = module.GetLastRaycastResult(0); if(result.gameObject == null) diff --git a/NEG/UI/UnityUi/MonoUiManager.cs b/NEG/UI/UnityUi/MonoUiManager.cs index e5ced8c..dbafda8 100644 --- a/NEG/UI/UnityUi/MonoUiManager.cs +++ b/NEG/UI/UnityUi/MonoUiManager.cs @@ -3,11 +3,13 @@ using NEG.UI.Popup; using NEG.UI.UnityUi.Buttons.Reaction; using NEG.UI.UnityUi.Buttons.Settings; using NEG.UI.UnityUi.Popup; +using NEG.UI.UnityUi.Window; using NEG.Utils; using System; using System.Collections.Generic; using UnityEngine; using UnityEngine.Assertions; +using UnityEngine.EventSystems; using UnityEngine.SceneManagement; using Object = UnityEngine.Object; @@ -68,6 +70,20 @@ namespace NEG.UI.UnityUi Instance = null; } + protected override void UpdatePopupsState(bool forceShow, int priority = 0, PopupData data = null) + { + base.UpdatePopupsState(forceShow, priority, data); + if(inputModule.CurrentSelectionSource != SelectionSource.Direction) + return; + + if (CurrentPopup == null && (EventSystem.current.currentSelectedGameObject == null || !EventSystem.current.currentSelectedGameObject.activeInHierarchy)) + { + if(((MonoWindow)CurrentMainWindow).DefaultSelectedItem == null) + return; + EventSystem.current.SetSelectedGameObject(((MonoWindow)CurrentMainWindow).DefaultSelectedItem); + } + } + private void SpawnDefaultPopup() { var canvas = Object.Instantiate(canvasPrefab); diff --git a/NEG/UI/UnityUi/Window/MonoWindow.cs b/NEG/UI/UnityUi/Window/MonoWindow.cs index ddbc35a..6536f7c 100644 --- a/NEG/UI/UnityUi/Window/MonoWindow.cs +++ b/NEG/UI/UnityUi/Window/MonoWindow.cs @@ -12,6 +12,7 @@ using UnityEngine.Serialization; namespace NEG.UI.UnityUi.Window { + [DefaultExecutionOrder(10)] public class MonoWindow : MonoBehaviour, IWindow { public event Action OnOpened; @@ -22,8 +23,11 @@ namespace NEG.UI.UnityUi.Window public IWindowSlot Parent { get; private set; } public bool IsMainWindow { get; private set; } + + public bool IsOpened { get; protected set; } private IWindowSlot DefaultWindowSlot => windowSlots[0]; + public GameObject DefaultSelectedItem => defaultSelectedItem; [SerializeField] private List windowSlots; @@ -32,6 +36,7 @@ namespace NEG.UI.UnityUi.Window public void SetOpenedState(IWindowSlot parentSlot, object data) { gameObject.SetActive(true); + IsOpened = true; Parent = parentSlot; EventSystem.current.SetSelectedGameObject(defaultSelectedItem); if (parentSlot.OpenWindowAsMain) @@ -42,6 +47,7 @@ namespace NEG.UI.UnityUi.Window public void SetClosedState() { gameObject.SetActive(false); + IsOpened = false; Parent = null; ((ISlotsHolder)this).CloseAllWindows(); UiManager.Instance.OnWindowClosed(this); @@ -54,6 +60,14 @@ namespace NEG.UI.UnityUi.Window private void Awake() => ((IWindow)this).SetHiddenState(); + private void OnDestroy() + { + if (IsOpened) + { + UiManager.Instance.OnWindowClosed(this); + } + } + private void OnValidate() { #if !NEG_UI_DISABLE_WARNING_DEFAULT_SELECTION diff --git a/NEG/UI/UnityUi/Window/MonoWindow.cs.meta b/NEG/UI/UnityUi/Window/MonoWindow.cs.meta index 4f6091a..2e55018 100644 --- a/NEG/UI/UnityUi/Window/MonoWindow.cs.meta +++ b/NEG/UI/UnityUi/Window/MonoWindow.cs.meta @@ -1,3 +1,11 @@ -fileFormatVersion: 2 +fileFormatVersion: 2 guid: 85d136d6850728d4b96c26fa286ffe3c -timeCreated: 1670709296 \ No newline at end of file +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 11 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/NEG/UI/UnityUi/Window/NoReactionOnBack.cs b/NEG/UI/UnityUi/Window/NoReactionOnBack.cs new file mode 100644 index 0000000..7ba12ee --- /dev/null +++ b/NEG/UI/UnityUi/Window/NoReactionOnBack.cs @@ -0,0 +1,13 @@ +using NegUtils.NEG.UI; + +namespace NEG.UI.UnityUi.Window +{ + public class NoReactionOnBack : MonoController + { + protected override void OnBackUsed(IControllable.BackUsed backUsed) + { + base.OnBackUsed(backUsed); + backUsed.Used = true; + } + } +} \ No newline at end of file diff --git a/NEG/UI/UnityUi/Window/NoReactionOnBack.cs.meta b/NEG/UI/UnityUi/Window/NoReactionOnBack.cs.meta new file mode 100644 index 0000000..8be0e77 --- /dev/null +++ b/NEG/UI/UnityUi/Window/NoReactionOnBack.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: c4a5380c95244c76ac79f820d16ea11c +timeCreated: 1702565120 \ No newline at end of file diff --git a/NEG/UI/UnityUi/WindowSlot/SingleWindowSlot.cs b/NEG/UI/UnityUi/WindowSlot/SingleWindowSlot.cs index 04c49b9..9fff830 100644 --- a/NEG/UI/UnityUi/WindowSlot/SingleWindowSlot.cs +++ b/NEG/UI/UnityUi/WindowSlot/SingleWindowSlot.cs @@ -24,7 +24,13 @@ namespace NEG.UI.WindowSlot window.SetOpenedState(this, data); } - public override void DetachWindow(IWindow window) => CurrentWindow = null; + public override void DetachWindow(IWindow window) + { + if(UiManager.Instance.CurrentMainWindow == window) + UiManager.Instance.MainWindowClosed(window); + CurrentWindow = null; + } + public override void CloseAllWindows() => CurrentWindow = null; } } \ No newline at end of file diff --git a/NEG/UI/UnityUi/WindowSlot/SingleWindowSlotWithHistory.cs b/NEG/UI/UnityUi/WindowSlot/SingleWindowSlotWithHistory.cs index a718257..fc3390c 100644 --- a/NEG/UI/UnityUi/WindowSlot/SingleWindowSlotWithHistory.cs +++ b/NEG/UI/UnityUi/WindowSlot/SingleWindowSlotWithHistory.cs @@ -1,7 +1,10 @@ -using NEG.UI.UnityUi.WindowSlot; +using NEG.UI; +using NEG.UI.UnityUi.Window; +using NEG.UI.UnityUi.WindowSlot; using NEG.UI.Window; using System.Collections.Generic; using System.Linq; +using UnityEngine.EventSystems; namespace NegUtils.NEG.UI.UnityUi.WindowSlot { @@ -41,8 +44,11 @@ namespace NegUtils.NEG.UI.UnityUi.WindowSlot window.SetClosedState(); windowsHistory.Remove(window); if (window != currentWindow || windowsHistory.Count == 0) return; - windowsHistory[^1].SeVisibleState(); currentWindow = windowsHistory[^1]; + currentWindow.SeVisibleState(); + if(UiManager.Instance.CurrentMainWindow == window) + UiManager.Instance.MainWindowClosed(window); + EventSystem.current.SetSelectedGameObject(((MonoWindow)currentWindow).DefaultSelectedItem); } public override void CloseAllWindows() {