# Mirror WebGL

This guide will help you use [Mirror](https://mirror-networking.com/)'s Websocket Transport and create a headless server on Edgegap for a Unity project.

This guide will use the open-source sample project `Tanks`, available in the Mirror sample under `Assets/Mirror/Examples/Tanks`.

You can find the final version of this sample on our [GitHub](https://github.com/edgegap/mirror-webgl)

### Switch the transport

We first need to make some changes to the base scene before we're ready to build the game server.

* Open `Scene.unity` located under `Assets/Mirror/Examples/Tanks/Scenes`;
* In the `NetworkManager` gameObject, remove the `KcpTransport` script and replace it with the `SimpleWebTransport` located under `Assets/Mirror/Transports/SimpleWeb`, make sure to also update the Transport field of the `NetworkManager` script component with this new transport. Make sure that the `Auto Start Server Build` option is selected as well.
* Depending on your version of Mirror, you might need to change/update the `NetworkManagerHUD` to make it work with different transports than KCP, as well as to let you input the port value in the HUD before joining a server.

Take note of the port used for network communications, referred as the `[GAME PORT]`. In this case, the port used is `7778`.

### Build the game server & Containerizing

{% hint style="info" %}
To facilitate the containerizing and deployment process, it's possible to use the latest version of the Edgegap Unity Plugin on our [GitHub](https://github.com/edgegap/edgegap-unity-plugin) to automate the process. For more information on how to use this plugin, you can check our [documentation](https://docs.edgegap.com/docs/sample-projects/unity-netcodes/broken-reference).

If you want instead, you may also follow these step-by-step instructions.
{% endhint %}

Once ready with your game, head to the `Build` screen of the Unity Editor, under `File -> Build Settings` in the top menus. Make sure to select the right presets depending on your version of Unity.

* Prior to version 2021.2:
  * Set `Target Platform` to `Linux`;
  * Set `Architecture` to `x86_64`;
  * Check the `Server Build` option.
* Otherwise:
  * Set `Platform` to `Dedicated Server`;
  * Set `Target Platform` to `Linux`.

Then press build and select a new empty folder named `linux_server` as the file destination. Transfer the `linux_server` folder to a second empty folder, which will be refered as the `[SERVER BUILD]` folder in this document. Add the following `Dockerfile` and `boot.sh` file to the `[SERVER BUILD]` folder:

#### Dockerfile

```
FROM ubuntu:bionic
MAINTAINER <author_detail>

ARG DEBIAN_FRONTEND=noninteractive
ARG docker_version=17.06.0-ce

RUN
    apt-get update && \
    apt-get install -y libglu1 xvfb libxcursor1 ca-certificates && \
    update-ca-certificates && \
    apt-get clean

EXPOSE 7778/TCP

COPY linux_server/  /root/linux_server/
COPY boot.sh        /boot.sh

WORKDIR /root/
ENTRYPOINT ["/bin/bash", "/boot.sh"]
```

#### boot.sh

```
xvfb-run --auto-servernum --server-args='-screen 0 640x480x24:32' /root/linux_server/[YOUR GAME].x86_64 -batchmode -nographics
```

Make sure to replace the `[YOUR GAME]` placeholders with the name of the generated file

Then, start a command prompt in the `[SERVER BUILD]` folder; Run the following Docker commands to create an image of your build and push it to a private registry:

{% hint style="warning" %}
For ARM CPU (Mac M1, M2, etc.) users, add `--platform linux/amd64`  option to your build command.
{% endhint %}

#### Using Linux

```bash
# build the image
docker build . -t <IMAGE_NAME>:<IMAGE_TAG>

# login, a prompt will ask the password
docker login -u '<REGISTRY_USERNAME>' <REGISTRY_URL>

# add another tag to your image corresponding to the registry
docker image tag <IMAGE_NAME>:<IMAGE_TAG> <REGISTRY_URL>/<PROJECT_NAME>/<IMAGE_NAME>:<IMAGE_TAG>

#push the image
docker push <REGISTRY_URL>/<PROJECT_NAME>/<IMAGE_NAME>:<IMAGE_TAG>
```

#### Using cmd

```bash
# build the image
docker build . -t <IMAGE_NAME>:<IMAGE_TAG>

# login, a prompt will ask the password
docker login -u <REGISTRY_USERNAME> <REGISTRY_URL>

# add another tag to your image corresponding to the registry
docker image tag <IMAGE_NAME>:<IMAGE_TAG> <REGISTRY_URL>/<PROJECT_NAME>/<IMAGE_NAME>:<IMAGE_TAG>

#push the image
docker push <REGISTRY_URL>/<PROJECT_NAME>/<IMAGE_NAME>:<IMAGE_TAG>
```

#### Using Powershell

```bash
# build the image
docker build . -t <IMAGE_NAME>:<IMAGE_TAG>

# login, a prompt will ask the password
docker login -u '<REGISTRY_USERNAME>' <REGISTRY_URL>

# add another tag to your image corresponding to the registry
docker image tag <IMAGE_NAME>:<IMAGE_TAG> <REGISTRY_URL>/<PROJECT_NAME>/<IMAGE_NAME>:<IMAGE_TAG>

#push the image
docker push <REGISTRY_URL>/<PROJECT_NAME>/<IMAGE_NAME>:<IMAGE_TAG>
```

### Deploying server to Edgegap

After logging in on the Edgegap Dashboard, navigate to the `Applications & Games` page. Click on the `Create New` button in the top right hand corner to access the application form. Here are the fields and how to fill them properly:

* Application name : Can be any notable name you want to use to easily recognize your application among others.
* Image : Can be any specific image you want to use to easily recognize your application among others.
* Version name : You may want to use a version name to describe the scope of the version you are deploying. Examples may be “demo”, “production”, “v1”, “v2”
* Container :
  * Registry : “\[URL]”, where \[URL] is the value from the credentials you can display on the Container Repository page.
  * Image repository : “\[PROJECT]/\[YOUR GAME]”, where \[PROJECT] and \[YOUR GAME] are the values you used earlier when pushing the docker image.
  * Tag : “\[TAG]”, where \[TAG] is the value you used earlier when pushing the docker image.
  * Tick “Using a private repository”
  * Private registry username : “\[USERNAME]”, where \[USERNAME] is the value from your credentials.
  * Private registry token : “\[TOKEN]”, where \[TOKEN] is the value from your credentials.
  * Requirements : Left as is.
  * Ports : Click the `+ Add port` link to add a new port, and add the following entries :
    * `7778` - WS - enable TLS Upgrade (Beta)

{% hint style="warning" %}
If you use the WSS option, it is important to enable the `TLS Upgrade` option. Otherwise, you will encounter errors similar to this one in your container logs on the Edgegap dashboard.

```cmd
First bytes from client was not 'GET' for handshake, instead was 16-03-01
```

{% endhint %}

<figure><img src="https://3027732442-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2Fgit-blob-4996c904d603b04628fdd82091b1d3a5768aac40%2Fserver-port.png?alt=media" alt=""><figcaption></figcaption></figure>

Once your application has been created, you can press the `Deploy` button to proceed with deploying your game server. Once the latest status of you deployment is set to `Ready`, you will be able to connect to the server with a client version of the game. Take note of the `Host` url and, in the Port Mapping tab of your deployment, the `external port` that's publicly available.

### Testing the client

#### In the editor

Back in the Unity editor in the tank scene, select the `NetworkManager` gameObject and change the following settings:

* In the `Network Manager` component:
  * Set the `Network Address` to the the server deployment's `Host` url;
  * Uncheck the `Auto Start Server Build` option.
* In the `Simple Web Transport` component:
  * Set the `Port` value to the Edgegap deployment's `external port` e.g.: `32821`;
  * Make sure the `Client Use WSS` option is enabled.

<figure><img src="https://3027732442-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2Fgit-blob-8fe3a5d63fc65f33f18d8e0c39a5d2d5a5b97e6c%2Fnetwork-manager-client-settings-1.png?alt=media" alt=""><figcaption></figcaption></figure>

<figure><img src="https://3027732442-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2Fgit-blob-8a7da870b869174fc4117dc6e6e44edb8e62b906%2Fnetwork-manager-client-settings-2.png?alt=media" alt=""><figcaption></figcaption></figure>

Once this is done, click `Play` in the editor, then click the `Client` button; You'll get connected to the server and be able to play the game after a short moment.

#### On Itch.io

To put your game client on Itch, you will need to make a client build; You will need to install the `WebGL Build Support` module for your version of Unity to do that. Once that's done, head back to the `Build` screen of the Unity Editor, under `File -> Build Settings`, and select the following options:

* Set `Platform` to `WebGL`;
* Open up the `Player Settings`. Under `Player -> Publishing Settings`, set the `Compression Format` to `Gzip` and make sure the `Decompression Fallback` option is selected. Save these settings, and close the window.

<figure><img src="https://3027732442-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2Fgit-blob-04b0077a769072f95884b660b71bc3e93655f6a6%2Fclient-build.png?alt=media" alt=""><figcaption></figcaption></figure>

Then press build and select a new empty folder named `build` as the file destination. Transfer the `build` folder to a second empty folder, which will be refered as the `[CLIENT BUILD]` folder in this document.

Once your game has finished building, compress the files of this `build` folder into a zip folder, making sure that they are at the root of it. Then you simply need to upload the zip folder to your Itch project, and make sure to select the option for the file to play in the browser. Once you launch the game, you just need to make sure that the network address and port values are set correctly in the HUD, then click the `Client` button to play.

#### Hosting the client on Edgegap

It's even possible to host your game client on Edgegap! To do so, add the following `Dockerfile` and `nginx.conf` file to the `[CLIENT BUILD]` folder:

**Dockerfile**

```
FROM nginx:alpine
MAINTAINER <author_detail>

COPY build/ /usr/share/nginx/html
copy nginx.conf /etc/nginx/
```

**nginx.conf**

```
user  nginx;
worker_processes  auto;

error_log  /var/log/nginx/error.log notice;
pid        /var/run/nginx.pid;


events {
worker_connections  1024;
}


http {
include       /etc/nginx/mime.types;
default_type  application/octet-stream;

log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';

access_log  /var/log/nginx/access.log  main;

sendfile        on;
#tcp_nopush     on;

keepalive_timeout  65;

#gzip  on;

include /etc/nginx/conf.d/*.conf;

server {
# Add the following config within http server configuration
# ...

    # On-disk Brotli-precompressed data files should be served with compression enabled:
    location ~ .+\.(data|symbols\.json)\.br$ {
        # Because this file is already pre-compressed on disk, disable the on-demand compression on it.
        # Otherwise nginx would attempt double compression.
        gzip off;
        add_header Content-Encoding br;
        default_type application/octet-stream;
    }

    # On-disk Brotli-precompressed JavaScript code files:
    location ~ .+\.js\.br$ {
        gzip off; # Do not attempt dynamic gzip compression on an already compressed file
        add_header Content-Encoding br;
        default_type application/javascript;
    }

    # On-disk Brotli-precompressed WebAssembly files:
    location ~ .+\.wasm\.br$ {
        gzip off; # Do not attempt dynamic gzip compression on an already compressed file
        add_header Content-Encoding br;
        # Enable streaming WebAssembly compilation by specifying the correct MIME type for
        # Wasm files.
        default_type application/wasm;
    }

    # On-disk gzip-precompressed data files should be served with compression enabled:
    location ~ .+\.(data|symbols\.json)\.gz$ {
        gzip off; # Do not attempt dynamic gzip compression on an already compressed file
        add_header Content-Encoding gzip;
        default_type application/octet-stream;
    }

    # On-disk gzip-precompressed JavaScript code files:
    location ~ .+\.js\.gz$ {
        gzip off; # Do not attempt dynamic gzip compression on an already compressed file
        add_header Content-Encoding gzip;
        default_type application/javascript;
    }

    # On-disk gzip-precompressed WebAssembly files:
    location ~ .+\.wasm\.gz$ {
        gzip off; # Do not attempt dynamic gzip compression on an already compressed file
        add_header Content-Encoding gzip;
        # Enable streaming WebAssembly compilation by specifying the correct MIME type for
        # Wasm files.
        default_type application/wasm;
    }
}
}
```

Proceed with the [same Docker commands as before](#bootsh) to build and push an image of your game client to a private repository, but from a command window opened in the `[CLIENT BUILD]` folder. Make sure to use a different image name than the one for your server.

Then, create a new application for your client on the Edgegap dashboard with the following settings:

* Application name : Can be any notable name you want to use to easily recognize your application among others.
* Image : Can be any specific image you want to use to easily recognize your application among others.
* Version name : You may want to use a version name to describe the scope of the version you are deploying. Examples may be “demo”, “production”, “v1”, “v2”
* Container :
  * Registry : “\[URL]”, where \[URL] is the value from the credentials you can display on the Container Repository page.
  * Image repository : “\[PROJECT]/\[YOUR GAME]”, where \[PROJECT] and \[YOUR GAME] are the values you used earlier when pushing the docker image.
  * Tag : “\[TAG]”, where \[TAG] is the value you used earlier when pushing the docker image.
  * Tick “Using a private repository”
  * Private registry username : “\[USERNAME]”, where \[USERNAME] is the value from your credentials.
  * Private registry token : “\[TOKEN]”, where \[TOKEN] is the value from your credentials.
  * Requirements : Left as is.
  * Ports : Click the `+ Add port` link to add a new port, and add the following entries :
    * `80` - HTTPS

<figure><img src="https://3027732442-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2Fgit-blob-f88e313ed093082a221680f4b59b241afe7cbf70%2Fclient-port.png?alt=media" alt=""><figcaption></figcaption></figure>

Once your application has been created, you can press the `Deploy` button to proceed with deploying your game client. With both the server and client deployments set to `Ready`, open the game client's `Host` url at the specified `external port` in your browser, and you'll be able to play the game after setting the correct values in the game's HUD!

<figure><img src="https://3027732442-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2Fgit-blob-b140451a9c9404cba2498e715c6c83abb656e655%2Fonline-client.png?alt=media" alt=""><figcaption></figcaption></figure>

{% hint style="info" %}
If you need more information about the Mirror integration and websocket, you can refer to their [documentation](https://mirror-networking.gitbook.io/docs/manual/transports/websockets-transport).
{% 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/docs/sample-projects/unity-netcodes/mirror-on-edgegap-websocket.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.
