# Техническая спецификация игрового сервера DatsMagic

Данный документ описывает правила, физическую модель и API-контракты пошагово-непрерывного симулятора управления ковром-самолетом в условиях динамического окружения (пустыни).

---

## 1. Общие положения и игровой цикл

- **Игровая среда**: Двумерное непрерывное пространство (2D плоскость) с декартовой системой координат $(X, Y)$.
  - Ось **$X$** направлена вправо (возрастает вправо).
  - Ось **$Y$** направлена вверх (возрастает вверх).
- **Дискретизация времени (Game Loop)**:
  - Сервер работает циклично с фиксированным шагом времени (тиком):
    $$\Delta t = 0.2\text{ с } (200\text{ мс})$$
- **Сетевое взаимодействие**:
  - Клиент отправляет команды и получает снимок мира одним запросом `POST /play/magcarp/player/move`.
  - Отдельного игрового `GET`-эндпоинта нет; пустой список `transports` используется для получения снимка без новой команды.
  - На команду принимается не более одного непустого пакета за тик; принятые ускорения применяются игровым циклом.

---

## 2. Физическая модель движения (Векторная механика)

### 2.1. Векторы состояния игрока

Каждая сущность игрока (ковёр-самолёт) описывается в оперативной памяти сервера следующими величинами:

| Обозначение | Название | Описание |
| :--- | :--- | :--- |
| $\vec{P} = (x, y)$ | **Координаты** | Радиус-вектор текущего положения ковра в пространстве |
| $\vec{V} = (v_x, v_y)$ | **Скорость** | Вектор текущей скорости ковра |
| $\vec{A} = (a_x, a_y)$ | **Ускорение** | Вектор управляющего ускорения (задается игроком) |
| $\vec{W} = (w_x, w_y)$ | **Силы окружения** | Результирующий вектор внешних сил (ветер, гравитационное затягивание аномалий) |

### 2.2. Константы и ограничения симуляции

| Параметр | Поле в API | Описание | Значение по умолчанию |
| :--- | :--- | :--- | :--- |
| $A_{max}$ | `maxAccel` | Максимальный модуль вектора управляющего ускорения | Определяется профилем мира (обычно $40.0$) |
| $V_{max}$ | `maxSpeed` | Максимально допустимый модуль скорости ковра | Определяется профилем мира (обычно $110.0$) |
| $k_{f}$ | `friction` | Коэффициент вязкого трения среды (воздух/песок), затухание за шаг | $0.98$ |

---

### 2.3. Алгоритм пересчета физики на каждом тике (схема Эйлера)

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

#### Шаг 1. Валидация и нормализация команды игрока
Если длина заявленного игроком вектора ускорения превышает допустимый максимум ($\|\vec{A}\| > A_{max}$), сервер принудительно нормализует его:
$$\vec{A} = \frac{\vec{A}}{\|\vec{A}\|} \cdot A_{max}$$
Аномалии не блокируют управление: переданный вектор ускорения применяется после ограничения до $A_{max}$ даже в зоне их воздействия.
Если для живого ковра на очередном тике нет новой команды, сервер повторно применяет последнее принятое эффективное ускорение. Отсутствие запроса не означает остановку; чтобы остановить ковер, клиент должен явно отправить $(0,0)$. После гибели и респавна сохранённая команда очищается.

#### Шаг 2. Расчет сил окружения
На основе текущих координат $\vec{P}$ рассчитывается суммарное воздействие всех активных аномалий:
$$\vec{W} = \sum_{i} \vec{w}_i$$

#### Шаг 3. Интегрирование скорости с учетом трения
$$\vec{V}_{new} = (\vec{V}_{old} \cdot k_{f}) + (\vec{A} + \vec{W}) \cdot \Delta t$$

#### Шаг 4. Ограничение предельной скорости
Если модуль скорости превышает порог ($\|\vec{V}_{new}\| > V_{max}$), вектор направления сохраняется, но модуль усекается:
$$\vec{V}_{new} = \frac{\vec{V}_{new}}{\|\vec{V}_{new}\|} \cdot V_{max}$$

#### Шаг 5. Интегрирование позиции
$$\vec{P}_{new} = \vec{P}_{old} + \vec{V}_{new} \cdot \Delta t$$

---

## 3. Игровые сущности и правила взаимодействия

### 3.1. Ковры-самолеты (Игроки)

- **Радиус коллизии**: Точечный ($R = 0$) или минимальный физический радиус ($R_{player}$).
- **Статусы состояния**:
  - `normal` — штатное состояние, полное управление доступно.
  - `destroyed` — ковер уничтожен при контакте с ядром аномалии или выходе за карту; пока ковер жив, управление доступно и в зоне влияния аномалий.

### 3.2. Сокровища (Treasures)

Сущности со статическими координатами $\vec{P}_{treasure} = (x, y)$ и ценностью в $S$ очков.

- **Механика сбора**: На каждом тике проверяется отрезок движения ковра от позиции до физического шага к позиции после шага. Монета собирается, если минимальное расстояние от ее центра до этого отрезка не превышает сумму радиусов ковра и монеты: $d_{segment} \le R_{player} + R_{coin}$. Это предотвращает пропуск монеты, если круг ковра пересёк круг монеты между концами тика.
- **Результат**: При выполнении условия игроку начисляются очки $S$, а сокровище удаляется с карты (или переспавнивается).

### 3.3. Динамические аномалии / Вихри (Anomalies)

Подробно специфицированы в документе предметной области [`docs/domain/DR-005-anomalies.md`](domain/DR-005-anomalies.md).

Подвижные области природной стихии, заданные:
- Центром $\vec{P}_{anomaly} = (x, y)$ и вектором скорости $\vec{V}_{anomaly} = (v_x, v_y)$
- Смертоносным ядром $R_{core}$ и внешней зоной воздействия $R_{effect}$ ($R_{core} < R_{effect}$)
- Типом воздействия `type`: `attracting` (притягивающая) или `repelling` (отталкивающая)
- Прирожденной силой воздействия $F_{influence}$

#### Механика воздействия:
1. **Смертоносное ядро**: Если дистанция от центра ковра до центра аномалии достигает $\text{Distance}(\vec{P}_{player}, \vec{P}_{anomaly}) \le R_{core} + R_{player}$, ковер мгновенно **уничтожается** (`status: "destroyed"`), исключается из физического расчета и визуализации.
2. **Внешняя зона влияния**: Если ковер находится в зоне $R_{core} < \text{Distance}(\vec{P}_{player}, \vec{P}_{anomaly}) \le R_{effect}$:
   - Для `attracting` (притяжение):
     $$\vec{W}_{anomaly} = \frac{\vec{P}_{anomaly} - \vec{P}_{player}}{\|\vec{P}_{anomaly} - \vec{P}_{player}\|} \cdot F_{influence}$$
   - Для `repelling` (отталкивание):
     $$\vec{W}_{anomaly} = \frac{\vec{P}_{player} - \vec{P}_{anomaly}}{\|\vec{P}_{player} - \vec{P}_{anomaly}\|} \cdot F_{influence}$$
3. **Движение и жизненный цикл**: Аномалия рождается в буферной зоне за пределами арены, прямолинейно перемещается через мир с постоянной скоростью $\vec{V}_{anomaly}$, обязательно пересекая арену зоной действия, и деспавнится после полного выхода за границы арены. Аномалии беспрепятственно проходят сквозь друг друга (ghosting), а их силы векторно суммируются.

### 3.4. Противники (Enemies)

Другие управляемые игроки в зоне видимости. Сервер передает их идентификаторы `id`, координаты `position` и текущие векторы скорости `velocity`.

---

## 4. Контракты API (Спецификация JSON)

### 4.1. Общие требования
- **Авторизация игрового клиента**: Каждый запрос игрока к API должен содержать HTTP-заголовок:
  ```http
  X-Auth-Token: <токен, выданный Hub при регистрации команды>
  ```
- Пользовательский токен создаёт Hub после регистрации уникального имени. Отсутствующий или неизвестный токен игрока всегда отклоняется с `401 Unauthorized`; внутренний observer credential Hub описан ниже.
- **Формат данных**: `application/json` для тела запросов и ответов.

---

### 4.2. Единственный игровой метод

Публичный игровой API имеет один endpoint: `POST /play/magcarp/player/move`. Он одновременно принимает пакет ускорений и возвращает полный актуальный снимок `Desert`; отдельного игрового GET нет. Игрок авторизуется выданным Hub токеном в `X-Auth-Token`; неизвестный пользовательский токен получает `401 Unauthorized`. Для публичного веб-просмотра Hub использует отдельный случайный внутренний observer credential: он не раскрывается клиентам, не создаёт игрока и принимает только пустой пакет команд.

Для каждого зарегистрированного игрового токена действует общий лимит **5 HTTP-запросов за скользящую секунду**. Превышение возвращает `429 Too Many Requests` до сборки снимка мира. Это ограничение применяется и к запросам без команд. Отдельно сохраняется правило: не более одного непустого пакета команд на команду за один игровой тик. Для уменьшения передачи больших снимков клиент может передать `Accept-Encoding: gzip`; при согласовании ответ содержит `Content-Encoding: gzip`, а после стандартной HTTP-декомпрессии остаётся тем же JSON.

Тело запроса: `{"transports":[{"id":"<полученный ID ковра>","acceleration":{"x":0,"y":0}}]}`. Ответ содержит `transports`, `bounties`, `anomalies`, `enemies`, `mapSize`, лимиты мира, имя и счёт команды. У каждого транспорта есть `velocity`, `selfAcceleration` и `anomalyAcceleration`; координаты передаются отдельными `x`,`y`. Серверный тик — 200 мс, для команды принимается не более одного непустого пакета команд за тик.

Подробная таблица всех полей, примеры полного запроса/ответа и ошибок HTTP доступны в [справочнике игрового API](components/arena-hub/api.md). Порядок регистрации токена и руководство по созданию игрового бота описаны в [руководстве игрока](components/arena-hub/world-rules.md).

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