Skip to content
devAsmodeusPublic

About

Реконструкция мобильной стратегии Under Fire: Invasion / «Пекло!» (RJ Games, код SpaceHeat) для браузера: разбор данных движка Inferno (cocos2d-x), декодирование ассетов, веб-клиент

Topics

Resources

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

Under Fire: Invasion — реконструкция под браузер

Восстановление игры RJ Games Under Fire: Invasion (RU: «Пекло! Космическая стратегия!», внутр. код SpaceHeat) для запуска в браузере. Оригинал — Android/iOS/Windows на собственном движке Inferno (cocos2d-x). Серверы мертвы, но игра офлайновая — вся логика в клиенте.

Некоммерческий фанатский проект по сохранению игры, не связан с RJ Games. Все права на игру, её графику, звук, тексты и данные принадлежат правообладателям. Оригинальные файлы игры (APK, OBB) в репозиторий не входят; в data/ лежат данные, извлечённые из её конфигурации, — для исследования и сохранения. Чтобы пересобрать их, нужен свой экземпляр оригинала.

Источник (проверен на подлинность)

  • mobi.rjg.underfire v1.3.12 (versionCode 62, последняя, 29.05.2016), XAPK из APKPure, 649 МБ: APK + два OBB — main.13 и patch.59.
  • Подпись APK: C=RU, L=Moscow, O=RJ Games, OU=Mobile Games, MD5 сертификата F8:07:8F:CE:59:A8:54:8A:D1:27:94:CD:1E:D8:66:7C — оригинал, без модов.
  • Движок libinferno.so (cocos2d-x, 15 МБ) + FMOD, только armeabi (32-бит). 64-битной сборки нет → на Apple Silicon не запускается; поэтому цель — браузерная пересборка.
  • Код игры остаётся внутри APK (lib/armeabi/); в raw/ извлекаются только ассеты и данные.

Структура проекта

raw/            # распакованный оригинал — не в git (см. «Подготовка данных»)
  apk/assets/   # из APK: звуки, музыка, шрифты, шейдеры, немного интерфейса
  obb_main/     # main.13 OBB: основная графика и иконки, интерфейс, звук, config.xml 2014 г.
  obb_patch/    # patch.59 OBB: АВТОРИТЕТНЫЙ config.xml (2015 г., 5.4 МБ) + обновлённая графика
data/           # результат tools/parse_config.py — в git; руками не правим, только пересборкой
  config.json           # 50 секций, 13 511 сущностей (см. config_sections.json)
  config_sections.json  # сводка «секция → количество»
  server.json           # серверная часть: 21 секция, 11 782 сущности (награды квестов — actions)
  server_sections.json  # сводка по server.json
  locale_ru.json / locale_en.json  # все строки игры: 6 416 / 6 305, ключ «секция/…» (@ = значение)
assets/         # ассеты для браузера: WebP, атласы, анимации, макеты UI, шрифты — не в git,
                # собираются tools/build_assets.py или скачиваются из релиза (tools/fetch_assets.py)
web/            # браузерный клиент: TypeScript + Vite + PixiJS 8
  src/engine/   # слой совместимости с cocos2d-x 2.x (геометрия узлов, правила CocosBuilder)
  deploy/       # выкладка на свой сервер: deploy.sh и конфиг nginx (см. «Деплой»)
tools/          # парсеры/декодеры
  extract_xapk.py       # XAPK → raw/ (из APK — только assets/, оба OBB — целиком)
  parse_config.py       # config.xml, server.xml, локали (Inferno, lxml recover) → data/*.json
  build_assets.py       # весь конвейер ассетов raw/ → assets/ и архивы для релиза:
    decode_textures.py  #   .pkm.ccz → WebP с альфой из нижней половины
    convert_atlases.py  #   .atlas → спрайт-листы PixiJS + индекс кадров
    visuals_to_json.py  #   config/visuals/*.xml → анимации
    ccbi_to_json.py     #   макеты CocosBuilder → JSON (ccbi_write.py — обратно, для проверки)
  fetch_assets.py       # готовые ассеты из GitHub Release → assets/ (без XAPK)

Что внутри оригинала

Файлы patch перекрывают main, main — APK (1 618 путей есть и в main, и в patch). Без дублей и .DS_Store — 10 175 файлов из 11 929.

Тип Файлов Что это
.pkm.ccz 3 503 текстуры: ETC1 в zlib-контейнере (см. «Форматы ассетов»)
.atlas 2 685 нарезка текстур на кадры
.png 1 952 иконки (1 927) и мелкая графика — готовы к использованию
.xml 1 655 config.xml, анимации (config/visuals/), карты, миссии, локали
.ccbi 177 макеты интерфейса CocosBuilder
.wav / .mp3 115 / 63 звуки, музыка, эмбиенты
.ttf 12 шрифты
.frag / .vert 8 / 1 GLSL-шейдеры (размытие, ч/б и т. п.)

Модель данных (config.xml)

Склейка 548 XML-документов namespace inferno: без общего корня; lxml в режиме recover разбирает её без ошибок. Имён секций 53, три из них пустые (currency_groups, galaxies, stars), поэтому в config.json 50 секций. Patch — надмножество main: все секции main плюс achievements (69) и spaceport_store (14), 13 511 сущностей против 10 580, поэтому парсер читает только patch.

Ключевые секции: buildings (665), soldiers (320), units (86), turrets (11), resources (182), order_prices/offers/packs/spaceport_store (экономика), chapters (5)/missions (143)/maps (121), star_systems (9)/territories (120, галактика), quests (2 355), perks (7), abilities (180), behaviors (362), contracts (896), invasions (26), requirements (5 105). Модель совпадает по духу с Under Control (другая игра RJ Games).

server.xml — такая же склейка (477 документов) с серверной частью данных: 2 431 действие (actions — награды всех 2 355 квестов), требования, таймеры, контракты. Сервер игры встроен в клиент и читает её сам; парсер кладёт её в data/server.json.

Отдельно от config.xml лежат описания анимаций config/visuals/**/*.xml: visual → направления (атлас, смещение, hitArea) → состояния (idle, work, …) → слои с номерами кадров. parse_config.py их пока не читает.

Форматы ассетов

  • .pkm.ccz — 16-байтный заголовок CCZ! (сжатие zlib), внутри PKM v1.0, формат ETC1 RGB. ETC1 не хранит прозрачность: у 3 405 из 3 503 текстур закодированная высота вдвое больше реальной, и в нижней половине лежит альфа-маска (подтверждено декодированием и шейдером в libinferno.so). Цвет не премультиплицирован. Остальные 98 текстур — без альфы.
  • .atlas — текстовый формат Inferno (не plist cocos2d-x). Первая строка textures: <имя>.png, хотя фактически рядом лежит <имя>.pkm.ccz. Дальше по строке на кадр через табуляцию: имя, x y w h в текстуре, ox oy — смещение обрезанного кадра от левого верхнего угла исходного, W H — исходный размер. Необязательное 10-е поле r: кадр лежит повёрнутым на 90° по часовой (1 340 из 149 933 кадров).
  • .ccbi — макеты CocosBuilder, формат v5 в варианте Inferno: у колбэков кнопок лишние поля, поэтому штатный ридер ломается на 253 файлах из 306. Подробности — docs/research/ccbi.md.

Сделано

  • XAPK получен, подпись проверена, распакован (APK + 2 OBB).
  • Полная инвентаризация ассетов и данных; форматы текстур и атласов определены.
  • parse_config.py: config.xml → data/config.json (lossless по секциям) + локали; полнота сверена с исходником.
  • Публичный репозиторий; порядок работы — в CONTRIBUTING.md.
  • Распаковка XAPK одной командой (tools/extract_xapk.py), CI с линтером и тестами.
  • Исследование и выбор стека: пять отчётов в docs/research/, решение — docs/engine-decision.md.
  • Конвейер ассетов (tools/build_assets.py): текстуры → WebP, атласы → спрайт-листы PixiJS, анимации, макеты UI; готовый комплект — в релизе assets-v1.3.12 (tools/fetch_assets.py).
  • Прототип на PixiJS: интерфейс из ccbi, изометрия, размытие — стек подтверждён (docs/prototype.md).

Дальше (roadmap сборки под браузер)

Задачи по этапам — в milestones на GitHub.

  1. Стек: PixiJS 8 + TypeScript, решено 29.09.2026 — см. docs/engine-decision.md. Сначала браузеры на компьютере, телефоны — позже. Прототип сделан, стек подтверждён — docs/prototype.md.
  2. Графика: конвейер готов (tools/build_assets.py: WebP, спрайт-листы, анимации); осталась галерея для визуальной проверки и связка визуалов с сущностями конфига.
  3. Справочники: из config.json и server.json собрать читаемые каталоги: юниты со статами и уроном, здания по уровням, экономика, награды квестов, дерево миссий и глав.
  4. Тексты: сопоставить ключи конфига (X::name) со строками data/locale_*.json и шаблонами способностей.
  5. Отрисовка: браузерный клиент — UI из макетов ccbi, колония, карта галактики, сцена боя.
  6. Логика боя: интерпретатор скриптов поведения, способности, волны и условия миссий, ИИ. Чего не хватит в данных — реверсом libinferno.so, благо символы в нём с именами.
  7. Колония и прогресс: строительство и производство по таймерам, квесты, сохранения (в оригинале это открытый XML).

Подготовка данных

Оригинал в репозиторий не входит — нужен свой XAPK mobi.rjg.underfire 1.3.12. Скрипт распаковывает его в raw/: из APK — только assets/, оба OBB — целиком — и сверяет число файлов с эталоном версии (160 / 8 884 / 2 932).

uv run tools/extract_xapk.py /путь/к/Under+Fire_+Invasion_1.3.12_APKPure.xapk   # --force — перезаписать
uv run tools/build_assets.py                     # raw/ → assets/ (≈1,5 мин на 8 ядрах)

Без XAPK: готовые ассеты

Собранный assets/ выложен архивами в релиз assets-v1.3.12. Этого хватает для клиента, графики и интерфейса; raw/ нужен только для пересборки ассетов и реверса libinferno.so.

python3 tools/fetch_assets.py              # всё: JSON и WebP (≈450 МБ)
python3 tools/fetch_assets.py --only json  # без текстур: атласы, анимации, макеты UI, шрифты

Обновить релиз после пересборки (нужен raw/):

uv run tools/build_assets.py --pack dist/
gh release upload assets-v1.3.12 dist/* --clobber

Запуск инструментов

Зависимости Python описаны в pyproject.toml и закреплены в uv.lock; ставит их uv вместе с Python 3.12 из .python-version:

uv sync                          # .venv: lxml, Pillow, texture2ddecoder + pytest и ruff
uv run tools/parse_config.py     # пересобрать data/*.json из raw/

uv run запускает скрипт в .venv; то же даёт python3 tools/… после source .venv/bin/activate. Только tools/fetch_assets.py обходится стандартной библиотекой и работает без uv.

Проверки — те же, что в CI (GitHub Actions на каждый PR и push в main). Тесты не требуют файлов игры: парсер проверяется на синтетических XML, data/ — на согласованность.

uv run ruff check . && uv run pytest -q

Клиент

cd web && npm install
npm run dev                                       # http://localhost:5173; ассеты из ../assets — по /assets/
npm run typecheck && npm test && npm run build    # то же, что проверяет CI

Деплой

Клиент — статика: сборка web/dist плюс assets/. Выкладывается на свой сервер (Ubuntu, nginx) скриптом web/deploy/deploy.sh; адрес сервера и домен — UF_DEPLOY_HOST и UF_DOMAIN в .env (образец — .env.example, сам .env не коммитится).

web/deploy/deploy.sh --nginx --assets   # первый раз: nginx и конфиг сайта, ассеты релиза на сервер (≈450 МБ)
web/deploy/deploy.sh                    # дальше: собрать web/dist и выложить
web/deploy/deploy.sh --status           # что сейчас на сервере

На сервере сборка лежит в /var/www/underfire/dist и заменяется атомарно, ассеты — в /var/www/underfire/assets и отдаются как /assets/. Их сервер скачивает сам из релиза assets-v1.3.12 скриптом tools/fetch_assets.py, с компьютера уходит только сборка (~1 МБ). Конфиг nginx — web/deploy/underfire.nginx.conf: без домена сайт отвечает по IP, с UF_DOMAIN — по имени; HTTPS после первого деплоя — certbot --nginx -d <домен>.

Если работать прямо на сервере (репозиторий склонирован туда, есть Node.js), в .env ставится UF_DEPLOY_HOST=local, и те же команды выполняются без ssh.

Лицензия

Код и документация проекта — под лицензией MIT. Она не распространяется на содержимое игры: данные в data/ извлечены из Under Fire: Invasion, а права на игру, её графику, звук и тексты принадлежат RJ Games (правообладателям).

About

Реконструкция мобильной стратегии Under Fire: Invasion / «Пекло!» (RJ Games, код SpaceHeat) для браузера: разбор данных движка Inferno (cocos2d-x), декодирование ассетов, веб-клиент

Topics

Resources

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages