110 lines
3.7 KiB
C#
Executable File
110 lines
3.7 KiB
C#
Executable File
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();
|
|
}
|
|
}
|
|
} |