Files
bansonic_beta_main/Assets/scripts/_runtimecache/SceneObjectLookupCache.cs
T

162 lines
4.5 KiB
C#

using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
public static class SceneObjectLookupCache
{
private static readonly Dictionary<string, GameObject> Cache = new Dictionary<string, GameObject>(StringComparer.Ordinal);
private static readonly Dictionary<Type, UnityEngine.Object> AnyTypeCache = new Dictionary<Type, UnityEngine.Object>();
private static readonly Dictionary<Type, UnityEngine.Object> FirstTypeCache = new Dictionary<Type, UnityEngine.Object>();
private static bool hooked;
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
private static void ResetStaticState()
{
Cache.Clear();
AnyTypeCache.Clear();
FirstTypeCache.Clear();
hooked = false;
}
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
private static void Bootstrap()
{
if (hooked)
return;
hooked = true;
SceneManager.sceneLoaded -= OnSceneLoaded;
SceneManager.sceneLoaded += OnSceneLoaded;
SceneManager.activeSceneChanged -= OnActiveSceneChanged;
SceneManager.activeSceneChanged += OnActiveSceneChanged;
}
public static GameObject Find(string nameOrPath)
{
if (string.IsNullOrWhiteSpace(nameOrPath))
return null;
string key = nameOrPath.Trim();
if (Cache.TryGetValue(key, out GameObject cached))
{
if (IsUsableCachedGameObject(cached, key))
return cached;
Cache.Remove(key);
}
GameObject found = GameObject.Find(key);
if (found != null)
Cache[key] = found;
return found;
}
public static T FindComponent<T>(string nameOrPath) where T : Component
{
GameObject go = Find(nameOrPath);
return go != null ? go.GetComponent<T>() : null;
}
public static T FindAny<T>() where T : UnityEngine.Object
{
var type = typeof(T);
if (AnyTypeCache.TryGetValue(type, out var cached))
{
if (IsUsableCachedObject(cached))
return cached as T;
AnyTypeCache.Remove(type);
}
T found = UnityEngine.Object.FindAnyObjectByType<T>();
if (found != null)
AnyTypeCache[type] = found;
return found;
}
public static T FindFirst<T>() where T : UnityEngine.Object
{
var type = typeof(T);
if (FirstTypeCache.TryGetValue(type, out var cached))
{
if (IsUsableCachedObject(cached))
return cached as T;
FirstTypeCache.Remove(type);
}
T found = UnityEngine.Object.FindFirstObjectByType<T>();
if (found != null)
FirstTypeCache[type] = found;
return found;
}
public static Transform FindTransform(string nameOrPath)
{
GameObject go = Find(nameOrPath);
return go != null ? go.transform : null;
}
public static void Clear()
{
Cache.Clear();
AnyTypeCache.Clear();
FirstTypeCache.Clear();
}
private static void OnSceneLoaded(Scene scene, LoadSceneMode mode)
{
Cache.Clear();
AnyTypeCache.Clear();
FirstTypeCache.Clear();
}
private static void OnActiveSceneChanged(Scene oldScene, Scene newScene)
{
Cache.Clear();
AnyTypeCache.Clear();
FirstTypeCache.Clear();
}
private static bool IsUsableCachedObject(UnityEngine.Object cached)
{
if (cached == null)
return false;
if (cached is Component component)
return component != null && component.gameObject != null && component.gameObject.activeInHierarchy;
if (cached is GameObject go)
return go.activeInHierarchy;
return true;
}
private static bool IsUsableCachedGameObject(GameObject cached, string key)
{
if (cached == null || !cached.activeInHierarchy)
return false;
int slashIndex = key.IndexOf('/');
if (slashIndex < 0)
return cached.name == key;
return BuildHierarchyPath(cached.transform) == key;
}
private static string BuildHierarchyPath(Transform transform)
{
if (transform == null)
return string.Empty;
var path = transform.name;
while (transform.parent != null)
{
transform = transform.parent;
path = transform.name + "/" + path;
}
return path;
}
}