You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
lanlib/Scripts/Editor/Singleton/SingletonEditorManager.cs

147 lines
5.2 KiB
C#

10 months ago
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using UnityEditor;
using UnityEngine;
using Object = UnityEngine.Object;
namespace LanLib.Singleton.EditorUtilities
{
static class SingletonManager
{
private static Dictionary<Type, SingletonCreateCondition> _lutSingletonCreation = null;
static void DestroyGameObject(GameObject go)
{
if (Application.isPlaying)
{
Object.Destroy(go);
}
else
{
Object.DestroyImmediate(go);
}
}
static void RemoveAllSingletons(Func<SingletonBase, bool> predicate)
{
if (Selection.activeGameObject?.GetComponent<SingletonBase>())
{
Selection.activeGameObject = null;
}
var instances = Resources
.FindObjectsOfTypeAll<SingletonBase>()
.Where(predicate)
.ToArray();
foreach (var inst in instances)
{
DestroyGameObject(inst.gameObject);
}
}
static Dictionary<Type, SingletonCreateCondition> GetSingletonTypes()
{
if (_lutSingletonCreation != null) return _lutSingletonCreation;
var baseType = typeof(SingletonAutoLoadAttribute);
var thisAssemblyName = baseType.Assembly.GetName().ToString();
return _lutSingletonCreation = AppDomain.CurrentDomain.GetAssemblies()
.Where(assembly
=> assembly.GetReferencedAssemblies().Any(r => r.ToString() == thisAssemblyName)
&& assembly.GetName().ToString() != thisAssemblyName)
.SelectMany(assembly
=> assembly.GetCustomAttributes(false).OfType<SingletonAutoLoadAttribute>())
.Select(att => (att.type, att.createCondition))
.ToDictionary(d => d.type, d => d.createCondition);
}
[InitializeOnLoadMethod]
#if !UNITY_EDITOR
[RuntimeInitializeOnLoadMethod]
#endif
static void AutoCreateOnDomainReload()
{
foreach (var (t, con) in GetSingletonTypes())
{
if (con.Contains(SingletonCreateCondition.ReloadDomain))
{
t.BaseType.GetProperty("Instance", bindingFlags).GetValue(null);
}
}
}
[InitializeOnLoadMethod]
static void AutoCreateOnEnterPlayMode()
{
EditorApplication.playModeStateChanged += e =>
{
if (e == PlayModeStateChange.EnteredPlayMode)
{
foreach (var (t, con) in GetSingletonTypes())
{
if (con.Contains(SingletonCreateCondition.EnterPlay))
{
t.BaseType.GetProperty("Instance", bindingFlags).GetValue(null);
}
}
}
};
}
[InitializeOnLoadMethod]
static void CleanOnRecompileIfNeeded()
{
RemoveAllSingletons(inst => inst.shouldDestroyOnReloadDomain());
}
[InitializeOnLoadMethod]
static void CleanOnPlayModeChangeIfNeeded()
{
EditorApplication.playModeStateChanged += e =>
{
if (e == PlayModeStateChange.ExitingPlayMode)
{
RemoveAllSingletons(inst => inst.shouldDestroyOnExitPlayMode());
}
else if (e == PlayModeStateChange.ExitingEditMode)
{
RemoveAllSingletons(inst => inst.shouldDestroyOnExitEditMode());
}
else if (e == PlayModeStateChange.EnteredPlayMode)
{
var instances = Resources
.FindObjectsOfTypeAll<SingletonBase>()
.ToArray();
foreach (var inst in instances)
{
inst.DestroyOnSceneUnload = inst.DestroyOnSceneUnload;
}
}
};
}
static bool shouldDestroyOnReloadDomain(this SingletonBase singleton)
{
var t = singleton.GetType();
var isAutoCreate = GetSingletonTypes().ContainsKey(t)
&& GetSingletonTypes()[t].Contains(SingletonCreateCondition.ReloadDomain);
return singleton.DestroyCondition.Contains(SingletonDestroyCondition.ReloadDomain)
&& !isAutoCreate;
}
static bool shouldDestroyOnExitPlayMode(this SingletonBase singleton)
=> singleton.DestroyCondition.Contains(SingletonDestroyCondition.ExitPlay);
static bool shouldDestroyOnExitEditMode(this SingletonBase singleton)
=> singleton.DestroyCondition.Contains(SingletonDestroyCondition.ExitEdit);
static BindingFlags bindingFlags = 0
| BindingFlags.Static
// | BindingFlags.Instance
| BindingFlags.Public
// | BindingFlags.NonPublic
;
}
}