This commit is contained in:
@@ -0,0 +1,154 @@
|
||||
# M4 成长与 quest/combat 联动设计(2026-04-21)
|
||||
|
||||
更新时间:`2026-04-21`
|
||||
|
||||
## 0. 文档目标
|
||||
|
||||
本文件只冻结一件事:
|
||||
|
||||
**把 `player_progression / chapter_progression` 从“可单独调用的成长基座”推进到“任务交付与战斗胜利可自动写入的最小联动闭环”。**
|
||||
|
||||
本轮只落 `turn_in_quest` 和 `resolve_combat_action(Victory)` 两条经验链,不扩到完整章节蓝图 Rust 化、掉落分配、好感奖励或前端展示切换。
|
||||
|
||||
---
|
||||
|
||||
## 1. 本轮联动范围
|
||||
|
||||
本轮只接下面两条确定链路:
|
||||
|
||||
1. `turn_in_quest` 成功后,把 `quest_record.reward.experience` 发放到 `player_progression`。
|
||||
2. `resolve_combat_action` 结算为 `Victory` 后,把 `battle_state.experience_reward` 发放到 `player_progression`。
|
||||
|
||||
补充规则:
|
||||
|
||||
1. 若存在 `chapter_id`,同时尝试把经验记到 `chapter_progression` 账本。
|
||||
2. 若对应 `chapter_progression` 不存在,联动必须静默跳过,不能让任务交付或战斗结算失败。
|
||||
3. `SparComplete`、`Escaped`、`Ongoing` 都不发经验。
|
||||
|
||||
---
|
||||
|
||||
## 2. `turn_in_quest` 联动口径
|
||||
|
||||
### 2.1 经验来源
|
||||
|
||||
任务交付经验固定读取:
|
||||
|
||||
1. `quest_record.reward.experience.unwrap_or(0)`
|
||||
|
||||
### 2.2 成长写入
|
||||
|
||||
当经验值 `> 0` 时,`spacetime-module::turn_in_quest` 需要在任务状态切换为 `TurnedIn` 后调用:
|
||||
|
||||
1. `upsert_player_progression_after_grant_tx`
|
||||
|
||||
写入参数固定为:
|
||||
|
||||
1. `user_id = next.actor_user_id`
|
||||
2. `amount = reward_experience`
|
||||
3. `source = PlayerProgressionGrantSource::Quest`
|
||||
4. `updated_at_micros = next.updated_at_micros`
|
||||
|
||||
### 2.3 章节账本写入
|
||||
|
||||
若 `next.chapter_id` 存在,则在成长写入后继续尝试调用章节账本 helper:
|
||||
|
||||
1. `granted_quest_xp = reward_experience`
|
||||
2. `granted_hostile_xp = 0`
|
||||
3. `hostile_defeat_increment = 0`
|
||||
4. `level_at_exit = Some(updated_player.level)`
|
||||
|
||||
若章节记录不存在:
|
||||
|
||||
1. 静默跳过
|
||||
2. 保留任务交付成功
|
||||
3. 不把“章节计划尚未初始化”视为任务错误
|
||||
|
||||
---
|
||||
|
||||
## 3. `resolve_combat_action` 联动口径
|
||||
|
||||
### 3.1 battle_state 新增字段
|
||||
|
||||
为避免在 reducer 里临时反查外部上下文,本轮给 `BattleStateInput / BattleStateSnapshot / battle_state` 表补两个最小字段:
|
||||
|
||||
1. `chapter_id: Option<String>`
|
||||
2. `experience_reward: u32`
|
||||
|
||||
设计意图:
|
||||
|
||||
1. `chapter_id` 决定战斗胜利时是否记章节账本。
|
||||
2. `experience_reward` 作为已编译好的确定奖励,避免本轮就把章节蓝图和敌对档位计算重新耦回 battle reducer。
|
||||
|
||||
### 3.2 胜利经验发放
|
||||
|
||||
当 `resolve_combat_action` 返回:
|
||||
|
||||
1. `CombatOutcome::Victory`
|
||||
|
||||
则 `spacetime-module` 需要继续执行:
|
||||
|
||||
1. `upsert_player_progression_after_grant_tx`
|
||||
|
||||
写入参数固定为:
|
||||
|
||||
1. `user_id = result.snapshot.actor_user_id`
|
||||
2. `amount = result.snapshot.experience_reward`
|
||||
3. `source = PlayerProgressionGrantSource::HostileNpc`
|
||||
4. `updated_at_micros = result.snapshot.updated_at_micros`
|
||||
|
||||
补充规则:
|
||||
|
||||
1. 只有 `experience_reward > 0` 时才真正写成长表。
|
||||
2. `SparComplete` 不发经验,因为切磋不算敌对击杀。
|
||||
|
||||
### 3.3 章节账本写入
|
||||
|
||||
若 `result.snapshot.chapter_id` 存在,且本次为 `Victory`,则继续尝试:
|
||||
|
||||
1. `granted_quest_xp = 0`
|
||||
2. `granted_hostile_xp = experience_reward`
|
||||
3. `hostile_defeat_increment = 1`
|
||||
4. `level_at_exit = Some(updated_player.level)`
|
||||
|
||||
同样地,若章节记录不存在:
|
||||
|
||||
1. 静默跳过
|
||||
2. 仍保留 battle_state 的正常收束结果
|
||||
|
||||
---
|
||||
|
||||
## 4. reducer 分层约束
|
||||
|
||||
本轮保持以下分层不变:
|
||||
|
||||
1. `module-combat` 仍只承接纯战斗状态推进,不直接依赖 `module-progression`。
|
||||
2. `module-quest` 仍只承接纯任务状态流转,不直接依赖 `module-progression`。
|
||||
3. 真正的跨域写入统一放在 `crates/spacetime-module` reducer / transaction helper 中完成。
|
||||
|
||||
这样做的原因是:
|
||||
|
||||
1. 领域 crate 保持纯规则,便于后续单测和重用。
|
||||
2. SpacetimeDB 事务内的表写顺序集中在同一层,避免跨 crate 重复持久化策略。
|
||||
|
||||
---
|
||||
|
||||
## 5. 本轮明确不做
|
||||
|
||||
本轮明确不扩到以下内容:
|
||||
|
||||
1. 还不把 battle reward 在 reducer 内现场计算为经验值。
|
||||
2. 还不把 `quest` 奖励里的物品、货币、好感奖励统一并入同一事务。
|
||||
3. 还不把 `quest signal` 自动从战斗/剧情全量分发到任务系统。
|
||||
4. 还不把 `chapter_progression` 缺失时自动补建计划记录。
|
||||
|
||||
---
|
||||
|
||||
## 6. 验证要求
|
||||
|
||||
本轮变更完成后,至少执行:
|
||||
|
||||
1. `npm run check:encoding`
|
||||
2. `cargo test -p module-combat`
|
||||
3. `cargo test -p module-progression`
|
||||
4. `cargo test -p module-quest`
|
||||
5. `cargo check -p spacetime-module`
|
||||
Reference in New Issue
Block a user