Files

226 lines
8.1 KiB
C#

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<SceneInstance> _gameSceneHandle;
private AsyncOperationHandle<SceneInstance> _mainMenuSceneHandle;
private AsyncOperationHandle<SceneInstance>? _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<SceneInstance> 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
}
}
}