> 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/convai-unreal-engine-plugin/core-concepts/event-system.md).

# 事件系统

Convai 组件和子系统上核心运行时 Blueprint 委托的参考，按类别组织并附带时序细节。

Convai Unreal Engine 插件通过以下方式将核心运行时结果传递给 Blueprint： `UPROPERTY(BlueprintAssignable)` 组件和子系统上的委托。请在你的角色或玩家 Blueprint 中绑定这些委托，以驱动动画、更新 UI、分发动作，或响应连接变化。本页重点介绍核心运行时组件和子系统委托；异步代理、测试和视觉基础委托不在此核心概念参考范围内。

### 继承的委托（两个组件）

`UConvaiChatbotComponent` 和 `UConvaiPlayerComponent` 都继承自 `UConvaiConversationComponent`，而它又继承自 `UConvaiAudioStreamer`。下面这些委托在每个会话组件上都可用。

#### 音频播放

这三个委托定义在 `UConvaiAudioStreamer` 上，适用于聊天机器人和玩家组件。它们都不带参数。在聊天机器人组件上，这些“正在说话”委托标记角色音频播放边界。在玩家组件上，相同委托会从玩家语音回调中广播，表示用户语音开始/停止事件。

| 委托                          | 类别                | 触发时机                          |
| --------------------------- | ----------------- | ----------------------------- |
| `OnStartedTalkingDelegate`  | `Convai`          | 聊天机器人：角色音频播放开始。玩家：用户语音开始。     |
| `OnFinishedTalkingDelegate` | `Convai`          | 聊天机器人：角色音频播放结束。玩家：用户语音停止。     |
| `OnFacialDataReadyDelegate` | `Convai\|LipSync` | 一批新的预计算面部动画数据已到达，并可供唇形同步管线消费。 |

`OnStartedTalkingDelegate` 和 `OnFinishedTalkingDelegate` 是底层的说话边界事件。对于聊天机器人播放状态感知，请将 `UConvaiChatbotComponent::GetIsTalking` 与这些委托配合使用。对于中断相关处理，请绑定到 `OnInterruptedEvent`.

#### 转写

**`OnTranscriptionReceivedDelegate`** — 类别 `Convai|Transcription`

在一句话进行中或之后，每次收到转写更新时都会触发。该委托每轮会触发多次：每个中间部分结果触发一次，最终转写准备好时再触发一次。

| 参数                     | 类型                              | 说明                           |
| ---------------------- | ------------------------------- | ---------------------------- |
| `说话者`                  | `UConvaiConversationComponent*` | 其音频产生该转写的组件。                 |
| `监听者`                  | `UConvaiConversationComponent*` | 存在于委托签名中。当前广播位置传入 `nullptr`. |
| `转写`                   | `FString`                       | 此时该句的转写文本。                   |
| `IsTranscriptionReady` | `bool`                          | `true` 当文本已可显示时。             |
| `IsFinal`              | `bool`                          | `true` 当这是该句的最后一次更新时。        |

#### 出席者连接状态

**`OnAttendeeConnectionStateChangedEvent`** — 类别 `Convai|Connection`

当聊天机器人或玩家组件上某位出席者的连接状态发生变化时触发。

| 参数                            | 类型                              | 说明                                                                            |
| ----------------------------- | ------------------------------- | ----------------------------------------------------------------------------- |
| `ConvaiConversationComponent` | `UConvaiConversationComponent*` | 拥有此事件的组件。                                                                     |
| `AttendeeID`                  | `FString`                       | 状态发生变化的出席者标识符。                                                                |
| `ConnectionState`             | `EC_ConnectionState`            | 新状态。枚举定义了 `已断开连接`, `连接中`, `已连接`，以及 `重新连接中`；当前运行时路径驱动 `已断开连接`, `连接中`，以及 `已连接`. |

### 聊天机器人组件委托

这些委托位于 `UConvaiChatbotComponent` 上，仅在你使用 AI 角色时相关。

#### 收到的动作

**`OnActionReceivedEvent_V2`** — 显示名称 **On Actions Received** — 类别 `Convai` （当前版本）

当 Convai 针对玩家输入或叙事触发返回一串一个或多个角色动作时触发。动作可通过 `SequenceOfActions` 参数以及聊天机器人的 `ActionsQueue`获取，因此你既可以直接遍历事件参数，也可以使用 `FetchFirstAction` 和 `HandleActionCompletion` 来驱动基于队列的执行模型。

| 参数                           | 类型                            | 说明             |
| ---------------------------- | ----------------------------- | -------------- |
| `ChatbotComponent`           | `UConvaiChatbotComponent*`    | 接收到这些动作的聊天机器人。 |
| `InteractingPlayerComponent` | `UConvaiPlayerComponent*`     | 触发这些动作的玩家。     |
| `SequenceOfActions`          | `TArray<FConvaiResultAction>` | 要执行的完整有序动作列表。  |

#### 情绪状态已更改

**`OnEmotionStateChangedEvent`** — 显示名称 **情绪状态已更改** — 类别 `Convai`

当 Convai 为角色返回更新后的情绪状态时触发。聊天机器人组件上的 `EmotionState` 属性在此触发时已经更新。使用 `GetEmotionScore` 读取某个基础情绪的当前值，并将其应用到你的动画系统中。

| 参数                           | 类型                         | 说明             |
| ---------------------------- | -------------------------- | -------------- |
| `ChatbotComponent`           | `UConvaiChatbotComponent*` | 其情绪发生变化的聊天机器人。 |
| `InteractingPlayerComponent` | `UConvaiPlayerComponent*`  | 触发情绪更新的玩家。     |

#### 角色数据已加载

**`OnCharacterDataLoadEvent_V2`** — 显示名称 **在角色数据加载完成时** — 类别 `Convai` （当前版本）

在插件尝试为聊天机器人组件加载角色数据后触发。这发生在组件启动期间以及调用 `LoadCharacter` 之后，包括通过 Blueprint setter 更改 `CharacterID` 时。使用 `成功` 参数来决定是否应继续角色相关 UI 或设置逻辑。

| 参数                 | 类型                         | 说明                                       |
| ------------------ | -------------------------- | ---------------------------------------- |
| `ChatbotComponent` | `UConvaiChatbotComponent*` | 加载数据的聊天机器人。                              |
| `成功`               | `bool`                     | `true` 如果获取成功； `false` 如果失败（例如角色 ID 无效）。 |

#### 叙事章节已接收

**`OnNarrativeSectionReceivedEvent`** — 显示名称 **叙事章节已接收** — 类别 `Convai`

当 AI 切换到 Convai 控制台中定义的叙事设计图的一个新章节时触发。可用它来同步游戏内状态——解锁门、推进任务标记，或触发过场动画逻辑——以响应角色进入的叙事分支。

| 参数                   | 类型                         | 说明              |
| -------------------- | -------------------------- | --------------- |
| `ChatbotComponent`   | `UConvaiChatbotComponent*` | 切换到新章节的聊天机器人。   |
| `NarrativeSectionID` | `FString`                  | 控制台中定义的叙事章节 ID。 |

#### 已接收交互 ID

**`OnInteractionIDReceivedEvent`** — 显示名称 **收到交互 ID 时** — 类别 `Convai`

在玩家与角色之间每次不同的交互（轮次）开始时触发。交互 ID 唯一标识此交换，可用于日志记录、分析，或将动作序列与产生它们的轮次进行匹配。

| 参数                           | 类型                         | 说明          |
| ---------------------------- | -------------------------- | ----------- |
| `ChatbotComponent`           | `UConvaiChatbotComponent*` | 参与交互的聊天机器人。 |
| `InteractingPlayerComponent` | `UConvaiPlayerComponent*`  | 参与交互的玩家。    |
| `InteractionID`              | `FString`                  | 此交互的唯一标识符。  |

#### 已中断

**`OnInterruptedEvent`** — 显示名称 **中断时** — 类别 `Convai`

在以下之后触发 `InterruptSpeech` 被应用且音频淡出开始。可用它将角色动画切换为“倾听”或“待机”姿势，重置字幕 UI，或清除任何“正在说话”状态指示器。

| 参数                           | 类型                         | 说明                                            |
| ---------------------------- | -------------------------- | --------------------------------------------- |
| `ChatbotComponent`           | `UConvaiChatbotComponent*` | 被中断的聊天机器人。                                    |
| `InteractingPlayerComponent` | `UConvaiPlayerComponent*`  | 存在于委托签名中。当前 `InterruptSpeech` 实现传入 `nullptr`. |

#### 失败

**`OnFailureEvent`** — 显示名称 **失败时** — 类别 `Convai`

声明为一个 `BlueprintAssignable` 不带参数的聊天机器人委托。 `UConvaiChatbotComponent::OnFailure()` 在该处理程序被调用时广播此事件。不要将其作为角色加载失败的主要信号；请将 `OnCharacterDataLoadEvent_V2` 及其 `成功` 参数用于角色数据加载。

### 玩家组件委托

这些委托位于 `UConvaiPlayerComponent` 并涵盖视线关注转换。玩家组件上的麦克风 API 是基于函数的（`GetIsStreaming`, `GetIsRecording`, `UnmuteStreamingAudio`等），而不是基于事件的——没有任何麦克风专用的 `BlueprintAssignable` 委托。

#### 视线与关注

这四个视线委托都具有相同签名：玩家组件以及涉及转换的对象组件。

| 委托                  | 显示名称 | 类别                               | 触发时机                                                                               |
| ------------------- | ---- | -------------------------------- | ---------------------------------------------------------------------------------- |
| `OnGazeBegin`       | —    | `Convai\|Gaze Attention\|Events` | 玩家的视线光标首次进入某个 `UConvaiObjectComponent` 的边界。会在任何关注阈值之前触发。                           |
| `OnGazeEnd`         | —    | `Convai\|Gaze Attention\|Events` | 玩家的视线离开某个 `UConvaiObjectComponent`，无论该对象是否已被提升为“被关注”。                              |
| `OnAttentionGained` | —    | `Convai\|Gaze Attention\|Events` | 一个被注视的对象持续处于凝视状态的时间超过 `GazeAttentionDelay` 秒后，关注通知将发送给符合条件的已注册聊天机器人。               |
| `OnAttentionLost`   | —    | `Convai\|Gaze Attention\|Events` | 关注释放通知会发送——要么是因为玩家移开视线的时间超过了 `GazeAttentionLossDelay` 秒，要么是另一个对象占用了该位置，或者关注目标已被销毁。 |

**视线委托签名：**

| 参数                | 类型                        | 说明         |
| ----------------- | ------------------------- | ---------- |
| `PlayerComponent` | `UConvaiPlayerComponent*` | 视线发生变化的玩家。 |
| `ObjectComponent` | `UConvaiObjectComponent*` | 参与转换的对象。   |

新的视线开始和获得关注事件要求 `bEnableGazeAttention` 为 `true` 在玩家组件上启用。如果在对象已经处于关注状态时禁用视线关注，当前关注可能会被释放，并且仍然可以广播关注丢失事件。

提升和释放阈值可在 `UConvaiPlayerComponent`: `OnAttentionGained` 在对象持续被凝视 `GazeAttentionDelay` 秒后触发（默认 `1.0` 秒）。 `OnAttentionLost` 在视线消失 `GazeAttentionLossDelay` 秒后触发（默认 `5.0` 秒后触发）。这两个值都可以在 **详情** 面板中调整，以匹配体验预期的交互速度。

### 对象组件事件

`UConvaiObjectComponent` 提供四个视线事件，从对象视角镜像玩家组件的视线委托。可用它们直接在对象的 Blueprint 上响应玩家关注，而无需轮询玩家组件。

| 委托                  | 类别                     | 触发时机                                                                   |
| ------------------- | ---------------------- | ---------------------------------------------------------------------- |
| `OnGazedIn`         | `Convai\|Object\|Gaze` | 玩家的视线光标进入该对象。会在任何关注阈值之前触发。                                             |
| `OnGazedOut`        | `Convai\|Object\|Gaze` | 玩家的视线离开该对象，无论关注状态如何。                                                   |
| `OnAttentionGained` | `Convai\|Object\|Gaze` | 该对象会在持续凝视阈值之后向符合条件的已注册聊天机器人发送关注获得通知。                                   |
| `OnAttentionLost`   | `Convai\|Object\|Gaze` | 当丢失计时器到期或视线切换到另一个对象时，该对象会发送关注丢失通知。被销毁目标的路径由玩家级别的关注丢失委托处理，其对象参数可为 null。 |

**对象视线事件签名：**

| 参数                | 类型                        | 说明                                         |
| ----------------- | ------------------------- | ------------------------------------------ |
| `ObjectComponent` | `UConvaiObjectComponent*` | 视线状态发生变化的对象。                               |
| `PlayerComponent` | `UConvaiPlayerComponent*` | 触发转换的玩家。可能为 `null` 在被销毁目标路径中——使用前务必进行空值检查。 |

这些事件仅在 `bGazeable` 是 `true` 为真时触发 `bGazeable` 到 `false` 在对象组件上（默认）。请在那些应存在于聊天机器人环境中用于动作或上下文目的、但不应通过玩家视线到达的对象上设置

### 子系统事件

`UConvaiSubsystem` 提供两个 `BlueprintAssignable` 委托，用于监视游戏实例中所有会话的全局连接状态。可通过以下方式从任意 Blueprint 访问该子系统： **获取游戏实例 → 获取子系统（Convai Subsystem）**.

| 委托                                    | 类别                   | 参数                                   | 触发时机                                                                                |
| ------------------------------------- | -------------------- | ------------------------------------ | ----------------------------------------------------------------------------------- |
| `OnServerConnectionStateChangedEvent` | `Convai\|Connection` | `EC_ConnectionState ConnectionState` | 全局 WebRTC 连接状态发生变化。使用 `ConnectionState` 参数来响应诸如 `连接中` 或 `已连接`.                      |
| `OnUserIdleWarning`                   | `Convai\|Event`      | `int32 RemainingSeconds`             | Convai 检测到用户已空闲。 `RemainingSeconds` 是连接自动关闭前剩余的时间。调用 `ResetIdleTimer` 在子系统上以防止断开连接。 |

绑定到 `OnServerConnectionStateChangedEvent` 用于应对任何会话状态变化的 UI 覆盖层或日志。绑定到 `OnUserIdleWarning` 以提示用户，或以编程方式重置计时器——例如在培训模拟中，无论学习者是否说话，只要完成一个任务步骤就重置计时器。

### 事件绑定模式

#### Blueprint

使用 **Assign** 节点上绑定组件引用中的任意 `BlueprintAssignable` 委托。对于聊天机器人事件，请在所属角色 Blueprint 的 `BeginPlay`中进行绑定。如果你的处理程序依赖于先加载角色数据（例如显示角色名称），则改为在 `OnCharacterDataLoadEvent_V2` 处理程序内部进行绑定。对于子系统事件，在从游戏实例获取子系统后进行绑定。

{% hint style="warning" %}
每个委托只绑定一次——通常在 `BeginPlay`中。避免在委托回调中，或在可能在每个 Actor 生命周期内被调用多次的任何函数中绑定。每次调用 **Assign** 都会添加一个新的绑定；重复绑定会导致同一处理程序在每次事件中被触发多次。
{% endhint %}

#### C++

在 C++ 中，请使用 `AddDynamic` 在 `BeginPlay` 和 `RemoveDynamic` 在 `EndPlay` 以匹配 Blueprint 的绑定模式。

```cpp
// AMyCharacter.h
UFUNCTION()
void HandleEmotionChanged(UConvaiChatbotComponent* ChatbotComp,
                          UConvaiPlayerComponent* PlayerComp);

UFUNCTION()
void HandleConnectionStateChanged(EC_ConnectionState NewState);
```

```cpp
// AMyCharacter.cpp
void AMyCharacter::BeginPlay()
{
    Super::BeginPlay();

    // 绑定聊天机器人委托
    if (ChatbotComponent)
    {
        ChatbotComponent->OnEmotionStateChangedEvent.AddDynamic(
            this, &AMyCharacter::HandleEmotionChanged);
    }

    // 绑定子系统委托
    if (UConvaiSubsystem* Subsystem = GetGameInstance()->GetSubsystem<UConvaiSubsystem>())
    {
        Subsystem->OnServerConnectionStateChangedEvent.AddDynamic(
            this, &AMyCharacter::HandleConnectionStateChanged);
    }
}

void AMyCharacter::EndPlay(const EEndPlayReason::Type EndPlayReason)
{
    if (ChatbotComponent)
    {
        ChatbotComponent->OnEmotionStateChangedEvent.RemoveDynamic(
            this, &AMyCharacter::HandleEmotionChanged);
    }

    if (UConvaiSubsystem* Subsystem = GetGameInstance()->GetSubsystem<UConvaiSubsystem>())
    {
        Subsystem->OnServerConnectionStateChangedEvent.RemoveDynamic(
            this, &AMyCharacter::HandleConnectionStateChanged);
    }

    Super::EndPlay(EndPlayReason);
}
```

在以下位置移除动态委托 `EndPlay` 在绑定由 Actor 拥有的处理程序时，尤其是对于其所有者寿命长于单个 Actor 的子系统事件。

### 使用示例

#### 情绪驱动的动画

一个角色在每次 Convai 返回新的情绪状态时都会更新其面部表情。

在 Blueprint 中， **Assign** 到 **情绪状态已更改** 在角色的 `BeginPlay` 事件中。处理程序节点接收聊天机器人组件引用——调用 **获取情绪分数** 它来读取当前情绪值并将其传递给你的动画系统或 Anim Blueprint。

在 C++ 中，使用 `AddDynamic` 在 `BeginPlay`:

```cpp
// BeginPlay
ChatbotComponent->OnEmotionStateChangedEvent.AddDynamic(
    this, &AMyCharacter::HandleEmotionChanged);

// 处理程序——触发时 EmotionState 已经更新
void AMyCharacter::HandleEmotionChanged(UConvaiChatbotComponent* ChatbotComp,
                                         UConvaiPlayerComponent* PlayerComp)
{
    // 使用 GetEmotionScore() 驱动你的 Anim Blueprint
}
```

预期结果：角色的面部表情在携带情绪数据的同一音频响应中更新。

#### 连接状态 UI 覆盖层

一个 HUD，在 Convai 会话尚未就绪时显示“正在连接…”覆盖层。

在 Blueprint 中，从 HUD 的 **Convai Subsystem** 中的游戏实例获取 `BeginPlay`，然后 **Assign** 到 **On Server Connection State Changed**。在处理程序中，根据传入状态是否为 `已连接`.

预期结果：覆盖层在 `连接中` 期间可见，并在会话达到 `已连接` 时自动隐藏——无需在 `Tick`.

#### 动作分发系统

一个按顺序执行一系列物理动作——移动、交互、说话——的角色。

在 Blueprint 中， **Assign** 到 **On Actions Received** 在 `BeginPlay`。在处理程序中，调用 **Fetch First Action** 从队列中读取第一个动作，执行相应的游戏逻辑（移动角色、触发动画、打开道具），然后调用 **处理动作完成** 并将 `true`。一次成功完成会将当前动作出队，并使下一个动作可供获取。

预期结果：每当前一个动作报告完成时，动作便按顺序执行，角色的语音并行播放。

### 故障排查

| 症状             | 可能原因                                                                           | 修复                                                                                                                                                   | 验证                                                          |
| -------------- | ------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------- |
| 委托从未触发         | 未建立绑定，或绑定创建时该事件已触发                                                             | 在角色 Blueprint 的 `BeginPlay` 中使用 **Assign** 节点进行绑定，或在 C++ 中使用 `AddDynamic` 。对于依赖角色数据的事件，请从 `OnCharacterDataLoadEvent_V2` 处理程序内部进行绑定，而不是在 `BeginPlay`. | 添加一个 **Print String** 到处理程序；它应在预期条件发生时输出。                   |
| 处理程序在每个事件中触发多次 | 委托被绑定了不止一次——例如， **Assign** 位于一个每次 `StartSession`                               | 确保每个 **Assign** 调用在每个 Actor 生命周期内只被到达一次。如果有意重新绑定，请在重新分配之前调用 **移除** （Blueprint）或 `RemoveDynamic` （C++）                                                | 在处理程序内记录一个计数器；它应在每个事件中恰好增加 1。                               |
| 角色数据设置在会话开始时失败 | 无效的 `CharacterID` 或 API 密钥配置问题                                                 | 请验证 `CharacterID` 在聊天机器人组件中的设置是否与 Convai 控制台中的某个角色匹配。确认并保存 **Convai 编辑器窗口**.                                                                         | `OnCharacterDataLoadEvent_V2` 与……一起触发 `成功 = true` 在有效会话启动后。 |
| 注视事件从不触发       | `bEnableGazeAttention` 是 `false` 在玩家组件上，或者目标 Actor 没有 `UConvaiObjectComponent` | 设置 **启用注视关注** 到 `true` 在玩家组件上。确认目标 Actor 具有一个 `UConvaiObjectComponent` 并将 `bGazeable` 已启用。                                                           | `OnGazeBegin` 当玩家看向目标时，会在玩家组件和对象组件上同时触发。                    |

### 相关概念

使用这些页面将委托触发时机与转身行为、组件所有权和会话生命周期决策联系起来。

{% content-ref url="/pages/422d78b3fb4f61a00785b876137cbfde618d7baa" %}
[对话流程](/api-docs/zh/cha-jian-yu-ji-cheng/convai-unreal-engine-plugin/core-concepts/conversation-flow.md)
{% endcontent-ref %}

{% content-ref url="/pages/0a71bb8fce84999367c663a06434475b944f88da" %}
[运行时架构](/api-docs/zh/cha-jian-yu-ji-cheng/convai-unreal-engine-plugin/core-concepts/runtime-architecture.md)
{% endcontent-ref %}

{% content-ref url="/pages/a8878427b216a80d6b385f1a342c440aa9b398c9" %}
[会话生命周期](/api-docs/zh/cha-jian-yu-ji-cheng/convai-unreal-engine-plugin/core-concepts/session-lifecycle.md)
{% endcontent-ref %}


---

# 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 by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.convai.com/api-docs/zh/cha-jian-yu-ji-cheng/convai-unreal-engine-plugin/core-concepts/event-system.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

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.
