Commit graph

22 commits

Author SHA1 Message Date
4bfe923577 Мобильный Sandbox: настоящий Q-меню, полный Lua и сенсорные кнопки
Some checks are pending
CI / checks (push) Waiting to run
- APK: полные lua/ + gamemodes/ + settings + resource/language (раньше был
  только autorun, и Sandbox-меню не собиралось, показывалось резервное).
  ASSET_VERSION=3: при обновлении старые распакованные файлы удаляются,
  иначе остаётся полный битый spawnlist.
- fs pack: список EXTRA_MODELS — 13 частых пропов и физган; спавнлист
  отфильтрован по моделям, которые реально есть в APK (31 запись в 7
  категориях вместо 7473 белых иконок).
- Сенсорное управление: Q, NOCLIP, LMB, RMB, JUMP, DUCK; полупрозрачные
  рамки с подписями и подсказка стика. LMB/RMB превращаются в настоящие
  события мыши (общий код физгана/оружия), noclip переключает полёт.
  Кнопка X рисуется поверх Q-меню, остальные под меню скрыты; свайп вверх/
  вниз в меню листает панели колесом.
- Lua-шим: list.Get для неизвестного списка возвращает пустую таблицу;
  panel:Call/SetHTML/AddFunction/QueueJavascript — заглушки; добавлены
  фразы vehicles/search/quick_filter и подсказки.
- Проверки: clippy -D warnings и cargo test --workspace зелёные.
2026-10-26 23:30:43 +03:00
8154f9d372 Физган: чистая пружина, угол от камеры; игрок толкает пропы; модель
Some checks are pending
CI / checks (push) Waiting to run
- Убран feed-forward скорости цели: он складывался с реакцией на ту же
  ошибку и на круговых движениях мышью давал перелёт. Осталась пружина
  v = ошибка / timeToArrive (отставание 60 юнитов при 1200 — как в GMod),
  тест circular_target_does_not_overshoot.
- Grab хранит ориентацию относительно камеры (кватернион): при повороте
  взгляда проп поворачивается вместе с ним, E вращает в осях камеры, а не
  мировые углы. Тест grab_keeps_angle_relative_to_camera.
- Вьюмодель физгана: телефото-посадка (distance 80, scale 2.12, right/up 59),
  перспектива FOV 100 больше не растягивает упоры и руки; idle-анимация.
- Физика игрока: кинематическая капсула высотой 72 (add_character /
  move_character), пропы не проходят сквозь игрока; луч физгана игнорирует
  Character-тела (иначе начинался внутри своей капсулы). push_props толкает
  пропы в сторону движения с sqrt(10/mass) — лёгкие отлетают, тяжёлые едут
  медленно; замороженные и удерживаемые не толкаются; noclip уводит капсулу
  под карту.
- Lua: DTextEntry IsMultiline/GetMultiline/Get- и SetEnterAllowed, заглушки
  panel_meta (OpenURL) — исправлены OnKeyCodeTyped и падения таймеров меню.

Проверки: cargo fmt, clippy -D warnings, cargo test --workspace — зелёные;
новые тесты капсулы, луча, угла и кругового движения.
2026-10-25 10:14:31 +03:00
3dce621bcd Merge branch 'feat/qmenu2'
Some checks are pending
CI / checks (push) Waiting to run
# Conflicts:
#	crates/client/src/map.rs
#	docs/DIARY.md
2026-10-24 23:26:13 +03:00
a3b884b7c6 Q-меню: hold/pin, кэш иконок, размер окна и сохранение скорости
Иконки: видимая сетка оставалась белыми заглушками, потому что при
бюджете 8 мс на кадр успевало загрузиться всего 1-2 превью. Бюджет поднят
до 12 штук / 40 мс, кэш увеличен с 512 до 1024 текстур и живёт весь сеанс
(LRU, ключ — нормализованный путь модели). Добавлены IconStats
(cached/rendered/reused/evicted/failed) и логи при открытии, закрытии и
выходе: повторное открытие показывает rendered_since_open=0.

Размер меню: прогрев до создания окна задавал корню 1280×720, а
ui_set_screen не обновлял размер (Rust звал несуществующий
__sr_resize_to_screen). ui.set_screen/ui.sync_root_size теперь растягивают
g_SpawnMenu на ScrW×ScrH при открытии, resize и раскладке.

Скорость: при открытии меню больше не обнуляются velocity/sprint. Игрок
заморожен (update не вызывается), но импульс сохраняется: до открытия и
после закрытия speed одинаковый, включая noclip.

Hold/pin Q: Q down открывает, Q up закрывает только без взаимодействий.
Клик, колесо, касание и ввод закрепляют меню (pinned), после чего Q
работает как toggle. Esc закрывает всегда. Для текстовых полей добавлены
ui.focus/RequestFocus/GetKeyboardFocus, SDL3 TextInput, Backspace/стрелки/
Enter и input.IsKeyTrapping: в фокусе Q печатается, а не закрывает меню.

Попутно исправлена передача аргументов hook.Run: колбэки hook.Add больше
не получают имя хука первым аргументом, как в GMod. Из-за этого
OnTextEntryGetFocus падал на pnl:HasParent, и StartKeyFocus не вызывался.

Проверки: cargo fmt, clippy -D warnings, cargo test --workspace (28 сьютов)
зелёные. Кадры 1280×720 и 1600×900: images=88/104, placeholders=0; xdotool:
hold open/close, клик+keyup, ввод q, повторный Q, скорость 250.45 до/после.
2026-10-24 22:56:26 +03:00
26a61b0e7e Слияние feat/viewmodel: посадка вьюмоделей и встроенный weapon_pistol
Some checks are pending
CI / checks (push) Waiting to run
Из ветки feat/viewmodel (32aad74):
- встроенный SWEP weapon_pistol (Slot 1, ClipSize 18, одиночный
  PrimaryAttack, HUD 17/18) — регистрируется только если в ассетах нет
  своего lua/weapons/weapon_pistol.lua (оригинал приоритетнее);
- посадка вьюмодели по модели: таблица right/up/distance/scale/angles
  (w_pistol, v_pistol, c_smg1); ключ — ось ствола: у w_pistol это +Y,
  у v_pistol/c_smg1 — +X; общий view_yaw=-90 ломал флечетган;
- движок: ModelInstance.scale, set_model_instance_scale,
  play_model_animation_oriented / move_model_instance_oriented;
  ViewModelFOV пересчитывается в масштаб, поля SWEP (ViewModelOffset/
  Angles/Scale) перекрывают таблицу;
- слот 1 возвращает пистолет после флечетгана/кулаков, 0 скрывает
  вьюмодель (c_arms без геометрии); тест slot_keys_match_gmod.

Проверено: 28 сьютов зелёные; кадры всех трёх моделей (ближе_near=0,
ствол вперёд), HUD пистолета, переключения.
2026-10-24 21:42:24 +03:00
32aad74eb5 Вьюмодель: посадка по модели и встроенный weapon_pistol
Посадка вьюмодели вынесена в таблицу по модели: у w_pistol ствол вдоль +Y, у v_pistol/c_smg1 — вдоль +X, поэтому общие view_yaw/дистанция не работали. В движке появился масштаб экземпляра и полный доворот модели; для w_pistol/v_pistol/c_smg1 подобраны дистанция, смещение, масштаб и yaw, near-плоскость не режет ни одну модель.

weapon_pistol в HL2 — движковое оружие, его Lua-скрипта в ассетах нет. Добавлен встроенный SWEP (Slot 1/SlotPos 1, 18 патронов, одиночный огонь) с регистрацией в weapons и list.Get("Weapon"); пользовательский lua/weapons/weapon_pistol.lua важнее встроенного. ViewModelFOV и необязательные ViewModelOffset/Angles/Scale из SWEP перекрывают таблицу.

Проверено кадрами на Xvfb: пистолет и флечетган в кадре, ближе_near=0, выстрел 18→17, слот 1 после флечетгана и кулаков возвращает пистолет, c_arms по-прежнему скрывается. Добавлен SOURCE_RS_TEST_SLOT для синтетической клавиши слота (xdotool не доставляет клавиши в SDL-окно на Xvfb).
2026-10-24 21:40:00 +03:00
1b24f280d3 Q-меню: dirty-снимок, слайдеры, колесо и выравнивание текста
Снимок Derma пересобирается по dirty-флагу (ввод, таймеры, сеттеры), а не раз в 6 кадров: в покое 0.26-0.5 мс вместо 4-6 мс, без пиков 47-84 мс. Невидимые поддеревья и обрезанные команды не попадают в снимок; сортировка детей без ZPos не аллоцирует; hover не перезапускает раскладку. Меню прогревается на загрузке карты.

Слайдеры: загружается dnumberscratch.lua, добавлены NoClipping/GetCaretPos/SetCaretPos/input.SetCursorPos, OnCursorMoved получает локальные координаты, MouseCapture удерживает перетаскивание; есть fallback DSlider/DNumSlider/DNumberScratch.

Колесо всплывает от иконки/кнопки до DScrollPanel/DTree; починен корень DTree (высота ChildNodes до VBar). Клик/колесо проверяются тестами и отладочными SOURCE_RS_UI_CLICK/WHEEL.

Текст: метрики surface.GetTextSize совпадают с bitmap-рендером, вертикаль по высоте глифа, ContentAlignment как в GMod, вкладки центрируются, дерево слева с отступом, заглушки иконок - две строки по центру с обрезкой.

Иконки: очередь видимых моделей по площади, до 8/~8 мс за кадр, LRU-кэш переиспользуется.
2026-10-24 20:37:18 +03:00
58daab03be Q-меню: 3D-иконки моделей, светлый скин и клиппинг
Some checks are pending
CI / checks (push) Waiting to run
2026-10-24 18:21:41 +03:00
30fe9dfec1 Клиент: настоящее Q-меню Sandbox из Lua
Some checks are pending
CI / checks (push) Waiting to run
В crates/client подключён UI-слой из glua: после Lua-инициализации
вызывается load_ui, и если OnGamemodeLoaded создал g_SpawnMenu, Q
открывает настоящее меню Sandbox, иначе остаётся qmenu.rs.

Рендер: ui_overlay переводит UiCommand в push_rect/push_text, цвета
sRGB→linear, бюджет глифов и отсечение за экраном. push_rect теперь
точный квад, а не растянутый глиф: тонкие линии дерева больше не
превращаются в квадраты.

Ввод: Q/Esc, мышь и колесо уходят в ui_mouse, игрок и камера стоят,
ЛКМ не стреляет; ui_set_screen на старте и resize. На Android добавлена
кнопка MENU и перевод касаний в пиксельные координаты.

Спавн: RunConsoleCommand складывает вызовы в очередь; клиент исполняет
gm_spawn (и gm_spawnsent/gm_spawnswep) обычным спавном пропа на полу
перед игроком.

Попутно: ui_snapshot_into переиспользует буфер, ui_take_errors отдаёт
ошибки панелей в лог; в VGUI-слое добавлены HasChildren/ChildrenSize/
HasFocus/GetTextSize/DrawTextEntryText, без которых сетка иконок имела
высоту 0 и клики не попадали.
2026-10-24 16:02:44 +03:00
ffd9e736bc Derma: настоящее Q-меню Sandbox на Lua поверх VGUI-слоя
Some checks are pending
CI / checks (push) Waiting to run
В crates/lua добавлен минимальный слой VGUI/Derma: панели-таблицы,
vgui.Register/Create, surface/draw с записью команд, ввод и снимок кадра
(до 4096 команд, глубина 32). На нём грузятся настоящие lua/derma,
lua/skins/default.lua, lua/vgui/* и lua/includes/modules/spawnmenu.lua,
затем Sandbox и OnGamemodeLoaded строят g_SpawnMenu.

Публичный контракт: UiKind/UiCommand, LuaRuntime::ui_toggle/ui_visible/
ui_snapshot/ui_mouse/ui_set_screen, load_ui -> UiLoad.

Попутно: file.Find в GMod-семантике (файлы и каталоги, маски *.txt),
DEFINE_BASECLASS -> local BaseClass, //-комментарии, регистронезависимый
include, SpawnableEntities хранит таблицу ENT.

Тесты на реальных ассетах: ~991 команда, вкладки/категории/модели,
клик по вкладке меняет снимок; без ассетов пропуск.
2026-10-24 15:03:32 +03:00
8aff0caf12 Слияние feat/qmenu: Q-меню спавна и SWEP в клиенте
Some checks are pending
CI / checks (push) Waiting to run
- map.rs: объединены ветки ввода. Пока меню открыто, Esc/Q/цифры/ЛКМ
  принадлежат меню (клик выбирает предмет, игрок стоит), иначе работают
  SWEP-атака и физган; отпускание ЛКМ снимает primary_up у SWEP и не
  трогает физган при открытом меню. Спавн из меню и по G идёт общим
  SpawnRequest с досборкой рендерера. HUD показывает активное оружие и
  подсказку с Q; вьюмодель SWEP сохранена.
- lua/lib.rs: сохранены и API SWEP (weapon_number, weapon_bool,
  set_active_weapon, cur_time, weapon_field, weapon_table), и ENT-API
  (entity_string, entity_bool), и лексер/препроцессор continue
  (Token, preprocess_continue, is_statement_continue, read_script),
  и find_model_literal для спавн-меню.
- render: push_rect и сплошной глиф для заливки оверлея.

Проверено: cargo fmt, clippy --workspace --all-targets -D warnings,
cargo test --workspace; glua с ассетами — оружия 3, энтити 6, ошибок 0;
engine world_real — 21 тест; кадры Q-меню (арбуз заспавнен перед камерой)
и SWEP (weapon_fists в HUD). При открытом меню ЛКМ не стреляет, после
закрытия ЛКМ вызывает attack: weapon_fists.
2026-10-24 13:45:44 +03:00
210182a940 Слияние feat/swep: реестр оружия в клиенте, слоты, атака, HUD
Some checks are pending
CI / checks (push) Waiting to run
Из ветки feat/swep (a46e4d8, 1fe36b6, 5a8f971):
- выбор SWEP из list.Get('Weapon') (фильтр Spawnable + существующая
  ViewModel), слоты 1..9, SOURCE_RS_SWEP для старта, Holster/Deploy при смене,
  вьюмодель из SWEP.ViewModel (SOURCE_RS_VIEW_MODEL — override);
- ЛКМ → PrimaryAttack через call_weapon_method, автоматический/одиночный огонь,
  Think каждый кадр; без SWEP — прежние физган и fire-анимация;
- HUD: PrintName и патроны Clip1/ClipSize;
- заглушки GMod-API под реальные скрипты: CurTime, IsValid, NULL, player.GetAll,
  util.TraceLine/TraceHull/TraceEntity/TracePhysics, trace.*, sound.*/EmitSound,
  константы PLAYER_ATTACK*/ACT_VM_*/MASK_*, база SWEP (GetOwner/GetViewModel/
  NetworkVar/SetNextPrimaryFire/SetHoldType/Clip1/EmitSound/SendWeaponAnim/
  SequenceDuration/ShootEffects/Remove), game.SinglePlayer как функция,
  GetConVar для sv_defaultdeployspeed/phys_pushscale;
- тест real_gmod_weapon_methods_run_without_errors прогоняет настоящие
  weapon_fists/flechettegun/medkit (SetupDataTables..Holster) без ошибок Lua.

Конфликт в crates/lua/tests/scripts.rs разрешён: сохранены тесты include и
геймода из feat/lua-pre и добавлен тест SWEP из feat/swep.
Проверено: 27 сьютов, 46+4+4 теста glua зелёные.
2026-10-24 13:33:50 +03:00
f41bfde690 Lua: поля ENT-скриптов и модель-представитель для спавн-меню 2026-10-24 13:33:34 +03:00
a46e4d827d Lua: база SWEP и GMod-заглушки для оружия
- swep_base.lua: GetOwner/GetViewModel, NetworkVar, SetNextPrimaryFire,
  Clip1, SetHoldType, EmitSound и безопасные заглушки;
- глобальные CurTime, IsValid, player.GetAll (таблица player),
  util.TraceLine/TraceHull, trace.*, sound.*, константы CLIENT/SERVER;
- game.SinglePlayer стал функцией (как в GMod), GetConVar знает
  sv_defaultdeployspeed/phys_pushscale — ноль давал inf в Deploy;
- загрузчик SWEP даёт базовые методы через метатаблицу, инициализирует
  SetupDataTables/Initialize и стартовый магазин;
- модель без геометрии (c_arms) теперь логирует причину, а не молчит;
- тест прогоняет реальные Deploy/PrimaryAttack/Think/Holster трёх SWEP.
2026-10-24 13:29:35 +03:00
0b82cd77f3 Lua: continue, include и загрузка геймода
- Препроцессор GMod: continue внутри for/while/repeat -> goto + уникальная
  метка; учтены строки/комментарии, вложенные циклы и функции, завершающие
  break/return (оборачиваются в do ... end). widget_bones.lua грузится:
  энтити 6 из 6.
- include(): поиск рядом с текущим файлом и в lua/ игры, тот же препроцессор,
  лимиты размера/глубины, защита от циклов и выхода за каталог игры.
- LuaRuntime::load_gamemode(): init.lua и cl_init.lua, сбор ошибок без
  падения. Sandbox init.lua выполняется, cl_init.lua упирается в VGUI
  (AccessorFunc); реестры list/scripted_ents после загрузки целы.
- Безопасные заглушки загрузочного слоя Sandbox: CLIENT/SERVER, is*,
  FindMetaTable, cleanup, drive, duplicator, net, cvars, player_manager.
- Тесты: юнит-тесты препроцессора, include на временных файлах и реальных
  lua/includes, загрузка sandbox на ассетах.
2026-10-24 13:29:30 +03:00
300a6c6d98 Lua: Rust-API к реестрам list/weapons (list_names, call_weapon_method, weapon_string)
Some checks are pending
CI / checks (push) Waiting to run
2026-10-24 13:01:27 +03:00
087d57b582 Lua GMod: библиотеки list/weapons/scripted_ents и загрузка скриптов
Some checks are pending
CI / checks (push) Waiting to run
- библиотека `list` (Set/Add/Get/GetEntry/HasEntry) — реестры GMod, на них
  держатся списки оружия, энтити и спавна;
- `weapons.Register/Get/GetStored` и `scripted_ents.Register/Get`, запись в
  `list.Get("Weapon")` и `list.Get("SpawnableEntities")`;
- загрузчик `LuaRuntime::load_scripts(game_dir)`: выполняет `lua/weapons/*.lua`
  (со свежей `SWEP`, заранее созданными `Primary`/`Secondary`) и
  `lua/entities/*.lua` (с `ENT`), ошибка одного файла не роняет остальные;
  размер файла ограничен 1 МиБ;
- заглушки, без которых скрипты не запускаются: AddCSLuaFile, Model, Sound,
  include, DEFINE_BASECLASS, Material, game.AddParticles; GMod-синтаксис
  проходит через препроцессор (`!` → `not`);
- клиент загружает скрипты при старте: на настоящих ассетах — 3 оружия
  (fists/flechettegun/medkit), 5 энтити; `weapons.Get('weapon_fists')` читает
  Primary.ClipSize и ViewModel.

Тест `real_gmod_weapons_and_entities_load` (пропускается без ассетов).
Осталось: `continue` в препроцессоре (ломает widget_bones), include базовых
классов, привязка SWEP к вьюмодели и Q-меню.

26 сьютов зелёные.
2026-10-24 12:12:29 +03:00
6f949085a9 Android: кросс-сборка клиента, SDL-обвязка и сенсорное управление
- client получил lib.rs (общий запуск) и cdylib с экспортом SDL_main;
- steamworks и mlua-фичи разведены по target cfg: на Android нет Steam,
  Lua 5.4 вместо LuaJIT;
- виртуальный стик, обзор свайпом и кнопки прыжка/приседа в map;
- android/: манифест, SDLActivity Java, build.sh (aapt2+d8+apksigner).
2026-10-23 13:37:11 +03:00
aa7558721a lua: стандартная библиотека GMod — hook.Run, math, game, file с песочницей
Батч 3, шаг 3. Сначала измерено, а не придумано: прогнаны 130 файлов
gamemodes/sandbox, извлечены 182 различных вызова API с частотами.
Топ по частоте: hook.Run (63), math.Clamp (61), game.SinglePlayer (36),
math.Rand (27), render.AddBeam (21). Первые четыре — чисто Lua-слой,
сделаны здесь; render.* — отдельная большая работа.

hook.Run не синоним hook.Call: он останавливается на первом не-nil. На этом
построены все проверки Sandbox, подмена Run на Call ломала бы их молча.

Найдено три дефекта, все — измерением:

1. Ключи хуков — строки (идентификаторы скриптов), а не числа. Отбор только
   целочисленных ключей давал пустой список: хуки не выполнялись вообще,
   hook.Run возвращал nil.
2. Vec<Value> реализует IntoLua как таблицу, поэтому Function::call передавал
   хуку ОДИН аргумент вместо трёх — молча, без ошибки. Проверено:
   select('#', ...) внутри хука давал 1 при трёх переданных. То же с одиночным
   числом. Лечится Variadic; отдельный тест фиксирует именно эту ошибку.
3. math.Rand определён на Lua, а не на Rust: он зовёт math.random того же
   состояния и передаёт аргументы нативно.

file.* — с песочницей на garrysmod/: выход за корень это отказ, а не
предупреждение, абсолютные пути не даны, чтение ограничено 8 МБ. На живом
клиенте file.Read('../../../../etc/passwd') вернул nil.

Совпадения с GMod зафиксированы тестами: math.Round(-2.5) = -3,
math.Rand(x) даёт целое в [1, x], AngleDifference(10, 370) = 0,
Remap на вырожденном диапазоне даёт out_min, а не NaN.

Тестов 38 в glua (было 24), 23 набора по воркспейсу, clippy чист.
2026-10-13 13:17:28 +03:00
b991cc59f1 lua: мост к движку — Entity(), ents.* работают с живым миром
Батч 3, шаг 2. Крейт glua не зависит от engine: поведение отдаётся через
трейт Host, реализация которого живёт в клиенте. Иначе был бы цикл
зависимостей и Lua-слой нельзя было бы тестировать в одиночку.

Мир переведён в Rc<RefCell<World>> — скрипт обращается к нему из хуков в
любой момент. Все обращения через try_borrow: пересечение заимствований
даёт panic, а падать из-за скрипта клиент не должен.

Проверено измерением на gm_construct: ents.GetAll() возвращает 1227
сущностей, ents.GetByClass('prop_physics') читает позицию.

Найден и исправлен рассинхрон: move_prop обновлял позу экземпляра пропа,
но не запись в пуле сущностей. Lua читал z = -64, пока физика уже опустила
проп на z = -84 — «данные» и «картинка» разошлись, и заметить это можно
было только глазами. Теперь поза пишется в оба места всегда, даже без
модели: проп без модели всё равно стоит правильно, он просто не рисуется.
Возвращаемое значение move_prop теперь означает именно «геометрия
пересчитана».

После правки Lua читает z = -84.15848, физика даёт -84.15847778320313 —
совпадение до последнего бита.

Тест на паникующий хост: скрипт получает «невалидно» вместо падения.

Тестов 24 в glua, 56 в engine, 23 набора по воркспейсу, clippy чист.
2026-10-13 12:57:01 +03:00
b9b03abe3b lua: типы GMod — Vector, Angle, Color с арифметикой
Батч 3, шаг 1. Фундамент Lua-API: без этих типов Entity:GetPos() не
возвращает ничего, с чем можно считать.

Проверено тестами через настоящий LuaRuntime, а не голый интерпретатор:
скрипт считает теми же глобалами, что и обычный автор в Sandbox.

Решения по совместимости:
- пропущенные аргументы не бывают ошибкой: Vector() и Vector(1, 2) должны
  работать, иначе ломается бытовой код Sandbox;
- деление на ноль даёт 1, а не inf — inf в позиции пропа отравляет всю
  геометрию объекта;
- NaN из скрипта не доезжает до физики;
- компоненты цвета обрезаются в 0..255, а не отвергаются;
- Source — левая система координат: нулевые углы смотрят вдоль +X,
  yaw=90 — вдоль +Y.

Найден дефект чтения чисел в mlua 0.11: Value::as_number() различает только
Number и молча возвращает None на Integer, а LuaJIT отдаёт целые как
Integer. Vector(1, 2, 3) давал Vector(0, 0, 0) — и это выглядело как
«арифметика не работает». Собственный value_number() принимает Number,
Integer и строку-число.

Ещё убрат шум тригонометрии: cos(90°) в f32 равен 6.1e-17, и
Angle(0,90,0):Forward() печатал -0.00000004371139 вместо 0.

Тестов 17 в glua (было 1), 23 набора по воркспейсу, clippy чист.
2026-10-13 12:48:50 +03:00
2c13062b03 lua: рантайм LuaJIT с GMod-подобным API и автозагрузкой клиентских аддонов
- glua: print/Msg, hook.Add/Remove/Call, timer.Simple, concommand.Add,
  CreateConVar/CreateClientConVar/GetConVar, util/engine/game заглушки, FCVAR_*
- препроцессор GMod-синтаксиса: ! → not, != → ~=, && → and, || → or
  (вне строк/комментариев) — оригинальные клиентские скрипты GMod грузятся
- client: команда lua run/list, автозагрузка lua/autorun/client/*.lua из VFS,
  Think-хук и таймеры каждый кадр, вывод в HUD-лог
- fs: VirtualFs::list(prefix) для перечисления файлов (VPK/Pak/каталоги)
2026-10-12 04:29:09 +03:00