9.1 KiB
9.1 KiB
Реестр проблем: болячки GMod/Source и что с ними делаем
Формат: симптом → почему так у Source/GMod → решение → этап.
P1. Нет анимаций игроков (пробел Source.NET)
- Симптом: модели видны, но статичны (замечено в Source.NET на ClassicBox).
- Почему: нет реализованного studio-анимационного стека.
- Решение: полный StudioRender (M5): VVD/VTX/ANIM, blend-граф,
$sequence, activity layers/gestures, IK, procedural bones ($bonefollowers), flex/eyeballs, аттачменты, GPU-скиннинг, animation LOD. - Этап: M5.
P2. Сандбокс-масштаб: кучи пропов, энтити, констрейнов ⭐
- Симптом: 2000+ пропов, кучи констрейнов и аддоновых сущностей превращают клиент в слайдшоу; открытые карты (gm_mobenix и подобные) — худший случай.
- Почему Source «не задумывался»:
- draw call на каждый проп — без инстансинга/батчинга;
- PVS — единственный механизм видимости; нет LOD от экранного размера;
- нет animation LOD: все скелеты обновляются, пока модель в кадре;
- клиентская физика тикает независимо от близости игрока;
- один поток на запись рендера;
- констрейны = шторм сетевых сущностей + аллокации + ребилд ропов.
- Принцип сандбокс-масштаба (подтверждён пользователем):
Мелкое и далёкое можно вообще не рисовать. Дефолты агрессивные, всё регулируется конварами.
- Решение — Interest & Visibility subsystem:
- Состояния:
Static → Sleeping → Dynamic → Impostor → Skipped(обратимо). - Screen-space importance:
pixels ≈ r / dist · (h / 2·tan(fov/2)). Пороги (черновые): skip < 1–2 px, impostor < 8 px, low-LOD < 24 px. - Инстансинг одинаковых моделей (indirect draw); merge спящих физикой пропов в статические батчи (пробуждение возвращает в dynamic).
- Animation LOD: 60/20/0 Гц + фриз костей; критерии: дистанция, в кадре ли, движение, свежесть сетевых апдейтов, взаимодействие.
- Physics hibernation: island sleep + принудительная заморозка дальних островов; пробуждение по сети/подходу/взаимодействию; Jolt на worker-пулах.
- Авто-импосторы с дисковым кэшем для дальних мелких пропов.
- Сеть под шторм: интернирование, пул сущностей без аллокаций, параллельный дельта-декод.
- Совместимость: куллинг не трогает существование сущностей и Lua-draw (PAC3/Starfall/HUD получают всё; у их рисования свои бюджеты).
- Состояния:
- Черновые конвары:
r_imp_minscreen,r_imp_impostor_screen,r_imp_lod_screen,r_animlod_hz/r_animlod_dist,phys_hibernate_dist/phys_hibernate_delay,r_nopvs_maxdist(для карт без PVS). - Этапы: M3 (каркас) → M4 (стресс-полигон) → M5 (anim LOD, статик-батчи) → M6 (hibernation) → M9 (импосторы-кэш, тюнинг).
- Вне нашей власти (клиент): серверный CPU от констрейнов и серверного Lua, серверный сетевой бюджет. У нас «констрейны» — это сеть/декод/визуал.
P3. Долгий заход в игру и на сервер
- Симптом: GMod грузит аддоны и контент минутами; вход на сервер — минуты (UDP-скачивание Lua/карты даже при наличии контента локально).
- Решение:
- параллельная LZMA-декомпрессия и запись в постоянный download-кэш;
- приоритет локального контента: workshop/аддоны, что уже есть, не качаем;
- стриминг-парсинг BSP по мере прихода;
- фоновый precache ассетов во время коннекта (загрузочный экран без чёрного экрана);
- быстрый старт меню: ленивое монтирование и фоновый warmup в игре.
- Этап: M2/M4/M9.
P4. Шейдерные стуттеры и подгрузки на ходу
- Почему: компиляция шейдеров в рантайме; синхронный декод текстур/моделей; отсутствие streaming.
- Решение: wgpu pipeline cache + прогрев; асинхронный декод в worker-пулах; VRAM-бюджет и деградация; дисковый кэш обработанных ассетов; mip-стриминг.
- Этап: M3/M9.
P5. 32-битность, OOM и лимиты
- Почему: исторически 32-битный клиент (есть 64-битная бета).
- Решение: сразу x86_64; собственные лимиты по бюджету RAM/VRAM с деградацией (скип/импостор/уменьшение качества), а не падение.
- Этап: архитектурно с M0.
P6. Однопоточный рендер
- Решение: параллельная запись команд, worker-пулы (куллинг/декод/скиннинг), многопоточная физика Jolt.
- Этап: M3/M6.
P7. PVS-only и дырявые открытые карты
- Симптом: карты с плохим/отсутствующим PVS рендерят всё.
- Решение: PVS + frustum + octree + screen-size пороги; fallback по дистанции
для плохих PVS (
r_nopvs_maxdist). - Этап: M3.
P8. Краши от злоумышленников (Starfall/PAC3) и кривых данных
- Векторы: бесконечные/вложенные циклы Lua, OOM Lua, гигантские RT/меши/материалы, path traversal при загрузке файлов, битые снапшоты, огромные строки.
- Решение:
- Lua-sandbox: лимит памяти, instruction-watchdog, запрет
io/os/ffi/debug, изоляция ошибок, лимиты на таймеры/RT/меши; - защита путей как требования gluasteal (никаких
.., абсолютных путей, NaN); - bounded-парсеры + fuzz; никаких
unwrapна внешних данных; catch_unwindна границах; краш одного аддона не убивает клиент;- safe mode: пометка «загружался файл X» → при нечистом завершении X добавляется в чёрный список следующего запуска.
- Lua-sandbox: лимит памяти, instruction-watchdog, запрет
- Этап: cross-cutting; ядро — M7; PAC3/Starfall — M8.
P9. Качество картинки (HDR/AA/вода/тени)
- Решение: HDR-конвейер (RGBA16F, tonemap, bloom), SMAA (TAA опцией), SSAO, анизотропия 16x, SSR воды, динамические тени моделей/игроков (опция), корректные color-space и alpha.
- Контракт: семантика материалов Source (
$additive, RT, lightwarps, alpha) не меняется — иначе аддоны визуально ломаются. - Этап: M3; тюнинг дефолтов — M9.
P10. VGUI тяжёлый и медленный
- Решение: нативный UI-слой (меню/консоль/HUD-рамка) на Rust; Derma — совместимый слой поверх быстрого бэкенда; шрифты TTF вместо медленного VGUI-пути.
- Этап: M7/M8.
P11. UX-мелочи
- Быстрый старт без чёрного экрана; информативный загрузочный экран; реконнект без перезапуска; стабильные alt-tab и курсор; громкость/аудио-устройства; консольные команды как в Source.
- Этап: по мере появления соответствующих систем.