Files
RebootKit/Runtime/Engine/Code/Services/Simulation/WorldService.cs
2025-05-14 10:52:53 +02:00

110 lines
3.7 KiB
C#

using System.Collections.Generic;
using System.Linq;
using System.Threading;
using Cysharp.Threading.Tasks;
using RebootKit.Engine.Foundation;
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.ResourceManagement.AsyncOperations;
using UnityEngine.ResourceManagement.ResourceProviders;
using UnityEngine.SceneManagement;
using Logger = RebootKit.Engine.Foundation.Logger;
namespace RebootKit.Engine.Services.Simulation {
public class WorldService : IService {
static readonly Logger s_logger = new(nameof(WorldService));
enum WorldState {
Unloaded,
Loading,
Loaded
}
WorldState m_WorldState = WorldState.Unloaded;
WorldConfig m_Config;
AsyncOperationHandle<SceneInstance> m_SceneInstance;
readonly List<Actor> m_Actors = new();
public void Dispose() {
Unload();
}
public async UniTask LoadAsync(WorldConfig worldConfig, CancellationToken cancellationToken) {
await UniTask.WaitWhile(() => m_WorldState == WorldState.Loading, cancellationToken: cancellationToken);
Unload();
m_WorldState = WorldState.Loading;
m_Config = worldConfig;
m_SceneInstance = worldConfig.mainScene.LoadSceneAsync(LoadSceneMode.Additive, false);
await m_SceneInstance.ToUniTask(cancellationToken: cancellationToken);
await m_SceneInstance.Result.ActivateAsync();
SceneManager.SetActiveScene(m_SceneInstance.Result.Scene);
foreach (GameObject root in m_SceneInstance.Result.Scene.GetRootGameObjects()) {
foreach (Actor actor in root.GetComponentsInChildren<Actor>()) {
RegisterActor(actor);
}
}
m_WorldState = WorldState.Loaded;
}
public async UniTask<TRequiredActor> LoadAsync<TRequiredActor>(WorldConfig worldConfig, CancellationToken cancellationToken) where TRequiredActor : Actor {
await LoadAsync(worldConfig, cancellationToken);
TRequiredActor actor = m_Actors.FirstOrDefault(t => t is TRequiredActor) as TRequiredActor;
if (actor is null) {
s_logger.Error($"Actor of type {typeof(TRequiredActor)} not found in the scene");
return null;
}
return actor;
}
public void Unload() {
KillAllActors();
if (m_SceneInstance.IsValid()) {
m_SceneInstance.Release();
m_SceneInstance = default;
}
m_WorldState = WorldState.Unloaded;
}
public async UniTask<TActor> SpawnActor<TActor>(AssetReferenceT<GameObject> asset, CancellationToken cancellationToken) where TActor : Actor {
GameObject gameObject = await Addressables.InstantiateAsync(asset);
if (cancellationToken.IsCancellationRequested) {
asset.ReleaseInstance(gameObject);
return null;
}
if (gameObject.TryGetComponent(out TActor actor)) {
return actor;
}
asset.ReleaseInstance(gameObject);
return null;
}
public void RegisterActor(Actor actor) {
m_Actors.Add(actor);
}
public void KillActor(Actor actor) {
Addressables.ReleaseInstance(actor.gameObject);
}
public void KillAllActors() {
foreach (Actor actor in m_Actors) {
Addressables.ReleaseInstance(actor.gameObject);
}
m_Actors.Clear();
}
}
}