> 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

场景元数据类的完整 C# 参考，涵盖对象属性、跟踪属性更新、注册表查询和手动发送触发器。

场景元数据脚本接口由三个部分组成。 `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` | 获取/设置。对象的显示名称。对象已注册时设置新值，会将更改重新同步到每个已连接的角色。                          |
| `对象描述`         | `string` | 获取/设置。对象的描述文本。对象已注册时设置新值，会将更改重新同步到每个已连接的角色，与 `ObjectName`.           |
| `包含在元数据中`      | `bool`   | 获取/设置。此对象是否包含在下一次元数据收集中。对象已注册时设置新值，会将更改重新同步到每个已连接的角色，与 `ObjectName`. |
| `IsRegistered` | `bool`   | 只读。 `true` 当此组件当前已在 `ConvaiMetadataRegistry`.                        |
| `IsValid`      | `bool`   | 只读。 `true` 当 `ObjectName` 中注册且非空、非空白字符时。                             |

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

#### 方法

| 方法                                                                                                                  | 返回              | 说明                                                                                                                                                                  |
| ------------------------------------------------------------------------------------------------------------------- | --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `SetTrackedPropertyValue(string propertyName, string value, ConvaiRespondMode reaction = ConvaiRespondMode.Silent)` | `void`          | 更新一个跟踪属性，并立即将新值推送到每个已连接的角色。这是对从 `Tracked Properties` Inspector 中的列表轮询的跟踪属性的命令式对应方法——当值由代码更改时调用它，而不是依赖自动轮询。 `reaction` 控制更新是否可以让角色说话；默认为 `ConvaiRespondMode.Silent`. |
| `BuildStateKey(string propertyName)`                                                                                | `string`        | 返回此对象上跟踪属性的动态上下文状态键，格式为 `"{ObjectName}.{propertyName}"`.                                                                                                            |
| `GetValidationErrors()`                                                                                             | `List<string>`  | 返回以下项的验证错误消息： `ObjectName` （必填，最多 50 个字符）和 `对象描述` （最多 200 个字符）。元数据有效时为空。                                                                                            |
| `ToSceneMetadata()`                                                                                                 | `SceneMetadata` | 将此组件的 `ObjectName` 和 `对象描述` 转换为 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` 是一个静态类。直接通过类名访问所有成员——无需实例或组件引用。

#### 属性

| 成员   | 类型    | 说明                                            |
| ---- | ----- | --------------------------------------------- |
| `数量` | `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($"Registered: {metadata.ObjectName} ({ConvaiMetadataRegistry.Count} total)");
}

private void HandleObjectUnregistered(ConvaiObjectMetadata metadata)
{
    Debug.Log($"Unregistered: {metadata.ObjectName}");
}
```

### ConvaiSceneMetadataCollector

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

```csharp
private ConvaiSceneMetadataCollector _collector;

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

#### 公共方法

| 方法                              | 返回                    | 说明                                                                                                           |
| ------------------------------- | --------------------- | ------------------------------------------------------------------------------------------------------------ |
| `IsReadyToSendMetadata()`       | `bool`                | 返回 `true` 当依赖项已注入且房间会话处于 `已连接` 状态时。调用 `CollectAndSendSceneMetadata()` 之前务必检查此项。                              |
| `CollectAndSendSceneMetadata()` | `void`                | 从 `ConvaiMetadataRegistry`读取所有有效元数据，组装负载，并通过 RTVI `更新场景元数据` 消息将其发送到 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($"Will send {_collector.GetMetadataCount()} objects");

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