2025-09-05 19:46:30 +08:00
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
2025-11-13 11:16:31 +08:00
|
|
|
using System.Reflection;
|
2025-09-05 19:46:30 +08:00
|
|
|
using System.Runtime.CompilerServices;
|
|
|
|
|
|
|
|
|
|
namespace AlicizaX.UI.Runtime
|
|
|
|
|
{
|
|
|
|
|
public static class UIMetaRegistry
|
|
|
|
|
{
|
|
|
|
|
public readonly struct UIMetaInfo
|
|
|
|
|
{
|
|
|
|
|
public readonly RuntimeTypeHandle RuntimeTypeHandle;
|
|
|
|
|
public readonly RuntimeTypeHandle HolderRuntimeTypeHandle;
|
|
|
|
|
public readonly int UILayer;
|
|
|
|
|
public readonly bool FullScreen;
|
|
|
|
|
public readonly int CacheTime;
|
2025-11-13 17:46:20 +08:00
|
|
|
public readonly bool NeedUpdate;
|
2025-09-05 19:46:30 +08:00
|
|
|
|
2025-11-13 17:46:20 +08:00
|
|
|
public UIMetaInfo(RuntimeTypeHandle runtimeTypeHandle, RuntimeTypeHandle holderRuntimeTypeHandle, UILayer windowLayer, bool fullScreen, int cacheTime, bool needUpdate)
|
2025-09-05 19:46:30 +08:00
|
|
|
{
|
|
|
|
|
RuntimeTypeHandle = runtimeTypeHandle;
|
|
|
|
|
HolderRuntimeTypeHandle = holderRuntimeTypeHandle;
|
|
|
|
|
UILayer = (int)windowLayer;
|
|
|
|
|
FullScreen = fullScreen;
|
|
|
|
|
CacheTime = cacheTime;
|
2025-11-13 17:46:20 +08:00
|
|
|
NeedUpdate = needUpdate;
|
2025-09-05 19:46:30 +08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static readonly Dictionary<RuntimeTypeHandle, UIMetaInfo> _typeHandleMap = new();
|
|
|
|
|
private static readonly Dictionary<string, RuntimeTypeHandle> _stringHandleMap = new();
|
|
|
|
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
2025-11-13 17:46:20 +08:00
|
|
|
public static void Register(Type uiType, Type holderType, UILayer layer = UILayer.UI, bool fullScreen = false, int cacheTime = 0, bool needUpdate = false)
|
2025-09-05 19:46:30 +08:00
|
|
|
{
|
2026-04-23 20:19:46 +08:00
|
|
|
RuntimeTypeHandle holderHandle = holderType.TypeHandle;
|
|
|
|
|
RuntimeTypeHandle uiHandle = uiType.TypeHandle;
|
2025-11-13 17:46:20 +08:00
|
|
|
_typeHandleMap[uiHandle] = new UIMetaInfo(uiHandle, holderHandle, layer, fullScreen, cacheTime, needUpdate);
|
2025-09-05 19:46:30 +08:00
|
|
|
_stringHandleMap[uiType.Name] = uiHandle;
|
|
|
|
|
}
|
|
|
|
|
|
2025-11-13 11:16:31 +08:00
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
2025-09-05 19:46:30 +08:00
|
|
|
public static bool TryGet(RuntimeTypeHandle handle, out UIMetaInfo info)
|
|
|
|
|
{
|
2025-11-13 11:16:31 +08:00
|
|
|
if (_typeHandleMap.TryGetValue(handle, out info))
|
2026-04-23 20:19:46 +08:00
|
|
|
{
|
2025-11-13 11:16:31 +08:00
|
|
|
return true;
|
2026-04-23 20:19:46 +08:00
|
|
|
}
|
2025-11-13 11:16:31 +08:00
|
|
|
|
2026-04-23 20:19:46 +08:00
|
|
|
return TryReflectAndRegister(Type.GetTypeFromHandle(handle), out info);
|
2025-11-13 11:16:31 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
|
|
|
public static bool TryGet(string typeName, out UIMetaInfo info)
|
|
|
|
|
{
|
2026-04-23 20:19:46 +08:00
|
|
|
if (_stringHandleMap.TryGetValue(typeName, out RuntimeTypeHandle handle))
|
|
|
|
|
{
|
2025-11-13 11:16:31 +08:00
|
|
|
return TryGet(handle, out info);
|
2026-04-23 20:19:46 +08:00
|
|
|
}
|
2025-11-13 11:16:31 +08:00
|
|
|
|
2026-04-23 20:19:46 +08:00
|
|
|
Type type = AlicizaX.Utility.Assembly.GetType(typeName);
|
2025-11-13 11:16:31 +08:00
|
|
|
if (type != null && TryReflectAndRegister(type, out info))
|
2026-04-23 20:19:46 +08:00
|
|
|
{
|
2025-11-13 11:16:31 +08:00
|
|
|
return true;
|
2026-04-23 20:19:46 +08:00
|
|
|
}
|
2025-11-13 11:16:31 +08:00
|
|
|
|
|
|
|
|
info = default;
|
|
|
|
|
return false;
|
2025-09-05 19:46:30 +08:00
|
|
|
}
|
|
|
|
|
|
2025-11-13 11:16:31 +08:00
|
|
|
[MethodImpl(MethodImplOptions.NoInlining)]
|
|
|
|
|
private static bool TryReflectAndRegister(Type uiType, out UIMetaInfo info)
|
2025-09-05 19:46:30 +08:00
|
|
|
{
|
2026-04-23 20:19:46 +08:00
|
|
|
if (uiType == null)
|
|
|
|
|
{
|
|
|
|
|
info = default;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Log.Warning($"[UI] UI not pre-registered: {uiType.FullName}, using reflection fallback.");
|
2025-12-24 20:44:36 +08:00
|
|
|
return TryReflectAndRegisterInternal(uiType, out info);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.NoInlining)]
|
|
|
|
|
private static bool TryReflectAndRegisterInternal(Type uiType, out UIMetaInfo info)
|
|
|
|
|
{
|
|
|
|
|
try
|
2025-11-13 11:16:31 +08:00
|
|
|
{
|
2026-04-23 20:19:46 +08:00
|
|
|
Type holderType = ResolveHolderType(uiType);
|
|
|
|
|
if (holderType == null)
|
2025-12-24 20:44:36 +08:00
|
|
|
{
|
2026-04-23 20:19:46 +08:00
|
|
|
info = default;
|
|
|
|
|
return false;
|
2025-12-24 20:44:36 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
UILayer layer = UILayer.UI;
|
|
|
|
|
bool fullScreen = false;
|
|
|
|
|
int cacheTime = 0;
|
|
|
|
|
bool needUpdate = false;
|
|
|
|
|
|
2026-04-23 20:19:46 +08:00
|
|
|
IList<CustomAttributeData> attributes = CustomAttributeData.GetCustomAttributes(uiType);
|
|
|
|
|
for (int i = 0; i < attributes.Count; i++)
|
2025-12-24 20:44:36 +08:00
|
|
|
{
|
2026-04-23 20:19:46 +08:00
|
|
|
CustomAttributeData attribute = attributes[i];
|
|
|
|
|
string attributeName = attribute.AttributeType.Name;
|
|
|
|
|
if (attributeName == nameof(WindowAttribute))
|
|
|
|
|
{
|
|
|
|
|
IList<CustomAttributeTypedArgument> args = attribute.ConstructorArguments;
|
|
|
|
|
if (args.Count > 0)
|
|
|
|
|
{
|
|
|
|
|
layer = (UILayer)(args[0].Value ?? UILayer.UI);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (args.Count > 1)
|
|
|
|
|
{
|
|
|
|
|
fullScreen = (bool)(args[1].Value ?? false);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (args.Count > 2)
|
|
|
|
|
{
|
|
|
|
|
cacheTime = (int)(args[2].Value ?? 0);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (attributeName == nameof(UIUpdateAttribute))
|
|
|
|
|
{
|
|
|
|
|
needUpdate = true;
|
|
|
|
|
}
|
2025-12-24 20:44:36 +08:00
|
|
|
}
|
|
|
|
|
|
2026-04-23 20:19:46 +08:00
|
|
|
Register(uiType, holderType, layer, fullScreen, cacheTime, needUpdate);
|
|
|
|
|
info = _typeHandleMap[uiType.TypeHandle];
|
|
|
|
|
return true;
|
2025-11-13 11:16:31 +08:00
|
|
|
}
|
2025-12-24 20:44:36 +08:00
|
|
|
catch (Exception ex)
|
2025-09-05 19:46:30 +08:00
|
|
|
{
|
2025-12-24 20:44:36 +08:00
|
|
|
Log.Error($"[UI] Failed to register UI type {uiType.FullName}: {ex.Message}");
|
2025-09-05 19:46:30 +08:00
|
|
|
}
|
|
|
|
|
|
2025-11-13 11:16:31 +08:00
|
|
|
info = default;
|
|
|
|
|
return false;
|
2025-09-05 19:46:30 +08:00
|
|
|
}
|
2026-04-23 20:19:46 +08:00
|
|
|
|
|
|
|
|
private static Type ResolveHolderType(Type uiType)
|
|
|
|
|
{
|
|
|
|
|
Type current = uiType;
|
|
|
|
|
while (current != null && current != typeof(object))
|
|
|
|
|
{
|
|
|
|
|
if (current.IsGenericType)
|
|
|
|
|
{
|
|
|
|
|
Type[] genericArgs = current.GetGenericArguments();
|
|
|
|
|
if (genericArgs.Length == 1 && typeof(UIHolderObjectBase).IsAssignableFrom(genericArgs[0]))
|
|
|
|
|
{
|
|
|
|
|
return genericArgs[0];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
current = current.BaseType;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return null;
|
|
|
|
|
}
|
2025-09-05 19:46:30 +08:00
|
|
|
}
|
|
|
|
|
}
|