Q2PRO-X 1.0 — Техническое руководство
Просмотр документа на сайте Q2PRO-X. Оригинальный файл можно скачать из окна сайта.
- Релиз 1.0 фиксирует финальную архитектуру modern cvar browser и overlay UX wave.
- Browser-local EN+RU font pipeline, UTF-8 wrap, detail scroll и browser-local scale завершены.
- Добавлены settings-gear переходы с tracked return flow обратно в исходный оверлей.
- LAGHAX HUD получил собственную alpha-модель и read-only runtime snapshot weapon predict.
- Data-layer 1.0 теперь явно включает q2pro-x.menu2 и q2prox_cvar_font.png как обязательные runtime-ресурсы.
- Server-authority по weapon predict сохранена: новая диагностика не меняет gameplay logic.
Архитектурные обновления релиза 1.0 относительно beta 0.99
- Modern cvar browser: переход от ASCII/console-style path к browser-local font/layout с единым EN+RU atlas и корректным UTF-8 wrap.
- Browser chrome переведён на runtime metrics от cl_cvar_browser_scale; текст и text-driven chrome больше не наезжают на кнопки и собственные границы.
- Overlay settings buttons теперь открывают menu flow с return-командой, а не просто выбрасывают пользователя в оторванное состояние UI.
- LAGHAX HUD использует отдельный global alpha cvar и новый snapshot API Ghost_GetRuntimeStats() для read-only runtime diagnostics.
- Release 1.0 закрепляет обязательный data-layer: q2pro-x.menu, q2pro-x.menu2, q2pro.modhelp, q2prox_cvar_font.png.
Обновления релиза 1.0 (архитектура)
Modern Cvar Browser: final UI architecture
Главный архитектурный итог 1.0 — modern cvar browser перестал быть надстройкой над legacy console-text path и получил собственный browser-local рендер текста, независимые метрики и отдельный font atlas для EN+RU.
Это позволило одновременно решить проблемы качества кириллицы, UTF-8 wrap/layout, внутренних scroll/clipping правил и user-facing scale control без влияния на общий HUD проекта.
Browser-local alpha теперь считается отдельно от scr_alpha, что делает поведение справочника cvar независимым и объяснимым на уровне UI-политики.
Overlay settings return flow
Шестерёнки в новых оверлеях реализуют tracked menu flow. При переходе в настройки клиент сохраняет источник вызова и при закрытии меню возвращает пользователя ровно в тот оверлей, из которого тот пришёл.
Это устраняет UX-разрыв между overlay-layer и menu-layer и делает настройки оверлеев частью единой пользовательской модели.
LAGHAX HUD: separate alpha + runtime snapshot
Добавление cl_laghax_hud_alpha отделило laghax HUD от общей alpha-политики scr_alpha. Итоговая прозрачность теперь следует модели modern overlays: собственный cvar × OLED UI alpha.
Новый runtime-блок weapon predict реализован как read-only snapshot API. screen.c не читает внутренние поля ghost.c напрямую; ответственность за сериализацию runtime-state остаётся внутри ghost.c.
Packaging layer for 1.0
Релиз 1.0 окончательно закрепляет правило additive-layer packaging. Клиентский пакет ship'ит только собственные бинарники, runtime-библиотеки и минимальный Q2PRO-X data-layer.
Новая обязательная часть этого data-layer — q2pro-x.menu2 и browser-local font atlas q2prox_cvar_font.png. Generated-конфиги пользователя в пакет не входят.
Multiplayer fairness note
Состояние 1.0 сохраняет server-authority по weapon predict: сервер остаётся источником истины для скорострельности, ammo, projectile spawn и damage. Runtime diagnostics LAGHAX HUD ничего не меняют в timing или боевой логике.
- Q2PRO-X 1.0
- Техническое руководство
Главный автор проекта, инициатор ключевых идей и основной тестировщик: ly
Тестирование: Quake II community
Документ актуализирован для релиза 1.0; новые разделы в конце фиксируют архитектурные изменения относительно beta 0.99.
Оглавление
2. Packaging и release philosophy 4
3. Menu overlay architecture 4
4. Config architecture: split by ownership and scope 4
5. Movement, predict и feel-совместимость 5
6. Weapon predict architecture 6
7. Laghax internals 6
8. Renderer architecture 6
8.1. win32egl and desktop fullscreen 6
8.2. Internal render scale paths 6
8.3. Visual FX stack 7
9. Modern server browser 7
10. Visibility/highlighting architecture 7
11. Sound architecture 8
11.1. OpenAL profiles, reverb and routing 8
11.2. Resamplers and high-precision output 8
11.3. Binaural layer and OpenAL Soft 8
12. Mod command overlay internals 8
13. Restart policy and live-apply policy 8
14. Known limitations и честные ограничения 9
15. Донорская карта проекта 9
16. 0.96: 4:3 pillarbox, resolution picker и fullscreen semantics 11
16.1. Практическая логика режимов 11
16.2. Почему это важно для beta/release layer 11
17. 0.97: OLED protection architecture 12
18. 0.97: weapon prediction follow-up and accepted limitations 12
19. 0.97: laghax HUD as a live diagnostic surface 12
20. 0.97: step smoothing lift jitter fix 13
16. Архитектурные обновления beta 0.98 относительно 0.97 13
16.1. Display mode state: windowed / desktop / exclusive 13
16.2. Runtime audio gain вместо грубого mute-переключателя 14
16.3. Предикт оружия: новая стабилизированная архитектура 14
16.4. Переключение оружия и непрерывная стрельба: почему это теперь работает лучше 15
16.5. HyperBlaster и rockets: точное сопоставление вместо грубого suppression 15
16.6. Laghax: starvation detector hardening 15
16.7. Server Browser Favorites: composite persistence model 16
16.8. UI correctness: single-predicate visibility for Favorites action 16
1. Роль Q2PRO-X относительно исходного Q2PRO
Q2PRO-X — это не просто форк с набором случайных патчей. Архитектурно это layered client build: базовая совместимость и поведение Q2PRO сохраняются, а новые функции добавляются как контролируемые user-facing слои поверх исходной базы.
- Базовая кодовая база: Q2PRO r3832.
- Новые системы по возможности живут отдельно, а не ломают старый путь насильно.
- Почти всё новое экспонируется через cvar и меню, а не скрытые магические переключатели.
- Приоритет у воспроизводимого поведения и у честной диагностики requested/applied состояния.
2. Packaging и release philosophy
Бета-пакет intentionally собирается как additive release layer. Это важно не только для удобства тестеров, но и для корректной архитектуры распространения: Q2PRO-X не должен зависеть от того, какое именно q2pro.menu или какие пользовательские cfg лежат у человека в baseq2.
3. Menu overlay architecture
Q2PRO-X menu architecture основана на отдельном q2pro-x.menu и inject-блоках. Это ключевое решение: клиент получает модульность меню и перестаёт зависеть от прямой правки пользовательского q2pro.menu.
- q2pro.menu грузится первым как base menu tree.
- Дополнительные menu overlays загружаются после него.
- Inject с parent/order semantics добавляет entry в существующий parent menu.
- Для одинаковых parent/order порядок должен быть детерминированным.
Практический вывод: Q2PRO-X можно распространять без перезаписи чужого q2pro.menu, что особенно важно для тестовых групп с уже настроенной средой.
4. Config architecture: split by ownership and scope
Конфиги Q2PRO-X намеренно отделены от обычного config.cfg. Более того, они разделены на global и mod-local scopes. Это избавляет от проблемы, когда пользователь настраивает клиент под себя, а потом теряет эти настройки при переключении на другой mod.
- Mod-local config не может перебивать global-owned cvars.
- При попытке ручного override клиент пишет точный warning с путём offending файла.
- Autosave, save и defaults обязаны уважать scope отдельно.
- Bind ownership split так же важен, как и cvar ownership split.
5. Movement, predict и feel-совместимость
В Q2PRO-X важно различать физику, client prediction backend, scheduler и purely local camera feel. Эти вещи тесно связаны в ощущениях игрока, но архитектурно их надо разделять.
Такое расщепление позволяет комбинировать старый feel предикта с современным fixedmove и отдельно выбирать R1Q2-like сглаживание ступенек, не скатываясь в один giant legacy mode.
Отдельно здесь живёт cl_movement_feel_mode. Это не ещё один predict backend, а именно command-timing / scheduler feel selector: 0 = current q2pro path, 1 = r1q2-like path.
- Важно не смешивать его с cl_predict_move_mode. predict backend отвечает за клиентское предсказание движения, а movement feel mode — за applied cadence формирования movement command.
- r1q2-like mode intentionally bypasses cl_fixedmove subdivision и возвращает classic monolithic phys_frame cadence. Именно поэтому в UI честно сказано, что fixed move в этом режиме ignored как feel-defining scheduler.
- При этом step smoothing остаётся независимым axis. Пользователь может выбрать q2pro / r1q2-like movement feel и отдельно добавить один из R1Q2-style вариантов сглаживания ступенек, если ему нравится именно такая комбинация.
Архитектурно это и было целью: не делать giant switch "become old client", а разнести predict backend, scheduler feel и camera smoothing на отдельные управляемые слои.
6. Weapon predict architecture
Weapon predicts в Q2PRO-X — это набор отдельных ghost/model/impact paths, а не одна большая общая галка. Такая декомпозиция нужна потому, что разные типы оружия имеют разные временные окна, разные формы server confirmation и разную чувствительность к визуальным артефактам.
- Rocket path включает и projectile, и optional explosion prediction.
- Railgun и hitscan-оружие требуют отдельной timing-модели и suppression duplicate effects.
- Shotgun и super shotgun работают через локальную правдоподобность fire feedback, а не через попытку симулировать серверную баллистику.
- Impact volume control позже завязан на recent-fire context, а не на простое имя wav-файла.
7. Laghax internals
Laghax adaptive mode — это stress-based window selection, а не просто линейный lerp. Внутри участвуют ping, jitter, packet disturbance, prediction debt и authority-gap.
- Малые ошибки можно снапать сразу, чтобы не превращать движение в мыло.
- При росте стресса окно коррекции растёт, но остаётся ограниченным hard cap.
- Loss-dominant low-ping refinement переоценивает роль потерь и burst-ов там, где jitter сигнал загрязнён именно ими.
- Debug/HUD path нужен не только для красивой визуализации, а для реального разбора поведения на проблемной линии.
8. Renderer architecture
Визуальные доработки Q2PRO-X не собраны в один гигантский rewrite. Архитектурно это набор слоёв: modern video backend, render scale subsystem, local visual fx, menu transparency и вспомогательные overlay UI.
8.1. win32egl and desktop fullscreen
win32egl в Q2PRO-X важен не только как второй video driver, а как supported path для современных desktop/hdr/capture сценариев. Поэтому в релизе есть ANGLE bundle, а desktop fullscreen и Alt+Tab/Alt+F4 входят в документированное поведение.
8.2. Internal render scale paths
Дополнительно quality resolve нельзя сводить к одному bilinear collapse. Именно поэтому в Q2PRO-X появился progressive downsample chain и tiled guard-band, иначе на высоких процентах scale начинается рябь и seam-артефакты.
8.3. Visual FX stack
Visual FX intentionally живёт на существующем scene/postprocess pipeline. Это позволяет держать live-apply и общую диагностику visual fx info, не плодя отдельный параллельный renderer.
9. Modern server browser
Новый browser не переписывает discovery backend. Архитектурно это новый frontend/window/UI layer поверх старой серверной информации, что снижает риск и делает развитие интерфейса самостоятельным направлением.
- Legacy browser сохраняется как fallback и user choice.
- Modern browser должен поддерживать both mouse-first and keyboard navigation.
- Address/connect target semantics должны быть честно разведены с тем, как строка красиво отображается в details.
- Custom source — это часть пользовательского workflow, а не только скрытый runtime preset.
10. Visibility/highlighting architecture
Visibility/highlighting развивалась по стадиям: сначала items, затем players, потом team-aware logic. Это позволило сначала опереться на strong truth, а только потом идти в более рискованные heuristics.
- Items классифицируются надёжнее, чем player team semantics, поэтому они и шли первым этапом.
- Player highlighting использует разные режимы и confidence hold, а не коммитится по одному кадру.
- Team auto допускается только при наличии strong team truth, а не по магическому предположению.
- Future safe screen-space outline зафиксирован отдельно, потому что world-scale > 1.0 в competitive context быстро становится exploit path.
11. Sound architecture
Звук в Q2PRO-X — это уже не только OpenAL on/off. Внутри есть несколько осей: OpenAL profile, acoustics/reverb, routing slots, sound profiles, per-weapon volumes, resamplers, high-precision output и binaural layer.
11.1. OpenAL profiles, reverb and routing
al_profile и al_reverb intentionally orthogonal. Первый отвечает за базовое feel behavior OpenAL path, второй — за пространственную акустику и EFX routing.
- Profile 0 = current Q2PRO-X baseline.
- Profile 1 = R1Q2-like feel with inverse-distance style behavior.
- al_reverb строится через OpenAL Soft / EFX, а не legacy hardware assumptions.
- Routing развивается от single-slot fallback к dual/triple/quad topology.
11.2. Resamplers and high-precision output
Архитектурно сначала был закрыт quality вопрос SRC, а уже потом high-precision output. Это важная последовательность: смысл float32/96kHz невысок, если sample-rate conversion path остаётся грубым.
11.3. Binaural layer and OpenAL Soft
Binaural/3D sound intentionally реализован как control layer поверх OpenAL Soft HRTF и app-local alsoft.ini. Это даёт хороший баланс между мощностью и совместимостью.
- al_hrtf сохранён как совместимый alias.
- al_binaural_profile управляет только binaural-specific ручками.
- Bundled soft_oal.dll — часть осознанной portable-runtime стратегии.
12. Mod command overlay internals
Overlay давно вышел за рамки простого справочника. Сейчас это mod-aware command assistant с ролями, confirm logic, search, pins, local overrides и prompt suggestions.
Отдельно важно, что prompt input path нельзя путать с обычным игровым input suppression: игровые bind'ы должны гаситься, но текст для vote map, vote kick и других prompt-команд должен вводиться полноценно.
13. Restart policy and live-apply policy
Q2PRO-X deliberately старается минимизировать ручные restart-ритуалы. Там, где restart неизбежен, пользователь должен видеть это честно, а система должна сама безопасно завершать промежуточные шаги.
14. Known limitations и честные ограничения
- game cvar after mod server — известное ограничение, а не скрытый баг.
- Некоторые applied audio/video states зависят от реального устройства и backend capabilities.
- Future safe outline intentionally не внедрён в текущий visibility path, потому что это отдельная серьёзная задача.
15. Донорская карта проекта
Приложение A. Технические изменения beta 0.95-a и 0.96
Weapon predict hidden-gun path: player_ent resolver теперь корректно декодирует MODELINDEX_PLAYER + skinnum >> 8 и больше не зависит от cl_vwep. Имена weapon attachments берутся из #-prefixed weapon model configstrings, поэтому режимы cl_gun 0 и cl_gun 1 + hand 2 больше не завязаны на видимость view gun.
Blaster held-fire: локальный ghost path больше не ограничен только rising-edge нажатием. Для бластера используется удерживаемая cadence-модель с тем же интервалом, что и раньше, но без ложных пропусков при зажатой атаке.
win32egl stabilization: EGL init теперь живёт в двухшаговой схеме. Если ANGLE platform display инициализируется, но дальше даёт 0 configs или другой поздний fail, клиент делает полноценный fallback на legacy eglGetDisplay path, а не остаётся с тёмным экраном.
Input/config layer: Alt+F4 вынесен в global Q2PRO-X cvar cl_altf4_exit. Горячая клавиша всё ещё перехватывается централизованно, но теперь поведение можно выключить без ручной правки bind-логики.
16. 0.96: 4:3 pillarbox, resolution picker и fullscreen semantics
Ветка 0.97 закрывает конкретный пользовательский pain point из beta 0.95-a: классический 4:3 fullscreen на современных 16:9/16:10 desktop-сценариях больше не должен зависеть от внешнего NVIDIA scaling, слепого перебора vid_modelist и случайного поведения borderless window.
- vid_desktop_fullscreen 1 теперь надо понимать как desktop-native presentation path: сам монитор остаётся в текущем desktop mode, а выбранные resolution / refresh используются для content aspect и для выбора подходящего fullscreen mode внутри клиентской логики.
- vid_desktop_fullscreen 0 остаётся классическим exclusive/fullscreen mode-switch path. В этом режиме Q2PRO-X действительно просит Windows и драйвер переключить дисплей в выбранный видеорежим через старую fullscreen-механику.
- vid_desktop_fullscreen_fit вводит presentation-rect layer: логическая игровая картинка рисуется в центр окна, а остальная площадь заполняется явными чёрными барами. Это детерминированное клиентское поведение, а не надежда на то, что монитор сам красиво сделает aspect scaling.
- vid_resolution и vid_refresh живут как глобальные string-picker cvars. Их значения собираются из EnumDisplaySettings, а затем сопоставляются с vid_modelist, чтобы меню и реальный mode backend говорили об одном и том же наборе дисплейных режимов.
- Startup-sync решает раннюю инициализационную дыру: q2pro-x.cfg исполняется раньше Win_Init, поэтому сохранённые resolution/refresh теперь дополнительно применяются в Win_GetModeList до первого set_mode. Иначе пользователь видел бы сохранённые строки в cvar, но не получал бы нужный режим на первом кадре.
- Black-bar input rejection завершает feature с точки зрения UX: мышиные клики и колесо за пределами content rect не должны трогать UI-элементы на кромке. Это особенно важно для server browser и mod overlay, где активные зоны плотнее, чем в обычном меню.
16.1. Практическая логика режимов
Для centred 4:3 внутри современного desktop fullscreen правильная комбинация такая: resolution = 800x600 или 1024x768, desktop fullscreen = yes, fullscreen fit = aspect. При этом display mode монитора не меняется, зато content aspect у игры становится строго 4:3.
- Если пользователю нужен именно настоящий 800x600 fullscreen mode switch, надо отключать desktop fullscreen. Тогда resolution/refresh становятся запросом к реальному видеорежиму, а итоговое масштабирование уже зависит от GPU/монитора.
- Если цель — просто fullscreen без лишних полос, resolution = desktop + desktop fullscreen = yes + fullscreen fit = fill возвращает пользователя к привычному borderless-native path.
- Разница между 800x600 и 1024x768 в Q2PRO-X не магическая: это два разных 4:3 content size. Выбор между ними — вопрос визуальной резкости, ретро-feel и производительности, а не вопрос разной логики клиента.
16.2. Почему это важно для beta/release layer
Для beta-дистрибутива это также важная release-story: тестировщику не нужно лезть в чужой q2pro.menu или собирать сторонние скрипты ради старых fullscreen-сценариев. Вся логика теперь живёт в стандартном Q2PRO-X menu/config layer и документируется как часть официального user-facing behaviour.
17. 0.97: OLED protection architecture
OLED-ветка в Q2PRO-X — это не одна опция, а небольшой набор независимых runtime-подсистем поверх существующего рендера. Архитектурно они объединены мастер-cvar vid_oled_enable, но внутри разделены на bar protection, idle full-screen dim и UI alpha protection.
- Bar protection активируется только там, где действительно есть aspect-fit black bars. То есть обычный full-fill режим не тратит на это логику зря.
- Idle protection работает поверх всего окна: уровень, HUD, меню, console, modern server browser, loading plaque и pillarbox-области затемняются единым слоем.
- Cursor suppression привязан не к одному draw-path, а к Windows cursor visibility layer: когда idle-пульс реально активен, системный курсор тоже уходит, а потом восстанавливается по user activity.
- UI alpha protection не переписывает scr_alpha, cl_serverbrowser_alpha или другие пользовательские cvar. Вместо этого вводится временный render-time multiplier, который мягко домножает итоговую alpha на лету.
- Pillarbox workspace для laghax HUD и server browser использует уже существующую геометрию aspect-fit presentation, а не отдельную систему координат поверх клиента.
Практический смысл такой декомпозиции: каждая подветка может быть включена или выключена отдельно, а в hot path при vid_oled_enable = 0 остаётся почти нулевой overhead.
18. 0.97: weapon prediction follow-up and accepted limitations
Главный архитектурный итог 0.97 по weapon predict: continuous-fire weapon-view animation не должна предсказываться клиентом вслепую. Для chain/machine/hyperblaster знания о fire-loop и wrap-frame живут в game DLL, а не в клиенте. Поэтому shipping-path intentionally оставляет gun model server-driven, чтобы не рисовать неверные кадры при переходах вроде 11 -> 6.
При этом hyperblaster projectile handoff был реально усилен. Прежняя логика опиралась на EF_HYPERBLASTER и потому пропускала effectless болты из стандартного fire loop. В 0.97 клиент классифицирует свои server HB bolts по модели projectile, проверке recent local burst, corridor/spawn consistency и затем матчится по FIFO seq. После совпадения включается точечное entnum suppression с узким fallback на самый первый кадр.
Это важно как пример общего правила Q2PRO-X: быстрый local feel допускается, пока он не начинает ломать truthfulness картинки. Когда риск неверного поведения выше пользы, клиент сознательно останавливается на documented limitation.
19. 0.97: laghax HUD as a live diagnostic surface
Laghax HUD в 0.97 перестаёт быть только окном про smoothing-window. Теперь это компактная live surface, где отражаются реально включённые predict и physics-параметры. Архитектурно это сделано без ручного кэша меню: overlay собирает состояние непосредственно из текущих cvar и поэтому сразу отражает изменения из Q2PRO-X menu.
- show weapons & player predicts enabled params — перечисляет только реально включённые weapon/player predict-path.
- show physics enabled params — всегда показывает movement feel и step smoothing, а legacy predict и fixed move выводит только когда они действительно определяют effective path.
- pillarbox workspace — переводит координатную базу overlay из gameplay viewport в full presentation area, что даёт корректный drag/hit-test для 4:3 aspect-fit режима.
20. 0.97: step smoothing lift jitter fix
Bugfix по лифтам живёт целиком в predict-layer и не требует правок в entities.c. Корневая проблема была в том, что R1Q2-style stair heuristic видел vertical mover как очередную ступеньку: игрок стоял on ground, origin Z рос, и predicted_step re-arm происходил каждый prediction tick.
В 0.97 добавлен вертикальный mover guard: если pm.groundentity — это движущийся brush-model с ненулевым vertical delta, step-smoothing path для режимов r1q2-1/2/3 принудительно сбрасывает predicted_step carry-over. Mode 0 намеренно не менялся: у него другая additive-семантика, и пользовательский багрепорт был не про него.
С практической точки зрения это один из тех патчей, где Q2PRO-X осознанно отступает от donor-purity. R1Q2-подобный stair feel сохранён, но плохое поведение на lift/mover больше не считается sacred behaviour.
16. Архитектурные обновления beta 0.98 относительно 0.97
Beta 0.98 не меняет базовую layered-модель Q2PRO-X, но добавляет несколько важных уточнений на уровне архитектуры: маршрутизация предикта оружия, display-mode state, runtime audio control, adaptive laghax classification и modern browser Favorites persistence.
16.1. Display mode state: windowed / desktop / exclusive
Вместо старой неявной модели, где vid picker мог незаметно уводить игру в exclusive fullscreen, теперь display mode разведен на два независимых состояния:
- `vid_windowed` — отвечает за normal resizable window.
- `vid_fullscreen_type` — хранит предпочтительный fullscreen path (`desktop` / `exclusive`) для случая, когда windowed выключен.
Такое разделение важно не только для меню, но и для корректного bootstrap/reverse-sync поведения. Оно убирает зависимость от случайного состояния legacy picker cvar и делает Alt+Enter предсказуемым переключателем windowed on/off.
16.2. Runtime audio gain вместо грубого mute-переключателя
Для audio inactivity / OLED idle path выбрана правильная архитектура runtime-gain слоя, а не перезапись пользовательских громкостей.
Это позволяет безопасно сочетать `mute when inactive` и `mute audio on idle protect`, а также плавное затухание по OLED idle fade / restore без порчи пользовательских настроек.
16.3. Предикт оружия: новая стабилизированная архитектура
Самая недооценённая, но архитектурно важная часть beta 0.98 — это стабилизация предикта оружия после нескольких beta-review циклов. Здесь важно понимать, что Q2PRO-X больше не пытается `одним механизмом` предсказывать всё подряд. Финальная схема намеренно разделена на четыре слоя.
Такой расклад и есть главное архитектурное изменение: не «больше предикта любой ценой», а предсказание только там, где это устойчиво и не создаёт ложные визуальные состояния.
16.4. Переключение оружия и непрерывная стрельба: почему это теперь работает лучше
Проблема старых итераций состояла в том, что предиктор пытался принять решение о состоянии выстрела слишком рано, когда оружие ещё находилось в фазе switch / weapon-up и сервер не успел подтвердить новый класс оружия. Отсюда возникали ложные выстрелы старого оружия и повреждённая анимация при удержании атаки.
В финальной архитектуре используется phase gate по метаданным (Option E): у каждого vanilla weapon есть описанные границы activate / fire / idle фаз, а ghost fire разрешается только когда authoritative `ps->gunframe` вышел из weapon-up фазы.
Отдельно был принят важный архитектурный компромисс: для непрерывно стреляющего оружия (machinegun / chaingun / hyperblaster) Q2PRO-X не рисует выдуманную client-only gun animation. Анимация view-weapon остаётся серверно-управляемой, а локально предсказываются звук, вспышка, попадания, локальный расход патронов и визуальная обратная связь по снарядам. Это сильно уменьшает риск неверной локальной анимации и делает систему честнее к серверной логике.
16.5. HyperBlaster и rockets: точное сопоставление вместо грубого suppression
HyperBlaster в beta 0.98 больше не живёт по примитивной схеме `спавним локальный bolt и надеемся, что сервер потом как-нибудь совпадёт`. Финальная схема использует classifier `Ghost_IsHBServerCandidate()`, локальное окно недавней очереди, пространственный коридор, FIFO-сопоставление по `seq` и точное `entnum`-совпадение после handoff.
Поверх этого локальная трасса HyperBlaster получила stop-on-hit, локальный эффект удара и suppression дубликатов `TE_BLASTER`, чтобы поток выглядел как единая трасса, а не как два несвязанных источника визуала.
Rocket path тоже стал строже. Предикт больше не должен скрывать чужие ракеты только потому, что у нас есть какой-то локальный paired ghost. Быстрый путь после handoff теперь привязан к конкретному entity: используется точный `entnum`, а не широкое условие `какая-то локальная ракета уже была paired`. Это и есть ключ к безопасному projectile prediction в мультиплеере.
Дополнительно введён runtime reset ghost-state на death / respawn, чтобы локальное владение projectile-объектами не протекало через смену жизненного состояния игрока.
16.6. Laghax: starvation detector hardening
В `cl_laghax 2` усилена классификация low-ping starvation-кейсов. Вместо попытки решать проблему только коэффициентами adaptive model получил два внутренних starvation proxy:
- receive-cadence starvation score (`rxgap`) — быстрый сигнал по интервалам между приходящими authoritative packet-ами;
- slow total-loss ratio (`tloss`) — медленный сигнал по общей картине server-to-client потерь.
Ни один новый пользовательский cvar при этом не добавлялся. Для игрока это остаётся тем же `cl_laghax 2`, но с лучшей автоматической реакцией на патологические low-ping packet-loss случаи.
16.7. Server Browser Favorites: composite persistence model
Favorites в modern browser пришлось делать с оглядкой на существующую composite-source модель, где одновременно участвуют:
- `favorites://` → legacy Address Book `adr0..adr15`
- `file:///servers.lst`
- `broadcast://` как transient source
Поэтому add-path пишет только в `servers.lst`, а remove-path обязан чистить и `servers.lst`, и совпадающие `adrN`, иначе удалённый сервер немедленно вернётся через вторую половину composite-source.
Отдельно была закрыта Windows-специфичная проблема с двойной текстовой трансляцией line endings при rewrite `servers.lst`: финальный код теперь работает через normalized read + raw write, чтобы не получать `CR-CR-LF` corruption.
16.8. UI correctness: single-predicate visibility for Favorites action
В процессе review выяснилось, что Favorites action button в modern browser мог оказаться невидимым, но всё ещё доступным через stale hit-rect или keyboard focus.
Финальная версия beta 0.98 использует один общий predicate (`fav_drawn`) для draw, mouse hit-testing, keyboard activation и Tab traversal. Это маленькое, но важное правило UI-целостности: скрытая кнопка не должна оставаться интерактивной.