using Unity.Entities;
using Unity.Scenes;
using Unity.Collections;
using UnityEngine;
using jeanf.SceneManagement;
namespace jeanf.scenemanagement
{
///
/// ECS system that monitors subscene loading state for debugging purposes.
/// Runs after VolumeSystem to capture scene load/unload requests.
///
[UpdateInGroup(typeof(SimulationSystemGroup))]
[UpdateAfter(typeof(VolumeSystem))]
public partial struct SceneLoadingDebugSystem : ISystem
{
private NativeHashMap _trackedScenes;
private NativeHashMap _sceneStates;
private EntityQuery _levelInfoQuery;
private EntityQuery _sectionQuery;
private enum SceneLoadingState
{
Unloaded,
Loading,
Loaded
}
public void OnCreate(ref SystemState state)
{
_trackedScenes = new NativeHashMap(100, Allocator.Persistent);
_sceneStates = new NativeHashMap(100, Allocator.Persistent);
_levelInfoQuery = SystemAPI.QueryBuilder()
.WithAll()
.Build();
_sectionQuery = SystemAPI.QueryBuilder()
.WithAll()
.Build();
}
public void OnDestroy(ref SystemState state)
{
if (_trackedScenes.IsCreated)
_trackedScenes.Dispose();
if (_sceneStates.IsCreated)
_sceneStates.Dispose();
}
public void OnUpdate(ref SystemState state)
{
var tracker = SceneLoadingTracker.Instance;
if (tracker == null)
return;
// Track scenes with LevelInfo (dynamic volume-based loading)
var levelEntities = _levelInfoQuery.ToEntityArray(Allocator.Temp);
var levelInfos = _levelInfoQuery.ToComponentDataArray(Allocator.Temp);
for (int i = 0; i < levelEntities.Length; i++)
{
var entity = levelEntities[i];
var levelInfo = levelInfos[i];
var sceneName = levelInfo.sceneReference.ToString();
var isLoaded = levelInfo.runtimeEntity != Entity.Null;
// Check if we're already tracking this scene
if (!_trackedScenes.ContainsKey(entity))
{
_trackedScenes.Add(entity, new FixedString128Bytes(sceneName));
_sceneStates.Add(entity, SceneLoadingState.Unloaded);
}
var currentState = _sceneStates[entity];
var newState = isLoaded ? SceneLoadingState.Loaded : SceneLoadingState.Unloaded;
// State changed
if (currentState != newState)
{
_sceneStates[entity] = newState;
// Track state changes (tracker is MonoBehaviour singleton, already on main thread)
if (newState == SceneLoadingState.Loaded)
{
// Scene just loaded
tracker.TrackSubsceneLoadStart(sceneName);
tracker.TrackSceneLoadComplete(sceneName);
}
else if (currentState == SceneLoadingState.Loaded && newState == SceneLoadingState.Unloaded)
{
// Scene unloading
tracker.TrackSceneUnloadStart(sceneName);
tracker.TrackSceneUnloadComplete(sceneName);
}
}
}
levelEntities.Dispose();
levelInfos.Dispose();
// Track section loading (for SectionRangeSystem)
var sectionEntities = _sectionQuery.ToEntityArray(Allocator.Temp);
var sectionRanges = _sectionQuery.ToComponentDataArray(Allocator.Temp);
for (int i = 0; i < sectionEntities.Length; i++)
{
var entity = sectionEntities[i];
var sectionRange = sectionRanges[i];
// Create a readable name using entity index and position
// Note: SceneSectionData can't be accessed due to Unity.Mathematics.Extensions dependency
var sceneName = $"Section_{entity.Index}_Pos({sectionRange.Center.x:F0},{sectionRange.Center.z:F0})";
var hasRequestSceneLoaded = state.EntityManager.HasComponent(entity);
if (!_trackedScenes.ContainsKey(entity))
{
_trackedScenes.Add(entity, new FixedString128Bytes(sceneName));
_sceneStates.Add(entity, SceneLoadingState.Unloaded);
}
var currentState = _sceneStates[entity];
var newState = hasRequestSceneLoaded ? SceneLoadingState.Loading : SceneLoadingState.Unloaded;
if (currentState != newState)
{
_sceneStates[entity] = newState;
if (newState == SceneLoadingState.Loading)
{
tracker.TrackSectionLoadStart(sceneName);
}
else if (currentState == SceneLoadingState.Loading && newState == SceneLoadingState.Unloaded)
{
tracker.TrackSceneUnloadStart(sceneName);
}
}
}
sectionEntities.Dispose();
sectionRanges.Dispose();
}
}
}