# Mirror WebGL

Это руководство поможет вам использовать [Mirror](https://mirror-networking.com/)Websocket Transport и создать безголовый сервер на Edgegap для проекта Unity.

В этом руководстве будет использован открытый пример проекта `Tanks`, доступный в примерах Mirror в каталоге `Assets/Mirror/Examples/Tanks`.

Вы можете найти финальную версию этого примера на нашем [GitHub](https://github.com/edgegap/mirror-webgl)

### Смена транспорта

Сначала нам нужно внести некоторые изменения в базовую сцену, прежде чем мы будем готовы собрать сервер игры.

* Откройте `Scene.unity` расположенную в `Assets/Mirror/Examples/Tanks/Scenes`;
* В `NetworkManager` gameObject удалите `KcpTransport` скрипт и замените его на `SimpleWebTransport` расположенную в `Assets/Mirror/Transports/SimpleWeb`, также убедитесь, что обновили поле Transport у `NetworkManager` компонента скрипта на этот новый транспорт. Также убедитесь, что опция `Auto Start Server Build` выбрана.
* В зависимости от вашей версии Mirror вам возможно потребуется изменить/обновить `NetworkManagerHUD` чтобы он работал с транспортами, отличными от KCP, а также чтобы вы могли вводить значение порта в HUD перед подключением к серверу.

Обратите внимание на порт, используемый для сетевых коммуникаций, который в тексте обозначается как `[GAME PORT]`. В этом случае используется порт `7778`.

### Сборка серверa игры и контейнеризация

{% hint style="info" %}
Чтобы упростить процесс контейнеризации и деплоя, можно использовать последнюю версию плагина Edgegap для Unity на нашем [GitHub](https://github.com/edgegap/edgegap-unity-plugin) для автоматизации процесса. Для получения дополнительной информации о том, как использовать этот плагин, вы можете ознакомиться с нашей [документацией](https://docs.edgegap.com/ru/docs/sample-projects/unity-netcodes/broken-reference).

Если вы предпочитаете, вы также можете следовать этим пошаговым инструкциям.
{% endhint %}

Когда игра будет готова, перейдите на `Экран сборки` редактора Unity, в меню `File -> Build Settings` в верхнем меню. Убедитесь, что выбрали правильные пресеты в зависимости от вашей версии Unity.

* До версии 2021.2:
  * Установите `Target Platform` в `Linux`;
  * Установите `Architecture` в `x86_64`;
  * Отметьте опцию `Server Build` .
* В противном случае:
  * Установите `Platform` в `Dedicated Server`;
  * Установите `Target Platform` в `Linux`.

Затем нажмите собрать и выберите новую пустую папку с именем `linux_server` в качестве места назначения файлов. Перенесите папку `linux_server` в другую пустую папку, которая в этом документе будет называться `[SERVER BUILD]` папкой. Добавьте следующие `Dockerfile` и `boot.sh` файлы в эту `[SERVER BUILD]` папку:

#### 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
```

Убедитесь, что вы заменили `[YOUR GAME]` заполнители на имя сгенерированного файла

Затем запустите командную строку в папке `[SERVER BUILD]` ; Выполните следующие команды Docker, чтобы создать образ вашей сборки и отправить его в приватный реестр:

{% hint style="warning" %}
Для пользователей ARM CPU (Mac M1, M2 и т.д.) добавьте `--platform linux/amd64`  опцию к вашей команде сборки.
{% endhint %}

#### Использование 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>
```

#### Использование 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>
```

#### Использование 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>
```

### Развертывание сервера на Edgegap

После входа в панель управления Edgegap перейдите на страницу `Applications & Games` . Нажмите кнопку `Create New` в правом верхнем углу, чтобы открыть форму создания приложения. Ниже перечислены поля и как их правильно заполнять:

* Название приложения: Может быть любым заметным именем, которое вы хотите использовать, чтобы легко распознавать ваше приложение среди других.
* Изображение: Может быть любым специфическим изображением, которое вы хотите использовать, чтобы легко распознавать ваше приложение среди других.
* Имя версии: Вы можете использовать имя версии, чтобы описать назначение версии, которую вы разворачиваете. Примеры: “demo”, “production”, “v1”, “v2”
* Контейнер:
  * Реестр: “ \[URL] ”, где \[URL] — это значение из учетных данных, которые вы можете показать на странице Container Repository.
  * Репозиторий изображения: “ \[PROJECT]/\[YOUR GAME] ”, где \[PROJECT] и \[YOUR GAME] — это значения, которые вы использовали ранее при отправке docker-образа.
  * Тэг: “ \[TAG] ”, где \[TAG] — это значение, которое вы использовали ранее при отправке docker-образа.
  * Отметьте “Using a private repository”
  * Имя пользователя приватного реестра: “ \[USERNAME] ”, где \[USERNAME] — это значение из ваших учетных данных.
  * Токен приватного реестра: “ \[TOKEN] ”, где \[TOKEN] — это значение из ваших учетных данных.
  * Требования: Оставить без изменений.
  * Порты: Нажмите на `+ Add port` ссылку, чтобы добавить новый порт, и добавьте следующие записи:
    * `7778` - WS - включить TLS Upgrade (Бета)

{% hint style="warning" %}
Если вы используете опцию WSS, важно включить опцию `TLS Upgrade` . В противном случае вы столкнетесь с ошибками, похожими на эту, в логах контейнера на панели Edgegap.

```cmd
Первые байты от клиента не были 'GET' для рукопожатия, вместо этого были 16-03-01
```

{% endhint %}

<figure><img src="https://3845012722-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>

После создания приложения вы можете нажать кнопку `Deploy` чтобы приступить к деплою вашего серверa игры. Как только последний статус деплоя станет `Ready`, вы сможете подключиться к серверу с клиентской версией игры. Обратите внимание на `Host` URL и, на вкладке Port Mapping вашего деплоя, на `внешний порт` , доступный публично.

### Тестирование клиента

#### В редакторе

Возвратясь в редактор Unity в сцене с танком, выберите `NetworkManager` gameObject и измените следующие настройки:

* В `Компонент` Network Manager
  * : `Установите` Network Address `Host` в адрес деплоя сервера;
  * Снимите галочку с `Auto Start Server Build` .
* В `Simple Web Transport` Network Manager
  * : `Поле Port` значение на порт Edgegap деплоя, `внешний порт` например: `32821`;
  * Убедитесь, что опция `Client Use WSS` включена.

<figure><img src="https://3845012722-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://3845012722-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>

После этого нажмите `Play` в редакторе, затем нажмите кнопку `Client` ; Вы подключитесь к серверу и сможете сыграть через короткое время.

#### На Itch.io

Чтобы разместить клиент игры на Itch, вам нужно выполнить сборку клиента; для этого необходимо установить модуль `WebGL Build Support` для вашей версии Unity. После этого вернитесь в `Экран сборки` редактора Unity, в меню `File -> Build Settings`и выберите следующие опции:

* Установите `Platform` в `WebGL`;
* Откройте `Player Settings`. В разделе `Player -> Publishing Settings`установите `Compression Format` в `Gzip` и убедитесь, что опция `Decompression Fallback` выбрана. Сохраните эти настройки и закройте окно.

<figure><img src="https://3845012722-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>

Затем нажмите собрать и выберите новую пустую папку с именем `сборка` в качестве места назначения файлов. Перенесите папку `сборка` в другую пустую папку, которая в этом документе будет называться `[CLIENT BUILD]` папка в этом документе.

После завершения сборки игры сожмите файлы этой `сборка` папки в zip-архив, убедившись, что они находятся в корне архива. Затем просто загрузите zip-архив в ваш проект на Itch и убедитесь, что выбрана опция воспроизведения файла в браузере. После запуска игры убедитесь, что значения сетевого адреса и порта правильно установлены в HUD, затем нажмите кнопку `Client` чтобы играть.

#### Хостинг клиента на Edgegap

Также можно разместить клиент вашей игры на Edgegap! Для этого добавьте следующий `Dockerfile` и `nginx.conf` файлы в эту `[CLIENT BUILD]` папку:

**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 {
# Добавьте следующую конфигурацию внутри секции http сервера
# ...

    # Файлы данных, предварительно сжатые Brotli на диске, должны обслуживаться с включённой компрессией:
    location ~ .+\.(data|symbols\.json)\.br$ {
        # Поскольку этот файл уже предварительно сжат на диске, отключите для него динамическое сжатие.
        # Иначе nginx попытается выполнить двойное сжатие.
        gzip off;
        add_header Content-Encoding br;
        default_type application/octet-stream;
    }

    # Файлы JavaScript, предварительно сжатые Brotli на диске:
    location ~ .+\.js\.br$ {
        gzip off; # Не пытайтесь динамически gzip-сжимать уже сжатый файл
        add_header Content-Encoding br;
        default_type application/javascript;
    }

    # Файлы WebAssembly, предварительно сжатые Brotli на диске:
    location ~ .+\.wasm\.br$ {
        gzip off; # Не пытайтесь динамически gzip-сжимать уже сжатый файл
        add_header Content-Encoding br;
        # Включите потоковую компиляцию WebAssembly, указав корректный MIME-тип для
        # Wasm-файлов.
        default_type application/wasm;
    }

    # Файлы данных, предварительно сжатые gzip на диске, должны обслуживаться с включённой компрессией:
    location ~ .+\.(data|symbols\.json)\.gz$ {
        gzip off; # Не пытайтесь динамически gzip-сжимать уже сжатый файл
        add_header Content-Encoding gzip;
        default_type application/octet-stream;
    }

    # Файлы JavaScript, предварительно сжатые gzip на диске:
    location ~ .+\.js\.gz$ {
        gzip off; # Не пытайтесь динамически gzip-сжимать уже сжатый файл
        add_header Content-Encoding gzip;
        default_type application/javascript;
    }

    # Файлы WebAssembly, предварительно сжатые gzip на диске:
    location ~ .+\.wasm\.gz$ {
        gzip off; # Не пытайтесь динамически gzip-сжимать уже сжатый файл
        add_header Content-Encoding gzip;
        # Включите потоковую компиляцию WebAssembly, указав корректный MIME-тип для
        # Wasm-файлов.
        default_type application/wasm;
    }
}
}
```

Продолжите с [тем же набором команд Docker, что и ранее](#bootsh) чтобы собрать и отправить образ вашего игрового клиента в приватный репозиторий, но из окна командной строки, открытого в `[CLIENT BUILD]` папке. Убедитесь, что используется другое имя образа, чем для вашего сервера.

Затем создайте новое приложение для вашего клиента на панели управления Edgegap со следующими настройками:

* Название приложения: Может быть любым заметным именем, которое вы хотите использовать, чтобы легко распознавать ваше приложение среди других.
* Изображение: Может быть любым специфическим изображением, которое вы хотите использовать, чтобы легко распознавать ваше приложение среди других.
* Имя версии: Вы можете использовать имя версии, чтобы описать назначение версии, которую вы разворачиваете. Примеры: “demo”, “production”, “v1”, “v2”
* Контейнер:
  * Реестр: “ \[URL] ”, где \[URL] — это значение из учетных данных, которые вы можете показать на странице Container Repository.
  * Репозиторий изображения: “ \[PROJECT]/\[YOUR GAME] ”, где \[PROJECT] и \[YOUR GAME] — это значения, которые вы использовали ранее при отправке docker-образа.
  * Тэг: “ \[TAG] ”, где \[TAG] — это значение, которое вы использовали ранее при отправке docker-образа.
  * Отметьте “Using a private repository”
  * Имя пользователя приватного реестра: “ \[USERNAME] ”, где \[USERNAME] — это значение из ваших учетных данных.
  * Токен приватного реестра: “ \[TOKEN] ”, где \[TOKEN] — это значение из ваших учетных данных.
  * Требования: Оставить без изменений.
  * Порты: Нажмите на `+ Add port` ссылку, чтобы добавить новый порт, и добавьте следующие записи:
    * `80` - HTTPS

<figure><img src="https://3845012722-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>

После создания приложения вы можете нажать кнопку `Deploy` кнопкой для продолжения развертывания вашего игрового клиента. При условии, что развертывания сервера и клиента установлены на `Ready`, откройте у игрового клиента `Host` url по указанному `внешний порт` в вашем браузере, и вы сможете играть в игру после установки правильных значений в HUD игры!

<figure><img src="https://3845012722-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" %}
Если вам нужна дополнительная информация о интеграции Mirror и websocket, вы можете обратиться к их [документацией](https://mirror-networking.gitbook.io/docs/manual/transports/websockets-transport).
{% endhint %}
