# Photon Fusion 2

探索如何使用以下技术在 Edgegap 上托管 Unity 项目： [Fusion 2 小行星 示例](https://doc.photonengine.com/fusion/current/game-samples/fusion-asteroids).

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

## ✔️ 准备工作

在开始之前，您将需要：

* Unity 6 - [使用 Unity Hub 下载](https://unity.com/releases/unity-6),
* 为 Edgegap 修改的 Fusion 2 小行星 示例项目 - [从 GitHub 下载](https://github.com/edgegap/netcode-sample-photon-fusion-2).

## ⚡ 部署与连接

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

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

☑️ [为您的应用创建一个新的应用版本](https://app.edgegap.com/application-management/applications/fusion-2-asteroids-sample/versions/create)，选择 Fusion 2 小行星 示例。

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

☑️ 导航到 工具 / Edgegap Hosting，然后到第 6 步。 在 Edgegap 上部署服务器。

☑️ 按 部署到云 并且 [打开您新部署的详细信息](https://app.edgegap.com/deployment-management/deployments/list).

☑️ 找到您部署的唯一一次性连接详情：

* **主机 URL** 格式为 `780aa4260e83.pr.edgegap.net` .

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

### 2. 从编辑器连接

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

☑️ 按 ▶️ 播放 按钮以启动您的游戏客户端。

☑️ 将主机 URL（上一步的连接详情）作为房间名输入。

☑️ 按 开始 Edgegap 按钮以连接到您的服务器。

☑️ 使用第二个虚拟玩家连接，方法是 [多人游戏 播放 模式](https://docs-multiplayer.unity3d.com/mppm/current/about/) 或 [ParrelSync](https://github.com/VeriorPies/ParrelSync).

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

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

{% hint style="success" %}
参见 [unity](https://docs.edgegap.com/zh/unity "mention") 以便 Unity **了解如何构建和自定义服务器**.
{% endhint %}

### 在 Photon 上创建应用

{% hint style="info" %}
为了让初始演示更简单，我们使用了由 Edgegap 拥有的免费层 Photon Cloud 帐户。
{% endhint %}

☑️ [创建 Photon 免费账号](https://dashboard.photonengine.com/).

☑️ [在 Photon 上创建一个应用](https://dashboard.photonengine.com/app/create):

* `多人游戏`,
* `Fusion` Photon SDK，
* `Fusion 2` SDK 版本。

☑️ 找到您的应用 ID，格式为 `85314a99-56fc-4ab3-ba26-50efca09f303` .

☑️ 在 工具 / Fusion / Fusion Hub (Alt + F) 下的 Photon 设置中输入您的 ID。

### 将 Fusion 2 项目与 Edgegap 集成

{% hint style="success" %}
参见 `EdgegapServerManager.cs`  用于示例性将 Fusion 2 与 Edgegap 集成的脚本。
{% endhint %}

{% hint style="warning" %}
您的 `NetworkProjectConfig`  **必须使用 `对等模式 = 单一` （专用 服务器）**，而不是 `多重` （客户端-主机）！
{% endhint %}

游戏客户端将通过 [Photon Fusion 2 ](https://doc.photonengine.com/fusion/current/manual/connection-and-matchmaking/matchmaking#creating-and-joining-a-game-session)[会话（房间） ](https://doc.photonengine.com/fusion/current/manual/connection-and-matchmaking/matchmaking#creating-and-joining-a-game-session)[功能 连接到游戏服务器](https://doc.photonengine.com/fusion/current/manual/connection-and-matchmaking/matchmaking#creating-and-joining-a-game-session).

您的游戏服务器需要在调用时用会话名称注册其 IP 地址和外部端口， `_runnerInstance.StartGame(StartGameArgs args)`:

* 使用 `GameMode.Server`  以确保您的连接不会通过 Photon Cloud 中继（会增加延迟），
* 使用 `NetAddress.CreateFromIpPort` 来自 Fusion 的方法，
* 提供服务器的 IP 地址：\
  `Environment.GetEnvironmentVariable("ARBITRIUM_PUBLIC_IP")`
* 提供服务器的外部端口：\
  `Environment.GetEnvironmentVariable("ARBITRIUM_PORT_GAMEPORT_EXTERNAL")`
  * 如果您使用我们的默认端口映射名称，这是默认名称， [将您的服务器打包的 Unity 插件](https://docs.edgegap.com/zh/unity).

使用 Edgegap 部署主机 URL 作为会话名称：

* 在游戏服务器中，通过以下方式获取：\
  `$"{Environment.GetEnvironmentVariable("ARBITRIUM_REQUEST_ID")}.pr.edgegap.net"`
* 在测试游戏客户端时，从仪表板 - 部署详情页面 / 主机 URL 获取
  * 从我们的以下位置为测试创建部署： [快速入门 托管 插件](https://docs.edgegap.com/zh/unity/developer-tools#dedicated-servers-quickstart-plugin),
* 在游戏客户端上线时，从以下位置获取： [匹配 / 工单分配 / FQDN](https://docs.edgegap.com/zh/learn/pei-dui/matchmaker-in-depth#player-api):
  * 另请参见 [入门：匹配服务](https://docs.edgegap.com/zh/learn/pei-dui).

{% tabs %}
{% tab title="客户端集成" %}
{% code title="EdgegapClientManager.cs" %}

```csharp
// 获取 fusion 2 网络运行器
_runnerInstance = FindFirstObjectByType<NetworkRunner>();
_runnerInstance.ProvideInput = true;

// 从 Edgegap 匹配器分配或 Fusion 2 会话 API 获取此值
string sessionName = "<requestId.pr.edgegap.net>";

// 查找 fusion 2 会话（使用会话名称）
var result = await _runnerInstance.StartGame(
    new StartGameArgs() {
        GameMode = GameMode.Client,
        SessionName = sessionName,
        ObjectProvider = _runnerInstance.GetComponent<NetworkObjectPoolDefault>(),
    }
);

// fusion 现在将基于会话名称获取服务器 IP 和端口并进行连接
```

{% endcode %}
{% endtab %}

{% tab title="服务器集成" %}
{% code title="EdgegapServerManager.cs" %}

```csharp
// 读取 edgegap 注入的环境变量
string requestId = Environment.GetEnvironmentVariable("ARBITRIUM_REQUEST_ID");
string listenPort = Environment.GetEnvironmentVariable("ARBITRIUM_PORT_GAMEPORT_INTERNAL");
string connectIP = Environment.GetEnvironmentVariable("ARBITRIUM_PUBLIC_IP");
string connectPort = Environment.GetEnvironmentVariable("ARBITRIUM_PORT_GAMEPORT_EXTERNAL");

// 获取 fusion 2 网络运行器
_runnerInstance = FindFirstObjectByType<NetworkRunner>();
_runnerInstance.ProvideInput = true;

// 注册 fusion 2 会话，以便客户端稍后查找（使用会话名称）
var result = await _runnerInstance.StartGame(
    new StartGameArgs() {
        GameMode = GameMode.Server,
        SessionName = $"{requestId}.pr.edgegap.net",
        ObjectProvider = _runnerInstance.GetComponent<NetworkObjectPoolDefault>(),
        Address = NetAddress.Any(listenPort),
        CustomPublicAddress = NetAddress.CreateFromIpPort(connectIP, connectPort),
    }
);

// 加载初始场景
if (result.Ok && _runnerInstance.IsServer) {
    await _runnerInstance.LoadScene(sceneName);
}
```

{% endcode %}
{% endtab %}
{% endtabs %}

### 故障排除

<details>

<summary><code>游戏不存在 (32758)</code></summary>

* Photon 房间要求玩家连接到与部署所在位置相同的 Photon Cloud 区域。 从仪表板部署使用了随机的玩家 IP。
* 您可能需要在地图上找到部署的位置，并在 Assets / Photon / Fusion / Resources / PhotonAppSettings.asset 中将您的游戏客户端配置为匹配的 [Photon Cloud 区域](https://doc.photonengine.com/fusion/current/manual/connection-and-matchmaking/regions#photon-cloud-for-gaming).
* Edgegap [会尽可能靠近玩家进行部署](https://docs.edgegap.com/zh/learn/bian-pai/deployments#id-1.-server-score-strategy-best-practice) 当使用我们的 [插件 时](https://docs.edgegap.com/zh/unity/developer-tools) 或 [API](https://docs.edgegap.com/zh/docs/api/zhuan-yong-fu-wu-qi) 因此在生产环境中，设置 Photon Cloud 区域不是必需的。

</details>
