using System.Collections.Generic; using System.Threading; using Cysharp.Threading.Tasks; using RebootKit.Engine.Foundation; using RebootKit.Engine.Main; using RebootKit.Engine.Services.Simulation; using Unity.Netcode; using UnityEngine; using UnityEngine.AddressableAssets; using UnityEngine.Assertions; using UnityEngine.ResourceManagement.AsyncOperations; using UnityEngine.ResourceManagement.ResourceProviders; using UnityEngine.SceneManagement; using Logger = RebootKit.Engine.Foundation.Logger; namespace RebootKit.Engine.Simulation { public interface IWorldContext { } public class WorldService : IService { static readonly Logger s_Logger = new Logger(nameof(WorldService)); enum WorldState { Unloaded, Loading, Loaded } WorldState m_WorldState = WorldState.Unloaded; WorldConfig m_Config; AsyncOperationHandle m_SceneInstance; enum ActorOrigin { InScene, Prefab } struct ActorData { public ActorOrigin Origin; public Actor Actor; public ActorData(ActorOrigin origin, Actor actor) { Origin = origin; Actor = actor; } } readonly List m_Actors = new List(); public IWorldContext Context { get; private set; } public string WorldID { get { return string.IsNullOrEmpty(m_Config.name) ? string.Empty : m_Config.name; } } public WorldService() { } 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); // await UniTask.WaitWhile(() => RR.CoreNetworkGameSystemsInstance is null, cancellationToken: cancellationToken); foreach (GameObject root in m_SceneInstance.Result.Scene.GetRootGameObjects()) { if (root.TryGetComponent(out IWorldContext worldContext)) { Assert.IsNull(Context, "WorldContext is already set. There should be only one WorldContext in the scene."); Context = worldContext; } foreach (Actor actor in root.GetComponentsInChildren()) { RR.NetworkSystemInstance.Actors.RegisterInSceneActor(actor); } } m_WorldState = WorldState.Loaded; } public void Unload() { if (m_WorldState == WorldState.Unloaded) { return; } if (RR.NetworkSystemInstance is not null) { RR.NetworkSystemInstance.Actors.CleanUp(); } if (m_SceneInstance.IsValid()) { m_SceneInstance.Release(); m_SceneInstance = default; } m_WorldState = WorldState.Unloaded; Context = null; } } }