using System; using System.Collections.Generic; using UnityEngine; using UnityEngine.SceneManagement; public static class UIBackStack { private sealed class Entry { public UnityEngine.Object owner; public Func canHandle; public Func handleBack; public long sequence; } private static readonly List entries = new List(); private static long nextSequence; private static bool hookedSceneEvents; public static void RegisterOrBump(UnityEngine.Object owner, Func canHandle, Func handleBack) { if (owner == null || handleBack == null) { return; } EnsureSceneHook(); PurgeInvalidEntries(); for (int i = 0; i < entries.Count; i++) { Entry existing = entries[i]; if (ReferenceEquals(existing.owner, owner)) { existing.canHandle = canHandle; existing.handleBack = handleBack; existing.sequence = ++nextSequence; return; } } entries.Add(new Entry { owner = owner, canHandle = canHandle, handleBack = handleBack, sequence = ++nextSequence }); } public static void Unregister(UnityEngine.Object owner) { if (owner == null) { return; } for (int i = entries.Count - 1; i >= 0; i--) { if (ReferenceEquals(entries[i].owner, owner)) { entries.RemoveAt(i); } } } public static bool TryHandleTop() { EnsureSceneHook(); PurgeInvalidEntries(); entries.Sort((a, b) => a.sequence.CompareTo(b.sequence)); for (int i = entries.Count - 1; i >= 0; i--) { Entry entry = entries[i]; if (!CanEntryHandle(entry)) { continue; } try { if (entry.handleBack()) { PurgeInvalidEntries(); return true; } } catch (Exception ex) { Debug.LogWarning($"[UIBackStack] HandleBack failed: {ex.Message}"); } } PurgeInvalidEntries(); return false; } private static bool CanEntryHandle(Entry entry) { if (entry == null || entry.owner == null) { return false; } try { return entry.canHandle == null || entry.canHandle(); } catch (Exception ex) { Debug.LogWarning($"[UIBackStack] CanHandle failed: {ex.Message}"); return false; } } private static void PurgeInvalidEntries() { for (int i = entries.Count - 1; i >= 0; i--) { Entry entry = entries[i]; if (entry == null || entry.owner == null) { entries.RemoveAt(i); continue; } if (entry.owner is Behaviour behaviour && behaviour.gameObject == null) { entries.RemoveAt(i); continue; } if (entry.owner is GameObject ownerGo && ownerGo == null) { entries.RemoveAt(i); } } } private static void EnsureSceneHook() { if (hookedSceneEvents) { return; } hookedSceneEvents = true; SceneManager.sceneLoaded += HandleSceneLoaded; } private static void HandleSceneLoaded(Scene scene, LoadSceneMode mode) { PurgeInvalidEntries(); } }