# 实体生成准入规范(Map / Object / Character Manifest Spec)

> 状态:v1 · 这是 map/object/character **扩展与素材生成的统一契约**。新增任何实体 = 写一份过"准入校验"的 manifest。
> 一份 manifest 同时喂养两条线:**仿真侧**(`sim` 字段 → Persona/Place/WorldObject)与**素材侧**(`art` 段 → PixelLab 生成精灵图)。

## 1. 为什么要这份规范

map/object/agent 要能热扩展、能批量生成素材,就必须有**单一事实来源**。否则仿真配置和美术资源各搞一套,扩展时必乱。本规范把两者绑成一份声明式 YAML,且**先过校验才能进世界(准入)**。

## 2. 目录约定

```
worlds/<世界名>/
  characters/*.yaml    # 角色
  objects/*.yaml       # 物体
  places/*.yaml        # 地点
assets/sprites/        # 素材线生成的精灵图(按 id 命名),生成后回填到 manifest.art.sprite_path
```
`WorldBuilder.from_directory(worlds/<世界名>)` 递归加载全部 manifest,校验后一键建世界。

## 3. 通用结构

```yaml
kind: character | object | place   # 必填,决定类型
id: <英文 slug>                     # 必填,稳定唯一,用于跨实体引用 + 素材文件名
# ... sim 字段(因 kind 而异)...
art:                               # 可选,缺省则不生成素材(纯逻辑实体)
  description: <英文 prompt>        # 有 art 时必填
  ...
```
**id vs name**:`id` 是英文 slug(引用与素材命名用);`name` 是中文显示名(进 LLM prompt、世界里展示)。引用一律用 id。

## 4. 三类实体字段

### 4.1 character(角色)
| 字段 | 必填 | 说明 |
|---|---|---|
| id / name | ✓ | slug / 中文名(**姓名须全局唯一**,用作 agent 标识) |
| age | ✓ | 0–130 |
| mbti | ✓ | 合法 16 型(校验) |
| occupation | ✓ | 职业,决定挂载的工具集(`default_toolset`) |
| start_location | ✓ | 出生地的 place **id** |
| gender / backstory / hobbies / relationships | | 人设补充;relationships 是 `{对方名: 关系}` |
| art | | 见 §5(角色额外需 directions/animations) |

→ 转 `Persona`(L0 人设层)。

### 4.2 object(物体)
| 字段 | 必填 | 说明 |
|---|---|---|
| id / name | ✓ | slug / 中文名 |
| affordances | | 可供性列表(能对它做什么,如 `[做咖啡]`),进 agent 感知 |
| art | | 见 §5 |

→ 转 `WorldObject`。

### 4.3 place(地点)
| 字段 | 必填 | 说明 |
|---|---|---|
| id / name | ✓ | slug / 中文名 |
| description | | 场景描述 |
| geography | ✓ | 枚举:`town/city/village/seaside/snow_mountain/forest/plaza/indoor` |
| objects | | 该地点的物体 **id** 列表(须存在) |
| adjacent | | 可直达地点的 **id** 列表(须存在) |
| art | | tileset 描述 |

→ 转 `Place`(World 层)。

## 5. art 段(素材生成规格 → PixelLab)
| 字段 | 必填 | 默认 | 说明 |
|---|---|---|---|
| description | ✓ | — | 英文 prompt |
| size | | 64 | 像素尺寸,>0 |
| view | | side | `side / low top-down / high top-down` |
| directions | 角色✓ | 4 | 仅角色:行走方向数 `4/8` |
| animations | 角色 | [idle] | 仅角色:`idle/walk/run/sit/talk/work` 子集 |
| sprite_path | | — | 生成后由素材线回填 |

## 6. 准入校验规则(过不了不进世界)
1. **结构**:kind 合法;无未知字段;必填字段齐全。
2. **取值**:MBTI 合法、age 合理、geography ∈ 枚举、view ∈ 枚举、角色 directions ∈ {4,8}、animations ⊆ 允许集、art.description 非空。
3. **跨引用**(`WorldBuilder.validate_refs`):place.objects / place.adjacent / character.start_location 指向的 id 都必须存在;角色姓名全局唯一。

校验失败抛 `ManifestError`,信息含实体 id 与原因。

## 7. 扩展点
- **新职业**:在 `tools/registry.py` 的 `OCCUPATION_TOOLS` 登记职业→工具,角色 manifest 写该 occupation 即自动挂载。
- **新地理/视角/动画**:在 `manifest/schema.py` 的 `GEOGRAPHIES/VIEWS/ANIMATIONS` 集合登记。
- **新世界**:新建 `worlds/<名>/` 目录放 manifest 即可。

## 8. 示例
见 `worlds/smalltown/`(咖啡馆三人场景:林朵/老王/张三 + 咖啡机/钢琴 + 咖啡馆/广场),`WorldBuilder.from_directory` 可一键复现。
