> 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-unity-sdk/features/scene-metadata/scripting-api-reference.md).

# 场景元数据脚本 API

场景元数据脚本接口分为三部分。 `ConvaiObjectMetadata` 是每个场景对象上的组件——可在运行时用它读取和更新对象属性及跟踪属性。 `ConvaiMetadataRegistry` 是静态中心注册表——可用它查询注册状态并监听变化。 `ConvaiSceneMetadataCollector` 是运行时编排器——可用它触发收集、检查就绪状态并审计所有已注册对象。

### ConvaiObjectMetadata

`ConvaiObjectMetadata` 是一个 `MonoBehaviour` ——可通过序列化字段或 `GetComponent<ConvaiObjectMetadata>()`访问它。有关 Inspector 字段、生命周期和验证规则，请参见 [场景元数据组件参考](/api-docs/zh/cha-jian-yu-ji-cheng/convai-unity-sdk/features/scene-metadata/component-reference.md).

#### 属性

| 成员                  | 类型       | 描述                                                                   |
| ------------------- | -------- | -------------------------------------------------------------------- |
| `ObjectName`        | `string` | 可读/可设。对象的显示名称。在对象已注册时设置新值，会将更改重新同步到每个已连接角色。                          |
| `ObjectDescription` | `string` | 可读/可设。对象的描述文本。在对象已注册时设置新值，会将更改重新同步到每个已连接角色，与 `ObjectName`.           |
| `IncludeInMetadata` | `bool`   | 可读/可设。该对象是否包含在下一次元数据收集中。在对象已注册时设置新值，会将更改重新同步到每个已连接角色，与 `ObjectName`. |
| `IsRegistered`      | `bool`   | 只读。 `true` 当此组件当前已注册到 `ConvaiMetadataRegistry`.                      |
| `IsValid`           | `bool`   | 只读。 `true` 当 `ObjectName` 非空且不全为空白字符时。                               |

{% hint style="info" %}
设置 `ObjectName`, `ObjectDescription`，或 `IncludeInMetadata` 在对象已注册时会自动将新值重新同步到每个已连接角色——无需手动发送。下文中的运行时对象排除模式仍会在设置后显式调用 `CollectAndSendSceneMetadata()` 设置 `IncludeInMetadata`；对于属性更改本身，这次调用现在是多余的，但如果你想强制立即发送并记录到控制台，它仍然有效。
{% endhint %}

#### 方法

| 方法                                                                                                                  | 返回值             | 描述                                                                                                                                                        |
| ------------------------------------------------------------------------------------------------------------------- | --------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `SetTrackedPropertyValue(string propertyName, string value, ConvaiRespondMode reaction = ConvaiRespondMode.Silent)` | `void`          | 更新一个跟踪属性，并立即将新值推送给每个已连接角色。这是从 Inspector 中的 `跟踪属性` 列表轮询得到的跟踪属性的命令式对应方法——当值从代码更改时使用它，而不是依赖自动轮询。 `reaction` 控制更新是否可以让角色开口说话；默认值为 `ConvaiRespondMode.Silent`. |
| `BuildStateKey(string propertyName)`                                                                                | `string`        | 返回此对象上某个跟踪属性的动态上下文状态键，格式为 `"{ObjectName}.{propertyName}"`.                                                                                                |
| `GetValidationErrors()`                                                                                             | `List<string>`  | 返回以下项的验证错误消息： `ObjectName` （必填，最多 50 个字符）和 `ObjectDescription` （最多 200 个字符）。当元数据有效时为空。                                                                    |
| `ToSceneMetadata()`                                                                                                 | `SceneMetadata` | 将此组件的 `ObjectName` 和 `ObjectDescription` 转换为内部用于 RTVI 消息传递的可序列化载荷类型。                                                                                      |

**推送跟踪属性更新：**

{% code title="Door.cs" %}

```csharp
public class Door : MonoBehaviour
{
    [SerializeField] private ConvaiObjectMetadata _metadata;
    private bool _isOpen;

    public void ToggleDoor()
    {
        _isOpen = !_isOpen;
        _metadata.SetTrackedPropertyValue("State", _isOpen ? "open" : "closed");
    }
}
```

{% endcode %}

### ConvaiMetadataRegistry

`ConvaiMetadataRegistry` 是一个静态类。直接通过类名访问所有成员——无需实例或组件引用。

#### 属性

| 成员      | 类型    | 描述                                                           |
| ------- | ----- | ------------------------------------------------------------ |
| `Count` | `int` | 已注册实例的总数，包括无效和已禁用的实例。 `ConvaiObjectMetadata` 实例，包括无效和已禁用的实例。 |

#### 方法

| 方法                        | 返回值                          | 描述                                                                   |
| ------------------------- | ---------------------------- | -------------------------------------------------------------------- |
| `GetAllMetadata()`        | `ConvaiObjectMetadata[]`     | 返回所有已注册实例，包括名称为空、已禁用 `包含在元数据中`，或空引用。                                 |
| `GetValidMetadata()`      | `ConvaiObjectMetadata[]`     | 仅返回非空、具有 `包含在元数据中` 已启用并通过名称验证（`IsValid == true`）的实例。这正是下一次发送中包含的集合。  |
| `GetSceneMetadataList()`  | `List<SceneMetadata>`        | 将所有有效元数据转换为可序列化的传输格式。这是发送给 Convai 的载荷。                               |
| `GetStatistics()`         | `Dictionary<string, object>` | 返回包含以下键的统计明细： `已注册总数`, `有效元数据`, `无效元数据`, `空引用`, `有效名称`, `无效原因`。用于调试。 |
| `CleanupNullReferences()` | `int`                        | 移除已销毁但尚未注销的条目。返回移除的数量。如果对象在正常 Unity 生命周期事件之外被销毁，请调用此方法。              |
| `Clear()`                 | `void`                       | 清除所有已注册条目。用于测试和场景卸载时。不要在生产环境中调用。                                     |

#### 静态事件

| 事件                       | 签名                             | 触发时机                                     |
| ------------------------ | ------------------------------ | ---------------------------------------- |
| `OnMetadataRegistered`   | `Action<ConvaiObjectMetadata>` | 一个 `ConvaiObjectMetadata` 组件启用并完成注册。     |
| `OnMetadataUnregistered` | `Action<ConvaiObjectMetadata>` | 一个 `ConvaiObjectMetadata` 组件禁用或被销毁并完成注销。 |

```csharp
void OnEnable()
{
    ConvaiMetadataRegistry.OnMetadataRegistered += HandleObjectRegistered;
    ConvaiMetadataRegistry.OnMetadataUnregistered += HandleObjectUnregistered;
}

void OnDisable()
{
    ConvaiMetadataRegistry.OnMetadataRegistered -= HandleObjectRegistered;
    ConvaiMetadataRegistry.OnMetadataUnregistered -= HandleObjectUnregistered;
}

private void HandleObjectRegistered(ConvaiObjectMetadata metadata)
{
    Debug.Log($"已注册：{metadata.ObjectName}（总计 {ConvaiMetadataRegistry.Count} 个）");
}

private void HandleObjectUnregistered(ConvaiObjectMetadata metadata)
{
    Debug.Log($"已注销：{metadata.ObjectName}");
}
```

### ConvaiSceneMetadataCollector

通过组件引用访问。 `ConvaiManager` 在启动时注入依赖项——无需手动设置。

```csharp
private ConvaiSceneMetadataCollector _collector;

void Awake()
{
    _collector = FindObjectOfType<ConvaiSceneMetadataCollector>();
}
```

#### 公共方法

| 方法                              | 返回值                   | 描述                                                                                                                           |
| ------------------------------- | --------------------- | ---------------------------------------------------------------------------------------------------------------------------- |
| `IsReadyToSendMetadata()`       | `bool`                | 返回值 `true` 当依赖项已注入且房间会话处于 `Connected` 状态时。调用 `CollectAndSendSceneMetadata()` 之前务必先检查。                                        |
| `CollectAndSendSceneMetadata()` | `void`                | 从 `ConvaiMetadataRegistry`读取所有有效元数据，组装载荷，并通过 RTVI `update-scene-metadata` 消息将其发送给 Convai。如果房间未连接或依赖项尚未注入，则会提前返回并在控制台记录警告或错误。 |
| `GetMetadataCount()`            | `int`                 | 返回可包含且有效的对象数量，不会触发发送。用于 UI 显示或发送前验证。                                                                                         |
| `GetCurrentMetadata()`          | `List<SceneMetadata>` | 返回当前载荷列表，不会触发发送。用于检查下一次调用将发送什么。                                                                                              |
| `ValidateAllMetadata()`         | `void`                | 将所有已注册对象的验证问题记录到控制台。开发期间使用此方法可发现缺失名称、长度超限或已禁用对象。                                                                             |

#### 常见模式

**场景加载时手动触发：**

```csharp
IEnumerator LoadScenario(ScenarioData data)
{
    yield return StartCoroutine(SpawnScenarioProps(data));

    // 等待房间就绪
    yield return new WaitUntil(() => _collector.IsReadyToSendMetadata());
    _collector.CollectAndSendSceneMetadata();
}
```

**运行时对象排除与重新发送：**

```csharp
// 当锁定的门打开时，从 AI 上下文中移除它
void OnDoorUnlocked(ConvaiObjectMetadata doorMetadata)
{
    doorMetadata.IncludeInMetadata = false;
    if (_collector.IsReadyToSendMetadata())
        _collector.CollectAndSendSceneMetadata();
}
```

**发送前审计：**

```csharp
void LogPreSendAudit()
{
    _collector.ValidateAllMetadata(); // 将所有问题打印到控制台
    Debug.Log($"将发送 {_collector.GetMetadataCount()} 个对象");

    var preview = _collector.GetCurrentMetadata();
    foreach (var item in preview)
        Debug.Log($"  - {item.Name}: {item.Description}");
}
```

**调试统计：**

```csharp
var stats = ConvaiMetadataRegistry.GetStatistics();
foreach (var kv in stats)
    Debug.Log($"{kv.Key}: {kv.Value}");
```

### 下一步

{% content-ref url="/pages/16c5aa93667aec71180b560b3408b114f488e893" %}
[场景元数据使用示例](/api-docs/zh/cha-jian-yu-ji-cheng/convai-unity-sdk/features/scene-metadata/usage-examples.md)
{% endcontent-ref %}

{% content-ref url="/pages/f6f3f3d88a3636afea1b0c8774162c2014fba780" %}
[排查场景元数据问题](/api-docs/zh/cha-jian-yu-ji-cheng/convai-unity-sdk/features/scene-metadata/troubleshooting-and-diagnostics.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, and the optional `goal` query parameter:

```
GET https://docs.convai.com/api-docs/zh/cha-jian-yu-ji-cheng/convai-unity-sdk/features/scene-metadata/scripting-api-reference.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

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.
