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 сьютов зелёные.
62 lines
2.7 KiB
Rust
62 lines
2.7 KiB
Rust
//! Загрузка настоящих скриптов GMod (оружие и энтити) из установки игры.
|
|
//!
|
|
//! Без ассетов тест пропускается: путь задаётся `SOURCE_RS_ASSETS` или
|
|
//! `~/gmod_server/server/garrysmod`.
|
|
|
|
use glua::LuaRuntime;
|
|
use std::path::PathBuf;
|
|
|
|
fn game_dir() -> Option<PathBuf> {
|
|
let root = std::env::var_os("SOURCE_RS_ASSETS")
|
|
.map(PathBuf::from)
|
|
.or_else(|| {
|
|
std::env::var_os("HOME").map(|home| PathBuf::from(home).join("gmod_server/server"))
|
|
})?;
|
|
let game = root.join("garrysmod");
|
|
game.is_dir().then_some(game)
|
|
}
|
|
|
|
#[test]
|
|
fn real_gmod_weapons_and_entities_load() {
|
|
let Some(game) = game_dir() else {
|
|
eprintln!("пропуск: ассеты Garry's Mod не найдены");
|
|
return;
|
|
};
|
|
let runtime = LuaRuntime::new().expect("рантайм");
|
|
let (weapons, entities, failed) = runtime.load_scripts(&game);
|
|
eprintln!("скрипты: оружия {weapons}, энтити {entities}, ошибок {failed}");
|
|
assert!(weapons >= 3, "мало оружия: {weapons}");
|
|
// 5 из 6: `widget_bones.lua` использует GMod-расширение `continue`,
|
|
// которого нет в стандартном Lua (отдельная задача препроцессора).
|
|
assert!(entities >= 5, "мало энтити: {entities}");
|
|
|
|
// Поля SWEP прочитаны (Primary создаётся до выполнения скрипта).
|
|
let clip = runtime
|
|
.probe("return tostring(weapons.Get('weapon_fists').Primary.ClipSize)")
|
|
.expect("probe")
|
|
.unwrap_or_default();
|
|
assert_eq!(clip, "-1", "Primary.ClipSize кулаков");
|
|
let model = runtime
|
|
.probe("return weapons.Get('weapon_fists').ViewModel.path")
|
|
.expect("probe")
|
|
.unwrap_or_default();
|
|
assert!(model.contains("c_arms"), "ViewModel: {model}");
|
|
|
|
// Реестр list.Get("Weapon") — то, из чего строится меню.
|
|
let count = runtime
|
|
.probe("local n=0 for _ in pairs(list.Get('Weapon') or {}) do n=n+1 end return tostring(n)")
|
|
.expect("probe")
|
|
.unwrap_or_default();
|
|
eprintln!("list.Get('Weapon') = {count}");
|
|
assert!(
|
|
count.parse::<usize>().unwrap_or(0) >= 3,
|
|
"list.Get('Weapon'): {count}"
|
|
);
|
|
|
|
// Энтити: запись доступна и помечена как спавнабельная.
|
|
let entity = runtime
|
|
.probe("return tostring(scripted_ents.Get('sent_ball') ~= nil)")
|
|
.expect("probe")
|
|
.unwrap_or_default();
|
|
assert_eq!(entity, "true", "scripted_ents.Get('sent_ball')");
|
|
}
|