# Lucky Dice 核心流程架构蓝图 ## 文档信息 - 来源 PRD:[lucky-dice-core-flow-prd.md](../PRD/lucky-dice-core-flow-prd.md) - 关联需求:[lucky-dice-core-flow-requirements.md](../Requirements/lucky-dice-core-flow-requirements.md) - 关联规格:[lucky-dice-core-flow-spec.md](../Specs/lucky-dice-core-flow-spec.md) - 适用项目:FishDice Unity 项目 - Unity 版本:2022.3.62f2c1 - 生成日期:2026-06-22 本文档定义 Lucky Dice 第一版核心闭环的架构蓝图。它不替代需求或接口规格,而是回答后续实现时最容易失控的几个问题: - 普通 Roll、组合规则、Lucky Dice、目标玩法入口之间怎么分层。 - 哪些模块可以通过配置扩展,哪些模块才需要新增代码。 - 数据从玩家 Roll 到最终玩法模式如何流动。 - 追踪、兜底、测试和 Unity 落地目录应如何组织。 当前项目尚未落地生产 C# 玩法模块,因此本文档描述的是第一版建议架构,而不是对现有代码的复盘。 ## 架构定位 Lucky Dice 不是普通骰子的二次 Roll,也不是一个独立短玩法本体。它在架构中承担的是“特殊玩法入口选择器”职责: ```text 普通 Roll 负责产出组合事实 组合规则负责决定业务行为 Lucky Dice 负责从特殊结果池中选择目标入口 目标玩法模块负责执行 Slap Down / Treasure Heist 等具体内容 ``` 第一版架构应优先保证三件事: 1. **可扩展**:新增组合、骰子数量、特殊结果、目标玩法模式时优先改配置。 2. **可测试**:组合事实、规则匹配、筛选、权重随机都能用确定性输入测试。 3. **可追踪**:一次 Roll 的所有关键决策能用同一个 `RollSessionId` 串起来。 ## 架构原则 ### 两套骰子集合隔离 普通骰子集合只表达主循环 Roll 的结果,例如 `2 / 3 / 4 / 5 / 6 / clover`。Lucky Dice 特殊结果集合只表达后续玩法入口,例如 `rocket / thief`。 两者不能混用同一套裸字符串,也不能让普通组合匹配器直接处理 Lucky Dice 特殊结果。 ### 规则匹配先于行为执行 普通 Roll 结果必须先转换成结构化 `ComboFacts`,再交给规则匹配器。业务行为不应读取“左骰 / 右骰”这类固定位置状态。 ```text DiceRollResult → ComboFacts → ComboRule → RollActionSpec → IRollActionExecutor ``` ### 配置增长优先于代码增长 组合数量增加时,应增加 `ComboRule` 配置。只有出现新的通用匹配能力时才新增 matcher,只有出现新的通用业务行为时才新增 executor。 禁止形成下面这种随组合数量膨胀的结构: ```text clover_clover -> TriggerLuckyDice() 2_clover -> GrantCloverReward() 3_clover -> GrantCloverReward3() ... ``` ### 流程服务不依赖表现层 核心流程可以产出展示所需数据,例如 Lucky Dice 标题、倍率、结果槽和目标玩法反馈,但不能依赖 UI 动画完成时序来做核心决策。 第一版表现层只消费核心结果,不参与筛选、随机和模式解析。 ## 总览图 ```mermaid flowchart TD Player["玩家触发 Roll"] --> RollService["DiceRollService"] RollService --> FactBuilder["ComboFactBuilder"] FactBuilder --> RuleMatcher["ComboRuleMatcher"] RuleMatcher --> ActionDispatcher["RollActionDispatcher"] ActionDispatcher --> Reward["RewardExecutor"] ActionDispatcher --> Multiplier["MultiplierExecutor"] ActionDispatcher --> LuckyTrigger["TriggerLuckyDiceExecutor"] LuckyTrigger --> LuckyFlow["LuckyDiceFlowService"] LuckyFlow --> CandidateFilters["CandidateFilters"] CandidateFilters --> WeightedPicker["WeightedPicker"] WeightedPicker --> SlotBuilder["ResultSlotBuilder"] SlotBuilder --> ModeResolver["TargetModeResolver"] ModeResolver --> Launcher["TargetModeLauncher"] Launcher --> TargetGameplay["Slap Down / Treasure Heist"] TargetGameplay --> MainLoop["回到主循环"] RollService -.-> Trace["RollTrace"] RuleMatcher -.-> Trace ActionDispatcher -.-> Trace LuckyFlow -.-> Trace ModeResolver -.-> Trace ``` ## 分层架构 | 层级 | 主要职责 | 允许依赖 | 禁止依赖 | | --- | --- | --- | --- | | 配置层 | 提供骰子集合、规则、候选结果、目标模式映射 | Unity 资源、本地 JSON、静态配置 | UI 动画状态、运行时随机结果 | | Roll 层 | 根据 DiceSet 生成普通骰子结果 | 配置层、随机源 | 规则、奖励、玩法入口 | | 组合事实层 | 把普通 Roll 结果转为统计事实 | Roll 层数据 | Lucky Dice 特殊结果、UI | | 规则匹配层 | 按 matcher 和优先级命中规则 | 组合事实、规则配置 | 行为执行器、目标玩法 | | 行为执行层 | 按 action type 分发通用行为 | 规则结果、上下文服务 | 组合 key 到独立方法映射 | | Lucky Dice 层 | 候选池、筛选、权重随机、结果槽 | 候选配置、上下文、随机源 | 普通组合 matcher | | 模式解析层 | `ResultKey -> TargetKey -> ModeKey` | Lucky Dice 结果、上下文、模式配置 | 短玩法内部实现 | | 表现层 | 展示 Lucky Dice 标题、倍率、结果槽、跳转反馈 | 核心流程产物 | 核心规则决策 | | 目标玩法层 | 执行 Slap Down / Treasure Heist 等玩法 | TargetModeEntry | Lucky Dice 随机细节 | | 追踪层 | 汇总关键决策链路 | 所有核心层事件 | 改变玩法结果 | 依赖方向应从上游输入流向下游结果。追踪层可以被各层写入,但不应反向影响流程决策。 ## 组件职责 ### DiceSetConfigProvider 负责提供骰子集合配置,包括普通骰子面、普通骰子数量、Lucky Dice 特殊结果面、默认结果槽数量。 第一版可以使用 ScriptableObject、JSON 或硬编码本地配置启动,但调用方必须只通过 provider 读取,不把 `2` 颗骰子或 `3` 个结果槽写死到流程逻辑中。 ### DiceRollService 负责按骰子集合配置生成 Roll 结果。普通 Roll 会产出多个普通骰子面;Lucky Dice 第一版不需要真的 Roll 三颗特殊骰,而是由候选选择结果再生成展示槽。 该服务只负责“随机出可见骰子面”,不负责奖励、倍率或玩法入口。 ### ComboFactBuilder 负责把普通 Roll 结果转成 `ComboFacts`: - 原始面列表 - 面数量统计 - 数字列表 - 点数和 - Clover 数量 - 无序归一化 key - 有序 key 它必须支持 N 颗骰子。`2 + clover` 与 `clover + 2` 的无序 key 必须一致。 ### ComboRuleMatcher 负责把 `ComboFacts` 与规则配置匹配。matcher 按类型注册,例如 `ExactCombo`、`AllNumbers`、`ContainsFace`、`FaceCountRange`。 第一版按优先级从高到低匹配,默认命中高优先级规则后停止继续匹配,除非规则配置声明可以继续匹配。 ### RollActionDispatcher 负责把命中规则中的 `RollActionSpec` 分发给对应 executor。 dispatcher 只能维护 `ActionType -> Executor` 注册表,不能维护组合 key 到方法的映射。 ### LuckyDiceFlowService 负责 Lucky Dice 的核心入口选择流程: ```text 构建候选池 → 筛选候选池 → 处理空池兜底 → 权重随机 → 生成展示结果槽 ``` 它不直接启动 Slap Down 或 Treasure Heist,而是把选中结果交给模式解析层。 ### TargetModeResolver 负责把 Lucky Dice 结果解析到具体目标玩法模式。 第一版映射: | ResultKey | TargetKey | ModeKey | | --- | --- | --- | | `rocket` | `slap_down` | `slap_down_normal` | | `thief` | `treasure_heist` | `treasure_heist_normal` | 后续教程模式、bonus 模式应通过 mode rule 扩展,而不是在 Lucky Dice 随机代码里写分支。 ### TargetModeLauncher 负责统一启动目标玩法。它接收 `TargetModeEntry`,把 Lucky Dice 的结果、倍率、触发来源、`RollSessionId` 传给目标玩法入口。 目标玩法结束后,通过明确的 completion 回调或流程事件回到主循环。 ### RollTrace 负责记录一次 Roll 的关键路径。追踪不是埋点管线本身,第一版可以是本地结构化日志或调试面板数据。 最小字段应覆盖: - 原始普通骰子结果 - 组合事实和归一化 key - 命中规则和执行行为 - Lucky Dice 初始候选、过滤过程、兜底类型 - 权重随机输入和选中结果 - 解析出的 TargetKey 和 ModeKey - 最终结果 ## 核心数据流 ### 普通 Roll ```mermaid sequenceDiagram participant P as Player participant R as DiceRollService participant F as ComboFactBuilder participant M as ComboRuleMatcher participant A as RollActionDispatcher participant T as RollTrace P->>R: Roll(normal_main) R->>T: record normal faces R->>F: DiceRollResult F->>T: record ComboFacts F->>M: ComboFacts M->>T: record matched rule M->>A: RollActionSpec list A->>T: record executed actions ``` ### Lucky Dice ```mermaid sequenceDiagram participant A as TriggerLuckyDiceExecutor participant L as LuckyDiceFlowService participant F as CandidateFilters participant W as WeightedPicker participant S as ResultSlotBuilder participant M as TargetModeResolver participant T as RollTrace A->>L: LuckyDiceContext L->>T: record initial candidates L->>F: apply filters F->>T: record filter decisions F->>W: filtered candidates W->>T: record random value and selected result W->>S: selected candidate S->>T: record result slots S->>M: selected candidate + context M->>T: record target mode ``` ## 配置架构 第一版建议至少拆成四类配置: | 配置 | 示例内容 | 扩展方向 | | --- | --- | --- | | DiceSetConfig | `normal_main`、`lucky_dice`、骰子面、骰子数量、默认槽数 | 支持关卡自定义骰子数量 | | ComboRuleConfig | 规则 id、优先级、matcher、actions | 策划新增组合语义 | | LuckyDiceCandidateConfig | result、target、weight、enabled、slot count、default | 扩展特殊结果与概率 | | TargetModeConfig | target、default mode、tutorial mode、bonus mode | 扩展玩法模式 | 配置读取顺序建议: ```text 本地默认配置 → 关卡或活动覆盖配置 → 运行时上下文修正 ``` 远端热更不在第一版范围内,但数据结构应避免与 Unity 场景对象强绑定,给后续迁移到远端配置留出空间。 ## Unity 落地目录建议 如果第一版开始实现 C# 模块,建议按运行时核心、配置、表现、测试分开: ```text FishDice/Assets/FishDice/ Runtime/ LuckyDice/ Core/ DiceRollService.cs ComboFactBuilder.cs ComboRuleMatcher.cs RollActionDispatcher.cs LuckyDiceFlowService.cs TargetModeResolver.cs Config/ DiceSetConfig.cs ComboRuleConfig.cs LuckyDiceCandidateConfig.cs TargetModeConfig.cs Actions/ GrantRewardExecutor.cs AddMultiplierExecutor.cs TriggerLuckyDiceExecutor.cs EnterModeExecutor.cs Filters/ EnabledFilter.cs ProgressFilter.cs SourceFilter.cs CooldownFilter.cs TutorialFilter.cs Presentation/ LuckyDicePresenter.cs LuckyDiceResultSlotView.cs Trace/ RollTrace.cs RollTraceLogger.cs Tests/ EditMode/ LuckyDice/ ``` 第一版核心流程建议尽量放在纯 C# 类里,减少对 `MonoBehaviour` 的依赖。表现层再通过 Unity 组件消费核心流程产物。 ## 错误处理与兜底 ### 普通组合未命中 处理策略: 1. 记录 `RollSessionId`、原始骰子面、`NormalizedKey`。 2. 走普通奖励兜底,或在调试模式返回明确错误。 3. 不进入 Lucky Dice。 ### Lucky Dice 候选池为空 处理策略: 1. 尝试使用配置的 default result。 2. default result 不可用时,降级为普通奖励兜底。 3. 记录每个 filter 过滤前后的候选数量和空池原因。 ### 模式解析失败 处理策略: 1. 记录 `ResultKey`、`TargetKey` 和上下文。 2. 尝试使用目标玩法默认模式。 3. 仍失败时降级为普通奖励兜底,并标记为配置错误。 兜底必须可观测,不能静默吞掉。否则后续配置错误会表现成“玩家只是没进 Lucky Dice”,很难定位。 ## 测试架构 测试应围绕外部行为和完整链路,而不是私有实现细节。 ### 单元测试 | 测试对象 | 重点 | | --- | --- | | ComboFactBuilder | N 骰统计、无序 key、有序 key、Clover 数量 | | ComboRuleMatcher | 优先级、matcher 类型、停止继续匹配 | | RollActionDispatcher | 按 action type 分发,不按 combo key 分发 | | CandidateFilters | enabled、progress、source、cooldown、tutorial 过滤 | | WeightedPicker | 固定随机源下结果可预测 | | TargetModeResolver | rocket/thief 映射和默认模式 | ### 链路测试 链路测试是第一版最重要的测试口: ```text 给定 Roll 请求 给定 DiceSet 配置 给定 ComboRule 配置 给定 Lucky Dice 候选池 给定固定随机源 断言最终 outcome ``` 最小链路用例: - `2 + 3` 发普通奖励。 - `2 + clover` 发普通奖励并提供 Clover bonus。 - `clover + clover` 触发 Lucky Dice。 - Lucky Dice 选中 `rocket` 后进入 `slap_down_normal`。 - Lucky Dice 选中 `thief` 后进入 `treasure_heist_normal`。 - 候选池为空时进入可观测兜底。 - 普通骰子数量改成 3 后,组合事实和 matcher 仍可工作。 ## 架构决策记录 完整 ADR 存放在 [Docs/Decisions](../Decisions/README.md)。本节只保留摘要,后续决策变更应优先新增或更新独立 ADR 文档。 ### ADR-001:普通骰子和 Lucky Dice 特殊结果分成两套集合 [ADR-001](../Decisions/adr-001-separate-normal-and-lucky-dice-sets.md) 上下文:普通骰子负责奖励组合,Lucky Dice 负责玩法入口。两者语义不同。 决策:使用 `DiceSetType.Normal` 和 `DiceSetType.Lucky` 区分集合,不让普通组合匹配器处理 Lucky Dice 特殊结果。 结果:避免数字结算和玩法入口混用。代价是配置和调试界面需要明确展示集合类型。 ### ADR-002:Roll 结果先转组合事实,再匹配规则 [ADR-002](../Decisions/adr-002-build-combo-facts-before-rule-matching.md) 上下文:第一版默认 2 颗骰子,但未来需要支持 3 颗、4 颗或关卡自定义骰子数量。 决策:所有普通 Roll 都先生成 `ComboFacts`,matcher 只依赖事实统计,不依赖固定位置。 结果:后续扩骰数量时风险更低。代价是第一版需要多写一层事实构建和测试。 ### ADR-003:行为按 action type 注册 [ADR-003](../Decisions/adr-003-dispatch-actions-by-action-type.md) 上下文:如果每个组合 key 绑定一个独立方法,组合增长会让执行层失控。 决策:规则只声明 action 列表,dispatcher 只按 `ActionType` 找 executor。 结果:新增组合多数情况下只改配置。代价是 action 参数需要有清晰校验。 ### ADR-004:Lucky Dice 随机源可注入 [ADR-004](../Decisions/adr-004-inject-random-source-for-lucky-dice.md) 上下文:权重随机必须可测试、可回放。 决策:Lucky Dice 权重随机通过 `IRandomSource` 或等价接口注入随机源。 结果:测试可预测,线上问题可复盘。代价是运行时需要统一管理随机源生命周期。 ## 新功能开发蓝图 ### 新增普通组合 1. 确认现有 matcher 能否表达该组合。 2. 能表达时新增 `ComboRuleConfig`。 3. 需要新业务效果时,优先复用现有 action。 4. 只有确实出现新的通用行为时,新增 executor。 5. 补一条规则匹配测试和一条链路测试。 ### 新增 Lucky Dice 特殊结果 1. 在 Lucky Dice 特殊结果集合中新增 `ResultKey`。 2. 在候选配置中声明 `TargetKey`、权重、启用条件、槽数、default 标记。 3. 在目标模式配置中声明默认 `ModeKey`。 4. 补候选筛选测试、权重随机测试和目标模式解析测试。 ### 新增目标玩法模式 1. 在 `TargetModeConfig` 中增加模式映射。 2. 如模式选择依赖上下文,新增 mode rule。 3. 不修改 Lucky Dice 随机逻辑。 4. 补 `TargetModeResolver` 测试。 ### 接入表现动画 1. 核心流程先产出 `LuckyDiceResultSlots` 和 `TargetModeEntry`。 2. 表现层播放标题、倍率、结果槽和跳转反馈。 3. 动画完成后再调用 launcher,或先启动目标玩法再做过场,取决于产品节奏。 4. 动画失败不能改变核心选择结果。 ## 架构治理 实现和评审时重点检查以下规则: - 核心流程中没有固定读取第 0/1 颗骰子的业务判断。 - 普通骰子和 Lucky Dice 特殊结果没有混用同一套集合。 - 新增组合时没有新增组合 key 到独立方法的 map。 - Lucky Dice 候选必须先筛选再随机。 - 候选池为空、模式解析失败、未命中规则都有可观测兜底。 - `RollSessionId` 贯穿普通 Roll、规则匹配、Lucky Dice、模式解析、目标玩法启动。 - 表现层不参与规则匹配、候选筛选和权重随机。 ## 第一版落地顺序 建议按以下顺序实现: 1. 定义核心数据结构和本地默认配置。 2. 实现普通 Roll、组合事实和规则匹配。 3. 实现 action dispatcher 和普通奖励 / Clover bonus / trigger Lucky Dice 执行器。 4. 实现 Lucky Dice 候选筛选、权重随机、结果槽生成。 5. 实现 `rocket -> slap_down_normal` 和 `thief -> treasure_heist_normal` 模式解析。 6. 实现最小表现层:标题、倍率、结果槽、目标玩法跳转反馈。 7. 补齐链路测试和追踪字段。 这个顺序能先把核心闭环跑通,再逐步加表现和更多结果类型,避免一开始被动画和短玩法完整内容拖散。