Files

266 lines
9.0 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using UnityEditor;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.SceneManagement;
using Object = UnityEngine.Object;
namespace XRLib
{
public static partial class Core
{
#pragma warning disable IDE0090 // 'new(...)' 사용
internal static Dictionary<MonoBehaviour, GameObject> monoTable = new Dictionary<MonoBehaviour, GameObject>();
internal static Dictionary<int, MonoBehaviour> singleTable = new Dictionary<int, MonoBehaviour>();
internal static Dictionary<int, MonoBehaviour> keyTable = new Dictionary<int, MonoBehaviour>();
static Dictionary<Type, List<MonoBehaviour>> diWaitingTable = new Dictionary<Type, List<MonoBehaviour>>();
#pragma warning restore IDE0090 // 'new(...)' 사용
static Core()
{
//Debug.Log("WISystem Active");
SceneManager.sceneLoaded += OnSceneLoaded;
}
private static void OnSceneLoaded(Scene arg0, LoadSceneMode arg1)
{
Init();
}
static void Init()
{
monoTable.Clear();
singleTable.Clear();
diWaitingTable.Clear();
//keyTable.NullCleaning();
}
public static void Regist(Object mo)
{
if (mo is not MonoBehaviour)
return;
if (!Regist(mo as MonoBehaviour))
return;
Hooker.initializerList.Enqueue(mo as MonoBehaviour);
Hooker.Initializing();
}
internal static bool Regist(MonoBehaviour mb)
{
//?? Addressable 다운로드를 하면 null mb가 생성된다.
if (mb.gameObject == null)
return false;
if (!mb.gameObject.scene.isLoaded)
return false;
//Debug.Log($"Regist {mb.name}");
if (!monoTable.TryAdd(mb, mb.gameObject))
{
//Debug.Log($"Regist failed : {mb.name}");
return false;
}
if (!RegistSingleBehaviour(mb))
return false;
Injection(mb);
return true;
}
internal static void Unregist(MonoBehaviour mb)
{
//Debug.Log($"Unregist:{mb.name}");
monoTable.Remove(mb);
if (mb is ISingle)
singleTable.Remove(mb.GetHashCode());
}
static bool RegistSingleBehaviour(MonoBehaviour mb)
{
if (mb is not ISingle)
return true;
var hashCode = mb.GetType().GetHashCode();
//Debug.Log($"Regist Single {wi}");
if (singleTable.ContainsKey(hashCode))
{
//Debug.Log($"SameCode! Origin={singleTable[hashCode].gameObject.name}, New={wi.gameObject.name}");
if (singleTable[hashCode].GetHashCode() != mb.GetHashCode())
{
//Debug.Log($"Move To Trash");
TrashThrow(mb, singleTable[hashCode]);
return false;
}
return false;
}
singleTable.Add(hashCode, mb);
if (diWaitingTable.TryGetValue(mb.GetType(), out var watingList))
{
//Debug.Log($"Find Wating Table");
foreach (var w in watingList)
{
var injectTargets = w.GetType().GetAllFields();
foreach (var t in injectTargets)
{
if (t.FieldType == mb.GetType())
{
//Debug.Log($"Find Missing");
t.SetValue(w, mb);
}
}
}
}
//Debug.Log($"RS_{mb.name}");
return true;
}
internal static void Injection(MonoBehaviour mb)
{
var wiType = mb.GetType();
var targetFields = wiType.GetAllFields();
List<Component> childs = mb.transform.FindAll<Component>();
List<UIBehaviour> uiElements = new ();
List<Transform> childTransforms = new ();
//Filtering
foreach (var c in childs)
{
if (c == null)
continue;
var cType = c.GetType();
if (cType.IsSubclassOf(typeof(UIBehaviour)))
{
uiElements.Add(c as UIBehaviour);
continue;
}
if (cType.IsSubclassOf(typeof(Transform)) || cType.Equals(typeof(Transform)) || cType.Equals(typeof(RectTransform)))
{
childTransforms.Add(c as Transform);
continue;
}
}
foreach (var f in targetFields)
{
#region LabelInjection
Label label = (Label)f.GetCustomAttribute(typeof(Label));
if (label != null)
{
foreach (var c in childs)
{
if (c.name.Equals(label.name))
{
if (c.TryGetComponent(label.target, out var value))
{
f.SetValue(mb, value);
}
}
}
}
#endregion
#region ISingleInjection
if (f.FieldType.GetInterface(nameof(ISingle)) != null)
{
//Debug.Log($"{wi} in ISingle.");
if (singleTable.TryGetValue(f.FieldType.GetHashCode(), out var value))
{
//Debug.Log($"Inject {value}");
f.SetValue(mb, value);
}
else
{
if (!diWaitingTable.ContainsKey(f.FieldType))
{
diWaitingTable.Add(f.FieldType, new List<MonoBehaviour>());
}
diWaitingTable[f.FieldType].Add(mb);
//Debug.Log($"Inject Waiting {wi}");
}
continue;
}
#endregion
#region IHotkeybinding
//if (f.FieldType.GetInterface(nameof(IHotkeyAction)) != null)
//{
// //Debug.Log($"{wi} in ISingle.");
// if (keyTable.TryGetValue(f.FieldType.GetHashCode(), out var value))
// {
// //Debug.Log($"Inject {value}");
// f.SetValue(mb, value);
// }
// continue;
//}
#endregion
#region UIBehaviourInjection
if (f.FieldType.IsSubclassOf(typeof(UIBehaviour)))
{
InjectNameAndType(uiElements, f, mb);
continue;
}
#endregion
#region TransformInjection
if (f.FieldType.IsSubclassOf(typeof(Transform)) || f.FieldType.Equals(typeof(Transform)))
{
InjectNameAndType(childTransforms, f, mb);
continue;
}
if (f.FieldType.Equals(typeof(RectTransform)))
{
InjectNameAndType(childTransforms, f, mb);
}
#endregion
if (f.FieldType.IsGenericType)
{
if (f.FieldType.GetGenericTypeDefinition().Equals(typeof(Container<>)))
{
var loadType = f.FieldType.GetGenericArguments()[0];
var containerType = typeof(Container<>).MakeGenericType(new Type[] { loadType });
var container = Activator.CreateInstance(containerType);
var stuffs = childs
.Where(c => loadType.Equals(c.GetType()));
container.GetType().GetMethod("Loading").Invoke(container, new object[] { stuffs });
f.SetValue(mb, container);
}
}
}
}
static void TrashThrow(MonoBehaviour target, MonoBehaviour origin)
{
var trash = target.gameObject.AddComponent<TrashBehaviour>();
trash.originBehaviour = origin;
monoTable.Remove(target);
GameObject.Destroy(target);
}
static void InjectNameAndType<T>(List<T> arr, FieldInfo info, MonoBehaviour target) where T : Component
{
foreach (var a in arr)
{
if (!a.name.Equals(info.Name))
continue;
if (!a.GetType().Equals(info.FieldType))
continue;
info.SetValue(target, a);
return;
}
}
}
}