> 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 是一个领域服务，它会将附近的玩家分组到各个岛屿中，在他们移动时重新分配，并提供连接到实际后端所需的信息，后端会转发他们的消息。

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

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

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

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

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

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

{% hint style="warning" %}
虽然较大的领域运行 Archipelago 服务，但较小的领域可能会选择为所有玩家提供固定的后端连接字符串。若存在该 URI，可在以下位置找到： `comms.fixedAdapter` 领域的 `/about`.
{% endhint %}

在这些情况下，将无法使用动态岛屿分配，并且不应将该领域的 RPC 接口用于此目的。

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

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

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

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

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

```mermaid
序列图
    参与者 Client
    参与者 Archipelago
    
    Client 和 Archipelago 之间的注释：连接
    Client->>Archipelago：ChallengeRequestMessage
    Archipelago->>Client：ChallengeResponseMessage
    Client->>Archipelago：SignedChallengeMessage
    Archipelago->>Client：WelcomeMessage
```

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

在会话期间，客户端必须定期发送一个 [`心跳`](#Heartbeat) 消息，以便让 Archipelago 持续获得发放岛屿分配所需的必要信息。

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

如果客户端停止发送 [`心跳`](#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)

由客户端作为会话的第一条消息发送，以启动身份验证流程。

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

该 `地址` 字段必须从 [身份验证链](https://github.com/decentraland/docs/tree/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/tree/main/contributor/auth/authchain/README.md) ，并以挑战签名结束。 |

其中的第一个键 [身份验证链](https://github.com/decentraland/docs/tree/main/contributor/auth/authchain/README.md) 必须对应于最初发送的地址 [`ChallengeRequestMessage`](#ChallengeRequestMessage).

***

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

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

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

第一个 `心跳` 客户端发送的消息后很快会跟随一个 [`IslandChangedMessage`](#IslandChangedMessage) 来自 Archipelago 的消息。不过，后续更新与岛屿分配无关。客户端不应期望 `心跳` 得到对……的响应。

当 `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/tree/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/tree/main/contributor/communications/transports/README.md). |
| `peers`          | `map<string, Position>` | 说明。                                                                                                             |

收到一个……的客户端 `IslandChangedMessage` 应结束与岛屿后端的连接，并连接到以下字段给出的那个 `conn_str`.

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

***

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

Archipelago 在关闭连接前发送。

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

该字段的标准值包括： `原因` 字段有：

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

***

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

当某个对等方被分配到客户端的岛屿时，由 Archipelago 发送。

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

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

***

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

当某个对等方从客户端的岛屿中移除时，由 Archipelago 发送。

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

该 `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 by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.decentraland.org/contributor/contributor-zh/tong-xin/archipelago.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.
