Revamp the prompt system, the bootstrapper system, the starting cinematic
This commit is contained in:
269
Assets/Scripts/Bootstrap/BootSceneController.cs
Normal file
269
Assets/Scripts/Bootstrap/BootSceneController.cs
Normal file
@@ -0,0 +1,269 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
using UI;
|
||||
using Core;
|
||||
using UnityEngine.SceneManagement;
|
||||
using Cinematics;
|
||||
|
||||
namespace Bootstrap
|
||||
{
|
||||
/// <summary>
|
||||
/// Controller for the boot scene that coordinates bootstrap initialization with loading screen
|
||||
/// </summary>
|
||||
public class BootSceneController : MonoBehaviour
|
||||
{
|
||||
[SerializeField] private string mainMenuSceneName = "MainMenu";
|
||||
[SerializeField] private float minDelayAfterBoot = 0.5f; // Small delay after boot to ensure smooth transition
|
||||
[SerializeField] private bool debugMode = false;
|
||||
[SerializeField] private InitialLoadingScreen initialLoadingScreen; // Reference to our specialized loading screen
|
||||
|
||||
// Progress distribution between bootstrap and scene loading
|
||||
[SerializeField, Range(0.1f, 0.9f)] private float bootProgressWeight = 0.5f; // Default 50/50 split
|
||||
|
||||
private enum LoadingPhase { Bootstrap, SceneLoading }
|
||||
private LoadingPhase _currentPhase = LoadingPhase.Bootstrap;
|
||||
|
||||
private bool _bootComplete = false;
|
||||
private bool _hasStartedLoading = false;
|
||||
private float _sceneLoadingProgress = 0f;
|
||||
|
||||
private void Start()
|
||||
{
|
||||
Debug.Log("[BootSceneController] Boot scene started");
|
||||
|
||||
// Ensure the initial loading screen exists
|
||||
if (initialLoadingScreen == null)
|
||||
{
|
||||
Debug.LogError("[BootSceneController] No InitialLoadingScreen assigned! Please assign it in the inspector.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Subscribe to the loading screen completion event
|
||||
initialLoadingScreen.OnLoadingScreenFullyHidden += OnInitialLoadingComplete;
|
||||
|
||||
// Show the loading screen immediately with our combined progress provider
|
||||
initialLoadingScreen.ShowLoadingScreen(GetCombinedProgress);
|
||||
|
||||
// Subscribe to boot progress events
|
||||
CustomBoot.OnBootProgressChanged += OnBootProgressChanged;
|
||||
|
||||
// Register our boot completion handler with the BootCompletionService
|
||||
// This will execute either immediately if boot is already complete,
|
||||
// or when the boot process completes
|
||||
BootCompletionService.RegisterInitAction(
|
||||
OnBootCompleted,
|
||||
50, // Higher priority (lower number)
|
||||
"BootSceneController.OnBootCompleted"
|
||||
);
|
||||
|
||||
// In debug mode, log additional information
|
||||
if (debugMode)
|
||||
{
|
||||
InvokeRepeating(nameof(LogDebugInfo), 0.1f, 0.5f);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called when the initial loading screen is fully hidden
|
||||
/// </summary>
|
||||
private void OnInitialLoadingComplete()
|
||||
{
|
||||
Debug.Log("[BootSceneController] Initial loading screen fully hidden, boot sequence completed");
|
||||
|
||||
// Play the intro cinematic if available
|
||||
if (CinematicsManager.Instance != null)
|
||||
{
|
||||
Debug.Log("[BootSceneController] Attempting to play intro cinematic");
|
||||
|
||||
// Use LoadAndPlayCinematic to play the intro sequence
|
||||
CinematicsManager.Instance.LoadAndPlayCinematic("IntroSequence");
|
||||
|
||||
// Immediately unload the StartingScene - no need to wait for cinematic to finish
|
||||
// since CinematicsManager is bootstrapped and won't be unloaded
|
||||
UnloadStartingScene();
|
||||
}
|
||||
else
|
||||
{
|
||||
// If no cinematics manager, unload the StartingScene directly
|
||||
UnloadStartingScene();
|
||||
}
|
||||
}
|
||||
|
||||
private void OnDestroy()
|
||||
{
|
||||
// Clean up event subscriptions
|
||||
CustomBoot.OnBootCompleted -= OnBootCompleted;
|
||||
CustomBoot.OnBootProgressChanged -= OnBootProgressChanged;
|
||||
|
||||
if (initialLoadingScreen != null)
|
||||
{
|
||||
initialLoadingScreen.OnLoadingScreenFullyHidden -= OnInitialLoadingComplete;
|
||||
}
|
||||
|
||||
if (debugMode)
|
||||
{
|
||||
CancelInvoke(nameof(LogDebugInfo));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Progress provider that combines bootstrap and scene loading progress
|
||||
/// </summary>
|
||||
private float GetCombinedProgress()
|
||||
{
|
||||
switch (_currentPhase)
|
||||
{
|
||||
case LoadingPhase.Bootstrap:
|
||||
// Scale bootstrap progress from 0 to bootProgressWeight
|
||||
return CustomBoot.CurrentProgress * bootProgressWeight;
|
||||
|
||||
case LoadingPhase.SceneLoading:
|
||||
// Scale scene loading progress from bootProgressWeight to 1.0
|
||||
return bootProgressWeight + (_sceneLoadingProgress * (1f - bootProgressWeight));
|
||||
|
||||
default:
|
||||
return 0f;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnBootProgressChanged(float progress)
|
||||
{
|
||||
if (debugMode)
|
||||
{
|
||||
Debug.Log($"[BootSceneController] Bootstrap progress: {progress:P0}, Combined: {GetCombinedProgress():P0}");
|
||||
}
|
||||
}
|
||||
|
||||
private void LogDebugInfo()
|
||||
{
|
||||
Debug.Log($"[BootSceneController] Debug - Phase: {_currentPhase}, Bootstrap: {CustomBoot.CurrentProgress:P0}, " +
|
||||
$"Scene: {_sceneLoadingProgress:P0}, Combined: {GetCombinedProgress():P0}, Boot Complete: {_bootComplete}");
|
||||
}
|
||||
|
||||
private void OnBootCompleted()
|
||||
{
|
||||
// Unsubscribe to prevent duplicate calls
|
||||
CustomBoot.OnBootCompleted -= OnBootCompleted;
|
||||
|
||||
Debug.Log("[BootSceneController] Boot process completed");
|
||||
_bootComplete = true;
|
||||
|
||||
// After a small delay, start loading the main menu
|
||||
// This prevents jerky transitions if boot happens very quickly
|
||||
Invoke(nameof(StartLoadingMainMenu), minDelayAfterBoot);
|
||||
}
|
||||
|
||||
private void StartLoadingMainMenu()
|
||||
{
|
||||
if (_hasStartedLoading)
|
||||
return;
|
||||
|
||||
_hasStartedLoading = true;
|
||||
_currentPhase = LoadingPhase.SceneLoading;
|
||||
LoadMainMenu();
|
||||
}
|
||||
|
||||
private async void LoadMainMenu()
|
||||
{
|
||||
Debug.Log($"[BootSceneController] Loading main menu scene: {mainMenuSceneName}");
|
||||
|
||||
try
|
||||
{
|
||||
// Initialize scene loading progress to 0 to ensure proper remapping
|
||||
_sceneLoadingProgress = 0f;
|
||||
|
||||
// Create a custom progress reporter using a custom class
|
||||
var progressHandler = new ProgressHandler(value => {
|
||||
// Store the raw scene loading progress (0-1)
|
||||
_sceneLoadingProgress = value;
|
||||
|
||||
if (debugMode)
|
||||
{
|
||||
Debug.Log($"[BootSceneController] Scene loading raw: {value:P0}, Combined: {GetCombinedProgress():P0}");
|
||||
}
|
||||
});
|
||||
|
||||
// Step 1: Additively load the main menu scene - don't unload StartingScene yet
|
||||
var op = SceneManager.LoadSceneAsync(mainMenuSceneName, LoadSceneMode.Additive);
|
||||
|
||||
// Disable scene activation until we're ready to show it
|
||||
op.allowSceneActivation = true;
|
||||
|
||||
// Track progress while loading
|
||||
while (!op.isDone)
|
||||
{
|
||||
progressHandler.ReportProgress(op.progress);
|
||||
await System.Threading.Tasks.Task.Yield();
|
||||
}
|
||||
|
||||
// Update the current gameplay scene in SceneManagerService
|
||||
SceneManagerService.Instance.CurrentGameplayScene = mainMenuSceneName;
|
||||
|
||||
// Ensure progress is complete
|
||||
_sceneLoadingProgress = 1f;
|
||||
|
||||
// Step 2: Scene is fully loaded, now hide the loading screen
|
||||
// This will trigger OnInitialLoadingComplete via the event when animation completes
|
||||
initialLoadingScreen.HideLoadingScreen();
|
||||
|
||||
// Step 3: The OnInitialLoadingComplete method will handle playing the intro cinematic
|
||||
// Step 4: StartingScene will be unloaded after the cinematic completes in OnIntroCinematicFinished
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogError($"[BootSceneController] Error loading main menu: {e.Message}");
|
||||
// Still try to hide the loading screen even if there was an error
|
||||
initialLoadingScreen.HideLoadingScreen();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unloads the StartingScene, completing the transition to the main menu
|
||||
/// </summary>
|
||||
private async void UnloadStartingScene()
|
||||
{
|
||||
try
|
||||
{
|
||||
// Get the current scene (StartingScene)
|
||||
Scene currentScene = SceneManager.GetActiveScene();
|
||||
string startingSceneName = currentScene.name;
|
||||
|
||||
Debug.Log($"[BootSceneController] Unloading StartingScene: {startingSceneName}");
|
||||
|
||||
// Unload the StartingScene
|
||||
await SceneManager.UnloadSceneAsync(startingSceneName);
|
||||
|
||||
// Set the main menu scene as the active scene
|
||||
Scene mainMenuScene = SceneManager.GetSceneByName(mainMenuSceneName);
|
||||
SceneManager.SetActiveScene(mainMenuScene);
|
||||
|
||||
Debug.Log($"[BootSceneController] Transition complete: {startingSceneName} unloaded, {mainMenuSceneName} is now active");
|
||||
|
||||
// Destroy the boot scene controller since its job is done
|
||||
Destroy(gameObject);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logging.Warning($"[BootSceneController] Error unloading StartingScene: {e.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper class to handle progress reporting without running into explicit interface implementation issues
|
||||
/// </summary>
|
||||
private class ProgressHandler
|
||||
{
|
||||
private Action<float> _progressAction;
|
||||
|
||||
public ProgressHandler(Action<float> progressAction)
|
||||
{
|
||||
_progressAction = progressAction;
|
||||
}
|
||||
|
||||
public void ReportProgress(float value)
|
||||
{
|
||||
_progressAction?.Invoke(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user