Когда дедлайны горят, а легаси-база данных снова выдает таймауты, хочется сделать с ней что-то радикальное — например, запустить в ней культовый шутер 1993 года. Звучит как бред митапа после полуночи, но для инженеров, привыкших выжимать из СУБД невозможное (и молиться, чтобы на проде ничего не упало), «It runs Doom» — это не шутка, а полноценный вызов. Сегодня мы разберем этот безумный инжиниринг: как заставить декларативный язык таблиц обсчитывать физику, рендерить графику и крутить кадры без единой строки C++.

Введение: когда реляционная алгебра встречается с демонами ада

Мировое IT-сообщество давно одержимо культовой фразой: «It runs Doom». За прошедшие десятилетия классический шутер 1993 года запускали на самых неожиданных устройствах и средах: от осциллографов и банковских терминалов до тестов на беременность и клеток ДНК. Инженеры соревнуются в изобретательности, заставляя рендерить трёхмерный мир на оборудовании, которое для этого абсолютно не предназначено.

Однако один из самых безумных и технически сложных экспериментов в этой области — это попытка портировать Doom внутрь реляционной системы управления базами данных (СУБД), используя исключительно SQL и процедурные расширения вроде PL/pgSQL. На первый взгляд, эта идея звучит как чистейшая ересь. SQL — это декларативный язык для работы с таблицами, оптимизированный под хранение, выборку и агрегацию данных. Doom — это процедурная, событийно-ориентированная программа на C, требующая жесткого контроля над памятью и стабильных 35 кадров в секунду (что звучит как несбыточная мечта для любого джуниора после первого релиза). Как можно заставить реляционный движок обрабатывать трассировку лучей, физику коллизий и обработку ввода?

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

Архитектурный вызов: как превратить реляционные таблицы в игровой движок

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

В мире SQL все данные должны быть нормализованы и разложены по таблицам. Чтобы заставить СУБД выполнять функции игрового движка, разработчикам пришлось совершить ментальный сдвиг и представить каждый элемент игрового мира как строку в реляционной таблице:

  • Стены и сектóры (WAD-данные): Геометрия уровня конвертируется в реляционные структуры данных. Вершины, линии и подсектора хранятся в связных таблицах с индексами для быстрого пространственного поиска.
  • Сущности (Mobj): Враги, патроны, пули и сам игрок представлены в единой таблице объектов с координатами $(x, y, z)$, углами обзора, векторами скорости и состоянием здоровья.
  • Кадровый буфер (Framebuffer): Экран игры размером 320x200 пикселей предстает в виде огромной матрицы или таблицы пикселей, где каждый пиксель обновляется с помощью SQL-запросов (прямо как те самые «оптимизированные» дашборды в Excel на клиентских ноутбуках).

Основной цикл игры (Main Loop), который в оригинале выглядит как бесконечный цикл на C, внутри СУБД реализуется через хранимые процедуры, рекурсивные CTE (Common Table Expressions) или триггеры.

Рендеринг графики и обработка физики через реляционные запросы

Самая сложная задача при портировании Doom на SQL — заставить реляционный движок заниматься отрисовкой графики (Raycasting) и обсчетом коллизий в реальном времени. В реляционных базах данных нет понятия «экрана» или «видеопамяти» в привычном понимании GPU, поэтому всю математику проекции приходится выполнять силами SQL-запросов.

Трассировка лучей и BSP-дерево

Оригинальный Doom использует BSP-дерево (Binary Space Partitioning) для быстрого определения видимости стен от точки зрения игрока. В СУБД это дерево преобразуется