> For the complete documentation index, see [llms.txt](https://docs.decentraland.org/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.decentraland.org/contributor/contributor-zh/tong-xin/archipelago.md).

# Archipelago

Archipelago 是 realm 服务，它会将附近的玩家分组到各个岛屿中，在他们移动时重新分配，并提供连接到实际后端所需的信息，而该后端会中继他们的消息。

{% hint style="info" %}
你可以通过开源的 [Comms Station](https://decentraland.github.io/comms-station/).
{% endhint %}

要使用该服务，客户端必须连接到其 realm 的 Archipelago websocket 端点并进行身份验证以开始会话。然后，它们可以开始发送位置更新并接收岛屿分配（参见 [客户端生命周期](https://github.com/decentraland/docs/blob/main/contributor/communications/overview/README.md#lifecycle)).

与 Archipelago 服务交换的所有消息都使用 protocol buffers 编码，如 Decentraland 中所定义的 [协议仓库](https://github.com/decentraland/protocol).

### 连接 <a href="#connecting" id="connecting"></a>

首先，客户端必须建立一个安全的 websocket 连接（`wss:`）到 realm 的 `/archipelago/ws` 端点。

一旦连接成功，客户端会有一个由 realm 策略定义的时间窗口（默认 60 秒）来发送认证流程中的每条消息， [身份验证](#authenticating) 。

{% hint style="warning" %}
虽然较大的 realm 运行 Archipelago 服务，但较小的 realm 可能会为所有玩家提供固定的后端连接字符串。如果存在该 URI，可在 realm 的 `comms.fixedAdapter` 属性中找到，位于 realm 的 `/about`.
{% endhint %}

在这些情况下，动态岛屿分配将不可用，并且 realm 的 RPC 接口不应被用于该目的。

### 身份验证 <a href="#authenticating" id="authenticating"></a>

在连接到 Archipelago 后，客户端必须先向服务请求并签署一个挑战，以验证其身份。

客户端发送的第一条消息是一个 [`ChallengeRequestMessage`](https://github.com/decentraland/docs/blob/main/contributor/communications/ChallengeRequestMessage/README.md) ，其中包含其 Ethereum 地址（即其公钥）。它们将收到一个 [`ChallengeResponseMessage`](https://github.com/decentraland/docs/blob/main/contributor/communications/ChallengeResponseMessage/README.md) ，其中包含一个随机生成的待签名字符串，并且必须使用 [`SignedChallengeMessage`](#SignedChallengeMessage).

该 [`SignedChallengeMessage`](#SignedChallengeMessage) ，其中携带一个 JSON 序列化的 [认证链](https://github.com/decentraland/docs/blob/main/contributor/auth/authchain/README.md) ，该认证链以提供的地址开头，以挑战签名结束。

如果服务成功验证了签名，客户端就会通过身份验证，并将收到一个 [`WelcomeMessage`](#WelcomeMessage).

{% @mermaid/diagram content="sequenceDiagram
participant Client
participant Archipelago

```
Note over Client,Archipelago: Connect
Client->>Archipelago: ChallengeRequestMessage
Archipelago->>Client: ChallengeResponseMessage
Client->>Archipelago: SignedChallengeMessage
Archipelago->>Client: WelcomeMessage" %}
```

### 发送心跳 <a href="#heartbeat" id="heartbeat"></a>

在会话期间，客户端必须定期发送一个 [`Heartbeat`](#Heartbeat) 消息，以保持 Archipelago 更新必要的信息，从而发放岛屿分配。

{% hint style="info" %}
comms 客户端的推荐心跳频率大约是每秒一次更新。
{% endhint %}

如果客户端停止发送 [`Heartbeat`](#Heartbeat) 消息，Archipelago（取决于其当前策略）可能会关闭连接。

### 获取岛屿分配 <a href="#assignment" id="assignment"></a>

第一次心跳后不久，Archipelago 会向客户端发送其第一条 [`IslandChangedMessage`](https://github.com/decentraland/protocol/blob/9a568b16b2eafb134177329ba670c1451be8a169/proto/decentraland/kernel/comms/v3/archipelago.proto#L17).

主要字段是 `conn_str`，可用于初始化传输并连接到该岛。其值通常如下所示：

```
livekit:wss://comms.example.com?access_token=eyJhbGciOiJI...
```

第一个 `:` 前面的标签是传输类型，其余部分是该传输的专用 URI。它可以包含预授权令牌或其他参数。

在会话期间，Archipelago 可能会因多种原因在任何时候发送新的分配：

1. 位置变化：客户端报告其正在远离岛屿中的其他人。
2. 岛屿请求：客户端请求被分配到某个特定岛屿。
3. Archipelago 策略：服务决定创建或拆分岛屿，以更好地平衡人数。

客户端必须监听这些分配，按指示关闭并打开传输连接，并在需要时更改所使用的传输类型。

### 客户端消息

**`ChallengeRequestMessage`** [**↗ 源码**](https://github.com/decentraland/protocol/blob/9a568b16b2eafb134177329ba670c1451be8a169/proto/decentraland/kernel/comms/v3/archipelago.proto#L54)

由客户端作为会话的第一条消息发送，用于开始身份验证流程。

| 字段        | 类型    | 值      |
| --------- | ----- | ------ |
| `address` | `字符串` | 用户的地址。 |

该 `address` 该字段必须从 [认证链](https://github.com/decentraland/docs/blob/main/contributor/auth/authchain/README.md) 将要展示的首个私钥派生出来。

***

**`SignedChallengeMessage`** [**↗ 源码**](https://github.com/decentraland/protocol/blob/9a568b16b2eafb134177329ba670c1451be8a169/proto/decentraland/kernel/comms/v3/archipelago.proto#L58)

由客户端在收到一个 [`ChallengeResponseMessage`](#ChallengeResponseMessage)后发送，以完成身份验证流程。

| 字段                | 类型    | 值                                                                                                                  |
| ----------------- | ----- | ------------------------------------------------------------------------------------------------------------------ |
| `auth_chain_json` | `字符串` | 一个 JSON 序列化的 [认证链](https://github.com/decentraland/docs/blob/main/contributor/auth/authchain/README.md) ，其结束于挑战签名。 |

中的第一个键 [认证链](https://github.com/decentraland/docs/blob/main/contributor/auth/authchain/README.md) 必须对应于原始 [`ChallengeRequestMessage`](#ChallengeRequestMessage).

***

**`Heartbeat`** [**↗ 源码**](https://github.com/decentraland/protocol/blob/9a568b16b2eafb134177329ba670c1451be8a169/proto/decentraland/kernel/comms/v3/archipelago.proto#L62)

由客户端按固定间隔发送（通常每秒一次），用于向 Archipelago 更新其位置和/或请求岛屿分配。

| 字段             | 类型     | 值                |
| -------------- | ------ | ---------------- |
| `position`     | `位置`   | 客户端在世界地图中的 3D 位置 |
| `desired_room` | `字符串？` | 客户端希望被分配到的岛屿 ID  |

第一条 `Heartbeat` 消息会很快跟随一个 [`IslandChangedMessage`](#IslandChangedMessage) 来自 Archipelago 的消息。然而，后续更新与岛屿分配无关。客户端不应指望 `Heartbeat` 会得到响应。

当包含 `desired_room` 参数时，服务将尝试满足该请求，但不能保证会重新分配到该岛。这取决于 Archipelago 的策略（例如对岛屿人数的限制）。

### 服务器消息

**`ChallengeResponseMessage`** [**↗ 源码**](https://github.com/decentraland/protocol/blob/9a568b16b2eafb134177329ba670c1451be8a169/proto/decentraland/kernel/comms/v3/archipelago.proto#L8)

由 Archipelago 作为对一个 [`ChallengeRequestMessage`](#ChallengeRequestMessage)

| 字段                  | 类型    | 值                                                                                                             |
| ------------------- | ----- | ------------------------------------------------------------------------------------------------------------- |
| `challenge_to_sign` | `字符串` | 的响应发送，用于生成字符串并创建一个 [认证链](https://github.com/decentraland/docs/blob/main/contributor/auth/authchain/README.md) |
| `already_connected` | `布尔值` | 是否已存在该用户密钥的连接                                                                                                 |

***

**`WelcomeMessage`** [**↗ 源码**](https://github.com/decentraland/protocol/blob/9a568b16b2eafb134177329ba670c1451be8a169/proto/decentraland/kernel/comms/v3/archipelago.proto#L13)

由 Archipelago 在身份验证成功后发送。

| 字段        | 类型    | 值                         |
| --------- | ----- | ------------------------- |
| `peer_id` | `字符串` | 已通过身份验证的客户端的唯一标识符（通常是其地址） |

***

**`IslandChangedMessage`** [**↗ 源码**](https://github.com/decentraland/protocol/blob/9a568b16b2eafb134177329ba670c1451be8a169/proto/decentraland/kernel/comms/v3/archipelago.proto#L17)

由 Archipelago 在客户端被（重新）分配到某个岛屿时发送。

描述。

| 字段               | 类型                      | 值                                                                                                               |
| ---------------- | ----------------------- | --------------------------------------------------------------------------------------------------------------- |
| `island_id`      | `字符串`                   | 新岛屿的 ID                                                                                                         |
| `from_island_id` | `字符串？`                  | 旧岛屿的 ID，如果这是一次重新分配                                                                                              |
| `conn_str`       | `字符串`                   | 该岛屿的连接字符串 [传输](https://github.com/decentraland/docs/blob/main/contributor/communications/transports/README.md). |
| `peers`          | `map<string, Position>` | 描述。                                                                                                             |

收到一个 `IslandChangedMessage` 的客户端应结束与岛屿后端的连接，并连接到 `conn_str`.

该 `peers` 字段中包含该岛屿内所有 peer 的当前身份和位置，以便客户端填充其初始集合。在此之后，它们应依赖通过岛屿 [传输](https://github.com/decentraland/docs/blob/main/contributor/communications/transports/README.md) 接收的消息来获取位置更新。

***

**`KickedMessage`** [**↗ 源码**](https://github.com/decentraland/protocol/blob/9a568b16b2eafb134177329ba670c1451be8a169/proto/decentraland/kernel/comms/v3/archipelago.proto#LL37C1-L38C1)

由 Archipelago 在关闭连接之前发送。

| 字段       | 类型             | 值                   |
| -------- | -------------- | ------------------- |
| `reason` | `KickedReason` | Archipelago 关闭连接的原因 |

该 `reason` 字段的标准值有：

* `KR_NEW_SESSION`：另一个连接使用相同的密钥完成了身份验证。

***

**`JoinIslandMessage`** [**↗ 源码**](https://github.com/decentraland/protocol/blob/9a568b16b2eafb134177329ba670c1451be8a169/proto/decentraland/kernel/comms/v3/archipelago.proto#L29)

由 Archipelago 在某个 peer 被分配到客户端的岛屿时发送。

| 字段          | 类型    | 值                     |
| ----------- | ----- | --------------------- |
| `island_id` | `字符串` | 该岛屿的标识符               |
| `peer_id`   | `字符串` | 该 peer 的唯一标识符（通常是其地址） |

该 `island_id` 字段将与客户端当前的分配相匹配。

***

**`LeftIslandMessage`** [**↗ 源码**](https://github.com/decentraland/protocol/blob/9a568b16b2eafb134177329ba670c1451be8a169/proto/decentraland/kernel/comms/v3/archipelago.proto#L24)

由 Archipelago 在某个 peer 从客户端的岛屿中移除时发送。

| 字段          | 类型    | 值                     |
| ----------- | ----- | --------------------- |
| `island_id` | `字符串` | 该岛屿的标识符               |
| `peer_id`   | `字符串` | 该 peer 的唯一标识符（通常是其地址） |

该 `island_id` 字段将与客户端当前的分配相匹配。


---

# 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.decentraland.org/contributor/contributor-zh/tong-xin/archipelago.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.
