Platform should be initialized in the Boot, before everything else. Got rid of the coroutines

This commit is contained in:
Sebastian Bularca
2026-06-18 23:53:51 +02:00
parent 5517fc17a2
commit 7cb7089d2f
9 changed files with 71 additions and 79 deletions

View File

@@ -56,7 +56,7 @@ MonoBehaviour:
m_SerializedLabels: [] m_SerializedLabels: []
FlaggedDuringContentUpdateRestriction: 0 FlaggedDuringContentUpdateRestriction: 0
- m_GUID: b487ee33dc82a43d48013b2331278664 - m_GUID: b487ee33dc82a43d48013b2331278664
m_Address: Assets/Database/Core/InitializerSettingsFile.asset m_Address: InitializerSettingsFile
m_ReadOnly: 0 m_ReadOnly: 0
m_SerializedLabels: [] m_SerializedLabels: []
FlaggedDuringContentUpdateRestriction: 0 FlaggedDuringContentUpdateRestriction: 0

View File

@@ -1,13 +1,15 @@
using Nox.EditorCode; using Nox.EditorCode;
using System; using System;
using Unity.VectorGraphics; using System.Threading.Tasks;
using UnityEditor; using Nox.Input;
using Nox.Platform;
using UnityEngine; using UnityEngine;
using UnityEngine.AddressableAssets; using UnityEngine.AddressableAssets;
using UnityEngine.SceneManagement; using UnityEngine.SceneManagement;
namespace Nox.Core { namespace Nox.Core {
public class Boot { public class Boot {
private static readonly AssetReferenceT<InitializerSettingsFile> InitializerSettingsFile = new ("InitializerSettingsFile");
/// <summary> /// <summary>
/// The is the first method called when the game starts. It will load the Initializer prefab which will initialize the project /// The is the first method called when the game starts. It will load the Initializer prefab which will initialize the project
/// </summary> /// </summary>
@@ -18,7 +20,7 @@ namespace Nox.Core {
case BootType.UnityDefault: case BootType.UnityDefault:
return; return;
case BootType.SceneBoot: case BootType.SceneBoot:
Addressables.InstantiateAsync("Initializer").WaitForCompletion(); InitializeEntrypoint();
break; break;
case BootType.FullBoot: case BootType.FullBoot:
var loadOperation = SceneManager.LoadSceneAsync("Startup", LoadSceneMode.Single); var loadOperation = SceneManager.LoadSceneAsync("Startup", LoadSceneMode.Single);
@@ -30,13 +32,44 @@ namespace Nox.Core {
throw new ArgumentOutOfRangeException(); throw new ArgumentOutOfRangeException();
} }
#else #else
Addressables.InstantiateAsync("Initializer").WaitForCompletion(); InitializeEntrypoint();
#endif #endif
} }
private static void OnCompleted(AsyncOperation obj) { private static void OnCompleted(AsyncOperation obj) {
obj.allowSceneActivation = true; obj.allowSceneActivation = true;
Addressables.InstantiateAsync("Initializer").WaitForCompletion(); InitializeEntrypoint();
}
private static void InitializeEntrypoint() {
var entryPoint = Addressables.InstantiateAsync("Initializer").WaitForCompletion().GetComponent<EntryPoint>();
_ = CreatePlatformFactory(entryPoint);
}
private static async Task CreatePlatformFactory(EntryPoint entryPoint) {
var gameDataState = new GameDataState {
platformSelector = new PlatformSelector(PlatformSelector.GetDevicePlatform(), PlatformSelector.GetPlatformDefaultInputMode()),
};
var initSettingsHandle = Addressables.LoadAssetAsync<InitializerSettingsFile>(InitializerSettingsFile);
await initSettingsHandle.Task;
var initializerSettings = initSettingsHandle.Result;
var devicePlatform = gameDataState.platformSelector.devicePlatform;
IPlatform platform = devicePlatform switch {
DevicePlatform.Desktop => new DesktopPlatform(initializerSettings.desktopPlatformSettings),
DevicePlatform.UnityEditor => new UnityEditorPlatform(initializerSettings.unityEditorPlatformSettings),
_ => null
};
if(!Equals(gameDataState.platformSelector.devicePlatform, DevicePlatform.Desktop) &&
PlatformSelector.GetPlatformDefaultInputMode() == InputMode.Desktop) {
platform = new DesktopPlatform(initializerSettings.desktopPlatformSettings);
}
await platform?.Initialize(gameDataState)!;
_ = entryPoint.StartGame(gameDataState,initializerSettings, platform);
} }
} }
} }

View File

@@ -1,96 +1,58 @@
using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading.Tasks;
using Nox.Game; using Nox.Game;
using Nox.Game.UI; using Nox.Game.UI;
using Nox.Input;
using Nox.Platform; using Nox.Platform;
using Jovian.SaveSystem; using Jovian.SaveSystem;
using Jovian.InGameLogging; using Jovian.InGameLogging;
using Nox.EditorCode;
using Unity.Profiling; using Unity.Profiling;
using UnityEngine; using UnityEngine;
using UnityEngine.AddressableAssets; using UnityEngine.AddressableAssets;
using UnityEngine.ResourceManagement.AsyncOperations;
namespace Nox.Core { namespace Nox.Core {
/// <summary> /// <summary>
/// The main boot class which is initializing the project, loads the platforms settings, initializes the platforms and creates the game states /// The main boot class which is initializing the project, loads the platforms settings, initializes the platforms and creates the game states
/// </summary> /// </summary>
public class EntryPoint : MonoBehaviour { public class EntryPoint : MonoBehaviour {
public AssetReferenceT<InitializerSettingsFile> initializerSettingsFile;
private IPlatform platform;
private GameDataState gameDataState;
private Dictionary<GameState, IGameState> applicationStates; private Dictionary<GameState, IGameState> applicationStates;
private ProfilerMarker createApplicationStateMarker = new ProfilerMarker("createApplicationState");
private ISceneTransition sceneTransition; private ISceneTransition sceneTransition;
private ISaveSystem saveSystem; private ISaveSystem saveSystem;
private IGameLogStore gameLogStore; private IGameLogStore gameLogStore;
private InitializerSettingsFile initializerSettings;
private BootstrapReferences bootstrapReferences; private BootstrapReferences bootstrapReferences;
private MenuGameStateData menuGameStateData; private MenuGameStateData menuGameStateData;
public IEnumerator Start() { public async Task StartGame(GameDataState gameDataState, InitializerSettingsFile initializerSettings, IPlatform selectedPlatform) {
DontDestroyOnLoad(this); DontDestroyOnLoad(this);
// scene authoring is helping with making each scene stand-alone playable // scene authoring is helping with making each scene stand-alone playable
var activeSceneReference = FindFirstObjectByType<SceneReference>(); var activeSceneReference = FindFirstObjectByType<SceneReference>();
if(activeSceneReference == null) { if(!activeSceneReference) {
Debug.LogWarning("The scene has no SceneReference script. Will start by default in Splash Application State"); Debug.LogWarning("The scene has no SceneReference script. Will start by default in Splash Application State");
var sceneRef = new GameObject { var sceneRef = new GameObject {
name = "Scene Reference" name = "Scene Reference"
}; };
activeSceneReference = sceneRef.AddComponent<SceneReference>(); activeSceneReference = sceneRef.AddComponent<SceneReference>();
activeSceneReference.gameState = GameState.BootState; activeSceneReference.gameState = GameState.BootState;
yield return null; await Task.Yield();
} }
// Initialize platform
gameDataState = new GameDataState {
platformSelector = new PlatformSelector(PlatformSelector.GetDevicePlatform(), PlatformSelector.GetPlatformDefaultInputMode()),
};
gameDataState.ChangeGameState(activeSceneReference.gameState); gameDataState.ChangeGameState(activeSceneReference.gameState);
// Load Initialization Settings
var initSettingsHandle = Addressables.LoadAssetAsync<InitializerSettingsFile>(initializerSettingsFile);
yield return new WaitUntil(() => initSettingsHandle.IsDone);
initializerSettings = initSettingsHandle.Result;
yield return CreatePlatformFactory();
var bootStrapsSettingsHandle = Addressables.LoadAssetAsync<BootstrapReferences>(initializerSettings.bootstrapSettings); var bootStrapsSettingsHandle = Addressables.LoadAssetAsync<BootstrapReferences>(initializerSettings.bootstrapSettings);
yield return new WaitUntil(() => bootStrapsSettingsHandle.IsDone); await bootStrapsSettingsHandle.Task;
bootstrapReferences = bootStrapsSettingsHandle.Result; bootstrapReferences = bootStrapsSettingsHandle.Result;
menuGameStateData = new MenuGameStateData(); menuGameStateData = new MenuGameStateData();
var fadeObject = new GameObject("ScreenFadeTransition"); var fadeObject = new GameObject("ScreenFadeTransition");
sceneTransition = fadeObject.AddComponent<ScreenFadeTransition>(); sceneTransition = fadeObject.AddComponent<ScreenFadeTransition>();
CreateApplicationStates(); CreateApplicationStates(gameDataState, selectedPlatform);
var gameStateRunner = gameObject.AddComponent<GameStateRunner>(); var gameStateRunner = gameObject.AddComponent<GameStateRunner>();
gameStateRunner.Initialize(applicationStates, gameDataState, platform, sceneTransition); gameStateRunner.Initialize(applicationStates, gameDataState, selectedPlatform, sceneTransition);
} }
private IEnumerator CreatePlatformFactory() { private void CreateApplicationStates(GameDataState gameDataState, IPlatform selectedPlatform) {
platform = null;
var devicePlatform = gameDataState.platformSelector.devicePlatform;
platform = devicePlatform switch {
DevicePlatform.Desktop => new DesktopPlatform(initializerSettings.desktopPlatformSettings),
DevicePlatform.UnityEditor => new UnityEditorPlatform(initializerSettings.unityEditorPlatformSettings),
_ => platform
};
if(!Equals(gameDataState.platformSelector.devicePlatform, DevicePlatform.Desktop) &&
PlatformSelector.GetPlatformDefaultInputMode() == InputMode.Desktop) {
platform = new DesktopPlatform(initializerSettings.desktopPlatformSettings);
}
yield return platform?.Initialize(gameDataState);
}
private void CreateApplicationStates() {
createApplicationStateMarker.Begin();
// Save System // Save System
var saveSettings = SaveSystemSettings.Load(); var saveSettings = SaveSystemSettings.Load();
ISaveSerializer saveSerializer = saveSettings.saveFormat == SaveFormat.Json ISaveSerializer saveSerializer = saveSettings.saveFormat == SaveFormat.Json
@@ -104,12 +66,10 @@ namespace Nox.Core {
var adventureData = new AdventureData(); var adventureData = new AdventureData();
applicationStates = new Dictionary<GameState, IGameState> { applicationStates = new Dictionary<GameState, IGameState>();
[GameState.BootState] = new SplashGameState(bootstrapReferences, gameDataState), applicationStates.TryAdd(GameState.BootState, new SplashGameState(bootstrapReferences, gameDataState));
[GameState.MainMenu] = new MainMenuGameState(gameDataState, menuGameStateData, bootstrapReferences, saveSystem, adventureData, gameLogStore), applicationStates.TryAdd(GameState.MainMenu, new MainMenuGameState(gameDataState, menuGameStateData, bootstrapReferences, saveSystem, adventureData, gameLogStore));
[GameState.GameMode] = new GameModeGameState(gameDataState, bootstrapReferences, platform.PlatformSettings, saveSystem, sceneTransition, adventureData, gameLogStore), applicationStates.TryAdd(GameState.GameMode, new GameModeGameState(gameDataState, bootstrapReferences, selectedPlatform.PlatformSettings, saveSystem, sceneTransition, adventureData, gameLogStore));
};
createApplicationStateMarker.End();
} }
} }
} }

View File

@@ -17,8 +17,8 @@ namespace Nox.Core {
/// </summary> /// </summary>
public class GameModeGameState : IGameState { public class GameModeGameState : IGameState {
private readonly GameDataState gameDataState; private readonly GameDataState gameDataState;
private readonly BootstrapReferences bootstrapReferences;
private readonly PlatformSettings platformSettings; private readonly PlatformSettings platformSettings;
private readonly PlayModeSettings bootstrapSettings;
private readonly ISaveSystem saveSystem; private readonly ISaveSystem saveSystem;
private readonly ISceneTransition sceneTransition; private readonly ISceneTransition sceneTransition;
private readonly AdventureData adventureData; private readonly AdventureData adventureData;
@@ -35,10 +35,9 @@ namespace Nox.Core {
private bool stateEntered; private bool stateEntered;
private AsyncOperationHandle<AdventureSettings> advSettingsHandler; private AsyncOperationHandle<AdventureSettings> advSettingsHandler;
private AdventureSettings? adventureSettings; private AdventureSettings? adventureSettings;
private PlayModeSettings? playModeSettings;
public bool IsGameStateInitialized { public bool IsGameStateInitialized => stateEntered && (playMode == null || playMode.IsGameModeInitialized);
get => stateEntered && (playMode == null || playMode.IsGameModeInitialized);
}
public GameModeGameState(GameDataState gameDataState, public GameModeGameState(GameDataState gameDataState,
BootstrapReferences bootstrapReferences, BootstrapReferences bootstrapReferences,
@@ -48,19 +47,19 @@ namespace Nox.Core {
AdventureData adventureData, AdventureData adventureData,
IGameLogStore gameLogStore) { IGameLogStore gameLogStore) {
this.gameDataState = gameDataState; this.gameDataState = gameDataState;
this.bootstrapReferences = bootstrapReferences;
this.platformSettings = platformSettings; this.platformSettings = platformSettings;
this.saveSystem = saveSystem; this.saveSystem = saveSystem;
this.sceneTransition = sceneTransition; this.sceneTransition = sceneTransition;
this.adventureData = adventureData; this.adventureData = adventureData;
this.gameLogStore = gameLogStore; this.gameLogStore = gameLogStore;
bootstrapSettings = Addressables.LoadAssetAsync<PlayModeSettings>(bootstrapReferences.playModeSettings).WaitForCompletion();
} }
public void EnterGameState() { public void EnterGameState() {
playModeSettings ??= Addressables.LoadAssetAsync<PlayModeSettings>(bootstrapReferences.playModeSettings).WaitForCompletion();
if(gameDataState.ActivePlayMode == PlayMode.None) { if(gameDataState.ActivePlayMode == PlayMode.None) {
var sceneReference = Object.FindFirstObjectByType<SceneReference>(); var sceneReference = Object.FindFirstObjectByType<SceneReference>();
if(bootstrapSettings.gameModeData.AsValueEnumerable().Any(g => g.playMode == sceneReference.playMode)) { if(playModeSettings.gameModeData.AsValueEnumerable().Any(g => g.playMode == sceneReference.playMode)) {
gameDataState.ChangePlayMode(sceneReference.playMode); gameDataState.ChangePlayMode(sceneReference.playMode);
} }
} }
@@ -108,7 +107,7 @@ namespace Nox.Core {
} }
playMode = gameDataState.ActivePlayMode switch { playMode = gameDataState.ActivePlayMode switch {
PlayMode.Adventure => new AdventurePlayMode(platformSettings, activeParty, bootstrapSettings, gameDataState, saveSystem, adventureSettings, adventureData), PlayMode.Adventure => new AdventurePlayMode(platformSettings, activeParty, playModeSettings, gameDataState, saveSystem, adventureSettings, adventureData),
PlayMode.PauseMenu => new PauseMenuPlayMode(platformSettings, gameDataState, pauseMenuView!), PlayMode.PauseMenu => new PauseMenuPlayMode(platformSettings, gameDataState, pauseMenuView!),
PlayMode.Town => new TownPlayMode(platformSettings, activeParty), PlayMode.Town => new TownPlayMode(platformSettings, activeParty),
PlayMode.Rest => new RestPlayMode(platformSettings, activeParty), PlayMode.Rest => new RestPlayMode(platformSettings, activeParty),

View File

@@ -95,10 +95,7 @@ namespace Nox.Core {
} }
private void ChangeApplicationState(GameState newGameState) { private void ChangeApplicationState(GameState newGameState) {
if(currentState != null) { currentState?.ExitGameState();
currentState.ExitGameState();
}
currentState = applicationStates[newGameState]; currentState = applicationStates[newGameState];
currentState.EnterGameState(); currentState.EnterGameState();
currentStateType = newGameState; currentStateType = newGameState;

View File

@@ -19,7 +19,8 @@ namespace Nox.Core {
} }
public void EnterGameState() { public void EnterGameState() {
DisclaimerReference gdprReference = Addressables.InstantiateAsync(bootStrapInitializer.splashUIReference).WaitForCompletion().GetComponent<DisclaimerReference>(); DisclaimerReference gdprReference = Addressables.InstantiateAsync(bootStrapInitializer.splashUIReference)
.WaitForCompletion().GetComponent<DisclaimerReference>();
gdprReference.continueButton.onClick.AddListener(() => { gdprReference.continueButton.onClick.AddListener(() => {
gameDataState.ChangeGameState(GameState.MainMenu); gameDataState.ChangeGameState(GameState.MainMenu);
Object.Destroy(gdprReference.gameObject); Object.Destroy(gdprReference.gameObject);

View File

@@ -1,5 +1,6 @@
using Nox.Input; using Nox.Input;
using System.Collections; using System.Collections;
using System.Threading.Tasks;
using UnityEngine; using UnityEngine;
using UnityEngine.AddressableAssets; using UnityEngine.AddressableAssets;
@@ -14,9 +15,9 @@ namespace Nox.Platform {
} }
public PlatformSettings PlatformSettings => desktopPlatformSettings; public PlatformSettings PlatformSettings => desktopPlatformSettings;
public IEnumerator Initialize(object applicationData) { public async Task Initialize(object applicationData) {
var handle = Addressables.LoadAssetAsync<DesktopPlatformSettings>(assetReference); var handle = Addressables.LoadAssetAsync<DesktopPlatformSettings>(assetReference);
yield return new WaitUntil(() => handle.IsDone); await handle.Task;
desktopPlatformSettings = handle.Result; desktopPlatformSettings = handle.Result;
Debug.Log($"Device Platform {desktopPlatformSettings.devicePlatform} initialized"); Debug.Log($"Device Platform {desktopPlatformSettings.devicePlatform} initialized");
InitializeInput(); InitializeInput();

View File

@@ -1,5 +1,6 @@
using Nox.Input; using Nox.Input;
using System.Collections; using System.Collections;
using System.Threading.Tasks;
namespace Nox.Platform { namespace Nox.Platform {
@@ -16,7 +17,7 @@ namespace Nox.Platform {
/// </summary> /// </summary>
public interface IPlatform { public interface IPlatform {
PlatformSettings PlatformSettings { get; } PlatformSettings PlatformSettings { get; }
IEnumerator Initialize(object applicationData); Task Initialize(object applicationData);
IInput InitializeInput(); IInput InitializeInput();
void Tick(); void Tick();
void Dispose(); void Dispose();

View File

@@ -1,5 +1,5 @@
using Nox.Input; using Nox.Input;
using System.Collections; using System.Threading.Tasks;
using UnityEngine; using UnityEngine;
using UnityEngine.AddressableAssets; using UnityEngine.AddressableAssets;
@@ -12,9 +12,9 @@ namespace Nox.Platform {
this.assetReference = assetReference; this.assetReference = assetReference;
} }
public PlatformSettings PlatformSettings => editorPlatformSettings; public PlatformSettings PlatformSettings => editorPlatformSettings;
public IEnumerator Initialize(object applicationData) { public async Task Initialize(object applicationData) {
var handle = Addressables.LoadAssetAsync<UnityEditorPlatformSettings>(assetReference); var handle = Addressables.LoadAssetAsync<UnityEditorPlatformSettings>(assetReference);
yield return new WaitUntil(() => handle.IsDone); await handle.Task;
editorPlatformSettings = handle.Result; editorPlatformSettings = handle.Result;
Debug.Log($"Device Platform {editorPlatformSettings.devicePlatform} initialized"); Debug.Log($"Device Platform {editorPlatformSettings.devicePlatform} initialized");
InitializeInput(); InitializeInput();