From a74731fff8d3ed36cce818c964fad9b1750a4dd9 Mon Sep 17 00:00:00 2001 From: zzz <1638644816@qq.com> Date: Mon, 16 Jun 2025 09:43:16 +0800 Subject: [PATCH 1/2] 1 --- .obsidian/workspace.json | 131 +- 1Project/宠物宇宙/地图编辑器/需要做的优化.md | 13 +- .../{需要支持的小功能.md => 需要支持的地图功能.md} | 29 +- 1Project/宠物宇宙/版本需求.md | 29 + 1Project/宠物宇宙/皮肤导入.md | 13 - .../业务插件(RTwoGameBusiness)TCP接口设计说明.md | 1541 +++++++++++++++++ .../硬件交互}/用户卡及游戏信息处理过程设计文档.md | 0 1Project/开发文章/将开发文章阅读并分类.md | 1 + 2Areas/提升效率/未命名.md | 5 + .../Unity/loxodon/loxodon-framework Public.md | 5 + InBox/loxodon-framework.md | 0 ... Image - Quality UI Outlines and Shadow-哔哩哔哩】.md | 3 + InBox/网络/封装可扩展网络请求框架.md | 5 + ..._v3_02n6_ff40a1a4-d813-45f7-b132-6f14a74cfd7g.jpg | Bin 0 -> 276849 bytes .../业务插件(RTwoGameBusiness)TCP接口设计说明.md | 1541 +++++++++++++++++ 15 files changed, 3206 insertions(+), 110 deletions(-) rename 1Project/宠物宇宙/地图编辑器/{需要支持的小功能.md => 需要支持的地图功能.md} (55%) create mode 100644 1Project/宠物宇宙/版本需求.md delete mode 100644 1Project/宠物宇宙/皮肤导入.md create mode 100644 1Project/宠物宇宙/硬件交互/业务插件(RTwoGameBusiness)TCP接口设计说明.md rename {4Archives/宠物宇宙 => 1Project/宠物宇宙/硬件交互}/用户卡及游戏信息处理过程设计文档.md (100%) create mode 100644 2Areas/提升效率/未命名.md create mode 100644 3Projects/Unity/loxodon/loxodon-framework Public.md create mode 100644 InBox/loxodon-framework.md create mode 100644 InBox/【Unity插件 - 图标轮廓渲染插件 SDF Image - Quality UI Outlines and Shadow-哔哩哔哩】.md create mode 100644 InBox/网络/封装可扩展网络请求框架.md create mode 100644 渲染/软渲染/图片/img_v3_02n6_ff40a1a4-d813-45f7-b132-6f14a74cfd7g.jpg create mode 100644 渲染/软渲染/图片/业务插件(RTwoGameBusiness)TCP接口设计说明.md diff --git a/.obsidian/workspace.json b/.obsidian/workspace.json index f1f40cb..1b8a66b 100644 --- a/.obsidian/workspace.json +++ b/.obsidian/workspace.json @@ -4,21 +4,21 @@ "type": "split", "children": [ { - "id": "f8022c29023d2af6", + "id": "1890c7ad64a39d65", "type": "tabs", "children": [ { - "id": "efa82152d99167ff", + "id": "3e6f0931816b44e6", "type": "leaf", "state": { "type": "markdown", "state": { - "file": "2Areas/健康/运动-拉伸/八段锦/八段锦.md", + "file": "3Projects/Unity/loxodon/loxodon-framework Public.md", "mode": "source", "source": false }, "icon": "lucide-file", - "title": "八段锦" + "title": "loxodon-framework Public" } } ] @@ -214,92 +214,53 @@ "copilot:Open Copilot Chat": false } }, - "floating": { - "id": "8ad6c7a89369c9f6", - "type": "floating", - "children": [ - { - "id": "ea5faaa0d41b6909", - "type": "window", - "children": [ - { - "id": "5ac5102bf53c6860", - "type": "tabs", - "children": [ - { - "id": "fd65654aeee0713f", - "type": "leaf", - "state": { - "type": "empty", - "state": {}, - "icon": "lucide-file", - "title": "新标签页" - } - } - ] - } - ], - "direction": "vertical", - "x": 2595, - "y": 19, - "width": 1024, - "height": 800, - "maximize": false, - "zoom": 0 - } - ] - }, - "active": "efa82152d99167ff", + "active": "3e6f0931816b44e6", "lastOpenFiles": [ - "2Areas/习惯养成/规范日常行为.md", + "InBox/loxodon-framework.md", + "3Projects/Unity/loxodon/loxodon-framework Public.md", + "3Projects/Unity/loxodon", + "3Projects/Unity", + "3Projects", + "1Project/宠物宇宙/版本需求.md", + "InBox/网络同步.md", + "InBox/obsidian右键扩展.md", + "InBox/接口与抽象类区别.md", + "InBox/【Unity插件 - 图标轮廓渲染插件 SDF Image - Quality UI Outlines and Shadow-哔哩哔哩】.md", + "InBox/资源/资源导入.md", + "InBox/编辑器/时间轴编辑器/Timeline TODO.canvas", + "InBox/编辑器/图片/Pasted image 20221025121100.png", + "1Project/宠物宇宙/地图编辑器/需要做的优化.md", + "1Project/宠物宇宙/地图编辑器/需要支持的地图功能.md", + "1Project/开发文章/将开发文章阅读并分类.md", + "InBox/GAS", + "1Project/宠物宇宙/bug.md", + "1Project/宠物宇宙/硬件交互/业务插件(RTwoGameBusiness)TCP接口设计说明.md", + "1Project/宠物宇宙/硬件交互/用户卡及游戏信息处理过程设计文档.md", + "1Project/宠物宇宙/未命名 1", + "1Project/宠物宇宙/硬件交互", + "渲染/软渲染/图片/业务插件(RTwoGameBusiness)TCP接口设计说明.md", + "InBox/网络/封装可扩展网络请求框架.md", + "InBox/网络", + "2Areas/提升效率/未命名.md", + "2Areas/提升效率", + "渲染/软渲染/图片/img_v3_02n6_ff40a1a4-d813-45f7-b132-6f14a74cfd7g.jpg", + "渲染/软渲染/图片", + "InBox/自动化生成文档/uml.md", + "InBox/自动化生成文档/docfx.md", + "InBox/自动化生成文档", + "InBox/战斗/输入框架/游戏输入框架的设计(基于Unity).md", + "2Areas/健康/运动-拉伸/八段锦/八段锦.md", + "2Areas/如何记录笔记/如何开启一个项目.md", "2Areas/如何记录笔记/笔记如何组织.md", "2Areas/如何记录笔记/段落标记.md", - "2Areas/如何记录笔记/如何结束一个项目.md", - "2Areas/如何记录笔记/如何开启一个项目.md", "2Areas/如何记录笔记/抓捕生活中的灵感.md", - "2Areas/健康/运动-拉伸/八段锦/八段锦.md", - "2Areas/习惯养成", - "2Areas/如何记录笔记", - "InBox/编辑器/时间轴编辑器/Timeline TODO.canvas", - "1Project/开发文章/将开发文章阅读并分类.md", - "4Archives/宠物宇宙/用户卡及游戏信息处理过程设计文档.md", - "2Areas/健康/运动-拉伸/八段锦", - "4Archives/All in hole/查看UIGame代码.md", - "4Archives/All in hole/还原材质球.md", - "4Archives/All in hole/玩法.md", - "1Project/宠物宇宙/bug.md", - "4Archives/All in hole/编辑器.md", - "渲染/软渲染/图片/Pasted image 20250609171235.png", - "InBox/AI for Obsidian/20250315 - 测试 Obsidian+ AI 的能力边界/第五个用法|成为插件助手/Dataview 插件/测试用文档/项目复盘会议.md", - "InBox/AI for Obsidian/20250315 - 测试 Obsidian+ AI 的能力边界/第五个用法|成为插件助手/Dataview 插件/测试用文档/项目A计划.md", - "InBox/AI for Obsidian/20250315 - 测试 Obsidian+ AI 的能力边界/第五个用法|成为插件助手/Dataview 插件/测试用文档/财务季度报告.md", - "InBox/AI for Obsidian/20250315 - 测试 Obsidian+ AI 的能力边界/第五个用法|成为插件助手/Dataview 插件/测试用文档/简易待办事项.md", - "InBox/AI for Obsidian/20250315 - 测试 Obsidian+ AI 的能力边界/第五个用法|成为插件助手/Dataview 插件/测试用文档/用户反馈分析.md", - "InBox/AI for Obsidian/20250315 - 测试 Obsidian+ AI 的能力边界/第五个用法|成为插件助手/Dataview 插件/测试用文档/每周例会记录.md", - "InBox/AI for Obsidian/20250315 - 测试 Obsidian+ AI 的能力边界/第五个用法|成为插件助手/Dataview 插件/测试用文档/技术架构设计.md", - "InBox/AI for Obsidian/20250315 - 测试 Obsidian+ AI 的能力边界/第五个用法|成为插件助手/Dataview 插件/测试用文档/市场调研报告.md", - "InBox/AI for Obsidian/20250315 - 测试 Obsidian+ AI 的能力边界/第五个用法|成为插件助手/Dataview 插件/测试用文档/产品功能需求.md", - "InBox/AI for Obsidian/20250315 - 测试 Obsidian+ AI 的能力边界/第五个用法|成为插件助手/Dataview 插件/测试用文档/团队建设活动.md", - "InBox/AI for Obsidian/20250315 - 测试 Obsidian+ AI 的能力边界/第五个用法|成为插件助手/Dataview 插件/测试用文档/Bug修复计划.md", - "InBox/AI for Obsidian/20250315 - 测试 Obsidian+ AI 的能力边界/第一个用法|查漏补缺/如何搞钱/小白金融知识/20_理财书籍推荐与学习资源:持续学习,不断进步.md", - "InBox/AI for Obsidian/20250315 - 测试 Obsidian+ AI 的能力边界/第五个用法|成为插件助手/Dataview 插件/测试用文档", - "InBox/AI for Obsidian/20250315 - 测试 Obsidian+ AI 的能力边界/第四个用法|成为对弈的棋手/正方观点/观点9.md.edtz", - "InBox/AI for Obsidian/20250315 - 测试 Obsidian+ AI 的能力边界/第四个用法|成为对弈的棋手/正方观点/观点8.md.edtz", - "InBox/AI for Obsidian/20250315 - 测试 Obsidian+ AI 的能力边界/第四个用法|成为对弈的棋手/正方观点/观点7.md.edtz", - "InBox/AI for Obsidian/20250315 - 测试 Obsidian+ AI 的能力边界/第四个用法|成为对弈的棋手/正方观点/观点6.md.edtz", - "InBox/AI for Obsidian/20250315 - 测试 Obsidian+ AI 的能力边界/第四个用法|成为对弈的棋手/正方观点/观点5.md.edtz", - "InBox/AI for Obsidian/20250315 - 测试 Obsidian+ AI 的能力边界/第四个用法|成为对弈的棋手/正方观点/观点4.md.edtz", - "InBox/渲染/软渲染/图片/Pasted image 20230613102109.png", - "InBox/渲染/GPU/Pasted image 20230413163234.png", - "InBox/编辑器/图片/Pasted image 20221025121100.png", - "InBox/Mesh/图片/Pasted image 20221021171104.png", - "InBox/战斗/动作时间轴 随想.canvas", - "编辑器/图片/Pasted image 20221025121100.png", - "编辑器/时间轴编辑器/Timeline TODO.canvas", - "渲染/软渲染/图片/Pasted image 20230613102109.png", - "渲染/GPU/Pasted image 20230413163234.png", - "Mesh/图片/Pasted image 20221021171104.png", + "2Areas/如何记录笔记/如何结束一个项目.md", "InBox/TODO.canvas", + "渲染/软渲染/图片/Pasted image 20250609171235.png", + "InBox/战斗/动作时间轴 随想.canvas", + "InBox/渲染/GPU/Pasted image 20230413163234.png", + "InBox/Mesh/图片/Pasted image 20221021171104.png", + "InBox/渲染/软渲染/图片/Pasted image 20230613102109.png", "未命名 1.canvas", "并行计算/GPU.canvas", "并行计算/CPU.canvas", diff --git a/1Project/宠物宇宙/地图编辑器/需要做的优化.md b/1Project/宠物宇宙/地图编辑器/需要做的优化.md index 13a872d..1e216be 100644 --- a/1Project/宠物宇宙/地图编辑器/需要做的优化.md +++ b/1Project/宠物宇宙/地图编辑器/需要做的优化.md @@ -1,6 +1,7 @@ ##### 流程组件 - [ ] **构建流程组件** + 抽象成管线 找出运行时和编辑器共有的模块 把这些模块做成组件 运行时和编辑器分别实例不同的组件 @@ -19,6 +20,11 @@ - 预览图 - 地板数据,长宽高, - 地板承载的摆件怪物标志信息 + 缺点: + - SO文件会实时改动到实际的物体的配置数据 + 但编辑器通常的模式是,需要dirty,不想保存的修改,不能直接修改到原有的数据 + - 对于无法序列化的东西无法保存,比如字典,参考路线配置,需要存一份文本配置来做序列化的事情 + - Json文件 - 一份额外信息,key为mapIndex,value为对应的额外信息 - StreamingAssetPath中 @@ -27,7 +33,12 @@ - 新的数据结构 - 文件夹下 - - + - 所有地板以及地板摆放的物体.json + - 一份关于地图的数据,地图Id,地图名字 + - 预览图 + - 配置表 + - 波次数据 + - 房间从1001开头用 多主键联合的方式 ##### 重新梳理关系和职责 ###### SpreadMap和SpreadMapLevel diff --git a/1Project/宠物宇宙/地图编辑器/需要支持的小功能.md b/1Project/宠物宇宙/地图编辑器/需要支持的地图功能.md similarity index 55% rename from 1Project/宠物宇宙/地图编辑器/需要支持的小功能.md rename to 1Project/宠物宇宙/地图编辑器/需要支持的地图功能.md index fd10f64..4e490bf 100644 --- a/1Project/宠物宇宙/地图编辑器/需要支持的小功能.md +++ b/1Project/宠物宇宙/地图编辑器/需要支持的地图功能.md @@ -3,24 +3,25 @@ > [!important] 优先级 **1** - - [x] 添加RoomComponents - - [ ] IExtension - - [ ] 生成怪物测试 - - [ ] id不再自增长 - - [x] 碰撞盒和标志需要添加自定义功能 + + - [x] IExtension + - [x] 创建地块的Width和Height + - [x] A*报错 + - ![[img_v3_02n6_ff40a1a4-d813-45f7-b132-6f14a74cfd7g.jpg]] + - [x] 松鼠异常 - [ ] 地图地板图片导入 自动修改图片大小 - [ ] 添加白膜地图 - - 创建100*100的地图,宽高跟随Rect大小变化 + - 创建100 - 100的地图,宽高跟随Rect大小变化 - - [ ] 将RoomConfig改到==关卡表==里 - RoomConfig的内容为SpecialRoom - - [ ] 碰撞盒需要添加旋转 - + - [x] 碰撞盒需要添加旋转 > [!note] 优先级 **2** + - [ ] id不再自增长 + - [ ] 将RoomConfig改到==关卡表==里 + RoomConfig的内容为SpecialRoom - [ ] 枚举改为英文名 - [ ] 瓦片地图 - [ ] 优化重构 @@ -30,6 +31,8 @@ > [!note] 优先级 **3** - [ ] 提取单个地块编辑 + - [ ] 添加脏标单个保存地块 + - [ ] 编辑地块的操作逻辑 > [!note] 优先级 **4** @@ -37,4 +40,8 @@ - [ ] 地图大背景优化移动方案 - \ No newline at end of file + > [!success] 已完成 + + - [x] 添加RoomComponents + - [x] 生成怪物测试 + - [x] 碰撞盒和标志需要添加自定义功能 \ No newline at end of file diff --git a/1Project/宠物宇宙/版本需求.md b/1Project/宠物宇宙/版本需求.md new file mode 100644 index 0000000..64e45fd --- /dev/null +++ b/1Project/宠物宇宙/版本需求.md @@ -0,0 +1,29 @@ + +> # 此版本 + + +- [x] 皮肤导入 + - [x] 上海限定 C:\Users\1\Desktop\cache\57015 + - 游戏中 + - [x] C:\Users\1\Desktop\cache\红/蓝/绿皮肤7.0 + - [x] 胳膊导入 + - 结算 + - [x] C:\Users\1\Desktop\cache\角色胜利结算 + - 卡面 + - [x] C:\Users\1\Desktop\cache\第三弹裁切输出 + - UI名字 + - [x] C:\Users\1\Desktop\cache\皮肤 +- [ ] 枪械宠物UI导入 +- [ ] 测试网络点数 开机检测 +- [ ] 地图编辑器 [[需要支持的地图功能]] + - [ ] Boss立绘 + - [ ] C:\Users\1\Desktop\cache\雷鸟血条UI + +--- + + + +> ## 下个版本 + + - [ ] 网络状态3\4 + [[1Project/宠物宇宙/硬件交互/业务插件(RTwoGameBusiness)TCP接口设计说明]] diff --git a/1Project/宠物宇宙/皮肤导入.md b/1Project/宠物宇宙/皮肤导入.md deleted file mode 100644 index 6b7056b..0000000 --- a/1Project/宠物宇宙/皮肤导入.md +++ /dev/null @@ -1,13 +0,0 @@ - -- [ ] 皮肤导入 - - [x] 上海限定 C:\Users\1\Desktop\cache\57015 - - 游戏中 - - [x] C:\Users\1\Desktop\cache\红/蓝/绿皮肤7.0 - - [ ] 胳膊导入 - - 结算 - - [x] C:\Users\1\Desktop\cache\角色胜利结算 - - 卡面 - - [x] C:\Users\1\Desktop\cache\第三弹裁切输出 - - UI名字 - - [ ] C:\Users\1\Desktop\cache\皮肤 - diff --git a/1Project/宠物宇宙/硬件交互/业务插件(RTwoGameBusiness)TCP接口设计说明.md b/1Project/宠物宇宙/硬件交互/业务插件(RTwoGameBusiness)TCP接口设计说明.md new file mode 100644 index 0000000..2db50d1 --- /dev/null +++ b/1Project/宠物宇宙/硬件交互/业务插件(RTwoGameBusiness)TCP接口设计说明.md @@ -0,0 +1,1541 @@ +# 业务插件(RTwoGameBusiness)TCP接口说明 + +## 1. 文档概述 + +### 1.1 版本 + +| 版本号 | 日期 | 作者 | 变更内容 | 状态 | +|-------|------|------|---------|------| +| 1.0 | 2025-05-29 | JJX | 初始创建 | 正式发布 | +| 1.1 | 2025-06-15 | JJX | 添加get-system-info接口说明和更新check-unis-net-state接口说明 | 正式发布 | + +### 1.2 目的 + +本文档详细描述RTwoGameBusiness业务插件提供的TCP接口规范,用于游戏客户端与业务插件之间的通信。该文档面向开发人员、测试人员和集成人员,提供接口的详细说明、参数格式、错误码以及使用示例。 + +### 1.3 适用范围 + +- 开发人员:用于实现游戏客户端与业务插件的通信 +- 测试人员:用于验证接口功能和性能 +- 集成人员:用于系统集成和故障排查 +- 维护人员:用于系统维护和问题定位 + +### 1.4 接口概述 + +RTwoGameBusiness插件通过TCP协议提供服务,主要包括以下功能类别: + +1. **用户卡功能**:用户信息查询、刷卡登录等 +2. **点数卡功能**:点数查询、充值、扣点等 +3. **游戏记录功能**:游戏积分、金币、宝石、卡牌、投币记录等 +4. **4G网络控制**:4G模块状态查询、启动和停止等 + +## 2. 基础信息 + +### 2.1 服务端口 + +RTwoGameBusiness插件默认监听TCP端口:**12103** + +该端口可通过配置文件修改,修改后需重启插件生效。 + +### 2.2 通信协议 + +- 通信协议:TCP +- 字符编码:UTF-8 +- 数据格式:JSON + +### 2.3 请求格式 + +所有请求都应遵循以下JSON格式: + +```json +{ + "command": "命令名称", + "data": { + // 根据不同命令类型包含不同的参数 + }, + "ts": 1621234567890 // 可选,请求时间戳(毫秒) +} +``` + +### 2.4 响应格式 + +所有响应都遵循以下JSON格式: + +```json +{ + "result": true, // 响应结果,true成功,false失败 + "errMsg": "", // 错误信息,成功时为空 + "statusCode": 0, // 状态码,0表示成功,非0表示各种错误 + "command": "命令名称", // 关联的指令标识 + "data": { // 返回数据,根据不同接口有不同结构 + // 根据不同命令返回不同的数据 + }, + "ts": 1621234567890 // 可选,响应时间戳(毫秒) +} +``` + +## 3. 接口详细说明 + +根据功能分类,本章节将详细介绍RTwoGameBusiness插件提供的所有TCP接口。 + +### 3.1 用户卡功能接口 + +#### 3.1.1 用户信息查询 (select-user-info) + +该接口用于查询用户卡所绑定的用户信息,并可选择性地返回排行榜数据。 + +**请求命令**:`select-user-info` + +**请求参数**: + +| 参数名 | 类型 | 必填 | 说明 | +|-------|------|------|------| +| cardId | string | 是(与cardSn二选一) | 卡ID | +| cardSn | string | 是(与cardId二选一) | 卡序列号 | +| gameLevel | string | 否 | 游戏关卡,不传则返回所有关卡的排行榜 | +| topLimit | int | 否 | 排行榜条数限制,默认为10 | +| topType | int | 否 | 排行榜类型:0=积分排行榜(默认),1=时长排行榜 | + +**请求示例**: + +```json +{ + "command": "select-user-info", + "data": { + "cardId": "1234567890", + "gameLevel": "1", + "topLimit": 10, + "topType": 0 + } +} +``` + +**响应参数**: + +| 参数名 | 类型 | 说明 | +|-------|------|------| +| cardId | string | 卡ID | +| cardSn | string | 卡序列号 | +| userName | string | 用户名称 | +| userAvatar | string | 用户头像URL | +| userSex | int | 用户性别:0-未知 1-男 2-女 | +| topType | int | 排行榜类型:0=积分排行榜,1=时长排行榜 | +| leaderboards | object | 按游戏关卡分组的排行榜,key为游戏关卡 | + +**leaderboards对象内部结构**: + +| 参数名 | 类型 | 说明 | +|-------|------|------| +| rank | int | 用户在此排行榜中的排名 | +| score | int | 用户在此排行榜中的积分(当topType=0时有效) | +| duration | int | 用户在此排行榜中的游戏时长(当topType=1时有效) | +| gameLevel | string | 游戏关卡 | +| records | array | 排行榜记录列表 | + +**records数组内部结构**: + +| 参数名 | 类型 | 说明 | +|-------|------|------| +| id | int | 记录ID | +| cardId | string | 卡ID | +| userName | string | 用户名称 | +| score | int | 游戏得分 | +| gameDuration | int | 游戏时长(秒) | +| playTime | string | 游戏时间(格式化字符串) | +| gameLevel | string | 游戏关卡 | +| gameType | string | 游戏类型 | +| skinId | string | 皮肤ID | +| playerCount | int | 共同游戏的玩家数量 | + +**响应示例**: + +```json +{ + "result": true, + "errMsg": "", + "statusCode": 0, + "command": "select-user-info", + "data": { + "cardId": "1234567890", + "cardSn": "A1B2C3D4", + "userName": "玩家001", + "userAvatar": "http://example.com/avatar/001.jpg", + "userSex": 1, + "topType": 0, + "leaderboards": { + "1": { + "rank": 3, + "score": 1500, + "gameLevel": "1", + "records": [ + { + "id": 123, + "cardId": "9876543210", + "userName": "玩家088", + "score": 2000, + "gameDuration": 300, + "playTime": "2025-05-28 14:30:00", + "gameLevel": "1", + "gameType": "standard", + "skinId": "skin_001", + "playerCount": 1 + }, + { + "id": 124, + "cardId": "8765432109", + "userName": "玩家072", + "score": 1800, + "gameDuration": 280, + "playTime": "2025-05-28 15:20:00", + "gameLevel": "1", + "gameType": "standard", + "skinId": "skin_002", + "playerCount": 1 + }, + { + "id": 125, + "cardId": "1234567890", + "userName": "玩家001", + "score": 1500, + "gameDuration": 260, + "playTime": "2025-05-28 16:10:00", + "gameLevel": "1", + "gameType": "standard", + "skinId": "skin_003", + "playerCount": 1 + } + ] + } + } + } +} +``` + +**错误码说明**: + +| 状态码 | 说明 | +|-------|------| +| 0 | 成功 | +| 1 | 通用错误 | +| 10 | 参数错误(卡ID和卡序列号都为空) | +| 40 | 用户不存在 | + +**备注**: +1. 卡ID和卡序列号必须至少提供一个,优先使用卡ID查询。 +2. 如果未指定排行榜类型,默认返回积分排行榜。 +3. 如果未指定游戏关卡,将返回所有关卡的排行榜数据。 +4. 排行榜数据按分数或时长降序排列。 + +#### 3.1.2 刷卡登录 (cwyz-swipe-card) + +该接口用于处理游戏中的刷卡操作,关联用户与游戏。 + +**请求命令**:`cwyz-swipe-card` + +**请求参数**: + +| 参数名 | 类型 | 必填 | 说明 | +|-------|------|------|------| +| cardSn | string | 是 | 卡序列号 | +| playerIdx | int | 是 | 玩家索引,用于多人游戏时区分不同玩家位置 | + +**请求示例**: + +```json +{ + "command": "cwyz-swipe-card", + "data": { + "cardSn": "A1B2C3D4", + "playerIdx": 1 + } +} +``` + +**响应参数**: + +| 参数名 | 类型 | 说明 | +|-------|------|------| +| cardId | string | 卡ID | +| cardSn | string | 卡序列号 | +| userName | string | 用户名称 | +| userAvatar | string | 用户头像URL | +| userSex | int | 用户性别:0-未知 1-男 2-女 | +| playerIdx | int | 玩家索引 | + +**响应示例**: + +```json +{ + "result": true, + "errMsg": "", + "statusCode": 0, + "command": "cwyz-swipe-card", + "data": { + "cardId": "1234567890", + "cardSn": "A1B2C3D4", + "userName": "玩家001", + "userAvatar": "http://example.com/avatar/001.jpg", + "userSex": 1, + "playerIdx": 1 + } +} +``` + +**错误码说明**: + +| 状态码 | 说明 | +|-------|------| +| 0 | 成功 | +| 1 | 通用错误 | +| 10 | 参数错误(卡序列号为空) | +| 40 | 用户卡不存在 | +| 30 | 网络错误(与服务器通信失败) | + +**备注**: +1. 刷卡操作会尝试从服务器获取最新的用户信息,如果网络不可用,会使用本地存储的用户信息。 +2. 玩家索引用于区分多人游戏时的不同位置,通常从1开始,对应游戏机的不同位置。 +3. 如果卡片未绑定用户,会返回默认的用户信息。 + +### 3.2 点数卡功能接口 + +#### 3.2.1 查询剩余点数 (get-remaining-points) + +该接口用于查询当前游戏机剩余的点数,用于显示给用户或判断是否有足够点数执行出卡操作。 + +**请求命令**:`get-remaining-points` + +**请求参数**: +无需参数 + +**请求示例**: + +```json +{ + "command": "get-remaining-points", + "data": {} +} +``` + +**响应参数**: + +| 参数名 | 类型 | 说明 | +|-------|------|------| +| remainingPoints | int | 剩余点数 | + +**响应示例**: + +```json +{ + "result": true, + "errMsg": "", + "statusCode": 0, + "command": "get-remaining-points", + "data": { + "remainingPoints": 100 + } +} +``` + +**错误码说明**: + +| 状态码 | 说明 | +|-------|------| +| 0 | 成功 | +| 1 | 通用错误 | +| 20 | 数据库错误(读取点数卡信息失败) | + +**备注**: +1. 此接口会返回所有已绑定点数卡的剩余点数总和。 +2. 如果没有任何点数卡,返回的剩余点数为0。 +3. 点数信息优先从本地数据库获取,确保即使在网络不可用时也能正常工作。 + +#### 3.2.2 绑定点卡 (bind-point-card) + +该接口用于绑定新的点数卡到游戏机上。 + +**请求命令**:`bind-point-card` + +**请求参数**: + +| 参数名 | 类型 | 必填 | 说明 | +|-------|------|------|------| +| cardCode | string | 是 | 点卡卡号 | + +**请求示例**: + +```json +{ + "command": "bind-point-card", + "data": { + "cardCode": "PC12345678" + } +} +``` + +**响应参数**: + +| 参数名 | 类型 | 说明 | +|-------|------|------| +| remainingPoints | int | 绑定后的剩余点数 | + +**响应示例**: + +```json +{ + "result": true, + "errMsg": "", + "statusCode": 0, + "command": "bind-point-card", + "data": { + "remainingPoints": 100 + } +} +``` + +**错误码说明**: + +| 状态码 | 说明 | +|-------|------| +| 0 | 成功 | +| 1 | 通用错误 | +| 10 | 参数错误(卡号为空) | +| 20 | 数据库错误(绑定点数卡失败) | +| 60 | 卡片不存在(点卡号无效) | +| 61 | 点卡已使用 | + +**备注**: +1. 绑定点卡后,点数将自动添加到游戏机的总点数中。 +2. 一个点卡只能被绑定一次,绑定后不能重复使用。 +3. 点卡绑定后立即生效,无需重启游戏机。 + +#### 3.2.3 出卡扣点 (deduct-points) + +该接口用于游戏出卡时扣除相应点数。 + +**请求命令**:`deduct-points` + +**请求参数**: + +| 参数名 | 类型 | 必填 | 说明 | +|-------|------|------|------| +| pointsToDeduct | int | 否 | 需要扣除的点数,默认为1 | +| playerIdx | int | 否 | 机台位置索引,默认为1 | + +**请求示例**: + +```json +{ + "command": "deduct-points", + "data": { + "pointsToDeduct": 1, + "playerIdx": 1 + } +} +``` + +**响应参数**: + +| 参数名 | 类型 | 说明 | +|-------|------|------| +| remainingPoints | int | 扣除后的剩余点数 | +| isUploaded | bool | 是否已上报到服务器 | + +**响应示例**: + +```json +{ + "result": true, + "errMsg": "", + "statusCode": 0, + "command": "deduct-points", + "data": { + "remainingPoints": 99, + "isUploaded": true + } +} +``` + +**错误码说明**: + +| 状态码 | 说明 | +|-------|------| +| 0 | 成功 | +| 1 | 通用错误 | +| 10 | 参数错误(扣点数量无效) | +| 20 | 数据库错误(扣点操作失败) | +| 50 | 点数不足 | + +**备注**: +1. 扣点操作会根据当前配置的扣点模式执行(本地模式、实时模式或混合模式)。 +2. 如果使用本地模式,操作会先在本地执行,然后在适当时机上报到服务器。 +3. 如果使用实时模式,操作会直接上报到服务器,并立即返回结果。 +4. 如果点数不足,将返回错误码50。 +5. 每次扣点操作都会记录在扣点记录表中,用于后续统计和审计。 + +### 3.3 游戏记录功能接口 + +#### 3.3.1 保存游戏积分 (cwyz-score-save) + +该接口用于保存玩家的游戏积分和相关游戏数据,同时可以获取游戏排行榜信息。 + +**请求命令**:`cwyz-score-save` + +**请求参数**: + +| 参数名 | 类型 | 必填 | 说明 | +|-------|------|------|------| +| cardId | string | 是 | 卡ID,用于关联用户 | +| score | int | 是 | 游戏得分 | +| gameLevel | string | 是 | 游戏关卡 | +| gameType | string | 是 | 游戏类型 | +| topLimit | int | 否 | 排行榜总数,默认为10 | +| gameDuration | int | 否 | 游戏时长(秒) | +| golds | int | 否 | 获得金币数量 | +| gemstone | int | 否 | 获得的未鉴定宝石数量 | +| playerIdx | int | 否 | 玩家索引,默认为1 | +| skinId | string | 否 | 皮肤ID | +| playerCount | int | 否 | 共同游戏的玩家数量,默认为1 | + +**请求示例**: + +```json +{ + "command": "cwyz-score-save", + "data": { + "cardId": "1234567890", + "score": 1500, + "gameLevel": "1", + "gameType": "standard", + "topLimit": 10, + "gameDuration": 300, + "golds": 50, + "gemstone": 2, + "playerIdx": 1, + "skinId": "skin_001", + "playerCount": 1 + } +} +``` + +**响应参数**: + +| 参数名 | 类型 | 说明 | +|-------|------|------| +| gameType | string | 游戏类型 | +| leaderboards | object | 按游戏关卡分组的排行榜,key为游戏关卡 | + +**leaderboards对象内部结构**: + +| 参数名 | 类型 | 说明 | +|-------|------|------| +| rank | int | 用户在此排行榜中的排名 | +| score | int | 用户在此排行榜中的积分 | +| gameLevel | string | 游戏关卡 | +| records | array | 排行榜记录列表 | + +**records数组内部结构**: + +| 参数名 | 类型 | 说明 | +|-------|------|------| +| id | int | 记录ID | +| cardId | string | 卡ID | +| userName | string | 用户名称 | +| score | int | 游戏得分 | +| gameDuration | int | 游戏时长(秒) | +| playTime | string | 游戏时间(格式化字符串) | +| gameLevel | string | 游戏关卡 | +| gameType | string | 游戏类型 | +| skinId | string | 皮肤ID | +| playerCount | int | 共同游戏的玩家数量 | + +**响应示例**: + +```json +{ + "result": true, + "errMsg": "", + "statusCode": 0, + "command": "cwyz-score-save", + "data": { + "gameType": "standard", + "leaderboards": { + "1": { + "rank": 3, + "score": 1500, + "gameLevel": "1", + "records": [ + { + "id": 123, + "cardId": "9876543210", + "userName": "玩家088", + "score": 2000, + "gameDuration": 300, + "playTime": "2025-05-28 14:30:00", + "gameLevel": "1", + "gameType": "standard", + "skinId": "skin_001", + "playerCount": 1 + }, + { + "id": 124, + "cardId": "8765432109", + "userName": "玩家072", + "score": 1800, + "gameDuration": 280, + "playTime": "2025-05-28 15:20:00", + "gameLevel": "1", + "gameType": "standard", + "skinId": "skin_002", + "playerCount": 1 + }, + { + "id": 125, + "cardId": "1234567890", + "userName": "玩家001", + "score": 1500, + "gameDuration": 260, + "playTime": "2025-05-28 16:10:00", + "gameLevel": "1", + "gameType": "standard", + "skinId": "skin_003", + "playerCount": 1 + } + ] + } + } + } +} +``` + +**错误码说明**: + +| 状态码 | 说明 | +|-------|------| +| 0 | 成功 | +| 1 | 通用错误 | +| 10 | 参数错误(必填参数缺失) | +| 20 | 数据库错误(保存积分失败) | +| 40 | 用户不存在 | + +**备注**: +1. 如果提供了金币(golds)参数且大于0,系统会自动调用保存金币记录的功能。 +2. 如果提供了宝石(gemstone)参数且大于0,系统会自动调用保存宝石记录的功能。 +3. 积分数据会根据游戏类型和游戏关卡进行分类,便于后续查询。 +4. 响应中的排行榜数据包含当前用户的排名和指定数量的最高分记录。 +5. 如果用户卡ID不存在,系统会尝试创建一个游客记录。 + +#### 3.3.2 获取游戏排行榜 (cwyz-query-score-top) + +该接口用于获取游戏排行榜信息。 + +**请求命令**:`cwyz-query-score-top` + +**请求参数**: + +| 参数名 | 类型 | 必填 | 说明 | +|-------|------|------|------| +| gameType | string | 是 | 游戏类型 | +| gameLevel | string | 否 | 游戏关卡,不传则返回所有关卡的排行榜 | +| topLimit | int | 否 | 需要查询的排行榜条数,默认为10 | +| isGlobal | bool | 否 | 是否获取全网排名,默认为false(即默认获取本地排名) | + +**请求示例**: + +```json +{ + "command": "cwyz-query-score-top", + "data": { + "gameType": "standard", + "gameLevel": "1", + "topLimit": 10, + "isGlobal": false + } +} +``` + +**响应参数**: + +| 参数名 | 类型 | 说明 | +|-------|------|------| +| gameType | string | 游戏类型 | +| leaderboards | object | 按游戏关卡分组的排行榜,key为游戏关卡 | + +**leaderboards对象内部结构**: + +| 参数名 | 类型 | 说明 | +|-------|------|------| +| rank | int | 用户在此排行榜中的排名 | +| score | int | 用户在此排行榜中的积分 | +| gameLevel | string | 游戏关卡 | +| records | array | 排行榜记录列表 | + +**records数组内部结构**: + +| 参数名 | 类型 | 说明 | +|-------|------|------| +| id | int | 记录ID | +| cardId | string | 卡ID | +| userName | string | 用户名称 | +| score | int | 游戏得分 | +| gameDuration | int | 游戏时长(秒) | +| playTime | string | 游戏时间(格式化字符串) | +| gameLevel | string | 游戏关卡 | +| gameType | string | 游戏类型 | +| skinId | string | 皮肤ID | +| playerCount | int | 共同游戏的玩家数量 | + +**响应示例**: + +```json +{ + "result": true, + "errMsg": "", + "statusCode": 0, + "command": "cwyz-query-score-top", + "data": { + "gameType": "standard", + "leaderboards": { + "1": { + "rank": 3, + "score": 1500, + "gameLevel": "1", + "records": [ + { + "id": 123, + "cardId": "9876543210", + "userName": "玩家088", + "score": 2000, + "gameDuration": 300, + "playTime": "2025-05-28 14:30:00", + "gameLevel": "1", + "gameType": "standard", + "skinId": "skin_001", + "playerCount": 1 + }, + { + "id": 124, + "cardId": "8765432109", + "userName": "玩家072", + "score": 1800, + "gameDuration": 280, + "playTime": "2025-05-28 15:20:00", + "gameLevel": "1", + "gameType": "standard", + "skinId": "skin_002", + "playerCount": 1 + }, + { + "id": 125, + "cardId": "1234567890", + "userName": "玩家001", + "score": 1500, + "gameDuration": 260, + "playTime": "2025-05-28 16:10:00", + "gameLevel": "1", + "gameType": "standard", + "skinId": "skin_003", + "playerCount": 1 + } + ] + } + } + } +} +``` + +**错误码说明**: + +| 状态码 | 说明 | +|-------|------| +| 0 | 成功 | +| 1 | 通用错误 | +| 10 | 参数错误(必填参数缺失) | +| 20 | 数据库错误(获取排行榜失败) | +| 40 | 用户不存在 | + +**备注**: +1. 排行榜数据包含当前用户的排名和指定数量的最高分记录。 +2. 如果用户卡ID不存在,系统会尝试创建一个游客记录。 + +#### 3.3.3 获取游戏时长排行榜 (cwyz-query-duration-top) + +该接口用于获取游戏时长排行榜信息。 + +**请求命令**:`cwyz-query-duration-top` + +**请求参数**: + +| 参数名 | 类型 | 必填 | 说明 | +|-------|------|------|------| +| gameType | string | 是 | 游戏类型 | +| gameLevel | string | 否 | 游戏关卡,不传则返回所有关卡的排行榜 | +| topLimit | int | 否 | 需要查询的排行榜条数,默认为10 | +| isGlobal | bool | 否 | 是否获取全网排名,默认为false(即默认获取本地排名) | + +**请求示例**: + +```json +{ + "command": "cwyz-query-duration-top", + "data": { + "gameType": "standard", + "gameLevel": "1", + "topLimit": 10, + "isGlobal": false + } +} +``` + +**响应参数**: + +| 参数名 | 类型 | 说明 | +|-------|------|------| +| gameType | string | 游戏类型 | +| leaderboards | object | 按游戏关卡分组的排行榜,key为游戏关卡 | + +**leaderboards对象内部结构**: + +| 参数名 | 类型 | 说明 | +|-------|------|------| +| rank | int | 用户在此排行榜中的排名 | +| duration | int | 用户在此排行榜中的游戏时长(秒) | +| gameLevel | string | 游戏关卡 | +| records | array | 排行榜记录列表 | + +**records数组内部结构**: + +| 参数名 | 类型 | 说明 | +|-------|------|------| +| id | int | 记录ID | +| cardId | string | 卡ID | +| userName | string | 用户名称 | +| score | int | 游戏得分 | +| gameDuration | int | 游戏时长(秒) | +| playTime | string | 游戏时间(格式化字符串) | +| gameLevel | string | 游戏关卡 | +| gameType | string | 游戏类型 | +| skinId | string | 皮肤ID | +| playerCount | int | 共同游戏的玩家数量 | + +**响应示例**: + +```json +{ + "result": true, + "errMsg": "", + "statusCode": 0, + "command": "cwyz-query-duration-top", + "data": { + "gameType": "standard", + "leaderboards": { + "1": { + "rank": 2, + "duration": 280, + "gameLevel": "1", + "records": [ + { + "id": 123, + "cardId": "9876543210", + "userName": "玩家088", + "score": 1800, + "gameDuration": 320, + "playTime": "2025-05-28 14:30:00", + "gameLevel": "1", + "gameType": "standard", + "skinId": "skin_001", + "playerCount": 1 + }, + { + "id": 124, + "cardId": "1234567890", + "userName": "玩家001", + "score": 1500, + "gameDuration": 280, + "playTime": "2025-05-28 15:20:00", + "gameLevel": "1", + "gameType": "standard", + "skinId": "skin_002", + "playerCount": 1 + }, + { + "id": 125, + "cardId": "8765432109", + "userName": "玩家072", + "score": 1200, + "gameDuration": 240, + "playTime": "2025-05-28 16:10:00", + "gameLevel": "1", + "gameType": "standard", + "skinId": "skin_003", + "playerCount": 1 + } + ] + } + } + } +} +``` + +**错误码说明**: + +| 状态码 | 说明 | +|-------|------| +| 0 | 成功 | +| 1 | 通用错误 | +| 10 | 参数错误(游戏类型为空) | +| 20 | 数据库错误(获取排行榜失败) | + +**备注**: +1. 该接口专门用于获取按游戏时长排序的排行榜。 +2. 排行榜数据按游戏时长降序排列。 +3. 如果设置isGlobal为true,将获取全网的排行榜数据,可能需要更长的响应时间。 + +#### 3.3.4 统一获取游戏排行榜 (cwyz-query-top) + +该接口统一了获取积分排行榜和时长排行榜的功能,通过topType参数区分不同类型的排行榜。 + +**请求命令**:`cwyz-query-top` + +**请求参数**: + +| 参数名 | 类型 | 必填 | 说明 | +|-------|------|------|------| +| gameType | string | 是 | 游戏类型 | +| gameLevel | string | 否 | 游戏关卡,不传则返回所有关卡的排行榜 | +| topLimit | int | 否 | 需要查询的排行榜条数,默认为10 | +| topType | int | 是 | 排行榜类型:0=积分排行榜,1=时长排行榜 | +| isGlobal | bool | 否 | 是否获取全网排名,默认为false(即默认获取本地排名) | + +**请求示例**: + +```json +{ + "command": "cwyz-query-top", + "data": { + "gameType": "standard", + "gameLevel": "1", + "topLimit": 10, + "topType": 0, + "isGlobal": false + } +} +``` + +**响应参数**: + +| 参数名 | 类型 | 说明 | +|-------|------|------| +| gameType | string | 游戏类型 | +| topType | int | 排行榜类型:0=积分排行榜,1=时长排行榜 | +| leaderboards | object | 按游戏关卡分组的排行榜,key为游戏关卡 | + +**leaderboards对象内部结构**: + +| 参数名 | 类型 | 说明 | +|-------|------|------| +| rank | int | 用户在此排行榜中的排名 | +| score | int | 用户在此排行榜中的积分(当topType=0时有效) | +| duration | int | 用户在此排行榜中的游戏时长(当topType=1时有效) | +| gameLevel | string | 游戏关卡 | +| records | array | 排行榜记录列表 | + +**records数组内部结构**: + +| 参数名 | 类型 | 说明 | +|-------|------|------| +| id | int | 记录ID | +| cardId | string | 卡ID | +| userName | string | 用户名称 | +| score | int | 游戏得分 | +| gameDuration | int | 游戏时长(秒) | +| playTime | string | 游戏时间(格式化字符串) | +| gameLevel | string | 游戏关卡 | +| gameType | string | 游戏类型 | +| skinId | string | 皮肤ID | +| playerCount | int | 共同游戏的玩家数量 | + +**响应示例(积分排行榜)**: + +```json +{ + "result": true, + "errMsg": "", + "statusCode": 0, + "command": "cwyz-query-top", + "data": { + "gameType": "standard", + "topType": 0, + "leaderboards": { + "1": { + "rank": 3, + "score": 1500, + "gameLevel": "1", + "records": [ + { + "id": 123, + "cardId": "9876543210", + "userName": "玩家088", + "score": 2000, + "gameDuration": 300, + "playTime": "2025-05-28 14:30:00", + "gameLevel": "1", + "gameType": "standard", + "skinId": "skin_001", + "playerCount": 1 + }, + { + "id": 124, + "cardId": "8765432109", + "userName": "玩家072", + "score": 1800, + "gameDuration": 280, + "playTime": "2025-05-28 15:20:00", + "gameLevel": "1", + "gameType": "standard", + "skinId": "skin_002", + "playerCount": 1 + }, + { + "id": 125, + "cardId": "1234567890", + "userName": "玩家001", + "score": 1500, + "gameDuration": 260, + "playTime": "2025-05-28 16:10:00", + "gameLevel": "1", + "gameType": "standard", + "skinId": "skin_003", + "playerCount": 1 + } + ] + } + } + } +} +``` + +**错误码说明**: + +| 状态码 | 说明 | +|-------|------| +| 0 | 成功 | +| 1 | 通用错误 | +| 10 | 参数错误(游戏类型为空或排行榜类型无效) | +| 20 | 数据库错误(获取排行榜失败) | + +**备注**: +1. 该接口可以根据topType参数灵活获取不同类型的排行榜。 +2. 当topType=0时,排行榜按积分降序排列;当topType=1时,排行榜按游戏时长降序排列。 +3. 如果设置isGlobal为true,将获取全网的排行榜数据,可能需要更长的响应时间。 +4. 推荐使用该接口代替单独的积分排行榜和时长排行榜接口,提高代码复用性。 + +#### 3.3.5 保存出卡记录 (cwyz-outcard-save) + +该接口用于记录游戏中玩家获得卡片的信息。 + +**请求命令**:`cwyz-outcard-save` + +**请求参数**: + +| 参数名 | 类型 | 必填 | 说明 | +|-------|------|------|------| +| cardId | string | 是 | 卡ID,用于关联用户 | +| cardStar | int | 是 | 卡片星级 | +| cardType | string | 是 | 卡片类型 | +| cardName | string | 是 | 卡片名称 | +| gameType | string | 是 | 游戏类型 | +| playerIdx | int | 否 | 玩家索引,默认为1 | + +**请求示例**: + +```json +{ + "command": "cwyz-outcard-save", + "data": { + "cardId": "1234567890", + "cardStar": 4, + "cardType": "monster", + "cardName": "火焰龙", + "gameType": "standard", + "playerIdx": 1 + } +} +``` + +**响应参数**: + +| 参数名 | 类型 | 说明 | +|-------|------|------| +| success | bool | 操作是否成功 | +| cardId | string | 卡ID | +| userName | string | 用户名称 | +| cardStar | int | 卡片星级 | +| cardType | string | 卡片类型 | +| cardName | string | 卡片名称 | +| drawTime | string | 出卡时间(格式化字符串) | +| playerIdx | int | 玩家索引 | + +**响应示例**: + +```json +{ + "result": true, + "errMsg": "", + "statusCode": 0, + "command": "cwyz-outcard-save", + "data": { + "success": true, + "cardId": "1234567890", + "userName": "玩家001", + "cardStar": 4, + "cardType": "monster", + "cardName": "火焰龙", + "drawTime": "2025-05-28 16:30:45", + "playerIdx": 1 + } +} +``` + +**错误码说明**: + +| 状态码 | 说明 | +|-------|------| +| 0 | 成功 | +| 1 | 通用错误 | +| 10 | 参数错误(必填参数缺失) | +| 20 | 数据库错误(保存出卡记录失败) | +| 40 | 用户不存在 | + +**备注**: +1. 出卡记录会保存在本地数据库中,并在网络可用时上传到服务器。 +2. 出卡时间使用服务器时间,确保统一性。 +3. 卡片星级通常为1-5,表示卡片的稀有程度。 +4. 卡片类型可以是游戏定义的任何类型,如"monster"、"magic"、"trap"等。 + +#### 3.3.6 保存硬币记账 (cwyz-coin-save) + +该接口用于记录玩家投币和消耗硬币的信息。 + +**请求命令**:`cwyz-coin-save` + +**请求参数**: + +| 参数名 | 类型 | 必填 | 说明 | +|-------|------|------|------| +| cardId | string | 是 | 卡ID,用于关联用户 | +| coinCount | int | 是 | 硬币数量 | +| type | int | 是 | 类型:1=投币,2=消耗 | +| playerIdx | int | 否 | 玩家索引,默认为1 | + +**请求示例**: + +```json +{ + "command": "cwyz-coin-save", + "data": { + "cardId": "1234567890", + "coinCount": 5, + "type": 1, + "playerIdx": 1 + } +} +``` + +**响应参数**: + +| 参数名 | 类型 | 说明 | +|-------|------|------| +| success | bool | 操作是否成功 | +| cardId | string | 卡ID | +| userName | string | 用户名称 | +| coinCount | int | 硬币数量 | +| type | int | 操作类型:1=投币,2=消耗 | +| balance | int | 当前余额 | +| processTime | string | 处理时间(格式化字符串) | +| playerIdx | int | 玩家索引 | + +**响应示例**: + +```json +{ + "result": true, + "errMsg": "", + "statusCode": 0, + "command": "cwyz-coin-save", + "data": { + "success": true, + "cardId": "1234567890", + "userName": "玩家001", + "coinCount": 5, + "type": 1, + "balance": 15, + "processTime": "2025-05-28 17:15:30", + "playerIdx": 1 + } +} +``` + +**错误码说明**: + +| 状态码 | 说明 | +|-------|------| +| 0 | 成功 | +| 1 | 通用错误 | +| 10 | 参数错误(必填参数缺失或硬币数量为0) | +| 20 | 数据库错误(保存硬币记录失败) | +| 40 | 用户不存在 | +| 50 | 余额不足(当type=2,消耗硬币时) | + +**备注**: +1. 硬币记账会记录玩家的投币和消耗情况,便于统计和分析。 +2. 类型为1表示投币(增加余额),类型为2表示消耗(减少余额)。 +3. 响应中的balance字段表示操作后的硬币余额。 +4. 如果是消耗操作且余额不足,将返回错误码50。 +5. 所有操作都会记录在硬币记账表中,用于后续统计和审计。 + +### 3.4 4G网络控制接口 + +#### 3.4.1 查询4G模块信息 (query-4g-info) + +该接口用于查询4G网络模块的详细信息,包括网络状态、信号强度、SIM卡信息等。 + +**请求命令**:`query-4g-info` + +**请求参数**: +无需参数 + +**请求示例**: + +```json +{ + "command": "query-4g-info", + "data": {} +} +``` + +**响应参数**: + +| 参数名 | 类型 | 说明 | +|-------|------|------| +| mnc | string | 网络MNC码 | +| cid | string | 基站CID | +| lac | string | 位置区域码 | +| serialPort | string | 串口名称 | +| dbm | int | 信号强度 | +| revision | string | 模块固件版本 | +| sim | string | SIM卡ICCID | +| imsi | string | SIM卡IMSI | +| imei | string | 设备IMEI | +| ndisEnabled | bool | NDIS网卡状态 | + +**响应示例**: + +```json +{ + "result": true, + "errMsg": "", + "statusCode": 0, + "command": "query-4g-info", + "data": { + "mnc": "01", + "cid": "123456", + "lac": "7890", + "serialPort": "COM3", + "dbm": -65, + "revision": "EG25GGBR07A08M2G", + "sim": "898600123456789012345", + "imsi": "460012345678901", + "imei": "862512345678901", + "ndisEnabled": true + } +} +``` + +**错误码说明**: + +| 状态码 | 说明 | +|-------|------| +| 0 | 成功 | +| 1 | 通用错误 | +| 80 | 4G模块不存在 | +| 81 | 4G模块通信错误 | + +**备注**: +1. 信号强度(dbm)通常在-50到-120之间,数值越大(越接近0)表示信号越强。 +2. ndisEnabled表示4G网卡是否启用,true表示已启用,false表示已禁用。 +3. 如果设备没有4G模块,将返回错误码80。 +4. 该接口仅查询信息,不会改变任何网络设置。 + +#### 3.4.2 禁用4G网络 (stop-4g-net) + +该接口用于禁用4G网络,可用于节省流量或解决网络冲突问题。 + +**请求命令**:`stop-4g-net` + +**请求参数**: +无需参数 + +**请求示例**: + +```json +{ + "command": "stop-4g-net", + "data": {} +} +``` + +**响应参数**: + +| 参数名 | 类型 | 说明 | +|-------|------|------| +| success | bool | 操作是否成功 | + +**响应示例**: + +```json +{ + "result": true, + "errMsg": "", + "statusCode": 0, + "command": "stop-4g-net", + "data": { + "success": true + } +} +``` + +**错误码说明**: + +| 状态码 | 说明 | +|-------|------| +| 0 | 成功 | +| 1 | 通用错误 | +| 80 | 4G模块不存在 | +| 81 | 4G模块通信错误 | +| 82 | 网络已经处于禁用状态 | + +**备注**: +1. 该接口会关闭4G网卡,停止所有网络通信。 +2. 操作成功后,设备将无法通过4G网络连接互联网,但可以通过其他网络接口(如WiFi、有线网络)连接。 +3. 4G网络禁用后,可通过start-4g-net接口重新启用。 +4. 如果设备没有4G模块,将返回错误码80。 + +#### 3.4.3 启用4G网络 (start-4g-net) + +该接口用于启用4G网络,恢复设备的移动网络连接。 + +**请求命令**:`start-4g-net` + +**请求参数**: +无需参数 + +**请求示例**: + +```json +{ + "command": "start-4g-net", + "data": {} +} +``` + +**响应参数**: + +| 参数名 | 类型 | 说明 | +|-------|------|------| +| success | bool | 操作是否成功 | + +**响应示例**: + +```json +{ + "result": true, + "errMsg": "", + "statusCode": 0, + "command": "start-4g-net", + "data": { + "success": true + } +} +``` + +**错误码说明**: + +| 状态码 | 说明 | +|-------|------| +| 0 | 成功 | +| 1 | 通用错误 | +| 80 | 4G模块不存在 | +| 81 | 4G模块通信错误 | +| 83 | 网络已经处于启用状态 | +| 84 | SIM卡异常 | + +**备注**: +1. 该接口会启用4G网卡,恢复移动网络连接。 +2. 操作成功后,设备将能够通过4G网络连接互联网。 +3. 网络连接过程可能需要几秒到几十秒不等,取决于网络信号强度和运营商网络状况。 +4. 如果设备没有4G模块或SIM卡异常,将返回相应的错误码。 + +### 3.5 世宇接口状态 + +#### 3.5.1 检查世宇接口状态 (check-unis-net-state) + +该接口用于检查与世宇服务器的连接状态。 + +**请求命令**:`check-unis-net-state` + +**请求参数**: +无需参数 + +**请求示例**: + +```json +{ + "command": "check-unis-net-state", + "data": {} +} +``` + +**响应参数**: + +| 参数名 | 类型 | 说明 | +|-------|------|------| +| state | int | 世宇网络连接状态: 0-断开连接 1-有线网络 2-4G网络 3-服务异常 4-系统异常 | + +**响应示例**: + +```json +{ + "result": true, + "errMsg": "", + "statusCode": 0, + "command": "check-unis-net-state", + "data": { + "state": 1 + } +} +``` + +**错误码说明**: + +| 状态码 | 说明 | +|-------|------| +| 0 | 成功 | +| 1 | 通用错误 | + +**网络状态代码说明**: + +| 网络状态码 | 描述 | 说明 | +|-----------|------|------| +| 0 | 网络断开 | 无网络连接 | +| 1 | 有线网络 | 有线网络连接正常且能访问世宇服务器 | +| 2 | 4G网络 | 4G网络连接正常且能访问世宇服务器 | +| 3 | 服务异常 | 网络连接正常但无法登录世宇服务器 | +| 4 | 系统异常 | 网络连接正常但无法获取登录凭证 | + +**备注**: +1. 该接口用于检查业务插件与世宇服务器的连接状态。 +2. 检查过程包括网络连接检测和世宇服务器登录尝试。 +3. 有线网络和4G网络状态表示网络连接正常且可成功登录世宇服务器。 +4. 服务异常表示网络连接正常但无法登录世宇服务器,可能是服务器问题。 +5. 系统异常表示网络连接正常但无法获取登录凭证,可能是配置问题。 + +#### 3.5.2 获取系统信息 (get-system-info) + +该接口用于获取系统综合信息,包括网络状态、版本信息、磁盘信息和剩余点数。 + +**请求命令**:`get-system-info` + +**请求参数**: +无需参数 + +**请求示例**: + +```json +{ + "command": "get-system-info", + "data": {} +} +``` + +**响应参数**: + +| 参数名 | 类型 | 说明 | +|-------|------|------| +| networkState | int | 网络状态代码: 0-断开连接 1-有线网络 2-4G网络 3-服务异常 4-系统异常 | +| networkStateDesc | string | 网络状态描述文本 | +| versionInfo | object | 版本信息对象 | +| diskInfos | array | 磁盘信息数组 | +| remainingPoints | int | 剩余点数 | + +**versionInfo对象内部结构**: + +| 参数名 | 类型 | 说明 | +|-------|------|------| +| gameVersion | string | 游戏版本 | +| updaterVersion | string | 更新器版本 | +| businessVersion | string | 业务模块版本 | +| consoleVersion | string | 控制台版本 | +| deviceId | string | 设备ID | + +**diskInfos数组内部结构**: + +| 参数名 | 类型 | 说明 | +|-------|------|------| +| driveLetter | string | 盘符 | +| freeSpace | string | 可用空间(格式化后的字符串) | +| totalSpace | string | 总空间(格式化后的字符串) | +| usedSpace | string | 已用空间(格式化后的字符串) | +| freePercent | float | 可用空间百分比 | + +**响应示例**: + +```json +{ + "result": true, + "errMsg": "", + "statusCode": 0, + "command": "get-system-info", + "data": { + "networkState": 1, + "networkStateDesc": "有线网络", + "versionInfo": { + "gameVersion": "1.0.5", + "updaterVersion": "1.2.0", + "businessVersion": "1.1.0", + "consoleVersion": "1.0.8", + "deviceId": "ABCDEF123456" + }, + "diskInfos": [ + { + "driveLetter": "C:", + "freeSpace": "50.5 GB", + "totalSpace": "100 GB", + "usedSpace": "49.5 GB", + "freePercent": 50.5 + }, + { + "driveLetter": "D:", + "freeSpace": "120 GB", + "totalSpace": "500 GB", + "usedSpace": "380 GB", + "freePercent": 24.0 + } + ], + "remainingPoints": 100 + } +} +``` + +**错误码说明**: + +| 状态码 | 说明 | +|-------|------| +| 0 | 成功 | +| 1 | 通用错误 | + +**备注**: +1. 该接口汇总了系统的多项信息,便于快速了解系统状态。 +2. 网络状态检测逻辑与check-unis-net-state接口保持一致。 +3. 版本信息通过向更新器发送get-version-info指令获取。 +4. 磁盘信息按盘符字母顺序排列。 +5. 剩余点数与get-remaining-points接口返回的值一致。 diff --git a/4Archives/宠物宇宙/用户卡及游戏信息处理过程设计文档.md b/1Project/宠物宇宙/硬件交互/用户卡及游戏信息处理过程设计文档.md similarity index 100% rename from 4Archives/宠物宇宙/用户卡及游戏信息处理过程设计文档.md rename to 1Project/宠物宇宙/硬件交互/用户卡及游戏信息处理过程设计文档.md diff --git a/1Project/开发文章/将开发文章阅读并分类.md b/1Project/开发文章/将开发文章阅读并分类.md index 9a3d38f..5ef1b1a 100644 --- a/1Project/开发文章/将开发文章阅读并分类.md +++ b/1Project/开发文章/将开发文章阅读并分类.md @@ -1,4 +1,5 @@ +### GAS优先!! - [ ] [焦虑、内耗、爱破防,真的是你的锅吗?硬核心理学让你从此掌控自我!-我要等到什么时候-稍后再看-哔哩哔哩视频](https://www.bilibili.com/list/watchlater?oid=114079968532107&bvid=BV1YM9gYdECb&spm_id_from=333.1007.top_right_bar_window_view_later.content.click) - [ ] [动作游戏框架05.扩展Timeline:使用组合,而非继承,来扩展Timeline的基础功能-我要等到什么时候-稍后再看-哔哩哔哩视频](https://www.bilibili.com/list/watchlater?oid=114522652147889&bvid=BV1HKJAzyEZ5&spm_id_from=333.1007.top_right_bar_window_view_later.content.click) diff --git a/2Areas/提升效率/未命名.md b/2Areas/提升效率/未命名.md new file mode 100644 index 0000000..a653333 --- /dev/null +++ b/2Areas/提升效率/未命名.md @@ -0,0 +1,5 @@ + +[【全网首发】专注力与创造力的秘诀|大脑炎症与创伤修复|脑科学与大脑默认模式网络|本世纪最详尽脑网络_哔哩哔哩_bilibili](https://www.bilibili.com/video/BV1DdXLYNEGz/?spm_id_from=333.788.recommend_more_video.17&vd_source=c0e8ba1ae97ae182776824f6b7c45879) +评论摘要 + +大道至简: 第一步先把身体搞好,优先级排序睡眠、饮食、运动。第二步减少干扰,黄片、游戏、小说、电影能免则免。第三步专项训练,冥想和正念。第四步才是术,番茄工作法、todolist、心流理论之类的。 \ No newline at end of file diff --git a/3Projects/Unity/loxodon/loxodon-framework Public.md b/3Projects/Unity/loxodon/loxodon-framework Public.md new file mode 100644 index 0000000..841147b --- /dev/null +++ b/3Projects/Unity/loxodon/loxodon-framework Public.md @@ -0,0 +1,5 @@ + + +Source:[loxodon-framework/Loxodon.Framework.TextUGUI at master · vovgou/loxodon-framework · GitHub](https://github.com/vovgou/loxodon-framework/tree/master/Loxodon.Framework.TextUGUI) + +--- diff --git a/InBox/loxodon-framework.md b/InBox/loxodon-framework.md new file mode 100644 index 0000000..e69de29 diff --git a/InBox/【Unity插件 - 图标轮廓渲染插件 SDF Image - Quality UI Outlines and Shadow-哔哩哔哩】.md b/InBox/【Unity插件 - 图标轮廓渲染插件 SDF Image - Quality UI Outlines and Shadow-哔哩哔哩】.md new file mode 100644 index 0000000..bb22d63 --- /dev/null +++ b/InBox/【Unity插件 - 图标轮廓渲染插件 SDF Image - Quality UI Outlines and Shadow-哔哩哔哩】.md @@ -0,0 +1,3 @@ + + + https://b23.tv/tZzXJrB \ No newline at end of file diff --git a/InBox/网络/封装可扩展网络请求框架.md b/InBox/网络/封装可扩展网络请求框架.md new file mode 100644 index 0000000..902b0e5 --- /dev/null +++ b/InBox/网络/封装可扩展网络请求框架.md @@ -0,0 +1,5 @@ + +Source:[Unity网络请求封装实战:手把手教你打造一套可扩展的网络请求框架](https://mp.weixin.qq.com/s/p9qDdJqHj-7x58XAPNNabA) + +--- + diff --git a/渲染/软渲染/图片/img_v3_02n6_ff40a1a4-d813-45f7-b132-6f14a74cfd7g.jpg b/渲染/软渲染/图片/img_v3_02n6_ff40a1a4-d813-45f7-b132-6f14a74cfd7g.jpg new file mode 100644 index 0000000000000000000000000000000000000000..7f4f666cefe27f233c2b63ee06b16e1faf3a903c GIT binary patch literal 276849 zcmeFZ1ymeew;Zus@^0kg zxAb^TD4^~6;dups216JQ8y*_~1Uv&+bxx5m8sfDI;>gsi;Yug6wun9yiWl?r6mR8+ZAWt0KqFVa?ceu(WQ<*KwyVF|Km7%V;|T#bfMwuJ@$d!P^a2k66e+Pm4Q9z-Li-k<^~(!7Ikz z#aj5Oc98P=7FXl-aC^~RTe`Q&%+o^o`ofQ85BvLI4VGsg+ zP$pXyF)o_S33{9#VuJ6dp}v^WC^nL3fY{#HUH>y6VGg{8ajPKQV#3zw4$&0 zK2i74a3pKWZBxNwiz0H`HTITMaXYC`6;?!2mZo;r#%xcKn81XoH4=hW2g4WK{9Nc6 zBT2M=BlM_Oa@xL=YSUKyE+!3WxUXX0eU7wp39Us7W1Rf_p`Y*m8_Fq)(6CRu2pUlz zzQBqUTK1v;@D9G5@2^n*X3vq2K6gNX>7w&Rl%S-)!>*}#DC!J`6MHW2G}*A5x%7wL z(d=zVhX>9 zRF3KSUcI!4no@y8t%R~RhJ0ucE;avP#UVK;yE~ZoGhK9-%&2j!H5ocaX4&`X!079o z8N{=;Fk_gu2-giP{!*6NJBc`gWe_6n0QuNbKk$%5k&UyTDxJahb0KmqjatPMQdT8A z9#vO5ack@OHRCFpQ}g{?y^iphaX-?jZPrb=;Qk4MsN>}`fMZ%A$6if~Ki}d=`m0Ft zZW2>VhNeo6zhAs*akRtM-Ev>R9%a6o?U;x&2S1c(!^E0&%fYX%w_Er)OB6hUoCQdT#P=p&C@jG5F*)|)sG^N zCUEVoya+Kc$?Wsg5TM3@QwpIMQ%lcrAf2E#MlhstQA8N9pmX7a_GW(LAv;EvR?Fq3 z>g$JC=aDz1iS3!5<{M6i`FwE=x~hwf$6(!N>St{{X%WP~Nv+0j9a5*2?-R5!y2O&K z;(m0IpF2g$i5>hHv}4~2muO7kSnQTPNRm0_NGea_5K)1glG5&AvT{%ysX9Zmo$JQ^ zem9|fi_xDN>Uc3@aty}ihtv(SoO3f|9p55lsqyAm3opLif(H363J-3@Y`J>eJW+;k z#lz&4{WPdV9{4aR`V8nBc?LX^-m#w1_x&Nf#ZU7FCZoFow^7{1dr|YMM z>dK`3y6drx(#Dk^woA?+jT%Y%mJ(SK;ct1@{x$P5%)t56%ZGS{XTXnhP;=t`mpHX~ zgmSqll-=~xa<4(WI@5^KrGg4IynAa!`lvyg$=A`_B&_BS-SE zwwQ)}NSGsO3^oU{l*FK0JgyP!q84y^V>>P~MrSw?ieKs?$r#~3+Kk5L8hXhUqfukO z--gpER1yfyMEEueN$&5?+Ukt7WbI+TPc_8($b7u%T;uBYS~tJ0Oxt9gg@v~`@n=KX zl!-oO$HE5^VZX??`{tht%g-a`zq5m?R#FKe-s--zKIMiC;xY@gA~tdR8f6!<+C7*` zMHu}k#s{nt9KogJqoMAf|yT_N70(As`4xkV|I-sywKt}lpwBdZJvqvVO&`rjPe#I8O}?w^&myu%aIEJ+jd8uC4Z#tB z3Jq>gBrA!%vnGDn$Ue8Wyq;K^XdU3r1)(?Q?2$Y^MDnSf;nt|UMJ;f)C9*$shQ9uS z#xkzM@;+t!2MaN?ho+noJ|#c$1>bm7jgr|Kw^xdkZ8&$bio`P@4M-)@NGdJrcML!^ zoSzo2p8q1FQ?6e*U#w?4o(ePxOH0M#$A2e)yk$Zv6lu-l89hpjyd0xRh{t7HGe!EY8xGO<(`EUW zKppARgIYFRAyDCo@3raPgQ*R_l>FCr`X$jc>K96U7>` B{z2H{OxlS#_vZBY26{ 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�*_ke^ zzXVW|6^Jhk=$`G~2EL~cwsf=PAKtdZ5W75LCg6yww*9}`p1 z!(~5~dWlWJ$$a(Np-?$)*+s@XaR}^hF5rfoB>h_GedxSR`O52*Y+lnm$c`Iv{`EYb5T=H!m#l@V(Nn znqS`g@8+e(WHNpHriNe{@T~xvh?>y$iqBvUM?s{|^q_i%VKM>YMs=BdvCP`-OwznuT;?|?DmDe43;;o0(t+;Df)0rFk zoMXBcGn-~P8rSzmV!?wv<#@~vB0A-9pK@e-v#&V?J$6A_s&StCGpRdQkFQVuAx+#T z2?Z+*JDz29ZZLItOQya%w{$#eOckO@wJ@Wn+?xJU7Rk2-oUMhCH;_`((*YDMNgkE; zOZ|`YPI5or^aw}$I3pU9BGXrPjBlF(iY~6qIwEx`UJNQQSN`KsHwH}YhRQj1?C^MM z@Ob#CC6#ILWEVZwogOJsrr(dEx^fpQ{~32^ooa$-0*H(D>a2eb&EtKtl{ZjLaP#OB z7U%`xtaSB4dLY!5_HO*)9rL~BnmdZpjOpcKdR-NEs#rgvCQ8?tZdZ!+#!d^25`B5I zOWP0|6Dd-j0hVU{P-XiQA6_>9w*|eeKdF%6EPVmP%pbo%+=zLila2)DX65MO`3z1+ ziGu4Oy{$`75SKno*^R(Oot5(*@0hm#=A(S;`Tb`nTpZWp$Zvu-=i_4K;yP>HiE1fP z2zW)>25roWpyTnZ9(E+rWY6AG?^(Y#!+WN&+@FTB5adIimJB!K2PJmjzgDlt^l+fm zU?{WcR){=H(Wl`435a-{P`q02dJux zs_Pa+x+z_J%5DM=#5l_4`d!$PR+^eJ2#Q~a3&?l1GZ2?KG9G%hW=EOFsD(Vj#BU%u zn`$@1xgm(fi$MeA6@{V3rha z@z>$jS}DQ~7w6o02gDHGyaOQw;tNFdSDp)1K{WYD9-C@Xz~ zi7U^0M$Yn-?MRR#pm`1E&i;)8M=hVhy5~0KJ73pr;#-n%Tk@Vav;>b-63;6E?vj7c z?01RPWS6HUReKwbK23hk*o2lqODFzjc&u<02e*V=_*$FoWyuvtqub%kFL-ds67QGf z#z^5AY#Oe=HEW=AyZaG9@*Y(wGk1QV%q8J&)rt@WYd=-K0~)+fZ242w2Eic-#rFPd z=f+2dplTJXJaeqcd()93e10Q+d!5q1T!3MRs+OHtH0@L&ZE!QjWwsHp?+icUo)I!% z-|on!(EljMenVHo{MjczLk%s?*(XWfGtpwYln`8Zg3;FXBXP zN7|H$ifJ_bvvg7Mv{#}`_8{$h$h`2&bA3-i`&)EJ;Rmz2k7L5R$|K|8@==r6<=PN+ zM}gPWno%6aPnVvpB;$%1{cw_-N9TsV=Y={OlSej7*4oVm#VN@(2o@rxzMC_D`EK|! zXY+18>*0eTu)qtk>1Z6?q#dfvnCM%xkac3~Ge?7L1);{x%;mutNK&ghQ_cpKg@7WxkTOTzHlm9NTbOKD5!JEO@sAZHDGrBM9m-)702XXxoMO#KNg%Yt49S+``R*M7>G#L!yyb ztRC^)OnZ7+=+xMz3=QK<*edfD?i6g#ZnX#^>|A|iL`k577nVwcF`!s3NNPQUQQWJs zVauuaodXN5X>Ufb#Zp}GFWuYP@qs4e0T*w01|T|j=oCeGlL>V#-~QOe6IS3A!I)k_ zJEt-fj+U#N-V$g#FbV}0FL4-mno}CsSvI2&I&Q6JHbGy+a8R7ElQG)I61y$cCVd=` zD9EaEL8)5Akux=sZfvwtznX|N{y?~~9}dyK__H3Z_6sX_Y6%w}v`oi_Kc{a;=~h>> z+FzZE*xifDj(udR-TsKak>g4NjPwaQ!D((3f`Vh&#*FARa_C{JpA|d#an@G+MSvu) zm-fH%)UG^4bDoDTkmzHSP=9go>5#H1_bI6c11u#%o7t+UmlWA_$2uWt7_w9I%t>Hw z<~!)i>;q|A{3h%@oV(#Ag_Z~SxA)yi-(RoLVh+UAc5F^KNyzH=z8=iJpPx?z5mKRN ziAe80#@Y3iOii~Npqxf?=a&A-@6_43K)s}06f&gXt`R5;_>f?wrJcKKWi<@BoT^D+ zZ*p>>SaxA*Br>|KdGZf}i21T7`6Byb`48#g{)$l$Lw%k8gp9N*IX3^-bQ&)c?l<#I zyP1@;YjvG6D)-=#P zR~*c3Xc8`4=A`=A(E9<{T&mb+V!t@?Oq9GEWFs1=#imr;vL33uK$^E$5)z!bQtTkRx5t%pv* z`ThXA(MA02k1jMpXgFKxjY~x!Hp@sJP6Oa?pZWCX7D1nxBK=I2O_rfQ$5?hnU}l!# zDPe^Yeb1RSrydy7P)Yxrm_bH~=R5L%$%0pMU#yiG97l<*c78gI6##A%i9be(`=uI{ zr2%Xbg>K;if^aim#O_FZvw6kRQIG&N@h|~fmwAXBVOW}p0^0I-R6|GMX%a!J%vrwt@}IS9==fdOLl~42rs6E6R}8T6 z2|u!x>o4?Fc)POZ?;;n;T6d6tz!{3*OyM^vWIyUTkX!KK@C__>+)>-r>76KjX)00N zSy3z9@S9nQtm+!A%>^*XPh~^N5bk>KrjtfxZzo%$Xw?M+o31#zy}PdE3`A7UvnB(V z{Lt=X)s5co0gT6J!%Pje4Xx;^a>`v{eG?Uy9C+V`_{hSOstM=k?}_*;7|%k&ocBTA zH5m%I8kbw#Sfuu7VDoKTaAiHTkvAU12KZ|SIYJLUughq1~c$XBy zUH%yw!p%^qEp}G#JDdvyv_3sJ2#xMTubuk(K^CJ_AhV{wFCquTy$=fkfUI~M@~(`j z^9Ehd)3po9x~@%@{*TA)wl!D#2d>y;B}E6zFaGgDifpzSe08b}`3bA!+A9%+gKr(v zbrYAY|GLPxK$-P&pQwmx^FIusz1|?;wyqDm*rk0wBIBVyD>=Jum)8SZF76%Tw4(4j z$g}c%`em4It8R3E9`ixwmtQy0>v&gB$1@EHnYqekV*~ug+hx5VLGEU5JehZZ#Izh^ zMz8Nhzmvacte3~|t$ZC4{Rw7|VXb_J)hYPEgX_Ul4}ImVfm@a++r2K{kTHN;%Y8)2KB-jC`U zGN2|f45=q9c5o$Vavw6`DQY7U0etbx?&U`JouQw}xx2j51{oClfmkrU9O3Hio5;4X zsik2!+!)Sx~?2raGlRH+wX`JbKn?z$n|K5?uh&LsN@u&Me1@O3aHj|y;I_u81 z@%jWUuze`i084^@TPqUVH2Amiaroy&o)y@KiKY}yS+-=O3J;^#5Zn0Zsmk<{)3e_t zgjm&fcjV1$5)?0A8(Qu9ijUnU8Yho{No;NJ04l5GY7e!T;8J_evOM=fLthXczWV7e z8aIF!SUQD`Gt$%u<3sAB*R~RhJ-1wA%^rXW9nvjb7H30881i};Gz#Wk=d8MTtC3^gzrivscu?Fm&)Z`8-J`Z)PZ+Ix6aB>ciBH9k{M+TgnLP(X%7;_D3i*(o~&dkEjf1MOTw^z6ZytPMwPY{m= zR}^;JiF6KqdUyRedfnf($VzHf-Ic+hOn2Qqde8S4!-oEQ4EqNq@2ooG=3>A;1%7CU z=(_P?2hN&HxdHD`^deQ6IsE)Z?5}tvc;deJI;OXCUnKCSiMU7qL8ylrd}sJJ5e+}i z14P3pX%g)7^Z*P-kaqt2%lv*?eF~-Q+`wG~TSQS&;-1J>NEwOa^`KFtQo$PfU$ZC* z<)Ag=9mDKY9v<232gwj(x$=)}u}z_C$jTZgih`GyOPn;`YJB=t_u_H2pdfN4)@Shi z95erl*gqu1Fv!S7Rz0<1kp)nvdj$(R!v<^!>7!!u*ZJ{$kW&}E;6u=X>SV%y;CXF8 z+SS38O-K_Mc9f4G@cxIMt04gNgG)qSCP7j3wVFg}0NnH>hVKdPbbmABnKWIo4-E+w=ueas=(f3h@}1%S`$y-koZ^{2 zXH=_;I8TOA!@y8y~NZA}(L_a^-Ok&dH%n9|pQzx*Zwm(Yh}ZD6s4t1XFjI_pQhlV0cQ zXBr7YFT!C>UP5Jh@#|T!=>O}8iE8?Xls4NxH7&X7aI1OS@c+ELqTk!;CET0*{bg3c zyV)MD_e)pb7R|-C4xh(ZOjSor_EdmrlR;F?XTaICUO0eE0Y5dNHF=~jm3_3?B(RBJ zjsp8f_0by=K*wRgGhvRdk_Acaz^J81VuB8CmXXAuqV*`)LBuk~uA>-PCq;Ha`1RwH zVp@Ux6ZsAH(WOc|pG}2iVF{K|-Y;NA*LUBV=^$c7jN!It?zDeM9K;yPYGix5nQsJ@ zO0WWbkJ{uD3p`u%Gb3jL!ZK^}Vg)ar3^DNY?xxkOjV;Rxb$fn>nG+V(#4+d{myG`*iiXNoL7x{)? zf*+oJ?aI$O&<5Vl+fQv2F4ep^}^ZHekse56GyBq4wI3Z|Ps>WF85 z)78_O5${l~GtOKlqBqF+oYgfZ{nmT_gY0*tB`ok`+{a=L%8!sl>YHV;;I*fy6Rg^{ zM|~<*?GPpUs7^f-lM3whtVO>?qJLLb6DttabzPsB8a;XO#aB&eIX56+ru+@R%YT(&rlvQyU zuvoZ2yia)gZF;9&g0jUoWB1VAabEilJts3?DoxwYewBU5!g+?hX?^p;kfo7Lx$_<* z?b}U}icsQ0mjp_t@YL^^5+p@~UFH0DpW2hmYxQW{@89bH0Oz-jl2R@1U>IeRDM5|K zk}Dx3=b`9W579c74WQ?UIQxf`ZAHD_;>XBrcVckzrJK|RuaY<%aCjQH^v$Aax<&jVQChgRJCwPtQwo8>FY3%#lcFj-%Jd)WXU?nn?Pi8 z6c4yq*F!T6l%F!KNvawv7EwGo%K#e_cRq?@!4Vw5=)Ui~IoW=7GSe2jW!~Aw)TRgg zKX;42SyTD@GOL(Y_9dCS;|yg``qF!DR?w;y(XgFxEgUG7JPE)pXyj+yG7WBzBlWsD zm%bOF|H8Kh{ZYRh~ zmtHid-HM+)*3gLbalOqtxYn~1vkU-43i?f-z(qpyw%Nsb>=yRF;QL2k5{Rc54Vn6t zUM_c(eD%HE*%4(c3PKHG37%KHO+1d@BL<&4iJ)-H{oWzb##j zTm;9a5TAJ{;7R`a5qX$V+I`!zlx~M7N-NdbsxYGPBjrs`*Byx=W*gDRS}AgS-VZI; zF?O%yGnJ?(`pdL@NdnL)0w{>=!v@USE_y=g# z(|UV}30GuSzG)_(1!$!C89fuB-6MC8njL>k36xr6HanpevxU)oWAUso6}RP$b-Cpo`;naAIQQ_u0tC_(jZn%)85`_DAXNj!Q6(rv=o3xu*f=OaK&pq&+SJX zL;g8K*K1Xu&Ep3X${f=UGcK~m>VwF;)rQv9e@IHt6m%U1%$s-8Brh|$&wnmpa|qaj zW&iQpM!(a~&}Gt>j_;CY|B&owsE#6@CD_?-uWqWHhWQ-`=*Y&1)|SgA_UdVaxl&j& zszK-{F_tLe_(zSu90J~$G8;y3WT}V+z+EJWAUJ+bt=00q_5%(2N93MV`qlK%f;e_A z?c6zs9y!fs7`Rhvm4VIUL);2wb>)Wt)`pAHJWi)t`&P3O(V-0fYInz|UPd{9*CSXJV9BTsDSea^9-)#ICc&GnS7tGq z*bD&wTnG+2*uccUGp#6FD=6Y^yatMfOoP9o8J*eAWIGKmpTEsw?}8x*nb>@7C|>kh zt8nZ2jfOwpg2xp1%|_|cEz90+PN~KuuoqG|Hl}CP#Z}?i>q=OI{R}sG6UKbdM$J(e zqi49Xyw)PJ;pSwJZHNX{dhhHlSF zNgxN+-dd=ze{+i(>7(#HO0iptgSI!8pDV0b%(=;UK(?^tua~QtOCYs7hbRqg;>G&= zK~4cq^*7y@)N4;@vVD8wR;H1v{9u| zgDMMtET#J&=JMTh+T-Zr_@$WrGKHxkcRn|cZbR~FV}_bD;RfXo{UPiNm&o=)iYXBV z|B#l}VNNU9u8ki7v)+ZPpN@Qwmk9f{h9k#34Q2EzDpibMpUbJxB?`>zfBu|sm(VvV zS2%u=u+nwYeQ|mUfLCc#XjQ$NV=d8jCf^cyBmsS+1_N~FKIkvc+HuHj0eH9Na?1Hh z-`KElZzr<5@)hEgz`uLxb{n1Z8!MP8K-V}u7dnd;;dOdRthKF;tNN=)#+~j($kt5S zGi2$BNndXhfju;i!?*+w?4Bd6gcz~ip}5Vk3lzMiB`?}^V`t}ML=VnU3X@bu?UjZz zIHCA4$nv~8?2A2>sp;}}m=j%o)Eq`kOz%_vSw1}`Y@}=Tm17+`hl8DYeU@CEf~8k& zT>{BtjthSoDtF_U`r7)zo*J!RpbI&cDwBV4oGLHn^Ad<{Ne7eIR<0nZKv!w4M%TxG zCOqb(6x-a_I)N}LU%s1P7Nyd1DJCH;tY5F@-G=})OtHm??dF5eI2&&WRYqF!FIhz% zjNCda_-QVEx{QqQ*I!xIE`AU0AlBYDUP?$2AOwGi_#ou+=YfvL3-=j}AMBSg)a`gA zB3z|t;j%Nb@pp)FUen#6LB=(t3Q4c^6hFV+n?()3UB_PAA3gc1m{dl#-^ifhf>XZnsILQ!0r_?9H%JEc+`B~}6fU=PnMKjY>Gge` zU`bDD0HH|6pI!Q3D=)$SO&SRPz{SsTvFN0a8InQ~4Tw8LoiW?9sXnuw)CJGTkigDp zkIiBb;|L$6eiSQPv{r@kRJ|=c3wj;%84}tMv}w}#lQo3+BqhT5C?!fb)zo<`QU9l@VvxM<%AvRZD0~&q5oJK5tSjty4D0#Q^Xa&KS#; z*-Q~PyB4ugA}>~Hmuz|GTg_TA&*YN}dyL*gc4Md0bJiw{E3QnzuHb8(sIO z2yk0Ywi|@CjLiLA3M*x{#p}n5xZin_pNnl-XAvsnsCkx~i*YG?c!I0?H;wPcppG`( zaE>htdg-kqi&AeT9+^?%8^;;koetug%tEMtx3!djjm zsnb3psNUoI{2`}=2$eVc^-xFhU}-A31HL&bZ&d1OIxB6!>*PR%LB zCgGwlu}0P=FLM~(#dPySE9PP zGfQ}+B85*_bC%DUu(nTbHJmZi7UKM;Ixg*oP-us_9M6ZAb&raHM|QwKPmZnS4E^&G zt}sgdjc>B|DiI8m$W8P2Bb68rwSiTgSqX!+2(P8-t{6BSd;N8ZAvD`b31Y26i-wF# z)|R|Jzj0DQ#X&!*t8!VPps`#ONkRC{;(gE+L2{+>spf)y7``D54uwEI`TJ3Gp^Y+I zuVTYlZf!uT?n!E}$5}pc7=#%f^o?(ae~>YXc~_G@5!3E&eN0u2@-O~2(!qo##FZ*J zpRmh|fo_48ZrSXtVr00~E3RF(bWOzOEMQNIpttwSzzBTdUagX$zGf`DzQ~-kKLtb> z6W2JbxYJWzk~!F96ZJ}pGF*W~F=HL4Cd6>ENC5lKE^l>BAn1FDo|7^Tq-$)3NX?qs zNu}JF4lYD&A2((EQNGlYYp;wt__rKGD!uoffq&IXioWK?ckB>5t+pF`6|GXPCKO{y z^q2C6y0#40N!2AlyR~W4^0+6D*8Wf7Z|KZuc#Z;+$*n+P&C;hpn^}i;7n`mtwB>F( zb9tC+6u}RWZR`*4heJ4*xDWR&N|f>WxIkC4mH9#N zn0L9kg~}n;XEo#XEuRJLWdlf8~yaZy++tfu-Z~6syqnLJ9%((p|B)vu4VL)l0 zws-fFd%@qUvE8aZpXsg97S%4?LB=2AuFZX!1W{aFsnNeH8&Av2`sK7cIAEtJMsL{P zV<_uM8_zaarRS~0!`##)goL^-zdJUK2$EcE5VLZw4K>mpK$vQyd&daI0EUuj$=Pq- z^=f&EEoDnwqz}{R{jp$d5WQj5kgEa42yal(djN~ffthUqdDudJ)fFw=)wPH~BSCrll5^=IR7+F1 zY7x0=omIgipn7SWv9c8qRi`ar(Cew*!0NpWB5rWZ{`a6DN5G6DVaEzFp@w5e6=73DBZ&+iGKY1R3b|vlyVJ#T zV%bk}zuSr~>7R^FYGoO;Sju-j1oH2ttERhO-9)h$U?VrKHuD)4MOQTE0aH#=1)e;z zW^SP(Jm2S6NvP4d+`V1a%y^O%4#Jwi0Mz3B)r)WZ1xCE1m`kx)Lz%En~P4{yeb;NDiks>fhLDU+%+$RZZ9vN zGZ(aF**MH`S>>l_(yQnA&2vWL^3RUXjIuW^&5gF*sRNiJ<-8~w#1GC3#{WS6X zt8(;n8{7k;a9#cGTri>tm9U=5+~B+?wb?7=e5T z*p-I#KG2wdw{6oM#7}W8iZgg6dBlsFo75Ue>{hDy%oyiY?+dD<>l>ahpPjLM@RLQ; z;t~{hvVYTr(yVoyWqEpuvE5Y^pqVLmM}r<3l*FOB7wbY%Knr zdU8Sok6-=hgMOY5#q#x+zL}`dwI8L8J#Fsq=BZ7G+Mg_pD5!2JhZjtN?Kd51uW&y8 zc1fsTHpp;JV9%M;FfAUp%521UUW^kWgC!6|OeIfASvs%W+C_<_SPfJhqj%X8tm3|< ziwoKsuhyp!x*+x(?Fbb)xitJ~;&YGuvZ*5HJ8ikQTr6u~*kVXNDBI(l)gTcm2Qo>$ zI!;a2u`dVM%#62%nOW{u-&2j@Ob&InDI_$9yw>tBuM4@b*CNqpO_xpO%Ou^kx;1Q( ziSZz{Xn{LS6Ke!@m8R!yGh=IaO8wwq_eZ!U!}*yVk;9dk6CIxDS@Ic1 zy6>4Y<)%Emw^?|%Oi+7@@zk$77!49m6J^d%Dy4Gm`H9)|Y@(p3eAnyaboZ6}c~3ms zF~X1Pu*9HvZ?le+xa3(n{v!fWUN`5JTw!p- z>qP-r+@h2KaU!xhAL#j>s^8Vzpy$|GTh1_QpIK0>>j&!5w(2;n&NY{Jm)FuNY3(0+ zFL5F^rCSQyRu-m97p!JRd!|fFF)V4Y$IpE2Q?e@N4JSntGHX^23;+W_w6_Gpou}|zu0%R=3P4kLv_# z{eqQwviaa;s&BV%dN!!n5u&TN#%a(L&GbvW|CQUo*98n0bv@~39`BW+Z8#wB*$)1i ziRCc~Au$tBokdps4ARMDr|wU$T6if01>5}F^*K`gy!Rro(1Z<&D%@*94Wv%M6U$FL z=Vu;|=5)0W;YPH?q6P-6qv2Gw;Zysqo0qC*rqCHVV}3igO>Ux%cCLxSl3ubnA3|7FDz@2@d>vuWcu!zNjYE#LfWwgGDb|6ks_tu z=jw7RP4kE}Np@9Kq-pz8yvfr|u2^v+6Bh2u+-KI@#FhpZrYxX8XRIo3K|+e(#G>Pg z6$N%#n7@L9B|J!rlz7U$&z?Nbtb-|6v6p;6RYhijnX~FpUJtj=D~7z^ECHy>>g92= z0@#dyg*IFkjpg4!rGGXBD4G#|MK8;~HmSVk*0@Em;tyf$DFrdAyiX3TSe5r|LdEi* zWlAJA`ZoX@UU3$_%>T6q*`z~-0y$@cyqCntn9{@C=EVGZx{cRrn7-^fQLX+R_;7{M zlWnTKQ#!@b-L}S^T(@QI`}T_Jx$!>~x`#Tz;ZKc_ed0@r4Zkbut)eA4139%xwN`^5 z`#e8^5t~{Da}XQH$!@iVko~=`k+MB2SJc_g5tw;{SXFeZ?UwA_E=F#aU6k(}*aB7o zIL#?^ zbHHl8v}0PehRAhZ!mn6J7;JTCeZJ9fQ|5k8Z4>E--d|Gt-dm2%gw&}0;emxHv0C+q zdB8@AiK}0HWsQC1%mTFGl{2YZN<@`OMw@7+$9iUvKpPl4T8{ZDoKc7%o>u_!~V^K}ZE3miaU$sa%EE zq&BZMpYFDtM9ez2?A4!*em^(OpK1*{*+tUCm!6{OYp}nFHIjqcw6EVtG14~x^*~@A z;woHz|LE~DzV7YHu&aiRQd19`Ezsm@dB}M4~9gXJ#k5sAk7l+ zkY{CX4!TK$x^;R)4WaY}`1b7idKnBPzSUzTH9Rs*afI{V6y+y4-iUB`q%QQ`ar_hh z!o~Ad#AGzrn_CxCzn+D4ez-(@Si8<Am~6?|Mw?12|+2Vw}B`YxE$74Wi24D^k&i*UL{>Rmprv`A#T6+e>QKiU%#b z8wLu~<=pw(W`9b=I78FQ6d}{cv>2Ih|5JL zePIOY7vsxu&y`X7mVAnLNx~UOCV$B^nkH}n?ZoW`ap5q?&#DaZ?&^LTq53Zu;4-Mt z)1P1TpwB;vi6qA|dI@^2z0UmIZJEpIuHk2W)> z%w>~Nyc-kW2&6K3&-e1rQ!0z?$6M#8iLy1twA5LSkh2xb@|_VF{;XX0@HLwy9}s%s z$LXimfJjo)VS%ONO!R{PRaWXANzp&_a;S2IU!dNloK2R(*}oc`=|5Zm+u~-SZTU!T z-7E%-N|5l7giCY+0ki!(oj@A~alRzfAB)z##tiin^07_70F_WD|3p_gbm~lFCZm`K zq14hUD_GGCx7P_#x!5drc(mXL3^@`3z_~DG9Rb zFMIKO57~E}X)5O|oj5IjdUi#w5en+V#zk9knDRlm30bOZl74QE_)Rr8R!k+8I0d_aBj~v~F!SvXdJz3tZ>+x-K-e z*`Uqz``M>A`s=z;Dt=p1%`fKtf<{sk{YtKs96hfAXxc3bZcwR43-5I264f`{wBpRW zfXTQn`f!q5(uPlq{+=+8pJr$@Z@23G7Z;Of#*?Q%?J4a7_gZ|_Z0>x)+C?u4+Qg+U zvB)C5j3RgN62|mPdHeBm7+oelG{59m5C=P^kimN6Qn<=}V&D}|olen*=4~`;b1T_W zY-fO8p$~I->FuPR4Wld4x$zBYraBs8GVwLnWr>DHT#+;OQi^1S{*8Q7sjArN=2OaK zO5Rc1AD^6eT-}oToge8=E?UIXu|#O_`C?H}-XW5b=W6?X=_(A2FU(+Zmo8YGi&)r( z>utq}%Gn%nE^<5R$l^Ipa_tX%Y^xN)W)UqI-Xcx8$g-QW_v73}ib;L3b;d^$bcrsD z5BM15wMa<*orLqtH>$cqp8fgVQha^6_OXursQTqE((W^7o`rsm53j9bj-}Bzj-Xn5g%@>3L$j( zx~Ob!`KN^+HlN~aI$jkX2_GpA?^d|2B{P@2&g}>#R6a^6GF~sj$yX_$X+#{BZ7!hs zXJLTsd5PHlOk(@W_pG+}Y)i|Qo#k)Ggvs6n903EvZN6;Kqg;%lOe<83KCE)S=N&H? zcd_qOu-q;l=eMN267F7?o_psfXR&TpLZo=2zfZ(zF#iosd-7v^u};dZg@=CoZMmN{ z`(79q_6x9iaR!g?f!C{BYVAM+baVY4e5?O{owG@2&jrTN)!|`Yxx_Ym30b#y8*&Qt z(}7fb`HHG2fBE9jR=gl8rm=BM#k=bbdzARgwBed7z;?-*Jc(Xu=Qok|qh3$8--sj8 zAIDGVQAzC_5gokMJ-^>f86s2jSeJ64dDTGwJW{cM_dS zN04(HAbPZ@p|kXhZ`zC3_QBskX&Q@;`>VBvT8pX886k*+f}y5{Bqs+1?iJ|$boVv5 zPaio6{@}idG0;|zco1NzUnVzlwfi(=fYQXV_LNw;|HDtKh?p2lYraaa3Xl zWvpJOZx0~Q&baSZl(4d=@dWyZ90*!aX);|SFaATbZX~HXmBof#I#7f!2Q&nirS*By zVth4q!(UP=mHz^wIj+?WcdXQ(BckWhgtqmncvdZ4D%xFH+I=WNv{A=E`!4@ zE(Q{-SC}0{rGiUpwl^PK9uj#L%7-iD!jV%6XLJBhAv?}Am`a)L9}R8k zl$zES!O)g(U1=0`X&88Wf{}v7sc7Hu9E!~L!apT`?D@;E!AYXW&c&I0h*t@?t4qhM z*OTtwbW!zWC0&QmP-FjD-(r*zLgC_t?xgJ1CCFHD^D_{;F~AkiL#f5hfR_^KrwBHo zSpBmRsSbwSi`->E^bP|8*C@@_OYJ+-+p>+IXy01$|L-_nvF1s2%t)NJ(-FIdzs5C6?ApY z)9A|_x89hhz2_4r-P3*^6)#)g+SB#o6hN83|JGov4nMbSTj1lHapY^_cg^D6HCxD% z^^g8{&D{9A^A1P&_j!MZT}r4J_V;x@Rt<|aub(UTRQGxSFav<{VSKH1EY+KheYhsq z*a=sW^k?0t?<(7CA<;pG+)RUCNrnM?mNIY1{b#N`{_AZ9mL$60=L|6 z5mi!bNK|Vqvts76*%Bz>m2cbDdBrwa=|mkpG7v}@{`d7p#aYwI5F_Ih%ln+0pnRSx z73U{vVa6Qb>v>l1?+US{-NB?O4y=Ylc+p%ywn*9V9=_o@ocsx&zYOahYw)!qjyocB z+f3Va3=THIpu5uF>_(L=>iJutVLfdt{@bYEV@}%b-51VU<4Em7{dq@$84jiLMc@BY zZD2a-2GEpi6fK`!F9Z2X8?=~fb50Gg%I?jP3|K4+@(P3zul4!2E;*wTx;{r!ipH-P z{G-m|Op$@D9s$+n;Od&cK`3(ftMC@3r|*x0W{U!1#kU%~)zUH&$~b(aq~o^?IWb z35EqJRcM*uB^7SgNPQnA;zA|bKq5yU-?qVKeRjxZ7z7>r=j ziC#TWkX&|ME!A!@JU3+6Q!4F0L?sjt4u>n62NHR3KY0k*QOM6vE^@mO{L=Z!EX%{) z9|uIeP?+R+he?q#>iX}8k+e=tma_L%qs$!2&k4+VbGhSdz?_eh{oK*Z0xENn5-vXn{d1_lMTugw7Gz4G$q?g15&M)f8yxi{lmav9e)1n#1h%zT7`~9Eel6?!FIY+vO0i z!NRWhb8%i&t2#x2;xOn35f#<=NgrK?L818$etE)O>{&#dJqy5@(8YJu2jGIRvl&h{ zWM`>-w%)yDTJ$}~g|O6exRMGt$#lR|MqGG%?O^EReTUS;boapCZx2L3*LhjLM|A!V=>9YS{?AZQ|M*yt$rlKDRb7mou42Kxj2&yt82 ziMcusME|;|7~kA`vdTd6TA2@8h5gF6B-e@rbGv8V7rQ}m!mLmR%v|m>pN?w>$Mgk8 z4LDE6lj^Jn&_)Z?Oj=-@_9KzRrN}3!MvHVugetT#jqR?dvZp_{Z?`&*ZKk!}rK8fu zQ+VRUF30T-_~cM2rG3iOD+7sWv0y!&y&guvmI~g}e#Zyb-kN2d%cYzrl;Ut)qkflq z%{WDYub)KXPW`f>zNdLs_SfhkF40pn95GMU;K$TN1?vsdZZ!5EWG4LfwWg074BY8! zvv!Et$`xbV{+T3alu|5Xo4n`v_wBkHKGwXUXL0C@-L&c) z7eD2n)FWPo_iVMK=U-=&Bx8vLwH0bJnoH%2xyu-PAlGg1yweg}%A$4lMt7GrNx%7% z8H$aSvjrVaRyhq&CBi{>Z|INZg!uP7uS-Er5oSLy<6F~Kf5~*0=ZvubP;8#UZ)-2m z)Be6>w;9N;nqC5_K92-tcPuuc&9_pYZT>?s(74}Ic~W}vMwLvVQ+?T1^H@i&+q)6D z5{B0sE!~YE<|gsh5v2;AUMfK0hl;|gM{iggOP6!b&#`JE;HVF3pu%kABNKD~mThk%9;3Tb1ZGeoR4w?PX+&@w zFbm)w8zXu=f<0b>g(fL^wZcscW8enp6|bE5E_97sZa1EXZ>kZ!qYIKufx* zJGN{2nZb=4MLwGsc)0Y^n=$4N?d#htHRWtiFpHWTjk{DsSB;VTGCB8LVQ*#pj+Bkk z`e^=uBx8sUjf8njBXzRSNF=B9U*@^6YC+C#QiTK5CH|iM2`_!N3iHO?(O&eP!l$yz zsEFXh%n#z+n0!rs)}nzeQ?eV+$a5$KqTIqT*Vc3f$m68>l=b!2Nzn0AxVoe2q9J`04_EMk zg()QJ^fR1gZa=`$=JOYDtYS%!W82StWg8dYCXsH2p!sH3oAQyc)~66?Ia&mm<$Rr=E8(%3R4YK)2h+*4C}7+W=*aTB-!CWVu)W zv`=%Z_XW5nvtHU&MmsNdB=&n_V{?m;{QWCGj_-M@3kMkgvN6r(d9k0aB!JLKV!mIQ zX;l8=ps!yGd1YyNgL0EiyrfksU*`C}Qm|$Z|p3{x9{*lDOV^>?} zJa1Vgu@gvB5h3uEqYZJ$E;?nNM6Lu!5g^ouz>HZkB?d|l5Kp;pf{JT;{_;`CWH!B| zNc{dGu80>G(6UkttCc>~z7hOEhC8CcX@Y#2lN<+rKNl^5AM|&5A&^G9VjjHar4vDJ z&x)D7AB^NQgBa1qkgtEM3G#rIS-W!lWM_$!#_3t_XN%t3ARAn_AJc#JaNs242Tu-l z6Dmd3r)Kc~P`C^L5035UZHD)6?Zh059IxxlWXEa# z=L@i=mZaic{=~|{&R8JbIZdOj>?X*{Ya{joHVi<@H-|}un7~Qa*n*RmtI8PF-XK%}`s3K--KpSuCbg93A*j^yjg^Eoz zi`xeHeQ+5n75~)Fr<@FqAgN&?LmaIM)Ah1Xi2^#0zjcl$7r>0(#R#y&iZL~iYjxV} zdf>;`%#Ptq!AGs1}7ZtIB|u|lMtxCFS-pEgo9 z(ANDc$tz$kFmQT?7@N_Em-V^U9)rLt)%6XgbS9n?HgB8}n=t{o3;1RHE!p~)d+y&=N?~xox7W0^CrTA$*Sh@Jsm5Jo10)o%RcQ8C!l_UaS$bm47gCn)JGcXF-q8 zzpF=^a9OKNS-T=-V4+}PCk~%4I~6_vTvrWe*|+RwtH(|U^IHs3^ju^(ZzWf%_5}Yu z)CB_EoYX6H98I6pKJtF1GBlcwD~xMNg%(t1GQU=Aswhsi$-XVj5!F?rb@>maRDP3N zn2nqC@g*=gZoySKc|G>wl@c{WG!x8DV4II2S-CR73dX@ZMC~;}o9R^B^TLW9?}Gok znN0um|E@1CbbmiR{+nHSiVFw4HGcg6pBOFN>Ab)z75FYSuN)K`C8`z7T{GGTrnf(& zL|S=%s^9eNhpiRKE=NW)2v65WUlKQxQuehNW|P_>^Ho45Ab=#(RD;4|!(eAHVn(F= zR>)sO^AbNl+K?o=SHJ!PfPE}fb>rsk;gT|{O!b)HXM|%#{H<~LSQD@r!ndSW;OY%& z^nSrnX6TNRBgY2BrZZ~itV{VaGbBxm9$uQm)g$?b555XJfMDY2^*(NCCn3Z4-{Q^p zg3XD(UBFI19Q)wcZxY0#taj()nK{0d!5CDA%)V})EBSP`Rj)oLK>vcrrGC>&gw33I zg9%RcbDDFCXlWA5i&a*Uk_*;zs7ksR>F8}XECV zhz*GUQF#Sdma=*okf`Vc8$ZCKw9^-MsHv#5P|VnDoG6$nTM)cOffuJ+$~#@iIBz37 zSv>he{VqU2;&UKxANh2vOpssH-f)?bqF^m|K#TMD?GCqP?6 zNlU+FX*#O4b^B}_92Rcj#u=yO|H2b?NcXfcG;%pwANz~02e}msg%vF{K76QO3qlX} zy6jg;9p1DRe$sDUJM!Fob^(EtJG6*~4$$qq)9TQ1J5k$3mmLxl!p$>(abIbj(fd%g zCqd3f8WP;I`As~lrAb0ne4TfOhvyGW{i8{AkqrUC%xdTU{?2g2>@=E4+oHHd!<%Zi zU!6@?pFuZwCqT)-AkDoy`kpyZvwh>%S_OLdMP0MWyG|=pJ6@ei`;YXpGnY&)bb#tN z1S>LV317ZH9G`wX=Bo%>c+xuA2X6%h?1WwXmArY>9W0K#ms))4^ymzWzkhx9G;^wd7GK-KSvR^Mbb60_C81>OVjE8s^x@u<*;u_ z>(T9tF9*TU7v6XRHCW-n_dk({q)qPqk$HO)+aeAmoV=HZ`CHS&M3nGbXKNSkPW2iG zzm)#4lw8l$f{q}MH^J%kX!xcryvak&TOE3f#Dgi!&CDk5%8jjrn^wa=ev|Yp;o3vH zT#Sb}1>Pp&0YjKFU!q-Y`=+NkYTSj{ItyBaci{6^B}ZoETdKQsJ5 z80;*r3tYI^u{iSj1N1xLPSNMQF{v{fLOrX9gy)23jWvVT%G~no&skgt6&VKBX&E^-`vy{HB7=?sqkaDyzT?LaH(lH#%~)>|{ZXq^>L3Su}VY zH}eacJIr;*q@gM!ZR(kaIC*Fhaev3jZsuA#(&i?Iho~3t)L*x3;gu^ZNhJ? z{8g%(3mIRD=)~oqrjz1tABN0LC+BnVnofnd)8t5iy_DGZepU(9z}(`^#K7Tk8-YB& zRbLH%=yp93{Nq_#`!wQKggV(?dl3N|Jk>!@5*C)b6b1PTRqJye8ZN~;c%DXFS9s`n zv}ma5aL`mdF))M&{MGW?^?Tcb)pf!?plT?oZok$_u^A{FKLT%Wa|3^&vZ#e&kep}3 z{&)?v$G8KZvuKo_)E`9qaB9dFmTq?ps-qyz55M$z&6?V{;toE;0-agj*R9sM)KtzM zD80LANY-QHjTp($OM(-mqsk6+E~J~u6*KXV*_fG^IL8gIpZ|x_PFAQfdj^Qu!QPM$ z@XHl{okzkdZ_7lVL{^1fJAtLUt@4|oj!;me{Uy~G=%~DEoG#o|8EE~ve~Yk*Cbs{w z(;|VfM$*=|un~ah;AQ*NU-2*qJLgeI!dk?lUM#4cv(5G><3@^LJqkE}giffHdDmtF zTiROvP8{X$w7kcUQ?A_JenL-ZU&P%C;7z@-{eG+-74U-J)?3mi2W&7cV^*}0P zGxp{)2~V^+w}gE227LFNF@K7$Bpg(+30r=W4eIwgl9UMM6AEHrwYn zzpzhN-9s|ehp=g9*Jwm*rmJ)$&OUcyexmC@ZHe}BcvfDpC zu3#9oR62vh6hjBW-UB6%G4r2#Fhx=|C$o`I+h zX;?E6QOCjzXuIfI_yP%Lqm2QUqJ1*lu^|=On#}}STFxN4R{1g4X`*a$+|%=s~BRlv7g56H$c^}iSmFuWgmkN$VV((SE&J37SjyD5fymOZ`NJAS2~#sfTeXMXOx zuFgFmWA{)Ls$JVAUonyvkk0J6s&hqUN2FmZjE^hIfjfpy{#cG6%jLC`b(#i2&m`?U z$HL#_hqtyTp@J@tydN7w{zCyw)xQPbt$ZQy2?=uQ;OicbRY>Xlz+<4d2}N$Z!-B-IW~6n!QoEzxC0bt_t) z;Z&Q^-ZIXcCac%&fwnQODhS8O;<73CyzVUgiI|%N0E`82qDNoq7_AN~Ef>|;NQIpa z^vr6dM->{5C{m_|^nJV{%rC~T)w_)TLy`MqHWU=Cl$-QDL2<3WDVt82^tE|~A-^+o zE1^CR9L=g8W1yzRxYV*Q3&CJtw>{#pOL<8dPranuV*eML;|s-mVld-H1^msV2*Gq& zo-&UTLM3-`nQ|? zI&DRGTJx=6z=N-ezF<(*3pgR$zp=n82m1BOh<`>uWQRSTX?D~9CT`>F!B;!QaVgNC z6zKYWU8aBJ2ghdOU}rVFtkiJ!p1o>6@!}k{tY9HM2TJA^`gY~4dHgI(4x+U=Ago#N zO?^BPwp+tXKNG*(X?^T{OSD5bAr!nozIl+@QhX?ls}k#lV5 zi)~&hx{Hj8geH_{iBAgc#r};G{fb+i0hc`T_;ShMqLzG5o9Tm{ji)io=REJ3I5za1 z1Qtb=#fvU0IZ{<_N5y%Txwyf97F+p-59pzh*1n$?J#U|QG4z`vWeJ0pQb}(V(K=wP z)H7BJ2J88sGj(f5W@}28LXsi%DT%@>VOWJ+Gu3NcYwTqN2dkAQ`ny~G7j{L9L6p5z zbpe=aLyg!&J0N{x_FU_M8rQ)1>yzqN^vl+TpWFnsM;>0fu#U)pwC6KLx?k>;(j=qkS8^=;-G!0(3T`vf#r50J26Kk|%z3pjtgI_c={Ztee0d zoZ_)PomtJ+Cl~tsxG$CmZ3eZTgjU>zc-o#9pFB3p5RgbjqWt%v)Z6gk(p3DlCV z+sMtv)kWI`WdaPg8SLK>bm=)IFl#%LU)*{^EjEuCZM6V$tvWU3HAf}+MS>@Q2cP%2 z^_rmk)Q?Z&&3H+l)56U%GjmNU0|53K^dpWDe7LRvA-)QiA|)b1`CZ=L1LNEsRdLTg zDEmMFnLxW&|Hn#9W-boRKo_tS7&gA{P1^biSs}KuDaQD1O%6BXhiRA{A2`7-+L=4- z;~nwrsTvf!)iSvpF;)qr)#J%2>bEQ^utR0djc$Z0%`MmZQ8&uvNf&(~F2Hu>i$7~# zw{Cre{qsD_iTNA!k8&V6x}B%a@ZKoAvY$QG&Lx`{Y9NEo6?5ZQO%{9nOwobg#!!Ry zbuPmuw%Bkwm#w37l1|~Sw?1ompGJ{q5mdHOwWPT}K7v9L z>;xC}ipmWd`MNJ@5xlAI#OyA2E#l+7=1t7R1QPMCzu(?n=~PvPTk4ade~No(5-;7I+YBlvt^We;(7Tu0)?@j|4{ftY+rrx znGaY!$s+$$jb;Z+kUK+)-EPED{Gz=)BkNQgVkkTzj#;-vRjJ7MbJMpH@;AV!OKG!6 zX0A!h^f6a32^yQ5+^k{KsK*azs&g(5^8(B<_$GqIvwrZ-L!;|0jdavQ))|p3UoSAhPncAPq%t>Z{tOb^BZ=7|bcGiHqAwTD`c0 zuKT!9k#7`M!>qvHD=QWsk2xVl`n*(SJk4rKln9}8jb*WF>nT?lDuExH&U3jMiYC|i zY5UOm7KZMLHLbi?=6@)r>r)Hjc8^6^#tN8GmwE6|<>2`yH8kkWaofJd)I;>y#ceS; zg*DGJKIU22md$I62Q`y;ZlP?V!{jv2{Da@l6Z~6{^(JZwq2W0;kxoAxfca`^vOWI5 zxdqswVPykIK}OI+S*UX7&tNxE8QAve2w#)q=e9*ffg4EYy9UO+8brbEtcTPX3>R?G zKoV_Bi^<;epuS;-{yG$}oGv8%v1^LMEJg%twIlMVyLWDr4T>Two+j*;GTfBE416-) zSRSym%k_#m2Xi&#byjRolUEbAc#sPl_{NBcEx zAmKFU^6%%Pd=282>BWqioLa&Tk*%1eWQIa(s|Q01j$W#0rh|MYu&v5zqRgW9p9S)F zhY$xNdTuJ|?$2p<+Vmhi{HF19 z^4{D({=C_9Dm5?8F6_GsZe~FRV(!5$dOP$EZuVw1#h#{O%T%SYYre?krJyX3aIEX{ zE(CUz%u(FJ^;b*S#oDhB{doww_&8Hkn>^ap-(w`B0gMaaBCb&tOF>U9_M6$>{SH_Cnl?F+k^6w}cE=ZR@DrcU96@m#bY^1dli&}9B=p4U*?$2tDLw(5iXQ@{X1fm$O7*U9gOH6>S2f%>bh zy3@**By2RYkOdPJu1Mxdc(c8$_hqTRHk8hAT7G9Iph=&LsBNWtg2+jmqqC`5#?tk; z#>F8DA`xBzY|enxK%&wuHk=!;8JQ_ado2&wkJ)rSwjMG2U|ccjW7F8b(HIfES{w24r2UK zQ_r>kYR-i+RkV#i)F(kmNxeijMdP=Cf86^9o1A)u4bf?5lwhqWL(xzaPVSosQ`m4npWPAQzov4tGVev$=QfvlbPPL!VGIRiI*Jv(kt`x=ZHG|h_wQkiH0w%o?GeBAX3acHv zUyS)^AIxn4Sq^dxQiooDAb|?-2M>W}SltGxk8tXKKrr_&MHxNq95uEzsDh~ljRRs( zvsLJW@*W~*ZT*5i#eUOX=1W4rJ&11n+pypAkW3T|pHrwX#o)eZ&Iu%EHb)tltwb_P z6_W;S;0Ise98R47!?a~fv{$p^%Z%&$8!tcQ^V~4C2w#Ns|N69Tv1(L2CZ1#9u~E(? zM{J8bE(0fa0fcER@sIPVba}J+=z7FvyJsny;FV{`Kbmc_kw)>@1(@3#NV^60(=FL` zuee$HY$1;4ezO~>4*VRh3Iq;U&O6B}>vDcFr=1IU7$k0ueH92d=183Lg4V9Sf?~jbQ`Nyh8{&zjS*+4z}g)XtwjEQe6zkq zWk7w)ALv(=OaBAYhyL6?$*>qvDdAz9qjp(?GTMx|I8F45?U4Ntm%6i_! z$8&J2T?)dJoSO+Wbz;A(CKZE5;ti}xH2hXk^EW-k8>h<6G!81~bDi$E?Qr&MhUW~& zk;e*{k@KeM)@}yh(e1B)0vKB;Yi;_&O#e22JjEtQH0#It9a`_Kqy3EK%=vIsU%*?; zvYbWCihF`}FTzXF^(aFfIdgV7NN`ELJhyrSSS9nF_ccH&zXOj^#H*qfaUw?ucP%Tx z)?D?1^5l~eejfdnyf2lomYnzN3X0evCxt0A>4mzG;^BqKuG`6)7fR3*?vEgvWyy%k zS?iHJN_1JT##P0(WyB*%1mnrCYw z+FLo6Hio-;vsz6(7A}QoQ!-O)X@=9BJ9kblcTu>~BsS2C-wS)qGZI>JDl5MYRi0*s z=O1giN0=AX)ICB@$JXDU$>4NR=%`!{qrMgzAiCZ$oyg*-_~IrxiW0pFLdX*8DQC(qcK()7ADoA zdiVl+Nc$`~aU`$A>qy@;=PWgn6z6W|*Wn}@n*feG+M7onmtvcgs7~jk63YOtz`lL3 zL)U)$;^(Oy7jn!zT@?NgEC{7hjtbAMFSl6Hs$32!z5~U^#GOHWorqJC0q3(*wY*=7 zk;yJ*W;pk+8s7D9GaE^^3cRDh)}I3P*UEpzxn|SoFpsM0)!FbR?i{FH@0jS9+`^O$ zH#vEGSBOKMWJG1y%ahe@he;o?#->tT%0*Pi;zECn6GC*oelQf{m#lHo&t{ZU6icM3 zyp@l(apw|u@SR!Bq8UK6A(T+HUS>krZek6+-^;&q#b&Y(8s1}WVV%hS^|0mC(jc?I zHjB#5&7zJ3VnIYezR~BIU$Hu!d=p1|)`{1VMDzbJ#6aHqvmDsM%=vS|5kx9fMqa^ZM+sP||KBc;yjQX2sUeK*) zW&N6><4?QEeVta8r(cP<2$F$edD{5EKaa~F@05aXzBohJ#5RF?P^g|qPVX|C8y--? zgHp6WpSGLIo*~-QPC&+Ipbe64*G|%C)1$+;H7Hf?)%Dq_-=mJ}Oe)CZEuV2con~Fr#@p4o%7h|uyX_2iF8ukV&4k+Isk>iHZJxw!}zpm9)$E_)d8 zWS`84r@-Tp2*SgDn6l#*9zM-gwX1w5ZY=_*ep>i*vl;;_uXAn?kh{oThxb%DKfxf@ z4Vx}^u}ug`36_2)A7s3p;oUj`CG`t9QZIV?8a-jtDoS33Eq%&Xg2N=C1X)t%V_|&; zFP+Q}A{oaI`UY|68SZk?)zNU#ABgc&_+F1(oJB)2xl^ApS_<@K$@FB?Y4@@tFelk} z-L<5F*oFPuF4ptj1+B^O6cjxNt9Q7+A{Ovh2+|Ywb1P)2J`(-Vt){zC`*I6!2+3OV zA?-NA%i(C;6hou_M)f*>awUo@*{`a*knq5L6e~7P$kyqTUH*q5O+^Gcg#~EW@QK5Z zC%y1GQT##oCb{?@=&wm5XCKggb!V9iy(aEwp=c9{(6yoQsa-Ih!Oc;h_}V!edYbaR zvhqd+(9 zu!bzNwoJH&V7>7xuDWiO;g_LTAAx_w)1S2>;ETN-u!bQOJT!hFeQQ?Yi-Bv&Pw~N3 zVew#!`Nsy}Bgz|R@Seae>v#6&yR+p~jv_Q1EWeLA{A9w;OIz$>^jhkNtC%?t#R1i! zr0b7HAxU@6Fv-RQ=ZERjvUr`ksGd#((;r{?6@Jk(H)fo}anr>#{Tv+tTm1N4EqX;&1a{Dg3F?KK$!lZ|{|cwI4#4%!-pT+yZ0fg?Xr{(M6* zRdTOkzHB1QSBK4M)&44abYzc8)SQ|&+W1GP0%Ou!f-{M`^0A79s=9AP*t`5#JgBYT z3-61#loVH|ic!0shmyF#gDAL2ja=nk7$N;Jy({ktfk_-aZ|?oAcql|i>oSWRYmUwP z#F6&?+a0S^x9bu-^sVGpHIV`p&R~P%EIot`ci~dWI#K|4gV)#$gBwU}Osw^z z+8jtlNKD>f$mhQOo4#g#J)b+*xK-^VrQoK|Z$d1j8I}c@S;q0C`A!&7nI(Ka+j`-E z?`VEGs+fC`qjkS2ytz~~aZvsHTevD=nf>cj7c!e;BnD}#tC9Db8Cnr)BT3S_T!&An zb9K(yU(?wUlGm@?lX8WfQPj8USv7ED;}^b!06Q(H2}_XE{iLCPYVtek(?%Q{cz9RK z4QM|#o_%&ZR}E0di+{7vJI;EMid+*I>*0Tk<1_KeluXz`g2iZkz0XMx8Ct-uz%~nuoGz18E;vV z*Npo;?&=}}Ttb-WT4O&$T_LY341bu5goX`_@^r<2%=jb`zJ%&3_|M-cHD#P2pZruM z($>egJHpOFF+WSWD-m;~J%}8k!f;pf#y8*JZN?x4uS&%LTRB2~j`x6|`jT{9mHBMz zkjD4gjpm)Esj?J(Q-?pX3z;I~;-Rp#JKW?c9cH$)=w(2C7Xa39wtvMdX3{zpBLRMo zv;0+sK%Ud-b0=eTtXHXFVhktVn_bzn{6viLM_IfqBuh|Z;b2GaL@hHHKry1Bp@8m8 zh8XS|+qacNKp^vdASCFFdXFNHgYxVasV_`A=bX9juF}>yTaKge~UToU_gw$T8ueci~~2c zlzZ0Ki1O568F>lgPq?nH3i2X{EtgdjU;jPTcIR1~g{^(~$r>HZ0v#tDuObt3zY-d- zuO;gU1s3~i#wyk|P^`vKUs`2gS@#OZ^-fG=N3-t7c!HNf9zON!P_=6UF1>jYbah&j`W28%dot7r#KU_`54pTAP!~4=f zD7KkM&=om>_WgT35SbVg+^@eX@S6`qjV+*IOpVCweFw5G&9VV_U;wNg_%6C|W&QK} z40IRADf_7vYQJk6=|rPPWEoGi53vhH7H5uLo9^>LG76-#YJHTxhP_~S@A4^#knRf8 zO75Bhvn3{QXN%n0-uC}bCH0}o(|U96G2*-jyJz68o3RJxvYu*((pU2fCJ&asuWau+XF zD$-PK(yVB`tcdmu28CHrZ?fQdrwZ=V458xG6(|h3wWBB!J<~{v`>ot0#rXIIYa(SW z=KE{4O)mI+tVUjO0r>OT{sy74&$@{DtwwaA?=pub;Bk*55}LV_|9ApX zDJ15g(#eDd+!luId~js7?n?S7lt z7~r>^KklZ#5HG?J^7u8tiPGmful`l*jVrY~#ifI$c}UqN3L|bq_f&>EXJs4Y^uBRQ zoQ}`nZ=ziGQ^{n4XN4wTp_qrTD(fz})z5!jo#^nGg30;@gYIU~uiaA5on@%OGKl?n z$7bW52XMa=AuQu)DC8HP5HYT5Saemz2>NKj_7%l8?o(J$U=>GHqr0#=U=uHQn22>U zn|PrZyva~LKW142wURWQspH0vU1-VW<`mSQvh^4dPK;51xtZZaJeK`;6DR;Urm8jU z?FL|ecB+fB=%8RPFpN<=zGYrNwr>&oG$i6^xiq0d#kGgO0}i+PmD~XOw+q!cM4f8V zhw4=t7B_;QCC-Kq(maLJ%>|?&pU5|D)PC(pD5emjj?qLM^*b~Tz(1bAA%~#^T)cma zp#LjU6YV}RiTWK~kw!9A07};1xF|KrIU|gYjMytDc#?CIYu!^iyNilN1Ap7yFt8n?W4&AFmm&&O0_GHVEKn; z-Jng)*=tse6<5|&sCg?3Rtv``>Mbz~cC*hH4863^o3alVk&CV7VFO>4|xs)Jir8f7>;8CR!~sC93*(x8}c6l zuElrqe;6tN!hqB}!#J@~IHDjzH`iopNLTN;+t$2**;PrxZnl{FX1j`gFB4U_hVCD|h3w47}J z#6v5A7sxu*$(=U4;yOrk6J3KmA1;wvyI#hY{fsMMDT0LL${FO~=*(a!1Nv!%{Pgt% zARN&?`eTyE!k|A_-0||tbk{g6N><;^xKI2%U3O+=rIye!PTqpw{B5JsJB^IUDTT~MN`Yo0R zH^GxqZ7eTCC*Aro?}7%aQ46NKW;j6`=7<6X~_LQN^=x&C4S@{F7HT&&vkwwij- zZciZz7P8QFaqblHw`+tt04-W$a)(;uNV#h+x7G$4$A%LG-;cy<*<#WWqS2ftC?^}> z>XH3jy!fl11N%@xId)l5-UPd2&w9)z2yL*aD*TKp z{fUZFjQ0i`c|oW~kxiGoX1@yS1t4If)3D?}d)8C$p2&l~S;GPh*#IB>O9U0{CeBLk zG6L(&DGU@4#){HA3rE+};V1^*{}8~Cru0|T8xA|oy0`9#)WGq;#k;Nx8L?O4;@*z1 zpxKxwa_DO(mUy*9)sLj<&kHhDrhYr#h0%ISSgBVaDV$AR7DxFOIZ(v!czLz;+#1;_ zgAK*Q?Isi$y|vIdi)x;ve!Tut|Gmq<&Z<3|R&&OYw??3x$d8lSN3z(Iw!f#Trq!R! zW=lAT($w0KX6YLpyqFRGgj=y?Ru%RkG0}U2pjpto7K|#{%iP(;vYPupK4?2|7L9p z85z2dYiLmo4IF0a-DMbU@zS-D>AEDvCt;wh^r@kzPM2skgj7UU6-x`d9IV|;hnUNe z-Y%n>LTASmHcbWv$h2i$l4nK!oa1sODRRjqa%Fz_O&lmtQ^>l@0nI+%ZEoZjakf1f z0~TFXvP40?%){0ScGc)NazHR`iWdJHxrg#H4eR5L>>#cK6v1~7g2fR*MTQe^lSZQm zS!BV_*d6AnqUTkliMhHfcYx!~|J_d4eG67LzV9-sqb#GgEiAH_>?><%N-R8O$vukn zIkVjAvUfYJ%)Dg`O8nL*N?G|o4|R?Gq4jNZ{E^@-!!UZLZ_?Xz)~M$$N?yb0MmIl| zs$N?F(p*2by-U@)8k!MnWw4w1oj&vYFFr%sC@?sQTxmWR1*jhiBDb8UCvJVkJy$*W z>+n79Bv9#FswqYBAO@LWTwt8>M`%ibZ=$XU8s^+M4ZL2IKi#7qLs-QYDoeQLnhyTq zOGxn_nl~(*E>#aXG#h+qTB|!-E;iMfzFqV9duP$)f&sP9_-g94b$!7cB++U*+EQ}V zNRkc}+$p>LB4Oj0(CqUcf?>ZrGVxBgQ6}>lf!y)Ab^$HPGue>o6ILsxd!0;wC%xN0 zSpH(+y6-VsNLvW5cm4c3s|dD=DBkjk_0!ggyMRXDeU4ryoZd8QfM7g-wyp*n9X7Wb zt^q`ie0ub>$1;6J*@Z>2?rfjXbC{4f>wx-m*6cUDcif0F{&x=;EUdqjR6gaL{Xzb% z3d|I`rqevElaQ|eJB?4q#})*h>7-#L**nnee00dSI4K45@N8i3lM82-3&qkzePn07 zDgqBNIB(oS8PZq&G}&-m@maBai>ZcEep8 zA;qw4fZ}@UO?}p&Ra&Te9Yf%I3{g)KlVdUEw__#{jmCV2=ZW>S&R*exQN<6*=uwe> zv}BWKcWk<4qEc;ELOPdssv=x_r$m2>62x_LVG8U}6F4YQ% zfV;{z02c+*ro1=opIrpYPw~5CiE$=`eyC|MM(VfxGXD^&NKNqxhmacY;}{IX_w;74`ZA-u0z+ax zy(VJi1{KF1gMTASWO<^7(%OxhX`l22e|9wa!D=QHI72WsfFb5hr(o3~Z_X7^P%BAH z;7+&z{x-5gzP$OX=-cjd-ViTZ&VL9~G048hYlkDhJ4|XR9qkkNQ|OgCC#^tno)v|2 zEN~t&28NlT?;K}zmtHzvr1D;JMRep6sv5etUj&+!8|Sh5NN?vw1${eyOi-NCKT<#8 zc^_eWa+Fam?N4bX<>-rw(6Xtob zn+uc~X zClmE@oAh}%Y)vp?tAWz0w%kJgs9z&n%XqCO_IFTli!qVl%MPUlac>5-TAduOU!KFE zgEgVI^Uqg{l-&4j=l>8$pN6Fx*B6cf!J4N(7@VACI&T#`y((B6XAr9OH<;1cP}XZL z^R#6{&$|G$&hJ#d5>)(1wx3sm-{wpO_LHwX=_}30pHXFy};}LGO#}N!Np$P2dnYdFT9XmFN@dprpyQk4P z%SEG#l)@+dq1a(fJ3BSxbOcOGmm1rSNGqxZ=8{;zzqba|^ut+K6T(zz&elcu)q&S$ z55>}3#fUx_rf)aCXv7UjH>*3oGiJegclt5KW$3!%eLCo@AZkUdZmfXbYp#D{aDcY z^J8oqses$Ti^t3kSTCx~5$Ow*%H_*59}sLlLeIK3EL-!;W)B)Z`HqPYf!-$Jlbwaa zwrZb9V*jQ7P6ruK!1dLkYV{|?ggR?|@#Zev+NGOYJt4F2tJC|ll9A@qihqdCSI7L# z{k^Lh%wLxAJ{%VKeuDq-u;4~w#=_w2oZ!aUlj2je|Igu`TF6UaYzjBamrgS_vJq8> zU3InIQsR&>-TG3g#_$9E5jko|0JMUH;a#e#zHdQ;VEPmlS$_l@4;$3`_zz#HXPM32 zyRI$gx{Yby1~a9c1!^Y89FPIJlIuMw$PeV*U0AwZ9w3yktcv9${D)7)ZW75NG#V-~ zz9(^D6MV+y?<&jNlwZjJ=9R3IhM4dmYANYpfAAr8SE#VzjetZ-E%3I6%3jCxM#$-= zxQee&)^`lhA3f%}NY|{3Id&2=tDllaT<6v^WQij46htl79FGvTJ*h$#T_j~O35|rY zeB#}P%@m++;}rrUodI3!TPZLh@Z2e*Z;h4M%F=5?!1 z0G$!+P2k^e(?KIM(MCg=eE|+n@Z{gPQzzD(}As=EKysn78km&NmxU*rF^b& zV?+J06I5Y6D)K&+L$#9|mZa~i%^jT7Zqg-C=N`@iiTX(NfVUYcu%UwU_vIdaZl2_y z?+?^_2l2ldQH-GPe;Cc*E??r%O&lF%>N2f4Fm?hPDZXOdm6g%zvjI{jf5Ii#LP0rL z*{yY7mc2YgUKS*y8E9`-GX)pWbn@=$2dKCd8ElxieQ1xT8%r+SxuZoRRq;K{zkBDX z0$-k;3P&Xpzd!@~usmWcGH!&EU!201>D}`wwZ$cGM5a@M-Z|v4*NLi+AZsn&8X_mh zkJACz49&SvnWO(hD4y9v!;Xk(5)|J7Antme}{vx{oi}wg;wAaS!9}cQ@zpM;!d6oUbry5dx!}%aXP?s&cbEY z4&r$?U4K%=+J?c8LHv&80~?pxab_(p5~2NZXsE%5_sc~V=sc<=IF{&{`uDl^Baw=G zD@;v~WtlECaAY|d{H`o)1?-X>C!N9sM^hLn(!4+tyM<(qHN-)nSM-jBuaI|7{5XMC zZLdPFF)C&?box>vw+_?zvsJBOv|%T2dHLI{ic|~kvTGe;9F9!f;=zM3X?6mm2HMTo&SL*>f2Itk8qx#U%^OS&g~ zWm$1p6sxLpRv16HE2+Mgl2LuMb)uCr>_(j7KoyWFaN6uFSA}h}K6s}N*nMzayZzmT z6OqLA>;%i(j6ju2A_JC_1O{1P;3UT|StzEW#;4*^<)Gdtb}SxWX$T`K&1&v?Bli$b zdy~N*}#3q`EK z$Z#EZW7*PnPgS31LB8g~Bmv)GugAiGHNm8&a)NUYZwQFbFZ=Pi=GJ9GV@)G|j%QvO zOV)+1^gy)4xJzB*;Vm@tnw(Lh&4ce&JZy>%bgg6~lDZLb%(ZKDj{K*#vr?f|Culz^ ztVSV71q(QTD+$w7a$?4S;MNQEs=3cUD2h$)9*#}w*$~2Uu3ckJKG^O#`Bw=YP6ZC? zs4XsIfd)buY9~SR3h30;ba8b)0J1S){{$WSFat&wuGUB zzU37%7dbrK+hacTfB193?@1Duvx{^H|nrK0dAE_5Q!D+ib zDie$SG^2viIC?X5Tvr;2158AOLVYBBK_|Q z<-_JN{HhDhgf5L5H>buhZi{jq<_N-fRJjX#v%RaeX%PZHOr4>MsNkY1hj9EgAU zr!WkOA@kYoAtv_B2gyxtViqs^Kv=!ri&=*?5Zd^YA^Rt14Hj$937|=%F@(oCRK}IN z`3boaAowPsFPpXPy`E;AulnWBI-y$-z9jGAa5%-~Q|GVrj9hNDri zNa_HC&$VWT*?<%OpH?d>QnE0y6V{3VtNG!gYI0$`?z|?U$~}i$`FS9x7|xqO*UHt+ zpW_E*@?38`40?a1M1x`7G$UpLrt@oKdG&``zF@_hWS38juU*4ZU4i=!n`YI7j+TzW z&NUJ?L%x_d!m|>L9onn&L_M{R(*XW{ck?orrB&iHfF^d+8MTuZ&VqIsiy*hRP$q7N z2dSZJGpDhY;Ys>)*Zxg7|2`0~Tr=oZ*AGQDOVM7>{pJ!fyv-bR5n6DoVCsip__p6v!XBNs@)Mww57-#;W`m=9i z94Aoqr~L;O@DQ=*kxVkW%zRAc66g1#3{~VLksuWXxpk*}i^YF%D)Y;=ok_63E9L0b zTLX>B>0lzc-U0lBT+)8#$|v{_!K8iO8334c_#FNTF+vRdTr&LKC7on`r#Vr?-kXc+ zT1wxF@@+QYPiPxH=5#~NbsFrJb>R8PdU834c1fse*%^91*IjRR9P=Guo%64RPWq0x z)Ge0v?u4x7n_u1!{w7{#E3{$ESm=ykb|7N8O%M5;FI1pLmkrRFjrH^?qrb$)yp_FK zz!a>)Cmh(Gy&nSv6w6)cP!FOMR*a-7cmIcwsovuhNo)`F{lO749Z~Mt1jVyG#rz1C zoZXop=L#<%SU=XtIa|6LRpk1?hLX*S26-1_ghleVQb0#p$n4nIFDQTbO_}!uu}t8n zwy#3s!wmQ|<6ds1UO+=#7oM5+i{wg&a`m}8y-1BOF3!&*6?MD4tda}vGmBTQ)T%h+ z95nF;M$_%9krf7p5=`I5f~z;DdnVY6M~V*R1lQXYDo<;~vMww7lHukeq>@#aFaIID zu3s7)xzBmIDgRWg7P(n{Vo0hO6@ul+bn1GVzWwVwCw0sqD#{a*+Qf#48B2FcG}(-B zVFNj`$JYN@IM#z(blh~F+ox@7HmeTW=#dQOKBKBSXb<^; zoRBKRL3}4uIMd~k*j!ldNy>MJ?Tcx0@gKsfuezj@X$yZfH}-9nVjaPxAi+Kxs0wI~ z>{_;u!CjlcN8%1c*uaqheA4ti);0YwA}mYg#Shif7_R^-x#^r#FYuXGDR!3A?|<^$ zxNdv_@(T?f4hU^l$LFAzmzOxG;n17QBJkj8r|YtDY*o~Mg24`)mh!*JCB+Zh)!Zz)E8Gi8qnPgTw9sfOAQbtkt3 z`HB5H%g!@MVX`*OpEez`$}WCFCIm(rCortOqzTRA4$ocW6~-XXI9vf`@@Y|Cigv{! zVYW5U%dlnpo8M-%{oFU(kfl>yIb9!V*o;tBOl?IX4yp_atpSDU2NI^R;-x0JN8J)T z5t~A#)&)ats#U_={nZm;q)cbUss9j4rZDcwHJj2N_ztmKE(h#qw5Pg5RqqhU z|MmczBCPPyeXsGxpS?n)TuZj6Z#P(M|BMg(ZxXpoP21y;Z$^-E?uc*Dsl1^DaK`>v z9X4Xa%D*6k`gcRAlUMhsJNjVPuT0-HkD^LEI1-@I1wWn6aRCCBB2+M*9~+o@s1|Dak8-b+7)^R-%N04L)=Kh^vnmmya9S+Xx2e3Vv!R{F^T{DjM$ z08^U`T2q*Ey=@ct=QIYIO4TPe9Wk(Va`J7vHh&JSoFUt_WW9|H_@Yn z1sdLle@^tVpgH!P6DG%wX&dsUk@#lwa&E1+W0Ml3W_CVwd+bc?x?jrTwp84=h@}QMzhf4fR0Xnvg*SooQACul7>ZdM$3l-tG?GiymJk-5%1kMrjsk%vx zFw`iuVRbuj5bQ+?u(308MSCt4ME$z&aOaq|JiUUhYCgoiS>NZm$agk2$vS{M?UsPKL&tH93E?uXLR>L*-Qv(F*&`Ip7jNPIb zRm#0K@0Q{9Eq8x02&}<)N9>E)dcLFGN~b&hZwZyFd@SY3&gMi#Th+TvW+~B6SjNXz z^S7z`(HM9O{?Q>`{~;vZvqY4+j<0mYr{o8opx2z$?s(mOTQ9dQe_sMt%NcZ>ck%qU zvbOH5faqq0|0u(NJAfd?SemNL)~Aj;PL~xcW*LX;2KSGuv3o**i4xO!Zwj|FFgp{z z7rqg1cx$+u_Y|+o zUV4AO_R@q;-mPLoSbz;|SnV*GaIe6Y=o8q$Ro3>s{uj&h@3aIf5R~m`SS(;*U_p{p zO~ZXN3IbsCT^^7qg0e}TU&*NnDA}nTFnX@1s9W~|&YM?Q6^6~=-IFz?16voGO)Eq7 zSOC|aN5;Db*e*xJEQ_W(*J|>JP>zevpPp;a(x{6)9UFG>?w9Ej2hNZjBJbX`iM%EJFe`0d zu92z>XuEF2SB-u}o4@>Uio62c4>GGEmXXd=%pMtE>zJfW4rXaUTJxp>E%+t@>a|In z%isF^oGj$pg&z#iZE~7Ss_EjgZn7JHL{rW$de~BkI`rDZvkH6p-X3S2dSLM;^deX+ z$3X&s_SdTO({TP_mq`w$(Od~uzC#UoVw+=^9cjidB5p21fZA9r*pra z6%%6FGZx4k1*@Kj4q=neS4Ce0Xr8tOiliIX0D6VSKwe9JD=hOj>?*HiE$hcX7~VaO z{gsYqZBvUUNy<3vtll7JWVpy6P51*EtnwxD((f+I8rI>_`$X@VdkW}v`_{1O2Syph z1UOY^gXA@1a7W{TQt1Pvqz|fvUe4I$JpC}DmYg?V+#B*W-=z-70S1F-Mj`U!Jqdj|3g)Z);agUg2}NS?P!XRLm<`)XLh)JJlXB5TvcW1#!U zE!kCD0VNTHtmu04scVG4byAp^^x}QHgZA|8`@|SU%wK9$OE02ZV$aCd6BQ0_)!gx5(iT-G0X<> zhGTX|yemJ?G%Y^G*B%^`qaXUGsCdfM@=wy*t%K(BTQ?f!M#f5L@htBX#U@j+tdgt0 zEPC*#1p;Si|3jcLHPv2q>NaciN?fx)LApQn8xCOyMYX?vI493e?=~+A7}yv&H&B5Z zo|AjYTyl9+h1oA0V40VN=H=lM4>vCgXEMvEkBJ906fF@k9YaYtRm!|fH)qIyYtCqe zoG&(2dqwyIoZaMG6F?6s`|S)M5k0;LB%ugKF9@oE{H&R1%pC2r82NecKbaP6bYMeb>Pc>~VJ*QV1K4n=?PR|sJKGV#0M66q|1{6(&Dy3tYogk*@4%&m zB7!rd$cHpbV;m>)Tk-2I0Y|X*2{l|y5}ZuAAf1W>a3#1YY*}AgVf~D**j_GYQRc)& zD&upCWWZ+oDeFBxc<1ELW+}*P#)R|j&KBSnd;WZPF+A(H|Aoj2a{GLQ;__-Za@S#= zu!B5+zSDx7!gcQcDZJVy4LCuV!2KzUFzRtnEz-bGf+DQ^?mvW7mZ#|1gwxiGMiLI8 z*w+ct5`O{vS^>}(ZBO&S?}nex%1QaPXV5~8JWEWE^1skjqZ`ByoV#$^97^54Apu#& zA?c3tsKr{&Q_bZ!S$gK`qe->=fFE84T}WR-t^_|=>O~t~i`VaeRp~$U5R-kmrf(cg)CT#Z^6SIBy)WWp<3Yqui+*v5{aajE>{6CHx@s$>r$-6Irk>eUY z5}1KcGAIUc)o%N`xl|ryd2fb@L?66LS zA%PPYJ;E&EwZ!Pxk!3Z3^ysIU5FYP}Ll>`Hi$2wQhGFl2WBG!G&DSOu!Ay8nM*-d7 zz|)GV^BY){+pK(dBifrb;;9dvp+|MVfY{=3#RG@X3z!rlx zYlU6jyv5&_(Ka(|i*5*>NNM<%Qn(p+ucj%i#lD%C>awibh5j7qw-?7C$oW%J$!lor zma)wyJC(;<1&`0{Z2}f(ZSBz)mJxWQvtXYNciMQ5hou=14USxF(q`))bwSa?`8=`? zk_>=M9#Dqr#DlL)^zS5kfCm$!+08-oEab9u{_NF`dBO^AthKkPdX)tl#w z+t7^tcotxFA1^gJ^GUg+gh~R@biZ0<=$bEd`tB*Wt#AOM(n&Je7n|IfQ@W2Q>sFW_ zKcY7-vH;DIbPW+)ApGIlEQE(@DDR$KqN|H5JEIUKD;_*)iAFv+Fg#y}Wv=>tL^(OJ z^Xc9qeFEAr=|DeGXp2`)JIUABe>9+vlzHYNmz^22A-pfOGN*b}D4*!F+E!Ym^>mx1 zF`H>xuK6{0ImtpU5~DxdCjxpaXqpKU%T{h_YhY;UcS%&swsO&{ivBT2#A@^i1+4wP zb+(S|Z?dY*WwTlIFD8Sp`a7PQtm!$zJUca2T$qHurq?EBE@#APQzyFUwY7**eGz2g z>&6{mBBO)!F#if+{h<>!&TSZ?8gR|1a4hyQ8dJ|IXuUwCp9$SBhbbG&C6l|!s)&*z_JX>jx-DCv79ve zfB)+rnov+V>~S9gx+WH8IP=WKEF`SOH_53JM}dAZ7XEpXe6j?!r(q(9;CW@K%te@c zh#N_uCL|;LN`Fp34nKF9>)I5(r(V6N>x3cS=#H#*$c=o=Vve#BAjZ>z?N>XwGC9H9 zysREr_hgTU+&5S;l|37?>{0ni^MJN_>A_CC`U|xkz+_#Rl)<4%nNZzyz^I( zWJkHpI;6eSZO;j8Z!2P5oj*2UNWK0nwVm+o=Tdg{Qr^U?2nSFrbL*Rc%FnuwO#egp zXGAzty23D(U*4!f%M!hiuj(t1 z=_2cDm~-@!NK{Yq=65k8>y=y;=A{TQZ1ZpG(Pek;AolyD?ZGl|D$S)F%j%rNmtLZJ z3;Pyrk|AgGfh6yffYN-7s|lgla$((wC- zYzH!8JYuQi+yaVNQNPNt(m#hUG0xJM{+?YC0xZVR?No8FG3JK$8)c+_V-HM{^sk#L z+7QVa4HK@Kk&G3J_g+kKv5N^X_q;N#xDXCS zF*Kv>6wM}i^ajt4f%tw7Tb2pN0rLY8b+h$g9T>-rl(ydyk|x+%Cw~{ud{IdFA&pK* zD0PBCBu}GnX--&yI;b(7D0Vwn420YAmwd12^trgvMzXTL`^@7i?S0Z>0IQcTJenWy z*cWviLzk?$xEz<4ERm>%GPqNsT?+Y*BV&G8r|DAI)y~j+z8mGTP{xcy+U)#}WxsJu z9Qeca9>yxbYw84DsA!E=BB`j=l}gR+896nrHECcxdT=nqwgPHPo6NLhX%k=nS~V{> zy#rYf^Wu*KtjwTftz~J3nhl@qPQbL^l`7R!*fVJ+!NLQ*q?E%#wDvabb zp@PPN4o0#|3=|7L6KzBI_g!U(AM_icG%q$3F-AUZ;hF7H9qJVMS3Df zX?O7g-#PX~^zm_hpDMRqR|ugXjnR{H-29vp6V|qb<5mAvBq)0(fB6VNan)qwVJh`I zO16H@&rCGf1QY-9HBZv9HF@=_*00ghhMEa&sxUB;=?_FKp6nQ&G;ZT2UHx&ST~$ku zc>b1mk5amO?eibP?1A;cp%-%iy9A)f0Cg%=R%^Hd2_ZBq>51&(Yx0r45nk8@y#|MX z`1oRN=KLzT-DTTA?b3e;Yh4K8O-164*S|WSqZm<{-X+m3MmF3zuZ}j#Qwy?KP)8C2 zR}lY=rOhgK>K0zjCh`F=`*hzTjE|{|5MD`9#g~lU^4^9jIG1tRsL7vN4`S_>3?){YO5*n^}9m>3n`q^ zQE~^lLbEKXAvzi*A}#AsTDtIPhETEHdatJd9qb>eElb}wL)_#%O`-^Tjjmp5*vHFF zOfoRk?2dG!_za5xkjVu7KJF+3i=c#D@`*SPY5;@2s$};yqZ&v|diM$4Y|Ja~ZF3B| z^z@M{wQZdF=Y_Jz=d!^Bx7N?0^(Xl>^P0~Y6xh|&k6e6E`Q;BTvdnd59IHz02aiId z^4oOxoJobW>?S`A^;=0UsX-e;BaS{J{QLF3oX5HN`6e5AjMByP4r%3>1J0 z!c1;qL@*QZ3~#-A{I1}PXw1Ce@yk>3(3|t54t$X#TSe0|xe~dDVpO%Dske`+O71B3 z@>#x)M0xIh$;$iLQlbk%u=>pUY|Cv_9~f1AE`+Gj_2IqeVzZri-{p++vg;HU|9Hs| zv{R5B4ezpb{Ld?B*wMWnN|I)|67DIePHZ$sz-t!Y-^%HEZW3I|Yzhx{S#rCVi9MK0 z#$RV|Fl`{JDju89E{ad2Ay0^RfspXhEqb(4x)iM#%jO+tO^#*UwZozV0@|-81B13+ z`QhnJuArb+{@R)*s#5k!U2L)`fadUbRg>>e3mf?!BYH9wI@KJK@2PoaJ>sc?wRHnZ zvo)UQz^pUH4 zbc9KJ5hw_Mq9u!KzKi0w*AqwVX_l;F0@+@U=kys9W)Am|`t1h$WVR@tX(Eo5K&Wa0 zgDVqa+*2Tr%$yasol9s0%oo0YJfggP_sypuW#rO~^0M{%M0Hc7-pRGF^+-UL$Z};T z-?28DQ9+Nn$}6yT5lj%9jTeXrxb`CpABRz;<&HM3?_#Dwo%S^afklPR z$uE?;Rs@){3u=W9`%E4t(jDxRwzN7B`+b<|-vc@BcH-&M=OkLA7RXd`-G%8er^zb(@HEz359RVJ2Il`~%7Bsdb>}Yk zemp1Ul^@fyF9n(+BBobTUt=_uly9Q9-hi#8*8m8^YY0%-GVfm1Si`FNXcf*orZO!z z8%5M#8nZ2Zl^DI7RUZiCZLu}Yh-lOCl{a##U&6oMW{f2STXVx3J9b@C+CYZg>ERQbNP~^M5UO7~b2Q1?)ioL+GVkWeaY2`}vea(=_)V!dcY7 z>n)$z-R@;YFcgq**EjdN?el6f3yWpErMwkHg?qDExDQi=Otnx-KzBX)e2J`G8!!*2rV)1U= z4z}`$sgI&D?sB{-w*~$K{Sa>)Us4X9n0=nP`~=IBBj^~$5r5oY-5}4LlFuy4Eoq?k z@XDH2aMj>FGF9VbKtq88;^z0maf;xnhc&XRqJ90(CS4yDLhrvS>Z=sY-b)ECzb&tHHP`0$mB%mm)lST`8{Olu9BvXD>T0mkOF@wC<_y`oql{lWDa18%g{El6 z8CnA|k9}5$s1o;P&)}q+!g(miBeiime7yWv`7Dxqf7A9%NBL^-zwi;l5>EpSP;@vx z;+%Q#mAkOAl)@MHNSc%UI8PvCf#U9#Y+-yV{TwjFI(H3#_jTmgYll4z#pnnkTN7KHf;G^6X2> z?5$b=0g;MdIX;1H^A4a&-)wXz=l?k#UP4UkAycCHrks}%F8}9WM7WG0{ z*>!J&qEz}fSnYHQ#z-?3WuLs{BxKzz8gv-5sti_H2ERJ})E+}KWb#DiJ%y-YS=H6^ zHPYHL&{v0Vuc#vtBWJ3r@Ftk>4{>r8DQs9tuYVi+=>Yi@?OAWmvC!X}d&Ye_L5F8P zvld-6p676zidMGh#+kw?0XVAK+rD7R`>;7<5{T4)Vn$PYv;Qh09l7coQ}yCS z-9rQU&AvaAnn5Y|#c(nb*#%od)8bHeJlkf5moD$&ZrHxv$PLTeAK0o7y0|0ycIR&I zJ^pMG_EEizD%*TDb#iQA^go3D1QgpR4Y;*Iik%Po)Exu7?YjO<=KrlzPwFtA(Z<-# zaUV zmG2h3`Qnwx-m#?H9AfK9XzeDkGKCs3?4RNK9AQ;h(armOTq0C$)$Om^^OyR~ZzX@1 z^+ZY+FTyZK%w;Hgz+Zvm=veDA{fX)-m*jZ- z0#Op1?s@T7{4~hd5iD*A68a*5!KPX&x_-)vRngSxzS@se{;}u^WV4JnmS#R zL@X>Dbh0FhxpV|%+O5={vQ=MPut;j(mdhKNHVyg#Z6};n!f+M(b#>6OS7V^$)unaB zSqBc8J)5T)rmV23$|>!W1UyQNM@MC8V0hiig}N~4Ms}2cVwXEqn&9WaXP#mD%X@BC z_xibqC|ZM}sJwz1McZao6Ov+fxS@#)hV!5_l%V#zn{{9$nkFwX)8QIISQdpzqc*|~ z=Fzl__hndT=UYV0r#LO7I@Wa%VN|N}auqEM0vUo)=$V5@uLUlI@#dml$rFp6I@9zt z^+N2Wnk+@3;LO9i*=UWVPw%H}esWVgHNCji9DtUx?@Sy%6zwk6SoK=+S?-uz^3S-; z>douKDR6yh)_~N&=%tVxR@*zu*fH5j2Bgx^f4C57U5dt7Zs;FpsK@_gX*kz+bQA3= zxq;&9=(7fQ@DJrPnVNGsv(|sE<$KRVlT$EjN3Bm>Ug&;L0SI=_3`mOkxZ5*P)R`e` zdAca156Hj#?r**STAKj_9bp2R%YV!|9cJW^2;6x=QzL#1)#=6q33&zy@YjMyKe>?P zSi#?ujf{FOSmyn2?}*1QKb!BZ$?ei>S`Z&YR+QLHB(xhoC=bfinvFn?n1*8QSJZ}9t)kA+^lQW~mnC@kpRQni^kGWIwXqe!;wIgw44g=I@h z@7YAjwWP1jo$8Znu-9X?4HQfo)7_^JIN{qWvKWx-^<9bh%)zrimtwRDaMJFU!~Rlk zr;qWHUc*SKC337eMqmeBp_byq(GHZLo-&NIUPgifQh~(2k?nJS8I%?rW#gmT9JVm;$0n4b9v`q5~7GOYtOph zVmolLRBx^_$JHp|f?}(tUBEB}>^y5{Dtp9w%Fj*+sxqDroOy&2y{tirVOKBQduqw; zmoFUx77uz3iBPkax}ERq6p21U2m2bVPHnR$;5GVT-O3*CYGP#zxecpfCZJ`DZ$g{c zYKVcl<$JOh2%}c$(7dpSR&Hl<<>FU%g@J$$qiDKN<|e_SwWU%&&V_Z=$N~oRku5Fr z+@k~c-WXn|-v3vd|G%NnSH8V^sn;Q$kR&g5scsXW7Yz2sE);BptOwL4AtX}ohy$hNT5&+IVOwaWdhSw3m_AA-Td_BWcvk<}N^8gC_F3`@}0_k6d@{n~3z zXJ=-RFQe|KOEj%EOgV3$;U^<}P-~<<-nwxV3e0Jig+`B%swVpM#GuD(+A&49O68r( zIv49ViynLW$*Vx^_ ziYwOzl9P_37KWNF2MhFGG`LB!hrnCAk;fU{cp5MDrlm7~?OyqOX#2hRp_h&brq5{C zc~Dshh6sBj>{>yGz3K+J$?+6Y3f72kk!Th4SlOyFK=sKs&#II8vS8aRZ`68YmXePV zqXJ5M69}Te^!!|`uoe0H%mgWuzrLC`vGR9WSs2GF$-rOwODzKT#st9oNng^H6=%X0 z#@&hqH%O-gE0kkIUI;i&lAf$G1Cro+I0 z6kRU8O^42hsy+UnY%U#oa0H!ChO5ySrO)PjD#iL4yS;EUD- z67VLr~>{k&y#MFQnoe=H`)Qiv+)rb-tVD*xZzfDi0-g=^!mk~00 z+%H^r`7O1x7XJ(QI(Sj_F$-iDWg4~3k0|scn(jcaPa4+1MY-fcNr*Y`{4tipq##%k zobpxl=<598=wDrnLtU-|Gu(k&aM@IF8{mx?haZK*m^;9{eS+I$P!mA>9;Fqf)n71g z5xtjl(9wTLL7@fN&z=vK)z`4UV|yId5;m+Vcws%Hl#&mWJpLTo@5TFcCHo0Wh0zvcCHf*c_EUKnxa@=U$dEM z4@?Be$MOz>+5?!4F2~wU>#Mqi@;3S_q8}6OyG8`c&)sGy0~^xoJ$aGr_1t50UsgoM zbjr`I@ADGWt5@c3IL`MX4{PT;A4#N~#L@od@;GJU)z0-?Ol$u?_L+R?~11ol$YYor&WqApVbE-jHQRNr6;}CZ=Sd4C?0Ck zo-;%YBb8SZ%(+el&7}MqI|8NlJ625EJZ8wn-nRHsla7^T$CjgmjyjqyU+-ilN~CCU zgvkc(7u*k0#hXEzqU0+M#pJURl0nXL%1N;sd0rtoZZ!4F+$rj=W~e`~xwssn)V-NP zTCf8q0s*FuKmupoT1$)!RXxwBXYz}`)2^!Z22Mq!rH!}T%I#y?PQgYgEk?(dh=B>O zG{@Tv)yfSB*Z94j=epK+DhH&tYR8WfQBHY+u?rZ+s*LyIzT5u7>q`H7pr2j)p6mek zP?2X(5EPJq1ZXXSfj#q&5HxxH+iOgzCa@gqEtQkX=93&@Xb_Ah`&nSoNtXq4F^x=wU| z_1Bkv`jr(2rLuQ*SUKoyb8m|KgdP3q0pAYZ0rIUYWt~sqVs?_%w z?`Ixncn=Laq3Hx~BmP9#--~`fy}aF(|fadIM65 zbLr!#*k%j9yiF$-2*6mBi!Wtz_lQGiZ+=ul&*GhUfaRm7hz2g9c5*y!UVSiQUXSta zSOuOor5S?s?-+ergb)@g|3HRAN)iBqf{aO?-lCAYuhDt`8{ zfz+g5uxxw;Hl}!CSr$7@_@^Urb$Uh;neqB}Y3asSaJ?H+)~$vwyqmQ4a%a>M9GhIcgv@(2*{|j%d>wII zdN;Lfh&CTTkyZ4=hQq*i3tMSj{AiiYCyCNh{5o8jeX(fc!EQ99-VEkFnqJGIekxWK zU@AW<1T$;K%8!`G0-B&1s0pwH9OoHoGoU_GTy$1*Gbi|?$_qS=xr-i$d#U|g=SuR& z{fxe=n^&;Wh3eUct1eAQO-rr71tG4H=)du_vzx;{4z;Zzo|1qonkTRUJJ|-%`kADs zKBLo~>5gLRu6Oz>%RuJpS>(G0l-g>|SJ{sZM3yGMShl=XCnmW3J(`M6)y#?Y_e0MB z`c8kDYjyuV{994zuY_x6hUc~C?CnpZo!eI-l3CYBCRQfr4yh&q!$5KRLBVS$+ zz`X=<@YCq808)|K>nof`q@)sMT#`mDkw{Anhc0@mB@nC2$SiEaT&ku)@Ptu_15a=Q zBzr~3PZ&)1=0BtlTN-}aNzo6@Vc$XenWk<5;p?L*zG|NR?lmG*c67I{toNZ^T|m&g+PE6X~NQrwn-|#b`xHSIxRo z)IiM#A+Aa2*N1M>Z;uR1TAtx{@1{Gia)W=>aURIvd(VUn2OEkAUHH$eM0}=_aOjs^ zhv@zq>A7ar61~dik<@wjo(&aip#N4g!z4JiI`s9-BM;-sL2`gXnH0H)*sW~MaFm$lzQICBk zs4&Ppr=v-^YSB(sEp5^Kgfb`wbm_A1!U|3e@(%bF6XXDV`?Vv0iPbc+g89%^=0SQL zIxHx#{N&k5`kFf8+Nw`^@g0JrNTMNZf&3fvF`n{+}FgiPl5ad8or08KT!Jg!S>3!MWt?TRi3zf%a3gIZJ z5zG1y$sLRDPm^0IhOiZUo=@z7(HZyl&ose{slasLtBF9WlF*Y9XWkU^)@N7xBJgGR&OmR!6PAP7X0=N- zX|Yo1Jg6wNbM5)Dn`0J1$|yfZpywVEZo>K8ymYg0_L%ag$0(98IwgrT2fA6Vnrv_iJYpc_+JG&$^rDo!YIz2pAS69Gs>4?_^mdd1|}tTYra={a>u??$^x8Fhlbxf zX-REC{I-o-^eJGeq#cddQ*q((ZDEFy>u#&uYKmx1@8Nh7Hen9DR9&hhh#2y+L6Fpo z1LEjAWN_j$i~>>A;>!2+9>e_AK=j~`CCh)Di1UsR(J`!GQsES&k!KiV9DoS~06_Sn zcIJ!wOD6hXHgCOT z&|v}1<8*S}f(Yw*VEawfRd~XYXHo2akl!P2;>TOXEEhS!k7m-2vw~5n3KH9`+igR- zz}c;~nv*!BsoM?*3vfq9|I#iP5v2(Xr@HphFXE3S+(VreX!t>^Nh*N+S5;m_#FOCt z|4i&kM(yQ4=2)+b)32-E#fn|FxgQ0$QUxkKhDxkEAWqM-|6t{R7W{LFX(%nieE*4Y z7#O<|{x^p}vq9jb6V3z)3jZOwSxOM=x&J!Hq7Hq?F`rfL<%mF9u%Zn=X8RwQE8O=# zq(OtEXax_AgNI99)fN5aF6`EQVZk=98+2{%gVyHPNiT1*!=9Zlw=tECv2p&pTj1f; z)nm3y`ICEx8~R@nLjHM2DId3ar86%jl&^+~CqiU2^V;eSa`fy~*R@245c>U5N&U!_j^|x;;{9<#Eueu($pnO|d zci5_?Z`osf&I0KQRIW1kV(rW1KIpUJCE2>IWo#1>Mg-vj;}8vAkBdf(X9@ygr+1c= z#%M7SQg{o%jD&P0Y!NROz0vQ07!RSdjFz|bdiE;D6dgNW+x*e;DR38)*QZ$u*{otM zz>+VcbhR6Mhd$ME4p;zDR)~-xEFNUnyiYT2TMnjQ7jItyxPv_7_r^1Yt6C1~T=R!$ zX|k{-&0|Mf^`}o9;#9|IHu*Mi*AhB6zmz0H&NLMluPibz_oNMlRQG;(bIJ7jESvs| zV5#+y;IJ-Zt8W9|t)ovS7CD^W7){Piw%97eF~dYSll5T9yYF-=KnusEdlqMC?SDx5#GrQ>299~L2`Rjlk-u&e(Uwq!b#i4SM<{9f^MxG7K zsk6*TLpdMdva(?zX)awHOV`e7e(R4aKq!}I%1qY$E>?4###A7aylhKEa3$C?KA^p^ zD*@@Qnk0kTYxM8~eoxA)RGdc-Pd1NKW>`?KS zQU3frvQb37LH56}NCX^Oi+FkQ2Ydd9)< zk*@#{KL}zWoVj~`$fqloqgnCpC6O$}V_w0+h}nx3KaGJB?!zjG*&4l?SoXH4+JfwF z$|}6eI<52a2wN_pWj3J|k>S829aV-|m-GwQc~QDwTt_#b3l74XuZ(#dZhd{UNwE?@ zi?`_Svk7epaH}ilcM+uym5Bzc(Y5W@r2dRP_qhwT)n!Mb&jk(RrSyt`Z}pHZai0dH zxNu}<%W4BA8X_4QsU1Q(hLLjAS&W7A@`aPi@m#yYHGo%l0(RqSBk^Z0-tChT;j`s7 zRgU^ld3oz4kJpV2jj0!bCpm7qqT?4fPpa(2;MU6R$j@FbWhTu%G3)Xb^S|mXTviv2(LJe(&GA&bm=o??Ln?%m&^?vH^u;>w`(xZF6ohVBRjsFp1 zoz3fZ<0(Sc5~Pm5LI>5~afMeX;3N#h-X-Z-asW6fkbY-CRdIg(rX&2yyf79fki_To zP-+o$QzD6XPQM%qP}&!l3UFPw2z@dZf4hQhcP5KV{+80A-hj;M=!d3qS@26*eL{dHGi?1MACE4U3CA zu?psAIT(e%vgRrjLLHVUS7hzj%|ewyW+sE2Q7V;1rmi+Ncp68hHryK8XbzeQG|-dE z>vIzNmEfC|&sKoj(NO!xgV!0m+%)4d==R2Fa))9yQ@x0TEsgHeA^#p7p0wHm^}sgy z+>8yWN*stk<{yoF5xv7}Am=UCdbd@wp%$p2S6}!fry`(Z1Un1=(R=%t3K-6i&A6Qw zEDV?ZLW4kQ2KzksN3McHFf#-KW&(8L)ZGp`OY3ziG^}}SXJT6Id89rfDIT&eD$^_e zA<`_(^k7a?EKLf&TQMp16TA88w%@B?h{k|mI^#PQusKRg{vo=f(!BgdV8(JQI2}6~J4)b8Hr=+rJ4xO|fh2P$SnMv*Vxbyyv8VHTYDA7J%ETq2x3KaNvpwLPbY;bc z1&AbVuxBs%?snW`=3yvbIcZdE&$-loD=^?=)=d-J?hQld!9M#t=op!P*r{t&6=}~x zFqt>S1P=vskwfKwNPkL(<IUpWvvaKfNA;0egPL5&lgt z)Y2ih*ZW>KRM~|4f&FTD&FcMoYB6%oY5}UyYHs*RK||S?=%th)e+@0i@xAp>9{U

* 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 literal 0 HcmV?d00001 diff --git a/渲染/软渲染/图片/业务插件(RTwoGameBusiness)TCP接口设计说明.md b/渲染/软渲染/图片/业务插件(RTwoGameBusiness)TCP接口设计说明.md new file mode 100644 index 0000000..2db50d1 --- /dev/null +++ b/渲染/软渲染/图片/业务插件(RTwoGameBusiness)TCP接口设计说明.md @@ -0,0 +1,1541 @@ +# 业务插件(RTwoGameBusiness)TCP接口说明 + +## 1. 文档概述 + +### 1.1 版本 + +| 版本号 | 日期 | 作者 | 变更内容 | 状态 | +|-------|------|------|---------|------| +| 1.0 | 2025-05-29 | JJX | 初始创建 | 正式发布 | +| 1.1 | 2025-06-15 | JJX | 添加get-system-info接口说明和更新check-unis-net-state接口说明 | 正式发布 | + +### 1.2 目的 + +本文档详细描述RTwoGameBusiness业务插件提供的TCP接口规范,用于游戏客户端与业务插件之间的通信。该文档面向开发人员、测试人员和集成人员,提供接口的详细说明、参数格式、错误码以及使用示例。 + +### 1.3 适用范围 + +- 开发人员:用于实现游戏客户端与业务插件的通信 +- 测试人员:用于验证接口功能和性能 +- 集成人员:用于系统集成和故障排查 +- 维护人员:用于系统维护和问题定位 + +### 1.4 接口概述 + +RTwoGameBusiness插件通过TCP协议提供服务,主要包括以下功能类别: + +1. **用户卡功能**:用户信息查询、刷卡登录等 +2. **点数卡功能**:点数查询、充值、扣点等 +3. **游戏记录功能**:游戏积分、金币、宝石、卡牌、投币记录等 +4. **4G网络控制**:4G模块状态查询、启动和停止等 + +## 2. 基础信息 + +### 2.1 服务端口 + +RTwoGameBusiness插件默认监听TCP端口:**12103** + +该端口可通过配置文件修改,修改后需重启插件生效。 + +### 2.2 通信协议 + +- 通信协议:TCP +- 字符编码:UTF-8 +- 数据格式:JSON + +### 2.3 请求格式 + +所有请求都应遵循以下JSON格式: + +```json +{ + "command": "命令名称", + "data": { + // 根据不同命令类型包含不同的参数 + }, + "ts": 1621234567890 // 可选,请求时间戳(毫秒) +} +``` + +### 2.4 响应格式 + +所有响应都遵循以下JSON格式: + +```json +{ + "result": true, // 响应结果,true成功,false失败 + "errMsg": "", // 错误信息,成功时为空 + "statusCode": 0, // 状态码,0表示成功,非0表示各种错误 + "command": "命令名称", // 关联的指令标识 + "data": { // 返回数据,根据不同接口有不同结构 + // 根据不同命令返回不同的数据 + }, + "ts": 1621234567890 // 可选,响应时间戳(毫秒) +} +``` + +## 3. 接口详细说明 + +根据功能分类,本章节将详细介绍RTwoGameBusiness插件提供的所有TCP接口。 + +### 3.1 用户卡功能接口 + +#### 3.1.1 用户信息查询 (select-user-info) + +该接口用于查询用户卡所绑定的用户信息,并可选择性地返回排行榜数据。 + +**请求命令**:`select-user-info` + +**请求参数**: + +| 参数名 | 类型 | 必填 | 说明 | +|-------|------|------|------| +| cardId | string | 是(与cardSn二选一) | 卡ID | +| cardSn | string | 是(与cardId二选一) | 卡序列号 | +| gameLevel | string | 否 | 游戏关卡,不传则返回所有关卡的排行榜 | +| topLimit | int | 否 | 排行榜条数限制,默认为10 | +| topType | int | 否 | 排行榜类型:0=积分排行榜(默认),1=时长排行榜 | + +**请求示例**: + +```json +{ + "command": "select-user-info", + "data": { + "cardId": "1234567890", + "gameLevel": "1", + "topLimit": 10, + "topType": 0 + } +} +``` + +**响应参数**: + +| 参数名 | 类型 | 说明 | +|-------|------|------| +| cardId | string | 卡ID | +| cardSn | string | 卡序列号 | +| userName | string | 用户名称 | +| userAvatar | string | 用户头像URL | +| userSex | int | 用户性别:0-未知 1-男 2-女 | +| topType | int | 排行榜类型:0=积分排行榜,1=时长排行榜 | +| leaderboards | object | 按游戏关卡分组的排行榜,key为游戏关卡 | + +**leaderboards对象内部结构**: + +| 参数名 | 类型 | 说明 | +|-------|------|------| +| rank | int | 用户在此排行榜中的排名 | +| score | int | 用户在此排行榜中的积分(当topType=0时有效) | +| duration | int | 用户在此排行榜中的游戏时长(当topType=1时有效) | +| gameLevel | string | 游戏关卡 | +| records | array | 排行榜记录列表 | + +**records数组内部结构**: + +| 参数名 | 类型 | 说明 | +|-------|------|------| +| id | int | 记录ID | +| cardId | string | 卡ID | +| userName | string | 用户名称 | +| score | int | 游戏得分 | +| gameDuration | int | 游戏时长(秒) | +| playTime | string | 游戏时间(格式化字符串) | +| gameLevel | string | 游戏关卡 | +| gameType | string | 游戏类型 | +| skinId | string | 皮肤ID | +| playerCount | int | 共同游戏的玩家数量 | + +**响应示例**: + +```json +{ + "result": true, + "errMsg": "", + "statusCode": 0, + "command": "select-user-info", + "data": { + "cardId": "1234567890", + "cardSn": "A1B2C3D4", + "userName": "玩家001", + "userAvatar": "http://example.com/avatar/001.jpg", + "userSex": 1, + "topType": 0, + "leaderboards": { + "1": { + "rank": 3, + "score": 1500, + "gameLevel": "1", + "records": [ + { + "id": 123, + "cardId": "9876543210", + "userName": "玩家088", + "score": 2000, + "gameDuration": 300, + "playTime": "2025-05-28 14:30:00", + "gameLevel": "1", + "gameType": "standard", + "skinId": "skin_001", + "playerCount": 1 + }, + { + "id": 124, + "cardId": "8765432109", + "userName": "玩家072", + "score": 1800, + "gameDuration": 280, + "playTime": "2025-05-28 15:20:00", + "gameLevel": "1", + "gameType": "standard", + "skinId": "skin_002", + "playerCount": 1 + }, + { + "id": 125, + "cardId": "1234567890", + "userName": "玩家001", + "score": 1500, + "gameDuration": 260, + "playTime": "2025-05-28 16:10:00", + "gameLevel": "1", + "gameType": "standard", + "skinId": "skin_003", + "playerCount": 1 + } + ] + } + } + } +} +``` + +**错误码说明**: + +| 状态码 | 说明 | +|-------|------| +| 0 | 成功 | +| 1 | 通用错误 | +| 10 | 参数错误(卡ID和卡序列号都为空) | +| 40 | 用户不存在 | + +**备注**: +1. 卡ID和卡序列号必须至少提供一个,优先使用卡ID查询。 +2. 如果未指定排行榜类型,默认返回积分排行榜。 +3. 如果未指定游戏关卡,将返回所有关卡的排行榜数据。 +4. 排行榜数据按分数或时长降序排列。 + +#### 3.1.2 刷卡登录 (cwyz-swipe-card) + +该接口用于处理游戏中的刷卡操作,关联用户与游戏。 + +**请求命令**:`cwyz-swipe-card` + +**请求参数**: + +| 参数名 | 类型 | 必填 | 说明 | +|-------|------|------|------| +| cardSn | string | 是 | 卡序列号 | +| playerIdx | int | 是 | 玩家索引,用于多人游戏时区分不同玩家位置 | + +**请求示例**: + +```json +{ + "command": "cwyz-swipe-card", + "data": { + "cardSn": "A1B2C3D4", + "playerIdx": 1 + } +} +``` + +**响应参数**: + +| 参数名 | 类型 | 说明 | +|-------|------|------| +| cardId | string | 卡ID | +| cardSn | string | 卡序列号 | +| userName | string | 用户名称 | +| userAvatar | string | 用户头像URL | +| userSex | int | 用户性别:0-未知 1-男 2-女 | +| playerIdx | int | 玩家索引 | + +**响应示例**: + +```json +{ + "result": true, + "errMsg": "", + "statusCode": 0, + "command": "cwyz-swipe-card", + "data": { + "cardId": "1234567890", + "cardSn": "A1B2C3D4", + "userName": "玩家001", + "userAvatar": "http://example.com/avatar/001.jpg", + "userSex": 1, + "playerIdx": 1 + } +} +``` + +**错误码说明**: + +| 状态码 | 说明 | +|-------|------| +| 0 | 成功 | +| 1 | 通用错误 | +| 10 | 参数错误(卡序列号为空) | +| 40 | 用户卡不存在 | +| 30 | 网络错误(与服务器通信失败) | + +**备注**: +1. 刷卡操作会尝试从服务器获取最新的用户信息,如果网络不可用,会使用本地存储的用户信息。 +2. 玩家索引用于区分多人游戏时的不同位置,通常从1开始,对应游戏机的不同位置。 +3. 如果卡片未绑定用户,会返回默认的用户信息。 + +### 3.2 点数卡功能接口 + +#### 3.2.1 查询剩余点数 (get-remaining-points) + +该接口用于查询当前游戏机剩余的点数,用于显示给用户或判断是否有足够点数执行出卡操作。 + +**请求命令**:`get-remaining-points` + +**请求参数**: +无需参数 + +**请求示例**: + +```json +{ + "command": "get-remaining-points", + "data": {} +} +``` + +**响应参数**: + +| 参数名 | 类型 | 说明 | +|-------|------|------| +| remainingPoints | int | 剩余点数 | + +**响应示例**: + +```json +{ + "result": true, + "errMsg": "", + "statusCode": 0, + "command": "get-remaining-points", + "data": { + "remainingPoints": 100 + } +} +``` + +**错误码说明**: + +| 状态码 | 说明 | +|-------|------| +| 0 | 成功 | +| 1 | 通用错误 | +| 20 | 数据库错误(读取点数卡信息失败) | + +**备注**: +1. 此接口会返回所有已绑定点数卡的剩余点数总和。 +2. 如果没有任何点数卡,返回的剩余点数为0。 +3. 点数信息优先从本地数据库获取,确保即使在网络不可用时也能正常工作。 + +#### 3.2.2 绑定点卡 (bind-point-card) + +该接口用于绑定新的点数卡到游戏机上。 + +**请求命令**:`bind-point-card` + +**请求参数**: + +| 参数名 | 类型 | 必填 | 说明 | +|-------|------|------|------| +| cardCode | string | 是 | 点卡卡号 | + +**请求示例**: + +```json +{ + "command": "bind-point-card", + "data": { + "cardCode": "PC12345678" + } +} +``` + +**响应参数**: + +| 参数名 | 类型 | 说明 | +|-------|------|------| +| remainingPoints | int | 绑定后的剩余点数 | + +**响应示例**: + +```json +{ + "result": true, + "errMsg": "", + "statusCode": 0, + "command": "bind-point-card", + "data": { + "remainingPoints": 100 + } +} +``` + +**错误码说明**: + +| 状态码 | 说明 | +|-------|------| +| 0 | 成功 | +| 1 | 通用错误 | +| 10 | 参数错误(卡号为空) | +| 20 | 数据库错误(绑定点数卡失败) | +| 60 | 卡片不存在(点卡号无效) | +| 61 | 点卡已使用 | + +**备注**: +1. 绑定点卡后,点数将自动添加到游戏机的总点数中。 +2. 一个点卡只能被绑定一次,绑定后不能重复使用。 +3. 点卡绑定后立即生效,无需重启游戏机。 + +#### 3.2.3 出卡扣点 (deduct-points) + +该接口用于游戏出卡时扣除相应点数。 + +**请求命令**:`deduct-points` + +**请求参数**: + +| 参数名 | 类型 | 必填 | 说明 | +|-------|------|------|------| +| pointsToDeduct | int | 否 | 需要扣除的点数,默认为1 | +| playerIdx | int | 否 | 机台位置索引,默认为1 | + +**请求示例**: + +```json +{ + "command": "deduct-points", + "data": { + "pointsToDeduct": 1, + "playerIdx": 1 + } +} +``` + +**响应参数**: + +| 参数名 | 类型 | 说明 | +|-------|------|------| +| remainingPoints | int | 扣除后的剩余点数 | +| isUploaded | bool | 是否已上报到服务器 | + +**响应示例**: + +```json +{ + "result": true, + "errMsg": "", + "statusCode": 0, + "command": "deduct-points", + "data": { + "remainingPoints": 99, + "isUploaded": true + } +} +``` + +**错误码说明**: + +| 状态码 | 说明 | +|-------|------| +| 0 | 成功 | +| 1 | 通用错误 | +| 10 | 参数错误(扣点数量无效) | +| 20 | 数据库错误(扣点操作失败) | +| 50 | 点数不足 | + +**备注**: +1. 扣点操作会根据当前配置的扣点模式执行(本地模式、实时模式或混合模式)。 +2. 如果使用本地模式,操作会先在本地执行,然后在适当时机上报到服务器。 +3. 如果使用实时模式,操作会直接上报到服务器,并立即返回结果。 +4. 如果点数不足,将返回错误码50。 +5. 每次扣点操作都会记录在扣点记录表中,用于后续统计和审计。 + +### 3.3 游戏记录功能接口 + +#### 3.3.1 保存游戏积分 (cwyz-score-save) + +该接口用于保存玩家的游戏积分和相关游戏数据,同时可以获取游戏排行榜信息。 + +**请求命令**:`cwyz-score-save` + +**请求参数**: + +| 参数名 | 类型 | 必填 | 说明 | +|-------|------|------|------| +| cardId | string | 是 | 卡ID,用于关联用户 | +| score | int | 是 | 游戏得分 | +| gameLevel | string | 是 | 游戏关卡 | +| gameType | string | 是 | 游戏类型 | +| topLimit | int | 否 | 排行榜总数,默认为10 | +| gameDuration | int | 否 | 游戏时长(秒) | +| golds | int | 否 | 获得金币数量 | +| gemstone | int | 否 | 获得的未鉴定宝石数量 | +| playerIdx | int | 否 | 玩家索引,默认为1 | +| skinId | string | 否 | 皮肤ID | +| playerCount | int | 否 | 共同游戏的玩家数量,默认为1 | + +**请求示例**: + +```json +{ + "command": "cwyz-score-save", + "data": { + "cardId": "1234567890", + "score": 1500, + "gameLevel": "1", + "gameType": "standard", + "topLimit": 10, + "gameDuration": 300, + "golds": 50, + "gemstone": 2, + "playerIdx": 1, + "skinId": "skin_001", + "playerCount": 1 + } +} +``` + +**响应参数**: + +| 参数名 | 类型 | 说明 | +|-------|------|------| +| gameType | string | 游戏类型 | +| leaderboards | object | 按游戏关卡分组的排行榜,key为游戏关卡 | + +**leaderboards对象内部结构**: + +| 参数名 | 类型 | 说明 | +|-------|------|------| +| rank | int | 用户在此排行榜中的排名 | +| score | int | 用户在此排行榜中的积分 | +| gameLevel | string | 游戏关卡 | +| records | array | 排行榜记录列表 | + +**records数组内部结构**: + +| 参数名 | 类型 | 说明 | +|-------|------|------| +| id | int | 记录ID | +| cardId | string | 卡ID | +| userName | string | 用户名称 | +| score | int | 游戏得分 | +| gameDuration | int | 游戏时长(秒) | +| playTime | string | 游戏时间(格式化字符串) | +| gameLevel | string | 游戏关卡 | +| gameType | string | 游戏类型 | +| skinId | string | 皮肤ID | +| playerCount | int | 共同游戏的玩家数量 | + +**响应示例**: + +```json +{ + "result": true, + "errMsg": "", + "statusCode": 0, + "command": "cwyz-score-save", + "data": { + "gameType": "standard", + "leaderboards": { + "1": { + "rank": 3, + "score": 1500, + "gameLevel": "1", + "records": [ + { + "id": 123, + "cardId": "9876543210", + "userName": "玩家088", + "score": 2000, + "gameDuration": 300, + "playTime": "2025-05-28 14:30:00", + "gameLevel": "1", + "gameType": "standard", + "skinId": "skin_001", + "playerCount": 1 + }, + { + "id": 124, + "cardId": "8765432109", + "userName": "玩家072", + "score": 1800, + "gameDuration": 280, + "playTime": "2025-05-28 15:20:00", + "gameLevel": "1", + "gameType": "standard", + "skinId": "skin_002", + "playerCount": 1 + }, + { + "id": 125, + "cardId": "1234567890", + "userName": "玩家001", + "score": 1500, + "gameDuration": 260, + "playTime": "2025-05-28 16:10:00", + "gameLevel": "1", + "gameType": "standard", + "skinId": "skin_003", + "playerCount": 1 + } + ] + } + } + } +} +``` + +**错误码说明**: + +| 状态码 | 说明 | +|-------|------| +| 0 | 成功 | +| 1 | 通用错误 | +| 10 | 参数错误(必填参数缺失) | +| 20 | 数据库错误(保存积分失败) | +| 40 | 用户不存在 | + +**备注**: +1. 如果提供了金币(golds)参数且大于0,系统会自动调用保存金币记录的功能。 +2. 如果提供了宝石(gemstone)参数且大于0,系统会自动调用保存宝石记录的功能。 +3. 积分数据会根据游戏类型和游戏关卡进行分类,便于后续查询。 +4. 响应中的排行榜数据包含当前用户的排名和指定数量的最高分记录。 +5. 如果用户卡ID不存在,系统会尝试创建一个游客记录。 + +#### 3.3.2 获取游戏排行榜 (cwyz-query-score-top) + +该接口用于获取游戏排行榜信息。 + +**请求命令**:`cwyz-query-score-top` + +**请求参数**: + +| 参数名 | 类型 | 必填 | 说明 | +|-------|------|------|------| +| gameType | string | 是 | 游戏类型 | +| gameLevel | string | 否 | 游戏关卡,不传则返回所有关卡的排行榜 | +| topLimit | int | 否 | 需要查询的排行榜条数,默认为10 | +| isGlobal | bool | 否 | 是否获取全网排名,默认为false(即默认获取本地排名) | + +**请求示例**: + +```json +{ + "command": "cwyz-query-score-top", + "data": { + "gameType": "standard", + "gameLevel": "1", + "topLimit": 10, + "isGlobal": false + } +} +``` + +**响应参数**: + +| 参数名 | 类型 | 说明 | +|-------|------|------| +| gameType | string | 游戏类型 | +| leaderboards | object | 按游戏关卡分组的排行榜,key为游戏关卡 | + +**leaderboards对象内部结构**: + +| 参数名 | 类型 | 说明 | +|-------|------|------| +| rank | int | 用户在此排行榜中的排名 | +| score | int | 用户在此排行榜中的积分 | +| gameLevel | string | 游戏关卡 | +| records | array | 排行榜记录列表 | + +**records数组内部结构**: + +| 参数名 | 类型 | 说明 | +|-------|------|------| +| id | int | 记录ID | +| cardId | string | 卡ID | +| userName | string | 用户名称 | +| score | int | 游戏得分 | +| gameDuration | int | 游戏时长(秒) | +| playTime | string | 游戏时间(格式化字符串) | +| gameLevel | string | 游戏关卡 | +| gameType | string | 游戏类型 | +| skinId | string | 皮肤ID | +| playerCount | int | 共同游戏的玩家数量 | + +**响应示例**: + +```json +{ + "result": true, + "errMsg": "", + "statusCode": 0, + "command": "cwyz-query-score-top", + "data": { + "gameType": "standard", + "leaderboards": { + "1": { + "rank": 3, + "score": 1500, + "gameLevel": "1", + "records": [ + { + "id": 123, + "cardId": "9876543210", + "userName": "玩家088", + "score": 2000, + "gameDuration": 300, + "playTime": "2025-05-28 14:30:00", + "gameLevel": "1", + "gameType": "standard", + "skinId": "skin_001", + "playerCount": 1 + }, + { + "id": 124, + "cardId": "8765432109", + "userName": "玩家072", + "score": 1800, + "gameDuration": 280, + "playTime": "2025-05-28 15:20:00", + "gameLevel": "1", + "gameType": "standard", + "skinId": "skin_002", + "playerCount": 1 + }, + { + "id": 125, + "cardId": "1234567890", + "userName": "玩家001", + "score": 1500, + "gameDuration": 260, + "playTime": "2025-05-28 16:10:00", + "gameLevel": "1", + "gameType": "standard", + "skinId": "skin_003", + "playerCount": 1 + } + ] + } + } + } +} +``` + +**错误码说明**: + +| 状态码 | 说明 | +|-------|------| +| 0 | 成功 | +| 1 | 通用错误 | +| 10 | 参数错误(必填参数缺失) | +| 20 | 数据库错误(获取排行榜失败) | +| 40 | 用户不存在 | + +**备注**: +1. 排行榜数据包含当前用户的排名和指定数量的最高分记录。 +2. 如果用户卡ID不存在,系统会尝试创建一个游客记录。 + +#### 3.3.3 获取游戏时长排行榜 (cwyz-query-duration-top) + +该接口用于获取游戏时长排行榜信息。 + +**请求命令**:`cwyz-query-duration-top` + +**请求参数**: + +| 参数名 | 类型 | 必填 | 说明 | +|-------|------|------|------| +| gameType | string | 是 | 游戏类型 | +| gameLevel | string | 否 | 游戏关卡,不传则返回所有关卡的排行榜 | +| topLimit | int | 否 | 需要查询的排行榜条数,默认为10 | +| isGlobal | bool | 否 | 是否获取全网排名,默认为false(即默认获取本地排名) | + +**请求示例**: + +```json +{ + "command": "cwyz-query-duration-top", + "data": { + "gameType": "standard", + "gameLevel": "1", + "topLimit": 10, + "isGlobal": false + } +} +``` + +**响应参数**: + +| 参数名 | 类型 | 说明 | +|-------|------|------| +| gameType | string | 游戏类型 | +| leaderboards | object | 按游戏关卡分组的排行榜,key为游戏关卡 | + +**leaderboards对象内部结构**: + +| 参数名 | 类型 | 说明 | +|-------|------|------| +| rank | int | 用户在此排行榜中的排名 | +| duration | int | 用户在此排行榜中的游戏时长(秒) | +| gameLevel | string | 游戏关卡 | +| records | array | 排行榜记录列表 | + +**records数组内部结构**: + +| 参数名 | 类型 | 说明 | +|-------|------|------| +| id | int | 记录ID | +| cardId | string | 卡ID | +| userName | string | 用户名称 | +| score | int | 游戏得分 | +| gameDuration | int | 游戏时长(秒) | +| playTime | string | 游戏时间(格式化字符串) | +| gameLevel | string | 游戏关卡 | +| gameType | string | 游戏类型 | +| skinId | string | 皮肤ID | +| playerCount | int | 共同游戏的玩家数量 | + +**响应示例**: + +```json +{ + "result": true, + "errMsg": "", + "statusCode": 0, + "command": "cwyz-query-duration-top", + "data": { + "gameType": "standard", + "leaderboards": { + "1": { + "rank": 2, + "duration": 280, + "gameLevel": "1", + "records": [ + { + "id": 123, + "cardId": "9876543210", + "userName": "玩家088", + "score": 1800, + "gameDuration": 320, + "playTime": "2025-05-28 14:30:00", + "gameLevel": "1", + "gameType": "standard", + "skinId": "skin_001", + "playerCount": 1 + }, + { + "id": 124, + "cardId": "1234567890", + "userName": "玩家001", + "score": 1500, + "gameDuration": 280, + "playTime": "2025-05-28 15:20:00", + "gameLevel": "1", + "gameType": "standard", + "skinId": "skin_002", + "playerCount": 1 + }, + { + "id": 125, + "cardId": "8765432109", + "userName": "玩家072", + "score": 1200, + "gameDuration": 240, + "playTime": "2025-05-28 16:10:00", + "gameLevel": "1", + "gameType": "standard", + "skinId": "skin_003", + "playerCount": 1 + } + ] + } + } + } +} +``` + +**错误码说明**: + +| 状态码 | 说明 | +|-------|------| +| 0 | 成功 | +| 1 | 通用错误 | +| 10 | 参数错误(游戏类型为空) | +| 20 | 数据库错误(获取排行榜失败) | + +**备注**: +1. 该接口专门用于获取按游戏时长排序的排行榜。 +2. 排行榜数据按游戏时长降序排列。 +3. 如果设置isGlobal为true,将获取全网的排行榜数据,可能需要更长的响应时间。 + +#### 3.3.4 统一获取游戏排行榜 (cwyz-query-top) + +该接口统一了获取积分排行榜和时长排行榜的功能,通过topType参数区分不同类型的排行榜。 + +**请求命令**:`cwyz-query-top` + +**请求参数**: + +| 参数名 | 类型 | 必填 | 说明 | +|-------|------|------|------| +| gameType | string | 是 | 游戏类型 | +| gameLevel | string | 否 | 游戏关卡,不传则返回所有关卡的排行榜 | +| topLimit | int | 否 | 需要查询的排行榜条数,默认为10 | +| topType | int | 是 | 排行榜类型:0=积分排行榜,1=时长排行榜 | +| isGlobal | bool | 否 | 是否获取全网排名,默认为false(即默认获取本地排名) | + +**请求示例**: + +```json +{ + "command": "cwyz-query-top", + "data": { + "gameType": "standard", + "gameLevel": "1", + "topLimit": 10, + "topType": 0, + "isGlobal": false + } +} +``` + +**响应参数**: + +| 参数名 | 类型 | 说明 | +|-------|------|------| +| gameType | string | 游戏类型 | +| topType | int | 排行榜类型:0=积分排行榜,1=时长排行榜 | +| leaderboards | object | 按游戏关卡分组的排行榜,key为游戏关卡 | + +**leaderboards对象内部结构**: + +| 参数名 | 类型 | 说明 | +|-------|------|------| +| rank | int | 用户在此排行榜中的排名 | +| score | int | 用户在此排行榜中的积分(当topType=0时有效) | +| duration | int | 用户在此排行榜中的游戏时长(当topType=1时有效) | +| gameLevel | string | 游戏关卡 | +| records | array | 排行榜记录列表 | + +**records数组内部结构**: + +| 参数名 | 类型 | 说明 | +|-------|------|------| +| id | int | 记录ID | +| cardId | string | 卡ID | +| userName | string | 用户名称 | +| score | int | 游戏得分 | +| gameDuration | int | 游戏时长(秒) | +| playTime | string | 游戏时间(格式化字符串) | +| gameLevel | string | 游戏关卡 | +| gameType | string | 游戏类型 | +| skinId | string | 皮肤ID | +| playerCount | int | 共同游戏的玩家数量 | + +**响应示例(积分排行榜)**: + +```json +{ + "result": true, + "errMsg": "", + "statusCode": 0, + "command": "cwyz-query-top", + "data": { + "gameType": "standard", + "topType": 0, + "leaderboards": { + "1": { + "rank": 3, + "score": 1500, + "gameLevel": "1", + "records": [ + { + "id": 123, + "cardId": "9876543210", + "userName": "玩家088", + "score": 2000, + "gameDuration": 300, + "playTime": "2025-05-28 14:30:00", + "gameLevel": "1", + "gameType": "standard", + "skinId": "skin_001", + "playerCount": 1 + }, + { + "id": 124, + "cardId": "8765432109", + "userName": "玩家072", + "score": 1800, + "gameDuration": 280, + "playTime": "2025-05-28 15:20:00", + "gameLevel": "1", + "gameType": "standard", + "skinId": "skin_002", + "playerCount": 1 + }, + { + "id": 125, + "cardId": "1234567890", + "userName": "玩家001", + "score": 1500, + "gameDuration": 260, + "playTime": "2025-05-28 16:10:00", + "gameLevel": "1", + "gameType": "standard", + "skinId": "skin_003", + "playerCount": 1 + } + ] + } + } + } +} +``` + +**错误码说明**: + +| 状态码 | 说明 | +|-------|------| +| 0 | 成功 | +| 1 | 通用错误 | +| 10 | 参数错误(游戏类型为空或排行榜类型无效) | +| 20 | 数据库错误(获取排行榜失败) | + +**备注**: +1. 该接口可以根据topType参数灵活获取不同类型的排行榜。 +2. 当topType=0时,排行榜按积分降序排列;当topType=1时,排行榜按游戏时长降序排列。 +3. 如果设置isGlobal为true,将获取全网的排行榜数据,可能需要更长的响应时间。 +4. 推荐使用该接口代替单独的积分排行榜和时长排行榜接口,提高代码复用性。 + +#### 3.3.5 保存出卡记录 (cwyz-outcard-save) + +该接口用于记录游戏中玩家获得卡片的信息。 + +**请求命令**:`cwyz-outcard-save` + +**请求参数**: + +| 参数名 | 类型 | 必填 | 说明 | +|-------|------|------|------| +| cardId | string | 是 | 卡ID,用于关联用户 | +| cardStar | int | 是 | 卡片星级 | +| cardType | string | 是 | 卡片类型 | +| cardName | string | 是 | 卡片名称 | +| gameType | string | 是 | 游戏类型 | +| playerIdx | int | 否 | 玩家索引,默认为1 | + +**请求示例**: + +```json +{ + "command": "cwyz-outcard-save", + "data": { + "cardId": "1234567890", + "cardStar": 4, + "cardType": "monster", + "cardName": "火焰龙", + "gameType": "standard", + "playerIdx": 1 + } +} +``` + +**响应参数**: + +| 参数名 | 类型 | 说明 | +|-------|------|------| +| success | bool | 操作是否成功 | +| cardId | string | 卡ID | +| userName | string | 用户名称 | +| cardStar | int | 卡片星级 | +| cardType | string | 卡片类型 | +| cardName | string | 卡片名称 | +| drawTime | string | 出卡时间(格式化字符串) | +| playerIdx | int | 玩家索引 | + +**响应示例**: + +```json +{ + "result": true, + "errMsg": "", + "statusCode": 0, + "command": "cwyz-outcard-save", + "data": { + "success": true, + "cardId": "1234567890", + "userName": "玩家001", + "cardStar": 4, + "cardType": "monster", + "cardName": "火焰龙", + "drawTime": "2025-05-28 16:30:45", + "playerIdx": 1 + } +} +``` + +**错误码说明**: + +| 状态码 | 说明 | +|-------|------| +| 0 | 成功 | +| 1 | 通用错误 | +| 10 | 参数错误(必填参数缺失) | +| 20 | 数据库错误(保存出卡记录失败) | +| 40 | 用户不存在 | + +**备注**: +1. 出卡记录会保存在本地数据库中,并在网络可用时上传到服务器。 +2. 出卡时间使用服务器时间,确保统一性。 +3. 卡片星级通常为1-5,表示卡片的稀有程度。 +4. 卡片类型可以是游戏定义的任何类型,如"monster"、"magic"、"trap"等。 + +#### 3.3.6 保存硬币记账 (cwyz-coin-save) + +该接口用于记录玩家投币和消耗硬币的信息。 + +**请求命令**:`cwyz-coin-save` + +**请求参数**: + +| 参数名 | 类型 | 必填 | 说明 | +|-------|------|------|------| +| cardId | string | 是 | 卡ID,用于关联用户 | +| coinCount | int | 是 | 硬币数量 | +| type | int | 是 | 类型:1=投币,2=消耗 | +| playerIdx | int | 否 | 玩家索引,默认为1 | + +**请求示例**: + +```json +{ + "command": "cwyz-coin-save", + "data": { + "cardId": "1234567890", + "coinCount": 5, + "type": 1, + "playerIdx": 1 + } +} +``` + +**响应参数**: + +| 参数名 | 类型 | 说明 | +|-------|------|------| +| success | bool | 操作是否成功 | +| cardId | string | 卡ID | +| userName | string | 用户名称 | +| coinCount | int | 硬币数量 | +| type | int | 操作类型:1=投币,2=消耗 | +| balance | int | 当前余额 | +| processTime | string | 处理时间(格式化字符串) | +| playerIdx | int | 玩家索引 | + +**响应示例**: + +```json +{ + "result": true, + "errMsg": "", + "statusCode": 0, + "command": "cwyz-coin-save", + "data": { + "success": true, + "cardId": "1234567890", + "userName": "玩家001", + "coinCount": 5, + "type": 1, + "balance": 15, + "processTime": "2025-05-28 17:15:30", + "playerIdx": 1 + } +} +``` + +**错误码说明**: + +| 状态码 | 说明 | +|-------|------| +| 0 | 成功 | +| 1 | 通用错误 | +| 10 | 参数错误(必填参数缺失或硬币数量为0) | +| 20 | 数据库错误(保存硬币记录失败) | +| 40 | 用户不存在 | +| 50 | 余额不足(当type=2,消耗硬币时) | + +**备注**: +1. 硬币记账会记录玩家的投币和消耗情况,便于统计和分析。 +2. 类型为1表示投币(增加余额),类型为2表示消耗(减少余额)。 +3. 响应中的balance字段表示操作后的硬币余额。 +4. 如果是消耗操作且余额不足,将返回错误码50。 +5. 所有操作都会记录在硬币记账表中,用于后续统计和审计。 + +### 3.4 4G网络控制接口 + +#### 3.4.1 查询4G模块信息 (query-4g-info) + +该接口用于查询4G网络模块的详细信息,包括网络状态、信号强度、SIM卡信息等。 + +**请求命令**:`query-4g-info` + +**请求参数**: +无需参数 + +**请求示例**: + +```json +{ + "command": "query-4g-info", + "data": {} +} +``` + +**响应参数**: + +| 参数名 | 类型 | 说明 | +|-------|------|------| +| mnc | string | 网络MNC码 | +| cid | string | 基站CID | +| lac | string | 位置区域码 | +| serialPort | string | 串口名称 | +| dbm | int | 信号强度 | +| revision | string | 模块固件版本 | +| sim | string | SIM卡ICCID | +| imsi | string | SIM卡IMSI | +| imei | string | 设备IMEI | +| ndisEnabled | bool | NDIS网卡状态 | + +**响应示例**: + +```json +{ + "result": true, + "errMsg": "", + "statusCode": 0, + "command": "query-4g-info", + "data": { + "mnc": "01", + "cid": "123456", + "lac": "7890", + "serialPort": "COM3", + "dbm": -65, + "revision": "EG25GGBR07A08M2G", + "sim": "898600123456789012345", + "imsi": "460012345678901", + "imei": "862512345678901", + "ndisEnabled": true + } +} +``` + +**错误码说明**: + +| 状态码 | 说明 | +|-------|------| +| 0 | 成功 | +| 1 | 通用错误 | +| 80 | 4G模块不存在 | +| 81 | 4G模块通信错误 | + +**备注**: +1. 信号强度(dbm)通常在-50到-120之间,数值越大(越接近0)表示信号越强。 +2. ndisEnabled表示4G网卡是否启用,true表示已启用,false表示已禁用。 +3. 如果设备没有4G模块,将返回错误码80。 +4. 该接口仅查询信息,不会改变任何网络设置。 + +#### 3.4.2 禁用4G网络 (stop-4g-net) + +该接口用于禁用4G网络,可用于节省流量或解决网络冲突问题。 + +**请求命令**:`stop-4g-net` + +**请求参数**: +无需参数 + +**请求示例**: + +```json +{ + "command": "stop-4g-net", + "data": {} +} +``` + +**响应参数**: + +| 参数名 | 类型 | 说明 | +|-------|------|------| +| success | bool | 操作是否成功 | + +**响应示例**: + +```json +{ + "result": true, + "errMsg": "", + "statusCode": 0, + "command": "stop-4g-net", + "data": { + "success": true + } +} +``` + +**错误码说明**: + +| 状态码 | 说明 | +|-------|------| +| 0 | 成功 | +| 1 | 通用错误 | +| 80 | 4G模块不存在 | +| 81 | 4G模块通信错误 | +| 82 | 网络已经处于禁用状态 | + +**备注**: +1. 该接口会关闭4G网卡,停止所有网络通信。 +2. 操作成功后,设备将无法通过4G网络连接互联网,但可以通过其他网络接口(如WiFi、有线网络)连接。 +3. 4G网络禁用后,可通过start-4g-net接口重新启用。 +4. 如果设备没有4G模块,将返回错误码80。 + +#### 3.4.3 启用4G网络 (start-4g-net) + +该接口用于启用4G网络,恢复设备的移动网络连接。 + +**请求命令**:`start-4g-net` + +**请求参数**: +无需参数 + +**请求示例**: + +```json +{ + "command": "start-4g-net", + "data": {} +} +``` + +**响应参数**: + +| 参数名 | 类型 | 说明 | +|-------|------|------| +| success | bool | 操作是否成功 | + +**响应示例**: + +```json +{ + "result": true, + "errMsg": "", + "statusCode": 0, + "command": "start-4g-net", + "data": { + "success": true + } +} +``` + +**错误码说明**: + +| 状态码 | 说明 | +|-------|------| +| 0 | 成功 | +| 1 | 通用错误 | +| 80 | 4G模块不存在 | +| 81 | 4G模块通信错误 | +| 83 | 网络已经处于启用状态 | +| 84 | SIM卡异常 | + +**备注**: +1. 该接口会启用4G网卡,恢复移动网络连接。 +2. 操作成功后,设备将能够通过4G网络连接互联网。 +3. 网络连接过程可能需要几秒到几十秒不等,取决于网络信号强度和运营商网络状况。 +4. 如果设备没有4G模块或SIM卡异常,将返回相应的错误码。 + +### 3.5 世宇接口状态 + +#### 3.5.1 检查世宇接口状态 (check-unis-net-state) + +该接口用于检查与世宇服务器的连接状态。 + +**请求命令**:`check-unis-net-state` + +**请求参数**: +无需参数 + +**请求示例**: + +```json +{ + "command": "check-unis-net-state", + "data": {} +} +``` + +**响应参数**: + +| 参数名 | 类型 | 说明 | +|-------|------|------| +| state | int | 世宇网络连接状态: 0-断开连接 1-有线网络 2-4G网络 3-服务异常 4-系统异常 | + +**响应示例**: + +```json +{ + "result": true, + "errMsg": "", + "statusCode": 0, + "command": "check-unis-net-state", + "data": { + "state": 1 + } +} +``` + +**错误码说明**: + +| 状态码 | 说明 | +|-------|------| +| 0 | 成功 | +| 1 | 通用错误 | + +**网络状态代码说明**: + +| 网络状态码 | 描述 | 说明 | +|-----------|------|------| +| 0 | 网络断开 | 无网络连接 | +| 1 | 有线网络 | 有线网络连接正常且能访问世宇服务器 | +| 2 | 4G网络 | 4G网络连接正常且能访问世宇服务器 | +| 3 | 服务异常 | 网络连接正常但无法登录世宇服务器 | +| 4 | 系统异常 | 网络连接正常但无法获取登录凭证 | + +**备注**: +1. 该接口用于检查业务插件与世宇服务器的连接状态。 +2. 检查过程包括网络连接检测和世宇服务器登录尝试。 +3. 有线网络和4G网络状态表示网络连接正常且可成功登录世宇服务器。 +4. 服务异常表示网络连接正常但无法登录世宇服务器,可能是服务器问题。 +5. 系统异常表示网络连接正常但无法获取登录凭证,可能是配置问题。 + +#### 3.5.2 获取系统信息 (get-system-info) + +该接口用于获取系统综合信息,包括网络状态、版本信息、磁盘信息和剩余点数。 + +**请求命令**:`get-system-info` + +**请求参数**: +无需参数 + +**请求示例**: + +```json +{ + "command": "get-system-info", + "data": {} +} +``` + +**响应参数**: + +| 参数名 | 类型 | 说明 | +|-------|------|------| +| networkState | int | 网络状态代码: 0-断开连接 1-有线网络 2-4G网络 3-服务异常 4-系统异常 | +| networkStateDesc | string | 网络状态描述文本 | +| versionInfo | object | 版本信息对象 | +| diskInfos | array | 磁盘信息数组 | +| remainingPoints | int | 剩余点数 | + +**versionInfo对象内部结构**: + +| 参数名 | 类型 | 说明 | +|-------|------|------| +| gameVersion | string | 游戏版本 | +| updaterVersion | string | 更新器版本 | +| businessVersion | string | 业务模块版本 | +| consoleVersion | string | 控制台版本 | +| deviceId | string | 设备ID | + +**diskInfos数组内部结构**: + +| 参数名 | 类型 | 说明 | +|-------|------|------| +| driveLetter | string | 盘符 | +| freeSpace | string | 可用空间(格式化后的字符串) | +| totalSpace | string | 总空间(格式化后的字符串) | +| usedSpace | string | 已用空间(格式化后的字符串) | +| freePercent | float | 可用空间百分比 | + +**响应示例**: + +```json +{ + "result": true, + "errMsg": "", + "statusCode": 0, + "command": "get-system-info", + "data": { + "networkState": 1, + "networkStateDesc": "有线网络", + "versionInfo": { + "gameVersion": "1.0.5", + "updaterVersion": "1.2.0", + "businessVersion": "1.1.0", + "consoleVersion": "1.0.8", + "deviceId": "ABCDEF123456" + }, + "diskInfos": [ + { + "driveLetter": "C:", + "freeSpace": "50.5 GB", + "totalSpace": "100 GB", + "usedSpace": "49.5 GB", + "freePercent": 50.5 + }, + { + "driveLetter": "D:", + "freeSpace": "120 GB", + "totalSpace": "500 GB", + "usedSpace": "380 GB", + "freePercent": 24.0 + } + ], + "remainingPoints": 100 + } +} +``` + +**错误码说明**: + +| 状态码 | 说明 | +|-------|------| +| 0 | 成功 | +| 1 | 通用错误 | + +**备注**: +1. 该接口汇总了系统的多项信息,便于快速了解系统状态。 +2. 网络状态检测逻辑与check-unis-net-state接口保持一致。 +3. 版本信息通过向更新器发送get-version-info指令获取。 +4. 磁盘信息按盘符字母顺序排列。 +5. 剩余点数与get-remaining-points接口返回的值一致。 From 6f01ab3054412783f24aace1dc88a151bb1a7610 Mon Sep 17 00:00:00 2001 From: zzz <1638644816@qq.com> Date: Mon, 16 Jun 2025 18:36:04 +0800 Subject: [PATCH 2/2] 1 --- .obsidian/app.json | 3 +- .obsidian/workspace.json | 91 +- 1Project/宠物宇宙/地图编辑器/需要做的优化.md | 1 - .../宠物宇宙/地图编辑器/需要支持的地图功能.md | 4 +- 1Project/宠物宇宙/版本需求.md | 10 +- 1Project/开发文章/将开发文章阅读并分类.md | 4 +- .../如何实现一个强大的MMO技能系统——BUFF.md | 153 ++ 3Projects/UE/UE-CORE-002 TickTaskManager.md | 1949 +++++++++++++++++ 3Projects/Unity/Log插件/Log插件.md | 153 ++ .../Unity/loxodon/loxodon-framework Public.md | 17 + InBox/自动化生成文档/docfx.md | 0 InBox/自动化生成文档/uml.md | 1 - 12 files changed, 2339 insertions(+), 47 deletions(-) create mode 100644 1Project/战斗编辑器/参考文章/如何实现一个强大的MMO技能系统——BUFF.md create mode 100644 3Projects/UE/UE-CORE-002 TickTaskManager.md create mode 100644 3Projects/Unity/Log插件/Log插件.md delete mode 100644 InBox/自动化生成文档/docfx.md delete mode 100644 InBox/自动化生成文档/uml.md diff --git a/.obsidian/app.json b/.obsidian/app.json index a00803f..131a11e 100644 --- a/.obsidian/app.json +++ b/.obsidian/app.json @@ -1,5 +1,6 @@ { "promptDelete": false, "attachmentFolderPath": "渲染/软渲染/图片", - "alwaysUpdateLinks": true + "alwaysUpdateLinks": true, + "showLineNumber": false } \ No newline at end of file diff --git a/.obsidian/workspace.json b/.obsidian/workspace.json index 85cea2f..d5d0d03 100644 --- a/.obsidian/workspace.json +++ b/.obsidian/workspace.json @@ -4,11 +4,25 @@ "type": "split", "children": [ { - "id": "f8022c29023d2af6", + "id": "1890c7ad64a39d65", "type": "tabs", "children": [ { - "id": "efa82152d99167ff", + "id": "3e6f0931816b44e6", + "type": "leaf", + "state": { + "type": "markdown", + "state": { + "file": "1Project/开发文章/将开发文章阅读并分类.md", + "mode": "source", + "source": false + }, + "icon": "lucide-file", + "title": "将开发文章阅读并分类" + } + }, + { + "id": "e0316e2f70484fe5", "type": "leaf", "state": { "type": "markdown", @@ -21,7 +35,8 @@ "title": "需要做的优化" } } - ] + ], + "currentTab": 1 } ], "direction": "vertical" @@ -214,48 +229,50 @@ "copilot:Open Copilot Chat": false } }, - "active": "3e6f0931816b44e6", + "active": "e0316e2f70484fe5", "lastOpenFiles": [ - "1Project/宠物宇宙/地图编辑器/需要支持的小功能.md", + "1Project/宠物宇宙/地图编辑器/地图工作流.canvas", "1Project/宠物宇宙/地图编辑器/需要做的优化.md", - "1Project/宠物宇宙/皮肤导入.md", + "1Project/宠物宇宙/地图编辑器/需要支持的地图功能.md", + "1Project/宠物宇宙/版本需求.md", + "1Project/开发文章/将开发文章阅读并分类.md", + "1Project/战斗编辑器/参考文章/如何实现一个强大的MMO技能系统——BUFF.md", + "1Project/战斗编辑器/参考文章", + "1Project/战斗编辑器", + "3Projects/UE/UE-CORE-002 TickTaskManager.md", + "3Projects/Unity/Log插件/Log插件.md", + "3Projects/UE", + "3Projects/Unity/loxodon/loxodon-framework Public.md", + "3Projects/Unity/Log插件", + "1Project/宠物宇宙/硬件交互/用户卡及游戏信息处理过程设计文档.md", + "1Project/宠物宇宙/硬件交互/业务插件(RTwoGameBusiness)TCP接口设计说明.md", "2Areas/哲学/目的论与原因论.md", "2Areas/哲学/他者贡献.md", - "2Areas/健康/运动-拉伸/八段锦/八段锦.md", "2Areas/哲学", - "2Areas/习惯养成/规范日常行为.md", - "2Areas/如何记录笔记/笔记如何组织.md", - "2Areas/如何记录笔记/段落标记.md", - "2Areas/如何记录笔记/抓捕生活中的灵感.md", - "2Areas/如何记录笔记/如何结束一个项目.md", - "2Areas/如何记录笔记/如何开启一个项目.md", - "2Areas/如何记录笔记/抓捕生活中的灵感.md", - "2Areas/习惯养成", - "2Areas/如何记录笔记", + "InBox/loxodon-framework.md", + "3Projects/Unity/loxodon", + "3Projects/Unity", + "3Projects", + "InBox/网络同步.md", + "InBox/obsidian右键扩展.md", + "InBox/接口与抽象类区别.md", + "InBox/【Unity插件 - 图标轮廓渲染插件 SDF Image - Quality UI Outlines and Shadow-哔哩哔哩】.md", + "InBox/资源/资源导入.md", "InBox/编辑器/时间轴编辑器/Timeline TODO.canvas", - "1Project/开发文章/将开发文章阅读并分类.md", - "4Archives/宠物宇宙/用户卡及游戏信息处理过程设计文档.md", - "2Areas/健康/运动-拉伸/八段锦", - "4Archives/All in hole/查看UIGame代码.md", - "4Archives/All in hole/还原材质球.md", - "4Archives/All in hole/玩法.md", + "InBox/编辑器/图片/Pasted image 20221025121100.png", + "InBox/GAS", "1Project/宠物宇宙/bug.md", - "4Archives/All in hole/编辑器.md", + "1Project/宠物宇宙/未命名 1", + "渲染/软渲染/图片/业务插件(RTwoGameBusiness)TCP接口设计说明.md", + "InBox/网络/封装可扩展网络请求框架.md", + "2Areas/提升效率/未命名.md", + "渲染/软渲染/图片/img_v3_02n6_ff40a1a4-d813-45f7-b132-6f14a74cfd7g.jpg", + "InBox/自动化生成文档/uml.md", + "InBox/自动化生成文档/docfx.md", + "InBox/战斗/输入框架/游戏输入框架的设计(基于Unity).md", + "InBox/TODO.canvas", "渲染/软渲染/图片/Pasted image 20250609171235.png", - "InBox/AI for Obsidian/20250315 - 测试 Obsidian+ AI 的能力边界/第五个用法|成为插件助手/Dataview 插件/测试用文档/项目复盘会议.md", - "InBox/AI for Obsidian/20250315 - 测试 Obsidian+ AI 的能力边界/第五个用法|成为插件助手/Dataview 插件/测试用文档/项目A计划.md", - "InBox/AI for Obsidian/20250315 - 测试 Obsidian+ AI 的能力边界/第五个用法|成为插件助手/Dataview 插件/测试用文档/财务季度报告.md", - "InBox/AI for Obsidian/20250315 - 测试 Obsidian+ AI 的能力边界/第五个用法|成为插件助手/Dataview 插件/测试用文档/简易待办事项.md", - "InBox/AI for Obsidian/20250315 - 测试 Obsidian+ AI 的能力边界/第五个用法|成为插件助手/Dataview 插件/测试用文档/用户反馈分析.md", - "InBox/AI for Obsidian/20250315 - 测试 Obsidian+ AI 的能力边界/第五个用法|成为插件助手/Dataview 插件/测试用文档/每周例会记录.md", - "InBox/AI for Obsidian/20250315 - 测试 Obsidian+ AI 的能力边界/第五个用法|成为插件助手/Dataview 插件/测试用文档/技术架构设计.md", - "InBox/AI for Obsidian/20250315 - 测试 Obsidian+ AI 的能力边界/第五个用法|成为插件助手/Dataview 插件/测试用文档", - "InBox/AI for Obsidian/20250315 - 测试 Obsidian+ AI 的能力边界/第四个用法|成为对弈的棋手/正方观点/观点9.md.edtz", - "InBox/AI for Obsidian/20250315 - 测试 Obsidian+ AI 的能力边界/第四个用法|成为对弈的棋手/正方观点/观点8.md.edtz", - "InBox/AI for Obsidian/20250315 - 测试 Obsidian+ AI 的能力边界/第四个用法|成为对弈的棋手/正方观点/观点7.md.edtz", - "InBox/AI for Obsidian/20250315 - 测试 Obsidian+ AI 的能力边界/第四个用法|成为对弈的棋手/正方观点/观点6.md.edtz", - "InBox/AI for Obsidian/20250315 - 测试 Obsidian+ AI 的能力边界/第四个用法|成为对弈的棋手/正方观点/观点5.md.edtz", - "InBox/渲染/软渲染/图片/Pasted image 20230613102109.png", + "InBox/战斗/动作时间轴 随想.canvas", "InBox/渲染/GPU/Pasted image 20230413163234.png", "InBox/Mesh/图片/Pasted image 20221021171104.png", "InBox/渲染/软渲染/图片/Pasted image 20230613102109.png", diff --git a/1Project/宠物宇宙/地图编辑器/需要做的优化.md b/1Project/宠物宇宙/地图编辑器/需要做的优化.md index 3ec555d..8cd3cad 100644 --- a/1Project/宠物宇宙/地图编辑器/需要做的优化.md +++ b/1Project/宠物宇宙/地图编辑器/需要做的优化.md @@ -47,4 +47,3 @@ 二者相互引用且耦合 ###### 先抽象工作流,在开始构建管道 - diff --git a/1Project/宠物宇宙/地图编辑器/需要支持的地图功能.md b/1Project/宠物宇宙/地图编辑器/需要支持的地图功能.md index 4e490bf..175c435 100644 --- a/1Project/宠物宇宙/地图编辑器/需要支持的地图功能.md +++ b/1Project/宠物宇宙/地图编辑器/需要支持的地图功能.md @@ -10,8 +10,8 @@ - ![[img_v3_02n6_ff40a1a4-d813-45f7-b132-6f14a74cfd7g.jpg]] - [x] 松鼠异常 - - [ ] 地图地板图片导入 自动修改图片大小 - - [ ] 添加白膜地图 + - [x] 地图地板图片导入 自动修改图片大小 + - [x] 添加白膜地图 - 创建100 - 100的地图,宽高跟随Rect大小变化 - [x] 碰撞盒需要添加旋转 diff --git a/1Project/宠物宇宙/版本需求.md b/1Project/宠物宇宙/版本需求.md index 64e45fd..18f5af0 100644 --- a/1Project/宠物宇宙/版本需求.md +++ b/1Project/宠物宇宙/版本需求.md @@ -13,11 +13,13 @@ - [x] C:\Users\1\Desktop\cache\第三弹裁切输出 - UI名字 - [x] C:\Users\1\Desktop\cache\皮肤 -- [ ] 枪械宠物UI导入 +- [x] 枪械宠物UI导入 - [ ] 测试网络点数 开机检测 -- [ ] 地图编辑器 [[需要支持的地图功能]] - - [ ] Boss立绘 - - [ ] C:\Users\1\Desktop\cache\雷鸟血条UI +- [x] 地图编辑器 [[需要支持的地图功能]] + - [x] Boss立绘 + - [x] C:\Users\1\Desktop\cache\雷鸟血条UI +- [ ] 积分系统 + - [ ] --- diff --git a/1Project/开发文章/将开发文章阅读并分类.md b/1Project/开发文章/将开发文章阅读并分类.md index 5ef1b1a..5fa1f55 100644 --- a/1Project/开发文章/将开发文章阅读并分类.md +++ b/1Project/开发文章/将开发文章阅读并分类.md @@ -3,4 +3,6 @@ - [ ] [焦虑、内耗、爱破防,真的是你的锅吗?硬核心理学让你从此掌控自我!-我要等到什么时候-稍后再看-哔哩哔哩视频](https://www.bilibili.com/list/watchlater?oid=114079968532107&bvid=BV1YM9gYdECb&spm_id_from=333.1007.top_right_bar_window_view_later.content.click) - [ ] [动作游戏框架05.扩展Timeline:使用组合,而非继承,来扩展Timeline的基础功能-我要等到什么时候-稍后再看-哔哩哔哩视频](https://www.bilibili.com/list/watchlater?oid=114522652147889&bvid=BV1HKJAzyEZ5&spm_id_from=333.1007.top_right_bar_window_view_later.content.click) -- [ ] https://zhuanlan.zhihu.com/p/28352150798# Unity-SM节点式动画技能编辑器 \ No newline at end of file +- [ ] https://zhuanlan.zhihu.com/p/28352150798# Unity-SM节点式动画技能编辑器 +- [ ] [[Log插件]] +- [ ] [[UE-CORE-002 TickTaskManager]] \ No newline at end of file diff --git a/1Project/战斗编辑器/参考文章/如何实现一个强大的MMO技能系统——BUFF.md b/1Project/战斗编辑器/参考文章/如何实现一个强大的MMO技能系统——BUFF.md new file mode 100644 index 0000000..4a07b96 --- /dev/null +++ b/1Project/战斗编辑器/参考文章/如何实现一个强大的MMO技能系统——BUFF.md @@ -0,0 +1,153 @@ +--- +tags: + - Buff +--- + +source:[(2 封私信 / 4 条消息) 如何实现一个强大的MMO技能系统——BUFF - 知乎](https://zhuanlan.zhihu.com/p/150812545?utm_psn=1894773352150832417) + +--- + +## 前言 + +Buff模块可以说是技能中最核心又最复杂的系统了。一个优秀的[Buff系统](https://zhida.zhihu.com/search?content_id=121646042&content_type=Article&match_order=1&q=Buff%E7%B3%BB%E7%BB%9F&zhida_source=entity)能够让策划的创意得到最大限度的发挥,大幅增强游戏的战斗深度和可玩性,并且同时也能让开发者轻易的扩展维护,支持更多的效果和功能。本章将为你详细讲述一个强大的Buff系统是如何实现的。(长文预警) + +## 正文 + +### 第一节:Buff定义 + +首先我们将Buff系统分为三个层次,具体继承关系如下: + +![](https://picx.zhimg.com/v2-fbac31f1aed84bb08ba0df09f73b6117_1440w.jpg) + +**Buff:**所有Buff的基类,包含各类成员函数和基本接口。 + +**[Modifier](https://zhida.zhihu.com/search?content_id=121646042&content_type=Article&match_order=1&q=Modifier&zhida_source=entity):**继承于Buff,代表这个Buff是一个修改器,它可以用来修改当前目标的各种属性,状态等等。抽象Modifier这个类的目的是出于性能优化的考虑。因为当Buff修改角色的属性或者状态时,会导致重新计算角色的动态属性, 而在游戏中我们很多的Buff并不需要修改角色的属性状态,仅仅用来提供一段逻辑。那么如果它是一个Buff不是Modifier,就不需要重新计算角色的动态属性。 + +**[MotionModifier](https://zhida.zhihu.com/search?content_id=121646042&content_type=Article&match_order=1&q=MotionModifier&zhida_source=entity):**继承于Modifier,代表此类Buff提供修改玩家运动效果的功能。因为牵涉到与运动组件的交互,所以抽象出一个新的类。 + +Buff类层次结构划分了之后,那么Buff需要包含那些成员数据呢? + +我们提供BuffTypeId(Buff类型Id), **Caster**(Buff施加者),Parent(Buff当前挂载的目标), **Ability**(Buff由哪个技能创建),BuffLayer(层数), BuffLevel(等级)BuffDuration(时长),**BuffTag,BuffImmuneTag(免疫BuffTag)**以及**Context**(Buff创建时的一些相关上下文数据)等等。 + +在这里,我将说明一下Caster,Ability以及Context这三个成员,这也可能是我们Buff系统中一些独特的点。 + +**Caster代表Buff的施加者**,它有可能为空,也有可能不为空,视具体构造时是否传Caster参数而定。但是Buff有一个配置项bNoCaster(是否强制设置Caster为空)。**如果bNoCaster = true。则Buff的Caster一定为空。** + +为什么要有一个bNoCaster设置呢?那是因为**我们的Caster不仅仅是一个成员项,它还关系到Buff合并问题。**如果存在两个TypeId类型相同的Buff时候,当他们的Caster相同才可以走合并流程(Buff层数增加),如果Caster不同,则不能合并。**当策划有一些玩法需求可以多人给BOSS叠Buff时就可以配置Buff的bNoCaster=true,**这样就不需要开发者在写代码添加Buff的时候小心翼翼的设置Caster参数为空了。另外还有几种情况也需要设置bNoCaster=true,比如存在一个熔岩地图,或者冰雪地图,玩家每秒掉多少血量,这个时候也可以配置bNoCaster=true。再比如说一些活动buff,如双倍经验buff,红名惩罚buff,都可以由策划配置bNoCaster=true。类似于双倍经验,还有红名Buff这种**所有需要存盘的Buff,我们都需要设置bNoCaster=true。**也许会有人有疑问,这样能满足需求吗?完全可以,我会在最后的示例部分举出一个例子来解答这个疑问。 + +**Ability代表Buff是由哪个技能创建**,它有可能为空,也有可能不为空,视具体构造时是否传Ability参数而定。通过Ability这个成员类型,我们就将Buff与技能联系起来了,我们能在Buff中取得技能的各种数据,通过获取技能的数据,然后由Buff来实现各种各样的技能效果。 + +**BuffTag,BuffImmuneTag由策划配置(基于标记位),标注这个Buff属于那些种类以及免疫哪些种类。**策划可以定义一些Tag如下: + +1. Metal = 1 << 1 (金系) +2. Wood = 1 << 2(木系) +3. Water = 1 << 3(水系) +4. Fire = 1 << 4(火系) +5. Earth = 1 << 5(土系) + +当策划配置BuffTag为Meta | Wood时,则代表这个Buff归属为金系和木系Buff。如果策划配置BuffImmuneTag为Wood | Fire时,则代表这个Buff可以免疫所有木系和火系Buff。由于Tag的实际定义由策划控制,策划可以根据他们的需求组合出各种各样的免疫效果。我将在后面的示例里面描述一些基于Tag和ImmuneTag用法的例子来让读者体会Tag和ImmuneTag者两个概念抽象的简洁之美。 + +**Context代表Buff创建时候的一些上下文数据**,它是一个不确定的项,通过外部传入各种自定义的数据,然后在Buff逻辑中使用这些自定义数据。 + +### 第二节:Buff执行流程 + +在Buff从创建到销毁的过程中,我们划分为如下几个阶段: + +1. Buff创建前检查当前Buff是否可创建。一般主要是检测目标身上是否存在免疫该Buff的相关Buff,如果被免疫则不会创建该Buff。 +2. Buff在实例化之后,生效之前(还未加入到Buff容器中)时会抛出一个**[OnBuffAwake](https://zhida.zhihu.com/search?content_id=121646042&content_type=Article&match_order=1&q=OnBuffAwake&zhida_source=entity)**事件。如果存在某种Buff的效果是:受到负面效果时,驱散当前所有负面效果,并给自己加一个护盾。那么这个时候就需要监听BuffAwake事件了,此时会给自己加护盾,并且把所有负面Buff驱散。**这意味着一个Buff可能还未生效之前即销毁了(小心Buff的生命周期)。** +3. 当Buff生效时(加入到Buff容器后),我们提供给策划一个抽象接口**[OnBuffStart](https://zhida.zhihu.com/search?content_id=121646042&content_type=Article&match_order=1&q=OnBuffStart&zhida_source=entity)**,由策划配置具体效果。 +4. 当Buff添加时存在相同类型且Caster相等的时候,Buff执行刷新流程(更新Buff层数,等级,持续时间等数据)。我们提供给策划一个抽象接口**[OnBuffRefresh](https://zhida.zhihu.com/search?content_id=121646042&content_type=Article&match_order=1&q=OnBuffRefresh&zhida_source=entity)**,由策划配置具体效果。 +5. 当Buff销毁前(还未从Buff容器中移除),我们提供给策划一个抽象接口**[OnBuffRemove](https://zhida.zhihu.com/search?content_id=121646042&content_type=Article&match_order=1&q=OnBuffRemove&zhida_source=entity)**,由策划配置具体效果。 +6. 当Buff销毁后(已从Buff容器中移除),我们提供给策划一个抽象接口**[OnBuffDestroy](https://zhida.zhihu.com/search?content_id=121646042&content_type=Article&match_order=1&q=OnBuffDestroy&zhida_source=entity)**,由策划配置具体效果。 +7. Buff还可以创建定时器,以触发间隔持续效果。通过策划配置时调用**StartIntervalThink**操作,提供**OnIntervalThink**抽象接口供策划配置具体效果。 +8. Buff还可以通过请求改变运动来触发相关效果。通过策划配置时调用**ApplyMotion**操作,提供**[OnMotionUpdate](https://zhida.zhihu.com/search?content_id=121646042&content_type=Article&match_order=1&q=OnMotionUpdate&zhida_source=entity)**和**[OnMotionInterrupt](https://zhida.zhihu.com/search?content_id=121646042&content_type=Article&match_order=1&q=OnMotionInterrupt&zhida_source=entity)**接口供策划配置具体效果。 + +Buff由于其有着生命周期可控,低耦合(通过监听事件修改逻辑),高内聚、易于扩展的特性,因此通过使用Buff来管理逻辑的话,不仅方便处理各种复杂的行为,同时还能有效的减少开发者的维护难度。 + +例如延迟触发伤害是游戏中非常常见的需求,在一些开发者的设计中就是直接给角色挂个定时器触发伤害。简单的游戏里这样做没什么大问题,但是如果技能逻辑稍微复杂点,这样就会带来很多问题。例如某天策划提出需求,如果受到控制效果时需要取消该延迟伤害。此时你怎么办,直接干掉timer?结果策划过了两天又提出了个新的需求,还是受到控制效果时,需要这个延迟伤害立即触发,你又怎么办?再又比如说,当角色受到伤害超过1000点时,这个延迟伤害立即触发,你又该怎么做? + +这里就体现出Buff的方便之处了,我们可以直接添加一个持续时间为N秒的Buff。Buff销毁时触发伤害。如果需求变更为受到控制时取消伤害,那么我们就在Buff中检查当前是否包含有Tag为Control的Buff。如果有,则设置Buff.bTriggerDamage=false,同时自我销毁。然后在BuffDestroy触发的时候检查是否触发伤害,如果bTriggerDamage为false则不触发伤害。同理,当需求为Buff监听伤害超过1000点伤害立即触发时,我们只需要通过Buff监听OnTakeDamage事件,检查当前受到的伤害值是否大于1000点,如果是则销毁Buff,此时立即触发BuffDestroy并执行伤害效果。 + +从上面的例子我们可以看出整个控制逻辑都是在Buff内部完成的,不需要各种手动开启/取消定时器。只需要Buff扩展下逻辑检查即可,具有非常好的扩展性和高内聚性。 + +### 第三节:Buff修改状态(ModifyState) + +Buff可以通过修改状态去影响角色行为逻辑。以下列举一些最常见的状态: + +1. Stun(眩晕状态——目标不再响应任何操控) +2. Root(缠绕,又称定身——目标不响应移动请求,但是可以执行某些操作,如施放某些技能) +3. Silence (沉默——目标禁止施放技能) +4. Invincible (无敌——几乎不受到所有的伤害和效果影响) +5. Invisible (隐身——不可被其他人看见) + +这些状态是高度凝练的精华,抽象到极致的代表。**非常多的游戏效果实际上都是这几种状态+运动+动画的组合。**这里很多开发者都会有一个**设计误区**就是**把Buff的状态跟运动和动画耦合在一块**,比如:眩晕状态一定就是播个眩晕动画,然后击退状态就是击退位移+击退动画。这样最后导致的问题就是状态膨胀,而且各种逻辑耦合,Bug频出,最后维护成本大大提高。 + +以Stun为例,很多人第一眼看过去就觉得它是个Debuff,是个敌人给我方加的控制Buff。实际上并非如此,Stun可以用到的地方非常多。例如有个技能是野蛮冲撞,释放后2秒内向前移动10米并将敌人推开。那这个Buff的实现就是技能Spell的时候给角色加个Buff,这个Buff会有个Stun状态同时带位移突进效果。挂上这个Buff后,技能施放后角色2秒内就不会响应角色按键移动和释放其他技能的请求了,同时往前突进的效果由Buff控制,将来处理各种位移打断效果也很方便。 再比如说有个技能叫寒冰屏障:你被一道寒冰屏障所笼罩,在十秒内不会受到任何物理和法术伤害,但这期间无法移动、攻击或施法。那这个技能的实现也很简单,就是一个十秒的Buff同时添加了眩晕和无敌这两个状态,如果还需要每秒回血,则StartIntervalThink(interval),然后OnIntervalThink的时候Heal当前角色即可。 + +除了各类战斗效果之外,我们的Buff甚至可以扩展到一些其他场景。比如说打BOSS前有个播过场动画的需求,此时策划希望隐藏Boss和玩家的血条和姓名。那么此时我们完全可以做个Buff,这个Buff扩展个状态HideHpBar,当有这个状态时即隐藏血条和名字就行了。而且我们还可以让这个Buff加上无敌状态,毕竟播过场动画的时候我们不希望玩家或者BOSS真的受到什么伤害。 + +总而言之,Buff状态除了上面提到几种高度凝练抽象的状态外,我们还可以根据具体游戏的需求去扩展各种特殊状态,以满足策划的需求,同时方便开发者管理逻辑。 + +### 第四节:Buff修改属性(ModifyAttribute) + +在游戏中Buff的添加与移除是一个频繁的过程。而玩家的属性来源有很多,如等级,装备,成就,任务,时装等等各种各样的来源。相比于Buff,这些模块修改属性的频率要远低于Buff,所以我们一般将玩家的属性划分为两层,第一层时Core(核心层),第二层是External(外部层)。Core层是玩家各个其他模块的属性总和,而External层则是Buff修改属性的总和。两者相加既为玩家的实时属性。 + +### 第五节:Buff修改运动(ModifyMotion) + +现在的MMO中为了增加动作表现力,经常会有很多位移效果,如突进,翻滚,千斤坠,击退,击飞,拖拽,吸引等等。那么这些效果该如何实现呢?而且有时候会遇到各种复杂的运动打断效果,比如击飞时不能被击退,击飞过程又能被冰冻效果定住,然后又有破冰技能击退冰冻物体并解除冰冻效果。面对这些复杂的情况,我们该如何设计呢? + +在我们的系统中,运动都是统一通过MovementComponent来管理。因此通过使用MotionModifier来与MovementComponent交互。MovementComponent中有一个CustomMotion,用来具体实现各种运动位移。具体运动实现相关细节我们将在后面的运动章节讲述。 + +在MotionModifier中,**我们会提供一个接口ApplyMotion(motionTypeId,priority, forceInterrupt)来向运动组件请求运动效果。**同时通过设置回调UpdateBeforeMovement和UpdateAfterMovement来触发运动前和运动后的Buff效果。下面我们初步介绍下ApplyMotion函数的三个参数: + +- motionTypeId:运动类型id,配置项。包含运动位移参数及相关数据。 +- priority:运动优先级,每个运动都有优先级,低优先级不能打断高优先级。 +- forceInterrrupt:是否忽略优先级,强制打断当前的Motion。 + +通过这三个参数,我们就能实现各类打断需求了。 + +比如说击退的运动优先级是100,击飞的运动优先级是200。那么在击飞过程中,施加击退Buff调用ApplyMotion的时候会返回false,这时可以销毁掉这个击退Buff,即击飞时无法击退。如果击飞时被冰冻,且冻在半空中停止不动,那么我们就需要设计一个静止Buff:运动优先级是300,作用效果是速度设置为0,不受重力影响,同时修改Stun状态并挂载冰冻特效。当破冰技消除冰冻效果时,则设置破冰Buff的位移效果为击退,设置运动优先级为100,forceInterrupt为true。此时ApplyMotion强制打断运动,冰冻Buff会触发OnMotionInterrupt回调,在此接口中冰冻Buff自我销毁即可。 + +**Buff修改运动仅代表修改运动轨迹。**比如说击退仅仅只是以直线移动一段距离。而击飞是以曲线移动一段距离。同理**轻功的翻滚,突刺其实都与击退是相同的运动轨迹。**他们都是在一定的时间内以直线到达目标地点,且都设置Stun状态。它们不一样的地方其实仅仅只是动画层的表现的不同。(可能策划还会设置不同的Tag和ImmuneTag标记下) + +**我们要牢牢记住,玩家看起来各种花哨的轻功击退击飞等位移效果实际上是State+Motion+Animation的组合。**掌握住了这一点,我们就可以通过简单的组合实现各种丰富的效果了,而不会被各种花哨的效果所迷惑,以为他们都是不一样的效果,导致最后设计出无比庞杂且难以维护的系统了。 + +### 第六节:Buff监听事件 + +Buff可以通过监听各类事件,执行特定逻辑或者修改事件数据来实现各种效果。 + +最常见的事件监听一般有: + +- **OnAbilityExecuted,监听某个主动技能执行成功。**常用于被动技能Buff,比如说角色施法时有10%概率获得30%的攻速提升。那么我们通常是Buff-A监听OnAbilityExcuted事件,然后10%概率添加Buff-B。Buff-B的作用是修改玩家属性,增加30%攻速。 +- **OnBeforeGiveDamage,OnAfterGiveDamage监听我方给目标造成伤害时触发。**比如说对目标造成的伤害有10%概率无法被闪避,那么这个效果我们就可以通过监听OnBeforeGiveDamage的流程来实现。当执行伤害流程时,在计算伤害前我们抛出一个事件event。event里面有当前伤害数据。Buff在调用OnBeforeGiveDamage(event)时,修改event.Damage.DamageFlag |= DamageFlag_NotMiss,标注该伤害无法被闪避就行了。又或者如果有一个需求是给目标造成伤害后有10%几率触发DOT伤害效果,那么我们在OnAfterGiveDamage的时候取出event.Target并给这个目标加个DOT类Buff即可。 +- **OnBeforeTakeDamage,OnAfterTakeDamage监听我方受到伤害时触发。**如护盾类Buff通常在OnBeforeTakeDamage的时候修改伤害数据。又或者有某些Buff在受到伤害后可以触发各类效果就可以通过监听OnAfterTakeDamage事件来触发指定逻辑。 +- **OnBeforeDead,OnAfterDead监听我方死亡时触发。**如免疫致死效果可以通过监听OnBeforeDead事件修改角色当前的Hp>0,从而让角色提前退出死亡流程以避免死亡。死亡后触发额外效果,如爆炸或者召唤其他生物都可以通过监听OnAfterDead事件来执行。 +- **OnKill事件,监听我方击杀目标时触发。**如当击杀目标后获得治疗效果回复即可通过监听到Kill事件时给自己加一个HOT的Buff来实现。 + +开发者可以通过扩展各类事件列表,让Buff通过监听对应事件就能执行任意逻辑。不需要与任何模块耦合,只需要抛出事件,监听事件,执行逻辑即可获得Buff功能上的扩展。 + +## 总结 + +以上我们通过六个小节讲述了Buff系统主要模块的实现方法。通过这样的设计,我们让Buff的深度和扩展性都能够得到了极大的提升,几乎能实现各种各样的效果。足以让策划的创意得到最大限度的发挥。 + +## 示例 + +为了让读者便于直观理解,我会提出一些具体实现的例子以供参考: + +- 问:Buff互斥效果也很常见,怎么做? +- 答:BuffTag和BuffImmuneTag可轻松实现。比如说火系Buff和水系Buff互斥。无论策划的需求是存在水系Buff的时候无法添加火系Buff,还是存在水系Buff的时候添加火系Buff会驱散水系Buff都可以实现。第一种情况最简单,水系Buff配置Tag 为Water的时候配置ImmuneTag为Fire。此时存在水系Buff的时候即可免疫火系Buff了。第二中情况也好办。配置BuffTag为Water。当OnBuffStart的时候调用驱散接口DispelByTag(Water),驱散掉所有火系Tag相关Buff即可。 + + + +- 问:霸体效果怎么实现,而且假如说存在破霸体效果又怎么实现,而且Boss的霸体效果完全不受影响又怎么实现?万一还存在特殊效果可以让Boss受到控制怎么办? +- 答:我们可以定义两个BuffTag:WeakControl(弱控制)和StrongControl(强控制),普通霸体效果通过Buff配置ImmuneTag:WeakControl即可免疫控制效果。如果是破霸体效果,我们给这个Buff的Tag标记StrongControl就行,同时Boss的Buff配置ImmuneTag为WeakControl | StrongControl(免疫弱控制和强控制)就满足需求了。如果存在某个特殊的效果能让Boss受到控制效果的话,那这个Buff的Tag不要标记WeakControl和StrongControl就行了,这样它就无法被免疫掉了。看起来复杂的霸体破霸体效果实际实现就这么简单,就这么清晰,不需要引入任何新的系统。 + + + +- 问:Buff存盘那块如何处理跟施法者相关的属性数据?如施法者可以给目标添加一个强力的毒Buff,具体伤害数值有施法者属性决定,离线后依旧生效,直到Buff时间结束才移除。 +- 答:这块我们的处理依旧很简单,Buff依然设置bNoCaster=true。但是在Buff创建的Context里面我们设置Context.DamageValue为根据施法者属性计算出来的伤害数值。然后Buff持续造成伤害的时候直接取Context.DamageValue即可。至于说想要玩家离线再上线,Caster离线再上线后,毒的伤害数值还能实时修改的话,这样的需求是不存在的,如果一定要做,当然也能做,只是麻烦一点而且也没有必要。这样的需求一般仅仅存在测试的大脑中,策划是不会有这样的玩法需求了。 + + + +- 问:常见的基于指定地点延迟触发的AOE效果怎么实现?当技能施法成功后就延迟触发,不会被打断AOE效果。(如果能被打断,我们可以用引导类技能轻松实现) +- 答:我们将技能标记为可指定目标地点释放,当技能Spell的时候我们先给自己加一个Buff,这个Buff仅仅用于延迟效果(当然可以有更多的可能性,如监听到某种事件立即结束并触发AOE效果),当Buff持续时间到了的时候在OnBuffDestroy的时候创建AOE效果Buff。这个AOE Buff会调用StartIntervalThink函数,在OnIntervalThink的时候通过Buff:GetAbility():GetCastPosition()为基准位置检查周围的敌方单位是否在AOE半径内,如果是,则施加作用效果。 \ No newline at end of file diff --git a/3Projects/UE/UE-CORE-002 TickTaskManager.md b/3Projects/UE/UE-CORE-002 TickTaskManager.md new file mode 100644 index 0000000..80780dd --- /dev/null +++ b/3Projects/UE/UE-CORE-002 TickTaskManager.md @@ -0,0 +1,1949 @@ + +source:[UE-CORE-002 TickTaskManager](https://descriptive-cemetery-9e2.notion.site/UE-CORE-002-TickTaskManager-20da28348a39808cb364f311819b06dc#20fa28348a39807596ddc5508ea7b477) + +--- + + +# 一、概述 + +## 1.1 Tick 任务调度的重要性 + +在游戏引擎中,**Tick**(如 UE 的 Tick 以及 Unity 的 Update)是驱动动态内容更新的核心机制。每一帧的时间内,引擎需要完成大量的计算和逻辑处理,例如物理模拟、动画更新、AI 决策、用户输入响应等。这些任务的执行顺序和时机直接决定了游戏世界的稳定性和一致性。因此,**Tick 任务调度**的设计和实现是游戏引擎架构中的关键部分。 + +Tick 是一个每帧调用一次的函数,用于更新对象的状态或执行特定的逻辑。在 UE 中,几乎所有动态行为都依赖于 Tick 系统。以下是一些常见的 Tick 使用场景: + +- **输入处理** :如根据玩家输入,更新角色的位置和方向。 +- **物理模拟** :计算刚体动力学、碰撞检测和约束求解。 +- **动画更新** :驱动骨骼动画系统,确保角色动作流畅且与物理状态一致。 +- **网络同步** :将本地状态同步到服务器或其他客户端。 +- **UI 更新** :刷新界面元素的状态(如血条、计时器等)。 + +由于这些任务之间存在复杂的依赖关系(例如,物理结算必须先于动画更新),如果 Tick 任务的调度不当,可能会导致数据竞争、状态不一致甚至崩溃。 + +另外,由于每帧的时间是有限的,尤其是在高帧率(如 60 FPS 或更高)的情况下,每一帧只有约 16 毫秒的时间来完成所有任务。如果 Tick 系统没有经过良好的设计和优化,可能会导致以下问题: + +- **性能瓶颈** :高频 Tick 任务会占用大量 CPU 时间,影响其他系统的运行效率。 +- **资源浪费** :某些对象可能并不需要每帧都更新(例如远处的静态物体),但仍然被频繁调用。 + +同时,现代游戏引擎通常需要处理大量的异步任务(如数据加载与解码),为了支持这些异步任务,Tick 系统需要提供专门的机制,确保它们能够与其他任务正确协作。 + +综上所述,Tick 调度系统不仅是一个简单的“每帧调用”机制,更是游戏引擎运行时的核心支柱。它承担着以下几个重要职责: + +1. **确保任务按正确的顺序执行** :通过分组和依赖管理,避免逻辑冲突和状态不一致。 +2. **优化性能** :通过按需更新、多线程支持和细粒度控制,最大限度地提高运行效率。 +3. **支持复杂场景** :通过异步任务和动态注册机制,适应现代游戏开发中的多样化需求。 + +正因为 Tick 调度如此重要,UE 提供了一个专门的组件——**`FTickTaskManager`**,来管理和调度所有的 Tick 任务。它并非一个简单的功能优化,而是维系整个游戏世界稳定、高效、可预测运行的**核心基石**。 + +![Tick 任务调度核心与挑战](attachment:7bd27db8-d583-45aa-a558-11c3669e4e86:Editor___Mermaid_Chart-2025-06-11-030235.png) + +Tick 任务调度核心与挑战 + +## 1.2 FTickTaskManager 的角色与定位 + +`FTickTaskManager` 并非一个孤立的系统,而是紧密集成在 UWorld 的 Tick 流程中,扮演着一个至关重要的角色。 + +大致可以从以下三个层面来精确定位 `FTickTaskManager` 的角色: + +1. **UWorld 的中央调度核心**:`UWorld::Tick` 函数本身并不直接执行任何 Actor 或 Component 的 Tick 逻辑。它将这一复杂任务完全委托给了 `FTickTaskManager`。在每一帧,UWorld 会首先命令 `FTickTaskManager` 进行准备 (StartFrame),然后根据预设的 Tick Group 顺序,多次调用 `FTickTaskManager` 的 `RunTickGroup` 来执行相应阶段的任务,最后再通知其进行清理 (EndFrame)。可以说,FTickTaskManager 是 `UWorld::Tick` 的“大脑”和“执行引擎”,负责将 UWorld 的更新意图转化为具体的、有序的任务执行。 +2. **依赖关系解析器**:`FTickTaskManager` 的核心能力之一,是理解并处理 `FTickFunction` 之间通过 `AddPrerequisite` 建立的依赖关系。在 StartFrame 阶段,它会收集所有需要更新的 Tick 任务,并分析它们之间的前后置依赖,最终构建出一个有向无环图。这个依赖图精确地描述了本帧所有任务的执行约束,是保证逻辑正确性的基础。 +3. **并发任务分发器**:`FTickTaskManager` 自身不直接执行并行计算,但它扮演着连接上层游戏逻辑与底层 Task Graph 系统的关键桥梁。在 `RunTickGroup` 阶段,它会将依赖图中那些没有前置约束、可以并行执行的任务,打包成 `FGraphEvent` 并提交给 Task Graph 系统。由 Task Graph 系统负责将这些任务高效地分配到不同的 CPU 工作线程上。因此,`FTickTaskManager` 的角色更像一个“计划者”和“分包商”,它制定了详细的施工计划(依赖图),然后将具体的施工任务(可并行的 Tick)分发给专业的施工队(Task Graph)。 + +总结而言,**FTickTaskManager 的定位是:一个位于 UWorld 内部,负责将海量、无序、且相互依赖的 Tick 任务,转化为一个结构化、有序、且部分可并行的执行计划,并将其提交给底层系统来完成的高级调度器。** 它是 UE 解决 Tick 任务调度三大难题(顺序、依赖、性能)的核心技术实现。 + +![FTickTaskManager 分层架构](attachment:1b0f4837-c508-43f3-b708-132be492a28f:Editor___Mermaid_Chart-2025-06-11-031205.png) + +FTickTaskManager 分层架构 + +# 二、源码剖析 + +## 2.1 核心数据结构 + +### 2.1.1 FTickFunction + +> **源码文件**:`Source/Runtime/Engine/Classes/Engine/EngineBaseTypes.h` + +`FTickFunction` 是一个 **USTRUCT**,这意味着它可以被 UE 的反射系统识别。它本身**不是一个可执行的函数**,而是一个**描述 Tick 任务所有属性和状态的“数据包”或“配置文件”**。当一个 Actor 或 Component 需要逐帧更新时,它内部就会包含一个 `FTickFunction` 的派生实例,并将其注册到 `FTickTaskManager` 中。 + +--- + +1. **公开配置属性** + +这部分成员变量主要用于配置一个 Tick 任务的基本行为。 + +```cpp +// 定义了这个Tick任务所属的Tick组,决定了其大致的执行阶段 +UPROPERTY(...) +TEnumAsByte TickGroup; + +// 定义了这个Tick任务必须在此Tick组之前完成 +UPROPERTY(...) +TEnumAsByte EndTickGroup; + +// 该任务是否在游戏暂停时也执行 +UPROPERTY(...) +uint8 bTickEvenWhenPaused:1; + +// 【关键】这个Tick功能是否在代码层面被永久启用。如果为false,它永远不会被注册。 +UPROPERTY() +uint8 bCanEverTick:1; + +// 如果为true,该任务在创建时默认是启用的,但后续可以动态关闭。 +UPROPERTY(...) +uint8 bStartWithTickEnabled:1; + +// 是否允许在专用服务器上运行 +UPROPERTY(...) +uint8 bAllowTickOnDedicatedServer:1; + +// Tick的执行频率(秒)。如果大于0,引擎会尝试按这个间隔来调用,而不是每帧都调。 +UPROPERTY(...) +float TickInterval; +``` + +**分析**: + +这部分定义了 Tick 任务的**静态行为蓝图**。`bCanEverTick` 是最重要的一个开关,它在编译时就决定了这个 Tick 功能是否存在。`TickGroup` 和 `EndTickGroup` 则是向 `FTickTaskManager` 声明其执行顺序的“意图”。开发者通过调整这些参数,可以精细地控制一个 Tick 任务的基础属性。 + +--- + +1. **内部状态与控制标志** + +这部分主要是一些非 UPROPERTY 的 bool 标志,用于更精细地控制 Tick 的行为。 + +```cpp +// 是否允许将多个类似的Tick任务打包在一起执行以提升性能 +uint8 bAllowTickBatching:1; + +// 是否在本Tick组内优先执行,用于需要尽早开始的异步任务 +uint8 bHighPriority:1; + +// 【关键】如果为true,该任务可以在任何工作线程上并行执行,否则只能在游戏主线程。 +uint8 bRunOnAnyThread:1; + +// ... 其他一些实验性或特殊用途的标志 ... + +// Tick任务的当前状态(启用、禁用、冷却中) +ETickState TickState : 2; +``` + +**分析:** + +`bRunOnAnyThread` 是实现并行优化的关键。如果一个 Tick 任务的逻辑不依赖于任何游戏线程特有的数据(比如 UI、某些 UObject 操作),就可以将此标志设为 true,`FTickTaskManager` 就会放心地将它交给任意一个空闲的 CPU 核心去执行,从而与游戏主线程并行工作,缩短帧时间。 + +--- + +1. **核心功能性成员** + +这部分是 `FTickFunction` 实现其调度能力的核心数据。 + +```cpp +// 【关键】存储该Tick任务的所有前置依赖项。 +// FTickTaskManager在构建任务图时会读取这个数组,来确定任务间的先后关系。 +TArray Prerequisites; + +// 【关键】一个懒加载的、包含所有运行时状态的内部数据结构。 +// 只有当Tick函数被注册后,这个指针才会被分配内存。 +// 这样做可以节省未注册的Tick函数的内存开销。 +TUniquePtr InternalData; +``` + +**分析:** + +`Prerequisites` 是依赖系统的**物理实现**。任何通过 `AddPrerequisite()` 添加的依赖,最终都会被存储在这个数组中。`InternalData` 的设计则体现了**性能优化的思想**。对于成千上万个可能永远不会Tick的组件,引擎不会为它们分配额外的运行时数据,只有当 `RegisterTickFunction` 被调用时,才会按需创建 `FInternalData`,这是一种非常高效的内存管理策略。 + +`FInternalData` 内部包含了诸如 `TaskPointer`(指向底层T ask Graph 任务的指针)、`ActualStartTickGroup`(因依赖延迟后,实际开始执行的 Tick 组)等**运行时动态变化的状态**。将这些动态状态与静态配置分离,使得整个结构更加清晰。 + +--- + +1. **核心功能性函数** + +这部分是 `FTickFunction` 对外暴露的主要API,以及其虚函数。 + +```cpp +// 注册/注销Tick函数到FTickTaskManager +ENGINE_API void RegisterTickFunction(class ULevel* Level); +ENGINE_API void UnRegisterTickFunction(); + +// 动态启用/禁用Tick +ENGINE_API void SetTickFunctionEnable(bool bInEnabled); + +// 【关键】添加/移除依赖项 +ENGINE_API void AddPrerequisite(UObject* TargetObject, struct FTickFunction& TargetTickFunction); +ENGINE_API void RemovePrerequisite(UObject* TargetObject, struct FTickFunction& TargetTickFunction); + +// 【关键】纯虚函数,必须由派生类实现。这里是真正执行Tick逻辑的地方。 +ENGINE_API virtual void ExecuteTick(...) PURE_VIRTUAL(,); + +// 【关键】纯虚函数,用于在产生循环依赖等错误时,提供可读的诊断信息。 +ENGINE_API virtual FString DiagnosticMessage() PURE_VIRTUAL(, ...); +``` + +**分析:** + +`RegisterTickFunction` 和 `UnRegisterTickFunction` 是 Tick 任务生命周期的起点和终点。`AddPrerequisite` 是构建复杂依赖关系网的API入口。 + +最重要的两个**纯虚函数(PURE_VIRTUAL)** `ExecuteTick` 和 `DiagnosticMessage`,揭示了 `FTickFunction` 的设计模式:它是一个**抽象基类**,定义了一个**契约**。任何想要成为可Tick任务的类(如 `FActorTickFunction`),都必须实现这两个函数。`ExecuteTick` 负责“做什么”,`DiagnosticMessage` 负责“我是谁”。`FTickTaskManager` 在调度时,并不关心具体是谁在Tick,它只知道调用 `ExecuteTick` 这个标准接口即可,这是一种典型的**多态**应用。 + +--- + +**总结**: + +`FTickFunction` 是一个设计精巧、高度工程化的数据结构。它完美地体现了以下设计思想: + +- **配置与状态分离:** 将静态配置(UPROPERTY)与运行时动态数据(InternalData)分离。 +- **懒加载:** 通过 `TUniquePtr` 按需分配 `InternalData`,优化内存使用。 +- **抽象与多态:** 通过纯虚函数定义了一个统一的执行契约,让上层调度代码可以与具体实现解耦。 +- **数据驱动:** 整个结构就是一个数据容器,其行为完全由内部的成员变量配置来驱动。 + +![FTickFunction 结构类图](attachment:3dbe052f-4415-4baf-8e3f-c0145e11d5d3:Editor___Mermaid_Chart-2025-06-11-084044.png) + +FTickFunction 结构类图 + +### 2.1.2 FActorTickFunction & FActorComponentTickFunction + +> **源码文件**:`Source/Runtime/Engine/Classes/Engine/EngineBaseTypes.h` + +```cpp +/** +* Tick function that calls AActor::TickActor +**/ +USTRUCT() +struct FActorTickFunction : public FTickFunction +{ + GENERATED_USTRUCT_BODY() + + /** AActor that is the target of this tick **/ +#if UE_WITH_REMOTE_OBJECT_HANDLE + TObjectPtr Target; +#else + class AActor* Target; +#endif + + /** + * Abstract function actually execute the tick. + * @param DeltaTime - frame time to advance, in seconds + * @param TickType - kind of tick for this frame + * @param CurrentThread - thread we are executing on, useful to pass along as new tasks are created + * @param MyCompletionGraphEvent - completion event for this task. Useful for holding the completetion of this task until certain child tasks are complete. + **/ + ENGINE_API virtual void ExecuteTick(float DeltaTime, ELevelTick TickType, ENamedThreads::Type CurrentThread, const FGraphEventRef& MyCompletionGraphEvent) override; + /** Abstract function to describe this tick. Used to print messages about illegal cycles in the dependency graph **/ + ENGINE_API virtual FString DiagnosticMessage() override; + ENGINE_API virtual FName DiagnosticContext(bool bDetailed) override; + +#if UE_WITH_REMOTE_OBJECT_HANDLE + /** Exposes references to GC system */ + ENGINE_API void AddStructReferencedObjects(FReferenceCollector& Collector); +#endif +}; +``` + +```cpp +/** +* Tick function that calls UActorComponent::ConditionalTick +**/ +USTRUCT() +struct FActorComponentTickFunction : public FTickFunction +{ + GENERATED_USTRUCT_BODY() + +#if UE_WITH_REMOTE_OBJECT_HANDLE + TObjectPtr Target; +#else + /** AActor component that is the target of this tick **/ + class UActorComponent* Target; +#endif + + /** + * Abstract function actually execute the tick. + * @param DeltaTime - frame time to advance, in seconds + * @param TickType - kind of tick for this frame + * @param CurrentThread - thread we are executing on, useful to pass along as new tasks are created + * @param MyCompletionGraphEvent - completion event for this task. Useful for holding the completetion of this task until certain child tasks are complete. + **/ + ENGINE_API virtual void ExecuteTick(float DeltaTime, ELevelTick TickType, ENamedThreads::Type CurrentThread, const FGraphEventRef& MyCompletionGraphEvent) override; + /** Abstract function to describe this tick. Used to print messages about illegal cycles in the dependency graph **/ + ENGINE_API virtual FString DiagnosticMessage() override; + ENGINE_API virtual FName DiagnosticContext(bool bDetailed) override; + + /** + * Conditionally calls ExecuteTickFunc if registered and a bunch of other criteria are met + * @param Target - the actor component we are ticking + * @param bTickInEditor - whether the target wants to tick in the editor + * @param DeltaTime - The time since the last tick. + * @param TickType - Type of tick that we are running + * @param ExecuteTickFunc - the lambda that ultimately calls tick on the actor component + */ + + //NOTE: This already creates a UObject stat so don't double count in your own functions + + template + static void ExecuteTickHelper(UActorComponent* Target, bool bTickInEditor, float DeltaTime, ELevelTick TickType, const ExecuteTickLambda& ExecuteTickFunc); + +#if UE_WITH_REMOTE_OBJECT_HANDLE + /** Exposes references to GC system */ + ENGINE_API void AddStructReferencedObjects(FReferenceCollector& Collector); +#endif +}; +``` + +由上面的源码可知,`FActorTickFunction` & `FActorComponentTickFunction` 这两个结构体都直接继承自 `FTickFunction`。它们的核心作用是**将抽象的 Tick 任务具体化**,使其与一个特定的 `AActor` 或 `UActorComponent` 实例绑定,并负责在 `ExecuteTick` 被调用时,真正地去执行那个实例的 `Tick` 或 `TickComponent` 方法。 + +在分别解析之前,我们先看它们完全相同的设计模式: + +- **共同的核心设计**: + 1. **继承 `FTickFunction`:** 它们都继承了基类所有的配置属性(`TickGroup`等)、状态管理(`InternalData`)和API(`RegisterTickFunction`等)。 + 2. **实现纯虚函数:** 它们都用 `override` 关键字实现了基类中定义的两个纯虚函数 `ExecuteTick` 和 `DiagnosticMessage`,从而满足了基类定义的“契约”。 + 3. **持有目标指针:** 它们都包含一个名为 `Target` 的成员变量,用于**指向**它们所服务的具体 `UObject` 实例。 + +--- + +1. **`struct FActorTickFunction` 解析** + +- **`Target` 成员** + - **职责:** 这个指针就是 `FActorTickFunction` 的“服务对象”。它明确地指出了这个 Tick 任务是属于哪一个 `AActor` 实例的。 + - **类型选择:** + - `TObjectPtr`: 在较新的 UE 版本中,使用 `TObjectPtr` 是一种更现代、更安全的指针类型,它能被 GC 系统更好地追踪。 + - `AActor*`: 在旧版本或特定编译配置下,使用裸指针。 +- **`ExecuteTick()` 实现** + - **职责:** 这是**连接调度与执行的最后一环**。当 `FTickTaskManager` 调度到这个任务时,就会调用这个函数。 + - **内部实现(在 `.cpp` 文件中):** 这个函数的实现非常直接,其核心逻辑为:检查 `Target` 指针是否有效,然后调用 `AActor` 类中真正的 `TickActor` 方法(`TickActor` 内部会再调用我们熟悉的 `virtual void Tick(float DeltaTime)`)。 + +```cpp +void FActorTickFunction::ExecuteTick(float DeltaTime, enum ELevelTick TickType, ENamedThreads::Type CurrentThread, const FGraphEventRef& MyCompletionGraphEvent) +{ + if (IsValid(Target)) + { + if (TickType != LEVELTICK_ViewportsOnly || Target->ShouldTickIfViewportsOnly()) + { + FScopeCycleCounterUObject ActorScope(Target); + Target->TickActor(DeltaTime*Target->CustomTimeDilation, TickType, *this); + } + } +} +``` + +- **`DiagnosticMessage()` 实现** + - **职责:** 当 `FTickTaskManager` 检测到循环依赖等问题时,会调用这个函数来获取一段可读的错误信息,用于日志输出。 + - **内部实现:** 它通常会返回类似 `FString::Printf(TEXT("FActorTickFunction for %s"), *Target->GetFullName())` 的字符串,清晰地指明是哪个 Actor 的 Tick 出了问题。 + +--- + +1. **`struct FActorComponentTickFunction` 解析** + +它与 `FActorTickFunction` 的结构和原理几乎完全相同,只是服务对象不同。 + +- **`Target` 成员** + - **职责:** 指向其所服务的具体 `UActorComponent` 实例。 +- **`ExecuteTick()` 实现** + - **内部实现:** 其核心逻辑与 `FActorTickFunction` 类似,但它最终调用的是 `Target` 组件的 `TickComponent` 方法: + +```cpp +void FActorComponentTickFunction::ExecuteTick(float DeltaTime, enum ELevelTick TickType, ENamedThreads::Type CurrentThread, const FGraphEventRef& MyCompletionGraphEvent) +{ + TRACE_CPUPROFILER_EVENT_SCOPE(FActorComponentTickFunction::ExecuteTick); + + ExecuteTickHelper(Target, Target->bTickInEditor, DeltaTime, TickType, [this, TickType](float DilatedTime) + { + Target->TickComponent(DilatedTime, TickType, this); + }); +} +``` + +--- + +**总结**: + +`FActorTickFunction` 和 `FActorComponentTickFunction` 是 `FTickFunction` 抽象概念的**具体化实现**。它们扮演着“适配器”(Adapter)的角色,将 `FTickTaskManager` 的泛型调度指令,精准地“翻译”为对特定 `AActor` 或 `UActorComponent` 实例的成员函数调用。 + +它们的设计体现了面向对象中**多态**和**继承**的核心思想,使得上层调度系统无需关心 Tick 任务的具体类型,从而实现了高度的解耦和可扩展性。 + +### 2.1.3 FInternalData + +> **源码文件**:`Source/Runtime/Engine/Classes/Engine/EngineBaseTypes.h` + +`FInternalData` 是一个专门用于存储 **已注册** 的 `FTickFunction` 在**运行时动态变化的状态**的内部数据结构。 + +它的存在本身就是一个**性能优化设计**。`FTickFunction` 通过 `TUniquePtr InternalData;` 来持有它。这意味着,只有当一个 Tick 任务通过 `RegisterTickFunction()` 被激活时,引擎才会为其分配 `FInternalData` 的内存。对于成千上万个可能永远不会被注册的 Tick 任务(例如,一个从未被使用的组件),引擎不会浪费任何内存来存储它们的运行时状态。这是一种典型的 **懒加载** 策略。 + +--- + +1. **核心状态与注册信息** + +```cpp +// 标志位,表示该Tick函数是否已向FTickTaskManager注册。 +bool bRegistered : 1; + +// 内部状态,决定了 TaskPointer 指针的类型和含义。 +// ETickTaskState 枚举的可能值:NotQueued, Pending, HasTask, HasCompletionEvent +ETickTaskState TaskState; + +// 指向其所属的 FTickTaskLevel 的反向指针。 +// 这使得FTickTaskManager可以快速地从一个FTickFunction找到它所在的Level。 +class FTickTaskLevel* TickTaskLevel; +``` + +**分析:** + +`bRegistered` 是生命周期的起点。`TaskState` 是整个 Tick 调度过程中最重要的状态机,`FTickTaskManager` 通过改变这个状态来管理一个 Tick 任务从“待处理”到“已排队”再到“已完成”的整个流程。`TickTaskLevel` 则提供了上下文信息。 + +--- + +1. **运行时 Tick Group 信息** + +```cpp +// 由于依赖关系,一个Tick任务实际开始执行的Tick组可能晚于其配置的TickGroup。 +// 这个变量记录了它在本帧实际开始的Tick组。 +TEnumAsByte ActualStartTickGroup; + +// 类似地,记录了它在本帧保证会结束的Tick组。 +TEnumAsByte ActualEndTickGroup; +``` + +**分析:** 这组变量体现了依赖系统的动态性。一个配置为 `TG_PrePhysics` 的任务,如果它依赖的另一个任务直到 `TG_EndPhysics` 才完成,那么它自己的 `ActualStartTickGroup` 就会被动态调整为 `TG_EndPhysics` 之后的某个组。这是 `FTickTaskManager` 在 `StartFrame` 阶段进行依赖图解析后得出的**动态调度计划**。 + +--- + +1. **并发与任务图相关数据** + +```cpp +// 【关键】一个void*指针,其具体指向的类型由 TaskState 决定。 +// 它可能指向一个 FGraphEventRef(代表一个独立的Task Graph任务)或 +// 其他内部任务结构。这是FTickFunction与底层Task Graph系统连接的纽带。 +void* TaskPointer; + +// 用于多线程同步的原子计数器,记录该Tick任务在哪一帧被访问过,以防止重复处理。 +std::atomic TickVisitedGFrameCounter; + +// 记录该Tick任务在哪一帧被排入队列。 +std::atomic TickQueuedGFrameCounter; +``` + +**分析:** + +`TaskPointer` 是与底层并行系统交互的核心。`FTickTaskManager` 将一个 `FTickFunction` 包装成一个 `Task Graph` 任务后,会将任务的句柄(Handle)存储在这里。`std::atomic` 的使用则表明这些变量会在多线程环境下被访问,用于保证在并行调度时,每个任务在一帧内只被处理一次,避免了竞态条件。 + +--- + +1. **Tick 间隔与冷却管理** + +这部分成员专门用于实现 `TickInterval` 功能。 + +```cpp +// 标志位,缓存该函数是否因设置了TickInterval而被重新调度。 +bool bWasInterval:1; + +// 指向冷却列表中的下一个FTickFunction。 +// FTickTaskManager内部维护了一个按冷却时间排序的链表来管理所有设置了TickInterval的任务。 +FTickFunction* Next; + +// 剩余的冷却时间(秒)。 +// 它存储的是相对于链表中前一个元素的相对时间,这种设计可以高效地更新整个链表。 +float RelativeTickCooldown; + +// 上一次该函数被Tick时的游戏时间。 +// 用于计算下一次应该在何时Tick。 +float LastTickGameTimeSeconds; +``` + +**分析:** 这组数据揭示了 `TickInterval` 的实现原理。引擎并非为每个有间隔的 Tick 都创建一个独立的计时器,而是将它们组织成一个**高效的排序链表(冷却列表)**。每一帧,引擎只需要检查链表头部的任务,看看它的 `RelativeTickCooldown` 是否已经到期。这种设计避免了每帧遍历所有任务来检查时间,极大地提升了效率。 + +--- + +**总结**: + +![FInternalData Mindmap](attachment:7a4ed083-c473-4b10-b01d-db2a3b05c91a:Editor___Mermaid_Chart-2025-06-11-080937.png) + +FInternalData Mindmap + +FInternalData 是一个纯粹的**运行时数据容器**,它的设计充满了对性能和效率的考量: + +- **懒加载:** 只有在需要时才分配内存。 +- **状态驱动:** 通过 ETickTaskState 状态机来管理复杂的任务生命周期。 +- **动态调度:** 通过 ActualStartTickGroup 等变量记录依赖解析后的动态结果。 +- **并发安全:** 使用原子变量来确保多线程环境下的数据一致性。 +- **高效算法:** 通过精巧的链表和相对时间来管理 Tick 间隔,避免了不必要的计算。 + +FTickFunction 主体定义了“我是谁以及我想做什么”,而 FInternalData 则记录了“我现在正在做什么以及我接下来要去哪”。两者结合,构成了一个完整的、功能强大的 Tick 任务单元。 + +### 2.1.4 FTickPrerequisite + +> **源码文件**:`Source/Runtime/Engine/Classes/Engine/EngineBaseTypes.h` + +`FTickPrerequisite` 是一个专门用于**安全地存储和引用一个前置依赖 Tick 任务**的 `USTRUCT`。当我们在 `FTickFunction` 中调用 `AddPrerequisite` 时,实际上就是在其内部的 `Prerequisites` 数组中添加了一个 `FTickPrerequisite` 的实例。`FTickPrerequisite` 这个结构体虽然小,但却是实现 `FTickTaskManager` 依赖系统的关键“连接件”。它的核心设计目标是解决一个问题:**如何在保证内存安全的前提下,持有一个指向另一个 `FTickFunction` 的指针?** + +--- + +```cpp +/** + * This is small structure to hold prerequisite tick functions + */ +USTRUCT() +struct FTickPrerequisite +{ + GENERATED_USTRUCT_BODY() + + /** Tick functions live inside of UObjects, so we need a separate weak pointer to the UObject solely for the purpose of determining if PrerequisiteTickFunction is still valid. */ + TWeakObjectPtr PrerequisiteObject; + + /** Pointer to the actual tick function and must be completed prior to our tick running. */ + struct FTickFunction* PrerequisiteTickFunction; + + /** Noop constructor. */ + FTickPrerequisite() + : PrerequisiteTickFunction(nullptr) + { + } + /** + * Constructor + * @param TargetObject - UObject containing this tick function. Only used to verify that the other pointer is still usable + * @param TargetTickFunction - Actual tick function to use as a prerequisite + **/ + FTickPrerequisite(UObject* TargetObject, struct FTickFunction& TargetTickFunction) + : PrerequisiteObject(TargetObject) + , PrerequisiteTickFunction(&TargetTickFunction) + { + check(PrerequisiteTickFunction); + } + /** Equality operator, used to prevent duplicates and allow removal by value. */ + bool operator==(const FTickPrerequisite& Other) const + { + return PrerequisiteObject == Other.PrerequisiteObject && + PrerequisiteTickFunction == Other.PrerequisiteTickFunction; + } + /** Return the tick function, if it is still valid. Can be null if the tick function was null or the containing UObject has been garbage collected. */ + struct FTickFunction* Get() + { + if (PrerequisiteObject.IsValid(true)) + { + return PrerequisiteTickFunction; + } + return nullptr; + } + + const struct FTickFunction* Get() const + { + if (PrerequisiteObject.IsValid(true)) + { + return PrerequisiteTickFunction; + } + return nullptr; + } +}; +``` + +--- + +1. **核心成员变量解析** + +由上面的源码可知,这个结构体只有两个成员变量,但它们的设计配合得很巧妙。 + +```cpp +// 用于验证 PrerequisiteTickFunction 指针是否仍然有效的弱引用。 +TWeakObjectPtr PrerequisiteObject; + +// 指向实际的前置依赖Tick函数的裸指针。 +struct FTickFunction* PrerequisiteTickFunction; +``` + +**分析:为什么定义两个指针?** + +- `FTickFunction` 本身并不是一个 `UObject`,所以它不受 UE 的垃圾回收(GC)系统直接管理。它通常是作为 `UObject`(如 `AActor` 或 `UActorComponent`)的成员变量存在的。 +- 如果直接持有一个 `FTickFunction*` 裸指针,我们无法知道它所依附的 `UObject` 是否已经被GC销毁。如果其宿主`UObject`被销毁,这个裸指针就会变成一个危险的**悬空指针**。 +- **`TWeakObjectPtr` 的关键作用:**`TWeakObjectPtr`(弱对象指针)是 UE 提供的一种智能指针,它**不会**阻止其指向的 `UObject` 被 GC 回收。它的核心能力是提供了一个 `IsValid()` 方法。在访问裸指针之前,我们可以通过检查 `PrerequisiteObject.IsValid()` 来安全地判断那个 `UObject` 是否还存活。如果 `IsValid()` 返回 `false`,就意味着宿主对象已经被销毁,那么 `PrerequisiteTickFunction` 这个裸指针也必然失效了。 +- **协同工作机制:** + - `PrerequisiteObject` 扮演着“哨兵”的角色。 + - `PrerequisiteTickFunction` 存储着实际的目标地址。 + - 只有在“哨兵”确认安全(`IsValid()`)之后,我们才会去使用那个地址。 + +![FTickPrerequisite 安全访问机制](attachment:7c645043-e873-45c0-b3e2-f341eefbb72f:mermaid-diagram-2025-06-11-151136.png) + +FTickPrerequisite 安全访问机制 + +--- + +1. **核心功能性函数解析** + +- **构造函数**: + +```cpp +FTickPrerequisite(UObject* TargetObject, struct FTickFunction& TargetTickFunction) +: PrerequisiteObject(TargetObject) +, PrerequisiteTickFunction(&TargetTickFunction) +{ + check(PrerequisiteTickFunction); +} +``` + +**分析:** + +构造函数非常直白,它同时接收宿主 UObject 的指针和 FTickFunction 的引用,并将它们分别存入两个成员变量中。这确保了每次创建一个依赖关系时,安全验证所需的信息都被完整地记录下来。 + +--- + +- **Get() 方法** + +```cpp +struct FTickFunction* Get() +{ + if (PrerequisiteObject.IsValid(true)) + { + return PrerequisiteTickFunction; + } + return nullptr; +} +``` + +**分析:** + +这是该结构体最核心的对外接口。它实践了我们上述提到的“先检查,后访问”的安全模式。 + +- 首先调用 PrerequisiteObject.IsValid(true)。参数 true 表示即使对象正在等待被清理(Pending Kill),也将其视为无效。 +- 只有在弱指针验证通过,确认宿主 UObject 仍然存活的情况下,它才会返回那个可能有效的 PrerequisiteTickFunction 裸指针。 +- 如果宿主对象已失效,它会安全地返回 nullptr,避免了任何访问悬空指针的风险。 + +FTickTaskManager 在构建依赖图时,就会通过调用这个 Get() 方法来安全地获取每一个依赖项。 + +--- + +**总结**: + +FTickPrerequisite 虽然定义简单,但却是一个展示**如何在非 UObject 上下文中安全引用 UObject 成员**的优秀范例。它通过将一个**裸指针**与一个**用于生命周期验证的弱指针**巧妙地捆绑在一起,构建了一个既高效(直接访问裸指针)又安全(通过 TWeakObjectPtr 验证)的依赖引用机制。 + +--- + +### 2.1.5 ETickingGroup + +> **源码文件**:`Source/Runtime/Engine/Classes/Engine/EngineBaseTypes.h` + +`ETickingGroup` 是一个枚举类型,它定义了一系列离散的、有序的**“时间阶段”。`FTickTaskManager` 在一帧内,会严格按照这个枚举定义的顺序,一个接一个地执行属于每个阶段(Group)的 Tick 任务。**这套机制是 UE 用来解决 Tick 任务执行顺序和依赖关系问题的基石。 + +接下来,我将按照它们的实际执行顺序来逐一分析每个 Tick Group 的职责和设计目的。 + +(下面分析中提到的 ”注释描述“ 部分指的是源码中对于当前枚举值的注释。) + +--- + +1. **`TG_PrePhysics` - 物理模拟前** + +- **注释描述:** `Any item that needs to be executed before physics simulation starts.` (任何需要在物理模拟开始前执行的项) +- **职责:** 这是绝大多数游戏逻辑的默认执行阶段。所有决定物体“本帧想要如何运动”的逻辑都应该放在这里。 +- **典型用例:** + - **玩家输入处理:** 根据玩家的键盘/手柄输入,计算角色的移动向量。 + - **AI 决策:** AI Controller 在此决定本帧的移动目标或攻击行为。 + - **动画蓝图更新(非物理部分):** 更新状态机,决定要播放哪个动画序列。 +- **设计原因:** 物理引擎需要知道物体的“意图”(如目标速度、施加的力)才能开始计算。此阶段就是为了准备好所有这些输入数据。 + +--- + +1. **`TG_StartPhysics` - 物理模拟开始** + +- **注释描述:** `Special tick group that starts physics simulation.` (启动物理模拟的特殊Tick组) +- **元数据:** `UMETA(Hidden)` - 表示这个选项通常不在编辑器中对用户暴露。 +- **职责:** 一个内部阶段,用于触发物理引擎(如 Chaos)开始本帧的模拟计算。它更像是一个命令信号,而不是一个让用户注册任务的阶段。 + +--- + +1. **`TG_DuringPhysics` - 物理模拟中** + +- **注释描述:** `Any item that can be run in parallel with our physics simulation work.` (任何可以与物理模拟并行运行的项) +- **职责:** 提供一个时间窗口,用于执行那些**不依赖**于本帧物理计算最终结果的、且可以并行化的任务。 +- **典型用例:** + - **异步场景查询:** 发起一些耗时的射线检测或形状检测,而不阻塞主线程。 + - 一些独立的视觉效果或系统更新。 +- **设计原因:** 物理模拟是CPU密集型任务,通常在独立的线程上异步进行。`TG_DuringPhysics` 允许游戏主线程在等待物理计算的同时,去“插空”执行其他不相关的任务,从而提高CPU的利用率和整体性能。 + +--- + +1. **`TG_EndPhysics` - 物理模拟结束** + +- **注释描述:** `Special tick group that ends physics simulation.` (结束物理模拟的特殊Tick组) +- **元数据:** `UMETA(Hidden)` +- **职责:** 这是一个关键的**同步点**。游戏主线程会在此等待,直到异步的物理模拟线程完成其所有计算。完成后,物理引擎会将计算出的最终结果(如新的位置、旋转、碰撞事件)写回到游戏世界中的对象上。 + +--- + +1. **`TG_PostPhysics` - 物理模拟后** + +- **注释描述:** `Any item that needs rigid body and cloth simulation to be complete before being executed.` (任何需要刚体和布料模拟完成才能执行的项) +- **职责:** 执行所有**依赖于**本帧物理结算结果的逻辑。 +- **典型用例:** + - **骨骼动画更新:** 这是骨骼网格体组件的默认 Tick Group。它需要根据角色经过物理计算后的最终位置和速度来调整动画,例如使用 IK 将脚踩在正确的地面上,或根据速度混合不同的跑动动画。 + - **相机更新:** 相机需要跟随已经移动到最终位置的角色。 + - **碰撞事件响应:** 在这里处理 `OnComponentHit` 等事件是安全的,因为所有的碰撞信息此时都已生成。 +- **设计原因:** 这是为了保证**“表现”基于“事实”**。物理结果就是本帧的“事实”,而动画、相机等视觉表现必须基于这个事实来进行调整,否则就会出现“脚滑”、穿模等视觉错误。 + +--- + +1. **`TG_PostUpdateWork` - 更新工作后** + +- **注释描述:** `Any item that needs the update work to be done before being ticked.` (任何需要在更新工作完成后被Tick的项) +- **职责:** 在所有主要的游戏逻辑和视觉表现更新都完成后,执行一些收尾的更新任务。 +- **典型用例:** + - **布料模拟:** 布料通常需要附着在已经更新完动画的角色骨骼上,所以放在这里执行。 + - 一些最终的清理或同步逻辑。 + +--- + +1. **`TG_LastDemotable` - 可降级的最后任务** + +- **注释描述:** `Catchall for anything demoted to the end.` (一个用于接收所有被降级到末尾任务的“捕集器”) +- **元数据:** `UMETA(Hidden)` +- **职责:** 优先级最低的阶段。用于执行那些即使在一帧内被跳过也不会造成严重问题的任务。 + +--- + +1. **`TG_NewlySpawned` - 特殊:新生成对象** + +- **注释描述:** `...After every tick group this is repeatedly re-run until there are no more newly spawned items to run.` (在每个Tick组之后,这个组会重复运行,直到没有新生成的对象需要运行) +- **职责:** 这是一个非常特殊的“伪”组。它的目的是处理那些**在本帧的Tick过程中被动态生成(Spawn)出来的新Actor**。 +- **工作机制:** 假设在 `TG_PrePhysics` 阶段,一个Actor A 的 Tick 函数 `Spawn` 了一个新的 Actor B。Actor B 错过了本帧的 `TG_PrePhysics` 调度。为了让 B 也能在**当前帧**就被更新(而不是等到下一帧),`FTickTaskManager` 在 `TG_PrePhysics` 执行完后,会立即检查并执行所有新生成的、属于`TG_PrePhysics` 的对象的Tick。这个过程会在每个主Tick组后都重复一次。 +- **设计原因:** 解决了“帧内生成,帧内更新”的问题,使得动态生成的对象能够更及时地融入游戏世界,避免了一帧的延迟。 + +--- + +**总结**: + +ETickingGroup 是 UE 对一帧游戏时间的**“时间切片”**。通过将 Tick 任务强制归入这些有序的“切片”中,FTickTaskManager 实现了对整个世界模拟流程的精确控制,从根本上保证了复杂系统中数据流的正确性和逻辑的稳定性。这是 UE 高性能和高保真模拟能力的架构基石。 + +![ETickingGroup 流程图](attachment:c79803ca-b0d3-4f5f-bbae-c6c9b68a267c:Editor___Mermaid_Chart-2025-06-11-074346.png) + +**ETickingGroup 流程图** + +## 2.2 核心类 + +### 2.2.1 FTickTaskManagerInterface + +> **源码文件**:`Source\\Runtime\\Engine\\Public\\TickTaskManagerInterface.h` + +```cpp +/** + * Interface for the tick task manager + **/ +class FTickTaskManagerInterface +{ +public: + virtual ~FTickTaskManagerInterface() + { + } + + /** Allocate a new ticking structure for a ULevel **/ + virtual FTickTaskLevel* AllocateTickTaskLevel() = 0; + + /** Free a ticking structure for a ULevel **/ + virtual void FreeTickTaskLevel(FTickTaskLevel* TickTaskLevel) = 0; + + /** + * Queue all of the ticks for a frame + * + * @param World - World currently ticking + * @param DeltaSeconds - time in seconds since last tick + * @param TickType - type of tick (viewports only, time only, etc) + */ + virtual void StartFrame(UWorld* InWorld, float DeltaSeconds, ELevelTick TickType, const TArray& LevelsToTick) = 0; + + /** + * Run all of the ticks for a pause frame synchronously on the game thread. + * The capability of pause ticks are very limited. There are no dependencies or ordering or tick groups. + * @param World - World currently ticking + * @param DeltaSeconds - time in seconds since last tick + * @param TickType - type of tick (viewports only, time only, etc) + */ + virtual void RunPauseFrame(UWorld* InWorld, float DeltaSeconds, ELevelTick TickType, const TArray& LevelsToTick) = 0; + + /** + * Run a tick group, ticking all actors and components + * @param Group - Ticking group to run + * @param bBlockTillComplete - if true, do not return until all ticks are complete + */ + virtual void RunTickGroup(ETickingGroup Group, bool bBlockTillComplete ) = 0; + + /** Finish a frame of ticks **/ + virtual void EndFrame() = 0; + + /** Dumps all registered tick functions to output device. */ + virtual void DumpAllTickFunctions(FOutputDevice& Ar, UWorld* InWorld, bool bEnabled, bool bDisabled, bool bGrouped) = 0; + + /** Returns a map of enabled ticks, grouped by 'diagnostic context' string, along with count of enabled ticks */ + virtual void GetEnabledTickFunctionCounts(UWorld* InWorld, TSortedMap& TickContextToCountMap, int32& EnabledCount, bool bDetailed, bool bFilterCoolingDown=false) = 0; + + /** + * Singleton to retrieve the GLOBAL tick task manager + * + * @return Reference to the global cache tick task manager + */ + static ENGINE_API FTickTaskManagerInterface& Get(); + +}; +``` + +由以上源码可知,`FTickTaskManagerInterface` 是一个**纯抽象基类**。它定义了全局唯一的 Tick 任务管理器(`FTickTaskManager`)所必须提供的一系列公共服务和功能。 + +它的所有核心方法都被声明为**纯虚函数 (`= 0`)**,这意味着这个接口本身不能被实例化,任何想要成为一个有效的 Tick Task Manager 的类,都**必须**继承自这个接口并实现其所有纯虚函数。在UE中,这个唯一的实现者就是我们后面会分析的 `class FTickTaskManager`。 + +这种设计是**接口与实现分离**设计模式的典型应用,它允许引擎的其他部分(主要是`UWorld`)依赖于一个稳定的、抽象的接口,而无需关心其底层的具体实现可能会如何变化。 + +我们可以将 `FTickTaskManagerInterface` 中的接口函数按照其在 Tick 生命周期中的作用进行分组,下面我们分组进行分析。 + +--- + +1. **生命周期管理函数** + +这组函数构成了 `FTickTaskManager` 在一帧内的主要工作流程,由 `UWorld::Tick` 严格按顺序调用。 + +```cpp +// 在一帧的Tick开始时被调用,用于收集和规划所有任务。 +virtual void StartFrame(...) = 0; + +// 在一帧的Tick结束时被调用,用于清理和重置状态。 +virtual void EndFrame() = 0; + +// 【关键】执行一个指定Tick Group中的所有任务。 +// UWorld::Tick 会为每个ETickingGroup(如TG_PrePhysics)调用一次这个函数。 +virtual void RunTickGroup(ETickingGroup Group, bool bBlockTillComplete) = 0; +``` + +**分析:** + +`StartFrame`, `RunTickGroup`, `EndFrame` 共同定义了 Tick 管理器的**三段式工作模型**。这是 `UWorld` 与 `FTickTaskManager` 交互的主干道。`RunTickGroup` 中的 `bBlockTillComplete` 参数更是暴露了其支持同步/异步执行模式的能力,这是实现高性能并发调度的关键接口。 + +--- + +1. **特殊帧处理函数** + +```cpp +// 在游戏暂停时,执行一个简化的、同步的Tick流程。 +// 暂停时的Tick功能受限,没有依赖、排序或分组。 +virtual void RunPauseFrame(...) = 0; +``` + +**分析:** 这个函数提供了一种处理“游戏暂停”这一特殊状态的专用路径。它将暂停时的 Tick 逻辑与正常的游戏 Tick 逻辑分离开来,使得两种情况的处理都更加清晰。 + +--- + +1. **Tick 任务结构管理函数** + +这组函数负责管理与 `ULevel` 绑定的底层数据结构。 + +```cpp +// 为一个ULevel分配一个新的、用于存储其Tick任务的数据结构。 +virtual FTickTaskLevel* AllocateTickTaskLevel() = 0; + +// 释放一个ULevel不再使用的Tick任务数据结构。 +virtual void FreeTickTaskLevel(FTickTaskLevel* TickTaskLevel) = 0; +``` + +**分析:** 这两个函数揭示了 `FTickTaskManager` 内部是**以 Level 为单位**来组织 Tick 任务的。当一个`ULevel`被加载到世界中时,`UWorld`会调用`AllocateTickTaskLevel`来为它创建一个“账本”(`FTickTaskLevel`),用于记录该关卡内所有 Actor 和 Component 的 Tick 任务。当 Level 被卸载时,则调用`FreeTickTaskLevel`来销毁这个“账本”。这与 UE 的关卡流送(Level Streaming)机制紧密相关。 + +--- + +1. **调试与分析函数** + +这组函数主要用于开发和调试,提供了查询和输出 Tick 系统内部状态的能力。 + +```cpp +// 将所有已注册的Tick函数的信息(启用/禁用、分组等)转储到输出设备(如日志文件)。 +virtual void DumpAllTickFunctions(...) = 0; + +// 获取当前已启用的Tick函数的统计信息,按上下文(通常是类名)分组计数。 +// 这是Unreal Insights等性能分析工具获取数据的重要来源。 +virtual void GetEnabledTickFunctionCounts(...) = 0; +``` + +**分析:** 这些接口的存在表明,`FTickTaskManager` 在设计之初就充分考虑到了**可观测性**和**可调试性**。开发者可以通过这些工具,清晰地看到当前有哪些 Tick 在运行,它们的分组是什么,以及各类 Tick 的数量,这对于性能优化和问题排查至关重要。 + +--- + +1. **单例访问器** + +```cpp +// 全局静态函数,用于获取唯一的、全局的FTickTaskManagerInterface实例。 +static ENGINE_API FTickTaskManagerInterface& Get(); +``` + +**分析:** 这是典型的**单例模式**。整个引擎中只有一个 `FTickTaskManager` 实例,任何需要与它交互的代码(如`UWorld`, `AActor`等)都通过这个静态 `Get()` 方法来获取对它的引用。 + +--- + +**总结**: + +`FTickTaskManagerInterface` 如同一份清晰的“产品说明书”,它通过一系列纯虚函数,向整个引擎精确地定义了 Tick 调度系统所能提供的服务: + +- **核心服务:** 提供了一套完整的 `StartFrame` -> `RunTickGroup` -> `EndFrame` 的生命周期管理。 +- **组织方式:** 明确了其内部是以 `Level` 为单位来管理 Tick 任务的。 +- **特殊处理:** 定义了处理暂停帧的专门逻辑。 +- **可观测性:** 提供了强大的调试和性能分析接口。 +- **访问模式:** 规定了其作为一个全局单例的存在形式。 + +通过分析这个接口,我们无需深入其复杂的实现细节,就能从一个很高的层面理解`FTickTaskManager`的**设计目标、功能边界和核心职责**。 + +![FTickTaskManagerInterface 类图](attachment:4183eddf-e8df-42fa-b083-8b06068e7bcf:image.png) + +FTickTaskManagerInterface 类图 + +### 2.2.2 FTickTaskManager + +> **源码文件**:`Source\\Runtime\\Engine\\Private\\TickTaskManager.cpp` + +`FTickTaskManager` 是 `FTickTaskManagerInterface` 的**唯一实现**。它是一个全局单例,负责接收 `UWorld` 的指令,并将海量的、无序的 `FTickFunction` 组织成一个有序的、部分可并行的执行计划,然后提交给底层的 `Task Graph` 系统去执行。 + +--- + +1. **核心成员变量** + +```cpp +// 对一个更底层的、专门负责任务排序和依赖解析的辅助类的引用。 +FTickTaskSequencer& TickTaskSequencer; + +// 本帧需要进行Tick的所有Level的FTickTaskLevel的列表。 +TArray LevelList; + +// 存储本帧Tick的上下文信息,如World, DeltaSeconds, TickType等。 +FTickContext Context; + +// 一个关键的状态标志。当为true时,表示正处于一帧的Tick流程中, +// 此时任何新注册的Tick函数都需要被特殊处理(加入到新生成队列)。 +bool bTickNewlySpawned; +``` + +**分析:** + +`TickTaskSequencer` 是一个非常重要的内部辅助类,`FTickTaskManager` 将大量的复杂排序和依赖解析工作都委托给了它。`LevelList` 表明了其以`Level`为单位的管理模式。`Context` 作为一个上下文结构体,方便地将本帧的所有共享信息传递给各个子系统。`bTickNewlySpawned` 则是控制“帧内生成,帧内更新”机制的总开关。 + +--- + +1. **生命周期函数** + +这是 `UWorld::Tick` 驱动 `FTickTaskManager` 工作的主流程。 + +

+ +--- + + + +--- + + + +--- + +1. **Tick 函数注册/注销接口** + +```cpp +void AddTickFunction(ULevel* InLevel, FTickFunction* TickFunction) +{ + // ... + FTickTaskLevel* Level = TickTaskLevelForLevel(InLevel); // 找到或创建Level对应的TickTaskLevel + Level->AddTickFunction(TickFunction); // 在Level的“账本”中添加这个Tick函数 + // ... +} + +void RemoveTickFunction(FTickFunction* TickFunction) +{ + // ... + FTickTaskLevel* Level = TickFunction->InternalData->TickTaskLevel; // 从TickFunction自身找到它的“账本” + Level->RemoveTickFunction(TickFunction); // 从“账本”中移除 +} +``` + +**分析:** + +`AActor` 和 `UActorComponent` 在创建和销毁时调用的就是这两个函数。它们清晰地展示了 `FTickTaskManager` 是如何通过 `FTickTaskLevel` 来**按 Level 组织**所有 Tick 函数的。每个 `FTickFunction` 也通过其 `InternalData` 反向持有一个指向其所属 `FTickTaskLevel` 的指针,形成了一个双向链接,方便快速地添加和移除。 + +--- + +**总结**: + +![FTickTaskManager 工作流程](attachment:6f9c6260-4c36-4e42-b495-449f11e15aef:Editor___Mermaid_Chart-2025-06-11-100647.png) + +FTickTaskManager 工作流程 + +`FTickTaskManager` 的实现是一个典型的**分层委托**架构: + +- 它作为**高层管理者**,定义了 `StartFrame` -> `RunTickGroup` -> `EndFrame` 的宏观流程。 +- 它将**复杂的任务收集和排序逻辑**,委托给了内部的 `FTickTaskLevel` 和 `FTickTaskSequencer`。 +- 它将**最终的并行执行**,委托给了 `TickTaskSequencer` 背后的 `Task Graph` 系统。 + +通过这种层层委托,`FTickTaskManager` 以一种相对清晰、高内聚的方式,精心安排了整个极其复杂的 Tick 调度过程。 + +### 2.2.3 FTickTaskSequencer + +> **源码文件**:`Source\\Runtime\\Engine\\Private\\TickTaskManager.cpp` + +`FTickTaskSequencer` 是一个全局单例,是`FTickTaskManager`的**核心工作委托对象**。它的名字“Sequencer”(序列器)精准地描述了其核心职责:将一堆无序的、带有依赖关系的 Tick 任务,组织成一个可以被`Task Graph`系统高效执行的**任务序列**。 + +--- + +1. **核心成员变量** + +```cpp +// 存储用于批处理(Batching)的Tick任务信息 +TArray< TPair > > TickBatches; + +// 【关键】为每个Tick组(TG_MAX个)存储一个FGraphEventRef数组。 +// 当一个Tick任务被创建时,它的完成事件(Completion Event)会被添加到这个数组中。 +TArrayWithThreadsafeAdd > TickCompletionEvents[TG_MAX]; + +// 【关键】一个二维数组,用于存储所有Tick任务。 +// 第一个维度是任务的开始Tick组,第二个维度是结束Tick组。 +// 分为高优先级和普通优先级。 +TArrayWithThreadsafeAdd HiPriTickTasks[TG_MAX][TG_MAX]; +TArrayWithThreadsafeAdd TickTasks[TG_MAX][TG_MAX]; + +// 用于存储需要在帧末尾完成的清理任务。 +FGraphEventArray CleanupTasks; + +// 记录上一个被阻塞等待的Tick组,用于确定下一次需要等待哪些组。 +ETickingGroup WaitForTickGroup; + +// 一系列控制行为的布尔开关,由CVar控制。 +bool bAllowConcurrentTicks; // 是否允许并行Tick +bool bAllowBatchedTicksForFrame; // 是否允许Tick批处理 +// ... +``` + +**分析:** + +- **`TickCompletionEvents`** 和 **`TickTasks` / `HiPriTickTasks`** 是这个类的**核心数据容器**。 +- `TickTasks[StartGroup][EndGroup]` 这种二维数组的设计非常精巧。它使得`Sequencer`可以快速地根据**开始组**来分发任务,并根据**结束组**来收集它们的完成事件。 +- `TArrayWithThreadsafeAdd` 的使用,暗示了这些数组可以在**多个线程中被安全地添加元素**,这对于并行化的`StartFrame`流程至关重要。 +- `TickBatches` 则是一种性能优化,它尝试将属性相同(比如都在同一个 Tick 组、都没有依赖)的多个小 Tick 任务,打包成一个大的`Task Graph`任务来执行,以减少任务调度的开销。 + +--- + +1. **核心函数** + + + + + + + + + +--- + +**总结**: + +![FTickTaskSequencer 工作流程](attachment:5a98047a-d98f-4e09-b89f-a4d15db8ba90:Editor___Mermaid_Chart-2025-06-11-125137.png) + +FTickTaskSequencer 工作流程 + +`FTickTaskSequencer` 是一个高度优化的、与底层 `Task Graph` 系统紧密耦合的精密调度器。 + +- 它使用**二维数组**来高效地组织和索引海量的 Tick 任务,实现了按“开始组”和“结束组”的快速访问。 +- 它的 `Queue` 系列函数负责将上层的 `FTickFunction` **翻译**成底层的 `Task Graph` 任务。 +- 它的 `ReleaseTickGroup` 函数通过“分发”(Dispatch)和“等待”(Wait)两个步骤,精确地控制了**任务的并发执行和必要的同步**。 + +可以说,`FTickTaskManager` 是“战略层”,而 `FTickTaskSequencer` 则是“战术层”。它处理了所有最棘手的并发、同步和性能优化细节,是 UE Tick 机制能够高性能运行的真正幕后功臣。 + +### 2.2.4 FTickTaskLevel + +> **源码文件**:`Source\\Runtime\\Engine\\Private\\TickTaskManager.cpp` + +`FTickTaskLevel` 可以被理解为 **一个 `ULevel` 中所有 `FTickFunction` 的“账本”或“花名册”**。它的核心职责是**管理隶属于单个 `ULevel` 的所有 Tick 任务**,并对它们进行分类、预处理,为上层的 `FTickTaskManager` 提供干净、有序的数据。 + +每一个`ULevel`对象内部都有一个指向`FTickTaskLevel`实例的指针(`Level->TickTaskLevel`),这构成了`FTickTaskManager`按 Level 组织 Tick 任务的基础。 + +--- + +1. **核心成员变量** + +这是 `FTickTaskLevel` 用来分类和管理 `FTickFunction` 的内部容器。 + +```cpp +// 对全局Sequencer的引用,方便直接调用 +FTickTaskSequencer& TickTaskSequencer; + +// 【关键】存储所有明确启用的、需要每帧Tick的函数。TSet保证了不重复。 +TSet AllEnabledTickFunctions; + +// 【关键】一个自定义的链表,用于存储所有设置了TickInterval且当前处于“冷却”状态的函数。 +FCoolingDownTickFunctionList AllCoolingDownTickFunctions; + +// 存储所有明确禁用的Tick函数。 +TSet AllDisabledTickFunctions; + +// 临时数组,用于存放本帧结束后需要重新计算冷却时间的Tick函数。 +TArrayWithThreadsafeAdd TickFunctionsToReschedule; + +// 存储在本帧Tick期间新生成的Tick函数。 +TSet NewlySpawnedTickFunctions; + +// 当前帧的Tick上下文 +FTickContext Context; + +// 是否处于Tick流程中的标志 +bool bTickNewlySpawned; +``` + +**分析:** + +- `FTickTaskLevel` 的核心就是这**四大容器**:`AllEnabledTickFunctions`, `AllCoolingDownTickFunctions`, `AllDisabledTickFunctions`, 和 `NewlySpawnedTickFunctions`。它将一个 Level 内的所有 Tick 函数分门别类地进行管理。 +- **`AllCoolingDownTickFunctions`** 的链表结构设计非常巧妙。因为它需要处理基于`DeltaTime`的动态激活,链表结构比数组或集合更适合进行高效的遍历和中间节点的移除。 +- `TickFunctionsToReschedule` 和 `NewlySpawnedTickFunctions` 是**临时性**的容器,用于处理帧内的状态变化,体现了其逻辑的严谨性。 + +--- + +1. **核心函数**: + + + + + + + + + +--- + +**总结**: + +![FTickTaskLevel 数据组织与工作流](attachment:7280ffcf-e8ba-4fb7-a182-3a9f9fd1b764:Editor___Mermaid_Chart-2025-06-11-132305.png) + +FTickTaskLevel 数据组织与工作流 + +`FTickTaskLevel` 是一个**面向单个`ULevel`的、高度特化的 Tick 任务管理器**。它的存在体现了 UE 设计的**分而治之**思想。 + +- **数据组织者:** 它将一个`ULevel`中成百上千的 Tick 函数,通过`TSet`和自定义链表,分门别类地管理起来,极大地降低了上层`FTickTaskManager`的管理复杂度。 +- **预处理器:** 它在`StartFrame`阶段就独立处理完了复杂的`TickInterval`逻辑,为主调度器提供了干净、明确的“待办事项列表”。 +- **执行委托者:** 它通过调用`FTickFunction::QueueTickFunction`,将最终的排队任务委托出去,自身不直接与`FTickTaskSequencer`深度耦合。 + +通过引入`FTickTaskLevel`这一中间层,UE 的 Tick 系统架构变得更加清晰、模块化,并且能够与关卡流送系统完美协同工作。 + +## 2.3 调用上下文 + +### 2.3.1 UWorld::Tick + +> **源码文件**:`Source\\Runtime\\Engine\\Private\\LevelTick.cpp` + +`UWorld::Tick` 的源码虽然冗长,但我们只需要聚焦于它与 `FTickTaskManager` 直接交互的**三个关键阶段**,就能清晰地看到 `FTickTaskManager` 是如何被驱动的。 + +--- + +1. **第一阶段:`StartFrame` - 规划与准备** + +在 `UWorld::Tick` 的核心循环中,当确定了本帧需要进行 Actor Tick (`bDoingActorTicks` 为 `true`) 之后,第一件重要的事情就是调用 `FTickTaskManager` 的 `StartFrame` 方法。 + +```cpp +// in UWorld::Tick, inside the main for-loop over LevelCollections + +if (bDoingActorTicks) +{ + // ... + TickGroup = TG_PrePhysics; // 重置世界的当前Tick组 + + // 【关键调用 1】通知TickTaskManager开始新的一帧 + FTickTaskManagerInterface::Get().StartFrame(this, DeltaSeconds, TickType, LevelsToTick); + + // ... 后续的RunTickGroup调用 ... +} +``` + +**上下文剖析:** + +1. **时机:** 这个调用发生在所有 `RunTickGroup` **之前**。 +2. **传递的参数:** + - `this` (`UWorld*`): 告诉 `FTickTaskManager` 当前工作的世界是哪一个。 + - `DeltaSeconds`, `TickType`: 传递本帧的时间和Tick类型上下文。 + - `LevelsToTick`: 一个 `TArray`,明确告知 `FTickTaskManager` **本帧只需要考虑这些 `ULevel` 中的 Tick 任务**。这对于关卡流送至关重要,它避免了对已卸载或隐藏的 Level 进行不必要的工作。 +3. **作用:** `UWorld` 在这里扮演了**“信息提供者”**和**“启动者”**的角色。它将所有必要的上下文信息打包好,然后按下 `FTickTaskManager` 的“启动按钮”。`StartFrame` 接收到指令后,会执行我们之前分析过的内部逻辑:收集所有相关Level的Tick函数,并构建本帧的任务依赖图。 + +--- + +1. **第二阶段:`RunTickGroup` - 按部就班地执行** + +在 `StartFrame` 完成规划后,`UWorld::Tick` 进入了一个高度结构化的执行阶段,它像一个严谨的工序流程单,依次调用 `RunTickGroup`。 + +```cpp +// in UWorld::Tick, right after StartFrame + +// 【关键调用 2】按严格顺序执行每个Tick组 +{ SCOPE_CYCLE_COUNTER(STAT_TG_PrePhysics); RunTickGroup(TG_PrePhysics); } +EnsureCollisionTreeIsBuilt(); +{ SCOPE_CYCLE_COUNTER(STAT_TG_StartPhysics); RunTickGroup(TG_StartPhysics); } +{ SCOPE_CYCLE_COUNTER(STAT_TG_DuringPhysics); RunTickGroup(TG_DuringPhysics, false); } +// ... +{ SCOPE_CYCLE_COUNTER(STAT_TG_EndPhysics); RunTickGroup(TG_EndPhysics); } +{ SCOPE_CYCLE_COUNTER(STAT_TG_PostPhysics); RunTickGroup(TG_PostPhysics); } +// ... +{ SCOPE_CYCLE_COUNTER(STAT_TG_PostUpdateWork); RunTickGroup(TG_PostUpdateWork); } +{ SCOPE_CYCLE_COUNTER(STAT_TG_LastDemotable); RunTickGroup(TG_LastDemotable); } +``` + +**上下文剖析:** + +1. **严格的顺序:** `UWorld` **硬编码**了 `RunTickGroup` 的调用顺序,从 `TG_PrePhysics` 一直到 `TG_LastDemotable`。这从根本上保证了不同阶段任务的执行顺序,是整个 Tick 依赖系统能够正常工作的基础。 +2. **阻塞与非阻塞:** + - 大部分 `RunTickGroup` 调用(如 `TG_PrePhysics`, `TG_EndPhysics`)都使用了默认的 `bBlockTillComplete = true` 参数。这意味着 `UWorld` 的执行流会在这里**暂停**,直到该 Tick 组的所有任务完成。这是实现**同步点**的关键。 + - `RunTickGroup(TG_DuringPhysics, false)` 是一个特例。`false` 参数告诉 `UWorld` **不要等待**物理模拟完成。这使得游戏主线程可以在物理计算在后台线程进行的同时,继续执行其他工作,从而实现了**并发**,提升了性能。 +3. **作用:** `UWorld` 在这里扮演了**“工序调度员”**的角色。它不关心每个`TickGroup`内部具体有哪些任务,只负责按照预设的蓝图,一步步地命令 `FTickTaskManager`去执行每一个工序。 + +--- + +1. **第三阶段:`EndFrame` - 清理与收尾** + +在所有 `RunTickGroup` 都执行完毕后,`UWorld::Tick` 会调用 `FTickTaskManager` 的 `EndFrame` 来结束本帧的 Tick 调度。 + +```cpp +// in UWorld::Tick, after all RunTickGroup calls + +if (bDoingActorTicks) +{ + // ... + // 【关键调用 3】通知TickTaskManager本帧的Tick调度工作全部结束 + FTickTaskManagerInterface::Get().EndFrame(); +} +``` + +**上下文剖析:** + +1. **时机:** 这个调用发生在所有 `RunTickGroup` **之后**。 +2. **作用:** `UWorld` 在这里发出一个**“收工”**的信号。`FTickTaskManager` 接收到后,会执行其内部的清理逻辑,如重置状态、清空临时容器等,为下一帧做好准备。 + +--- + +**总结**: + +![UWorld::Tick 与 FTickTaskManager 交互时序图](attachment:de5ca54d-82ca-4c26-bf55-01f5e0c0f00c:Editor___Mermaid_Chart-2025-06-11-133444.png) + +UWorld::Tick 与 FTickTaskManager 交互时序图 + +从 `UWorld::Tick` 这个调用上下文的视角来看,`FTickTaskManager` 并非一个自我驱动的系统,而是一个**被动响应的、服务于 `UWorld` 的高级工具**。 + +- `UWorld` 负责**定义“做什么”和“按什么顺序做”**(提供 LevelsToTick,按序调用 RunTickGroup)。 +- `FTickTaskManager` 负责**解决“如何高效、正确地做”**(收集任务、解析依赖、并行执行)。 + +这种清晰的**职责分离**是 UE 架构设计的精髓。`UWorld` 掌握着宏观的、游戏逻辑驱动的流程控制,而 `FTickTaskManager` 则封装了所有复杂的、与具体游戏逻辑无关的底层调度技术。 + +### 2.3.2 AActor + +> **源码文件**:`Source\\Runtime\\Engine\\Private\\Actor.cpp` + +`AActor` 是整个 Tick 调度系统最主要的服务对象。引擎为`AActor`提供了一套封装良好、易于使用的 API,让游戏开发者可以在不了解`FTickTaskManager`复杂实现的情况下,方便地控制 Actor 的 Tick 行为。 + +--- + +1. **注册与注销:`RegisterAllActorTickFunctions`** + - **函数:** `void AActor::RegisterAllActorTickFunctions(bool bRegister, bool bDoComponents)` + + - **调用时机:** + + - `bRegister = true`: 当Actor被创建并添加到世界时(如通过 `SpawnActor` 或关卡加载)。 + - `bRegister = false`: 当Actor被销毁时。 + - **源码剖析:** + + ```cpp + void AActor::RegisterAllActorTickFunctions(bool bRegister, bool bDoComponents) + { + // ... + // 防止重复注册/注销 + if (bTickFunctionsRegistered != bRegister) + { + // 【关键】调用RegisterActorTickFunctions来处理自身的PrimaryActorTick + RegisterActorTickFunctions(bRegister); + bTickFunctionsRegistered = bRegister; + // ... + } + + if (bDoComponents) + { + // 递归地为所有子组件也执行注册/注销 + for (UActorComponent* Component : GetComponents()) + { + if (Component) + { + Component->RegisterAllComponentTickFunctions(bRegister); + } + } + } + // ... + } + ``` + + ```cpp + void AActor::RegisterActorTickFunctions(bool bRegister) + { + if(bRegister) + { + if(PrimaryActorTick.bCanEverTick) + { + // 1. 设置Target,让FActorTickFunction知道要Tick哪个Actor + PrimaryActorTick.Target = this; + // 2. 设置初始启用状态 + PrimaryActorTick.SetTickFunctionEnable(...); + // 3. 【核心调用】将自身的PrimaryActorTick注册到其所在Level的FTickTaskLevel中 + PrimaryActorTick.RegisterTickFunction(GetLevel()); + } + } + else + { + if(PrimaryActorTick.IsTickFunctionRegistered()) + { + // 【核心调用】从管理器中注销 + PrimaryActorTick.UnRegisterTickFunction(); + } + } + } + ``` + + - **上下文剖析:** + + - 这是`AActor`与`FTickTaskManager`的**第一次握手**。当一个 Actor 诞生时,`RegisterAllActorTickFunctions`会被调用。 + - 它首先通过调用`RegisterActorTickFunctions`,将自己的`PrimaryActorTick`(一个`FActorTickFunction`实例)注册到调度系统中。 + - `PrimaryActorTick.RegisterTickFunction(GetLevel())` 这个调用最终会触发 `FTickTaskManager::AddTickFunction`,将这个Tick任务添加到正确的`FTickTaskLevel`中。 + - 同时,它还会递归地为所有子组件执行相同的操作,确保整个Actor及其所有部分的Tick都能被正确管理。 + +--- + +1. **执行 Tick 逻辑:从`ExecuteTick`到`AActor::Tick`** + - **函数:** `void FActorTickFunction::ExecuteTick(...)` + + - **调用时机:** 当`FTickTaskSequencer`通过`Task Graph`执行这个`FActorTickFunction`对应的任务时。 + + - **源码剖析:**`AActor::TickActor`是一个内部函数,它会进一步调用我们熟悉的`AActor::Tick`。 + + ```cpp + void FActorTickFunction::ExecuteTick(float DeltaTime, ...) + { + if (IsValid(Target)) // Target就是之前注册时设置的AActor* + { + // ... + // 【关键】调用Actor自身的TickActor方法 + Target->TickActor(DeltaTime*Target->CustomTimeDilation, TickType, *this); + } + } + ``` + + ```cpp + void AActor::Tick( float DeltaSeconds ) + { + // 如果是蓝图Actor,调用其蓝图事件图中的Tick事件 + if (/* 是蓝图 */) + { + ReceiveTick(DeltaSeconds); + } + // ... + // 处理该Actor的Latent Actions + LatentActionManager.ProcessLatentActions(this, ...); + } + ``` + + - **上下文剖析:** + + - 这里展示了**从底层调度到上层逻辑的完整调用链**。 + - `FTickTaskSequencer` 并不知道`AActor`的存在,它只知道执行一个`FTickFunction`的`ExecuteTick`虚函数。 + - `FActorTickFunction` 作为派生类,在`ExecuteTick`的实现中,调用了其`Target`(即`AActor`实例)的`Tick`方法。 + - 最终,控制权传递到了我们游戏开发者所编写的C++ `Tick`函数或蓝图的`Event Tick`节点。这是一个典型的**策略模式**和**多态**的应用。 + +--- + +1. **动态控制 API:`SetActorTickEnabled`及其伙伴** + - **函数:** `SetActorTickEnabled`, `SetActorTickInterval`, `SetTickGroup`, `AddTickPrerequisiteActor`等。 + + - **调用时机:** 在游戏运行时的任何时候,由开发者根据逻辑需要调用。 + + - **源码剖析:** + + ```cpp + void AActor::SetActorTickEnabled(bool bEnabled) + { + // 直接调用其PrimaryActorTick的API + PrimaryActorTick.SetTickFunctionEnable(bEnabled); + } + + void AActor::AddTickPrerequisiteActor(AActor* PrerequisiteActor) + { + // 将对Actor的依赖,翻译成对该Actor的PrimaryActorTick的依赖 + PrimaryActorTick.AddPrerequisite(PrerequisiteActor, PrerequisiteActor->PrimaryActorTick); + } + ``` + + - **上下文剖析:** + + - `AActor` 提供的这一整套API,本质上都是对其内部成员`PrimaryActorTick`的**简单封装**。 + - 这种设计非常优雅。它为上层开发者提供了简洁、易于理解的接口(`SetActorTickEnabled`),同时将所有与底层调度系统交互的复杂性都**隐藏**在了`FTickFunction`的实现内部。 + - 开发者只需要与`AActor`打交道,而无需关心`FTickFunction`、`FTickTaskManager`这些底层细节,这大大降低了使用的门槛。 + +--- + +**总结**: + +![AActor 与 Tick 系统的交互](attachment:77dae94b-ae07-434b-8118-2e4366fb884a:Editor___Mermaid_Chart-2025-06-11-140839.png) + +AActor 与 Tick 系统的交互 + +`AActor` 作为 Tick 系统的主要**“客户端”**,通过以下方式与调度系统交互: + +1. **生命周期绑定:** 在创建和销毁时,通过`RegisterAllActorTickFunctions`来**订阅/退订** Tick 服务。 +2. **执行回调:** 通过`FActorTickFunction`这个**适配器(Adapter)**,让底层的`ExecuteTick`调用能够最终触发到上层的`AActor::Tick`逻辑。 +3. **接口封装:** 提供了一系列简洁的 API,将对`FTickFunction`属性的修改**封装**起来,为开发者提供了便利。 + +### 2.3.3 UActorComponent + +> **源码文件**:`Source\\Runtime\\Engine\\Private\\Components\\ActorComponent.cpp` + +`UActorComponent` 作为 Actor 功能的载体,同样需要与底层的 Tick 调度系统进行交互。它的实现方式与`AActor`如出一辙,都是通过**封装**其内部的`FTickFunction`派生实例(`FActorComponentTickFunction`)来提供 API。 + +--- + +1. **注册与注销:`RegisterAllComponentTickFunctions`** + - **函数:** `void UActorComponent::RegisterAllComponentTickFunctions(bool bRegister)` + + - **调用时机:** 这个函数通常由其所属的`AActor`在`RegisterAllActorTickFunctions`中递归调用。 + + - **源码剖析:** + + ```cpp + void UActorComponent::RegisterAllComponentTickFunctions(bool bRegister) + { + // 只有当组件已经注册到世界后,才能注册其Tick函数 + if (bRegistered) + { + // ... 防止重复注册/注销 ... + if (bTickFunctionsRegistered != bRegister) + { + // 【关键】调用RegisterComponentTickFunctions来处理自身的PrimaryComponentTick + RegisterComponentTickFunctions(bRegister); + bTickFunctionsRegistered = bRegister; + // ... + } + } + } + ``` + + ```cpp + void UActorComponent::RegisterComponentTickFunctions(bool bRegister) + { + if(bRegister) + { + // 【核心调用】SetupActorComponentTickFunction是注册逻辑的核心 + if (SetupActorComponentTickFunction(&PrimaryComponentTick)) + { + // 设置Target,让FPrimaryComponentTickFunction知道要Tick哪个Component + PrimaryComponentTick.Target = this; + } + } + else + { + // ... 注销逻辑 ... + } + } + ``` + + ```cpp + bool UActorComponent::SetupActorComponentTickFunction(struct FTickFunction* TickFunction) + { + if(TickFunction->bCanEverTick && !IsTemplate()) + { + // ... + // 【核心调用】最终还是调用FTickFunction的RegisterTickFunction + TickFunction->RegisterTickFunction(ComponentLevel); + return true; + } + return false; + } + ``` + + - **上下文剖析:** + + - 流程与`AActor`高度相似:`RegisterAll...` -> `Register...` -> `Setup...` -> `FTickFunction::RegisterTickFunction`。 + - 一个重要的区别是,Component 的 Tick 注册有一个前提条件:`if (bRegistered)`,即**组件必须先附加到 Actor 并注册到世界中**,然后才能注册它的 Tick。这体现了 Component 对 Actor 的从属关系。 + - 最终,它同样是通过调用`FTickFunction`的公共 API `RegisterTickFunction`,将自己注册到`FTickTaskManager`中。 + +--- + +1. **执行 Tick 逻辑:从`ExecuteTick`到`UActorComponent::TickComponent`** + - **函数:** `void FActorComponentTickFunction::ExecuteTick(...)` + + - **调用时机:** 当`FTickTaskSequencer`执行这个`FPrimaryComponentTickFunction`对应的任务时。 + + - **源码剖析:** + + ```cpp + void FActorComponentTickFunction::ExecuteTick(float DeltaTime, ...) + { + // ... + // 【关键】ExecuteTickHelper是一个辅助函数,最终会调用下面的Lambda + ExecuteTickHelper(Target, ..., [this, TickType](float DilatedTime) + { + // 在Lambda中,调用Component自身的TickComponent方法 + Target->TickComponent(DilatedTime, TickType, this); + }); + } + ``` + + ```cpp + void UActorComponent::TickComponent(float DeltaTime, ...) + { + // ... + // 如果是蓝图组件,调用其蓝图事件图中的Tick事件 + if (/* 是蓝图 */) + { + ReceiveTick(DeltaTime); + } + // ... 处理Latent Actions ... + } + ``` + + - **上下文剖析:** + + - 这再次展示了从底层调度到上层逻辑的**回调机制**。 + - `FTickTaskSequencer` 调用 `FActorComponentTickFunction::ExecuteTick`。 + - `ExecuteTick` 内部通过其 `Target` 指针,最终调用到我们为组件编写的 `TickComponent` 函数或蓝图的 `Event Tick` 节点。 + - 这种设计模式的复用,使得 Actor 和 Component 在 Tick 执行层面遵循着完全一致的逻辑。 + +--- + +1. **动态控制 API:一系列`Set...`和`Add...`函数** + - **函数:** `SetComponentTickEnabled`, `SetTickGroup`, `AddTickPrerequisiteComponent`等。 + + - **调用时机:** 游戏运行时,由开发者调用。 + + - **源码剖析:** + + ```cpp + void UActorComponent::SetComponentTickEnabled(bool bEnabled) + { + // 直接调用其PrimaryComponentTick的API + PrimaryComponentTick.SetTickFunctionEnable(bEnabled); + } + + void UActorComponent::AddTickPrerequisiteComponent(UActorComponent* PrerequisiteComponent) + { + // 将对Component的依赖,翻译成对该Component的PrimaryComponentTick的依赖 + PrimaryComponentTick.AddPrerequisite(PrerequisiteComponent, PrerequisiteComponent->PrimaryComponentTick); + } + ``` + + - **上下文剖析:** + + - 与`AActor`的设计**完全一致**。所有这些上层 API 都是对内部成员`PrimaryComponentTick`(一个`FPrimaryComponentTickFunction`实例)的**简单、直接的封装**。 + - 这种一致性极大地降低了开发者的学习成本。一旦你学会了如何控制 Actor 的 Tick,你就自然而然地学会了如何控制 Component 的 Tick。 + +--- + +**结论**: + +![UActorComponent 与 Tick 系统的交互](attachment:f40fd509-be3a-4923-a41d-6cdaa7510b75:Editor___Mermaid_Chart-2025-06-11-142214.png) + +UActorComponent 与 Tick 系统的交互 + +通过剖析`UActorComponent`的上下文,我们可以得出结论: + +`UActorComponent`在与 Tick 系统交互方面,是**`AActor`设计模式的完美复刻**。它同样通过**生命周期绑定**、**执行回调**和**接口封装**这三大手段,实现了与底层`FTickTaskManager`的解耦和交互。 + +这种高度一致的设计,体现了 UE 在 API 设计上的**泛化和复用**思想。它将`Tick`的能力从一个宏观的`AActor`,下放到了更细粒度的、可组合的`UActorComponent`上,同时保持了接口的统一和简洁。这使得开发者可以像组装乐高积木一样,为 Actor 添加各种带有独立更新逻辑的功能模块,而无需关心它们底层的调度细节。 + +# 三、总结 + +经过对`FTickTaskManager`从宏观定位、核心数据结构,到内部实现,再到外部调用上下文的逐层剖析,我们已经相对完整地构建了 UE 核心 Tick 调度系统的全貌。 + +## 3.1 设计思想:FTickTaskManager 如何解决复杂性 + +`FTickTaskManager` 的核心设计,可以归结为对**“分层、委托与解耦”**这一软件工程黄金法则的极致应用。它通过以下三个层面的设计,成功地将一个极其复杂的调度问题分解为多个可控的子问题: + +1. **宏观分层(`UWorld` vs. `FTickTaskManager`):** `UWorld` 作为“战略层”,只负责定义“做什么”(提供Tick上下文)和“按什么顺序做”(按序调用`RunTickGroup`)。而`FTickTaskManager`作为“战术层”,则完全封装了“如何高效正确地做”的所有技术细节。这种职责分离,使得游戏逻辑与底层调度技术彻底解耦。 +2. **中观委托(`FTickTaskManager` vs. `FTickTaskSequencer`):** `FTickTaskManager` 自身也并非单体,它将更底层的、与`Task Graph`系统直接交互的任务排序、依赖解析和并发提交工作,进一步委托给了内部的`FTickTaskSequencer`。这使得`FTickTaskManager`可以更专注于高层的管理和接口封装,而`FTickTaskSequencer`则可以专注于性能极致的调度算法。 +3. **微观组织(`FTickTaskManager` vs. `FTickTaskLevel`):** `FTickTaskManager` 并没有采用一个巨大的全局列表来管理所有Tick任务,而是创造性地通过`FTickTaskLevel`,将任务**按`ULevel`进行分组**。这种“分而治之”的策略,不仅极大地提升了管理效率,更与 UE 的关卡流送(Level Streaming)机制完美契合,使得动态加载和卸载关卡时的 Tick 管理变得轻而易举。 + +## 3.2 性能考量:为何它比简单的循环更高效 + +`FTickTaskManager` 的高性能源于其对两大性能瓶颈的精准打击: + +1. **依赖解析与拓扑排序:** 通过`FTickPrerequisite`和对依赖图的构建,`FTickTaskManager`解决了任务间的执行顺序问题。它能够生成一个保证逻辑正确的**拓扑排序**,这是高性能调度的前提。 +2. **并发执行:** 它的真正威力在于,在保证了依赖关系的前提下,能够识别出依赖图中所有**可以并行执行**的任务(那些没有前置依赖的节点),并将它们打包成`FGraphEvent`,提交给底层的`Task Graph`系统。由`Task Graph`将这些任务分发到多个 CPU 核心上同时运行,从而将原本漫长的串行`for`循环,变成了一个高效的并行计算过程,极大地缩短了帧时间。 + +## 3.3 启示:如何更好地利用 Tick 系统 + +通过本次剖析,我们作为上层开发者可以得到以下重要启示: + +1. **善用`TickGroup`:** 理解并善用`TickGroup`是编写健壮、无抖动逻辑的第一步。 +2. **巧用`AddPrerequisite`:** 当 Actor 或 Component 之间存在明确的逻辑先后关系时,使用`AddTickPrerequisite`来明确声明这种依赖,而不是依赖于不确定的执行顺序或使用延迟等“魔法”手段。 +3. **为性能优化着想:** 对于那些不依赖游戏线程数据、纯计算密集型的 Tick 逻辑,可以考虑将其封装并尝试开启`bRunOnAnyThread`(需谨慎评估线程安全),以充分利用引擎的并行调度能力。 + +![FTickTaskManager 机制总结](attachment:3ef28401-8182-47c8-8d55-700873bf47b9:Mermaid_Chart_-_Create_complex_visual_diagrams_with_text._A_smarter_way_of_creating_diagrams.-2025-06-11-144606.png) + +FTickTaskManager 机制总结 + +总而言之,`FTickTaskManager` 是 UE 工程智慧的集中体现。它不仅仅是一个功能模块,更是一套解决大规模实时系统中任务调度问题的完整方案。 \ No newline at end of file diff --git a/3Projects/Unity/Log插件/Log插件.md b/3Projects/Unity/Log插件/Log插件.md new file mode 100644 index 0000000..6b537a6 --- /dev/null +++ b/3Projects/Unity/Log插件/Log插件.md @@ -0,0 +1,153 @@ + +source:[加Log就卡?不加Log就瞎?”——这个插件治好了我的精神内耗](https://mp.weixin.qq.com/s/Nii4fC15eKoNN8MOAzrmDQ) + +--- + + +# + +- 1 现有日志打印情况 + + +- 1 日志阻塞 + +- 2 从调试到生产,日志策略的抉择 + + +- 2 问题出现原因 + + +- 2.1 日志打印原理分析 + +- 2.2 log4j2 Disruptor 的初始化 + +- 2.3 队列满导致日志阻塞 + +- 2.4 产生的根本原因 + + +- 3 应对方案 + + +- 3.1 方案选择 + +- 3.2 技术选择 + +- 3.3 落地实现 + + +- 4 总结 + + + + +## 1 现有日志打印情况 + +  日志作为软件工程实践中的重要基础设施,在系统监控、异常诊断及行为追溯等关键环节发挥着不可替代的作用。Apache Log4j2作为当前主流的日志框架,凭借其模块化架构和高度可扩展的特性,为开发者提供了灵活的多维度日志管理方案。然而若未能深入理解其异步日志机制、缓冲区策略等核心原理,或存在配置参数与业务场景匹配度不足等问题,则可能导致日志I/O阻塞、内存资源过度消耗等负面效应,甚至引发严重的服务性能瓶颈。因此,在实际工程实践中需遵循科学合理的使用准则,通过日志分级管理、输出格式优化、滚动策略定制等手段,方能充分发挥其技术优势,有效规避潜在风险。 + +### 1 日志阻塞 + +  日志导致线程Block的问题,相信你或许已经遇到过,对此应该深有体会;或许你还没遇到过,但不代表没有问题,只是可能还没有触发而已。常见的现象是出现大量的block线程,查看jstack常常是下图现象:![图片](https://mmbiz.qpic.cn/mmbiz_png/dHUzltsJpQsMHUpibOgSB9tj4iaVbseaZHIR2NAfdDEgKBvNfWKcAd1jXHF2qRU1ibbNA8jIMaTs5hrlGibj02kiblg/640?wx_fmt=png&from=appmsg&tp=webp&wxfrom=5&wx_lazy=1) + +### 2 从调试到生产,日志策略的抉择 + +  在软件项目的全生命周期中,从开发阶段到生产环境的演进过程中,日志管理往往面临着微妙的平衡。开发阶段我们倾向于采用详尽的日志策略:业务接口的入参出参被完整记录,跨系统的调用链路被清晰标注,甚至非核心逻辑的辅助性信息也得以留存——这些详实的日志如同开发者的双目,为联调排障与功能验证提供了不可或缺的洞察。 + +  然而当服务迈向生产环境时,过度日志带来的问题便逐渐显现。冗余的调试信息不仅会影响系统性能,更可能淹没真正关键的业务轨迹。尽管我们尝试在上线前进行日志裁剪,但总存在令人踌躇的灰色地带:某些开发期辅助日志是否暗含未来的诊断价值?那些看似非核心的流程记录会否在某个异常场景下成为关键线索?这种取舍的困境,本质上反映了我们对系统可观测性与运行效能之间永续的权衡。 + +## 2 问题出现原因 + +### 2.1 日志打印原理分析 + +  在我们使用的log4j的应用中采用的是异步日志配置,简单的说明一下一条日志打印在log4j中的处理流程如下图所示:![图片](https://mmbiz.qpic.cn/mmbiz_png/dHUzltsJpQsMHUpibOgSB9tj4iaVbseaZHwWGYn7OQfa7tNica1TerbgEjIP0VNJnNbpGlKdAvCic5Lbk0sTCNElTw/640?wx_fmt=png&from=appmsg&tp=webp&wxfrom=5&wx_lazy=1)  简单点来说,就是多线程通过 log4j2 的门面类进行日志的打印,日志经过一系列的处理(过滤,包装)后放入到Disruptor的环形 buffer 中,在服务器的消费端会单启一个线程进行这些日志的消费,最终放入到我们指定的文件中。 + +### 2.2 log4j2 Disruptor 的初始化 + +  当LoggerContext启动时,所有AsyncLoggerConfig会通过start()方法初始化其Disruptor:![图片](https://mmbiz.qpic.cn/mmbiz_png/dHUzltsJpQsMHUpibOgSB9tj4iaVbseaZHvaPOfupg1o0Wnb2HpqzUewncx7ibHiczTLJdCq6Na2yopKYxZ3thu14w/640?wx_fmt=png&from=appmsg&tp=webp&wxfrom=5&wx_lazy=1)  其中Disruptor 是一个环形 buffer,官方做了很多的性能优化,这里有兴趣的可以了解其实现原理,这里不进行深入的讨论,其中在我们的应用log4j.xml配置中,没对RingBuffer进行自定义的配置,使用的是默认的大小256K。 + +### 2.3 队列满导致日志阻塞 + +  Disruptor 的 RingBuffer 是一个固定大小的环形队列,其发布逻辑:![图片](https://mmbiz.qpic.cn/mmbiz_png/dHUzltsJpQsMHUpibOgSB9tj4iaVbseaZHiav0RIpxia6HI61Y86ohwoyxYkic8Zsiaj6CygPU5PEibrVuEMC7kialgKWg/640?wx_fmt=png&from=appmsg&tp=webp&wxfrom=5&wx_lazy=1) + +  队列满时的默认行为:AsyncLoggerConfig.SynchronizeEnqueueWhenQueueFull=true,此时会等待着消费出下一个可以生产的环形 buffer 槽;此时所有打印日志的线程会尝试获取全局锁。此时会阻塞线程,也就是我们上述堆栈中看到的异常。 + +### 2.4 产生的根本原因 + +  生产者速度 > 消费者速度: + +  AsyncAppender 的后台线程从队列中取出事件并交给实际 Appender(如 FileAppender)处理,如果实际 Appender 的写入速度慢(如磁盘 I/O 高),消费者线程无法及时清空队列,导致队列积压。其实log4j消费时会调用多次 flush,这些flush的调用根本在文件写入的 native 调用,当这种native调用太多时,系统写入不过来。 + +## 3 应对方案 + +### 3.1 方案选择 + +  上述问题情况解决,大致分成两个方向:生产者方向&消费者方向,具体行为如下图简述:![图片](https://mmbiz.qpic.cn/mmbiz_png/dHUzltsJpQsMHUpibOgSB9tj4iaVbseaZHWnueNI4rlREl0V3JSEtRDC1ibkpR4jhZ2XqMFbrsqiarajepynlCIvfA/640?wx_fmt=png&from=appmsg&tp=webp&wxfrom=5&wx_lazy=1)  在应对日志管理的挑战时,除了调整日志队列容量等基础优化(需警惕OOM风险),更核心的问题在于如何平衡日志的详实性与系统稳定性。开发者往往陷入两难:若详尽记录日志,可能引发阻塞风险;若过度精简,则排查问题时如盲人摸象,难溯根源。 + +为此,可考虑将日志划分为两类: + +功能日志(必须):如埋点数据、核心流程记录,确保业务可观测性; + +业务排查日志(非必须):如RPC入参/出参、调试断点等,按需动态启停; + +  通过这种分层策略,既能在高并发场景下保障核心日志的稳定输出,又能灵活控制辅助日志的打印量,使系统整体具备更强的适应性与可控性。如此,我们既能从容应对生产环境的严苛要求,又能在需要时快速激活详尽的诊断信息,实现运维效率与系统性能的兼得。 + +### 3.2 技术选择 + +  在日志打印的精细化控制中,核心在于灵活性与精准度的平衡。传统的全局级别过滤(如INFO/WARN/ERROR)虽能粗放管理,却难以适配复杂多变的业务场景。理想的方案应突破层级限制,实现行级细粒度控制——无论是核心链路的关键节点,还是特定业务场景的临时调试,均可针对单行日志动态启停。 + +  这种设计赋予开发者更高的自主权:业务视角:按需捕获特定模块的完整上下文;链路视角:精准聚焦某次调用的全生命周期轨迹;应急场景:即时激活深层诊断日志,无需重启或改码。 + +  通过将控制粒度细化至代码行,我们既能维持生产环境的日志精简,又能随时按业务诉求“点亮”关键路径,使系统可观测性兼具严谨与弹性。 + +#### 3.2.1 区分必要日志和非必要日志打印: + + 自定义封装日志打印的方式如下图所示:![图片](https://mmbiz.qpic.cn/mmbiz_png/dHUzltsJpQsMHUpibOgSB9tj4iaVbseaZHvb9FLG3BmhibttKEy83BOWs8t7gXOdibkPicJaV18MVzicLUKlsO7a1nVQ/640?wx_fmt=png&from=appmsg&tp=webp&wxfrom=5&wx_lazy=1) + +#### 3.2.2 如何对非必要日志进行行级别控制 + + 1、自定义Appender中的filter: + +  在实现行级日志控制时,若需精确控制特定代码行(如第133行)的日志输出,采用自定义Appender过滤机制是一种可行方案。其核心思路在于:通过解析日志调用的堆栈信息,动态判断当前行号是否符合预设的打印条件,若不符合则直接过滤。 + +  然而,该方案存在若干固有局限: 堆栈解析的可靠性问题:Lambda表达式中的日志调用往往难以准确获取行号信息,即使通过堆栈缓存优化,仍存在定位失准的风险;性能损耗隐患:频繁的堆栈遍历操作会引入不可忽视的性能开销,在高并发场景下可能成为新的瓶颈;分类管理缺失:该机制难以与既有的日志分级体系(必需/非必需日志)形成有机协同,增加了运维复杂度。 + + 2、在打印日志前获取日志的行信息: + +  最简单的方式是人工的形式,在写日志的时候同时将日志的行信息写入进去,比如:![图片](https://mmbiz.qpic.cn/mmbiz_png/dHUzltsJpQsMHUpibOgSB9tj4iaVbseaZHeZpkYq1kU9e6CAgUu57X9iblfAWCDURp2yZhDkJN2HEcicND4nIiciaTLA/640?wx_fmt=png&from=appmsg&tp=webp&wxfrom=5&wx_lazy=1)这种方式在可扩展性和可观测性维度存在设计缺陷。 + + 3、在编译的时候获取日志的行信息: + +  我们想使用LogUtils.debug(()->log.info("业务日志"));这种方式,但是我们不会在代码中明显的写入,可以在代码编译期间将行信息获取到后使用字节码修改这行代码,利用Java的重写。将它转变成 LogUtils.debug("类+行",()->log.info("业务日志")); 然后再这个方法执行中进行条件判断。 + +字节码技术选择: +  ![图片](https://mmbiz.qpic.cn/mmbiz_png/dHUzltsJpQsMHUpibOgSB9tj4iaVbseaZHgVuiaHTK1MtAjYCibgrCVDZJ6oOyx4ac2R1O3CydMwX9fngib5diaWpnoQ/640?wx_fmt=png&from=appmsg&tp=webp&wxfrom=5&wx_lazy=1)  在本次实现中需要更灵活的方式操作字节码,还要考虑性能的问题,以及对应用框架的支持, 我们选择ASM的形式。 + +4、如何随心控制开启和关闭: + +  这里我们采用的是ider插件的方式,有idea插件上报我们的对这行日志的控制行为,如下图所示:![图片](https://mmbiz.qpic.cn/mmbiz_png/dHUzltsJpQsMHUpibOgSB9tj4iaVbseaZHNHrI1ibxujSAmoPy2AXYUx8PbdXEyDyl6cJWIJrOEvSaEWYNMcRerIw/640?wx_fmt=png&from=appmsg&tp=webp&wxfrom=5&wx_lazy=1) + +### 3.3 落地实现 + +#### 3.3.1 Maven编译插件 + +  目的:获取日志所在的类和行信息。 + +  运行时获取的方式:在 Logger 配置中启用 includeLocation,代码从 LogEvent通过堆栈分析获取行号。这种方式存在很大的弊端,堆栈跟踪生成开销很大,每次调用 getStackTrace() 时,JVM 需要遍历当前线程的调用栈,生成完整的堆栈信息,这是一个 同步且耗时 的操作(尤其在深调用链中),如果每秒有数万次日志调用,频繁生成堆栈跟踪可能导致 CPU 使用率飙升,直接影响吞吐量。 + +   Maven的process-classes阶段获取:通过Maven编译之后获取到字节码文件时,对字节码文件进行修改,存放日志的类和行信息。对运行期间无额外消耗。处理逻辑如下图所示:![图片](https://mmbiz.qpic.cn/mmbiz_png/dHUzltsJpQsMHUpibOgSB9tj4iaVbseaZHDvnxCOu4GPuag84E5dITibibdYwfVPKdRwMSIiby36Mb08YNX88CmAWLA/640?wx_fmt=png&from=appmsg&tp=webp&wxfrom=5&wx_lazy=1) + +#### 3.3.2 Idea插件 + +  目的:精准的控制某一行日志是否进行打印。 + +  利用Idea的插件能力,将我们对某一行日志的开启和关闭状态进行上报,整个过程不阻塞主线程,保持Idea操作流畅性。提供定时能力,保障线上我们可以更灵活的控制日志是否打印的状态。处理逻辑如下图所示;![图片](https://mmbiz.qpic.cn/mmbiz_png/dHUzltsJpQsMHUpibOgSB9tj4iaVbseaZHSqkWttkMvjV3ELwy9OKhHwrsz1msFA18D5vaOFneT1AJ7QkjtRWIPQ/640?wx_fmt=png&from=appmsg&tp=webp&wxfrom=5&wx_lazy=1) + +#### 3.3.3 整体流程 + +  使用方式:通过在项目中使用上述Maven插件对项目进行编译部署,使用Idea插件对目标日志的是否开启打印状态进行上报,存储状态采用的Apollo的能力,通过自定义打印工具类中对Apollo配置内容的分析,进一步做判断逻辑,最终将日志进行打印或者不打印。处理逻辑如下图所示:![图片](https://mmbiz.qpic.cn/mmbiz_png/dHUzltsJpQsMHUpibOgSB9tj4iaVbseaZHU1ibLCk1ZVPspwevm1y1AAX5QKibQ1nXKic2YKA3RWoDlxzlD5ibym8vMw/640?wx_fmt=png&from=appmsg&tp=webp&wxfrom=5&wx_lazy=1) + +## 4 总结 + +  在分布式系统日益复杂的今天,日志管理已从简单的信息记录演进为系统可观测性的核心支柱。本文揭示的日志阻塞与策略困境,折射出现代化服务在稳定性与可维护性之间的深层博弈。通过剖析Log4j2异步日志机制的内在原理,我们识别出队列积压导致线程阻塞的关键症结,并由此展开对日志治理体系的深度重构。 + +  本次优化方案突破传统日志分级思维的桎梏,创新性地提出双轨制日志管理体系:将日志划分为功能型与诊断型两类,前者确保核心业务脉络的持续可见,后者实现按需动态管控。通过编译期字节码增强技术,我们实现代码行级别的精准控制,配合IDE插件的可视化操作,使开发人员能够像调试断点般自由启停日志输出。这种"外科手术式"的日志管理,既避免了传统方案"一刀切"的弊端,又赋予系统在高负载场景下的弹性适应能力。 \ No newline at end of file diff --git a/3Projects/Unity/loxodon/loxodon-framework Public.md b/3Projects/Unity/loxodon/loxodon-framework Public.md index 841147b..7e4d377 100644 --- a/3Projects/Unity/loxodon/loxodon-framework Public.md +++ b/3Projects/Unity/loxodon/loxodon-framework Public.md @@ -3,3 +3,20 @@ Source:[loxodon-framework/Loxodon.Framework.TextUGUI at master · vovgou/loxodon-framework · GitHub](https://github.com/vovgou/loxodon-framework/tree/master/Loxodon.Framework.TextUGUI) --- + + +单向绑定 +``` csharp +[OnValueChanged(viewModel=>viewModel.hp, value=>string.Format("{0:D4}"))] +CustomText text; + +public class CustomText +{ + public Text text; + public void SetText(string str) + { + text.text = str; + } +} + +``` \ No newline at end of file diff --git a/InBox/自动化生成文档/docfx.md b/InBox/自动化生成文档/docfx.md deleted file mode 100644 index e69de29..0000000 diff --git a/InBox/自动化生成文档/uml.md b/InBox/自动化生成文档/uml.md deleted file mode 100644 index 75cab91..0000000 --- a/InBox/自动化生成文档/uml.md +++ /dev/null @@ -1 +0,0 @@ -[(2 封私信 / 4 条消息) UML类图太难画?试试这5款AI工具,一键搞定! - 知乎](https://zhuanlan.zhihu.com/p/1905656789493580115) \ No newline at end of file