> For the complete documentation index, see [llms.txt](https://docs.edgegap.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.edgegap.com/zh/docs/sample-projects/unity-netcodes/unity-netcode-on-edgegap.md).

# Unity NGO

了解如何使用以下内容中的技术在 Edgegap 上托管 Unity 项目： [NGO Boss Room 示例](https://unity.com/demos/small-scale-coop-sample).

{% hint style="info" %}
此示例 **不需要任何 Unity Gaming Services（UGS）**、Multiplay 或 Relays 即可运行。
{% endhint %}

{% embed url="<https://youtu.be/8Qi-wXswjkw>" %}

## ✔️ 准备工作

开始之前，你需要：

* Unity 6 - [使用 Unity Hub 下载](https://unity.com/releases/unity-6),
* Unity NGO \[Netcode for Game Objects] Boss Room 示例项目（已为 Edgegap 修改）：
  * [从 Github 下载](https://github.com/edgegap/netcode-sample-unity-ngo-bossroom).

## ⚡ 部署并连接

### 1. 在 Edgegap 上部署服务器

☑️ 要开始，你需要 [在 Edgegap 创建一个免费账户](https://app.edgegap.com/auth/register)。无需信用卡。

☑️ [为你的应用程序创建一个新的应用版本](https://app.edgegap.com/application-management/applications/unity-ngo-bossroom-sample/versions/create)，选择 NGO Boss Room 示例。

☑️ [使用你的 NGO Boss Room 示例应用版本部署服务器](https://app.edgegap.com/deployment-management/deployments/list).

☑️ [打开你新部署的详情](https://app.edgegap.com/deployment-management/deployments/list) 并找到你独有的一次性连接信息：

* **外部端口** 格式为 `30854`  （5 位数字）。

☑️ 导航到“日志”选项卡，并查找（CTRL+F）你独有的一次性连接信息：

* `ARBITRIUM_PUBLIC_IP` 格式为 `172.234.244.38` .

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

### 2. 从编辑器连接

☑️ 在 Unity 中打开你的新项目。

☑️ 确认你已打开场景： `Assets/Scenes/MainMenu.unity`.

☑️ 按下 ▶️ 播放按钮以启动你的游戏客户端：

* 按下 **使用直接 IP 开始** 按钮，
* 选择选项卡 **使用 IP 加入。**

☑️ 输入上一步的连接信息。

☑️ 按下 **加入** 按钮以连接到你的服务器。

☑️ 使用以下方式连接第二个虚拟玩家： [Multiplayer Play Mode](https://docs-multiplayer.unity3d.com/mppm/current/about/) 或 [ParrelSync](https://github.com/VeriorPies/ParrelSync).

🙌 恭喜你在 Edgegap 上完成首次部署！

## ✏️ 自定义服务器构建

{% hint style="success" %}
请参阅 [Unity](/zh/unity.md) Unity 的 **了解如何构建和自定义服务器**.
{% endhint %}

### 以专用服务器运行

为了让此示例以专用服务器运行，我们做了以下更改：

{% tabs %}
{% tab title="服务器初始化" %}
新脚本（添加到你的 `MainMenu` 场景中的一个新的空 `GameObject`):

<pre class="language-csharp" data-title="Assets/Scripts/EdgegapServerStarter.cs" data-line-numbers><code class="lang-csharp">using System;
using System.Collections;
using System.Collections.Generic;
using Unity.BossRoom.ConnectionManagement;
using UnityEngine;

namespace Unity.Multiplayer.Samples.BossRoom
{
    public class EdgegapServerStarter : MonoBehaviour
    {
<strong>        public string portMapName = <a data-footnote-ref href="#user-content-fn-1">"gameport"</a>;
</strong>
        // 在第一次帧更新前调用 Start
        void Start()
        {
            if (Application.isBatchMode)
            {
                ConnectionManager connectionManager = GameObject.Find("ConnectionManager").GetComponent&#x3C;ConnectionManager>();
<strong>                string internalPortAsStr = Environment.GetEnvironmentVariable($"ARBITRIUM_PORT_{portMapName.ToUpper()}_INTERNAL");
</strong>
                if (internalPortAsStr == null || !ushort.TryParse(internalPortAsStr, out ushort port))
                {
                    throw new Exception($"找不到端口映射，请确保你的应用版本端口名称与 \"{portMapName}\" 一致")
                }

<strong>                connectionManager.StartHostIp("<a data-footnote-ref href="#user-content-fn-2">服务器</a>", "0.0.0.0", port);
</strong>            }
        }
    }
}
</code></pre>

{% endtab %}

{% tab title="连接管理" %}
已修改文件：

<pre class="language-csharp" data-title="Assets/Scripts/ConnectionManagement/ConnectionMethod.cs"><code class="lang-csharp"><strong>116        public override async Task SetupHostConnectionAsync()
</strong>117        {
<strong>118            <a data-footnote-ref href="#user-content-fn-3">//SetConnectionPayload(GetPlayerId(), m_PlayerName); // 也需要为主机设置连接负载，因为主机也是客户端</a>
</strong>119            var utp = (UnityTransport)m_ConnectionManager.NetworkManager.NetworkConfig.NetworkTransport;
120            utp.SetConnectionData(m_Ipaddress, m_Port);
121        }
</code></pre>

<pre class="language-csharp" data-title="Assets/Scripts/ConnectionManagement/ConnectionState/StartingHostState.cs"><code class="lang-csharp"><strong>66        async void StartHost()
</strong>67        {
              ...

72                // NGO 的 StartHost 会启动所有内容
<strong>--                <a data-footnote-ref href="#user-content-fn-3">//if (!m_ConnectionManager.NetworkManager.StartHost())</a>
</strong><strong>73                <a data-footnote-ref href="#user-content-fn-4">if (!m_ConnectionManager.NetworkManager.StartServer())</a>
</strong>74                {
75                    StartHostFailed();
76                }

              ...
</code></pre>

<pre class="language-csharp" data-title="Assets/Scripts/Gameplay/GameplayObjects/Character/ClientCharacter.cs"><code class="lang-csharp"><strong>112        public override void OnNetworkSpawn()
</strong>113        {
               ...

125            m_ServerCharacter.IsStealthy.OnValueChanged += OnStealthyChanged;
126            m_ServerCharacter.MovementStatus.OnValueChanged += OnMovementStatusChanged;
<strong>127            <a data-footnote-ref href="#user-content-fn-3">//OnMovementStatusChanged(MovementStatus.Normal, m_ServerCharacter.MovementStatus.Value);</a>
</strong> 
               ...
</code></pre>

{% endtab %}

{% tab title="编辑器/服务器兼容性" %}
修改文件：

<pre class="language-csharp" data-title="Assets/Scripts/ConnectionManagement/ConnectionState/HostingState.cs"><code class="lang-csharp"><strong>148        ConnectStatus GetConnectStatus(ConnectionPayload connectionPayload)
</strong>149        {
               ...
                
<strong>155            <a data-footnote-ref href="#user-content-fn-5">//if (connectionPayload.isDebug != Debug.isDebugBuild)</a>
</strong><strong>156            //{
</strong><strong>157            //    return ConnectStatus.IncompatibleBuildType;
</strong><strong>158            //}
</strong>
               ...
</code></pre>

{% endtab %}
{% endtabs %}

[^1]: Edgegap 上的默认端口名称

[^2]: 服务器的玩家名称可以是任意值

[^3]: 仅限 p2p ⇒ 将此注释掉

[^4]: 改为以专用服务器启动

[^5]: 编辑器兼容性 ⇒ 将此注释掉
