chore: initial commit

This commit is contained in:
2026-05-08 11:04:00 +08:00
commit f55d2a57c3
6278 changed files with 866081 additions and 0 deletions

View File

@@ -0,0 +1,428 @@
# 42 · Debug / 开发者工具系统
> **命名空间** `BaseGames.Debug`(仅在 `UNITY_EDITOR || DEVELOPMENT_BUILD` 下编译)
> **所属文档集** [← 返回索引](./README.md) · [总览](./00_Overview.md)
> **依赖** `BaseGames.Player` · `BaseGames.Core`GameManager · SaveManager· `BaseGames.Progression`
> **关联** 09_EditorExtensions调试叠加层 §4· 27_PerformanceBudgetGuide性能监控· 31_SaveDataSchemaSaveData 强制写入)
---
## 目录
1. [系统总览](#1-系统总览)
2. [编译条件保护](#2-编译条件保护)
3. [DebugConsole — 运行时控制台](#3-debugconsole--运行时控制台)
4. [内置调试命令表](#4-内置调试命令表)
5. [DebugConfigSO — 开发者配置资产](#5-debugconfigso--开发者配置资产)
6. [快捷键绑定](#6-快捷键绑定)
7. [无敌模式GodMode](#7-无敌模式godmode)
8. [瞬移到房间Teleport](#8-瞬移到房间teleport)
9. [强制解锁能力UnlockAbility](#9-强制解锁能力unlockability)
10. [强制设置存档标志SetFlag](#10-强制设置存档标志setflag)
11. [性能叠加层PerfOverlay](#11-性能叠加层perfoverlay)
12. [QA 场景直接启动](#12-qa-场景直接启动)
13. [编辑器菜单集成](#13-编辑器菜单集成)
---
## 1. 系统总览
Debug 系统在**开发版 Build 和 Editor 中可用**,在 Release Build 中**完全剥离**,不影响性能和安全性。
```
Debug 系统职责:
├─ DebugConsole → 运行时命令控制台(类似 Quake/CS 控制台)
├─ DebugConfigSO → 开发者专用配置(无敌、起始场景、默认能力等)
├─ DebugOverlay → 屏幕角实时 FPS/GC/状态显示
├─ CheatCommands → 命令实现集合god / tp / unlock / setflag 等)
└─ QABootstrapper → 支持任意场景直接播放时正确初始化 Persistent 层
```
---
## 2. 编译条件保护
所有 Debug 代码用 `#if` 包裹,确保 Release 版本零开销:
```csharp
// Assets/Scripts/Debug/DebugConsole.cs
#if UNITY_EDITOR || DEVELOPMENT_BUILD
namespace BaseGames.Debug
{
public class DebugConsole : MonoBehaviour
{
// 实现见下方
}
}
#endif
```
### Player Settings 约定
| Build Type | `DEVELOPMENT_BUILD` | Debug 功能 |
|-----------|-------------------|-----------|
| Editor Play Mode | 自动为 true | ✅ 全功能 |
| Development Build | 勾选 Development Build | ✅ 全功能 |
| Release BuildQA 内部)| 不勾选 | ❌ 完全剥离 |
| Release Build发行版| 不勾选 | ❌ 完全剥离 |
---
## 3. DebugConsole — 运行时控制台
### 激活方式
**` (反引号 / Tilde)** 键呼出/收起控制台覆盖层UI Toolkit 实现,覆盖在 HUD 上方)。
### 控制台 UI 结构
```
┌───────────────────────────────────────────────────────────┐
│ [DEBUG CONSOLE] [×]关闭 │
│ > god on ← 命令输入框 │
│ ───────────────────────────────────────────────────── │
│ [OK] GodMode 已开启 ← 输出日志区 │
│ [OK] 传送至 Room_Cave_03 ← 最新在上 │
│ [ERR] 未知命令: foo ← 错误用红色显示 │
└───────────────────────────────────────────────────────────┘
```
### 命令解析
```csharp
public class DebugConsole : MonoBehaviour
{
// 命令注册表:命令名 → handler
private Dictionary<string, Action<string[]>> _commands = new();
void Awake()
{
// 内置命令自动注册
Register("god", CheatCommands.GodMode);
Register("tp", CheatCommands.Teleport);
Register("unlock", CheatCommands.UnlockAbility);
Register("setflag", CheatCommands.SetFlag);
Register("givegeo", CheatCommands.GiveGeo);
Register("killall", CheatCommands.KillAll);
Register("timescale",CheatCommands.SetTimeScale);
Register("perf", CheatCommands.TogglePerfOverlay);
Register("reload", CheatCommands.ReloadScene);
Register("help", CheatCommands.Help);
}
public void Register(string name, Action<string[]> handler)
=> _commands[name.ToLower()] = handler;
void Execute(string input)
{
var parts = input.Trim().Split(' ');
if (parts.Length == 0) return;
var cmd = parts[0].ToLower();
var args = parts[1..];
if (_commands.TryGetValue(cmd, out var handler))
handler(args);
else
LogError($"未知命令: {cmd}(输入 help 查看命令列表)");
}
}
```
---
## 4. 内置调试命令表
| 命令 | 语法 | 说明 |
|------|------|------|
| `god` | `god [on\|off]` | 切换无敌模式(无参数 = toggle|
| `tp` | `tp <SceneName> [SpawnId]` | 瞬移到指定场景和出生点 |
| `unlock` | `unlock <AbilityName>` | 解锁指定能力(如 `unlock doublejump`|
| `unlock all` | `unlock all` | 解锁全部能力 |
| `setflag` | `setflag <flagKey> <true\|false>` | 强制写入 SaveData 任意布尔标志 |
| `givegeo` | `givegeo <amount>` | 给予指定数量货币 |
| `givehp` | `givehp <amount>` | 设置当前 HP |
| `killall` | `killall` | 击杀当前房间所有敌人 |
| `spawnenemy` | `spawnenemy <EnemyId> [x y]` | 在指定位置生成敌人 |
| `timescale` | `timescale <0.02.0>` | 设置 `Time.timeScale` |
| `perf` | `perf [on\|off]` | 切换性能叠加层显示 |
| `reload` | `reload` | 重新加载当前场景 |
| `savestate` | `savestate` | 立即写入存档 |
| `loadstate` | `loadstate` | 重新读取最新存档 |
| `form` | `form <FormId>` | 强制切换玩家形态(如 `form EarthSoul`|
| `help` | `help [cmd]` | 显示命令列表或指定命令帮助 |
---
## 5. DebugConfigSO — 开发者配置资产
```csharp
#if UNITY_EDITOR || DEVELOPMENT_BUILD
[CreateAssetMenu(menuName = "Debug/DebugConfig")]
public class DebugConfigSO : ScriptableObject
{
[Header("启动配置")]
public string startSceneOverride; // 非空时 QABootstrapper 加载此场景
public string startSpawnPointId; // 配合 startSceneOverride
[Header("开局默认能力(跳过前期解锁,快速测试后期内容)")]
public bool startWithDoubleJump;
public bool startWithWallGrab;
public bool startWithDash;
public bool startWithSwim;
public string startFormId = "Form_HeavenSoul";
[Header("开局资源")]
public int startGeo = 0;
public int startMaxHP = 5;
[Header("自动化测试")]
public bool enableGodModeAtStart;
public bool skipCutscenes; // 所有 Timeline 直接跳过
public bool skipDialogue; // 所有对话直接结束
}
#endif
```
`DebugConfigSO` 资产放在 `Assets/Debug/`(不加入 Addressable Group不进入发行包。
---
## 6. 快捷键绑定
快捷键仅在 `UNITY_EDITOR || DEVELOPMENT_BUILD` 下注册,不占用玩家输入:
| 快捷键 | 功能 |
|--------|------|
| **`` ` ``** (Tilde) | 呼出/收起控制台 |
| **F1** | 切换无敌模式 |
| **F2** | 切换 PerfOverlay |
| **F3** | 快速存档 |
| **F4** | 快速读档(回到最后存档点)|
| **F5** | 重新加载当前场景 |
| **F8** | 击杀当前房间所有敌人 |
| **Ctrl + Shift + T** | 打开 Teleport 快捷面板 |
---
## 7. 无敌模式GodMode
```csharp
public static class CheatCommands
{
public static void GodMode(string[] args)
{
bool enable = args.Length == 0
? !PlayerStats.Instance.IsGodMode
: args[0] == "on";
PlayerStats.Instance.IsGodMode = enable;
DebugConsole.Log($"GodMode {(enable ? "开启" : "关闭")}");
}
}
```
`PlayerStats.IsGodMode` 属性在 `HurtBox.ReceiveDamage` 入口处检测:
```csharp
// HurtBox.cs
#if UNITY_EDITOR || DEVELOPMENT_BUILD
if (_owner.TryGetComponent<PlayerStats>(out var ps) && ps.IsGodMode)
return; // 跳过伤害处理
#endif
```
---
## 8. 瞬移到房间Teleport
```csharp
public static async void Teleport(string[] args)
{
if (args.Length == 0) { DebugConsole.LogError("用法: tp <SceneName> [SpawnId]"); return; }
string sceneName = args[0];
string spawnId = args.Length > 1 ? args[1] : "Default";
// 复用正常的场景加载流程,保证 GameManager / SaveManager 状态一致
var channel = Resources.Load<LoadSceneEventChannelSO>("Events/LoadSceneChannel");
channel.Raise(new LoadSceneEvent(sceneName, spawnId));
DebugConsole.Log($"传送至 {sceneName} @ {spawnId}");
}
```
**注意**Teleport 不影响 SaveData不触发正常 OnRoomEntered 流程,仅用于测试。
### Teleport 快捷面板
`Ctrl + Shift + T` 打开一个 EditorWindow 风格的浮层Runtime UI Toolkit列出所有已知场景名从 `ProgressionSystem.RegionDefinitionSO` 读取),点击即瞬移。
---
## 9. 强制解锁能力UnlockAbility
```csharp
public static void UnlockAbility(string[] args)
{
if (args.Length == 0) { DebugConsole.LogError("用法: unlock <ability|all>"); return; }
if (args[0] == "all")
{
foreach (AbilityType a in Enum.GetValues(typeof(AbilityType)))
PlayerStats.Instance.UnlockAbility(a);
DebugConsole.Log("已解锁全部能力");
return;
}
if (Enum.TryParse<AbilityType>(args[0], true, out var ability))
{
PlayerStats.Instance.UnlockAbility(ability);
DebugConsole.Log($"已解锁: {ability}");
}
else
{
DebugConsole.LogError($"未知能力: {args[0]}");
DebugConsole.Log("可用值: " + string.Join(", ", Enum.GetNames(typeof(AbilityType))));
}
}
```
---
## 10. 强制设置存档标志SetFlag
用于测试"Boss 已击败 → 大门已开"等状态敏感逻辑:
```csharp
public static void SetFlag(string[] args)
{
// 语法: setflag world.defeatedBossIds Boss_Forest true
if (args.Length < 2) { DebugConsole.LogError("用法: setflag <path> <value>"); return; }
// 通过反射或 switch 路由到 SaveData 对应字段
SaveManager.Instance.SetDebugFlag(args[0], args[1]);
DebugConsole.Log($"标志 [{args[0]}] 已设为 {args[1]}");
}
```
`SaveManager.SetDebugFlag` 内部通过 `switch` 路由已知键路径(不做通用反射,避免安全风险):
```csharp
public void SetDebugFlag(string path, string value)
{
switch (path)
{
case "world.defeatedBossIds.add":
Current.World.DefeatedBossIds.Add(value); break;
case "player.abilities.swim":
Current.Player.Abilities.Swim = bool.Parse(value); break;
case "player.abilities.dash":
Current.Player.Abilities.Dash = bool.Parse(value); break;
// ... 其他已知路径
default:
UnityEngine.Debug.LogWarning($"[Debug] 不支持的标志路径: {path}"); break;
}
}
```
---
## 11. 性能叠加层PerfOverlay
`PerfOverlay` 在屏幕右上角显示实时诊断数据:
```
┌──────────────────────────┐
│ FPS: 62 (16.1ms) │
│ GC: 0.2 KB/frame │
│ Draw Calls: 128 │
│ Particles: 34 / 500 │
│ ─────────────────────── │
│ PlayerState: WallGrab │
│ HP: 4/5 Soul: 66/99 │
│ Form: HeavenSoul │
│ Pos: (-12.5, 3.0) │
└──────────────────────────┘
```
实现基于 Unity `FrameTimingManager` + `GarbageCollector.GetTotalMemory(false)`,性能采样间隔 0.25 秒,不产生额外 GC。
参见 09_EditorExtensions §4调试叠加层获取完整实现细节。
---
## 12. QA 场景直接启动
Unity Editor 中直接播放非 Persistent 场景时(如 `Room_Cave_03``QABootstrapper` 自动初始化必要系统:
```csharp
#if UNITY_EDITOR || DEVELOPMENT_BUILD
/// <summary>
/// 当非 Persistent 场景被直接播放时,自动加载 Persistent 场景并初始化调试配置。
/// 挂在每个 Room_* 场景的 [Debug] 根物件下Editor Only
/// </summary>
public class QABootstrapper : MonoBehaviour
{
[SerializeField] DebugConfigSO _config;
async void Awake()
{
// 检查 Persistent 场景是否已加载
if (!SceneManager.GetSceneByName("Persistent").isLoaded)
{
await Addressables.LoadSceneAsync(
AddressKeys.ScenePersistent, LoadSceneMode.Additive).Task;
}
// 应用 DebugConfig 起始状态
if (_config != null)
ApplyDebugConfig(_config);
}
void ApplyDebugConfig(DebugConfigSO cfg)
{
var stats = PlayerStats.Instance;
if (cfg.startWithDoubleJump) stats.UnlockAbility(AbilityType.DoubleJump);
if (cfg.startWithWallGrab) stats.UnlockAbility(AbilityType.WallGrab);
if (cfg.startWithDash) stats.UnlockAbility(AbilityType.Dash);
if (cfg.startWithSwim) stats.UnlockAbility(AbilityType.Swim);
if (cfg.enableGodModeAtStart) stats.IsGodMode = true;
var form = FormController.Instance;
form.SwitchForm(cfg.startFormId);
}
}
#endif
```
---
## 13. 编辑器菜单集成
```
菜单: BaseGames/Debug/
├── [开启 GodMode] → PlayerPrefs 写入临时标志,下次 Play 自动开启
├── [快速跳转场景...] → 打开 SceneSelector EditorWindow
├── [解锁所有能力] → 修改 DebugConfigSO 默认值
├── [清空存档Slot 0] → 删除 slot_0.json确认弹窗
├── [打开 SaveData 编辑器] → 打开 SaveDataEditor 窗口(见 31_SaveDataSchema §10
└── [生成 QABootstrapper 到当前场景] → 自动在当前场景添加 QABootstrapper 组件
```
---
## 附录:常见 QA 测试流程
| 测试目标 | 推荐命令序列 |
|---------|------------|
| 测试 Boss 关卡(跳过前期)| `unlock all` → `tp Boss_Forest` |
| 测试后期区域(深渊)| `unlock all` → `tp Room_Abyss_01` |
| 复现特定死亡存档状态 | `setflag world.defeatedBossIds.add Boss_Forest` → `savestate` → 手动触发死亡 |
| 性能 Profile 特效密集场景 | `perf on` → `spawnenemy EnemySwarmType 0 0` × 20 |
| 测试游泳系统(无能力)| `tp Room_Abyss_Lake_01` → 进入水体观察溺水计时 |
| 测试游泳系统(有能力)| `unlock swim` → `tp Room_Abyss_Lake_01` |
---
*文档版本 1.0 · 2025*