This commit is contained in:
2026-04-28 20:25:37 +08:00
parent f0471a4f8d
commit 0f013b6eee
45 changed files with 1117 additions and 1047 deletions

View File

@@ -6,44 +6,36 @@
统一角色属性系统把一个世界中“角色能力如何被理解”收口到 `CustomWorldProfile.attributeSchema.slots`。这六个 slot 是世界级设定,不是单个角色自己的六个字段。
当前结果页世界页可以展示角色维度,但编辑世界信息时只能修改世界名称、概述、基调、目标等文本,尚不能手动修订六个维度本身的信息
当前结果页世界页可以展示角色维度。旧方案曾允许编辑维度定义、正负信号和战斗/社交/探索用途,但这些字段会让创作和提示词下游过早背负规则说明。本轮收缩为只允许修订六个维度名称
## 2. 本次目标
在“编辑世界信息”独立面板中允许用户编辑六个角色维度的信息
在“编辑基本设定”独立面板中允许用户编辑六个角色维度名称
1. 修改 `attributeSchema.slots` 中每个维度的 `name``definition``positiveSignals``negativeSignals``combatUseText``socialUseText``explorationUseText`
1. 修改 `attributeSchema.slots` 中每个维度的 `name`
2. 不在可扮演角色或场景角色编辑器中新增单角色六维数值编辑。
3. 保存时同步更新 `profile.attributeSchema`
4.`profile.ownedSettingLayers.ruleProfile.attributeSchema` 存在,同步写入同一份 schema避免世界档案和设定层出现双源漂移。
5. 前端只负责编辑结构化文本,不新增属性结算逻辑。
5. 前端只负责编辑名称,不新增属性结算逻辑,也不再保存维度说明、正负信号和用途文本
## 3. 交互设计
入口位置:
- 世界页点击“世界概述”里的编辑按钮
- 打开现有“编辑世界信息”面板
- 世界页点击“基本设定”里的编辑按钮
- 打开现有“编辑基本设定”面板
- 在基础世界文本字段下方增加“角色维度”区块
每个维度展示并允许编辑
- 维度名称
- 定义
- 正向信号
- 负向信号
- 战斗体现
- 社交体现
- 探索体现
正向信号与负向信号使用逗号、中文逗号或换行拆分成数组。
每个维度展示并允许编辑“维度名称”。
## 4. 数据落点
保存路径:
- `profile.attributeSchema.slots[n]`
- `profile.ownedSettingLayers.ruleProfile.attributeSchema.slots[n]`,仅当 `ownedSettingLayers` 已存在时同步
- `profile.attributeSchema.slots[n].name`
- `profile.ownedSettingLayers.ruleProfile.attributeSchema.slots[n].name`,仅当 `ownedSettingLayers` 已存在时同步
系统仍保留 `slotId` 作为稳定键,解析旧草稿时会丢弃旧 `definition``positiveSignals``negativeSignals``combatUseText``socialUseText``explorationUseText` 字段。
不修改:
@@ -52,7 +44,7 @@
## 5. 验收
1. 世界信息面板能看到六个角色维度。
2. 修改任一维度名称、定义、信号或三类用途说明后,保存到 `profile.attributeSchema.slots`
1. 基本设定面板能看到六个角色维度名称
2. 修改任一维度名称后,保存到 `profile.attributeSchema.slots`,且不会写回旧说明字段
3. 编辑角色自身时不出现单角色六维数值输入区。
4. UI 仍读取当前世界 schema不回退写死旧四维文案。

View File

@@ -162,3 +162,29 @@
5. `npm run test -- src/services/ai.test.ts src/hooks/rpg-runtime-story/storyRequestCoordinator.test.ts src/hooks/rpg-runtime-story/useRpgRuntimeStoryController.test.tsx`
6. `npm run test -- src/hooks/rpg-runtime-story/sessionActions.test.ts src/hooks/rpg-runtime-story/choiceActions.test.ts src/hooks/rpg-runtime-story/npcEncounterActions.test.ts`
7. `npx eslint src/hooks/rpg-runtime-story/sessionActions.ts src/hooks/rpg-runtime-story/sessionActions.test.ts src/hooks/rpg-runtime-story/useRpgRuntimeNpcInteraction.ts src/hooks/rpg-runtime-story/choiceActions.ts src/hooks/rpg-runtime-story/choiceActions.test.ts --max-warnings 0`
### 4.6 `camp_travel_home_scene` 后端收尾
本轮继续收口完成度核验中最后一个残留点:`camp_travel_home_scene` 不能再被前端 `runCampTravelHomeChoice(...)` 提前拦截并本地拼装正式状态。
落地规则:
1. 前端点击 `camp_travel_home_scene` 后统一进入 `runServerRuntimeChoiceAction(...)`,只提交 `sessionId / clientVersion / functionId / optionText / runtimePayload`
2. `server-rs/crates/api-server/src/runtime_story/compat.rs` 负责解析离营目标场景:
- 优先使用 action payload 中的 `targetSceneId`
- 内置世界按 `playerCharacter.id + worldType` 映射到角色主场景。
- 自定义世界优先找玩家角色在 `landmarks[].sceneNpcIds` 中绑定的地点,否则使用当前营地的 `forwardSceneId / connectedSceneIds` 或第一个 landmark。
3. 后端 resolver 写入完整离营状态:
- `currentScenePreset`
- `currentEncounter / sceneHostileNpcs / npcInteractionActive / inBattle`
- `runtimeStats.scenesTraveled`
- `playerX / playerFacing / animationState / playerActionMode / scrollWorld`
- `lastObserveSigns* / currentBattle* / spar* / activeCombatEffects`
4. 后端在目标场景上生成确定性的 encounter preview内置场景至少带一个可交互 NPC自定义场景复用 `build_custom_scene_preset(...)` 中的 NPC 投影。
5. 后端保存 `storyHistory``currentStory`,随后继续走 `project_story_engine_after_action(...)` 和持久化快照。
6. 前端保留 `camp_travel_home_scene` 作为 function id 与展示用 helper但不再保留正式状态构造函数。
验证新增:
1. 后端 route 测试覆盖 `camp_travel_home_scene` 点击后 hydrated snapshot 已进入角色主场景、生成 encounter preview、递增 `scenesTraveled` 并持久化。
2. 前端 `choiceActions.test.ts` 覆盖 `camp_travel_home_scene` 即使命中旧 helper 判定,也只调用 `runServerRuntimeChoiceAction(...)`

View File

@@ -7,7 +7,7 @@ RPG Agent 生成世界草稿时,前端会把 `draftProfile` 归一化成 `Cust
## 落地约束
- `draftProfile.attributeSchema` 是世界草稿真相源的一部分,必须随 foundation draft 一起生成并保存。
- 六维固定使用 `axis_a``axis_f` 六个槽位,但 `schemaName`每个槽位 `name` 和说明必须贴合本次世界设定
- 六维固定使用 `axis_a``axis_f` 六个系统槽位,但创作、提示词输出、解析后保存的数据只保留每个槽位 `name``slotId` 由系统补齐用于数值映射,不要求模型理解或生成额外说明字段
- 维度名不得沿用通用旧词:生命、法力、护甲、攻击、防御、力量、敏捷、智力、精神。
- 若模型遗漏或结构不合规,后端必须生成中文兜底属性体系,不能让前端只靠固定模板补齐。
- 世界页面的“世界”页签必须展示当前 `attributeSchema.slots` 的六个名称,作为玩家进入世界前可见的规则信号。
@@ -25,7 +25,7 @@ RPG Agent 生成世界草稿时,前端会把 `draftProfile` 归一化成 `Cust
3. `server-rs/crates/api-server/src/custom_world_foundation_draft.rs`
- `normalize_framework_shape()` 归一化 `attributeSchema`
- `build_foundation_draft_profile_from_framework()` 将归一化后的 `attributeSchema` 写入 `draftProfile`
- 新增兜底生成器,基于世界名、基调、目标、冲突和种子文本生成六个中文维度。
- 新增兜底生成器,基于世界名、基调、目标、冲突和种子文本生成六个中文维度名称
4. `src/components/CustomWorldEntityCatalog.tsx`
- 在世界页签增加“角色维度”区域,直接渲染 `profile.attributeSchema.slots` 的六个名称。
@@ -33,5 +33,5 @@ RPG Agent 生成世界草稿时,前端会把 `draftProfile` 归一化成 `Cust
## 验收
- 新生成的 RPG 世界草稿 JSON 顶层包含 `attributeSchema.slots.length === 6`
- 结果页/世界页展示六个自定义维度名,而非固定的力量、敏捷、智力、精神。
- 结果页/世界页展示六个自定义维度名,而非固定的力量、敏捷、智力、精神;页面不展示维度说明、正负信号或用途说明
- 缺失或非法模型输出会被后端兜底为合法中文六维。