> 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/docs/sample-projects/unity-netcodes/photon-fusion-2-br200.md).

# Photon Fusion 2 BR200

Host Photon's BR200 battle royale sample (Photon Fusion 2) on Edgegap dedicated servers, one deployment per match, using the Edgegap BR200 kit.

Explore how to host Unity projects on Edgegap using techniques from the [BR200 Battle Royale Sample](https://assetstore.unity.com/packages/templates/packs/br200-battle-royale-multiplayer-photon-fusion-226753), a battle royale for up to 200 players.

{% hint style="info" %}
Our [Edgegap BR200 kit](https://github.com/edgegap/fusion-br200-edgegap) is a set of files you copy into your BR200 project. It **doesn't change or include any Photon licensed code**, so you get BR200 from the Unity Asset Store under your own license.
{% endhint %}

This sample shows:

* **BR200 as a dedicated server** - one deployment per match, [placed close to players](/learn/orchestration/deployments.md#server-placement).
* **No BR200 code changes** - a start script maps [injected variables](/learn/orchestration/deployments.md#injected-environment-variables) to BR200's own command-line options.
* **Direct connections** - the server binds `0.0.0.0`, so clients connect directly instead of through Photon relay.
* **Photon region choice** - the server picks the Photon region closest to its deployment.
* **Server self-stop** - the server stops its own deployment when the match ends.

{% hint style="success" %}
See [Photon Fusion 2](/docs/sample-projects/unity-netcodes/photon-fusion-2-on-edgegap.md) for a **general guide to Photon Fusion 2 on Edgegap**. See the kit's [README](https://github.com/edgegap/fusion-br200-edgegap) for the full list of files, runtime variables and test results.
{% endhint %}

## ✔️ Preparation

Before we start, you will need:

* [BR200 Battle Royale (Photon Fusion)](https://assetstore.unity.com/packages/templates/packs/br200-battle-royale-multiplayer-photon-fusion-226753) - download and open in a supported Unity version.
* Edgegap BR200 kit - [download from GitHub](https://github.com/edgegap/fusion-br200-edgegap).
* Photon Fusion App ID - find it in your [Photon dashboard](https://dashboard.photonengine.com).

{% hint style="info" %}
Open your project and install server build tools by following [Unity](/unity.md) preparation steps.
{% endhint %}

This kit was tested with BR200 2.1.0, Fusion 2.1.1 (build 2177) and Unity 6000.3.11f1 on Windows.

{% hint style="warning" %}
Your server **must be an IL2CPP build** (BR200's default). Mono servers fail BR200's RPCs with `MethodAccessException` and players never get a character.
{% endhint %}

☑️ To build Linux IL2CPP on Windows, add Unity's Linux toolchain in Window / Package Manager / + / Add package by name:

* Unity 6000.3 and later: `com.unity.toolchain.win-x86_64-linux` and `com.unity.sdk.linux-x86_64`,
* earlier versions: `com.unity.toolchain.win-x86_64-linux-x86_64`.

## ⚡ Deploy and Connect

### 1. Add the Kit to Your Project

☑️ Copy `Assets/EdgegapBR200`, `edgegap/`, `scripts/`, `.dockerignore` and `.gitattributes` from the kit to your BR200 project root, next to `Assets/`.

☑️ Paste your Fusion App ID in Tools / Fusion / Realtime Settings, and note your **App Version**.

{% hint style="info" %}
Clients and server **must use the same App ID, App Version and Photon region**, otherwise they won't find each other.
{% endhint %}

☑️ Set **Peer Mode** to `Single` in Tools / Fusion / Network Project Config.

☑️ Run Tools / Edgegap BR200 / Check Project and fix any reported issues.

You don't need to edit the Loader scene or script. Server mode, address, port, session and region are passed on the command line.

{% hint style="info" %}
If your console shows `Unsafe code may only appear if compiling with /unsafe` right after the first import, close and reopen your project.
{% endhint %}

✅ You may now proceed to the next step.

### 2. Build and Upload the Server

☑️ To get started, you'll need to [create a free account with Edgegap](https://app.edgegap.com/auth/register). No credit card required.

☑️ Build and upload your server with the Edgegap plugin or from a terminal:

{% tabs %}
{% tab title="Edgegap Plugin (Recommended)" %}
☑️ Run Tools / Edgegap BR200 / Build Linux Server. It checks your project, enables *Allow 'unsafe' Code* if needed, and builds the Linux **Server** subtarget to `Builds/EdgegapServer`.

☑️ Open Tools / Edgegap Server Hosting. In step **3. Containerize Your Server**, click **Path To Dockerfile** and select `edgegap/Dockerfile`. Keep **Relative Build Path** at `Builds/EdgegapServer`, then Containerize and upload.

☑️ Keep port `7777` / UDP when the plugin creates your app version.
{% endtab %}

{% tab title="Terminal (for Agents)" %}
☑️ Find your [Container Registry](/learn/advanced-features/edgegap-container-registry.md#getting-your-credentials) project name and credentials, then log in with `docker login registry.edgegap.com`.

☑️ Build your server, then package and push the image (Git Bash works on Windows):

{% code collapsedlinecount="10" %}

```bash
scripts/build-server.sh
scripts/package.sh registry.edgegap.com/<your-registry-project>/br200
```

{% endcode %}

`package.sh` prints the new tag it pushed.

☑️ [Create an application](https://app.edgegap.com/application-management/applications/list) and a version for your image. You can also use the kit's `examples/app-version.json` with `POST /v1/app/{app}/version`.
{% endtab %}
{% endtabs %}

{% hint style="danger" %}
:x: **DO NOT - overwrite existing tags or use `latest` tag** - this will deploy an outdated cache.\
:white\_check\_mark: **DO - always increase your version tag** and deploy the new build.
{% endhint %}

☑️ Configure your app version with:

* [port](/learn/orchestration/application-and-versions.md#port-mapping) `7777`, protocol **UDP**, named `gameport`,
* [restart policy](/learn/orchestration/application-and-versions.md#safety-guardrails) `never` - deployment ends when the match ends and the server exits,
* max duration a little above your longest match (60 minutes in the example),
* resources 1 vCPU and 2 GB as a starting point.

✅ You may now proceed to the next step.

### 3. Test Locally

☑️ Run your image locally with the same injected variables a real deployment gets:

{% code collapsedlinecount="10" %}

```bash
scripts/run-local.sh eu
```

{% endcode %}

☑️ Join the printed session name from two editors or two client builds, using **Option B** from the next step with that session name and the region you passed.

{% hint style="info" %}
Local clients connect **Relayed**, as a clients on the same machine can't reach Docker Desktop's NAT address directly. On Edgegap, the same image connects **Direct**.
{% endhint %}

✅ You may now proceed to the next step.

### 4. Deploy and Connect

☑️ Start a deployment from the plugin, [dashboard](https://app.edgegap.com/deployment-management/deployments/list), or `POST /v2/deployments` with the kit's `examples/deploy-request.json`. Pass your players' public IPs to [deploy close to them](/learn/orchestration/deployments.md#server-placement).

Your deployment's FQDN (e.g. `0a1b2c3d4e5f.pr.edgegap.net`) is also the BR200 session and server name. The first server log lines show bind address, public address and chosen Photon region:

{% code collapsedlinecount="10" %}

```
[edgegap-br200] deployment=0a1b2c3d4e5f session=0a1b2c3d4e5f.pr.edgegap.net bind=0.0.0.0:7777/udp public=203.0.113.10:31502
[edgegap-br200] photon_region=eu (nearest to Frankfurt (50.11, 8.68)) max_players=200 mode=default scene=default
```

{% endcode %}

☑️ Connect a client with one of these options:

* **Option A: Menu** - open `TPSBR/Scenes/Menu`, press ▶️ Play, choose the same region and join the server from the list,
* **Option B: Standalone Manager auto-join** - open the scene set as the Loader's **Batch Mode Scene**. In **Standalone Manager**, set Game Mode `Client`, set Server Name and Session Name to your FQDN, set Region to the server's region, then press ▶️ Play.

{% hint style="warning" %}
BR200 starts a **120-second waiting timer when the server boots**. Players joining after it runs out count as eliminated. Deploy once your group is ready, and connect clients as soon as the deployment is Ready.
{% endhint %}

☑️ Press **Tab** in a connected client. The overlay's top-left corner shows **CT** (Connection Type), which should say **Direct**.

🙌 Congratulations on your first Deployment on Edgegap!

## 🔄 Match Lifecycle

1. Edgegap starts the deployment and [injects `ARBITRIUM_*` variables](/learn/orchestration/deployments.md#injected-environment-variables).
2. `edgegap/start-server.sh` turns them into BR200's command-line options. It always passes `-dedicatedServer -ip 0.0.0.0 -port 7777`, names the session after the deployment FQDN, and picks the Photon region closest to the deployment.
3. Clients find the server in the same Photon region and connect Direct.
4. When BR200 exits at match end, the script calls `ARBITRIUM_DELETE_URL` to stop the deployment, so a finished match stops billing right away. When Edgegap stops the deployment, the script forwards the stop signal to BR200 instead.

See [Deployments](/learn/orchestration/deployments.md) to learn more.

## ⚙️ Environment Variables

Edgegap [injects `ARBITRIUM_*` variables](/learn/orchestration/deployments.md#injected-environment-variables) automatically. Set these `BR200_*` variables on your app version (every match) or deployment request (this match only):

| Variable                 | Default                                                                                            | BR200 option                                     |
| ------------------------ | -------------------------------------------------------------------------------------------------- | ------------------------------------------------ |
| `BR200_SESSION`          | The deployment FQDN, `<ARBITRIUM_REQUEST_ID>.pr.edgegap.net`                                       | `-sessionName`                                   |
| `BR200_SERVER_NAME`      | Same as the session                                                                                | `-serverName`                                    |
| `BR200_REGION`           | `auto`: the Photon region nearest the deployment. `best`: let Fusion ping. Or a code such as `eu`. | `-region`                                        |
| `BR200_REGION_ALLOWLIST` | All Photon regions. Comma-separated codes that `auto` may pick from.                               |                                                  |
| `BR200_MAX_PLAYERS`      | `200` (1 to 200)                                                                                   | `-maxPlayers`                                    |
| `BR200_MODE`             | BR200's default. `battleRoyale`, `deathmatch` or `elimination`.                                    | `-battleRoyale` / `-deathmatch` / `-elimination` |
| `BR200_SCENE`            | The Loader's Batch Mode Scene                                                                      | `-scene`                                         |
| `BR200_LOBBY`            | BR200's default                                                                                    | `-lobby`                                         |
| `BR200_FPS`              | Fusion's tick rate                                                                                 | `-fps`                                           |
| `BR200_RECORD`           | `false`. `true` writes session stats to `/data`.                                                   | `-recordSession -dataPath /data`                 |
| `BR200_EXTRA_ARGS`       | None. Other options, appended last.                                                                |                                                  |
| `BR200_SELF_STOP`        | `true`. Stop the deployment when BR200 exits.                                                      |                                                  |

If your clients use a fixed Photon region, or your Photon app only allows some regions, set `BR200_REGION` on the deployment, or restrict `auto` with `BR200_REGION_ALLOWLIST`.

## 🔌 Direct Connection

BR200's `IP` and `Port` set the address your server **binds** to. The kit binds `0.0.0.0:7777`, Fusion finds the deployment's public address on its own, and clients connect **Direct** - even though Edgegap gives players a different [external port](/learn/orchestration/application-and-versions.md#port-mapping).

| Server `IP`                | Result                                                                                                                                           |
| -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ |
| `0.0.0.0` (this kit)       | **Direct** on Edgegap.                                                                                                                           |
| `127.0.0.1`                | The server starts, but clients are **Relayed** through Photon, which adds latency. Nothing outside the container can reach the loopback address. |
| The deployment's public IP | The server **doesn't start** (`Failed to bind socket`), because the container doesn't own that address. Clients get `GameNotFound`.              |

{% hint style="warning" %}
Leave `IP` empty or `0.0.0.0`. **Don't set it to `127.0.0.1` or to your deployment's public IP.**
{% endhint %}

## 🚨 Troubleshooting

<details>

<summary><code>MethodAccessException ... CheckInvokeRpc</code> in server log</summary>

* Your server was built with Mono. Rebuild it with IL2CPP.

</details>

<details>

<summary><code>No Toolchain found for host platform</code> or <code>No Linux sysroot found</code></summary>

* Linux toolchain packages are missing, see [Preparation](#preparation).

</details>

<details>

<summary>Client gets <code>GameNotFound</code></summary>

* App Version or Photon region differs between client and server. Compare with the server's `photon_region=` log line.

</details>

<details>

<summary>Client gets <code>InvalidAuthentication</code></summary>

* Your Fusion App ID is wrong or missing in the build.

</details>

<details>

<summary>Tab overlay shows CT Relayed</summary>

* Your server binds `127.0.0.1`, see [Direct Connection](#direct-connection).

</details>

<details>

<summary>Server isn't listed in the Menu</summary>

* Client region differs from the server's, or the 120-second waiting timer has already run out.

</details>

<details>

<summary>Deployment exits immediately with <code>error: ...</code></summary>

* A `BR200_*` value is invalid. The log line says which one.

</details>

{% hint style="info" %}
If you need help, [please reach out to us over Discord](https://discord.gg/MmJf8fWjnt). For live games support see our [ticketing system](https://edgegap.atlassian.net/servicedesk/customer/portal/3).
{% endhint %}
