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

@@ -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));
}
}
}