Refine UI stack and add Ashwick keypad puzzle

This commit is contained in:
2026-05-15 13:02:12 +01:00
parent 806cf80110
commit 58050abded
69 changed files with 17470 additions and 2752 deletions

View File

@@ -0,0 +1,7 @@
using BriarQueen.Framework.Events.System;
using BriarQueen.Framework.Managers.UI.Base;
namespace BriarQueen.Framework.Events.UI
{
public record UIWindowStateChangedEvent(WindowType WindowType, bool IsOpen) : IEvent;
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 1d8f895856a064fb09a7f2ec4393f686

View File

@@ -5,6 +5,7 @@ using BriarQueen.Framework.Events.Gameplay;
using BriarQueen.Framework.Events.Input;
using BriarQueen.Framework.Events.UI;
using BriarQueen.Framework.Managers.UI;
using BriarQueen.Framework.Managers.UI.Base;
using BriarQueen.Framework.Services.Game;
using UnityEngine;
using UnityEngine.InputSystem;
@@ -109,7 +110,7 @@ namespace BriarQueen.Framework.Managers.Input
if (_eventCoordinator != null)
{
_eventCoordinator.Unsubscribe<UIToggleHudEvent>(OnHudStateChanged);
_eventCoordinator.Unsubscribe<ToggleCodexEvent>(OnCodexStateChanged);
_eventCoordinator.Unsubscribe<UIWindowStateChangedEvent>(OnWindowStateChanged);
_eventCoordinator.Unsubscribe<ToggleToolScreenEvent>(OnToolScreenStateChanged);
_eventCoordinator.Unsubscribe<UIStackChangedEvent>(OnUIStackChanged);
}
@@ -158,7 +159,7 @@ namespace BriarQueen.Framework.Managers.Input
ApplyCursorModeForCurrentScheme();
_eventCoordinator.Subscribe<UIToggleHudEvent>(OnHudStateChanged);
_eventCoordinator.Subscribe<ToggleCodexEvent>(OnCodexStateChanged);
_eventCoordinator.Subscribe<UIWindowStateChangedEvent>(OnWindowStateChanged);
_eventCoordinator.Subscribe<ToggleToolScreenEvent>(OnToolScreenStateChanged);
_eventCoordinator.Subscribe<UIStackChangedEvent>(OnUIStackChanged);
@@ -422,9 +423,10 @@ namespace BriarQueen.Framework.Managers.Input
_hudHidden = !evt.Show;
}
private void OnCodexStateChanged(ToggleCodexEvent evt)
private void OnWindowStateChanged(UIWindowStateChangedEvent evt)
{
_codexShown = evt.Shown;
if (evt.WindowType == WindowType.CodexWindow)
_codexShown = evt.IsOpen;
}
private void OnToolScreenStateChanged(ToggleToolScreenEvent evt)
@@ -461,8 +463,8 @@ namespace BriarQueen.Framework.Managers.Input
{
if(_gameService.IsMainMenuSceneLoaded)
return;
_codexShown = !_codexShown;
_eventCoordinator?.Publish(new ToggleCodexEvent(_codexShown));
_eventCoordinator?.Publish(new ToggleCodexEvent(!_codexShown));
}
private void OnClick(InputAction.CallbackContext ctx)

View File

@@ -323,7 +323,7 @@ namespace BriarQueen.Framework.Managers.Interaction
if (candidate.sortingOrder != currentBest.sortingOrder)
return candidate.sortingOrder > currentBest.sortingOrder;
if (candidate.depth != currentBest.depth)
return candidate.depth > currentBest.depth;

View File

@@ -0,0 +1,10 @@
using Cysharp.Threading.Tasks;
namespace BriarQueen.Framework.Managers.UI.Base
{
public interface IUIOverlayHost
{
UniTask SuspendForOverlay();
UniTask ResumeFromOverlay();
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 4424bf26f2b764c1ca63bc73d75470d6

View File

@@ -0,0 +1,9 @@
namespace BriarQueen.Framework.Managers.UI.Events
{
public enum SettingsOpenSource
{
Unknown,
PauseMenu,
MainMenu
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: ed020edca638d4f1cbdf9b3468316efa

View File

@@ -2,5 +2,5 @@ using BriarQueen.Framework.Events.System;
namespace BriarQueen.Framework.Managers.UI.Events
{
public record UIToggleSettingsWindow(bool Show) : IEvent;
}
public record UIToggleSettingsWindow(bool Show, SettingsOpenSource Source = SettingsOpenSource.Unknown) : IEvent;
}

View File

@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Threading;
using BriarQueen.Data.Identifiers;
using BriarQueen.Framework.Coordinators.Events;
using BriarQueen.Framework.Events.UI;
@@ -34,6 +35,7 @@ namespace BriarQueen.Framework.Managers.UI
private readonly Dictionary<WindowType, IUIWindow> _windows = new();
private readonly Stack<IUIWindow> _windowStack = new();
private readonly SemaphoreSlim _windowTransitionGate = new(1, 1);
private bool _disposed;
@@ -43,6 +45,8 @@ namespace BriarQueen.Framework.Managers.UI
private IPopup _infoPopup;
private IPopup _tutorialPopup;
private IScreenFader _screenFader;
private IUIOverlayHost _mainMenuOverlayHost;
private IUIOverlayHost _activeSettingsOverlayHost;
[Inject]
public UIManager(
@@ -155,11 +159,33 @@ namespace BriarQueen.Framework.Managers.UI
_screenFader = screenFader;
}
public void RegisterMainMenuOverlayHost(IUIOverlayHost host)
{
_mainMenuOverlayHost = host;
}
public void UnregisterMainMenuOverlayHost(IUIOverlayHost host)
{
if (!ReferenceEquals(_mainMenuOverlayHost, host))
return;
if (ReferenceEquals(_activeSettingsOverlayHost, host))
_activeSettingsOverlayHost = null;
_mainMenuOverlayHost = null;
}
private IUIWindow GetWindow(WindowType windowType)
{
return _windows.TryGetValue(windowType, out var window) ? window : null;
}
public bool IsWindowOpen(WindowType windowType)
{
var target = GetWindow(windowType);
return target != null && _windowStack.Contains(target);
}
private async UniTask ApplyHudVisibility(bool visible)
{
if (_disposed || _hudContainer == null)
@@ -197,7 +223,7 @@ namespace BriarQueen.Framework.Managers.UI
private void ToggleSettingsWindow(UIToggleSettingsWindow eventData)
{
if (eventData.Show)
OpenWindow(WindowType.SettingsWindow);
OpenSettingsWindow(eventData.Source).Forget();
else
CloseWindow(WindowType.SettingsWindow);
}
@@ -208,9 +234,15 @@ namespace BriarQueen.Framework.Managers.UI
return;
if (eventData.Shown)
OpenWindow(WindowType.CodexWindow);
{
if (!IsWindowOpen(WindowType.CodexWindow))
OpenWindow(WindowType.CodexWindow);
}
else
CloseWindow(WindowType.CodexWindow);
{
if (IsWindowOpen(WindowType.CodexWindow))
CloseWindow(WindowType.CodexWindow);
}
}
private void OnCodexChangedEvent(CodexChangedEvent eventData)
@@ -300,32 +332,94 @@ namespace BriarQueen.Framework.Managers.UI
OpenWindowInternal(windowType).Forget();
}
private async UniTask OpenSettingsWindow(SettingsOpenSource source)
{
await _windowTransitionGate.WaitAsync();
try
{
if (_disposed)
return;
var window = GetWindow(WindowType.SettingsWindow);
if (window == null)
{
Debug.LogError("[UIManager] Window of type SettingsWindow not registered.");
return;
}
if (_windowStack.Contains(window))
return;
_activeSettingsOverlayHost = null;
var openingSettingsOverPause =
source == SettingsOpenSource.PauseMenu &&
ActiveWindow?.WindowType == WindowType.PauseMenuWindow &&
ActiveWindow is IUIOverlayHost;
var openingSettingsOverMainMenu =
source == SettingsOpenSource.MainMenu &&
_mainMenuOverlayHost != null;
if (openingSettingsOverPause)
{
_activeSettingsOverlayHost = (IUIOverlayHost)ActiveWindow;
await _activeSettingsOverlayHost.SuspendForOverlay();
}
else if (openingSettingsOverMainMenu)
{
_activeSettingsOverlayHost = _mainMenuOverlayHost;
await _activeSettingsOverlayHost.SuspendForOverlay();
}
else if (ActiveWindow != null)
{
await ActiveWindow.Hide();
}
_windowStack.Push(window);
await window.Show();
NotifyWindowStateChanged(window.WindowType, true);
NotifyUIStackChanged();
}
finally
{
_windowTransitionGate.Release();
}
}
private async UniTask OpenWindowInternal(WindowType windowType)
{
if (_disposed)
return;
var window = GetWindow(windowType);
if (window == null)
await _windowTransitionGate.WaitAsync();
try
{
Debug.LogError($"[UIManager] Window of type {windowType} not registered.");
return;
}
if (_disposed)
return;
if (ActiveWindow == window)
return;
if (ActiveWindow != null)
{
var window = GetWindow(windowType);
await ActiveWindow.Hide();
if (window == null)
{
Debug.LogError($"[UIManager] Window of type {windowType} not registered.");
return;
}
if (_windowStack.Contains(window))
return;
if (ActiveWindow != null)
await ActiveWindow.Hide();
_windowStack.Push(window);
await window.Show();
NotifyWindowStateChanged(window.WindowType, true);
NotifyUIStackChanged();
}
finally
{
_windowTransitionGate.Release();
}
_windowStack.Push(window);
await window.Show();
NotifyUIStackChanged();
}
public void CloseWindow(WindowType windowType)
@@ -335,27 +429,45 @@ namespace BriarQueen.Framework.Managers.UI
private async UniTask CloseWindowInternal(WindowType windowType)
{
if (_disposed || _windowStack.Count == 0)
return;
var target = GetWindow(windowType);
if (target == null)
return;
while (_windowStack.Count > 0)
await _windowTransitionGate.WaitAsync();
try
{
var current = _windowStack.Pop();
if (current != null)
await current.Hide();
if (_disposed || _windowStack.Count == 0)
return;
if (current == target)
break;
var target = GetWindow(windowType);
if (target == null || !_windowStack.Contains(target))
return;
while (_windowStack.Count > 0)
{
var current = _windowStack.Pop();
if (current != null)
{
await current.Hide();
NotifyWindowStateChanged(current.WindowType, false);
}
if (current == target)
break;
}
if (target.WindowType == WindowType.SettingsWindow && _activeSettingsOverlayHost != null)
{
await _activeSettingsOverlayHost.ResumeFromOverlay();
_activeSettingsOverlayHost = null;
}
else if (ActiveWindow != null)
{
await ActiveWindow.Show();
}
NotifyUIStackChanged();
}
finally
{
_windowTransitionGate.Release();
}
if (ActiveWindow != null)
await ActiveWindow.Show();
NotifyUIStackChanged();
}
public void CloseTopWindow()
@@ -380,18 +492,38 @@ namespace BriarQueen.Framework.Managers.UI
private async UniTask CloseTopWindowInternal()
{
if (_disposed || _windowStack.Count == 0)
return;
await _windowTransitionGate.WaitAsync();
try
{
if (_disposed || _windowStack.Count == 0)
return;
var top = _windowStack.Pop();
var top = _windowStack.Pop();
if (top != null)
await top.Hide();
if (top != null)
{
await top.Hide();
NotifyWindowStateChanged(top.WindowType, false);
}
if (ActiveWindow != null)
await ActiveWindow.Show();
if (top != null &&
top.WindowType == WindowType.SettingsWindow &&
_activeSettingsOverlayHost != null)
{
await _activeSettingsOverlayHost.ResumeFromOverlay();
_activeSettingsOverlayHost = null;
}
else if (ActiveWindow != null)
{
await ActiveWindow.Show();
}
NotifyUIStackChanged();
NotifyUIStackChanged();
}
finally
{
_windowTransitionGate.Release();
}
}
public void ResetUIState()
@@ -401,44 +533,71 @@ namespace BriarQueen.Framework.Managers.UI
public async UniTask ResetUIStateAsync()
{
while (_windowStack.Count > 0)
await _windowTransitionGate.WaitAsync();
try
{
var window = _windowStack.Pop();
if (window != null)
var shouldResumeSettingsHost = false;
while (_windowStack.Count > 0)
{
var window = _windowStack.Pop();
if (window == null)
continue;
if (window.WindowType == WindowType.SettingsWindow && _activeSettingsOverlayHost != null)
shouldResumeSettingsHost = true;
try
{
await window.Hide();
NotifyWindowStateChanged(window.WindowType, false);
}
catch
{
}
}
}
if (_tutorialPopup != null)
if (shouldResumeSettingsHost)
{
try
{
await _activeSettingsOverlayHost.ResumeFromOverlay();
}
catch
{
}
}
_activeSettingsOverlayHost = null;
if (_tutorialPopup != null)
{
try
{
await _tutorialPopup.Hide();
}
catch
{
}
}
if (_infoPopup != null)
{
try
{
await _infoPopup.Hide();
}
catch
{
}
}
NotifyUIStackChanged();
}
finally
{
try
{
await _tutorialPopup.Hide();
}
catch
{
}
_windowTransitionGate.Release();
}
if (_infoPopup != null)
{
try
{
await _infoPopup.Hide();
}
catch
{
}
}
NotifyUIStackChanged();
}
private void ResetUIStateHard()
@@ -462,11 +621,18 @@ namespace BriarQueen.Framework.Managers.UI
faderComponent.gameObject.SetActive(false);
_windowStack.Clear();
_activeSettingsOverlayHost = null;
_mainMenuOverlayHost = null;
}
private void NotifyUIStackChanged()
{
_eventCoordinator.Publish(new UIStackChangedEvent(_windowStack.Count > 0));
}
private void NotifyWindowStateChanged(WindowType windowType, bool isOpen)
{
_eventCoordinator.Publish(new UIWindowStateChangedEvent(windowType, isOpen));
}
}
}