For the complete documentation index, see llms.txt. This page is also available as Markdown.

响应名册与目标变化

订阅共享 Unity 房间中的名册和交互目标事件,并依赖 SDK 保证的事件顺序。

订阅 CharacterAdded, CharacterRemoved, CharacterStatusChanged,以及 InteractionTargetChanged 时自行注册 MultiCharacterRoomSession 在花名册或目标发生变化时立即响应。若你的场景需要在角色进出时更新 UI、日志或游戏状态,而不是轮询花名册,请使用此页。

先决条件

  • 一个已连接的多角色会话。参见 构建你的第一个多角色会话.

  • 对当前项的引用 MultiCharacterRoomSession,来自 IConvaiRoomConnectionService.CurrentMultiCharacterSession.

订阅花名册和目标事件

事件
签名
在以下情况触发

CharacterAdded

Action<CharacterRoomMembership>

在房间已连接之后,又向房间中添加了一个成员。

CharacterRemoved

Action<CharacterRoomMembership>

一个成员已从房间中移除。

CharacterStatusChanged

Action<CharacterRoomMembership>

一个成员身份转变为 就绪失败,或者一个新的成员身份被插入到成员列表中。

InteractionTargetChanged

Action<CharacterRoomMembership, CharacterRoomMembership>

规范的活动成员发生变化;当前成员为 null 当目标被清除时。

Assets/Scripts/MultiCharacterEventLogger.cs
using Convai.Runtime.Room;
using UnityEngine;

public class MultiCharacterEventLogger : MonoBehaviour
{
    private MultiCharacterRoomSession _session;

    public void Attach(MultiCharacterRoomSession session)
    {
        Detach();
        _session = session;
        if (_session == null) return;

        _session.CharacterAdded += HandleCharacterAdded;
        _session.CharacterRemoved += HandleCharacterRemoved;
        _session.CharacterStatusChanged += HandleCharacterStatusChanged;
        _session.InteractionTargetChanged += HandleInteractionTargetChanged;
    }

    public void Detach()
    {
        if (_session == null) return;

        _session.CharacterAdded -= HandleCharacterAdded;
        _session.CharacterRemoved -= HandleCharacterRemoved;
        _session.CharacterStatusChanged -= HandleCharacterStatusChanged;
        _session.InteractionTargetChanged -= HandleInteractionTargetChanged;
        _session = null;
    }

    private void HandleCharacterAdded(CharacterRoomMembership membership) =>
        Debug.Log($"[MultiCharacter] 已添加 {membership.CharacterId} ({membership.MembershipId})。");

    private void HandleCharacterRemoved(CharacterRoomMembership membership) =>
        Debug.Log($"[MultiCharacter] 已移除 {membership.CharacterId} ({membership.MembershipId})。");

    private void HandleCharacterStatusChanged(CharacterRoomMembership membership) =>
        Debug.Log($"[MultiCharacter] {membership.CharacterId} 现在是 {membership.Status}。");

    private void HandleInteractionTargetChanged(CharacterRoomMembership previous, CharacterRoomMembership current) =>
        Debug.Log($"[MultiCharacter] 目标已从 {previous?.MembershipId ?? "无"} 更改为 {current?.MembershipId ?? "无"}。");

    private void OnDestroy() => Detach();
}

移除活动角色时的顺序保证

移除当前持有交互目标的成员会按固定顺序触发两个事件: InteractionTargetChanged 会先触发,并将被移除的成员作为 之前null 当前 随后第二个事件触发。响应,以及 CharacterRemoved 的代码 CharacterRemoved 可以依赖在运行时交互目标已经被清除——无需单独检查 ActiveMembershipId 即可避免读取到过期值。

传入替代目标不会抑制第一个事件。SDK 会先应用移除,再应用新目标,因此带有替代项的移除会触发 InteractionTargetChanged 两次:第一次以 null 当前 随后第二个事件触发。响应,然后再以替代成员触发。应将 null 当前目标视为一种过渡状态,而不是终态。

相关的顺序保证同样适用于添加:当插入新成员时, CharacterAdded 会先触发,再触发 CharacterStatusChanged 针对同一成员的该事件。 CharacterAdded 对于给定成员也只会精确触发一次,即使 Convai 的生命周期消息先于花名册更新确认到达也是如此——SDK 会对两条路径去重,而不是触发两次事件。

CharacterAdded 不会为房间首次连接时已存在的角色触发——那些成员此时已经在 session.Characters 中,等会话对象创建完成时它们已经存在。请直接读取初始花名册,而不要等待 CharacterAdded 关于它的事件;该事件是针对房间已启动后才添加的角色。

会话结束时取消订阅

MultiCharacterRoomSession 每次重连时都会被替换,因此附加到某个会话实例上的处理程序在该实例被丢弃后就不再接收事件。请在 OnDisableOnDestroy中解除绑定,并重新绑定到新的 CurrentMultiCharacterSession 在……之后 IConvaiRoomConnectionService.Connected 再次触发。

故障排查

症状
原因
修复方法

CharacterAdded 从不会为场景初始时就存在的角色触发

这些成员是在创建会话对象时填充的,而不是通过运行时添加代码路径加入的。

阅读 session.Characters 在连接后立即读取,而不要等待 CharacterAdded.

InteractionTargetChanged 以……触发 随后第二个事件触发。响应 当前 null 意外地

持有目标的成员已被移除。无论是否提供替代目标,都会触发此事件。

预期行为。传入 replacementTargetMembershipId在运行时添加和移除角色 这样第二个事件会立即恢复目标,并将 null 视为一种过渡。

你期望的事件根本没有触发

底层确认已过期或重复,并被 epoch 保护机制丢弃。

参见 多角色会话的工作方式.

下一步

切换交互目标在运行时添加和移除角色角色身份与称呼

最后更新于

这有帮助吗?