Restructured for new direction.
This commit is contained in:
@@ -1,11 +1,12 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using BriarQueen.Data.Identifiers;
|
||||
using BriarQueen.Data.IO.Saves;
|
||||
using BriarQueen.Framework.Assets;
|
||||
using BriarQueen.Framework.Coordinators.Events;
|
||||
using BriarQueen.Framework.Events.Save;
|
||||
using BriarQueen.Framework.Events.UI;
|
||||
using BriarQueen.Framework.Managers.Assets;
|
||||
using BriarQueen.Framework.Managers.Audio;
|
||||
using BriarQueen.Framework.Managers.Interaction.Data;
|
||||
using BriarQueen.Framework.Managers.IO;
|
||||
@@ -31,11 +32,16 @@ namespace BriarQueen.Framework.Managers.Levels.Data
|
||||
|
||||
[Tooltip("Used for custom tooltip. Defaults to Item Name")]
|
||||
[SerializeField]
|
||||
private string _interactableTooltip = string.Empty;
|
||||
protected string _interactableTooltip = string.Empty;
|
||||
[Tooltip("Optional. Used for custom interaction.")]
|
||||
[SerializeField]
|
||||
private string _pickupText = string.Empty;
|
||||
|
||||
[Header("Object Setup")]
|
||||
[SerializeField]
|
||||
protected CanvasGroup _canvasGroup;
|
||||
|
||||
protected bool _isLocked;
|
||||
|
||||
protected AddressableManager AddressableManager;
|
||||
protected AssetRegistry AssetRegistry;
|
||||
@@ -68,8 +74,23 @@ namespace BriarQueen.Framework.Managers.Levels.Data
|
||||
|
||||
public virtual UICursorService.CursorStyle ApplicableCursorStyle => UICursorService.CursorStyle.Pickup;
|
||||
|
||||
public virtual string InteractableName =>
|
||||
!string.IsNullOrWhiteSpace(_interactableTooltip) ? _interactableTooltip : _itemData.ItemName;
|
||||
public virtual string InteractableName
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(_interactableTooltip))
|
||||
{
|
||||
return _interactableTooltip;
|
||||
}
|
||||
|
||||
if (_itemData != null && !string.IsNullOrWhiteSpace(_itemData.ItemName))
|
||||
{
|
||||
return _itemData.ItemName;
|
||||
}
|
||||
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
@@ -91,6 +112,15 @@ namespace BriarQueen.Framework.Managers.Levels.Data
|
||||
|
||||
await Pickup();
|
||||
await OnInteracted();
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(_pickupText))
|
||||
{
|
||||
EventCoordinator.Publish(new DisplayInteractEvent(_pickupText));
|
||||
}
|
||||
else
|
||||
{
|
||||
EventCoordinator.Publish(new DisplayInteractEvent(InteractEventIDs.Get(ItemInteractKey.LooksImportant)));
|
||||
}
|
||||
}
|
||||
|
||||
public virtual UniTask EnterHover()
|
||||
@@ -147,8 +177,8 @@ namespace BriarQueen.Framework.Managers.Levels.Data
|
||||
|
||||
protected virtual async UniTask Remove()
|
||||
{
|
||||
// TODO - Play Cut Vines SFX
|
||||
if (_canvasGroup == null) _canvasGroup = GetComponent<CanvasGroup>();
|
||||
if (_canvasGroup == null)
|
||||
_canvasGroup = GetComponent<CanvasGroup>();
|
||||
|
||||
if (PickupSequence.isAlive)
|
||||
{
|
||||
@@ -184,7 +214,7 @@ namespace BriarQueen.Framework.Managers.Levels.Data
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateSaveGameOnRemoval()
|
||||
protected virtual void UpdateSaveGameOnRemoval()
|
||||
{
|
||||
var save = SaveManager.CurrentSave;
|
||||
Debug.Log($"[Base Item] Found save - {save.SaveFileName}");
|
||||
@@ -240,5 +270,35 @@ namespace BriarQueen.Framework.Managers.Levels.Data
|
||||
await DestructionService.Destroy(gameObject);
|
||||
}
|
||||
}
|
||||
|
||||
public void Lock()
|
||||
{
|
||||
_isLocked = true;
|
||||
|
||||
_canvasGroup.blocksRaycasts = false;
|
||||
_canvasGroup.interactable = false;
|
||||
}
|
||||
|
||||
public void Unlock()
|
||||
{
|
||||
_isLocked = false;
|
||||
|
||||
_canvasGroup.blocksRaycasts = true;
|
||||
_canvasGroup.interactable = true;
|
||||
}
|
||||
|
||||
public void OnValidate()
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
|
||||
var canvasGroup = GetComponent<CanvasGroup>();
|
||||
|
||||
if (!canvasGroup)
|
||||
{
|
||||
canvasGroup = gameObject.AddComponent<CanvasGroup>();
|
||||
_canvasGroup = canvasGroup;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using BriarQueen.Data.Identifiers;
|
||||
using BriarQueen.Framework.Coordinators.Events;
|
||||
using BriarQueen.Framework.Events.UI;
|
||||
@@ -8,12 +10,19 @@ using BriarQueen.Framework.Managers.IO;
|
||||
using BriarQueen.Framework.Managers.Player;
|
||||
using BriarQueen.Framework.Managers.Player.Data.Codex;
|
||||
using BriarQueen.Framework.Services.Destruction;
|
||||
using BriarQueen.Framework.Services.Puzzles.Base;
|
||||
using BriarQueen.Framework.Services.Settings;
|
||||
using BriarQueen.Framework.Services.Tutorials;
|
||||
using Cysharp.Threading.Tasks;
|
||||
using NaughtyAttributes;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using VContainer;
|
||||
using SettingsService = BriarQueen.Framework.Services.Settings.SettingsService;
|
||||
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor;
|
||||
#endif
|
||||
|
||||
namespace BriarQueen.Framework.Managers.Levels.Data
|
||||
{
|
||||
@@ -30,6 +39,10 @@ namespace BriarQueen.Framework.Managers.Levels.Data
|
||||
|
||||
public List<CodexTrigger> CodexTriggers;
|
||||
|
||||
[Header("Puzzles")]
|
||||
[SerializeField]
|
||||
public List<BasePuzzle> Puzzles;
|
||||
|
||||
[Header("Setup")]
|
||||
[SerializeField]
|
||||
protected GraphicRaycaster _raycaster;
|
||||
@@ -47,8 +60,6 @@ namespace BriarQueen.Framework.Managers.Levels.Data
|
||||
|
||||
public virtual string LevelName => _levelName;
|
||||
|
||||
public virtual bool IsPuzzleLevel { get; }
|
||||
|
||||
public virtual int CurrentLevelHintStage { get; set; }
|
||||
|
||||
public virtual Dictionary<int, BaseHint> Hints { get; }
|
||||
@@ -112,5 +123,72 @@ namespace BriarQueen.Framework.Managers.Levels.Data
|
||||
{
|
||||
return UniTask.CompletedTask;
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
[Button("Discover Level References")]
|
||||
private void DiscoverLevelReferences()
|
||||
{
|
||||
Undo.RecordObject(this, "Discover Level References");
|
||||
|
||||
var discoveredCodexTriggers = GetComponentsInChildren<CodexTrigger>(true)
|
||||
.Where(trigger => trigger != null)
|
||||
.OrderBy(GetHierarchyPath, StringComparer.Ordinal)
|
||||
.ToList();
|
||||
|
||||
var discoveredPickups = GetComponentsInChildren<BaseItem>(true)
|
||||
.Where(item => item != null && item is not CodexTrigger)
|
||||
.OrderBy(GetHierarchyPath, StringComparer.Ordinal)
|
||||
.ToList();
|
||||
|
||||
var discoveredPuzzles = GetComponentsInChildren<BasePuzzle>(true)
|
||||
.Where(puzzle => puzzle != null)
|
||||
.OrderBy(GetHierarchyPath, StringComparer.Ordinal)
|
||||
.ToList();
|
||||
|
||||
Pickups = discoveredPickups;
|
||||
CodexTriggers = discoveredCodexTriggers;
|
||||
Puzzles = discoveredPuzzles;
|
||||
|
||||
EditorUtility.SetDirty(this);
|
||||
PrefabUtility.RecordPrefabInstancePropertyModifications(this);
|
||||
|
||||
Debug.Log(
|
||||
$"[BaseLevel] Discovery complete for '{name}'. Pickups: {Pickups.Count}, CodexTriggers: {CodexTriggers.Count}, Puzzles: {Puzzles.Count}",
|
||||
this);
|
||||
}
|
||||
|
||||
private static string GetHierarchyPath(Component component)
|
||||
{
|
||||
if (component == null)
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
var names = new Stack<string>();
|
||||
var current = component.transform;
|
||||
|
||||
while (current != null)
|
||||
{
|
||||
names.Push(current.name);
|
||||
current = current.parent;
|
||||
}
|
||||
|
||||
return string.Join("/", names);
|
||||
}
|
||||
#endif
|
||||
|
||||
public void OnValidate()
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
|
||||
CanvasScaler scaler = GetComponent<CanvasScaler>();
|
||||
scaler.uiScaleMode = CanvasScaler.ScaleMode.ScaleWithScreenSize;
|
||||
scaler.matchWidthOrHeight = 0.5f;
|
||||
scaler.referenceResolution = new Vector2(1920, 1200);
|
||||
|
||||
GraphicRaycaster raycaster = GetComponent<GraphicRaycaster>();
|
||||
_raycaster = raycaster;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,18 +2,17 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using BriarQueen.Data.IO.Saves;
|
||||
using BriarQueen.Framework.Assets;
|
||||
using BriarQueen.Framework.Coordinators.Events;
|
||||
using BriarQueen.Framework.Events.Gameplay;
|
||||
using BriarQueen.Framework.Events.Progression;
|
||||
using BriarQueen.Framework.Events.Save;
|
||||
using BriarQueen.Framework.Events.UI;
|
||||
using BriarQueen.Framework.Managers.Assets;
|
||||
using BriarQueen.Framework.Managers.IO;
|
||||
using BriarQueen.Framework.Managers.Levels.Data;
|
||||
using BriarQueen.Framework.Registries;
|
||||
using BriarQueen.Framework.Services.Destruction;
|
||||
using BriarQueen.Framework.Services.Puzzles;
|
||||
using BriarQueen.Framework.Services.Puzzles.Base;
|
||||
using Cysharp.Threading.Tasks;
|
||||
using UnityEngine;
|
||||
using VContainer;
|
||||
@@ -33,6 +32,7 @@ namespace BriarQueen.Framework.Managers.Levels
|
||||
private readonly SaveManager _saveManager;
|
||||
|
||||
private UniTask<bool> _activeLoadTask = UniTask.FromResult(false);
|
||||
private bool _isLoadInProgress;
|
||||
private BaseLevel _currentLevel;
|
||||
|
||||
public bool Initialized { get; private set; }
|
||||
@@ -57,7 +57,9 @@ namespace BriarQueen.Framework.Managers.Levels
|
||||
public void Initialize()
|
||||
{
|
||||
if (Initialized)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Debug.Log($"[{nameof(LevelManager)}] Initializing...");
|
||||
_saveManager.OnSaveRequested += OnSaveGameRequested;
|
||||
@@ -70,7 +72,9 @@ namespace BriarQueen.Framework.Managers.Levels
|
||||
public void Dispose()
|
||||
{
|
||||
if (!Initialized)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_saveManager.OnSaveRequested -= OnSaveGameRequested;
|
||||
_eventCoordinator.Unsubscribe<UpdateHintProgressEvent>(OnHintStageUpdated);
|
||||
@@ -81,10 +85,14 @@ namespace BriarQueen.Framework.Managers.Levels
|
||||
private void OnHintStageUpdated(UpdateHintProgressEvent evt)
|
||||
{
|
||||
if (_currentLevel == null || evt == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!string.Equals(evt.LevelID, _currentLevel.LevelID, StringComparison.Ordinal))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var incoming = Mathf.Max(0, evt.Stage);
|
||||
|
||||
@@ -101,7 +109,9 @@ namespace BriarQueen.Framework.Managers.Levels
|
||||
private void OnSaveGameRequested(SaveGame saveGame)
|
||||
{
|
||||
if (saveGame == null || _currentLevel == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
saveGame.CurrentLevelID = _currentLevel.LevelID;
|
||||
saveGame.CurrentSceneID = _currentLevel.SceneID;
|
||||
@@ -120,12 +130,73 @@ namespace BriarQueen.Framework.Managers.Levels
|
||||
|
||||
lock (_lock)
|
||||
{
|
||||
_activeLoadTask = LoadLevelInternal(levelAssetID);
|
||||
if (_isLoadInProgress)
|
||||
{
|
||||
Debug.LogWarning(
|
||||
$"[LevelManager] LoadLevel('{levelAssetID}') requested while another level load is already in progress. Returning the active load task.");
|
||||
return _activeLoadTask;
|
||||
}
|
||||
|
||||
_isLoadInProgress = true;
|
||||
_activeLoadTask = LoadLevelTracked(levelAssetID);
|
||||
return _activeLoadTask;
|
||||
}
|
||||
}
|
||||
|
||||
private async UniTask<bool> LoadLevelTracked(string levelAssetID)
|
||||
{
|
||||
try
|
||||
{
|
||||
return await LoadLevelInternal(levelAssetID);
|
||||
}
|
||||
finally
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
_isLoadInProgress = false;
|
||||
_activeLoadTask = UniTask.FromResult(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async UniTask<bool> LoadLevelInternal(string levelAssetID)
|
||||
{
|
||||
var previousLevelId = _currentLevel != null ? _currentLevel.LevelID : null;
|
||||
|
||||
_eventCoordinator.PublishImmediate(new FadeEvent(false, LEVEL_FADE_DURATION));
|
||||
await UniTask.Delay(TimeSpan.FromSeconds(LEVEL_FADE_DURATION));
|
||||
|
||||
if (_currentLevel != null)
|
||||
{
|
||||
await UnloadLevelInternal();
|
||||
}
|
||||
|
||||
if (await TryLoadLevelCore(levelAssetID))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(previousLevelId) &&
|
||||
!string.Equals(previousLevelId, levelAssetID, StringComparison.Ordinal))
|
||||
{
|
||||
Debug.LogWarning(
|
||||
$"[LevelManager] Failed to load '{levelAssetID}'. Attempting recovery by reloading previous level '{previousLevelId}'.");
|
||||
|
||||
if (await TryLoadLevelCore(previousLevelId))
|
||||
{
|
||||
Debug.LogWarning(
|
||||
$"[LevelManager] Recovery succeeded by reloading '{previousLevelId}'.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
_eventCoordinator.PublishImmediate(new FadeEvent(true, LEVEL_FADE_DURATION));
|
||||
await UniTask.Delay(TimeSpan.FromSeconds(LEVEL_FADE_DURATION));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private async UniTask<bool> TryLoadLevelCore(string levelAssetID)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -141,12 +212,6 @@ namespace BriarQueen.Framework.Managers.Levels
|
||||
return false;
|
||||
}
|
||||
|
||||
_eventCoordinator.PublishImmediate(new FadeEvent(false, LEVEL_FADE_DURATION));
|
||||
await UniTask.Delay(TimeSpan.FromSeconds(LEVEL_FADE_DURATION));
|
||||
|
||||
if (_currentLevel != null)
|
||||
await UnloadLevelInternal();
|
||||
|
||||
var levelObj = await _addressableManager.InstantiateAsync(levelRef);
|
||||
if (levelObj == null)
|
||||
{
|
||||
@@ -157,7 +222,8 @@ namespace BriarQueen.Framework.Managers.Levels
|
||||
var level = levelObj.GetComponent<BaseLevel>();
|
||||
if (level == null)
|
||||
{
|
||||
Debug.LogError($"[LevelManager] Instantiated level '{levelAssetID}' has no BaseLevel component. Destroying instance.");
|
||||
Debug.LogError(
|
||||
$"[LevelManager] Instantiated level '{levelAssetID}' has no BaseLevel component. Destroying instance.");
|
||||
await _destructionService.Destroy(levelObj);
|
||||
return false;
|
||||
}
|
||||
@@ -169,8 +235,7 @@ namespace BriarQueen.Framework.Managers.Levels
|
||||
|
||||
await _currentLevel.PostLoad();
|
||||
|
||||
if (_currentLevel is BasePuzzle puzzle)
|
||||
await _puzzleService.LoadPuzzle(puzzle);
|
||||
await _puzzleService.LoadPuzzles(_currentLevel.Puzzles);
|
||||
|
||||
_eventCoordinator.Publish(new LevelChangedEvent(_currentLevel));
|
||||
|
||||
@@ -178,7 +243,9 @@ namespace BriarQueen.Framework.Managers.Levels
|
||||
await UniTask.Delay(TimeSpan.FromSeconds(LEVEL_FADE_DURATION));
|
||||
|
||||
if (_currentLevel != null)
|
||||
{
|
||||
await _currentLevel.PostActivate();
|
||||
}
|
||||
|
||||
_eventCoordinator.Publish(new RequestGameSaveEvent());
|
||||
return true;
|
||||
@@ -186,29 +253,38 @@ namespace BriarQueen.Framework.Managers.Levels
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.LogError($"[LevelManager] Exception while loading '{levelAssetID}': {ex}");
|
||||
|
||||
if (_currentLevel != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
await _destructionService.Destroy(_currentLevel.gameObject);
|
||||
}
|
||||
catch (Exception destroyEx)
|
||||
{
|
||||
Debug.LogWarning($"[LevelManager] Failed to destroy broken level instance: {destroyEx}");
|
||||
}
|
||||
|
||||
_currentLevel = null;
|
||||
}
|
||||
|
||||
await CleanupFailedCurrentLevel();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private async UniTask CleanupFailedCurrentLevel()
|
||||
{
|
||||
if (_currentLevel == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
await _destructionService.Destroy(_currentLevel.gameObject);
|
||||
}
|
||||
catch (Exception destroyEx)
|
||||
{
|
||||
Debug.LogWarning($"[LevelManager] Failed to destroy broken level instance: {destroyEx}");
|
||||
}
|
||||
finally
|
||||
{
|
||||
_currentLevel = null;
|
||||
}
|
||||
}
|
||||
|
||||
private void RestoreHintStageForCurrentLevel()
|
||||
{
|
||||
if (_currentLevel == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var save = _saveManager.CurrentSave;
|
||||
if (save?.LevelHintStages == null)
|
||||
@@ -218,23 +294,33 @@ namespace BriarQueen.Framework.Managers.Levels
|
||||
}
|
||||
|
||||
if (save.LevelHintStages.TryGetValue(_currentLevel.LevelID, out var stage))
|
||||
{
|
||||
_currentLevel.CurrentLevelHintStage = Mathf.Max(0, stage);
|
||||
}
|
||||
else
|
||||
{
|
||||
_currentLevel.CurrentLevelHintStage = 0;
|
||||
}
|
||||
}
|
||||
|
||||
private async UniTask RestoreItemStateForCurrentLevel()
|
||||
{
|
||||
if (_currentLevel == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var save = _saveManager.CurrentSave;
|
||||
if (save == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var interactables = _currentLevel.Pickups;
|
||||
if (interactables == null || interactables.Count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var interactable in interactables)
|
||||
{
|
||||
@@ -245,10 +331,14 @@ namespace BriarQueen.Framework.Managers.Levels
|
||||
}
|
||||
|
||||
if (save.CollectedItems.Any(x => x.UniqueIdentifier == interactable.ItemData.UniqueID))
|
||||
{
|
||||
await _destructionService.Destroy(interactable.gameObject);
|
||||
}
|
||||
|
||||
if (save.RemovedItems.Any(x => x.UniqueIdentifier == interactable.ItemData.UniqueID))
|
||||
{
|
||||
await _destructionService.Destroy(interactable.gameObject);
|
||||
}
|
||||
}
|
||||
|
||||
var codexTriggers = _currentLevel.CodexTriggers;
|
||||
@@ -258,7 +348,9 @@ namespace BriarQueen.Framework.Managers.Levels
|
||||
if (save.DiscoveredCodexEntries.Any(x => x.UniqueIdentifier == trigger.Entry.UniqueID))
|
||||
{
|
||||
if (trigger.RemoveTrigger)
|
||||
{
|
||||
await _destructionService.Destroy(trigger.gameObject);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -268,7 +360,9 @@ namespace BriarQueen.Framework.Managers.Levels
|
||||
lock (_lock)
|
||||
{
|
||||
if (_activeLoadTask.Status == UniTaskStatus.Pending)
|
||||
{
|
||||
return _activeLoadTask.ContinueWith(_ => UnloadLevelInternal());
|
||||
}
|
||||
|
||||
return UnloadLevelInternal();
|
||||
}
|
||||
@@ -277,15 +371,16 @@ namespace BriarQueen.Framework.Managers.Levels
|
||||
private async UniTask UnloadLevelInternal()
|
||||
{
|
||||
if (_currentLevel == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var level = _currentLevel;
|
||||
_currentLevel = null;
|
||||
|
||||
try
|
||||
{
|
||||
if (level is BasePuzzle puzzle)
|
||||
await _puzzleService.SavePuzzle(puzzle);
|
||||
await _puzzleService.SavePuzzles(level.Puzzles);
|
||||
|
||||
_eventCoordinator.Publish(new RequestGameSaveEvent());
|
||||
await level.PreUnload();
|
||||
@@ -298,4 +393,4 @@ namespace BriarQueen.Framework.Managers.Levels
|
||||
await _destructionService.Destroy(level.gameObject);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user