# 策划工具系统 (Design Tools) - AI Skill 文档

## 概述

策划工具系统是基于Unity Editor的配置数据管理工具集，主要用于编辑xlsx配置表数据，并与美术资源（ArtTableSO）联动显示预览。所有工具通过Unity菜单栏「策划工具」菜单访问。

---

## 项目结构

### 代码目录
```
Assets/Design_SubModule/Scripts/Editor/Design_Tools/
├── BaseDesignToolEditor.cs          # 编辑器基类（Git管理、路径管理、UI框架）
├── ItemConfigEditor.cs              # 道具配置编辑器 (Item.xlsx)
├── Common/
│   └── DesignToolItemPickerWindow.cs # 通用道具选择弹窗（搜索+分页+筛选）
├── Collections/
│   ├── HeadFrameConfigEditor.cs     # 头像框配置 (Avatar.xlsx)
│   ├── HeadConfigEditor.cs          # 头像配置 (Face.xlsx)
│   └── EmojiConfigEditor.cs         # 表情配置 (Emoji.xlsx)
├── DesignSoundEditorWindow/
│   ├── AmbientSoundConfigEditor.cs  # 环境音配置 (Sound.xlsx - AmbientSound)
│   └── SoundItemConfigEditor.cs     # 音效配置 (Sound.xlsx - Sound)
├── Friends/
│   ├── FriendTreasureChestEditor.cs # 宝箱奖励及概率 (FriendTreasure.xlsx - Chest)
│   └── InviteRewardEditor.cs        # 邀请奖励 (Invite.xlsx - Reward)
├── LimitedTimeEvent/
│   └── CatTrickConstEditor.cs       # 小猫戏法常量 (LimitedTimeEvent.xlsx - Const)
└── Scene/
    ├── DecorateCostPlannerEditor.cs  # 装饰消耗规划 (DecorateCost.xlsx)
    ├── IndoorProgressEditor.cs       # 场景进度奖励 (IndoorProgress.xlsx + Item.xlsx)
    └── MaxAreaIdEditor.cs            # 最大场景ID (Constant.xlsx - ConstantInt)
```

### 菜单路径
| 菜单路径 | 编辑器类 | 操作的xlsx文件 |
|---------|---------|--------------|
| 策划工具/Item配置 | ItemConfigEditor | Item.xlsx (Sheet: Item) |
| 策划工具/收藏品/头像框 | HeadFrameConfigEditor | Avatar.xlsx (Sheet: Avatar) |
| 策划工具/收藏品/头像 | HeadConfigEditor | Face.xlsx (Sheet: Face) |
| 策划工具/收藏品/表情 | EmojiConfigEditor | Emoji.xlsx (Sheet: Emoji) |
| 策划工具/好友/好友馈赠/宝箱奖励及概率 | FriendTreasureChestEditor | FriendTreasure.xlsx (Sheet: Chest) |
| 策划工具/好友/邀请奖励 | InviteRewardEditor | Invite.xlsx (Sheet: Reward) |
| 策划工具/限时活动/小猫戏法常量 | CatTrickConstEditor | LimitedTimeEvent.xlsx (Sheet: Const) |
| 策划工具/场景/装饰消耗规划 | DecorateCostPlannerEditor | DecorateCost.xlsx (Sheet: DecorateCost) |
| 策划工具/场景/场景进度奖励 | IndoorProgressEditor | IndoorProgress.xlsx + Item.xlsx |
| 策划工具/场景/最大场景ID | MaxAreaIdEditor | Constant.xlsx (Sheet: ConstantInt) |
| 策划工具/音效配置/环境音 | AmbientSoundConfigEditor | Sound.xlsx (Sheet: AmbientSound + Sound) |
| 策划工具/音效配置/音效 | SoundItemConfigEditor | Sound.xlsx (Sheet: Sound) |

---

## Excel 表格约定

### 通用格式规则
- **第1行**：Key行（列名/字段名，如 Id, Name, IType, Res 等）
- **第2行**：备注行（中文说明，程序不读取）
- **第3行起**：实际数据行

### 数据起始行常量
所有编辑器中 `DATA_START_ROW = 3`（即从第3行开始读写数据）。

### xlsx文件位置
所有xlsx文件存放在Docs项目（外部Git仓库）的 `config/` 目录下。

### 主要xlsx结构

#### Item.xlsx (Sheet: Item)
| 列名 | 类型 | 说明 |
|------|------|------|
| Id | int | 道具唯一ID |
| Name | string | 道具名称 |
| IType | int | 道具类型（见IType类型表） |
| Effect | string | 效果数据（格式因IType而异） |
| Res | string | 美术资源引用，格式: `"TableName,ItemName"` → 对应ArtTableSO的TableName和ArtItemData的Name |

#### IndoorProgress.xlsx (Sheet: IndoorProgress)
| 列名 | 类型 | 说明 |
|------|------|------|
| Id | int | 唯一ID |
| Scene | int | 场景编号 |
| Lv | int | 等级/步骤 |
| Item | string | 道具奖励JSON: `[{"Id":83,"Num":1}]` |
| Emit | string | 发射的道具ID: `83` |
| Reward | string | 奖励: `83=1` |
| BigReward | string | 大奖励: `Energy=25` 或 `Energy=50,PurplePig=1` |
| AreaReward | string | 区域奖励JSON: `[{"Id":100001,"Num":25}]` |
| Part | int | 零件数量 |

#### FriendTreasure.xlsx (Sheet: Chest)
| 列名 | 类型 | 说明 |
|------|------|------|
| 第1列 | int | Id |
| 第2列 | string | Items JSON: `[{"Id":83,"Num":1}]` |
| 第3列 | int | Prob 概率（总和=1000，即千分之） |

#### Avatar.xlsx (Sheet: Avatar)
| 列名 | 类型 | 说明 |
|------|------|------|
| Id | int | 头像框ID |
| NameKey | string | 多语言key |
| Init | int | 是否初始拥有 (0/1) |
| Icon | int | 图标资源ID（对应HeadFrameResource SO中的ArtItemData.Id） |
| FrameImageScale | float | 缩放比例 |

#### Face.xlsx (Sheet: Face)
| 列名 | 类型 | 说明 |
|------|------|------|
| Id | int | 头像ID |
| NameKey | string | 多语言key |
| Init | int | 是否初始拥有 |
| Icon | int | 图标资源ID（对应HeadResource SO中的ArtItemData.Id） |

#### Emoji.xlsx (Sheet: Emoji)
类似Face.xlsx结构，Icon对应EmojiResource SO。

---

## IType 道具类型表

| IType | 名称 | 说明 |
|-------|------|------|
| 1 | 能量 | Energy |
| 2 | 星星 | Star |
| 3 | 钻石 | Diamond |
| 97 | Playroom宠物道具 | |
| 98 | 卡牌 | |
| 99 | 背包道具 | |
| 100 | 棋子 | 数量最多的类型 |
| 101 | 卡包 | |
| 102 | 限时事件 | Effect格式: `eventId,seconds` |
| 103 | 小猪存钱罐 | |
| 104 | 万能卡 | |
| 105 | 头像框 | Effect关联Avatar.xlsx |
| 106 | 活动代币 | |
| 107 | 竞赛游戏代币 | |
| 108 | Pet Playroom拜访道具 | |
| 109 | 表情 | Effect关联Emoji.xlsx |
| 110 | 头像 | Effect关联Face.xlsx |
| 111 | Playroom装饰 | |
| 112 | Playroom服装 | |
| 113 | Playroom装饰套装 | |
| 114 | Playroom服装套装 | |
| 115 | Playroom道具宝箱 | |
| 116 | 活动通行证代币道具 | |

---

## 美术资源系统 (Art Resource)

### 核心类

#### ArtTableSO (ScriptableObject)
```
路径: Assets/Art_SubModule/Art_Scripts/ArtTableSO.cs
```
| 字段 | 类型 | 说明 |
|------|------|------|
| TableId | int | 表ID（全局唯一，系统自动分配） |
| TableName | string | 表名称（全局唯一标识符，如 "HeadFrameResource"） |
| Items | List\<ArtItemData\> | 资源项列表 |

#### ArtItemData (Serializable)
```
路径: Assets/Art_SubModule/Art_Scripts/ArtItemData.cs
```
| 字段 | 类型 | 说明 |
|------|------|------|
| Id | int | 资源ID（表内唯一） |
| Name | string | 资源名称（唯一，用于查询） |
| Desc | string | 资源描述 |
| Sprite | Sprite | 图片资源引用（Editor模式） |
| SpritePath | string | 图片资源路径（Runtime模式） |
| SpineAsset | SkeletonDataAsset | Spine骨骼资源（Editor模式） |
| SpineAssetPath | string | Spine资源路径（Runtime模式） |
| SpineAnimName | string | Spine动画名称 |

### Art_SO 目录结构
```
Assets/Art_SubModule/Art_SO/
├── art_table_manifest.json         # 资源表全局配置清单
├── Collections/                    # 收藏品资源
│   ├── EmojiResource.asset         # 表情（TableName="EmojiResource"）
│   ├── HeadFrameResource.asset     # 头像框（TableName="HeadFrameResource"）
│   └── HeadResource.asset          # 头像（TableName="HeadResource"）
├── DecorateIcon/                   # 装饰图标资源（按场景区间分组）
│   ├── DecorateIconResource_1_8.asset
│   ├── DecorateIconResource_9_17.asset
│   └── ...（共9个按区间的资源）
├── DecorateScene/                  # 装饰场景资源
│   └── Scene1Resource.asset ~ Scene55Resource.asset
├── Scene/
│   └── SceneExpression.asset
└── Shop/
    ├── ShopBig.asset
    └── ShopOther.asset
```

### Res字段格式
Item.xlsx中的Res字段格式为 `"TableName,ItemName"`：
- `TableName` → 对应 ArtTableSO.TableName（全局唯一标识符）
- `ItemName` → 对应 ArtItemData.Name（表内唯一名称）
- 例如: `"HeadFrameResource,frame_001"` 表示 TableName="HeadFrameResource" 的 ArtTableSO 中 Name="frame_001" 的 ArtItemData
- 仅选了表但未选Item时: `"HeadFrameResource,"`（逗号后为空）

> **历史格式**: 旧版本使用 `"TableId,ItemId"`（数字格式如 `"3,15"`）。ItemConfigEditor中提供了「迁移Res格式(ID→Name)」按钮，可一键将旧格式转换为新格式。

### 资源查找流程
```
Res = "TableName,ItemName"
  → 找到 ArtTableSO (where TableName == TableName)
  → 在 Items 列表中找到 ArtItemData (where Name == ItemName)
  → 获取 Sprite / SpinePath 等资源
```

ItemConfigEditor中的DrawResField使用三级选择UI：
1. **组(Folder)** → Art_SO下的子文件夹（Collections/DecorateIcon等）
2. **表(Table)** → 该文件夹下的ArtTableSO
3. **Item** → 该表中的ArtItemData

---

## 基类架构 (BaseDesignToolEditor)

### 继承关系
```
EditorWindow
├── BaseDesignToolEditor (抽象基类)
│   ├── FriendTreasureChestEditor
│   ├── InviteRewardEditor
│   ├── CatTrickConstEditor
│   ├── AmbientSoundConfigEditor
│   ├── SoundItemConfigEditor
│   ├── DecorateCostPlannerEditor
│   └── MaxAreaIdEditor
│
├── ItemConfigEditor (独立，未继承基类)
├── HeadFrameConfigEditor (独立)
├── HeadConfigEditor (独立)
├── EmojiConfigEditor (独立)
└── IndoorProgressEditor (独立)
```

### 基类提供的能力
- `docsRootPath` 管理和EditorPrefs持久化
- `LoadData()` 统一加载流程：路径校验 → Git检查/更新 → 分支检查 → 子类LoadConfigData()
- `ExecuteGitCommand()` Git命令执行
- `CheckAndUpdateDocsRepository()` Docs仓库fetch/pull/冲突检测
- `CheckAndSwitchDesignSubModuleBranch()` Design_SubModule分支切换
- 统一UI框架：工具栏、路径选择、加载按钮、底部保存/重载按钮
- `GetDocsConfigFilePath(fileName)` 拼接Docs配置文件路径

### 子类必须实现的抽象方法
- `GetDocsPathPrefKey()` - 返回唯一的EditorPrefs key
- `GetWindowTitle()` - 窗口标题
- `LoadConfigData()` - 具体的数据加载逻辑
- `DrawDataEditor()` - 具体的UI绘制逻辑

### 子类可选覆盖的虚方法
- `GetMinWindowSize()` - 窗口最小尺寸（默认1000x600）
- `NeedCheckDesignSubModuleBranch()` - 是否检查分支（默认true）
- `SaveDataToExcel()` - 保存到Excel
- `ShowBottomButtons()` - 是否显示底部按钮（默认true）

---

## 通用组件

### DesignToolItemPickerWindow（道具选择弹窗）
```
路径: Common/DesignToolItemPickerWindow.cs
```
**功能**：弹出模态窗口，供用户在大量道具中快速查找并选择  
**使用方式**：
```csharp
DesignToolItemPickerWindow.ShowWindow(
    items,          // List<DesignToolItemPickerItem> 所有道具
    itemTypes,      // List<int> 所有IType列表
    typeNames,      // Dictionary<int,string> IType名称映射
    currentType,    // 当前筛选的IType
    selectedItemId, // 当前选中的ItemId
    ownerRect,      // 父窗口位置（弹窗居中用）
    onSelected      // Action<int> 选中回调，返回ItemId
);
```
**UI特性**：搜索框（按ID/Name匹配）、IType下拉筛选、分页（每页20条）、当前选中高亮

**使用者**：FriendTreasureChestEditor、IndoorProgressEditor（道具奖励和区域奖励均使用）

---

## 多语言支持

加载 `AllLanguage.xlsx` (Sheet: client)：
- 第1行: key行（key, zh_CN, en_US, pt_BR...）
- 第2行: 备注行
- 第3行起: 数据行
- 用于Collections编辑器中显示名称tooltip

---

## Git工作流

所有工具在加载数据前会：
1. 检查Docs目录是否为Git仓库（.git目录存在）
2. `git fetch` 检查远程更新
3. `git status -uno` 检查本地状态
4. 如有远程更新则 `git pull`
5. 检查Design_SubModule当前分支，必要时 `checkout main`

保存后会提醒用户手动commit和push。

---

## 关键数据格式

| 格式名 | 示例 | 使用场景 |
|--------|------|---------|
| Item JSON | `[{"Id":83,"Num":1}]` | IndoorProgress.Item / FriendTreasure.Items |
| 多Item JSON | `[{"Id":100001,"Num":50},{"Id":100021,"Num":1}]` | IndoorProgress.AreaReward |
| Reward字符串 | `83=1` | IndoorProgress.Reward |
| BigReward字符串 | `Energy=25,PurplePig=1` | IndoorProgress.BigReward（使用MY_ITEM_DICT映射名称） |
| Res引用 | `"TableName,ItemName"` 如 `"HeadFrameResource,frame_001"` | Item.xlsx.Res字段 |
| Effect引用 | `"id,param"` 如 `"5,0"` | Item.xlsx.Effect字段（收藏品/限时事件） |
| 限时事件 | `"eventId,seconds"` | IType=102的Effect |
