using System; using BriarQueen.Data.Identifiers; using BriarQueen.Framework.Assets; using BriarQueen.Framework.Coordinators.Events; using BriarQueen.Framework.Events.UI; 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; namespace BriarQueen.Framework.Services.Game { public class GameService { private readonly AddressableManager _addressableManager; private readonly AssetRegistry _assetRegistry; private readonly EventCoordinator _eventCoordinator; private readonly LevelManager _levelManager; private readonly SaveManager _saveManager; private AsyncOperationHandle _gameSceneHandle; private AsyncOperationHandle _mainMenuSceneHandle; private AsyncOperationHandle? _uiSceneHandle; public bool IsMainMenuSceneLoaded {get; private set;} [Inject] public GameService( SaveManager saveManager, EventCoordinator eventCoordinator, AddressableManager addressableManager, LevelManager levelManager, AssetRegistry assetRegistry) { _saveManager = saveManager; _eventCoordinator = eventCoordinator; _addressableManager = addressableManager; _levelManager = levelManager; _assetRegistry = assetRegistry; } public async UniTask LoadUIAndMainMenuScene() { if (_assetRegistry == null || !_assetRegistry.TryGetReference(AssetKeyIdentifiers.Get(SceneKey.UIScene), out var uiSceneRef)) { Debug.LogError("[GameService] UI Scene reference not found in registry."); return; } _uiSceneHandle = await _addressableManager.LoadSceneAsync(uiSceneRef); if (!_uiSceneHandle.Value.IsValid()) { Debug.LogError("[GameService] Failed to load UI Scene."); return; } // After UI is loaded, we fade to black to prevent pops _eventCoordinator.PublishImmediate(new FadeEvent(false, 0.2f)); await UniTask.Delay(TimeSpan.FromSeconds(0.5f)); await UniTask.NextFrame(); await LoadMainMenu(); } public async UniTask LoadMainMenu() { const float fadeDuration = 1f; _eventCoordinator.PublishImmediate(new FadeEvent(false, fadeDuration)); await UniTask.Delay(TimeSpan.FromSeconds(fadeDuration)); await UnloadGameSceneIfLoaded(); if (_assetRegistry == null || !_assetRegistry.TryGetReference( AssetKeyIdentifiers.Get(SceneKey.MainMenuScene), out var mainMenuSceneRef)) { Debug.LogError("[GameService] Main menu scene reference missing."); return; } _mainMenuSceneHandle = await _addressableManager.LoadSceneAsync(mainMenuSceneRef); if (!_mainMenuSceneHandle.IsValid()) { Debug.LogError("[GameService] Failed to load Main Menu scene."); return; } SceneManager.SetActiveScene(_mainMenuSceneHandle.Result.Scene); IsMainMenuSceneLoaded = true; await UniTask.NextFrame(); _eventCoordinator.PublishImmediate(new FadeEvent(true, fadeDuration)); } public async UniTask StartGame() { await EnterGameplayLoop(); } private async UniTask EnterGameplayLoop() { _eventCoordinator.PublishImmediate(new RequestUIOverrideEvent(false)); _eventCoordinator.PublishImmediate(new FadeEvent(false, 0.35f)); if (_mainMenuSceneHandle.IsValid()) { await _addressableManager.UnloadSceneAsync(_mainMenuSceneHandle); IsMainMenuSceneLoaded = false; } var currentSave = _saveManager.CurrentSave; if (currentSave == null) { Debug.LogError("[GameService] Cannot start game because CurrentSave is null."); await LoadMainMenu(); return; } Debug.Log($"[GameService] Loading scene '{currentSave.CurrentSceneID}'..."); if (!currentSave.OpeningCinematicPlayed) { if (_assetRegistry == null || !_assetRegistry.TryGetReference( AssetKeyIdentifiers.Get(SceneKey.OpeningCinematicScene), out var cinematicScene)) { Debug.LogError("[GameService] Opening cinematic scene reference missing."); await LoadMainMenu(); return; } var loadedSceneHandle = await _addressableManager.LoadSceneAsync(cinematicScene); if (!loadedSceneHandle.IsValid()) { Debug.LogError("[GameService] Failed to load opening cinematic scene."); await LoadMainMenu(); return; } await SwapGameSceneHandle(loadedSceneHandle); } else { if (_assetRegistry == null || !_assetRegistry.TryGetReference(currentSave.CurrentSceneID, out var chapterSceneRef)) { Debug.LogError($"[GameService] Scene reference missing for '{currentSave.CurrentSceneID}'."); await LoadMainMenu(); return; } Debug.Log($"[GameService] Loading chapter scene '{currentSave.CurrentSceneID}'..."); var loadedSceneHandle = await _addressableManager.LoadSceneAsync(chapterSceneRef); if (!loadedSceneHandle.IsValid()) { Debug.LogError($"[GameService] Failed to load chapter scene '{currentSave.CurrentSceneID}'."); await LoadMainMenu(); return; } await SwapGameSceneHandle(loadedSceneHandle); var levelLoaded = await _levelManager.LoadLevel(currentSave.CurrentLevelID); if (!levelLoaded) { Debug.LogError( $"[GameService] Failed to load level '{currentSave.CurrentLevelID}'. Returning to main menu."); await LoadMainMenu(); return; } } _eventCoordinator.PublishImmediate(new FadeEvent(true, 0.35f)); } public async UniTask UnloadGameSceneIfLoaded() { if (_gameSceneHandle.IsValid()) { await _addressableManager.UnloadSceneAsync(_gameSceneHandle); _gameSceneHandle = default; } } public async UniTask SwapGameSceneHandle(AsyncOperationHandle nextSceneHandle) { if (!nextSceneHandle.IsValid()) { Debug.LogError("[GameService] SwapGameSceneHandle called with invalid nextSceneHandle."); return; } if (_gameSceneHandle.IsValid() && _gameSceneHandle.Equals(nextSceneHandle)) { _gameSceneHandle = nextSceneHandle; return; } if (_gameSceneHandle.IsValid()) await _addressableManager.UnloadSceneAsync(_gameSceneHandle); _gameSceneHandle = nextSceneHandle; SceneManager.SetActiveScene(nextSceneHandle.Result.Scene); } public void QuitGame() { #if UNITY_EDITOR EditorApplication.isPlaying = false; #else Application.Quit(); #endif } } }