Акты Становления

850: Пакет/Игровой Сервис

Это как умный судья для компьютерных игр, который работает сам по себе. Он следит за всем, что происходит в пошаговых играх, например, в покере. Судья запоминает состояние игры, проверяет ходы игроков, использует специальные «движки» с правилами и сохраняет результаты. Ему неважно, как игроки с ним общаются — через сайт, приложение или что-то ещё.

Игровой Сервис (@idealic/game-service) — это программа-конструктор на Node.js, созданная для проведения пошаговых игр. Изначально она делалась для покера, но её устройство универсально. Она работает как безопасная «песочница», где можно создавать и проверять правила игры, не затрагивая основной сайт или приложение клиента.

Основная архитектура

Сервис построен по принципу «автомата с газировкой». Он не запоминает, кто вы. Вы просто делаете запрос (отправляете ход), а он обрабатывает его и выдаёт результат (новое состояние игры). Сервер получает версию событий от игрока, сверяет её со своей главной версией, проверяет ход и отправляет всем обновлённую информацию.

Подключаемые игровые движки

Сервис не знает правил самой игры. Он как игровая приставка, а правила игры — это картриджи. Можно вставить картридж с покером, а можно — с шахматами.

  • Список игр: У сервиса есть список всех «картриджей» (игровых движков), которые он умеет запускать.
  • Одинаковый «разъём»: Все «картриджи» должны иметь одинаковый набор команд (State.advance(), State.join() и т. д.), чтобы приставка понимала, как с ними работать.
  • Разделение обязанностей:
    • Игровой движок (например, покер): Знает правила, проверяет ходы и меняет состояние игры.
    • Игровой сервис (этот пакет): Отвечает за всё остальное — связь с игроками через интернет, сохранение игры, управление столами и временем на ход.

«Состояние» как единственный источник правды

Вся информация об игре хранится в одном большом «файле» — Объекте Состояния. Это не просто картинка текущей ситуации, а полная запись всей партии, как ходы в шахматах.

  • Обмен без памяти: Клиенты и сервер обмениваются этим «файлом» целиком. Никому не нужно ничего запоминать, вся правда — в этом файле.
  • Предсказуемость: В «файле» записано специальное случайное число. Благодаря этому можно в любой момент идеально точно воспроизвести всю игру с самого начала. Это помогает решать споры.
  • Взгляд игрока: Сервер умеет показывать каждому игроку свою версию «файла». Например, он скроет карты других игроков, чтобы вы видели только свои.

Уровень для связи с внешним миром

Сервису всё равно, как с ним общаются: через сайт, мобильное приложение или что-то ещё. Все способы общения вынесены в отдельный «переходник» (service.io.ts). Если нужно подключить новый способ, достаточно просто заменить этот «переходник».

  • Сохранение игры: Команды saveGame и loadGame отвечают за хранение главной версии состояния игры.
  • Управление деньгами: fetchPlayerStacks и savePlayerStacks связываются с внешними системами кошельков.
  • Общение в реальном времени: broadcastToPlayers рассылает обновления всем игрокам (например, через веб-сокеты).
  • Фоновые задачи: fetchTimedOutGames позволяет проверять, не закончилось ли у кого-то время на ход.

Концепция игровых столов

В этой системе игровые столы — это не что-то постоянное, что хранится в базе данных. Стол существует, пока идёт игра.

  • Создание по требованию: Столы создаются, когда они нужны. Если игрок ищет игру (например, «Техасский Холдем, $1/$2») и свободных мест нет, система тут же создаёт новый стол.
  • Жизненный цикл:
    1. Найти: Клиент ищет стол с нужными параметрами. Система находит существующий или создаёт новый.
    2. Наблюдать: Игрок получает состояние игры и может просто смотреть за происходящим.
    3. Присоединиться: Игрок отправляет команду join, чтобы сесть за стол.
    4. Играть: Идёт обычный игровой процесс.
    5. Завершить: Игроков убирают из-за стола, если у них закончилось время или деньги для следующей раздачи.

Как это работает

Вот как устроен рабочий цикл сервиса:

  1. Сигнал: Внешнее событие (например, ход игрока) запускает процесс.
  2. Загрузка: Сервер достаёт из памяти главную, самую правильную версию состояния игры.
  3. Сверка: Он сверяет данные, которые прислал клиент, со своей версией.
  4. Ход: Сервис просит игровой движок обработать ход и продолжать игру до тех пор, пока снова не понадобится действие от игрока.
  5. Завершение: Если раунд закончился, сервис подводит итоги, раздаёт выигрыш и начинает новый раунд.
  6. Сохранение и рассылка: Новое состояние игры сохраняется и отправляется всем игрокам.