@kkarum/framework 2.3.17 → 2.3.19

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,93 +1,167 @@
1
- # framework
2
-
3
-
4
-
5
- ## Getting started
6
-
7
- To make it easy for you to get started with GitLab, here's a list of recommended next steps.
8
-
9
- Already a pro? Just edit this README.md and make it your own. Want to make it easy? [Use the template at the bottom](#editing-this-readme)!
10
-
11
- ## Add your files
12
-
13
- - [ ] [Create](https://docs.gitlab.com/ee/user/project/repository/web_editor.html#create-a-file) or [upload](https://docs.gitlab.com/ee/user/project/repository/web_editor.html#upload-a-file) files
14
- - [ ] [Add files using the command line](https://docs.gitlab.com/ee/gitlab-basics/add-file.html#add-a-file-using-the-command-line) or push an existing Git repository with the following command:
15
-
16
- ```
17
- cd existing_repo
18
- git remote add origin http://47.243.247.195:8099/crazy_client/framework.git
19
- git branch -M main
20
- git push -uf origin main
21
- ```
22
-
23
- ## Integrate with your tools
24
-
25
- - [ ] [Set up project integrations](http://47.243.247.195:8099/crazy_client/framework/-/settings/integrations)
26
-
27
- ## Collaborate with your team
28
-
29
- - [ ] [Invite team members and collaborators](https://docs.gitlab.com/ee/user/project/members/)
30
- - [ ] [Create a new merge request](https://docs.gitlab.com/ee/user/project/merge_requests/creating_merge_requests.html)
31
- - [ ] [Automatically close issues from merge requests](https://docs.gitlab.com/ee/user/project/issues/managing_issues.html#closing-issues-automatically)
32
- - [ ] [Enable merge request approvals](https://docs.gitlab.com/ee/user/project/merge_requests/approvals/)
33
- - [ ] [Set auto-merge](https://docs.gitlab.com/ee/user/project/merge_requests/merge_when_pipeline_succeeds.html)
34
-
35
- ## Test and Deploy
36
-
37
- Use the built-in continuous integration in GitLab.
38
-
39
- - [ ] [Get started with GitLab CI/CD](https://docs.gitlab.com/ee/ci/quick_start/index.html)
40
- - [ ] [Analyze your code for known vulnerabilities with Static Application Security Testing (SAST)](https://docs.gitlab.com/ee/user/application_security/sast/)
41
- - [ ] [Deploy to Kubernetes, Amazon EC2, or Amazon ECS using Auto Deploy](https://docs.gitlab.com/ee/topics/autodevops/requirements.html)
42
- - [ ] [Use pull-based deployments for improved Kubernetes management](https://docs.gitlab.com/ee/user/clusters/agent/)
43
- - [ ] [Set up protected environments](https://docs.gitlab.com/ee/ci/environments/protected_environments.html)
44
-
45
- ***
46
-
47
- # Editing this README
48
-
49
- When you're ready to make this README your own, just edit this file and use the handy template below (or feel free to structure it however you want - this is just a starting point!). Thanks to [makeareadme.com](https://www.makeareadme.com/) for this template.
50
-
51
- ## Suggestions for a good README
52
-
53
- Every project is different, so consider which of these sections apply to yours. The sections used in the template are suggestions for most open source projects. Also keep in mind that while a README can be too long and detailed, too long is better than too short. If you think your README is too long, consider utilizing another form of documentation rather than cutting out information.
54
-
55
- ## Name
56
- Choose a self-explaining name for your project.
57
-
58
- ## Description
59
- Let people know what your project can do specifically. Provide context and add a link to any reference visitors might be unfamiliar with. A list of Features or a Background subsection can also be added here. If there are alternatives to your project, this is a good place to list differentiating factors.
60
-
61
- ## Badges
62
- On some READMEs, you may see small images that convey metadata, such as whether or not all the tests are passing for the project. You can use Shields to add some to your README. Many services also have instructions for adding a badge.
63
-
64
- ## Visuals
65
- Depending on what you are making, it can be a good idea to include screenshots or even a video (you'll frequently see GIFs rather than actual videos). Tools like ttygif can help, but check out Asciinema for a more sophisticated method.
66
-
67
- ## Installation
68
- Within a particular ecosystem, there may be a common way of installing things, such as using Yarn, NuGet, or Homebrew. However, consider the possibility that whoever is reading your README is a novice and would like more guidance. Listing specific steps helps remove ambiguity and gets people to using your project as quickly as possible. If it only runs in a specific context like a particular programming language version or operating system or has dependencies that have to be installed manually, also add a Requirements subsection.
69
-
70
- ## Usage
71
- Use examples liberally, and show the expected output if you can. It's helpful to have inline the smallest example of usage that you can demonstrate, while providing links to more sophisticated examples if they are too long to reasonably include in the README.
72
-
73
- ## Support
74
- Tell people where they can go to for help. It can be any combination of an issue tracker, a chat room, an email address, etc.
75
-
76
- ## Roadmap
77
- If you have ideas for releases in the future, it is a good idea to list them in the README.
78
-
79
- ## Contributing
80
- State if you are open to contributions and what your requirements are for accepting them.
81
-
82
- For people who want to make changes to your project, it's helpful to have some documentation on how to get started. Perhaps there is a script that they should run or some environment variables that they need to set. Make these steps explicit. These instructions could also be useful to your future self.
83
-
84
- You can also document commands to lint the code or run tests. These steps help to ensure high code quality and reduce the likelihood that the changes inadvertently break something. Having instructions for running tests is especially helpful if it requires external setup, such as starting a Selenium server for testing in a browser.
85
-
86
- ## Authors and acknowledgment
87
- Show your appreciation to those who have contributed to the project.
88
-
89
- ## License
90
- For open source projects, say how it is licensed.
91
-
92
- ## Project status
93
- If you have run out of energy or time for your project, put a note at the top of the README saying that development has slowed down or stopped completely. Someone may choose to fork your project or volunteer to step in as a maintainer or owner, allowing your project to keep going. You can also make an explicit request for maintainers.
1
+ # Framework
2
+
3
+ `assets/framework` 是面向 Cocos Creator 2.x 的自写业务框架,核心目标是把业务模块、UI Layer、资源、事件、网络、定时器、对象池和异步流程统一到 `FW` 全局命名空间下管理。
4
+
5
+ README 只做快速总览。详细开发规范请阅读 `assets/framework/docs/` 下的文档。
6
+
7
+ ## 核心入口
8
+
9
+ 框架初始化后会创建全局 `FW`:
10
+
11
+ - `FW.Framework`:依赖注入容器,负责注册和获取业务组件。
12
+ - `FW.Entry`:业务统一入口,聚合所有管理器。
13
+ - `FW.Log`:统一日志输出。
14
+ - `FW.SystemDefine`:框架枚举。
15
+ - `FW.EventDefine`:系统事件枚举。
16
+
17
+ 业务代码应优先通过 `FW.Entry` 使用框架能力,不要直接 new 框架管理器。
18
+
19
+ ## 主要模块
20
+
21
+ | 模块 | 说明 |
22
+ | --- | --- |
23
+ | `FW.Registry` | bundle 注册表,声明 Logic/Data/Config/Sender/Handle |
24
+ | `FW.FrameworkBase` | 业务基类,提供依赖获取、性能记录和错误包装 |
25
+ | `FW.Logic` | 业务流程 |
26
+ | `FW.Data` | 业务数据 |
27
+ | `FW.AssetConfig` | 资源配置 |
28
+ | `FW.LayerController` | UI Layer 控制器 |
29
+ | `FW.Entry.resMgr` | bundle 和资源加载/释放 |
30
+ | `FW.Entry.layerMgr` | UI Layer 打开、关闭、队列和栈 |
31
+ | `FW.Entry.uiMgr` | UI 事件注册、节点查找、按钮状态 |
32
+ | `FW.Entry.evtMgr` | 框架事件总线 |
33
+ | `FW.Entry.timeMgr` | 游戏生命周期定时器 |
34
+ | `FW.Entry.promiseMgr` | 可取消、超时、重试的 Promise |
35
+ | `FW.Entry.socketMgr` | Socket 连接管理 |
36
+ | `FW.Entry.objectMgr` | 对象池 |
37
+ | `FW.Entry.taskMgr` | 分帧任务 |
38
+
39
+ ## 推荐业务结构
40
+
41
+ 新增业务功能时,推荐按 bundle 拆分:
42
+
43
+ ```text
44
+ assets/<bundle>/
45
+ registry/<Bundle>Registry.ts
46
+ logic/<Bundle>Logic.ts
47
+ data/<Bundle>Data.ts
48
+ config/<Bundle>AssetConfig.ts
49
+ socket/<Bundle>Sender.ts
50
+ socket/<Bundle>Handle.ts
51
+ ui/<Feature>/<Feature>LayerController.ts
52
+ prefab/<Feature>Layer.prefab
53
+ ```
54
+
55
+ 命名必须保留框架后缀,例如 `ShopLogic`、`ShopData`、`ShopAssetConfig`、`ShopSender`、`ShopHandle`。框架会根据类名和 bundle 名自动推断依赖。
56
+
57
+ ## UI 开发约定
58
+
59
+ UI 页面、弹窗、常驻面板应使用 `FW.LayerController`:
60
+
61
+ ```ts
62
+ await FW.Entry.layerMgr.openAsync({
63
+ type: ShopLayerController,
64
+ args: { tab: "hot" },
65
+ });
66
+ ```
67
+
68
+ LayerController 中:
69
+
70
+ - 使用 `this.find()` 查找节点。
71
+ - 使用 `this.cc()` 绑定按钮事件。
72
+ - 使用 `this.fw()` 监听框架事件。
73
+ - 使用 `this.close()` 关闭 Layer。
74
+ - 通过 `layerAssetProperty` 指向 `AssetConfig` 中的 prefab。
75
+
76
+ 不要在业务代码中绕过 `layerMgr` 直接 `cc.instantiate` 业务弹窗。
77
+
78
+ ## 资源开发约定
79
+
80
+ 资源统一写入 `FW.AssetConfig`:
81
+
82
+ ```ts
83
+ preLoad = {
84
+ prefab: {
85
+ ShopLayer: {
86
+ bundle: "shop",
87
+ path: "prefab/ShopLayer",
88
+ type: cc.Prefab,
89
+ priorityLoaded: true,
90
+ autoRelease: true,
91
+ },
92
+ },
93
+ };
94
+ ```
95
+
96
+ 加载资源时使用:
97
+
98
+ ```ts
99
+ const prefab = await FW.Entry.resMgr.loadAsset<cc.Prefab>(assetProperty);
100
+ ```
101
+
102
+ 不要在业务代码中散落硬编码资源路径,也不要在资源未加载时调用 `getAsset()`。
103
+
104
+ ## 事件和异步
105
+
106
+ 框架事件:
107
+
108
+ ```ts
109
+ FW.Entry.evtMgr.dispatch("SHOP_GOODS_CHANGED", goods);
110
+ FW.Entry.evtMgr.register("SHOP_GOODS_CHANGED", this.renderGoods, this);
111
+ ```
112
+
113
+ 定时器:
114
+
115
+ ```ts
116
+ FW.Entry.timeMgr.schedule(this.tick, 1, cc.macro.REPEAT_FOREVER, this);
117
+ FW.Entry.timeMgr.unSchedule(this);
118
+ ```
119
+
120
+ 异步流程:
121
+
122
+ ```ts
123
+ const result = await this.invoke(
124
+ FW.Entry.resMgr.loadAssetData(assetProperty),
125
+ "loadAsset",
126
+ );
127
+ ```
128
+
129
+ `invoke()` 会记录性能并统一输出错误。调用方必须处理返回 `undefined` 的情况。
130
+
131
+ ## cocos-mcp 协作
132
+
133
+ 使用 cocos-mcp 做 UI 自动化时:
134
+
135
+ 1. 先用 `cocos_mcp_diagnose` 检查连接。
136
+ 2. 用 `scene_get_tree` 获取真实节点路径。
137
+ 3. 用 `asset_query` 或 `asset_resolve` 确认资源。
138
+ 4. 用 `ui_create_tree` 或 `ui_create_node` 创建 UI。
139
+ 5. 用 `ui_set_sprite_frame` 绑定图片。
140
+ 6. 需要复用时用 `prefab_create_from_node` 生成 prefab。
141
+ 7. 运行时事件优先写在 `LayerController` 中,不强行用编辑器 clickEvents。
142
+
143
+ MCP 节点路径必须使用绝对路径,例如 `/Canvas/ShopLayer/CloseButton`。
144
+
145
+ ## Codex 使用原则
146
+
147
+ Codex 在本项目中新增功能时必须遵守:
148
+
149
+ - 不修改框架内部源码,除非用户明确要求维护框架。
150
+ - 优先复用 `FW.Entry`、`FW.FrameworkBase`、`FW.LayerController`。
151
+ - UI 功能走 LayerController + prefab + AssetConfig。
152
+ - 业务流程放 Logic,业务状态放 Data。
153
+ - 网络协议放 Sender/Handle。
154
+ - 资源路径集中在 AssetConfig。
155
+ - 事件、定时器、Promise、对象池全部使用框架 API。
156
+
157
+ ## 详细文档
158
+
159
+ - [FRAMEWORK_OVERVIEW.md](docs/FRAMEWORK_OVERVIEW.md):框架整体架构。
160
+ - [FRAMEWORK_USAGE.md](docs/FRAMEWORK_USAGE.md):业务使用方式。
161
+ - [FRAMEWORK_API.md](docs/FRAMEWORK_API.md):常用 API 速查。
162
+ - [FRAMEWORK_PATTERNS.md](docs/FRAMEWORK_PATTERNS.md):新增功能模式和禁止事项。
163
+ - [FRAMEWORK_EXAMPLES.md](docs/FRAMEWORK_EXAMPLES.md):可复制代码示例。
164
+ - [CODEX_GUIDE.md](docs/CODEX_GUIDE.md):Codex 长期开发规范。
165
+ - [MCP_INTEGRATION.md](docs/MCP_INTEGRATION.md):cocos-mcp 自动化流程。
166
+ - [UI_DEVELOPMENT_GUIDE.md](docs/UI_DEVELOPMENT_GUIDE.md):UI 开发规范。
167
+ - [ERROR_HANDLING.md](docs/ERROR_HANDLING.md):错误处理和生命周期清理。
@@ -0,0 +1,151 @@
1
+ # Codex Guide
2
+
3
+ 本文档是 Codex 在本项目中新增、修改业务功能时必须优先参考的工作规范。
4
+
5
+ ## 首要约束
6
+
7
+ - 不修改 `assets/framework` 内部源码。
8
+ - 不把框架 README 当作唯一依据;以源码和 `docs/FRAMEWORK_*.md` 为准。
9
+ - 新业务功能优先扩展业务 bundle。
10
+ - 所有框架能力优先复用 `FW.Entry`、`FW.FrameworkBase`、`FW.LayerController`。
11
+ - UI 自动化优先配合 cocos-mcp 创建节点、绑定资源、保存 prefab 或场景。
12
+
13
+ ## 开工前检查
14
+
15
+ Codex 在写代码前应先做:
16
+
17
+ 1. 搜索目标 bundle 是否已存在。
18
+ 2. 查找已有 `Registry`、`Logic`、`Data`、`AssetConfig`、`LayerController`。
19
+ 3. 查找同类 UI 控制器的命名、目录、事件风格。
20
+ 4. 查找资源路径和 prefab 命名。
21
+ 5. 如果涉及 Cocos 场景/UI,先通过 cocos-mcp `scene_get_tree` 获取真实节点路径。
22
+
23
+ ## 新增业务功能决策
24
+
25
+ ### 用户要新增页面、弹窗、面板
26
+
27
+ 执行:
28
+
29
+ 1. 新增或复用 prefab。
30
+ 2. 新增 `XxxLayerController extends FW.LayerController`。
31
+ 3. 在 `AssetConfig` 中声明 prefab。
32
+ 4. `layerAssetProperty` 返回该资源。
33
+ 5. 使用 `FW.Entry.layerMgr.openAsync({ type: XxxLayerController, args })` 打开。
34
+ 6. 事件用 `this.cc()`、`this.fw()`。
35
+
36
+ 不要:
37
+
38
+ - 直接 `cc.instantiate(prefab)` 打开业务 UI。
39
+ - 直接在组件里 `node.on` 后不清理。
40
+ - 在构造函数里查节点。
41
+
42
+ ### 用户要新增业务流程
43
+
44
+ 执行:
45
+
46
+ 1. 放入 `XxxLogic`。
47
+ 2. 状态读写放入 `XxxData`。
48
+ 3. 网络请求通过 `XxxSender`。
49
+ 4. 网络返回通过 `XxxHandle` 写入 Data 或派发事件。
50
+ 5. UI 监听事件刷新。
51
+
52
+ 不要:
53
+
54
+ - 把网络请求写在 LayerController。
55
+ - 把 UI 节点保存到 Data。
56
+
57
+ ### 用户要新增资源
58
+
59
+ 执行:
60
+
61
+ 1. 在 `XxxAssetConfig` 增加 `preLoad` 或 `demandLoad`。
62
+ 2. 使用 `FW.Entry.resMgr.loadAsset()` 或 `loadAssetData()`。
63
+ 3. 如果用于 Layer prefab,优先 `preLoad.prefab`。
64
+
65
+ 不要:
66
+
67
+ - 在多个文件硬编码相同资源路径。
68
+ - 资源未加载就调用 `getAsset()`。
69
+
70
+ ### 用户要新增 Socket 协议
71
+
72
+ 执行:
73
+
74
+ 1. 在 `Sender` 写发送方法。
75
+ 2. 在 `Handle.onMessage()` 做协议分发。
76
+ 3. 用 `FW.Entry.evtMgr.dispatch()` 通知业务。
77
+ 4. 心跳识别实现 `onHeart()`。
78
+ 5. 协议轮询实现 `getProtocolKey()`。
79
+
80
+ 不要:
81
+
82
+ - 直接 new `WebSocket`。
83
+ - 在 UI 中解析所有网络消息。
84
+
85
+ ## 必须复用的 API
86
+
87
+ | 场景 | 必须优先使用 |
88
+ | --- | --- |
89
+ | 打开 UI | `FW.Entry.layerMgr.openAsync/openSync` |
90
+ | 关闭 UI | `ctr.close()` 或 `FW.Entry.layerMgr.close(ctr)` |
91
+ | 查节点 | `ctr.find()` 或 `FW.Entry.uiMgr.find()` |
92
+ | 按钮事件 | `ctr.cc()` 或 `ctr.registerEvent()` |
93
+ | 全局事件 | `FW.Entry.evtMgr.register/dispatch` |
94
+ | 资源加载 | `FW.Entry.resMgr` |
95
+ | 定时器 | `FW.Entry.timeMgr` |
96
+ | 异步重试/取消 | `FW.Entry.promiseMgr` 或 `FrameworkBase.invoke()` |
97
+ | 对象复用 | `FW.Entry.objectMgr.createObjectPool()` |
98
+ | 日志 | `FW.Log.debug/warn/error/...` |
99
+ | 业务依赖 | `this.getLogic/getData/getConfig/getSender/getHandle` |
100
+
101
+ ## 代码风格
102
+
103
+ 必须:
104
+
105
+ - 类名使用业务名前缀和框架后缀。
106
+ - 继承对应框架基类。
107
+ - 控制器使用 `private` 方法拆分 `cacheNodes()`、`bindEvents()`、`render()`。
108
+ - 异步方法处理 `undefined` 返回。
109
+ - 用 `FW.Log` 记录业务错误。
110
+ - UI 事件设置合理 `responseInterval`,默认 500ms 已由 `LayerController` 提供。
111
+
112
+ 避免:
113
+
114
+ - 在一个方法里混合资源加载、网络请求、UI 渲染、数据变更。
115
+ - 使用魔法字符串事件名散落各处;大型功能应集中定义事件常量。
116
+ - 同一资源路径在多个文件重复。
117
+ - 在 `onDestroy` 外留下未清理定时器和事件。
118
+
119
+ ## cocos-mcp 工作流
120
+
121
+ 当任务涉及 UI 自动化:
122
+
123
+ 1. 调用 `cocos_mcp_diagnose` 检查连接和当前场景。
124
+ 2. 调用 `scene_get_tree({ includeDiagnostics: true })` 获取节点路径。
125
+ 3. 如果要绑定真实资源,先用 `asset_query` 或 `asset_resolve` 获取准确资源。
126
+ 4. 创建大结构用 `ui_create_tree`,小改动用 `ui_create_node`、`ui_set_node_props`、`ui_add_component`。
127
+ 5. 设置 SpriteFrame 用 `ui_set_sprite_frame`,不要猜 uuid。
128
+ 6. 创建 prefab 用 `prefab_create_from_tree` 或 `prefab_create_from_node`。
129
+ 7. 绑定按钮只在脚本组件和 handler 已存在时使用 `ui_bind_button_event`;否则让 `LayerController.cc()` 在代码中绑定。
130
+ 8. 完成后用 `scene_get_tree` 验证节点。
131
+ 9. 用户确认需要保存时调用 `scene_save`。
132
+
133
+ ## UI 自动化注意事项
134
+
135
+ - MCP 节点路径必须是绝对路径,如 `/Canvas/ShopLayer/CloseButton`。
136
+ - 不要随机选择同名资源;如果 `asset_resolve` 返回 ambiguous,必须让用户或上下文消歧。
137
+ - 创建 UI 前确认 Canvas 和目标父节点存在。
138
+ - 如果生成框架 Layer prefab,根节点应挂 `FW.Layer` 对应组件名,且 prefab 名应与 `layerAssetProperty.path` 对齐。
139
+ - UI 代码中的节点名必须和 MCP 创建的节点名一致。
140
+
141
+ ## 完成前验证
142
+
143
+ Codex 完成改动后应检查:
144
+
145
+ - 没有修改 `assets/framework`。
146
+ - 新业务类名满足注入约定。
147
+ - `AssetConfig` 资源路径和 prefab 实际路径一致。
148
+ - LayerController 的 `layerAssetProperty` 不为空。
149
+ - 事件和定时器有生命周期清理。
150
+ - TypeScript 没有明显类型错误。
151
+ - 如果用 MCP 创建 UI,真实场景树里节点存在。
@@ -0,0 +1,6 @@
1
+ {
2
+ "ver": "2.0.2",
3
+ "uuid": "f0b82119-ca20-436b-b62c-502d61a98227",
4
+ "importer": "markdown",
5
+ "subMetas": {}
6
+ }
@@ -0,0 +1,233 @@
1
+ # Error Handling
2
+
3
+ 本文档定义框架内业务错误处理、异步失败、资源失败和生命周期清理规范。
4
+
5
+ ## 日志
6
+
7
+ 统一使用 `FW.Log`:
8
+
9
+ ```ts
10
+ FW.Log.debug("message");
11
+ FW.Log.warn("warning", data);
12
+ FW.Log.error("error", error);
13
+ FW.Log.request("request", msg);
14
+ FW.Log.response("response", msg);
15
+ FW.Log.send("socket send", msg);
16
+ FW.Log.receive("socket receive", msg);
17
+ FW.Log.system("system", msg);
18
+ ```
19
+
20
+ 发布构建中框架会关闭 console 输出。业务代码不要自行覆盖 console。
21
+
22
+ ## FrameworkBase.invoke
23
+
24
+ 异步业务方法优先用 `invoke()`:
25
+
26
+ ```ts
27
+ const result = await this.invoke(
28
+ FW.Entry.resMgr.loadAssetData(asset),
29
+ "loadAssetData",
30
+ );
31
+
32
+ if (!result) {
33
+ return;
34
+ }
35
+ ```
36
+
37
+ `invoke()` 会:
38
+
39
+ - 记录开始和结束时间。
40
+ - 上报到 `performanceMgr`。
41
+ - 慢操作输出 warn。
42
+ - 捕获异常并输出结构化错误。
43
+ - 返回 `undefined`。
44
+
45
+ 调用方必须处理 `undefined`。
46
+
47
+ ## Promise 错误
48
+
49
+ 使用 `FW.Entry.promiseMgr.execute()` 时设置合理超时:
50
+
51
+ ```ts
52
+ const proxy = FW.Entry.promiseMgr.execute(resolveWork, {
53
+ timeout: 10000,
54
+ retryCount: 3,
55
+ retryInterval: 2,
56
+ retryCondition: (error, count) => true,
57
+ });
58
+ ```
59
+
60
+ 取消:
61
+
62
+ ```ts
63
+ proxy.abort("layer closed");
64
+ ```
65
+
66
+ 批量结果不会直接抛出所有错误,而是返回:
67
+
68
+ ```ts
69
+ {
70
+ success: [{ id, value }],
71
+ failed: [{ id, reason }],
72
+ cancelled: [id]
73
+ }
74
+ ```
75
+
76
+ ## 资源加载失败
77
+
78
+ 资源加载统一走 `FW.Entry.resMgr`。可注册拒绝处理器:
79
+
80
+ ```ts
81
+ FW.Entry.resMgr.registerRejectHandler({
82
+ loadBundleHandler(error, bundleName) {
83
+ FW.Log.error("load bundle failed", bundleName, error);
84
+ },
85
+ loadResHandler(error, path) {
86
+ FW.Log.error("load resource failed", path, error);
87
+ },
88
+ });
89
+ ```
90
+
91
+ 加载失败时:
92
+
93
+ - 不继续操作节点。
94
+ - 不调用 `getAsset()` 兜底。
95
+ - UI 应显示空态、重试按钮或关闭弹窗。
96
+ - Codex 不应通过修改框架资源管理器绕过错误。
97
+
98
+ ## Layer 错误
99
+
100
+ `FWLayerManager.openAsync()` 失败时会:
101
+
102
+ - 设置状态为 loading/opening。
103
+ - 失败后移除状态。
104
+ - 清理失败的 Layer 注册。
105
+ - 抛出错误。
106
+
107
+ 业务调用:
108
+
109
+ ```ts
110
+ try {
111
+ await FW.Entry.layerMgr.openAsync({ type: RewardLayerController });
112
+ } catch (error) {
113
+ FW.Log.error("open reward layer failed", error);
114
+ }
115
+ ```
116
+
117
+ `openSync()` 失败通常返回 `undefined`,调用方必须判断。
118
+
119
+ ## Socket 错误
120
+
121
+ Socket 错误处理在 `Handle` 中实现:
122
+
123
+ ```ts
124
+ onError(msg: any) {
125
+ FW.Log.error("socket error", msg);
126
+ }
127
+
128
+ onTimeout() {
129
+ FW.Entry.evtMgr.dispatch("SOCKET_TIMEOUT");
130
+ }
131
+
132
+ onWeakNetWork() {
133
+ FW.Entry.evtMgr.dispatch("SOCKET_WEAK_NETWORK");
134
+ }
135
+
136
+ onClose() {
137
+ FW.Entry.evtMgr.dispatch("SOCKET_CLOSED");
138
+ }
139
+ ```
140
+
141
+ 框架会处理:
142
+
143
+ - 心跳发送。
144
+ - 弱网检测。
145
+ - 心跳超时重连。
146
+ - 最大重连次数。
147
+ - 协议轮询清理。
148
+
149
+ 业务不要重复实现底层重连循环。
150
+
151
+ ## 事件清理
152
+
153
+ LayerController 销毁时,框架会调用:
154
+
155
+ ```ts
156
+ FW.Entry.timeMgr.unSchedule(this);
157
+ FW.Entry.evtMgr.targetOff(this);
158
+ this.layer?.unscheduleAllCallbacks();
159
+ this.layer?.node?.stopAllActions();
160
+ this.layer?.node?.destroy();
161
+ ```
162
+
163
+ 普通对象或非 Layer 组件必须自行清理:
164
+
165
+ ```ts
166
+ onDestroy() {
167
+ FW.Entry.evtMgr.targetOff(this);
168
+ FW.Entry.timeMgr.unSchedule(this);
169
+ }
170
+ ```
171
+
172
+ UI 事件使用 `uiMgr.register()` 后,可用:
173
+
174
+ ```ts
175
+ FW.Entry.uiMgr.unRegisterTarget(target);
176
+ ```
177
+
178
+ ## 定时器清理
179
+
180
+ 创建定时器时传 target:
181
+
182
+ ```ts
183
+ FW.Entry.timeMgr.schedule(this.tick, 1, cc.macro.REPEAT_FOREVER, this);
184
+ ```
185
+
186
+ 销毁时:
187
+
188
+ ```ts
189
+ FW.Entry.timeMgr.unSchedule(this);
190
+ ```
191
+
192
+ 禁止使用无 target 的长期定时器,除非它属于全局系统并有明确 tag。
193
+
194
+ ## 空值和节点有效性
195
+
196
+ 操作 Cocos 节点前检查:
197
+
198
+ ```ts
199
+ if (!cc.isValid(node)) {
200
+ FW.Log.warn("node invalid");
201
+ return;
202
+ }
203
+ ```
204
+
205
+ `FW.Entry.uiMgr.find()` 找不到节点会返回 `null` 并打印 warn。业务代码要处理:
206
+
207
+ ```ts
208
+ const button = this.find("ConfirmButton", this.layer.node);
209
+ if (!button) return;
210
+ ```
211
+
212
+ ## 错误边界
213
+
214
+ 推荐分层处理:
215
+
216
+ - 网络层:解析、连接、超时错误。
217
+ - Logic:业务失败和重试。
218
+ - Data:不抛 UI 错误。
219
+ - LayerController:展示失败状态、关闭或重试。
220
+
221
+ 不要让底层错误直接导致 UI 生命周期中断且没有日志。
222
+
223
+ ## Codex 错误处理清单
224
+
225
+ 生成代码时必须检查:
226
+
227
+ - 每个 `await` 的失败路径是否可接受。
228
+ - `invoke()` 返回 `undefined` 时是否处理。
229
+ - `openSync()` 返回空是否处理。
230
+ - 节点查找失败是否处理。
231
+ - 事件和定时器是否随 target 清理。
232
+ - 资源路径是否来自 `AssetConfig`。
233
+ - Socket 错误是否在 `Handle` 中有入口。
@@ -0,0 +1,6 @@
1
+ {
2
+ "ver": "2.0.2",
3
+ "uuid": "a955657c-a1bb-4b4a-b218-f17ff5649eb3",
4
+ "importer": "markdown",
5
+ "subMetas": {}
6
+ }