Compare commits

..

24 Commits

Author SHA1 Message Date
ALEXTANG
90f84a2764 更新README
更新README
2023-12-20 12:43:39 +08:00
ALEXTANG
6107b41770 修正动态添加/异步添加ui组件的脏数据问题
修正动态添加/异步添加ui组件的脏数据问题
2023-12-19 18:24:33 +08:00
ALEXTANG
1423a3716a 编辑器模式重定向所有热更dll,以防编辑器运行AB时出现两份元数据。
编辑器模式重定向所有热更dll,以防编辑器运行AB时出现两份元数据。
2023-12-18 19:49:46 +08:00
ALEXTANG
6a87db76ee 优化局部单位事件分发器ActorEventDispatcher,EventRegInfo池化
优化局部单位事件分发器ActorEventDispatcher,EventRegInfo池化
2023-12-15 15:11:12 +08:00
ALEXTANG
3a6170dca6 Update UIWidget.cs 2023-12-15 14:25:41 +08:00
ALEXTANG
9d137d613a 修正Utility.Unity注入非Mono的LateUpdate时序问题
修正Utility.Unity注入非Mono的LateUpdate时序问题
2023-12-15 14:15:08 +08:00
ALEXTANG
ba77ec6b45 Update EventInterfaceGenerate.cs 2023-12-14 15:07:04 +08:00
ALEXTANG
b661da68f2 Update EventInterfaceGenerate.cs 2023-12-14 10:12:56 +08:00
ALEXTANGXIAO
e1040110bb 升级拓展GameEvent,支持基于Interface的方法调用抛出事件,以及自动化根据声明的Interface来生成实现代码。
升级拓展GameEvent,支持基于Interface的方法调用抛出事件,以及自动化根据声明的Interface来生成实现代码。
2023-12-13 23:27:54 +08:00
ALEXTANGXIAO
2d53fa1687 升级HybridCLR 4.0.13=>4.0.14
升级HybridCLR 4.0.13=>4.0.14
2023-12-13 19:27:05 +08:00
ALEXTANG
c4ef07f13e Update UnityExtension.cs 2023-12-12 13:00:53 +08:00
ALEXTANG
1f2d99ddc9 修正UIWindow资源句柄时序导致UI同步显示失效的问题。 2023-12-08 10:38:19 +08:00
ALEXTANG
edf4925a7a UIWidget增加Visible设置
UIWidget增加Visible设置
2023-12-07 16:32:54 +08:00
ALEXTANG
5d67238c8f 统一封装对shader的管理和示例。
统一封装对shader的管理和示例。
2023-12-07 10:55:50 +08:00
ALEXTANG
6cfd352482 关闭ResourceCacheMgr测试日志
关闭ResourceCacheMgr测试日志
2023-12-07 10:30:50 +08:00
ALEXTANG
40373c473d 修改通过Tag加载资源对象集合接口。(Operation需要自行管理生命周期释放)
修改通过Tag加载资源对象集合接口。(Operation需要自行管理生命周期释放)
2023-12-07 10:27:17 +08:00
ALEXTANG
d799f9fdf0 优化资源引用类与资源分组类。 2023-12-06 17:57:54 +08:00
ALEXTANG
15735c3d2d 修正循环列表GetItem,增加普通列表组件。 2023-12-06 14:41:31 +08:00
ALEXTANG
818a74f437 释放资源前判断资源合法性 2023-12-06 11:35:33 +08:00
ALEXTANG
f248757401 消除Editor引用隐患
消除Editor引用隐患
2023-12-01 17:41:43 +08:00
ALEXTANG
6ada0e7de7 移除测试日志 2023-12-01 17:18:13 +08:00
ALEXTANG
7ea472f97e 修正日志重定向下层日志跳转功能
修正日志重定向下层日志跳转功能
2023-12-01 10:45:57 +08:00
ALEXTANG
fb8528ff52 音频代理类增加暂停和取消暂停接口。
音频代理类增加暂停和取消暂停接口。
2023-11-30 16:17:35 +08:00
ALEXTANG
e3ac92ef46 修正音频模块回收池
修正音频模块回收池
2023-11-30 15:30:01 +08:00
74 changed files with 1688 additions and 278 deletions

View File

@@ -1,16 +1,16 @@
# TEngine # TEngine
## TEngine-Runtime ## TEngine-Runtime
### AOT内核基于Gameframework,最简化以及商业化适配。 ### AOT内核基于Gameframework,优化、最简化以及商业化适配。
![image](src/2-1.png) ![image](src/2-1.png)
## AOT游戏框架模块基类。 ## AOT游戏框架模块基类。
#### 框架思路为面向接口编程如Resource资源模块开发白皮书为先定义IResourceManager的接口规范然后编写ResourceManager继承框架具体实现(GameFrameworkModule)以及实现接口。最后实现调用层GameFrameworkModuleBase,调用层可以拓展编辑器供开发者自定义模块参数。 #### 框架思路为面向接口编程如Resource资源模块开发白皮书为先定义IResourceManager的接口规范然后编写ResourceManager继承框架具体实现(ModuleImp)以及实现接口。最后实现调用层Module调用层可以拓展编辑器供开发者自定义模块参数。
``` csharp ``` csharp
/// <summary> /// <summary>
/// 游戏框架模块抽象类。GameFrameworkModule为具体框架模块实现。 /// 游戏框架模块抽象类。ModuleImp为具体框架模块实现。
/// </summary> /// </summary>
internal abstract class GameFrameworkModule internal abstract class ModuleImp
{ {
/// <summary> /// <summary>
/// 获取游戏框架模块优先级。 /// 获取游戏框架模块优先级。
@@ -34,16 +34,16 @@ internal abstract class GameFrameworkModule
//=====================================================================// //=====================================================================//
/// <summary> /// <summary>
/// 游戏框架模块抽象类。GameFrameworkModuleBase 为Mono调用层。 /// 游戏框架模块抽象类。Module 为Mono调用层。
/// </summary> /// </summary>
public abstract class GameFrameworkModuleBase : MonoBehaviour public abstract class Module : MonoBehaviour
{ {
/// <summary> /// <summary>
/// 游戏框架模块初始化。 /// 游戏框架模块初始化。
/// </summary> /// </summary>
protected virtual void Awake() protected virtual void Awake()
{ {
GameEntry.RegisterModule(this); ModuleSystem.RegisterModule(this);
} }
} }
``` ```

16
Books/Donate.md Normal file
View File

@@ -0,0 +1,16 @@
## <strong>Buy me a coffee.
您的赞助会让我们做得更快更好如果觉得TEngine对您有帮助不妨赞助我买杯咖啡吧~
<p align="center">
<img src="src/Donate-微信.jpg" alt="logo" width="384" height="562">
</p>
<p align="center">
<img src="src/Donate-支付宝.jpg" alt="logo" width="384" height="562">
</p>

BIN
Books/src/Donate-微信.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 113 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 214 KiB

View File

@@ -46,6 +46,7 @@
* [06_对象池模块](Books/3-4-%E5%AF%B9%E8%B1%A1%E6%B1%A0%E6%A8%A1%E5%9D%97.md): 展示对象池模块概览。 * [06_对象池模块](Books/3-4-%E5%AF%B9%E8%B1%A1%E6%B1%A0%E6%A8%A1%E5%9D%97.md): 展示对象池模块概览。
* [07_配置表模块](Books/3-6-%E9%85%8D%E7%BD%AE%E8%A1%A8%E6%A8%A1%E5%9D%97.md): 展示配置表模块概览。 * [07_配置表模块](Books/3-6-%E9%85%8D%E7%BD%AE%E8%A1%A8%E6%A8%A1%E5%9D%97.md): 展示配置表模块概览。
* [08_流程模块](Books/3-7-%E6%B5%81%E7%A8%8B%E6%A8%A1%E5%9D%97.md): 展示商业化流程模块。 * [08_流程模块](Books/3-7-%E6%B5%81%E7%A8%8B%E6%A8%A1%E5%9D%97.md): 展示商业化流程模块。
* [09_UI模块](Books/3-5-UI模块.md): 展示商业化UI模块。
## <strong>为什么要使用TEngine ## <strong>为什么要使用TEngine
@@ -85,6 +86,11 @@ Assets
└── GameLogic // 游戏业务逻辑程序集 [Dll] └── GameLogic // 游戏业务逻辑程序集 [Dll]
├── GameApp.cs // 热更主入口 ├── GameApp.cs // 热更主入口
└── GameApp_RegisterSystem.cs // 热更主入口注册系统 └── GameApp_RegisterSystem.cs // 热更主入口注册系统
TEngine
├── Editor // TEngine编辑器核心代码
└── Runtime // TEngine运行时核心代码
``` ```
- 必要:项目使用了以下第三方插件,请自行购买导入: - 必要:项目使用了以下第三方插件,请自行购买导入:
@@ -103,3 +109,8 @@ Assets
## <strong>交流群 ## <strong>交流群
### <a href="http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=MzOcQIzGVLQ5AC5LHaqqA3h_F6lZ_DX4&authKey=LctqAWGHkJ7voQvuj1oaSe5tsGrc1XmQG3U4QniieGUlxY3lC7FtDIpEvPOX0vT8&noverify=0&group_code=862987645">群 号862987645 </strong></a> ### <a href="http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=MzOcQIzGVLQ5AC5LHaqqA3h_F6lZ_DX4&authKey=LctqAWGHkJ7voQvuj1oaSe5tsGrc1XmQG3U4QniieGUlxY3lC7FtDIpEvPOX0vT8&noverify=0&group_code=862987645">群 号862987645 </strong></a>
## <strong>Buy me a coffee.
[您的赞助会让我们做得更快更好如果觉得TEngine对您有帮助不妨赞助我买杯咖啡吧~](Books/Donate.md)

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 40a878a415f34e7a855fc4916bbb8e6b
timeCreated: 1702479104

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 1dcaa491f139438dbd963d8bbf0dba85
timeCreated: 1702385397

View File

@@ -0,0 +1,9 @@
using System;
namespace GameLogic
{
[AttributeUsage(AttributeTargets.Class)]
public class BaseAttribute: Attribute
{
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 819c4eaddddd4646a100da2e3f19c3c7
timeCreated: 1702385397

View File

@@ -0,0 +1,75 @@
using System;
using System.Collections.Generic;
using System.Reflection;
namespace GameLogic
{
public class CodeTypes
{
private static CodeTypes _instance;
public static CodeTypes Instance => _instance ??= new CodeTypes();
private readonly Dictionary<string, Type> _allTypes = new();
private readonly UnOrderMultiMapSet<Type, Type> _types = new();
public void Init(Assembly[] assemblies)
{
Dictionary<string, Type> addTypes = GetAssemblyTypes(assemblies);
foreach ((string fullName, Type type) in addTypes)
{
_allTypes[fullName] = type;
if (type.IsAbstract)
{
continue;
}
// 记录所有的有BaseAttribute标记的的类型
object[] objects = type.GetCustomAttributes(typeof(BaseAttribute), true);
foreach (object o in objects)
{
_types.Add(o.GetType(), type);
}
}
}
public HashSet<Type> GetTypes(Type systemAttributeType)
{
if (!_types.ContainsKey(systemAttributeType))
{
return new HashSet<Type>();
}
return _types[systemAttributeType];
}
public Dictionary<string, Type> GetTypes()
{
return _allTypes;
}
public Type GetType(string typeName)
{
return _allTypes[typeName];
}
public static Dictionary<string, Type> GetAssemblyTypes(params Assembly[] args)
{
Dictionary<string, Type> types = new Dictionary<string, Type>();
foreach (Assembly ass in args)
{
foreach (Type type in ass.GetTypes())
{
if (type.FullName != null)
{
types[type.FullName] = type;
}
}
}
return types;
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 01fdfc4515314c579523ac3716005210
timeCreated: 1702385429

View File

@@ -0,0 +1,80 @@
using System.Collections.Generic;
namespace GameLogic
{
public class UnOrderMultiMapSet<TKey, TValue>: Dictionary<TKey, HashSet<TValue>>
{
public new HashSet<TValue> this[TKey t]
{
get
{
HashSet<TValue> set;
if (!TryGetValue(t, out set))
{
set = new HashSet<TValue>();
}
return set;
}
}
public Dictionary<TKey, HashSet<TValue>> GetDictionary()
{
return this;
}
public void Add(TKey t, TValue k)
{
HashSet<TValue> set;
TryGetValue(t, out set);
if (set == null)
{
set = new HashSet<TValue>();
base[t] = set;
}
set.Add(k);
}
public bool Remove(TKey t, TValue k)
{
HashSet<TValue> set;
TryGetValue(t, out set);
if (set == null)
{
return false;
}
if (!set.Remove(k))
{
return false;
}
if (set.Count == 0)
{
Remove(t);
}
return true;
}
public bool Contains(TKey t, TValue k)
{
HashSet<TValue> set;
TryGetValue(t, out set);
if (set == null)
{
return false;
}
return set.Contains(k);
}
public new int Count
{
get
{
int count = 0;
foreach (KeyValuePair<TKey,HashSet<TValue>> kv in this)
{
count += kv.Value.Count;
}
return count;
}
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: b798f0c1317c4caf9ace168f07b51d4f
timeCreated: 1702385485

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 123e7155051957847883c574bf957c7f
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,49 @@
using UnityEngine;
namespace TEngine
{
/// <summary>
/// 封装一个角色可能用到的各种shader场景。
/// </summary>
class ActorShaderGroup
{
private readonly TShader[] _allShader = new TShader[(int)ActorShaderEnvType.EnvTypeMax];
/// <summary>
/// 增加Shader到角色Shader分组。
/// </summary>
/// <param name="shaderType">当前环境类型。</param>
/// <param name="shader">TShader。</param>
public void AddShader(ActorShaderEnvType shaderType, TShader shader)
{
_allShader[(int)shaderType] = shader;
}
/// <summary>
/// 根据当前环境获取Shader。
/// </summary>
/// <param name="type">当前环境类型。</param>
/// <returns>TShader。</returns>
public TShader GetShader(ActorShaderEnvType type)
{
return _allShader[(int)type];
}
/// <summary>
/// 判断是否符合shader集合。
/// </summary>
/// <param name="shader">Shader实例。</param>
/// <returns>是否符合。</returns>
public bool IsMatch(Shader shader)
{
foreach (var dodShader in _allShader)
{
if (dodShader != null && dodShader.Shader == shader)
{
return true;
}
}
return false;
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 79b6e5be73e14c929b6a3b4a980976ac
timeCreated: 1701916950

View File

@@ -0,0 +1,117 @@
using GameBase;
using UnityEngine;
namespace TEngine
{
enum ActorShaderGroupType
{
/// <summary>
/// 通用的角色shader
/// </summary>
Brdf = 0,
/// <summary>
/// 眼睛
/// </summary>
BrdfEye,
///可能后面扩展,比如特效的特殊角色材质
GroupMax,
}
enum ActorShaderEnvType
{
/// <summary>
/// 游戏内场景默认模型不带阴影不带xray不透明效果
/// </summary>
EnvNormal = 0,
/// <summary>
/// 展示场景
/// </summary>
EnvShow,
/// <summary>
/// 带阴影
/// </summary>
EnvShadow,
/// <summary>
/// 带xray默认也带Shadow
/// </summary>
EnvXRay,
/// <summary>
/// 透明渐隐效果
/// </summary>
EnvAlphaFade,
/// <summary>
/// 展示场景没shadow
/// </summary>
EnvShow_NoShadow,
EnvTypeMax
}
/// <summary>
/// 角色Shader管理器。
/// </summary>
class ActorShaderMgr : Singleton<ActorShaderMgr>
{
private readonly ActorShaderGroup[] _allShaderGroup = new ActorShaderGroup[(int)ActorShaderGroupType.GroupMax];
public ActorShaderMgr()
{
CreateBrdfShader();
}
/// <summary>
/// 根据当前Render查找角色的Shader分组。
/// </summary>
/// <param name="render">Render。</param>
/// <returns>角色的Shader分组。</returns>
public ActorShaderGroup FindShaderGroup(Renderer render)
{
var sharedMat = render.sharedMaterial;
if (sharedMat == null)
{
return null;
}
var shader = sharedMat.shader;
foreach (var group in _allShaderGroup)
{
if (group != null && group.IsMatch(shader))
{
return group;
}
}
return null;
}
private void CreateBrdfShader()
{
//通用的效果
var actorShader = new ActorShaderGroup();
actorShader.AddShader(ActorShaderEnvType.EnvNormal, new TShader("TEngine/Actor/ActorBrdf",shaderLocation:"ActorBrdf"));
actorShader.AddShader(ActorShaderEnvType.EnvShow, new TShader("TEngine/Actor/Show/ActorBrdf",shaderLocation:"ActorBrdf_Show"));
actorShader.AddShader(ActorShaderEnvType.EnvShow_NoShadow, new TShader("TEngine/Actor/Show/ActorBrdf_NoShadow",shaderLocation:"ActorBrdf_NoShadow"));
actorShader.AddShader(ActorShaderEnvType.EnvShadow, new TShader("TEngine/Actor/ActorBrdf",shaderLocation:"ActorBrdf_Normal"));
actorShader.AddShader(ActorShaderEnvType.EnvXRay, new TShader("TEngine/Actor/X-Ray",shaderLocation:"X-Ray"));
actorShader.AddShader(ActorShaderEnvType.EnvAlphaFade, new TShader("TEngine/Actor/Fade/ActorBrdf",shaderLocation:"ActorBrdf_Fade"));
_allShaderGroup[(int)ActorShaderGroupType.Brdf] = actorShader;
//眼睛效果
actorShader = new ActorShaderGroup();
actorShader.AddShader(ActorShaderEnvType.EnvNormal, new TShader("TEngine/Actor/ActorEye",shaderLocation:"ActorEye"));
actorShader.AddShader(ActorShaderEnvType.EnvShow, new TShader("TEngine/Actor/Show/ActorEye",shaderLocation:"ActorEye_Show", "MRT_DISABLE", "MRT_ENABLE"));
actorShader.AddShader(ActorShaderEnvType.EnvShadow, new TShader("TEngine/Actor/ActorEye",shaderLocation:"ActorEye"));
actorShader.AddShader(ActorShaderEnvType.EnvXRay, new TShader("TEngine/Actor/ActorEye",shaderLocation:"ActorEye"));
actorShader.AddShader(ActorShaderEnvType.EnvAlphaFade, new TShader("TEngine/Actor/Fade/ActorEye",shaderLocation:"ActorEye_Fade"));
_allShaderGroup[(int)ActorShaderGroupType.BrdfEye] = actorShader;
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 5a38b9b4bee84fabb1ef8db5292a6db6
timeCreated: 1701916853

View File

@@ -0,0 +1,154 @@
using System.Collections.Generic;
using UnityEngine;
namespace TEngine
{
/// <summary>
/// TShader scripts used for all rendering.
/// <remarks>统一封装对shader的管理。</remarks>
/// </summary>
public class TShader
{
private bool _loaded;
private Shader _shader;
private readonly string _shaderName;
private readonly string _shaderLocation;
private readonly List<string> _keywordOn = new List<string>();
private readonly List<string> _keywordOff = new List<string>();
/// <summary>
/// Shader scripts used for all rendering.
/// </summary>
public Shader Shader
{
get
{
if (!_loaded)
{
_loaded = true;
_shader = FindShader(_shaderLocation,_shaderName);
if (_shader == null)
{
Log.Error($"invalid shader path: {_shaderLocation}, shader name {_shaderName}");
}
}
return _shader;
}
}
/// <summary>
/// 查找Shader。
/// </summary>
/// <param name="shaderLocation">Shader定位地址。</param>
/// <param name="shaderName">Shader名称。</param>
/// <returns>Shader实例。</returns>
public static Shader FindShader(string shaderLocation,string shaderName)
{
Shader shader = GameModule.Resource.LoadAsset<Shader>(shaderLocation);
if (shader != null)
{
return shader;
}
return Shader.Find(shaderName);
}
/// <summary>
/// TShader构造函数。
/// </summary>
/// <param name="shaderName">shader名称。</param>
/// <param name="shaderLocation">shader路径。</param>
public TShader(string shaderName, string shaderLocation)
{
_shaderName = shaderName;
_shaderLocation = shaderLocation;
_shader = null;
}
/// <summary>
/// TShader构造函数。
/// </summary>
/// <param name="shaderName">shader名称。</param>
/// <param name="shaderLocation">shader路径。</param>
/// <param name="keywordOn">开启选项。</param>
/// <param name="keywordOff">关闭选项。</param>
public TShader(string shaderName, string shaderLocation, string keywordOn, string keywordOff)
{
_shaderName = shaderName;
_shaderLocation = shaderLocation;
_shader = null;
_keywordOn.Add(keywordOn);
_keywordOff.Add(keywordOff);
}
/// <summary>
/// TShader构造函数。
/// </summary>
/// <param name="shaderName">shader名称。</param>
/// <param name="shaderLocation">shader路径。</param>
/// <param name="keywordOn">开启选项。</param>
/// <param name="keywordOff">关闭选项。</param>
public TShader(string shaderName, string shaderLocation, string[] keywordOn, string[] keywordOff)
{
_shaderName = shaderName;
_shaderLocation = shaderLocation;
_shader = null;
_keywordOn.AddRange(keywordOn);
_keywordOff.AddRange(keywordOff);
}
/// <summary>
/// 设置Shader效果。
/// </summary>
/// <param name="render">渲染对象。</param>
public void ApplyRender(Renderer render)
{
var sharedMat = render.sharedMaterial;
if (sharedMat != null)
{
//copy一份材质
sharedMat = render.material;
sharedMat.shader = Shader;
foreach (var keyword in _keywordOff)
{
sharedMat.DisableKeyword(keyword);
}
foreach (var keyword in _keywordOn)
{
sharedMat.EnableKeyword(keyword);
}
}
}
/// <summary>
/// 清除shader。
/// </summary>
/// <param name="render">渲染对象。</param>
public void ClearRender(Renderer render)
{
if (_keywordOff.Count <= 0 && _keywordOn.Count <= 0)
{
return;
}
var sharedMat = render.sharedMaterial;
if (sharedMat != null)
{
//copy一份材质。
sharedMat = render.material;
for (int k = 0; k < _keywordOn.Count; k++)
{
sharedMat.DisableKeyword(_keywordOn[k]);
}
for (int k = 0; k < _keywordOff.Count; k++)
{
sharedMat.EnableKeyword(_keywordOff[k]);
}
}
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: e219233984c14f7d97bc744c07fe13d0
timeCreated: 1698115491

View File

@@ -9,10 +9,10 @@ namespace GameLogic
/// <summary> /// <summary>
/// UI列表Item /// UI列表Item
/// </summary> /// </summary>
/// <typeparam name="DataT"></typeparam> /// <typeparam name="TData"></typeparam>
public interface IListDataItem<in DataT> public interface IListDataItem<in TData>
{ {
void SetItemData(DataT d); void SetItemData(TData d);
} }
/// <summary> /// <summary>
@@ -180,8 +180,7 @@ namespace GameLogic
/// <param name="n"></param> /// <param name="n"></param>
public void SetDatas(List<DataT> dataList, int n = -1) public void SetDatas(List<DataT> dataList, int n = -1)
{ {
AdjustItemNum(Mathf.Max(0, n >= 0 ? n : (dataList == null ? 0 : (dataList.Count - dataStartOffset))), AdjustItemNum(Mathf.Max(0, n >= 0 ? n : (dataList == null ? 0 : (dataList.Count - dataStartOffset))), dataList);
dataList);
} }
/// <summary> /// <summary>
@@ -215,8 +214,7 @@ namespace GameLogic
return; return;
} }
var listDataItem = item as IListDataItem<DataT>; if (item is IListDataItem<DataT> listDataItem)
if (listDataItem != null)
{ {
listDataItem.SetItemData(GetData(i)); listDataItem.SetItemData(GetData(i));
} }
@@ -271,8 +269,7 @@ namespace GameLogic
var preIndex = selectIndex; var preIndex = selectIndex;
m_selectIndex = i; m_selectIndex = i;
var item = GetItem(preIndex) as IListSelectItem; if (GetItem(preIndex) is IListSelectItem item)
if (item != null)
{ {
item.SetSelected(false); item.SetSelected(false);
} }
@@ -282,13 +279,20 @@ namespace GameLogic
{ {
item.SetSelected(true); item.SetSelected(true);
} }
UpdateSnapTargetItem();
if (triggerEvt && funcOnSelectChange != null) if (triggerEvt && funcOnSelectChange != null)
{ {
funcOnSelectChange.Invoke(); funcOnSelectChange.Invoke();
} }
} }
/// <summary>
/// 刷新Snap
/// </summary>
protected virtual void UpdateSnapTargetItem()
{
}
/// <summary> /// <summary>
/// 获取当前选中的数据 /// 获取当前选中的数据
/// </summary> /// </summary>
@@ -312,13 +316,18 @@ namespace GameLogic
/// <summary> /// <summary>
/// 获取item /// 获取item
/// </summary> /// </summary>
/// <param name="index"></param> /// <param name="i"></param>
/// <returns></returns> /// <returns></returns>
public virtual ItemT GetItem(int index) public virtual ItemT GetItem(int i)
{ {
return null; return null;
} }
/// <summary>
/// 点击选择
/// </summary>
public bool SelectByClick = true;
/// <summary> /// <summary>
/// item被点击 /// item被点击
/// </summary> /// </summary>
@@ -331,7 +340,10 @@ namespace GameLogic
funcOnItemClick.Invoke(i); funcOnItemClick.Invoke(i);
} }
selectIndex = i; if (SelectByClick)
{
selectIndex = i;
}
} }
} }
} }

View File

@@ -0,0 +1,57 @@
using System;
using System.Collections.Generic;
using TEngine;
namespace GameLogic
{
/// <summary>
/// 普通UI列表。
/// </summary>
public class UIListWidget<TItem, TData> : UIListBase<TItem, TData> where TItem : UIWidget, new()
{
/// <summary>
/// item列表。
/// </summary>
protected List<TItem> m_items = new List<TItem>();
/// <summary>
/// item列表。
/// </summary>
public List<TItem> items => m_items;
/// <summary>
/// 设置显示数据。
/// </summary>
/// <param name="n"></param>
/// <param name="datas"></param>
/// <param name="funcItem"></param>
protected override void AdjustItemNum(int n, List<TData> datas = null, Action<TItem, int> funcItem = null)
{
base.AdjustItemNum(n, datas, funcItem);
AdjustIconNum(m_items, n, gameObject.transform, itemBase);
UpdateList(funcItem);
}
/// <summary>
/// 刷新列表。
/// </summary>
/// <param name="funcItem"></param>
protected void UpdateList(Action<TItem, int> funcItem = null)
{
for (var i = 0; i < m_items.Count; i++)
{
UpdateListItem(m_items[i], i, funcItem);
}
}
/// <summary>
/// 获取item
/// </summary>
/// <param name="i"></param>
/// <returns></returns>
public override TItem GetItem(int i)
{
return i >= 0 && i < m_items.Count ? m_items[i] : null;
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 96f732d895e94fbc99c904d66ca844ca
timeCreated: 1701844130

View File

@@ -66,6 +66,7 @@ namespace GameLogic
LoopRectView.SetListItemCount(n); LoopRectView.SetListItemCount(n);
LoopRectView.RefreshAllShownItem(); LoopRectView.RefreshAllShownItem();
m_tpFuncItem = null; m_tpFuncItem = null;
UpdateAllItemSelect();
} }
/// <summary> /// <summary>
@@ -145,14 +146,23 @@ namespace GameLogic
return widget; return widget;
} }
/// <summary> /// <summary>
/// 获取item /// 获取item
/// </summary> /// </summary>
/// <param name="index"></param> /// <param name="index"></param>
/// <returns></returns> /// <returns></returns>
public override TItem GetItem(int index) public override TItem GetItem(int index)
{ {
return index >= 0 && index < m_itemCache.Count ? m_itemCache.GetValueByIndex(index) : null; for (var i = 0; i < m_itemCache.Count; i++)
{
var item = m_itemCache.GetValueByIndex(i);
if (item.GetItemIndex() == index)
{
return item;
}
}
return null;
} }
/// <summary> /// <summary>
@@ -178,5 +188,21 @@ namespace GameLogic
{ {
return m_itemCache.GetValueByIndex(index); return m_itemCache.GetValueByIndex(index);
} }
/// <summary>
/// 刷新所有item选中状态
/// </summary>
/// <returns></returns>
public void UpdateAllItemSelect()
{
var index = selectIndex;
for (var i = 0; i < m_itemCache.Count; i++)
{
if (m_itemCache.GetValueByIndex(i) is IListSelectItem item)
{
item.SetSelected(item.GetItemIndex() == index);
}
}
}
} }
} }

View File

@@ -65,8 +65,9 @@ namespace GameLogic
base.AdjustItemNum(n, datas, funcItem); base.AdjustItemNum(n, datas, funcItem);
m_tpFuncItem = funcItem; m_tpFuncItem = funcItem;
LoopRectView.SetListItemCount(n); LoopRectView.SetListItemCount(n);
// LoopRectView.RefreshAllShownItem(); LoopRectView.RefreshAllShownItem();
m_tpFuncItem = null; m_tpFuncItem = null;
UpdateAllItemSelect();
} }
/// <summary> /// <summary>
@@ -151,7 +152,16 @@ namespace GameLogic
/// <returns></returns> /// <returns></returns>
public override TItem GetItem(int index) public override TItem GetItem(int index)
{ {
return index >= 0 && index < m_itemCache.Count ? m_itemCache.GetValueByIndex(index) : null; for (var i = 0; i < m_itemCache.Count; i++)
{
var item = m_itemCache.GetValueByIndex(i);
if (item.GetItemIndex() == index)
{
return item;
}
}
return null;
} }
/// <summary> /// <summary>
@@ -186,5 +196,30 @@ namespace GameLogic
{ {
return m_itemCache.GetValueByIndex(index); return m_itemCache.GetValueByIndex(index);
} }
/// <summary>
/// 刷新所有item选中状态
/// </summary>
/// <returns></returns>
public void UpdateAllItemSelect()
{
var index = selectIndex;
for (var i = 0; i < m_itemCache.Count; i++)
{
if (m_itemCache.GetValueByIndex(i) is IListSelectItem item)
{
item.SetSelected(item.GetItemIndex() == index);
}
}
}
protected override void UpdateSnapTargetItem()
{
base.UpdateSnapTargetItem();
if (LoopRectView != null && LoopRectView.ItemSnapEnable)
{
LoopRectView.SetSnapTargetItemIndex(selectIndex);
}
}
} }
} }

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: d1f693ff76ae490fbe194855d94e8266
timeCreated: 1702479172

View File

@@ -0,0 +1,20 @@
using System;
using TEngine;
namespace GameLogic
{
/// <summary>
/// 事件接口帮助类。
/// </summary>
internal class EventInterfaceHelper
{
/// <summary>
/// 初始化。
/// </summary>
public static void Init()
{
RegisterEventInterface_Logic.Register(GameEvent.EventMgr);
RegisterEventInterface_UI.Register(GameEvent.EventMgr);
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 9afaf331ee7249adb5cc0953dfd3413c
timeCreated: 1702379658

View File

@@ -0,0 +1,16 @@
using TEngine;
namespace GameLogic
{
[System.AttributeUsage(System.AttributeTargets.Class)]
internal class EventInterfaceImpAttribute : BaseAttribute
{
private EEventGroup _eGroup;
public EEventGroup EventGroup => _eGroup;
public EventInterfaceImpAttribute(EEventGroup group)
{
_eGroup = group;
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 8bbf40942b0e4470bb8d8a82577f713c
timeCreated: 1702479403

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: de49bf2e9f0a4fac85851a582e2fb4ed
timeCreated: 1702379835

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: bff68b49afffbe54b9d5ff4e4cad4f23
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,70 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by autoBindTool.
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
using UnityEngine;
using UnityEngine.UI;
using TEngine;
namespace GameLogic
{
public partial class IActorLogicEvent_Event
{
public static readonly int OnMainPlayerDataChange = RuntimeId.ToRuntimeId("IActorLogicEvent_Event.OnMainPlayerDataChange");
public static readonly int OnMainPlayerLevelChange = RuntimeId.ToRuntimeId("IActorLogicEvent_Event.OnMainPlayerLevelChange");
public static readonly int OnMainPlayerGoldChange = RuntimeId.ToRuntimeId("IActorLogicEvent_Event.OnMainPlayerGoldChange");
public static readonly int OnMainPlayerDiamondChange = RuntimeId.ToRuntimeId("IActorLogicEvent_Event.OnMainPlayerDiamondChange");
public static readonly int OnMainPlayerBindDiamondChange = RuntimeId.ToRuntimeId("IActorLogicEvent_Event.OnMainPlayerBindDiamondChange");
public static readonly int OnMainPlayerCurrencyChange = RuntimeId.ToRuntimeId("IActorLogicEvent_Event.OnMainPlayerCurrencyChange");
public static readonly int OnMainPlayerExpChange = RuntimeId.ToRuntimeId("IActorLogicEvent_Event.OnMainPlayerExpChange");
}
[EventInterfaceImp(EEventGroup.GroupLogic)]
public partial class IActorLogicEvent_Gen : IActorLogicEvent
{
private EventDispatcher _dispatcher;
public IActorLogicEvent_Gen(EventDispatcher dispatcher)
{
_dispatcher = dispatcher;
}
public void OnMainPlayerDataChange()
{
_dispatcher.Send(IActorLogicEvent_Event.OnMainPlayerDataChange);
}
public void OnMainPlayerLevelChange()
{
_dispatcher.Send(IActorLogicEvent_Event.OnMainPlayerLevelChange);
}
public void OnMainPlayerGoldChange(System.UInt32 oldVal,System.UInt32 newVal)
{
_dispatcher.Send(IActorLogicEvent_Event.OnMainPlayerGoldChange,oldVal,newVal);
}
public void OnMainPlayerDiamondChange(System.UInt32 oldVal,System.UInt32 newVal)
{
_dispatcher.Send(IActorLogicEvent_Event.OnMainPlayerDiamondChange,oldVal,newVal);
}
public void OnMainPlayerBindDiamondChange(System.UInt32 oldVal,System.UInt32 newVal)
{
_dispatcher.Send(IActorLogicEvent_Event.OnMainPlayerBindDiamondChange,oldVal,newVal);
}
public void OnMainPlayerCurrencyChange(GameLogic.CurrencyType type,System.UInt32 oldVal,System.UInt32 newVal)
{
_dispatcher.Send(IActorLogicEvent_Event.OnMainPlayerCurrencyChange,type,oldVal,newVal);
}
public void OnMainPlayerExpChange(System.UInt64 oldVal,System.UInt64 newVal)
{
_dispatcher.Send(IActorLogicEvent_Event.OnMainPlayerExpChange,oldVal,newVal);
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 12d7d4edd7d06bc4286ea4af153380c6
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 615ca01c7a524654c91935631f39f570
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,40 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by autoBindTool.
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
using UnityEngine;
using UnityEngine.UI;
using TEngine;
namespace GameLogic
{
public partial class ILoginUI_Event
{
public static readonly int OnRoleLogin = RuntimeId.ToRuntimeId("ILoginUI_Event.OnRoleLogin");
public static readonly int OnRoleLoginOut = RuntimeId.ToRuntimeId("ILoginUI_Event.OnRoleLoginOut");
}
[EventInterfaceImp(EEventGroup.GroupUI)]
public partial class ILoginUI_Gen : ILoginUI
{
private EventDispatcher _dispatcher;
public ILoginUI_Gen(EventDispatcher dispatcher)
{
_dispatcher = dispatcher;
}
public void OnRoleLogin(System.Boolean isReconnect)
{
_dispatcher.Send(ILoginUI_Event.OnRoleLogin,isReconnect);
}
public void OnRoleLoginOut()
{
_dispatcher.Send(ILoginUI_Event.OnRoleLoginOut);
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: bde7ed0ea10cf29448370b39ecd69a97
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 7cf3381dedbf4daeb53e710a5c544204
timeCreated: 1702433587

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 610229edeca4417685ffd07f18b2b9f1
timeCreated: 1702379817

View File

@@ -0,0 +1,38 @@
using System;
using TEngine;
namespace GameLogic
{
/// <summary>
/// 示例货币枚举。
/// </summary>
public enum CurrencyType
{
None,
Gold,
Diamond,
}
/// <summary>
/// 示意逻辑层事件。
/// <remarks> 优化抛出事件,通过接口约束事件参数。</remarks>
/// <remarks> example: GameEvent.Get<IActorLogicEvent>().OnMainPlayerCurrencyChange(CurrencyType.Gold,oldVal,newVal); </remarks>
/// </summary>
[EventInterface(EEventGroup.GroupLogic)]
interface IActorLogicEvent
{
void OnMainPlayerDataChange();
void OnMainPlayerLevelChange();
void OnMainPlayerGoldChange(uint oldVal, uint newVal);
void OnMainPlayerDiamondChange(uint oldVal, uint newVal);
void OnMainPlayerBindDiamondChange(uint oldVal, uint newVal);
void OnMainPlayerCurrencyChange(CurrencyType type, uint oldVal, uint newVal);
void OnMainPlayerExpChange(ulong oldVal, ulong newVal);
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 8d4558cb74e8462a86f0ee3461f6b7c9
timeCreated: 1702383645

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 90e13cc92c5d42f28b4f5fab599f472a
timeCreated: 1702379805

View File

@@ -0,0 +1,17 @@
using TEngine;
namespace GameLogic
{
/// <summary>
/// 示意UI层事件。
/// <remarks> 优化抛出事件,通过接口约束事件参数。</remarks>
/// <remarks> example: GameEvent.Get<ILoginUI>().OnRoleLogin(isReconnect); </remarks>
/// </summary>
[EventInterface(EEventGroup.GroupUI)]
public interface ILoginUI
{
public void OnRoleLogin(bool isReconnect);
public void OnRoleLoginOut();
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 33b45e62bd3447498acfe874017b9a35
timeCreated: 1702433755

View File

@@ -0,0 +1,41 @@
using System;
using System.Collections.Generic;
using TEngine;
namespace GameLogic
{
/// <summary>
/// 逻辑层事件接口。
/// </summary>
internal class RegisterEventInterface_Logic
{
/// <summary>
/// 注册逻辑层事件接口。
/// </summary>
/// <param name="mgr">事件管理器。</param>
public static void Register(EventMgr mgr)
{
HashSet<Type> types = CodeTypes.Instance.GetTypes(typeof(EventInterfaceImpAttribute));
foreach (Type type in types)
{
object[] attrs = type.GetCustomAttributes(typeof(EventInterfaceImpAttribute), false);
if (attrs.Length == 0)
{
continue;
}
EventInterfaceImpAttribute httpHandlerAttribute = (EventInterfaceImpAttribute)attrs[0];
if (httpHandlerAttribute.EventGroup != EEventGroup.GroupLogic)
{
continue;
}
object obj = Activator.CreateInstance(type, mgr.Dispatcher);
mgr.RegWrapInterface(obj.GetType().GetInterfaces()[0]?.FullName, obj);
}
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: b8bdf6c139b44758aa16db2e1837f5d9
timeCreated: 1702379518

View File

@@ -0,0 +1,41 @@
using System;
using System.Collections.Generic;
using TEngine;
namespace GameLogic
{
/// <summary>
/// UI层事件接口。
/// </summary>
internal class RegisterEventInterface_UI
{
/// <summary>
/// 注册UI层事件接口。
/// </summary>
/// <param name="mgr">事件管理器。</param>
public static void Register(EventMgr mgr)
{
HashSet<Type> types = CodeTypes.Instance.GetTypes(typeof(EventInterfaceImpAttribute));
foreach (Type type in types)
{
object[] attrs = type.GetCustomAttributes(typeof(EventInterfaceImpAttribute), false);
if (attrs.Length == 0)
{
continue;
}
EventInterfaceImpAttribute httpHandlerAttribute = (EventInterfaceImpAttribute)attrs[0];
if (httpHandlerAttribute.EventGroup != EEventGroup.GroupUI)
{
continue;
}
object obj = Activator.CreateInstance(type, mgr.Dispatcher);
mgr.RegWrapInterface(obj.GetType().GetInterfaces()[0]?.FullName, obj);
}
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: f53b67f2cfbe4912bffee9593cd60970
timeCreated: 1702379505

View File

@@ -1,4 +1,5 @@
using System.Collections.Generic; using System.Collections.Generic;
using GameLogic;
using TEngine; using TEngine;
using UnityEngine; using UnityEngine;
@@ -8,6 +9,8 @@ public partial class GameApp
private void Init() private void Init()
{ {
CodeTypes.Instance.Init(_hotfixAssembly.ToArray());
EventInterfaceHelper.Init();
_listLogicMgr = new List<ILogicSys>(); _listLogicMgr = new List<ILogicSys>();
RegisterAllSystem(); RegisterAllSystem();
InitSystemSetting(); InitSystemSetting();

View File

@@ -116,8 +116,7 @@ namespace GameMain
{ {
ChangeState<ProcedureStartGame>(m_procedureOwner); ChangeState<ProcedureStartGame>(m_procedureOwner);
#if UNITY_EDITOR #if UNITY_EDITOR
m_MainLogicAssembly = AppDomain.CurrentDomain.GetAssemblies(). m_MainLogicAssembly = GetMainLogicAssembly();
First(assembly => $"{assembly.GetName().Name}.dll" == SettingsUtils.HybridCLRCustomGlobalSettings.LogicMainDllName);
#endif #endif
if (m_MainLogicAssembly == null) if (m_MainLogicAssembly == null)
{ {

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 86094b7c7ca31ab4da174cc7eae14a3c
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,227 @@
#region Class Documentation
/************************************************************************************************************
Class Name: EventInterfaceGenerate.cs
Type: Editor, Generator, Util, Static
Definition:
用法,在目录"Assets/GameScripts/HotFix/GameLogic/Event/Interface/"下分组照示例声明Interface 模块待抛出事件的接口。编译后自动生成接口实现抛出的脚本。
Example:
旧版抛出事件方式: GameEvent.Send(RuntimeId.ToRuntimeId("OnMainPlayerCurrencyChange"),CurrencyType.Gold,oldVal,newVal);
新版抛出事件方式 GameEvent.Get<IActorLogicEvent>().OnMainPlayerCurrencyChange(CurrencyType.Gold,oldVal,newVal);
************************************************************************************************************/
#endregion
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using TEngine;
using Unity.EditorCoroutines.Editor;
using UnityEditor;
using UnityEngine;
[InitializeOnLoad]
public static class EventInterfaceGenerate
{
public static string NameSpace = @"GameLogic";
public const string EventInterfacePath = "Assets/GameScripts/HotFix/GameLogic/Event/Interface/";
public static bool BOpenAutoGenerate = false;
static EventInterfaceGenerate()
{
BOpenAutoGenerate = EditorPrefs.GetBool("EventInterfaceGenerate.BOpenAutoGenerate", true);
if (BOpenAutoGenerate)
{
Generate();
}
}
[MenuItem("TEngine/EventInterface/OpenAutoGenerate", false, 300)]
public static void OpenAutoGenerate()
{
EditorPrefs.SetBool("EventInterfaceGenerate.BOpenAutoGenerate", true);
Debug.Log("OpenAutoGenerate");
}
[MenuItem("TEngine/EventInterface/CloseAutoGenerate", false, 301)]
public static void CloseAutoGenerate()
{
EditorPrefs.SetBool("EventInterfaceGenerate.BOpenAutoGenerate", false);
Debug.Log("CloseAutoGenerate");
}
[MenuItem("TEngine/EventInterface/Generate EventInterface", false, 302)]
public static void Generate()
{
if (EventInterfaceGenerateTag.HadGenerate)
{
return;
}
EventInterfaceGenerateTag.HadGenerate = true;
// 加载程序集
Assembly assembly = typeof(GameApp).Assembly;
// 获取程序集中的所有类型
Type[] types = assembly.GetTypes();
// 遍历每个类型
foreach (Type type in types)
{
// 检查类型是否是接口
if (!type.IsInterface)
{
continue;
}
var attribute = type.GetCustomAttributes(typeof(EventInterfaceAttribute), false).FirstOrDefault();
if (attribute != null)
{
EventInterfaceAttribute eventInterfaceAttribute = attribute as EventInterfaceAttribute;
GenAutoBindCode(type, eventInterfaceAttribute);
}
}
AssetDatabase.Refresh();
Debug.Log("Generate EventInterface Complete");
// EditorUtility.DisplayDialog("提示", "代码生成完毕", "OK");
EditorCoroutineUtility.StartCoroutine(EventInterfaceGenerateTag.Reset(), null);
}
/// <summary>
/// 生成自动绑定代码
/// </summary>
private static void GenAutoBindCode(Type interfaceType, EventInterfaceAttribute eventInterfaceAttribute)
{
string interfaceName = interfaceType.Name;
string className = $"{interfaceName}_Gen";
string codePath = $"{Application.dataPath}/GameScripts/HotFix/GameLogic/Event/Gen/{eventInterfaceAttribute.EventGroup}";
if (!Directory.Exists(codePath))
{
Directory.CreateDirectory(codePath);
}
using (StreamWriter sw = new StreamWriter($"{codePath}/{className}.cs"))
{
sw.WriteLine(
$"//------------------------------------------------------------------------------\n//\t<auto-generated>\n//\t\tThis code was generated by autoBindTool.\n//\t\tChanges to this file may cause incorrect behavior and will be lost if\n//\t\tthe code is regenerated.\n//\t</auto-generated>\n//------------------------------------------------------------------------------");
sw.WriteLine("using UnityEngine;");
sw.WriteLine("using UnityEngine.UI;");
sw.WriteLine("using TEngine;");
sw.WriteLine("");
if (!string.IsNullOrEmpty(NameSpace))
{
//命名空间
sw.WriteLine("namespace " + NameSpace);
sw.WriteLine("{");
}
#region EventId生成
sw.WriteLine($"\tpublic partial class {interfaceName}_Event");
sw.WriteLine("\t{");
// 获取接口中的所有方法
MethodInfo[] methods = interfaceType.GetMethods();
HashSet<string> hadGenerate = new HashSet<string>();
//组件字段
foreach (MethodInfo method in methods)
{
if (hadGenerate.Contains(method.Name))
{
continue;
}
sw.WriteLine($"\t\tpublic static readonly int {method.Name} = RuntimeId.ToRuntimeId(\"{interfaceName}_Event.{method.Name}\");");
hadGenerate.Add(method.Name);
}
sw.WriteLine("\t}");
sw.WriteLine("");
#endregion
//类名
sw.WriteLine($"\t[EventInterfaceImp(EEventGroup.{eventInterfaceAttribute.EventGroup})]");
sw.WriteLine($"\tpublic partial class {className} : {interfaceName}");
sw.WriteLine("\t{");
sw.WriteLine("\t\tprivate EventDispatcher _dispatcher;");
sw.WriteLine($"\t\tpublic {className}(EventDispatcher dispatcher)");
sw.WriteLine("\t\t{");
sw.WriteLine($"\t\t\t_dispatcher = dispatcher;");
sw.WriteLine("\t\t}");
sw.WriteLine("");
//组件字段
foreach (MethodInfo methodInfo in methods)
{
ParameterInfo[] parameterInfos = methodInfo.GetParameters(); //得到指定方法的参数列表
if (parameterInfos.Length <= 0)
{
sw.WriteLine(
$" public void {methodInfo.Name}()\n {{\n _dispatcher.Send({interfaceName}_Event.{methodInfo.Name});\n }}");
}
else
{
string paramStr = "";
string paramStr2 = "";
for (int i = 0; i < parameterInfos.Length; i++)
{
var parameterInfo = parameterInfos[i];
Type type = parameterInfo.ParameterType;
string paramName = parameterInfo.Name;
if (i == parameterInfos.Length - 1)
{
paramStr += $"{type.FullName} {paramName}";
paramStr2 += $"{paramName}";
}
else
{
paramStr += $"{type.FullName} {paramName},";
paramStr2 += $"{paramName},";
}
}
sw.WriteLine(
$" public void {methodInfo.Name}({paramStr})\n {{\n _dispatcher.Send({interfaceName}_Event.{methodInfo.Name},{paramStr2});\n }}");
}
sw.WriteLine("");
}
sw.WriteLine("\t}");
if (!string.IsNullOrEmpty(NameSpace))
{
sw.WriteLine("}");
}
}
}
}
public static class EventInterfaceGenerateTag
{
public static bool HadGenerate = false;
public static IEnumerator Reset()
{
yield return new WaitForSeconds(10f);
HadGenerate = false;
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 3e3af172e88343e4cb49c9e870518ede
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -5,7 +5,9 @@
"GUID:24c092aee38482f4e80715eaa8148782", "GUID:24c092aee38482f4e80715eaa8148782",
"GUID:e34a5702dd353724aa315fb8011f08c3", "GUID:e34a5702dd353724aa315fb8011f08c3",
"GUID:4d1926c9df5b052469a1c63448b7609a", "GUID:4d1926c9df5b052469a1c63448b7609a",
"GUID:2373f786d14518f44b0f475db77ba4de" "GUID:2373f786d14518f44b0f475db77ba4de",
"GUID:6e76b07590314a543b982daed6af2509",
"GUID:478a2357cc57436488a56e564b08d223"
], ],
"includePlatforms": [ "includePlatforms": [
"Editor" "Editor"

View File

@@ -19,6 +19,21 @@ namespace TEngine.Editor
{ {
return false; return false;
} }
// 获取资源路径
string assetPath = AssetDatabase.GetAssetPath(instanceID);
// 判断资源类型
if (!assetPath.EndsWith(".cs"))
{
return false;
}
bool autoFirstMatch = assetPath.Contains("Logger.cs") ||
assetPath.Contains("DefaultLogHelper.cs") ||
assetPath.Contains("GameFrameworkLog.cs") ||
assetPath.Contains("AssetsLogger.cs") ||
assetPath.Contains("Log.cs");
var stackTrace = GetStackTrace(); var stackTrace = GetStackTrace();
if (!string.IsNullOrEmpty(stackTrace) && (stackTrace.Contains("[Debug]") || if (!string.IsNullOrEmpty(stackTrace) && (stackTrace.Contains("[Debug]") ||
stackTrace.Contains("[INFO]") || stackTrace.Contains("[INFO]") ||
@@ -28,6 +43,15 @@ namespace TEngine.Editor
stackTrace.Contains("[EXCEPTION]"))) stackTrace.Contains("[EXCEPTION]")))
{ {
if (!autoFirstMatch)
{
var fullPath = UnityEngine.Application.dataPath.Substring(0, UnityEngine.Application.dataPath.LastIndexOf("Assets", StringComparison.Ordinal));
fullPath = $"{fullPath}{assetPath}";
// 跳转到目标代码的特定行
InternalEditorUtility.OpenFileAtLineExternal(fullPath.Replace('/', '\\'), line);
return true;
}
// 使用正则表达式匹配at的哪个脚本的哪一行 // 使用正则表达式匹配at的哪个脚本的哪一行
var matches = Regex.Match(stackTrace, @"\(at (.+)\)", var matches = Regex.Match(stackTrace, @"\(at (.+)\)",
RegexOptions.IgnoreCase); RegexOptions.IgnoreCase);

View File

@@ -60,6 +60,11 @@ namespace TEngine
while (itr.MoveNext()) while (itr.MoveNext())
{ {
var kv = itr.Current; var kv = itr.Current;
List<EventRegInfo> list = kv.Value;
foreach (var eventRegInfo in list)
{
EventRegInfo.Release(eventRegInfo);
}
kv.Value.Clear(); kv.Value.Clear();
} }
@@ -97,6 +102,7 @@ namespace TEngine
{ {
Log.Info("remove delay delete eventId[{0}]", eventId); Log.Info("remove delay delete eventId[{0}]", eventId);
listListener[i] = listListener[^1]; listListener[i] = listListener[^1];
EventRegInfo.Release(listListener[i]);
listListener.RemoveAt(listListener.Count - 1); listListener.RemoveAt(listListener.Count - 1);
i--; i--;
} }
@@ -437,7 +443,7 @@ namespace TEngine
return; return;
} }
listListener.Add(new EventRegInfo(listener, owner)); listListener.Add(EventRegInfo.Alloc(listener, owner));
} }
/// <summary> /// <summary>
@@ -469,6 +475,7 @@ namespace TEngine
else else
{ {
list[i] = list[^1]; list[i] = list[^1];
EventRegInfo.Release(list[i]);
list.RemoveAt(list.Count - 1); list.RemoveAt(list.Count - 1);
i--; i--;
} }
@@ -587,17 +594,17 @@ namespace TEngine
/// <summary> /// <summary>
/// 事件注册信息。 /// 事件注册信息。
/// </summary> /// </summary>
public class EventRegInfo public class EventRegInfo : IMemory
{ {
/// <summary> /// <summary>
/// 事件回调。 /// 事件回调。
/// </summary> /// </summary>
public readonly Delegate Callback; public Delegate Callback;
/// <summary> /// <summary>
/// 事件持有者。 /// 事件持有者。
/// </summary> /// </summary>
public readonly object Owner; public object Owner;
/// <summary> /// <summary>
/// 事件是否删除。 /// 事件是否删除。
@@ -610,5 +617,28 @@ namespace TEngine
Owner = owner; Owner = owner;
IsDeleted = false; IsDeleted = false;
} }
public EventRegInfo() { }
public void Clear()
{
Callback = null;
Owner = null;
IsDeleted = false;
}
public static EventRegInfo Alloc(Delegate callback, object owner)
{
EventRegInfo ret = MemoryPool.Acquire<EventRegInfo>();
ret.Callback = callback;
ret.Owner = owner;
ret.IsDeleted = false;
return ret;
}
public static void Release(EventRegInfo eventRegInfo)
{
MemoryPool.Release(eventRegInfo);
}
} }
} }

View File

@@ -19,10 +19,11 @@ namespace TEngine
} }
[System.AttributeUsage(System.AttributeTargets.Interface)] [System.AttributeUsage(System.AttributeTargets.Interface)]
public class EventInterface : Attribute public class EventInterfaceAttribute : Attribute
{ {
private EEventGroup _eGroup; private EEventGroup _eGroup;
public EventInterface(EEventGroup group) public EEventGroup EventGroup => _eGroup;
public EventInterfaceAttribute(EEventGroup group)
{ {
_eGroup = group; _eGroup = group;
} }

View File

@@ -51,6 +51,21 @@ namespace TEngine
} }
} }
/// <summary>
/// 注册wrap的函数。
/// </summary>
/// <param name="typeName">类型名称。</param>
/// <param name="callerWrap">调用接口名。</param>
public void RegWrapInterface(string typeName,object callerWrap)
{
var entry = new EventEntryData();
entry.InterfaceWrap = callerWrap;
if (typeName != null)
{
_eventEntryMap.Add(typeName, entry);
}
}
/// <summary> /// <summary>
/// 分发注册器。 /// 分发注册器。
/// </summary> /// </summary>

View File

@@ -12,6 +12,7 @@ namespace TEngine
/// </summary> /// </summary>
private static readonly EventMgr _eventMgr = new EventMgr(); private static readonly EventMgr _eventMgr = new EventMgr();
public static EventMgr EventMgr => _eventMgr;
#region #region
/// <summary> /// <summary>

View File

@@ -1,7 +1,9 @@
using System; using System;
using System.IO; using System.IO;
using System.Text; using System.Text;
#if UNITY_EDITOR
using UnityEditor; using UnityEditor;
#endif
using UnityEngine; using UnityEngine;
namespace TEngine namespace TEngine

View File

@@ -1,4 +1,5 @@
using System.Collections; using System.Collections;
using Cysharp.Threading.Tasks;
using UnityEngine; using UnityEngine;
using UnityEngine.Events; using UnityEngine.Events;
using UnityEngine.Internal; using UnityEngine.Internal;
@@ -108,6 +109,12 @@ namespace TEngine
public static void AddUpdateListener(UnityAction fun) public static void AddUpdateListener(UnityAction fun)
{ {
_MakeEntity(); _MakeEntity();
AddUpdateListenerImp(fun).Forget();
}
private static async UniTaskVoid AddUpdateListenerImp(UnityAction fun)
{
await UniTask.Yield(/*PlayerLoopTiming.LastPreUpdate*/);
_behaviour.AddUpdateListener(fun); _behaviour.AddUpdateListener(fun);
} }
@@ -118,6 +125,12 @@ namespace TEngine
public static void AddFixedUpdateListener(UnityAction fun) public static void AddFixedUpdateListener(UnityAction fun)
{ {
_MakeEntity(); _MakeEntity();
AddFixedUpdateListenerImp(fun).Forget();
}
private static async UniTaskVoid AddFixedUpdateListenerImp(UnityAction fun)
{
await UniTask.Yield(PlayerLoopTiming.LastEarlyUpdate);
_behaviour.AddFixedUpdateListener(fun); _behaviour.AddFixedUpdateListener(fun);
} }
@@ -128,6 +141,12 @@ namespace TEngine
public static void AddLateUpdateListener(UnityAction fun) public static void AddLateUpdateListener(UnityAction fun)
{ {
_MakeEntity(); _MakeEntity();
AddLateUpdateListenerImp(fun).Forget();
}
private static async UniTaskVoid AddLateUpdateListenerImp(UnityAction fun)
{
await UniTask.Yield(/*PlayerLoopTiming.LastPreLateUpdate*/);
_behaviour.AddLateUpdateListener(fun); _behaviour.AddLateUpdateListener(fun);
} }

View File

@@ -134,8 +134,9 @@ namespace TEngine
/// <param name="isSetNativeSize">是否使用原生分辨率。</param> /// <param name="isSetNativeSize">是否使用原生分辨率。</param>
/// <param name="isAsync">是否使用异步加载。</param> /// <param name="isAsync">是否使用异步加载。</param>
/// <param name="customPackageName">指定资源包的名称。不传使用默认资源包</param> /// <param name="customPackageName">指定资源包的名称。不传使用默认资源包</param>
/// <param name="assetReference">指定资源引用组。</param>
public static void SetSprite(this UnityEngine.UI.Image image, string spriteName, bool isSetNativeSize = false, public static void SetSprite(this UnityEngine.UI.Image image, string spriteName, bool isSetNativeSize = false,
bool isAsync = false, string customPackageName = "") bool isAsync = false, string customPackageName = "",AssetReference assetReference = null)
{ {
if (image == null) if (image == null)
{ {
@@ -157,7 +158,14 @@ namespace TEngine
image.SetNativeSize(); image.SetNativeSize();
} }
image.gameObject.GetOrAddComponent<AssetReference>().Reference(operation, spriteName); if (assetReference != null)
{
assetReference.Reference(operation, spriteName);
}
else
{
image.gameObject.GetOrAddComponent<AssetReference>().Reference(operation, spriteName);
}
} }
else else
{ {
@@ -176,7 +184,15 @@ namespace TEngine
image.SetNativeSize(); image.SetNativeSize();
} }
image.gameObject.GetOrAddComponent<AssetReference>().Reference(operation, spriteName); image.sprite = operation.AssetObject as Sprite;
if (assetReference != null)
{
assetReference.Reference(operation, spriteName);
}
else
{
image.gameObject.GetOrAddComponent<AssetReference>().Reference(operation, spriteName);
}
}, customPackageName: customPackageName); }, customPackageName: customPackageName);
} }
} }
@@ -189,8 +205,9 @@ namespace TEngine
/// <param name="spriteName">图片名称。</param> /// <param name="spriteName">图片名称。</param>
/// <param name="isAsync">是否使用异步加载。</param> /// <param name="isAsync">是否使用异步加载。</param>
/// <param name="customPackageName">指定资源包的名称。不传使用默认资源包</param> /// <param name="customPackageName">指定资源包的名称。不传使用默认资源包</param>
/// <param name="assetReference">指定资源引用组。</param>
public static void SetSprite(this SpriteRenderer spriteRenderer, string spriteName, bool isAsync = false, public static void SetSprite(this SpriteRenderer spriteRenderer, string spriteName, bool isAsync = false,
string customPackageName = "") string customPackageName = "",AssetReference assetReference = null)
{ {
if (spriteRenderer == null) if (spriteRenderer == null)
{ {
@@ -208,7 +225,14 @@ namespace TEngine
var operation = GameModule.Resource.LoadAssetGetOperation<Sprite>(spriteName, customPackageName: customPackageName); var operation = GameModule.Resource.LoadAssetGetOperation<Sprite>(spriteName, customPackageName: customPackageName);
spriteRenderer.sprite = operation.AssetObject as Sprite; spriteRenderer.sprite = operation.AssetObject as Sprite;
spriteRenderer.gameObject.GetOrAddComponent<AssetReference>().Reference(operation, spriteName); if (assetReference != null)
{
assetReference.Reference(operation, spriteName);
}
else
{
spriteRenderer.gameObject.GetOrAddComponent<AssetReference>().Reference(operation, spriteName);
}
} }
else else
{ {
@@ -222,7 +246,14 @@ namespace TEngine
} }
spriteRenderer.sprite = operation.AssetObject as Sprite; spriteRenderer.sprite = operation.AssetObject as Sprite;
spriteRenderer.gameObject.GetOrAddComponent<AssetReference>().Reference(operation, spriteName); if (assetReference != null)
{
assetReference.Reference(operation, spriteName);
}
else
{
spriteRenderer.gameObject.GetOrAddComponent<AssetReference>().Reference(operation, spriteName);
}
}, customPackageName: customPackageName); }, customPackageName: customPackageName);
} }
} }

View File

@@ -4,6 +4,46 @@ using YooAsset;
namespace TEngine namespace TEngine
{ {
public class AudioData : MemoryObject
{
public AssetOperationHandle AssetOperationHandle { private set; get; }
public bool InPool { private set; get; } = false;
public override void InitFromPool()
{
}
public override void RecycleToPool()
{
if (!InPool)
{
AssetOperationHandle.Dispose();
}
InPool = false;
AssetOperationHandle = null;
}
internal static AudioData Alloc(AssetOperationHandle assetOperationHandle, bool inPool)
{
AudioData ret = MemoryPool.Acquire<AudioData>();
ret.AssetOperationHandle = assetOperationHandle;
ret.InPool = inPool;
ret.InitFromPool();
return ret;
}
internal static void DeAlloc(AudioData audioData)
{
if (audioData != null)
{
MemoryPool.Release(audioData);
audioData.RecycleToPool();
}
}
}
/// <summary> /// <summary>
/// 音频代理辅助器。 /// 音频代理辅助器。
/// </summary> /// </summary>
@@ -11,7 +51,7 @@ namespace TEngine
{ {
private int _instanceId; private int _instanceId;
private AudioSource _source; private AudioSource _source;
private AssetOperationHandle _assetOperationHandle; private AudioData _audioData;
private AudioModuleImp _audioModuleImp; private AudioModuleImp _audioModuleImp;
private Transform _transform; private Transform _transform;
float _volume = 1.0f; float _volume = 1.0f;
@@ -32,6 +72,7 @@ namespace TEngine
{ {
public string Path; public string Path;
public bool BAsync; public bool BAsync;
public bool BInPool;
} }
/// <summary> /// <summary>
@@ -47,7 +88,7 @@ namespace TEngine
/// <summary> /// <summary>
/// 资源操作句柄。 /// 资源操作句柄。
/// </summary> /// </summary>
public AssetOperationHandle AssetOperationHandle => _assetOperationHandle; public AudioData AudioData => _audioData;
/// <summary> /// <summary>
/// 音频代理辅助器音频大小。 /// 音频代理辅助器音频大小。
@@ -196,7 +237,8 @@ namespace TEngine
_source = host.AddComponent<AudioSource>(); _source = host.AddComponent<AudioSource>();
_source.playOnAwake = false; _source.playOnAwake = false;
AudioMixerGroup[] audioMixerGroups = AudioMixerGroup[] audioMixerGroups =
audioCategory.AudioMixer.FindMatchingGroups(Utility.Text.Format("Master/{0}/{1}", audioCategory.AudioMixerGroup.name, $"{audioCategory.AudioMixerGroup.name} - {index}")); audioCategory.AudioMixer.FindMatchingGroups(Utility.Text.Format("Master/{0}/{1}", audioCategory.AudioMixerGroup.name,
$"{audioCategory.AudioMixerGroup.name} - {index}"));
_source.outputAudioMixerGroup = audioMixerGroups.Length > 0 ? audioMixerGroups[0] : audioCategory.AudioMixerGroup; _source.outputAudioMixerGroup = audioMixerGroups.Length > 0 ? audioMixerGroups[0] : audioCategory.AudioMixerGroup;
_source.rolloffMode = audioCategory.AudioGroupConfig.audioRolloffMode; _source.rolloffMode = audioCategory.AudioGroupConfig.audioRolloffMode;
_source.minDistance = audioCategory.AudioGroupConfig.minDistance; _source.minDistance = audioCategory.AudioGroupConfig.minDistance;
@@ -218,7 +260,7 @@ namespace TEngine
_duration = 0; _duration = 0;
if (!string.IsNullOrEmpty(path)) if (!string.IsNullOrEmpty(path))
{ {
if (_audioModuleImp.AudioClipPool.TryGetValue(path, out var operationHandle)) if (bInPool && _audioModuleImp.AudioClipPool.TryGetValue(path, out var operationHandle))
{ {
OnAssetLoadComplete(operationHandle); OnAssetLoadComplete(operationHandle);
return; return;
@@ -239,7 +281,7 @@ namespace TEngine
} }
else else
{ {
_pendingLoad = new LoadRequest { Path = path, BAsync = bAsync }; _pendingLoad = new LoadRequest { Path = path, BAsync = bAsync, BInPool = bInPool };
if (_audioAgentRuntimeState == AudioAgentRuntimeState.Playing) if (_audioAgentRuntimeState == AudioAgentRuntimeState.Playing)
{ {
@@ -249,7 +291,7 @@ namespace TEngine
} }
/// <summary> /// <summary>
/// 停音频代理辅助器。 /// 停止播放音频代理辅助器。
/// </summary> /// </summary>
/// <param name="fadeout">是否渐出。</param> /// <param name="fadeout">是否渐出。</param>
public void Stop(bool fadeout = false) public void Stop(bool fadeout = false)
@@ -269,6 +311,28 @@ namespace TEngine
} }
} }
/// <summary>
/// 暂停音频代理辅助器。
/// </summary>
public void Pause()
{
if (_source != null)
{
_source.Pause();
}
}
/// <summary>
/// 取消暂停音频代理辅助器。
/// </summary>
public void UnPause()
{
if (_source != null)
{
_source.UnPause();
}
}
/// <summary> /// <summary>
/// 资源加载完成。 /// 资源加载完成。
/// </summary> /// </summary>
@@ -277,16 +341,15 @@ namespace TEngine
{ {
if (handle != null) if (handle != null)
{ {
handle.Completed -= OnAssetLoadComplete;
if (_inPool) if (_inPool)
{ {
_audioModuleImp.AudioClipPool.TryAdd(handle.GetAssetInfo().AssetPath, handle); _audioModuleImp.AudioClipPool.TryAdd(handle.GetAssetInfo().Address, handle);
} }
} }
if (_pendingLoad != null) if (_pendingLoad != null)
{ {
if (handle != null) if (!_inPool && handle != null)
{ {
handle.Dispose(); handle.Dispose();
} }
@@ -294,19 +357,21 @@ namespace TEngine
_audioAgentRuntimeState = AudioAgentRuntimeState.End; _audioAgentRuntimeState = AudioAgentRuntimeState.End;
string path = _pendingLoad.Path; string path = _pendingLoad.Path;
bool bAsync = _pendingLoad.BAsync; bool bAsync = _pendingLoad.BAsync;
bool bInPool = _pendingLoad.BInPool;
_pendingLoad = null; _pendingLoad = null;
Load(path, bAsync); Load(path, bAsync, bInPool);
} }
else if (handle != null) else if (handle != null)
{ {
if (_assetOperationHandle != null) if (_audioData != null)
{ {
_assetOperationHandle.Dispose(); AudioData.DeAlloc(_audioData);
_audioData = null;
} }
_assetOperationHandle = handle; _audioData = AudioData.Alloc(handle, _inPool);
_source.clip = _assetOperationHandle.AssetObject as AudioClip; _source.clip = handle.AssetObject as AudioClip;
if (_source.clip != null) if (_source.clip != null)
{ {
_source.Play(); _source.Play();
@@ -350,8 +415,9 @@ namespace TEngine
{ {
string path = _pendingLoad.Path; string path = _pendingLoad.Path;
bool bAsync = _pendingLoad.BAsync; bool bAsync = _pendingLoad.BAsync;
bool bInPool = _pendingLoad.BInPool;
_pendingLoad = null; _pendingLoad = null;
Load(path, bAsync); Load(path, bAsync, bInPool);
} }
_source.volume = _volume; _source.volume = _volume;
@@ -371,9 +437,9 @@ namespace TEngine
Object.Destroy(_transform.gameObject); Object.Destroy(_transform.gameObject);
} }
if (_assetOperationHandle != null) if (_audioData != null)
{ {
_assetOperationHandle.Dispose(); AudioData.DeAlloc(_audioData);
} }
} }
} }

View File

@@ -127,7 +127,7 @@ namespace TEngine
for (int i = 0; i < AudioAgents.Count; i++) for (int i = 0; i < AudioAgents.Count; i++)
{ {
if (AudioAgents[i].AssetOperationHandle == null || AudioAgents[i].IsFree) if (AudioAgents[i].AudioData?.AssetOperationHandle == null || AudioAgents[i].IsFree)
{ {
freeChannel = i; freeChannel = i;
break; break;

View File

@@ -22,7 +22,8 @@ namespace TEngine
public AssetOperationHandle Handle => _handle; public AssetOperationHandle Handle => _handle;
/// <summary> /// <summary>
/// 标签。 /// 自定义资源标签。
/// <remarks>不同于AssetTag。</remarks>
/// </summary> /// </summary>
public string Tag { private set; get; } public string Tag { private set; get; }
@@ -31,7 +32,7 @@ namespace TEngine
/// </summary> /// </summary>
public void Clear() public void Clear()
{ {
if (_handle != null) if (_handle is { IsValid: true })
{ {
_handle.Dispose(); _handle.Dispose();
} }
@@ -79,6 +80,7 @@ namespace TEngine
{ {
private readonly Dictionary<string,AssetHandleData> _assetHandleDataMap = new Dictionary<string,AssetHandleData>(); private readonly Dictionary<string,AssetHandleData> _assetHandleDataMap = new Dictionary<string,AssetHandleData>();
#region
/// <summary> /// <summary>
/// 引用资源数据到资源组内。 /// 引用资源数据到资源组内。
/// </summary> /// </summary>
@@ -105,32 +107,38 @@ namespace TEngine
_assetHandleDataMap[address] = handleData; _assetHandleDataMap[address] = handleData;
return true; return true;
} }
#endregion
#region
private readonly List<AssetHandleData> _tempResult = new List<AssetHandleData>();
/// <summary> /// <summary>
/// 从资源组内释放资源数据。 /// 从资源组内释放资源数据。
/// </summary> /// </summary>
/// <param name="assetTag">资源标签。</param> /// <param name="tag">自定义资源标签。</param>
/// <returns>是否释放成功。</returns> /// <returns>是否释放成功。</returns>
public bool ReleaseByTag(string assetTag) public bool ReleaseByTag(string tag)
{ {
AssetHandleData founded = null; _tempResult.Clear();
foreach (var assetHandleData in _assetHandleDataMap.Values) foreach (var assetHandleData in _assetHandleDataMap.Values)
{ {
if (assetHandleData.Tag == assetTag) if (assetHandleData.Tag == tag)
{ {
founded = assetHandleData; _tempResult.Add(assetHandleData);
break;
} }
} }
if (founded != null) if (_tempResult.Count > 0)
{ {
_assetHandleDataMap.Remove(founded.Handle.GetAssetInfo().Address); foreach (var founded in _tempResult)
AssetHandleData.Release(founded); {
_assetHandleDataMap.Remove(founded.Handle.GetAssetInfo().Address);
AssetHandleData.Release(founded);
}
return true; return true;
} }
Log.Warning($"Release AssetHandleData Tag:{assetTag} Failed"); Log.Warning($"Release AssetHandleData Tag:{tag} Failed");
return false; return false;
} }
@@ -178,20 +186,9 @@ namespace TEngine
Log.Warning($"Release AssetHandleData Handle:{handle} Failed"); Log.Warning($"Release AssetHandleData Handle:{handle} Failed");
return false; return false;
} }
#endregion
public void Clear() #region
{
var etr = _assetHandleDataMap.GetEnumerator();
while (etr.MoveNext())
{
AssetHandleData assetHandleData = etr.Current.Value;
AssetHandleData.Release(assetHandleData);
}
etr.Dispose();
_assetHandleDataMap.Clear();
}
/// <summary> /// <summary>
/// 从内存池中获取资源分组数据。 /// 从内存池中获取资源分组数据。
/// </summary> /// </summary>
@@ -217,24 +214,40 @@ namespace TEngine
MemoryPool.Release(assetGroup); MemoryPool.Release(assetGroup);
} }
public void Clear()
{
var etr = _assetHandleDataMap.GetEnumerator();
while (etr.MoveNext())
{
AssetHandleData assetHandleData = etr.Current.Value;
AssetHandleData.Release(assetHandleData);
}
etr.Dispose();
_assetHandleDataMap.Clear();
}
#endregion
/// <summary> /// <summary>
/// 同步加载资源。 /// 同步加载资源。
/// </summary> /// </summary>
/// <param name="assetName">要加载资源的名称。</param> /// <param name="location">资源的定位地址。</param>
/// <param name="parent">父节点位置。</param> /// <param name="parent">父节点位置。</param>
/// <param name="needInstance">是否需要实例化。</param>
/// <param name="packageName">指定资源包的名称。不传使用默认资源包</param>
/// <typeparam name="T">要加载资源的类型。</typeparam> /// <typeparam name="T">要加载资源的类型。</typeparam>
/// <returns>资源实例。</returns> /// <returns>资源实例。</returns>
public T LoadAsset<T>(string assetName, Transform parent = null) where T : Object public T LoadAsset<T>(string location, bool needInstance = true,string packageName = "",Transform parent = null) where T : Object
{ {
if (string.IsNullOrEmpty(assetName)) if (string.IsNullOrEmpty(location))
{ {
Log.Error("Asset name is invalid."); Log.Error("Asset name is invalid.");
return default; return default;
} }
if (_assetHandleDataMap.TryGetValue(assetName,out var assetHandleData)) if (_assetHandleDataMap.TryGetValue(location,out var assetHandleData))
{ {
if (typeof(T) == typeof(GameObject)) if (typeof(T) == typeof(GameObject) && needInstance)
{ {
GameObject ret = assetHandleData.Handle.InstantiateSync(parent); GameObject ret = assetHandleData.Handle.InstantiateSync(parent);
return ret as T; return ret as T;
@@ -245,11 +258,20 @@ namespace TEngine
} }
} }
AssetOperationHandle handle = YooAssets.LoadAssetSync<T>(assetName); AssetOperationHandle handle;
if (string.IsNullOrEmpty(packageName))
{
handle = YooAssets.LoadAssetSync<T>(location);
}
else
{
var package = YooAssets.GetPackage(packageName);
handle = package.LoadAssetSync<T>(location);
}
Reference(handle); Reference(handle);
if (typeof(T) == typeof(GameObject)) if (typeof(T) == typeof(GameObject) && needInstance)
{ {
GameObject ret = handle.InstantiateSync(parent); GameObject ret = handle.InstantiateSync(parent);
return ret as T; return ret as T;
@@ -261,113 +283,27 @@ namespace TEngine
} }
/// <summary> /// <summary>
/// 步加载资源。 /// 步加载资源。
/// </summary> /// </summary>
/// <param name="assetName">要加载资源的名称。</param> /// <param name="location">资源的定位地址。</param>
/// <typeparam name="T">要加载资源的类型。</typeparam>
/// <param name="assetOperationHandle">资源操作句柄。</param>
/// <returns>资源实例。</returns>
public T LoadAsset<T>(string assetName,out AssetOperationHandle assetOperationHandle) where T : Object
{
assetOperationHandle = null;
if (string.IsNullOrEmpty(assetName))
{
Log.Error("Asset name is invalid.");
return default;
}
if (_assetHandleDataMap.TryGetValue(assetName,out var assetHandleData))
{
if (typeof(T) == typeof(GameObject))
{
GameObject ret = assetHandleData.Handle.InstantiateSync();
return ret as T;
}
else
{
return assetHandleData.Handle.AssetObject as T;
}
}
assetOperationHandle = YooAssets.LoadAssetSync<T>(assetName);
Reference(assetOperationHandle);
if (typeof(T) == typeof(GameObject))
{
GameObject ret = assetOperationHandle.InstantiateSync();
return ret as T;
}
else
{
return assetOperationHandle.AssetObject as T;
}
}
/// <summary>
/// 同步加载资源。
/// </summary>
/// <param name="assetName">要加载资源的名称。</param>
/// <param name="parent">父节点位置。</param>
/// <param name="assetOperationHandle">资源操作句柄。</param>
/// <typeparam name="T">要加载资源的类型。</typeparam>
/// <returns>资源实例。</returns>
public T LoadAsset<T>(string assetName, Transform parent,out AssetOperationHandle assetOperationHandle) where T : Object
{
assetOperationHandle = null;
if (string.IsNullOrEmpty(assetName))
{
Log.Error("Asset name is invalid.");
return default;
}
if (_assetHandleDataMap.TryGetValue(assetName,out var assetHandleData))
{
if (typeof(T) == typeof(GameObject))
{
GameObject ret = assetHandleData.Handle.InstantiateSync(parent);
return ret as T;
}
else
{
return assetHandleData.Handle.AssetObject as T;
}
}
assetOperationHandle = YooAssets.LoadAssetSync<T>(assetName);
Reference(assetOperationHandle);
if (typeof(T) == typeof(GameObject))
{
GameObject ret = assetOperationHandle.InstantiateSync(parent);
return ret as T;
}
else
{
return assetOperationHandle.AssetObject as T;
}
}
/// <summary>
/// 异步加载资源实例。
/// </summary>
/// <param name="assetName">要加载的实例名称。</param>
/// <param name="cancellationToken">取消操作Token。</param> /// <param name="cancellationToken">取消操作Token。</param>
/// <returns>资源实实例。</returns> /// <param name="needInstance">是否需要实例。</param>
// ReSharper disable once UnusedParameter.Global /// <param name="packageName">指定资源包的名称。不传使用默认资源包。</param>
// ReSharper disable once RedundantAssignment /// <param name="parent">资源实例父节点。</param>
public async UniTask<T> LoadAssetAsync<T>(string assetName, CancellationToken cancellationToken = default) where T : Object /// <typeparam name="T">要加载资源的类型。</typeparam>
/// <returns>异步资源实例。</returns>
public async UniTask<T> LoadAssetAsync<T>(string location, CancellationToken cancellationToken = default,
bool needInstance = true, string packageName = "", Transform parent = null) where T : Object
{ {
if (string.IsNullOrEmpty(assetName)) if (string.IsNullOrEmpty(location))
{ {
Log.Error("Asset name is invalid."); Log.Error("Asset name is invalid.");
return default; return default;
} }
if (_assetHandleDataMap.TryGetValue(assetName,out var assetHandleData)) if (_assetHandleDataMap.TryGetValue(location,out var assetHandleData))
{ {
if (typeof(T) == typeof(GameObject)) if (typeof(T) == typeof(GameObject) && needInstance)
{ {
GameObject ret = assetHandleData.Handle.InstantiateSync(); GameObject ret = assetHandleData.Handle.InstantiateSync();
return ret as T; return ret as T;
@@ -378,7 +314,16 @@ namespace TEngine
} }
} }
AssetOperationHandle handle = YooAssets.LoadAssetAsync<T>(assetName); AssetOperationHandle handle;
if (string.IsNullOrEmpty(packageName))
{
handle = YooAssets.LoadAssetSync<T>(location);
}
else
{
var package = YooAssets.GetPackage(packageName);
handle = package.LoadAssetSync<T>(location);
}
Reference(handle); Reference(handle);
@@ -391,9 +336,9 @@ namespace TEngine
return null; return null;
} }
if (typeof(T) == typeof(GameObject)) if (typeof(T) == typeof(GameObject) && needInstance)
{ {
GameObject ret = handle.InstantiateSync(); GameObject ret = handle.InstantiateSync(parent);
return ret as T; return ret as T;
} }
else else
@@ -401,16 +346,5 @@ namespace TEngine
return handle.AssetObject as T; return handle.AssetObject as T;
} }
} }
/// <summary>
/// 异步加载游戏物体。
/// </summary>
/// <param name="assetName">要加载的游戏物体名称。</param>
/// <param name="cancellationToken">取消操作Token。</param>
/// <returns>异步游戏物体实例。</returns>
public async UniTask<GameObject> LoadGameObjectAsync(string assetName, CancellationToken cancellationToken = default)
{
return await LoadAssetAsync<GameObject>(assetName,cancellationToken);
}
} }
} }

View File

@@ -59,7 +59,7 @@ namespace TEngine
public void Bind(AssetOperationHandle operation, string assetLocation, AssetReference parent = null, public void Bind(AssetOperationHandle operation, string assetLocation, AssetReference parent = null,
string packageName = "") string packageName = "")
{ {
if (_operationHandle != null) if (_operationHandle is { IsValid: true })
{ {
Log.Warning($"rebind AssetReference gameObject.name:{gameObject.name} assetLocation:{assetLocation}"); Log.Warning($"rebind AssetReference gameObject.name:{gameObject.name} assetLocation:{assetLocation}");
_operationHandle.Dispose(); _operationHandle.Dispose();
@@ -153,82 +153,49 @@ namespace TEngine
/// <summary> /// <summary>
/// 同步加载资源。 /// 同步加载资源。
/// </summary> /// </summary>
/// <param name="assetName">要加载资源的名称。</param> /// <param name="location">资源的定位地址。</param>
/// <typeparam name="T">要加载资源的类型。</typeparam>
/// <returns>资源实例。</returns>
public T LoadAsset<T>(string assetName) where T : Object
{
DirtyInitAssetGroup();
return _assetGroup.LoadAsset<T>(assetName);
}
/// <summary>
/// 同步加载资源。
/// </summary>
/// <param name="assetName">要加载资源的名称。</param>
/// <param name="parent">父节点位置。</param> /// <param name="parent">父节点位置。</param>
/// <param name="needInstance">是否需要实例化。</param>
/// <param name="packageName">指定资源包的名称。不传使用默认资源包</param>
/// <typeparam name="T">要加载资源的类型。</typeparam> /// <typeparam name="T">要加载资源的类型。</typeparam>
/// <returns>资源实例。</returns> /// <returns>资源实例。</returns>
public T LoadAsset<T>(string assetName, Transform parent) where T : Object public T LoadAsset<T>(string location, bool needInstance = true,string packageName = "",Transform parent = null) where T : Object
{ {
DirtyInitAssetGroup(); DirtyInitAssetGroup();
return _assetGroup.LoadAsset<T>(assetName, parent); return _assetGroup.LoadAsset<T>(location, needInstance, packageName, parent);
} }
/// <summary> /// <summary>
/// 步加载资源。 /// 步加载资源。
/// </summary> /// </summary>
/// <param name="assetName">要加载资源的名称。</param> /// <param name="location">资源的定位地址。</param>
/// <typeparam name="T">要加载资源的类型。</typeparam>
/// <param name="assetOperationHandle">资源操作句柄。</param>
/// <returns>资源实例。</returns>
// ReSharper disable once ParameterHidesMember
public T LoadAsset<T>(string assetName, out AssetOperationHandle assetOperationHandle) where T : Object
{
DirtyInitAssetGroup();
return _assetGroup.LoadAsset<T>(assetName, out assetOperationHandle);
}
/// <summary>
/// 同步加载资源。
/// </summary>
/// <param name="assetName">要加载资源的名称。</param>
/// <param name="parent">父节点位置。</param>
/// <typeparam name="T">要加载资源的类型。</typeparam>
/// <param name="assetOperationHandle">资源操作句柄。</param>
/// <returns>资源实例。</returns>
// ReSharper disable once ParameterHidesMember
public T LoadAsset<T>(string assetName, Transform parent, out AssetOperationHandle assetOperationHandle)
where T : Object
{
DirtyInitAssetGroup();
return _assetGroup.LoadAsset<T>(assetName, parent, out assetOperationHandle);
}
/// <summary>
/// 异步加载资源实例。
/// </summary>
/// <param name="assetName">要加载的实例名称。</param>
/// <param name="cancellationToken">取消操作Token。</param> /// <param name="cancellationToken">取消操作Token。</param>
/// <returns>资源实实例。</returns> /// <param name="needInstance">是否需要实例。</param>
public async UniTask<T> LoadAssetAsync<T>(string assetName, CancellationToken cancellationToken = default) /// <param name="packageName">指定资源包的名称。不传使用默认资源包。</param>
where T : Object /// <param name="parent">资源实例父节点。</param>
/// <typeparam name="T">要加载资源的类型。</typeparam>
/// <returns>异步资源实例。</returns>
public async UniTask<T> LoadAssetAsync<T>(string location, CancellationToken cancellationToken = default,
bool needInstance = true, string packageName = "", Transform parent = null) where T : Object
{ {
DirtyInitAssetGroup(); DirtyInitAssetGroup();
return await _assetGroup.LoadAssetAsync<T>(assetName, cancellationToken); return await _assetGroup.LoadAssetAsync<T>(location, cancellationToken, needInstance, packageName, parent);
} }
/// <summary> /// <summary>
/// 异步加载游戏物体。 /// 异步加载游戏物体。
/// </summary> /// </summary>
/// <param name="assetName">要加载的游戏物体名称。</param> /// <param name="location">资源的定位地址。</param>
/// <param name="cancellationToken">取消操作Token。</param> /// <param name="cancellationToken">取消操作Token。</param>
/// <returns>异步游戏物体实例。</returns> /// <param name="needInstance">是否需要实例。</param>
public async UniTask<GameObject> LoadGameObjectAsync(string assetName, /// <param name="packageName">指定资源包的名称。不传使用默认资源包。</param>
CancellationToken cancellationToken = default) /// <param name="parent">资源实例父节点。</param>
/// <returns>异步资源实例。</returns>
public async UniTask<GameObject> LoadGameObjectAsync(string location, CancellationToken cancellationToken = default,
bool needInstance = true, string packageName = "", Transform parent = null)
{ {
DirtyInitAssetGroup(); DirtyInitAssetGroup();
return await _assetGroup.LoadGameObjectAsync(assetName, cancellationToken); return await LoadAssetAsync<GameObject>(location, cancellationToken, needInstance, packageName, parent);
} }
/// <summary> /// <summary>

View File

@@ -280,7 +280,7 @@ namespace TEngine
/// <param name="packageName">指定资源包的名称。不传使用默认资源包</param> /// <param name="packageName">指定资源包的名称。不传使用默认资源包</param>
/// <typeparam name="T">资源类型。</typeparam> /// <typeparam name="T">资源类型。</typeparam>
/// <returns>资源对象集合。</returns> /// <returns>资源对象集合。</returns>
UniTask<List<T>> LoadAssetsByTagAsync<T>(string assetTag, string packageName = "") where T : UnityEngine.Object; UniTask<LoadAssetsByTagOperation<T>> LoadAssetsByTagAsync<T>(string assetTag, string packageName = "") where T : UnityEngine.Object;
/// <summary> /// <summary>
/// 异步加载资源。 /// 异步加载资源。

View File

@@ -14,7 +14,7 @@ namespace TEngine
private readonly Dictionary<string, ResCacheData> _cachePool = new Dictionary<string, ResCacheData>(); private readonly Dictionary<string, ResCacheData> _cachePool = new Dictionary<string, ResCacheData>();
private readonly Dictionary<string, ResCacheData> _persistCachePool = new Dictionary<string, ResCacheData>(); private readonly Dictionary<string, ResCacheData> _persistCachePool = new Dictionary<string, ResCacheData>();
private bool _enableLog = true; private bool _enableLog = false;
private readonly List<ResourceCacheConfig> _needCacheResList = new List<ResourceCacheConfig>(); private readonly List<ResourceCacheConfig> _needCacheResList = new List<ResourceCacheConfig>();
private readonly List<string> _needPersistResList = new List<string>(); private readonly List<string> _needPersistResList = new List<string>();
private GameTimerTick _tickCheckExpire; private GameTimerTick _tickCheckExpire;

View File

@@ -824,15 +824,13 @@ namespace TEngine
return package.LoadSubAssetsSync(assetInfo); return package.LoadSubAssetsSync(assetInfo);
} }
public async UniTask<List<T>> LoadAssetsByTagAsync<T>(string assetTag, string packageName = "") public async UniTask<LoadAssetsByTagOperation<T>> LoadAssetsByTagAsync<T>(string assetTag,string packageName = "")
where T : UnityEngine.Object where T : UnityEngine.Object
{ {
LoadAssetsByTagOperation<T> operation = new LoadAssetsByTagOperation<T>(assetTag, packageName); LoadAssetsByTagOperation<T> operation = new LoadAssetsByTagOperation<T>(assetTag, packageName);
YooAssets.StartOperation(operation); YooAssets.StartOperation(operation);
await operation.ToUniTask(); await operation.ToUniTask();
List<T> assetObjects = operation.AssetObjects; return operation;
operation.ReleaseHandle();
return assetObjects;
} }
public async UniTask<T> LoadAssetAsync<T>(string location, CancellationToken cancellationToken = default, public async UniTask<T> LoadAssetAsync<T>(string location, CancellationToken cancellationToken = default,

View File

@@ -671,7 +671,7 @@ namespace TEngine
/// <param name="customPackageName">指定资源包的名称。不传使用默认资源包</param> /// <param name="customPackageName">指定资源包的名称。不传使用默认资源包</param>
/// <typeparam name="T">资源类型。</typeparam> /// <typeparam name="T">资源类型。</typeparam>
/// <returns>资源对象集合。</returns> /// <returns>资源对象集合。</returns>
public async UniTask<List<T>> LoadAssetsByTagAsync<T>(string assetTag, string customPackageName = "") public async UniTask<LoadAssetsByTagOperation<T>> LoadAssetsByTagAsync<T>(string assetTag, string customPackageName = "")
where T : UnityEngine.Object where T : UnityEngine.Object
{ {
return await m_ResourceManager.LoadAssetsByTagAsync<T>(assetTag, packageName: customPackageName); return await m_ResourceManager.LoadAssetsByTagAsync<T>(assetTag, packageName: customPackageName);

View File

@@ -176,6 +176,14 @@ namespace TEngine
{ {
} }
internal void SetUpdateDirty()
{
m_updateListValid = false;
if (Parent != null)
{
Parent.SetUpdateDirty();
}
}
#region FindChildComponent #region FindChildComponent

View File

@@ -24,7 +24,7 @@ namespace TEngine
/// 窗口组件名称。 /// 窗口组件名称。
/// </summary> /// </summary>
// ReSharper disable once InconsistentNaming // ReSharper disable once InconsistentNaming
public string name { private set; get; } = nameof(UIWidget); public string name { protected set; get; } = string.Empty;
/// <summary> /// <summary>
/// UI类型。 /// UI类型。
@@ -53,6 +53,20 @@ namespace TEngine
} }
} }
/// <summary>
/// 窗口可见性
/// </summary>
public bool Visible
{
get => gameObject.activeSelf;
set
{
gameObject.SetActive(value);
OnSetVisible(value);
}
}
internal bool InternalUpdate() internal bool InternalUpdate()
{ {
if (!IsPrepare) if (!IsPrepare)
@@ -89,6 +103,11 @@ namespace TEngine
{ {
var uiWidget = listChild[i]; var uiWidget = listChild[i];
if (uiWidget == null)
{
continue;
}
TProfiler.BeginSample(uiWidget.name); TProfiler.BeginSample(uiWidget.name);
var needValid = uiWidget.InternalUpdate(); var needValid = uiWidget.InternalUpdate();
TProfiler.EndSample(); TProfiler.EndSample();
@@ -194,6 +213,7 @@ namespace TEngine
RestChildCanvas(parentUI); RestChildCanvas(parentUI);
parent = parentUI; parent = parentUI;
Parent.ListChild.Add(this); Parent.ListChild.Add(this);
Parent.SetUpdateDirty();
ScriptGenerator(); ScriptGenerator();
BindMemberProperty(); BindMemberProperty();
RegisterEvent(); RegisterEvent();
@@ -205,6 +225,13 @@ namespace TEngine
{ {
gameObject.SetActive(false); gameObject.SetActive(false);
} }
else
{
if (!gameObject.activeSelf)
{
gameObject.SetActive(true);
}
}
return true; return true;
} }
@@ -216,6 +243,7 @@ namespace TEngine
return false; return false;
} }
name = GetType().Name;
transform = go.GetComponent<Transform>(); transform = go.GetComponent<Transform>();
rectTransform = transform as RectTransform; rectTransform = transform as RectTransform;
gameObject = go; gameObject = go;
@@ -257,6 +285,8 @@ namespace TEngine
/// </summary> /// </summary>
internal void OnDestroyWidget() internal void OnDestroyWidget()
{ {
Parent?.SetUpdateDirty();
RemoveAllUIEvent(); RemoveAllUIEvent();
foreach (var uiChild in ListChild) foreach (var uiChild in ListChild)

View File

@@ -255,7 +255,8 @@ namespace TEngine
this.userDatas = userDatas; this.userDatas = userDatas;
if (!FromResources) if (!FromResources)
{ {
GameModule.Resource.LoadAssetAsync<GameObject>(location, Handle_Completed, needCache: NeedCache); Handle = GameModule.Resource.LoadAssetAsyncHandle<GameObject>(location, needCache: NeedCache);
Handle.Completed += Handle_Completed;
} }
else else
{ {
@@ -317,6 +318,11 @@ namespace TEngine
{ {
var uiWidget = listChild[i]; var uiWidget = listChild[i];
if (uiWidget == null)
{
continue;
}
TProfiler.BeginSample(uiWidget.name); TProfiler.BeginSample(uiWidget.name);
var needValid = uiWidget.InternalUpdate(); var needValid = uiWidget.InternalUpdate();
TProfiler.EndSample(); TProfiler.EndSample();
@@ -394,13 +400,11 @@ namespace TEngine
{ {
throw new GameFrameworkException("Load uiWindows Failed because AssetObject is null"); throw new GameFrameworkException("Load uiWindows Failed because AssetObject is null");
} }
Handle = handle;
// 实例化对象 // 实例化对象
var panel = handle.InstantiateSync(UIModule.UIRootStatic); var panel = handle.InstantiateSync(UIModule.UIRootStatic);
if (!NeedCache) if (!NeedCache)
{ {
AssetReference.BindAssetReference(panel, handle, AssetName); AssetReference.BindAssetReference(panel, Handle, AssetName);
} }
Handle_Completed(panel); Handle_Completed(panel);
} }

View File

@@ -5,7 +5,7 @@
"depth": 0, "depth": 0,
"source": "git", "source": "git",
"dependencies": {}, "dependencies": {},
"hash": "f810ede6d74a7fcfc2c2fd03ad08c44696b3a0e0" "hash": "410bb9b542664e9288588b5c23d3300e01e5936e"
}, },
"com.cysharp.unitask": { "com.cysharp.unitask": {
"version": "file:UniTask", "version": "file:UniTask",