gmod-rs/docs/PROBLEMS.md

9.1 KiB
Raw Blame History

Реестр проблем: болячки 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:
    1. Состояния: Static → Sleeping → Dynamic → Impostor → Skipped (обратимо).
    2. Screen-space importance: pixels ≈ r / dist · (h / 2·tan(fov/2)). Пороги (черновые): skip < 1–2 px, impostor < 8 px, low-LOD < 24 px.
    3. Инстансинг одинаковых моделей (indirect draw); merge спящих физикой пропов в статические батчи (пробуждение возвращает в dynamic).
    4. Animation LOD: 60/20/0 Гц + фриз костей; критерии: дистанция, в кадре ли, движение, свежесть сетевых апдейтов, взаимодействие.
    5. Physics hibernation: island sleep + принудительная заморозка дальних островов; пробуждение по сети/подходу/взаимодействию; Jolt на worker-пулах.
    6. Авто-импосторы с дисковым кэшем для дальних мелких пропов.
    7. Сеть под шторм: интернирование, пул сущностей без аллокаций, параллельный дельта-декод.
    8. Совместимость: куллинг не трогает существование сущностей и 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 добавляется в чёрный список следующего запуска.
  • Этап: 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.
  • Этап: по мере появления соответствующих систем.