# Unity

通过实践学习，并在 Edgegap 上部署您的第一个专用服务器。在本指南结束时，您将能够以零成本使用 Edgegap 部署一个专用服务器。

{% embed url="<https://youtu.be/4FR04V4YEUk>" %}

## ✔️ 准备工作

<details>

<summary><a href="https://github.com/edgegap/edgegap-unity-plugin">安装 Edgegap 的 Unity 专用服务器快速入门插件</a></summary>

</details>

{% hint style="info" %}
**对您的服务器构建很有信心吗？** 跳转到 [#customize-server-image](#customize-server-image "mention") 或 [advanced-features](https://docs.edgegap.com/zh/learn/advanced-features "mention") 了解更多。
{% endhint %}

## ⚙️ 1. 连接账户

☑️ 登录并确认您的 Unity 控制台中没有与 Edgegap 插件相关的新错误。

✅ 现在您可以继续下一步了。

<details>

<summary>故障排除与常见问题</summary>

`!Success: 400 BAD REQUEST - POST | https://api.edgegap.com/v1/wizard/init-quick-start - {"message": "浏览器（或代理）发送了此服务器无法理解的请求。"}`

* 如果您是通过复制 ZIP 文件安装的，或者使用了一个以这种方式复制插件的示例项目，则您需要手动安装包依赖项，包括 Newtonsoft JSON 库，请参阅 [官方插件仓库](https://github.com/edgegap/edgegap-unity-plugin/tree/main?tab=readme-ov-file#instructions-1).
* 如果不是这种情况，请通过 [社区 Discord](https://discord.gg/NgCnkHbsGp) 联系我们寻求帮助。

</details>

## 🔧 2. 构建游戏服务器

无论您使用的是 Windows、Mac 还是 Linux 机器，您都 **需要为 Linux 运行时构建服务器**，因为现在大多数云服务提供商（包括 Edgegap）都运行在 Linux 上。别担心，使用我们的插件完成此操作不需要任何 Linux 知识。

☑️ **确认您已安装所需的 Unity Linux 构建工具。**

☑️ 编辑构建设置，以 **确保所有必需的游戏场景都已包含**.

{% hint style="info" %}
**高级 Unity 用户** - 可选地更改 [Unity 构建设置](https://docs.unity3d.com/Manual/BuildSettings.html)。注意！这可能会破坏您的构建。
{% endhint %}

☑️ 可选：从 Edgegap Server Hosting 菜单（右键 / :heavy\_plus\_sign: 在 Hierarchy 窗口中）将用于端口验证和环境初始化的特定于 netcode 的脚本添加到您的初始服务器场景中。

<figure><img src="https://3334189208-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2FZ8dV9ERoV3rczrXXUdV9%2Fimage.png?alt=media&#x26;token=f7c44a27-7521-4392-9d11-276c48410ed0" alt="" width="360"><figcaption></figcaption></figure>

{% hint style="info" %}
当您完成步骤 [#id-6.-deploy-a-server-on-edgegap](#id-6.-deploy-a-server-on-edgegap "mention")后，如果您的 netcode 地址或端口与您的 Edgegap [应用版本端口映射](https://docs.edgegap.com/zh/learn/bian-pai/application-and-versions#other-parameters-optional) 配置不匹配，端口验证脚本将记录警告。
{% endhint %}

{% hint style="success" %}
服务器构建应在您的 netcode 传输中使用地址 `0.0.0.0`  和端口 `7777`  。如果您自定义了端口，请在您 [#port-mapping](https://docs.edgegap.com/zh/learn/bian-pai/application-and-versions#port-mapping "mention") 之后指定相同的端口 [#id-5.-upload-to-edgegap](#id-5.-upload-to-edgegap "mention").
{% endhint %}

☑️ 当您对配置满意后，点击 **构建服务器**，等待 प्रक्रिया 完成并确认您的 Unity 控制台中没有新错误。完成此步骤后，您的 **项目根目录中会出现一个新文件夹** - `Builds/EdgegapServer/ServerBuild` .

✅ 现在您可以继续下一步了。

<details>

<summary>故障排除与常见问题</summary>

Unity：唯一受支持的独立目标是带有 OpenXR 的 Windows x64 和 OSX。

* 在构建服务器之前，请打开 Packages 并禁用 OpenXR。
* OpenXR 插件仅客户端需要，并且与 Linux 服务器构建不兼容。将其从服务器构建中排除不会丢失任何功能。

</details>

## 🐋 3. 将服务器容器化

在开发者团队中工作意味着要共享代码。当事情出错时，您最不想听到的就是“在我机器上是好的”。游戏服务器必须在任何机器上都可靠运行，因为一个成功游戏的服务器会在全球成千上万台服务器机器上运行。

为了帮助您的服务器更可靠，我们使用 Docker——一种虚拟化软件，可确保您的所有服务器代码依赖项一直到操作系统级别，在服务器启动方式或位置如何变化的情况下都始终完全一致。

☑️ 现在，请先点击 **验证** 按钮以确保您已完成 [#usage-requirements](https://docs.edgegap.com/zh/developer-tools#usage-requirements "mention").

☑️ 您可以配置以下选项（或保持默认值）：

* **构建路径** 是指向您的服务器构建产物的相对路径，暂时保持默认即可。

{% hint style="warning" %}
Docker 只接受相对于项目根文件夹的构建路径， **请将构建保留在项目文件夹内**.
{% endhint %}

* **镜像名称** 是您自定义的唯一标识，用于在发布前标记您的服务器构建。
  * 通常，这会包含您的游戏名称——例如“my-game-server”。
* **镜像标签** 是指向镜像特定版本的标识。
  * “构建产物”一词有时用于指代镜像的特定版本。
  * 时间戳是一个很好的标签选项，例如 `2024.01.30-16.23.00-UTC` .
* **Dockerfile 路径** 可用于自定义您的镜像构建配方。
  * 我们建议暂时保持默认设置，您稍后可以在 [#customize-server-image](#customize-server-image "mention").
* **可选的 docker 构建参数** 部分了解更多。
  * 可用于进一步向 Docker 指示更细微的设置。 [我们建议暂时保持默认设置，您可以](https://docs.docker.com/reference/cli/docker/image/build/#options).

☑️ 当您对配置满意后，点击 **稍后在 Docker 文档中阅读更多内容**，等待 प्रक्रिया 完成并确认您的 Unity 控制台中没有新错误。完成此步骤后，您的 **新镜像出现在您的本地机器上**。您可以在 Docker Desktop 的 Local（默认）下的 Images 选项卡中验证这一点，或者在 docker CLI 中运行 `docker images` .

✅ 现在您可以继续下一步了。

<details>

<summary>故障排除与常见问题</summary>

`/bin/bash：找不到 docker：命令` ，或者 `找不到 Packages\com.edgegap.unity-servers-plugin\Editor`

* 首先，确保您已完成 [#usage-requirements](https://docs.edgegap.com/zh/developer-tools#usage-requirements "mention").
* 确认您已验证您的 Edgegap 账户，您应该已通过电子邮件收到验证链接。
* 更新 Docker Desktop 后，某些设置可能已重置。请尝试进入 Docker Desktop 设置 / 高级，并在“Choose how to configure the installation of Docker’s CLI tools:”中选择“System (requires password)”。

***

`docker build 需要恰好 1 个参数`

* 请确认您的镜像标签不包含任何空白字符（空格、制表符）。重新输入镜像标签值可以确保您没有意外复制这些字符。

***

`(HTTP code 400) unexpected - invalid tag format`

* 这是一个 [macOS Docker 4.33 版本中的已知问题](https://github.com/docker/for-win/issues/14258)，请考虑回滚到 4.32 或升级到 4.35。

***

`ERROR: failed to solve: ubuntu:22.04: failed to resolve source metadata for http://docker.io/library/ubuntu:22.04: failed to authorize: failed to fetch oauth token`

* 您位于中国吗？您的连接可能会被防火长城中断。请尝试手动运行 `docker pull ubuntu:22.04` 在命令行中（按 Win+R 打开命令行，然后输入 `cmd` 并按 Enter）。

***

`System.IndexOutOfRangeException：索引超出了数组的范围。`

* 如果您是通过下载 ZIP 文件安装我们的 Unity 快速入门插件，您的 Unity Editor 缓存可能已损坏。请尝试删除插件副本，并使用 git URL 或从 Unity Asset Store 安装。您将不再需要 Newtonsoft.JSON 包，因为它会与其他源一起自动包含。

***

我的 docker 镜像大小非常大（超过 1GB）/ 非常小（低于 100MB），这样可以吗？

* 在某些情况下这可能没问题，只要您能够运行服务器并成功连接（参见 [#id-4.-test-your-server-locally](#id-4.-test-your-server-locally "mention")）。如果不是这种情况，请考虑检查您的构建选项，将其重置为默认值，并逐步添加选项以查看它们如何影响构建大小。另请参阅 [#optimize-server-build-size](#optimize-server-build-size "mention").

***

我遇到了本文档中任何地方都未提到的其他问题。

* 首先，请尝试 [更新您的 Edgegap 插件](https://github.com/edgegap/edgegap-unity-plugin?tab=readme-ov-file#update-the-plugin-in-unity) ，因为我们可能已经发布了修复。如果这没有帮助，请通过我们的 [社区 Discord](https://discord.gg/NgCnkHbsGp) 联系我们，我们会立即与您一起调查。

</details>

## 🧪 4. 在本地测试服务器

☑️ 您可以配置以下选项（或保持默认值）：

* **服务器镜像标签** 来自上一步。
  * 默认为您使用该插件构建的最后一个标签。
* **可选的 docker run 参数** 可用于暴露多个端口，或在 macOS 机器上运行您的镜像。
  * 如有需要，您可以为容器发布多个端口，只需为每个端口添加参数 `-p {internal port}/{protocol}` ，例如 `-p 8080/tcp -p 7770/udp` 即可发布并映射您的服务器端口 `8080` 到一个随机外部端口用于 TCP 连接，并同时将服务器端口 `7777` 到一个随机外部端口用于 UDP 连接。
  * **在您的 Transport 或特定 netcode 的设置中查找服务器端口配置。**
  * 如果您使用的是 ARM 架构的机器（macOS M1、M2、M3 等），您应该在可选的 docker 构建参数中看到包含此可选参数： `--platform=linux/amd64` .

☑️ 当您对配置满意后，点击 **部署本地容器**，等待进程完成，并确认您的 Unity 控制台中没有新错误。完成此步骤后，您的 **将启动一个新容器** 在您的开发机器上。

{% hint style="info" %}
更多详情请参见 Docker Desktop / Containers，或 Docker CLI 命令 `docker ps` .
{% endhint %}

☑️ 现在是时候 **将您的 Unity Editor 游戏客户端连接到本地 docker 容器** 以验证您的服务器镜像是否正常工作。找到您的 netcode 客户端设置并输入：

* `localhost` 或 `127.0.0.1` （在大多数情况下等同）替代服务器 IP，
* 在 Docker Desktop / Containers / edgegap-server-test 中找到的随机化外部端口值。

✅ 现在您可以继续下一步了。

<details>

<summary>故障排除与常见问题</summary>

我无法使用 Unity Editor 游戏客户端连接到本地 docker 容器。

* 首先，确保容器状态为 Up，而不是 Restarting 或 Exited，这将表明存在运行时异常。如果您的容器未运行，请通过 Docker Desktop 的 Containers 选项卡（点击您的容器）或使用 `docker logs {container_id} --timestamps` 通过 docker CLI 查看其日志。
* 接下来，请确认您的服务器构建中的 Network Manager 端口设置与 **可选的 docker run 参数**中的发布端口一致。如果不一致，请尝试重置或手动更改此输入字段的值，使其与 `{container}` 端口一致，并调整您的 Network Manager 设置。请在您的 netcode 设置中查找协议。
* 最后，确认您的 Unity Editor 游戏客户端 netcode 设置使用的是 **可选的 docker run 参数** 中发布的端口（参见上方截图）。

***

`（分段错误）- 核心已转储`

* 如果您使用的是 ARM 架构的机器（macOS M1、M2、M3 等），您应该在可选的 docker 构建参数中看到包含此可选参数： `--platform=linux/amd64` 。如果不是，请尝试重置此输入字段的值。

***

`在 SceneObjects 中找不到 SceneId 为 9120233082191360994 的对象。`

* 这可能意味着您尝试加载的场景未正确包含在构建中，这是旧版插件中的已知问题。为解决此问题，请尝试更新您的 netcode 集成版本或 [更新您的 Edgegap 插件](https://github.com/edgegap/edgegap-unity-plugin?tab=readme-ov-file#update-the-plugin-in-unity).

***

`http2: 服务器：从客户端读取 preface 时出错 //./pipe/docker_engine：文件已经被关闭`

* 这是一个 [Windows 版 Docker Desktop 的旧版本中的已知问题](https://github.com/docker/for-win/issues/13611)。请更新您的 Docker Desktop 应用并再次尝试容器化。

***

`Curl 错误 35：证书握手失败。致命错误。UnityTls 错误代码：7`

* 此错误表示根 SSL 证书验证问题，这是旧版插件中的已知问题。为解决此问题，请尝试 [更新您的 Edgegap 插件](https://github.com/edgegap/edgegap-unity-plugin?tab=readme-ov-file#update-the-plugin-in-unity).

</details>

## ☁️ 5. 上传到 Edgegap

☑️ 您可以配置以下选项（或保持默认值）：

* **应用名称** 在 Edgegap 上可以与您的镜像名称一致，也可以自定义。
  * 我们目前选择复制您的镜像名称。
* **应用版本** 在 Edgegap 上可以与您的标签一致，也可以自定义。
  * 时间戳是应用版本名称的好选择，例如 `2024.01.30-16.50.20-UTC` .
  * 多个应用版本可以指向同一个镜像标签，例如 `v1.1.0` 和 `dev` .
  * 了解更多关于 [application-and-versions](https://docs.edgegap.com/zh/learn/bian-pai/application-and-versions "mention") 的内容，稍后再说。
* **服务器镜像名称** 来自步骤 [#id-3.-containerize-your-game-server](#id-3.-containerize-your-game-server "mention").
* **服务器镜像标签** 来自步骤 [#id-3.-containerize-your-game-server](#id-3.-containerize-your-game-server "mention").

{% hint style="success" %}
在 **Docker Desktop / Images**.
{% endhint %}

☑️ 当您对配置满意后，点击 **中找到保存在您机器上的任意镜像名称和标签**上传镜像并创建应用版本

，等待进程完成，并确认您的 Unity 控制台中没有新错误。 [☑️ 您将被带到我们的](https://app.edgegap.com/)控制面板 [，您可以在那里配置可选设置。完成此步骤后将会创建一个](https://app.edgegap.com/application-management/applications/list)新的应用版本 [，并将您的](https://app.edgegap.com/registry-management/repositories/list).

现在系统会提示您为新的应用版本定义一个端口。请确保将服务器端口值设置为与步骤 [#id-4.-test-your-server-locally](#id-4.-test-your-server-locally "mention") 中来自您的 Transport 或特定 netcode 设置的值相同。

✅ 现在您可以继续下一步了。

## 🚀 6. 部署到云端

☑️ 现在我们将进行最终测试，并 **将您的 Unity Editor 游戏客户端连接到云端部署**。输入来自部署详情中的游戏客户端连接信息：

* **主机** **URL** 指向服务器 IP，通常在 `NetworkManager` 组件中。
* **外部端口** 映射到 [服务器的内部监听端口](https://docs.edgegap.com/zh/learn/bian-pai/application-and-versions#port-mapping)，通常在 Transport 组件中。

<details>

<summary>故障排除与常见问题</summary>

无法将客户端连接到服务器 - `请求超时。` , `请求超时` , `ConnectionFailed` ，或者 `端口验证失败`

* 首先，确保部署状态为 Ready，并且您的部署日志中没有运行时异常或错误。如果您的部署已停止，请在我们的 [☑️ 您将被带到我们的](https://app.edgegap.com/deployment-management/deployments/list).
* 如果您使用的是 Mirror netcode，则需要将 ["Auto Start Server”](https://mirror-networking.gitbook.io/docs/hosting/edgegap-hosting-plugin-guide#build-and-push) 在您的 `NetworkManager` 中选中，然后重新构建、推送并重新部署您的服务器。
* 如果您使用的是 FishNet netcode，则需要启用 [“Start on Headless”](https://fish-networking.gitbook.io/docs/manual/components/managers/server-manager#settings-are-general-settings-related-to-the-servermanager) 在您的 `ServerManager`中选中，然后重新构建、推送并重新部署您的服务器。
* 如果您使用的是 Photon Fusion 2 netcode，请确保您的服务器传递了部署公网 IP、外部端口以及 `roomCode` 在服务器上，并在客户端的 [“NeworkRunner.StartGame”](https://doc.photonengine.com/fusion/current/manual/network-runner#creating-or-joining-a-room) 参数中使用相同的房间代码 `StartGameArgs`。部署 ID（例如 `b63e6003b19f`）是一个很好的选择，因为它在全球范围内唯一，并且客户端可通过 [Matchmaker](https://docs.edgegap.com/zh/learn/pi-pei/matchmaker-in-depth) 和 [#injected-environment-variables](https://docs.edgegap.com/zh/learn/pi-pei/matchmaker-in-depth#injected-environment-variables "mention").
* 轻松访问。接下来，请确认您服务器构建的 netcode 设置中的端口设置与您的 [应用版本](https://app.edgegap.com/application-management/applications/list)中的内部端口一致。您可以通过编辑 [应用版本](https://app.edgegap.com/application-management/applications/list) 来更改端口映射，而无需重新构建。在您的 netcode 集成中查找协议。
* 请确保您的游戏客户端正在连接到部署详情页面上显示的 **外部端口** ，由于安全原因，此值始终会随机化。
* 如果您在 netcode 集成中使用安全 WebSocket（WSS）协议，请确保您的 [应用版本](https://app.edgegap.com/application-management/applications/list) WSS 端口的端口配置已启用 TLS 升级。
* 您位于中国并且正在使用 [Smart Fleets](https://docs.edgegap.com/docs/deployment/session/fleet-manager/fleet)吗？您的连接可能会被防火长城阻止。请考虑在您的舰队中添加一个位于中国的服务器，或使用 VPN 进行连接。

***

我的部署已停止/重启，我再也无法访问它的日志。

* 如果服务器进程因异常崩溃，我们的系统将尝试自动重启服务器。建议 [在本地测试您的服务器](#id-4.-test-your-server-locally) 以查明根本原因。
* 我们只会在部署期间保留日志，如果您希望在部署停止后检查日志，请 [集成第三方日志存储](https://docs.edgegap.com/docs/deployment/endpoint-storage).
* 请参阅 [#id-5.-deployment-stopped](https://docs.edgegap.com/zh/learn/bian-pai/deployments#id-5.-deployment-stopped "mention") 以了解导致部署停止的所有原因。

***

我的部署在 X 分钟后自动停止了。

* 免费层部署有 60 分钟限制，请考虑升级您的账户。
* 根据我们的服务器清理策略、用于基础设施维护，以及防止在部署未正确关闭时产生意外费用，所有部署将在运行 24 小时后终止。对于长时间运行的服务器，请考虑使用 [si-you-ji-qun](https://docs.edgegap.com/zh/learn/bian-pai/si-you-ji-qun "mention") 配合 [chi-jiu-hua](https://docs.edgegap.com/zh/learn/bian-pai/chi-jiu-hua "mention").
* 请参阅 [#id-5.-deployment-stopped](https://docs.edgegap.com/zh/learn/bian-pai/deployments#id-5.-deployment-stopped "mention") 以了解导致部署停止的所有原因。

***

我的部署已就绪，但之后几分钟内我仍无法连接。

* 一旦部署就绪，您的游戏引擎初始化就会开始。此过程可能需要从几秒到几分钟不等，在此期间服务器不会接受玩家连接。
* 建议优化服务器初始化以缩短这段时间。
* 游戏客户端应每秒重试一次连接，重试一段有限时间（取决于您的初始化持续时间），之后应返回匹配队列。
* 建议添加一个加载场景，这样服务器可以在与客户端同步状态的同时执行初始化（以及在 Unreal Engine 中进行旅行）。

***

我的 Meta Quest 设备报错 `HTTP 0：无法解析目标主机` .

* 当为 Android 目标构建 Unity 应用时，您的 Internet Access 权限可能会从输出的 APK 客户端构建产物中自动移除。
* 在以下位置重新添加权限（需要之后重新构建客户端）：
  * Project Settings / OpenXR / :gear: Meta Quest Support / Force Remove Internet Permissions（取消勾选）。
  * Player Settings / Internet Access（设置为 require）。

***

如果玩家离开我的部署，会发生什么？

* 默认情况下，服务器不会拒绝玩家连接。玩家认证由您开发团队决定，因为可以使用许多不同的方法和玩家认证提供商。
* 游戏客户端可能会在本地存储连接信息，以便在意外客户端崩溃时尝试重新连接。
* 要允许玩家加入正在进行的游戏，请考虑使用 [#backfill](https://docs.edgegap.com/zh/learn/pi-pei/matchmaker-in-depth#backfill "mention") 或 [Sessions](https://docs.edgegap.com/docs/deployment/session).

***

我的服务器在变为就绪后显示 100% CPU 占用。

* 这可能不是问题，因为游戏引擎在服务器初始化期间往往会执行大量 CPU 密集型操作。如果从部署开始 2-3 分钟后 CPU 使用率仍未下降，您可能需要优化服务器或增加应用版本资源。
* 降低 tick rate 可以影响 CPU 使用率，因为服务器执行的消息操作会更少。
* 如果您使用的是 Mirror netcode，则需要将 ["Auto Start Server”](https://mirror-networking.gitbook.io/docs/hosting/edgegap-hosting-plugin-guide#build-and-push) 在您的 `NetworkManager` 中选中，然后重新构建、推送并重新部署您的服务器。
* 如果您使用的是 FishNet netcode，则需要启用 [“Start on Headless”](https://fish-networking.gitbook.io/docs/manual/components/managers/server-manager#settings-are-general-settings-related-to-the-servermanager) 在您的 `ServerManager`中选中，然后重新构建、推送并重新部署您的服务器。
* 在免费层中，您仅限于 1.5 vCPU 和 3GB 内存（RAM）。
* 在创建新的应用版本时，您可以增加分配的资源。您可以在我们的控制面板中复制您的应用版本并根据需要调整这些值，而无需重新构建服务器或镜像。

***

我的部署反复重启并显示错误 `OOM kill`

* 这是由于超出了分配的内存量。建议通过对象池、压缩或移除场景中不需要的对象来优化内存使用。
* 确保您的项目正在加载包含您的 `NetworkManager` 的默认场景，并且该场景已包含在 Unity 的构建设置中。
* 在免费层中，您仅限于 1.5 vCPU 和 3GB 内存（RAM）。
* 在创建新的应用版本时，您可以增加分配的资源。您可以在我们的控制面板中复制您的应用版本并根据需要调整这些值，而无需重新构建服务器或镜像。

***

有时，我服务器的内存（RAM）使用量会激增到很高，这会有问题吗？

* 只要您保持在分配的应用版本内存量以内，这就不是问题。
* 超过分配的应用版本内存量将导致 `OOM kill` （见上文）。

***

同一台机器上运行的其他服务器会影响我的服务器性能吗？

* 不会，我们的平台确保分配的资源不会被其他工作室或共享基础设施上的其他服务器使用。在 Edgegap 上，不存在“吵闹的邻居”。

</details>

## 👉 下一步

### 停止部署

了解各种方法以 [停止部署](https://docs.edgegap.com/zh/learn/bian-pai/deployments#id-5.-deployment-stopped) ，在比赛结束且玩家离开后执行。

为了优雅关闭，我们强烈建议在您的游戏中实现自停止 API：

<details>

<summary>Unity C# 自停止 API 代码片段示例</summary>

```csharp
using System;
using System.Collections;
using UnityEngine;
using UnityEngine.Networking;

public class EdgegapSelfStop : MonoBehaviour
{
    private const int MaxRetries = 2;
    private const int TimeoutSeconds = 30;
    private string url = Environment.GetEnvironmentVariable("ARBITRIUM_DELETE_URL");
    private string token = Environment.GetEnvironmentVariable("ARBITRIUM_DELETE_TOKEN");

    public void Run()
    {
        StartCoroutine(SendDeleteWithRetry());
    }

    private IEnumerator SendDeleteWithRetry()
    {
        if (string.IsNullOrEmpty(url))
        {
            Debug.LogError("Edgegap | ARBITRIUM_DELETE_URL 未设置。");
            yield break;
        }

        if (string.IsNullOrEmpty(token))
        {
            Debug.LogError("Edgegap | ARBITRIUM_DELETE_TOKEN 未设置。");
            yield break;
        }

        int attempt = 0;

        while (attempt <= MaxRetries)
        {
            attempt++;

            using (UnityWebRequest request = UnityWebRequest.Delete(url))
            {
                request.timeout = TimeoutSeconds;
                request.SetRequestHeader("Authorization", token);

                yield return request.SendWebRequest();

                if (request.result == UnityWebRequest.Result.Success)
                {
                    Debug.Log("Edgegap | DELETE 请求成功。");
                    yield break;
                }

                Debug.LogWarning(
                    $"Edgegap | 第 {attempt} 次 DELETE 尝试失败。\n" +
                    $"结果：{request.result}，错误：{request.error}"
                );

                if (attempt == MaxRetries)
                {
                    Debug.LogError("Edgegap | 在所有重试后 DELETE 请求仍失败。");
                    yield break;
                }
            }
        }
    }
}
```

</details>

{% hint style="info" %}
您的 Unity 服务器将在崩溃或内存不足时自动重启。
{% endhint %}

### 注入变量

通过访问注入的环境变量，读取部署 ID、服务器 IP 地址、服务器位置等有用信息。每个部署都会自动包含：

* [部署变量](https://docs.edgegap.com/zh/learn/bian-pai/deployments#injected-environment-variables) - 由 Edgegap 自动提供，
* [匹配变量](https://docs.edgegap.com/zh/learn/pi-pei/matchmaker-in-depth#injected-environment-variables) - 在使用 [pi-pei](https://docs.edgegap.com/zh/learn/pi-pei "mention"),
* [应用版本变量](https://docs.edgegap.com/zh/learn/bian-pai/application-and-versions#injected-variables) - 由您配置的自定义键值对。

**通过检查 Edgegap 变量是否已设置来验证当前实例是游戏客户端还是服务器** ：

```csharp
if (
  string.IsNullOrEmpty(Environment.GetEnvironmentVariable("ARBITRIUM_REQUEST_ID"))
)
{
  // 客户端代码
} else {
  // 服务器代码
}
```

### 匹配

手动启动您的部署、粘贴 URL 和端口对于在线游戏来说是不够的。

{% hint style="success" %}
[**阅读更多关于匹配的信息**](https://docs.edgegap.com/zh/learn/pi-pei) **即可自动按需部署**，当玩家上线时。
{% endhint %}

### 优化服务器构建

**仅重新构建自上次构建以来发生更改的资源。**

建议使用 [Unity 的增量构建](https://docs.unity3d.com/Manual/incremental-build-pipeline.html) 来加快构建时间。

* 建议使用 [Unity 的增量构建](https://docs.unity3d.com/Manual/incremental-build-pipeline.html) 来加快构建时间。

**只包含服务器运行绝对需要的内容。**

* 在镜像中复制未使用的文件会导致镜像膨胀、上传时间更长、缓存速度更慢以及整体服务器启动更慢。 [查看 Docker 镜像优化建议](https://docs.docker.com/build-cloud/optimization/#dockerignore-files).

**禁用网格的静态批处理以减小镜像大小。**

* [禁用静态批处理可加快构建、上传和部署速度。](https://docs.unity3d.com/Manual/DrawCallBatching.html)

**压缩网格以减小镜像大小。**

* [将网格压缩设置为 High 以加快构建、上传和部署速度。](https://docs.unity3d.com/6000.0/Documentation/Manual/compressing-mesh-data-optimization.html)
* 顶点压缩不会影响镜像大小。

**实现资源的条件性延迟加载。**

* 通过以下方式排除仅客户端资产： [将纹理和网格设置为禁用 CPU 读/写](https://docs.unity3d.com/6000.0/Documentation/Manual/dedicated-server-optimizations.html).
* 建议使用 [Unity Addressables](https://docs.unity3d.com/Packages/com.unity.addressables@2.1/manual/index.html) 用于您的客户端构建，以便通过以下方式加快构建和部署： [按需加载资源](https://docs.unity3d.com/Packages/com.unity.addressables@1.19/manual/LoadingAddressableAssets.html)，或者在服务器构建中通过检查是否存在来跳过加载某些资源 [#injected-environment-variables](https://docs.edgegap.com/zh/learn/bian-pai/deployments#injected-environment-variables "mention").

**建议使用** [**多阶段 Docker 构建（链接）**](https://docs.docker.com/build/building/multi-stage/)**.**

* 将大型服务器依赖项拆分到单独的镜像中，以便在多阶段构建中重复使用。Docker 会缓存每一层并简单地重用之前的版本，除非特别指示，否则会跳过上传此部分，从而节省您的带宽和等待上传完成的时间。
* 如果您不确定为什么 Dockerfile 的某条命令会报错，请尝试在本地调试。在问题发生之前创建一个新阶段（添加第二个 `FROM` 命令），使用 `--target` 指示构建过程在有问题的阶段停止，然后 `docker exec -it {container} /bin/bash` 进入容器内的交互式终端。之后，您可以使用基础镜像中的 shell 命令进一步调查（例如 `top` 在 ubuntu 上）。

### 自定义服务器镜像

我们也支持为需要更多镜像控制的用户添加自己的 Dockerfile，例如为了优化构建大小、处理额外依赖或需要更复杂的启动流程。您可以在步骤 [#id-3.-containerize-your-game-server](#id-3.-containerize-your-game-server "mention")中选择性地提供自定义 Dockerfile 的路径。接下来我们将分享一些“自己动手”的技巧和最佳实践。

**在使用 WebSockets 或 HTTPS 请求时遇到问题？**

* 如果您遇到 `Curl 错误 35：证书握手失败。致命错误。UnityTls 错误代码：7` 请不要惊慌，这是旧版基础（`FROM`）镜像中包含已过期根证书颁发机构证书的已知问题。您可以通过升级到更新的基础镜像版本（例如 `ubuntu:22.04`）并运行 `update-ca-certificates` 来修复它，请将以下内容添加到您的 Dockerfile：

  ```docker
  FROM ubuntu:22.04

  RUN apt-get install -y ca-certificates && \
      apt-get clean && \
      update-ca-certificates
  ```

{% hint style="info" %}
遇到困难了吗？我们在我们的 [社区 Discord](https://discord.gg/MmJf8fWjnt) 中随时提供帮助。
{% endhint %}
