diff --git a/UnityProject/Assets/GameScripts/HotFix/GameLogic/Module/UIModule/UIModule.cs b/UnityProject/Assets/GameScripts/HotFix/GameLogic/Module/UIModule/UIModule.cs
index 416f360a..cbdfd2f2 100644
--- a/UnityProject/Assets/GameScripts/HotFix/GameLogic/Module/UIModule/UIModule.cs
+++ b/UnityProject/Assets/GameScripts/HotFix/GameLogic/Module/UIModule/UIModule.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
+using System.Threading;
using Cysharp.Threading.Tasks;
using GameLogic;
using TEngine;
@@ -8,35 +9,43 @@ using UnityEngine.UI;
namespace GameLogic
{
+ ///
+ /// UI管理模块。
+ ///
public sealed partial class UIModule : Singleton, IUpdate
{
- private static Transform _instanceRoot = null;
+ // 核心字段
+ private static Transform _instanceRoot = null; // UI根节点变换组件
+ private bool _enableErrorLog = true; // 是否启用错误日志
+ private Camera _uiCamera = null; // UI专用摄像机
+ private readonly List _uiStack = new List(128); // 窗口堆栈
+ private ErrorLogger _errorLogger; // 错误日志记录器
- private bool _enableErrorLog = true;
-
- private Camera _uiCamera = null;
-
- private readonly List _uiStack = new List(100);
-
- public const int LAYER_DEEP = 2000;
+ // 常量定义
+ public const int LAYER_DEEP = 2000;
public const int WINDOW_DEEP = 100;
public const int WINDOW_HIDE_LAYER = 2; // Ignore Raycast
public const int WINDOW_SHOW_LAYER = 5; // UI
+ // 资源加载接口
public static IUIResourceLoader Resource;
///
- /// UI根节点。
+ /// UI根节点访问属性
///
public static Transform UIRoot => _instanceRoot;
///
- /// UI根节点。
+ /// UI摄像机访问属性
///
public Camera UICamera => _uiCamera;
-
- private ErrorLogger _errorLogger;
+ ///
+ /// 模块初始化(自动调用)。
+ /// 1. 查找场景中的UIRoot
+ /// 2. 初始化资源加载器
+ /// 3. 配置错误日志系统
+ ///
protected override void OnInit()
{
var uiRoot = GameObject.Find("UIRoot");
@@ -84,6 +93,12 @@ namespace GameLogic
}
}
+ ///
+ /// 模块释放(自动调用)。
+ /// 1. 清理错误日志系统
+ /// 2. 关闭所有窗口
+ /// 3. 销毁UI根节点
+ ///
protected override void OnRelease()
{
if (_errorLogger != null)
@@ -103,7 +118,7 @@ namespace GameLogic
///
/// 设置屏幕安全区域(异形屏支持)。
///
- /// 安全区域
+ /// 安全区域矩形(基于屏幕像素坐标)。
public static void ApplyScreenSafeRect(Rect safeRect)
{
CanvasScaler scaler = UIRoot.GetComponentInParent();
@@ -232,9 +247,9 @@ namespace GameLogic
///
/// 用户自定义数据。
/// 打开窗口操作句柄。
- public void ShowUIAsync(params System.Object[] userDatas) where T : UIWindow
+ public void ShowUIAsync(params System.Object[] userDatas) where T : UIWindow , new()
{
- ShowUIImp(typeof(T), true, userDatas);
+ ShowUIImp(true, userDatas);
}
///
@@ -254,9 +269,9 @@ namespace GameLogic
/// 窗口类。
/// 用户自定义数据。
/// 打开窗口操作句柄。
- public void ShowUI(params System.Object[] userDatas) where T : UIWindow
+ public void ShowUI(params System.Object[] userDatas) where T : UIWindow , new()
{
- ShowUIImp(typeof(T), false, userDatas);
+ ShowUIImp(false, userDatas);
}
///
@@ -264,9 +279,9 @@ namespace GameLogic
///
/// 用户自定义数据。
/// 打开窗口操作句柄。
- public async UniTask ShowUIAsyncAwait(params System.Object[] userDatas) where T : UIWindow
+ public async UniTask ShowUIAsyncAwait(params System.Object[] userDatas) where T : UIWindow , new()
{
- return await ShowUIAwaitImp(typeof(T), true, userDatas) as T;
+ return await ShowUIAwaitImp(true, userDatas) as T;
}
///
@@ -284,38 +299,54 @@ namespace GameLogic
{
string windowName = type.FullName;
- // 如果窗口已经存在
- if (IsContains(windowName))
+ if (!TryGetWindow(windowName, out UIWindow window, userDatas))
{
- UIWindow window = GetWindow(windowName);
- Pop(window); //弹出窗口
- Push(window); //重新压入
- window.TryInvoke(OnWindowPrepare, userDatas);
- }
- else
- {
- UIWindow window = CreateInstance(type);
+ window = CreateInstance(type);
Push(window); //首次压入
window.InternalLoad(window.AssetName, OnWindowPrepare, isAsync, userDatas).Forget();
}
}
- private async UniTask ShowUIAwaitImp(Type type, bool isAsync, params System.Object[] userDatas)
+ private void ShowUIImp(bool isAsync, params System.Object[] userDatas) where T : UIWindow , new()
{
+ Type type = typeof(T);
string windowName = type.FullName;
- // 如果窗口已经存在
+ if (!TryGetWindow(windowName, out UIWindow window, userDatas))
+ {
+ window = CreateInstance();
+ Push(window); //首次压入
+ window.InternalLoad(window.AssetName, OnWindowPrepare, isAsync, userDatas).Forget();
+ }
+ }
+
+ private bool TryGetWindow(string windowName,out UIWindow window, params System.Object[] userDatas)
+ {
+ window = null;
if (IsContains(windowName))
{
- UIWindow window = GetWindow(windowName);
+ window = GetWindow(windowName);
Pop(window); //弹出窗口
Push(window); //重新压入
window.TryInvoke(OnWindowPrepare, userDatas);
- return window;
+
+ return true;
+ }
+ return false;
+ }
+
+ private async UniTask ShowUIAwaitImp(bool isAsync, params System.Object[] userDatas) where T : UIWindow , new()
+ {
+ Type type = typeof(T);
+ string windowName = type.FullName;
+
+ if (TryGetWindow(windowName, out UIWindow window, userDatas))
+ {
+ return window as T;
}
else
{
- UIWindow window = CreateInstance(type);
+ window = CreateInstance();
Push(window); //首次压入
window.InternalLoad(window.AssetName, OnWindowPrepare, isAsync, userDatas).Forget();
float time = 0f;
@@ -328,13 +359,14 @@ namespace GameLogic
}
await UniTask.Yield();
}
- return window;
+ return window as T;
}
}
///
- /// 关闭窗口
+ /// 关闭窗口。
///
+ /// 窗口类型
public void CloseUI() where T : UIWindow
{
CloseUI(typeof(T));
@@ -375,7 +407,7 @@ namespace GameLogic
window.Visible = false;
window.IsHide = true;
- window.HideTimerId = ModuleSystem.GetModule().AddTimer((arg) =>
+ window.HideTimerId = GameModule.Timer.AddTimer((arg) =>
{
CloseUI(type);
},window.HideTimeToClose);
@@ -481,10 +513,32 @@ namespace GameLogic
}
}
}
+
+ private UIWindow CreateInstance() where T : UIWindow , new()
+ {
+ Type type = typeof(T);
+ UIWindow window = new T();
+ WindowAttribute attribute = Attribute.GetCustomAttribute(type, typeof(WindowAttribute)) as WindowAttribute;
+
+ if (window == null)
+ throw new GameFrameworkException($"Window {type.FullName} create instance failed.");
+
+ if (attribute != null)
+ {
+ string assetName = string.IsNullOrEmpty(attribute.Location) ? type.Name : attribute.Location;
+ window.Init(type.FullName, attribute.WindowLayer, attribute.FullScreen, assetName, attribute.FromResources, attribute.HideTimeToClose);
+ }
+ else
+ {
+ window.Init(type.FullName, (int)UILayer.UI, fullScreen: window.FullScreen, assetName: type.Name, fromResources: false, hideTimeToClose: 10);
+ }
+
+ return window;
+ }
private UIWindow CreateInstance(Type type)
{
- UIWindow window = Activator.CreateInstance(type) as UIWindow;
+ UIWindow window = EmitHelper.CreateInstance(type) as UIWindow;
WindowAttribute attribute = Attribute.GetCustomAttribute(type, typeof(WindowAttribute)) as WindowAttribute;
if (window == null)
@@ -507,7 +561,7 @@ namespace GameLogic
/// 异步获取窗口。
///
/// 打开窗口操作句柄。
- public async UniTask GetUIAsyncAwait() where T : UIWindow
+ public async UniTask GetUIAsyncAwait(CancellationToken cancellationToken) where T : UIWindow
{
string windowName = typeof(T).FullName;
var window = GetWindow(windowName);
@@ -536,7 +590,7 @@ namespace GameLogic
{
break;
}
- await UniTask.Yield();
+ await UniTask.Yield(cancellationToken: cancellationToken);
}
return ret;
}
@@ -612,7 +666,9 @@ namespace GameLogic
{
// 如果已经存在
if (IsContains(window.WindowName))
- throw new System.Exception($"Window {window.WindowName} is exist.");
+ {
+ throw new GameFrameworkException($"Window {window.WindowName} is exist.");
+ }
// 获取插入到所属层级的位置
int insertIndex = -1;
diff --git a/UnityProject/Assets/GameScripts/HotFix/GameLogic/Module/UIModule/UIWidget.cs b/UnityProject/Assets/GameScripts/HotFix/GameLogic/Module/UIModule/UIWidget.cs
index 1c4a5119..a012e168 100644
--- a/UnityProject/Assets/GameScripts/HotFix/GameLogic/Module/UIModule/UIWidget.cs
+++ b/UnityProject/Assets/GameScripts/HotFix/GameLogic/Module/UIModule/UIWidget.cs
@@ -55,7 +55,7 @@ namespace GameLogic
}
///
- /// 窗口可见性
+ /// 窗口可见性。
///
public bool Visible
{
@@ -278,7 +278,7 @@ namespace GameLogic
/// 组件被销毁调用。
/// 请勿手动调用!
///
- internal void OnDestroyWidget()
+ protected internal void OnDestroyWidget()
{
Parent?.SetUpdateDirty();
diff --git a/UnityProject/Assets/GameScripts/HotFix/GameLogic/Module/UIModule/UIWindow.cs b/UnityProject/Assets/GameScripts/HotFix/GameLogic/Module/UIModule/UIWindow.cs
index e9558bf4..6c4516c9 100644
--- a/UnityProject/Assets/GameScripts/HotFix/GameLogic/Module/UIModule/UIWindow.cs
+++ b/UnityProject/Assets/GameScripts/HotFix/GameLogic/Module/UIModule/UIWindow.cs
@@ -130,7 +130,7 @@ namespace GameLogic
}
///
- /// 窗口可见性
+ /// 窗口可见性。
///
public bool Visible
{
@@ -174,7 +174,7 @@ namespace GameLogic
}
///
- /// 窗口交互性
+ /// 窗口交互性。
///
private bool Interactable
{
diff --git a/UnityProject/Assets/GameScripts/HotFix/GameLogic/Module/UIModule/WindowAttribute.cs b/UnityProject/Assets/GameScripts/HotFix/GameLogic/Module/UIModule/WindowAttribute.cs
index 957ce835..a5b70f58 100644
--- a/UnityProject/Assets/GameScripts/HotFix/GameLogic/Module/UIModule/WindowAttribute.cs
+++ b/UnityProject/Assets/GameScripts/HotFix/GameLogic/Module/UIModule/WindowAttribute.cs
@@ -14,8 +14,11 @@ namespace GameLogic
System = 4,
}
+ ///
+ /// UI窗口属性。
+ ///
[AttributeUsage(AttributeTargets.Class)]
- public class WindowAttribute : Attribute
+ public class WindowAttribute : Attribute // 用于标记UI窗口,最好完整支持是做成配置表,可以支持货币栏位配置,UI跳转配置等等~
{
///
/// 窗口层级
diff --git a/UnityProject/Assets/TEngine/Runtime/Core/MemoryPool/MemoryPool.MemoryCollection.cs b/UnityProject/Assets/TEngine/Runtime/Core/MemoryPool/MemoryPool.MemoryCollection.cs
index aba4bcf0..2d222e41 100644
--- a/UnityProject/Assets/TEngine/Runtime/Core/MemoryPool/MemoryPool.MemoryCollection.cs
+++ b/UnityProject/Assets/TEngine/Runtime/Core/MemoryPool/MemoryPool.MemoryCollection.cs
@@ -77,7 +77,7 @@ namespace TEngine
}
_addMemoryCount++;
- return (IMemory)Activator.CreateInstance(_memoryType);
+ return (IMemory)EmitHelper.CreateInstance(_memoryType);
}
public void Release(IMemory memory)
@@ -121,7 +121,7 @@ namespace TEngine
_addMemoryCount += count;
while (count-- > 0)
{
- _memories.Enqueue((IMemory)Activator.CreateInstance(_memoryType));
+ _memories.Enqueue((IMemory)EmitHelper.CreateInstance(_memoryType));
}
}
}
diff --git a/UnityProject/Assets/TEngine/Runtime/Core/ModuleSystem.cs b/UnityProject/Assets/TEngine/Runtime/Core/ModuleSystem.cs
index 401590d4..d7eb37e1 100644
--- a/UnityProject/Assets/TEngine/Runtime/Core/ModuleSystem.cs
+++ b/UnityProject/Assets/TEngine/Runtime/Core/ModuleSystem.cs
@@ -106,7 +106,7 @@ namespace TEngine
/// 要创建的游戏框架模块。
private static Module CreateModule(Type moduleType)
{
- Module module = (Module)Activator.CreateInstance(moduleType);
+ Module module = (Module)EmitHelper.CreateInstance(moduleType);
if (module == null)
{
throw new GameFrameworkException(Utility.Text.Format("Can not create module '{0}'.", moduleType.FullName));
diff --git a/UnityProject/Assets/TEngine/Runtime/Core/Utility/EmitHelper.cs b/UnityProject/Assets/TEngine/Runtime/Core/Utility/EmitHelper.cs
new file mode 100644
index 00000000..bf30026b
--- /dev/null
+++ b/UnityProject/Assets/TEngine/Runtime/Core/Utility/EmitHelper.cs
@@ -0,0 +1,193 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+using System.Reflection.Emit;
+
+namespace TEngine
+{
+ public static class EmitHelper
+ {
+ private static readonly Dictionary _defaultCache = new Dictionary();
+
+ private static readonly Dictionary _argCache = new Dictionary();
+
+ public static T CreateInstance() where T : new()
+ {
+ var type = typeof(T);
+
+ if (!_defaultCache.TryGetValue(type, out var factory))
+ {
+ if (!_defaultCache.TryGetValue(type, out factory))
+ {
+ factory = CreateFactory();
+ _defaultCache.TryAdd(type, factory);
+ }
+ }
+
+ return ((Func)factory)();
+ }
+
+ public static object CreateInstance(Type type)
+ {
+ if (!_defaultCache.TryGetValue(type, out var factory))
+ {
+ lock (_defaultCache)
+ {
+ if (!_defaultCache.TryGetValue(type, out factory))
+ {
+ var constructor = type.GetConstructor(
+ BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic,
+ null, Type.EmptyTypes, null);
+
+ if (constructor == null)
+ {
+ throw new MissingMethodException($"No parameterless constructor defined for type '{type.FullName}'");
+ }
+
+ // 创建动态方法(关键优化点)
+ var dynamicMethod = new DynamicMethod(
+ name: $"CreateInstance_{type.FullName}",
+ returnType: typeof(object),
+ parameterTypes: Type.EmptyTypes,
+ owner: typeof(object),
+ skipVisibility: true);
+
+ // 生成IL指令(核心逻辑)
+ var il = dynamicMethod.GetILGenerator();
+
+ // 处理值类型和引用类型的差异
+ if (type.IsValueType)
+ {
+ il.DeclareLocal(type);
+ il.Emit(OpCodes.Ldloca_S, 0);
+ il.Emit(OpCodes.Initobj, type);
+ il.Emit(OpCodes.Ldloc_0);
+ il.Emit(OpCodes.Box, type); // 值类型需要装箱
+ }
+ else
+ {
+ il.Emit(OpCodes.Newobj, constructor);
+ }
+
+ il.Emit(OpCodes.Ret);
+
+ factory = dynamicMethod.CreateDelegate(typeof(Func