# Использование Workshop

Перед использованием сайта <https://autodonate.magicbyte.ru/workshop> прочитайте пользовательское соглашение <https://autodonate.magicbyte.ru/workshop/documents/tos>

Для начала оформления услуги убедитесь, что вы авторизованы через дискорд.

Далее из предложенных карточек услуг выбираете, что вам интересно. Обязательно прочитайте описание мода.

Каждая модификация имеет описание её возможностей и полную инструкцию по установке.<br>

После выбора самой модификации Вам нужно выбрать, на какой период вы приобретаете доступ: 30 дней или бессрочно (Возможность арендовать мод доступна только для владельцев сайтов Premium).

&#x20;После выбора периода у вас появится блок для заполнение информации.&#x20;

<figure><img src="https://2909774895-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F5GELIejIJQv0W9HfglUO%2Fuploads%2Fj6AYppf99TuMLiDwP4kO%2Fimage.png?alt=media&amp;token=f58d03e2-3d7b-4c79-a5c8-408caa9ba218" alt=""><figcaption></figcaption></figure>

Магазин - список арендуемых Вами сайтов. Выберите тот, который представляет проект, для которого Вы приобретаете доступ к модификации.

Название сервера - укажите название вашего сервера так, как оно отображается в лаунчере игры.&#x20;

IP сервера - укажите IP-адрес Вашего сервера (как отображается в лаунчере).&#x20;

Порт сервера - укажите игровой порт Вашего сервера (как отображается в лаунчере).

**Если Вы укажете неверные данные или запустите модификацию на другом сервере, доступ к модификации для Вас будет заблокирован.**

После нажатия на кнопку "продолжить" Вас перенаправит в личный кабинет.

<figure><img src="https://2909774895-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F5GELIejIJQv0W9HfglUO%2Fuploads%2F6J1ILr25NucRXZWZhnPq%2Fimage.png?alt=media&amp;token=d7a3272a-8a23-45ec-a82f-291200fd5b28" alt=""><figcaption></figcaption></figure>

Теперь Вам нужно дождаться, пока данные Вашего сервера будут проверены. После успешной проверки статус изменится на ожидание оплаты:&#x20;

<figure><img src="https://2909774895-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F5GELIejIJQv0W9HfglUO%2Fuploads%2F7nX1smHbDN9ZfeLlvqIN%2Fimage.png?alt=media&amp;token=53954de6-c263-4f89-aef0-607f80b0268d" alt=""><figcaption></figcaption></figure>

Теперь вы можете оплатить услугу:

<figure><img src="https://2909774895-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F5GELIejIJQv0W9HfglUO%2Fuploads%2FyUirVyOjATj5kfDfwOzA%2Fimage.png?alt=media&amp;token=a282f30c-7e5e-4758-a8c4-3b89ae2fb02e" alt=""><figcaption></figcaption></figure>

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

Теперь у вас появилась кнопка с иконкой глаза. Нажав её, Вы можете получить дальнейшую инструкцию в краткой форме. Дополнительная информация доступна на странице гайда конкретного мода.

{% hint style="danger" %}
ВАЖНО!!!\
Если вы будете использовать модификации на не разрешенном сервере, или будете пойманы на воровстве.\
Вам будет ограничен доступ ко всем нашим сервисам.&#x20;
{% endhint %}


# Установка модификации

Как установить только что скачанный мод?

Сначала прочитайте статью [Использование Workshop](https://workshop-guide.magicbyte.ru/workshop/ispolzovanie-workshop).

При нажатии кнопки "скачать", на Ваше устройство скачается архив с модификацией. Внутри этого архива можно найти:

* Папку MagicByte. **Важно: эту папку обязательно нужно перенести в папку профиля сервера. В ней содержится ключ лицензии Вашей модификации. Это необходимо делать для каждой модификации, даже если папку уже есть в папке профиля сервера. Если этого не сделать, модификация не будет работать.**
* Архив, название которого совпадает с названием модификации (например, при скачивании MagicByteSharedLibrary это будет архив MagicByteSharedLibrary.7z). В этом архиве можно найти:
  * Папку, название которой совпадает с названием модификации. Внутри неё находится папка Addons, в которой лежит pbo самой модификации. Данный pbo Вы устанавливате на Ваш сервер.
  * Какие-либо ещё файлы. Это могут быть файлы конфигурации или что-то ещё. Подробнее об этих файлах можно узнать на странице гайда модификации.


# Редактирование файлов локализации

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

Файлы локализации имеют расширение .loc и устанавливаются в папку профиля (profile) Вашего сервера. Все моды, поддерживающие локализацию, уже идут в комплекте с файлом русской локализации.

Рассмотрим файл локализации на примере MagicByteSharedLibrary (комментарии, указанные через //, не поддерживаются файлом, и указаны ниже для иллюстрации назначения строк):

```json
DEFAULT ru //Задаём стандартный язык - русский

SECTION ru //Указываем, что дальше идёт настройка русского языка 
MBSL_DIALOGUE_OK Ок //Указываем значение для ключа MBSL_DIALOGUE_OK
MBSL_DIALOGUE_CANCEL Отмена
MBSL_DIALOGUE_YES Да
MBSL_DIALOGUE_NO Нет
```

Файл локализации состоит из определения стандартного языка и блоков языков:

* После ключевого слова DEFAULT указывается стандартный язык. Если для какого-то языка не указан перевод ключа, то перевод будет взят из этого языка.
* После ключевого слова SECTION указывается определяемый далее язык. Блок языка состоит из пар ключ-значение. Ключ предопределён модификацией и состоит из одного слова (без пробелов, символов табуляции и конца строки). Значение - отображаемая по ключу строка, не может быть перенесена на несколько строк.

```
КЛЮЧ_В_ОДНО_СЛОВО ЗНАЧЕНИЕ ИЗ НЕСКОЛЬКИХ СЛОВ
```

Файлы локализации поддерживают все 12 языков, доступных в dayz. Языки обозначаются следующими кодами:

* en - Английский.
* fr - Французский.
* es - Испанский.
* it - Итальянский.
* de - Немецкий.
* cs - Чешский.
* ru - Русский.
* zhs - Китайский (упрощённый).
* zh - Китайский.
* pl - Польский.
* ja - Японский.
* pt - Португальский.


# Форматы цветов

На этой страницы описаны используемые форматы цветов

{% hint style="danger" %}
Хотя обычно используется цветовое пространство sRGB, цветовые пространства DayZ и конкретных приложений могут отличаться, поэтому выбранный Вами в некотором приложении цвет может отображаться по-другому в DayZ.
{% endhint %}

## Целочисленное представление

{% hint style="info" %}
**Краткое описание:**

Данный формат является 32-битным целочисленным представлением дополнительного кодом со знаком цвета в формате ARGB, где каждый канал представлен 2 байтами. &#x20;
{% endhint %}

Данный формат используется для представления цвета в виде одного числа, что позволяет сделать его ввод простым.

Чтобы получить цвет в этом формате, нам нужно взять шестнадцатеричное представление ARGB цвета - для этого можно воспользоваться любым инструментом для выбора цветов (например, <https://csscolor.ru/>).

<figure><img src="https://2909774895-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F5GELIejIJQv0W9HfglUO%2Fuploads%2F4konXxzAovjECXJrUvJH%2Fimage.png?alt=media&amp;token=4b357eb2-9317-4ba6-9c42-e6242a9dd9de" alt=""><figcaption></figcaption></figure>

Цвет в этом представлении выглядит подбным образом:

```
751b1b6a
```

{% hint style="warning" %}
Существуют также формат RGBA, который выглядит аналогично, но в котором цвета представлены по-другому. Важно не перепутать эти форматы.
{% endhint %}

{% hint style="warning" %}
Цвет в формате ARGB в шестнадцатеричном представлении состоит именно из 8 символов. Если вы видите цвет из 6 символов, скорее всего, это RGB. Чтобы преобразовать его в ARGB, допишите ff в начале (слева от) цвета.
{% endhint %}

Далее нам необходимо преобразовать этот цвет (его дополнительный код со знаком) в число в десятичной системе счисления. Для этого нужно воспользоваться конвертером (рекомендуем <https://www.rapidtables.com/convert/number/hex-to-decimal.html>, далее в примере будем использовать его).

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

Вводим число в первое поле и берём результат из **третьего поля.**

<figure><img src="https://2909774895-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F5GELIejIJQv0W9HfglUO%2Fuploads%2FsO5R4Cb0pdXKnuTCs80M%2Fimage.png?alt=media&amp;token=4cf09494-f0ff-43f7-a77d-dc0d57b48c40" alt=""><figcaption></figcaption></figure>

Полученное число и есть цвет в этом представлении.


# Проблемы с модификациями

Прежде чем открыть тикет о проблеме с модификацией, прочитайте эту страницу.

## Модификация не работает

На примере модификации SuicideButton, версии 1.0.0 зависящей от MagicByteSharedLibrary. Название и версия могут отличаться в Вашем случае.

1. Откройте последний скрипт-лог вашего сервера.
2. Найдите в нём строку (если данная строка отсутствует, Вы некорректно установили pbo-файл модификации):

```
[01:54:58][MagicByteSharedLibrary] Loading addon 'SuicideButton' (version 1.0.0).
```

3. Далее найдите строку (если данная строка отсутствует, Вы не переместили папку MagicByte из архива скачанного мода в папку профиля Вашего сервера или указали некорректные данные при покупке доступа к моду):

```
[01:54:58][MagicByteSharedLibrary] Addon 'SuicideButton' (version 1.0.0) has been loaded.
```

4. В логе также могут присутствовать следующие строки, если Вы не установили обязательную зависимость или ей не удалось запуститься (повторите этот раздел для неё), или если версия обязательной зависимости не соответствует ожидаемой (обновите мод-зависимость). При этом модификация не будет работать.

```
[01:54:58][MagicByteSharedLibrary] Error: Addon 'SuicideButton' is missing hard dependency 'MagicByteSharedLibrary' (expected version 2.0.0).
[01:54:58][MagicByteSharedLibrary] Error: Addon 'SuicideButton' is missing hard dependency 'MagicByteSharedLibrary' (expected version 2.0.0, found version 1.0.0).
```

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

```
[01:54:58][MagicByteSharedLibrary] Warning: Addon 'SuicideButton' is missing soft dependency 'MagicByteSharedLibrary' (expected version 2.0.0).
[01:54:58][MagicByteSharedLibrary] Warning: Addon 'SuicideButton' is missing soft dependency 'MagicByteSharedLibrary' (expected version 2.0.0, found version 1.0.0).
```

6. Если вы используете версии MagicByteSharedLibrary 2.1.0-2.1.5, проверьте наличие следующей строки. Если она присутствует, попробуйте перезапустить клиент/сервер. Если проблема сохраняется, обновите версию мода до актуальной.

```
[01:54:58][MagicByteSharedLibrary] Unix timestamp fetch failed.
```

## Как сообщать о проблемах с модификацией

Открывая тикет о проблеме с модификацией, сразу предоставьте:

1. Подробное описание проблемы: что именно случилось, и какого поведения Вы ожидали.
2. Подробные шаги для воспроизведения проблемы: что нужно нажать и что при этом должно отобразиться, чтобы проблема возникла. Данное описание должно быть максимально подробным, необходимо описывать каждое действие и каждое изменение отображаемого на экране. Можно также прикрепить скриншоты/видео. На скриншотах необходимо выделить проблемное места. Описание при этом тоже нужно.
3. Скрипт-лог сервера и лог консоли сервера.&#x20;
4. Если проблема произошла на клинете, прикрепите также скрипт-лог клиента.


# MagicByteSharedLibrary

Вспомогательный мод для модов от MagicByte.

Сначала прочитайте статью [Установка модификации](/workshop/ustanovka-modifikacii).

{% hint style="danger" %}
Могут возникать проблемы, если используете модификации, которые «оптимизируют» снижают FPS сервера.
{% endhint %}

## В архиве с модификацией Вы найдёте следующие файлы:

* MagicByteSharedLibrary.pbo - pbo модификации. Если Вы используете клиентские модификации, зависящие от этого мода, то его необходимо устанавливать как клиентский. Иначе можно установить как серверный.
* Папка MBSL - помещается в папку профиля (profile) Вашего сервера. Здесь находятся файл локализации и файл конфигурации модификации.

## Файл конфигурации

Файл конфигурации модификации расположен по пути *профиль\_сервера/MBSL/config.json.* В приведённом ниже файле конфигурации используются комментарии (символ '//' и следующие после них слова). Используемый формат (JSON) не поддерживает комментарии, поэтому данные файлы не могут быть использованы в качестве файлов конфигурации.

```json5
{
	"ServerLanguage": "ru", //Язык сервера.
	"TargetTPS": 180, //Значение - минимальный допустимый FPS сервера.
	"Debug": {
		"VerboseLogging": false, //Вкл/выкл Детальное логирование
		"PerformanceMonitor": false //Вкл/выкл Монитор производительности
	},
	"UI": {
		"NotificationColor": -11115786 //Цвет информационных уведомлений в виде десятичного представления
	}
}
```

Наиболее интересный параметром здесь является NotificationColor - он позволяет изменить цвет информационных уведомлений. Цвет здесь нужно указать в [целочисленном представлении](/mods/formaty-cvetov#celochislennoe-predstavlenie).

### Язык сервера

Язык сервера используется системой локализации, чтобы определить, сообщения на каком языке должны использовать серверные модификации или логи сервера. Значение параметра является кодом языка, полный список которых можно найти в статье [Редактирование файлов локализации](/mods/redaktirovanie-failov-lokalizacii).

### Подробное логирование

Включает/выключает режим подробного логирования. В режиме подробного логирования модификации могут выводить больше сообщений в скрипт-лог сервера. Эффект зависит от конкретной модификации. Сообщения в основном полезны для поиска и устранения проблем.

### Монитор производительности

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


# DayZShop

**DayZShop** - это клиентский мод (можно использовать как серверный), отвечающий за внутриигровую корзину. Вы можете запаковывать его в свой модпак и подписывать своими ключами.

## Установка

В полученном архиве вы увидите:

* Папку MagicByte, в которой будет находиться ключ лицензии. Её нужно перенести в директорию профиля (profiles, но может отличаться). Если у вас в директории профиля уже существует папка MagicByte, тогда вам нужно перенести в вашу папку файл под названием DayZShop.idx. **Это обязательно нужно сделать, иначе мод не будет работать.**
* Архив. В нем вы увидите папку DayZShop. В этой папке находится сам мод. Установите PBO как клиентскую часть.\
  В архиве также будет папка DZS - она содержит конфиги мода. Необходимо **всю папку** перенести в директорию профиля (обычно profiles), а затем **настроить** конфиг мод&#x430;**.**

## Настройка конфига

Для настройки конфига мода открываем файл **config.json**.

<figure><img src="https://2909774895-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F5GELIejIJQv0W9HfglUO%2Fuploads%2F7IUfFeFakisCPUQlJZc3%2Fimage.png?alt=media&amp;token=3f0005a5-3e0f-4735-abb2-a7330d4ff6f6" alt=""><figcaption></figcaption></figure>

{% hint style="danger" %}
Нужно обязательно настроить значения в server\_url и api\_token.
{% endhint %}

{% hint style="warning" %}
Кавычки в файле обязательны в соответствующих местах, не удаляйте их.
{% endhint %}

В строчке server\_url указывается ссылка, нужная для работы мода. Вам нужно заменить **только** premium.dayzplay.ru на Ваш домен.

В строчке api\_token указывается токен, нужный для работы мода. Вам нужно заменить token на api-токен сервера, который Вы получаете из настроек сервера в админ-панели Вашего сайта.

В строчке EnableServerOnlyMode значение должно быть false, если Вы используете мод как клиентский, и true, если как серверный. **Если перепутать значение, то у Вас будут баги на сервере.**

В строчке AccentColor указывается цвет акцента (кнопок) в интерфейсе корзине. Вам нужно указать цвет в формате [целочисленного представления](/mods/formaty-cvetov#celochislennoe-predstavlenie).

## Настройка локализации

В папке DZS можно найти файл local.loc. В нём можно отредактировать весь текст, который отображается модом. Про формат файла подробнее написано в [статье о файлах локализации](/mods/redaktirovanie-failov-lokalizacii).

## Добавление превью товаров

{% hint style="danger" %}
Рекомендуемое разрешение изображений превью: 200x130 или с аналогичным соотношением сторон (например, превью товаров с первого и второго шаблонов магазина).
{% endhint %}

{% hint style="info" %}
Кратко: в поле "Изображение в игре" необходимо указывать путь до изображения в VFS (виртуальной файловой системе) игры.
{% endhint %}

Для добавления превью товара необходимо создать pbo, содержащее картинки с превью товаров. Ниже приведен пример этого процесса.

{% hint style="info" %}
Пункты 1-3 описывают настройку Workbench. Если у Вас уже установлен и настроен Workbench, можно начать с пункта 4.
{% endhint %}

1. Устанавливаем и запускаем DayZ Tools из Steam.
2. Запускаем Workbench из DayZTools.
3. В настройках изменяем значение Source Data Directory на удобную папку. Перезапускаем Workbench.<br>

<figure><img src="https://2909774895-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F5GELIejIJQv0W9HfglUO%2Fuploads%2FfKYbATXzlFmN3sa1yY9l%2Fimage.png?alt=media&amp;token=2d0f5173-0744-475b-b6d7-b629db236ded" alt=""><figcaption><p>Options - настройки</p></figcaption></figure>

<figure><img src="https://2909774895-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F5GELIejIJQv0W9HfglUO%2Fuploads%2Fv6Ol09E9cYTVLpUzkXzY%2Fimage.png?alt=media&amp;token=2e57a52f-424d-4cd1-9b7f-753b200d6e44" alt=""><figcaption><p>Source data directory</p></figcaption></figure>

4. Создаём новую папку в указанной в предыдущем шаге папке (назовём её "DayZShopImages" в примере, но название может быть любым).
5. Помещаем все изображения в созданную папку.

{% hint style="warning" %}
Рекомендуется все изображения предварительно конвертировать в PNG. При использовании других форматов изображения могут некорректно конвертироваться.
{% endhint %}

6. Выделяем все изображения с зажатым Shift, нажимаем ПКМ -> "Register resource and import".&#x20;

<figure><img src="https://2909774895-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F5GELIejIJQv0W9HfglUO%2Fuploads%2FgCUZad23SYV7gnXvH7sP%2Fimage.png?alt=media&amp;token=31ee100d-a983-4d83-b0b8-5cb5584df658" alt=""><figcaption><p>Register resource and import</p></figcaption></figure>

{% hint style="warning" %}
Иногда Workbench может не преобразовать файл. В таком случае нужно выделить изображение, нажать ПКМ -> "Reimport resource".
{% endhint %}

7. Удаляем из папки оригинальные картинки, оставляя только EDDS-файлы.
8. Закрываем Workbench, открываем Addon Builder.
9. В Addon Builder в первой строке выбираем созданную в 4 шаге папку. Во второй строке выбираем любую удобную папку. **Третью строку оставляем пустой.** Нажимаем Pack.

<figure><img src="https://2909774895-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F5GELIejIJQv0W9HfglUO%2Fuploads%2FUh8nVDUn5pkSl8ONufsW%2Fimage.png?alt=media&amp;token=8fa7bdc8-932c-411c-8417-713384613fd6" alt=""><figcaption><p>Addon Builder</p></figcaption></figure>

10. В указанной в предыдущем пункте папке появится pbo-файл (в примере - DayZShopImages). Добавляем его в клиентский мод. Запоминаем название pbo. На сайте в поле "Изображение в игре" вводим "название\_пбо/названи&#x435;*\_*&#x43A;артинки.edds". Например, для картинки test.png из примера в поле необходимо было бы ввести "DayZShopImages/test.edds".

## Система "Обмена"

Настройка конфига config\_tradein.json

> ```json
>
> {
> 	"options": [
> 		{
> 			"id": "1", /// Уникальный id обмена
> 			"cooldown": 5, /// Кд между обменами, указывается в секундах
> 			"name": "Обмен фруктов", /// Название обмена, отображается в корзине.
> 			"reward": 500, /// Награда, сколько коинов получит игрок на сайте.
> 			"locations": [ /// Локации где будут доступен обмен, если вы хотите сделать его доступным, укажите радиус 15000 и координаты центра карты.
> 				{
> 					"radius": 15000, 
> 					"pos": [
> 						7000,
> 						34,
> 						9300
> 					]
> 				}
> 			],
> 			"items": [
> 				{
> 					"health": 50, /// Здоровье предмета, больше 50%
> 					"count": 3, /// Кол-во предметов 
> 					"quantity": 1, /// Заполняемость предмета
> 					"classname": "Pear" /// Сам предмет
> 				},
> 				{
> 					"health": 50,
> 					"count": 3,
> 					"quantity": 1,
> 					"classname": "Apple"
> 				}
> 			]
> 		},
> 		{
> 			"id": "bazar_market2",
> 			"cooldown": 2000,
> 			"name": "Bazar Trade2",
> 			"reward": 600,
> 			"locations": [
> 				{
> 					"radius": 400,
> 					"pos": [
> 						10589,
> 						34,
> 						2524
> 					]
> 				}
> 			],
> 			"items": [
> 				{
> 					"health": 50,
> 					"count": 3,
> 					"quantity": 1,
> 					"classname": "Pear"
> 				},
> 				{
> 					"health": 50,
> 					"count": 3,
> 					"quantity": 1,
> 					"classname": "Apple"
> 				}
> 			]
> 		}
> 	],
> 	"enabled": true
> }
> ```


# DayZSetManager 1.0.0-1.1.3

Мод предназначен для предоставлением игрокам выбора снаряжения и точки появление при возрождении.

Сначала прочитайте статью [Установка модификации](/workshop/ustanovka-modifikacii).

## Возможности мода:

* Удобная и гибкая настройка снаряжения игрока.
* Игрок может сам собрать свой уникальный набор из доступных предметов.
* Игрок может сохранять собранный набор для быстрого выбора.
* Возможность настройки персонального снаряжения для игрока по SteamID 64.
* Блок "описание" для каждой вещи берется из конфигурации игры и так же информирует игрока о дополнительных предметах/аттачментах внутри или на предмете оружие и тд.&#x20;
* В блоке "содержимое" информирует игрока что на нем будем вообщем надето при появление.
* Игрок может выбрать точку появления между теми которые настроила администрация сервера.
* Есть возможность устанавливать к/д на появление в одной точке
* При появление игроков в одной точке, мод по радиусу проверит игроков рядом и если на точке будут находиться посторонние игроки, он проинформирует игрока что появление опасно.
* Если все разрешенный точки находятся в к/д появление произойдет случайным образом в одну из разрешенных точек (система предпочтет точку где рядом не будет игроков)
* Мод поддерживает локализацию
* Имеет интеграцию с модом @DayZShop

Совместимость модов (тестирование проводилось на ванильном сервере, дополни

## Config

* Данный конфиг не является работоспособным при копирование, сделан для информирование клиентов о его переменных.

  ```json
  {
  	"DefaultSets": [ /// Список наборов доступный всем игрокам 
  		"Example Set" ///Название набора 
  	],
  	"Definitions": { /// Настройка сета
  		"TestSet": /// название сета
  		{
  			"display": true, /// Отображать или не отображать сет в разделе сохраненные сеты false не отображать  
  			"items": [ /// Тут указываются предметы которые будут выдаватся игроку при любом выбранном сете 
  				{
  					"content": [], /// Аттачменты, то что требуется повесить на предмет "count": 1, "quantity": 1,"classname": "BINT"
  					"count": 1, /// Кол-во повторений выдачи предмета
  					"quantity": 1, /// Целостность/наполняемость предмета
  					"classname": "BINT" /// Classsname прдмета для выдачи
  				}
  			], 
  			"spawns": { /// настройки точек появления
  				"Example spawn 2": { /// Название точки (для игроков)
  					"cooldown": 10, /// Установка к/д на точку (указывается в секундах)
  					"points": [/// фактические точки появления игрока (можно указать множество кол-во точек, мод выберит одну из рандомным способом)
  						{
  							"radius": 20,/// Радиус проверки на игроков по близости (в метрах)
  							"position": "6000.000000 400.000000 6000.000000" ///Фактическая точка появления
  						}
  					],
  					"position": "6000.000000 400.000000 6000.000000" ///Позиция маркера на карте (высота не имеет значения)
  					
  				}
  			},
  			"slots": /// Настройка слотов (отображение возможных категорий для выбора снаряжений 
  			[
  				{
  					"category": "Weapon", /// Название категории 
  					"content": [], /// Аттачменты, то что требуется повесить на предмет
  					"count": 1, /// Кол-во повторений выдачи предмета
  					"quantity": 1, /// Целостность/наполняемость предмета
  					"classname": "AK74" /// Classsname прдмета для появления
  				},
  			]
  		},
  	}
  }
  ```

## Для вашего удобства мы подготовили онлайн конструктор для создание конфига

Ссылка на онлайн конструктор [тут](https://autodonate.magicbyte.ru/utils/sets-config-generator)

Для начала создания сетов нажимаем на синею кнопку "добавить сет" и указываем его id (это может быть текст)

<figure><img src="https://2909774895-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F5GELIejIJQv0W9HfglUO%2Fuploads%2FZKnfIspmghXLZoo2i78m%2Fimage.png?alt=media&amp;token=f94e2eab-083d-4f96-a9a2-0dd0f8f97234" alt=""><figcaption></figcaption></figure>

Мы будем использовать тестовое название "test1"

<figure><img src="https://2909774895-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F5GELIejIJQv0W9HfglUO%2Fuploads%2FNhl7IuhOl1TCg04rbcLi%2Fimage.png?alt=media&amp;token=3cad3ab7-7073-4ef6-9cde-749b76d62813" alt=""><figcaption><p>Если вы ставите галочку на пресете, он будет отображаться в сохраненных наборах.</p></figcaption></figure>

Нажимаем предметы по категориям и кнопку добавить&#x20;

<figure><img src="https://2909774895-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F5GELIejIJQv0W9HfglUO%2Fuploads%2FtRfsiM46qzkHQicniKh5%2Fimage.png?alt=media&amp;token=8e14fe34-4b7c-48cf-ae2e-c244475f5bc2" alt=""><figcaption></figcaption></figure>

<figure><img src="https://2909774895-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F5GELIejIJQv0W9HfglUO%2Fuploads%2FsUbiEa3t1hEjKFSydqE6%2Fimage.png?alt=media&amp;token=96371b5a-58b6-45c4-b789-f04007936e79" alt=""><figcaption><p>Тут мы можем наблюдать что мы создали категорию голова, и дали возможность повесить на нее шлем (вместо шлема вы указываете его класс нейм)</p></figcaption></figure>

Если вы хотите что бы шлем появлялся с пнв (при условие что на ваш шлем оно вешается) нажимаем на кнопку содержимое этого предмета и указываем пнв

<figure><img src="https://2909774895-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F5GELIejIJQv0W9HfglUO%2Fuploads%2FTMaqzfDgeYrEFo6PB0iN%2Fimage.png?alt=media&amp;token=1cc50db0-5bb8-4cb4-bcce-68b3acb89314" alt=""><figcaption></figcaption></figure>

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

<figure><img src="https://2909774895-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F5GELIejIJQv0W9HfglUO%2Fuploads%2FShNnmICDOMTOzxrW6tJN%2Fimage.png?alt=media&amp;token=9eb43224-7662-4854-befa-8a0b8aff39f9" alt=""><figcaption></figcaption></figure>

И так далее, вы можете создать все категория, правая рука, левая, нога, голова туловище рюкзак, называть категория вы можете как вам удобнее (советуем называть их более понятными для игроков, все же вы делаете это для них) и в каждую категорию вы можете добавить вариацию одежды, пример: на голову можно одеть шлем, а можно еще одеть шлем с пнв, на ноги можно одеть пять разных штанин и так далее.

Теперь мы переедем к стартовому набору ( то что будет появляться у игрока) и что бы это не прописывать в каждую одежду, нажимаем на кнопку дополнительные предметы.&#x20;

<figure><img src="https://2909774895-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F5GELIejIJQv0W9HfglUO%2Fuploads%2FUXVanO4kztt72Ecw18bH%2Fimage.png?alt=media&amp;token=fe810fc9-a3c2-4627-b45d-c139e1c3c391" alt=""><figcaption></figcaption></figure>

Мы хотим что бы у каждого игрока при появление было два бинта (первое поле на скрине)

Один нож  (второе поле на скрине)

И одно целое яблоко (третий скрин на экране)

После этого мы перейдем настройкам точек появления.

<figure><img src="https://2909774895-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F5GELIejIJQv0W9HfglUO%2Fuploads%2F2MY9HhpWTpcjCwpW6c3Z%2Fimage.png?alt=media&amp;token=97bae0a2-550a-4256-8f37-63cbe3ee27e3" alt=""><figcaption></figcaption></figure>

id спавна это название точки, для теста называем её "тест1"

<figure><img src="https://2909774895-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F5GELIejIJQv0W9HfglUO%2Fuploads%2FTTXnP1q9wEUUnLIW6beY%2Fimage.png?alt=media&amp;token=8fdae77e-bcf5-460f-9a30-5314321982f3" alt=""><figcaption></figcaption></figure>

В первом поле мы указываем куда будет фокусироваться маркер на карте для визуального понимания игрока где он появится\
Далее мы можем указать к/д на появление в этой точке, установил 20 секунд, если после появление не пройдет 20 секунд и ему потребуется возродится он не сможет это сделать до окончание к/д. &#x20;

Теперь добавляем фактические точки появления, мы рекомендуем делать 5-7 точек ( что бы игроки при выборе спавна не появлялись только  одной (друг на друге), 5-7 точек с дистанцией друг от друга 20-30 метров отлично подойдут

У каждой точке можно указать радиус проверки на игроков рядом.

**\*\* Между координатами не должно быть не каких точек и запятых**

После всех этих настроек мы можем прокрутить сайт на самый вверх и по  нажатию на зеленную кнопку скачать конфиг. (если вы завершили настройку, так же в любой момент конфиг можно загрузить на сайт)

Вот что получилось&#x20;

```json
{
    "DefaultSets": [],
    "Definitions": {
        "test1": {
            "display": false,
            "items": [
                {
                    "content": [],
                    "classname": "Бинт",
                    "count": 2,
                    "quantity": 1
                },
                {
                    "content": [],
                    "classname": "нож",
                    "count": 1,
                    "quantity": 1
                },
                {
                    "content": [],
                    "classname": "Яблоко",
                    "count": 3,
                    "quantity": 1000
                }
            ],
            "slots": [
                {
                    "category": "Голова",
                    "content": [
                        {
                            "classname": "пнв",
                            "count": 1,
                            "quantity": 1
                        }
                    ],
                    "classname": "Шлем",
                    "count": 1,
                    "quantity": 1
                },
                {
                    "category": "Штаны",
                    "content": [
                        {
                            "classname": "бинт",
                            "count": 1,
                            "quantity": 1
                        }
                    ],
                    "classname": "Штаны",
                    "count": 1,
                    "quantity": 1
                }
            ],
            "spawns": {
                "тест1": {
                    "position": "6000.000000 400.000000 6000.000000",
                    "cooldown": 20,
                    "points": [
                        {
                            "radius": 1,
                            "position": "0 0 0"
                        },
                        {
                            "radius": 1,
                            "position": "0 0 0"
                        }
                    ]
                }
            }
        }
    }
}
```

В DefaultSets вам нужно прописать название вашего созданного сета "DefaultSets": \["test1"]

Теперь мы перейдем к настройки индивидуальных ситов (по SteamID64)

Добавляем новый сет, для примера название будет "test2"

<figure><img src="https://2909774895-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F5GELIejIJQv0W9HfglUO%2Fuploads%2FP6dJhvGKbRKLU3GhaR9K%2Fimage.png?alt=media&amp;token=239d7a65-b27b-4653-b34c-dd284d31b859" alt=""><figcaption></figcaption></figure>

Для удобства игроков, рекомендуем устанавливать галочку, тем самым игроки сразу увидят свой сет в сохраненных наборах.

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

После уже всех настроек мы скачиваем конфиг

Для того чтобы прописать созданный сет определенному игроку, в папке Profiles находим серверную папку нашего мода DZSM > users тут вы должны найти файл с названием SteamID 64 игрока которому хотите прописать определенный сет, для этого в поле "AvailableSets": \[] прописываем название сета (в кавычках) если таких сетов несколько, прописываем названия через запятую&#x20;

Пример "AvailableSets": \["test2","test3"],&#x20;

```json
{
	"Cooldowns": {
		"Example Set": {
			"Example spawn": 1668526617
		}
	},
	"AvailableSets": ["test2"],
	"SavedSets": {}
}
```

Установка мода

Для установки мода вам потребуется бесплатный вспомогательный мод @[MagicByteSharedLibrary](https://autodonate.magicbyte.ru/workshop/product/magicbyte-shared-library)

В скачанном архиве будут следующие файлы: папка с модом @DayZSetManager устанавливаете как обычный клиентский мод.

Папка MagicByte лицензия мода (устанавливается в папку профиль)

Папку DZSM устанавливаем в папку профиль (не меняйте название этой папки)

В папки DZSM находится файл конфигурации и локализации

Файл конфигурации вы можете настроить через онлайн конструктор (о котором говорилось ранее, не забудьте в "DefaultSets": \[] прописать название созданных сетов.

Интеграция с модом @DayZShop позволяет через сайт с авто доната продавать: сеты, точки появления и дает возможность игроку полностью настроить свой сет (для работы интеграции на сервере должен быть установлен мод @DayZShop)

Локализация мода

В папке DZSM есть файл с разрешением .loc

&#x20;

```
DEFAULT ru ///Дефолнтный перевод 

SECTION ru ///Перевод текста на ru 
DZSM_EQUIPMENTTAB_BUTTONTAB_TEXT Выбор снаряжения
DZSM_EQUIPMENTTAB_HEADER_TEXT Выбор снаряжения
DZSM_EQUIPMENTTAB_BUTTONSAVE_TEXT Сохранить
DZSM_EQUIPMENTTAB_BUTTONRANDOMIZE_TEXT Случайно
DZSM_SAVEDSETSTAB_HEADER_TEXT Сохранённые наборы
DZSM_SAVEDSETSTAB_BUTTONTAB_TEXT Сохранённые наборы
DZSM_BUTTONTOMAP_TEXT Выбор локации
DZSM_SETNAME_BUTTONCONFIRM_TEXT Сохранить
DZSM_SETNAME_BUTTONCANCEL_TEXT Отмена
DZSM_CONTENTPREVIEW_HEADER_TEXT Содержимое
DZSM_ITEMPREVIEW_CONTENT_TEXT Содержит:
DZSM_ITEMPREVIEW_HEADER_TEXT Описание
DZSM_SET_LOAD_ERROR Предмет %1 для категории %2 из набора %3 недоступен.
DZSM_SPAWNTAB_BUTTONTOEQUIPMENT_TEXT Выбор снаряжения
DZSM_SPAWNTAB_BUTTONSPAWN_TEXT Выбрать
DZSM_SPAWNTAB_BUTTONRANDOMSPAWN_TEXT Случайный выбор
DZSM_SPAWNTAB_PAGEHEADER_TEXT Выбор локации
DZSM_ITEM_DESCRIPTOR %1 (%2/%3) x%4
DZSM_DUPLICATE_SET_NAME_ERROR Ошибка: такое имя уже используется.
DZSM_SPAWNTAB_COOLDOWN_ERROR Ошибка: время восстановления точки ещё не прошло.
DZSM_SPAWNTAB_PROXIMITY_ERROR Внимание: рядом с точкой есть игроки! Появиться здесь?
DZSM_BUTTON_OK Ок
DZSM_BUTTON_CANCEL Отмена
```

Если вы хотите сделать перевод на английский язык, дублируете все ключи вмести с SECTION и ru заменяете на en, после русский перевод меняете на английский&#x20;

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

Поддержка языков:

0 - English (en)

1 - French (fr)&#x20;

2 - Spanish (es)&#x20;

3 - Italian (it)&#x20;

4 - German (de)&#x20;

5 - Czech (cs)&#x20;

6 - Russian (ru)&#x20;

7 - Chinese simplified (zhs)&#x20;

8 - Chinese (zh)&#x20;

9 - Polish (pl)&#x20;

10 - Japanese (ja)&#x20;

11 - Portuguese (pt)

Распространенные вопросы&#x20;

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

Особенности:

disableRespawnDialog = 0 если значение будет 1, мод не будет работать.


# DayZSetManager 2.0.0 +

Мод предназначен для предоставления игрокам возможности выбора снаряжения и точки появления при возрождении.

Сначала прочитайте статью [Установка модификации](/workshop/ustanovka-modifikacii).

## Возможности мода

* Удобная и гибкая настройка снаряжения игрока.
* Игрок может сам собрать свой уникальный набор из доступных предметов.
* Игрок может сохранять собранный набор для быстрого выбора. Сохранённые наборы привязываются к серверу.
* Возможность настройки персонального снаряжения для игрока по SteamID 64.
* Блок "описание" для каждой вещи берется из конфигурации игры, а также информирует игрока о дополнительных предметах/аттачментах внутри или на предмете/оружии и т. д.&#x20;
* Блоке "содержимое" информирует игрока о всех предметах, которые он получит при появлении.
* Игрок может выбрать точку появления из набора, настроенного администраторами сервера.
* Есть возможность устанавливать к/д на появление в одной точке.
* При выборе точке мод проверит наличие появляющихся/находящихся у точки других игроков и предупредит игрока об их наличии.
* Если все точки находятся на к/д, игрок может выбрать случайную точку. Мод предпочтёт точку, у которой нет других игроков, при наличии такой, или предупредить игрока о наличии игроков.
* После появления игрока и выдачи ему снаряжения, функция StartingEquipSetup из init.c будет вызвана, что позволит дополнительно настроить процесс появления игрока.
* Мод поддерживает настраиваемую через файл на сервере локализацию.
* Имеет интеграцию с модом @DayZShop.

## Установка

Для установки мода:

* Установите DayZSetManager.pbo как клиентскую модификацию.
* Папку DZSM поместите в папку профиля вашего сервера.
* Папку MagicByte поместите в папку профиля вашего сервера. Если такая папка есть, объедините их содержимое.

## Конфигурация мода

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

### Файл конфигурации набора

Файл конфигурации набора размещается по пути DZSM/sets/{название набора}.json. Название файла должно соответствовать названию набора. Файл использует формат JSON. Ниже приведён пример файла конфигурации набора под названием "Example Set". Отметим, что в данном файле конфгурации в некоторых местах не указываются поля, поэтому система использует их стандартные значения (значение "count" - "1", значение "quantity" - "1", значение "content" - "\[]").&#x20;

```json
{
	"Definition": { //Обязательное поле, в котором описан сам набор
		"display": true, //Отображать ли набор в списке "сохранённые наборы"
		"slots": [ //Предметы, распределённые по категориям
			{
				"category": "Character", //Категория предмета. Может быть любым текстом.
				"classname": "SurvivorM_Mirek", //Класснейм предмета. В данном случае - персонаж.
				"content": //Что положить в предмет. В случае с персонажем - что выдать ему в инвентарь, если он будет выбран.
				[
					{
						"classname": "TShirt_Red", //Класснейм предмета
						"count": 1, //Сколько раз выдать предмет. Если поля нет, предмет будет выдан один раз.
						"quantity": 1, //Заполненность предмета/прочность/количество в стаке. Если поля нет, оно считается равным 1.
					        "UsePercentileQuantity": true // Процентное заполнение Quantity - true, точное заполнение Quantity - false.
                                         }
				]
			},
			{
				"category": "Bag", //Категория предмета. Может быть любым текстом.
				"count": 1, //Сколько раз выдать предмет. Если поля нет, предмет будет выдан один раз.
				"quantity": 1, //Заполненность предмета/прочность/количество в стаке. Если поля нет, оно считается равным 1.
			        "UsePercentileQuantity": true // Процентное заполнение Quantity - true, точное заполнение Quantity - false.
				"classname": "AssaultBag_Black", //Класснейм предмета
				"content": [ //Что положить в предмет
					{
						"classname": "CZ61", //Класснейм предмета
						"count": 2, //Сколько раз выдать предмет. Если поля нет, предмет будет выдан один раз.
						"content": [
							{
								"classname": "Mag_CZ61_20Rnd" //Класснейм предмета
							},
							{
								"classname": "PistolSuppressor" //Класснейм предмета
							}
						]
					}
				]
			}
		],
		"items": [ //Дополнительные предметы, которые игрок получит при появлении всегда, если у него есть доступ к этому набору
			{
				"count": 1, //Выдать предмет 1 раз
				"quantity": 1, //Заполненность предмета/прочность/количество в стаке. Если поля нет, оно считается равным 1.
			        "UsePercentileQuantity": true // Процентное заполнение Quantity - true, точное заполнение Quantity - false.
				"classname": "SodaCan_Cola", //Класснейм предмета
				"content": [] //Что положить в предмет. Если в предмет ничего не помещается, поле можно не указывать
			}
		], 
		"spawns": { //Настройки точек появления, которые игрок увидит, если у него есть доступ к этому набору
			"Example spawn": { //Точка под названием "Example spawn"
				"cooldown": 120, //К/д точки
				"points": [ //Набор реальных точек, среди которых будет выбрано место после выбора этой точки
					{
						"radius": 20, //Радиус проверки на игроков
						"position": "2500.000000 20.000000 2000.000000" //Координаты точки
					}
				],
				"position": "2500.000000 0.000000 2000.000000" //Отображаемая на карте позиция точки
			}
		},
	}
}
```

Если игрок имеет доступ к данному набору, то в меню у него в категории Character появится пункт с персонажем Mirek, на которого будет надета футболка, в категории "Bag" появится рюкзак, в котором будет лежать 2 CR-61 Skorpion, на каждом их которых будет закреплён глушитель и магазин на 20 патронов. Также игрок получит доступ к точке появления под названием "Example Set", расположенной на поверхности на координатах 2500 0 2000.

### Глобальный файл конфигурации

Глобальный файл конфигурации находится по пути DZSM/config.json. Файл использует формат JSON.

```json
{
        "UserSetsOverrideDefaultSets": true/false //Скрывать ли def наборы, если у игрока есть другие наборы. 
	"DefaultSets": [ //Список доступным всем наборов
		"Example Set", //Название набора
		"Test" //Название набора
	],
	"PreloadSets": [ //Список предзагружаемых наборов
		"Example Set" //Предзагружаемый набор
	]
	        "quickslots": { //Слоты быстродействия, работают в порядке очереди.
                "slot1": ["BandageDressing","Apple"], //В каждый слот вы можете назначить предмет.
                "slot2": [],
                "slot3": [],
                "slot4": [],
                "slot5": [],
                "slot6": [],
                "slot7": [],
                "slot8": [],
                "slot9": [],
                "slot0": []
        },
        "InterfaceColor": -16101938 //Цвет интерфейса, подробнее в разделе "форматы цветов"
}
```

В данном файле конфигурации можно настроить как доступные всем наборы, так и предзагружаемые наборы. Предзагружаемые наборы - это наборы, информация о которых читается из их файлов конфигурации в момент загрузки сервера. Эти наборы увеличивают время загрузки сервера, но не влияют на время открытия меню. Остальные наборы загружаются по необходимости. Загрузка такого набора начинается, когда впервые какой-либо игрок с доступом к нему открывает меню. Такие наборы влияют на время открытия меню в первый раз у первого игрока, которому потребовался такой набор.

Иначе говоря, предзагружаемые наборы замедляю загрузку сервера, но уменьшают время открытия меню у игроков.&#x20;

### Файл конфигурации игрока

Файл конфигурации игрока размещается по пути DZSM/users/{steamID64}.json. Файл использует формат JSON. Файл читается сервером при входе игрока, и обновляется при выходе игрока.

```json
{
	"Cooldowns": { //Список к/д точек появления игрока
		"Example Set": { //Набор, из которого взяты точки
			"Example spawn": 1692032832 //Точки, взятые из набора, и Unix-timestamp времени, когда к/д закончится
		}
	},
	"AvailableSets": [ //Список доступных игроку наборов
		"Test" //Название набора
	]
}
```

## Локализация

Файл локализации располагается по пути DZSM/locale.loc. Для инструкций по его изменению обратитесь к статье [Редактирование файлов локализации](/mods/redaktirovanie-failov-lokalizacii). В файле локализации можно указывать id набора в качестве ключа (в таком случае оно не должно содержать пробелов), чтобы переводить названия наборов на клиенте.


# NotPicksarAnims

Сначала прочитайте статью [Установка модификации](/workshop/ustanovka-modifikacii).

{% embed url="<https://www.youtube.com/watch?v=n1FruLv-mro>" %}

Модификация добавляет различные анимации (смотрите в видео)\
\
Требуется вспомогательный мод [MagicByteSharedLibrary](/mods/magicbytesharedlibrary)&#x20;

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

PBO NotPicksarAnims - является клиент частью (Можете запаковать в свой мод)

Папка MagicByte - является лицензией устанавливается в папку Profile (если папка уже существует, закидываете только ее содержимое уже в существующую папку) \
\
Не совместим с посторонними модификациями по анимациям \
Тестировался на ванильном сервере версии 1.23<br>


# DayZPartyManager

Открытие меню - P. Установка метки - T

Сначала прочитайте статью [Установка модификации](/workshop/ustanovka-modifikacii).

<figure><img src="https://2909774895-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F5GELIejIJQv0W9HfglUO%2Fuploads%2FPZhxq7J3Yh0C3u29f7iO%2FDayZPartyManager.png?alt=media&amp;token=03f176d4-4ec3-47fb-b9e8-8aadeae69c26" alt=""><figcaption></figcaption></figure>

Требуется БЕСПЛАТНАЯ вспомогательная модификация [MagicByteSharedLibrary](/mods/magicbytesharedlibrary)

Скачиваемый архив:

DayZPartyManager.pbo - клиентская часть, разрешено запаковывать в собственный мод.

Папка MagicByte - устанавливается в папку profile (если у вас уже есть эта папка, вставьте в существующую только содержимое)

DZPM - это конфиг и локализация, устанавливается в папку profile

config.json

<pre class="language-json"><code class="lang-json">{
<strong>  "WorldMarkerDetailedDistance": true, // Отображать дистанцию до метки в метрах (если дистанция меньше 1км)
</strong>  "PlayerMarkerDetailedDistance": true, // Отображать дистанцию до ирока в метрах (если дистанция меньше 1км)
  "WorldMarkerMaximumLimit": 5, // Лимит на максимальное число меток (которые игрок сможет установить)
  "PlayerMarkerMinimalDistanceDisplay": 0, // Растояние с которого отображается дистанция над игроком (если указать 30, то дистанция меньше 30м не будет отображаться)
  "EnableWorldMarkers": true, // Вкл/выкл меток
  "WorldMarkerAllowDistanceDisplay": true, // Отображать дистанцию до меток
  "WorldMarkerMaximumLifetime": 60, // Максимальное время жизни метки
  "DefaultPartySize": 5, // Лимит команды 
  "UIDetailedDistanceDisplay": true, // Отображать дистанцию до игрока в метрах в HUD (если дистанция меньше 1км)
  "WorldMarkerMinimalDistanceDisplay": 0, // Растояние с которого отображается дистанция до метки (если указать 30, то дистанция меньше 30м не будет отображаться)
  "UIAllowDistanceDisplay": true, // Отображать дистанцию HUD
  "MaximumUpdateInterval": 5000, // Максимальная частота обновления в мс
  "HiddenPlayers": null, // Скрытый список игроков онлайн ["SteamId","SteamID"]
  "PlayerMarkerAllowDistanceDisplay": true, // Отображать дистанцию до игроков
  "MinimalUpdateInterval": 100, // Минимальная частота обновления в мс
  "DisplayOnline": true // Отображать онлайн сервера
  "AllowMembersToInvite": true // Приглашать в команду могут все участники команты или только лидер
}
</code></pre>

&#x20;76561198287620561.json - это конфиг игрока

```json
{
	"PartySizeModifier": 0, // Индивидуальное разширение команды (цифра)
	"TeamID": "76561198287620561" // id команды
}
```

\
&#x20; 76561198287620561.json - это конфиг команды (не предназначен для редактирования) можно отслеживать кто находится в команде.

```json
{
   "MaxSize":2, // максимальное кол-во команды
   "Leader":{
      "Name":"BAREBUX", // ник лидера
      "SteamID":"76561198287620561" // steamID64 лидера
   },
   "Members":[
      {
         "Name":"BAREBUX", // Ник игрока в команде 
         "SteamID":"76561198287620561" // steamID64 игрока в команде 
      }
   ]
}
```


# Magic Bank

Банкинг от MagicByte

Сначала прочитайте статью [Установка модификации](/workshop/ustanovka-modifikacii).

## Файлы модификации

В архиве с модификацией можно найти следующие файлы:

* Папка DZB - в этой папке содержатся файлы конфигурации и локализации модификации. Помещается в папку профиля сервера.
* Папка MagicBank - в этой папке содержится pbo-файл модификации.
* Файл ConfigConvert.html - конвертер файлов данных игроков из других модификаций-банкингов. Открывается с помощью браузера.

## Конвертирование файлов данных игроков

Чтобы конвертировать файлы данных игроков от старой модификации, необходимо запустить ConfigConvert.html, после чего в браузере откроется вкладка с конвертером. Сначала нужно выбрать, файлы какой модификации конвертировать, после чего нужно нажать на кнопку "выбрать файлы" и выбрать файлы данных игроков (можно выбрать несколько файлов).

![](https://2909774895-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F5GELIejIJQv0W9HfglUO%2Fuploads%2FXiJS5pyk6OW9HnOowGLp%2Fimage.png?alt=media\&token=3db89e4f-c92a-42ff-91bb-c803475137b0)

После подтверждения выбора файлов, конвертер автоматически преобразует все файлы в формат, используемый модификацией Magic Bank, и предложит сохранить архив с ними. Если какие-то файлы не удастся преобразовать, они будут проигнорированы.

## Добавление банкоматов

Модификация добавляет 3 стандартных банкомата, представленных класснеймами: DZB\_ATMTinkoff, DZB\_ATMMagicBank, DZB\_ATMKramtsovBank. Для их работы достаточно создать их в мире в любом удобном месте.

## Логи модификации

Модификация ведёт логи всех совершаемых игроками операций. Логи попадают в папку *профиль\_сервера/DZB/logs.* Каждый лог имеет название *DayZBank\_год\_месяц\_день\_час\_минута\_секунда.txt.* Дата и время в названии соответствуют времени запуска модификации. Вся информация в логе соответствует операциям, совершённым после этого времени.&#x20;

## Конфигурация мода

Файл конфигурации мода находится по пути *профиль\_сервера/DZB/config.json*. В приведённом ниже файле конфигурации используются комментарии (символ '//' и следующие после них слова). Используемый формат (JSON) не поддерживает комментарии, поэтому данные файлы не могут быть использованы в качестве файлов конфигурации.

```json5
{
	"Commission": 0.3, //Комиссия, взымаемая при переводе другому игроку 
	"OperationDelay": 5, // Задержка между действиями (снять/пополнить/перевести) в секундах
	"CurrencyConversionRate": { //Список поддерживаемой валюты в формате "класснейм": стоимость_единицы
		"kr_money_rub10": 10, //Один kr_money_rub10 стоит 10 ед. валюты
		"kr_money_rub50": 50, //Один kr_money_rub50  стоит 50 ед. валюты
		"kr_money_rub100": 100, //Один kr_money_rub100 стоит 100 ед. валюты
		"kr_money_rub500": 500, //Один kr_money_rub500 стоит 500 ед. валюты
		"kr_money_rub1000": 1000, //Один kr_money_rub1000 стоит 1000 ед. валюты
		"kr_money_rub2000": 2000, //Один kr_money_rub2000 стоит 2000 ед. валюты
		"kr_money_rub5000": 5000, //Один  kr_money_rub5000 стоит 5000 ед. валюты
	},
	"Account": { //Настройки счёта игрока
		"DefaultCurrencyLimit": 10000, //Стандартный лимит счёта
		"InitialAmount": 1000 //Изначальный баланс счёта
	},
	"Payday": //Настройки системы зарплаты
	{
		"Enable": true, //Вкл/Выкл систему
		"AccumulatePlaytime": true, //Вкл/выкл накопления отыгранного времени
		"Interval": 60, //Сколько времени (в секундах) нужно отыграть, чтобы получить зарплату
		"BasePay": 1000 //Стандартная зарплата
	}
}
```

## Файл данных игрока

Файлы данных игроков находится в папке *профиль\_сервера/DZB/users*. Название файла совпадает со SteamID64 игрока. В приведённом ниже файле конфигурации используются комментарии (символ '//' и следующие после них слова). Используемый формат (JSON) не поддерживает комментарии, поэтому данные файлы не могут быть использованы в качестве файлов конфигурации.

**Важно: изменения в файле данных игрока применяются, только когда игрок не находится на сервере. Изменения, сделанные, пока игрок находится на сервере, отменяются.**

```json5
{
	"AccumulatedPlaytime": 8, //Отыгранное время с прошлой зарплаты (в секундах)
	"Amount": 13000, //Баланс счёта
	"PayModifiers": { //Модификаторы зарплаты игрока в формате "уникальное_название": сумма
		"Example": 500 //Увеличивает зарплату игрока на 500
	},
	"LimitModifiers": { //Модификаторы лимита счёта игрока в формате "уникальное_название": сумма
		"Test": 1000, //Увеличивает лимит счёта игрока на 1000
		"Test2": 2000 //Увеличивает лимит счёта игрока ещё на 2000
	}
}
```

### Модификаторы лимита счёта

В отличие от других модификаций, Magic Bank использует не одно поле бонуса лимита счёта, а систему модификаторов. Это позволяет совмещать несколько бонусов и легко отличать их, а также другим даёт других модам возможность добавлять свои бонусы, не конфликтуя с другими бонусами. Каждый модификатор должен иметь уникальное (для этого игрока) название.

Лимит счёта игрока равен: стандартный лимит счёта + сумма модификаторов. Для файла данных и конфига выше лимит счёта этого игрока будет равен: 10000 + 1000 + 2000 = 13000.

### Модификаторы зарплаты игрока

Аналогично модификатором счёта, модификация также добавляет модификаторы зарплаты. Сумма модификаторов добавляется к **каждой** зарплате игрока. Название каждого модификатора должно быть уникальным.

Зарплата игрока равна: базовая зарплата + сумма модификаторов. Для файла данных и конфига выше зарплата игрока равна: 1000 + 500 = 1500.


# MagicBattlePass

MagicBattlePass - это серверная модификация, предназначена для получение данных с сервера и передачи их на сайт. <br>

{% hint style="danger" %}
Для получение данной модификации требуется пройти дополнительную модерацию через тикет систему.
{% endhint %}

После того как ваша модификация успешно пройдет модерацию, вы сможете скачать её.

В архиве вы найдёте:

* Папку Profile. В ней будет находиться папка MagicByte. Вам нужно будет перенести всю папку на ваш сервер в папку Profile. Если у вас уже есть папка MagicByte, просто объедините их содержимое.
* Папку MBP, это конфиг модификации, перенесите в папку Profile и отредактируйте конфиг.
* Папку MagicBattlePass - это сам мод, установите как серверный мод.


# MagicSkins

🔹 **MagicSkins** — уникальная модификация, которая позволяет **перекрашивать вещи прямо в игре** с помощью баллончика.

## В архиве с модификацией Вы найдёте следующие файлы:

* MagicByteSkins.pbo - pbo модификации. Установите модификацию как клиентскую.
* MagicByteSkins\_SERVER.pbo - Установите как серверная модификация.&#x20;
* Папка MBS - помещается в папку профиля (profile) Вашего сервера. Здесь находятся файл локализации и файл конфигурации модификации.

Общий конфиг SkinsConfig

```json
{
    "skinStructure": {             //  Обязательное поле, определяющее параметры перекраски предметов
        "base_reskin_cost": 10.0,  //  Базовый расход баллончика при перекраске предмета (единиц краски за одно применение).
        "variants": {              //  Возможные варианты перекраски предметов.
            "AK101": [             //  Базовый класс предмета (оригинальный внешний вид).
                "AK101_Black",     //  Возможный вариант нового цвета.
                "AK101_Green"      //  Возможный вариант нового цвета.
            ],
            "AKS74U": [            //  Базовый класс предмета (оригинальный внешний вид).
                "AKS74U_Black",    //  Возможный вариант нового цвета.
                "AKS74U_Green"     //  Возможный вариант нового цвета.
            ],
            "CZ527": [             //  Базовый класс предмета (оригинальный внешний вид).
                "CZ527_Black",     //  Возможный вариант нового цвета.
                "CZ527_Green",     //  Возможный вариант нового цвета.
                "CZ527_Camo"       //  Возможный вариант нового цвета.
            ],
            "MOSIN9130": [         //  Базовый класс предмета (оригинальный внешний вид).
                "MOSIN9130_Black", //  Возможный вариант нового цвета.
                "MOSIN9130_Green", //  Возможный вариант нового цвета.
                "MOSIN9130_Camo"   //  Возможный вариант нового цвета.
            ],
            "SKS": [               //  Базовый класс предмета (оригинальный внешний вид).
                "SKS_Black",       //  Возможный вариант нового цвета.
                "SKS_Green"        //  Возможный вариант нового цвета.
            ],
            "Winchester": [        //  Базовый класс предмета (оригинальный внешний вид).
                "Winchester_Black",//  Возможный вариант нового цвета.
                "Winchester_Green" //  Возможный вариант нового цвета.
            ],
            "M4A1": [              //  Базовый класс предмета (оригинальный внешний вид).
                "M4A1_Black",      //  Возможный вариант нового цвета.
                "M4A1_Green"       //  Возможный вариант нового цвета.
            ]
        },
        "defaults": [              //  Список предметов, доступных для всех игроков по умолчанию.
            "AK101_Green",         //  Возможный вариант нового цвета.
            "AKS74U_Green",        //  Возможный вариант нового цвета.
            "CZ527_Green",         //  Возможный вариант нового цвета.
            "MOSIN9130_Green",     //  Возможный вариант нового цвета.
            "SKS_Green",           //  Возможный вариант нового цвета.
            "Winchester_Green",    //  Возможный вариант нового цвета.
            "M4A1_Green"           //  Возможный вариант нового цвета.
        ],
        "reskin_costs": {          //  Индивидуальная стоимость перекраски для определённых предметов.
            "AK101": 15.0,         //  AK101: Расход 15 единиц баллончика.
            "M4A1_Black": 20.0     //  M4A1_Black: Расход 20 единиц баллончика.
        }
    }
}
```

Users - конфиг определенного пользователя.

```json
{
    "access": [ //Перечисление доступных игроку предметом для перекраски.
        "AK101_Black",
        "AKS74U_Black",
        "CZ527_Black",
        "CZ527_Camo",
        "MOSIN9130_Black",
        "MOSIN9130_Camo",
        "SKS_Black",
        "Winchester_Black",
        "M4A1_Black"
    ]
}

```

{% hint style="danger" %}
Если вы **не используете автоматизацию AutoDonate** для получения скинов пользователями, выполните следующие шаги:

1\. Внесите необходимые изменения в файл.\
2️. Создайте **дубликат** файла.\
3️. Измените формат с **steamID64.json** на **steamID64.json.refresh**.

🔄 После взаимодействия игрока **пустой файл автоматически удалится**, и новые скины станут доступны. 🚀
{% endhint %}

{% hint style="success" %}

#### 🎨 **Гибкость модификации – больше, чем просто покраска!**

Функционал модификации открывает **широкие возможности** и не ограничивается только изменением внешнего вида оружия. Вы можете использовать его для:

🧥 **Одежды** – создавайте уникальные стили и кастомные наряды.\
🔧 **Аттачментов и запчастей** – модернизируйте оружие, машины и другие предметы.\
🔄 **Трансформации предметов** – превращайте одни вещи в другие (например, **магазин на 10 патронов** можно изменить на **30 патронов**).

Все зависит только от вашей фантазии! 🚀✨
{% endhint %}


# DayZMapManager

**DayZMapManager** — модификация, добавляющая в игру удобную интерактивную карту.\
Карта открывается мгновенно по нажатию клавиши **M**, позволяя быстро ориентироваться на местности и получать необходимую информацию прямо во время игры.

***

#### Содержимое архива

В архиве находятся файлы, необходимые для корректной работы модификации:

**`DayZMapManager.pbo`**\
Основной файл модификации. Устанавливается на **клиентскую часть** игры.

**`DZMM`**\
Папка с конфигурацией модификации.\
Её необходимо полностью поместить в папку **profiles** на сервере.

***

#### Содержимое конфигурации

В папке конфигурации находятся следующие файлы:

**`config.json`**\
Отвечает за настройки интерфейса.\
Здесь можно задать **цвет активных кнопок** и другие визуальные параметры карты.

**`locale.loc`**\
Файл локализации модификации.\
Позволяет **перевести интерфейс на любые языки** или изменить существующие тексты.

**`server_markers.json`**\
Файл для настройки **серверных маркеров** на карте.\
С его помощью можно добавлять важные точки, зоны или другие объекты, которые будут отображаться игрокам.

> **`server_markers.json`**

```json
{
	"markers": [
		{
			"active": true, // true/false - включение/отключение маркера
			"marker_color": [0, 0, 255], // RGB - Цвет маркера 
			"name": "Название маркера", // Название маркера
			"marker_image": "$DZMM/new_markers/mark.edds", // Путь до иконки маркера
			"marker_type": "area", // Тип маркера point - точка и area - зона
			"radius": 200, // Радиус зоны
			"position": [ // Позиция размещения маркера
				4572.84, // х
				90.8049, // y
				3468.37 // z
			]
		},
		{
			"active": true,
			"marker_color": [0, 255, 0],
			"name": "Название маркера2",
			"marker_image": "$DZMM/new_markers/mark.edds",
			"marker_type": "Point",
			"position": [
				4008.29,
				70.0338,
				4209.53
			],
			"allow3d": false // true/false - включение/отключение 3d маркера для игроков
		}
	]
}
```

\
Стандартные пути маркеров

В модификации уже предусмотрен набор стандартных иконок маркеров, которые можно использовать для отображения объектов и точек интереса на карте.

Доступные пути к стандартным маркерам:

```json
"$DZMM/new_markers/box.edds"
"$DZMM/new_markers/car.edds"
"$DZMM/new_markers/home.edds"
"$DZMM/new_markers/mark.edds"
"$DZMM/new_markers/stash.edds"
"$DZMM/new_markers/zombie.edds"
```

Эти иконки можно использовать в конфигурации серверных маркеров для отображения различных типов объектов на карте.

***

#### Создание собственного маркера

Если стандартных иконок недостаточно, вы можете добавить **собственный маркер**.

Для этого необходимо:

1. Создать **собственную модификацию**.
2. Добавить иконку в формате **`.edds`** в папку вашего мода.
3. Указать путь к иконке в конфигурации маркеров.

Пример пути к пользовательскому маркеру:

```json
"MY_MOD/data/icons/icon.edds"
```

#### Горячие клавиши

Для удобства использования модификации предусмотрены быстрые клавиши управления картой и маркерами.

**Ь** — открытие игровой карты.\
Позволяет мгновенно открыть карту прямо во время игры.

**Ъ** — скрывает или показывает все 3D-маркеры.\
Используется для временного отключения отображения маркеров в игровом мире, чтобы не загромождать экран и сосредоточиться на игровом процессе.\
\
В модификации предусмотрено API для добавление и удаление сессионных маркеров в процессе игры&#x20;

```csharp
// Получаем доступ к серверной модели модификации.
// Через неё выполняется управление маркерами: добавление, удаление и изменение.
DZMM_ServerModel model = DZMM_ServerModel.GetInstance();

// Создаём экземпляр маркера.
// Далее заполняются его основные параметры.
DZMM_MarkerData data = new DZMM_MarkerData();

// Название маркера, которое будет отображаться на карте.
data.name = "My Marker";

// Позиция маркера в мире (формат: X Y Z).
data.position = "5000 0 5000";

// Путь к иконке маркера.
data.marker_image = "$DZMM/point.edds";

// Цвет маркера (RGB).
data.marker_r = 255;   // Красный канал
data.marker_g = 128;   // Зелёный канал
data.marker_b = 0;     // Синий канал

// Тип маркера (например: point, area и т.д.).
data.marker_type = "point";

// Активность маркера (true — отображается, false — скрыт).
data.active = true;

// Добавляем маркер в игровую сессию.
// Описание аргументов.
// "My Category" — название категории маркеров. (string)
// Если категории не существует, она будет создана автоматически.
// data — содержимое маркера. (DZMM_MarkerData)
// true — включает отображение 3D-маркера в игровом мире. (bool)
int id = model.AddSessionMarker("My Category", data, true);. 

// ─────────────────────────────────────────────────────────────────────────────
// Пример использования: AddSessionMarkerForPlayer — маркер для конкретного игрока
// ─────────────────────────────────────────────────────────────────────────────
// Принцип тот же, что и выше, но маркер отправляется только одному игроку.
// Игрок идентифицируется по PlainId (SteamID без двоеточий, например "76561198085441104").
//
// Если игрок не в сети в момент вызова — маркер сохраняется на сервере и будет
// автоматически отправлен ему при следующем подключении.
//
// Аргументы:
//   "76561198085441104" — PlainId целевого игрока (string).
//   "My Category"       — название категории (string).
//   data                — содержимое маркера (DZMM_MarkerData).
//   true                — включить 3D-маркер (bool).
// Возвращает ID маркера. Удаление — model.RemoveSessionMarker(id) — работает для всех игроков.
//   int id = model.AddSessionMarkerForPlayer("76561198085441104", "My Category", data, true);



```


# UI

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


# Система уведомлений

MBSL реализует кастомную систему уведомлений (класс MBSL\_NotificationSystem), не связанную с системой уведомлений игры, отображаемую в правом верхнем углу экрана.

## Встроенные уведомления

Вместе с системой предоставляются два основных класса уведомлений - MBSL\_DefaultNotification и MBSL\_FormattedNotification. Эти классы используют стандартный для MBSL дизайн уведомлений, размер которого подстраивается под размер текста.

Основная разница между ними заключается в том, что DefaultNotification использует указанный текст как ключ локализации (см. [система локализации](/mbsl-docs/ui/sistema-lokalizacii)) напрямую для отображения заголовка/содержимого, в то время как FormattedNotification исполняет лямбда-функции (см. [лямбда-функции](broken://pages/FfNI00u9D9cDSzqeqext)), которые в качестве аргумента получают уже локализованную строку, что позволяет форматировать строки перед отображением.

Стандартные уведомления рекомендуется добавлять встроенными в систему уведомлений функциями:

```clike
static void AddDefaultNotification(string header, string content, float lifetime = DefaultNotificationLifetime, bool important = false);
static void AddFormattedNotification(string header, string content, MBSL_LambdaBase1<string, string> headerFormatter, MBSL_LambdaBase1<string, string> contentFormatter, float lifetime = DefaultNotificationLifetime, bool important = false);
```

Данные функции принимают следующие аргументы:

* header - заголовок уведомления. Может быть как текстом, так и ключом локализации.
* content - текст, содержащийся в уведомлении. Может быть как текстом, так и ключом локализации.
* lifetime - время отображения уведомления в секундах.
* important - является ли уведомление важным (см. [свойства уведомлений](#svoistva-uvedomlenii)).&#x20;
* headerFormatter - лямбда-функция для форматирования заголовка. В качестве аргумента получает уже локализованную строку. Может быть равен null, тогда заголовок не будет форматироваться перед отображением.
* contentFormatter - лямбда-функция для форматирования текста уведомления. В качестве аргумента получает уже локализованную строку. Может быть равен null, тогда текст не будет форматироваться перед отображением.

## Кастомные уведомления

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

Система уведомлений также позволяет создавать уведомления, использующие другой дизайн, анимацию и т.д. Для этого необходимо реализовать класс уведомления, наследующий класс MBSL\_NotificationBase (наследующий MBSL\_WidgetGroup - см. [группа виджетов](/mbsl-docs/ui/gruppa-vidzhetov)), приведённый ниже:

```clike
class MBSL_NotificationBase : MBSL_WidgetGroup
{
	protected bool _Important;
	protected float _Lifetime;
	
	protected void MBSL_NotificationBase( bool important, float lifetime )
	{
		_Important = important;
		_Lifetime = lifetime;
	}
	
	bool IsImportant() { return _Important; }
	float GetLifetime() { return _Lifetime; }
	
	bool UpdateAppear(float timeslice) { return true; }
	bool UpdateDisappear(float timeslice) { return true; }
	void UpdateDisplay(float timeslice) {}
}
```

### Свойства уведомлений

Каждое уведомления обладает двумя основными свойствами, получаемыми системой методами IsImportant и GetLifetime:

* lifetime - время отображения уведомления в секундах.
* important - является ли уведомление важным. Важные уведомления гарантированно остаются на экране, пока не закончится их время отображения. Неважные же уведомления могут быть убраны с экрана до завершения их времени отображения, если на экране не хватает места для новых уведомлений (при этом для неважных уведомлений будут полностью выполнены анимации появления и исчезновения). Важными рекомендуется помечать лишь критически-важные уведомления, информация которых может сильно повлиять на игровой процесс, чтобы не задерживать очередь уведомлений.

### Анимации

***Система уведомлений не анимирует уведомления, ответственность за анимацию лежит на самом уведомлении.***

***В процессе анимации важно сохранять текущую вертикальную позицию (y) уведомления и его высоту, т.к. система уведомлений сама управляет вертикальной позицией, а высоту сохраняет и использует для внутренних вычислений.***

Для реализации анимаций система уведомлений вызывает на уведомлении 3 метода - UpdateAppear, UpdateDisplay, UpdateDisappear. Данные методы в качестве аргумента получают timeslice - время между предыдущим и предпредыдущим кадрами игры (методы вызываются на каждом Update, подробнее об update-loop в игровых движках можно найти в интернете).  Каждый метод отвечает за свою часть анимации, и эти методы не вызываются одновременно:

Метод UpdateAppear отвечает за анимацию появления. Он начинает вызываться, как только уведомление появляется на экране, и будет повторно вызываться в каждом последующем кадре, пока он возвращает true. Как только этот метод вернёт false, система считает, что уведомление завершило свою анимацию появления, и переходит к этапу отображения. Хотя система не имеет строгих ограничений по длительности этапа, рекомендуется не превышать значение константы MBSL\_NotificationSystem.DefaultNotificationAppearTime для времени появления уведомления.

Метод UpdateDisplay отвечает за анимацию во время отображения. Он начинает вызываться, как только уведомление завершает анимацию появления, и повторно вызывается в каждом последующем кадре, пока не пройдёт время отображения уведомления (или система не решит освободить место, досрочно убрав неважное уведомление).

Метод UpdateDisappear отвечает за анимацию исчезновения. Он начинает вызываться, как только проходит время отображения (или система решает досрочно убрать уведомление), и будет повторно вызываться в каждом последующем кадре, пока он возвращает true. Как только этот метод вернёт false, система считает, что уведомление завершило свою анимацию исчезновения, и убирает его с экрана. Хотя система не имеет строгих ограничений по длительности этапа, рекомендуется не превышать значение константы MBSL\_NotificationSystem.DefaultNotificationDisappearTime для времени исчезновения уведомления.


# Система локализации

Система локализации используется для автоматического выбора сообщения, соответствующего текущему языку игры, если такое определено. Главным отличием системы локализации MBSL от встроенной системы локализации DayZ является то, что все сообщения задаются через файлы конфигурации сервера, что позволяет администраторам/разработчикам легко корректировать сообщения без изменения мода. О формате файлов локализации можно прочитать в статье [редактирование файлов локализации](/mods/redaktirovanie-failov-lokalizacii).

Разработчиков модов интересуют следующие методы системы локализации (класс MBSL\_LocalizationAPI):

```clike
static bool ReadFromFile(string path);
static string TranslateString(string key);
```

* Метод ReadFromFile используется для считывания пар ключ-значение из файла локализации в соответствующем формате. Система локализации не использует файловую систему MBSL, поэтому путь до файла (path) должен иметь префикс файловой системы (например, $profile). Это может измениться в будущих версиях.
* Метод TranslateString использует для перевода ключа локализации (key) в соответствующее сообщение для текущего языка (система сама определит текущий язык). Если данного ключа нет ни в локализации текущего языка, ни в локализации стандартного языка, то система вернёт сам ключ.


# Группа виджетов

Группа виджетов представляет из себя простой класс-обёртку для виджетов, не создаваемых в методе Init класса UIScriptedMenu. Для использования класса необходимо переопределить следующие методы в наследуемом  классе:

```
protected Widget Init();
void RefreshText();
```

* Init - создаёт виджеты и возвращает корневой элемент. На каждом экземпляре вызывается строго один раз.
* RefreshText - обновить текст. Вызывается системой, когда необходимо гарантировать актуальность текста (например, при смене языка игре, для обновления локализации на отображаемых виджетах).&#x20;

Исходный код класса приведён ниже:

```clike
class MBSL_WidgetGroup : Managed
{
	protected Widget _Root;
	
	void MBSL_WidgetGroup()
	{
		MBSL_EventSystem.Subscribe(this, MBSL_DefaultClientEvents.ResetGUI);
	}
	
	private void ResetGUI()
	{
		if (_Root != null)
			RefreshText();
	}
	
	Widget GetRoot() 
	{
		if (_Root == null)
		{
			_Root = Init();
			RefreshText();
		}
			
		return _Root;
	}
	
	protected Widget Init() { return null; }
	
	void RefreshText() {}
}
```


# Модели вызова функций


# Асинхронное выполнение задач

Так как DayZ - практически полностью однопоточная игра, выполнение длительной задачи (например, чтение файла, парсинг json-файла и т.п.) приводит к блокировке выполнения всего процесса. На клиенте это выражается в зависании приложения и, при достаточно долгой задаче, выходом с сервера. На сервере это выражается в лагах и отключении игроков от сервера. Для решения данной проблемы в MBSL реализован механизм асинхронного выполнения задач, основная идея которого в разделении задачи на мелкие подзадачи и выполнении их не за раз, а на каждом вызове Update.

***Важно: система асинхронного выполнения не гарантирует порядка выполнения задач, поэтому задача, которая была добавлена позже, может выполнится раньше.***

## Класс задачи

Для создания асинхронной задачи необходимо реализовать выполняющий её класс. Базовым классом для таких классов служит MBSL\_AsyncTaskBase, исходный код которого приведён ниже:

```clike
enum MBSL_AsyncTaskStepResult
{
	TaskInProgess,
	TaskWaiting,
	TaskFinished
}

class MBSL_AsyncTaskBase : Managed
{
	MBSL_AsyncTaskStepResult Step(float timeslice);
}
```

Данный класс требует реализации всего одной функции Step, которая принимает один аргумент timeslice - время между предыдущим и предпредыдущим кадром. В этой функции задача должна выполнять одну из своих подзадач, при этом не рекомендуется, чтобы время выполнения превышало 10 мс, иначе теряется смысл асинхронного механизма выполнения.

Функция возвращает одной из значений enum'а MBSL\_AsyncTaskStepResult:

* TaskInProgress - задача выполняла работу на этом вызове Step и ещё не завершила выполнение.
* TaskWaiting - задача не выполняла работу на этом вызове (например, она ждёт чего-то), но ещё не завершила выполнение. **Устаревшее значение, которое более не используется, но оставлено для обратной совместимости.**
* TaskFinished - задача завершила выполнение работы.

## Диспетчер задач

Диспетчер (MBSL\_Dispatcher) - это класс, отвечающий за ведение очереди задач и вызов метода Step на задаче для выполнения. Для его использования требуется всего один метод:

```clike
static void QueueTask(MBSL_AsyncTaskBase task)
```

Данный метод принимает два аргумента:

* task - экземпляр выполняемой задачи.

## Принцип работы диспетчера

Текущая версия диспетчера построена на идее бюджета времени выполнения.

Сервер имеет целевую частоту тиков (TPS - ticks per second) для поддержания стабильной работы. На основе этого значения определяется бюджет времени выполнения для каждого тика (например, при TPS = 60 это значение равно 1/60 = 16 мс). Каждый тик диспетчер определяет уже затраченное игрой время на обработку тика и вычисляется оставшийся бюджет времени.

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


# Строго типизированные функции

Библиотека предоставляет механизм обёртывания функций в объекты строго типизированных функций, позволяющие гарантировать типовую безопасность при вызове функций, а также оперировать ими как и другими объектами в языке - сохранять в переменные, передавать их и производить другие операции над ними.

## Виды строго типизированных функций

Строго типизированные функции подразделяются в библиотеке на 2 группы:

* Строго типизированные действия (TypedAction). Функции, не имеющие возвращаемого значения.
* Строго типизированные функции (TypedFunction). Функции, имеющие возвращаемое значение.

Функции первой группы представлены классами MBSL\_TypedAction. В настоящее время библиотека поддерживает типизированные действия, принимающие от 0 до 8 аргументов.

```clike
//N - Количество аргументов функции
class MBSL_TypedActionN<Class T1, ..., Class TN> : MBSL_TypedFunctionBase
{
    //Создать слабое строго типизированное действие
    //См. дальше про создание функций
    //См. дальше про слабые и сильные функции
    static MBSL_TypedActionN<Class T1, ..., Class TN> Weak(Managed instance, string function);
    //Создать сильное строго типизированное действие
    //См. дальше про создание функций
    //См. дальше про слабые и сильные функции
    static MBSL_TypedActionN<Class T1, ..., Class TN> Strong(Managed instance, string function);
    //Вызывать функцию с указанными аргументами
    void Invoke(T1 arg1, ..., TN argN);
    //Проверить эквивалентность другой функции
    //Функции эквивалентны, если они имеют один тип
    //и ссылаются на одну и ту же функцию
    //одного и того же объекта
    bool Equals(MBSL_TypedFunctionBase other);
    //Жива ли функция - см. дальше про слабые и сильные функции
    bool IsAlive();
    //Создать копию этой функции как слабую функцию.
    //См. дальше про слабые и сильные функции
    MBSL_TypedActionN<Class T1, ..., Class TN> AsWeak();
    //Создать копию этой функции как сильную функцию.
    //См. дальше про слабые и сильные функции
    MBSL_TypedActionN<Class T1, ..., Class TN> AsStrong();
}

//Особый случай функции без аргументов, аналогичен остальным
class MBSL_TypedAction0 : MBSL_TypedFunctionBase {}

//Конкретный пример - функция с 3 аргументами
class MBSL_TypedAction3<Class T1, Class T2, Class T3> : MBSL_TypedFunctionBase {}
```

Функции второй группы представлены классами MBSL\_TypedFunction. В настоящее время библиотека поддерживает типизированные функции, принимающие от 0 до 8 аргументов.

```clike
//N - Количество аргументов функции
class MBSL_TypedFunctionN<Class ReturnType, Class T1, ..., Class TN> : MBSL_TypedFunctionBase
{
    //Создать слабую строго типизированную функцию
    //См. дальше про создание функций
    //См. дальше про слабые и сильные функции
    static MBSL_TypedFunctionN<Class ReturnType, Class T1, ..., Class TN> Weak(Managed instance, string function);
    //Создать сильную строго типизированную функцию
    //См. дальше про создание функций
    //См. дальше про слабые и сильные функции
    static MBSL_TypedFunctionN<Class ReturnType, Class T1, ..., Class TN> Strong(Managed instance, string function);
    //Вызывать функцию с указанными аргументами и получить результат
    ReturnType Invoke(T1 arg1, ..., TN argN);
    //Проверить эквивалентность другой функции
    //Функции эквивалентны, если они имеют один тип
    //и ссылаются на одну и ту же функцию
    //одного и того же объекта
    bool Equals(MBSL_TypedFunctionBase other);
    //Жива ли функция - см. дальше про слабые и сильные функции
    bool IsAlive();
    //Создать копию этой функции как слабую функцию.
    //См. дальше про слабые и сильные функции
    MBSL_TypedFunctionN<Class ReturnType, Class T1, ..., Class TN> AsWeak();
    //Создать копию этой функции как сильную функцию.
    //См. дальше про слабые и сильные функции
    MBSL_TypedFunctionN<Class ReturnType, Class T1, ..., Class TN> AsStrong();
}

//Особый случай функции без аргументов, аналогичен остальным
class MBSL_TypedFunction0<Class ReturnType> : MBSL_TypedFunctionBase {}

//Конкретный пример - функция с 3 аргументами
class MBSL_TypedFunction3<Class ReturnType, Class T1, Class T2, Class T3> : MBSL_TypedFunctionBase {}
```

## Создание строго типизированных функций

Все виды строго типизированных функций поддерживают создание с помощью двух статических методов их класса - Weak и Strong (про различие между слабыми и сильными функциями см. дальше). Обе функции принимают два аргумента:

* Managed instance - любой объект, наследующий Managed, которому принадлежит вызываемая функция. Не может быть null. **Сторого типизированные функции поддерживают только функции экземпляров объектов.**
* string function - название функции на переданном объекте, которая должна вызываться этой строго типизированной функцией. **Важно:** **из-за отсутствия возможности библиотека не проверяет переданное название функции на существование такой функции у объекта и на корректность типов. Этот факт лежит на ответственности создающего функцию кода. Если функция не будет существовать или типы не будут соответствовать реальным, при попытке вызова функции произойдёт ошибка.**

Если переданные в функцию аргументы корректны, то будет возвращён объект функции, иначе - null.

Ниже приведён пример создания строго типизированной функции:

```clike
class Example : Managed
{
    void DoPrint(string val)
    {
        Print(val);
    }
    
    int Sum(int a, int b)
    {
        return a+b;
    }
}

Example e = new Example();
MBSL_TypedAction1<string> print = MBSL_TypedAction1<string>.Weak(e, "DoPrint");
print.Invoke("Hello, world!"); //Напечатает "Hello, world!" в логи

MBSL_TypedFunction2<int, int, int> sum = MBSL_TypedFunction2<int, int, int>.Weak(e, "Sum");
int r = sum.Invoke(3, 4); //r = 7

MBSL_TypedAction1<string> error = MBSL_TypedAction1<string>.Weak(e, "NoFunction");
error.Invoke("hello"); //Произойдёт ошибка

MBSL_TypedAction1<int> error2 = MBSL_TypedAction1<int>.Weak(e, "DoPrint");
error2.Invoke(5); //Произойдёт ошибка
```

## Сильные и слабые функции

Все строго типизированные функции представлены в двух видах: сильные и слабые функции. Это название указывает на вид ссылки, которую держит строго типизированная функция на объект, на котором вызывается функция.

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

Слабые функции держат слабую ссылку на объект. Если больше сильных ссылок на объект нет, то он будет уничтожен, даже если функция ещё существует. Вызов такой функции приведёт к ошибке. Состояние слабой функции можно проверить с помощью метода IsAlive - он вернёт true, если объект, на который ссылается функция, всё-ещё существует и функцию можно вызвать, иначе - false.

**Важно:** необходимо остерегаться циклических ссылок при создании строго типизированной функции из самого объекта. В таком случае настоятельно рекомендуется создавать слабые функции и делать их сильные копии при необходимости.

<pre class="language-clike"><code class="lang-clike">class BadExample : Managed
{
    //Цилическая сильная ссылка - объект никогда не будет удалён!
    ref MBSL_TypedFunction2&#x3C;int, int, int> _Sum = MBSL_TypedFunction2&#x3C;int, int, int>.Strong(this, "Sum");
    int Sum(int a, int b)
    {
        return a+b;
    }
}

BadExample be = new BadExample();
<strong>MBSL_TypedFunction2&#x3C;int, int, int> bs = be._Sum;
</strong>
class GoodExample : Managed
{
    //Нет циклической сильной ссылки
    ref MBSL_TypedFunction2&#x3C;int, int, int> _Sum = MBSL_TypedFunction2&#x3C;int, int, int>.Weak(this, "Sum");
    int Sum(int a, int b)
    {
        return a+b;
    }
}

GoodExample ge = new GoodExample();
MBSL_TypedFunction2&#x3C;int, int, int> gs = ge._Sum.AsStrong(); //Создаём сильную функцию, чтобы объект жил, пока жива функция.
</code></pre>


# Привязка аргументов строго типизированных функций

Для механизма [строго типизированных функций](/mbsl-docs/modeli-vyzova-funkcii/strogo-tipizirovannye-funkcii) библиотека предоставляет также механизм привязки аргументов, что позволяет передать строго типизированную функцию с уже привязанной частью аргументов для дальнейшего вызова. Этот механизм представлен четыремя классами.

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

Для строго типизированных действий используется семейство классов BindAction и BindActionRef. Основное отличие в том, что класс с суффиксом Ref держат сильную ссылку на аргумент (и, как следствие, не совместимы с примитивными типами вроде int, float и т.п.), а без - нет. Это необходимо для обхода бага движка, при котором вид ссылки не передаётся при передачи типа в аргумент шаблона.

```clike
//N - количество аргументов ПОСЛЕ привязки, а не в привязываемой функции
//ClosureType - тип привязываемого аргумента
class MBSL_BindActionN<Class ClosureType, Class Arg1, ... Class Arg(N-1)> : Managed
{
    static MBSL_TypedAction(N-1)<Arg1, ..., Arg(N-1)> Bind(MBSL_TypedAction<ClosureType, Arg1, ... Arg(N-1)> function, ClosureType closure);
}


class MBSL_BindActionNRef<Class ClosureType, Class Arg1, ... Class Arg(N-1)> : Managed
{
    static MBSL_TypedAction(N-1)<Arg1, ..., Arg(N-1)> Bind(MBSL_TypedAction<ClosureType, Arg1, ... Arg(N-1)> function, ClosureType closure);
}
```

Для строго типизированных действий используется семейство классов BindFunction и BindFunctionRef. Отличия между Ref и обычный аналогичны TypedAction.

```clike
//N - количество аргументов ПОСЛЕ привязки, а не в привязываемой функции
//ClosureType - тип привязываемого аргумента
class MBSL_BindFunctionN<Class ReturnType, Class ClosureType, Class Arg1, ... Class Arg(N-1)> : Managed
{
    static MBSL_TypedFunction(N-1)<ReturnType, Arg1, ..., Arg(N-1)> Bind(MBSL_TypedFunction<ReturnType, ClosureType, Arg1, ... Arg(N-1)> function, ClosureType closure);
}


class MBSL_BindActionNRef<Class ReturnType, Class ClosureType, Class Arg1, ... Class Arg(N-1)> : Managed
{
    static MBSL_TypedFunction(N-1)<ReturnType, Arg1, ..., Arg(N-1)> Bind(MBSL_TypedFunction<ReturnType, ClosureType, Arg1, ... Arg(N-1)> function, ClosureType closure);
}
```

**Важно:** созданные таким образом функции уже не ссылаются на оригинальный объект, на которой ссылалась строго типизированная функция. Они автоматически генерируются как сильные функции и ссылаются на специальный промежуточный объект, поэтому не рекомендуется изменять их тип на слабые, иначе они могут стать невалидными из-за уничтожения промежуточного объекта. Фактически, тип их ссылки на оригинальный объект фиксируется в момент привязки оригинальной строго типизированной функции.&#x20;

Ниже приведён пример привязки аргумента строго типизированной функции:

```clike
class Example : Managed
{
    ref MBSL_TypedFunction2<int, int, int> _Sum = MBSL_TypedFunction2<int, int, int>.Weak(this, "Sum");
    int Sum(int a, int b)
    {
        return a+b;
    }
}

Example e = new Example();
MBSL_TypedFunction1<int, int> addFive = MBSL_BindFunction1<int, int, int>.Bind(e._Sum, 5);
int r = addFive.Invoke(7); //r = 12
MBSL_TypedFunction0<int> twoPlusFive = MBSL_BindFunction0<int, int>.Bind(addFive, 2);
r = twoPlusFive.Invoke(); //r = 7
```


# Строго типизированные события

TBD


# Promise (обещание значения)

Для упрощения работы с асинхронными задачами библиотека реализует механизм Promise - обещание значения. Данный объект представляет из себя обёртку результата выполнения асинхронной операции, который может быть уже доступен на момент завершения выполнения функции, а может стать доступен спустя какое-то время.

Promise может находится в трёх состояниях:

* Неразрешённое (unresolved). Результат выполнения операции ещё не доступен.
* Выполненное (fulfilled). Результат выполнения операции доступен.
* Отклонённое (rejected). Операция завершилась ошибкой и доступна информация  об ошибке, а не результат.

В библиотеке Promise представлен двумя классами MBSL\_Promise и MBSL\_PromiseRef. Ref-версия отличается тем, что хранит сильную ссылку на результат операции (и, как следствие, несовместима с примитивными типами). В остальном классы идентичны.

```clike
enum MBSL_PromiseState
{
	Unresolved,
	Rejected,
	Fulfilled
}

class MBSL_Promise<Class T> : MBSL_PromiseBase
{ 
	//Получить текущий статус 
	MBSL_PromiseState GetState();
	//Добавить обработчик отклонения Promise (при переходе в rejected)
	MBSL_PromiseBase WhenRejected(MBSL_TypedAction1<MBSL_Exception> handler);
	//Добавить обработчик выполнения Promise (при переходе в fulfilled)
	MBSL_Promise<T> WhenFulfilled(MBSL_TypedAction1<T> handler);
	//Добавить обработчик разрешения Promise (при переходе в rejected или fulfilled)
	MBSL_PromiseBase WhenResolved(MBSL_TypedAction1<MBSL_PromiseBase> handler);
	
	//Создать promise из источника (см. далее)
	static MBSL_Promise<T> FromSource(MBSL_PromiseSource<T> source);
	//Создать promise в состоянии fulfilled с указанным результатом
	static MBSL_Promise<T> Fulfilled(T result);
	//Создать promise в состоянии rejected с указанным результатом
	static MBSL_Promise<T> Rejected(MBSL_Exception exception);
}
```

Для получения результата Promise к нему необходимо прикрепить обработчик, используя WhenFulfilled для результата операции и WhenRejected для ошибки при выполнении операции. Если на момент прикрепления обработчика результат или ошибка уже доступны, то обработчик будет вызван сразу.

## Создание Promise

Библиотека поддерживает 3 способа создания Promise:

* Уже выполненный Promise с помощью Fulfilled. Используется, если результат доступен на момент создания Promise.
* Уже отклонённый Promise c помощью Rejected. Используется, если ошибка известна на момент создания Promise.
* Неразрешённый Promise из источника с помощью FromSource. Используется, если результат или ошибка недоступны на момент создания и позволяет асинхронно выполнить Promise.

Источником для Promise служит специальный класс MBSL\_PromiseSource. В отличие от Promise, этот класс не сохраняет результаты, а лишь используется для передачи результата или ошибки для Promise, поэтому перед вызовом его методов Fulfill/Reject необходимо создать из него все Promise. Каждый созданный Promise может быть выполнен или отклонён только один раз, поэтому после вызова Fulfill/Reject на PromiseSource более его использовать не стоит.

```clike
class MBSL_PromiseSource<Class T> : Managed
{
	//Выполнить все созданные из этого источника Promise с результатом
	void Fulfill(T result);
	//Отклонить все созданные из этого источника Promise с ошибкой
	void Reject(MBSL_Exception exception);
}
```


# Цепочки Promise

Для упрощения задач обработки результатов асинхронных операций библиотека предоставляет вспомогательные классы для создание "цепочек" Promise. Под цепочкой подразумевается Promise, который преобразует результат выполнения предшествующего ему Promise (например, последовательность "сделать HTTP-запрос -> декодировать JSON - обработать результат).

Этими вспомогательными классами является семейство классов MBSL\_PromiseChain (MBSL\_PromiseChain, MBSL\_PromiseChain\_ToRef, MBSL\_PromiseChain\_FromRef, MBSL\_PromiseChain\_FromRefToRef). Каждый класс позволяет сформировать "цепочку", получая "исходный" Promise и создавая "зависимый" Promise.

Главным отличием этих классов являются типы Promise, с которыми они работаю - MBSL\_Promise или MBSL\_PromiseRef. Классы с "FromRef" в названии принимаю в качестве "исходного" тип MBSL\_PromiseRef, без - MBSL\_Promise. Классы с "ToRef" в названии создают в качестве "зависимого" тип MBSL\_PromiseRef, без - MBSL\_Promise.

```clike
//PrevResultType - тип результата "родительского" Promise
//NextResultType - тип результата "зависимого" Promise 
class MBSL_PromiseChain<Class PrevResultType, Class NextResultType> : Managed
{
	//Создать цепочку Promise с асинхронным обработчиком
	static MBSL_Promise<NextResultType> Create(MBSL_Promise<PrevResultType> promise, MBSL_TypedFunction1<MBSL_Promise<NextResultType>, PrevResultType> handler);
	//Создать цепочку Promise с синхронным обработчиком
	static MBSL_Promise<NextResultType> Create(MBSL_Promise<PrevResultType> promise, MBSL_TypedFunction1<NextResultType, PrevResultType> handler);
}
```

При создании цепочки можно указать два вида обработчика - синхронный и асинхронный. Принцип работы цепочки значительно отличаться не будет:

1. Цепочка ожидает разрешения "родительского" Promise:
   1. Если "родительский" Promise был отклонён, то "зависимый" Promise отклоняется и вызов обработчика пропускается.
   2. Если "родительский" Promise был выполнен, то вызывается обработчик.
2. В зависимости от типа обработчика:
   1. Если обработчик синхронный, то "зависимый" Promise выполняется с результатом обработчика.
   2. Если обработчик асинхронный, то он создаёт "промежуточный" Promise.
3. Цепочка ожидает разрешения "промежуточного" Promise:
   1. Если "промежуточный" Promise был отклонён, то "зависимый" Promise отклоняется.
   2. Если "промежуточный" Promise был выполнен, то "зависимый" Promise выполняется с тем же результатом.

Пример использования цепочки:

```
class Example : Managed
{
    MBSL_Promise<string> GET(RestContext ctx, string url, int attempts = 5);
    
    ref MBSL_TypedFunction1<MBSL_PromiseRef<MBSL_JsonObject>, string> _Parse = MBSL_TypedFunction1<MBSL_PromiseRef<MBSL_JsonObject>, string>.Weak(this, "Parse");
    MBSL_PromiseRef<MBSL_JsonObject> Parse(string value);
    
    ref MBSL_TypedAction1<MBSL_JsonObject> _PrintIt = MBSL_TypedAction1<MBSL_JsonObject>.Weak(this, "PrintIt");
    void PrintIt(MBSL_JsonObject obj)
    {
        Print(obj.GetString("it"));
    } 
}

RestContext ctx = GetRestApi().GetRestContext("https://api.com");
Example e = new Example();
//Совершаем запрос к API, которое возвращает JSON
MBSL_Promise<string> req = e.GET(ctx, "/get_json");
//Создаём цепочку, чтобы когда запрос будет завершён, начать парсить JSON
MBSL_PromiseRef<MBSL_JsonObject> json = MBSL_PromiseChain_ToRef<string, MBSL_JsonObject>.Create(req, e._Parse.AsStrong());
//Когда JSON распрашен, выполняем полезную нагрузку с ним
json.WhenFulfilled(e._PrintIt);
```


# Работа с сетью


# RPC (Remote Procedure Call)

Для упрощения работы с RPC библиотека предоставляет свою обёртку механизма RPC игры. Обёртка состоит из двух компонентов: компонент вызова и обработчик.

Реализованная обёртка позволяет выполнять RPC, идентифицируемые сразу по 3 атрибутам: название модификации (пространство имён), название функции в модификации, типы аргументов функции. Таким образом, обёртка поддерживает перегрузку функций (т.е. создание двух функций с одинаковыми названиями, но разными аргументами).

Компонент вызова - это объект, который создаётся на вызывающей процедуру стороне, и используется для строго типизированного вызова процедуры. В библиотеке этот компонент представлен семейством классов MBSL\_RPC. При использовании компонента на клиенте параметр recipient можно игнорировать. При использовании на сервере он указывает получателя RPC (NULL = все игроки).

```clike
//N - число аргументов (от 0 до 7)
class MBSL_RPCN<Class Arg1, ..., Class ArgN> : Managed
{
    //Конструктор. Требует передать название модификации (пространство имён)
    //А также название функции в этой модификации (пространстве имён).
    void MBSL_RPCN(string modname, string functionname);
    //Вызвать удалённую процедуру с указанными аргументами
    void Invoke(Arg1 arg1, ..., ArgN argN, PlayerIdentity recipient = NULL);
}

//Вариант без аргументов
class MBSL_RPC0 : Managed
{
    //Конструктор. Требует передать название модификации (пространство имён)
    //А также название функции в этой модификации (пространстве имён).
    void MBSL_RPC0(string modname, string functionname);
    //Вызвать удалённую процедуру с указанными аргументами
    void Invoke(PlayerIdentity recipient = NULL);
}

//Особый вариант. Позволяет передать любое число аргументов в виде массива
class MBSL_RPCRaw : Managed
{
    //Конструктор. Требует передать название модификации (пространство имён)
    //А также название функции в этой модификации (пространстве имён).
    void MBSL_RPCRaw (string modname, string functionname);
    //Вызвать удалённую процедуру с указанными аргументами
    void Invoke(array<ref Param> params, PlayerIdentity recipient = null)
}
```

Обработчик - это вызываемая [строго типизированная функция](/mbsl-docs/modeli-vyzova-funkcii/strogo-tipizirovannye-funkcii) на другой стороне, которая получает аргументы, а также информацию о вызвавшем функцию игроке (если обработчик на  сервере). В библиотеке этот компонент представлен семейством классов MBSL\_RPC\_Handler.

<pre class="language-clike"><code class="lang-clike">//N - число аргументов (от 0 до 7)
<strong>class MBSL_RPC_HandlerN&#x3C;Class Arg1, ..., Class ArgN> : Managed
</strong>{
    //Добавить обработчик
    //Требует передать:
    //название модификации (пространство имён)
    //название функции в этой модификации (пространстве имён)
    //Функцию-обработчик
    static MBSL_RPC_HandlerBase Register(string modname, string funcname, MBSL_TypedAction(N+1)&#x3C;Arg1, ..., ArgN, PlayerIdentity> handler);
    //Удаляет ранее добавленный обработчик.
    //Возвращает false, если обработчик уже был ранее удалён.
    bool Unregister();
}

//Вариант без аргументов
class MBSL_RPC_Handler0 : Managed
{
    //Добавить обработчик
    //Требует передать:
    //название модификации (пространство имён)
    //название функции в этой модификации (пространстве имён)
    //Функцию-обработчик
    static MBSL_RPC_HandlerBase Register(string modname, string funcname, MBSL_TypedAction1&#x3C;PlayerIdentity> handler);
    //Удаляет ранее добавленный обработчик.
    //Возвращает false, если обработчик уже был ранее удалён.
    bool Unregister();
}

//Особый вариант. Получаем любое число аргументов
class MBSL_RPC_HandlerRaw : Managed
{
    //Добавить обработчик
    //Требует передать:
    //название модификации (пространство имён)
    //название функции в этой модификации (пространстве имён)
    //Функцию-обработчик
    static MBSL_RPC_HandlerBase Register(string modname, string funcname, MBSL_TypedAction2&#x3C;ParamsReadContext, PlayerIdentity> handler);
    //Удаляет ранее добавленный обработчик.
    //Возвращает false, если обработчик уже был ранее удалён.
    bool Unregister();
}
</code></pre>

Пример использования RPC:

```clike
//Клиент
MBSL_RPC1<string> sendMessage = new MBSL_RPC1<string>("ExampleMod", "SendMessage");
sendMessage.Invoke("Hello");

//Сервер
class Example : Managed
{
    void Example()
    {
        MBSL_RPC_Handler1<string>.Register("ExampleMod", "SendMessage", _SendMessage.AsStrong());
    }
    
    protected ref MBSL_TypedAction2<string, PlayerIdentity> _SendMessage = MBSL_TypedAction2<string, PlayerIdentity>.Weak(this, "SendMessage");
    protected void SendMessage(string message, PlayerIdentity sender)
    {
        Print(sender.GetPlainId() + " says: " + message);
    }
}
```


# RFC (Remote Function Call)

Для упрощения работы с RPC, результат которых необходимо получить на вызвавшей их стороне (например, при выполнении какого-то действия, доступного только на сервере) библиотека предоставляет обёртку механизма RPC самой библиотеки, называемую RFC (Remote Function Call). Обёртка состоит из двух компонентов: компонент вызова и обработчик.

Реализованная обёртка позволяет выполнять RFC, идентифицируемые сразу по 3 атрибутам: название модификации (пространство имён), название функции в модификации, типы аргументов функции. Таким образом, обёртка поддерживает перегрузку функций (т.е. создание двух функций с одинаковыми названиями, но разными аргументами).

Компонент вызова - это объект, который создаётся на вызывающей функцию стороне, и используется для строго типизированного вызова функции и получения [Promise](/mbsl-docs/modeli-vyzova-funkcii/promise-obeshanie-znacheniya) результата выполнения удалённой функции. В библиотеке этот компонент представлен семейством классов MBSL\_RFC. При использовании компонента на клиенте параметр recipient можно игнорировать. При использовании на сервере он указывает получателя RFC (NULL = недопустимое значение; обёртка не поддерживает одновременный вызов удалённой функции у каждого игрока).

```clike
//N - число аргументов (от 0 до 7)
class MBSL_RFCN<Class ReturnType, Class Arg1, ..., Class ArgN> : Managed
{
    //Конструктор. Требует передать название модификации (пространство имён)
    //А также название функции в этой модификации (пространстве имён).
    void MBSL_RFCN(string modname, string functionname);
    //Вызвать удалённую функцию с указанными аргументами и получить Promise результата
    MBSL_Promise<ReturnType> Invoke(Arg1 arg1, ..., ArgN argN, PlayerIdentity recipient = NULL);
}

​//N - число аргументов (от 0 до 7)
//Вариант, возвращающий PromiseRef
class MBSL_RFCNRef<Class ReturnType, Class Arg1, ..., Class ArgN> : Managed
{
    //Конструктор. Требует передать название модификации (пространство имён)
    //А также название функции в этой модификации (пространстве имён).
    void MBSL_RFCNRef(string modname, string functionname);
    //Вызвать удалённую функцию с указанными аргументами и получить Promise результата
    MBSL_PromiseRef<ReturnType> Invoke(Arg1 arg1, ..., ArgN argN, PlayerIdentity recipient = NULL);
}

//Вариант без аргументов
class MBSL_RFC0<Class ReturnType> : Managed
{
    //Конструктор. Требует передать название модификации (пространство имён)
    //А также название функции в этой модификации (пространстве имён).
    void MBSL_RFC0(string modname, string functionname);
    //Вызвать удалённую процедуру с указанными аргументами
    MBSL_Promise<ReturnType> Invoke(PlayerIdentity recipient = NULL);
}
```

Обработчик - это вызываемая [строго типизированная функция](/mbsl-docs/modeli-vyzova-funkcii/strogo-tipizirovannye-funkcii) на другой стороне, которая получает аргументы, а также информацию о вызвавшем функцию игроке (если обработчик на сервере), и создаёт [Promise](/mbsl-docs/modeli-vyzova-funkcii/promise-obeshanie-znacheniya) результата (даже если функция выполняется синхронно). В библиотеке этот компонент представлен семейством классов MBSL\_RFCHandler.

<pre class="language-clike"><code class="lang-clike">//N - число аргументов (от 0 до 7)
class MBSL_RFCHandlerN&#x3C;Class ReturnType, Class Arg1, ..., Class ArgN> : Managed
{
    //Добавить обработчик
    //Требует передать:
    //название модификации (пространство имён)
    //название функции в этой модификации (пространстве имён)
    //Функцию-обработчик
<strong>    static MBSL_RFCHandlerN Register(string modname, string funcname, MBSL_TypedFunction(N+1)&#x3C;MBSL_Promise&#x3C;ReturnType>, Arg1, ..., ArgN, PlayerIdentity> handler);
</strong><strong>    //Удаляет ранее добавленный обработчик.
</strong><strong>    //Возвращает false, если обработчик уже был ранее удалён.
</strong><strong>    bool Unregister();
</strong>}

//N - число аргументов (от 0 до 7)
//Вариант для функций, возвращающих PromiseRef.
class MBSL_RFCHandlerNRef&#x3C;Class ReturnType, Class Arg1, ..., Class ArgN> : Managed
{
    //Добавить обработчик
    //Требует передать:
    //название модификации (пространство имён)
    //название функции в этой модификации (пространстве имён)
    //Функцию-обработчик
    static MBSL_RFCHandlerN Register(string modname, string funcname, MBSL_TypedFunction(N+1)&#x3C;MBSL_PromiseRef&#x3C;ReturnType>, Arg1, ..., ArgN, PlayerIdentity> handler);
    //Удаляет ранее добавленный обработчик.
    //Возвращает false, если обработчик уже был ранее удалён.
    bool Unregister();
}
</code></pre>

При работе с удалёнными функциями (RFC) необходимо учитывать следующие особенности:

* При отключении клиента от игрового сервера (в том числе из-за выключения сервера) все удалённые вызовы, выполненные этим клиентом, но ещё не завершённые, будут автоматически отклонены на клиенте с ошибкой MBSL\_ConectionResetException. При этом сами удалённые функции на сервере никак не будут уведомлены об этом.
* При отключении клиента от игрового сервера (в том числе из-за выключения сервера) все удалённые вызовы, выполненные сервером к этому клиенту, но ещё не завершённый, будут автоматически отклонены на сервере с ошибкой MBSL\_ConectionResetException. При этом сами удалённые функции на клиенте никак не будут уведомлены об этом.


# Файловая система


# Коллекции

MagicByteSharedLibrary реализует ряд коллекций (структур данных для хранения нескольких объектов), которые описаны в этом разделе.


