UnityExplorer/src/ObjectExplorer/SceneHandler.cs

137 lines
5.7 KiB
C#
Raw Normal View History

2021-05-26 17:41:51 +10:00
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using UnityEngine;
using UnityEngine.SceneManagement;
2021-12-02 18:35:46 +11:00
using UniverseLib;
2021-05-26 17:41:51 +10:00
namespace UnityExplorer.ObjectExplorer
2021-05-26 17:41:51 +10:00
{
public static class SceneHandler
{
/// <summary>The currently inspected Scene.</summary>
2021-06-05 19:36:09 +10:00
public static Scene? SelectedScene
2021-05-26 17:41:51 +10:00
{
2021-05-29 14:50:27 +10:00
get => selectedScene;
2021-05-26 17:41:51 +10:00
internal set
{
if (selectedScene.HasValue && selectedScene == value)
2021-05-26 17:41:51 +10:00
return;
2021-05-29 14:50:27 +10:00
selectedScene = value;
OnInspectedSceneChanged?.Invoke((Scene)selectedScene);
2021-05-26 17:41:51 +10:00
}
}
2021-05-29 14:50:27 +10:00
private static Scene? selectedScene;
2021-05-26 17:41:51 +10:00
/// <summary>The GameObjects in the currently inspected scene.</summary>
public static GameObject[] CurrentRootObjects { get; private set; } = new GameObject[0];
2021-05-26 17:41:51 +10:00
/// <summary>All currently loaded Scenes.</summary>
public static List<Scene> LoadedScenes { get; private set; } = new();
//private static HashSet<Scene> previousLoadedScenes;
2021-05-26 17:41:51 +10:00
/// <summary>The names of all scenes in the build settings, if they could be retrieved.</summary>
public static List<string> AllSceneNames { get; private set; } = new();
2021-05-26 17:41:51 +10:00
/// <summary>Invoked when the currently inspected Scene changes. The argument is the new scene.</summary>
2021-05-26 17:41:51 +10:00
public static event Action<Scene> OnInspectedSceneChanged;
/// <summary>Invoked whenever the list of currently loaded Scenes changes. The argument contains all loaded scenes after the change.</summary>
public static event Action<List<Scene>> OnLoadedScenesUpdated;
2021-05-26 17:41:51 +10:00
/// <summary>Generally will be 2, unless DontDestroyExists == false, then this will be 1.</summary>
internal static int DefaultSceneCount => 1 + (DontDestroyExists ? 1 : 0);
2021-05-26 17:41:51 +10:00
/// <summary>Whether or not we are currently inspecting the "HideAndDontSave" asset scene.</summary>
public static bool InspectingAssetScene => SelectedScene.HasValue && SelectedScene.Value == default;
2021-05-26 17:41:51 +10:00
/// <summary>Whether or not we successfuly retrieved the names of the scenes in the build settings.</summary>
public static bool WasAbleToGetScenesInBuild { get; private set; }
2021-05-26 17:41:51 +10:00
/// <summary>Whether or not the "DontDestroyOnLoad" scene exists in this game.</summary>
public static bool DontDestroyExists { get; private set; }
2021-05-26 17:41:51 +10:00
internal static void Init()
{
// Check if the game has "DontDestroyOnLoad"
DontDestroyExists = Scene.GetNameInternal(-12) == "DontDestroyOnLoad";
2021-05-26 17:41:51 +10:00
// Try to get all scenes in the build settings. This may not work.
try
{
Type sceneUtil = ReflectionUtility.GetTypeByName("UnityEngine.SceneManagement.SceneUtility");
if (sceneUtil == null)
throw new Exception("This version of Unity does not ship with the 'SceneUtility' class, or it was not unstripped.");
2021-06-05 19:36:09 +10:00
2021-05-26 17:41:51 +10:00
var method = sceneUtil.GetMethod("GetScenePathByBuildIndex", ReflectionUtility.FLAGS);
int sceneCount = SceneManager.sceneCountInBuildSettings;
for (int i = 0; i < sceneCount; i++)
{
var scenePath = (string)method.Invoke(null, new object[] { i });
2021-08-06 18:44:13 +10:00
AllSceneNames.Add(scenePath);
2021-05-26 17:41:51 +10:00
}
2021-10-26 15:12:44 +11:00
WasAbleToGetScenesInBuild = true;
2021-05-26 17:41:51 +10:00
}
catch (Exception ex)
{
2021-08-06 18:44:13 +10:00
WasAbleToGetScenesInBuild = false;
2021-05-26 17:41:51 +10:00
ExplorerCore.LogWarning($"Unable to generate list of all Scenes in the build: {ex}");
}
}
internal static void Update()
{
// Inspected scene will exist if it's DontDestroyOnLoad or HideAndDontSave
bool inspectedExists =
SelectedScene.HasValue
&& ((DontDestroyExists && SelectedScene.Value.handle == -12)
|| SelectedScene.Value.handle == -1);
2021-05-26 17:41:51 +10:00
LoadedScenes.Clear();
2021-05-26 17:41:51 +10:00
for (int i = 0; i < SceneManager.sceneCount; i++)
{
Scene scene = SceneManager.GetSceneAt(i);
if (scene == default || !scene.isLoaded || !scene.IsValid())
2021-05-26 17:41:51 +10:00
continue;
// If we have not yet confirmed inspectedExists, check if this scene is our currently inspected one.
if (!inspectedExists && scene == SelectedScene)
2021-05-26 17:41:51 +10:00
inspectedExists = true;
LoadedScenes.Add(scene);
2021-05-26 17:41:51 +10:00
}
if (DontDestroyExists)
LoadedScenes.Add(new Scene { m_Handle = -12 });
LoadedScenes.Add(new Scene { m_Handle = -1 });
2021-12-28 23:24:44 +11:00
2021-05-26 17:41:51 +10:00
// Default to first scene if none selected or previous selection no longer exists.
if (!inspectedExists)
SelectedScene = LoadedScenes.First();
2021-05-26 17:41:51 +10:00
// Notify on the list changing at all
OnLoadedScenesUpdated?.Invoke(LoadedScenes);
2021-05-26 17:41:51 +10:00
// Finally, update the root objects list.
if (SelectedScene != null && ((Scene)SelectedScene).IsValid())
2022-01-31 21:24:01 +11:00
CurrentRootObjects = RuntimeHelper.GetRootGameObjects((Scene)SelectedScene);
2021-05-26 17:41:51 +10:00
else
{
2022-01-31 21:24:01 +11:00
var allObjects = RuntimeHelper.FindObjectsOfTypeAll(typeof(GameObject));
var objects = new List<GameObject>();
2021-05-26 17:41:51 +10:00
foreach (var obj in allObjects)
{
var go = obj.TryCast<GameObject>();
if (go.transform.parent == null && !go.scene.IsValid())
objects.Add(go);
2021-05-26 17:41:51 +10:00
}
CurrentRootObjects = objects.ToArray();
2021-05-26 17:41:51 +10:00
}
}
}
}