> 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/ru/unity/brauzer-serverov.md).

# Браузер серверов

Этот SDK — это необязательный стартовый набор для пользователей Unity, который позже можно расширять и настраивать.

## 💡 Возможности

Получите доступ к готовым автоматизированным функциям, установив наш SDK:

{% columns %}
{% column %}

* Полные примеры
* Управление жизненным циклом
* Управление вместимостью
  {% endcolumn %}

{% column width="33.33333333333333%" %}

* Компилятор фильтрующих запросов
* Определения типов (C#)
* Локальное тестирование при разработке
  {% endcolumn %}

{% column width="33.33333333333333%" %}

* Кроссплатформенность
* Легко настраивать
* Автоматический повтор
  {% endcolumn %}
  {% endcolumns %}

## ✔️ Подготовка

Unity SDK содержит дополнительные утилиты интеграции для Deployments, Matchmaking и Server Browser. Этот плагин официально поддерживает версии Unity 2021.3.0f1 и новее.

{% hint style="success" %}
Этот плагин предоставляется абсолютно бесплатно, в соответствии с Условиями и положениями Free Tier.
{% endhint %}

#### Требования

<details>

<summary>Установите Git-клиент (например <a href="https://git-scm.com/">git-scm</a>)</summary>

Git-клиент необходим, чтобы Unity могла автоматически загрузить и установить наш пакет Unity. После установки вам не потребуется использовать git напрямую.

</details>

#### Установка

1. Откройте ваш проект Unity,
2. Выберите `Window > Package Management > Package Manager` ,
3. Нажмите на :heavy\_plus\_sign: значок и выберите `Add package from git URL...` ,
4. Введите URL нашего SDK, когда будет предложено:

{% code title="" %}

```
https://github.com/edgegap/edgegap-unity-sdk.git
```

{% endcode %}

5. Нажмите `Добавить`  и дождитесь завершения установки.

#### Импортировать примеры

Этот пакет включает несколько примеров, предназначенных для использования по отдельности (не объединяйте примеры).

#### Проверенные источники

Это единственный официальный канал распространения этого SDK, не доверяйте непроверенным источникам!

#### Обновить пакет

Перейдите к Edgegap SDK в Unity Package Manager и нажмите `Обновить` .

{% hint style="warning" %}
**Импортированные примеры не обновляются автоматически!** Сделайте резервную копию любых пользовательских значений свойств, удалите используемые сейчас в вашей сцене скрипты примеров и импортируйте примеры заново.
{% endhint %}

{% hint style="info" %}
Некоторые релизы могут содержать несовместимые изменения. Это будет обозначено новой MAJOR-версией.
{% endhint %}

#### Обновление до v3

Это обновление включает множество новых [Браузер серверов](/ru/unity/brauzer-serverov.md) утилит и примеров, улучшает обработку ошибок матчмейкинга и многое другое. См. [Примечания к выпуску](/ru/docs/release-notes.md) полный список.

{% hint style="warning" %}
Обновление Unity SDK v3 включает несколько несовместимых изменений. Пожалуйста, тщательно повторно протестируйте вашу интеграцию.
{% endhint %}

## 🍀 Начало работы

Это руководство предполагает базовые знания [Браузер серверов](/ru/learn/brauzer-serverov.md) концепций и работающего Server Browser.

{% hint style="success" %}
**Мы настоятельно рекомендуем импортировать наш пример Auto-Assign** чтобы следовать коду по мере чтения этого документа. Сделать это можно в `Unity Package Manager > Edgegap SDK > Samples` .
{% endhint %}

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

### Обзор

Наш SDK активно использует [внедрение зависимостей](https://learn.microsoft.com/en-us/dotnet/core/extensions/dependency-injection/overview#the-concept) и [Наблюдатель](https://learn.microsoft.com/en-us/dotnet/standard/events/observer-design-pattern) шаблоны программирования.

{% hint style="info" %}
Этот пакет объединяет оба [Браузер серверов](/ru/learn/brauzer-serverov.md) и [Подбор игроков](/ru/learn/podbor-igrokov.md)которые можно использовать вместе или по отдельности. Вы можете свободно повторно использовать любые сценарии для своих собственных модифицированных форков и интеграций.
{% endhint %}

Этот пакет включает:

* Файлы runtime — будут скомпилированы и объединены с вашими клиентскими и серверными сборками:
  * Утилиты, специфичные для сервиса:
    * [#server-agent](#server-agent "mention") - полная серверная интеграция для повторного использования/расширения,
    * [#client-agent](#client-agent "mention") - полная клиентская интеграция для повторного использования/расширения,
    * Функции API — определения конечных точек, обработка ошибок и автоматизация логирования.
    * Компилятор фильтров — строго типизированные утилиты для построения фильтрующих запросов.
  * Специфичные для сервиса DTO[^1] - типизированные контейнеры данных для Server Browser API.
  * Общие утилиты — логирование, HTTP, ping, observables и т. д...
  * Общие DTO[^1] - используются несколькими сервисами Edgegap для передачи данных.
* Примеры файлов — включаются в сборку и компилируются ТОЛЬКО если импортированы в ваш проект:
  * [#auto-assign](#auto-assign "mention") - примеры обработчиков с автоматически назначаемыми резервациями,
  * [#custom-search](#custom-search "mention") - примеры обработчиков с ручным выбором экземпляра.

### Server Agent

**Управление жизненным циклом и вместимостью сервера** выполняется Server Agent.

После создания агент **родительский MonoBehaviour (обработчик) должен инициализировать агента** и предоставить:

* `onMonitorUpdate`  callback — отслеживать изменения состояния сервиса,
* `onInstanceUpdate`  callback — отслеживать изменения экземпляра и слотов и реагировать на них,
* `onConfirmationsUpdate`  callback — отслеживать и обрабатывать федеративную аутентификацию.

После инициализации этот агент автоматически предоставит проверки и подключит наблюдателей логирования, завершая всё одним вызовом к конечной точке API мониторинга для указания состояния сервиса.

Ожидается, что обработчик агента возьмёт управление на себя и вызовет функции агента с этого момента:

* `DiscoverInstance`  для создания первоначального Server Instance и слотов и запуска heartbeat,
* `DeleteInstance`  когда матч завершится / чтобы предотвратить присоединение новых игроков,
* `ConfirmReservation`  когда игроки подключаются, чтобы подтвердить их личность и назначение слота,
* `UpdateSlot`  для обновления вместимости слота (при присоединении/уходе игрока) или изменения метаданных,
* `UpdateInstance`  для изменения метаданных экземпляра,
* `Status`  для проверки состояния службы Server Browser.

{% hint style="success" %}
Подтверждения и обновления слотов/экземпляров **по умолчанию ставятся в очередь и выполняются пакетами** (режим Heartbeat), чтобы максимизировать масштабируемость. Чтобы быстрее проходить итерации во время тестирования разработки, используйте режим Greedy.
{% endhint %}

{% hint style="warning" %}
**При обновлении метаданных должны быть определены все индексы.** Чтобы снять значения неиндексированных ключей, просто не указывайте их.
{% endhint %}

Агент автоматически поддерживает heartbeat, чтобы сервер оставался доступным для обнаружения во время работы. Если агент не может связаться с вашим Server Browser в течение нескольких последовательных heartbeat (настраивается):

* меньше максимума — экземпляр будет автоматически обнаружен повторно,
* больше максимума — экземпляр будет автоматически удалён.

Когда устанавливается новое подключение игрока, ожидается, что игрок отправит свой ID резервации (ID игрока сторонней системы) на игровой сервер с помощью вашего netcode, чтобы выполнить подтверждение резервации.

Как только `onConfirmationsUpdate`  срабатывает, обработчик должен выполнить дополнительные действия:

* вызвать `UpdateSlot`  чтобы уменьшить число доступных мест для любых слотов с подтверждёнными резервациями,
* принять или отклонить подключение с помощью методов, специфичных для netcode.

Когда игрок покидает игру, ожидается, что обработчик увеличит число доступных мест для этого слота.

{% hint style="info" %}
Дайте игрокам короткий промежуток времени на повторное подключение перед уходом, на случай непредвиденных сбоев.
{% endhint %}

### Клиентский агент

**Поиск экземпляров, пагинация, фильтрация и резервации** выполняются Client Agent.

После создания агент **родительский MonoBehaviour (обработчик) должен инициализировать агента** и предоставить:

* `onMonitorUpdate`  callback — отслеживать изменения состояния сервиса,
* `onInstancesUpdate`  callback — отслеживать изменения списка экземпляров и реагировать на них.

После инициализации этот агент автоматически предоставит проверки и подключит наблюдателей логирования, завершая всё одним вызовом к конечной точке API мониторинга для указания состояния сервиса.

Ожидается, что обработчик агента возьмёт управление на себя и вызовет функции агента с этого момента:

* `ReserveSeats`  для создания резервации вместимости для конкретного экземпляра/слота или автоназначения,
* `ListInstances`  для получения списка экземпляров с заданным фильтром, порядком, курсором и размером страницы,
* `GetNextPage`  для получения дополнительных экземпляров с текущими параметрами (фильтры и т. д.),
* `RefreshList`  для очистки кэша и загрузки первой страницы или обновления с определённым курсором,
* `GetInstanceDetails`  для получения метаданных экземпляра и информации о слотах для конкретного экземпляра,
* `Status`  для проверки состояния службы Server Browser.

Когда устанавливается новое подключение игрока, ожидается, что игрок отправит свой ID резервации (ID игрока сторонней системы) на игровой сервер с помощью вашего netcode, чтобы выполнить подтверждение резервации.

{% hint style="success" %}
Сохраняйте данные подключения в клиенте или игровом бэкенде, чтобы переподключиться в случае неожиданного сбоя.
{% endhint %}

## 🧪 Примеры

Начните с примеров, включая полную рабочую интеграцию как для сервера, так и для клиента.

### Автоназначение

Использует резервации с автоназначением, при этом клиент указывает только имя политики. Server Browser автоматически выбирает экземпляр, соответствующий фильтру политики, и слот с достаточным числом мест.

### Пользовательский поиск

Включает полную реализацию, демонстрирующую, как искать экземпляры и слоты, подключать элементы интерфейса и позволять игроку вручную выбирать, где он хочет зарезервировать вместимость.

## ⚙️ Настройка

Этот SDK предназначен для расширения и модификации, хотя некоторые изменения могут быть рискованными:

✅ Обработчик — безопасно подключайте наблюдателей UI и вносите небольшие дополнения или изменения,

⚠️ Агент — изменяйте жизненный цикл и управление вместимостью на свой страх и риск,

⚠️ API — напишите собственную интеграцию с нуля, используя выбранные утилиты.

Обработчики могут наблюдать любые события, генерируемые агентами Server и Client, как описано ниже.

{% hint style="warning" %}
Обязательно ознакомьтесь с [Подробно о Server Browser](/ru/learn/brauzer-serverov.md) концепциями перед внесением изменений.
{% endhint %}

{% hint style="info" %}
Если вам нужна помощь, [свяжитесь с нами через Discord](https://discord.gg/MmJf8fWjnt). Для поддержки по играм в реальном времени см. нашу [систему тикетов](https://edgegap.atlassian.net/servicedesk/customer/portal/3).
{% endhint %}

### События сервера

Server Agent генерирует события (действия), которые родительский обработчик должен наблюдать и обрабатывать.

{% hint style="success" %}
Читать полезные данные событий, обращаясь к  `.Current` состоянию любого наблюдаемого объекта. 🔴 `Ошибка` события содержат полное сообщение об ошибке, отделённое символом новой строки после основного сообщения события.
{% endhint %}

Предпросмотр событий, генерируемых observable `Монитор` :

<table data-full-width="true"><thead><tr><th width="125">Тип действия</th><th width="450">Сообщение события</th><th>Описание</th></tr></thead><tbody><tr><td>🟢 <code>Обновление</code> </td><td><code>здорово</code></td><td>Все системы в норме.</td></tr><tr><td>🟢 <code>Обновление</code> </td><td><code>нездорово</code></td><td>Неожиданная проблема.</td></tr><tr><td>🔴 <code>Ошибка</code></td><td><code>не удалось получить монитор</code></td><td>Неверная конфигурация или неожиданная проблема.</td></tr><tr><td>🟡 <code>Предупреждение</code></td><td><code>тайм-аут запроса ограничен heartbeat [{timeout}]</code></td><td>Предотвращает состояния гонки.</td></tr></tbody></table>

Предпросмотр событий (действий), генерируемых observable `Экземпляр`:

<table data-full-width="true"><thead><tr><th width="125">Тип действия</th><th width="450">Сообщение события</th><th>Описание</th></tr></thead><tbody><tr><td>🟢 <code>Обновление</code> </td><td><code>обнаружен</code></td><td><a href="/pages/6c642f50ebd48e5f939d86627dadcc55f732cc5c#discover-instance">Обнаружение экземпляра</a> успешно завершено. Может быть вызвано, если экземпляр потерял соединение из-за временной проблемы и был обнаружен повторно.</td></tr><tr><td>🔴 <code>Ошибка</code></td><td><code>дублирование обнаружения</code></td><td>Экземпляр с этим Request ID уже обнаружен.</td></tr><tr><td>🔴 <code>Ошибка</code></td><td><code>обнаружение не удалось</code></td><td>Неожиданная проблема при обнаружении.</td></tr><tr><td>🔵 <code>Уведомление</code></td><td><code>heartbeat ok</code></td><td>Heartbeat успешно завершён.</td></tr><tr><td>🟡 <code>Предупреждение</code></td><td><code>heartbeat failed [{consecutive}/{maximum}]</code></td><td>Heartbeat не удался, сервер не смог связаться с Server Browser.</td></tr><tr><td>🔵 <code>Уведомление</code></td><td><code>обновление экземпляра поставлено в очередь</code></td><td>Обновление экземпляра поставлено в очередь для следующего пакета (heartbeat/greedy).</td></tr><tr><td>🟢 <code>Обновление</code> </td><td><code>экземпляр обновлён</code></td><td>Метаданные экземпляра успешно обновлены.</td></tr><tr><td>🔴 <code>Ошибка</code></td><td><code>не удалось обновить экземпляр, постановка в очередь на повтор</code></td><td>Не удалось обновить экземпляр, возможно, из-за ограничения частоты запросов или ошибки.</td></tr><tr><td>🟢 <code>Обновление</code> </td><td><code>экземпляр удалён</code></td><td>Экземпляр больше не доступен для обнаружения игроками.</td></tr><tr><td>🟢 <code>Обновление</code> </td><td><code>не удалось удалить экземпляр (не найден)</code></td><td>Срок действия экземпляра мог истечь из-за слишком большого числа пропущенных heartbeat.</td></tr><tr><td>🔴 <code>Ошибка</code></td><td><code>не удалось удалить экземпляр</code></td><td>Не удалось удалить экземпляр, возможно, из-за ограничения частоты запросов или ошибки.</td></tr><tr><td>🔵 <code>Уведомление</code></td><td><code>обновление слота поставлено в очередь [{slot}]</code></td><td>Обновление слота поставлено в очередь для следующего пакета (heartbeat/greedy).</td></tr><tr><td>🟢 <code>Обновление</code> </td><td><code>слот обновлён [{slot}]</code></td><td>Вместимость мест слота и/или метаданные успешно обновлены.</td></tr><tr><td>🟡 <code>Предупреждение</code></td><td><code>агент ограничил параллельное обновление слота</code></td><td>Предотвращена попытка параллельного обновления (состояние гонки).</td></tr><tr><td>🔴 <code>Ошибка</code></td><td><code>не удалось обновить слот (не найден) [{slot}]</code></td><td>Слот с таким именем ещё не определён для этого экземпляра.</td></tr><tr><td>🔴 <code>Ошибка</code></td><td><code>не удалось обновить слот (недостаточно мест) [{slot}]</code></td><td>При обновлении слота была попытка уменьшить доступные места ниже нуля.</td></tr><tr><td>🔴 <code>Ошибка</code></td><td><code>не удалось обновить слот, постановка в очередь на повтор [{slot}]</code></td><td>Не удалось обновить слот, возможно, из-за ограничения частоты запросов или ошибки.</td></tr></tbody></table>

Предпросмотр событий (действий), генерируемых observable `Подтверждения`:

<table data-full-width="true"><thead><tr><th width="125">Тип действия</th><th width="450">Сообщение события</th><th>Описание</th></tr></thead><tbody><tr><td>🔵 <code>Уведомление</code></td><td><code>поставлено в очередь [{player}]</code></td><td>Подтверждение поставлено в очередь для следующего пакета (heartbeat/greedy).</td></tr><tr><td>🟡 <code>Предупреждение</code></td><td><code>дубликат [{player}]</code></td><td>Предотвращена попытка дублирующего подтверждения (уже в очереди).</td></tr><tr><td>🟢 <code>Обновление</code> </td><td><code>подтверждено</code></td><td>Подтверждённые резервации для отдельных слотов; также включает просроченные и неизвестные ID игроков, которые обработчик должен разрешить (принять/кикнуть).</td></tr><tr><td>🔴 <code>Ошибка</code></td><td><code>не удалось</code></td><td>Неожиданная проблема с подтверждениями. Проверьте состояние сервиса.</td></tr></tbody></table>

### События клиента

Client Agent генерирует события (действия), которые родительский обработчик должен наблюдать и обрабатывать.

{% hint style="success" %}
Читать полезные данные событий, обращаясь к  `.Current` состоянию любого наблюдаемого объекта. 🔴 `Ошибка` события содержат полное сообщение об ошибке, отделённое символом новой строки после основного сообщения события.
{% endhint %}

Предпросмотр событий, генерируемых observable `Монитор` :

<table data-full-width="true"><thead><tr><th width="125">Тип действия</th><th width="450">Сообщение события</th><th>Описание</th></tr></thead><tbody><tr><td>🟢 <code>Обновление</code> </td><td><code>здорово</code></td><td>Все системы в норме.</td></tr><tr><td>🟢 <code>Обновление</code> </td><td><code>нездорово</code></td><td>Неожиданная проблема.</td></tr><tr><td>🔴 <code>Ошибка</code></td><td><code>не удалось получить монитор</code></td><td>Неверная конфигурация или неожиданная проблема.</td></tr></tbody></table>

Предпросмотр событий, генерируемых observable `Экземпляры`:

<table data-full-width="true"><thead><tr><th width="125">Тип действия</th><th width="450">Сообщение события</th><th>Описание</th></tr></thead><tbody><tr><td>🔵 <code>Уведомление</code></td><td><code>места зарезервированы</code></td><td>Резервация места выполнена успешно.</td></tr><tr><td>🔴 <code>Ошибка</code></td><td><code>не удалось зарезервировать места (не найдено)</code></td><td><a data-mention href="#auto-assign">#auto-assign</a> - имя политики не найдено (удалено или неактивно).<br><a data-mention href="#custom-search">#custom-search</a> - экземпляр или слот не найдены.</td></tr><tr><td>🔴 <code>Ошибка</code></td><td><code>не удалось зарезервировать места (достигнута вместимость)</code></td><td><a data-mention href="#auto-assign">#auto-assign</a> - политика достигла максимальной вместимости.<br><a data-mention href="#custom-search">#custom-search</a> - слот достиг максимальной вместимости.</td></tr><tr><td>🔴 <code>Ошибка</code></td><td><code>не удалось зарезервировать места</code></td><td>Не удалось зарезервировать места, возможно, из-за неверной политики, Request ID или ID слота.</td></tr><tr><td>🟢 <code>Обновление</code> </td><td><code>список экземпляров получен</code></td><td>Список экземпляров получен успешно.</td></tr><tr><td>🟢 <code>Обновление</code> </td><td><code>следующая страница списка экземпляров получена</code></td><td>Следующая страница экземпляров получена успешно.</td></tr><tr><td>🔴 <code>Ошибка</code></td><td><code>достигнута последняя страница списка экземпляров</code></td><td>Не удалось получить следующую страницу, попробуйте обновить или изменить фильтры.</td></tr><tr><td>🔴 <code>Ошибка</code></td><td><code>не удалось получить следующую страницу списка экземпляров</code></td><td>Не удалось получить следующую страницу, возможно, из-за неверного курсора.</td></tr><tr><td>🟢 <code>Обновление</code> </td><td><code>сведения об экземпляре получены</code></td><td>Сведения об экземпляре из списка получены успешно.</td></tr><tr><td>🟢 <code>Обновление</code> </td><td><code>экземпляр не закэширован, добавление в начало</code></td><td>Получены сведения об экземпляре вне текущего списка.</td></tr><tr><td>🔴 <code>Ошибка</code></td><td><code>не удалось получить сведения об экземпляре</code></td><td>Не удалось получить сведения, возможно, из-за неверного Request ID.</td></tr></tbody></table>

[^1]: Объект передачи данных
