using System;using Unity.Collections;using Unity.Entities;using Unity.NetCode;using Unity.Scenes;public struct LoadNextLevelCommand : IRpcCommand { }// For tracking when a scene has finished loading, when loading starts it's added here, removed when unloadedpublic struct TrackedSubScene : IBufferElementData{public Entity SceneEntity;}[RequireMatchingQueriesForUpdate][WorldSystemFilter(WorldSystemFilterFlags.ServerSimulation)]public partial class ServerLevelTracker : SystemBase{private LevelLoader m_Loader;protected override void OnCreate(){#if !UNITY_DOTSRUNTIMEif (UnityEngine.SceneManagement.SceneManager.GetActiveScene().name != "LevelSync_Bootstrap")Enabled = false;#endifm_Loader = World.GetExistingSystemManaged<LevelLoader>();}protected override void OnUpdate(){// Handle RPCs from client with next level load commandsvar ecb = new EntityCommandBuffer(Allocator.Temp);var shouldLoadNext = false;Entities.WithoutBurst().ForEach((Entity entity, in LoadNextLevelCommand level, in ReceiveRpcCommandRequest req) =>{UnityEngine.Debug.Log("Server received command to load next level");shouldLoadNext = true;ecb.DestroyEntity(entity);}).Run();ecb.Playback(EntityManager);if (shouldLoadNext){var levelState = SystemAPI.GetSingleton<LevelSyncStateComponent>();var levelCount = m_Loader.Levels.GetUniqueKeyArray(Allocator.Temp).Item2;levelState.CurrentLevel = ++levelState.CurrentLevel % levelCount;SystemAPI.SetSingleton(levelState);UnityEngine.Debug.Log($"[{World.Name}] trigger loading of level {levelState.CurrentLevel}");// Disable sync on all connectionsvar commandBuffer = new EntityCommandBuffer(Allocator.Temp);FixedString32Bytes worldName = World.Name;Entities.WithAll<NetworkStreamInGame>().ForEach((Entity entity, in NetworkId netId) =>{UnityEngine.Debug.Log($"[{worldName}] disable sync on {netId.Value}");commandBuffer.RemoveComponent<NetworkStreamInGame>(entity);}).Run();commandBuffer.Playback(EntityManager);m_Loader.UnloadAndLoadNext(levelState.CurrentLevel);NetcodeLevelSync.TriggerClientLoadLevel(levelState.CurrentLevel, World);}}}[RequireMatchingQueriesForUpdate][WorldSystemFilter(WorldSystemFilterFlags.ClientSimulation | WorldSystemFilterFlags.ThinClientSimulation)]public partial class ClientLevelTracker : SystemBase{private LevelLoader m_Loader;protected override void OnCreate(){#if !UNITY_DOTSRUNTIMEif (UnityEngine.SceneManagement.SceneManager.GetActiveScene().name != "LevelSync_Bootstrap")Enabled = false;#endifm_Loader = World.GetExistingSystemManaged<LevelLoader>();}protected override void OnUpdate(){var levelState = SystemAPI.GetSingleton<LevelSyncStateComponent>();if (levelState.State == LevelSyncState.LevelLoadRequest)m_Loader.UnloadAndLoadNext(levelState.NextLevel);}}[WorldSystemFilter(WorldSystemFilterFlags.ServerSimulation | WorldSystemFilterFlags.ClientSimulation | WorldSystemFilterFlags.ThinClientSimulation)][UpdateInGroup(typeof(SimulationSystemGroup), OrderLast = true)]public partial class LevelLoader : SystemBase{private NativeParallelMultiHashMap<int, Level> m_Levels;// When using manual loading/unloading of individual levels the automatic sync flow needs to be disabledprivate bool m_DisableLevelSync;public struct Level {public Hash128 guid;[Flags]public enum Flags : int{None = 0,Client = 1 << 0,Server = 1 << 1,}public Flags flags;}public NativeParallelMultiHashMap<int, Level> Levels => m_Levels;protected override void OnCreate(){#if !UNITY_DOTSRUNTIMEif (UnityEngine.SceneManagement.SceneManager.GetActiveScene().name != "LevelSync_Bootstrap"){Enabled = false;return;}#endifm_Levels = new NativeParallelMultiHashMap<int, Level>(2, Allocator.Persistent);RequireForUpdate<LevelSyncStateComponent>();if (SystemAPI.TryGetSingletonEntity<LevelSyncStateComponent>(out var levelSyncEntity))EntityManager.AddBuffer<TrackedSubScene>(levelSyncEntity);}protected override void OnDestroy(){if (m_Levels.IsCreated)m_Levels.Dispose();}protected override void OnUpdate(){if (m_DisableLevelSync)return;if (m_Levels.Count() == 0){if (SystemAPI.TryGetSingleton<SceneListData>(out var levelData)){m_Levels.Add(0, new Level(){flags = Level.Flags.Client | Level.Flags.Server, guid = levelData.Level1A});m_Levels.Add(0, new Level(){flags = Level.Flags.Client | Level.Flags.Server, guid = levelData.Level1B});m_Levels.Add(1, new Level(){flags = Level.Flags.Client | Level.Flags.Server, guid = levelData.Level2A});m_Levels.Add(1, new Level(){flags = Level.Flags.Client | Level.Flags.Server, guid = levelData.Level2B});}}CheckLevelLoading();}protected void CheckLevelLoading(){var levelState = SystemAPI.GetSingleton<LevelSyncStateComponent>();if (levelState.State == LevelSyncState.LevelLoadInProgress){var levelStateEntity = SystemAPI.GetSingletonEntity<LevelSyncStateComponent>();var trackedScenes = SystemAPI.GetBuffer<TrackedSubScene>(levelStateEntity);bool allScenesLoaded = true;for (int i = 0; i < trackedScenes.Length; ++i){if (!SceneSystem.IsSceneLoaded(World.Unmanaged, trackedScenes[i].SceneEntity))allScenesLoaded = false;}if (allScenesLoaded){// Notify levelsync logic that we're ready for next steplevelState.State = LevelSyncState.LevelLoaded;SystemAPI.SetSingleton(levelState);//UnityEngine.Debug.Log($"[{World.Name}] finished loading {EntityManager.GetName(m_SceneList[m_CurrentLevel])} GUID={m_Levels[m_CurrentLevel]}");UnityEngine.Debug.Log($"[{World.Name}] finished loading {trackedScenes.Length} subscenes");}}}public void UnloadAndLoadNext(int nextLevel){var levelStateEntity = SystemAPI.GetSingletonEntity<LevelSyncStateComponent>();var trackedScenes = SystemAPI.GetBuffer<TrackedSubScene>(levelStateEntity);var sceneEntities = trackedScenes.ToNativeArray(Allocator.Temp);for (int i = 0; i < sceneEntities.Length; ++i){var sceneEntity = sceneEntities[i].SceneEntity;UnityEngine.Debug.Log($"[{World.Name}] Unloading {sceneEntity}");if (SceneSystem.IsSceneLoaded(World.Unmanaged, sceneEntity))SceneSystem.UnloadScene(World.Unmanaged, sceneEntity);}trackedScenes = SystemAPI.GetBuffer<TrackedSubScene>(levelStateEntity);trackedScenes.Clear();var levelState = SystemAPI.GetSingleton<LevelSyncStateComponent>();levelState.State = LevelSyncState.LevelLoadInProgress;levelState.CurrentLevel = nextLevel;SystemAPI.SetSingleton(levelState);foreach (var level in m_Levels.GetValuesForKey(nextLevel)){Entity sceneEntity = Entity.Null;if (level.flags == Level.Flags.Client){ // GO only// This doesn't actually do anything or change the outcome of the tests running this code.// Removing this, since the feature to use LoadAsGOScene is gone. Leaving this here to preserve some context for when netcode updates or removes this.//var loadParams = new SceneSystem.LoadParameters {Flags = SceneLoadFlags.LoadAsGOScene};//sceneEntity = SceneSystem.LoadSceneAsync(World.Unmanaged, level.guid, loadParams);}else{sceneEntity = SceneSystem.LoadSceneAsync(World.Unmanaged, level.guid);}if (sceneEntity != Entity.Null){trackedScenes = SystemAPI.GetBuffer<TrackedSubScene>(levelStateEntity);trackedScenes.Add(new TrackedSubScene(){SceneEntity = sceneEntity});}UnityEngine.Debug.Log($"[{World.Name}] Loading '{World.EntityManager.GetName(sceneEntity)}' GUID={level.guid}");}}public void LoadLevel(int number){m_DisableLevelSync = true;foreach (var level in m_Levels.GetValuesForKey(number)){var lookupScene = SceneSystem.GetSceneEntity(World.Unmanaged, level.guid);if (lookupScene != Entity.Null && SceneSystem.IsSceneLoaded(World.Unmanaged, lookupScene))continue;Entity sceneEntity = Entity.Null;if (level.flags == Level.Flags.Client){ // GO only// This doesn't actually do anything or change the outcome of the tests running this code.// Removing this, since the feature to use LoadAsGOScene is gone. Leaving this here to preserve some context for when netcode updates or removes this.//var loadParams = new SceneSystem.LoadParameters {Flags = SceneLoadFlags.LoadAsGOScene};//sceneEntity = SceneSystem.LoadSceneAsync(World.Unmanaged, level.guid, loadParams);}else if ((level.flags & Level.Flags.Server) == Level.Flags.Server){sceneEntity = SceneSystem.LoadSceneAsync(World.Unmanaged, level.guid);}else{continue;}UnityEngine.Debug.Log($"[{World.Name}] Loading '{World.EntityManager.GetName(sceneEntity)}' GUID={level.guid}");NetcodeLevelSync.SetLevelState(LevelSyncState.LevelLoadInProgress, World);var trackedScenes = SystemAPI.GetBuffer<TrackedSubScene>(SystemAPI.GetSingletonEntity<LevelSyncStateComponent>());trackedScenes.Add(new TrackedSubScene(){SceneEntity = sceneEntity});}}public void UnloadLevel(int number){foreach (var level in m_Levels.GetValuesForKey(number)){if (level.flags == Level.Flags.Client) continue; // GO Scene// atm subscenes must be completely obliterated (not just unloaded) to properly trigger prespawn cleanupUnityEngine.Debug.Log($"[{World.Name}] unloading {level.guid}");var sceneEntity = SceneSystem.GetSceneEntity(World.Unmanaged, level.guid);SceneSystem.UnloadScene(World.Unmanaged, level.guid);var trackedScenes = SystemAPI.GetBuffer<TrackedSubScene>(SystemAPI.GetSingletonEntity<LevelSyncStateComponent>());for (int i = trackedScenes.Length - 1; i >= 0; i--){if (trackedScenes[i].SceneEntity == sceneEntity)trackedScenes.RemoveAtSwapBack(i);}}}public void ToggleSync(){var conQuery = World.EntityManager.CreateEntityQuery(ComponentType.ReadOnly<NetworkId>());var cons = conQuery.ToEntityArray(Allocator.Temp);var conIds = conQuery.ToComponentDataArray<NetworkId>(Allocator.Temp);for (int i = 0; i < cons.Length; ++i){if (World.EntityManager.HasComponent<NetworkStreamInGame>(cons[i])){UnityEngine.Debug.Log($"[{World}] Disable sync on {conIds[i].Value}");World.EntityManager.RemoveComponent<NetworkStreamInGame>(cons[i]);}else{UnityEngine.Debug.Log($"[{World}] Enable sync on {conIds[i].Value}");World.EntityManager.AddComponent<NetworkStreamInGame>(cons[i]);}}}}
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。