> 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 Unreal Engine 插件通过以下方式将核心运行时结果传递给 Blueprint `UPROPERTY(BlueprintAssignable)` 组件和子系统上的委托。在你的角色或玩家 Blueprint 中绑定这些委托，可驱动动画、更新 UI、分发动作，或响应连接变化。本页聚焦核心运行时组件和子系统委托；异步代理、测试和 vision-base 委托不在本核心概念参考范围内。

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

`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|连接`

当参与者在聊天机器人或玩家组件上的连接状态发生变化时触发。

| 参数                            | 类型                              | 描述                                                                              |
| ----------------------------- | ------------------------------- | ------------------------------------------------------------------------------- |
| `ConvaiConversationComponent` | `UConvaiConversationComponent*` | 拥有此事件的组件。                                                                       |
| `参与者 ID`                      | `FString`                       | 状态发生变化的参与者标识符。                                                                  |
| `ConnectionState`             | `EC_ConnectionState`            | 新状态。该枚举定义了 `已断开连接`, `正在连接`, `已连接`，和 `正在重新连接`；当前运行时路径驱动 `已断开连接`, `正在连接`，和 `已连接`. |

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

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

#### 已接收动作

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

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

| 参数                  | 类型                            | 描述            |
| ------------------- | ----------------------------- | ------------- |
| `聊天机器人组件`           | `UConvaiChatbotComponent*`    | 接收这些动作的聊天机器人。 |
| `交互中的玩家组件`          | `UConvaiPlayerComponent*`     | 其输入触发这些动作的玩家。 |
| `SequenceOfActions` | `TArray<FConvaiResultAction>` | 要执行的完整有序动作列表。 |

#### 情绪状态已更改

**`OnEmotionStateChangedEvent`** — 显示名称 **情绪状态变更** — 分类 `Convai`

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

| 参数         | 类型                         | 描述             |
| ---------- | -------------------------- | -------------- |
| `聊天机器人组件`  | `UConvaiChatbotComponent*` | 情绪发生变化的聊天机器人。  |
| `交互中的玩家组件` | `UConvaiPlayerComponent*`  | 其输入触发了情绪更新的玩家。 |

#### 角色数据已加载

**`OnCharacterDataLoadEvent_V2`** — 显示名称 **On Character Data Loaded** — 分类 `Convai` （当前版本）

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

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

#### 已接收叙事章节

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

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

| 参数                   | 类型                         | 描述               |
| -------------------- | -------------------------- | ---------------- |
| `聊天机器人组件`            | `UConvaiChatbotComponent*` | 进入新章节的聊天机器人。     |
| `NarrativeSectionID` | `FString`                  | 在控制台中定义的叙事章节 ID。 |

#### 已接收交互 ID

**`OnInteractionIDReceivedEvent`** — 显示名称 **On Interaction ID Received** — 分类 `Convai`

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

| 参数              | 类型                         | 描述            |
| --------------- | -------------------------- | ------------- |
| `聊天机器人组件`       | `UConvaiChatbotComponent*` | 参与此次交互的聊天机器人。 |
| `交互中的玩家组件`      | `UConvaiPlayerComponent*`  | 参与此次交互的玩家。    |
| `InteractionID` | `FString`                  | 此次交互的唯一标识符。   |

#### 被中断

**`OnInterruptedEvent`** — 显示名称 **On Interrupted** — 分类 `Convai`

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

| 参数         | 类型                         | 描述                                            |
| ---------- | -------------------------- | --------------------------------------------- |
| `聊天机器人组件`  | `UConvaiChatbotComponent*` | 被中断的聊天机器人。                                    |
| `交互中的玩家组件` | `UConvaiPlayerComponent*`  | 存在于委托签名中。当前 `InterruptSpeech` 实现传入 `nullptr`. |

#### 失败

**`OnFailureEvent`** — 显示名称 **On Failure** — 分类 `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` | 当丢失计时器到期或注视切换到另一个对象时，此对象会发送注意力丢失通知。对于目标被销毁的路径，使用带可空对象参数的玩家级注意力丢失委托来处理。 |

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

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

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

### 子系统事件

`UConvaiSubsystem` 公开两个 `BlueprintAssignable` 监控游戏实例中所有会话的全局连接状态的委托。可通过以下方式从任意 Blueprint 访问该子系统： **Get Game Instance → Get Subsystem (Convai Subsystem)**.

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

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

### 事件绑定模式

#### Blueprint

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

{% hint style="warning" %}
每个委托只绑定一次——通常在 `BeginPlay`。避免在委托回调中，或在任何每个 Actor 生命周期内可能被调用多次的函数中绑定。每次调用 **分配** 都会添加一个新的绑定；重复绑定会导致同一个处理器在每个事件中触发多次。
{% 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 中， **分配** 设为 **情绪状态变更** 在角色的 `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 会话尚未就绪时显示“Connecting…”覆盖层。

在 Blueprint 中，获取 **Convai 子系统** ，在 HUD 的游戏实例中 `BeginPlay`，然后 **分配** 设为 **服务器连接状态更改时**。在处理器中，根据传入状态是否为来显示或隐藏覆盖层小部件 `已连接`.

预期结果：覆盖层在以下期间可见： `正在连接` 并在会话到达以下状态时自动隐藏： `已连接` ——无需轮询 `Tick`.

#### 动作分发系统

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

在 Blueprint 中， **分配** 设为 **On Actions Received** 在 `BeginPlay`。在处理器中，调用 **获取第一个动作** 来读取队列中的第一个动作，执行相应的游戏逻辑（移动角色、触发动画、打开道具），然后调用 **处理动作完成** 与 `true`。成功完成后会将当前动作出队，并让下一个动作可供获取。

预期结果：动作会随着前一个动作报告完成而按顺序执行，角色的语音会并行播放。

### 故障排除

| 症状            | 可能原因                                                                           | 修复                                                                                                                                               | 验证                                                        |
| ------------- | ------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------ | --------------------------------------------------------- |
| 委托从未触发        | 从未建立绑定，或者是在事件已经触发之后才创建绑定                                                       | 在角色 Blueprint 的 `BeginPlay` 使用 **分配** 节点，或在 C++ 中使用 `AddDynamic` 在 C++ 中。对于依赖角色数据的事件，请在 `OnCharacterDataLoadEvent_V2` 处理器中进行绑定，而不要在 `BeginPlay`. | 添加一个 **打印字符串** 将其绑定到处理器；当预期条件发生时，它应输出。                    |
| 处理器每个事件触发多次   | 委托被绑定了不止一次——例如， **分配** 位于一个会在每次 `StartSession`                                 | 请确保每次 **分配** 调用在每个 Actor 生命周期内仅到达一次。如果需要重新绑定，请在重新分配前调用 **Remove** （Blueprint）或 `RemoveDynamic` （C++）移除。                                          | 在处理器中记录一个计数器；它应每个事件恰好增加 1。                                |
| 会话开始时角色数据设置失败 | 无效 `CharacterID` 或 API 密钥配置问题                                                  | 请确认 `CharacterID` 聊天机器人组件中的设置与您 Convai 仪表板中的字符匹配。请在以下位置确认并保存 API 密钥： **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 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/convai-unreal-engine-plugin/core-concepts/event-system.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.
