Bootstrap initialization order figured out and provided events + dispatchers
This commit is contained in:
166
Assets/Scripts/Bootstrap/BootCompletionService.cs
Normal file
166
Assets/Scripts/Bootstrap/BootCompletionService.cs
Normal file
@@ -0,0 +1,166 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace Bootstrap
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A service that provides information about the boot completion status
|
||||||
|
/// and allows systems to register for callbacks when boot is complete.
|
||||||
|
/// </summary>
|
||||||
|
public static class BootCompletionService
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// True if the boot process has fully completed
|
||||||
|
/// </summary>
|
||||||
|
public static bool IsBootComplete { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Timestamp when the boot completed (Time.realtimeSinceStartup)
|
||||||
|
/// </summary>
|
||||||
|
public static float BootCompletionTime { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Event triggered when boot process completes.
|
||||||
|
/// Will be triggered immediately for new subscribers if boot is already complete.
|
||||||
|
/// </summary>
|
||||||
|
public static event Action OnBootComplete;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Actions to be executed in a specific order once boot completes
|
||||||
|
/// </summary>
|
||||||
|
private static readonly List<OrderedInitAction> _orderedInitActions = new List<OrderedInitAction>();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Task completion source for async boot completion waiting
|
||||||
|
/// </summary>
|
||||||
|
private static TaskCompletionSource<bool> _bootCompletionTask;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initialize the service - called by CustomBoot
|
||||||
|
/// </summary>
|
||||||
|
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.AfterSceneLoad)]
|
||||||
|
private static void Initialize()
|
||||||
|
{
|
||||||
|
// Reset state
|
||||||
|
IsBootComplete = false;
|
||||||
|
_bootCompletionTask = new TaskCompletionSource<bool>();
|
||||||
|
|
||||||
|
// Subscribe to CustomBoot completion event
|
||||||
|
CustomBoot.OnBootCompleted += HandleBootCompleted;
|
||||||
|
|
||||||
|
Debug.Log("[BootCompletionService] Initialized and waiting for boot completion");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Handler for when CustomBoot reports completion
|
||||||
|
/// </summary>
|
||||||
|
private static void HandleBootCompleted()
|
||||||
|
{
|
||||||
|
if (IsBootComplete) return; // Avoid duplicate triggers
|
||||||
|
|
||||||
|
IsBootComplete = true;
|
||||||
|
BootCompletionTime = Time.realtimeSinceStartup;
|
||||||
|
|
||||||
|
Debug.Log($"[BootCompletionService] Boot completed at {BootCompletionTime:F2}s since startup");
|
||||||
|
|
||||||
|
// Execute ordered initialization actions
|
||||||
|
ExecuteOrderedInitActions();
|
||||||
|
|
||||||
|
// Complete the task
|
||||||
|
_bootCompletionTask.TrySetResult(true);
|
||||||
|
|
||||||
|
// Trigger the event
|
||||||
|
OnBootComplete?.Invoke();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Execute the registered ordered initialization actions
|
||||||
|
/// </summary>
|
||||||
|
private static void ExecuteOrderedInitActions()
|
||||||
|
{
|
||||||
|
// Sort actions by priority
|
||||||
|
_orderedInitActions.Sort((a, b) => a.Priority.CompareTo(b.Priority));
|
||||||
|
|
||||||
|
foreach (var action in _orderedInitActions)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Debug.Log($"[BootCompletionService] Executing priority {action.Priority} initialization: {action.Name}");
|
||||||
|
action.Action?.Invoke();
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Debug.LogError($"[BootCompletionService] Error executing initialization action '{action.Name}': {e.Message}\n{e.StackTrace}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear the list after execution
|
||||||
|
_orderedInitActions.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Register an action to be executed when boot is complete.
|
||||||
|
/// If boot is already complete, the action will execute immediately.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="action">The action to execute</param>
|
||||||
|
/// <param name="priority">Lower numbers execute first (default: 100)</param>
|
||||||
|
/// <param name="name">Optional name for debugging</param>
|
||||||
|
public static void RegisterInitAction(Action action, int priority = 100, string name = null)
|
||||||
|
{
|
||||||
|
if (action == null) return;
|
||||||
|
|
||||||
|
name = name ?? $"Anonymous_{_orderedInitActions.Count}";
|
||||||
|
|
||||||
|
if (IsBootComplete)
|
||||||
|
{
|
||||||
|
// Boot already completed, execute immediately
|
||||||
|
Debug.Log($"[BootCompletionService] Executing late initialization: {name} (boot already complete)");
|
||||||
|
try
|
||||||
|
{
|
||||||
|
action.Invoke();
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Debug.LogError($"[BootCompletionService] Error executing late initialization action '{name}': {e.Message}\n{e.StackTrace}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Add to ordered list
|
||||||
|
_orderedInitActions.Add(new OrderedInitAction
|
||||||
|
{
|
||||||
|
Action = action,
|
||||||
|
Priority = priority,
|
||||||
|
Name = name
|
||||||
|
});
|
||||||
|
Debug.Log($"[BootCompletionService] Registered initialization action: {name} with priority {priority}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns a task that completes when the boot process is complete.
|
||||||
|
/// If boot is already complete, returns a completed task.
|
||||||
|
/// </summary>
|
||||||
|
public static Task WaitForBootCompletionAsync()
|
||||||
|
{
|
||||||
|
if (IsBootComplete)
|
||||||
|
{
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
return _bootCompletionTask.Task;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Structure for ordered initialization actions
|
||||||
|
/// </summary>
|
||||||
|
private class OrderedInitAction
|
||||||
|
{
|
||||||
|
public Action Action;
|
||||||
|
public int Priority;
|
||||||
|
public string Name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
3
Assets/Scripts/Bootstrap/BootCompletionService.cs.meta
Normal file
3
Assets/Scripts/Bootstrap/BootCompletionService.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: aa0228cf33a64515bc166b7a9bc8c0b9
|
||||||
|
timeCreated: 1760606319
|
||||||
@@ -94,6 +94,19 @@ namespace Bootstrap
|
|||||||
CurrentProgress = 1f;
|
CurrentProgress = 1f;
|
||||||
OnBootProgressChanged?.Invoke(1f);
|
OnBootProgressChanged?.Invoke(1f);
|
||||||
OnBootCompleted?.Invoke();
|
OnBootCompleted?.Invoke();
|
||||||
|
|
||||||
|
// Notify the BootCompletionService that boot is complete
|
||||||
|
if (Application.isPlaying)
|
||||||
|
{
|
||||||
|
// We use reflection to avoid direct reference in case the service is disabled/removed
|
||||||
|
var type = System.Type.GetType("Bootstrap.BootCompletionService, Assembly-CSharp");
|
||||||
|
if (type != null)
|
||||||
|
{
|
||||||
|
var method = type.GetMethod("HandleBootCompleted",
|
||||||
|
System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static);
|
||||||
|
method?.Invoke(null, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -106,6 +119,19 @@ namespace Bootstrap
|
|||||||
CurrentProgress = 1f;
|
CurrentProgress = 1f;
|
||||||
OnBootProgressChanged?.Invoke(1f);
|
OnBootProgressChanged?.Invoke(1f);
|
||||||
OnBootCompleted?.Invoke();
|
OnBootCompleted?.Invoke();
|
||||||
|
|
||||||
|
// Notify the BootCompletionService that boot is complete
|
||||||
|
if (Application.isPlaying)
|
||||||
|
{
|
||||||
|
// We use reflection to avoid direct reference in case the service is disabled/removed
|
||||||
|
var type = System.Type.GetType("Bootstrap.BootCompletionService, Assembly-CSharp");
|
||||||
|
if (type != null)
|
||||||
|
{
|
||||||
|
var method = type.GetMethod("HandleBootCompleted",
|
||||||
|
System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static);
|
||||||
|
method?.Invoke(null, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -149,7 +149,7 @@ namespace Input
|
|||||||
{
|
{
|
||||||
_isQuitting = true;
|
_isQuitting = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Sets the default ITouchInputConsumer to receive input events.
|
/// Sets the default ITouchInputConsumer to receive input events.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
Reference in New Issue
Block a user