158 lines
3.7 KiB
C#
158 lines
3.7 KiB
C#
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<bool> canHandle;
|
|
public Func<bool> handleBack;
|
|
public long sequence;
|
|
}
|
|
|
|
private static readonly List<Entry> entries = new List<Entry>();
|
|
private static long nextSequence;
|
|
private static bool hookedSceneEvents;
|
|
|
|
public static void RegisterOrBump(UnityEngine.Object owner, Func<bool> canHandle, Func<bool> 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();
|
|
}
|
|
}
|