Compare commits

..

22 Commits

Author SHA1 Message Date
lms
571e299642 [docs][fix]: 更新框架架构.md 全局入口描述与文档关联
- 描述改为全局分层入口,引导至各模块使用指南
- 删除 Lua/ILRuntime 过时改进点,改为 HybridCLR 说明
- 更新版本、日期和适用项目
- 修正移动后的文档关联路径

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-15 14:42:11 +08:00
lms
d3312e19cf [docs][fix]: 清理过时术语并重命名 70-AI工具扫描范围文档
- 实体系统注意事项标题避免与 Unity DOTS ECS 混淆
- 70-项目设置.md 重命名为 70-AI工具扫描范围.md
- 更新 00-项目概览/项目规则入口/README 中的链接文字

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-15 14:41:26 +08:00
lms
d31b49221e [docs][fix]: 补齐单文件模块状态字段与 MCP 维护 checklist
- 场景系统/数据配置框架/网络系统/Hotfix启动增加验证与当前状态
- 数据配置变更清单补充具体菜单/路径/命令
- 模块登记规则增加 README/使用指南/注意事项量化标准
- 模块文档模板明确 README 与使用指南分工
- MCP 使用规则维护要求改为 checklist

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-15 14:40:38 +08:00
lms
bdadfd5759 [hooks][fix]: 补全 workflow-check 检查并修正 AssetBundle 拼写
- 增加 UTF-8 输出编码设置
- 增加 Unity Assets/ 路径中文检查
- 增加未跟踪 Markdown 专项提示
- 修正 AssestBundle -> AssetBundle 拼写
- 细化 commit-module-mappings 中 entity/event/scene/network/skill/pool/ui/resource 映射

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-15 14:39:51 +08:00
lms
45046d8d96 [docs][refactor]: 拆分重复模块文档并提升框架架构为全局入口
- 技能系统/相机系统/内存对象管理 README 改为概览+导航
- 框架架构.md 由通用框架子目录提升为全局入口
- 更新日期、过时改进点和文档关联路径
- 10-架构说明.md 拆分通用框架与框架架构链接

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-15 14:39:16 +08:00
lms
fc23b75e95 [docs][fix]: 统一通用框架分类并补录第三方插件到模块索引
- 通用框架分类由项目框架改为核心框架
- 模块索引补录第三方插件并校准各模块状态
- 项目规则入口声明核心规则完整定义
- 20/40 规则文档中重复 Git 规则改为链接引用

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-15 14:35:48 +08:00
Shiliang
001d9e5ef5 【整合】 框架使用规则 2026-07-10 17:50:20 +08:00
lms
db0143be83 Merge remote changes: integrate MCP tools and resource refactor docs into framework
- Resolve directory rename conflict from old 03/06 dirs
- Move remote-added 资源加载重构方案.md into modules/frameworks/资源管理/
- Move remote-added 06_工具脚本/MCP工具 into modules/frameworks/编辑器工具/MCP工具/
- Keep Tools/CodexUnityMcp/ as MCP Server implementation
- Update README.md, modules/模块索引.md, and parent READMEs
- Add 文档关联 sections to new docs and fix old absolute paths

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-07 19:07:27 +08:00
lms
ee1ff7f444 [docs][refactor]: 将旧 01~06 中文教程合并整理为 modules/frameworks 文件夹结构
- 删除 01~05 旧中文教程目录
- 将 03 核心功能教程拆分为各 framework 模块的子文档
- 06 工具脚本移入 modules/frameworks/编辑器工具/UI工具/
- 非框架内容合并进 rules/20-开发规则.md 与 rules/40-工作流清单.md
- 更新所有交叉链接与文档关联表

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-07 18:36:15 +08:00
Shiliang
00dc784d32 UI 卸载 2026-07-06 17:03:30 +08:00
Shiliang
21db0c0b47 【更新】调整Codex Unity MCP使用规则 2026-07-03 15:59:14 +08:00
Shiliang
b213e39b28 【迁移】迁移Codex Unity MCP工具到UnityAI 2026-07-03 15:04:38 +08:00
Shiliang
5e5b9f8c80 docs: 添加通用技能系统使用指南文档
- 创建通用技能系统使用指南
- 更新README.md,添加对新文档的引用
2026-06-02 10:30:55 +08:00
Shiliang
12eff784eb docs: 添加Git提交注意事项文档
- 新增Git提交注意事项文档,明确默认操作路径为E:\AI\UnityAI
- 更新README.md,添加对新文档的引用
2026-06-02 10:20:01 +08:00
Shiliang
fc14440497 feat: 添加Unity Entities注意事项文档并更新README
- 新增UnityEntities注意事项.md文档,记录Unity Entities开发中的重要注意事项
- 更新README.md,添加对新文档的引用
- 按照项目目录结构整理文档位置
2026-06-02 10:16:04 +08:00
Shiliang
0c4a4b53ed 【新增】创建Entity文件夹及Entity开发指南文档,包含Entity分类、创建规范、生命周期、System-Model架构、属性系统、对象池等内容 2026-05-29 15:01:50 +08:00
Shiliang
da3f24b086 移除文档中的用户名信息 2026-05-27 17:27:33 +08:00
Shiliang
62c76dc52b 移除文档中的密码信息,改为本地配置说明 2026-05-27 17:26:32 +08:00
Shiliang
bc87ac4d9c 删除所有工具脚本中的测试菜单代码(Tools菜单下的测试项) 2026-05-27 16:51:51 +08:00
Shiliang
3404f89f93 1. 删除编辑器菜单测试部分(不对外开放);2. 修正反向转换描述(开发者调整后用于版本控制) 2026-05-27 16:50:06 +08:00
Shiliang
9da0d6179c 修正描述:1. 版本更新;2. 强调JSON配置是UI人员核心工作流程 2026-05-27 16:47:30 +08:00
Shiliang
36df43fd55 修正生命周期职责划分:BindEvent应放在OnRunAwake,ShowView放在OnOpen 2026-05-27 16:44:46 +08:00
81 changed files with 6477 additions and 1597 deletions

View File

@@ -1,106 +0,0 @@
# StrayFog 框架开发规范指南
## 一、开发前准备
### 1.1 核心概念理解
#### 1.1.1 框架层级关系
```
┌─────────────────────────────────────────────────────────────┐
│ 开发层级视图 │
├─────────────────────────────────────────────────────────────┤
│ 业务层 (你开发的代码) │
│ ├── UI界面、业务逻辑、游戏数据 │
│ │ │
│ │ ┌───────────────────────────────────────────────────┐ │
│ │ │ 核心库 (只读,框架团队维护) │ │
│ │ │ ├── Core: 模拟行为、全局数据 │ │
│ │ │ ├── HF: 资源管理、事件系统、相机管理 │ │
│ │ │ └── General: 状态机、工具类 │ │
│ │ └───────────────────────────────────────────────────┘ │
│ │ │
│ └─────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
```
#### 1.1.2 核心库访问原则
| 原则 | 说明 |
|-----|-----|
| **只读访问** | 核心库代码只可读取,不可修改 |
| **接口优先** | 通过接口访问服务,而非直接实例化实现类 |
| **继承扩展** | 通过继承抽象类实现自定义逻辑 |
| **依赖注入** | 通过管理器获取实例,而非硬编码 |
---
## 二、业务代码结构
### 2.1 目录组织规范
```
Assets/Game/GameHFScripte/GameFunction/
├── Event/ # 消息处理
│ ├── ServerToClient/ # 服务器到客户端消息
│ ├── ClientToClient/ # 客户端内部消息
│ └── Handle/ # 消息处理器
├── GameRoot/ # 框架调用入口
│ ├── HFGameStart.cs # 热更新进入入口
│ ├── HFFunCatalogue.cs # 框架统一调用入口
│ ├── HFFunCatalogue_Function.cs # 功能调用方法
│ └── ...
├── HFDownLoadSubPackage/ # 分包下载
│ ├── HFSubPackageManager.cs # 分包管理器
│ ├── HFGameStartAssetsCheckManager.cs # 资源检查
│ └── ...
├── HFExtends/ # Class扩展方法
│ ├── UI/ # UI扩展
│ ├── Material/ # 材质扩展
│ ├── String/ # 字符串扩展
│ └── ...
├── Logic/ # 游戏主要业务逻辑存放各功能Manager
│ ├── User/ # 用户相关
│ ├── Login/ # 登录系统
│ ├── Fight/ # 战斗系统
│ ├── CardDeck/ # 卡组系统
│ ├── Bag/ # 背包系统
│ └── ...
├── UIWindows/ # UI窗口业务逻辑
│ ├── Login/ # 登录窗口
│ ├── Lobby/ # 大厅窗口
│ ├── Fight/ # 战斗窗口
│ ├── Shop/ # 商店窗口
│ └── ...
├── GameEntity/ # 游戏实体
│ ├── Entity/ # 实体定义
│ ├── EntityPool/ # 实体对象池
│ └── ...
├── SoundManagerPro/ # 音效管理
├── SceneManager/ # 场景管理
├── SDK/ # SDK集成
└── MonoCompent/ # Mono组件
```
### 2.2 文件命名规范
| 文件类型 | 命名规则 | 示例 |
|---------|---------|-----|
| **窗口类** | `XXXWindow.cs` | `LoginWindow.cs` |
| **组件类** | `XXXComponent.cs` | `ItemCellComponent.cs` |
| **管理器类** | `XXXManager.cs` | `UIManager.cs` |
| **数据类** | `XXXData.cs` | `PlayerData.cs` |
| **配置类** | `XXXConfig.cs` | `SkillConfig.cs` |
---
**版本**: v1.0
**生效日期**: 2026年
**适用范围**: GiftGameX项目业务开发人员

View File

@@ -1,179 +0,0 @@
# StrayFog 框架 UI开发指南
## 一、窗口开发
### 1.1 创建模板
```csharp
[HFAssetBundlePath(enHFLanguageRootFolder.ASSETS_GAME_GAMEHFRESOURCE, "UIWindows/MyWindow/MyWindow.prefab")]
[HFUIWindowLayer(enHFUICanvasLayer.UIWindow, enHFUIWindowLayer.Dynamic)]
public class MyWindow : AbsHFUIWindow
{
private SFUI_Button BtnClose;
protected override void OnRunAwake()
{
base.OnRunAwake();
BtnClose = FindUICtrlByName<SFUI_Button>("BtnClose");
BtnClose.OnAddClickListener += OnBtnClose;
}
protected override void OnOpen(Action _onOpenComplete)
{
base.OnOpen(_onOpenComplete);
RefreshUI();
}
private void OnBtnClose(GameObject go) => CloseWindow();
private void RefreshUI() { }
}
```
### 1.2 生命周期
| 方法 | 调用时机 | 推荐操作 |
|-----|---------|---------|
| `OnRunAwake` | 创建时一次 | 绑定UI事件 |
| `OnOpen` | 每次打开 | 注册TC事件、刷新数据 |
| `OnClose` | 每次关闭 | 取消TC事件 |
### 1.3 窗口操作
```csharp
// 打开
HFFunCatalogue.UIManager.OpenWindow<MyWindow>();
// 关闭
HFFunCatalogue.UIManager.CloseWindow<MyWindow>();
```
---
## 二、事件绑定
| 事件类型 | 绑定位置 | 是否需要 `-=` |
|---------|---------|--------------|
| UI按钮/拖拽 | `OnRunAwake` | 不需要 |
| 全局TC事件 | `OnOpen`/`OnClose` | 需要 |
---
## 三、常用组件
### 3.1 按钮
```csharp
SFUI_Button btn = GetComponent<SFUI_Button>();
btn.OnAddClickListener += OnBtnClick;
btn.SetSelfGray(true);
```
### 3.2 文本
```csharp
SFUI_TextMeshProUGUI txt = GetComponent<SFUI_TextMeshProUGUI>();
txt.text = "Hello";
```
### 3.3 图片
```csharp
SFUI_Image img = GetComponent<SFUI_Image>();
img.HFSetSprite(/* atlasName */, "Icon_Player", /* languageRoot */);
```
### 3.4 滚动列表(核心)
```csharp
SFUI_ScrollRect scroll = GetComponent<SFUI_ScrollRect>();
scroll.BindEvent(
() => itemList.Count,
(idx) => itemPrefab.gameObject,
OnUpdateItem,
(item) => item.gameObject.HFGetOrAddSimulateBehaviour<ItemSlot>()
);
scroll.ShowView();
```
---
## 四、对象池
| 场景 | 推荐方式 |
|-----|---------|
| 滚动列表 | `SFUI_ScrollRect.BindEvent`(内置池) |
| 固定栏(装备/技能) | `HFSimulateBehaviourPool<T>` |
---
## 五、子组件
### 5.1 多态基类
```csharp
public abstract class AbsListItem<T> : AbsHFUIWindow
{
protected SFUI_Button m_BtnItem;
protected Action<T> m_OnSelect;
protected override void OnRunAwake()
{
base.OnRunAwake();
m_BtnItem = gameObject.GetComponent<SFUI_Button>();
m_BtnItem.OnAddClickListener += OnBtnClick;
}
public virtual void SetData(T data, Action<T> onSelect = null)
{
m_OnSelect = onSelect;
OnDataChanged(data);
}
protected abstract void OnDataChanged(T data);
private void OnBtnClick(GameObject go) => m_OnSelect?.Invoke(m_CurrentData);
}
// 子类
public class CardItem : AbsListItem<CardData>
{
protected override void OnDataChanged(CardData data) { }
}
```
---
## 六、开发规范
### 6.1 文件路径
#### 6.1.1 核心资源路径
| 类型 | 路径 | 说明 |
|-----|------|------|
| **窗口脚本** | `Assets/Game/GameHFScripte/GameFunction/UIWindows/{WindowName}/` | 窗口逻辑脚本存放目录 |
| **窗口预制体** | `Assets/Game/GameHFResource/CN/UIWindows/{WindowName}/` | UI窗口预制体存放目录 |
| **图标图集** | `Assets/Game/GameHFResource/CN/SpriteAtlas/{AtlasName}/` | SpriteAtlas图集资源 |
| **字体资源** | `Assets/Game/GameHFResource/CN/Fonts/` | 字体文件存放目录 |
#### 6.1.2 工具脚本路径
| 工具名称 | 路径 | 职责 |
|---------|------|------|
| **UIPrefabGenerator** | `Assets/Editor/Command/UIPrefabGenerator.cs` | JSON转UI预制体 |
| **UIPrefabToJson** | `Assets/Editor/Command/UIPrefabToJson.cs` | 预制体转JSON |
| **RemoteCommand** | `Assets/Editor/Command/RemoteCommand.cs` | 外部命令接口 |
| **ExternalCommandListener** | `Assets/Editor/Command/ExternalCommandListener.cs` | 外部命令监听器 |
#### 6.1.3 文档路径
| 文档名称 | 路径 |
|---------|------|
| UI开发指南 | `UnityAI/03_核心功能/UI/UI开发指南.md` |
| UI界面拼接设计指南 | `UnityAI/03_核心功能/UI/UI界面拼接设计指南.md` |
#### 6.1.4 命令触发路径
- **触发文件**: `{ProjectRoot}/Trigger_Command.txt`
- **JSON配置**: `Assets/Editor/UI/{WindowName}.json`
### 6.2 性能优化
- 使用对象池复用UI元素
- 将图标打包到SpriteAtlas
- 滚动列表用 `SFUI_ScrollRect.BindEvent`
---
**版本**: v1.0
**适用**: StrayFog框架开发人员

View File

@@ -1,417 +0,0 @@
# UI界面拼接设计指南
## 一、界面结构设计原则
### 1.1 模块化拆分
将界面按功能划分为独立模块:
| 模块类型 | 功能定位 | 示例 |
|---------|---------|------|
| **信息展示区** | 显示玩家状态、资源等静态信息 | 顶部信息栏、左侧状态栏 |
| **功能入口区** | 提供功能按钮入口 | 中央功能区、底部快捷栏 |
| **交互面板区** | 可展开/收起的功能面板 | 右侧功能面板、顶部按钮区 |
| **输入输出区** | 用户输入和系统反馈 | 聊天输入框、提示信息 |
### 1.2 经典布局模式
```
┌─────────────────────────────────────────────────────┐
│ TopArea (信息展示 + 可收起功能按钮) │
├──────────┬───────────────────────┬──────────────────┤
│ Left │ │ Right │
│ Area │ CenterArea │ Area │
│ (状态) │ (核心功能入口) │ (功能面板) │
│ │ │ │
├──────────┴───────────────────────┴──────────────────┤
│ BottomArea (快捷功能 + 状态信息 + 输入) │
└─────────────────────────────────────────────────────┘
```
---
## 二、组件拆分方法
### 2.1 基础组件识别
| 组件类型 | 识别特征 | 处理方式 |
|---------|---------|---------|
| **按钮** | 可点击、有交互反馈 | 使用 `SFUI_Button` |
| **文本** | 静态/动态文字显示 | 使用 `SFUI_TextMeshProUGUI` |
| **图片** | 图标、背景图 | 使用 `SFUI_Image` |
| **进度条** | HP、MP、经验等 | 使用 `SFUI_Slider` |
| **列表** | 可滚动的项目列表 | 使用 `SFUI_ScrollRect` |
### 2.2 复合组件封装
将功能相关的基础组件组合为复合组件,便于复用和维护:
**设计原则**
- 将同一功能模块的组件封装在一起(如玩家头像+血条+蓝条)
- 提供统一的数据设置接口
- 保持组件之间的逻辑独立性
---
## 三、预制体层级规范
### 3.1 标准层级结构
```
WindowName (RectTransform)
├── ModuleName (RectTransform) # 模块容器
│ ├── ComponentName (SFUI_*) # 功能组件
│ ├── SubModule (RectTransform) # 子模块
│ └── CollapsibleArea (RectTransform) # 可收起区域
└── BtnCollapse (SFUI_Button) # 收起控制按钮
```
### 3.2 命名规范
| 类型 | 命名规则 | 示例 |
|-----|---------|------|
| 模块容器 | PascalCase + Area | `TopArea` |
| 功能组件 | PascalCase | `BtnCollapseTop` |
| 可收起区域 | PascalCase + FuncArea | `TopFuncArea` |
| 状态变量 | m_ + PascalCase | `m_IsTopCollapsed` |
---
## 四、收起/展开功能设计
### 4.1 功能定义
| 按钮 | 控制区域 | 用途 |
|-----|---------|------|
| `BtnCollapseTop` | 顶部功能按钮区 | 收起/展开顶部按钮群 |
| `BtnCollapseRight` | 右侧功能面板区 | 收起/展开右侧功能面板 |
### 4.2 设计要点
**状态管理**:每个可收起区域需要一个布尔状态变量来记录当前收起/展开状态。
**交互逻辑**
1. 点击收起按钮时,切换对应区域的显示/隐藏状态
2. 同时切换按钮图标(收起时显示展开图标,展开时显示收起图标)
**布局要求**
- 收起按钮应放置在对应区域的边缘位置,便于用户找到
- 收起区域内的所有元素应作为一个整体进行显示/隐藏控制
- 收起状态应在窗口生命周期内保持记忆
---
## 五、实际案例:主界面拼接
### 5.1 模块化设计思想
**核心原则**:将界面按功能边界划分为独立模块,模块内可嵌套子模块。
**模块归类方法**
1. **一级模块**:按空间位置划分(顶部、左侧、中央、右侧、底部)
2. **二级模块**:按功能类型划分(信息展示区、功能按钮区、输入输出区)
3. **三级模块**:按具体功能划分(玩家头像、资源显示、功能按钮群)
**层级关系示例**
```
Window
├── TopArea (一级:位置)
│ ├── InfoPanel (二级:信息展示)
│ │ └── TxtWelcome (三级:具体组件)
│ └── FuncButtons (二级:功能按钮)
│ └── BtnUpload (三级:具体按钮)
└── LeftArea (一级:位置)
└── PlayerPortrait (二级:复合组件)
├── ImgAvatar (三级:头像)
└── BarHP (三级:血条)
```
**设计要点**
- 同一功能域内的元素归为同一模块(如头像、血条、蓝条归为玩家状态模块)
- 独立交互功能作为独立模块(如收起按钮单独作为控制模块)
- 可收起区域作为独立子模块,便于统一控制显示/隐藏
---
## 六、界面拼接流程
### 6.1 设计阶段
1. **需求分析**:明确界面功能和交互需求
2. **模块划分**:将界面拆分为独立功能模块
3. **层级设计**:设计预制体层级结构
### 6.2 开发阶段
1. **组件创建**:创建基础组件和复合组件
2. **预制体搭建**:按层级结构搭建预制体
3. **脚本编写**:实现交互逻辑和收起/展开功能
### 6.3 测试阶段
1. **功能测试**:验证所有按钮和交互功能
2. **收起测试**:测试收起/展开功能正常工作
3. **适配测试**:验证不同分辨率下的显示效果
---
## 七、注意事项
1. **组件复用**:相同功能的组件尽量复用,减少冗余
2. **状态管理**:收起状态需要正确保存和恢复
3. **图标反馈**:收起按钮图标应随状态变化
4. **性能优化**:可收起区域使用 `SetActive` 而非销毁重建
5. **命名规范**:统一的命名规则便于维护和查找
---
## 八、JSON配置驱动的UI生成方式
### 8.1 概述
本项目支持JSON配置与Unity预制体的双向转换
- **正向转换**JSON配置 → UI预制体
- **反向转换**UI预制体 → JSON配置
实现UI界面的快速构建、迭代和版本控制。
### 8.2 核心组件
| 组件 | 职责 | 文件路径 |
|-----|------|---------|
| **UIPrefabGenerator** | 解析JSON并生成UI预制体 | `Assets/Editor/Command/UIPrefabGenerator.cs` |
| **UIPrefabToJson** | 从预制体反向导出JSON | `Assets/Editor/Command/UIPrefabToJson.cs` |
| **RemoteCommand** | 提供外部调用接口 | `Assets/Editor/Command/RemoteCommand.cs` |
| **ExternalCommandListener** | 监听外部命令触发文件 | `Assets/Editor/Command/ExternalCommandListener.cs` |
### 8.3 JSON配置文件结构
```json
{
"name": "BagWindow",
"width": 1024,
"height": 768,
"elements": [
{
"type": "Image",
"name": "BgPanel",
"anchorMin": [0, 0],
"anchorMax": [1, 1],
"position": [0, 0, 0],
"sizeDelta": [0, 0],
"sprite": "Assets/Game/GameHFResource/CN/UIWindows/BagWindow/Sprites/Bg.png"
},
{
"type": "Text",
"name": "TitleText",
"anchorMin": [0.5, 0.9],
"anchorMax": [0.5, 0.9],
"position": [0, 0, 0],
"sizeDelta": [200, 40],
"text": "背包",
"font": "Assets/Game/GameHFResource/CN/Fonts/FZY4K-M05S SDF.asset",
"fontSize": 28,
"color": [1, 1, 1, 1]
}
]
}
```
### 8.4 支持的UI元素类型
| 类型 | 对应Unity组件 | 关键属性 |
|-----|-------------|---------|
| **Image** | Image | sprite, color, type, preserveAspect |
| **TextMeshProUGUI** | TextMeshProUGUI | text, font, fontSize, color, alignment |
| **Button** | Button | interactable, transition, navigationMode |
| **Slider** | Slider | minValue, maxValue, value, wholeNumbers, direction |
| **Toggle** | Toggle | isOn, toggleTransition, transition |
| **InputField** | InputField | text, placeholder, characterLimit, contentType |
| **ScrollRect** | ScrollRect | horizontal, vertical, movementType |
| **GridLayoutGroup** | GridLayoutGroup | cellSize, spacing, constraint, padding |
| **VerticalLayoutGroup** | VerticalLayoutGroup | spacing, childAlignment, padding |
| **HorizontalLayoutGroup** | HorizontalLayoutGroup | spacing, childAlignment, padding |
### 8.5 外部命令触发机制
#### 8.5.1 触发方式
通过创建/修改 `Trigger_Command.txt` 文件触发UI生成
```
GenerateUIPrefab:Assets/Editor/UI/BagWindow.json
```
#### 8.5.2 命令格式
```
<命令名>:<参数1>:<参数2>:...
```
**支持的命令**
| 命令 | 参数 | 说明 |
|-----|------|------|
| **GenerateUIPrefab** | `jsonPath` [, `prefabPath`] | 根据JSON生成UI预制体 |
| **ExportPrefabToJson** | `prefabPath` [, `jsonPath`] | 从预制体反向导出JSON |
| **ReadJson** | [参数列表] | 读取JSON配置测试用 |
#### 8.5.3 完整执行流程
```
┌─────────────────────────────────────────────────────────────────────┐
│ 外部系统写入命令到 Trigger_Command.txt │
└─────────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────┐
│ ExternalCommandListener (FileSystemWatcher) 检测到文件变化 │
└─────────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────┐
│ 解析命令格式GenerateUIPrefab:Assets/Editor/UI/BagWindow.json │
└─────────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────┐
│ 通过反射调用 RemoteCommand.GenerateUIPrefab(string[] args) │
└─────────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────┐
│ UIPrefabGenerator.GeneratePrefabFromJson(jsonPath, prefabPath) │
└─────────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────┐
│ 生成预制体到指定路径Assets/Game/GameHFResource/CN/UIWindows/... │
└─────────────────────────────────────────────────────────────────────┘
```
### 8.6 Unity编辑器菜单测试
在Unity编辑器中提供了测试菜单
| 菜单路径 | 功能 |
|---------|------|
| `Tools > UI > Export Prefab to JSON` | 选择预制体导出JSON |
| `Tools > UI > Generate BagWindow Prefab` | 生成BagWindow预制体 |
| `Tools > External > Test ReadJson` | 测试ReadJson命令 |
| `Tools > External > Test GenerateUIPrefab` | 测试正向生成 |
| `Tools > External > Test ExportPrefabToJson` | 测试反向导出 |
### 8.7 使用示例
#### 方式一:外部命令触发
```bash
# 正向从JSON生成预制体
echo "GenerateUIPrefab:Assets/Editor/UI/BagWindow.json" > "F:\JMNet\CrystalBattle_Client\Trigger_Command.txt"
# 反向从预制体导出JSON
echo "ExportPrefabToJson:Assets/Game/GameHFResource/CN/UIWindows/BagWindow/BagWindow.prefab" > "F:\JMNet\CrystalBattle_Client\Trigger_Command.txt"
```
#### 方式二Unity编辑器菜单
**正向生成**
1. 打开Unity编辑器
2. 点击菜单 `Tools > External > Test GenerateUIPrefab`
3. 查看Console窗口日志确认执行结果
**反向导出**
1. 打开Unity编辑器
2. 点击菜单 `Tools > UI > Export Prefab to JSON`
3. 选择要导出的预制体文件
#### 方式三:代码调用
```csharp
// 正向从JSON生成预制体
UIPrefabGenerator.GeneratePrefabFromJson(
"Assets/Editor/UI/BagWindow.json",
"Assets/Game/GameHFResource/CN/UIWindows/BagWindow/BagWindow.prefab"
);
// 反向从预制体导出JSON
UIPrefabToJson.ExportPrefabToJson(
"Assets/Game/GameHFResource/CN/UIWindows/BagWindow/BagWindow.prefab",
"Assets/Editor/UI/BagWindow.json"
);
```
### 8.8 注意事项
1. **路径格式**JSON中的资源路径使用 `/` 分隔符且为Unity项目相对路径
2. **资源引用**确保JSON中引用的Sprite、Font等资源已存在于项目中
3. **编码格式**JSON文件使用UTF-8编码
4. **坐标系统**使用Unity RectTransform的anchorMin/anchorMax/position/sizeDelta四元组
5. **文件锁定**:生成前确保目标预制体文件未被其他进程占用
### 8.9 工具脚本部署
#### 8.9.1 工具位置
工具脚本位于UnityAI文档库的以下路径
```
UnityAI/06_工具脚本/UI工具/
├── ExternalCommandListener.cs # 外部命令监听器
├── RemoteCommand.cs # 远程命令接口
├── UIPrefabGenerator.cs # JSON转预制体生成器
└── UIPrefabToJson.cs # 预制体转JSON导出器
```
#### 8.9.2 部署步骤
**方法一:手动复制**
1. 复制 `06_工具脚本/UI工具/` 目录下的所有文件
2. 粘贴到目标项目的 `Assets/Editor/Command/` 目录中
3. 确保目录结构如下:
```
Assets/Editor/Command/
├── ExternalCommandListener.cs
├── RemoteCommand.cs
├── UIPrefabGenerator.cs
└── UIPrefabToJson.cs
```
**方法二:自动部署脚本**
创建部署脚本 `DeployUITools.bat`
```batch
@echo off
set "SOURCE_DIR=E:\AI\UnityAI\06_工具脚本\UI工具"
set "TARGET_DIR=%cd%\Assets\Editor\Command"
mkdir "%TARGET_DIR%" 2>nul
xcopy "%SOURCE_DIR%\*.cs" "%TARGET_DIR%\" /y
xcopy "%SOURCE_DIR%\*.cs.meta" "%TARGET_DIR%\" /y
echo UI工具部署完成
pause
```
#### 8.9.3 部署规则
| 检查项 | 要求 |
|-------|------|
| **目标路径** | 必须放置在 `Assets/Editor/Command/` 目录下 |
| **文件完整性** | 必须包含所有4个cs文件及其meta文件 |
| **Unity版本** | 支持Unity 2020及以上版本 |
| **依赖组件** | 需要导入 TextMeshPro 包 |
#### 8.9.4 验证部署
部署完成后在Unity编辑器中验证
1. 打开Unity编辑器
2. 检查菜单 `Tools > UI` 是否存在
3. 检查菜单 `Tools > External` 是否存在
4. 在Console窗口确认无编译错误
---
**版本**: v1.2
**适用**: StrayFog框架UI拼接开发人员

View File

@@ -1,86 +0,0 @@
# StrayFog 框架资源管理使用指南
## 一、AssetBundle资源加载
### 1.1 加载资源示例
```csharp
public class ResourceLoader : MonoBehaviour
{
public void LoadPlayerModel(int resId, Action<GameObject> onLoaded)
{
// 通过HFFunCatalogue统一入口加载资源
// resId: 从Res配置表中读取的资源ID
HFFunCatalogue.Asset.LoadAsset(resId, (res, obj) =>
{
if (obj != null)
{
GameObject model = res.GetAsset<GameObject>();
onLoaded?.Invoke(model);
}
else
{
Debug.LogError($"加载失败: resId={resId}");
}
});
}
}
```
### 1.2 实体资源加载示例
```csharp
// 在Entity中加载资源
HFFunCatalogue.Asset.LoadAsset(data.EntityRes.Id, (res, obj) => {
if (!entity.isDeath)
{
var Boddy = res.GetAsset<GameObject>();
data.SetBoddy(Boddy);
}
});
```
---
## 二、资源管理API
### 2.1 常用方法
| 类别 | 管理器 | 常用方法 |
|-----|-------|---------|
| **资源** | `HFABMgr` | `LoadAsset()`, `OnStartLoad()` |
### 2.2 资源加载流程
```
资源加载流程:
OnStartLoad(request)
检查缓存 → 获取/创建 HFAssetLoader
loader.AddRequest(request)
loader.LoadAsset() → 异步加载
加载完成 → 回调处理
```
---
## 三、资源管理注意事项
### 3.1 性能优化建议
- 及时释放不再使用的资源
- 使用异步加载避免卡顿
- 合理使用资源缓存
---
**版本**: v1.0
**生效日期**: 2026年
**适用范围**: GiftGameX项目业务开发人员

View File

@@ -1,46 +0,0 @@
# StrayFog 框架常见问题指南
## 一、常见问题解答
### 1.1 如何扩展核心库功能?
通过继承抽象类或实现接口来扩展,不要直接修改核心库代码。
### 1.2 核心库有Bug怎么办
提交Issue到框架团队由框架团队修复并发布新版本。
### 1.3 如何获取核心库的最新版本?
关注内部通知,定期更新核心库引用。
### 1.4 如何调试核心库代码?
可以设置断点调试,但不允许修改代码。
---
## 附录
### A. 常用核心库API
| 类别 | 管理器 | 常用方法 |
|-----|-------|---------|
| **对象池** | `HFObjectMemPool` | `GetItem()`, `GiveBack()` |
| **事件** | `IHFEventHandle` | `AddListener()`, `Dispatch()` |
| **资源** | `HFABMgr` | `OnStartLoad()` |
| **相机** | `HFCameraManager` | `AddCamera()`, `GetCamera()` |
### B. 核心库只读目录
```
Assets/StrayFog/Core/
Assets/Game/GameHFScripte/CopyToHF/
Assets/Game/GameGeneralScripte/
```
---
**版本**: v1.0
**生效日期**: 2026年
**适用范围**: GiftGameX项目业务开发人员

View File

@@ -1,108 +0,0 @@
# StrayFog 框架开发流程指南
## 一、文档学习阶段
### 1.1 必读文档清单
| 优先级 | 文档路径 | 目的 |
|-------|---------|-----|
| P0 | `01_框架架构/StrayFog框架架构分析.md` | 理解框架整体架构 |
| P0 | `02_开发规范/开发规范指南.md` | 掌握编码规范和命名约定 |
| P1 | `03_核心功能/事件系统使用指南.md` | 理解事件驱动机制 |
| P1 | `03_核心功能/对象池使用指南.md` | 掌握对象池复用机制 |
| P1 | `03_核心功能/资源管理使用指南.md` | 理解资源加载流程 |
### 1.2 功能专项文档
根据开发任务类型,必须阅读对应的专项指南:
| 任务类型 | 必读文档 |
|---------|---------|
| UI开发 | `03_核心功能/UI/UI开发指南.md` |
| UI界面设计 | `03_核心功能/UI/UI界面拼接设计指南.md` |
| 相机控制 | `03_核心功能/相机系统使用指南.md` |
### 1.3 输出要求
完成文档学习后,开发人员必须输出:
1. **工作流程说明**:详细描述从需求到交付的完整步骤
2. **技术选型说明**明确使用的框架组件和API
3. **风险评估**:识别潜在问题和解决方案
---
## 二、需求分析
### 2.1 需求分析步骤
1. **明确需求**:理解业务需求,确定需要实现的功能
2. **评估复杂度**:判断是否需要核心库支持或扩展
3. **设计方案**:规划代码结构和调用关系
---
## 三、代码编写
### 3.1 代码编写步骤
1. **创建目录**:在`GameBusiness`下创建对应模块目录
2. **编写代码**遵循编码规范使用核心库提供的API
3. **测试验证**在Unity中测试功能正确性
---
## 四、代码审查
### 4.1 代码审查流程
1. **自我检查**:检查是否符合规范,是否有潜在问题
2. **团队审查**:提交代码进行团队审查
3. **修复问题**:根据审查意见修改代码
---
## 五、集成测试
### 5.1 测试阶段
1. **模块测试**:测试单个模块功能
2. **集成测试**:测试模块间交互
3. **回归测试**:确保不影响现有功能
---
## 六、Git提交规范
### 6.1 提交格式要求
所有代码提交必须遵循以下格式:
```
【操作原因】具体操作内容
```
### 6.2 操作原因分类
| 分类 | 说明 | 适用场景 |
|------|------|----------|
| 【初始化】 | 首次创建或上传 | 新项目初始化、首次上传文档 |
| 【更新】 | 修改或完善现有内容 | 更新文档、优化代码 |
| 【新增】 | 添加新文件或功能 | 新增文档、新增代码模块 |
| 【修复】 | 修复错误或问题 | 修复Bug、修正文档错误 |
| 【重构】 | 重构代码或文档结构 | 优化架构、重新组织文档 |
| 【删除】 | 删除文件或功能 | 删除无用文件、移除废弃代码 |
| 【配置】 | 修改配置文件 | 更新配置、调整参数 |
### 6.3 提交示例
```bash
git commit -m "【更新】修复UI窗口打开时的空指针异常"
git commit -m "【新增】添加战斗系统核心模块"
git commit -m "【修复】修正开发流程指南中的错误描述"
```
---
**版本**: v1.0
**生效日期**: 2026年
**适用范围**: GiftGameX项目业务开发人员

View File

@@ -1,49 +0,0 @@
# StrayFog 框架最佳实践指南
## 一、性能优化
### 1.1 对象池使用
- 频繁创建销毁的对象必须使用对象池
- 合理设置对象池初始容量
- 定期清理空闲对象避免内存泄漏
### 1.2 资源管理
- 及时释放不再使用的资源
- 使用异步加载避免卡顿
- 合理使用资源缓存
---
## 二、代码组织
### 2.1 单一职责
- 每个类只负责一个功能
- 避免庞大的God类
### 2.2 依赖管理
- 通过管理器获取依赖,而非硬编码
- 使用接口解耦依赖关系
---
## 三、错误处理
### 3.1 异常捕获
- 在关键路径添加异常处理
- 记录错误日志便于排查
### 3.2 防御性编程
- 检查参数合法性
- 处理空引用情况
---
**版本**: v1.0
**生效日期**: 2026年
**适用范围**: GiftGameX项目业务开发人员

View File

@@ -1,111 +0,0 @@
# UnityAI Git 规定指南
## 一、提交日志格式规范
### 1.1 格式要求
所有 Git 提交日志必须遵循以下格式:
```
【操作原因】具体操作内容
```
### 1.2 格式说明
| 部分 | 说明 | 示例 |
|------|------|------|
| `【操作原因】` | 用中文方括号包裹,描述本次操作的核心目的 | 【初始化】、【更新】、【修复】 |
| `具体操作内容` | 详细描述本次提交的内容,使用中文 | 上传框架文档、修改配置文件 |
### 1.3 操作原因分类
| 分类 | 说明 | 适用场景 |
|------|------|----------|
| **【初始化】** | 首次创建或上传项目/文档 | 新项目初始化、首次上传文档 |
| **【更新】** | 修改或完善现有内容 | 更新文档内容、优化代码逻辑 |
| **【新增】** | 添加新的文件或功能 | 新增文档、新增代码模块 |
| **【修复】** | 修复错误或问题 | 修复文档错误、修复代码Bug |
| **【重构】** | 重构代码结构或文档结构 | 优化代码架构、重新组织文档 |
| **【删除】** | 删除文件或功能 | 删除无用文件、移除废弃代码 |
| **【迁移】** | 迁移文件或项目 | 文件位置调整、项目迁移 |
| **【配置】** | 修改配置文件 | 更新配置、调整参数 |
---
## 二、提交日志示例
### 2.1 文档相关
```
【初始化】上传UnityAI框架文档包含StrayFog框架架构分析、业务开发指南、核心库保护规范
【更新】完善StrayFog框架架构分析中Core层的描述
【新增】添加Git规定指南文档
【修复】修正业务开发指南中的代码示例错误
```
### 2.2 代码相关
```
【新增】实现AI决策系统核心模块
【更新】优化对象池性能
【修复】修复事件系统内存泄漏问题
【重构】重构技能系统架构
【删除】移除废弃的测试代码
```
### 2.3 配置相关
```
【配置】更新构建脚本参数
【配置】调整日志输出级别
```
---
## 三、Git 工作流程
### 3.1 提交流程
```
修改文件
git add . # 暂存所有修改
git commit -m "【操作原因】具体操作内容" # 提交并撰写规范日志
git push # 推送到远程仓库
```
### 3.2 分支管理
| 分支名称 | 用途 |
|----------|------|
| `master` | 主分支,稳定版本 |
| `develop` | 开发分支,日常开发 |
| `feature/*` | 功能分支,开发新功能 |
| `bugfix/*` | Bug修复分支 |
### 3.3 远程仓库信息
- **仓库地址**: `https://jinmt.com/Shiliang/UnityAI.git`
- **用户名**: `Shiliang`
- **密码**: `Sl940104`
---
## 四、注意事项
1. **日志语言**: 统一使用中文描述
2. **简洁明了**: 日志应简洁清晰,准确反映提交内容
3. **分类准确**: 选择合适的操作原因分类
4. **避免空提交**: 禁止无内容的空提交
5. **定期推送**: 开发完成后及时推送到远程仓库
---
**版本**: v1.0
**生效日期**: 2026年5月22日
**适用范围**: UnityAI项目团队

View File

@@ -1,80 +0,0 @@
# StrayFog 框架核心库保护规范
## 一、核心库定义
### 1.1 核心库范围(只读)
| 路径 | 说明 |
|------|------|
| `Assets/StrayFog/Core` | 基础框架核心 |
| `Assets/Game/GameHFScripte/CopyToHF` | 游戏核心业务框架 |
| `Assets/Game/GameGeneralScripte` | 通用工具层 |
---
## 二、保护规则
### 2.1 访问方式
**业务代码必须通过 `HFFunCatalogue` 统一入口访问核心库:**
```csharp
// ✅ 正确:通过统一入口访问
HFFunCatalogue.UIManager.OpenWindow<LoginWindow>();
HFFunCatalogue.Asset.LoadAsset<GameObject>("path");
HFFunCatalogue.Scene.LoadScene("MainScene");
// ❌ 禁止:直接访问核心库
HFUIWindowMgr.Instance.OpenWindow<LoginWindow>(); // 禁止
HFABMgr.Instance.LoadAsset<GameObject>("path"); // 禁止
```
### 2.2 禁止操作
| 禁止行为 | 后果 |
|---------|------|
| 修改核心库源代码 | 破坏框架稳定性 |
| 删除/重命名核心库文件 | 编译错误 |
| 直接实例化核心库内部类 | 违反封装原则 |
| 绕过 `HFFunCatalogue` 直接调用核心库单例 | 难以维护和测试 |
---
## 三、修改流程
```
业务人员发现问题/需求
提交Issue到框架团队
框架团队评估需求
┌────┴────┐
│ │
合理 不合理
│ │
▼ ▼
开发修复 反馈拒绝
代码审查 → 发布新版本 → 业务团队更新引用
```
---
## 四、违规处理
| 等级 | 违规行为 | 处理方式 |
|-----|---------|---------|
| **轻微** | 误修改注释、空行 | 警告+恢复 |
| **一般** | 修改非核心逻辑 | 通报批评+代码回滚 |
| **严重** | 修改核心逻辑导致Bug | 绩效扣分+修复责任 |
| **重大** | 删除核心文件导致崩溃 | 追责+修复责任 |
---
**版本**: v1.0
**生效日期**: 2024年
**适用范围**: OnlineGame项目

View File

@@ -1,194 +0,0 @@
using UnityEditor;
using UnityEngine;
using System.IO;
[InitializeOnLoad]
public static class ExternalCommandListener
{
private static FileSystemWatcher watcher;
private static string triggerFilePath;
private static bool isInitialized = false;
static ExternalCommandListener()
{
EditorApplication.update += InitializeOnFirstUpdate;
}
private static void InitializeOnFirstUpdate()
{
if (!isInitialized)
{
isInitialized = true;
EditorApplication.update -= InitializeOnFirstUpdate;
SetupFileWatcher();
Debug.Log("ExternalCommandListener started");
}
}
private static void SetupFileWatcher()
{
triggerFilePath = Path.Combine(Application.dataPath, "..", "Trigger_Command.txt");
string watchFolder = Path.GetDirectoryName(triggerFilePath);
if (watcher != null) watcher.Dispose();
watcher = new FileSystemWatcher(watchFolder, "Trigger_Command.txt");
watcher.NotifyFilter = NotifyFilters.CreationTime | NotifyFilters.LastWrite;
watcher.Created += OnFileChanged;
watcher.Changed += OnFileChanged;
watcher.EnableRaisingEvents = true;
}
private static void OnFileChanged(object sender, FileSystemEventArgs e)
{
if (e.ChangeType != WatcherChangeTypes.Created && e.ChangeType != WatcherChangeTypes.Changed)
return;
EditorApplication.delayCall += ExecuteCommandFromFile;
}
private static void ExecuteCommandFromFile()
{
try
{
if (!File.Exists(triggerFilePath)) return;
string content = File.ReadAllText(triggerFilePath).Trim();
File.Delete(triggerFilePath);
ParseAndExecute(content);
}
catch (System.Exception ex)
{
Debug.LogError("Execute failed: " + ex.Message);
}
}
private static void ParseAndExecute(string content)
{
content = content.Trim().Trim('"', '\'');
string[] parts = content.Split(':');
if (parts.Length == 0) return;
string command = parts[0].Trim();
string[] args = parts.Length > 1 ? parts[1..] : new string[0];
ExecuteCommand(command, args);
}
private static void ExecuteCommand(string command, string[] args)
{
switch (command)
{
case "ReadJson":
ExecuteReadJson(args);
break;
case "GenerateUIPrefab":
ExecuteGenerateUIPrefab(args);
break;
case "ExportPrefabToJson":
ExecuteExportPrefabToJson(args);
break;
default:
Debug.LogWarning("Unknown command: " + command);
break;
}
}
private static void ExecuteReadJson(string[] args)
{
try
{
var method = typeof(RemoteCommand).GetMethod("ReadJson",
System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static,
null,
new[] { typeof(string[]) },
null);
if (method != null)
{
method.Invoke(null, new object[] { args });
Debug.Log("Executed: ReadJson(" + string.Join(", ", args) + ")");
}
else
{
Debug.LogError("RemoteCommand.ReadJson not found");
}
}
catch (System.Exception ex)
{
Debug.LogError("ReadJson failed: " + ex.Message);
}
}
private static void ExecuteGenerateUIPrefab(string[] args)
{
try
{
var method = typeof(RemoteCommand).GetMethod("GenerateUIPrefab",
System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static,
null,
new[] { typeof(string[]) },
null);
if (method != null)
{
method.Invoke(null, new object[] { args });
Debug.Log("Executed: GenerateUIPrefab(" + string.Join(", ", args) + ")");
}
else
{
Debug.LogError("RemoteCommand.GenerateUIPrefab not found");
}
}
catch (System.Exception ex)
{
Debug.LogError("GenerateUIPrefab failed: " + ex.Message);
}
}
[MenuItem("Tools/External/Test ReadJson")]
public static void TestExecuteReadJson()
{
ExecuteReadJson(new string[0]);
}
[MenuItem("Tools/External/Test GenerateUIPrefab")]
public static void TestExecuteGenerateUIPrefab()
{
ExecuteGenerateUIPrefab(new[] { "Assets/Editor/UI/BagWindow.json" });
}
private static void ExecuteExportPrefabToJson(string[] args)
{
try
{
var method = typeof(RemoteCommand).GetMethod("ExportPrefabToJson",
System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static,
null,
new[] { typeof(string[]) },
null);
if (method != null)
{
method.Invoke(null, new object[] { args });
Debug.Log("Executed: ExportPrefabToJson(" + string.Join(", ", args) + ")");
}
else
{
Debug.LogError("RemoteCommand.ExportPrefabToJson not found");
}
}
catch (System.Exception ex)
{
Debug.LogError("ExportPrefabToJson failed: " + ex.Message);
}
}
[MenuItem("Tools/External/Test ExportPrefabToJson")]
public static void TestExecuteExportPrefabToJson()
{
ExecuteExportPrefabToJson(new[] { "Assets/Game/GameHFResource/CN/UIWindows/BagWindow/BagWindow.prefab" });
}
}

View File

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

View File

@@ -1,39 +0,0 @@
public static class RemoteCommand
{
public static void ReadJson(string[] args)
{
SFP.Error("收到参数: " + string.Join(", ", args));
}
public static void GenerateUIPrefab(string[] args)
{
if (args.Length == 0)
{
SFP.Error("GenerateUIPrefab: 需要提供JSON文件路径参数");
return;
}
string jsonPath = args[0];
string prefabPath = args.Length > 1 ? args[1] : null;
SFP.Error("GenerateUIPrefab: 开始生成UI, JSON路径: " + jsonPath);
UIPrefabGenerator.GeneratePrefabFromJson(jsonPath, prefabPath);
}
public static void ExportPrefabToJson(string[] args)
{
if (args.Length == 0)
{
SFP.Error("ExportPrefabToJson: 需要提供预制体文件路径参数");
return;
}
string prefabPath = args[0];
string jsonPath = args.Length > 1 ? args[1] : null;
SFP.Error("ExportPrefabToJson: 开始导出JSON, 预制体路径: " + prefabPath);
UIPrefabToJson.ExportPrefabToJson(prefabPath, jsonPath);
}
}

View File

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

31
AGENTS.md Normal file
View File

@@ -0,0 +1,31 @@
# UnityAI - Codex 入口
本文件是 Codex 的项目级入口包装。
处理本项目任务时,**先读取 `ai/AI接入入口.md`**,再按其中说明读取项目规则、项目知识和共享 hook 文档。
---
## AI 接入入口
- **[ai/AI接入入口.md](ai/AI接入入口.md)** — 所有 AI / IDE 工具的接入总入口。
## 说明
- 不要把项目规则重复写在你的系统提示里。
- 所有项目规则维护在 `rules/`
- 所有项目模块知识维护在 `modules/`
- 共享 hook 规则和检查脚本维护在 `hooks/`
- Codex 私有目录只放适配器,不复制项目规则。
---
## 文档关联
> 当本文档发生变更时,应同步检查以下关联文档,避免信息不一致。
| 文档 | 关联原因 |
|---|---|
| [ai/AI接入入口.md](ai/AI接入入口.md) | AGENTS.md 指向 AI 接入入口,入口变更需同步 |
| [CLAUDE.md](CLAUDE.md) | Claude Code 入口与 AGENTS.md 互为替代入口 |
| [RULES.md](RULES.md) | 通用兼容入口需与 AGENTS.md 保持一致 |

19
CLAUDE.md Normal file
View File

@@ -0,0 +1,19 @@
# UnityAI - Claude Code 入口
处理本项目任务时,先读取 [AI 工具接入入口](ai/AI接入入口.md),再按其中顺序读取项目规则、工作流、模块知识和共享检查。
## 说明
- 项目规则只维护在 `rules/`
- 框架知识只维护在 `modules/`
- 检查脚本只维护在 `hooks/`
- 重大变更按 [工作流清单](rules/40-工作流清单.md) 在对话中确认,稳定结论写入模块文档。
- 只有用户明确要求提交或推送时才触发 Git 写操作。
## 文档关联
| 文档 | 关联原因 |
|---|---|
| [AI 工具接入入口](ai/AI接入入口.md) | Claude Code 统一接入入口 |
| [AGENTS.md](AGENTS.md) | Codex 替代入口 |
| [RULES.md](RULES.md) | 通用兼容入口 |

View File

@@ -1,47 +1,69 @@
# UnityAI - StrayFog框架文档中心 # UnityAI - StrayFog 框架文档中心
## 📋 文档索引 UnityAI 是 StrayFog 框架的通用工作流与知识库。它面向 AI 工具、业务开发人员和框架维护人员;具体 Unity 项目提供真实实现与验证环境,当前主要验证对象为 `CrystalBattle_Client`
### 01_框架架构 ## 快速入口
- [StrayFog框架架构分析](01_框架架构/StrayFog框架架构分析.md)
### 02_开发规范 | 读者 | 入口 |
- [开发规范指南](02_开发规范/开发规范指南.md) |---|---|
| Codex | [AGENTS.md](AGENTS.md) |
| Claude Code | [CLAUDE.md](CLAUDE.md) |
| 其他 AI / 人工 | [RULES.md](RULES.md) |
| 项目工作流 | [工作流清单](rules/40-工作流清单.md) |
| 框架知识 | [模块索引](modules/模块索引.md) |
### 03_核心功能 ## 项目规则
- [对象池使用指南](03_核心功能/对象池使用指南.md)
- [事件系统使用指南](03_核心功能/事件系统使用指南.md)
- [资源管理使用指南](03_核心功能/资源管理使用指南.md)
- [相机系统使用指南](03_核心功能/相机系统使用指南.md)
#### UI相关 - [项目概览](rules/00-项目概览.md)
- [UI开发指南](03_核心功能/UI/UI开发指南.md) - 窗口开发、组件使用、事件绑定、对象池、开发规范 - [架构说明](rules/10-架构说明.md)
- [UI界面拼接设计指南](03_核心功能/UI/UI界面拼接设计指南.md) - 界面模块化设计、布局规划、模块组装 - [开发规则](rules/20-开发规则.md)
- [模块登记规则](rules/30-模块登记规则.md)
- [工作流清单](rules/40-工作流清单.md)
- [文档同步规则](rules/50-文档同步规则.md)
- [AI 工具扫描范围](rules/70-AI工具扫描范围.md)
### 04_开发流程 ## 核心框架
- [开发流程指南](04_开发流程/开发流程指南.md)
- [最佳实践指南](04_开发流程/最佳实践指南.md)
- [常见问题指南](04_开发流程/常见问题指南.md)
### 05_项目管理 - [通用框架](modules/frameworks/通用框架/README.md)
- [核心库保护规范](05_项目管理/核心库保护规范.md) - [实体系统](modules/frameworks/实体系统/README.md)
- [Git规定指南](05_项目管理/Git规定指南.md) - [技能系统](modules/frameworks/技能系统/README.md)
- [UI 窗口系统](modules/frameworks/UI窗口系统/README.md)
- [UI 开发指南](modules/frameworks/UI窗口系统/开发指南.md)
- [界面拼接](modules/frameworks/UI窗口系统/界面拼接.md)
- [事件系统](modules/frameworks/事件系统/README.md)
- [对象池与运行时对象管理](modules/frameworks/内存对象管理/README.md)
- [相机系统](modules/frameworks/相机系统/README.md)
- [资源管理](modules/frameworks/资源管理/README.md)
- [资源管理使用指南](modules/frameworks/资源管理/使用指南.md)
- [场景系统](modules/frameworks/场景系统.md)
- [网络系统](modules/frameworks/网络系统.md)
- [数据配置框架](modules/frameworks/数据配置框架.md)
- [Hotfix 启动](modules/frameworks/Hotfix启动.md)
### 06_工具脚本 ## 编辑器工具
- [UI工具](06_工具脚本/UI工具/) - UI预制体与JSON双向转换工具
--- - [编辑器工具](modules/frameworks/编辑器工具/README.md)
- [UI 拼接工具](modules/frameworks/编辑器工具/UI拼接工具.md)
- [MCP 工具](modules/frameworks/编辑器工具/MCP工具/README.md)
- [CrystalBattle Codex 与 Unity MCP 使用规则](modules/frameworks/编辑器工具/MCP工具/CrystalBattle_Codex_Unity_MCP使用规则.md)
## 🎯 快速入门 ## 工作方式
| 场景 | 推荐文档 | - UnityAI 定义通用标准,不把单个项目的业务实现写成框架强制规则。
|-----|---------| - 重大变更按 [工作流清单](rules/40-工作流清单.md) 在对话中确认,长期结论直接更新模块文档。
| 新人开发 | `02_开发规范/开发规范指南.md` | - 公共接口、架构和稳定流程变化后,直接更新对应模块文档。
| 使用对象池 | `03_核心功能/对象池使用指南.md` | - `ESF_` 框架源码通过 CopyToX 生成 `HF_` 代码,生成目录禁止手改。
| 使用事件系统 | `03_核心功能/事件系统使用指南.md` | - Git 提交和推送只在用户明确要求时执行,文档仓库与 Unity 项目分别处理。
| 遇到问题 | `04_开发流程/常见问题指南.md` |
--- ## 业务参考
**版本**: v1.0 - [PlayBalloons 业务参考](business-reference/playballoons/):外部项目案例,不作为框架规范。
**适用项目**: GiftGameX
## 文档关联
| 文档 | 关联原因 |
|---|---|
| [AI 工具接入入口](ai/AI接入入口.md) | AI 工具统一入口 |
| [项目规则入口](rules/项目规则入口.md) | 项目规则总入口 |
| [模块索引](modules/模块索引.md) | 模块清单与状态 |
| [项目概览](rules/00-项目概览.md) | UnityAI 定位与适用范围 |

21
RULES.md Normal file
View File

@@ -0,0 +1,21 @@
# UnityAI 通用入口
本文件是给其他 AI、IDE 或人工快速查看的兼容入口。
**请先读取:[ai/AI接入入口.md](ai/AI接入入口.md)**
---
> 本文件仅保留为兼容入口,不重复维护项目规则内容。
---
## 文档关联
> 当本文档发生变更时,应同步检查以下关联文档,避免信息不一致。
| 文档 | 关联原因 |
|---|---|
| [ai/AI接入入口.md](ai/AI接入入口.md) | RULES.md 是 AI 接入入口的兼容重定向 |
| [AGENTS.md](AGENTS.md) | AI 工具入口之一,需与 RULES.md 保持一致 |
| [CLAUDE.md](CLAUDE.md) | Claude Code 入口,需与 RULES.md 保持一致 |

2
Tools/CodexUnityMcp/.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
node_modules/
*.log

View File

@@ -0,0 +1,69 @@
# CrystalBattle Unity MCP
This local MCP server exposes selected CrystalBattle Unity Editor commands to Codex.
## Architecture
- Codex connects to this MCP server over stdio.
- The MCP server calls the Unity Editor bridge at `http://127.0.0.1:17777`.
- The Unity Editor bridge executes Unity API work on the editor main thread.
## Unity Setup
Open `CrystalBattle_Client` in Unity. The bridge starts automatically after scripts compile.
Manual controls are available from the bridge panel:
```text
Tools/Codex Unity MCP/Bridge Panel
```
The panel shows the current connection status, endpoint, listener thread state, pending command count, total request count, recent command, and cached log count. It also includes buttons to start, stop, restart, copy the endpoint, and print status to the Unity Console.
## Install Dependencies
From this directory:
```powershell
pnpm install
```
If `pnpm` is not on `PATH`, use the Codex bundled runtime:
```powershell
& "C:\Users\admin\.cache\codex-runtimes\codex-primary-runtime\dependencies\bin\pnpm.cmd" install
```
## Tools
- `unity_health`
- `unity_refresh_assets`
- `unity_execute_menu_item`
- `unity_get_console_logs`
- `unity_generate_ui_prefab`
- `unity_export_prefab_to_json`
## Environment
Optional:
```text
UNITY_MCP_BRIDGE_URL=http://127.0.0.1:17777
```
## Codex Config
The workspace includes `.codex/config.toml` with a `crystalbattle-unity` MCP server entry.
Restart Codex after dependency installation so the new MCP server is discovered.
---
## 文档关联
> 当本文档发生变更时,应同步检查以下关联文档,避免信息不一致。
| 文档 | 关联原因 |
|---|---|
| [MCP 工具](../../modules/frameworks/编辑器工具/MCP工具/README.md) | Codex ↔ Unity MCP 工具说明 |
| [CrystalBattle Codex ↔ Unity MCP 使用规则](../../modules/frameworks/编辑器工具/MCP工具/CrystalBattle_Codex_Unity_MCP使用规则.md) | 具体使用规则 |
| [modules/模块索引.md](../../modules/模块索引.md) | 模块索引是项目知识总入口 |

View File

@@ -0,0 +1,18 @@
{
"name": "codex-unity-mcp",
"version": "0.1.0",
"private": true,
"type": "module",
"description": "Local MCP server that exposes CrystalBattle Unity Editor commands to Codex.",
"main": "src/server.mjs",
"scripts": {
"start": "node src/server.mjs"
},
"dependencies": {
"@modelcontextprotocol/sdk": "^1.29.0",
"zod": "^3.25.76"
},
"engines": {
"node": ">=20"
}
}

784
Tools/CodexUnityMcp/pnpm-lock.yaml generated Normal file
View File

@@ -0,0 +1,784 @@
lockfileVersion: '9.0'
settings:
autoInstallPeers: true
excludeLinksFromLockfile: false
importers:
.:
dependencies:
'@modelcontextprotocol/sdk':
specifier: ^1.29.0
version: 1.29.0(zod@3.25.76)
zod:
specifier: ^3.25.76
version: 3.25.76
packages:
'@hono/node-server@1.19.14':
resolution: {integrity: sha512-GwtvgtXxnWsucXvbQXkRgqksiH2Qed37H9xHZocE5sA3N8O8O8/8FA3uclQXxXVzc9XBZuEOMK7+r02FmSpHtw==}
engines: {node: '>=18.14.1'}
peerDependencies:
hono: ^4
'@modelcontextprotocol/sdk@1.29.0':
resolution: {integrity: sha512-zo37mZA9hJWpULgkRpowewez1y6ML5GsXJPY8FI0tBBCd77HEvza4jDqRKOXgHNn867PVGCyTdzqpz0izu5ZjQ==}
engines: {node: '>=18'}
peerDependencies:
'@cfworker/json-schema': ^4.1.1
zod: ^3.25 || ^4.0
peerDependenciesMeta:
'@cfworker/json-schema':
optional: true
accepts@2.0.0:
resolution: {integrity: sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==}
engines: {node: '>= 0.6'}
ajv-formats@3.0.1:
resolution: {integrity: sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==}
peerDependencies:
ajv: ^8.0.0
peerDependenciesMeta:
ajv:
optional: true
ajv@8.20.0:
resolution: {integrity: sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==}
body-parser@2.3.0:
resolution: {integrity: sha512-2cGmJupaNgg+QUwVLAucDuWuoMZ6EX9iHDRswZ5lsNYEmwPaRknMPCLZz07yTzVq/83p4o/wzbDZbBrTvGGTIw==}
engines: {node: '>=18'}
bytes@3.1.2:
resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==}
engines: {node: '>= 0.8'}
call-bind-apply-helpers@1.0.2:
resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==}
engines: {node: '>= 0.4'}
call-bound@1.0.4:
resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==}
engines: {node: '>= 0.4'}
content-disposition@1.1.0:
resolution: {integrity: sha512-5jRCH9Z/+DRP7rkvY83B+yGIGX96OYdJmzngqnw2SBSxqCFPd0w2km3s5iawpGX8krnwSGmF0FW5Nhr0Hfai3g==}
engines: {node: '>=18'}
content-type@1.0.5:
resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==}
engines: {node: '>= 0.6'}
content-type@2.0.0:
resolution: {integrity: sha512-j/O/d7GcZCyNl7/hwZAb606rzqkyvaDctLmckbxLzHvFBzTJHuGEdodATcP3yIRoDrLHkIATJuvzbFlp/ki2cQ==}
engines: {node: '>=18'}
cookie-signature@1.2.2:
resolution: {integrity: sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==}
engines: {node: '>=6.6.0'}
cookie@0.7.2:
resolution: {integrity: sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==}
engines: {node: '>= 0.6'}
cors@2.8.6:
resolution: {integrity: sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw==}
engines: {node: '>= 0.10'}
cross-spawn@7.0.6:
resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==}
engines: {node: '>= 8'}
debug@4.4.3:
resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==}
engines: {node: '>=6.0'}
peerDependencies:
supports-color: '*'
peerDependenciesMeta:
supports-color:
optional: true
depd@2.0.0:
resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==}
engines: {node: '>= 0.8'}
dunder-proto@1.0.1:
resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==}
engines: {node: '>= 0.4'}
ee-first@1.1.1:
resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==}
encodeurl@2.0.0:
resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==}
engines: {node: '>= 0.8'}
es-define-property@1.0.1:
resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==}
engines: {node: '>= 0.4'}
es-errors@1.3.0:
resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==}
engines: {node: '>= 0.4'}
es-object-atoms@1.1.2:
resolution: {integrity: sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==}
engines: {node: '>= 0.4'}
escape-html@1.0.3:
resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==}
etag@1.8.1:
resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==}
engines: {node: '>= 0.6'}
eventsource-parser@3.1.0:
resolution: {integrity: sha512-kJezFj9YFAMLeORyi7aCLxLbD5/qWMQnoMVlVPyHIll7lgRJCc3JVln9Vgl9nwQi0YkMnhdGTMNn7CkRRAptMg==}
engines: {node: '>=18.0.0'}
eventsource@3.0.7:
resolution: {integrity: sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA==}
engines: {node: '>=18.0.0'}
express-rate-limit@8.5.2:
resolution: {integrity: sha512-5Kb34ipNX694DH48vN9irak1Qx30nb0PLYHXfJgw4YEjiC3ZEmZJhwOp+VfiCYwFzvFTdB9QkArYS5kXa2cx2A==}
engines: {node: '>= 16'}
peerDependencies:
express: '>= 4.11'
express@5.2.1:
resolution: {integrity: sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==}
engines: {node: '>= 18'}
fast-deep-equal@3.1.3:
resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==}
fast-uri@3.1.3:
resolution: {integrity: sha512-i70LwGWUduXqzicKXWshooq+sWL1K3WUU5rKZNG/0i3a1OSoX3HqhH5WbWwTmqWfor4urUakGPiRQcleRZTwOg==}
finalhandler@2.1.1:
resolution: {integrity: sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==}
engines: {node: '>= 18.0.0'}
forwarded@0.2.0:
resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==}
engines: {node: '>= 0.6'}
fresh@2.0.0:
resolution: {integrity: sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==}
engines: {node: '>= 0.8'}
function-bind@1.1.2:
resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==}
get-intrinsic@1.3.0:
resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==}
engines: {node: '>= 0.4'}
get-proto@1.0.1:
resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==}
engines: {node: '>= 0.4'}
gopd@1.2.0:
resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==}
engines: {node: '>= 0.4'}
has-symbols@1.1.0:
resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==}
engines: {node: '>= 0.4'}
hasown@2.0.4:
resolution: {integrity: sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==}
engines: {node: '>= 0.4'}
hono@4.12.27:
resolution: {integrity: sha512-1yrb/+w6HWQJrUCLkJ2IF5jNIPvvFkblV5RNOYl6bV+OA6p9GLcMpHFFGTosSvHvcAUibuUukRqhlYI4z32C7Q==}
engines: {node: '>=16.9.0'}
http-errors@2.0.1:
resolution: {integrity: sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==}
engines: {node: '>= 0.8'}
iconv-lite@0.7.2:
resolution: {integrity: sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==}
engines: {node: '>=0.10.0'}
inherits@2.0.4:
resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==}
ip-address@10.2.0:
resolution: {integrity: sha512-/+S6j4E9AHvW9SWMSEY9Xfy66O5PWvVEJ08O0y5JGyEKQpojb0K0GKpz/v5HJ/G0vi3D2sjGK78119oXZeE0qA==}
engines: {node: '>= 12'}
ipaddr.js@1.9.1:
resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==}
engines: {node: '>= 0.10'}
is-promise@4.0.0:
resolution: {integrity: sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==}
isexe@2.0.0:
resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
jose@6.2.3:
resolution: {integrity: sha512-YYVDInQKFJfR/xa3ojUTl8c2KoTwiL1R5Wg9YCydwH0x0B9grbzlg5HC7mMjCtUJjbQ/YnGEZIhI5tCgfTb4Hw==}
json-schema-traverse@1.0.0:
resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==}
json-schema-typed@8.0.2:
resolution: {integrity: sha512-fQhoXdcvc3V28x7C7BMs4P5+kNlgUURe2jmUT1T//oBRMDrqy1QPelJimwZGo7Hg9VPV3EQV5Bnq4hbFy2vetA==}
math-intrinsics@1.1.0:
resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==}
engines: {node: '>= 0.4'}
media-typer@1.1.0:
resolution: {integrity: sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==}
engines: {node: '>= 0.8'}
merge-descriptors@2.0.0:
resolution: {integrity: sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==}
engines: {node: '>=18'}
mime-db@1.54.0:
resolution: {integrity: sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==}
engines: {node: '>= 0.6'}
mime-types@3.0.2:
resolution: {integrity: sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==}
engines: {node: '>=18'}
ms@2.1.3:
resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
negotiator@1.0.0:
resolution: {integrity: sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==}
engines: {node: '>= 0.6'}
object-assign@4.1.1:
resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==}
engines: {node: '>=0.10.0'}
object-inspect@1.13.4:
resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==}
engines: {node: '>= 0.4'}
on-finished@2.4.1:
resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==}
engines: {node: '>= 0.8'}
once@1.4.0:
resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==}
parseurl@1.3.3:
resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==}
engines: {node: '>= 0.8'}
path-key@3.1.1:
resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==}
engines: {node: '>=8'}
path-to-regexp@8.4.2:
resolution: {integrity: sha512-qRcuIdP69NPm4qbACK+aDogI5CBDMi1jKe0ry5rSQJz8JVLsC7jV8XpiJjGRLLol3N+R5ihGYcrPLTno6pAdBA==}
pkce-challenge@5.0.1:
resolution: {integrity: sha512-wQ0b/W4Fr01qtpHlqSqspcj3EhBvimsdh0KlHhH8HRZnMsEa0ea2fTULOXOS9ccQr3om+GcGRk4e+isrZWV8qQ==}
engines: {node: '>=16.20.0'}
proxy-addr@2.0.7:
resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==}
engines: {node: '>= 0.10'}
qs@6.15.3:
resolution: {integrity: sha512-O9gl3zCl5h5blw1KGUzQKhA5oUXSl8rwUIM5o0S3nCXMliSvy5Dzx7/DJcI+SwgICv+IneSZwhBh1oSyEHA71A==}
engines: {node: '>=0.6'}
range-parser@1.3.0:
resolution: {integrity: sha512-hek2mFQpPuI4E1BBKrSto+BU3e3x4xuarsbiwr3+lf7p44juvFMV0XFWQAP3xUyqXA4RrXLIoaSUGbSt056ZMw==}
engines: {node: '>= 0.6'}
raw-body@3.0.2:
resolution: {integrity: sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==}
engines: {node: '>= 0.10'}
require-from-string@2.0.2:
resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==}
engines: {node: '>=0.10.0'}
router@2.2.0:
resolution: {integrity: sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==}
engines: {node: '>= 18'}
safer-buffer@2.1.2:
resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==}
send@1.2.1:
resolution: {integrity: sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==}
engines: {node: '>= 18'}
serve-static@2.2.1:
resolution: {integrity: sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==}
engines: {node: '>= 18'}
setprototypeof@1.2.0:
resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==}
shebang-command@2.0.0:
resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==}
engines: {node: '>=8'}
shebang-regex@3.0.0:
resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==}
engines: {node: '>=8'}
side-channel-list@1.0.1:
resolution: {integrity: sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==}
engines: {node: '>= 0.4'}
side-channel-map@1.0.1:
resolution: {integrity: sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==}
engines: {node: '>= 0.4'}
side-channel-weakmap@1.0.2:
resolution: {integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==}
engines: {node: '>= 0.4'}
side-channel@1.1.1:
resolution: {integrity: sha512-6x6dK6zJdpTzF4sQeNYxwtvBzf6Eg4GtlesS94HOvTudUeyK2WXAaIfmDgsyslYrRBeFIlsi54AYsFGUuhmvrQ==}
engines: {node: '>= 0.4'}
statuses@2.0.2:
resolution: {integrity: sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==}
engines: {node: '>= 0.8'}
toidentifier@1.0.1:
resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==}
engines: {node: '>=0.6'}
type-is@2.1.0:
resolution: {integrity: sha512-faYHw0anBbc/kWF3zFTEnxSFOAGUX9GFbOBthvDdLsIlEoWOFOtS0zgCiQYwIskL9iGXZL3kAXD8OoZ4GmMATA==}
engines: {node: '>= 18'}
unpipe@1.0.0:
resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==}
engines: {node: '>= 0.8'}
vary@1.1.2:
resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==}
engines: {node: '>= 0.8'}
which@2.0.2:
resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==}
engines: {node: '>= 8'}
hasBin: true
wrappy@1.0.2:
resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==}
zod-to-json-schema@3.25.2:
resolution: {integrity: sha512-O/PgfnpT1xKSDeQYSCfRI5Gy3hPf91mKVDuYLUHZJMiDFptvP41MSnWofm8dnCm0256ZNfZIM7DSzuSMAFnjHA==}
peerDependencies:
zod: ^3.25.28 || ^4
zod@3.25.76:
resolution: {integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==}
snapshots:
'@hono/node-server@1.19.14(hono@4.12.27)':
dependencies:
hono: 4.12.27
'@modelcontextprotocol/sdk@1.29.0(zod@3.25.76)':
dependencies:
'@hono/node-server': 1.19.14(hono@4.12.27)
ajv: 8.20.0
ajv-formats: 3.0.1(ajv@8.20.0)
content-type: 1.0.5
cors: 2.8.6
cross-spawn: 7.0.6
eventsource: 3.0.7
eventsource-parser: 3.1.0
express: 5.2.1
express-rate-limit: 8.5.2(express@5.2.1)
hono: 4.12.27
jose: 6.2.3
json-schema-typed: 8.0.2
pkce-challenge: 5.0.1
raw-body: 3.0.2
zod: 3.25.76
zod-to-json-schema: 3.25.2(zod@3.25.76)
transitivePeerDependencies:
- supports-color
accepts@2.0.0:
dependencies:
mime-types: 3.0.2
negotiator: 1.0.0
ajv-formats@3.0.1(ajv@8.20.0):
optionalDependencies:
ajv: 8.20.0
ajv@8.20.0:
dependencies:
fast-deep-equal: 3.1.3
fast-uri: 3.1.3
json-schema-traverse: 1.0.0
require-from-string: 2.0.2
body-parser@2.3.0:
dependencies:
bytes: 3.1.2
content-type: 2.0.0
debug: 4.4.3
http-errors: 2.0.1
iconv-lite: 0.7.2
on-finished: 2.4.1
qs: 6.15.3
raw-body: 3.0.2
type-is: 2.1.0
transitivePeerDependencies:
- supports-color
bytes@3.1.2: {}
call-bind-apply-helpers@1.0.2:
dependencies:
es-errors: 1.3.0
function-bind: 1.1.2
call-bound@1.0.4:
dependencies:
call-bind-apply-helpers: 1.0.2
get-intrinsic: 1.3.0
content-disposition@1.1.0: {}
content-type@1.0.5: {}
content-type@2.0.0: {}
cookie-signature@1.2.2: {}
cookie@0.7.2: {}
cors@2.8.6:
dependencies:
object-assign: 4.1.1
vary: 1.1.2
cross-spawn@7.0.6:
dependencies:
path-key: 3.1.1
shebang-command: 2.0.0
which: 2.0.2
debug@4.4.3:
dependencies:
ms: 2.1.3
depd@2.0.0: {}
dunder-proto@1.0.1:
dependencies:
call-bind-apply-helpers: 1.0.2
es-errors: 1.3.0
gopd: 1.2.0
ee-first@1.1.1: {}
encodeurl@2.0.0: {}
es-define-property@1.0.1: {}
es-errors@1.3.0: {}
es-object-atoms@1.1.2:
dependencies:
es-errors: 1.3.0
escape-html@1.0.3: {}
etag@1.8.1: {}
eventsource-parser@3.1.0: {}
eventsource@3.0.7:
dependencies:
eventsource-parser: 3.1.0
express-rate-limit@8.5.2(express@5.2.1):
dependencies:
express: 5.2.1
ip-address: 10.2.0
express@5.2.1:
dependencies:
accepts: 2.0.0
body-parser: 2.3.0
content-disposition: 1.1.0
content-type: 1.0.5
cookie: 0.7.2
cookie-signature: 1.2.2
debug: 4.4.3
depd: 2.0.0
encodeurl: 2.0.0
escape-html: 1.0.3
etag: 1.8.1
finalhandler: 2.1.1
fresh: 2.0.0
http-errors: 2.0.1
merge-descriptors: 2.0.0
mime-types: 3.0.2
on-finished: 2.4.1
once: 1.4.0
parseurl: 1.3.3
proxy-addr: 2.0.7
qs: 6.15.3
range-parser: 1.3.0
router: 2.2.0
send: 1.2.1
serve-static: 2.2.1
statuses: 2.0.2
type-is: 2.1.0
vary: 1.1.2
transitivePeerDependencies:
- supports-color
fast-deep-equal@3.1.3: {}
fast-uri@3.1.3: {}
finalhandler@2.1.1:
dependencies:
debug: 4.4.3
encodeurl: 2.0.0
escape-html: 1.0.3
on-finished: 2.4.1
parseurl: 1.3.3
statuses: 2.0.2
transitivePeerDependencies:
- supports-color
forwarded@0.2.0: {}
fresh@2.0.0: {}
function-bind@1.1.2: {}
get-intrinsic@1.3.0:
dependencies:
call-bind-apply-helpers: 1.0.2
es-define-property: 1.0.1
es-errors: 1.3.0
es-object-atoms: 1.1.2
function-bind: 1.1.2
get-proto: 1.0.1
gopd: 1.2.0
has-symbols: 1.1.0
hasown: 2.0.4
math-intrinsics: 1.1.0
get-proto@1.0.1:
dependencies:
dunder-proto: 1.0.1
es-object-atoms: 1.1.2
gopd@1.2.0: {}
has-symbols@1.1.0: {}
hasown@2.0.4:
dependencies:
function-bind: 1.1.2
hono@4.12.27: {}
http-errors@2.0.1:
dependencies:
depd: 2.0.0
inherits: 2.0.4
setprototypeof: 1.2.0
statuses: 2.0.2
toidentifier: 1.0.1
iconv-lite@0.7.2:
dependencies:
safer-buffer: 2.1.2
inherits@2.0.4: {}
ip-address@10.2.0: {}
ipaddr.js@1.9.1: {}
is-promise@4.0.0: {}
isexe@2.0.0: {}
jose@6.2.3: {}
json-schema-traverse@1.0.0: {}
json-schema-typed@8.0.2: {}
math-intrinsics@1.1.0: {}
media-typer@1.1.0: {}
merge-descriptors@2.0.0: {}
mime-db@1.54.0: {}
mime-types@3.0.2:
dependencies:
mime-db: 1.54.0
ms@2.1.3: {}
negotiator@1.0.0: {}
object-assign@4.1.1: {}
object-inspect@1.13.4: {}
on-finished@2.4.1:
dependencies:
ee-first: 1.1.1
once@1.4.0:
dependencies:
wrappy: 1.0.2
parseurl@1.3.3: {}
path-key@3.1.1: {}
path-to-regexp@8.4.2: {}
pkce-challenge@5.0.1: {}
proxy-addr@2.0.7:
dependencies:
forwarded: 0.2.0
ipaddr.js: 1.9.1
qs@6.15.3:
dependencies:
es-define-property: 1.0.1
side-channel: 1.1.1
range-parser@1.3.0: {}
raw-body@3.0.2:
dependencies:
bytes: 3.1.2
http-errors: 2.0.1
iconv-lite: 0.7.2
unpipe: 1.0.0
require-from-string@2.0.2: {}
router@2.2.0:
dependencies:
debug: 4.4.3
depd: 2.0.0
is-promise: 4.0.0
parseurl: 1.3.3
path-to-regexp: 8.4.2
transitivePeerDependencies:
- supports-color
safer-buffer@2.1.2: {}
send@1.2.1:
dependencies:
debug: 4.4.3
encodeurl: 2.0.0
escape-html: 1.0.3
etag: 1.8.1
fresh: 2.0.0
http-errors: 2.0.1
mime-types: 3.0.2
ms: 2.1.3
on-finished: 2.4.1
range-parser: 1.3.0
statuses: 2.0.2
transitivePeerDependencies:
- supports-color
serve-static@2.2.1:
dependencies:
encodeurl: 2.0.0
escape-html: 1.0.3
parseurl: 1.3.3
send: 1.2.1
transitivePeerDependencies:
- supports-color
setprototypeof@1.2.0: {}
shebang-command@2.0.0:
dependencies:
shebang-regex: 3.0.0
shebang-regex@3.0.0: {}
side-channel-list@1.0.1:
dependencies:
es-errors: 1.3.0
object-inspect: 1.13.4
side-channel-map@1.0.1:
dependencies:
call-bound: 1.0.4
es-errors: 1.3.0
get-intrinsic: 1.3.0
object-inspect: 1.13.4
side-channel-weakmap@1.0.2:
dependencies:
call-bound: 1.0.4
es-errors: 1.3.0
get-intrinsic: 1.3.0
object-inspect: 1.13.4
side-channel-map: 1.0.1
side-channel@1.1.1:
dependencies:
es-errors: 1.3.0
object-inspect: 1.13.4
side-channel-list: 1.0.1
side-channel-map: 1.0.1
side-channel-weakmap: 1.0.2
statuses@2.0.2: {}
toidentifier@1.0.1: {}
type-is@2.1.0:
dependencies:
content-type: 2.0.0
media-typer: 1.1.0
mime-types: 3.0.2
unpipe@1.0.0: {}
vary@1.1.2: {}
which@2.0.2:
dependencies:
isexe: 2.0.0
wrappy@1.0.2: {}
zod-to-json-schema@3.25.2(zod@3.25.76):
dependencies:
zod: 3.25.76
zod@3.25.76: {}

View File

@@ -0,0 +1,165 @@
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";
const DEFAULT_BRIDGE_URL = "http://127.0.0.1:17777";
const DEFAULT_TIMEOUT_MS = 30000;
const LONG_TIMEOUT_MS = 120000;
const bridgeUrl = (process.env.UNITY_MCP_BRIDGE_URL || DEFAULT_BRIDGE_URL).replace(/\/+$/, "");
const server = new McpServer({
name: "crystalbattle-unity",
version: "0.1.0"
});
server.registerTool(
"unity_health",
{
title: "Unity health",
description: "Check whether the CrystalBattle Unity Editor bridge is online.",
inputSchema: {}
},
async () => textResult(await getHealth())
);
server.registerTool(
"unity_refresh_assets",
{
title: "Refresh Unity assets",
description: "Run AssetDatabase.Refresh in the Unity Editor.",
inputSchema: {}
},
async () => textResult(await callUnity("refresh_assets", {}, DEFAULT_TIMEOUT_MS))
);
server.registerTool(
"unity_execute_menu_item",
{
title: "Execute Unity menu item",
description: "Execute a whitelisted Unity Editor menu item.",
inputSchema: {
menuItem: z.string().min(1).describe("Whitelisted Unity menu item path, for example Assets/Refresh.")
}
},
async ({ menuItem }) => textResult(await callUnity("execute_menu_item", { menuItem }, DEFAULT_TIMEOUT_MS))
);
server.registerTool(
"unity_get_console_logs",
{
title: "Get Unity console logs",
description: "Return recent logs captured by the Unity Editor bridge.",
inputSchema: {
limit: z.number().int().min(1).max(200).optional().describe("Maximum number of log entries to return.")
}
},
async ({ limit = 50 }) => textResult(await callUnity("get_console_logs", { limit }, DEFAULT_TIMEOUT_MS))
);
server.registerTool(
"unity_generate_ui_prefab",
{
title: "Generate UI prefab",
description: "Generate a Unity UI prefab from a JSON layout file.",
inputSchema: {
jsonPath: z.string().min(1).describe("JSON layout path. Absolute paths and Unity-project-relative paths are supported."),
prefabPath: z.string().min(1).optional().describe("Optional Unity asset path for the generated prefab.")
}
},
async ({ jsonPath, prefabPath }) =>
textResult(await callUnity("generate_ui_prefab", { jsonPath, prefabPath }, LONG_TIMEOUT_MS))
);
server.registerTool(
"unity_export_prefab_to_json",
{
title: "Export prefab to JSON",
description: "Export a Unity UI prefab to a JSON layout file.",
inputSchema: {
prefabPath: z.string().min(1).describe("Unity asset path of the prefab to export."),
jsonPath: z.string().min(1).optional().describe("Optional output JSON path.")
}
},
async ({ prefabPath, jsonPath }) =>
textResult(await callUnity("export_prefab_to_json", { prefabPath, jsonPath }, LONG_TIMEOUT_MS))
);
async function getHealth() {
const response = await request(`${bridgeUrl}/health`, {
method: "GET",
timeoutMs: DEFAULT_TIMEOUT_MS
});
return response;
}
async function callUnity(command, args, timeoutMs) {
return request(`${bridgeUrl}/command`, {
method: "POST",
timeoutMs,
body: {
id: `${command}-${Date.now()}`,
command,
args: stripUndefined(args)
}
});
}
async function request(url, options) {
const controller = new AbortController();
const timeout = setTimeout(() => controller.abort(), options.timeoutMs);
try {
const response = await fetch(url, {
method: options.method,
signal: controller.signal,
headers: options.body ? { "content-type": "application/json" } : undefined,
body: options.body ? JSON.stringify(options.body) : undefined
});
const text = await response.text();
let payload;
try {
payload = text ? JSON.parse(text) : {};
} catch {
payload = { ok: false, message: text || "Unity bridge returned a non-JSON response." };
}
if (!response.ok && payload.ok !== false) {
payload.ok = false;
payload.message = payload.message || `Unity bridge returned HTTP ${response.status}.`;
}
return payload;
} catch (error) {
const reason = error.name === "AbortError"
? `Timed out after ${options.timeoutMs} ms.`
: error.message;
return {
ok: false,
message: `Unity Editor bridge is not reachable at ${bridgeUrl}. ${reason}`,
data: {},
logs: []
};
} finally {
clearTimeout(timeout);
}
}
function stripUndefined(value) {
return Object.fromEntries(Object.entries(value).filter(([, item]) => item !== undefined));
}
function textResult(payload) {
return {
content: [
{
type: "text",
text: JSON.stringify(payload, null, 2)
}
]
};
}
const transport = new StdioServerTransport();
await server.connect(transport);

59
ai/AI接入入口.md Normal file
View File

@@ -0,0 +1,59 @@
# AI 工具接入入口
本文件是 Codex、Claude Code、Cursor、Windsurf、GitHub Copilot 等工具进入 UnityAI 的统一入口。根目录 `AGENTS.md``CLAUDE.md``RULES.md` 只负责跳转,不复制项目规则。
## 读取顺序
1. [项目规则入口](../rules/项目规则入口.md)
2. [工作流清单](../rules/40-工作流清单.md)
3. [模块索引](../modules/模块索引.md)
4. 任务相关的模块文档
5. [共享检查](../hooks/Hook共享层.md)
随后读取目标 Unity 项目的真实代码、Prefab、配置、项目版本和 Git 状态。UnityAI 是通用标准,具体工程是实现和验证依据。
## 文档分层
| 层级 | 位置 | 用途 |
|---|---|---|
| AI 接入 | `ai/AI接入入口.md` | 工具如何进入工作流 |
| 项目规则 | `rules/` | 架构、开发、工作流、文档同步和扫描范围 |
| 框架知识 | `modules/` | 模块职责、API、数据流和验证方式 |
| 业务参考 | `business-reference/` | 外部项目案例,不定义框架标准 |
| 共享检查 | `hooks/` | 只读工作流检查和提交检查 |
| 可执行工具 | `Tools/` | MCP Server 等工具实现 |
重大变更的确认和长期文档落盘方式统一遵循 [工作流清单](../rules/40-工作流清单.md)。
## 工具接入原则
- 工具专属入口只链接本文件,不复制 `rules/``modules/` 内容。
- 只有用户明确要求提交或推送时才执行 Git 写操作。
- UnityAI 与目标 Unity 项目分别检查、验证和提交。
- 任务结束时运行只读工作流检查:
```powershell
powershell -NoProfile -ExecutionPolicy Bypass -File hooks/workflow-check.ps1 `
-UnityProjectRoot <Unity工程路径>
```
- 检查脚本只给出状态、生成边界、验证和文档建议,不自动写文件。
## 接入新工具
1. 确认工具自动读取的入口文件。
2. 在入口文件中链接本文件。
3. 如支持任务结束命令,调用 `hooks/workflow-check.ps1`
4. 不在工具私有目录维护项目规则副本。
## 文档关联
| 文档 | 关联原因 |
|---|---|
| [AGENTS.md](../AGENTS.md) | Codex 入口 |
| [CLAUDE.md](../CLAUDE.md) | Claude Code 入口 |
| [RULES.md](../RULES.md) | 通用兼容入口 |
| [项目规则入口](../rules/项目规则入口.md) | 项目规则总入口 |
| [工作流清单](../rules/40-工作流清单.md) | 唯一任务流程 |
| [模块索引](../modules/模块索引.md) | 项目知识入口 |
| [共享检查](../hooks/Hook共享层.md) | 脚本入口 |

View File

@@ -0,0 +1,134 @@
# GM/调试功能
## 分类
- 项目功能
## 目的
记录 GM 面板、调试请求、测试入口和开发验证流程。
## 已知线索
- UI 路径:`Assets/Game/GameHFScripte/GameFunction/UIWindows/GMWindow/`
- 背包数据:`GMWindow_BagData.cs`
- 请求配置:`GMWindow_GM.cs`
- 能看到背包、战斗、商店等调试请求线索。
## 已确认内容
窗口定义:
```text
GMWindow : AbsHFUIWindow
-> [HFAssetBundlePath(..., "UIWindows/GMWindow/GMWindow.prefab")]
-> [HFUIWindowLayer(UIWindow, Popup)]
```
生命周期:
```text
GMWindow.OnRunAwake()
-> OnRunAwake_BagData()
-> OnRunAwake_GM()
GMWindow.OnOpen()
-> OnOpen_BagData()
-> OnOpen_GM()
GMWindow.OnClose()
-> OnClose_BagData()
-> OnClose_GM()
```
GM 请求结构:
```text
GM_Network_MsgId
-> msgId : Network_MsgId
-> tip
-> args : List<GM_Network_MsgId_Arg>
GM_Network_MsgId_Arg
-> tip
-> contentType
-> value
```
发送链路:
```text
点击 btnSendGM
-> OnSendGM()
-> new GMC2S()
-> gmC2S.Msgid = (int)selected.msgId
-> gmC2S.Args.AddRange(...)
-> HFSeverManager.Instance.SendMsg(gmC2S)
```
当前 GM 覆盖范围:
- 背包:
- 请求背包数据:`GetBagItem`
- 添加道具:`PlayerResourceChange`
- 关卡:
- `BattleLevelEnter`
- `BattleLevelExit`
- `BattleLevelWin`
- `BattleLevelFail`
- 用户外围数据:
- 设置关卡完成波数:`SetUserRolePeripheryLevelWaveProgress`
- 领取用户关卡进度奖励:`UserRolePeripheryClaimedProgressReward1Reward`
- 时间:
- `GetServerTimeStamp`
- 宝箱:
- 添加用户宝箱:`AddUserRolePeripheryTreasureChest`
- 删除用户宝箱:`DelUserRolePeripheryTreasureChest`
- 获取/开启/领取/结束冷却相关操作存在注释。
- 商店:
- `SetDailyFeaturedTotalRefreshCount` 使用硬编码 `(Network_MsgId)7090`
- Tower
- 上阵、下阵、升级、添加 Tower 的 GM 配置块存在,但全部注释。
当前接入状态:
- GMWindow 本身是完整 UI 窗口。
- GM 请求通过统一 `GMC2S` 包装真实业务 `Network_MsgId` 和参数。
- 未看到明显的开发环境开关MainWindow 中 GM 按钮也有编辑器开关注释,当前入口是否开放待确认。
## 梳理任务
- [ ] 梳理 GMWindow 打开入口。
- [x] 梳理 GM 请求结构和参数配置。
- [x] 梳理 GM 对背包、PVE、商店等功能的覆盖范围。
- [ ] 梳理 GM 功能是否只在开发环境启用。
- [x] 梳理 GM 请求和网络框架的关系。
## 待确认
- GMWindow 的正式打开入口待确认。
- 是否有权限/环境开关待确认。
- 是否允许线上包保留 GM 面板待确认。
- GM 操作通过服务器 GM 协议,有修改服务器数据的能力风险,需要上线前明确禁用策略。
## 相关框架
- [UI 框架](../../../modules/frameworks/UI窗口系统/README.md)
- [网络框架](../../../modules/frameworks/网络系统.md)
- [事件框架](../../../modules/frameworks/事件系统/README.md)
---
## 文档关联
> 当本文档发生变更时,应同步检查以下关联文档,避免信息不一致。
| 文档 | 关联原因 |
|---|---|
| [modules/模块索引.md](../../../modules/模块索引.md) | 模块索引是项目知识总入口 |
| [modules/frameworks/事件系统/README.md](../../../modules/frameworks/事件系统/README.md) | 事件框架 |
| [modules/frameworks/网络系统.md](../../../modules/frameworks/网络系统.md) | 网络框架 |
| [modules/frameworks/UI窗口系统/README.md](../../../modules/frameworks/UI窗口系统/README.md) | UI 框架 |
| [rules/10-架构说明.md](../../../rules/10-架构说明.md) | 架构说明定义总体分层和依赖方向 |
| [rules/30-模块登记规则.md](../../../rules/30-模块登记规则.md) | 模块登记规则定义分类和状态口径 |
| TODO补充依赖的框架/模块文档 | 如 UI、网络、事件、配置等框架 |

View File

@@ -0,0 +1,94 @@
# PVE/关卡战斗
## 分类
- 项目功能
## 目的
记录 PVE 关卡进入、战斗流程、胜负结算、波次和奖励逻辑。
## 已知线索
- 逻辑路径:`Assets/Game/GameHFScripte/GameFunction/Logic/GameScenes/`
- 地图路径:`Assets/Game/GameHFScripte/GameFunction/Logic/MapManager/`
- 伤害路径:`Assets/Game/GameHFScripte/GameFunction/Logic/DamageManager/`
- 地图资源:`Assets/Game/GameHFResource/CN/Map/`
- 网络消息线索:`BattleLevelEnter``BattleLevelExit``BattleLevelWin``BattleLevelFail`
- 配置线索:`XLSX_SRC/CN/Wave.xlsx`
## 已确认内容
当前 PVE/关卡战斗处于“有核心框架和协议线索,但主流程接入不完整或待确认”的状态。
已确认的子系统:
- `HFWaveManager`:从 `HFFunCatalogue.NDB.ds_WaveD0D9AA20TableData.ReadTableList()` 读取波次配置。
- `WaveInfo`:根据 `WaveTime``WaveID``WaveHpInc``GateFirst` 生成波次信息。
- `CreateMonsterInfo`:解析 `start_end_delay_monsterId_count` 格式的发怪配置。
- `HFMapManager.CreateMap(levelid, finish)`:当前会先 `ClearMap()`,再通过 `HFFunCatalogue.Asset.LoadAsset(1501, ...)` 加载地图 prefab。
- `HFDamageManager`存在伤害计算、掉落、死亡事件、HUD 飘字逻辑,但大部分实现当前被注释。
- 网络协议和事件已生成:`BattleLevelEnter``BattleLevelExit``BattleLevelWin``BattleLevelFail`
`HFWaveManager` 当前有 Editor GUI 调试入口:
```text
OnRunGUI
-> 按钮“游戏开始”
-> InitCampWaveInfo(Red/Blue)
-> TryCreateMonster
```
`OnRunFixedUpdate` 每秒尝试发怪:
```text
OnRunFixedUpdate
-> TryCreateMonster
-> CampWaveInfo.TryCreateMonster
-> WaveInfo.TryCreateMonster
-> CreateMonsterInfo.TryCreateMonster
```
## 梳理任务
- [ ] 找到 PVE 入口:从主界面、地图或 GM 进入关卡的调用点。
- [ ] 梳理关卡状态:进入、战斗中、胜利、失败、退出。
- [x] 梳理波次配置和怪物/实体生成关系。
- [x] 梳理伤害计算和实体框架之间的关系。
- [ ] 梳理结算奖励如何进入背包和奖励展示。
- [x] 梳理 PVE 相关网络消息和事件。
## 待确认
- 是否有明确的 PVE manager。
- 战斗是纯本地模拟、服务器校验,还是服务器主导。
- `GameScenes``MapManager``LineManager` 在 PVE 中的边界。
- `HFMapManager.CreateMap``levelid` 当前未用于读表,资源 id 固定为 `1501`,是否临时逻辑待确认。
- `HFWaveManager` 是否只通过 Editor GUI 调试启动,还是存在运行时入口待确认。
- `HFDamageManager` 大量逻辑被注释,当前战斗伤害是否启用待确认。
## 相关框架
- [实体框架](../../../modules/frameworks/实体系统/README.md)
- [场景框架](../../../modules/frameworks/场景系统.md)
- [网络框架](../../../modules/frameworks/网络系统.md)
- [事件框架](../../../modules/frameworks/事件系统/README.md)
- [数据/配置框架](../../../modules/frameworks/数据配置框架.md)
---
## 文档关联
> 当本文档发生变更时,应同步检查以下关联文档,避免信息不一致。
| 文档 | 关联原因 |
|---|---|
| [modules/模块索引.md](../../../modules/模块索引.md) | 模块索引是项目知识总入口 |
| [modules/frameworks/数据配置框架.md](../../../modules/frameworks/数据配置框架.md) | 数据/配置框架 |
| [modules/frameworks/实体系统/README.md](../../../modules/frameworks/实体系统/README.md) | 实体框架 |
| [modules/frameworks/事件系统/README.md](../../../modules/frameworks/事件系统/README.md) | 事件框架 |
| [modules/frameworks/网络系统.md](../../../modules/frameworks/网络系统.md) | 网络框架 |
| [modules/frameworks/场景系统.md](../../../modules/frameworks/场景系统.md) | 场景框架 |
| [rules/10-架构说明.md](../../../rules/10-架构说明.md) | 架构说明定义总体分层和依赖方向 |
| [rules/30-模块登记规则.md](../../../rules/30-模块登记规则.md) | 模块登记规则定义分类和状态口径 |
| TODO补充依赖的框架/模块文档 | 如 UI、网络、事件、配置等框架 |

View File

@@ -0,0 +1,80 @@
# PVP
## 分类
- 项目功能
## 目的
记录 PVP 是否存在、入口、协议、匹配、战斗和结算流程。
## 已知线索
- 当前未在初步扫描中发现明确的 PVP 目录或关键词。
## 已确认内容
已搜索关键词:
- `PVP`
- `PvP`
- `pvp`
- `Arena`
- `Rank`
- `Duel`
- `竞技`
- `排行`
- `匹配`
搜索范围:
- `Assets/Game/GameHFScripte/`
- `Assets/AutoBuildScript/`
- `XLSX_SRC/`
- `Assets/Editor/XLSX_SRC/`
结果:
- 未发现明确 PVP / 竞技场 / 排行 / 匹配业务代码。
- 未发现 PVP 相关 UIWindow。
- 未发现 PVP 相关配置表。
- 未发现 PVP 相关 protobuf 消息。
- 搜到的“匹配”均为正则匹配工具注释,不属于业务功能。
当前判断:
- 当前工程未发现 PVP 实现。
- 该模块目前只作为规划/占位模块保留。
## 梳理任务
- [x] 全局搜索 PVP、Arena、Match、Rank、Opponent 等关键词。
- [x] 检查 protobuf 是否有 PVP/匹配/排行相关消息。
- [x] 检查配置表是否有 PVP、竞技场或排行配置。
- [x] 检查 UIWindows 是否有隐藏或未接入的 PVP 窗口。
- [ ] 确认项目当前是否规划 PVP。
## 待确认
- 是否产品规划中存在 PVP。
- 如果短期不做,可以从模块索引移除,或保持为“规划占位”。
## 相关框架
- [网络框架](../../../modules/frameworks/网络系统.md)
- [PVE/关卡战斗](PVE关卡战斗.md)
---
## 文档关联
> 当本文档发生变更时,应同步检查以下关联文档,避免信息不一致。
| 文档 | 关联原因 |
|---|---|
| [modules/模块索引.md](../../../modules/模块索引.md) | 模块索引是项目知识总入口 |
| [modules/features/PVE关卡战斗.md](PVE关卡战斗.md) | PVE/关卡战斗 |
| [modules/frameworks/网络系统.md](../../../modules/frameworks/网络系统.md) | 网络框架 |
| [rules/10-架构说明.md](../../../rules/10-架构说明.md) | 架构说明定义总体分层和依赖方向 |
| [rules/30-模块登记规则.md](../../../rules/30-模块登记规则.md) | 模块登记规则定义分类和状态口径 |
| TODO补充依赖的框架/模块文档 | 如 UI、网络、事件、配置等框架 |

View File

@@ -0,0 +1,128 @@
# 商店
## 分类
- 项目功能
## 目的
记录商店商品、购买、货币消耗、体力/资源购买和商店 UI 入口。
## 已知线索
- GM 线索:`Assets/Game/GameHFScripte/GameFunction/UIWindows/GMWindow/GMWindow_GM.cs` 中有商店模块注释。
- Tips 线索:`Tips_GetPower` 引用 `ShopGoodsInfo`
- 图集线索:`SpriteAtlasAssets/Shop`
- 代码中可见 `ShopWindow``ShopGetCurrency` 注释引用。
## 已确认内容
协议和数据结构已生成:
- `Network_MsgId.GetShop = 2500`
- `Network_MsgId.ShopBuy = 2501`
- `Network_MsgId.ShopRefresh = 2502`
- `HFEvent_STC_GetShopS2C`
- `HFEvent_STC_ShopBuyS2C`
- `HFEvent_STC_ShopRefreshS2C`
请求/响应字段:
```text
GetShopC2S
-> ShopId
GetShopS2C
-> repeated ShopInfo
ShopBuyC2S
-> GoodsId
-> BuyType
ShopBuyS2C
-> ShopId
-> Goods
-> Item
ShopRefreshC2S
-> ShopId
-> RefreshType
ShopRefreshS2C
-> Shop
```
核心数据结构在:
- `Assets/Game/GameHFScripte/CopyToHF/Network/Player.cs`
- `Assets/Game/GameHFScripte/CopyToHF/Network/Common.cs`
```text
ShopInfo
-> ShopId
-> RefreshInfo : Map<int, ShopRefreshInfo>
-> Goods : Map<int, ShopGoodsInfo>
ShopGoodsInfo
-> GoodsId
-> BuyNum : Map<int, GoodsBuyNumInfo>
-> Item
ShopRefreshInfo
-> RefreshType
-> RefreshNum
GoodsBuyNumInfo
-> BuyType
-> BuyNum
```
体力购买相关:
- `Tips_GetPower` 是当前能看到的体力购买/领取 UI 线索。
- `Tips_GetPower` 读取 `Constants.PurchaseStamina`
- `Tips_GetPower` 监听 `HFEvent_BagItemUpdate` 刷新展示。
- `Stamina_QueryC2S` / `Stamina_GetC2S` 协议已生成,但当前未看到实际发送点。
当前接入状态:
- `MainWindow``OpenWindow<ShopWindow>``ShopGetCurrency``Tips_GetPower` 入口大多处于注释状态。
- 未发现 `GetShopC2S``ShopBuyC2S``ShopRefreshC2S` 在业务代码中的实际发送点。
- 未发现独立商店 manager。
- 因此当前判断:商店协议和部分 UI/资源痕迹存在,但客户端业务主流程未完整接入或处于注释/待开发状态。
## 梳理任务
- [x] 查找是否存在独立商店 manager、window 或配置表。
- [x] 梳理商品数据结构和 `ShopGoodsInfo` 来源。
- [ ] 梳理购买流程:打开、选择、校验、扣费、到账。
- [x] 梳理商店与背包、资源、体力之间的关系。
- [x] 确认当前商店功能是完整实现、部分接入还是已注释/待开发。
## 待确认
- 是否存在未纳入当前工程的 `ShopWindow``ShopGetCurrency` 或旧分支代码。
- 是否存在 `Shop.xlsx``Goods.xlsx``DailyDeals.xlsx` 等相关配置;当前配置列表未登记这些表,但生成代码里有旧表痕迹。
- 商店是否区分普通商店、体力购买、礼包、广告等类型。
- 商店 UI 当前看起来未接入,需要后续确认是否是产品阶段未启用。
## 相关框架
- [背包](背包.md)
- [UI 框架](../../../modules/frameworks/UI窗口系统/README.md)
- [网络框架](../../../modules/frameworks/网络系统.md)
- [数据/配置框架](../../../modules/frameworks/数据配置框架.md)
---
## 文档关联
> 当本文档发生变更时,应同步检查以下关联文档,避免信息不一致。
| 文档 | 关联原因 |
|---|---|
| [modules/模块索引.md](../../../modules/模块索引.md) | 模块索引是项目知识总入口 |
| [modules/features/背包.md](背包.md) | 背包 |
| [modules/frameworks/数据配置框架.md](../../../modules/frameworks/数据配置框架.md) | 数据/配置框架 |
| [modules/frameworks/网络系统.md](../../../modules/frameworks/网络系统.md) | 网络框架 |
| [modules/frameworks/UI窗口系统/README.md](../../../modules/frameworks/UI窗口系统/README.md) | UI 框架 |
| [rules/10-架构说明.md](../../../rules/10-架构说明.md) | 架构说明定义总体分层和依赖方向 |
| [rules/30-模块登记规则.md](../../../rules/30-模块登记规则.md) | 模块登记规则定义分类和状态口径 |
| TODO补充依赖的框架/模块文档 | 如 UI、网络、事件、配置等框架 |

View File

@@ -0,0 +1,148 @@
# 地图/关卡进度
## 分类
- 项目功能
## 目的
记录地图、关卡、波次、进度奖励和关卡状态。
## 已知线索
- 地图逻辑:`Assets/Game/GameHFScripte/GameFunction/Logic/MapManager/`
- 关卡资源:`Assets/Game/GameHFResource/CN/Map/Level.prefab`
- 配置线索:`XLSX_SRC/CN/Wave.xlsx`
- 网络线索:`UserRolePeripheryProgressReward*`
## 已确认内容
地图加载:
```text
HFMapManager.CreateMap(levelid, finish)
-> ClearMap()
-> HFFunCatalogue.Asset.LoadAsset(1501)
-> GetOrAddComponent<HFM_DLevelSetting>()
-> OnSetFinishLoad()
```
当前 `CreateMap` 传入了 `levelid`,但实际读取关卡配置的代码被注释:
```text
// MapInfo = HFFunCatalogue.NDB.ds_Level83D033B2TableData.ReadTableByPK(levelid);
```
地图配置数据:
- `stMapInfo` 使用 `MemoryPack`,包含障碍物/实体位置列表 `ObstaclesPos`
- `stMapEntityInfo` 包含 `Postion``EntityId``CellIndexs`
- `HF_MapEditor` 可以保存/读取地图配置文件到 `Assets/Game/GameHFResource/CN/MapInfoData/<Configuration>.txt`,但实体加载/放置代码大多处于注释状态。
- `HFM_MapSetting` 记录地图出生点、终点、Hero 引用。
- `HF_WaveInfo` 记录波次中的起止时间、怪物 id、数量和 Boss 卡显示等。
关卡/波次协议:
- `GetLevelInfo = 3004`
- `GetLevelWaveReward = 3005`
- `BattleLevelEnter = 3000`
- `BattleLevelExit = 3001`
- `BattleLevelWin = 3002`
- `BattleLevelFail = 3003`
字段线索:
```text
GetLevelInfoS2C
-> Levels
GetLevelWaveRewardC2S
-> Id
-> Wave
GetLevelWaveRewardS2C
-> Level
-> Item
BattleLevelEnterC2S
-> Id
BattleLevelWinC2S
-> Id
-> ChestType
-> KillMons
-> MaxWave
BattleLevelFailC2S
-> Id
-> MaxWave
-> KillMons
```
外围进度奖励协议:
- `GetUserRolePeripheryProgressReward1Data = 5000`
- `UserRolePeripheryClaimedProgressReward1Reward = 5001`
- `SetUserRolePeripheryLevelWaveProgress = 5901`,当前主要在 GM 调试入口看到。
字段线索:
```text
UserRolePeripheryDataProgressReward1
-> LevelId
-> MaxWave
-> State
-> ClaimedWave
GetUserRolePeripheryProgressReward1DataS2C
-> ProgressReward1 : repeated UserRolePeripheryDataProgressReward1
UserRolePeripheryClaimedProgressReward1RewardC2S
-> LevelId
UserRolePeripheryClaimedProgressReward1RewardS2C
-> Rewards : Map<int, int>
```
当前接入状态:
- PVE 战斗内波次由 `HFWaveManager` 读取 `Wave.xlsx`,属于战斗流程。
- 地图/关卡进度协议已生成,但业务 UI 和普通发送链路未确认。
- `GMWindow_GM.cs` 中有外围进度设置和领取奖励调试入口。
- 地图编辑器、关卡配置、地图实体摆放等代码保留较多注释,当前更像半接入/调试状态。
## 梳理任务
- [x] 梳理地图/关卡数据结构。
- [ ] 梳理关卡解锁、当前关卡、已通关状态。
- [x] 梳理波次和关卡配置的关系。
- [x] 梳理进度奖励领取条件和网络消息。
- [ ] 梳理地图进度如何驱动主界面或 PVE 入口。
## 待确认
- 地图是否有章节/大关/小关层级;`ChapterWindow` 有注释入口,但当前未确认实装。
- `Level` 相关配置表是否为旧表残留或当前未登记源表。
- 关卡进度是否全部由服务器维护。
- `GetLevelWaveReward` 与外围进度奖励 `ProgressReward1` 的产品边界。
- 地图进度如何驱动主界面或 PVE 入口。
## 相关框架
- [PVE/关卡战斗](PVE关卡战斗.md)
- [数据/配置框架](../../../modules/frameworks/数据配置框架.md)
- [网络框架](../../../modules/frameworks/网络系统.md)
- [UI 框架](../../../modules/frameworks/UI窗口系统/README.md)
---
## 文档关联
> 当本文档发生变更时,应同步检查以下关联文档,避免信息不一致。
| 文档 | 关联原因 |
|---|---|
| [modules/模块索引.md](../../../modules/模块索引.md) | 模块索引是项目知识总入口 |
| [modules/features/PVE关卡战斗.md](PVE关卡战斗.md) | PVE/关卡战斗 |
| [modules/frameworks/数据配置框架.md](../../../modules/frameworks/数据配置框架.md) | 数据/配置框架 |
| [modules/frameworks/网络系统.md](../../../modules/frameworks/网络系统.md) | 网络框架 |
| [modules/frameworks/UI窗口系统/README.md](../../../modules/frameworks/UI窗口系统/README.md) | UI 框架 |
| [rules/10-架构说明.md](../../../rules/10-架构说明.md) | 架构说明定义总体分层和依赖方向 |
| [rules/30-模块登记规则.md](../../../rules/30-模块登记规则.md) | 模块登记规则定义分类和状态口径 |
| TODO补充依赖的框架/模块文档 | 如 UI、网络、事件、配置等框架 |

View File

@@ -0,0 +1,123 @@
# 塔/角色养成
## 分类
- 项目功能
## 目的
记录塔、角色或卡片的升级、升星、技能升级、展示和养成配置。
## 已知线索
- 逻辑路径:`Assets/Game/GameHFScripte/GameFunction/Logic/TowerLevelUpManager/`
- 逻辑路径:`Assets/Game/GameHFScripte/GameFunction/Logic/TowerSkillUpManager/`
- UI 路径:`Assets/Game/GameHFScripte/GameFunction/UIWindows/AvatarItem/`
- 配置线索:`XLSX_SRC/CN/EntityConfig.xlsx`
- 配置线索:`XLSX_SRC/CN/SkillGroup.xlsx``SkillReleaser.xlsx``SkillTrigger.xlsx``SkillUp.xlsx`
## 已确认内容
启动初始化:
```text
HFGameStart.InitManager()
-> HFTowerStarUpManager.Instance
-> HFTowerSkillUpManager.Instance
```
协议已生成:
- `GetPlayerTower = 4000`
- `TowerLevelFormation = 4001`
- `TowerLevelUpLv = 4002`
- route
- `game.player.getTower`
- `game.player.formationTower`
- `game.player.levelUpTower`
请求/响应字段:
```text
GetPlayerTowerC2S
-> 无主要字段
GetPlayerTowerS2C
-> Formation : repeated long
TowerLevelFormationC2S
-> Formation : repeated long
TowerLevelFormationS2C
-> Formation : repeated long
TowerLevelUpLvC2S
-> Id
TowerLevelUpLvS2C
-> Id
-> Formation : repeated long
```
STC 事件:
- `HFEvent_STC_GetPlayerTowerS2C`
- `HFEvent_STC_TowerLevelFormationS2C`
- `HFEvent_STC_TowerLevelUpLvS2C`
配置和实体侧线索:
- `Constants` 中有塔相关字段:`BossTowerCardNum``BossTowerGetNum``TowerRange``TowerRectangle``NewTowerInitLevel``TowerPutEffect*``LucySpinSameTower` 等。
- 实体侧会读取 `EntityConfig``Resource``SkillGroup``SkillReleaser``SkillTrigger` 等表来驱动塔实体、模型、AI、技能。
- 历史/生成代码里存在 `Tower``Towerlevel``StarUpgrade``CardWeight` 等表的读取痕迹,但当前 `ZYXlsxProjectSettings` 登记的 CN 表没有显式列出这些源表,需要确认是否是旧生成残留或表源未纳入当前列表。
当前接入状态:
- `HFTowerStarUpManager` 主体逻辑几乎全部注释,包括选择塔、显示升级 HUD、读取 `StarUpgrade`、修改实体属性等。
- `HFTowerSkillUpManager` 主体逻辑也处于注释状态,包括监听 `HFEvent_TowerSkillState` 并修改实体技能能力。
- `AvatarItem` 的资源路径 attribute 被注释,当前更像 MainWindow 内嵌组件;`SetAvatarFrame` 尚未实装。
- `CardItem` 有卡片 UI 基础绑定,但 `SetData` 为空。
- 未发现 `GetPlayerTowerC2S``TowerLevelFormationC2S``TowerLevelUpLvC2S` 在业务代码中的实际发送点。
当前判断:
- “塔/角色养成”协议、配置痕迹、实体战斗联动线索都存在。
- 客户端养成主流程当前未完整实装,或被注释保留。
- 运行中的塔更偏战斗实体/技能系统;大厅养成、编队、升级 UI 还需要进一步确认产品接入状态。
## 梳理任务
- [x] 确认“塔”“角色”“卡片”在代码和配置中的对应概念。
- [x] 梳理塔升级和技能升级的入口。
- [ ] 梳理升级消耗和背包资源关系。
- [x] 梳理 Avatar/Card UI 展示数据来源。
- [x] 梳理养成数据是否同步服务器。
## 待确认
- `TowerLevelUpManager` / `TowerSkillUpManager` 当前初始化但主体逻辑被注释,需确认是否计划恢复。
- 升级、升星、技能升级是否属于同一产品功能域,需要结合 UI/策划表确认。
- 升级消耗、卡片碎片、背包资源之间的真实关系待确认。
- 养成结果如何同步并影响 PVE 实体属性,需要确认服务端返回和客户端应用链路。
- `Tower``Towerlevel``StarUpgrade``CardWeight` 等表是否是旧表残留或当前缺失源表。
## 相关框架
- [实体框架](../../../modules/frameworks/实体系统/README.md)
- [背包](背包.md)
- [数据/配置框架](../../../modules/frameworks/数据配置框架.md)
- [UI 框架](../../../modules/frameworks/UI窗口系统/README.md)
---
## 文档关联
> 当本文档发生变更时,应同步检查以下关联文档,避免信息不一致。
| 文档 | 关联原因 |
|---|---|
| [modules/模块索引.md](../../../modules/模块索引.md) | 模块索引是项目知识总入口 |
| [modules/features/背包.md](背包.md) | 背包 |
| [modules/frameworks/数据配置框架.md](../../../modules/frameworks/数据配置框架.md) | 数据/配置框架 |
| [modules/frameworks/实体系统/README.md](../../../modules/frameworks/实体系统/README.md) | 实体框架 |
| [modules/frameworks/UI窗口系统/README.md](../../../modules/frameworks/UI窗口系统/README.md) | UI 框架 |
| [rules/10-架构说明.md](../../../rules/10-架构说明.md) | 架构说明定义总体分层和依赖方向 |
| [rules/30-模块登记规则.md](../../../rules/30-模块登记规则.md) | 模块登记规则定义分类和状态口径 |
| TODO补充依赖的框架/模块文档 | 如 UI、网络、事件、配置等框架 |

View File

@@ -0,0 +1,105 @@
# 奖励/道具展示
## 分类
- 项目功能
## 目的
记录通用奖励、道具展示、资源展示、弹窗提示和奖励到账表现。
## 已知线索
- 奖励提示:`Assets/Game/GameHFScripte/GameFunction/UIWindows/Tips/Tips_CommonReward.cs`
- 资源组件:`Assets/Game/GameHFScripte/GameFunction/UIWindows/Components/ResourceItem.cs`
- 道具 UI`Assets/Game/GameHFScripte/GameFunction/UIWindows/Item/`
- 配置线索:`XLSX_SRC/CN/Gift.xlsx``Resource.xlsx`
## 已确认内容
通用入口:
```text
HFFunCatalogue.Tips.ShowCommonRewardTips(reward, cardReward)
-> HFFunCatalogue.UIManager.OpenWindow<Tips_CommonReward>()
-> Tips_CommonReward.SetData(reward, cardReward)
```
定义位置:
- `Assets/Game/GameHFScripte/GameFunction/Logic/UI/HFFunCatalogue_UI_TipsManager.cs`
- `Assets/Game/GameHFScripte/GameFunction/UIWindows/Tips/Tips_CommonReward.cs`
奖励数据结构:
- `Tips_CommonReward.SetData` 接收 `RepeatedField<BagItem>`
- `BagItem` 来自网络 protobuf。
- 当前代码中把奖励分成 `cards``items` 的逻辑存在,但核心分类代码被注释:
- 原计划通过 `Item` 配置表判断 `enItemType.Tower`
- 当前 `ZYXlsxProjectSettings` 未登记 `Item.xlsx`,但旧代码里有 `ds_Item860D2A9ETableData` 痕迹。
展示组件:
- `Tips_CommonReward`
- 标题固定设置为 `REWARDS`
- `ResourceItem` 当前固定调用 `SetData(1)` 展示顶部资源。
- 普通道具用 `ItemIcon` 池展示。
- 卡片奖励区域逻辑存在,但资源设置代码被注释。
- `ResourceItem`
- 监听 `HFEvent_InitBag`
- 通过 `HFFunCatalogue.Bag.GetGameResourceCount(resourceId)` 展示资源数量。
- 资源变化动画和主动刷新事件逻辑存在注释。
- `Tips_UnlockTower`
- 用于解锁塔/卡片提示。
- 当前读 `Tower` / `Item` 配置和设置图标的代码被注释。
配置线索:
- `Gift.xlsx` 已登记到 ZYXlsx生成 `Gift14537B33Sheet1`
- `Resource.xlsx` 已登记到 ZYXlsx生成 `Resource840C5F09TableData`
- `Constants.xlsx` 中有奖励相关字段:`LuckyLootRewardTimes``LoginUsersItem``QuickOfflineReward``FreeOfflineReward` 等。
当前接入状态:
- 通用奖励弹窗入口存在。
- 奖励 UI 框架存在,但道具/卡片配置读取大量注释。
- 入包逻辑不在奖励弹窗里,当前主要由背包/服务器推送 `PlayerResourceChangeS2C` 更新。
## 梳理任务
- [x] 梳理奖励数据结构和展示入口。
- [x] 梳理奖励中道具、卡片、资源的分类。
- [x] 梳理奖励展示和背包更新的先后关系。
- [x] 梳理通用 Tips 的打开方式和资源加载方式。
- [ ] 梳理奖励来源PVE、任务、商店、GM 或其他系统。
## 待确认
- 奖励展示当前看起来只负责表现,不负责入包;仍需结合具体领取协议确认。
- `Gift.xlsx` 和实际奖励结构的对应关系待确认。
- `Item.xlsx` / `Tower.xlsx` 是否是旧表残留或当前缺失源表。
- 飞图事件 `HFEvent_FlyIcon` 存在,但实际调用链待继续确认。
## 相关框架
- [背包](背包.md)
- [UI 框架](../../../modules/frameworks/UI窗口系统/README.md)
- [资源框架](../../../modules/frameworks/资源管理/README.md)
- [数据/配置框架](../../../modules/frameworks/数据配置框架.md)
---
## 文档关联
> 当本文档发生变更时,应同步检查以下关联文档,避免信息不一致。
| 文档 | 关联原因 |
|---|---|
| [modules/模块索引.md](../../../modules/模块索引.md) | 模块索引是项目知识总入口 |
| [modules/features/背包.md](背包.md) | 背包 |
| [modules/frameworks/数据配置框架.md](../../../modules/frameworks/数据配置框架.md) | 数据/配置框架 |
| [modules/frameworks/资源管理/README.md](../../../modules/frameworks/资源管理/README.md) | 资源框架 |
| [modules/frameworks/UI窗口系统/README.md](../../../modules/frameworks/UI窗口系统/README.md) | UI 框架 |
| [rules/10-架构说明.md](../../../rules/10-架构说明.md) | 架构说明定义总体分层和依赖方向 |
| [rules/30-模块登记规则.md](../../../rules/30-模块登记规则.md) | 模块登记规则定义分类和状态口径 |
| TODO补充依赖的框架/模块文档 | 如 UI、网络、事件、配置等框架 |

View File

@@ -0,0 +1,161 @@
# 登录
## 分类
- 项目功能
## 目的
记录登录流程、登录窗口、网络交互和进入游戏后的衔接关系。
## 关键文件
| 用途 | 路径 | 说明 |
|---|---|---|
| 登录管理器 | `Assets/Game/GameHFScripte/GameFunction/Logic/Login/HFLoginManager.cs` | 单例,负责连接服务器、发送登录协议、处理登录后事件链 |
| 登录窗口 | `Assets/Game/GameHFScripte/GameFunction/UIWindows/Login/LoginWindow.cs` | 继承 `AbsHFUIWindow`,绑定输入框和登录按钮 |
| 登录 Prefab | `Assets/Game/GameHFResource/UIWindows/Login/LoginWindow.prefab` | 窗口资源,由 `HFAssetBundlePath` 指定 |
| 启动入口 | `Assets/Game/GameHFScripte/GameFunction/GameRoot/HFGameStart.cs`(待确认) | 初始化 manager 并打开 `LoginWindow` |
## 数据流
```text
[启动]
HFGameStart.InitManager
-> OpenWindow<LoginWindow>
[用户点击]
LoginWindow.OnBtnLogin
-> 校验用户名非空
-> PlayerPrefs 保存用户名/密码
-> HFLoginManager.Instance.Login(InputName.text)
[连接服务器]
HFLoginManager.Login(account)
-> UNITY_EDITOR 下读取 EditorPrefs["IPData"] 覆盖 IP
-> HFSeverManager.ReConnect(OnReConnect)
-> HFSeverManager.Connect(MainConnect, WebSocket, m_IP, m_Port, m_Token, callback)
-> 连接成功后 OnSendLogin
[登录协议]
OnSendLogin
-> LoginAuthC2S
ServerId = 10001
Token = m_Token
Pid = "2126001"
UserName = m_Account
Password = m_Account
[服务端响应链]
LoginAuthS2C (ErrorCode == 0)
-> PlayerSelectC2S
-> PlayerSelectS2C
有角色PlayerEnterC2S
无角色PlayerCreateC2S -> PlayerEnterC2S
-> PlayerEnterS2C
-> PlayerFlushC2S(All = true)
-> RequestLoginData 触发后续背包、资源等初始化
```
## 关键协议
- `LoginAuthC2S` / `LoginAuthS2C`
- `PlayerSelectC2S` / `PlayerSelectS2C`
- `PlayerCreateC2S` / `PlayerCreateS2C`
- `PlayerEnterC2S` / `PlayerEnterS2C`
- `PlayerFlushC2S` / `PlayerFlushS2C`
- `ChangeNicknameC2S` / `ChangeNicknameS2C`
## 已确认流程
当前登录入口:
```text
HFGameStart.InitManager
-> OpenWindow<LoginWindow>
-> LoginWindow.OnBtnLogin
-> HFLoginManager.Login(InputName.text)
```
`HFLoginManager.Login` 流程:
```text
Login(account)
-> 读取 EditorPrefs["IPData"] 覆盖 IP仅 UNITY_EDITOR
-> ConnectServer
-> HFSeverManager.ReConnect(OnReConnect)
-> HFSeverManager.Connect(MainConnect, WebSocket, m_IP, m_Port, m_Token)
-> OnSendLogin
-> LoginAuthC2S.Dispatch
```
服务端事件链:
```text
LoginAuthS2C
-> PlayerSelectC2S
-> PlayerSelectS2C
-> 有角色PlayerEnterC2S
-> 无角色PlayerCreateC2S -> PlayerEnterC2S
-> PlayerEnterS2C
-> PlayerFlushC2S(All = true)
```
`LoginWindow` 会把用户名和密码写入 `PlayerPrefs`,但实际登录请求当前使用用户名作为 account密码未参与 `LoginAuthC2S`
## 梳理任务
- [x] 找到登录功能的入口方法和首个调用点。
- [x] 梳理登录请求、响应和错误处理。
- [x] 梳理登录成功后初始化了哪些 manager。
- [x] 梳理登录窗口 prefab 和脚本绑定关系。
- [ ] 确认登录完成后进入主界面或 PVE 的流程。
## 待确认
- 登录是否区分游客、账号、平台登录。
- 登录数据是否会初始化背包、关卡、角色/塔数据。
- 是否存在断线重连或重新登录流程。
- `PlayerFlushS2C` 收到后由谁打开主界面,目前未确认。
- 密码输入框当前只保存到 `PlayerPrefs`,是否应参与登录待确认。
## 相关框架
- [网络框架](../../../modules/frameworks/网络系统.md)
- [UI 框架](../../../modules/frameworks/UI窗口系统/README.md)
- [Hotfix 启动/目录](../../../modules/frameworks/Hotfix启动.md)
---
## 文档关联
> **注意**:当本模块发生变更时,应同步检查以下关联文档,避免信息不一致。
### 关联模块
| 模块 | 文档 | 关联原因 |
|---|---|---|
| 背包 | [背包](背包.md) | 登录成功后 `RequestLoginData` 触发背包初始化 |
| 奖励/道具展示 | [奖励/道具展示](奖励道具.md) | 登录流程涉及资源、道具配置 |
| GM/调试功能 | [GM/调试功能](GM调试.md) | `HFLoginManager` 在 Editor 下读取 `EditorPrefs["IPData"]` 覆盖 IP |
| PVE/关卡战斗 | [PVE/关卡战斗](PVE关卡战斗.md) | 登录后进入主界面或 PVE 的流程衔接 |
| 地图/关卡进度 | [地图/关卡进度](地图进度.md) | 登录后角色数据与关卡进度同步 |
### 关联框架文档
| 框架 | 文档 | 关联原因 |
|---|---|---|
| 网络框架 | [网络框架](../../../modules/frameworks/网络系统.md) | 登录协议(`LoginAuthC2S/S2C``PlayerEnterS2C` 等) |
| UI 框架 | [UI 框架](../../../modules/frameworks/UI窗口系统/README.md) | `LoginWindow` 继承 `AbsHFUIWindow` |
| Hotfix 启动/目录 | [Hotfix 启动/目录](../../../modules/frameworks/Hotfix启动.md) | `HFGameStart.InitManager` 为入口 |
| 事件框架 | [事件框架](../../../modules/frameworks/事件系统/README.md) | `RequestLoginData` 触发后续初始化事件链 |
| 场景框架 | [场景框架](../../../modules/frameworks/场景系统.md) | 登录后进入主界面涉及场景切换 |
### 关联规则
| 规则 | 文档 | 关联原因 |
|---|---|---|
| 模块登记规则 | [30-模块登记规则.md](../../../rules/30-模块登记规则.md) | 登录模块登记与状态 |
| 文档同步规则 | [50-文档同步规则.md](../../../rules/50-文档同步规则.md) | 长期接口或流程变化时同步模块文档 |
| 架构说明 | [10-架构说明.md](../../../rules/10-架构说明.md) | 登录为游戏入口,涉及整体架构 |
| 开发规则 | [20-开发规则.md](../../../rules/20-开发规则.md) | 网络协议、UI 窗口开发规范 |

View File

@@ -0,0 +1,168 @@
# 背包
## 分类
- 项目功能
## 目的
记录道具、资源数量、背包数据同步、资源展示和奖励入包逻辑。
## 关键文件
| 用途 | 路径 | 说明 |
|---|---|---|
| 背包管理器 | `Assets/Game/GameHFScripte/GameFunction/Logic/Bag/BagInfo/HFBagManager.cs` | 单例 `AbsHFSingleRunTime`,管理背包页签、道具/资源数量 |
| 背包数据结构 | `Assets/Game/GameHFScripte/GameFunction/Logic/Bag/BagInfo/StItem.cs` | 单个道具数据 |
| 背包数据结构 | `Assets/Game/GameHFScripte/GameFunction/Logic/Bag/BagInfo/stItemInfo.cs` | 道具信息 |
| 道具类型枚举 | `Assets/Game/GameHFScripte/GameFunction/Logic/Constant/enItemType.cs` | 货币、材料、防御塔、经验、道具等 |
| 背包窗口 | `Assets/Game/GameHFScripte/GameFunction/UIWindows/ItemWindow/ItemWindow.cs` | 单个道具/资源展示单元 |
| GM 调试 | `Assets/Game/GameHFScripte/GameFunction/UIWindows/GMWindow/GMWindow_BagData.cs` | GM 修改背包数据入口 |
| 资源配置 | `XLSX_SRC/CN/Resource.xlsx` | 资源/道具基础配置 |
## 数据流
### 登录初始化
```text
HFLoginManager.RequestLoginData
-> PlayerFlushC2S(All = true)
-> 服务端推送 GetBagItemS2C待确认具体时序
-> HFBagManager.OnPushBagItem
-> AddItem(item)
-> HFEvent_InitBag.Dispatch
```
### 增量更新
```text
PlayerResourceChangeS2C
-> ItemChange.Add / Del / Update
-> HFBagManager.OnUpdateBagItem
-> AddItem / DelItem
-> HFEvent_BagItemUpdate.Dispatch
```
## 关键 API
| 方法 | 用途 |
|---|---|
| `Init(int maxpage)` | 初始化背包页签 |
| `AddItem(Item item)` | 添加/更新道具 |
| `DelItem(...)` | 删除道具 |
| `GetGameResourceCount(int resId)` | 按 resid 快速获取资源数量 |
| `GetItemCount(int resid)` | 遍历具体 item 累加数量 |
| `BagPageIndex` | 当前背包页签 |
## 内部存储
- `m_BagPage`:按页签保存 `RB_Tree`
- `m_DicPageUUid`:按 `resid` 记录 uuid 到 page 的映射。
- `m_DicItemCount`:按 `resid` 快速记录数量(当前为覆盖值,不是累加值)。
## 关键事件
- `enHFSTCEvent.GetBagItem`:首次推送背包数据。
- `enHFSTCEvent.PlayerResourceChange`:资源/道具增量变化。
- `HFEvent_InitBag`:背包初始化完成。
- `HFEvent_BagItemUpdate`:背包数据更新。
## 已确认内容
背包 manager
- 主类:`HFBagManager`
- 基类:`AbsHFSingleRunTime<HFBagManager>`
- 初始化:`HFGameStart.InitManager` 访问 `HFBagManager.Instance` 时创建。
监听的服务端事件:
- `GetBagItemS2C` -> `OnPushBagItem`
- `PlayerResourceChangeS2C` -> `OnUpdateBagItem`
首次背包数据:
```text
HFLoginManager.RequestLoginData
-> PlayerFlushC2S(All = true)
-> 服务端推送 GetBagItemS2C待确认具体时序
-> HFBagManager.OnPushBagItem
-> AddItem
-> HFEvent_InitBag.Dispatch
```
增删改更新:
```text
PlayerResourceChangeS2C
-> ItemChange.Add / Del / Update
-> AddItem / DelItem
-> HFEvent_BagItemUpdate.Dispatch
```
内部存储:
- `m_BagPage`:按页签保存 `RB_Tree`
- `m_DicPageUUid`:按 `resid` 记录 uuid 到 page 的映射。
- `m_DicItemCount`:按 `resid` 快速记录数量。
- `GetGameResourceCount(resId)`:常用于资源数量展示。
- `GetItemCount(resid)`:遍历具体 item 累加数量。
## 梳理任务
- [x] 找到 `HFBagManager` 或背包 manager 的入口和生命周期。
- [x] 梳理背包数据来源登录初始化、网络消息、GM 请求或本地配置。
- [x] 梳理道具和资源的查询 API。
- [x] 梳理背包更新事件如何驱动 UI 刷新。
- [ ] 梳理奖励入包和奖励展示的关系。
## 待确认
- 背包是否区分道具、资源、卡片。
- 背包数据是否全部来自服务器。
- 是否有消耗、添加、合并、排序等本地逻辑。
- `PlayerFlushS2C``GetBagItemS2C` 的服务端推送时序需确认。
- `m_DicItemCount[resid] = count` 当前是覆盖值,不是累加值,是否符合资源类型语义待确认。
## 相关框架
- [事件框架](../../../modules/frameworks/事件系统/README.md)
- [网络框架](../../../modules/frameworks/网络系统.md)
- [UI 框架](../../../modules/frameworks/UI窗口系统/README.md)
- [数据/配置框架](../../../modules/frameworks/数据配置框架.md)
---
## 文档关联
> **注意**:当本模块发生变更时,应同步检查以下关联文档,避免信息不一致。
### 关联模块
| 模块 | 文档 | 关联原因 |
|---|---|---|
| 登录 | [登录](登录.md) | `HFLoginManager.RequestLoginData` 触发背包首次初始化 |
| 商店 | [商店](商店.md) | 商店购买/出售涉及背包道具增减 |
| 奖励/道具展示 | [奖励/道具展示](奖励道具.md) | 奖励入包展示、道具配置(`Resource.xlsx``Gift.xlsx` |
| 塔/角色养成 | [塔/角色养成](塔养成.md) | 养成消耗涉及背包资源扣除 |
| 地图/关卡进度 | [地图/关卡进度](地图进度.md) | 关卡奖励可能涉及背包道具更新 |
| GM/调试功能 | [GM/调试功能](GM调试.md) | `GMWindow_BagData` 为 GM 修改背包数据入口 |
### 关联框架文档
| 框架 | 文档 | 关联原因 |
|---|---|---|
| 事件框架 | [事件框架](../../../modules/frameworks/事件系统/README.md) | `HFEvent_InitBag``HFEvent_BagItemUpdate` 事件驱动 |
| 网络框架 | [网络框架](../../../modules/frameworks/网络系统.md) | `GetBagItemS2C``PlayerResourceChangeS2C` 协议 |
| UI 框架 | [UI 框架](../../../modules/frameworks/UI窗口系统/README.md) | `ItemWindow` 为背包 UI 展示单元 |
| 数据/配置框架 | [数据/配置框架](../../../modules/frameworks/数据配置框架.md) | `Resource.xlsx` 资源配置源 |
| 内存/对象管理 | [内存/对象管理](../../../modules/frameworks/内存对象管理/README.md) | `RB_Tree` 存储结构、对象池 |
### 关联规则
| 规则 | 文档 | 关联原因 |
|---|---|---|
| 模块登记规则 | [30-模块登记规则.md](../../../rules/30-模块登记规则.md) | 背包模块登记与状态 |
| 文档同步规则 | [50-文档同步规则.md](../../../rules/50-文档同步规则.md) | 长期接口或流程变化时同步模块文档 |
| 架构说明 | [10-架构说明.md](../../../rules/10-架构说明.md) | 背包为全局数据模块,涉及架构分层 |
| 开发规则 | [20-开发规则.md](../../../rules/20-开发规则.md) | 数据管理、事件使用规范 |

View File

@@ -0,0 +1,40 @@
# PlayBalloons 业务参考
> 本目录存放来自 **PlayBalloons / CrystalBattle** 实际项目的业务功能文档。
>
> 这些内容**不是 StrayFog 框架的一部分**,仅作为“使用 StrayFog 框架如何实现具体业务”的参考示例。
>
> AI 和人工开发者应先学习 StrayFog 框架核心文档,再按需查阅本目录。
---
## 入口文档
- [业务功能 → StrayFog 框架能力映射](业务框架映射接口.md)
- [features/](features/):原始业务功能文档
---
## 来源说明
这些文档原本位于 `modules/features/`(旧结构),是从 PlayBalloons 项目迁移而来。迁移时已移除与 StrayFog 框架核心无关的占位和未实现模块(如 PVP
---
## 使用建议
1. **不要直接套用**其中的具体类名、协议号、配置表字段到其他项目。
2. **重点关注通用模式**单例管理器、事件驱动数据流、GM 协议包装、通用弹窗接口等。
3. **对照框架文档阅读**:看到业务实现时,回溯到 `modules/frameworks/` 下对应框架模块文档,理解底层机制。
---
## 文档关联
> 当本文档发生变更时,应同步检查以下关联文档,避免信息不一致。
| 文档 | 关联原因 |
|---|---|
| [业务框架映射接口.md](业务框架映射接口.md) | 业务参考总入口指向框架能力映射 |
| [modules/模块索引.md](../../modules/模块索引.md) | 模块索引可链接业务参考区 |
| [rules/10-架构说明.md](../../rules/10-架构说明.md) | 架构说明定义业务功能与框架层的依赖方向 |

View File

@@ -0,0 +1,105 @@
# 业务功能 → StrayFog 框架能力映射
> 本文档是 PlayBalloons 业务参考的“接口文档”。>
> 它不描述业务实现细节,而是说明每个业务功能用到了 StrayFog 框架的哪些能力,以及应该参考哪些框架文档。
---
## 来源说明
以下业务功能来自 PlayBalloons 实际项目,仅作参考,不是 StrayFog 框架本身。
原始业务文档位于 [features/](features/) 目录。
---
## 业务功能映射表
| 业务功能 | 涉及 StrayFog 框架能力 | 参考文档 | 状态 |
|---|---|---|---|
| 登录 | 单例管理器、网络协议、UI 窗口、事件链 | 网络框架、UI 框架、Hotfix 启动 | 可提炼示例 |
| 背包 | 单例、RB_Tree 存储、事件驱动、增量同步 | 事件框架、网络框架、数据/配置框架 | 可提炼示例 |
| 商店 | 网络协议、Map 数据结构、UI 窗口 | 网络框架、UI 框架、数据/配置框架 | 部分接入 |
| PVE 战斗 | 场景、实体、波次管理、伤害管理器 | 实体框架、场景框架、网络框架 | 半接入 |
| 塔养成 | 单例、编队数据、实体属性联动 | 实体框架、数据/配置框架 | 未完整实装 |
| GM 调试 | GM 协议包装、参数配置、模块化窗口生命周期 | 网络框架、UI 框架 | 可提炼示例 |
| 奖励展示 | 通用 Tips、事件监听、资源组件 | UI 框架、事件框架、资源框架 | 可提炼示例 |
| 地图进度 | 地图加载、波次配置、进度奖励 | 场景框架、数据/配置框架 | 半接入 |
| PVP | — | — | 未发现实现 |
---
## 可复用模式索引
从业务文档中提炼出的通用模式,可作为使用 StrayFog 框架实现类似系统的参考:
### 1. 单例管理器 + 初始化模式
```text
HFGameStart.InitManager()
-> 各业务 Manager.Instance 初始化
-> Manager 监听 STC 事件
```
对应框架能力:
- [Hotfix 启动](../../modules/frameworks/Hotfix启动.md)
- [对象池](../../modules/frameworks/内存对象管理/README.md)
### 2. 事件驱动数据流
```text
服务器消息 S2C
-> 反射创建 STC 事件
-> 业务 Manager 监听并更新数据
-> 派发 CTC 事件通知 UI
```
对应框架能力:
- [事件系统](../../modules/frameworks/事件系统/README.md)
- [网络系统](../../modules/frameworks/网络系统.md)
### 3. GM 命令统一包装
```text
GM 窗口
-> 选择 msgId 和参数
-> 包装成 GMC2S
-> 发送真实业务 Network_MsgId
```
对应框架能力:
- [网络系统](../../modules/frameworks/网络系统.md)
- [UI 窗口系统](../../modules/frameworks/UI窗口系统/README.md)
### 4. 通用弹窗 / Tips 展示
```text
业务逻辑调用 HFFunCatalogue.Tips.ShowCommonRewardTips(rewardItems)
-> 打开通用奖励窗口
-> 窗口内资源组件监听背包事件刷新
```
对应框架能力:
- [UI 窗口系统](../../modules/frameworks/UI窗口系统/README.md)
- [事件系统](../../modules/frameworks/事件系统/README.md)
- [资源管理](../../modules/frameworks/资源管理/README.md)
---
## 使用说明
1. AI 阅读时应先读框架文档,再读业务参考。
2. 业务参考中的具体类名、协议号不可直接套用到其他项目。
3. 如需新增业务参考,放入 `business-reference/<project>/features/`,并在本文件补充映射。
---
## 文档关联
> 当本文档发生变更时,应同步检查以下关联文档,避免信息不一致。
| 文档 | 关联原因 |
|---|---|
| [业务参考总入口.md](业务参考总入口.md) | 业务参考总入口指向本映射文档 |
| [features/*.md](features/) | 每个业务功能文档都应在映射表中有对应行 |
| [modules/模块索引.md](../../modules/模块索引.md) | 模块索引可链接到业务参考区 |

59
hooks/Hook共享层.md Normal file
View File

@@ -0,0 +1,59 @@
# 共享检查
`hooks/` 提供只读工作流检查和提交信息检查。脚本不自动修改代码、资源或文档。
## 工作流检查
```powershell
powershell -NoProfile -ExecutionPolicy Bypass -File hooks/workflow-check.ps1 `
[-UnityProjectRoot <path>] [-DocsRoot <path>]
```
项目定位顺序:
1. `-UnityProjectRoot`
2. `UNITY_PROJECT_ROOT`
3. 当前目录本身是 Unity 项目
4. UnityAI 同级唯一 Unity 项目
5. 未找到时只检查文档仓库
检查内容:
- UnityAI 与 Unity 项目的 tracked、staged、unstaged 和 untracked 文件。
- 中文路径和未跟踪 Markdown。
- ESF/General 源码与 CopyTo 生成目标是否同时变化。
- 改动路径对应的建议构建、Unity 和平台验证。
- 可能需要复核的模块文档。
- 本次修改 Markdown 中的相对链接。
`archive-check.ps1` 是兼容包装,新接入统一调用 `workflow-check.ps1`
## 提交检查
```powershell
powershell -NoProfile -ExecutionPolicy Bypass -File hooks/commit-check.ps1 `
-RepositoryRoot <path> `
-Message "[模块][类型]: 描述"
```
脚本优先检查 staged 文件;没有 staged 文件时检查整个工作树。支持 UnityAI 和目标 Unity 项目,路径映射维护在 `commit-module-mappings.json`
允许类型:`feat``fix``docs``refactor``test``chore`
提交和推送仍然只在用户明确要求时执行。检查通过不代表可以自动提交。
## 维护规则
- 新增稳定模块路径时更新工作流与提交映射。
- 脚本保持 Windows PowerShell 5.1 可运行,不依赖写入仓库的缓存。
- 脚本只输出建议;源码边界警告不自动回退任何文件。
- 新增检查后补无改动、中文路径、无 Unity 工程和双仓库场景验证。
## 文档关联
| 文档 | 关联原因 |
|---|---|
| [工作流清单](../rules/40-工作流清单.md) | 检查对应的任务阶段 |
| [文档同步规则](../rules/50-文档同步规则.md) | 文档影响判断 |
| [开发规则](../rules/20-开发规则.md) | 源码与生成代码约束 |
| [AI 接入入口](../ai/AI接入入口.md) | AI 工具调用入口 |

10
hooks/archive-check.ps1 Normal file
View File

@@ -0,0 +1,10 @@
param(
[string]$UnityProjectRoot = '',
[string]$DocsRoot = ''
)
Write-Warning 'archive-check.ps1 is a compatibility entry. Use workflow-check.ps1 for new integrations.'
& (Join-Path $PSScriptRoot 'workflow-check.ps1') `
-UnityProjectRoot $UnityProjectRoot `
-DocsRoot $DocsRoot
exit $LASTEXITCODE

109
hooks/commit-check.ps1 Normal file
View File

@@ -0,0 +1,109 @@
param(
[Parameter(Mandatory = $true)]
[string]$Message,
[string]$RepositoryRoot = ''
)
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
$OutputEncoding = [System.Text.Encoding]::UTF8
$ErrorActionPreference = 'Stop'
if ([string]::IsNullOrWhiteSpace($RepositoryRoot)) {
$RepositoryRoot = (Get-Location).Path
}
$RepositoryRoot = [System.IO.Path]::GetFullPath($RepositoryRoot)
$gitRoot = & git -C $RepositoryRoot rev-parse --show-toplevel 2>$null | Select-Object -First 1
if ($LASTEXITCODE -ne 0 -or [string]::IsNullOrWhiteSpace($gitRoot)) {
Write-Error "Git repository was not found: $RepositoryRoot"
exit 1
}
$RepositoryRoot = [System.IO.Path]::GetFullPath($gitRoot)
$mappingFile = Join-Path $PSScriptRoot 'commit-module-mappings.json'
$mapping = Get-Content -LiteralPath $mappingFile -Raw -Encoding UTF8 | ConvertFrom-Json
function Get-CommitFiles {
param([string]$Root)
$staged = @(& git -C $Root -c core.quotepath=false diff --cached --name-only --diff-filter=ACMRD)
$staged = @($staged | Where-Object { -not [string]::IsNullOrWhiteSpace($_) })
if ($staged.Count -gt 0) {
return $staged
}
$files = @()
$statusLines = & git -C $Root -c core.quotepath=false status --porcelain=v1 --untracked-files=all
foreach ($line in $statusLines) {
if ([string]::IsNullOrWhiteSpace($line) -or $line.Length -lt 4) {
continue
}
$path = $line.Substring(3).Trim()
if ($path.Contains(' -> ')) {
$path = ($path -split ' -> ')[-1]
}
$files += $path.Replace('\', '/')
}
return @($files | Select-Object -Unique)
}
function Get-Modules {
param([string[]]$Files)
$modules = @()
foreach ($file in $Files) {
foreach ($entry in $mapping.mappings) {
if ($file -match $entry.pattern) {
$modules += $entry.module
break
}
}
}
return @($modules | Select-Object -Unique)
}
if ($Message -notmatch '^\[([^\]]+)\]\[([^\]]+)\]:\s+(.+)$') {
Write-Error 'Commit message format must be: [module][type]: description'
exit 1
}
$messageModule = $Matches[1]
$messageType = $Matches[2]
$description = $Matches[3]
if ([string]::IsNullOrWhiteSpace($description)) {
Write-Error 'Commit message description is empty.'
exit 1
}
if ($mapping.validTypes -notcontains $messageType) {
Write-Error ("Invalid commit type '{0}'. Allowed types: {1}" -f
$messageType, ($mapping.validTypes -join ', '))
exit 1
}
$files = @(Get-CommitFiles $RepositoryRoot)
$modules = @(Get-Modules $files)
Write-Output ("Repository: {0}" -f $RepositoryRoot)
if ($files.Count -eq 0) {
Write-Warning 'No staged, unstaged, or untracked files were found. Only the message was validated.'
}
else {
Write-Output 'Commit scope files:'
foreach ($file in $files) {
Write-Output (" - {0}" -f $file)
}
}
if ($modules.Count -gt 0) {
Write-Output ("Detected modules: {0}" -f ($modules -join ', '))
if ($modules -notcontains $messageModule) {
Write-Warning ("Message module [{0}] does not match detected modules [{1}]. Review the commit scope." -f
$messageModule, ($modules -join ', '))
}
}
else {
Write-Warning 'No path mapping matched. Review the commit module manually.'
}
Write-Output 'Commit message is valid.'
exit 0

View File

@@ -0,0 +1,55 @@
{
"mappings": [
{ "pattern": "^rules/", "module": "rules" },
{ "pattern": "^ai/|^(AGENTS|CLAUDE|RULES)\\.md$", "module": "ai" },
{ "pattern": "^hooks/", "module": "hooks" },
{ "pattern": "^Tools/CodexUnityMcp/|^modules/frameworks/编辑器工具/MCP工具/", "module": "mcp" },
{ "pattern": "^modules/frameworks/UI窗口系统/|^modules/frameworks/编辑器工具/UI拼接工具\\.md$", "module": "ui" },
{ "pattern": "^modules/frameworks/资源管理/", "module": "resource" },
{ "pattern": "^modules/frameworks/实体系统/", "module": "entity" },
{ "pattern": "^modules/frameworks/事件系统/", "module": "event" },
{ "pattern": "^modules/frameworks/内存对象管理/", "module": "pool" },
{ "pattern": "^modules/frameworks/相机系统/", "module": "camera" },
{ "pattern": "^modules/frameworks/场景系统", "module": "scene" },
{ "pattern": "^modules/frameworks/网络系统", "module": "network" },
{ "pattern": "^modules/frameworks/数据配置框架", "module": "config" },
{ "pattern": "^modules/frameworks/技能系统/", "module": "skill" },
{ "pattern": "^modules/frameworks/Hotfix启动", "module": "hotfix" },
{ "pattern": "^modules/frameworks/编辑器工具/", "module": "editor" },
{ "pattern": "^modules/frameworks/", "module": "framework" },
{ "pattern": "^modules/", "module": "docs" },
{ "pattern": "^business-reference/", "module": "business-reference" },
{ "pattern": "^README\\.md$", "module": "docs" },
{ "pattern": "^Assets/StrayFog/Editor/CopyToX/CopyToHF/(AssetBundle|SpriteAtlas)/", "module": "resource" },
{ "pattern": "^Assets/StrayFog/Core/SFSubPackageV2\\.cs$|^Assets/StrayFog/Editor/Tools/AssetBundle/", "module": "resource" },
{ "pattern": "^Assets/StrayFog/Editor/CopyToX/CopyToHF/UIWindowMgr/", "module": "ui" },
{ "pattern": "^Assets/StrayFog/Editor/", "module": "editor" },
{ "pattern": "^Assets/StrayFog/Core/", "module": "framework" },
{ "pattern": "^Assets/Editor/Command/", "module": "mcp" },
{ "pattern": "^Assets/Game/GameHFScripte/GameFunction/HFDownLoadSubPackage/|^Assets/Game/GameMono/Scripts/GameDllManager\\.cs$", "module": "resource" },
{ "pattern": "^Assets/Game/GameHFScripte/GameFunction/GameEntity/", "module": "entity" },
{ "pattern": "^Assets/Game/GameHFScripte/GameFunction/Event/", "module": "event" },
{ "pattern": "^Assets/Game/GameHFScripte/GameFunction/SceneManager/", "module": "scene" },
{ "pattern": "^Assets/Game/GameHFScripte/GameFunction/WebSocket/", "module": "network" },
{ "pattern": "^Assets/Game/GameHFScripte/GameFunction/Skill/", "module": "skill" },
{ "pattern": "^Assets/Game/GameHFScripte/GameFunction/UIWindows/|^Assets/Game/GameMono/Scripts/UIMono/", "module": "ui" },
{ "pattern": "^Assets/Game/GameHFScripte/CopyToHF/Network/", "module": "network" },
{ "pattern": "^Assets/Game/GameHFScripte/CopyToHF/MemoryManager/", "module": "pool" },
{ "pattern": "^Assets/Game/GameHFScripte/CopyToHF/Event/", "module": "event" },
{ "pattern": "^Assets/Game/GameHFScripte/CopyToHF/UIWindowMgr/", "module": "ui" },
{ "pattern": "^Assets/Game/GameHFScripte/CopyToHF/AssetBundle/", "module": "resource" },
{ "pattern": "^Assets/Game/GameHFScripte/", "module": "gamehf" },
{ "pattern": "^Assets/Game/GameGeneralScripte/", "module": "general" },
{ "pattern": "^Assets/Game/GameMono/", "module": "mono" },
{ "pattern": "^Assets/Game/GameHFResource/", "module": "asset" }
],
"validTypes": [
"feat",
"fix",
"docs",
"refactor",
"test",
"chore"
]
}

351
hooks/workflow-check.ps1 Normal file
View File

@@ -0,0 +1,351 @@
param(
[string]$UnityProjectRoot = '',
[string]$DocsRoot = ''
)
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
$OutputEncoding = [System.Text.Encoding]::UTF8
$ErrorActionPreference = 'Stop'
function Get-FullPath {
param([string]$Path, [string]$BasePath)
if ([string]::IsNullOrWhiteSpace($Path)) {
return $null
}
if (-not [System.IO.Path]::IsPathRooted($Path)) {
$Path = Join-Path $BasePath $Path
}
return [System.IO.Path]::GetFullPath($Path)
}
function Test-UnityProject {
param([string]$Path)
if ([string]::IsNullOrWhiteSpace($Path)) {
return $false
}
return (Test-Path -LiteralPath (Join-Path $Path 'Assets')) -and
(Test-Path -LiteralPath (Join-Path $Path 'ProjectSettings/ProjectVersion.txt'))
}
function Resolve-UnityProject {
param([string]$ExplicitPath, [string]$DocumentationRoot)
if (-not [string]::IsNullOrWhiteSpace($ExplicitPath)) {
$resolved = Get-FullPath $ExplicitPath (Get-Location).Path
if (-not (Test-UnityProject $resolved)) {
throw "Unity project was not found: $resolved"
}
return $resolved
}
if (-not [string]::IsNullOrWhiteSpace($env:UNITY_PROJECT_ROOT)) {
$resolved = Get-FullPath $env:UNITY_PROJECT_ROOT (Get-Location).Path
if (-not (Test-UnityProject $resolved)) {
throw "UNITY_PROJECT_ROOT is not a Unity project: $resolved"
}
return $resolved
}
$current = [System.IO.Path]::GetFullPath((Get-Location).Path)
if (Test-UnityProject $current) {
return $current
}
$parent = Split-Path -Parent $DocumentationRoot
$candidates = @()
if (Test-Path -LiteralPath $parent) {
$directories = Get-ChildItem -LiteralPath $parent -Directory -ErrorAction SilentlyContinue
foreach ($directory in $directories) {
if (Test-UnityProject $directory.FullName) {
$candidates += $directory.FullName
}
}
}
if ($candidates.Count -eq 1) {
return [System.IO.Path]::GetFullPath($candidates[0])
}
if ($candidates.Count -gt 1) {
Write-Warning 'Multiple sibling Unity projects were found. Use -UnityProjectRoot to select one.'
}
return $null
}
function Get-GitRoot {
param([string]$Path)
$result = & git -C $Path rev-parse --show-toplevel 2>$null
if ($LASTEXITCODE -ne 0 -or [string]::IsNullOrWhiteSpace($result)) {
return $null
}
return [System.IO.Path]::GetFullPath(($result | Select-Object -First 1))
}
function Get-GitChanges {
param([string]$RepositoryRoot, [string]$RepositoryName)
$result = @()
if ([string]::IsNullOrWhiteSpace($RepositoryRoot)) {
return $result
}
$lines = & git -C $RepositoryRoot -c core.quotepath=false status --porcelain=v1 --untracked-files=all
if ($LASTEXITCODE -ne 0) {
throw "Could not read git status: $RepositoryRoot"
}
foreach ($line in $lines) {
if ([string]::IsNullOrWhiteSpace($line) -or $line.Length -lt 4) {
continue
}
$path = $line.Substring(3).Trim()
if ($path.Contains(' -> ')) {
$path = ($path -split ' -> ')[-1]
}
$result += [pscustomobject]@{
Repository = $RepositoryName
Root = $RepositoryRoot
Status = $line.Substring(0, 2)
Path = $path.Replace('\', '/')
}
}
return $result
}
function Show-Changes {
param([string]$Title, [object[]]$Changes)
Write-Output ""
Write-Output "[$Title]"
if ($Changes.Count -eq 0) {
Write-Output ' Clean'
return
}
foreach ($change in $Changes) {
Write-Output (" {0} {1}" -f $change.Status, $change.Path)
}
}
function Show-ChinesePathWarnings {
param([object[]]$Changes)
$chineseRegex = New-Object System.Text.RegularExpressions.Regex '\p{IsCJKUnifiedIdeographs}', ([System.Text.RegularExpressions.RegexOptions]::CultureInvariant)
$offenders = @($Changes | Where-Object {
$_.Path -like 'Assets/*' -and $chineseRegex.IsMatch($_.Path)
})
Write-Output ''
Write-Output '[Chinese path check]'
if ($offenders.Count -eq 0) {
Write-Output ' No Chinese characters found in Unity project paths.'
}
else {
foreach ($change in $offenders) {
Write-Warning ("Chinese characters in Unity path: {0}" -f $change.Path)
}
}
}
function Show-UntrackedMarkdownHint {
param([object[]]$Changes)
$untrackedMarkdown = @($Changes | Where-Object {
$_.Status -match '^\?\?$' -and $_.Path -like '*.md'
})
if ($untrackedMarkdown.Count -gt 0) {
Write-Output ''
Write-Output '[Untracked Markdown hint]'
Write-Output ' The following Markdown files are untracked. If they are long-term knowledge, remember to update modules/模块索引.md.'
foreach ($change in $untrackedMarkdown) {
Write-Output (" - {0}" -f $change.Path)
}
}
}
function Get-MarkdownLinkFailures {
param([string]$DocumentationRoot, [object[]]$Changes)
$failures = @()
$markdownChanges = $Changes | Where-Object { $_.Path -like '*.md' -and $_.Status -notmatch 'D' }
foreach ($change in $markdownChanges) {
$fullPath = Join-Path $DocumentationRoot $change.Path
if (-not (Test-Path -LiteralPath $fullPath)) {
continue
}
$content = [System.IO.File]::ReadAllText($fullPath, [System.Text.Encoding]::UTF8)
$matches = [regex]::Matches($content, '!?(?:\[[^\]]*\])\((?<path>[^\)]+)\)')
foreach ($match in $matches) {
$link = $match.Groups['path'].Value.Trim()
if ([string]::IsNullOrWhiteSpace($link) -or $link.StartsWith('#') -or
$link -match '^[a-zA-Z][a-zA-Z0-9+.-]*://' -or $link -match '^mailto:') {
continue
}
if ($link.StartsWith('<') -and $link.EndsWith('>')) {
$link = $link.Substring(1, $link.Length - 2)
}
$pathOnly = ($link -split '#')[0]
if ([string]::IsNullOrWhiteSpace($pathOnly)) {
continue
}
$decoded = [System.Uri]::UnescapeDataString($pathOnly)
$target = Get-FullPath $decoded (Split-Path -Parent $fullPath)
if (-not (Test-Path -LiteralPath $target)) {
$failures += [pscustomobject]@{
Source = $change.Path
Link = $link
}
}
}
}
return $failures
}
$scriptRoot = Split-Path -Parent $MyInvocation.MyCommand.Path
if ([string]::IsNullOrWhiteSpace($DocsRoot)) {
$DocsRoot = Split-Path -Parent $scriptRoot
}
$DocsRoot = Get-FullPath $DocsRoot (Get-Location).Path
$docsGitRoot = Get-GitRoot $DocsRoot
if ([string]::IsNullOrWhiteSpace($docsGitRoot)) {
throw "Documentation git repository was not found: $DocsRoot"
}
$DocsRoot = $docsGitRoot
$resolvedUnityRoot = Resolve-UnityProject $UnityProjectRoot $DocsRoot
$unityGitRoot = $null
if (-not [string]::IsNullOrWhiteSpace($resolvedUnityRoot)) {
$unityGitRoot = Get-GitRoot $resolvedUnityRoot
if ([string]::IsNullOrWhiteSpace($unityGitRoot)) {
throw "Unity project is not a git repository: $resolvedUnityRoot"
}
}
$docsChanges = @(Get-GitChanges $DocsRoot 'UnityAI')
$unityChanges = @()
if (-not [string]::IsNullOrWhiteSpace($unityGitRoot)) {
$unityChanges = @(Get-GitChanges $unityGitRoot (Split-Path -Leaf $resolvedUnityRoot))
}
Write-Output '[workflow-check] Read-only UnityAI workflow check'
Write-Output ("Documentation repository: {0}" -f $DocsRoot)
if ($resolvedUnityRoot) {
Write-Output ("Unity project: {0}" -f $resolvedUnityRoot)
$versionFile = Join-Path $resolvedUnityRoot 'ProjectSettings/ProjectVersion.txt'
$versionLine = Get-Content -LiteralPath $versionFile -Encoding UTF8 |
Where-Object { $_ -match '^m_EditorVersion:' } | Select-Object -First 1
if ($versionLine) {
Write-Output ("Unity version: {0}" -f (($versionLine -split ':', 2)[1].Trim()))
}
}
else {
Write-Warning 'Unity project was not found. Running documentation-only checks.'
}
Show-Changes 'UnityAI changes' $docsChanges
Show-Changes 'Unity project changes' $unityChanges
Show-ChinesePathWarnings ($docsChanges + $unityChanges)
Show-UntrackedMarkdownHint $docsChanges
$unityPaths = @($unityChanges | ForEach-Object { $_.Path })
$copyRelationships = @(
[pscustomobject]@{
Name = 'CopyToHF'
SourcePattern = '^Assets/StrayFog/Editor/CopyToX/CopyToHF/'
TargetPattern = '^Assets/Game/GameHFScripte/CopyToHF/'
GeneratedName = 'HF'
},
[pscustomobject]@{
Name = 'CopyToGeneral'
SourcePattern = '^Assets/StrayFog/Editor/CopyToX/CopyToGeneral/'
TargetPattern = '^Assets/Game/GameGeneralScripte/CopyToGeneral/'
GeneratedName = 'General'
}
)
Write-Output ''
Write-Output '[Source and generation boundary]'
$relationshipDetected = $false
foreach ($relationship in $copyRelationships) {
$hasSource = @($unityPaths | Where-Object {
$_ -match $relationship.SourcePattern
}).Count -gt 0
$hasTarget = @($unityPaths | Where-Object {
$_ -match $relationship.TargetPattern
}).Count -gt 0
if (-not $hasSource -and -not $hasTarget) {
continue
}
$relationshipDetected = $true
if ($hasSource -and -not $hasTarget) {
Write-Warning ("{0} source changed but generated target did not change. Run CopyToX and inspect the generated diff." -f
$relationship.Name)
}
elseif ($hasTarget -and -not $hasSource) {
Write-Warning ("Generated {0} files changed without {1} source changes. Confirm that generated files were not edited directly." -f
$relationship.GeneratedName, $relationship.Name)
}
else {
Write-Output (" Source and generated target changes were both detected for {0}." -f
$relationship.Name)
}
}
if (-not $relationshipDetected) {
Write-Output ' No CopyToX source/target relationship was detected.'
}
$mappingPath = Join-Path $scriptRoot 'workflow-path-mappings.json'
$mapping = Get-Content -LiteralPath $mappingPath -Raw -Encoding UTF8 | ConvertFrom-Json
$documents = @{}
$verifications = @{}
foreach ($path in $unityPaths) {
foreach ($entry in $mapping.mappings) {
if ($path -match $entry.pattern) {
$documents[$entry.document] = $true
$verifications[$entry.verification] = $true
}
}
}
Write-Output ''
Write-Output '[Suggested verification]'
if ($verifications.Count -eq 0) {
Write-Output ' No Unity verification suggestions for the current diff.'
}
else {
foreach ($item in $verifications.Keys | Sort-Object) {
Write-Output (" - {0}" -f $item)
}
}
Write-Output ''
Write-Output '[Documentation impact]'
if ($documents.Count -eq 0) {
Write-Output ' No module document mapping matched the Unity diff.'
}
else {
foreach ($document in $documents.Keys | Sort-Object) {
$changed = @($docsChanges | Where-Object { $_.Path -eq $document }).Count -gt 0
$marker = if ($changed) { 'updated' } else { 'review if long-term behavior changed' }
Write-Output (" - {0} ({1})" -f $document, $marker)
}
}
$linkFailures = @(Get-MarkdownLinkFailures $DocsRoot $docsChanges)
Write-Output ''
Write-Output '[Markdown links]'
if ($linkFailures.Count -eq 0) {
Write-Output ' Changed Markdown links are valid.'
}
else {
foreach ($failure in $linkFailures) {
Write-Error ("Broken link in {0}: {1}" -f $failure.Source, $failure.Link)
}
exit 1
}
Write-Output ''
Write-Output '[workflow-check] Completed without writing files.'
exit 0

View File

@@ -0,0 +1,59 @@
{
"mappings": [
{
"pattern": "^Assets/StrayFog/Editor/CopyToX/CopyToHF/(AssetBundle|SpriteAtlas)/",
"document": "modules/frameworks/资源管理/README.md",
"verification": "执行 CopyToX检查 HF 生成差异,构建 GameHF并验证 Unity Console。"
},
{
"pattern": "^Assets/StrayFog/Core/SFSubPackageV2\\.cs$|^Assets/StrayFog/Editor/Tools/AssetBundle/",
"document": "modules/frameworks/资源管理/README.md",
"verification": "构建 StrayFogCore 或 SFEditor并验证 V2 清单、MD5、状态和目标平台下载。"
},
{
"pattern": "^Assets/Game/GameHFScripte/GameFunction/HFDownLoadSubPackage/|^Assets/Game/GameMono/Scripts/GameDllManager\\.cs$",
"document": "modules/frameworks/资源管理/使用指南.md",
"verification": "构建 GameHF 或 SFMono验证 Bootstrap 门禁、差异回调和普通资源更新。"
},
{
"pattern": "^Assets/StrayFog/Editor/CopyToX/CopyToHF/UIWindowMgr/|^Assets/Game/GameHFScripte/GameFunction/UIWindows/|^Assets/Game/GameMono/Scripts/UIMono/",
"document": "modules/frameworks/UI窗口系统/README.md",
"verification": "构建 GameHF/SFMono刷新 Unity检查 Prefab 层级、列表回收和实际显示。"
},
{
"pattern": "^Assets/Editor/Command/|^Tools/CodexUnityMcp/",
"document": "modules/frameworks/编辑器工具/MCP工具/README.md",
"verification": "检查 Unity Editor 编译、unity_health、目标命令和 Console 日志。"
},
{
"pattern": "^Assets/Game/GameHFResource/.+\\.prefab$",
"document": "modules/frameworks/UI窗口系统/界面拼接.md",
"verification": "刷新 Unity检查 RectTransform、组件状态、资源引用和运行时视觉结果。"
},
{
"pattern": "^Assets/StrayFog/Core/",
"document": "modules/frameworks/通用框架/README.md",
"verification": "构建 StrayFogCore并检查 Unity Console。"
},
{
"pattern": "^Assets/StrayFog/Editor/",
"document": "modules/frameworks/编辑器工具/README.md",
"verification": "构建 SFEditor 或触发 Unity 编译,并验证对应菜单或生成器。"
},
{
"pattern": "^Assets/Game/GameGeneralScripte/",
"document": "modules/frameworks/通用框架/README.md",
"verification": "构建 GameGeneral生成目录变化时确认 CopyToGeneral 源码同步。"
},
{
"pattern": "^Assets/Game/GameHFScripte/",
"document": "modules/模块索引.md",
"verification": "构建 GameHF并检查 Unity Console。"
},
{
"pattern": "^Assets/Game/GameMono/",
"document": "modules/模块索引.md",
"verification": "构建 SFMono并检查 Unity Console。"
}
]
}

View File

@@ -0,0 +1,66 @@
# Hotfix 启动
## 目的
记录非热更层更新启动代码、加载 AOT/HotUpdate 程序集并进入 `HFGameStart` 的稳定顺序。
## 主要路径
- 非热更入口:`Assets/Game/GameMono/Scripts/GameDllManager.cs`
- V2 公共下载层:`Assets/StrayFog/Core/SFSubPackageV2.cs`
- 热更入口:`Assets/Game/GameHFScripte/GameFunction/GameRoot/HFGameStart.cs`
- 普通资源检查:`Assets/Game/GameHFScripte/GameFunction/HFDownLoadSubPackage/`
## 启动顺序
```text
GameDllManager.GameStart
-> SetDownloadConfig
-> 获取远端 V2 subpackage.json
-> CheckAndDownloadBootstrapFiles
-> PersistentData / StreamingAssets / CDN 逐文件 MD5 校验
-> 按 LoadOrder 加载 AOT
-> 按 LoadOrder 加载 HotUpdate
-> 调用热更入口 HFGameStart.Init
-> CommitBootstrapCodeLoaded
-> CheckAndDownloadAllFiles 更新普通资源
-> 加载配置、场景和业务管理器
```
Bootstrap 阶段是普通资源的硬门禁。远端清单、代码下载、MD5、AOT、HotUpdate 或热更入口失败时,不提交新清单,也不进入普通资源比对。
## 失败处理
- 清单获取失败通过独立回调返回并阻断启动。
- 文件失败结果包含 Path、期望 MD5、错误和尝试 URL。
- 下载写临时文件MD5 成功后才替换 PersistentData 正式文件。
- AOT 始终先于 HotUpdate不同版本代码不能混合加载。
- 失败后可以重新执行整个 Bootstrap 阶段,已校验成功文件不会重复下载。
## 热更入口
`HFGameStart` 负责设置 GameSetting、检查普通资源、加载配置和场景、初始化业务管理器。业务访问框架能力统一通过 `HFFunCatalogue`
启动顺序变化必须同时检查非热更层、V2 门禁、普通资源和 UI 首屏,不能只修改热更入口一侧。
## 验证
- 构建 `GameMono``SFMono.csproj`)与非热更入口相关程序集。
- 构建 `GameHF.csproj`
- 在目标平台或 Editor 中验证 Bootstrap 阶段清单获取、MD5 校验、AOT/HotUpdate 加载顺序。
- 模拟 Bootstrap 失败(如断网、错误 MD5确认重试与回调行为。
- 验证普通资源更新后 `HFGameStart` 正常进入配置/场景加载。
## 当前状态
- 待验证
## 文档关联
| 文档 | 关联原因 |
|---|---|
| [模块索引](../模块索引.md) | 模块入口和状态 |
| [资源管理](资源管理/README.md) | V2 清单、Bootstrap 和普通资源 |
| [UI 窗口系统](UI窗口系统/README.md) | 启动后窗口加载 |
| [场景系统](场景系统.md) | 启动后的场景流程 |
| [架构说明](../../rules/10-架构说明.md) | 非热更层与热更层边界 |

View File

@@ -0,0 +1,66 @@
# UI 窗口系统
## 目的
记录 StrayFog 窗口管理、资源加载、生命周期、UIMono 绑定和虚拟列表的稳定使用规则。
## 主要路径
| 类型 | 路径 | 说明 |
|---|---|---|
| ESF 源码 | `Assets/StrayFog/Editor/CopyToX/CopyToHF/UIWindowMgr/` | 窗口框架真实源码 |
| HF 生成代码 | `Assets/Game/GameHFScripte/CopyToHF/UIWindowMgr/` | CopyToX 结果,禁止手改 |
| 业务窗口 | `Assets/Game/GameHFScripte/GameFunction/UIWindows/` | 窗口与子组件业务逻辑 |
| Mono 组件 | `Assets/Game/GameMono/Scripts/UIMono/` | SFUI/UIMono 和列表包装 |
| UI 资源 | `Assets/Game/GameHFResource/<语言>/UIWindows/` | Prefab 与窗口资源 |
## 打开流程
```text
HFFunCatalogue.UIManager.OpenWindow<T>()
-> HFUIWindowMgr 创建窗口任务
-> 读取 HFAssetBundlePath / HFUIWindowLayer
-> 复用缓存或创建窗口逻辑
-> LoadInMemory 加载 Prefab
-> BindGameObject / OnAttachWindow
-> OnRunAwake实例首次绑定
-> OnOpen每次打开
```
关闭窗口会执行 `OnClose`、隐藏实例并放入窗口缓存。需要释放窗口与资源时使用 UI 管理器公开卸载入口,不直接 Destroy 窗口 Prefab 或绕过管理器修改父节点和 siblingIndex。
## 生命周期
| 生命周期 | 用途 |
|---|---|
| `OnRunAwake` | 查找控件、绑定按钮、配置并初始化虚拟列表,只执行一次 |
| `OnOpen` | 注册本次打开所需事件、刷新数据与显示状态 |
| `OnClose` | 移除事件、停止计时器和清理本次打开状态 |
异步加载、动画和下载的成功、失败、取消路径都必须结束窗口任务,不能让窗口永久停在加载中。
## 使用规则
- 窗口继承 `AbsHFUIWindow`,配置 `HFAssetBundlePath``HFUIWindowLayer`
- 打开和关闭统一通过 `HFFunCatalogue.UIManager`
- `OnOpen``OnClose` 中的事件注册和释放保持对称。
- 引用绑定优先使用项目 UIMono/SFUI 流程,不堆叠 `transform.Find`
- 单列虚拟列表使用 LoopListView2 包装接口,多列布局使用 LoopGridView 包装接口。
- 模板节点在 Prefab 中保持禁用,由虚拟列表创建实例。
- UI 修改必须验证脚本、Prefab 层级、RectTransform、组件状态和运行时效果。
## 子文档
- [UI 开发指南](开发指南.md)
- [界面拼接](界面拼接.md)
- [UI 拼接工具](../编辑器工具/UI拼接工具.md)
## 文档关联
| 文档 | 关联原因 |
|---|---|
| [模块索引](../../模块索引.md) | 模块入口和状态 |
| [资源管理](../资源管理/README.md) | UI Prefab 加载与卸载 |
| [事件系统](../事件系统/README.md) | 窗口事件生命周期 |
| [架构说明](../../../rules/10-架构说明.md) | ESF/HF 源码边界 |
| [开发规则](../../../rules/20-开发规则.md) | UI 与 Prefab 通用约束 |

View File

@@ -0,0 +1,135 @@
# UI 开发指南
## 一、窗口开发
窗口类继承 `AbsHFUIWindow`,通过 attribute 声明资源路径和 Canvas 层级:
```csharp
[HFAssetBundlePath("UIWindows/ExampleWindow/ExampleWindow.prefab")]
[HFUIWindowLayer(enHFUICanvasLayer.Dynamic)]
public partial class ExampleWindow : AbsHFUIWindow
{
protected override void OnRunAwake()
{
base.OnRunAwake();
// 查找控件、绑定按钮、初始化列表。
}
protected override void OnOpen(object[] _args)
{
base.OnOpen(_args);
// 注册事件并刷新本次显示数据。
}
protected override void OnClose()
{
// 移除事件和计时器。
base.OnClose();
}
}
```
业务打开窗口使用:
```csharp
HFFunCatalogue.UIManager.OpenWindow<ExampleWindow>();
```
不要直接实例化窗口 Prefab也不要直接调用内部 `HFUIWindowMgr` 单例。
## 二、生命周期规则
- `OnRunAwake`:实例首次绑定时执行一次,适合控件查找、按钮绑定和虚拟列表初始化。
- `OnOpen`:每次打开执行,适合注册事件、应用参数和刷新数据数量。
- `OnClose`:每次关闭执行,与 `OnOpen` 中的监听、计时器和临时状态对称清理。
- 列表初始化不能依赖数据已经到达;先以数量 `0` 初始化,数据准备后再刷新数量。
## 三、单列虚拟列表
单列或单行滚动使用 LoopListView2 包装接口:
```csharp
m_List.SetLoopListViewItemPrefabs(
new GameObject[] { m_ItemTemplate.gameObject }, 0, 1);
m_List.InitListView(
0,
OnGetItem,
OnCreateItem,
OnUpdateItem,
OnGetPrefabIndex,
false);
```
数据准备或变化后:
```csharp
m_List.RefreshDataTotalCount(m_DataList == null ? 0 : m_DataList.Count);
```
回调职责:
| 回调 | 职责 |
|---|---|
| `OnGetItem` | 从已创建节点取得 `SFUI_ScrollRectItem` |
| `OnCreateItem` | 首次创建绑定类和 SimulateBehaviour |
| `OnUpdateItem` | 根据 dataIndex 更新显示,不能假设旧数据仍有效 |
| `OnGetPrefabIndex` | 多模板时返回模板索引,单模板返回 `0` |
垂直列表模板通常使用左上锚点和 pivot `(0, 1)`,宽度与 viewport 匹配;水平列表按滚动方向设置。模板尺寸或 pivot 错误会造成重叠、偏移或不可见。
## 四、多列虚拟列表
存在固定列数、`GridLayoutGroup` 语义或二维排布时使用 LoopGridView
```csharp
m_Grid.SetLoopGridViewItemPrefabs(
new GameObject[] { m_ItemTemplate.gameObject },
new Vector2(216, 293),
new Vector2(50, 30),
new RectOffset(55, 55, 0, 0),
4,
1);
m_Grid.InitGridView(
0,
OnGetGridItem,
OnCreateGridItem,
OnUpdateGridItem,
OnGetGridPrefabIndex);
```
刷新数量:
```csharp
m_Grid.RefreshGridDataTotalCount(m_DataList == null ? 0 : m_DataList.Count);
```
不要通过单列 ListView 模拟多列布局。Grid 的 itemSize、spacing、padding 和列数必须与 Prefab 视觉布局一致。
## 五、Prefab 设置
- 模板节点保持 `SetActive(false)`,但必须位于窗口层级中以便引用收集。
- `SFUI_ScrollRect`、viewport、content 和模板引用必须完整。
- 虚拟列表初始化会关闭旧 `LayoutGroup``ContentSizeFitter`,运行时布局由 SuperScrollView 管理。
- 不要因为这些旧组件在运行时被关闭就重新勾选或依赖它们计算虚拟列表尺寸。
- 检查模板上的 `LoopListViewItem2``LoopGridViewItem`;包装层会补组件,但 Prefab 结构仍需正确。
- UIMono 收集需要包含 inactive 子节点,不能只扫描激活节点。
## 六、验证清单
1. 构建 `SFMono.csproj` 和涉及的 `GameHF.csproj`
2. 刷新 Unity Assets 并读取 Console。
3. 检查 Prefab 的 viewport、content、模板、RectTransform 和组件启用状态。
4. 验证空数据、1 个元素、超出视口、多次刷新和重复打开。
5. 滚动后验证元素回收与复用,没有 `KeyNotFoundException`、旧数据显示或重复创建。
6. 多列列表验证最后一行不足列数时的尺寸和定位。
## 文档关联
| 文档 | 关联原因 |
|---|---|
| [UI 窗口系统](README.md) | 窗口框架入口与生命周期 |
| [界面拼接](界面拼接.md) | Prefab 结构和视觉实现 |
| [UI 拼接工具](../编辑器工具/UI拼接工具.md) | JSON/Prefab 双向转换 |
| [开发规则](../../../rules/20-开发规则.md) | 通用 UI 和 C# 规则 |

View File

@@ -0,0 +1,80 @@
# UI 界面拼接
## 一、输入与目标
开始拼接前同时确认:
- 设计原图、标注图或 PSD 中的尺寸、间距和层级。
- 项目现有 Sprite、SpriteAtlas、字体、材质和可复用 Prefab。
- 目标窗口名、Prefab 路径、Canvas 层级和脚本绑定方式。
- 目标分辨率、SafeArea、横竖屏和滚动区域。
不能只凭截图选择近似资源。设计图中的可检查对象必须使用语义正确的现有资源;缺失资源应明确记录,不能用无关图片顶替。
## 二、推荐层级
```text
WindowName
├── ImgBg
├── HeaderArea
├── ContentArea
│ ├── StaticContent
│ └── ListView
│ └── viewport
│ └── content
│ └── ItemTemplate (inactive)
├── FooterArea
└── PopupOrEffectArea
```
- 按视觉和功能边界组织节点,不为每个图片增加无意义容器。
- 节点命名应能对应脚本字段和功能,例如 `Btn_Close``Txt_Title``Img_Icon`
- 复用 Item 或子面板时保持独立根节点,便于 UIMono 绑定和对象复用。
- 全屏背景使用稳定锚点;局部模块使用明确尺寸,避免依赖编辑器当前分辨率。
## 三、列表选择
- 单列或单行滚动LoopListView2。
- 固定多列或网格LoopGridView。
- 模板节点保持禁用尺寸、pivot 和滚动方向必须匹配。
- 虚拟列表不依赖旧 LayoutGroup/ContentSizeFitter 运行时排版。
- 具体初始化接口见 [UI 开发指南](开发指南.md)。
## 四、拼接流程
1. 读取 [UnityAI README](../../../README.md) 中的 UI 入口和相关指南。
2. 检查目标 Prefab 是否已存在,导出或读取当前层级,避免覆盖有效结构。
3. 枚举目标资源目录和图集,建立设计元素到实际资源的对应关系。
4. 确定窗口根尺寸、锚点、主要功能区和列表类型。
5. 使用 Unity Editor 手工拼接,或通过 MCP 的 JSON 生成工具创建基础结构。
6. 绑定 SFUI/UIMono 组件与业务脚本,补齐交互、列表和动态数据。
7. 刷新资源并检查 Console、Prefab 序列化结构和运行时显示。
8. 对照原图检查尺寸、层级、颜色、字体、九宫格和点击区域。
JSON 生成适合批量创建稳定层级和组件,不代替视觉校对、业务绑定和运行时验证。
## 五、修改已有 Prefab
- 先读取现有 Prefab 和脚本引用,再调整层级或组件。
- 移动、重命名节点前搜索 `FindUICtrlByName`、序列化字段和生成绑定代码。
- 只修改目标节点,避免让 Unity 重序列化无关 Prefab。
- 组件勾选状态属于 Prefab 行为的一部分;修复显示问题时同时检查 `enabled` 与 GameObject active。
- 列表迁移后,旧布局组件可保留序列化参数作为参考,但运行时由新列表包装关闭。
## 六、验收
- Prefab 路径和窗口 attribute 一致。
- Sprite、字体、材质和图集引用有效。
- 锚点、pivot、sizeDelta 和层级与设计目标一致。
- 按钮、文本、列表、进度和弹窗交互正确。
- 空数据、极长文本、不同分辨率和重复打开不破版。
- Unity Console 无本次新增 Error运行时实际显示通过确认。
## 文档关联
| 文档 | 关联原因 |
|---|---|
| [UI 窗口系统](README.md) | 窗口框架和资源路径 |
| [UI 开发指南](开发指南.md) | 生命周期和虚拟列表接口 |
| [UI 拼接工具](../编辑器工具/UI拼接工具.md) | MCP JSON/Prefab 工具 |
| [MCP 使用规则](../编辑器工具/MCP工具/CrystalBattle_Codex_Unity_MCP使用规则.md) | Codex 与 Unity 的调用规则 |

View File

@@ -0,0 +1,122 @@
# 事件系统
## 分类
- 核心框架
## 目的
提供客户端内部事件CTC和服务器消息事件STC的统一派发、监听和释放机制。
---
## 核心路径
- 框架层:`Assets/Game/GameHFScripte/CopyToHF/Event/`
- 功能层:`Assets/Game/GameHFScripte/GameFunction/Event/`
- STC 事件参数:`Assets/Game/GameHFScripte/GameFunction/Event/STCEventArg/`
---
## 核心类
| 类 | 职责 |
|---|---|
| `HFEventManager` | 事件管理器单例,继承 `AbsHFSingleRunTime<HFEventManager>` |
| `TCEvent` | CTC 事件句柄 |
| `STCEvent` | STC 事件句柄 |
| `CTCHandle` | CTC 事件处理器定义位置 |
| `AbsHFEventArg<K,T>` | 事件参数基类 |
---
## 事件派发链路
### CTC 事件
```text
AbsHFEventArg<enHFCTCEvent>.Dispatch()
-> HFEventManager.Instance.TCEvent.Dispatch(arg)
```
CTC 事件来源:
- 功能代码手动创建事件参数对象。
- 设置字段后调用 `.Dispatch()`
- 示例:业务管理器派发初始化事件、背包更新事件。
### STC 事件
```text
AbsHFEventArg<enHFSTCEvent>.Dispatch()
-> HFEventManager.Instance.STCEvent.Dispatch(arg)
```
STC 事件来源:
```text
WSSession 收到 protobuf S2C
-> 反射创建 HFEvent_STC_{MessageTypeName}
-> 写入 Request / ErrorCode
-> Dispatch 到 STCEvent
```
---
## 监听与派发机制
```text
AddListener<TEventArg>(eventId, callback)
-> 按 eventId 分组
-> 按事件参数类型 hash 分组
Dispatch(arg)
-> 根据 arg.eventId 找事件组
-> 根据 arg.GetType() 找具体类型监听
-> Invoke callbacks
-> arg.Recycle()
```
---
## 使用规则
- UI 窗口在 `OnOpen` 中注册的事件,必须在 `OnClose` 中移除。
- 管理器监听 STC 事件通常在初始化时添加,在 `Recycle` 或销毁时移除。
- 不要直接监听与当前模块无关的事件。
- 事件参数对象由框架自动回收,业务代码不要重复释放。
---
## 错误响应
当服务器返回错误响应时:
```text
messagePage.IsError = true
-> 解析 ErrorResponse
-> 派发 HFEvent_ErrorCode
-> 同时仍创建对应 HFEvent_STC_* 并写入 ErrorCode
```
---
## 相关模块
- [网络系统](../网络系统.md)
- [UI 窗口系统](../UI窗口系统/README.md)
- [实体系统](../实体系统/README.md)
---
## 文档关联
> 当本文档发生变更时,应同步检查以下关联文档,避免信息不一致。
| 文档 | 关联原因 |
|---|---|
| [modules/模块索引.md](../../模块索引.md) | 模块索引是项目知识总入口 |
| [modules/frameworks/网络系统.md](../网络系统.md) | S2C 消息是 STC 事件来源 |
| [modules/frameworks/UI窗口系统/README.md](../UI窗口系统/README.md) | UI 窗口订阅和释放事件 |
| [rules/10-架构说明.md](../../../rules/10-架构说明.md) | 架构说明定义总体分层和依赖方向 |
| [rules/30-模块登记规则.md](../../../rules/30-模块登记规则.md) | 模块登记规则定义分类和状态口径 |

View File

@@ -1,4 +1,4 @@
# StrayFog 框架事件系统使用指南 # 事件系统使用指南
## 一、事件系统概述 ## 一、事件系统概述
@@ -13,7 +13,7 @@
### 2.1 定义事件枚举和参数 ### 2.1 定义事件枚举和参数
```csharp ```csharp
// 事件ID枚举 // 事件 ID 枚举
public enum GameEventId public enum GameEventId
{ {
PlayerLevelUp, PlayerLevelUp,
@@ -44,9 +44,9 @@ public class PlayerLevelUpEventArgs : GameEventArgs
--- ---
## 三、UI窗口事件监听 ## 三、UI 窗口事件监听
### 3.1 在窗口中注册CTCEvent ### 3.1 在窗口中注册 CTCEvent
```csharp ```csharp
[HFAssetBundlePath(enHFLanguageRootFolder.ASSETS_GAME_GAMEHFRESOURCE, "UIWindows/CardDeck/CardDeckWindow.prefab")] [HFAssetBundlePath(enHFLanguageRootFolder.ASSETS_GAME_GAMEHFRESOURCE, "UIWindows/CardDeck/CardDeckWindow.prefab")]
@@ -70,18 +70,18 @@ public class CardDeckWindow : AbsHFUIWindow
void OnCardUpdate(HFEventArgBase arg) void OnCardUpdate(HFEventArgBase arg)
{ {
HFEvent_CTC_CardUpdate cardArg = arg as HFEvent_CTC_CardUpdate; HFEvent_CTC_CardUpdate cardArg = arg as HFEvent_CTC_CardUpdate;
// 更新卡组UI显示 // 更新卡组 UI 显示
} }
} }
``` ```
> **注意**UI窗口中**不监听服务器事件STCEvent**服务器事件应在Logic层的Manager中监听。 > **注意**UI 窗口中**不监听服务器事件STCEvent**,服务器事件应在 Logic 层的 Manager 中监听。
--- ---
## 四、Manager事件监听 ## 四、Manager 事件监听
### 4.1 使用AbsHFSingleMonoBehaviour需要Update ### 4.1 使用 AbsHFSingleMonoBehaviour需要 Update
```csharp ```csharp
public class PlayerManager : AbsHFSingleMonoBehaviour<PlayerManager> public class PlayerManager : AbsHFSingleMonoBehaviour<PlayerManager>
@@ -107,7 +107,7 @@ public class PlayerManager : AbsHFSingleMonoBehaviour<PlayerManager>
{ {
HFEvent_STC_PlayerInfo info = arg as HFEvent_STC_PlayerInfo; HFEvent_STC_PlayerInfo info = arg as HFEvent_STC_PlayerInfo;
// 处理服务器返回的玩家信息 // 处理服务器返回的玩家信息
// 触发客户端事件通知UI更新 // 触发客户端事件通知 UI 更新
HFEvent_CTC_PlayerLevelUp evt = HFFunCatalogue.New<HFEvent_CTC_PlayerLevelUp>(); HFEvent_CTC_PlayerLevelUp evt = HFFunCatalogue.New<HFEvent_CTC_PlayerLevelUp>();
evt.playerId = info.playerId; evt.playerId = info.playerId;
evt.newLevel = info.level; evt.newLevel = info.level;
@@ -116,7 +116,7 @@ public class PlayerManager : AbsHFSingleMonoBehaviour<PlayerManager>
} }
``` ```
### 4.2 使用AbsHFSingleRunTime纯逻辑 ### 4.2 使用 AbsHFSingleRunTime纯逻辑
```csharp ```csharp
public class ConfigManager : AbsHFSingleRunTime<ConfigManager> public class ConfigManager : AbsHFSingleRunTime<ConfigManager>
@@ -137,15 +137,32 @@ public class ConfigManager : AbsHFSingleRunTime<ConfigManager>
--- ---
## 五、Manager类型对比 ## 五、Manager 类型对比
| 类型 | 说明 | 适用场景 | | 类型 | 说明 | 适用场景 |
|-----|------|---------| |-----|------|---------|
| `AbsHFSingleMonoBehaviour` | 生成GameObject可注册MonoBehaviour事件 | 需要Update/FixedUpdate等生命周期 | | `AbsHFSingleMonoBehaviour` | 生成 GameObject可注册 MonoBehaviour 事件 | 需要 Update/FixedUpdate 等生命周期 |
| `AbsHFSingleRunTime` | 纯内存单例无GameObject | 不需要生命周期事件 | | `AbsHFSingleRunTime` | 纯内存单例,无 GameObject | 不需要生命周期事件 |
--- ---
**版本**: v1.0 **版本**: v1.0
**生效日期**: 2026年 **生效日期**: 2026年
**适用范围**: GiftGameX项目业务开发人员 **适用范围**: 使用 StrayFog 框架的项目开发人员
---
## 文档关联
> 当本文档发生变更时,应同步检查以下关联文档,避免信息不一致。
| 文档 | 关联原因 |
|---|---|
| [事件系统入口](README.md) | 本文件是事件系统模块的子文档 |
| [网络系统](../网络系统.md) | STC 事件来源与网络系统相关 |
| [UI 窗口系统](../UI窗口系统/README.md) | UI 窗口订阅和释放事件 |
| [实体系统](../实体系统/README.md) | Manager 常与实体系统协作 |
| [modules/模块索引.md](../../模块索引.md) | 模块索引是项目知识总入口 |
| [rules/10-架构说明.md](../../../rules/10-架构说明.md) | 架构说明定义总体分层和依赖方向 |
| [rules/20-开发规则.md](../../../rules/20-开发规则.md) | 事件订阅/释放与开发规则互相引用 |
| [rules/30-模块登记规则.md](../../../rules/30-模块登记规则.md) | 模块登记规则定义分类和状态口径 |

View File

@@ -0,0 +1,60 @@
# 对象池与运行时对象管理
## 分类
- 核心框架
## 目的
提供类实例池、行为对象池、脚本对象池、实体池和 RT 展示对象的统一复用机制,减少 GC 和实例化开销。
## 核心路径
- 内存管理:`Assets/Game/GameHFScripte/CopyToHF/MemoryManager/`
- 运行时对象:`Assets/Game/GameHFScripte/GameFunction/RTObjectManager/`
- 调用池:`Assets/Game/GameHFScripte/GameFunction/Logic/CallPoolManager/`
- 实体池:`Assets/Game/GameHFScripte/GameFunction/GameEntity/EntityPool/`
## 池类型概览
| 池 | 用途 |
|---|---|
| `HFClassEntityManager` | 类实例池,按类型维护复用栈 |
| `HFSimulateBehaviourPool<T>` | 行为对象池,用于继承 `AbsHFSimulateBehaviour` 的对象 |
| `HFScriptMemPool<T>` | 脚本对象池,支持普通类与 MonoBehaviour |
| `HFEntityPool` | 实体池,见 [实体系统](../实体系统/README.md) |
| RT 展示对象 | 在独立相机展示模型/特效,资源加载走 `HFABMgr` |
## 回收接口
| 接口 | 职责 |
|---|---|
| `IHFRecycle` | 基础回收接口,声明 `Recycle()` |
| `IHFRecycleEventHandler` | 回收事件处理 |
| `OnAfterRecycleHandler` | 回收到类实例池 |
## 使用规则
- 频繁创建/销毁的对象优先使用对象池。
- 归还对象时确保来源正确,避免泄漏。
- 对象池内对象在归还后应重置状态。
- RT 对象注意及时释放相机 seat 和资源引用。
## 详细文档
- [使用指南](使用指南.md) — GameObject 池、脚本池、设计特点、性能建议与示例
- [实体系统](../实体系统/README.md) — 实体池特化
- [资源管理](../资源管理/README.md) — RT 对象资源加载
## 文档关联
> 当本文档发生变更时,应同步检查以下关联文档,避免信息不一致。
| 文档 | 关联原因 |
|---|---|
| [modules/模块索引.md](../../模块索引.md) | 模块索引是项目知识总入口 |
| [modules/frameworks/内存对象管理/使用指南.md](使用指南.md) | 本模块的详细 API 与使用说明 |
| [modules/frameworks/实体系统/README.md](../实体系统/README.md) | 实体池是对象池的一种特化 |
| [modules/frameworks/资源管理/README.md](../资源管理/README.md) | RT 对象资源加载依赖资源管理 |
| [rules/10-架构说明.md](../../../rules/10-架构说明.md) | 架构说明定义总体分层和依赖方向 |
| [rules/30-模块登记规则.md](../../../rules/30-模块登记规则.md) | 模块登记规则定义分类和状态口径 |

View File

@@ -1,6 +1,6 @@
# StrayFog 框架对象池使用指南 # 对象池使用指南
## 一、GameObject对象池 ## 一、GameObject 对象池
### 1.1 基本用法 ### 1.1 基本用法
@@ -82,11 +82,11 @@ public class EventArgPool : MonoBehaviour
### 3.1 对象池设计特点 ### 3.1 对象池设计特点
| 特性 | 说明 | | 特性 | 说明 |
|-----|-----| |-----|------|
| **双池结构** | 空闲池 + 使用池,高效管理对象状态 | | **双池结构** | 空闲池 + 使用池,高效管理对象状态 |
| **内存泄漏检测** | 归还时校验来源,及时发现问题 | | **内存泄漏检测** | 归还时校验来源,及时发现问题 |
| **泛型支持** | `HFScriptMemPool<T>` 提供类型安全 | | **泛型支持** | `HFScriptMemPool<T>` 提供类型安全 |
| **Mono支持** | 自动创建GameObject无缝集成Unity | | **Mono 支持** | 自动创建 GameObject无缝集成 Unity |
### 3.2 性能优化建议 ### 3.2 性能优化建议
@@ -98,4 +98,19 @@ public class EventArgPool : MonoBehaviour
**版本**: v1.0 **版本**: v1.0
**生效日期**: 2026年 **生效日期**: 2026年
**适用范围**: GiftGameX项目业务开发人员 **适用范围**: 使用 StrayFog 框架的项目开发人员
---
## 文档关联
> 当本文档发生变更时,应同步检查以下关联文档,避免信息不一致。
| 文档 | 关联原因 |
|---|---|
| [对象池与运行时对象管理入口](README.md) | 本文件是内存对象管理模块的子文档 |
| [实体系统](../实体系统/README.md) | 实体池是对象池的一种特化 |
| [资源管理](../资源管理/README.md) | RT 对象资源加载依赖资源管理 |
| [modules/模块索引.md](../../模块索引.md) | 模块索引是项目知识总入口 |
| [rules/10-架构说明.md](../../../rules/10-架构说明.md) | 架构说明定义总体分层和依赖方向 |
| [rules/30-模块登记规则.md](../../../rules/30-模块登记规则.md) | 模块登记规则定义分类和状态口径 |

View File

@@ -0,0 +1,108 @@
# 场景系统
## 分类
- 核心框架
## 目的
管理 Unity 场景的加载、资源配置读取和场景生命周期回调。
---
## 核心路径
- 场景管理器:`Assets/Game/GameHFScripte/GameFunction/SceneManager/`
- Unity 场景:`Assets/Game/GameMono/Scenes/`
---
## 核心类
| 类 | 职责 |
|---|---|
| `HFSceneMgr` | 场景管理器单例,继承 `AbsHFSingleMonoBehaviour<HFSceneMgr>` |
| `enHFSceneName` | 场景枚举,例如 `Game = 80001` |
---
## 加载流程
```text
LoadScene(enHFSceneName scene, Action complete)
-> 转为资源/关卡 id
-> LoadScene(int levelId, Action complete)
-> HFFunCatalogue.NDB.ds_Resource840C5F09TableData.ReadTableByPK(levelId)
-> 读取资源配置
```
### Editor 模式
```text
从配置 Path 取文件名
-> SceneManager.LoadScene(scName)
```
### 非 Editor 模式
```text
HFFunCatalogue.Asset.LoadAsset(levelId, ...)
-> 用结果中的 res.sceneName 调用 SceneManager.LoadScene
```
`OnLoadScene()` 同步调用 `SceneManager.LoadScene()` 后立即执行完成回调。
---
## 生命周期
`ZYCore` 中存在 `IZYH_ZYCore_Scene``AbsZYH_ZYCore_Scene` 接口:
- 进入加载场景
- 加载完成
- 进入/退出场景前后
- 切场景释放
`ZYUGUI` 窗口管理器提供:
- `isAutoCloseWhenToggleScene`:切场景时自动关闭
- `isAutoDestoryWhenToggleScene`:切场景时自动销毁
---
## 使用规则
- 场景切换统一走 `HFFunCatalogue.Scene.LoadScene()`
- 不要在场景里堆放运行时动态加载的资源。
- 切场景时注意 UI 窗口的自动关闭/销毁配置。
## 验证
- 构建 `GameHF.csproj``SFMono.csproj`
- 在 Unity Editor 中切换场景,确认加载回调、资源引用和 UI 自动关闭行为正确。
- 检查 `enHFSceneName` 与资源配置表的主键一致性。
## 当前状态
- 待验证
---
## 相关模块
- [资源管理](资源管理/README.md)
- [UI 窗口系统](UI窗口系统/README.md)
---
## 文档关联
> 当本文档发生变更时,应同步检查以下关联文档,避免信息不一致。
| 文档 | 关联原因 |
|---|---|
| [modules/模块索引.md](../模块索引.md) | 模块索引是项目知识总入口 |
| [modules/frameworks/资源管理/README.md](资源管理/README.md) | 场景资源加载依赖资源管理 |
| [modules/frameworks/UI窗口系统/README.md](UI窗口系统/README.md) | 切场景影响 UI 窗口生命周期 |
| [rules/10-架构说明.md](../../rules/10-架构说明.md) | 架构说明定义总体分层和依赖方向 |
| [rules/30-模块登记规则.md](../../rules/30-模块登记规则.md) | 模块登记规则定义分类和状态口径 |

View File

@@ -0,0 +1,138 @@
# 实体系统
## 分类
- 核心框架
## 目的
管理游戏实体的创建、生命周期、System-Model 架构、实体池和子系统协作。
---
## 核心路径
- 实体框架:`Assets/Game/GameHFScripte/GameFunction/GameEntity/`
- 实体数据:`Assets/Game/GameHFScripte/GameFunction/Logic/EntityData/`
- 子目录:`Core/``Entity/``EntityPool/``RVO/``StateMachineBehaviour/`
---
## 核心类
| 类 | 职责 |
|---|---|
| `HFAbsEntity` | 实体基类,继承 `AbsHFSimulateBehaviour` |
| `HFEntity_Basic` | 基础实体标签 |
| `HFEntity_Enemy` | 敌人类型标签 |
| `HFEntity_Human` | 人类/玩家类型标签 |
| `HFEntityPool` | 实体池入口 |
| `HFBasicPool` / `HFEnemyPool` / `HFHumanityPool` | 按 `enEntityLayer` 分类的实体池实现 |
| `AbsHFEntityPool` | 实体池抽象基类 |
| `stEntityInfo` | 实体数据结构 |
---
## System-Model 架构
`HFAbsEntity` 内部维护两个集合:
```text
m_Models : IModel[] // 数据层
m_Systems : ISystem[] // 表现层/逻辑层
```
`enSystemType` 关联 `IModel``ISystem`
添加系统:
```csharp
AddSystem<T>()
-> HFClassEntityManager.Instance.GetClassEntity<T>() // 创建或复用系统对象
-> IModel
-> model.Init(this, system.Init) // 建立实体、模型、系统关系
```
更新顺序:
```text
OnSystemUpdate() // 表现层更新
OnModelUpdate() // 数据层更新
```
---
## 实体池机制
`HFEntityPool``enEntityLayer` 注册不同的 `AbsHFEntityPool` 实现。
创建实体:
```text
AbsHFEntityPool.OnCreateEnity<T>()
-> 创建 GameObject 根节点
-> 维护 onlyid -> entity 索引
-> 维护 EntityId -> onlyid 索引
```
查询实体:
```text
HFEntityPool.SelectByOnlyid(onlyid)
-> 通过 onlyid -> enEntityLayer 找到对应池
-> 从具体池取实体
```
回收实体:
```text
DelEntityByOnlyid(onlyid)
-> 从池索引移除
-> 调用 entity.Recycle()
```
---
## 子系统
实体相关的子系统通常位于:
- `Models/AI``Systems/AI` — AI
- `Models/Animation``Systems/Animation` — 动画
- `Models/Feature``Systems/Feature` — 特性/属性
- `Models/Move``Systems/Move` — 移动
- `Models/Skill``Systems/Skill` — 技能
- `HFSkillTrigger_*` — 技能触发器
- `HFSkill_*_Releaser` — 技能释放器
- `GameEntity/RVO/RVOManager.cs` — RVO 避障
---
## 使用规则
- 新实体类型应继承 `HFAbsEntity`
- 实体对象统一通过 `HFEntityPool` 创建和回收。
- 系统通过 `AddSystem<T>()` 添加,避免直接 new。
- 子系统数据更新放在 `OnModelUpdate()`,表现更新放在 `OnSystemUpdate()`
---
## 相关模块
- [技能系统](../技能系统/README.md)
- [对象池](../内存对象管理/README.md)
- [数据/配置框架](../数据配置框架.md)
---
## 文档关联
> 当本文档发生变更时,应同步检查以下关联文档,避免信息不一致。
| 文档 | 关联原因 |
|---|---|
| [modules/模块索引.md](../../模块索引.md) | 模块索引是项目知识总入口 |
| [modules/frameworks/技能系统/README.md](../技能系统/README.md) | 技能系统是实体系统的子系统 |
| [modules/frameworks/内存对象管理/README.md](../内存对象管理/README.md) | 实体池与对象池机制相关 |
| [rules/10-架构说明.md](../../../rules/10-架构说明.md) | 架构说明定义总体分层和依赖方向 |
| [rules/30-模块登记规则.md](../../../rules/30-模块登记规则.md) | 模块登记规则定义分类和状态口径 |

View File

@@ -0,0 +1,339 @@
# Entity 开发指南
## 一、Entity 概述
Entity 是游戏世界中所有游戏对象的抽象基类包括玩家、敌人、塔楼、城堡等。Entity 系统提供统一的对象管理、生命周期控制和 **System-Model 架构**
### 1.1 Entity 分类
Entity 分类根据具体业务需求定义,以下为示例分类(项目实际分类以业务为准):
| 类别 | 说明 | 示例 |
|-----|------|------|
| **Human** | 具有生命、移动能力的实体 | Player、Enemy |
| **Tower** | 防御塔实体 | 箭塔、炮塔 |
| **Castle** | 城堡/基地实体 | 玩家基地 |
| **Obstacle** | 障碍物实体 | 墙壁、陷阱 |
> **说明**:实际项目中需根据业务需求定义 Entity 类型,继承 `HFAbsEntity` 基类并实现对应逻辑。
### 1.2 核心数据结构
```csharp
// Entity 唯一标识
public long onlyid { get; } // 运行时唯一ID
public int EntityId { get; } // 资源配置ID
public enEntityLayer entityType { get; } // Entity 类型
public enEntityCamp entityCamp { get; } // 阵营
public bool isDeath { get; } // 是否死亡
```
---
## 二、Entity 创建规范
### 2.1 继承结构
```csharp
// 核心基类
public abstract partial class HFAbsEntity : AbsHFSimulateBehaviour
{
public long onlyid { get; private set; }
public enEntityLayer entityType { get; private set; }
public enEntityCamp entityCamp { get; private set; }
public int EntityId { get; private set; }
public bool isDeath { get; private set; } // 逻辑死亡标记
// 初始化方法
public void Init() { ... }
public virtual void OnInit() { ... }
// 死亡方法(表现层)
public void Death() { ... } // 触发死亡事件
public virtual void OnDeath() { ... } // 子类重写处理表现死亡逻辑
// 逻辑死亡(数据层)
protected void Logic_Death() { ... } // 设置 isDeath=true数据层死亡
protected virtual void OnLogicDeath() { ... } // 子类重写处理逻辑死亡逻辑
}
// 具体 Entity 示例 - Human 类型
public class HFEntity_Human : HFAbsEntity
{
protected override void OnRunAwake()
{
base.OnRunAwake();
AddSystem<HFFeatureSystem>();
AddSystem<HFAnimationSystem_Human>();
AddSystem<HFApathMoveSystem>();
AddSystem<HFSkillSystem>();
}
public override void OnInit()
{
// 初始化配置数据
}
public override void OnDeath()
{
// 死亡处理逻辑
}
}
```
### 2.2 命名规范
| 类型 | 命名规则 | 示例 |
|-----|---------|------|
| Entity 类 | `HFEntity_{TypeName}` | `HFEntity_Human``HFEntity_Tower` |
| 系统类 | `HF{SystemName}System[_TypeName]` | `HFAnimationSystem_Human` |
| 模型类 | `HF{ModelName}Model[_TypeName]` | `HFAnimationModel_Human` |
| 数据结构 | `st{DataName}` | `stAbilityData``stDamageInfo` |
---
## 三、Entity 生命周期
### 3.1 生命周期方法
| 方法 | 调用时机 | 职责 | 层级 |
|-----|---------|------|-----|
| `OnRunAwake()` | 对象创建时 | 添加 System 组件 | 表现层 |
| `Init()` | 初始化时调用 | 重置死亡状态、调用 OnInit | - |
| `OnInit()` | Init 内部调用 | 子类重写,初始化配置数据 | 数据层 |
| `Logic_Death()` | HP 归零时调用 | 设置 `isDeath=true`,调用 OnLogicDeath | 数据层 |
| `OnLogicDeath()` | Logic_Death 内部调用 | 子类重写处理逻辑死亡逻辑 | 数据层 |
| `Death()` | 逻辑死亡后调用 | 触发死亡事件、调用 OnDeath | 表现层 |
| `OnDeath()` | Death 内部调用 | 子类重写,处理表现死亡逻辑(动画、特效等) | 表现层 |
| `OnRecycle()` | 对象回收时 | 清理资源、释放引用 | - |
> **重要区分**
> - **逻辑死亡**`Logic_Death()` 由伤害计算触发,设置 `isDeath=true`,仅影响数据层
> - **表现死亡**`Death()` 在逻辑死亡后调用,触发死亡事件和表现效果(动画、音效等)
### 3.2 创建流程
```csharp
// 1. 对象池创建 Entity
HFEntityPool.Instance.CreateEntity<HFEntity_Human>(onlyid, entityId,
() => HFClassEntityManager.Instance.GetClassEntity<HFEntity_Human>(),
(entity) => {
// 设置阵营
entity.SetEntityCamp(enEntityCamp.Player);
// 初始化
entity.Init();
});
```
---
## 四、System-Model 架构
### 4.1 架构设计
Entity 采用 **System-Model 分离架构**
- **System 层**处理表现逻辑Update、状态转换
- **Model 层**:处理数据逻辑(数据存储、计算)
### 4.2 添加系统
```csharp
public class HFEntity_Human : HFAbsEntity
{
protected override void OnRunAwake()
{
base.OnRunAwake();
// 添加系统(按执行顺序)
AddSystem<HFFeatureSystem>(); // 属性系统
AddSystem<HFAnimationSystem_Human>(); // 动画系统
AddSystem<HFApathMoveSystem>(); // 寻路移动系统
AddSystem<HFSkillSystem>(); // 技能系统
}
}
```
### 4.3 常用系统
| 系统 | 职责 | 适用 Entity |
|-----|------|-----------|
| `HFFeatureSystem` | 属性管理 | 所有 Entity |
| `HFAnimationSystem` | 动画控制 | Human、Tower |
| `HFMoveSystem` | 移动控制 | Human |
| `HFAISystem` | AI 行为 | Enemy、Tower |
| `HFSkillSystem` | 技能系统 | Human、Tower |
### 4.4 获取 Model
```csharp
// 通过 System 类型获取 Model
HFAnimationModel_Human animModel = GetModel<HFAnimationModel_Human>();
// 通过 System 对象获取 Model
HFSkillSystem skillSystem = ...;
HFSkillModel skillModel = GetModel<HFSkillModel>(skillSystem);
```
---
## 五、属性系统
### 5.1 属性分类
| 属性类型 | 说明 | 示例 |
|---------|------|------|
| **基础属性** | 配置表读取,基础值 | HP、SPD、MoveSpeed |
| **战斗属性** | 实际战斗中使用,受 Buff 影响 | Fight_SPD、Fight_ATK |
### 5.2 属性数据结构
```csharp
public partial class HFAbsEntity
{
// 基础属性(配置表)
private float m_Hp;
private float m_MaxHp;
private float m_SPD;
private float m_MoveSpeed;
private float m_NormalATK;
private float m_Critical;
private float m_CriticalDamage;
// 战斗属性(实时计算)
private float m_Fight_SPD;
private float m_Fight_NormalATK;
// ...
}
```
### 5.3 属性变更
```csharp
// 临时属性变更Buff
public void ChangeData(stAbilityData data)
{
if (data.IsPermanent)
{
// 永久属性变更
switch (data.ChangeTarget)
{
case enEntitityAbility.SPD:
m_SPD += data.Value;
break;
case enEntitityAbility.NormalATK:
m_NormalATK += data.Value;
break;
}
}
else
{
// 临时属性变更(存入 Buff 字典)
OnAddEntityAbilityData(data);
}
// 刷新战斗属性
OnRefushEntityAbility(data.ChangeTarget);
// 通知所有 Model 属性变更
ChangeAbility(data.ChangeTarget);
}
```
---
## 六、Entity 对象池
### 6.1 对象池职责
```csharp
public abstract partial class AbsHFEntityPool : IHFObject
{
public abstract enEntityLayer entityType { get; }
// 根据 onlyid 获取 Entity
public virtual HFAbsEntity SelectByOnlyid(long onlyid) { ... }
// 根据资源 ID 获取所有 Entity
public List<HFAbsEntity> SelectByResId(int resid) { ... }
// 删除 Entity
public virtual bool DelEntityByOnlyid(long onlyid) { ... }
// 获取所有 Entity
public List<HFAbsEntity> GetAllEntities() { ... }
}
```
### 6.2 使用示例
```csharp
// 创建 Entity
HFEntityPool.Instance.CreateEntity<HFEntity_Human>(
onlyid: 1001,
entityId: 10001,
func: () => HFClassEntityManager.Instance.GetClassEntity<HFEntity_Human>(),
action: (entity) => {
entity.SetEntityCamp(enEntityCamp.Player);
entity.Init();
});
// 获取 Entity
HFAbsEntity entity = HFEntityPool.Instance.SelectByOnlyid(1001);
HFEntity_Human human = entity as HFEntity_Human;
// 删除 Entity
HFEntityPool.Instance.DelEntityByOnlyid(1001);
```
---
## 七、开发规范
### 7.1 文件路径
| 类型 | 路径 |
|-----|------|
| Entity 基类 | `Assets/Game/GameHFScripte/GameFunction/GameEntity/Core/BaseEntity/AbsEntity/` |
| 具体 Entity | `Assets/Game/GameHFScripte/GameFunction/GameEntity/Entity/EntityTag/` |
| 系统类 | `Assets/Game/GameHFScripte/GameFunction/GameEntity/Entity/System/` |
| 模型类 | `Assets/Game/GameHFScripte/GameFunction/GameEntity/Entity/Model/` |
| 对象池 | `Assets/Game/GameHFScripte/GameFunction/GameEntity/Core/BaseEntity/EntityPool/` |
### 7.2 编码规范
1. **必须继承** `HFAbsEntity` 基类
2. **必须在** `OnRunAwake()` 中添加所需 System
3. **必须重写** `OnInit()` 初始化配置数据
4. **必须重写** `OnDeath()` 处理死亡逻辑
5. **禁止** 在 Entity 中直接访问 Manager通过 `HFFunCatalogue` 访问
6. **禁止** 在 Entity 中持有场景引用
### 7.3 性能优化
- 使用对象池复用 Entity 实例
- 使用 `AddSystem<T>()` 延迟初始化系统
- 属性变更通过 `ChangeAbility()` 通知所有 Model
- 死亡 Entity 通过 `OnDeathFinish()` 回调回收
---
**版本**: v1.1
**生效日期**: 2026年
**适用范围**: StrayFog 框架开发人员
---
## 文档关联
> 当本文档发生变更时,应同步检查以下关联文档,避免信息不一致。
| 文档 | 关联原因 |
|---|---|
| [实体系统入口](README.md) | 本文件是实体系统模块的子文档 |
| [通用技能系统使用指南](../技能系统/使用指南.md) | 技能系统是 Entity 常用子系统 |
| [对象池与运行时对象管理](../内存对象管理/README.md) | Entity 池机制相关 |
| [事件系统](../事件系统/README.md) | Entity 间通信常依赖事件系统 |
| [modules/模块索引.md](../../模块索引.md) | 模块索引是项目知识总入口 |
| [rules/10-架构说明.md](../../../rules/10-架构说明.md) | 架构说明定义总体分层和依赖方向 |
| [rules/20-开发规则.md](../../../rules/20-开发规则.md) | 编码规范与开发规则互相引用 |
| [rules/30-模块登记规则.md](../../../rules/30-模块登记规则.md) | 模块登记规则定义分类和状态口径 |

View File

@@ -0,0 +1,89 @@
# 实体系统开发注意事项和最佳实践
## 1. 枚举定义相关
### enHFCTCEvent 枚举
- **新增项**`Custom = 281` - 用于自定义事件
- **用途**:在 `HFEvent_OnDamage` 等自定义事件中使用
- **注意**:添加新事件时,确保数值不与其他事件冲突
### enEntityLayer 枚举
- **现有项**`None=0`, `Role`, `Monster`, `Max`
- **注意**:没有 `Enemy` 项,敌人应归类为 `Monster`
## 2. 实体-系统-模型 (ESM) 架构相关
### HFAbsEntity 访问方式
- **Transform 访问**:使用 `entity.gameObject.transform.position` 而不是 `entity.transform.position`
- **属性访问**:使用公共属性如 `entity.NormalATK` 而不是私有字段 `entity.m_NormalATK`
- **系统获取**`HFAbsEntity` 没有 `GetSystem<T>()` 方法,只有 `GetModel<T>()` 方法
- **模型获取**:通过 `entity.GetModel<T>()` 获取模型实例
### 系统间通信
- **推荐方式**:通过事件系统进行通信,而不是直接获取其他系统
- **事件分发**:使用 `event.Dispatch()` 而不是 `HFFunCatalogue.Event.TCEvent.SendEvent()`
## 3. 数据表字段映射
### Role 表字段
- `Lifefold` -> 生命值
- `Attackfold` -> 攻击力
- `Defensefold` -> 防御力
- `AttackRange` -> 攻击范围
- `CriticalRate` -> 暴击率
- `CriticalDamage` -> 暴击伤害
- **注意**Role 表中没有速度字段 (SPD)
## 4. 动画系统相关
### FSM (有限状态机) 系统
- **HFFMSModel** 现在包含 `CurrentSkeletonAnimation` 属性
- **访问方式**:通过 `FSM.CurrentSkeletonAnimation` 访问 SkeletonAnimation
- **动画速度设置**:使用 `skeletonAnimation.timeScale = speed`
## 5. AI 系统相关
### HFAIModel_Enemy
- **伤害处理**:通过事件系统 (`HFEvent_OnDamage`) 而不是直接获取系统
- **攻击逻辑**:创建并分发伤害事件,让其他系统处理实际伤害计算
## 6. 错误处理和调试
### 常见错误类型
- **CS0117**: 枚举中不包含指定定义 - 检查枚举项是否存在
- **CS1061**: 类型不包含指定定义 - 检查属性/方法名是否正确
- **CS0122**: 成员因保护级别不可访问 - 使用公共 API 而不是私有字段
### 修复策略
- 优先使用公共属性而不是私有字段
- 通过事件系统进行组件间通信
- 正确访问 GameObject 的 Transform 组件
- 使用正确的枚举值
## 7. 架构模式
### 系统-模型 (System-Model) 模式
- **AbsHFMoveSystem<T>** 需要指定泛型参数
- **AbsHFAIModel** 不能直接获取系统,应通过事件或模型进行通信
- **AbsHFAnimationModel** 需要配合 `AbsHFFMSModel` 使用
### 事件驱动架构
- 自定义事件需继承 `AbsHFEventArg<enHFCTCEvent>`
- 事件 ID 使用 `enHFCTCEvent.Custom` 或其他预定义事件
- 事件分发使用 `Dispatch()` 方法
---
## 文档关联
> 当本文档发生变更时,应同步检查以下关联文档,避免信息不一致。
| 文档 | 关联原因 |
|---|---|
| [实体系统入口](README.md) | 本文件是实体系统模块的子文档 |
| [Entity 开发指南](开发指南.md) | 与开发指南中的 System-Model、属性系统互补 |
| [事件系统](../事件系统/README.md) | 自定义事件派发相关 |
| [modules/模块索引.md](../../模块索引.md) | 模块索引是项目知识总入口 |
| [rules/10-架构说明.md](../../../rules/10-架构说明.md) | 架构说明定义总体分层和依赖方向 |
| [rules/20-开发规则.md](../../../rules/20-开发规则.md) | 公共 API 访问方式与开发规则互相引用 |
| [rules/30-模块登记规则.md](../../../rules/30-模块登记规则.md) | 模块登记规则定义分类和状态口径 |

View File

@@ -0,0 +1,55 @@
# 技能系统
## 分类
- 核心框架
## 目的
为角色、怪物等实体提供统一的技能管理、冷却控制、释放接口和事件通知。
## 核心组成
| 类/结构 | 职责 |
|---------|------|
| `HFGenericSkillSystem` | 通用技能系统,继承 `AbsHFSkillSystem<HFGenericSkillModel>` |
| `HFGenericSkillModel` | 通用技能模型,继承 `HFAbsModel` |
| `HFEvent_OnSkillUsed` | 技能使用事件 |
| `stSkillConfig` | 技能配置结构 |
## 使用规则
- 角色和怪物使用同一套技能系统接口。
- 技能 ID 在项目中应保持唯一。
- 技能效果逻辑应在事件处理器中实现,避免直接写在释放器里。
- 合理设置冷却时间以平衡游戏体验。
## 子系统边界
从实体系统角度看,技能相关子目录通常包括:
- `Models/Skill` — 技能数据模型
- `Systems/Skill` — 技能系统逻辑
- `HFSkillTrigger_*` — 技能触发器
- `HFSkill_*_Releaser` — 技能释放器
## 详细文档
- [使用指南](使用指南.md) — API 详情、配置加载、事件结构与最佳实践
- [实体系统](../实体系统/README.md) — 技能系统作为实体子系统的添加方式
- [事件系统](../事件系统/README.md) — 技能使用事件依赖事件系统
- [数据/配置框架](../数据配置框架.md) — 技能配置来源
## 文档关联
> 当本文档发生变更时,应同步检查以下关联文档,避免信息不一致。
| 文档 | 关联原因 |
|---|---|
| [modules/模块索引.md](../../模块索引.md) | 模块索引是项目知识总入口 |
| [modules/frameworks/技能系统/使用指南.md](使用指南.md) | 本模块的详细 API 与使用说明 |
| [modules/frameworks/实体系统/README.md](../实体系统/README.md) | 技能系统是实体系统的子系统 |
| [modules/frameworks/事件系统/README.md](../事件系统/README.md) | 技能使用事件依赖事件系统 |
| [modules/frameworks/数据配置框架.md](../数据配置框架.md) | 技能配置来源 |
| [rules/10-架构说明.md](../../../rules/10-架构说明.md) | 架构说明定义总体分层和依赖方向 |
| [rules/30-模块登记规则.md](../../../rules/30-模块登记规则.md) | 模块登记规则定义分类和状态口径 |

View File

@@ -0,0 +1,143 @@
# 通用技能系统使用指南
## 概述
通用技能系统(`HFGenericSkillSystem`)是一个适用于角色和怪物的统一技能管理系统,提供了一套标准化的技能操作接口。
## 架构设计
### 系统组成
- **HFGenericSkillSystem** - 通用技能系统(继承自 `AbsHFSkillSystem<HFGenericSkillModel>`
- **HFGenericSkillModel** - 通用技能模型(继承自 `HFAbsModel`
- **HFEvent_OnSkillUsed** - 技能使用事件
### 核心功能
#### 1. 技能管理
```csharp
// 添加技能
skillSystem.AddSkill(skillId);
// 移除技能
skillSystem.RemoveSkill(skillId);
// 检查技能是否就绪
bool isReady = skillSystem.IsSkillReady(skillId);
// 获取技能冷却时间
float cooldown = skillSystem.GetSkillCooldown(skillId);
```
#### 2. 技能使用
```csharp
// 使用技能(指定目标)
skillSystem.UseSkill(skillId, targetEntity);
// 使用技能(指定位置)
skillSystem.UseSkillAtPosition(skillId, worldPosition);
```
#### 3. 冷却管理
```csharp
// 检查是否有技能在冷却
bool hasCooldown = skillSystem.HasSkillInCooldown();
// 清除所有技能冷却
skillSystem.ClearAllCooldowns();
```
## 使用场景
### 角色实体
`HFEntity_Role` 中,技能系统被自动添加:
```csharp
AddSystem<HFGenericSkillSystem>(); // 替代原来的 HFSkillSystem
```
### 敌人实体
`HFEntity_Enemy``HFEntity_Boss` 中,技能系统被自动添加:
```csharp
AddSystem<HFGenericSkillSystem>(); // 替代原来的 HFSkillSystem
```
## 技能配置
### 技能配置结构
```csharp
public struct stSkillConfig
{
public int Id; // 技能ID
public string Name; // 技能名称
public float Cooldown; // 冷却时间
public float Range; // 作用范围
public float Damage; // 伤害值
public string Description; // 描述
}
```
### 技能加载
系统会根据实体配置自动加载对应的技能:
```csharp
// 从 EntityConfig 表加载技能
var config = HFFunCatalogue.NDB.ds_EntityConfig_Sheet_TableData_1FC4334A.ReadTable(ownerEntity.EntityId);
if (config != null && config.SkillID > 0)
{
AddSkill(config.SkillID);
}
```
## 事件系统
### 技能使用事件
当技能被使用时,系统会触发 `HFEvent_OnSkillUsed` 事件:
```csharp
public class HFEvent_OnSkillUsed : AbsHFEventArg<enHFCTCEvent>
{
public HFAbsEntity Caster { get; set; } // 施法者
public int SkillId { get; set; } // 技能ID
public HFAbsEntity Target { get; set; } // 目标
public Vector3 Position { get; set; } // 位置(可选)
}
```
## 扩展接口
### Buff 管理
```csharp
// 添加 Buff
skillSystem.AddBuff(buffTemplate);
// 移除 Buff
skillSystem.RemoveBuff(buffId);
```
## 最佳实践
1. **统一接口**:角色和怪物使用相同的技能系统接口
2. **自动配置**:技能配置根据实体类型自动加载
3. **冷却管理**:内置技能冷却机制
4. **事件驱动**:通过事件系统处理技能效果
5. **类型安全**使用强类型的技能ID和配置
## 注意事项
1. 技能释放器的具体实现需要根据游戏需求进行定制
2. 技能效果逻辑应在事件处理器中实现
3. 确保技能 ID 在项目中唯一
4. 合理设置技能冷却时间以平衡游戏体验
---
## 文档关联
> 当本文档发生变更时,应同步检查以下关联文档,避免信息不一致。
| 文档 | 关联原因 |
|---|---|
| [技能系统入口](README.md) | 本文件是技能系统模块的子文档 |
| [实体系统](../实体系统/README.md) | 技能系统是实体系统的子系统 |
| [事件系统](../事件系统/README.md) | 技能使用事件依赖事件系统 |
| [数据/配置框架](../数据配置框架.md) | 技能配置加载依赖配置框架 |
| [modules/模块索引.md](../../模块索引.md) | 模块索引是项目知识总入口 |
| [rules/10-架构说明.md](../../../rules/10-架构说明.md) | 架构说明定义总体分层和依赖方向 |
| [rules/30-模块登记规则.md](../../../rules/30-模块登记规则.md) | 模块登记规则定义分类和状态口径 |

View File

@@ -0,0 +1,123 @@
# 数据 / 配置框架
## 分类
- 核心框架
## 目的
管理 XLSX 配置表源、解析、生成运行时数据和读取 API。
---
## 核心路径
- 配置源:`XLSX_SRC/CN/``XLSX_SRC/EN/`
- 生成设置:`ProjectSettings/ZYF/ZYXlsx/ZYXlsxProjectSettings.asset`
- Resolve Asset`Assets/Editor/XLSX_SRC/Resolve/ZYXlsx/`
- 输出数据:`Assets/AutoBuildAsset/{Editor,Hotfix}/AutoFrame/Google.Protobuf/XLSX_SRC/<语言>/`
- 输出代码:`Assets/AutoBuildScript/{Editor,General,Hotfix}/AutoFrame/Google.Protobuf/XLSX_Script/`
---
## 常见配置表
| 表名 | 用途 |
|---|---|
| `Constants.xlsx` | 常量配置 |
| `EntityConfig.xlsx` | 实体配置 |
| `Gift.xlsx` | 礼包/奖励配置 |
| `Resource.xlsx` | 资源/道具配置 |
| `SkillGroup.xlsx` | 技能组配置 |
| `SkillReleaser.xlsx` | 技能释放器配置 |
| `SkillTrigger.xlsx` | 技能触发器配置 |
| `SkillUp.xlsx` | 技能升级配置 |
| `Sounds.xlsx` | 音效配置 |
| `Wave.xlsx` | 波次配置(业务示例) |
---
## 运行时加载调用链
```text
HFGameStart.LoadDB()
-> Hotfix_ZYXlsx_GoogleProtobuf_Helper.instance.LoadAllXlsx(OnLoadDbFinish)
-> 遍历 enZYXlsxSheet
-> GetExistsDataLang / GetSheetMemoryPackBufferFilePath
-> HFFunCatalogue.Asset.LoadDBHelper(path.GetHashCode(), path, callback)
-> 缓存 sheet bytes 到 mDicLangSheetBytes
```
---
## 运行时读取 API
```csharp
// 按主键读取单条
HFFunCatalogue.NDB.ds_xxx.ReadTableByPK(pk);
// 读取全表
HFFunCatalogue.NDB.ds_xxx.ReadTableList();
// 读取行列式数据
HFFunCatalogue.NDB.ds_xxx.ReadTableDeterminant();
```
---
## 使用规则
- 改表后必须重新生成。
- 配置读取必须在 `LoadAllXlsx` 完成后。
- 主键/全表/常量分别用对应 API。
- 禁止高频全表读取。
- id 优先来自表/协议/常量,禁止魔法数字。
- 高频配置在 manager 初始化或窗口打开时缓存。
- 多语言字段需补齐。
---
## 变更清单
1. 修改源表(`XLSX_SRC/CN/``XLSX_SRC/EN/`)。
2. 确认 `ProjectSettings/ZYF/ZYXlsx/ZYXlsxProjectSettings.asset` 与 Resolve 配置。
3. 通过 Unity 菜单 `StrayFog → XLSX → Generate Runtime Data`(或对应 MCP 白名单命令)重新生成。
4. 检查输出数据目录 `Assets/AutoBuildAsset/{Editor,Hotfix}/AutoFrame/Google.Protobuf/XLSX_SRC/<语言>/`
5. 检查输出代码目录 `Assets/AutoBuildScript/{Editor,General,Hotfix}/AutoFrame/Google.Protobuf/XLSX_Script/`
6. 编译 `GameGeneral``GameHF``SFMono` 等受影响程序集。
7. 运行时验证:确认 `HFGameStart.LoadDB()` 成功且读取 API 返回预期。
8. 更新本文档与 [模块索引](../模块索引.md)。
## 验证
- 生成器执行无 Error。
- 受影响程序集编译通过。
- 运行时 `LoadAllXlsx` 回调正常触发。
- 关键表(如 `EntityConfig``SkillGroup`)按主键读取结果正确。
## 当前状态
- 待验证
---
## 相关模块
- [实体系统](实体系统/README.md)
- [技能系统](技能系统/README.md)
- [资源管理](资源管理/README.md)
---
## 文档关联
> 当本文档发生变更时,应同步检查以下关联文档,避免信息不一致。
| 文档 | 关联原因 |
|---|---|
| [modules/模块索引.md](../模块索引.md) | 模块索引是项目知识总入口 |
| [modules/frameworks/实体系统/README.md](实体系统/README.md) | 实体配置来自配置表 |
| [modules/frameworks/技能系统/README.md](技能系统/README.md) | 技能配置来自配置表 |
| [modules/frameworks/资源管理/README.md](资源管理/README.md) | 配置资源加载依赖资源管理 |
| [rules/10-架构说明.md](../../rules/10-架构说明.md) | 架构说明定义总体分层和依赖方向 |
| [rules/30-模块登记规则.md](../../rules/30-模块登记规则.md) | 模块登记规则定义分类和状态口径 |

View File

@@ -1,14 +1,16 @@
# StrayFog 框架架构分析 # StrayFog 框架架构分析
> 本文档从实现视角描述 StrayFog 框架的整体分层与全局入口。各模块的详细实现、API 与使用规则见其自身的 README / 使用指南;高层架构规则与程序集边界见 [rules/10-架构说明.md](../../rules/10-架构说明.md)。
## 一、框架整体架构 ## 一、框架整体架构
### 1.1 模块划分 ### 1.1 模块划分
| 模块层级 | 路径 | 职责描述 | | 模块层级 | 路径 | 职责描述 |
|---------|------|---------| |---------|------|---------|
| **Core层** | `Assets/StrayFog/Core` | 核心基础框架,模拟行为系统、全局数据管理 | | **Core ** | `Assets/StrayFog/Core` | 核心基础框架,模拟行为系统、全局数据管理 |
| **HF层** | `Assets/Game/GameHFScripte/CopyToHF` | 游戏核心业务框架,资源管理、事件系统、相机管理等 | | **HF ** | `Assets/Game/GameHFScripte/CopyToHF` | 游戏核心业务框架,资源管理、事件系统、相机管理等 |
| **General层** | `Assets/Game/GameGeneralScripte` | 通用工具层,状态机、辅助工具等 | | **General ** | `Assets/Game/GameGeneralScripte` | 通用工具层,状态机、辅助工具等 |
### 1.2 架构图 ### 1.2 架构图
@@ -31,7 +33,7 @@
--- ---
## 二、Core层架构 ## 二、Core 层架构
### 2.1 SimulateBehaviour 模拟行为系统 ### 2.1 SimulateBehaviour 模拟行为系统
@@ -40,11 +42,11 @@
```csharp ```csharp
public interface ISimulateBehaviour public interface ISimulateBehaviour
{ {
long simulateGlobalId { get; } // 模拟行为全局ID long simulateGlobalId { get; } // 模拟行为全局 ID
int bindGameObjectInstanceId { get; } // 绑定对象实例ID int bindGameObjectInstanceId { get; } // 绑定对象实例 ID
void BindGameObject(GameObject _go); // 绑定GameObject void BindGameObject(GameObject _go); // 绑定 GameObject
void UnBindGameObject(); // 解绑GameObject void UnBindGameObject(); // 解绑 GameObject
// ... 完整的MonoBehaviour生命周期方法 // ... 完整的 MonoBehaviour 生命周期方法
} }
``` ```
@@ -52,8 +54,8 @@ public interface ISimulateBehaviour
| 设计目标 | 实现方式 | | 设计目标 | 实现方式 |
|---------|---------| |---------|---------|
| **解耦MonoBehaviour** | 将逻辑从MonoBehaviour中剥离便于测试和复用 | | **解耦 MonoBehaviour** | 将逻辑从 MonoBehaviour 中剥离,便于测试和复用 |
| **生命周期控制** | 完整模拟Unity生命周期支持自定义调度 | | **生命周期控制** | 完整模拟 Unity 生命周期,支持自定义调度 |
| **对象池优化** | 配合对象池实现高效对象复用 | | **对象池优化** | 配合对象池实现高效对象复用 |
#### 2.1.3 目录结构 #### 2.1.3 目录结构
@@ -63,14 +65,14 @@ SimulateBehaviour/
├── ISimulateBehaviour.cs # 核心接口定义 ├── ISimulateBehaviour.cs # 核心接口定义
├── Bind/ # 绑定实现 ├── Bind/ # 绑定实现
│ ├── IBindSimulateBehaviour.cs │ ├── IBindSimulateBehaviour.cs
│ ├── AbsBindSimulateBehaviour_Mono.cs # Mono绑定基类 │ ├── AbsBindSimulateBehaviour_Mono.cs # Mono 绑定基类
│ ├── AbsBindSimulateBehaviour_UI.cs # UI绑定基类 │ ├── AbsBindSimulateBehaviour_UI.cs # UI 绑定基类
│ └── BindSimulateBehaviour_Collect.cs # 收集器 │ └── BindSimulateBehaviour_Collect.cs # 收集器
├── MonoBehaviour/ # 各生命周期模拟实现 ├── MonoBehaviour/ # 各生命周期模拟实现
│ ├── SimulateMonoBehaviour_Awake__xxx.cs │ ├── SimulateMonoBehaviour_Awake__xxx.cs
│ ├── SimulateMonoBehaviour_Update__xxx.cs │ ├── SimulateMonoBehaviour_Update__xxx.cs
│ └── ... (40+生命周期方法) │ └── ... (40+ 生命周期方法)
└── UIBehaviour/ # UI生命周期模拟 └── UIBehaviour/ # UI 生命周期模拟
├── SimulateUIBehaviour_Awake__xxx.cs ├── SimulateUIBehaviour_Awake__xxx.cs
└── ... └── ...
``` ```
@@ -82,16 +84,16 @@ SimulateBehaviour/
```csharp ```csharp
public sealed class SFGlobalData public sealed class SFGlobalData
{ {
public static string assetBundleRoot; // AB包根路径 public static string assetBundleRoot; // AB 包根路径
public static string streamingAssetsRoot; // 流式资源根路径 public static string streamingAssetsRoot; // 流式资源根路径
public static string cdnassetBundleRoot; // CDN资源路径 public static string cdnassetBundleRoot; // CDN 资源路径
public static RuntimePlatform Platform(); // 当前平台判断 public static RuntimePlatform Platform(); // 当前平台判断
} }
``` ```
--- ---
## 三、HF层架构 ## 三、HF 层架构
### 3.1 接口体系 ### 3.1 接口体系
@@ -116,13 +118,13 @@ IHFObject (基础对象接口)
| `IHFObject` | 基础对象标识 | 无 | | `IHFObject` | 基础对象标识 | 无 |
| `IHFRecycle` | 对象回收机制 | `Recycle()` | | `IHFRecycle` | 对象回收机制 | `Recycle()` |
| `IHFGlobal` | 全局唯一标识 | `globalId` | | `IHFGlobal` | 全局唯一标识 | `globalId` |
| `IHFClone` | 对象克隆能力 | 系列Clone方法 | | `IHFClone` | 对象克隆能力 | 系列 Clone 方法 |
| `IHFLanguage` | 多语言支持 | 语言切换 | | `IHFLanguage` | 多语言支持 | 语言切换 |
| `IHFScene` | 场景管理 | 场景加载/卸载 | | `IHFScene` | 场景管理 | 场景加载/卸载 |
### 3.2 对象池系统 ### 3.2 对象池系统
#### 3.2.1 HFObjectMemPool - GameObject对象池 #### 3.2.1 HFObjectMemPool - GameObject 对象池
```csharp ```csharp
public class HFObjectMemPool public class HFObjectMemPool
@@ -143,7 +145,7 @@ public class HFScriptMemPool<T> : IHFRecycle
{ {
private Queue<T> m_UnoccupiedPool; private Queue<T> m_UnoccupiedPool;
private List<T> m_UsingPool; private List<T> m_UsingPool;
// 支持MonoBehaviour和普通类的自动创建 // 支持 MonoBehaviour 和普通类的自动创建
} }
``` ```
@@ -154,7 +156,7 @@ public class HFScriptMemPool<T> : IHFRecycle
| **双池结构** | 空闲池 + 使用池 | 高效管理对象状态 | | **双池结构** | 空闲池 + 使用池 | 高效管理对象状态 |
| **内存泄漏检测** | 归还时校验来源 | 及时发现问题 | | **内存泄漏检测** | 归还时校验来源 | 及时发现问题 |
| **泛型支持** | `HFScriptMemPool<T>` | 类型安全 | | **泛型支持** | `HFScriptMemPool<T>` | 类型安全 |
| **Mono支持** | 自动创建GameObject | 无缝集成Unity | | **Mono 支持** | 自动创建 GameObject | 无缝集成 Unity |
### 3.3 事件系统 ### 3.3 事件系统
@@ -177,7 +179,7 @@ public abstract class AbsHFEventHandle<K,T> : IHFEventHandle<K,T>
where K : struct, Enum where K : struct, Enum
where T : IHFEventArg<K> where T : IHFEventArg<K>
{ {
// 多级索引: EventId -> TypeHashCode -> Action列表 // 多级索引: EventId -> TypeHashCode -> Action 列表
HFMultiKeyDictionary<K, int, IHFCacheEventAction<K,T>> mICacheEventActionMaping; HFMultiKeyDictionary<K, int, IHFCacheEventAction<K,T>> mICacheEventActionMaping;
} }
``` ```
@@ -189,10 +191,10 @@ public abstract class AbsHFEventHandle<K,T> : IHFEventHandle<K,T>
Dispatch(arg) Dispatch(arg)
获取 EventId 对应的 Action字典 获取 EventId 对应的 Action 字典
获取 参数类型HashCode 对应的 CacheEventAction 获取 参数类型 HashCode 对应的 CacheEventAction
遍历执行所有 Action<T> 遍历执行所有 Action<T>
@@ -235,7 +237,7 @@ loader.LoadAsset() → 异步加载
#### 3.4.3 依赖管理 #### 3.4.3 依赖管理
通过Manifest文件解析资源依赖关系 通过 Manifest 文件解析资源依赖关系:
```csharp ```csharp
HFAssetBundlePathAttribute OnGetDependencyAbpAttr(string _depManifestName) HFAssetBundlePathAttribute OnGetDependencyAbpAttr(string _depManifestName)
@@ -271,12 +273,12 @@ HFMainCamera (主相机)
│ ├── CameraItem2 (Weight=20) │ ├── CameraItem2 (Weight=20)
│ └── CameraItem3 (Weight=5) │ └── CameraItem3 (Weight=5)
└── 按Weight排序 → 渲染顺序控制 └── 按 Weight 排序 → 渲染顺序控制
``` ```
--- ---
## 四、General层架构 ## 四、General 层架构
### 4.1 状态机系统 ### 4.1 状态机系统
@@ -296,16 +298,16 @@ IGFStateMachineBehaviour (接口)
#### 4.1.2 状态机特性 #### 4.1.2 状态机特性
| 特性 | 说明 | | 特性 | 说明 |
|-----|-----| |-----|------|
| **层级化设计** | 支持状态、层、机三个层级的行为绑定 | | **层级化设计** | 支持状态、层、机三个层级的行为绑定 |
| **参数化驱动** | 通过参数控制状态切换 | | **参数化驱动** | 通过参数控制状态切换 |
| **Inspector扩展** | 自定义编辑器支持 | | **Inspector 扩展** | 自定义编辑器支持 |
### 4.2 工具类 ### 4.2 工具类
#### 4.2.1 扩展方法集合 #### 4.2.1 扩展方法集合
**HFUGUIExtendEngine.cs** - UGUI扩展方法40+方法) **HFUGUIExtendEngine.cs** - UGUI 扩展方法40+ 方法)
| 功能分类 | 方法示例 | | 功能分类 | 方法示例 |
|---------|---------| |---------|---------|
@@ -318,9 +320,9 @@ IGFStateMachineBehaviour (接口)
| 工具类 | 职责 | | 工具类 | 职责 |
|-------|-----| |-------|-----|
| `HFAssetBundleHelper` | AB包辅助工具 | | `HFAssetBundleHelper` | AB 包辅助工具 |
| `HFDllHelper` | DLL加载辅助 | | `HFDllHelper` | DLL 加载辅助 |
| `HFEnumForAssetBundle` | AB包相关枚举 | | `HFEnumForAssetBundle` | AB 包相关枚举 |
| `MinGameModel` | 微信小游戏适配 | | `MinGameModel` | 微信小游戏适配 |
--- ---
@@ -332,46 +334,65 @@ IGFStateMachineBehaviour (接口)
| 模式 | 应用场景 | 实现类 | | 模式 | 应用场景 | 实现类 |
|-----|---------|-------| |-----|---------|-------|
| **单例模式** | 全局管理器 | `AbsHFSingleMonoBehaviour`, `AbsHFSingleRunTime` | | **单例模式** | 全局管理器 | `AbsHFSingleMonoBehaviour`, `AbsHFSingleRunTime` |
| **工厂模式** | 对象创建 | 对象池的GetItem | | **工厂模式** | 对象创建 | 对象池的 GetItem |
| **观察者模式** | 事件系统 | `IHFEventHandle` | | **观察者模式** | 事件系统 | `IHFEventHandle` |
| **策略模式** | 多平台适配 | `SFGlobalData.Platform()` | | **策略模式** | 多平台适配 | `SFGlobalData.Platform()` |
| **模板方法** | 生命周期 | `SimulateBehaviour`系列 | | **模板方法** | 生命周期 | `SimulateBehaviour` 系列 |
### 5.2 架构优势 ### 5.2 架构优势
| 优势 | 体现 | | 优势 | 体现 |
|-----|-----| |-----|------|
| **解耦性** | 逻辑与MonoBehaviour分离 | | **解耦性** | 逻辑与 MonoBehaviour 分离 |
| **可测试性** | 纯逻辑类易于单元测试 | | **可测试性** | 纯逻辑类易于单元测试 |
| **性能优化** | 对象池减少GC | | **性能优化** | 对象池减少 GC |
| **扩展性** | 接口驱动,易于扩展 | | **扩展性** | 接口驱动,易于扩展 |
| **可维护性** | 清晰的模块划分 | | **可维护性** | 清晰的模块划分 |
### 5.3 潜在改进点 ### 5.3 潜在改进点
| 改进方向 | 说明 | | 改进方向 | 说明 |
|---------|-----| |---------|------|
| **异步加载优化** | 可引入协程池或Job System | | **异步加载优化** | 可引入协程池或 Job System |
| **资源依赖可视化** | 可增加依赖关系图工具 | | **资源依赖可视化** | 可增加依赖关系图工具 |
| **性能监控** | 可增加加载时间、内存占用统计 | | **性能监控** | 可增加加载时间、内存占用统计 |
| **热更新支持** | 可考虑集成Lua或ILRuntime | | **热更新支持** | 当前热更新方案为 HybridCLR若未来需要替换需单独评估兼容性、包体大小和构建流程 |
--- ---
## 六、总结 ## 六、总结
StrayFog框架是一个结构清晰、设计完善的Unity游戏框架核心特点包括 StrayFog 框架是一个结构清晰、设计完善的 Unity 游戏框架,核心特点包括:
1. **模拟行为系统** - 实现了完整的MonoBehaviour生命周期解耦 1. **模拟行为系统** - 实现了完整的 MonoBehaviour 生命周期解耦
2. **对象池机制** - 高效的内存管理策略 2. **对象池机制** - 高效的内存管理策略
3. **事件驱动架构** - 灵活的事件分发系统 3. **事件驱动架构** - 灵活的事件分发系统
4. **资源管理体系** - 完善的AssetBundle加载和依赖管理 4. **资源管理体系** - 完善的 AssetBundle 加载和依赖管理
5. **模块化设计** - 清晰的分层和职责划分 5. **模块化设计** - 清晰的分层和职责划分
该框架适合中大型Unity项目使用具备良好的扩展性和维护性。 该框架适合中大型 Unity 项目使用,具备良好的扩展性和维护性。
--- ---
**版本**: v1.0 **版本**: v1.1
**分析日期**: 2024年 **最后更新日期**: 2026-07-15
**适用项目**: OnlineGame **适用项目**: 使用 StrayFog / UnityAI 框架的 Unity 项目
---
## 文档关联
> 当本文档发生变更时,应同步检查以下关联文档,避免信息不一致。
| 文档 | 关联原因 |
|---|---|
| [通用框架入口](通用框架/README.md) | Core / General 层详细说明 |
| [架构说明](../../rules/10-架构说明.md) | 高层架构规则与程序集边界 |
| [实体系统](实体系统/README.md) | 实体系统详细实现 |
| [对象池与运行时对象管理](内存对象管理/README.md) | 对象池详细实现 |
| [事件系统](事件系统/README.md) | 事件系统详细实现 |
| [资源管理](资源管理/README.md) | 资源管理详细实现 |
| [相机系统](相机系统/README.md) | 相机系统详细实现 |
| [modules/模块索引.md](../模块索引.md) | 模块索引是项目知识总入口 |
| [rules/20-开发规则.md](../../rules/20-开发规则.md) | 开发规则与框架架构互相引用 |
| [rules/30-模块登记规则.md](../../rules/30-模块登记规则.md) | 模块登记规则定义分类和状态口径 |

View File

@@ -0,0 +1,43 @@
# 相机系统
## 分类
- 核心框架
## 目的
管理多相机注册、相机堆栈排序、渲染顺序控制,为 UI、场景、特效等提供分层渲染能力。
## 核心类
| 类 | 职责 |
|---|---|
| `HFCameraManager` | 相机管理器单例,维护相机列表和主相机引用 |
| `HFMainCamera` | 主相机,管理 CameraStack |
| `AbsHFCameraItem` | 相机项抽象基类,子类实现具体相机逻辑 |
## 使用规则
- 相机项必须继承 `AbsHFCameraItem`
- `Weight` 决定堆栈内渲染顺序,值越大越靠后渲染。
- 添加和移除相机需成对出现,避免残留。
- UI 相机通常使用 `CameraClearFlags.Depth` 和较高 depth。
## 详细文档
- [使用指南](使用指南.md) — 自定义相机、堆栈管理、API 详情与示例
- [UI 窗口系统](../UI窗口系统/README.md) — UI 与相机的协作
- [资源管理](../资源管理/README.md) — 相机资源加载
## 文档关联
> 当本文档发生变更时,应同步检查以下关联文档,避免信息不一致。
| 文档 | 关联原因 |
|---|---|
| [modules/模块索引.md](../../模块索引.md) | 模块索引是项目知识总入口 |
| [modules/frameworks/相机系统/使用指南.md](使用指南.md) | 本模块的详细 API 与使用说明 |
| [modules/frameworks/UI窗口系统/README.md](../UI窗口系统/README.md) | UI 窗口系统常与相机系统协作 |
| [modules/frameworks/资源管理/README.md](../资源管理/README.md) | 相机资源加载依赖资源管理 |
| [rules/10-架构说明.md](../../../rules/10-架构说明.md) | 架构说明定义总体分层和依赖方向 |
| [rules/30-模块登记规则.md](../../../rules/30-模块登记规则.md) | 模块登记规则定义分类和状态口径 |

View File

@@ -1,8 +1,8 @@
# StrayFog 框架相机系统使用指南 # 相机系统使用指南
## 一、创建自定义相机 ## 一、创建自定义相机
### 1.1 继承AbsHFCameraItem ### 1.1 继承 AbsHFCameraItem
```csharp ```csharp
public class UIOverlayCamera : AbsHFCameraItem public class UIOverlayCamera : AbsHFCameraItem
@@ -64,12 +64,12 @@ HFMainCamera (主相机)
│ ├── CameraItem2 (Weight=20) │ ├── CameraItem2 (Weight=20)
│ └── CameraItem3 (Weight=5) │ └── CameraItem3 (Weight=5)
└── 按Weight排序 → 渲染顺序控制 └── 按 Weight 排序 → 渲染顺序控制
``` ```
--- ---
## 三、相机管理API ## 三、相机管理 API
### 3.1 常用方法 ### 3.1 常用方法
@@ -83,4 +83,19 @@ HFMainCamera (主相机)
**版本**: v1.0 **版本**: v1.0
**生效日期**: 2026年 **生效日期**: 2026年
**适用范围**: GiftGameX项目业务开发人员 **适用范围**: 使用 StrayFog 框架的项目开发人员
---
## 文档关联
> 当本文档发生变更时,应同步检查以下关联文档,避免信息不一致。
| 文档 | 关联原因 |
|---|---|
| [相机系统入口](README.md) | 本文件是相机系统模块的子文档 |
| [UI 窗口系统](../UI窗口系统/README.md) | UI 窗口系统常与相机系统协作 |
| [资源管理](../资源管理/README.md) | 相机资源加载依赖资源管理 |
| [modules/模块索引.md](../../模块索引.md) | 模块索引是项目知识总入口 |
| [rules/10-架构说明.md](../../../rules/10-架构说明.md) | 架构说明定义总体分层和依赖方向 |
| [rules/30-模块登记规则.md](../../../rules/30-模块登记规则.md) | 模块登记规则定义分类和状态口径 |

View File

@@ -0,0 +1,49 @@
# 第三方插件
## 分类
- 项目框架
## 目的
记录第三方插件和 embedded packages 的用途、边界和修改规则。
## 已知线索
- 插件目录:`Assets/ThirdPlugins/`
- Package 目录:`Packages/`
- 已识别插件包括 HybridCLR、Spine、DOTween、SuperScrollView、Astar、UnityWebSocket、SoundManagerPro、SRDebugger 等。
## 梳理任务
- [ ] 梳理主要插件列表和用途。
- [ ] 标记哪些插件是运行时依赖,哪些是编辑器依赖。
- [ ] 梳理插件是否有项目本地修改。
- [ ] 梳理升级插件的风险和验证步骤。
- [ ] 记录禁止直接修改 vendor 的规则例外。
## 待确认
- 哪些插件来自 Asset Store哪些来自 package。
- 是否有插件被项目深度改造。
- 哪些插件参与 hotfix 或 WebGL 构建。
## 相关模块
- [通用框架](通用框架/README.md)
- [编辑器工具索引](../模块索引.md#编辑器工具)
---
## 文档关联
> 当本文档发生变更时,应同步检查以下关联文档,避免信息不一致。
| 文档 | 关联原因 |
|---|---|
| [modules/模块索引.md](../模块索引.md) | 编辑器工具索引 |
| [modules/frameworks/通用框架/README.md](通用框架/README.md) | 通用框架 |
| [rules/10-架构说明.md](../../rules/10-架构说明.md) | 架构说明定义总体分层和依赖方向 |
| [rules/20-开发规则.md](../../rules/20-开发规则.md) | 开发规则与框架/生成规则互相引用 |
| [rules/30-模块登记规则.md](../../rules/30-模块登记规则.md) | 模块登记规则定义分类和状态口径 |
| TODO补充依赖或使用本框架的模块文档 | 如依赖本框架的功能模块 |

View File

@@ -0,0 +1,125 @@
# CrystalBattle Codex 与 Unity MCP 使用规则
## 一、定位
Codex 通过本地 stdio MCP Server 调用 Unity Editor 内的 HTTP Bridge。Bridge 只监听 `127.0.0.1:17777`,并把 Unity API 工作排队到 Editor 主线程执行。
当前能力只面向 Unity Editor 自动化,不覆盖 Play Mode、真机运行时调试或远程网络访问。
## 二、对接点
```text
MCP Server: UnityAI/Tools/CodexUnityMcp/
Codex config: .codex/config.toml
Unity Bridge: http://127.0.0.1:17777
```
本文档不维护 Unity Bridge 的打开方式或 Unity Editor 内部目录结构。
## 三、可用工具
| 工具 | 用途 |
|---|---|
| `unity_health` | 检查 Bridge、项目路径和 Unity 版本 |
| `unity_refresh_assets` | 执行 `AssetDatabase.Refresh()` |
| `unity_execute_menu_item` | 执行 Bridge 白名单中的菜单项 |
| `unity_get_console_logs` | 读取最近 Unity Console 日志 |
| `unity_generate_ui_prefab` | 根据 JSON 生成 UI Prefab |
| `unity_export_prefab_to_json` | 将 UI Prefab 导出为 JSON |
`unity_execute_menu_item` 不能执行任意菜单。新增菜单能力时必须同时修改 Bridge 白名单并验证风险。
## 四、标准调用流程
1. 每轮 Unity 自动化前先调用 `unity_health`
2. 确认返回的项目路径就是当前目标工程。
3. 执行当前任务需要的最少工具调用。
4. 资源变化后调用 `unity_refresh_assets`
5. 调用 `unity_get_console_logs` 检查新增 Error 和关键 Warning。
6. Prefab/UI 继续做结构和实际显示验证,不能只确认命令返回成功。
`unity_health` 失败时停止后续 Unity 命令并报告错误,不假设 Bridge 已经执行任何操作。
## 五、UI 生成
UI 任务必须先从 [UnityAI README](../../../../README.md) 进入 UI 文档,并阅读:
- [UI 开发指南](../../UI窗口系统/开发指南.md)
- [UI 界面拼接](../../UI窗口系统/界面拼接.md)
- [UI 拼接工具](../UI拼接工具.md)
随后按以下步骤执行:
1. 检查设计图、目标 Prefab、窗口脚本和现有资源。
2. 明确传入 JSON 路径和目标 Prefab 路径。
3. 调用 `unity_generate_ui_prefab`
4. 刷新 Assets 并读取 Console。
5. 检查 Prefab 层级、RectTransform、组件状态和资源引用。
6. 需要核对双向转换时调用 `unity_export_prefab_to_json`
7. 在 Unity 运行环境验证实际显示和交互。
不规定固定测试目录、测试窗口名或中间数据目录。任务产生的路径由调用方明确提供,覆盖正式 Prefab 前必须确认。
## 六、安全边界
- Bridge 只监听 `127.0.0.1`,禁止改为 `0.0.0.0` 或局域网地址。
- MCP Server 不直接操作 Unity 资源,资源变更交给 Unity Bridge。
- HTTP 线程只接收和返回数据Unity API 回到主线程执行。
- 不开放任意菜单、任意 C# 执行、批量删除、构建发布或 Git 操作。
- 生成和导出只修改调用参数明确指定的目标。
- 日志和错误返回包含命令、路径和失败原因,不返回无上下文的“失败”。
## 七、排错
### 连接失败
1. 调用 `unity_health` 保留原始错误。
2. 检查 `.codex/config.toml` 的 Node command 和 server 入口。
3. 确认 `Tools/CodexUnityMcp` 依赖已经安装。
4. 连接恢复前不执行其他 Unity 工具。
### 端口占用
- Bridge 如果发现同端口已经存在有效服务,应连接到现有监听状态而不是重复启动。
- 不能通过同时启动多个监听器解决端口冲突。
- 状态仍不一致时记录端口、进程和 Bridge 状态,再处理占用来源。
### UI 生成失败
1. 读取 Unity Console。
2. 检查 JSON 和目标路径是否存在且格式正确。
3. 检查 Sprite、Font、Material 等 Asset 路径。
4. 检查 `rectTransform`、递归 `children` 和组件字段。
5. 检查目标 Prefab 是否被错误覆盖或无法写入。
## 八、维护
新增 MCP tool 时同步更新:
- [ ] `Tools/CodexUnityMcp/src/server.mjs`
- [ ] Unity Bridge 对应命令
- [ ] 本文档工具列表和验证步骤
- [ ] 对应测试用例或示例调用
- [ ] Bridge 白名单(如适用)
Bridge 返回统一结构:
```json
{
"ok": true,
"message": "done",
"data": {},
"logs": []
}
```
## 文档关联
| 文档 | 关联原因 |
|---|---|
| [MCP 工具入口](README.md) | MCP 模块入口 |
| [UI 开发指南](../../UI窗口系统/开发指南.md) | UI 生命周期和列表规则 |
| [UI 界面拼接](../../UI窗口系统/界面拼接.md) | Prefab 拼接流程 |
| [UI 拼接工具](../UI拼接工具.md) | JSON/Prefab 工具结构 |
| [MCP Server README](../../../../Tools/CodexUnityMcp/README.md) | Server 安装和实现 |
| [工作流清单](../../../../rules/40-工作流清单.md) | Unity/MCP 验证流程 |

View File

@@ -0,0 +1,31 @@
# MCP 工具
Codex 通过本地 Node MCP Server 与 Unity Editor Bridge 交互,当前实现已经在 CrystalBattle_Client 验证。
## 实现位置
- MCP Server`UnityAI/Tools/CodexUnityMcp/`
- Unity Editor Bridge目标项目 `Assets/Editor/Command/`
- Codex 配置:工作区 `.codex/config.toml`
- 本地地址:`http://127.0.0.1:17777`
## 能力
- Unity 健康检查
- AssetDatabase 刷新
- 白名单菜单执行
- Console 日志读取
- UI JSON 生成 Prefab
- Prefab 导出 JSON
具体调用、UI 前置阅读、安全边界和排错见 [CrystalBattle Codex 与 Unity MCP 使用规则](CrystalBattle_Codex_Unity_MCP使用规则.md)。
## 文档关联
| 文档 | 关联原因 |
|---|---|
| [编辑器工具入口](../README.md) | 编辑器工具模块入口 |
| [MCP 使用规则](CrystalBattle_Codex_Unity_MCP使用规则.md) | 具体调用规范 |
| [MCP Server README](../../../../Tools/CodexUnityMcp/README.md) | 安装和实现 |
| [模块索引](../../../模块索引.md) | 模块状态 |
| [工作流清单](../../../../rules/40-工作流清单.md) | Unity 自动化验证步骤 |

View File

@@ -0,0 +1,36 @@
# 编辑器工具
## SF Editor
- 路径:`Assets/StrayFog/Editor/`
- 程序集:`SFEditor`
- 职责CopyToX、AssetBundle、SpriteAtlas、配置生成和 StrayFog Editor 窗口。
`Assets/StrayFog/Editor/CopyToX` 保存生成运行时代码的真实源文件。生成后的 GameHF/GameGeneral 目标目录禁止手改。
## Project Editor Assets
- 路径:目标项目 `Assets/Editor/`
- 职责:项目级 Editor 菜单、构建辅助、UI 转换和 Unity MCP Bridge。
## 使用规则
- Unity Editor API 只在主线程执行。
- 运行时代码不得引用 Editor 程序集。
- 生成器修改后同时验证输入配置、生成差异、目标程序集和 Unity Console。
- 新增菜单时使用稳定路径MCP 可调用菜单必须进入显式白名单。
- 编辑器工具不能把机器绝对路径、个人目录或临时数据目录写成通用规则。
## 子文档
- [UI 拼接工具](UI拼接工具.md)
- [MCP 工具](MCP工具/README.md)
## 文档关联
| 文档 | 关联原因 |
|---|---|
| [模块索引](../../模块索引.md) | 编辑器工具入口和状态 |
| [资源管理](../资源管理/README.md) | AssetBundle 与分包生成 |
| [架构说明](../../../rules/10-架构说明.md) | Editor 与运行时边界 |
| [工作流清单](../../../rules/40-工作流清单.md) | 生成和验证流程 |

View File

@@ -8,46 +8,6 @@ using TMPro;
public static class UIPrefabGenerator public static class UIPrefabGenerator
{ {
[MenuItem("Tools/UI/Generate BagWindow Prefab")]
public static void GenerateBagWindowPrefab()
{
string jsonPath = "Assets/Editor/UI/BagWindow.json";
string prefabPath = "Assets/Game/GameHFResource/CN/UIWindows/BagWindow/BagWindow.prefab";
if (!File.Exists(jsonPath))
{
Debug.LogError("JSON file not found: " + jsonPath);
return;
}
string jsonContent = File.ReadAllText(jsonPath);
UILayoutData layoutData = JsonUtility.FromJson<UILayoutData>(jsonContent);
GameObject root = new GameObject(layoutData.name);
root.layer = 5;
Canvas canvas = root.AddComponent<Canvas>();
canvas.renderMode = RenderMode.ScreenSpaceOverlay;
canvas.pixelPerfect = layoutData.canvas.pixelPerfect;
root.AddComponent<CanvasScaler>();
root.AddComponent<GraphicRaycaster>();
RectTransform rootRect = root.GetComponent<RectTransform>();
SetRectTransform(rootRect, layoutData.rectTransform);
foreach (var childData in layoutData.children)
{
CreateUIElement(childData, root.transform);
}
CreatePrefab(root, prefabPath);
GameObject.DestroyImmediate(root);
AssetDatabase.Refresh();
Debug.Log("UI Prefab generated successfully: " + prefabPath);
}
public static void GeneratePrefabFromJson(string jsonPath, string prefabPath = null) public static void GeneratePrefabFromJson(string jsonPath, string prefabPath = null)
{ {
if (!File.Exists(jsonPath)) if (!File.Exists(jsonPath))

View File

@@ -9,19 +9,6 @@ using TMPro;
public static class UIPrefabToJson public static class UIPrefabToJson
{ {
[MenuItem("Tools/UI/Export Prefab to JSON")]
public static void ExportPrefabToJsonMenu()
{
string prefabPath = EditorUtility.OpenFilePanel("选择预制体", "Assets", "prefab");
if (!string.IsNullOrEmpty(prefabPath))
{
string projectPath = Application.dataPath.Replace("/Assets", "");
string relativePath = prefabPath.Replace(projectPath + "/", "");
string jsonPath = relativePath.Replace(".prefab", ".json");
ExportPrefabToJson(relativePath, jsonPath);
}
}
public static void ExportPrefabToJson(string prefabPath, string jsonPath = null) public static void ExportPrefabToJson(string prefabPath, string jsonPath = null)
{ {
if (!AssetDatabase.LoadAssetAtPath<GameObject>(prefabPath)) if (!AssetDatabase.LoadAssetAtPath<GameObject>(prefabPath))

View File

@@ -0,0 +1,104 @@
# UI 拼接工具
## 目的
UI 拼接工具通过 JSON 与 Unity Prefab 双向转换,帮助 Codex 和开发人员创建基础 UI 层级、检查现有 Prefab并继续在 Unity 中完成业务绑定和视觉校对。
## 当前实现
| 组件 | 位置 | 职责 |
|---|---|---|
| `UIPrefabGenerator` | `Assets/Editor/Command/UIPrefabGenerator.cs` | 读取 UI JSON 并生成 Prefab |
| `UIPrefabToJson` | `Assets/Editor/Command/UIPrefabToJson.cs` | 导出 Prefab 的层级和组件数据 |
| Unity Bridge | `Assets/Editor/Command/CodexUnityEditorBridge.cs` | 在 Unity 主线程执行生成和导出命令 |
| MCP Server | `UnityAI/Tools/CodexUnityMcp/` | 把 Unity Bridge 命令暴露给 Codex |
当前外部入口是 MCP Bridge不使用文件监听或文本触发命令。
## 数据结构
根节点使用 `UILayoutData`
```json
{
"name": "ExampleWindow",
"type": "Canvas",
"layer": 5,
"rectTransform": {
"anchorMin": [0.5, 0.5],
"anchorMax": [0.5, 0.5],
"position": [0, 0, 0],
"sizeDelta": [1080, 1920],
"pivot": [0.5, 0.5],
"localScale": [1, 1, 1],
"localRotation": [0, 0, 0]
},
"children": []
}
```
子节点使用 `UIElementData`,可配置 `rectTransform``image``button``text``layoutGroup``scrollRect``toggle``slider``inputField``customComponents` 和递归 `children`
## 支持组件
- `Image` / `SFUI_Image`
- `Button` / `SFUI_Button`
- `TextMeshProUGUI` / `SFUI_TextMeshProUGUI`
- `RectTransform``Canvas``CanvasScaler``GraphicRaycaster`
- `ScrollRect` / `SFUI_ScrollRect`
- `SFUI_Viewport``SFUI_Content``SFUI_ListViewItem`
- `GridLayoutGroup``VerticalLayoutGroup``HorizontalLayoutGroup`
- `Toggle` / `SFUI_Toggle`
- `Slider` / `SFUI_Slider`
- `InputField` / `SFUI_InputField`
资源字段使用 Unity Asset 路径,例如 `Assets/Game/...`,路径分隔符统一使用 `/`
## MCP 调用
生成 Prefab
```text
unity_generate_ui_prefab(jsonPath, prefabPath)
```
导出 Prefab
```text
unity_export_prefab_to_json(prefabPath, jsonPath)
```
路径由当前任务明确传入,不规定固定测试目录或中间数据目录。目标正式窗口通常位于:
```text
Assets/Game/GameHFResource/<语言>/UIWindows/<WindowName>/<WindowName>.prefab
```
## 标准流程
1. 先读 [UI 界面拼接](../UI窗口系统/界面拼接.md) 和 [UI 开发指南](../UI窗口系统/开发指南.md)。
2. 调用 `unity_health` 确认 Unity 项目和版本。
3. 检查目标 Prefab、窗口脚本和可用资源。
4. 生成基础 Prefab或先导出现有 Prefab 再调整 JSON。
5. 调用 `unity_refresh_assets`
6. 调用 `unity_get_console_logs` 检查 Error 和关键 Warning。
7. 在 Unity 中检查层级、RectTransform、组件、资源引用和实际显示。
工具生成成功只表示 Prefab 文件已创建,不表示 UI 已完成。业务脚本、列表初始化、字体、图集、点击区域和视觉结果仍需验证。
## 安全规则
- 覆盖已有 Prefab 前确认目标路径和现有内容。
- 不通过 UI 生成工具批量删除、移动资源或执行构建发布。
- Unity API 必须由 Bridge 排队到 Editor 主线程执行。
- 生成后检查 Git 差异,避免无意义重序列化其他资源。
- JSON 递归结构出现 serialization depth warning 时检查实际生成结果;新增 Error 必须处理。
## 文档关联
| 文档 | 关联原因 |
|---|---|
| [编辑器工具入口](README.md) | 编辑器工具模块入口 |
| [UI 窗口系统](../UI窗口系统/README.md) | 窗口框架和资源路径 |
| [UI 界面拼接](../UI窗口系统/界面拼接.md) | 视觉与 Prefab 流程 |
| [MCP 使用规则](MCP工具/CrystalBattle_Codex_Unity_MCP使用规则.md) | Codex 调用和安全边界 |

View File

@@ -0,0 +1,132 @@
# 网络系统
## 分类
- 核心框架
## 目的
提供 WebSocket 连接、protobuf 消息收发、消息 ID / route 映射和错误响应处理。
---
## 核心路径
- protobuf 源:`GoogleProtobufNetwork/`
- 生成输出:`Assets/Game/GameHFScripte/CopyToHF/Network/`
- WebSocket`Assets/Game/GameHFScripte/GameFunction/WebSocket/`
---
## 核心类
| 类 | 职责 |
|---|---|
| `HFSeverManager` | 网络管理器单例 |
| `WSSession` | WebSocket 会话 |
| `HFM_Socket_WS` | WebSocket 底层连接 |
| `HFWebSocket_Manager_AutoMsgMap` | 自动生成消息映射 |
| `HFNetWorkMsgIdMap` | 网络消息 ID 映射 |
| `MessagePage` | 数据包编解码 |
---
## C2S 发送链路
```text
IMessage.Dispatch()
-> HFSeverManager.Instance.SendMsg(message)
-> HFSeverManager.OnAuto_OnGetProtocNo(message)
-> HFSeverManager.OnAuto_OnGetRoute(Network_MsgId)
-> m_Session.SendMessage(protoNo, route, PacketType.Data, Request, message)
```
`IMessage.Dispatch()` 定义在 `Assets/Game/GameHFScripte/GameFunction/WebSocket/Extends/HFServer_Extend.cs`
---
## WebSocket 连接流程
```text
登录管理器.ConnectServer
-> HFSeverManager.Connect(MainConnect, WebSocket, ip, port, token)
-> WSSession.Connect
-> HFM_Socket_WS.Connect
-> Handshake -> HandshakeAck -> 连接成功回调
```
---
## S2C 收包和派发
```text
WSSession.ReceiveMessages(PacketType.Data)
-> MessagePage.Decode(packet.Body)
-> Response.MessageId / Push.Route -> Network_MsgId
-> HFSeverManager.OnAuto_OnMergeFrom(msgid, body)
-> protobuf Parser.ParseFrom
-> 反射创建 HFEvent_STC_{MessageTypeName}
-> 写入 Request / ErrorCode
-> AbsHFEventArg<enHFSTCEvent>.Dispatch()
-> HFEventManager.Instance.STCEvent.Dispatch(arg)
```
---
## 自动生成映射
- `HFWebSocket_Manager_AutoMsgMap.cs`:提供 `OnAuto_OnGetProtocNo``OnAuto_OnGetRoute``OnAuto_OnMergeFrom``msrDicRouteToMsg`、S2C/C2S 类型字典。
- `HFNetWorkMsgIdMap.cs`:为 protobuf partial class 标记 `[HFNetworkMsg(...)]`
---
## 使用规则
- 新增协议先改 `.proto``msg.proto``route.txt`
- 不手动修改生成输出。
- 不硬编码 route 或数字 msgId。
- UI 监听 S2C 必须在 `OnClose` 移除。
- 错误响应会触发 `HFEvent_ErrorCode`
---
## 协议变更清单
1. 修改 `.proto``msg.proto`
2. 登记 msgId / route`route.txt` 或对应生成配置)。
3. 通过生成器重新生成 C# 代码到 `Assets/Game/GameHFScripte/CopyToHF/Network/`
4. 检查 `HFNetWorkMsgIdMap.cs` / `HFWebSocket_Manager_AutoMsgMap.cs` 是否同步。
5. 更新业务入口和监听。
6. 编译 `GameHF` 并运行连接/收发测试。
## 验证
- 构建 `GameHF.csproj`
- 在支持服务器的运行环境中登录、收发 C2S/S2C 消息。
- 确认 `HFEvent_STC_*` 正确派发并在 `OnClose` 时移除监听。
- 验证错误码事件 `HFEvent_ErrorCode` 触发路径。
## 当前状态
- 待验证
---
## 相关模块
- [事件系统](事件系统/README.md)
- [数据/配置框架](数据配置框架.md)
---
## 文档关联
> 当本文档发生变更时,应同步检查以下关联文档,避免信息不一致。
| 文档 | 关联原因 |
|---|---|
| [modules/模块索引.md](../模块索引.md) | 模块索引是项目知识总入口 |
| [modules/frameworks/事件系统/README.md](事件系统/README.md) | S2C 消息派发为 STC 事件 |
| [modules/frameworks/数据配置框架.md](数据配置框架.md) | 配置表与网络消息可能联动 |
| [rules/10-架构说明.md](../../rules/10-架构说明.md) | 架构说明定义总体分层和依赖方向 |
| [rules/30-模块登记规则.md](../../rules/30-模块登记规则.md) | 模块登记规则定义分类和状态口径 |

View File

@@ -0,0 +1,170 @@
# 资源管理
## 目的
资源管理负责 AssetBundle、依赖、语言资源、SpriteAtlas、内存卸载、启动代码更新和普通资源分包下载。
## 源码边界
| 类型 | 路径 | 说明 |
|---|---|---|
| ESF AssetBundle 源码 | `Assets/StrayFog/Editor/CopyToX/CopyToHF/AssetBundle/` | 框架修改源头 |
| HF AssetBundle 代码 | `Assets/Game/GameHFScripte/CopyToHF/AssetBundle/` | CopyToX 生成,禁止手改 |
| V2 公共运行时 | `Assets/StrayFog/Core/SFSubPackageV2.cs` | 非热更层与热更层共享下载状态 |
| V2 编辑器构建 | `Assets/StrayFog/Editor/Tools/AssetBundle/` | 包配置、校验、清单和枚举生成 |
| 热更业务门面 | `Assets/Game/GameHFScripte/GameFunction/HFDownLoadSubPackage/` | 普通资源下载 API |
| 启动代码入口 | `Assets/Game/GameMono/Scripts/GameDllManager.cs` | Bootstrap 校验、下载和加载 |
修改 `ESF_` 后执行 CopyToX再检查生成的 `HF_` 差异和 `GameHF` 编译结果。
## AssetBundle 加载
```text
HFFunCatalogue.Asset / HFABMgr.LoadInMemory
-> 读取 AssetBundleManifest
-> 语言与路径修正
-> 创建或复用 HFAssetLoader
-> 加载依赖 Bundle
-> 加载主 Bundle
-> HFAssetResponse.GetAsset<T>()
```
`HFABMgr` 继续作为统一入口,并使用 partial 文件组织 Manifest、Loader、GC、路径和模式逻辑。内部职责可以封装但业务入口不拆散。
### Manifest 与来源顺序
Editor 模式直接读取工程资源。Player 本地模式按以下顺序初始化 Manifest
```text
PersistentData Manifest
-> 不存在或无效时读取 StreamingAssets Manifest
-> 两处都不可用且已配置 CDN 时读取 CDN Manifest
```
- PersistentData 保存热更新后的可写资源,优先于母包资源。
- StreamingAssets 是只读随包资源Android、WebGL 等 URL 路径通过 UnityWebRequest 协程读取。
- CDN 是本地 Manifest 都不可用或资源需要更新时的远端来源。
- 显式 CDN/小游戏模式按平台适配层和缓存回调工作,不假设普通文件系统可用。
- `Application.dataPath` 只用于 `UNITY_EDITOR` 下的资源定位和分析。
PersistentData 普通文件优先使用 `AssetBundle.LoadFromFileAsync`。StreamingAssets URL、CDN byte[]、小游戏缓存和需要解密的数据继续使用 `LoadFromMemoryAsync`
### CDN 落盘
`SetCdnSaveRootPath(string)` 允许平台层传入保存根目录。有效外部路径优先;未设置时使用 `SFGlobalData.assetBundleRoot`,即项目 PersistentData 资源根目录。保存时保留相对目录结构。
## 内存与卸载
- GC 与主动卸载共用 loader 释放流程。
- 释放时调用 `AssetBundle.Unload(false)`,销毁 loader并同步清理 loader 映射、生命周期池和内存统计。
- 按资源名卸载只在唯一匹配且 loader 可卸载时成功;未找到、重名、加载未完成或仍有请求时返回 `false`
- 内存大小使用 loader 统计或本地文件长度估算,只用于运行时观察,不替代 Unity Profiler。
公开使用方式见 [资源管理使用指南](使用指南.md)。
## 分包 V2
V2 将编辑器构建清单与设备下载状态分离。运行时只消费编辑器生成的 V2 清单,不识别旧 `SPI_*` 结构。
### 编辑器阶段
资源包通过 Unity 编辑器自由配置XML 只负责持久化。每个 Package 包含:
- `Id``DisplayName``Priority``BuiltIn`
- `RootPaths[]`
- `DependencyPackageIds[]`
保存和构建会校验空/重复 ID、无效路径、自依赖、缺失依赖和循环依赖。根路径使用标准化小写路径与目录边界前缀匹配重叠目录警告但允许构建。
构建顺序:
```text
普通 AssetBundle
-> AOT 与 HotUpdate DLL 产物
-> 收集最终文件
-> 生成 V2 subpackage.json
-> 复制 BuiltIn 文件并生成分析结果
```
生成清单的同时生成 `enHFSubPackageId.cs`。枚举成员由 PackageId 转换XML 注释使用 DisplayName业务通过映射恢复原始 PackageId生成文件禁止手改。
### V2 清单
```text
Version / Platform / BuildId
BootstrapFiles[] AOT 与 HotUpdate 启动代码
Files[] 普通 AB 的 Path、MD5、Size、Dependencies
Packages[] 包配置、FilePaths 和 Size
```
- `BootstrapFiles``CodeKind``LoadOrder` 控制 AOT、HotUpdate 加载顺序。
- `Files` 以标准化 Path 全局唯一,依赖来自 Unity AssetBundleManifest。
- `Packages` 没有固定业务类型PackageId 的业务意义由调用方决定。
- Package 显式依赖和 AB 文件依赖是两套关系,运行时都会递归展开。
### 运行时顺序
```text
下载并校验远端 V2 清单
-> 比对 BootstrapFiles
-> PersistentData 命中则复用
-> 否则检查 StreamingAssets
-> 仍不匹配则从 CDN 下载到临时文件并校验 MD5
-> AOT 加载成功
-> HotUpdate 加载与入口执行成功
-> CommitBootstrapCodeLoaded 提交清单和状态
-> 普通资源比对与下载开放
```
Bootstrap 是普通资源的硬门禁。清单、下载、MD5、AOT、HotUpdate 或入口任一步失败都不会开放普通资源阶段。
CDN URL 使用:
```text
{BaseUrl}/{AppPartner}/{AppVersion}/{Platform}/{FilePath}
```
BaseUrl 按配置顺序尝试,使用 `/` 进行 URI 拼接。Bootstrap 文件最多三轮,每轮尝试全部有效 BaseUrl普通文件一次请求按顺序尝试有效地址。
### 普通资源更新范围
`CheckAndDownloadAllFiles` 不会无条件下载整个 `Files[]`,它处理:
- 未归属任何 Package 的基础文件。
- `BuiltIn = true` 的 Package 及依赖包。
- `DownloadedPackageIds` 中历史成功下载的 Package 及依赖包。
- 上述文件的完整 AB 依赖闭包。
从未下载、非 BuiltIn 的可选 Package 不会被全量更新误下载。业务可按 PackageId 主动下载,资源加载缺文件时也可按 `Files[]` 下载目标文件依赖闭包。
### 状态与去重
`subpackage_state.json` 当前保存:
- `BuildId`
- `DownloadedFiles` 的 Path 与 MD5
- `DownloadedPackageIds`
Package 完整成功后才记录请求包和依赖包。查询 Package 是否完成时会同时检查当前清单、PackageId 状态、依赖包状态和所有文件 MD5。
去重分为三层:清单 Path 唯一、进行中任务按 `Path + MD5` 合并、本地文件和状态校验通过后复用。文件只有完整写入并通过 MD5 后才更新状态和进度计数。
## 验证重点
- PersistentData、StreamingAssets 和 CDN 的 Manifest 回退不会卡住主线程。
- 本地文件使用正确加载策略,平台 URL 使用协程。
- GC/主动卸载后能重新加载loader 映射和内存统计正确。
- V2 差异结果在下载前回调,失败信息包含 Path、期望 MD5 和尝试 URL。
- 冷启动会从状态继续按文件校验,已完成文件不重复下载。
- 已下载 Package 在远端 MD5、依赖或 FilePaths 变化后参与更新。
## 文档关联
| 文档 | 关联原因 |
|---|---|
| [资源管理使用指南](使用指南.md) | 业务调用、卸载、内存和分包 API |
| [模块索引](../../模块索引.md) | 模块入口和状态 |
| [UI 窗口系统](../UI窗口系统/README.md) | UI Prefab 加载与卸载 |
| [Hotfix 启动](../Hotfix启动.md) | Bootstrap 代码加载入口 |
| [架构说明](../../../rules/10-架构说明.md) | ESF/HF 源码边界 |
| [工作流清单](../../../rules/40-工作流清单.md) | 生成和平台验证流程 |

View File

@@ -0,0 +1,174 @@
# 资源管理使用指南
## 一、加载资源
业务统一通过 `HFFunCatalogue.Asset` 调用:
```csharp
HFFunCatalogue.Asset.LoadAsset(@"Perfabs\Tower\LavaGuard.prefab", (response, args) =>
{
GameObject prefab = response.GetAsset<GameObject>();
if (prefab == null)
{
SFP.Error("Load LavaGuard failed.");
return;
}
GameObject instance = GameObject.Instantiate(prefab);
});
```
资源路径仍按项目 `HFAssetBundlePathAttribute`、语言目录和 AssetBundle 配置解析。业务不要直接创建 `HFAssetLoader` 或依赖 assetBundleKey。
## 二、主动卸载
业务使用易读名称接口:
```csharp
bool prefabUnloaded = HFFunCatalogue.Asset.UnloadPrefabObject("LavaGuard");
bool assetUnloaded = HFFunCatalogue.Asset.UnloadAssetObject("common_icon");
```
调用前必须确认业务实例和窗口已经释放引用。框架会查找唯一 loader并检查加载、请求和释放状态未找到、重名或仍不可卸载时返回 `false`
`AssetBundle.Unload(false)` 不会自动销毁已经实例化的 GameObject。业务仍应先关闭窗口或 Destroy 实例,再请求卸载 Bundle 内存。
同名资源存在多个 loader 时不要随机卸载;使用更完整的资源路径,或根据错误日志定位冲突来源。
## 三、内存查看
```csharp
long bytes = HFFunCatalogue.Asset.GetLoadedAssetBundleMemorySize();
float kb = HFFunCatalogue.Asset.GetLoadedAssetBundleMemorySizeKB();
float mb = HFFunCatalogue.Asset.GetLoadedAssetBundleMemorySizeMB();
string text = HFFunCatalogue.Asset.GetLoadedAssetBundleMemorySizeText();
HFFunCatalogue.Asset.LogLoadedAssetBundleMemorySize();
```
该数值是已完成 loader 的 AssetBundle 内存估算。`LoadFromFileAsync` 没有托管 byte[] 时使用文件长度估算,因此只用于调试面板和趋势观察。
## 四、AssetBundle CDN 保存路径
平台层可以在初始化时配置:
```csharp
HFFunCatalogue.Asset.SetCdnSaveRootPath(platformSaveRoot);
```
未配置或传入无效值时使用 PersistentData 资源根目录。平台专用目录由平台适配层传入,不在通用 ESF 逻辑中硬编码。
## 五、分包 V2 配置
非热更启动层使用:
```csharp
SFSubPackageRuntimeV2.Instance.SetDownloadConfig(
downloadSetting.WebBaseUrlBase,
downloadSetting.AppVersion,
downloadSetting.AppPartner);
```
如平台使用自定义文件系统,调用 `SetLocalStorage` 重载传入 exists、read、write 和 delete 回调。默认存储根目录为 PersistentData。
`SetDownLoadUri(string)` 只作为单地址兼容入口,新代码优先使用 `SetDownloadConfig`
## 六、启动代码更新
`GameDllManager` 负责调用:
```csharp
SFSubPackageRuntimeV2.Instance.CheckAndDownloadBootstrapFiles(
OnProgress,
OnBootstrapCompleted,
OnManifestFailed);
```
成功下载不等于启动完成。AOT、HotUpdate 和热更入口成功后,调用:
```csharp
SFSubPackageRuntimeV2.Instance.CommitBootstrapCodeLoaded(OnCommitted);
```
提交成功后普通资源 API 才可使用。失败时调用 `InvalidateBootstrapCode` 保持门禁关闭,并向业务展示重试或退出。
## 七、更新普通资源
### 更新基础、BuiltIn 和历史包
```csharp
HFSubPackageManager.Instance.CheckAndDownloadAllFiles(
progress => UpdateLoading(progress),
() => OnResourceUpdateCompleted(),
result => SFP.Error(SFDownloadResultLog.Format("普通资源下载失败", result)));
```
该接口会先完成差异扫描并回调差异结果再开始删除旧遮挡文件和下载。它只处理基础文件、BuiltIn 包、历史已下载包及依赖闭包。
### 按枚举下载 Package
```csharp
HFSubPackageManager.Instance.CheckAndDownloadPackage(
enHFSubPackageId.PACKAGE_1001,
progress => UpdateLoading(progress),
() => OnPackageReady(),
result => SFP.Error(SFDownloadResultLog.Format("Package 下载失败", result)));
```
枚举由编辑器生成,成员注释来自 Package DisplayName。不要手改 `Generated/enHFSubPackageId.cs`
字符串接口仍保留:
```csharp
HFSubPackageManager.Instance.CheckAndDownloadPackage(
packageId, progress, finish, failed);
```
### 查询 Package 状态
```csharp
bool ready = HFSubPackageManager.Instance.IsPackageDownloaded(
enHFSubPackageId.PACKAGE_1001);
```
返回 `true` 需要Bootstrap 已提交、Package 存在于当前清单和 `DownloadedPackageIds`、依赖包已记录、全部文件状态符合当前 MD5。`BuiltIn = true` 本身不等于业务已经下载过。
### 按文件兜底
资源加载知道目标 AB 路径时可以使用 `CheckAndDownloadFile`。运行时会从 `Files[]` 找到目标文件,递归展开 Dependencies下载差异后重试原加载流程。
## 八、进度和失败
进度对象包含:
- `Stage``Max``DownloadedCount`
- `TotalBytes``DownloadedBytes`
- `CurrentPath``CurrentFileSize`
- `CurrentFileDownloadedBytes``CurrentFileProgress``Progress`
失败结果包含:
- `DifferenceFiles``DeletedOldFiles``UpdatedFiles`
- `FailedFiles[].Path`
- `ExpectedMD5``Error``TriedUrls`
单文件只有写入完成且 MD5 通过后才增加完成计数。进程被结束后,下次启动会重新读取远端清单和本地状态,逐文件检查;已完成文件复用,未完成文件从文件头重新下载,不做单文件字节级续传。
## 九、验证清单
- PersistentData 文件正确时不访问 CDN。
- PersistentData 错误但 StreamingAssets 正确时使用母包文件并处理遮挡旧文件。
- 两处均无有效文件时从 CDN 下载到默认或外部保存路径。
- 差异日志在普通资源下载进度之前输出。
- 两个 Package 共享依赖时只建立一个 `Path + MD5` 任务。
- 远端 MD5 变化后历史 Package 会参与 `CheckAndDownloadAllFiles`
- 下载失败释放进行中任务,下一次请求可以重试。
- Android/WebGL 的 StreamingAssets 失败会继续 fallback不会阻塞主线程。
## 文档关联
| 文档 | 关联原因 |
|---|---|
| [资源管理入口](README.md) | 架构、来源顺序和 V2 数据流 |
| [UI 窗口系统](../UI窗口系统/README.md) | UI 加载与卸载调用方 |
| [Hotfix 启动](../Hotfix启动.md) | Bootstrap 接入 |
| [开发规则](../../../rules/20-开发规则.md) | 业务入口和异步规则 |

View File

@@ -0,0 +1,70 @@
# 通用框架
## 分类
- 核心框架
## 目的
记录 general/shared 代码、生成框架、StrayFog 核心和跨模块通用能力。
## 已知线索
- General`Assets/Game/GameGeneralScripte/`
- 生成 General`Assets/AutoBuildScript/General/`
- StrayFog Core`Assets/StrayFog/Core/`
- 程序集:`GameGeneral``ZY.General.ZYCore``StrayFogCore`
## 当前结构
- `GameGeneralScripte/`:项目通用运行时代码,包含 `CopyToGeneral`、状态机扩展、`GameGeneral.asmdef``SEHFCommon.dll`
- `AutoBuildScript/General/`:生成框架的 General 层,包含 `ZYCore``ZYXlsx``ZYUGUI` 的通用模板和属性。
- `StrayFog/Core/`:底层核心程序集和模拟行为桥接,包含 `SFCore.dll``SFGlobalData``SFAssetUtility_Unity``SimulateBehaviour`
- `GameGeneralScripte/CopyToGeneral/AssetBundle/HFAssetBundleHelper.cs`资源路径、StreamingAssets、PersistentData、CDNAssets、微信小游戏文件读写适配。
- `GameGeneralScripte/CopyToGeneral/DllHelper/HFDllHelper.cs`Hotfix DLL、PDB、HybridCLR AOT DLL bytes 路径和读取。
- `GameGeneralScripte/CopyToGeneral/Enum/HFEnumForAssetBundle.cs`AssetBundle 加载/更新模式枚举。
- `GameGeneralScripte/StateMachineBehaviour/`Animator 状态机扩展和只读属性 Drawer。
## 边界判断
- `GameGeneralScripte` 更像项目运行时可依赖的通用层。
- `AutoBuildScript/General` 更像代码生成框架的通用模板层。
- `StrayFog/Core` 提供更底层的工具、全局路径和模拟行为桥接能力。
- 资源框架、配置框架、Hotfix 启动都会依赖这里的通用能力;反向依赖 hotfix 业务逻辑应避免。
## 梳理任务
- [x] 梳理 `GameGeneralScripte``AutoBuildScript/General` 的边界。
- [x] 梳理 StrayFog Core 提供的基础能力。
- [x] 梳理通用 attributes、enum、dll helper、asset bundle helper。
- [x] 梳理哪些功能/框架允许依赖 general/shared。
- [x] 梳理生成代码和手写代码的边界。
## 待确认
- `StrayFog` 是项目自研框架还是外部框架。
- `CopyToGeneral` 的复制/生成来源需要继续追 `AutoBuildScript` 配置。
- General 层建议保持底层通用,不依赖 hotfix 业务层。
## 相关模块
- [Hotfix 启动/目录](../Hotfix启动.md)
- [资源框架](../资源管理/README.md)
- [数据/配置框架](../数据配置框架.md)
---
## 文档关联
> 当本文档发生变更时,应同步检查以下关联文档,避免信息不一致。
| 文档 | 关联原因 |
|---|---|
| [modules/模块索引.md](../../模块索引.md) | 模块索引是项目知识总入口 |
| [modules/frameworks/数据配置框架.md](../数据配置框架.md) | 数据/配置框架 |
| [modules/frameworks/Hotfix启动.md](../Hotfix启动.md) | Hotfix 启动/目录 |
| [modules/frameworks/资源管理/README.md](../资源管理/README.md) | 资源框架 |
| [rules/10-架构说明.md](../../../rules/10-架构说明.md) | 架构说明定义总体分层和依赖方向 |
| [rules/20-开发规则.md](../../../rules/20-开发规则.md) | 开发规则与框架/生成规则互相引用 |
| [rules/30-模块登记规则.md](../../../rules/30-模块登记规则.md) | 模块登记规则定义分类和状态口径 |
| TODO补充依赖或使用本框架的模块文档 | 如依赖本框架的功能模块 |

View File

@@ -0,0 +1,64 @@
# 模块名称
## 目的
TODO一句话说明模块解决的问题。
## 主要路径
| 类型 | 路径 | 说明 |
|---|---|---|
| 源码 | `Assets/...` | TODO |
| 生成代码 | `Assets/...` | 没有则删除本行 |
| 资源/配置 | `Assets/...` | TODO |
## 边界
- 本模块负责TODO
- 本模块不负责TODO
- 源码与生成结果TODO
## 数据流
```text
TODO入口 -> 处理 -> 输出
```
## 关键类与接口
| 类/方法 | 用途 |
|---|---|
| `ClassName` | TODO |
## 使用规则
- TODO
## 验证
- TODO编译、Unity、运行时或目标平台验证方式。
## 当前状态
- 已识别 / 初步梳理 / 待验证 / 已完成 / 未发现实现
## 文档关联
| 文档 | 关联原因 |
|---|---|
| [模块索引](模块索引.md) | 模块入口和状态 |
| [模块登记规则](../rules/30-模块登记规则.md) | 文档分类和结构 |
| [架构说明](../rules/10-架构说明.md) | 代码分层和依赖方向 |
## 文档结构
- 轻量模块只保留 README。
- 公共 API 较多时增加 `使用指南.md``开发指南.md`,具体判断标准见 [模块登记规则](../rules/30-模块登记规则.md)。
- 特殊限制较多时增加 `注意事项.md`;一次性任务文档规则见 [工作流清单](../rules/40-工作流清单.md)。
### README 与使用指南的分工
| 文档 | 内容 |
|---|---|
| `README.md` | 模块定位、核心组成、使用规则、边界、导航链接 |
| `使用指南.md` | 详细 API、调用示例、数据流、架构图、最佳实践、边界场景 |

56
modules/模块索引.md Normal file
View File

@@ -0,0 +1,56 @@
# 模块索引
这里是 UnityAI / StrayFog 框架知识总入口。模块入口和状态以本文件为准,状态定义见 [模块登记规则](../rules/30-模块登记规则.md)。
## 核心框架
| 模块 | 主要路径 | 职责 | 状态 |
|---|---|---|---|
| [通用框架](frameworks/通用框架/README.md) | `Assets/StrayFog/Core/``GameGeneralScripte/` | 模拟行为、全局数据和通用工具 | 已完成 |
| [对象池](frameworks/内存对象管理/README.md) | `CopyToHF/MemoryManager/` | GameObject、脚本和类实例池 | 已完成 |
| [事件系统](frameworks/事件系统/README.md) | `CopyToHF/Event/` | CTC/STC 事件派发 | 已完成 |
| [资源管理](frameworks/资源管理/README.md) | `CopyToHF/AssetBundle/``StrayFog/Core/SFSubPackageV2.cs` | AssetBundle、图集、卸载、分包 V2 和下载 | 已完成 |
| [相机系统](frameworks/相机系统/README.md) | `GameHFScripte/` | 多相机、堆栈和渲染顺序 | 已完成 |
| [实体系统](frameworks/实体系统/README.md) | `GameFunction/GameEntity/` | 实体、System、Model 和实体池 | 已完成 |
| [UI 窗口系统](frameworks/UI窗口系统/README.md) | `CopyToHF/UIWindowMgr/``GameFunction/UIWindows/` | 窗口生命周期、加载、卸载和列表 | 已完成 |
| [技能系统](frameworks/技能系统/README.md) | `GameFunction/GameEntity/` | 技能触发、释放和配置联动 | 已完成 |
| [场景系统](frameworks/场景系统.md) | `GameFunction/SceneManager/` | 场景加载和生命周期 | 待验证 |
| [网络系统](frameworks/网络系统.md) | `CopyToHF/Network/``GameFunction/WebSocket/` | WebSocket、protobuf 和消息映射 | 待验证 |
| [数据配置](frameworks/数据配置框架.md) | 项目表格、proto 和生成目录 | 配置源、解析和代码生成 | 待验证 |
| [Hotfix 启动](frameworks/Hotfix启动.md) | `GameFunction/GameRoot/``GameDllManager` | AOT、热更 DLL 和业务入口 | 待验证 |
## 项目框架
| 模块 | 主要路径 | 职责 | 状态 |
|---|---|---|---|
| [第三方插件](frameworks/第三方插件.md) | `Assets/ThirdPlugins/``Packages/` | 记录 HybridCLR、Spine、DOTween 等插件用途、边界、本地修改和升级风险 | 已识别 |
## 编辑器工具
| 模块 | 主要路径 | 职责 | 状态 |
|---|---|---|---|
| [SF Editor](frameworks/编辑器工具/README.md#sf-editor) | `Assets/StrayFog/Editor/` | StrayFog 生成器和 Editor 扩展 | 已完成 |
| [项目 Editor Assets](frameworks/编辑器工具/README.md#project-editor-assets) | `Assets/Editor/` | 项目级 Editor 工具 | 已识别 |
| [UI 拼接工具](frameworks/编辑器工具/UI拼接工具.md) | `Assets/Editor/Command/` | UI Prefab 与 JSON 双向转换 | 已完成 |
| [MCP 工具](frameworks/编辑器工具/MCP工具/README.md) | `Tools/CodexUnityMcp/`、Unity Bridge | Codex 与 Unity Editor 工具桥 | 已完成 |
## 业务参考
- [PlayBalloons](../business-reference/playballoons/业务参考总入口.md):外部项目业务实现示例,不作为框架规范。
## 文档拆分
- 轻量模块只保留 README。
- 公共 API 较多时增加使用指南或开发指南。
- 特殊限制较多时增加注意事项。
- 一次性任务不扩展模块文档结构,具体规则见 [工作流清单](../rules/40-工作流清单.md)。
## 文档关联
| 文档 | 关联原因 |
|---|---|
| [模块登记规则](../rules/30-模块登记规则.md) | 分类、状态和拆分规则 |
| [架构说明](../rules/10-架构说明.md) | 模块代码分层和源码边界 |
| [框架架构](frameworks/框架架构.md) | 全局实现视角的框架分层 |
| [项目规则入口](../rules/项目规则入口.md) | 项目知识入口 |
| [AI 接入入口](../ai/AI接入入口.md) | AI 必读模块索引 |

57
rules/00-项目概览.md Normal file
View File

@@ -0,0 +1,57 @@
# 项目概览
## 定位
`UnityAI` 是 StrayFog 框架的通用知识库和工作流标准,服务 AI 工具、业务开发人员与框架维护人员。本仓库不保存完整游戏业务代码,具体结论必须结合接入的 Unity 项目验证。
- **通用标准仓库**`UnityAI`
- **当前主要验证对象**`CrystalBattle_Client`
- **文档语言**:中文
- **适用范围**:使用 StrayFog 框架的 Unity 项目
CrystalBattle_Client 用于验证目录、接口、生成流程和平台行为,但项目专有实现不应被写成所有项目都必须遵守的框架规则。
## 目录
| 目录 | 用途 |
|---|---|
| `ai/` | AI 工具统一接入入口 |
| `rules/` | 架构、开发、工作流、文档同步和扫描规则 |
| `modules/frameworks/` | StrayFog 模块架构与使用文档 |
| `business-reference/` | 外部项目业务案例,只作参考 |
| `hooks/` | 只读工作流检查和提交检查 |
| `Tools/` | MCP Server 等可执行工具 |
本仓库不建立独立的需求方案、阶段进度或任务清单目录。重大变更在对话中确认,稳定结论直接进入模块文档。
## 使用方式
### AI 工具
1. 读取 [AI 接入入口](../ai/AI接入入口.md)。
2. 读取 [项目规则入口](项目规则入口.md) 和 [工作流清单](40-工作流清单.md)。
3. 从 [模块索引](../modules/模块索引.md) 读取任务相关模块。
4. 读取目标 Unity 项目的真实代码、Prefab、配置和日志后再得出结论。
### 人工开发者
1. 从 [架构说明](10-架构说明.md) 了解源码和生成代码边界。
2. 从 [开发规则](20-开发规则.md) 了解编码、资源和生成约束。
3. 从具体模块 README 和使用指南查找接口与数据流。
## 文档原则
- `rules/` 保存跨模块标准。
- `modules/` 保存模块长期知识。
- 一个事实只在一处完整定义,其他文档通过链接引用。
- `business-reference/` 不能反向定义框架规范。
- 当前工程的临时排错过程不进入长期文档。
## 文档关联
| 文档 | 关联原因 |
|---|---|
| [项目规则入口](项目规则入口.md) | 项目规则总入口 |
| [架构说明](10-架构说明.md) | 代码分层和项目边界 |
| [模块索引](../modules/模块索引.md) | 框架知识总入口 |
| [AI 工具扫描范围](70-AI工具扫描范围.md) | 扫描范围和忽略目录 |

68
rules/10-架构说明.md Normal file
View File

@@ -0,0 +1,68 @@
# 架构说明
本文档定义 StrayFog 项目的代码分层、真实源码位置与生成边界。具体项目路径不同的时候,以项目配置和生成器实现为准。
## 总体分层
```text
游戏业务GameFunction / GameMono / GameHFResource
|
v
生成后的运行时框架CopyToHF / GameGeneral
|
v
StrayFog Core / Unity Engine / 第三方插件
StrayFog Editor / CopyToX --------------> 生成运行时代码与资源
```
## 源码与生成结果
| 路径 | 类型 | 修改规则 |
|---|---|---|
| `Assets/StrayFog/Core` | 直接维护的框架运行时源码 | 按框架需求直接修改并构建 `StrayFogCore` |
| `Assets/StrayFog/Editor` | Editor 工具与生成器源码 | 直接修改;运行时代码不得反向依赖 |
| `Assets/StrayFog/Editor/CopyToX/CopyToHF` | `ESF_` 热更框架源码 | 框架修改的主要源头,修改后执行 CopyToX |
| `Assets/StrayFog/Editor/CopyToX/CopyToGeneral` | General 层生成源码 | 修改后执行 CopyToX |
| `Assets/Game/GameHFScripte/CopyToHF` | CopyToX 生成的 `HF_` 运行时代码 | 禁止手改,只检查生成差异 |
| `Assets/Game/GameGeneralScripte/CopyToGeneral` | CopyToX 生成的 General 代码 | 禁止手改,只检查生成差异 |
| `Assets/Game/GameHFScripte/GameFunction` | 项目热更业务代码 | 业务需求直接修改 |
| `Assets/Game/GameMono` | 项目 Mono 桥接和组件代码 | 直接修改并构建 `SFMono` |
| `Assets/Game/GameHFResource` | Prefab、图集、配置和 AssetBundle 资源 | 通过 Unity 或已有工具修改并验证序列化结果 |
| `Assets/Editor/Command` | 项目 Editor/MCP 工具 | 直接修改,在 Unity 主线程验证 Editor API |
CopyToX 会删除并重新生成目标子目录,同时把 `ESF_` 标记转换为 `HF_`。因此目标目录中的手工改动会丢失,也不能作为下一次生成的源码。
## 程序集
| 程序集 | 主要职责 |
|---|---|
| `StrayFogCore` | StrayFog 基础运行时 |
| `SFEditor` | StrayFog Editor 工具 |
| `GameGeneral` | 生成后的通用运行时层 |
| `GameHF` | 热更框架与业务代码 |
| `SFMono` | MonoBehaviour、UIMono 和桥接层 |
项目接入第三方插件时,以 asmdef 依赖为准,不把第三方源码复制为框架规则。
## 依赖方向
- 业务代码可以依赖公开框架入口和通用层。
- 业务调用优先通过 `HFFunCatalogue` 等项目统一入口,不绕过封装直接依赖内部单例。
- Core 和生成后的框架运行时不能依赖具体业务模块。
- 运行时代码不能依赖 Editor 程序集。
- Editor 工具可以读取或生成运行时代码和资源,但生成结果不能成为生成器的反向依赖。
## 当前验证基线
AI 每次都应读取目标项目的 `ProjectSettings/ProjectVersion.txt`,不把文档中的版本当作永久值。当前 CrystalBattle_Client 的验证基线为 Unity `2022.3.29f1`
## 文档关联
| 文档 | 关联原因 |
|---|---|
| [开发规则](20-开发规则.md) | 源码边界对应具体修改规则 |
| [工作流清单](40-工作流清单.md) | 生成和验证步骤引用本架构 |
| [模块索引](../modules/模块索引.md) | 模块职责和入口 |
| [通用框架](../modules/frameworks/通用框架/README.md) | General / Core 通用能力说明 |
| [框架架构](../modules/frameworks/框架架构.md) | StrayFog 实现视角的架构说明 |

87
rules/20-开发规则.md Normal file
View File

@@ -0,0 +1,87 @@
# 开发规则
## 基本原则
- 先读取附近代码和模块文档,再决定实现方式。
- 修改范围保持聚焦,优先复用项目已有模式和公开入口。
- 真实源码、生成代码、业务代码和资源必须按 [架构说明](10-架构说明.md) 区分。
- 不回退任务开始前已有的修改,不顺带格式化或重序列化无关文件。
- 一个长期事实只在一处完整定义,其他文档使用链接。
## C# 规则
### 命名与结构
- 类型、属性和方法使用 PascalCase。
- 私有字段沿用项目 `m_` 前缀,例如 `m_UserName`
- 方法参数沿用项目 `_` 前缀,例如 `_userName`
- 一个文件原则上只放一个主要类型partial 和小型辅助类型遵循附近实现。
- public API 添加简洁中文 XML 注释,说明用途、参数和返回值。
- 日志包含方法、资源路径、PackageId 或平台等关键上下文,不只输出“失败”。
### 语言兼容性
- 先读取 Unity 版本、asmdef 和附近代码风格,不默认使用最新 C# 语法。
- 优先使用项目已有的显式类型、普通属性、传统 `switch` 和清晰的回调/协程写法。
- 非必要时不引入 record、init-only、范围索引、复杂模式匹配、目标类型推断等较新语法。
- 新语法只有在目标 Unity/编译器已验证且确实降低复杂度时使用。
- 避免超长方法、深层嵌套和为了封装而封装的辅助层。
## 框架与业务边界
- 业务代码通过 `HFFunCatalogue` 等统一入口访问资源、UI、场景和其他框架能力。
- 业务功能直接修改 `GameFunction``GameMono` 和对应资源。
- 框架维护任务可以修改 `Assets/StrayFog/Core``Assets/StrayFog/Editor` 和 CopyToX 源码,不套用“业务不得改框架”的限制。
- CopyToX 生成目录禁止手改;生成结果有问题时修正 ESF/General 源码或生成器。
- 修改 ESF 后必须执行 CopyToX并检查生成后的 HF 差异。
## Unity 与异步规则
- Unity API 只在 Unity 主线程调用;后台线程只做不触碰 UnityEngine 对象的工作。
- StreamingAssets、UnityWebRequest、CDN 和 WebGL 下载使用协程或回调。
- 禁止在主线程用阻塞式 `while`、忙等或同步等待网络与文件结果。
- 下载进度只在单文件完整写入并通过 MD5/完整性校验后计数。
- 平台路径、只读 StreamingAssets、PersistentData 和外部存储回调分别验证。
## UI 与 Prefab
- 修改前同时读取窗口脚本、UIMono、Prefab 层级和相关资源。
- 单列虚拟列表使用 `SetLoopListViewItemPrefabs``InitListView``RefreshDataTotalCount`
- 多列虚拟列表使用 `SetLoopGridViewItemPrefabs``InitGridView``RefreshGridDataTotalCount`
- 模板节点保持禁用,由列表运行时创建实例;不要依赖旧 LayoutGroup 或 ContentSizeFitter 驱动虚拟列表。
- Prefab 修改检查锚点、pivot、sizeDelta、组件启用状态、序列化引用和实际显示。
- 避免文本方式大范围重写 Prefab优先使用 Unity Editor、MCP 或结构化序列化工具。
详细规则见 [UI 窗口系统](../modules/frameworks/UI窗口系统/README.md)。
## 资源与生成规则
- Prefab、图集、配置、AssetBundle 和代码生成优先修改源资源或生成配置。
- SpriteAtlas 按模块组织;打图集设置以项目生成器为准。
- 网络消息以 proto/schema 为源头,生成输出只用于检查。
- 资源加载、分包、MD5、下载和卸载规则见 [资源管理](../modules/frameworks/资源管理/README.md)。
- 生成操作后检查 Git 差异,确认没有删除或覆盖用户维护的非生成文件。
## 验证与 Git
- 验证范围随改动范围扩大,最低要求见 [工作流清单](40-工作流清单.md)。
- 编译通过后仍需检查 Unity ConsoleUI 和平台逻辑继续做实际运行验证。
- UnityAI 与目标 Unity 项目分别检查 Git 状态。
- Git 提交规则见 [项目规则入口](项目规则入口.md)。
## 文档规则
- 长期文档只记录稳定架构、公共 API、生成流程和使用规则。
- 重大变更的讨论和文档落盘方式遵循 [工作流清单](40-工作流清单.md)。
- 文档使用相对链接;代码示例必须可编译或明确标注伪代码。
- 模块入口或状态变化时更新 [模块索引](../modules/模块索引.md)。
## 文档关联
| 文档 | 关联原因 |
|---|---|
| [架构说明](10-架构说明.md) | 源码与生成目录边界 |
| [工作流清单](40-工作流清单.md) | 实施与验证流程 |
| [文档同步规则](50-文档同步规则.md) | 长期文档更新条件 |
| [UI 窗口系统](../modules/frameworks/UI窗口系统/README.md) | UI 专项规范 |
| [资源管理](../modules/frameworks/资源管理/README.md) | 资源专项规范 |

View File

@@ -0,0 +1,55 @@
# 模块登记规则
模块入口、分类和状态统一维护在 [模块索引](../modules/模块索引.md),其他文档不复制模块清单。
## 分类
- **核心框架**:运行时系统,例如 UI、资源、事件、实体、对象池和场景。
- **编辑器工具**Unity Editor 内的生成器、窗口、菜单和 MCP Bridge。
- **业务参考**:外部项目案例,仅用于说明框架如何被使用。
## 状态
- **未识别**:尚无稳定实现线索。
- **已识别**:已发现路径或入口,未完成系统梳理。
- **初步梳理**:职责、路径或基本数据流已记录,仍有待确认项。
- **待验证**:文档已有结论,尚未通过 Unity、运行时、生成器或日志闭环。
- **已完成**:当前文档与实现已经验证,后续随代码演进维护。
- **未发现实现**:按目录和关键词检查后暂未发现实现。
## 文档结构
- 轻量模块使用一个 `README.md`
- API 和业务调用较多时增加 `使用指南.md``开发指南.md`
- 特殊限制写入 `注意事项.md`,不创建计划、进度或任务文件。
- 模块发生大改时,讨论保留在对话中;实现后的稳定结论直接更新现有文档。
- 模块新增、删除、重命名或状态变化时更新模块索引。
### 量化标准
| 维度 | 使用一个 README | 增加使用/开发指南 | 增加注意事项 |
|---|---|---|---|
| 核心类/接口数 | ≤3 个 | ≥5 个公共方法或 ≥3 个配置项 | — |
| 状态机/生命周期复杂度 | 无复杂状态机 | 存在多阶段调用顺序 | — |
| 公共 API 数量 | ≤5 个 | >5 个 | — |
| 必须遵守的禁忌/性能约束 | ≤1 条 | — | ≥2 条 |
| 典型使用示例必要性 | 一句话可描述 | 需要完整调用链示例 | 存在特殊边界场景 |
`README.md` 只保留模块定位、核心组成、使用规则和导航链接;具体 API、调用链、架构图、最佳实践写入 `使用指南.md``开发指南.md`
## 登记规则
- 框架模块放入 `modules/frameworks/`
- 编辑器工具放入 `modules/frameworks/编辑器工具/`
- 外部业务案例放入 `business-reference/<project>/`,不作为框架规范。
- 文档路径反映模块职责,不按一次性任务名称建立目录。
- 一个模块的职责和入口由 README 完整定义,索引只保存摘要和链接。
## 文档关联
| 文档 | 关联原因 |
|---|---|
| [模块索引](../modules/模块索引.md) | 模块清单和状态的唯一事实来源 |
| [架构说明](10-架构说明.md) | 模块分类与代码分层 |
| [文档同步规则](50-文档同步规则.md) | 模块变化的同步条件 |
| [模块文档模板](../modules/模块文档模板.md) | 新模块文档结构 |

133
rules/40-工作流清单.md Normal file
View File

@@ -0,0 +1,133 @@
# 工作流清单
本文档是 UnityAI 唯一的任务执行流程。其他入口只链接本文件,不复制完整步骤。
## 一、任务分类
| 类型 | 判断标准 | 处理方式 |
|---|---|---|
| 分析检查 | 查询、解释、定位、评审,不要求修改 | 读取真实实现和证据,输出结论与风险 |
| 局部修复 | 目标明确、影响集中、公开行为基本不变 | 检查上下文后直接修改并验证 |
| 重大变更 | 公共接口、框架架构、生成流程、跨模块数据、批量资源或平台流程变化 | 先在对话中确认目标、边界、方案和验收条件,再实施 |
重大变更不创建 Spec、Plan、progress 或 tasks 文件。需要长期保存的内容,在实现确认后写入对应模块 README、架构说明或使用指南。
## 二、标准执行流程
### 1. 准备与定位
1. 读取 [项目规则入口](项目规则入口.md) 和相关模块文档。
2. 检查 UnityAI 与目标 Unity 项目的分支、工作树和未跟踪文件。
3. 读取 `ProjectSettings/ProjectVersion.txt`,确认 Unity 版本。
4. 搜索调用入口、数据流、Prefab、配置、生成器和测试方式。
5. 按 [架构说明](10-架构说明.md) 确认修改对象是真实源码还是生成结果。
无法从仓库发现的信息才向用户确认。已有修改默认属于用户,必须保留并在其基础上工作。
### 2. 分析与确认
- 分析检查:继续读取直到结论有代码、资源、配置或日志支撑。
- 局部修复:说明准备修改的位置和行为,然后直接实施。
- 重大变更:在对话中确认目标、范围、兼容性、数据流、失败行为和验证标准。
- 存在多个真实取舍时提供备选方案;没有实际取舍时不制造方案数量。
### 3. 实施
- 遵循附近文件的结构、命名和语言特性。
- 修改保持在需求涉及的模块内,不顺带重构无关代码。
- 使用结构化 API 处理 JSON、XML、Prefab 和配置,不使用脆弱的字符串替换。
- 修改资源时优先通过 Unity Editor、已有生成器或 MCP 工具,避免无意义的 Prefab 重序列化。
- 不修改任务无关文件,不回退已有工作树变更。
### 4. 生成代码
修改 `Assets/StrayFog/Editor/CopyToX` 下的 `ESF_` 源码后:
1. 通过 Unity 菜单或 MCP 白名单命令执行 CopyToX。
2. 检查 `Assets/Game/GameHFScripte/CopyToHF` 或对应目标目录的生成差异。
3. 确认 `ESF_``HF_` 的类型名、文件名和调用关系转换正确。
4. 编译目标程序集并读取 Unity Console。
出现“HF 已修改但 ESF 未修改”时先判断是否误改生成文件出现“ESF 已修改但 HF 未变化”时,必须补执行 CopyToX。
### 5. 分层验证
| 改动范围 | 最低验证 |
|---|---|
| `Assets/StrayFog/Core` | 构建 `StrayFogCore.csproj`,再检查 Unity Console |
| `Assets/StrayFog/Editor``Assets/Editor` | 构建适用 Editor 程序集或在 Unity 中触发编译,检查 Console 和菜单行为 |
| `GameGeneralScripte` | 构建 `GameGeneral.csproj` |
| `GameMono` | 构建 `SFMono.csproj` |
| `GameHFScripte` | 构建 `GameHF.csproj` |
| Prefab/UI | 刷新资源检查层级、RectTransform、组件启用状态、引用和实际显示 |
| AssetBundle/分包/下载 | 除 Editor 外验证目标平台路径、协程、MD5、失败回退和日志 |
常用命令:
```powershell
dotnet build SFMono.csproj --no-restore -v:minimal
dotnet build GameHF.csproj --no-restore -v:minimal
```
其他程序集按实际改动替换项目文件。构建结果需区分既有警告和本次新增错误。
### 6. Unity 与 MCP 验证
需要 Unity 自动化时:
1. 调用 `unity_health`,确认项目路径和 Unity 版本。
2. 执行白名单菜单、资源刷新、Prefab 生成或导出。
3. 调用 `unity_get_console_logs` 检查新增 Error 和关键 Warning。
4. Prefab/UI 任务继续做结构与实际显示验证,不能以“文件已生成”作为完成条件。
连接失败时停止后续 Unity 命令并报告原因,不假设命令已经执行。
### 7. 文档同步
按 [文档同步规则](50-文档同步规则.md) 判断是否存在长期知识变化:
- 公共接口、架构边界、生成流程、平台行为或稳定使用规则变化时,同步模块文档。
- 局部 Bug 修复、临时日志和实现细节不自动写入长期文档。
- 同一事实只在一个文档完整定义,其他位置链接引用。
### 8. Git
- Git 提交与推送规则见 [项目规则入口](项目规则入口.md)。
- 提交前运行工作流检查、目标测试、`git diff --check` 和提交信息检查。
- 不把两个仓库的改动描述成一个提交,也不夹带任务开始前的无关修改。
## 三、UI 专项流程
1. 先读 [UI 开发指南](../modules/frameworks/UI窗口系统/开发指南.md) 和 [界面拼接](../modules/frameworks/UI窗口系统/界面拼接.md)。
2. 同时检查 Prefab 层级、脚本绑定、模板节点、布局组件和数据刷新时机。
3. 单列列表使用 LoopListView2 接口,多列布局使用 LoopGridView 接口。
4. 列表初始化放在一次性生命周期,数据数量刷新放在窗口打开或数据变化时。
5. 完成后验证空数据、少量数据、超出视口、重复打开和回收重用。
## 四、异步与平台规则
- UnityWebRequest、StreamingAssets、CDN 和 WebGL 等待流程使用协程或回调。
- 不在主线程使用阻塞式 `while`、忙等或同步等待网络结果。
- Editor 可用不代表 Android、iOS、WebGL 或小游戏路径可用;平台路径和存储回调必须分别验证。
- 下载完成计数只在单个文件完整写入并通过校验后推进。
## 五、完成检查
- [ ] 修改了真实源码,没有误改生成文件。
- [ ] 必要生成步骤已经执行并检查差异。
- [ ] 相关程序集编译通过。
- [ ] Unity Console 无本次新增错误。
- [ ] UI/Prefab 或平台行为完成实际验证。
- [ ] 长期文档按影响同步,没有写入流水账。
- [ ] 两个仓库状态分别检查,未触碰用户无关修改。
- [ ] 未经明确要求没有提交或推送。
## 文档关联
| 文档 | 关联原因 |
|---|---|
| [项目规则入口](项目规则入口.md) | 指向本工作流的快速入口 |
| [架构说明](10-架构说明.md) | 源码与生成代码边界 |
| [开发规则](20-开发规则.md) | 实施阶段的代码与 Unity 规范 |
| [文档同步规则](50-文档同步规则.md) | 完成后的长期知识同步 |
| [共享检查](../hooks/Hook共享层.md) | 工作流和提交检查脚本 |

View File

@@ -0,0 +1,59 @@
# 文档同步规则
文档同步的目标是保存长期有效的框架知识,不是记录每次任务过程。
## 必须同步的变化
- 公共 API、参数、返回值或调用顺序变化。
- 框架分层、源码位置、生成目录或依赖方向变化。
- Prefab、资源、配置或构建产物的稳定结构变化。
- Editor 工具、CopyToX、AssetBundle、分包、热更新等生成流程变化。
- 平台路径、下载策略、失败回退或兼容性规则变化。
- 模块新增、删除、重命名、状态或入口变化。
## 通常不写入长期文档
- 不改变公开行为的局部 Bug 修复。
- 临时断点、调试日志、截图和排错过程。
- 一次性测试数据或仅服务当前任务的文件列表。
- 可以直接从代码读出的私有实现细节。
- 尚未确认的讨论结论和未来计划。
## 同步位置
| 变化 | 写入位置 |
|---|---|
| 跨模块规则和工作方式 | `rules/` 中对应唯一规则 |
| 模块职责、架构和数据流 | 模块 `README.md` |
| 业务调用和公共 API | 模块 `使用指南.md` 或开发指南 |
| 模块入口或状态 | `modules/模块索引.md` |
| 外部项目案例 | `business-reference/` 对应项目 |
重大变更的讨论和任务过程文档规则以 [工作流清单](40-工作流清单.md) 为准;实现后的稳定结论直接进入上述长期文档。
## 单一事实来源
- 一个事实只在一个文档完整定义。
- 其他文档只写任务所需的最短摘要并链接到事实来源。
- 修改事实来源后,检查所有引用是否仍然成立;不要复制整段内容同步维护。
- 模块索引只保存入口、职责摘要和状态,不承载完整使用说明。
## 检查方式
任务完成后运行:
```powershell
powershell -NoProfile -ExecutionPolicy Bypass -File hooks/workflow-check.ps1 `
-UnityProjectRoot <Unity工程路径>
```
脚本只输出工作树、源码/生成代码关系、建议验证和可能需要同步的文档,不自动修改文件。最终是否更新文档按本规则判断。
## 文档关联
| 文档 | 关联原因 |
|---|---|
| [项目规则入口](项目规则入口.md) | 引用文档同步原则 |
| [工作流清单](40-工作流清单.md) | 定义同步发生的任务阶段 |
| [模块登记规则](30-模块登记规则.md) | 模块文档结构和状态口径 |
| [共享检查](../hooks/Hook共享层.md) | 提供只读检查脚本 |

View File

@@ -0,0 +1,82 @@
# AI 工具扫描范围
> 本文件定义 AI 工具在正常分析项目时应跳过的目录和文件,以节省 token 并避免误读本地缓存/生成噪音。
>
> Codex 和 Claude Code 均遵循此规则。
>
> 返回主规则索引:[rules/项目规则入口.md](项目规则入口.md)
---
## 通用跳过模式
| 模式 | 原因 |
|------|------|
| `.git/` | Git 版本控制元数据 |
| `.vs/` | Visual Studio 本地缓存 |
| `obj/` | .NET 编译中间输出目录 |
| `bin/` | .NET 编译输出目录 |
| `node_modules/` | Node.js 依赖目录 |
| `*.log` | 运行时日志 |
| `*.tmp` / `*.temp` | 临时文件 |
| `Thumbs.db` / `.DS_Store` | 系统缩略图/缓存 |
## Unity 项目跳过模式
由于 StrayFog 是 Unity 框架,若知识库关联 Unity 工程AI 分析时还应跳过:
| 模式 | 原因 |
|------|------|
| `Library/` | Unity 本地缓存(资源导入、编译缓存、包缓存等),非项目源码 |
| `Temp/` | Unity 运行时临时文件 |
| `Logs/` | Unity 运行时日志 |
| `UserSettings/` | Unity 用户本地偏好设置 |
| `*.csproj` | 由 Unity 自动生成的项目文件 |
| `*.sln` | 由 Unity 自动生成的解决方案文件 |
| `Library/PackageCache/` | Unity Package Manager 缓存的第三方包源码 |
| `HybridCLRData/` | HybridCLR 构建生成输出DLL、桥接文件等 |
## AI 工具本地状态
| 模式 | 原因 |
|------|------|
| `.codex/` | Codex 本地 hooks 状态 |
| `.claude/` | Claude Code 本地命令/技能状态(除 `config` 外) |
## 文档仓库跳过模式
本仓库本身以 Markdown 文档为主,以下文件通常无需 AI 全文读取:
| 模式 | 原因 |
|------|------|
| 图片、音频、视频等二进制资源 | 非文本内容 |
| `.claude/` 中的本地 skill/hook 状态 | 工具私有状态 |
| `__pycache__/` | Python 缓存 |
## 例外情况
当任务明确要求分析**构建问题**或**生成流程问题**时,可以按需读取以下目录中的特定文件:
- `HybridCLRData/` — 检查 HybridCLR 构建输出、DLL 生成结果或 AOT 桥接错误
- `Library/PackageCache/` — 检查特定包的版本或源码(仅限调试包相关问题时)
- `*.csproj` / `*.sln` — 检查项目引用或编译配置问题
> 例外读取后,应在分析结论中说明读取了哪些缓存/生成文件以及原因。
## 相关规则
- [rules/项目规则入口.md](项目规则入口.md) — 项目规则总索引
- [00-项目概览.md](00-项目概览.md) — 项目概览与重要目录说明
- [20-开发规则.md](20-开发规则.md) — 开发规则(含生成文件约束)
---
## 文档关联
> 当本文档发生变更时,应同步检查以下关联文档,避免信息不一致。
| 文档 | 关联原因 |
|---|---|
| [rules/项目规则入口.md](项目规则入口.md) | 项目设置是项目规则入口索引的关键规则 |
| [rules/00-项目概览.md](00-项目概览.md) | 扫描范围中的目录说明与项目概览互相引用 |
| [rules/20-开发规则.md](20-开发规则.md) | 生成文件约束、例外读取与扫描范围互相引用 |

View File

@@ -0,0 +1,64 @@
# UnityAI 项目规则入口
UnityAI 是 StrayFog 框架的通用工作流与知识标准。具体游戏项目负责提供真实代码、资源和验证环境;当前主要验证对象为 `CrystalBattle_Client`
## 快速启动
处理任务时按顺序执行:
1. 读取本文件和 [工作流清单](40-工作流清单.md)。
2. 从 [模块索引](../modules/模块索引.md) 读取相关模块文档。
3. 检查 UnityAI 与目标 Unity 项目的 Git 状态,保留已有修改。
4. 根据 [架构说明](10-架构说明.md) 找到真实源码,区分源码、生成代码、业务代码和资源。
5. 按任务类型分析、修改、生成和验证。
6. 按 [文档同步规则](50-文档同步规则.md) 判断是否需要更新长期文档。
## 工作方式
- **分析检查**读取代码、Prefab、配置或日志给出有证据的结论不修改文件。
- **局部修复**:影响范围明确时直接修复并完成针对性验证。
- **重大变更**:涉及公共接口、框架、生成流程、跨模块数据或批量迁移时,先在对话中确认目标、影响和实现方式,再修改。
- 重大变更的讨论和长期结论保存方式以 [工作流清单](40-工作流清单.md) 为准。
完整步骤与验收条件统一维护在 [工作流清单](40-工作流清单.md),本文件不重复展开。
## 关键约束
以下约束为项目级核心规则的完整定义,其他规则文档只保留链接或一句话摘要。
- 先定位源码再修改,禁止把生成目录当作源码。
- `ESF_` 框架修改发生在 `Assets/StrayFog/Editor/CopyToX`,随后通过 CopyToX 生成 `HF_` 代码。
- 不直接手改 `Assets/Game/GameHFScripte/CopyToHF`
- 业务代码通过项目公开入口使用框架;维护框架时修改真实框架源码。
- Prefab/UI 修改必须同时核对脚本、层级、RectTransform、组件状态和实际显示。
- Unity、平台和网络相关逻辑不能只凭 Editor 编译结果判断正确。
- 只在用户明确要求提交或推送时执行 Git 写操作UnityAI 与游戏项目分别提交。
- 不覆盖、不回退任务开始前已有的修改或未跟踪文件。
## 规则索引
| 文档 | 用途 |
|---|---|
| [项目概览](00-项目概览.md) | UnityAI 定位、目录与读者 |
| [架构说明](10-架构说明.md) | 代码分层、源码边界和依赖方向 |
| [开发规则](20-开发规则.md) | C#、Unity、资源和生成代码规范 |
| [模块登记规则](30-模块登记规则.md) | 模块分类、状态与文档结构 |
| [工作流清单](40-工作流清单.md) | 唯一的任务执行流程 |
| [文档同步规则](50-文档同步规则.md) | 长期文档更新条件和方法 |
| [AI 工具扫描范围](70-AI工具扫描范围.md) | 扫描范围和忽略目录 |
## 知识入口
- [模块索引](../modules/模块索引.md):框架、编辑器工具和使用文档入口。
- [共享检查](../hooks/Hook共享层.md):工作流和提交检查脚本。
- `business-reference/`:外部业务项目案例,只作参考,不作为框架规范。
## 文档关联
| 文档 | 关联原因 |
|---|---|
| [AI 接入入口](../ai/AI接入入口.md) | AI 工具通过该入口进入本规则 |
| [工作流清单](40-工作流清单.md) | 任务执行流程的唯一事实来源 |
| [文档同步规则](50-文档同步规则.md) | 任务完成后的长期知识同步规则 |
| [模块索引](../modules/模块索引.md) | 项目知识入口 |
| [共享检查](../hooks/Hook共享层.md) | 规则的脚本化检查入口 |