feat(lucky-dice): 提交 demo 前核心流程
This commit is contained in:
@@ -0,0 +1,487 @@
|
||||
# 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. 补齐链路测试和追踪字段。
|
||||
|
||||
这个顺序能先把核心闭环跑通,再逐步加表现和更多结果类型,避免一开始被动画和短玩法完整内容拖散。
|
||||
Reference in New Issue
Block a user