# Архитектура Source RS ## 1. Workspace ``` crates/ tier — tracing-логи, конвары, CommandLine, конфиг, время, пулы, interning math — Vector/Angle (Source-семантика углов), Matrix, Quaternion, AABB, plane fs — поисковые пути и порядок монтирования: dir, VPK v1/v2, GMA, BSP pakfile, mount.cfg, mmap, кэш индексов (rkyv) formats — kv (KeyValues), bsp, vtf, vmt, mdl (+vvd/vtx/anim), pcf, phy, snd, demo net — netchan (UDP, фрагментация, bz2), dt (send/recv tables), stringtable, usermessages, GMod-расширения, мост к Steam engine — мир, entity-стор (архетипы/пулы), интерполяция, prediction, usercmd, interest-система (классификация, важность, бюджеты) render — wgpu: device/swapchain, HDR-таргет, material system (compat-семантика + современный shading), шейдеры, инстансинг, RT-менеджер, post, pipeline cache studio — StudioRender: mdl-инстансы, кости, blend-граф, IK, procedural bones, flex, LOD, аттачменты physics — Jolt (C-API + свой безопасный слой), hibernation, prediction-мир, рагдоллы audio — kira (микс) + symphonia (декод), пространственность, звуковые скрипты ui — нативный UI: меню, консоль, шрифты, HUD-рамка, загрузочные экраны lua — mlua (vendored LuaJIT), sandbox, рельсы API, мосты к engine/render/studio steam — фичи steamworks-rs (тикет, UGC/workshop), отдельный steam-поток client — бинарь `gmod-rs` и библиотека: сборка всего, главный цикл, конфиг, CLI; на Android — cdylib с `SDL_main` (см. `ANDROID.md`) ``` ### Правило зависимостей Строго «вниз по списку»: ``` tier, math → fs, formats → net → engine → render, studio, physics, audio, ui → lua → client ``` - `lua` и `client` вправе зависеть от всего (lua — движковый API, client — композиция). - Обратные зависимости запрещены; `render` может зависеть от `studio` (модели), `engine` — от `net` (типы снапшотов), но не наоборот. ## 2. Технологический стек и почему | Задача | Выбор | Почему | |---|---|---| | GPU | **wgpu** (Vulkan на Linux) | Современные фичи, кроссплатформенность, pipeline cache, compute | | Окно/ввод | **SDL3** (при проблемах — winit) | Геймпады, IME, зрелость, кроссплатформенность | | Физика | **Jolt** через C-API | Де-факто замена VPhysics в современных Source-подобных; job-friendly | | Lua | **mlua + vendored LuaJIT** | Семантика 5.1 как в GMod + производительность | | Звук | **kira** + **symphonia** | Гибкий микс + декод mp3/ogg/wav | | Steam | **steamworks-rs** | Тикет, UGC/workshop, браузер позже | | Форматы | Свои парсеры + `bzip2`, LZMA (raw LZMA1) | Полный контроль, bounded, fuzzable | | Кэши | `rkyv`/`bincode`, mmap (`memmap2`) | Быстрый старт, индекс VPK, обработанные ассеты | | Логи | `tracing` | Каналы, фильтры, интеграция с dev-тулингом | | Ошибки | `thiserror` (крейты) + `anyhow` (границы приложения) | Явные типы, удобный верхний уровень | ## 3. Подсистемы ### 3.1 FileSystem (`fs`) Порядок монтирования (уточняется в M1 по поведению GMod): ``` platform → sourceengine (hl2-база) → garrysmod_*.vpk → garrysmod/addons/* → workshop (по списку сервера, через Steam) → download-кэш (lua/контент с сервера) → BSP pakfile (мапа) → write-пути (наш конфиг/cache) ``` - `mount.cfg` пользователя учитывается (`~/gmod_server/server/garrysmod/cfg/mount.cfg`). - Все открытия — через единый интерфейс с нормализованными путями (защита от traversal). - Индекс VPK кэшируется на диск (content-hash + версия парсера). ### 3.2 Сеть (`net`) Конвейер: ``` UDP → netchan (сборка фрагментов, bz2) → потоки сообщений → signon/delta-декод → очередь «снапшот готов» → применение на главном потоке (тик интерполяции) ``` - Никаких блокировок в горячих путях: net-поток кладёт пакеты в lock-free очередь, декод — в worker-пулах, применение — двойная буферизация. - Все ограничения входных данных — явные (размеры строк/массивов, глубина, количество энтити). - Dump/replay: `net` умеет писать/читать сырые потоки с метаданными (см. `NETWORK.md`). ### 3.3 Entity-система (`engine`) - Хранение — архетипами/пулами (SoA-ish), стабильные ID, без аллокаций на сущность в кадре. - Клиентские энтити — прокси для рендера/физики; Lua-фасад создаётся лениво, только если аддоны реально трогают сущность. - Интерполяция: буфер из 2–3 снапшотов, рендер с задержкой (как в Source MP). - Prediction: локальный игрок (movement по SDK), usercmd, реконсиляция. ### 3.4 Interest & Visibility (`engine` + `render`) «Принцип сандбокс-масштаба» (детали — `PROBLEMS.md` §P2): - Состояния: `Static → Sleeping → Dynamic → Impostor → Skipped` (обратимо). - Важность: экранный размер, дистанция, движение, свежесть сети, взаимодействие. - Бюджеты: анимации (60/20/0 Гц), скиннинг, тени, партиклы, обновление костей. - Инстансинг повторяющихся моделей; merge спящих пропов в статические батчи. - Куллинг: PVS + frustum + octree, многопоточно; fallback без PVS. - **Правило совместимости:** куллинг не влияет на существование сущностей и на Lua-draw (PAC3/Starfall/HUD видят всё; у них свои бюджеты). ### 3.5 Рендер (`render`) Два слоя: 1. **Compat-семантика** — точный render state и поведение материалов Source: render modes (`$additive`, `$translucent`, `$alphatest`), RT, lightwarps, cubemaps, eyes, skinning, decals, halos. Контракт: аддоны не должны отличать нашу картинку от GMod. 2. **Современный shading** — HDR-конвейер (RGBA16F), линейное освещение, tonemap, bloom, SSAO, SMAA (TAA опцией), SSR воды, динамические тени моделей (опцией), анизотропия. Прочее: pipeline cache на диске; параллельная запись команд; shadow/RT-бюджеты; texture streaming и VRAM-бюджет (с M9). Шейдеры по приоритету: LightmappedGeneric → VertexLitGeneric → UnlitGeneric → вода → спрайты → декали/эффекты → прочее. Аддонские DXBC — вне первой фазы. ### 3.6 StudioRender (`studio`) - Загрузка: MDL/VVD/VTX/ANIM, `$keyvalues`, bodygroups, аттачменты. - Анимация: blend-граф (секвенции/жесты/activity layers), IK, procedural bones (`$bonefollowers`), flex/eyeballs. - LOD: по важности; GPU-скиннинг в storage buffers; фриз костей для дальних. - Ragdoll-позы + клиентская физика (Jolt). ### 3.7 Потоки и конкурентность - **Main** — ввод, применение снапшотов, Lua (как в GMod), запись кадра. - **Pool** — куллинг, скиннинг-подготовка, декод ассетов, копирование данных на GPU. - **Net** — сокет и netchan; декод в отдельных worker'ах. - **Physics** — Jolt jobs (многоядерно), hibernation дальних островов. - **Steam** — отдельный поток: Steam API не потокобезопасен, все вызовы там; наружу — каналы. - **Lua** — главный поток (как в GMod); тяжёлые вычисления — только через явные API; watchdog следит за зависаниями. ### 3.8 Ассет-пайплайн и кэши Каталог кэша (по умолчанию `~/.cache/source-rs`, настраивается): | Кэш | Содержимое | Инвалидция | |---|---|---| | `vpk-index/` | Индексы VPK/GMA | content-hash + версия парсера | | `textures/` | Обработанные текстурные блобы+mips | хэш исходника + версия | | `meshes/` | Готовые vertex/index-буферы, импосторы | хэш + версия | | `pipelines/` | wgpu pipeline cache | версия драйвера/шейдеров | | `lua-bc/` | Байткод LuaJIT (опц.) | хэш + версия LuaJIT | | `downloads/` | Файлы, скачанные с серверов | хэш (вечный кэш) | Цель: второй и последующие запуски — секунды; серверные файлы не качаются повторно. ### 3.9 Конфигурация - `~/.config/source-rs/config.toml` (или `--config`): корни ассетов, каталог кэша, серверы, фичи. - Авто-детект ассетов: (1) явный путь; (2) `~/gmod_server/server`; (3) Steam common. - Внутриигровые настройки — конвары (как в Source), сохраняются в `cfg/`. ### 3.10 Android - Тот же клиент собирается как `cdylib` и грузится штатной `SDLActivity` из SDL3; экспорт — `SDL_main`. Сборка APK — `android/build.sh` (aapt2 + d8, без Gradle), debug-подпись. - Целевые ABI: `arm64-v8a` (телефон) и `x86_64` (эмулятор). `minSdk 31`, `targetSdk 35`, фиксированный ландшафт. - `target.'cfg(target_os = "android")'`: без `steamworks`, Lua 5.4 вместо LuaJIT; логирование в logcat. - Ассеты — во внешнем каталоге приложения; касания (`FingerDown/Motion/Up`) переведены в те же `wish_forward/right`, прыжок и присед, что клавиатура. - Детали и ограничения — `docs/ANDROID.md`, команды установки — `android/README.md`. ## 4. Конвенции кода 1. `unwrap/expect/panic` запрещены в путях обработки внешних данных (сеть/диск/Lua). Для внутренних инвариантов — `debug_assert` и явные ошибки. 2. FFI-границы (Jolt, Steam, Lua) оборачиваются в безопасные слои; все входы проверяются. 3. `catch_unwind` — на границах Lua/FFI/worker; паника одного аддона/задачи не убивает клиент. 4. Без `unsafe` вне FFI-обёрток; FFI-крейты изолированы. 5. Горячие пути — без аллокаций; interning строк; пулы. 6. Ошибки — типизированные (`thiserror`) в крейтах, `anyhow` на верхнем уровне. 7. Тесты — рядом с кодом; fuzz-таргеты для всех парсеров; бенчмарки для hot paths. ## 5. Бюджеты производительности (ориентиры для M9) | Стадия | Бюджет (мс/кадр, RTX 3060, стресс-сцена) | |---|---| | Сеть/декод (не main) | ≤ 2 | | Применение снапшотов | ≤ 1 | | Interest/куллинг | ≤ 1 | | Анимации (подготовка) | ≤ 2 | | Запись рендер-команд | ≤ 3 | | Main total | ≤ 8 (цель 60+ FPS со запасом) | ## 6. Схема кадра (упрощённо) ``` Input → Usercmd → Prediction(local) Net queue → Snapshot apply → Entities → Interp states Interest/Visibility → cull → instancing/static batches → anim LOD → render graph → present Lua: Frame → HUD/Paint → Render hooks (в порядке как в GMod; sandbox) Physics (client-side) → интерполяция/рагдоллы ```