Это продолжение моей статьи о том, как я сделал движок совместимый с GTA San Andreas для запуска в браузере, рекомендую сначала прочитать:

https://habr.com/ru/articles/1051828/

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

Что это такое — и чем это не является. OpenSA — это эксперимент и учебный проект. Цель — сам движок: браузерный рантайм, созданный совместимым с форматами RenderWare, которые использует GTA San Andreas, — а не клонировать игру или распространять её. Он не поставляет никаких игровых ассетов; вы приносите свою легальную копию (или мод от комьюнити). Считайте это альтернативным способом запустить игру, которая у вас уже есть, в браузере. GTA San Andreas, её ассеты и торговые марки принадлежат Rockstar Games / Take-Two — это неофициальный некоммерческий фанатский проект.


Если лень читать — сразу дам ссылки на важные ресурсы:

Прошлая статья: https://habr.com/ru/articles/1051828/

Repo: https://github.com/AlexSergey/opensa

Trailer: https://www.youtube.com/watch?v=pdplknPkhAQ

Зачем это нужно?

Оригинальная GTA San Andreas вышла в далёком 2004 году. Как сейчас помню, это был сентябрь месяц, я только поступил в институт, и после пар зашёл и приобрёл DVD-диск. В нём была, кстати, та самая культовая локализация «Потрачено». На тот момент это была беспрецедентно большая игра, занимала целый DVD, в распакованном виде около 4.5 гигабайт данных.

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

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

GTA славится тем, что на неё выходило и продолжает выходить огромное количество модов от фанатов, это как крупные моды, меняющие города и полностью всю концепцию, так и мелкие исправления.

Одна из команд энтузиастов, взяв на борт пачку хороших модов исправлений оригинальной карты и потратив несколько лет ручного фикса всех объектов игры, выпустила крупный мод:

https://www.mixmods.com.br/2026/06/sa-proper-fixes/

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

Во-первых, это проект довольно закрытый, поставляется как мод — всё включено, мы его технически можем расширять, но это делать довольно сложно.

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

Я изначально хотел использовать кастом.

В-третьих, авторы не выходили со мной на связь.

Поэтому было принято решение — не зависеть от сторонних модов, а сделать свой.

Проблемы которые нужно исправить

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

В оригинальной карте существуют разные классы крупных фундаментальных багов:

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

Битые полигоны
Битые полигоны

Битые нормали. Оригинальная игра не работает с реальным освещением, а лишь эмулирует его через Prelight и Night Vertex, поэтому для оригинала это не проблема, но для моего кастом-рендера в браузере это не просто проблема, это блокер.

Битые нормали
Битые нормали
Битые нормали 2
Битые нормали 2

Дыры в карте. Многие объекты стыкуются плохо, имеют видимые зазоры.

Дыры в карте
Дыры в карте

Prelight. Одна из самых очевидных проблем. Что такое prelight — это запечённое освещение в текстуру модели (по факту освещение модели), и многие объекты оригинала выглядят либо сильно тёмными относительно остальных, либо наоборот светятся в темноте.

Сломанный прелайт
Сломанный прелайт

И многие другие.

Но также лично у меня были претензии к оригинальному поведению:

Модели деревьев, кустов и прочего устарели. Я хотел использовать современные моды типа BSOR для растительности. Проблема была в том, что деревья не имеют уровня прорисовки, и когда игрок едет, дерево может появиться прямо перед носом.

Низкокачественные модели
Низкокачественные модели

В целом уровень прорисовки в игре ужасен — в оригинале используется подход, что каждое здание, поверхность, дорога имеют свои низкополигональные копии. Не всегда игра успевает прогрузить HD-модель прежде чем игрок увидит этот ужас перед лицом. Данные LOD-модели не совпадают с оригиналом — поэтому игрок может провалиться в него.

Проблемы прорисовки
Проблемы прорисовки

Уровень прорисовки мелких объектов, таких как камни и прочее.

Стриминг — порой игра не успевает прорисовывать объекты, особенно если они высокого качества.

Проблемы стриминга
Проблемы стриминга

Короче, фронт работ был понятен. Требовались огромные правки тысяч объектов карты, поэтому у меня сразу зародилась концепция пайплайна.

Концепция пайплайна

На каждую вышеописанную проблему я решил сделать отдельный tool, который будет независим и самодостаточен.

Все такие тулы будут иметь unix-стиль — мы подаём на вход игру, получаем на выходе модифицированную игру.

Такие пайплайны будут чейниться между собой.

Архитектура данного решения вначале выглядела как-то так:

Архитектура
Архитектура

Позже она будет меняться, но об этом далее.

Реализация

Mod-installer

Собрать идеальную карту без использования модов в 2026 — это преступление! На GTA San Andreas вышло огромное количество самых разнообразных модов, которые в том числе исправляют и дополняют оригинальную карту не ломая общий посыл игры — именно это нам и нужно.

Но в моём движке пока не было реализовано механизма работы с модами поверх основной карты.

Тут сделаю небольшое отступление: существует 2 вида установки модов — legacy-подход, когда мы патчим ресурсы игры «вшивая» мод прямо в исходники, и более продвинутый — через modloader, в таком подходе мод устанавливается в отдельную папку и подмешивается в игру при запуске.

Вариант с modloader очень хорошо ложился на мою архитектуру движка, о которой подробно написано - https://habr.com/ru/articles/1051828/. Всего лишь надо было сделать дополнительный модуль между assets loader и vfs.

Но мне нужен был и legacy-подход — зачем, опишу позже.

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

Map-optimizer

Самая интересная часть. После того как мы вшили моды в игру и mod-installer передал нам пропатченные ресурсы, мы можем полностью поднять карту в map-optimizer, проанализировать прелайт относительно всех смежных объектов карты, перенастроить его, поправить геометрию, заполнить дыры и прочее.

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

Fixed Objects Viewer
Fixed Objects Viewer

Данный тул имеет плагиновую архитектуру, и я его расширил 20 плагинами, которые делают полную чистку всех моделей игры, полную перенастройку прелайта и авто-фикс прочих багов. Ввёл дополнительно override: если результат обработки не корректен, для отдельных случаев можно вручную передать параметры, что очень удобно.

lod-trees-generator

После полной обработки карты через map-optimizer мы подмешиваем любой понравившийся нам мод для замены всей растительности на карте.

Я взял очень популярный мод BSOR.

BSOR
BSOR

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

Алгоритм довольно простой:

Берём модель дерева.

Рендерим его в текстуру с 4 сторон:

Атлас
Атлас

Берём габариты исходного дерева:

Дерево
Дерево

Строим по этим габаритам 6 плоскостей на крест:

LOD дерево
LOD дерево

Получаем упрощённую копию оригинала, но в тысячу раз проще.

Теперь задача tool — расставить их по карте и заставить GTA их рисовать.

На этом этапе мы получили красивую реалистичную растительность.

Деревья
Деревья

Как видите, деревья на месте, прорисовка увеличена. На скрине всё ещё проблема с LOD самой карты. Двигаемся далее.

lod-procobj

procobj — это всякие мелкие объекты, кусты, камни. В оригинальной игре механика была такая — игрок заходит, например, в лес (лес — это зона, где генерируются procobj), и в радиусе 50 метров возникают кусты, камни, ветки. Данная генерация не позволяет сделать им LOD-объекты, и это крайне странно выглядит в процессе игры — мы подходим, а перед нами начинают быстро прорисовываться объекты.

У меня в движке уже была генерация такого рода объектов в нужных зонах.

Осталось только убрать тулой реальную генерацию из игрового стриминга и поместить на нужные позиции модели. В целом процесс плюс-минус как в lod-trees.

procobj
procobj

Я бы мог опустить вообще этот tool из описания, если б не один интересный баг:

После того как я сгенерировал LOD’ы для procobj, я, облетая карту в реальной игре, наткнулся на странную аномалию.

Barrier Bug
Barrier Bug

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

Короче, начали с Opus копать… Долго-долго, пробовали разные варианты. И тут Anthropic выпустили Fable.

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

Пока что данная проблема до конца не пофикшена, просто снизил плотность генерации.

lod-generator

lod-generator — это tool, который генерирует более качественные LOD-объекты для игры, чтобы не было «мыла» в графике.

До данного тула все предыдущие проводили генерацию карты в полной совместимости с оригинальной игрой.

Но так как в своём движке я сделал более прогрессивную систему рендеринга, о которой вы можете почитать - https://habr.com/ru/articles/1051828/:

мне пришлось создать 2 разных тула генерации лодов:

- sa-lod-generator

- opensa-lod-generator

Отличие в том, что оригинальная игра имеет LOD-объект на каждый HD-объект.

В Opensa у меня composite lods, я имею 1 крупный лод на район, что позволяет избежать проблем недогрузки объектов в принципе.

Как работает алгоритм генерации лодов:

Я вначале пробовал просто упрощать сетку:

но это приводило к битым моделям, дырам в поверхностях и прочему.

Некоторые результаты вообще повергли в ужас:

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

Тем самым получаем почти один в один модель, как на скрине выше, но на 20% меньше объёмом за счёт удаления всяких невидимых издалека деталей.

Для Opensa потом данные модели склеиваются в район. В этом теперь у нас расхождение между подходами.

Генерация LOD и склейка — самая долгая и ресурсоёмкая операция. На моём Macbook Pro M3 это занимает примерно 10-15 минут в 6 потоков.

perfect-map-builder

Это оркестратор, который последовательно запускает все tools в цепочке.

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

А вот видео с тем, что получилось:

https://www.youtube.com/watch?v=pdplknPkhAQ

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

Проблема стриминга в Opensa

Так как карта стала значительно тяжелее из-за модов и hi-poly lod’s, то и игра начала проседать по производительности.

Была разработана совершенно новая система стриминга:

Когда игра загрузилась, игрок появился в заданных координатах — у нас строится сетка из Hi-poly + Lods окантовка вокруг, как описано - https://habr.com/ru/articles/1051828/.

Игрок начинает движение — игра строит луч по направлению — грузятся ячейки в радиусе видимости. Так как ячейки тяжёлые, они прогреваются в 1px скрытом холсте.

Для подмены ячеек с LOD <=> HD используется worker, чтобы не загружать основной поток. Это очень простое описание процесса, на самом деле там всё сложнее, не хочу грузить вас.

Результатом стало то, что даже при hi-poly карте игра работает без просадок производительности.

https://www.youtube.com/watch?v=HJNWYNKRmWM

Работа с Fable

За время разработки всех этих инструментов я столкнулся с огромным количеством багов и проблем. Последнюю неделю я работал только с Fable, так как Opus показал себя хуже. Fable ведёт себя как настоящий разработчик: в поиске багов сразу предлагает решения по упрощению, чтобы найти ту грань между «есть баг — нет бага», чтобы было понятно, что привело к нему.

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

В данной итерации я строил данные tools по такому алгоритму:

  • Локально создаю ветку.

  • В начале создаю прототип tool, если я могу сделать то, что планировал — переношу в чистовой вариант.

  • Каждый tool имеет свой plan, разбитый на итерации, свою документацию, что позволяет не смешивать их с кодом движка.

В основную ветку планов ввёл такое понятие как open-issues, что даёт возможность трекать там нерешённые проблемы и делать пометки, что мы попробовали, что сработало, а что нет.

Также ввёл такое понятие как ideas — с вынесенными планами на будущее.

Что дальше

На данном этапе я получил чистую карту, с которой можно работать далее. Сейчас исправлены нормали, нет дабл-фейсов, настроены smoothed groups, что позволяет приступить к написанию нового прогрессивного рендеринга.

Следующим этапом я хочу попробовать сделать графику уровня современных ААА-игр, но в браузере. Посмотрим, что из этого выйдет. Или не выйдет. В любом случае поглядим.

К сожалению демо пока не досутпно - не адаптировано под новые фичи. Извините за эти неудобства!

Спасибо всем за внимание!