# 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") 或 [高级功能](/zh/learn/advanced-features.md) 。
{% endhint %}

## ⚙️ 1. 连接账户

☑️ 登录并检查你的 Unity 控制台中是否没有与 Edgegap 插件相关的新错误。

✅ 现在你可以继续下一步。

<details>

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

`!成功：400 错误请求 - 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: 在你的层级窗口中）向初始服务器场景添加用于端口验证和环境引导的 netcode 特定脚本。

<figure><img src="/files/eff6c33e6df7153e5ed6e1c644217fe278c7a43b" alt="" width="360"><figcaption></figcaption></figure>

{% hint style="info" %}
一旦你完成步骤 [#id-6.-deploy-to-cloud](#id-6.-deploy-to-cloud "mention")，如果你的 netcode 地址或端口与你的 Edgegap [应用版本端口映射](/zh/learn/bian-pai/application-and-versions.md#other-parameters-optional) 配置不匹配，端口验证脚本将记录警告。
{% endhint %}

{% hint style="success" %}
服务器构建应在你的 netcode 传输中使用地址 `0.0.0.0`  和端口 `7777`  。如果你自定义了端口，请在你的 [应用与版本](/zh/learn/bian-pai/application-and-versions.md#port-mapping) 中指定相同的值，之后 [#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——一种虚拟化软件，以确保你的所有服务器代码依赖项直到操作系统层级都始终完全相同，无论服务器如何或在何处启动。

☑️ 现在先点击 **验证** 按钮，以确保你已完成 [开发者工具](/zh/unity/developer-tools.md#usage-requirements).

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

* **构建路径** 是你的服务器构建产物的相对路径，我们暂时保持默认值。

{% 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 进一步说明更细微的配置。
  * 我们建议暂时保留默认设置，你可以 [稍后在 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`

* 首先，确保你已完成 [开发者工具](/zh/unity/developer-tools.md#usage-requirements).
* 确认你已验证你的 Edgegap 账户，你应该已通过电子邮件收到验证链接。
* 更新 Docker Desktop 后，某些设置可能已重置。尝试进入 Docker Desktop 设置 / 高级，并在“选择如何配置 Docker CLI 工具的安装：”中选择“系统（需要密码）”。

***

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

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

***

`（HTTP 代码 400）意外错误 - 无效的标签格式`

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

***

`错误：解决失败：ubuntu:22.04：为 http://docker.io/library/ubuntu:22.04 解析源元数据失败：授权失败：获取 oauth 令牌失败`

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

***

`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 运行参数** 可用于暴露多个端口，或在 macOS 机器上运行你的镜像。
  * 如果需要，你可以为容器发布多个端口，只需为每个端口添加参数 `-p {内部端口}/{协议}` ，例如 `-p 8080/tcp -p 7777/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` 或 `0.0.0.0` （在大多数情况下等同）代替服务器 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 运行参数**中发布的端口一致。如果不一致，请尝试重置或手动更改此输入字段的值以匹配 `{container}` 端口与你的 Network Manager 设置。请在你的 netcode 设置中查找协议。
* 最后，确认你的 Unity Editor 游戏客户端 netcode 设置使用的是在 **可选的 docker 运行参数** 中发布的端口（见上方截图）。

***

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

* 如果你使用的是 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` .
  * 了解更多关于 [应用与版本](/zh/learn/bian-pai/application-and-versions.md) 的信息，稍后。
* **服务器镜像名称** 来自步骤 [#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 控制台中没有新错误。 [Dashboard](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` 组件中。
* **外部端口** 映射到 [服务器的内部监听端口](/zh/learn/bian-pai/application-and-versions.md#port-mapping)，通常在 Transport 组件中。

<details>

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

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

* 首先，确保部署状态为 Ready，并且你的部署日志中没有运行时异常或错误。如果部署已停止，请在我们的 [Dashboard](https://app.edgegap.com/deployment-management/deployments/list).
* 如果你使用 Mirror netcode，你需要启用 [“自动启动服务器”](https://mirror-networking.gitbook.io/docs/hosting/edgegap-hosting-plugin-guide#build-and-push) 在你的 `NetworkManager` 中勾选，然后重新构建、推送并重新部署你的服务器。
* 如果你使用 FishNet netcode，你需要启用 [“在无头模式下启动”](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](/zh/learn/pi-pei/matchmaker-in-depth.md) 和 [深入了解](/zh/learn/pi-pei/matchmaker-in-depth.md#injected-environment-variables).
* 接下来，请验证你的服务器构建中的 netcode 设置里的端口配置是否与你的 [App 版本](https://app.edgegap.com/application-management/applications/list)中的内部端口一致。你可以通过编辑 [App 版本](https://app.edgegap.com/application-management/applications/list) 来更改端口映射，而无需重新构建。在你的 netcode 集成中找到你的协议。
* 请确保你的游戏客户端连接到容器详情页面上显示的 **外部端口** ，出于安全原因，此值始终会随机生成。
* 如果你在 netcode 集成中使用 Secure Websocket（WSS）协议，请确保你的 [App 版本](https://app.edgegap.com/application-management/applications/list) WSS 端口的端口配置已启用 TLS Upgrade。
* 你是否位于中国并正在使用 [更新了游戏示例](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).
* 参见 [/pages/5e7e2169ca3822647d4607dfc1d3487ebcc0836c#id-5.-deployment-stopped](https://docs.edgegap.com/zh/pages/5e7e2169ca3822647d4607dfc1d3487ebcc0836c#id-5.-deployment-stopped "mention") 以了解导致部署停止的所有原因。

***

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

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

***

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

* 一旦部署就绪，你的游戏引擎初始化就会开始。此过程可能需要几秒到几分钟，在此期间服务器不会接受玩家连接。
* 考虑优化服务器初始化以缩短这段时间。
* 游戏客户端应每隔 1 秒重试一次连接，并持续有限时间（取决于你的初始化时长），之后应返回匹配队列。
* 可以考虑添加加载场景，这样服务器就可以在客户端同步状态的同时执行初始化（如果是 Unreal Engine，还可以执行 travel）。

***

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

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

***

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

* 默认情况下，服务器不会拒绝玩家连接。如何对玩家进行身份验证取决于你的开发者，因为可以使用许多不同的方法和玩家认证提供商。
* 游戏客户端可以在本地保存连接信息，以便在客户端意外崩溃时尝试重新连接。
* 要允许玩家加入进行中的游戏，可以考虑使用 [深入了解](/zh/learn/pi-pei/matchmaker-in-depth.md#backfill) 或 [Sessions](https://docs.edgegap.com/docs/deployment/session).

***

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

* 这可能不是问题，因为游戏引擎在服务器初始化期间往往会执行 CPU 密集型操作。如果在部署开始后 2-3 分钟内 CPU 使用率没有下降，你可能需要优化服务器或增加应用版本资源。
* 降低 tick 速率可能会影响 CPU 使用率，因为服务器执行的消息操作更少。
* 如果你使用 Mirror netcode，你需要启用 [“自动启动服务器”](https://mirror-networking.gitbook.io/docs/hosting/edgegap-hosting-plugin-guide#build-and-push) 在你的 `NetworkManager` 中勾选，然后重新构建、推送并重新部署你的服务器。
* 如果你使用 FishNet netcode，你需要启用 [“在无头模式下启动”](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）。
* 在创建新的应用版本时，你可以增加分配的资源。你可以在我们的 Dashboard 中复制你的应用版本并根据需要调整这些值，而无需重新构建服务器或镜像。

***

我的部署不断重启，并显示错误 `OOM kill`

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

***

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

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

***

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

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

</details>

## 👉 下一步

### 停止部署

一旦比赛结束（或玩家离开），就可以停止你的部署以节省成本。 [空运行或仅部分填充运行会不必要地增加你的成本！](https://edgegap.com/blog/how-session-fill-rate-affects-your-multiplayer-hosting-costs)

{% hint style="success" %}
导入我们的 `DeploymentAgent`  来自 Unity SDK 的示例到 **轻松且可靠地停止服务器**.
{% endhint %}

### 注入变量

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

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

{% hint style="success" %}
导入我们的 `DeploymentAgent`  来自 Unity SDK 的示例到 **轻松读取强类型变量**.
{% endhint %}

### Session 自动化

### 优化构建

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

考虑使用 [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)

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

* [将网格压缩设置为高以加快构建、上传和部署速度。](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)来加快你的客户端构建和部署，或者通过检查是否存在来跳过加载服务器构建中的某些资源 [部署](/zh/learn/bian-pai/deployments.md#injected-environment-variables).

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

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

### 自定义镜像

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

**在使用 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 %}


---

# Agent Instructions: 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:

```
GET https://docs.edgegap.com/zh/unity.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
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.
