# Описание FSM

Система FSM (Finite State Machine) предназначена для централизованного управления состояниями игровых объектов, обеспечивая чёткое и последовательное выполнение действий на основе различных входящих запросов от управляющих подсистем (AI, пользовательские команды, физика и другие). \
Цель FSM — разрешать конфликтующие запросы и выбирать наиболее подходящее состояние объекта для поддержания логической согласованности и плавности анимаций, а также корректной работы игровых механик.

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

**Основные функции FSM:**

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

## Компоненты FSM

### Состояние

**Состояние** (**state**) представляет собой описание текущей позиции или действия юнита (например: stand, walk, fire, blown\_away).\
В каждый момент времени юнит может находиться только в одном состоянии.\
Состояния являются узлами в FSM-графе переходов между состояниями.

Каждое состояние:

* имеет уникальное имя;
* имеет как минимум один тег;
* связи между состояниями формируют возможные переключения между состояниями.

### Теги&#x20;

**Тег** (**tag**) — это текстовая метка, назначаемая состоянию. Тег выполняет две функции:

* позволяет внешним системам понять, в каком логическом состоянии находится юнит;
* определяет, какой запрос должен привести к данному состоянию.\
  Пример: одно из доступных состояний с тегом fire будет выбрано в ответ на запрос fire.

### Запросы&#x20;

**Запрос** (**request**)— это внешняя команда, поступающая от управляющих подсистем игры (AI, пользовательского ввода, физики и др.), которая инициирует в рамках FSM процесс перевода управляемого объекта в новое состояние.

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

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

{% hint style="info" %}
Теги в состояниях могут использоваться не только для связи с запросами, но и для работы других игровых подсистем.
{% endhint %}

Результат обработки запроса зависит от:

* текущего состояния управляемого объекта;
* приоритета запроса;
* правил переходов, описанных в FSM-графе.

FSM поддерживает несколько **типов запросов**.&#x20;

{% hint style="danger" %}
**Типы запросов** заданы в коде и не могут быть переопределены через конфигурационные файлы FSM.&#x20;
{% endhint %}

{% hint style="info" %}
*Таблица типов запросов приведена для ознакомления, с целью целостного восприятия работы конечного автомата (FSM) в Gem RTS.*
{% endhint %}

<table><thead><tr><th width="125.6484375">Тип</th><th width="365.98046875">Описание</th><th>Пример</th></tr></thead><tbody><tr><td><code>Switch</code></td><td>Запрос этого типа вызывается в коде однократно и ожидает в очереди возможности для выполнения. После выполнения удаляется.</td><td>Команда “Лечь”</td></tr><tr><td><code>Job</code></td><td>Тип запроса, вызываемый из кода каждый квант после перевода юнита в целевое FSM-состояние. Удерживает юнита в этом состоянии, пока запрос остаётся активным. Запрос данного типа сбрасывается при отсутствии его вызова из кода дольше, чем указано в параметре <code>duration</code>, или при поступлении более приоритетного запроса.<br>При сбросе запускает запрос типа <code>Switch</code> из блока <code>exit</code> в описании FSM, если юнит всё ещё находится в целевом состоянии.</td><td>Команда “Ремонтировать”</td></tr><tr><td><code>Action</code></td><td>Запрос данного типа вызывается из кода каждый квант до возможности перехода юнита в целевое состояние; при срабатывании переводит юнита в целевое состояние для выполнения действия, после чего удаляется. Если запрос не вызывался хотя бы один квант, то он удаляется без выполнения.</td><td>Команда “Бросить  гранату”</td></tr><tr><td><code>State</code></td><td>Запрос вызывается в коде однократно, после чего происходит переход в целевое состояние. Состояние сохраняется, пока не будет отменен или не придёт более приоритетный запрос.</td><td>Спрятать оружие, если оно воткнулось в стену</td></tr></tbody></table>

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

{% hint style="success" %}
[Список запросов и тегов, предопределенных в коде](/documentation/gem-rts-v1-ru/animacii/anymatsyonnaia_systema_yunytov/format-opisaniya-fsm/fsm-dlya-yunita-chelovek.md)
{% endhint %}

### Подмножества состояний

**FSM-подмножество** (**Subset**) — это компонент FSM, задающий ограничения на переходы, исключая из рассмотрения состояния, несовместимые с текущим состоянием объекта.

**Пример**\
Если юнит удерживает канистру, **FSM-подмножество** исключает состояния лежать, сидеть и ремонтировать, поскольку выполнение этих действий несовместимо с текущим состоянием объекта.

## Обработка запроса в FSM

### **Этапы процесса обработки запроса:**

* **Выбор FSM-подмножества**\
  В соответствии с текущим состоянием юнита обработчик состояний выбирает **FSM-подмножество**, которое ограничивает выборку доступных для перехода состояний.&#x20;
* **Анализ приоритетов**\
  При поступлении нескольких запросов одновременно FSM анализирует их приоритеты. Запрос с наивысшим приоритетом имеет преимущество при выборе нового состояния. Равнозначные по приоритету запросы разрешаются согласно порядку поступления.
* **Проверка доступности перехода**:
  * Задан ли графом FSM переход в целевое состояние из текущего состояния.
  * Выполняются ли условия (например, заданы соответствующие теги и/или дополнительные параметры запроса).
* **Результат обработки запроса**\
  FSM выбирает ближайшее доступное по графу состояние, соответствующее тегу запроса, независимо от того, находится ли оно в прямой связи с текущим состоянием — переключение состояний может происходить через промежуточные состояния.

### Типичный сценарий работы FSM

Стартовая позиция: юнит находится в состоянии ожидания (idle). \
Начинается бой: юнит обнаруживает противника, получает приказ от AI атаковать врага и одновременно команду от игрока «окопаться». Рядом с юнитом происходит взрыв, взрывная волна достаточной силы, чтобы отбросить юнита и нанести ему урон. Запросы на изменение состояния юнита отправляются в FSM.\
Поскольку юнит не может пребывать одновременно в нескольких состояниях (окапываться, атаковать, реагировать на взрыв, лечиться или умирать), FSM разрешает этот конфликт, выбирая наиболее приоритетное и допустимое состояние.

При активации нового состояния объекта, обработчик состояний передает состояние в игровые системы, а также запускает скрипты и анимации, соответствующие этому  состоянию.&#x20;

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

## Компоненты конфигурации FSM

Логика конечного автомата описывается в **.def** файле объекта с использованием блока `fsm`:

> **Формат записи**
>
> ```
> {fsm "name"
>   ...
> }
> ```
>
> где `"name"` — имя FSM.

{% hint style="info" %}
**Описание FSM** может быть вынесено в отдельный файл или каталог.

Например, в ресурсах игры **Men of War II**:

* `\properties\animal.ext` — FSM для объекта `horse`;
* `\properties\human_fsm\` — FSM для объекта `human`.
  {% endhint %}

### Список FSM-запросов&#x20;

Блоки `request` в описании FSM используется для регистрации запросов.&#x20;

{% hint style="danger" %}
Полное описание запросов находится в исходном коде и не доступен для переконфигурации в текстовых файлах игры.
{% endhint %}

Каждый блок соответствует одному именованному запросу и включает параметры, определяющие правила его обработки внутри FSM.

> **Структура описания запроса**
>
> ```
> {Request "name"
>     {priority N} 
>     {interrupt}
>     {duration N}
>     {exit "state_name"} 
> }
> ```

<table><thead><tr><th width="139.54296875">Параметр</th><th>Описание</th></tr></thead><tbody><tr><td><code>Request</code></td><td>Имя запроса. <br>FSM выбирает состояние, у которого тег совпадает с указанным именем.</td></tr><tr><td><code>priority</code></td><td>Определяет приоритет запроса. <br>При обработке конкурирующих запросов выбирается запрос с более высоким значением.</td></tr><tr><td><code>interrupt</code></td><td>Разрешает немедленный переход в новое состояние, принудительно завершая текущее, независимо от состояния активных анимаций.<br>Опционально.</td></tr><tr><td><code>duration</code></td><td>Задает максимальный интервал в тактах между последовательными вызовами запроса из кода; если запрос не вызывается в течение указанного времени, он автоматически отменяется.<br>Опционально, только для <strong>Job</strong>-запросов</td></tr><tr><td><code>exit</code></td><td>Задает имя состояния для автоматического перехода при отмене запроса после превышения времени ожидания, указанного в параметре <code>duration</code>.<br>Опционально, только для <strong>Job</strong>-запросов</td></tr></tbody></table>

<details>

<summary>Пример описания запроса в fsm</summary>

```
{Request "move"
    {priority 30}
    {interrupt}
    {duration 2}
    {exit "stop-move"}
}
```

Блок регистрирует запрос с именем `move`.

При обработке запросов FSM выберет этот запрос, если все остальные поступившие запросы имеют приоритет ниже `30`.

Параметр `interrupt` указывает, что запрос может немедленно прервать текущее состояние, независимо от завершения анимаций.

FSM будет искать состояние, у которого в параметре `tag` указано значение `move`, и осуществит переход в него при активации запроса.

Запрос остаётся активным до тех пор, пока он регулярно обновляется в коде. Если в течение двух тактов обновление не произошло (`duration 2`), запрос автоматически отменяется.

В случае отмены запроса FSM выполнит переход в состояние с тегом `stop-move`, как задано параметром `exit`.

</details>

### Начальное FSM-состояние

Блок параметра `Start` используется для указания  имени состояния для инициализации юнита.

> **Формат описания начального fsm-состояния**
>
> ```
> {Start "state_name"}
> ```

### Список FSM-состояний

С помощью блоков параметра `state` задаются узлы графа FSM, они же FSM-состояния. \
Вложенные блоки используются для описания доступных переходов между состояниями, тегов состояний и других параметров.

> **Структура описания параметров fsm-состояний**
>
> ```
> {State "state_name"
>     {from "source_state"}
>     {fromTagged "source_tag"}
>     {transit "transit_state"}
>     {to "target_state"}
>     {tag "name"}
>     {condition "name"}
>     {split "part1" "part2"}
> }
> ```

<table><thead><tr><th width="258.82421875">Параметр</th><th>Описание</th></tr></thead><tbody><tr><td><code>State "state_name"</code></td><td>Уникальный идентификатор описываемого состояния</td></tr><tr><td><code>from "source_state"</code></td><td>Определяет исходное состояние, из которого разрешён переход в описываемое состояние.</td></tr><tr><td><code>fromTagged "source_state"</code></td><td>Разрешает переход в описываемое состояние из любого состояния, имеющего указанный тег.</td></tr><tr><td><code>transit "transit_state"</code></td><td>(Опционально) Определяет автоматический переход в следующее состояние без внешнего запроса, как только это станет возможно.</td></tr><tr><td><code>to "target_state"</code></td><td>Доступность перехода в указанное состояние из описываемого. Может быть указано несколько строк с параметром <code>to</code>, если допустимы  переходы в альтернативные состояния.</td></tr><tr><td><code>tag "name"</code></td><td>Тег описываемого состояния. <br>Опционально может быть записано несколько строк с параметром tag для одного состояния. </td></tr><tr><td><code>condition "name"</code></td><td>Условие, при котором разрешён вход в это состояние, в качестве значения параметра указывается имя запроса. </td></tr><tr><td><code>split "part1" "part2"</code></td><td>Разделение объекта на полунезависимые части (например, "walk_all" "linked"). Используется для сложных переходов или действий, когда анимацию юнита можно разделить на анимации его частей: например, верхней и нижней частей туловища. </td></tr></tbody></table>

{% hint style="success" %}
Имена состояний и названия тегов записываются в двойных кавычках
{% endhint %}

<table data-card-size="large" data-view="cards"><thead><tr><th data-type="content-ref"></th><th data-hidden data-card-cover data-type="files"></th></tr></thead><tbody><tr><td><a href="/pages/8QNGtwiAPg9zkEZgmrFy">/pages/8QNGtwiAPg9zkEZgmrFy</a></td><td><a href="/files/7PiLyqlIStMHdiy0XHd4">/files/7PiLyqlIStMHdiy0XHd4</a></td></tr><tr><td><a href="/pages/dg0bGW5CwGVwU7Q4JjyT">/pages/dg0bGW5CwGVwU7Q4JjyT</a></td><td><a href="/files/1Wz2EiMNSsKkf8UZ0kwL">/files/1Wz2EiMNSsKkf8UZ0kwL</a></td></tr></tbody></table>

<details>

<summary>Пример описания fsm-состояния</summary>

```
{State "stand_bazooka_pick"
    {from "stand"}
    {fromTagged "up"}
    {transit "stand"}
    {to "stand"}
    {tag "up"}
    {tag "bazooka-pick"}
    {condition "knock-down"}
    {split "walk_all" "linked"}
}
```

Блок описывает состояние с именем `stand_bazooka_pick`.

Переход в это состояние разрешён из состояния `stand` или из любого другого состояния, у которого задан тег `up`.

Параметр `condition` указывает, что переход в состояние возможен только при активном запросе `knock-down`.

После завершения текущего состояния FSM автоматически выполнит переход в состояние `stand`, как задано параметром `transit`.

Также из этого состояния разрешён явный переход в `stand`, заданный через параметр `to`.

Состоянию присвоены два тега: `up` и `bazooka-pick`. Эти значения могут использоваться для сопоставления с запросами и в логике обработки состояний.

Параметр `split "walk_all" "linked"` указывает, что в этом состоянии применяется раздельное воспроизведение анимаций: нижняя часть тела может использовать анимацию `walk_all`, в то время как верхняя остаётся синхронизированной с основной последовательностью.

</details>

### Подмножество FSM-состояний

С помощью блока параметра `subset` описываются подмножества состояний, чтобы ограничить список допустимых для выбора состояний в зависимости от текущего FSM-состояния.&#x20;

> **Структура описания FSM-подмножества**
>
> ```
> {subset "name" from "source_subset"
>   {disable "state_A"}
>   {enable "state_B"}
> }
> ```

<table><thead><tr><th width="145.171875">Параметр</th><th>Описание</th></tr></thead><tbody><tr><td><code>subset</code></td><td>Имя fsm-подмножества. <br>Определяет набор разрешенных и запрещенных состояний для данного поднабора.</td></tr><tr><td><code>from</code></td><td>Имя родительского подмножества, от которого наследуются разрешённые состояния.<br>(Опционально) </td></tr><tr><td><code>disable</code></td><td>Отключает доступ к состояниям, помеченным указанным тегом, в рамках данного подмножества. Может использоваться несколько раз для разных тегов.</td></tr><tr><td><code>enable</code></td><td>Включает доступ к состояниям, помеченным указанным тегом, в рамках данного подмножества. Может использоваться несколько раз для разных тегов.</td></tr></tbody></table>

<details>

<summary>Пример описания fsm-подмножества</summary>

```
{subset "with_item" from "default"
    {disable "down"}
    {disable "squat"}
    {disable "looking"}
    {disable "repair"}
    {disable "step-aside"}
    {enable "open-with_item"}
}
```

Подмножество с именем `with_item` наследует состояния подмножества `default`, но исключает из выборки возможных переходов состояния: лежать (down), сидеть в укрытии (squat), осматриваться (looking), ремонтировать (repair) или стрейфиться (step-aside), так как указанные состояния несовместимы с состоянием, когда юнит несет в руках тяжелый предмет, например, канистру или ящик.

</details>


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://bestway-1.gitbook.io/documentation/gem-rts-v1-ru/animacii/anymatsyonnaia_systema_yunytov/format-opisaniya-fsm.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
