Restructured for new direction.
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
using System;
|
||||
using BriarQueen.Framework.Assets;
|
||||
using BriarQueen.Framework.Managers.Assets;
|
||||
using Cysharp.Threading.Tasks;
|
||||
using UnityEngine;
|
||||
using VContainer;
|
||||
|
||||
@@ -1,19 +1,22 @@
|
||||
using System;
|
||||
using BriarQueen.Data.Identifiers;
|
||||
using BriarQueen.Framework.Assets;
|
||||
using BriarQueen.Framework.Coordinators.Events;
|
||||
using BriarQueen.Framework.Events.UI;
|
||||
using BriarQueen.Framework.Managers.Assets;
|
||||
using BriarQueen.Framework.Managers.IO;
|
||||
using BriarQueen.Framework.Managers.Levels;
|
||||
using BriarQueen.Framework.Registries;
|
||||
using Cysharp.Threading.Tasks;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using UnityEngine.ResourceManagement.AsyncOperations;
|
||||
using UnityEngine.ResourceManagement.ResourceProviders;
|
||||
using UnityEngine.SceneManagement;
|
||||
using VContainer;
|
||||
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor;
|
||||
#endif
|
||||
|
||||
namespace BriarQueen.Framework.Services.Game
|
||||
{
|
||||
public class GameService
|
||||
@@ -75,7 +78,7 @@ namespace BriarQueen.Framework.Services.Game
|
||||
_eventCoordinator.PublishImmediate(new FadeEvent(false, fadeDuration));
|
||||
await UniTask.Delay(TimeSpan.FromSeconds(fadeDuration));
|
||||
|
||||
await UnloadGameSceneIfLoaded();
|
||||
await PrepareToLeaveGameplayScene();
|
||||
|
||||
if (_assetRegistry == null ||
|
||||
!_assetRegistry.TryGetReference(
|
||||
@@ -193,6 +196,12 @@ namespace BriarQueen.Framework.Services.Game
|
||||
}
|
||||
}
|
||||
|
||||
private async UniTask PrepareToLeaveGameplayScene()
|
||||
{
|
||||
await _levelManager.UnloadLevel();
|
||||
await UnloadGameSceneIfLoaded();
|
||||
}
|
||||
|
||||
public async UniTask SwapGameSceneHandle(AsyncOperationHandle<SceneInstance> nextSceneHandle)
|
||||
{
|
||||
if (!nextSceneHandle.IsValid())
|
||||
@@ -208,7 +217,10 @@ namespace BriarQueen.Framework.Services.Game
|
||||
}
|
||||
|
||||
if (_gameSceneHandle.IsValid())
|
||||
{
|
||||
await _levelManager.UnloadLevel();
|
||||
await _addressableManager.UnloadSceneAsync(_gameSceneHandle);
|
||||
}
|
||||
|
||||
_gameSceneHandle = nextSceneHandle;
|
||||
SceneManager.SetActiveScene(nextSceneHandle.Result.Scene);
|
||||
@@ -223,4 +235,4 @@ namespace BriarQueen.Framework.Services.Game
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,42 +1,44 @@
|
||||
// ==============================
|
||||
// PuzzleBase.cs (updated)
|
||||
// ==============================
|
||||
|
||||
using System.Collections.Generic;
|
||||
using BriarQueen.Framework.Assets;
|
||||
using BriarQueen.Framework.Coordinators.Events;
|
||||
using BriarQueen.Framework.Managers.Assets;
|
||||
using BriarQueen.Framework.Managers.Audio;
|
||||
using BriarQueen.Framework.Managers.Hints.Data;
|
||||
using BriarQueen.Framework.Managers.IO;
|
||||
using BriarQueen.Framework.Managers.Levels.Data;
|
||||
using BriarQueen.Framework.Registries;
|
||||
using BriarQueen.Framework.Services.Destruction;
|
||||
using Cysharp.Threading.Tasks;
|
||||
using UnityEngine;
|
||||
using VContainer;
|
||||
|
||||
namespace BriarQueen.Framework.Services.Puzzles.Base
|
||||
{
|
||||
public abstract class BasePuzzle : BaseLevel
|
||||
public abstract class BasePuzzle : MonoBehaviour
|
||||
{
|
||||
protected AddressableManager AddressableManager;
|
||||
protected AssetRegistry AssetRegistry;
|
||||
protected AudioManager AudioManager;
|
||||
protected DestructionService DestructionService;
|
||||
protected EventCoordinator EventCoordinator;
|
||||
protected ItemRegistry ItemRegistry;
|
||||
protected PuzzleService PuzzleService;
|
||||
protected SaveManager SaveManager;
|
||||
|
||||
public abstract string PuzzleID { get; }
|
||||
|
||||
public override bool IsPuzzleLevel => true;
|
||||
|
||||
// BaseLevel still requires these.
|
||||
public abstract override string LevelName { get; }
|
||||
public abstract override Dictionary<int, BaseHint> Hints { get; }
|
||||
|
||||
public abstract UniTask CompletePuzzle();
|
||||
|
||||
public virtual UniTask PostLoad()
|
||||
{
|
||||
return UniTask.CompletedTask;
|
||||
}
|
||||
|
||||
public virtual UniTask PreUnload()
|
||||
{
|
||||
return UniTask.CompletedTask;
|
||||
}
|
||||
|
||||
[Inject]
|
||||
public void Construct(EventCoordinator eventCoordinator, AudioManager audioManager,
|
||||
SaveManager saveManager, ItemRegistry itemRegistry, AddressableManager addressableManager,
|
||||
AssetRegistry assetRegistry, PuzzleService puzzleService)
|
||||
AssetRegistry assetRegistry, PuzzleService puzzleService, DestructionService destructionService)
|
||||
{
|
||||
EventCoordinator = eventCoordinator;
|
||||
AudioManager = audioManager;
|
||||
@@ -45,6 +47,7 @@ namespace BriarQueen.Framework.Services.Puzzles.Base
|
||||
AddressableManager = addressableManager;
|
||||
AssetRegistry = assetRegistry;
|
||||
PuzzleService = puzzleService;
|
||||
DestructionService = destructionService;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ namespace BriarQueen.Framework.Services.Puzzles
|
||||
{
|
||||
private readonly SaveManager _saveManager;
|
||||
|
||||
private BasePuzzle _currentBasePuzzle;
|
||||
private readonly Dictionary<string, BasePuzzle> _activePuzzles = new();
|
||||
private bool _isWritingState;
|
||||
|
||||
[Inject]
|
||||
@@ -31,40 +31,98 @@ namespace BriarQueen.Framework.Services.Puzzles
|
||||
|
||||
public async UniTask LoadPuzzle(BasePuzzle basePuzzle)
|
||||
{
|
||||
_currentBasePuzzle = basePuzzle;
|
||||
if (_currentBasePuzzle == null)
|
||||
if (basePuzzle == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
await TryRestorePuzzleState(_currentBasePuzzle);
|
||||
if (string.IsNullOrWhiteSpace(basePuzzle.PuzzleID))
|
||||
{
|
||||
Debug.LogWarning($"[PuzzleService] Cannot load puzzle '{basePuzzle.name}' with null/empty PuzzleID.");
|
||||
return;
|
||||
}
|
||||
|
||||
_activePuzzles[basePuzzle.PuzzleID] = basePuzzle;
|
||||
|
||||
await basePuzzle.PostLoad();
|
||||
await TryRestorePuzzleState(basePuzzle);
|
||||
}
|
||||
|
||||
public async UniTask LoadPuzzles(IEnumerable<BasePuzzle> basePuzzles)
|
||||
{
|
||||
_activePuzzles.Clear();
|
||||
|
||||
if (basePuzzles == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var basePuzzle in basePuzzles)
|
||||
{
|
||||
await LoadPuzzle(basePuzzle);
|
||||
}
|
||||
}
|
||||
|
||||
public async UniTask SavePuzzle(BasePuzzle basePuzzle)
|
||||
{
|
||||
if (basePuzzle == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (_currentBasePuzzle != null && basePuzzle != _currentBasePuzzle)
|
||||
if (!string.IsNullOrWhiteSpace(basePuzzle.PuzzleID) &&
|
||||
_activePuzzles.TryGetValue(basePuzzle.PuzzleID, out var activePuzzle) &&
|
||||
activePuzzle != basePuzzle)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
await SavePuzzleState(basePuzzle, flushToDisk: true);
|
||||
_currentBasePuzzle = null;
|
||||
await basePuzzle.PreUnload();
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(basePuzzle.PuzzleID))
|
||||
{
|
||||
_activePuzzles.Remove(basePuzzle.PuzzleID);
|
||||
}
|
||||
}
|
||||
|
||||
public async UniTask SavePuzzles(IEnumerable<BasePuzzle> basePuzzles)
|
||||
{
|
||||
if (basePuzzles != null)
|
||||
{
|
||||
foreach (var basePuzzle in basePuzzles)
|
||||
{
|
||||
await SavePuzzle(basePuzzle);
|
||||
}
|
||||
}
|
||||
|
||||
_activePuzzles.Clear();
|
||||
}
|
||||
|
||||
private async UniTask OnBeforeSaveRequestedAsync()
|
||||
{
|
||||
if (_currentBasePuzzle == null)
|
||||
if (_activePuzzles.Count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
await SavePuzzleState(_currentBasePuzzle, flushToDisk: false);
|
||||
foreach (var basePuzzle in _activePuzzles.Values.ToList())
|
||||
{
|
||||
await SavePuzzleState(basePuzzle, flushToDisk: false);
|
||||
}
|
||||
}
|
||||
|
||||
private async UniTask TryRestorePuzzleState(BasePuzzle basePuzzle)
|
||||
{
|
||||
if (basePuzzle == null || _saveManager.CurrentSave == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (basePuzzle is not IPuzzleStateful stateful)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var save = _saveManager.CurrentSave;
|
||||
var entry = save.PuzzleStates?.FirstOrDefault(x => x != null && x.PuzzleID == basePuzzle.PuzzleID);
|
||||
@@ -83,20 +141,28 @@ namespace BriarQueen.Framework.Services.Puzzles
|
||||
private async UniTask SavePuzzleState(BasePuzzle basePuzzle, bool flushToDisk)
|
||||
{
|
||||
if (basePuzzle == null || _saveManager.CurrentSave == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (basePuzzle is not IPuzzleStateful stateful)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (_isWritingState)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_isWritingState = true;
|
||||
|
||||
try
|
||||
{
|
||||
if (basePuzzle is IPuzzleWorldStateSync worldStateSync)
|
||||
{
|
||||
worldStateSync.SyncWorldStateToSave();
|
||||
}
|
||||
|
||||
var save = _saveManager.CurrentSave;
|
||||
save.PuzzleStates ??= new List<PuzzleStateSaveData>();
|
||||
@@ -123,7 +189,9 @@ namespace BriarQueen.Framework.Services.Puzzles
|
||||
existing.Completed = stateful.IsCompleted;
|
||||
|
||||
if (flushToDisk)
|
||||
{
|
||||
await _saveManager.SaveGameDataLatest();
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
@@ -131,4 +199,4 @@ namespace BriarQueen.Framework.Services.Puzzles
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,9 +9,6 @@ namespace BriarQueen.Framework.Services.Settings.Data
|
||||
public float MusicVolume;
|
||||
public float SfxVolume;
|
||||
public float VoiceVolume;
|
||||
public float AmbienceVolume;
|
||||
public float UIVolume;
|
||||
public bool MuteWhenUnfocused;
|
||||
|
||||
public AudioSettings()
|
||||
{
|
||||
@@ -19,9 +16,6 @@ namespace BriarQueen.Framework.Services.Settings.Data
|
||||
MusicVolume = 0.75f; // 75%
|
||||
SfxVolume = 0.75f; // 75%
|
||||
VoiceVolume = 1.0f; // 100%
|
||||
AmbienceVolume = 0.75f; // 75%
|
||||
UIVolume = 0.5f; // 50%
|
||||
MuteWhenUnfocused = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -89,7 +89,6 @@ namespace BriarQueen.Framework.Services.Settings
|
||||
AudioMixerGroups.MASTER_GROUP => Audio.MasterVolume,
|
||||
AudioMixerGroups.MUSIC_GROUP => Audio.MusicVolume,
|
||||
AudioMixerGroups.SFX_GROUP => Audio.SfxVolume,
|
||||
AudioMixerGroups.UI_GROUP => Audio.UIVolume,
|
||||
AudioMixerGroups.VOICE_GROUP => Audio.VoiceVolume,
|
||||
_ => Audio.MasterVolume
|
||||
};
|
||||
@@ -111,10 +110,6 @@ namespace BriarQueen.Framework.Services.Settings
|
||||
_audioManager.SetVolume(AudioMixerParameters.MUSIC_VOLUME, a.MusicVolume);
|
||||
_audioManager.SetVolume(AudioMixerParameters.SFX_VOLUME, a.SfxVolume);
|
||||
_audioManager.SetVolume(AudioMixerParameters.VOICE_VOLUME, a.VoiceVolume);
|
||||
_audioManager.SetVolume(AudioMixerParameters.AMBIENCE_VOLUME, a.AmbienceVolume);
|
||||
_audioManager.SetVolume(AudioMixerParameters.UI_VOLUME, a.UIVolume);
|
||||
|
||||
Application.runInBackground = !a.MuteWhenUnfocused;
|
||||
}
|
||||
|
||||
private void ApplyVisual(VisualSettings v)
|
||||
|
||||
@@ -2,8 +2,11 @@ using BriarQueen.Data.Identifiers;
|
||||
using BriarQueen.Framework.Coordinators.Events;
|
||||
using BriarQueen.Framework.Events.Save;
|
||||
using BriarQueen.Framework.Events.UI;
|
||||
using BriarQueen.Framework.Managers.Input;
|
||||
using BriarQueen.Framework.Managers.IO;
|
||||
using BriarQueen.Framework.Services.Settings;
|
||||
using System.Text.RegularExpressions;
|
||||
using UnityEngine.InputSystem;
|
||||
using VContainer;
|
||||
|
||||
namespace BriarQueen.Framework.Services.Tutorials
|
||||
@@ -11,23 +14,26 @@ namespace BriarQueen.Framework.Services.Tutorials
|
||||
public class TutorialService
|
||||
{
|
||||
private readonly EventCoordinator _eventCoordinator;
|
||||
private readonly SettingsService _settingsService;
|
||||
private readonly SaveManager _saveManager;
|
||||
private readonly SettingsService _settingsService;
|
||||
private readonly SaveManager _saveManager;
|
||||
private readonly InputManager _inputManager;
|
||||
|
||||
[Inject]
|
||||
public TutorialService(
|
||||
EventCoordinator eventCoordinator,
|
||||
SettingsService settingsService,
|
||||
SaveManager saveManager)
|
||||
SettingsService settingsService,
|
||||
SaveManager saveManager,
|
||||
InputManager inputManager)
|
||||
{
|
||||
_eventCoordinator = eventCoordinator;
|
||||
_settingsService = settingsService;
|
||||
_saveManager = saveManager;
|
||||
_settingsService = settingsService;
|
||||
_saveManager = saveManager;
|
||||
_inputManager = inputManager;
|
||||
}
|
||||
|
||||
public void DisplayTutorial(TutorialPopupID tutorialPopupID)
|
||||
{
|
||||
var save = _saveManager.CurrentSave;
|
||||
var save = _saveManager.CurrentSave;
|
||||
var tutorialVars = save?.PersistentVariables?.TutorialPopupVariables;
|
||||
|
||||
if (tutorialVars == null)
|
||||
@@ -39,9 +45,60 @@ namespace BriarQueen.Framework.Services.Tutorials
|
||||
tutorialVars.MarkDisplayed(tutorialPopupID);
|
||||
|
||||
if (_settingsService.AreTutorialsEnabled())
|
||||
_eventCoordinator.Publish(new DisplayTutorialPopupEvent(tutorialPopupID));
|
||||
{
|
||||
var resolvedText = ResolveText(tutorialPopupID);
|
||||
_eventCoordinator.Publish(new DisplayTutorialPopupEvent(tutorialPopupID, resolvedText));
|
||||
}
|
||||
|
||||
_eventCoordinator.PublishImmediate(new RequestGameSaveEvent());
|
||||
}
|
||||
|
||||
// ── Text resolution ───────────────────────────────────────────
|
||||
|
||||
/// <summary>
|
||||
/// Resolves {ActionName} tokens in the tutorial text for the given ID
|
||||
/// to the current binding display string for that action.
|
||||
/// Hotswap-safe — reads the current control scheme at call time.
|
||||
/// </summary>
|
||||
public string ResolveText(TutorialPopupID id)
|
||||
{
|
||||
if (!TutorialPopupTexts.AllPopups.TryGetValue(id, out var template))
|
||||
return string.Empty;
|
||||
|
||||
return ResolveText(template);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resolves {ActionName} tokens in an arbitrary string to the current
|
||||
/// binding display string for that action.
|
||||
/// </summary>
|
||||
public string ResolveText(string template)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(template))
|
||||
return template;
|
||||
|
||||
return Regex.Replace(template, @"\{(\w+)\}", match =>
|
||||
{
|
||||
var actionName = match.Groups[1].Value;
|
||||
var binding = GetBindingDisplayString(actionName);
|
||||
return string.IsNullOrWhiteSpace(binding) ? match.Value : binding;
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the display string for a named action's current binding,
|
||||
/// matched to the active control scheme.
|
||||
/// </summary>
|
||||
public string GetBindingDisplayString(string actionName)
|
||||
{
|
||||
if (_inputManager == null) return string.Empty;
|
||||
|
||||
var action = _inputManager.GetAction(actionName);
|
||||
if (action == null) return string.Empty;
|
||||
|
||||
var displayString = action.GetBindingDisplayString(group: _inputManager.CurrentControlScheme);
|
||||
|
||||
return string.IsNullOrWhiteSpace(displayString) ? string.Empty : displayString;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user