Underground 2 Revived
Chrome과 Firefox에서 Need for Speed Underground 2를 WebGPU로 두고 팬 프로젝트입니다
아직 감지된 업데이트가 없습니다. GitHub 릴리스가 나오면 여기에 보입니다.
개인 계정의 공개 저장소 소유자는 GitHub로 로그인해 운영자를 확인하고 소개를 직접 관리할 수 있습니다. 관리자 승인은 필요하지 않습니다.
로그인한 뒤 확인 파일을 만들어 이 저장소의 기본 브랜치에 30분 안에 커밋해 주세요. 다른 브랜치나 포크의 파일은 인정하지 않습니다. 파일을 올린 뒤 아래에서 확인하면 관리자 승인 없이 관리할 수 있습니다. 자격을 유지하려면 파일을 남겨 두세요.
로그인이 필요하면 로그인 화면으로 이동합니다. 로그인 후 이곳으로 돌아와 원하는 확인 버튼을 다시 눌러 주세요.
프로젝트 폴더에서 /nomorevibe verify를 실행하면 소유권을 확인하고 소개를 직접 관리할 수 있습니다.
1분 만에 확인하기메이커가 쓴 소개는 위의 한 줄이 전부입니다. 더 자세한 내용은 저장소 README에서 읽을 수 있습니다. 저장소 README ↗
README 전체를 불러오는 중입니다.
README 전문 보기 ↗3D-просмотр демок Counter-Strike 2 в браузере, собственный парсер демо и автоматическая запись клипов лучших моментов (мультикиллы, клатчи, ноускопы…) в MP4.
.dem (на базе demoparser2): позиции и углы
обзора всех игроков, HP/броня/оружие/деньги, раунды, киллы, выстрелы, урон,
траектории гранат, дымы, молотовы, бомба, статистика. Демо на 13 раундов
разбирается за ~4 секунды..dem.zst открываются как есть.setpos для консоли.cs2demo render;cs2demo watch следит за папкой с демками и
записывает лучшие моменты каждого нового матча; в веб-интерфейсе есть галочка
«Автозапись 5 лучших после загрузки демо».Всё работает локально: демо никуда не отправляется.
https://knyazvaleriy1-ai.github.io/3DDEMOPARSERCS2/ (GitHub Pages) или свой адрес на Vercel — как опубликовать, см. «Публикация сайта».
Откройте ссылку, нажмите «Открыть демо» и выберите .dem, архив .rar с HLTV или
.dem.zst с FACEIT (или вставьте ссылку на матч FACEIT). Ничего не
загружается на сервер: демо разбирает прямо в браузере тот же парсер
(demoparser2, скомпилированный в WebAssembly), а логика сборки данных — точная
копия Python-парсера (вывод совпадает байт в байт). Разобранные демо и записанные
клипы хранятся в браузере (IndexedDB), их можно открыть снова без повторного
разбора. Клипы пишутся в MP4 прямо в браузере: «Скачать» или «Поделиться» (на
телефоне — сразу в Telegram, галерею и т. п.).
.rar с HLTV открывается как есть: сайт сам распакует его прямо в
браузере и спросит, какие карты разобрать (уже разобранные откроются сразу).
Архив читается по кускам, а распакованное сразу уходит в парсер, поэтому
памяти нужно столько же, сколько для обычной .dem. Архивы с паролем и
многотомные (.part1.rar…) не поддерживаются.api/faceit.js), на GitHub Pages — только открытие
скачанного файла.Сайт — статические файлы; собрать его вручную: python scripts/build_site.py site/
и раздать папку site/ любым статическим сервером (в корне домена или в
подпапке — все пути относительные). Готовые варианты:
Vercel.
— или на vercel.com: Add New → Project → Import этот репозиторий →
Deploy, ничего не меняя: настройки берутся из vercel.json (сборка
scripts/vercel_build.sh → папка dist/, кэширование ассетов). При сборке
Vercel скачивает карты из awpy-data и модель игрока (~1 минута). Дальше каждый
пуш в master публикуется автоматически, а для каждого pull request Vercel
делает отдельную preview-ссылку.
Чтобы на сайте работали ссылки на матчи FACEIT, добавьте ключ: Settings →
Environment Variables → FACEIT_API_KEY (и FACEIT_DOWNLOADS_TOKEN, если FACEIT
выдал отдельный токен), затем Redeploy. Подробнее — «Демки FACEIT».
Если сборка падает с «No entrypoint found» (или «No FastAPI entrypoint
found»), значит, в собираемой ветке нет vercel.json: без него Vercel
принимает репозиторий за сервер на Node.js/FastAPI и ищет app.js/main.py.
vercel.json перекрывает пресет, выбранный в настройках проекта, так что
менять там ничего не нужно — только собирать ветку, где он есть.
GitHub Pages. Собирается при каждом пуше в master (GitHub Actions, см.
.github/workflows/pages.yml). Один раз нужно включить Pages: Settings →
Pages → Build and deployment → Source: GitHub Actions, затем перезапустить
последний запуск «Web version (GitHub Pages)» во вкладке Actions (или
просто сделать следующий пуш).
WebAssembly-парсер лежит в cs2demo/web/vendor/demoparser/;
пересобрать его — wasm/build.sh (нужны Rust с таргетом wasm32-unknown-unknown
и wasm-bindgen-cli 0.2.100).
Нужен Python 3.10+.
Windows: запустите start.bat — он создаст окружение, установит зависимости
и откроет просмотрщик в браузере.
Linux / macOS: ./start.sh
Вручную:
python -m venv .venv
.venv/bin/pip install -r requirements.txt # Windows: .venv\Scripts\pip ...
.venv/bin/python -m playwright install chromium # только для записи клипов на сервере / из CLI
.venv/bin/python -m cs2demo serve --open
Откроется http://127.0.0.1:8000. Перетащите .dem или архив .rar в окно — он разберётся,
и откроется 3D-просмотр. При первом открытии карты её 3D-геометрия и радар
скачиваются из релизов awpy-data
(1–10 МБ на карту) и кешируются в data/maps/, а модель игрока (2 МБ) — в
data/models/. Команда python -m cs2demo maps скачивает всё заранее (для работы
без интернета).
…\Steam\steamapps\common\Counter-Strike Global Offensive\game\csgo\replays\..rar можно открывать как есть — он распакуется сам (в браузере
или, в командной строке, системным unrar / 7-Zip / tar)..dem.zst как есть — распаковывать не нужно.Ссылку на матч (https://www.faceit.com/ru/cs2/room/1-…) можно вставить в поле
«Ссылка на матч FACEIT» в окне «Демки», просто нажать Ctrl+V в любом месте
сайта, или открыть …/?faceit=<ссылка>. В окне есть закладка «CS2 3D ▸»:
перетащите её на панель закладок и нажимайте прямо на странице матча FACEIT.
Из командной строки ссылку принимают все команды:
python -m cs2demo parse https://www.faceit.com/…/room/1-… (и render, pov, …).
Демо скачивается через API FACEIT, поэтому нужен ключ:
FACEIT_API_KEY (для Vercel — в настройках
проекта, для своего сервера — в окружении перед cs2demo serve).FACEIT_DOWNLOADS_TOKEN.FACEIT хранит демо около 30 дней после матча. Ключ остаётся на сервере: браузер
получает от функции api/faceit только временную ссылку на сам файл (а если
хранилище FACEIT не разрешает читать его с чужого сайта — файл идёт через функцию).
Учтите, что опубликованным сайтом с ключом сможет пользоваться любой, у кого есть
ссылка на сайт.
| Клавиша | Действие |
|---|---|
| Пробел | пуск / пауза |
| ← / → | ±5 секунд |
| Shift + ← / → | предыдущий / следующий раунд |
[ / ] | медленнее / быстрее |
| 1 … 6 | камера: свободная, следить, от 1-го лица, из-за спины, сверху, обзор |
| Tab / Shift+Tab | следующий / предыдущий живой игрок |
| M | звук вкл/выкл (громкость — ползунок внизу) |
| K | экранная клавиатура вкл/выкл (или кнопка ⌨ внизу) |
| V | войс: все → команда игрока → только игрок → T → CT → выкл (или список 🎙 внизу) |
| F | от 1-го лица: ускорять раунд после смерти игрока (или кнопка ⏩ внизу) |
Мышь: ЛКМ — вращение, ПКМ — сдвиг, колесо — зум. Клик по игроку в списке — следить за ним. Клик по таймлайну — перемотка. На вкладке «Вид» — срез крыш, ники, игроки сквозь стены, гранаты, трассеры, следы от пуль, тени, детальные материалы, радар на полу, сетка, оружие в руках.
Если в демо записан голосовой чат (демки FACEIT и ESEA, демки, записанные самим
игроком; в GOTV-демках с HLTV его обычно нет), список 🎙 внизу выбирает, кого
слышно: все, команда игрока (за которым следит камера — то, что слышал он
сам), только игрок, только T или только CT, либо выкл. Клавиша V
переключает по кругу. Кто сейчас говорит — видно в левом нижнем углу кадра.
В клипы войс попадает по настройке «Войс» в «Автозаписи клипов» (--voice в
cs2demo render / pov); при замедлении речь не замедляется.
Войс хранится в демо как пакеты Opus (или, в демках до 2024 года, в формате Steam: Opus-кадры с SteamID говорящего); парсер сохраняет их как есть, а браузер декодирует libopus, собранным в WebAssembly, и выравнивает громкость реплик. Пока кто-то говорит, звуки игры приглушаются. Демо, разобранные до появления войса, нужно открыть заново.
Дым — облако вокруг гранаты, которое заполняет пространство, но не проходит сквозь стены (проверяется по геометрии карты), растёт из центра и тает в конце. Пули, пролетающие через дым, оставляют в нём тоннели, которые затягиваются за пару секунд; HE-граната в дыму раздувает большую дыру, которая потом заполняется. Куда попала пуля, в демо не записано, поэтому каждый выстрел трассируется от глаз стрелка по направлению взгляда до стены карты: там остаётся след (за раунд, выключается на вкладке «Вид»), пыль от попадания и конец трассера. Отдача не учитывается — следы ложатся туда, куда смотрел прицел.
Кнопка ⌨ (или клавиша K, или галочка на вкладке «Вид») включает и
выключает экранную клавиатуру: в углу кадра видно, какие клавиши в этот момент
держит выбранный игрок — W A S D, Shift (шаг), Ctrl (присед),
Space, Tab, R, E, F, — и мышь: ЛКМ (стрельба), ПКМ
(прицел), колесо и движение мыши (стрелка показывает, куда и как резко игрок
ведёт прицел). Включённая клавиатура запоминается; в клипы она попадает, если
отметить «Экранная клавиатура в клипе» (или --keys в cs2demo render /
montage).
Клавиши берутся из маски кнопок, которую сервер записывает в демо
(m_nButtonDownMaskPrev). Прокрутка колеса в маску не попадает (нажатие и
отпускание укладываются в один тик), поэтому колесо подсвечивается, когда
игрок оторвался от земли в прыжке, а пробел при этом не был зажат, — это прыжок
с колеса. На про-демках это хорошо видно: у одних игроков все прыжки с
пробела, у других — почти все с колеса.
В веб-версии доступны все клавиши. Python-версия зависит от demoparser2: в
0.42.0 нет Space/Ctrl (и колеса), а Shift в нём не работает вообще (ошибка
в библиотеке, в WebAssembly-сборке исправлена патчем в wasm/build.sh);
недоступные клавиши показываются серыми. Демо, разобранные до появления
клавиатуры, нужно открыть заново.
Модели игроков. По умолчанию — анимированный солдат (idle/walk/run на
скелете Mixamo) из примеров three.js; он скачивается при первом запуске в
data/models/soldier.glb. T и CT отличаются цветом брони и визора. Поверх
анимаций код сгибает ноги в приседе (IK), наклоняет корпус и голову за взглядом,
решает IK рук, чтобы они держали текущее оружие (процедурные модели AK, M4,
AWP, пистолетов, SMG, дробовиков, пулемётов, ножа, гранат, C4, Zeus), а убитые
падают и лежат до конца раунда.
Свою модель можно подложить в data/models/: player_t.glb и player_ct.glb
(для каждой стороны) или player.glb (для обеих). Подойдёт любой риггованный
гуманоид в glTF; со скелетом Mixamo (mixamorig:*) работают прицеливание, присед
и хват оружия. Например, модели агентов CS2 можно экспортировать из своей копии
игры через Source 2 Viewer — в
репозиторий такие файлы класть нельзя, но для себя локально — пожалуйста.
Звуки. Выстрелы, гранаты и бомба синтезируются из акустических моделей
(ударная волна выстрела, сверхзвуковой щелчок пули у винтовок, пороховые газы,
затвор), у каждого звука несколько вариантов, чтобы очередь не звучала как
пулемёт из одинаковых сэмплов. Шаги, попадания, звон шлема, отскоки гранат,
стекло молотова и установка бомбы — настоящие записи
(Kenney Impact Sounds, CC0) в
web/audio/. Всё звучит в одном «помещении»: свёрточная реверберация (тем
больше, чем дальше звук), панорама вокруг слушателя, компрессор; пока кто-то
говорит в войсе, игра приглушается. Шаги и звуки попаданий можно выключить во
вкладке «Вид». Любой звук можно заменить своим: положите файл
.wav/.mp3/.ogg в data/sounds/ с именем из списка: rifle, ak47, m4,
silenced, sniper, auto_sniper, pistol, deagle, smg, shotgun,
lmg, taser, knife, throw, bounce, he, flash, smoke, molotov,
glass, fire_loop, decoy, bomb_beep, bomb_planted, bomb_defused,
c4_explode, step, hit, headshot, helmet.
Иконки килфида — из game-icons.net (CC BY 3.0),
повёрнуты и обрезаны скриптом scripts/build_icons.py.
Раскраска карт: палитры для Mirage, Dust2, Inferno, Nuke, Overpass, Vertigo,
Ancient, Anubis, Train, Cache, Office, Italy (web/js/palettes.js) — цвета стен,
пола, крыш, тип кладки, размер плитки, небо и солнце. Для остальных карт —
нейтральная палитра.
Вкладка «Хайлайты» показывает найденные моменты с очками и тегами. Для каждого можно:
demo_gototick …; spec_player "…"),
чтобы открыть этот момент в самой игре.Отметьте несколько хайлайтов (кнопка «Лучшие 5» отмечает топ) и нажмите
«Записать выбранные». Готовые ролики сохраняются в data/clips/<демо>/ и
появляются на вкладке «Клипы» (просмотр, скачивание, удаление).
«Рендер на сервере» делает то же самое в фоновом headless-браузере — можно
закрыть вкладку. Нужен Playwright (python -m playwright install chromium).
Панель «POV игрока» на вкладке «Хайлайты»: выберите игрока, раунды и что делать после его смерти. ▶ Смотреть POV включает вид от первого лица с ускорением; ● Записать POV пишет всё в один MP4:
Звук пишется по раундам, а длинные видео — потоком в файл, поэтому даже POV
целого матча не держится в памяти целиком. То же из командной строки —
cs2demo pov (см. ниже) или кнопка «Рендер на сервере».
Вкладка «Смоки» показывает все смоки демо: куда упал (место на карте), откуда брошен, как — джампсроу, разбег + прыжок, с бега, шагом, присев, стоя — и какой кнопкой (ЛКМ — далеко, ПКМ — под себя, ЛКМ+ПКМ — средне), дальность, время до раскрытия, видел ли игрок точку (вслепую — бросок через стены). Одинаковые броски из разных раундов (или обеими командами) собираются в один лайнап «×N». Интересные лайнапы — дальние броски по точке: вслепую, в прыжке, повторённые — помечаются автоматически и идут первыми (фильтр «только лайнапы» / «все смоки», а также по стороне, месту, типу броска и игроку).
setpos x y z; setang pitch yaw 0 — встать туда, откуда
брошен смок, на своём сервере (sv_cheats 1). Для джампсроу — точка, где игрок
оттолкнулся.Из командной строки: cs2demo smokes match.dem --list и
cs2demo smokes match.dem --top 5 (или --ids из списка).
python -m cs2demo montage берёт одно или несколько демо, выбирает лучшие
моменты по очкам (--top 10), рендерит их и склеивает в один MP4: титульная
карточка с названиями матчей, обратный отсчёт «#10 → #1» (лучший момент в
конце), команды и раунд в углу кадра, плавные переходы, звук. Клатч 1v5
автоматически получает максимум очков; --include clutch1v5,ace гарантирует,
что такие моменты попадут в нарезку, --per-demo 3 ограничивает число моментов
из одного матча, --jobs 2 рендерит два клипа параллельно. Готовый файл — в
data/clips/montages/. Если прервать рендер и запустить ту же команду снова,
уже готовые клипы с теми же настройками не пересчитываются.
В веб-интерфейсе: вкладка «Клипы» → отметьте готовые клипы в нужном порядке → «Склеить в нарезку».
Про-демо скачиваются со страницы матча на HLTV
(кнопка GOTV Demo, архив .rar с .dem каждой карты).
Как считаются очки: база за число киллов (2K — 22, 3K — 45, 4K — 70, ACE — 100),
python -m cs2demo serve [--port 8000] [--host 127.0.0.1] [--open]
python -m cs2demo parse match.dem # разобрать (можно несколько файлов)
python -m cs2demo parse match.rar # архив HLTV: распакует и разберёт все карты
python -m cs2demo list # разобранные демо
python -m cs2demo highlights match.dem --top 10 # найденные хайлайты (--json, --player, --min-score)
python -m cs2demo render match.dem --top 5 --pov first --res 1920x1080 --fps 60 --slowmo
python -m cs2demo render <id> --clips r05-player-3k,r12-player-clutch1v3
python -m cs2demo watch "C:\...\game\csgo\replays" --render --top 5 # автозапись новых матчей
python -m cs2demo montage match1.dem match2.dem --top 10 --slowmo --include clutch1v5 # нарезка в один MP4
python -m cs2demo pov match.dem --player s1mple --rounds 1-12 --ff 8 --voice team # POV игрока в один MP4
python -m cs2demo smokes match.dem --list # лайнапы смоков (* — интересные)
python -m cs2demo smokes match.dem --top 5 # повторы лучших лайнапов в MP4 (или --ids a,b)
python -m cs2demo maps de_mirage de_inferno # заранее скачать карты (без аргументов — все)
render и watch --render рисуют каждый кадр отдельно (без пропусков) и
кодируют H.264 + AAC через ffmpeg (ставится вместе с пакетом imageio-ffmpeg).
Опции: --no-sound, --no-hud, --keys, --voice all|team|player|T|CT|off,
--quality auto|low|high; у pov — --rounds 1-12 или 3,5,7-9 (по умолчанию все)
и --ff 4|8|16 (ускорение после смерти, 0 — вырезать остаток раунда). Headless-браузер
использует видеокарту, если она доступна; без неё рендер идёт на процессоре
(SwiftShader, ~1 с на кадр 720p), и в режиме auto карта рисуется упрощёнными
материалами — --quality high включает полные.
Архивы .rar принимают все команды (parse, highlights, render, montage,
watch следит и за ними): из архива берутся все .dem. Для распаковки нужен
один из: unrar, 7-Zip (7z/7zz), bsdtar (в Windows 10+ и macOS он
встроен как tar), unar или Node.js — тогда работает тот же WebAssembly-UnRAR,
что и в браузере.
Переменные окружения:
| Переменная | Назначение |
|---|---|
CS2DEMO_DATA | папка данных (по умолчанию ./data) |
CS2DEMO_RENDER_GPU=0 | принудительно рендерить headless на процессоре (SwiftShader) |
CS2DEMO_CHROMIUM | путь к своему Chrome/Chromium для headless-рендера |
CS2DEMO_MAPDATA_VERSION | зафиксировать версию релиза awpy-data |
FACEIT_API_KEY | ключ FACEIT API для скачивания демо по ссылке на матч |
FACEIT_DOWNLOADS_TOKEN | токен Downloads API, если FACEIT выдал его отдельно от ключа |
cs2demo/
parser.py .dem → meta.json (игроки, раунды, события, хайлайты) + frames.bin
highlights.py поиск и оценка хайлайтов (работает только по meta.json)
maps.py загрузка геометрии/радаров карт из awpy-data (HTTP Range: только нужная карта)
server.py FastAPI: библиотека демо, данные, карты, клипы, фоновый рендер
recorder.py headless-рендер клипов: Chromium (Playwright) → JPEG-кадры → ffmpeg → MP4
montage.py нарезка: выбор лучших моментов нескольких демо, рендер, склейка
cli.py команды serve / parse / list / highlights / render / pov / smokes / watch / maps
archives.py .rar: распаковка системным unrar / 7-Zip / bsdtar / unar или Node.js (unrar_cli.mjs); .dem.zst / .dem.gz
faceit.py демо по ссылке на матч FACEIT (Data API → Downloads API → .dem.zst)
models.py модель игрока: загрузка по умолчанию и пользовательские замены
web/ просмотрщик (Three.js, без сборки)
js/backend.js откуда данные: сервер (/api) или браузер (IndexedDB, статические ассеты)
js/parse/ парсер в браузере: порт parser.py и highlights.py, распаковка .rar, Web Worker
vendor/demoparser/ demoparser2 в WebAssembly (собирается wasm/build.sh)
vendor/unrar/ UnRAR в WebAssembly (node-unrar-js)
vendor/mediabunny/ запись MP4 и AAC-кодер (FFmpeg в WebAssembly) для клипов
vendor/opus/ декодер Opus (libopus в WebAssembly) для войса
vendor/fzstd/ распаковка .dem.zst (FACEIT) в браузере
js/faceit.js скачивание по ссылке FACEIT: через сервер или функцию Vercel
js/viewer.js сцена, камеры, воспроизведение
js/map.js меш карты, процедурная раскраска, тени, небо
js/palettes.js палитры карт
js/skinned.js анимированные модели игроков, IK рук и ног, viewmodel
js/weapons.js процедурные модели оружия
js/audio.js звуки (синтез + записи web/audio/), позиционирование, эхо, звуковая дорожка клипов
js/lineups.js смоки: откуда и как брошены, куда упали, оценка лайнапов
js/smokes.js вкладка «Смоки»: камера гранаты, повтор и запись лайнапов
js/voice.js войс игроков: реплики, фильтр по командам, декодирование Opus
js/smoke.js объёмные дымы: заполнение без прохода сквозь стены, дыры от пуль и HE
js/bullets.js куда попал каждый выстрел (трассеры, следы, дыры в дыму)
js/raycast.js трассировка лучей по мешу карты (сетка + 2D DDA)
js/pov.js POV игрока: план по раундам, ускорение после смерти, запись
js/icons.js иконки килфида (генерируется scripts/build_icons.py)
js/clips.js режиссёр клипа, экспорт MP4 (WebCodecs + Mediabunny, AAC) / MediaRecorder, API для headless-рендера
scripts/build_icons.py сборка icons.js из game-icons
scripts/build_site.py сборка веб-версии (GitHub Pages)
wasm/ Rust-обёртка demoparser2 для WebAssembly
api/faceit.js функция Vercel: ссылка на матч FACEIT → ссылка на демо (ключ API остаётся на сервере)
frames.bin хранит состояние каждого игрока каждые 2 тика (32 Гц):
float32 xyz, int16 yaw/pitch, uint8 hp/броня/флаги/оружие/присед/место,
uint16 деньги, uint16 зажатые клавиши; браузер интерполирует между кадрами. Ещё два
раздела — войс: uint32 тик/игрок/длина на каждый пакет и сами пакеты Opus. Сжатый
gzip-ом файл для полного матча — 1–5 МБ (с войсом FACEIT — больше).
pip install pytest httpx
python -m pytest
Тесты парсера на реальном демо запускаются, если положить .dem в
tests/fixtures/ или указать путь в CS2DEMO_TEST_DEMO.
Код проекта — MIT. Сторонние материалы перечислены в THIRD_PARTY.md: three.js (MIT), Mediabunny (MPL-2.0) с AAC-кодером из FFmpeg (LGPL-2.1+), иконки game-icons.net (CC BY 3.0), demoparser2 в WebAssembly (MIT), UnRAR в WebAssembly (node-unrar-js — MIT, UnRAR — лицензия UnRAR, freeware). Геометрия карт и радары (собственность Valve) и модель игрока не входят в репозиторий — они скачиваются на ваш компьютер при первом запуске, а для веб-версии — при сборке сайта. Проект не связан с Valve.