> For the complete documentation index, see [llms.txt](https://docs.convai.com/api-docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.convai.com/api-docs/zh/cha-jian-yu-ji-cheng/unity-plugin-beta-overview/features/narrative-design/troubleshooting-and-diagnostics.md).

# 故障排查与诊断

## 诊断并解决叙事设计问题

大多数叙事设计问题都属于三类之一：触发器未触发、节事件未响应，或后端获取失败。本页将涵盖这三类问题，先从内置状态系统开始 `ConvaiNarrativeDesignTrigger` 并逐步排查最常见的 Inspector 错误配置。

对于每个问题，解决方案都会与原因一起列出。排查问题时请在 **启用诊断** 触发器组件上启用，以便获得详细的 Console 输出（参见 启用诊断）。

## TriggerStatus 参考

`ConvaiNarrativeDesignTrigger.CurrentStatus` 始终报告触发器的当前状态。可用它来理解为什么触发器没有触发。

| 状态             | 原因                                    | 解决方案                                              |
| -------------- | ------------------------------------- | ------------------------------------------------- |
| `Ready`        | 正常——正在等待激活条件。                         | 无需操作。                                             |
| `AlreadyFired` | `仅触发一次` 已启用并且触发器已经触发。                 | 调用 `ResetTrigger()` 以重新武装它，或禁用 **仅触发一次** 在检查器中。   |
| `等待角色就绪排队中`    | 触发器已被接受，但角色尚未进入活动对话。                  | 等待会话打开。触发器会自动触发。调用 `CancelQueuedTrigger()` 来中止队列。 |
| `配置错误`         | `ValidateConfiguration()` 检测到一个或多个问题。 | 阅读 `验证警告` （参见 以编程方式验证配置）并修复每个问题。                  |
| `已禁用`          | 组件或其父级 GameObject 被禁用了。               | 启用该组件或 GameObject。                                |

## 首要排查

当某些功能无法正常工作时，请先按此检查清单排查，再深入查看具体症状。大多数问题会在第 2 或第 3 步解决。

{% stepper %}
{% step %}
**检查触发器上的 CurrentStatus**

选择 `ConvaiNarrativeDesignTrigger` Inspector 中的 GameObject。 **当前状态** 显示在组件顶部。任何不等于 `Ready` 的值都会立即告诉你触发器正在等待什么——请参阅 TriggerStatus 参考表了解解决方案。
{% endstep %}

{% step %}
**启用诊断并复现问题**

在 Trigger 组件中启用 **启用诊断**。按下 Play，并重复应该触发触发器的操作。每一次状态转换——区域进入/退出、队列开始、角色就绪检测、触发器发送——都会记录到 Console。按从上到下的顺序阅读日志序列，以找出链路在哪一处断开。

```csharp
// 或从代码中启用
trigger.SetDiagnosticsEnabled(true);
```

{% endstep %}

{% step %}
**验证角色 ID 和 API 密钥**

打开 **Edit > Project Settings > Convai SDK** 并确认 API 密钥已存在。选择你的角色 GameObject，并确认 **Character ID** 字段在 `ConvaiCharacter` 不为空。如果其中任一项缺失，从触发器的角度看，获取操作和会话连接都会静默失败。
{% endstep %}

{% step %}
**转储完整触发器状态**

调用 `PrintDiagnostics()` 从测试脚本中打印，或按下 **Invoke** / **Reset** 按钮（在 Play Mode 中该按钮会显示在组件上）。该转储会一次显示所有字段，便于发现不匹配：

```csharp
trigger.PrintDiagnostics();
```

{% endstep %}

{% step %}
**运行 ValidateConfiguration**

```csharp
if (!trigger.ValidateConfiguration())
{
    foreach (string warning in trigger.ValidationWarnings)
        Debug.LogWarning($"Trigger validation: {warning}");
}
```

或者启用 **启动时验证** 在 Inspector 中，这样它会在每次 Play 会话开始时自动运行。
{% endstep %}
{% endstepper %}

## 常见问题

| 症状                                     | 可能原因                               | 修复                                                                        |
| -------------------------------------- | ---------------------------------- | ------------------------------------------------------------------------- |
| 在以下之后节列表为空 **与后端同步**                   | API 密钥缺失或无效                        | **Edit > Project Settings > Convai SDK** ——请验证密钥；检查 **上次获取错误** Manager 上的 |
| 在以下之后节列表为空 **与后端同步**                   | 未设置角色 ID                           | 设置 **Character ID** 在 `ConvaiCharacter` 组件                                |
| `OnTriggerActivated` 触发了但节从未变化         | 触发器名称与仪表板边缘不完全匹配（区分大小写）            | 点击 **获取** 在 Trigger 上，从下拉菜单中重新选择正确的触发器                                    |
| `OnSectionStart` 尽管节已变化，但从未触发          | 本地节 ID 与仪表板不同步                     | 点击 **与后端同步** 在 Manager 上；如果仍然有问题，请调用 `ClearAllSectionConfigs()` 并重新同步     |
| `OnPlayerEnterZone` 从未触发（Collision 模式） | **Is Trigger** 在 Collider 上被禁用     | 启用 **Is Trigger** 在 Collider 组件上                                          |
| `OnPlayerEnterZone` 从未触发（Collision 模式） | 否 `Rigidbody` 在任一对象上               | 添加一个 `Rigidbody` 到触发器 GameObject 或玩家                                      |
| `OnPlayerEnterZone` 从未触发（Collision 模式） | Player GameObject 的标签未设置为 `Player` | 将标签设置为 `Player` 在 Inspector 中                                             |
| 错误的对象激活了触发器                            | **玩家层** 遮罩设置为 `无` (0)              | 设置 **玩家层** 设置为玩家所在的层                                                      |
| 无法识别 Player 标签                         | 该标签未在 Unity 的 Tag Manager 中定义      | 在以下位置添加该标签： **Edit > Project Settings > Tags and Layers**                 |
| “发现多个 ConvaiCharacters” 警告             | `自动查找角色` 无法消除歧义                    | 请在以下位置显式分配目标角色 **角色** 字段                                                  |
| 节显示 **孤立** 徽标                          | 本地同步后，仪表板中的节已删除                    | 如果是有意为之：手动删除条目。如果是误删：在仪表板上恢复，然后点击 **与后端同步**                               |
| 模板键对角色对话没有影响                           | 键名与仪表板占位符的大小写不匹配                   | 请精确比对键： `{playerName}` 在仪表板上 → 键 `playerName`，而不是 `PlayerName`            |

## 启用诊断

`ConvaiNarrativeDesignTrigger` 内置诊断日志记录器。可在 Inspector 中或通过代码启用：

```csharp
trigger.SetDiagnosticsEnabled(true);
```

启用诊断后，每一次状态转换——区域进入/退出、队列开始、角色就绪检测、触发器发送——都会通过 `ConvaiLogger.Debug`.

在任何时候将触发器的当前完整状态转储到 Console：

```csharp
trigger.PrintDiagnostics();
```

`PrintDiagnostics()` 日志：

```
[ConvaiNarrativeDesignTrigger] === DIAGNOSTICS ===
  GameObject: TriggerZone_Checkpoint1
  状态：等待角色就绪排队中
  已触发：False
  仅触发一次：True
  触发器名称：'CheckpointReached'
  触发器 ID：'a1b2c3d4-...'
  激活模式：Collision
  已分配角色：SafetyInstructor
  角色已就绪：False
  玩家在区域内：True
  玩家变换：PlayerController
  已排队等待就绪：True
  上次错误：无
  验证警告：0
===========================
```

在 Play Mode 中，Inspector 还会显示一个 **Invoke** 按钮（触发 `InvokeTrigger()`）以及一个 **Reset** 按钮（触发 `ResetTrigger()`），可直接在 Inspector 中操作，无需编写任何代码。

## 以编程方式验证配置

```csharp
bool valid = trigger.ValidateConfiguration();

if (!valid)
{
    foreach (string warning in trigger.ValidationWarnings)
        Debug.LogWarning($"Trigger validation: {warning}");
}
```

`ValidateConfiguration()` 会运行两项自动检查：

1. **Collider 检查** （Collision 和 TimeBased 模式）：验证一个 `Collider` 存在于同一个 GameObject 上，并且 **Is Trigger** 已启用，则自动查找。
2. **Player 标签检查**：验证在 **玩家标签** 中指定的标签已在 Unity 的 Tag Manager 中定义。如果该标签不存在，则记录警告。

启用 **启动时验证** 在 Inspector 中启用，以便自动在 `Start()` 时运行此检查，这样一旦 Play Mode 开始，就能立即捕获问题。

## 获取失败

如果 `FetchAndSyncFromBackend()` 失败：

1. **上次获取错误** 在 Manager 的 Inspector 中会显示确切的错误字符串。
2. 调用 `ClearFetchError()` 以在解决问题后重置错误显示：

```csharp
narrativeManager.ClearFetchError();
```

常见原因：

| 错误                 | 原因                                         |
| ------------------ | ------------------------------------------ |
| `“API 密钥未配置”`      | 在 Project Settings > Convai SDK 中缺少 API 密钥 |
| `“需要角色 ID”`        | 在 `ConvaiCharacter`                        |
| `“异常：...”`         | 网络错误，或无法访问 Convai 后端                       |
| `“未分配角色，或角色没有 ID”` | Manager 没有角色引用，且自动检测失败                     |

你也可以检查以下调用的结果： `FetchAndSyncFromBackendAsync()` 在代码中：

```csharp
SectionSyncResult result = await narrativeManager.FetchAndSyncFromBackendAsync();
if (!result.Success)
    Debug.LogError($"Sync failed: {result.Error}");
```

## 理解挂起状态

当模板键或触发器在角色会话打开之前发送时，SDK 会将它们保存在内部队列中。投递是自动的——你无需手动重新发送任何内容。

| 事件        | 发生了什么                                                             |
| --------- | ----------------------------------------------------------------- |
| 会话打开      | `FlushPending()` 会在内部调用；所有排队的键和触发器都会按顺序发送。                        |
| 会话断开并重新连接 | `MarkPendingReplayAfterDisconnect()` 会在内部调用；最新的模板键快照会在下一次连接时重新发送。 |

{% hint style="info" %}
你可以调用 `SetTemplateKey` 或 `InvokeTrigger` 在场景生命周期的任何时刻——包括在 `Awake` 或者在 Play Mode 完全运行之前——一旦连接就绪，SDK 就会正确投递这些值。
{% endhint %}

## 队列超时

`ConvaiNarrativeDesignTrigger`的 **等待就绪前排队** 功能每 0.25 秒轮询一次角色是否就绪。超时由 **最大等待时间** 控制（默认： `30` 秒）。

当达到超时时间时， `OnTriggerFailed` 会触发并显示消息：

```
等待角色就绪超时，已等待 30 秒。
```

如需在超时前取消已排队的触发器：

```csharp
trigger.CancelQueuedTrigger();
```

{% hint style="warning" %}
设置 **最大等待时间** 到 `0` 会完全禁用超时。在会话始终无法连接的构建版本中（例如，由于网络中断），等待协程会一直运行，直到场景卸载。对于生产构建，请始终设置合理的超时并处理 `OnTriggerFailed` 以便通知用户或优雅降级。
{% endhint %}

## Console 日志参考

当 **启用诊断** 已开启，或者运行时发生错误时，会出现以下日志消息。请使用此表了解每条消息的含义以及下一步该检查什么。

| 日志消息                                | 组件                               | 含义                                                        |
| ----------------------------------- | -------------------------------- | --------------------------------------------------------- |
| `触发器已触发：<name>`                     | `ConvaiNarrativeDesignTrigger`   | 触发器已被接受并成功发送到后端。                                          |
| `已排队的触发器：<name>——等待角色就绪`            | `ConvaiNarrativeDesignTrigger`   | 角色会话尚未打开。连接后触发器会自动触发。                                     |
| `角色已就绪——正在发送已排队的触发器：<name>`         | `ConvaiNarrativeDesignTrigger`   | 会话已打开；延迟的触发器现在正在发送。                                       |
| `等待角色就绪超时，已等待 <N> 秒。`               | `ConvaiNarrativeDesignTrigger`   | `MaxWaitTime` 已耗尽。请处理 `OnTriggerFailed` 并增加超时时间，或检查会话连接。  |
| `触发器已触发。调用 ResetTrigger() 以重新武装。`   | `ConvaiNarrativeDesignTrigger`   | `仅触发一次` 为 `true` 并且触发器已经触发。                               |
| `验证警告：<detail>`                     | `ConvaiNarrativeDesignTrigger`   | 在 Start 时检测到配置问题（collider、标签或角色引用）。请阅读 detail 字符串以了解具体字段。 |
| `在场景中发现多个 ConvaiCharacters——请显式分配。` | `ConvaiNarrativeDesignTrigger`   | 自动查找存在歧义。将正确的角色拖入 **角色** 字段。                              |
| `节已更改：<previousId> → <newId>`       | `ConvaiNarrativeDesignManager`   | 已收到节切换。如果 `OnSectionStart` 未触发，则节 ID 不在本地配置列表中——请重新同步。    |
| `同步完成：新增 <N> 个，更新 <N> 个，孤立 <N> 个`   | `ConvaiNarrativeDesignManager`   | 上次 **与后端同步** 次调用的摘要。孤立计数非零表示仪表板中的节已被移除。                   |
| `获取失败：<error>`                      | `ConvaiNarrativeDesignManager`   | API 密钥、角色 ID 或网络问题。请检查 **上次获取错误** 在检查器中。                  |
| `已发送模板键：<N> 个键`                     | `CharacterNarrativeDesignFacade` | 键已发送到后端。如果角色未使用这些值，请验证仪表板上的占位符语法。                         |

## 触发器未触发——决策树

```mermaid
flowchart TD
    A[触发器未触发] --> B[检查 CurrentStatus]
    B --> C{状态？}
    C -- AlreadyFired --> D[调用 ResetTrigger\n或禁用 Trigger Once]
    C -- QueuedWaitingForCharacter --> E[等待会话\n或检查 MaxWaitTime]
    C -- ConfigurationError --> F[读取 ValidationWarnings\n修复每个问题]
    C -- Disabled --> G[启用组件\n或其父级 GameObject]
    C -- Ready --> H{角色已就绪？}
    H -- false --> I{QueueUntilReady？}
    I -- false --> J[启用 Queue Until Ready\n或在触发前等待会话]
    I -- true --> K[触发器已排队\n等待会话打开]
    H -- true --> L{已设置 TriggerName？}
    L -- empty --> M[获取触发器并选择一个\n或在代码中调用 SetTrigger]
    L -- set --> N[检查网络连接\n和后端图配置]
```

## 结论

内置的 `TriggerStatus`, `PrintDiagnostics()`, `ValidateConfiguration()`，详细的诊断日志覆盖了 Narrative Design 的完整排查范围。请先从 `CurrentStatus` 开始进行即时诊断，启用 `EnableDiagnostics` 以跟踪完整事件链，并使用常见问题表来解决最常见的错误配置。如果在浏览本指南后问题仍然存在，请将诊断转储输出与 Console 日志参考中的预期日志模式进行比较，以找出预期行为与实际行为之间的任何差异。


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.convai.com/api-docs/zh/cha-jian-yu-ji-cheng/unity-plugin-beta-overview/features/narrative-design/troubleshooting-and-diagnostics.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
