//! Загрузка настоящих скриптов GMod (оружие и энтити) из установки игры. //! //! Без ассетов тест пропускается: путь задаётся `SOURCE_RS_ASSETS` или //! `~/gmod_server/server/garrysmod`. use glua::LuaRuntime; use std::path::PathBuf; fn game_dir() -> Option { 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::().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')"); }