> 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/server-browser.md).

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

Добавьте браузер серверов в свою игру на Unity с помощью дополнительного стартового SDK Edgegap, чтобы игроки могли находить и присоединяться к живым сессиям из списка.

Этот 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="info" %}
**Последняя версия Unity SDK — `3.5.4`**. Все примеры в этой документации актуальны.
{% endhint %}

{% 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. Выберите `Окно > Управление пакетами > Менеджер пакетов` ,
3. Нажмите на :heavy\_plus\_sign: значок и выберите `Добавить пакет из 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/server-browser.md) утилит и примеров, улучшает обработку ошибок matchmaking и многое другое. См. [Примечания к релизам](/ru/docs/release-notes.md) полный список.

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

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

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

{% hint style="success" %}
**Мы настоятельно рекомендуем импортировать наш пример Auto-Assign Example** чтобы вы могли следовать коду по мере чтения этого документа. Сделать это можно в `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/matchmeiking.md)которые можно использовать вместе или по отдельности. Вы можете свободно повторно использовать любые сценарии для своих собственных модифицированных форков и интеграций.
{% endhint %}

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

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

### Агент сервера

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

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

* `onMonitorUpdate`  callback — наблюдение за изменениями состояния сервиса.
* `onInstanceUpdate`  callback — наблюдение и реакция на изменения инстанса и слотов.
* `onConfirmationsUpdate`  callback — наблюдение и реакция на федеративную аутентификацию.

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

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

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

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

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

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

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

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

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

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

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

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

### Агент клиента

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

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

* `onMonitorUpdate`  callback — наблюдение за изменениями состояния сервиса.
* `onInstancesUpdate`  callback — наблюдение и реакция на изменения списка инстансов.

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

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

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

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

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

## 🧪 Примеры

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

### Автоматическое назначение

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

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

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

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

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

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

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

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

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

{% hint style="warning" %}
Обязательно ознакомьтесь с [Глубокое изучение браузера серверов](/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="/ru/learn/brauzer-serverov.md#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 в порядке</code></td><td>Heartbeat успешно завершён.</td></tr><tr><td>🟡 <code>Предупреждение</code></td><td><code>heartbeat не удался [{consecutive}/{maximum}]</code></td><td>Heartbeat не удался, сервер не смог связаться с браузером серверов.</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]: Объект передачи данных
