├── .gitignore ├── rglua-macros ├── README.md ├── tests │ ├── main.rs │ └── base.rs ├── Cargo.toml └── src │ └── lib.rs ├── rustfmt.toml ├── Cargo.toml ├── rglua ├── src │ ├── interface │ │ ├── cvar │ │ │ ├── mod.rs │ │ │ ├── convar.rs │ │ │ └── icvar.rs │ │ ├── engine │ │ │ ├── mod.rs │ │ │ ├── server.rs │ │ │ └── client.rs │ │ ├── net │ │ │ ├── mod.rs │ │ │ ├── message.rs │ │ │ └── channel.rs │ │ ├── panel.rs │ │ ├── lua │ │ │ ├── shared.rs │ │ │ ├── interface.rs │ │ │ ├── mod.rs │ │ │ └── base.rs │ │ ├── materials.rs │ │ ├── client │ │ │ └── mod.rs │ │ ├── mdl.rs │ │ ├── common.rs │ │ └── mod.rs │ ├── lib.rs │ ├── prelude.rs │ ├── userdata │ │ └── mod.rs │ ├── lua │ │ ├── mod.rs │ │ ├── types.rs │ │ ├── globals.rs │ │ └── shared.rs │ └── util │ │ └── mod.rs ├── tests │ └── test.rs └── Cargo.toml ├── examples ├── interfaces │ ├── README.md │ ├── Cargo.toml │ └── src │ │ └── lib.rs ├── is_even │ ├── README.md │ ├── Cargo.toml │ └── src │ │ └── lib.rs ├── vector │ ├── README.md │ ├── Cargo.toml │ └── src │ │ └── lib.rs ├── engine │ ├── Cargo.toml │ ├── README.md │ └── src │ │ └── lib.rs └── exception │ ├── Cargo.toml │ └── src │ └── lib.rs ├── .github └── workflows │ └── ci.yml ├── LICENSE.md └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | Cargo.lock 3 | .vscode -------------------------------------------------------------------------------- /rglua-macros/README.md: -------------------------------------------------------------------------------- 1 | # 🌑 ``rglua-macros`` 2 | > Proc-macros for use with rglua -------------------------------------------------------------------------------- /rustfmt.toml: -------------------------------------------------------------------------------- 1 | hard_tabs = true 2 | format_macro_bodies = false 3 | trailing_comma = "Never" -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = [ 3 | "rglua", 4 | "rglua-macros" 5 | ] 6 | exclude = ["examples"] -------------------------------------------------------------------------------- /rglua-macros/tests/main.rs: -------------------------------------------------------------------------------- 1 | #[test] 2 | fn tests() { 3 | let t = trybuild::TestCases::new(); 4 | t.pass("tests/base.rs"); 5 | } 6 | -------------------------------------------------------------------------------- /rglua/src/interface/cvar/mod.rs: -------------------------------------------------------------------------------- 1 | use super::prelude; 2 | 3 | mod convar; 4 | mod icvar; 5 | 6 | pub use convar::CVar; 7 | pub use icvar::ConVar; 8 | -------------------------------------------------------------------------------- /rglua/src/interface/engine/mod.rs: -------------------------------------------------------------------------------- 1 | use super::{common, materials, prelude}; 2 | 3 | mod client; 4 | mod server; 5 | 6 | pub use client::EngineClient; 7 | pub use server::EngineServer; 8 | -------------------------------------------------------------------------------- /examples/interfaces/README.md: -------------------------------------------------------------------------------- 1 | ## ``interfaces`` 2 | Generic binary module to display usage of a few source interfaces. 3 | 4 | ## interfaces.reloadTextures() 5 | Reloads gmod's texture system -------------------------------------------------------------------------------- /rglua/src/lib.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] 2 | pub mod util; 3 | #[cfg(feature = "interfaces")] 4 | pub mod interface; 5 | 6 | #[macro_use] 7 | pub mod lua; 8 | pub use lua::types; 9 | 10 | pub use rglua_macros::*; 11 | pub mod prelude; 12 | pub mod userdata; 13 | -------------------------------------------------------------------------------- /examples/is_even/README.md: -------------------------------------------------------------------------------- 1 | # 💻 ``is_even`` 2 | Binary module that adds two functions to the existing ``math`` library. 3 | 4 | ## math.is_even(n: number) 5 | Returns ``true`` if the number is even, else false 6 | 7 | ## math.is_odd(n: number) 8 | Returns ``true`` if the number is odd, else false -------------------------------------------------------------------------------- /examples/vector/README.md: -------------------------------------------------------------------------------- 1 | # 🔢 ``vector`` 2 | Binary module that adds some extra functions to the ``Vector`` type. 3 | 4 | ## Vector:IsPositive() 5 | Returns if the vector consists of positive numbers 6 | 7 | ## Vector:GetPow(n: number) 8 | Returns the vector multiplied by itself n times (exp ^) -------------------------------------------------------------------------------- /examples/engine/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "gmod_engine" 3 | description = "Binary module that accesses engine.dll" 4 | version = "0.4.0" 5 | edition = "2021" 6 | publish = false 7 | 8 | [lib] 9 | crate-type = ["cdylib"] 10 | 11 | [dependencies] 12 | rglua = { path = "../../rglua" } 13 | -------------------------------------------------------------------------------- /examples/vector/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "vector" 3 | description = "Binary module that adds some extra functions to the gmod Vector type" 4 | version = "0.1.0" 5 | edition = "2021" 6 | publish = false 7 | 8 | [lib] 9 | crate-type = ["cdylib"] 10 | 11 | [dependencies] 12 | rglua = { path = "../../rglua" } -------------------------------------------------------------------------------- /examples/is_even/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "gmod_is_even" 3 | description = "Binary module that exposes a function called 'is_even' that does what it says." 4 | version = "0.3.0" 5 | edition = "2021" 6 | publish = false 7 | 8 | [lib] 9 | crate-type = ["cdylib"] 10 | 11 | [dependencies] 12 | rglua = { path = "../../rglua" } -------------------------------------------------------------------------------- /examples/exception/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "gmod_exception" 3 | description = "Binary module to display exception handling with rglua" 4 | version = "0.1.0" 5 | edition = "2021" 6 | publish = false 7 | 8 | [lib] 9 | crate-type = ["cdylib"] 10 | 11 | [dependencies] 12 | rglua = { path = "../../rglua" } 13 | thiserror = "1.0.30" 14 | -------------------------------------------------------------------------------- /examples/interfaces/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "gmod_interfaces" 3 | description = "Binary module displaying basic functionality from source interfaces" 4 | version = "0.1.0" 5 | edition = "2021" 6 | publish = false 7 | 8 | [lib] 9 | crate-type = ["cdylib"] 10 | 11 | [dependencies] 12 | rglua = { path = "../../rglua" } 13 | thiserror = "1.0.30" 14 | -------------------------------------------------------------------------------- /rglua/src/prelude.rs: -------------------------------------------------------------------------------- 1 | pub use crate::lua::*; 2 | pub use crate::types::{LuaCFunction, LuaInteger, LuaNumber, LuaState, LuaString}; 3 | pub use crate::userdata::{Angle, Vector}; 4 | 5 | pub use crate::util::dump_stack; 6 | pub use crate::{cstr, iface, printgm, reg, rstr, try_cstr, try_rstr}; 7 | 8 | pub use rglua_macros::{gmod_close, gmod_open, lua_function}; 9 | -------------------------------------------------------------------------------- /rglua/src/interface/net/mod.rs: -------------------------------------------------------------------------------- 1 | use super::prelude; 2 | 3 | #[repr(C)] 4 | #[derive(Debug)] 5 | pub enum NetEnum { 6 | Generic = 0, 7 | LocalPlayer, 8 | OtherPlayers, 9 | Entities, 10 | Sounds, 11 | Events, 12 | UserMessages, 13 | EntMessages, 14 | Voice, 15 | StringTable, 16 | Move, 17 | StringCmd, 18 | SignOn, 19 | Total 20 | } 21 | 22 | mod message; 23 | pub use message::NetMessage; 24 | mod channel; 25 | pub use channel::{NetChannelHandler, NetChannel, NetChannelInfo, CNetChan}; -------------------------------------------------------------------------------- /rglua/tests/test.rs: -------------------------------------------------------------------------------- 1 | #[test] 2 | fn cstr_test() { 3 | use rglua::cstr; 4 | let a_ptr = cstr!("Hello world!"); 5 | unsafe { 6 | assert_eq!(*a_ptr, *(b"Hello world!\0".as_ptr() as *const i8)); 7 | let a_str = std::ffi::CStr::from_ptr(a_ptr); 8 | 9 | assert_eq!(a_str.to_str(), Ok("Hello world!")); 10 | } 11 | } 12 | 13 | #[test] 14 | fn rstr_test() { 15 | use rglua::{cstr, rstr}; 16 | 17 | let a = cstr!("How are you?"); 18 | 19 | let b = rstr!(a); 20 | assert_eq!(b, "How are you?"); 21 | } 22 | -------------------------------------------------------------------------------- /rglua/src/interface/panel.rs: -------------------------------------------------------------------------------- 1 | use super::prelude::*; 2 | /// "VGUI_Panel009" 3 | /// "vgui2" 4 | #[vtable] 5 | pub struct Panel { 6 | #[offset(36)] 7 | pub GetName: extern "C" fn(vguiPanel: u32) -> *const c_char, 8 | 9 | #[offset(41)] 10 | /// PaintTraverse function, notorious for getting you banned from every other source engine game. 11 | /// Lua runs properly here, so maybe you'd want to detour this. 12 | pub PaintTraverse: extern "C" fn(vguiPanel: u32, forceRepaint: bool, allowForce: bool) 13 | } 14 | -------------------------------------------------------------------------------- /rglua/src/interface/net/message.rs: -------------------------------------------------------------------------------- 1 | use super::{prelude::*, NetChannel}; 2 | 3 | #[vtable] 4 | pub struct NetMessage { 5 | #[skip(1)] // Skip destructor 6 | pub SetNetChannel: extern "C" fn(net_channel: *mut NetChannel), 7 | pub SetReliable: extern "C" fn(reliable: bool), 8 | pub Process: extern "C" fn() -> bool, 9 | pub ReadFromBuffer: extern "C" fn(buffer: &mut c_void) -> bool, 10 | pub WriteToBuffer: extern "C" fn(buffer: &mut c_void) -> bool, 11 | pub IsReliable: extern "C" fn() -> bool, 12 | pub GetType: extern "C" fn() -> c_int, 13 | pub GetGroup: extern "C" fn() -> c_int, 14 | pub GetName: extern "C" fn() -> *const c_char, 15 | pub GetNetChannel: extern "C" fn() -> *mut NetChannel, 16 | pub ToString: extern "C" fn() -> *const c_char, 17 | } -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: Build & Lint 2 | on: [push, pull_request] 3 | 4 | jobs: 5 | build: 6 | runs-on: windows-latest 7 | 8 | steps: 9 | - uses: actions/checkout@v2 10 | 11 | - name: Setup Toolchain 12 | uses: actions-rs/toolchain@v1 13 | with: 14 | toolchain: stable 15 | components: clippy 16 | target: x86_64-pc-windows-msvc 17 | 18 | - name: Build 19 | uses: actions-rs/cargo@v1 20 | with: 21 | command: build 22 | args: --verbose 23 | 24 | - name: Clippy 25 | uses: actions-rs/clippy-check@v1 26 | with: 27 | token: ${{ secrets.GITHUB_TOKEN }} 28 | args: --all-features 29 | -------------------------------------------------------------------------------- /rglua-macros/tests/base.rs: -------------------------------------------------------------------------------- 1 | use rglua::prelude::*; 2 | use rglua_macros::{gmod_close, gmod_open, lua_function}; 3 | 4 | #[derive(Debug)] 5 | enum LuaError {} 6 | 7 | 8 | // The errors you return must implement display, to be relayed to gmod. 9 | use std::fmt::{Display, Formatter}; 10 | impl Display for LuaError { 11 | fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { 12 | write!(f, "LuaError") 13 | } 14 | } 15 | 16 | #[lua_function] 17 | fn add(_state: LuaState) -> Result { 18 | Ok(0) 19 | } 20 | 21 | #[gmod_open] 22 | fn entry(_state: LuaState) -> Result { 23 | println!("Hello world!"); 24 | Ok(0) 25 | } 26 | 27 | #[gmod_close] 28 | fn close(_s: LuaState) -> Result { 29 | Ok(0) 30 | } 31 | 32 | // Appease test runner 33 | fn main() {} 34 | -------------------------------------------------------------------------------- /rglua/src/interface/cvar/convar.rs: -------------------------------------------------------------------------------- 1 | use super::icvar::ConCommandBase; 2 | use super::prelude::*; 3 | 4 | // type ChangeCallback = extern "C" fn(var: *mut IConVar, old: *const c_char, fl_old: c_float); 5 | 6 | #[vtable] 7 | pub struct CVar { 8 | pub base: ConCommandBase, 9 | 10 | pub parent: *mut CVar, 11 | pub default_value: *const c_char 12 | /*value: *mut c_char, 13 | len: c_int, 14 | 15 | has_min: bool, 16 | min_value: c_float, 17 | has_max: bool, 18 | max_value: c_float, 19 | 20 | callback: ChangeCallback*/ 21 | } 22 | 23 | impl std::fmt::Debug for CVar { 24 | fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> { 25 | write!( 26 | f, 27 | "CVar {{ base: {:?}, parent: {:?}, default_value: {:?} }}", 28 | self.base, self.parent, self.default_value 29 | ) 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /rglua-macros/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "rglua-macros" 3 | description = "Procedural macros to be used with rglua" 4 | version = "0.3.0" 5 | authors = ["Vurv "] 6 | keywords = ["glua", "garrysmod", "lua", "gmod"] 7 | categories = ["api-bindings", "external-ffi-bindings", "development-tools::ffi", "game-development", "accessibility"] 8 | readme = "README.md" 9 | license = "MIT" 10 | edition = "2021" 11 | repository = "https://github.com/Vurv78/rglua" 12 | 13 | [lib] 14 | proc-macro = true 15 | 16 | [[test]] 17 | name = "tests" 18 | path = "tests/main.rs" 19 | 20 | [dependencies] 21 | proc-macro2 = "1.0.34" 22 | quote = "1.0.10" 23 | syn = { version = "1.0.82", features = ["full"] } 24 | 25 | [dev-dependencies] 26 | trybuild = { version = "1.0.49", features = ["diff"] } 27 | rglua = { path = "../rglua" } 28 | -------------------------------------------------------------------------------- /rglua/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "rglua" 3 | description = "Toolkit for garrysmod development with the source sdk and luajit api" 4 | version = "3.0.0" 5 | authors = ["Vurv "] 6 | keywords = ["glua", "garrysmod", "lua", "gmod"] 7 | categories = ["api-bindings", "external-ffi-bindings", "development-tools::ffi", "game-development", "accessibility"] 8 | readme = "../README.md" 9 | license = "MIT" 10 | edition = "2021" 11 | repository = "https://github.com/Vurv78/rglua" 12 | 13 | # Remember to make your output module a cdylib. 14 | 15 | [dependencies] 16 | libloading = "0.7.2" 17 | once_cell = "1.8.0" 18 | thiserror = "1.0.30" 19 | 20 | rglua-macros = { version = "0.3.0", path = "../rglua-macros" } 21 | 22 | viable = { version = "0.2", optional = true } 23 | 24 | [features] 25 | default = ["interfaces"] 26 | interfaces = ["viable"] -------------------------------------------------------------------------------- /rglua/src/interface/cvar/icvar.rs: -------------------------------------------------------------------------------- 1 | use super::prelude::*; 2 | use super::CVar; 3 | 4 | #[repr(C)] 5 | #[derive(Debug)] 6 | pub struct ConCommandBase { 7 | pub base_vtable: *mut c_void, // 0 8 | pub next: *mut ConCommandBase, // 4 9 | pub registered: bool, // 8 10 | pub name: *const c_char, // 12 11 | pub help_string: *const c_char, // 16 12 | pub flags: c_int // 20 13 | } 14 | 15 | /// This is probably very wrong 16 | /// "VEngineCvar007" 17 | /// "vstdlib" 18 | #[vtable] 19 | pub struct ConVar { 20 | pub RegisterConCommand: extern "C" fn(pCommandBase: *mut ConCommandBase), 21 | pub UnregisterConCommand: extern "C" fn(pCommandBase: *mut ConCommandBase), 22 | #[offset(7)] 23 | pub FindVar: extern "C" fn(var_name: *const c_char) -> *mut CVar, 24 | 25 | #[offset(11)] 26 | pub GetCommands: extern "C" fn() -> *mut ConCommandBase 27 | } 28 | -------------------------------------------------------------------------------- /examples/engine/README.md: -------------------------------------------------------------------------------- 1 | # ⚙️ ``iengine`` 2 | Binary module that adds engine functions from IEngineClientV015 to the ``iengine`` library 3 | 4 | ## iengine.concmd(command: string) 5 | Runs a concommand on yourself, internally calls ``ExecuteClientCmd`` 6 | 7 | ## iengine.getResolution() -> number, number 8 | Returns your screen resolution, internally using ``GetScreenSize`` 9 | 10 | ## iengine.getGameDirectory() -> string 11 | Returns the absolute location of your garrysmod dir, internally using ``GetGameDirectory`` 12 | 13 | ## iengine.getLevel() -> string 14 | Returns the current level/map name, internally using ``GetLevelName`` 15 | 16 | ## iengine.isRecording() -> boolean 17 | Returns ``true`` if you are recording a demo, else ``false``, internally using ``IsRecordingDemo`` 18 | 19 | ## iengine.isPaused() -> boolean 20 | Returns ``true`` if the game is paused, else ``false``, internally using ``IsPaused`` 21 | -------------------------------------------------------------------------------- /examples/exception/src/lib.rs: -------------------------------------------------------------------------------- 1 | use rglua::prelude::*; 2 | 3 | #[derive(Debug, thiserror::Error)] 4 | enum ResultError { 5 | #[error("Number was negative!")] 6 | Negative, 7 | #[error("Number greater than 5!")] 8 | Catastrophic 9 | } 10 | 11 | #[lua_function] 12 | fn result(l: LuaState) -> Result { 13 | let num = luaL_checkinteger(l, 1); 14 | 15 | if num > 5 { 16 | return Err( ResultError::Catastrophic ) 17 | } else if num < 0 { 18 | return Err( ResultError::Negative ) 19 | } else { 20 | lua_pushinteger(l, num); 21 | return Ok(1) 22 | } 23 | } 24 | 25 | #[gmod_open] 26 | fn open(l: LuaState) -> i32 { 27 | printgm!(l, "Loaded exception module!"); 28 | 29 | let lib = reg! [ 30 | // "panic" => panic, (Soon™️) 31 | "result" => result 32 | ]; 33 | 34 | luaL_register(l, cstr!("except"), lib.as_ptr()); 35 | 0 36 | } 37 | 38 | #[gmod_close] 39 | fn close(_l: LuaState) -> i32 { 40 | 0 41 | } 42 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Vurv 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /rglua/src/interface/lua/shared.rs: -------------------------------------------------------------------------------- 1 | use super::interface::LuaInterface; 2 | use super::prelude::*; 3 | /// 4 | /// This doesn't work on x86. =( 5 | #[vtable] 6 | pub struct LuaShared { 7 | #[skip(2)] // ~LuaShared, Init 8 | pub Shutdown: extern "C" fn(), 9 | pub DumpStats: extern "C" fn(), 10 | pub CreateLuaInterface: extern "C" fn(realm: c_uchar, b: bool) -> *mut LuaInterface, 11 | pub CloseLuaInterface: extern "C" fn(iface: *mut LuaInterface), 12 | 13 | /// 0 - Client 14 | /// 1 - Server 15 | /// 2 - Menu 16 | pub GetLuaInterface: extern "C" fn(realm: c_uchar) -> *mut LuaInterface, 17 | #[skip(2)] // LoadFile, GetCache 18 | pub MountLua: extern "C" fn(l: *const c_char), 19 | pub MountLuaAdd: extern "C" fn(l: *const c_char, l2: *const c_char), 20 | pub UnMountLua: extern "C" fn(l: *const c_char), 21 | pub SetFileContents: extern "C" fn(l: *const c_char, c: *const c_char), 22 | pub SetLuaFindHook: extern "C" fn(p: *mut c_void), 23 | #[skip(1)] // FindScripts 24 | pub GetStackTraces: extern "C" fn() -> *const c_char, 25 | #[skip(1)] // InvalidateCache 26 | pub EmptyCache: extern "C" fn(), 27 | } 28 | -------------------------------------------------------------------------------- /rglua/src/userdata/mod.rs: -------------------------------------------------------------------------------- 1 | macro_rules! udata { 2 | ( 3 | $(#[$outer:meta])* 4 | $vis:vis struct $name:ident { 5 | $( 6 | $fieldvis:vis $field:ident: $ty:ty 7 | ),* 8 | } 9 | $($rest:tt)* 10 | ) => { 11 | #[repr(C)] 12 | #[derive( 13 | PartialEq, 14 | PartialOrd, 15 | Debug, 16 | Default, 17 | Copy, 18 | Clone 19 | )] 20 | $(#[$outer])* 21 | $vis struct $name { 22 | $( 23 | $fieldvis $field: $ty 24 | ),* 25 | } 26 | 27 | impl $name { 28 | pub fn new( $($field: $ty),* ) -> $name { 29 | $name { 30 | $($field),* 31 | } 32 | } 33 | } 34 | udata!( $($rest)* ); 35 | }; 36 | () => (); 37 | } 38 | 39 | udata! { 40 | // https://github.com/danielga/sourcesdk-minimal/blob/cab3e07edc4a41e7e69ea645ea51c1e5c5d1be71/public/mathlib/vector.h#L66 41 | /// Floating point vector type created by the Vector() function in lua and Vector::new() in Rust. 42 | pub struct Vector { 43 | pub x: f32, 44 | pub y: f32, 45 | pub z: f32 46 | } 47 | 48 | // https://github.com/danielga/sourcesdk-minimal/blob/cab3e07edc4a41e7e69ea645ea51c1e5c5d1be71/public/mathlib/vector.h#L1765 49 | /// Euler angle type. 50 | /// This is a QAngle in the source engine. 51 | pub struct Angle { 52 | pub p: f32, 53 | pub y: f32, 54 | pub r: f32 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /examples/is_even/src/lib.rs: -------------------------------------------------------------------------------- 1 | use rglua::prelude::*; 2 | 3 | // The functions we want to provide to lua 4 | #[lua_function] 5 | fn is_even(l: LuaState) -> i32 { 6 | let num = luaL_checkinteger(l, 1); 7 | // Ask for the first argument of the function. 8 | // If this is the wrong type or missing, an error will be thrown to lua (if you don't want this, use the lua_to* functions) 9 | 10 | lua_pushboolean(l, (num % 2 == 0) as i32); 11 | 12 | // This returns one value 13 | 1 14 | } 15 | 16 | #[lua_function] 17 | fn is_odd(l: LuaState) -> i32 { 18 | let num = luaL_checkinteger(l, 1); 19 | 20 | lua_pushboolean(l, (num % 2 != 0) as i32); 21 | 1 22 | } 23 | 24 | // Note that since this is #[gmod_open] the name of the function does not matter 25 | // This is the same for #[gmod_close] 26 | #[gmod_open] 27 | fn open(l: LuaState) -> i32 { 28 | // Print to the gmod console 29 | printgm!(l, "Loaded is_even module!"); 30 | 31 | // Create a library to organize all of our functions to export to gmod. 32 | let lib = reg! [ 33 | "is_even" => is_even, 34 | "is_odd" => is_odd 35 | ]; 36 | 37 | // Register our functions in ``_G.math`` 38 | // This WILL NOT overwrite _G.math if it already exists (which it should..) 39 | luaL_register(l, cstr!("math"), lib.as_ptr()); 40 | 1 41 | } 42 | 43 | #[gmod_close] 44 | fn close(l: LuaState) -> i32 { 45 | printgm!(l, "Goodbye garrysmod!"); 46 | 0 47 | } -------------------------------------------------------------------------------- /examples/vector/src/lib.rs: -------------------------------------------------------------------------------- 1 | use rglua::prelude::*; 2 | 3 | #[lua_function] 4 | fn is_positive(l: LuaState) -> i32 { 5 | let vec = luaL_checkvector(l, 1); 6 | lua_pushboolean(l, (vec.x > 0.0 && vec.y > 0.0 && vec.z > 0.0) as i32); 7 | 1 8 | } 9 | 10 | #[lua_function] 11 | fn get_pow(l: LuaState) -> i32 { 12 | let vec = luaL_checkvector(l, 1); 13 | let by = luaL_checknumber(l, 2) as f32; 14 | 15 | lua_pushvector(l, Vector::new(vec.x.powf(by), vec.y.powf(by), vec.z.powf(by))); 16 | 1 17 | } 18 | 19 | // Note that since this is #[gmod_open] the name of the function does not matter 20 | // This is the same for #[gmod_close] 21 | #[gmod_open] 22 | fn open(l: LuaState) -> i32 { 23 | // Create a library consisting of functions to export to gmod. 24 | let lib = reg! [ 25 | "IsPositive" => is_positive, 26 | "GetPow" => get_pow 27 | ]; 28 | 29 | // Get the ``Vector`` metatable from the lua registry and put it onto the stack. 30 | luaL_getmetatable(l, cstr!("Vector")); 31 | 32 | // Give a null pointer as the libname so that luaL_register knows we are trying to instead add these functions to the value on top of the stack; 33 | // This being the Vector metatable at (-1). 34 | luaL_register(l, std::ptr::null(), lib.as_ptr()); 35 | 36 | // Return nothing (0 objects) 37 | 0 38 | } 39 | 40 | #[gmod_close] 41 | fn close(l: LuaState) -> i32 { 42 | printgm!(l, "Goodbye garrysmod!"); 43 | 0 44 | } -------------------------------------------------------------------------------- /examples/interfaces/src/lib.rs: -------------------------------------------------------------------------------- 1 | use rglua::prelude::*; 2 | use rglua::interface::{self, NetChannel, CNetChan}; 3 | 4 | #[lua_function] 5 | fn reload_textures(_l: LuaState) -> Result { 6 | let matsys = iface!(MaterialSystem)?; 7 | matsys.ReloadTextures(); 8 | 9 | Ok(0) 10 | } 11 | 12 | #[lua_function] 13 | fn disconnect(l: LuaState) -> Result { 14 | let msg = luaL_checkstring(l, 1); 15 | let engine = iface!(EngineClient)?; 16 | 17 | let chan = engine.GetNetChannelInfo() as *mut CNetChan; 18 | let chan = unsafe { chan.as_mut() } 19 | .ok_or(interface::Error::AsMut)?; 20 | 21 | printgm!(l, "{:?}", try_rstr!(chan.GetAddress())); 22 | 23 | chan.Clear(); 24 | chan.Shutdown(msg); 25 | return Ok(0); 26 | } 27 | 28 | #[gmod_open] 29 | fn open(l: LuaState) -> Result { 30 | // Access the lua state when you aren't directly given it. 31 | let lua_shared = iface!(LuaShared)?; 32 | 33 | // 0 to get client state. this will error if you try and run the binary module on the server or menu realms. 34 | let client = unsafe { lua_shared.GetLuaInterface(0).as_mut() } 35 | .ok_or(interface::Error::AsMut)?; 36 | 37 | printgm!(client.base as _, "Hello from ILuaShared!"); 38 | 39 | let lib = reg! [ 40 | "reloadTextures" => reload_textures, 41 | "disconnect" => disconnect 42 | ]; 43 | 44 | luaL_register(l, cstr!("interfaces"), lib.as_ptr()); 45 | 46 | Ok(0) 47 | } 48 | 49 | #[gmod_close] 50 | fn close(_l: LuaState) -> i32 { 51 | 0 52 | } -------------------------------------------------------------------------------- /rglua/src/interface/lua/interface.rs: -------------------------------------------------------------------------------- 1 | use super::base::LuaBase; 2 | use super::prelude::*; 3 | use super::LuaObject; 4 | 5 | /// 6 | /// Basically what is given to ordinary C++ binary modules that do not interface with lua_shared. 7 | /// You can use this but should really just use the lua_shared bindings. 8 | #[vtable] 9 | pub struct LuaInterface { 10 | pub base: *mut *mut LuaBase, 11 | 12 | #[offset(1)] 13 | pub Shutdown: extern "C" fn(), 14 | pub Cycle: extern "C" fn(), 15 | 16 | #[offset(3)] 17 | pub Global: extern "C" fn() -> *mut LuaObject, 18 | pub GetObject: extern "C" fn(index: c_int) -> *mut LuaObject, 19 | pub PushLuaObject: extern "C" fn(o: *mut LuaObject), 20 | pub PushLuaFunction: extern "C" fn(f: crate::types::LuaCFunction), 21 | pub LuaError: extern "C" fn(err: *const c_char, idx: c_int), 22 | pub TypeError: extern "C" fn(name: *const c_char, idx: c_int), 23 | pub CallInternal: extern "C" fn(args: c_int, rets: c_int), 24 | 25 | #[offset(20)] 26 | pub IsServer: extern "C" fn() -> bool, 27 | 28 | #[offset(21)] 29 | pub IsClient: extern "C" fn() -> bool, 30 | 31 | #[offset(22)] 32 | pub IsMenu: extern "C" fn() -> bool, 33 | 34 | #[offset(37)] 35 | pub RunString: extern "C" fn( 36 | filename: *const c_char, 37 | path: *const c_char, 38 | code: *const c_char, 39 | run: bool, 40 | show_errors: bool 41 | ) -> bool, 42 | 43 | #[offset(39)] 44 | pub Error: extern "C" fn(err: *const c_char), 45 | 46 | #[offset(45)] 47 | pub ErrorNoHalt: extern "C" fn(fmt: *const c_char, ...), 48 | pub Msg: extern "C" fn(fmt: *const c_char, ...) 49 | } 50 | -------------------------------------------------------------------------------- /rglua/src/interface/materials.rs: -------------------------------------------------------------------------------- 1 | use super::prelude::*; 2 | use viable::vtable; 3 | 4 | #[vtable] 5 | /// You do not get this through creating an interface, it is instead exported by other interface functions. 6 | pub struct Material { 7 | pub GetName: extern "C" fn() -> *const c_char, 8 | pub GetTextureGroupName: extern "C" fn() -> *const c_char, 9 | 10 | #[offset(17)] 11 | pub IsTranslucent: extern "C" fn() -> bool, 12 | pub IsAlphaTested: extern "C" fn() -> bool, 13 | pub IsVertexLit: extern "C" fn() -> bool, 14 | 15 | 16 | #[offset(31)] 17 | pub GetReflectivity: extern "C" fn(reflect: &mut Vector), 18 | 19 | #[offset(34)] 20 | pub SetShader: extern "C" fn(shader: *const c_char), 21 | 22 | #[offset(37)] 23 | pub Refresh: extern "C" fn(), 24 | 25 | #[offset(42)] 26 | pub IsErrorMaterial: extern "C" fn() -> bool 27 | } 28 | 29 | pub type MaterialHandle = c_ushort; 30 | 31 | /// "VMaterialSystem080" 32 | /// "materialsystem.dll" 33 | #[vtable] 34 | pub struct MaterialSystem { 35 | #[offset(72)] 36 | pub ReloadTextures: extern "C" fn(), 37 | pub ReloadMaterials: extern "C" fn(pSubString: *const c_char), 38 | 39 | pub CreateMaterial: 40 | extern "C" fn(mat_name: *const c_char, vmt_kv: *const c_void) -> *mut c_void, 41 | pub FindMaterial: extern "C" fn( 42 | mat_name: *const c_char, 43 | texture_group_name: *const c_char, 44 | complain: bool, 45 | complain_prefix: *const c_char 46 | ) -> *mut c_void, 47 | 48 | #[offset(77)] 49 | pub FirstMaterial: extern "C" fn() -> MaterialHandle, 50 | pub NextMaterial: extern "C" fn(handle: MaterialHandle) -> MaterialHandle, 51 | pub InvalidMaterial: extern "C" fn() -> MaterialHandle, 52 | pub GetMaterial: extern "C" fn(handle: MaterialHandle) -> *mut c_void 53 | } 54 | -------------------------------------------------------------------------------- /rglua/src/interface/client/mod.rs: -------------------------------------------------------------------------------- 1 | use super::{prelude::*, net::{NetChannelHandler, NetChannel, NetMessage}}; 2 | #[vtable] 3 | /// Client retrieved from Server interface. 4 | pub struct Client { 5 | base: *mut *mut NetChannelHandler, 6 | 7 | #[skip(1)] // Skip destructor 8 | Connect: extern "C" fn(name: *const c_char, userid: c_int, chan: *mut NetChannel, fakeply: bool, challenge: c_int) -> bool, 9 | Inactivate: extern "C" fn(), 10 | Reconnect: extern "C" fn(), 11 | 12 | // Variadics don't work so.. 13 | Disconnect: extern "C" fn(reason: *const c_char, ...), 14 | GetPlayerSlot: extern "C" fn() -> c_int, 15 | GetUserID: extern "C" fn() -> c_int, 16 | // GetNetworkID: extern "C" fn() -> UserID, 17 | 18 | #[skip(1)] 19 | GetClientName: extern "C" fn() -> *const c_char, 20 | GetNetChannel: extern "C" fn() -> *mut NetChannel, 21 | // GetServer: extern "C" fn() -> *mut Server, 22 | 23 | #[skip(1)] 24 | GetUserSetting: extern "C" fn(cvar: *const c_char) -> *const c_char, 25 | GetNetworkIDString: extern "C" fn() -> *const c_char, 26 | 27 | SetRate: extern "C" fn(rate: c_int, force: bool), 28 | GetRate: extern "C" fn() -> c_int, 29 | 30 | SetUpdateRate: extern "C" fn(rate: c_int, force: bool), 31 | GetUpdateRate: extern "C" fn() -> c_int, 32 | 33 | Clear: extern "C" fn(), 34 | GetMaxAckTickCount: extern "C" fn() -> c_int, 35 | ExecuteStringCommand: extern "C" fn(command: *const c_char) -> bool, 36 | SendNetMsg: extern "C" fn(msg: &mut NetMessage, force_reliable: bool), 37 | ClientPrint: extern "C" fn(msg: *const c_char, ...), 38 | IsConnected: extern "C" fn() -> bool, 39 | IsSpawned: extern "C" fn() -> bool, 40 | IsActive: extern "C" fn() -> bool, 41 | IsFakeClient: extern "C" fn() -> bool, 42 | IsHLTV: extern "C" fn() -> bool, 43 | 44 | // IsReplay ? 45 | 46 | IsHearingClient: extern "C" fn(id: c_int) -> bool, 47 | IsProximityHearingClient: extern "C" fn(id: c_int) -> bool, 48 | SetMaxRoutablePayloadSize: extern "C" fn(size: c_int), 49 | } -------------------------------------------------------------------------------- /rglua/src/interface/lua/mod.rs: -------------------------------------------------------------------------------- 1 | pub(crate) use super::prelude::{self, *}; 2 | 3 | #[vtable] 4 | pub struct LuaObject { 5 | pub Set: extern "C" fn(obj: *mut LuaObject), 6 | pub SetFromStack: extern "C" fn(i: c_int), 7 | pub Unreference: extern "C" fn(), 8 | pub GetType: extern "C" fn() -> c_int, 9 | pub GetString: extern "C" fn() -> *const c_char, 10 | pub GetFloat: extern "C" fn() -> c_float, 11 | pub GetInt: extern "C" fn() -> c_int, 12 | pub GetUserdata: extern "C" fn() -> *mut c_void, 13 | 14 | pub SetMember: extern "C" fn(name: *const c_char), 15 | pub SetMemberObj: extern "C" fn(name: *const c_char, obj: *mut LuaObject), 16 | pub SetMemberFloat: extern "C" fn(name: *const c_char, f: c_float), 17 | pub SetMemberBool: extern "C" fn(name: *const c_char, b: bool), 18 | pub SetMemberStr: extern "C" fn(name: *const c_char, s: *const c_char), 19 | //pub SetMemberFunc: extern "C" fn(name: *const c_char, func: crate::types::LuaCFunction), 20 | #[offset(14)] 21 | pub GetMemberBool: extern "C" fn(name: *const c_char, default: bool) -> bool, 22 | pub GetMemberInt: extern "C" fn(name: *const c_char, default: c_int) -> c_int, 23 | pub GetMemberFloat: extern "C" fn(name: *const c_char, default: c_float) -> c_float, 24 | pub GetMemberStr: extern "C" fn(name: *const c_char, default: *const c_char) -> *const c_char, 25 | pub GetMemberUserdata: extern "C" fn(name: *const c_char, default: *mut c_void) -> *mut c_void, 26 | pub GetMemberUserdataNum: extern "C" fn(ind: c_float, default: *mut c_void) -> *mut c_void, 27 | 28 | pub SetMetatable: extern "C" fn(mt: *mut LuaObject), 29 | pub SetUserdata: extern "C" fn(ud: *mut c_void), 30 | 31 | pub Push: extern "C" fn(), 32 | pub isNil: extern "C" fn() -> bool, 33 | pub isTable: extern "C" fn() -> bool, 34 | pub isString: extern "C" fn() -> bool, 35 | pub isNumber: extern "C" fn() -> bool, 36 | pub isFunction: extern "C" fn() -> bool, 37 | pub isUserdata: extern "C" fn() -> bool, 38 | 39 | pub GetMemberF: extern "C" fn(key: c_float) -> *mut LuaObject 40 | } 41 | 42 | mod base; 43 | mod interface; 44 | mod shared; 45 | 46 | pub use base::LuaBase; 47 | pub use interface::LuaInterface; 48 | pub use shared::LuaShared; 49 | -------------------------------------------------------------------------------- /rglua/src/interface/mdl.rs: -------------------------------------------------------------------------------- 1 | use super::common::StudioHdr; 2 | use super::prelude::*; 3 | 4 | #[repr(C)] 5 | pub enum MDLCacheDataType { 6 | // Callbacks to get called when data is loaded or unloaded for these: 7 | StudioHDR = 0, 8 | StudioHWData, 9 | VCollide, 10 | 11 | // Callbacks NOT called when data is loaded or unloaded for these: 12 | AnimBlock, 13 | VirtualModel, 14 | Vertexes, 15 | DecodedAnimBlock 16 | } 17 | 18 | #[vtable] 19 | pub struct MdlCacheNotify { 20 | /// Called right after data is loaded 21 | pub OnDataLoaded: extern "C" fn(ty: MDLCacheDataType, handle: MDLHandle), 22 | /// Called right before data is unloaded 23 | pub OnDataUnloaded: extern "C" fn(ty: MDLCacheDataType, handle: MDLHandle) 24 | } 25 | 26 | pub type MDLHandle = c_ushort; 27 | pub type VirtualModel = c_void; // Todo? 28 | 29 | const MAX_NUM_LODS: usize = 8; 30 | 31 | #[repr(C)] 32 | pub struct VertexFileHeader { 33 | id: c_int, 34 | version: c_int, 35 | checksum: c_int, 36 | numLODs: c_int, 37 | numLODVertexes: [c_int; MAX_NUM_LODS], 38 | numFixups: c_int, 39 | fixupTableStart: c_int, 40 | vertexDataStart: c_int, 41 | tangentDataStart: c_int 42 | } 43 | 44 | #[vtable] 45 | /// "MDLCache004" 46 | /// "datacache" 47 | pub struct MdlCache { 48 | pub SetCacheNotify: extern "C" fn(pNotify: *mut MdlCacheNotify), 49 | pub FindMDL: extern "C" fn(pMDLRelativePath: *const c_char) -> MDLHandle, 50 | pub AddRef: extern "C" fn(handle: MDLHandle) -> c_int, 51 | pub Release: extern "C" fn(handle: MDLHandle) -> c_int, 52 | pub GetRef: extern "C" fn(handle: MDLHandle) -> c_int, 53 | pub GetStudioHdr: extern "C" fn(handle: MDLHandle) -> *mut StudioHdr, 54 | 55 | #[offset(9)] 56 | pub GetVirtualModel: extern "C" fn(handle: MDLHandle) -> *mut VirtualModel, 57 | 58 | #[offset(11)] 59 | pub GetVertexData: extern "C" fn(handle: MDLHandle) -> *mut VertexFileHeader, 60 | pub TouchAllData: extern "C" fn(handle: MDLHandle) -> (), 61 | pub SetUserData: extern "C" fn(handle: MDLHandle, pData: *mut c_void) -> (), 62 | pub GetUserData: extern "C" fn(handle: MDLHandle) -> *mut c_void, 63 | pub IsErrorModel: extern "C" fn(handle: MDLHandle) -> bool, 64 | 65 | #[offset(18)] 66 | pub GetModelName: extern "C" fn(handle: MDLHandle) -> *const c_char, 67 | pub GetVirtualModelFast: 68 | extern "C" fn(pStudioHdr: *const StudioHdr, handle: MDLHandle) -> *mut VirtualModel, 69 | pub BeginLock: extern "C" fn(), 70 | pub EndLock: extern "C" fn() 71 | } 72 | -------------------------------------------------------------------------------- /rglua/src/lua/mod.rs: -------------------------------------------------------------------------------- 1 | use libloading::Library; 2 | use std::path::PathBuf; 3 | 4 | use once_cell::sync::Lazy; 5 | 6 | mod shared; 7 | pub use shared::*; 8 | 9 | mod globals; 10 | pub use globals::*; 11 | 12 | pub mod types; 13 | pub use types::*; 14 | 15 | /// Path to lua_shared dynamic library, found relative to [std::env::current_dir] 16 | #[cfg(all(target_os = "windows", target_arch = "x86_64"))] 17 | pub static LUA_SHARED_PATH: Lazy> = 18 | Lazy::new(|| Some(PathBuf::from("bin/win64/lua_shared.dll"))); 19 | 20 | #[cfg(all(target_os = "windows", target_arch = "x86"))] 21 | /// Path to lua_shared dynamic library, found relative to [std::env::current_dir] 22 | pub static LUA_SHARED_PATH: Lazy> = Lazy::new(|| { 23 | let gmod = std::env::current_dir().expect("Failed to get current dir"); 24 | 25 | for path in ["garrysmod/bin/lua_shared.dll", "bin/lua_shared.dll"] { 26 | let full = gmod.join(path); 27 | if full.exists() { 28 | return Some(full); 29 | } 30 | } 31 | None 32 | }); 33 | 34 | #[cfg(all(target_os = "macos"))] 35 | /// Path to lua_shared dynamic library, found relative to [std::env::current_dir] 36 | pub static LUA_SHARED_PATH: Lazy> = 37 | Lazy::new(|| Some(PathBuf::from("garrysmod/bin/lua_shared.dylib"))); 38 | 39 | #[cfg(all(target_os = "linux", target_arch = "x86"))] 40 | pub static LUA_SHARED_PATH: Lazy> = Lazy::new(|| { 41 | let gmod = std::env::current_dir().expect("Failed to get current dir"); 42 | 43 | for path in [ 44 | "garrysmod/bin/lua_shared_srv.so", 45 | "garrysmod/bin/lua_shared.so", 46 | "bin/linux32/lua_shared.so", 47 | "bin/linux32/lua_shared_client.so" 48 | ] { 49 | let full = gmod.join(path); 50 | if full.exists() { 51 | return Some(full); 52 | } 53 | } 54 | None 55 | }); 56 | 57 | #[cfg(all(target_os = "linux", target_arch = "x86_64"))] 58 | /// Path to lua_shared dynamic library, found relative to [std::env::current_dir] 59 | pub static LUA_SHARED_PATH: Lazy> = Lazy::new(|| { 60 | let gmod = std::env::current_dir().expect("Failed to get current dir"); 61 | 62 | for path in [ 63 | "bin/linux64/lua_shared.so", 64 | "bin/linux64/lua_shared_client.so" 65 | ] { 66 | let full = gmod.join(path); 67 | if full.exists() { 68 | return Some(full); 69 | } 70 | } 71 | None 72 | }); 73 | 74 | /// This tries to retrieve [LUA_SHARED_PATH], creates a [libloading::Library] to it and returns it. 75 | /// If it could not find lua_shared.dll or create a [libloading::Library], this will panic! 76 | pub static LUA_SHARED_RAW: Lazy = Lazy::new(|| { 77 | let path = LUA_SHARED_PATH 78 | .as_ref() 79 | .expect("Couldn't find lua_shared dylib!"); 80 | unsafe { Library::new(path).expect("Could not open library") } 81 | }); 82 | -------------------------------------------------------------------------------- /rglua/src/interface/common.rs: -------------------------------------------------------------------------------- 1 | use super::prelude::*; 2 | 3 | #[repr(C)] 4 | #[allow(non_snake_case)] 5 | #[derive(Debug)] 6 | pub struct PlayerInfo { 7 | unknown: u64, 8 | xuid: u64, 9 | name: [i8; 32], 10 | unknown01: [char; 96], 11 | m_szPlayerName: [char; 128], 12 | m_nUserID: i32, 13 | m_szSteamID: [char; 33], 14 | m_nSteam3ID: u32, 15 | userID: i32, 16 | guid: [char; 33], 17 | friendsID: i32, 18 | fakeplayer: bool, 19 | ishltv: bool, 20 | customFiles: [u64; 4], 21 | filesDownloaded: u8, 22 | pad: [i8; 304] 23 | } 24 | 25 | #[repr(C)] 26 | pub struct StudioHdr { 27 | pub id: c_int, 28 | pub version: c_int, 29 | pub checksum: c_int, 30 | 31 | pub name: [c_char; 64], 32 | pub length: c_int, 33 | 34 | pub eyeposition: Vector, 35 | pub illumposition: Vector, 36 | pub hull_min: Vector, 37 | pub hull_max: Vector, 38 | pub view_bbmin: Vector, 39 | pub view_bbmax: Vector, 40 | pub flags: c_int, 41 | pub numbones: c_int, 42 | pub boneindex: c_int, 43 | pub numbonecontrollers: c_int, 44 | pub bonecontrollerindex: c_int, 45 | pub numhitboxsets: c_int, 46 | pub hitboxsetindex: c_int 47 | } 48 | 49 | #[repr(C)] 50 | pub enum ButtonCode { 51 | Invalid = -1, 52 | None = 0, 53 | 54 | Key0, 55 | Key1, 56 | Key2, 57 | Key3, 58 | Key4, 59 | Key5, 60 | Key6, 61 | Key7, 62 | Key8, 63 | Key9, 64 | KeyA, 65 | KeyB, 66 | KeyC, 67 | KeyD, 68 | KeyE, 69 | KeyF, 70 | KeyG, 71 | KeyH, 72 | KeyI, 73 | KeyJ, 74 | KeyK, 75 | KeyL, 76 | KeyM, 77 | KeyN, 78 | KeyO, 79 | KeyP, 80 | KeyQ, 81 | KeyR, 82 | KeyS, 83 | KeyT, 84 | KeyU, 85 | KeyV, 86 | KeyW, 87 | KeyX, 88 | KeyY, 89 | KeyZ, 90 | KeyPad0, 91 | KeyPad1, 92 | KeyPad2, 93 | KeyPad3, 94 | KeyPad4, 95 | KeyPad5, 96 | KeyPad6, 97 | KeyPad7, 98 | KeyPad8, 99 | KeyPad9, 100 | KeyPadDIVIDE, 101 | KeyPadMULTIPLY, 102 | KeyPadMINUS, 103 | KeyPadPLUS, 104 | KeyPadENTER, 105 | KeyPadDECIMAL, 106 | KeyLBRACKET, 107 | KeyRBRACKET, 108 | KeySEMICOLON, 109 | KeyAPOSTROPHE, 110 | KeyBACKQUOTE, 111 | KeyCOMMA, 112 | KeyPERIOD, 113 | KeySLASH, 114 | KeyBACKSLASH, 115 | KeyMINUS, 116 | KeyEQUAL, 117 | KeyENTER, 118 | KeySPACE, 119 | KeyBACKSPACE, 120 | KeyTAB, 121 | KeyCAPSLOCK, 122 | KeyNUMLOCK, 123 | KeyESCAPE, 124 | KeySCROLLLOCK, 125 | KeyINSERT, 126 | KeyDELETE, 127 | KeyHOME, 128 | KeyEND, 129 | KeyPAGEUP, 130 | KeyPAGEDOWN, 131 | KeyBREAK, 132 | KeyLSHIFT, 133 | KeyRSHIFT, 134 | KeyLALT, 135 | KeyRALT, 136 | KeyLCONTROL, 137 | KeyRCONTROL, 138 | KeyLWIN, 139 | KeyRWIN, 140 | KeyAPP, 141 | KeyUP, 142 | KeyLEFT, 143 | KeyDOWN, 144 | KeyRIGHT, 145 | KeyF1, 146 | KeyF2, 147 | KeyF3, 148 | KeyF4, 149 | KeyF5, 150 | KeyF6, 151 | KeyF7, 152 | KeyF8, 153 | KeyF9, 154 | KeyF10, 155 | KeyF11, 156 | KeyF12, 157 | KeyCAPSLOCKTOGGLE, 158 | KeyNUMLOCKTOGGLE, 159 | KeySCROLLLOCKTOGGLE, 160 | 161 | // Mouse 162 | MouseLeft, 163 | MouseRight, 164 | MouseMiddle, 165 | Mouse4, 166 | Mouse5, 167 | MouseWheelUp, // A fake button which is 'pressed' and 'released' when the wheel is moved up 168 | MouseWheelDown // A fake button which is 'pressed' and 'released' when the wheel is moved down 169 | } 170 | 171 | #[allow(non_upper_case_globals)] 172 | impl ButtonCode { 173 | pub const KeyFIRST: Self = Self::None; 174 | pub const KeyNONE: Self = Self::KeyFIRST; 175 | pub const KeyLAST: Self = Self::KeySCROLLLOCKTOGGLE; 176 | pub const KeyCOUNT: i32 = (Self::KeyLAST as i32 - Self::KeyFIRST as i32 + 1); 177 | } 178 | 179 | #[repr(C)] 180 | pub enum SkyboxVisibility { 181 | NotVisible, 182 | Visible3D, 183 | Visible2D 184 | } -------------------------------------------------------------------------------- /rglua/src/interface/lua/base.rs: -------------------------------------------------------------------------------- 1 | use super::prelude::*; 2 | use crate::userdata::{Angle, Vector}; 3 | 4 | use crate::lua::LuaCFunction; 5 | 6 | #[vtable] 7 | pub struct LuaBase { 8 | pub state: crate::types::LuaState, 9 | 10 | /// Returns the amount of values on the stack 11 | pub Top: extern "C" fn() -> c_int, 12 | pub Push: extern "C" fn(iStackPos: c_int), 13 | pub Pop: extern "C" fn(iAmt: c_int), 14 | pub GetTable: extern "C" fn(iStackPos: c_int), 15 | pub GetField: extern "C" fn(iStackPos: c_int, strName: *const c_char), 16 | pub SetField: extern "C" fn(iStackPos: c_int, strName: *const c_char), 17 | pub CreateTable: extern "C" fn(), 18 | pub SetTable: extern "C" fn(iStackPos: c_int), 19 | pub SetMetaTable: extern "C" fn(iStackPos: c_int), 20 | pub GetMetaTable: extern "C" fn(iStackPos: c_int) -> bool, 21 | pub Call: extern "C" fn(iArgs: c_int, iResults: c_int), 22 | pub PCall: extern "C" fn(iArgs: c_int, iResults: c_int, iErrorFunc: c_int) -> c_int, 23 | pub Equal: extern "C" fn(iStackPos1: c_int, iStackPos2: c_int) -> c_int, 24 | pub RawEqual: extern "C" fn(iStackPos1: c_int, iStackPos2: c_int) -> c_int, 25 | pub Insert: extern "C" fn(iStackPos: c_int), 26 | pub Remove: extern "C" fn(iStackPos: c_int), 27 | pub Next: extern "C" fn(iStackPos: c_int), 28 | #[deprecated = "Use usertype functions"] 29 | pub NewUserdata: extern "C" fn(iSize: c_uint) -> *mut c_void, 30 | pub ThrowError: extern "C" fn(strError: *const c_char) -> !, 31 | pub CheckType: extern "C" fn(iStackPos: c_int, iType: c_int), 32 | pub ArgError: extern "C" fn(iArgNum: c_int, strMessage: *const c_char) -> !, 33 | pub RawGet: extern "C" fn(iStackPos: c_int), 34 | pub RawSet: extern "C" fn(iStackPos: c_int), 35 | pub GetString: extern "C" fn(iStackPos: c_int, iOutLen: *mut c_uint) -> *const c_char, 36 | pub GetNumber: extern "C" fn(iStackPos: c_int) -> c_double, 37 | pub GetBool: extern "C" fn(iStackPos: c_int) -> bool, 38 | pub GetCFunction: extern "C" fn(iStackPos: c_int) -> LuaCFunction, 39 | #[deprecated = "Use usertype functions"] 40 | pub GetUserdata: extern "C" fn(iStackPos: c_int) -> *mut c_void, 41 | 42 | pub PushNil: extern "C" fn(), 43 | pub PushString: extern "C" fn(val: *const c_char, ilen: c_uint), 44 | pub PushNumber: extern "C" fn(val: c_double), 45 | pub PushBool: extern "C" fn(val: bool), 46 | pub PushCFunction: extern "C" fn(val: LuaCFunction), 47 | pub PushCClosure: extern "C" fn(val: LuaCFunction, iUpValues: c_int), 48 | #[deprecated] 49 | pub PushUserdata: extern "C" fn(val: *mut c_void), 50 | 51 | pub ReferenceCreate: extern "C" fn(iType: c_int) -> c_int, 52 | pub ReferenceFree: extern "C" fn(iRef: c_int), 53 | pub ReferencePush: extern "C" fn(iRef: c_int), 54 | pub PushSpecial: extern "C" fn(iType: c_int), 55 | pub IsType: extern "C" fn(iStackPos: c_int, iType: c_int) -> bool, 56 | pub GetType: extern "C" fn(iStackPos: c_int) -> c_int, 57 | pub GetTypeName: extern "C" fn(iType: c_int) -> *const c_char, 58 | 59 | #[deprecated] 60 | pub CreateMetaTableType: extern "C" fn(strName: *const c_char, iType: c_int), 61 | pub CheckString: extern "C" fn(iStackPos: c_int) -> *const c_char, 62 | pub CheckNumber: extern "C" fn(iStackPos: c_int) -> c_double, 63 | pub ObjLen: extern "C" fn(iStackPos: c_int) -> c_int, 64 | 65 | pub GetAngle: extern "C" fn(iStackPos: c_int) -> &'static Angle, 66 | pub GetVector: extern "C" fn(iStackPos: c_int) -> &'static Vector, 67 | 68 | pub PushAngle: extern "C" fn(ang: &Angle), 69 | pub PushVector: extern "C" fn(vec: &Vector), 70 | 71 | pub SetState: extern "C" fn(pState: *mut c_void), 72 | pub CreateMetaTable: extern "C" fn(strName: *const c_char) -> bool, 73 | pub PushMetaTable: extern "C" fn(iType: c_int) -> bool, 74 | pub PushUserType: extern "C" fn(data: *mut c_void, iType: c_int), 75 | pub SetUserType: extern "C" fn(iStackPos: c_int, data: *mut c_void) 76 | } 77 | -------------------------------------------------------------------------------- /examples/engine/src/lib.rs: -------------------------------------------------------------------------------- 1 | use rglua::interface; 2 | use rglua::prelude::*; 3 | 4 | #[lua_function] 5 | fn concmd(l: LuaState) -> Result { 6 | let engine = iface!(EngineClient)?; 7 | engine.ExecuteClientCmd( luaL_checkstring(l, 1) ); 8 | Ok(0) 9 | } 10 | 11 | #[lua_function] 12 | fn get_resolution(l: LuaState) -> Result { 13 | let engine = iface!(EngineClient)?; 14 | 15 | let (w, h) = (&mut 0, &mut 0); 16 | engine.GetScreenSize(w, h); 17 | 18 | lua_pushinteger(l, *w as isize); 19 | lua_pushinteger(l, *h as isize); 20 | 21 | Ok(2) 22 | } 23 | 24 | #[lua_function] 25 | fn get_directory(l: LuaState) -> Result { 26 | let engine = iface!(EngineClient)?; 27 | 28 | let dir = engine.GetGameDirectory(); 29 | lua_pushstring(l, dir); 30 | 31 | Ok(1) 32 | } 33 | 34 | #[lua_function] 35 | fn get_level(l: LuaState) -> Result { 36 | let engine = iface!(EngineClient)?; 37 | 38 | let level = engine.GetLevelName(); 39 | lua_pushstring(l, level); 40 | 41 | Ok(1) 42 | } 43 | 44 | #[lua_function] 45 | fn is_recording(l: LuaState) -> Result { 46 | let engine = iface!(EngineClient)?; 47 | 48 | let demo = engine.IsRecordingDemo(); 49 | lua_pushboolean(l, demo as i32); 50 | 51 | Ok(1) 52 | } 53 | 54 | #[lua_function] 55 | fn is_paused(l: LuaState) -> Result { 56 | let engine = iface!(EngineClient)?; 57 | 58 | let paused = engine.IsPaused(); 59 | lua_pushboolean(l, paused as i32); 60 | 61 | Ok(1) 62 | } 63 | 64 | #[lua_function] 65 | fn is_console_visible(l: LuaState) -> Result { 66 | let engine = iface!(EngineClient)?; 67 | 68 | lua_pushboolean(l, engine.IsConsoleVisible() as i32); 69 | 70 | Ok(1) 71 | } 72 | 73 | #[lua_function] 74 | fn net_infos(l: LuaState) -> Result { 75 | let flow = luaL_checkinteger(l, 1) as i32; 76 | 77 | let engine = iface!(EngineClient)?; 78 | 79 | let infos = unsafe { engine.GetNetChannelInfo().as_mut() } 80 | .ok_or(interface::Error::AsMut)?; 81 | 82 | lua_newtable(l); 83 | 84 | lua_pushstring(l, infos.GetName()); 85 | lua_setfield(l, -2, cstr!("name")); 86 | 87 | lua_pushstring(l, infos.GetAddress()); 88 | lua_setfield(l, -2, cstr!("address")); 89 | 90 | lua_pushnumber(l, infos.GetTime() as f64); 91 | lua_setfield(l, -2, cstr!("time")); 92 | 93 | lua_pushnumber(l, infos.GetTimeConnected() as f64); 94 | lua_setfield(l, -2, cstr!("time_connected")); 95 | 96 | lua_pushnumber(l, infos.GetBufferSize() as f64); 97 | lua_setfield(l, -2, cstr!("buffer_size")); 98 | 99 | lua_pushnumber(l, infos.GetDataRate() as f64); 100 | lua_setfield(l, -2, cstr!("data_rate")); 101 | 102 | lua_pushnumber(l, infos.GetAvgLoss(flow) as f64); 103 | lua_setfield(l, -2, cstr!("avg_loss")); 104 | 105 | lua_pushnumber(l, infos.GetAvgChoke(flow) as f64); 106 | lua_setfield(l, -2, cstr!("avg_choke")); 107 | 108 | lua_pushnumber(l, infos.GetAvgData(flow) as f64); 109 | lua_setfield(l, -2, cstr!("avg_data")); 110 | 111 | lua_pushnumber(l, infos.GetAvgLatency(flow) as f64); 112 | lua_setfield(l, -2, cstr!("avg_latency")); 113 | 114 | Ok(1) 115 | } 116 | 117 | #[gmod_open] 118 | fn open(l: LuaState) -> Result { 119 | printgm!(l, "Loaded engine module!"); 120 | 121 | let lua = iface!(LuaShared)?; 122 | 123 | let client = lua.GetLuaInterface(0); 124 | let menu = lua.GetLuaInterface(2); 125 | if client.is_null() && menu.is_null() { 126 | // TODO: Serverside support & Clientside in one module :) 127 | luaL_error(l, cstr!("This module is only compatible with the CLIENT or MENU states!")); 128 | } 129 | 130 | let lib = reg! [ 131 | "concmd" => concmd, 132 | "getResolution" => get_resolution, 133 | "getGameDirectory" => get_directory, 134 | "getLevel" => get_level, 135 | "isRecording" => is_recording, 136 | "isPaused" => is_paused, 137 | "isConsoleVisible" => is_console_visible, 138 | "getNetInfo" => net_infos 139 | ]; 140 | 141 | luaL_register(l, cstr!("iengine"), lib.as_ptr()); 142 | Ok(0) 143 | } 144 | 145 | #[gmod_close] 146 | fn close(_l: LuaState) -> i32 { 147 | 0 148 | } 149 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ⚠️ Deprecated 2 | 3 | There is a new, nicer to use, slimmer rglua on the horizon. 4 | 5 | For the lua api equivalent to rglua, [autorun-lua](https://github.com/thevurv/Autorun-ng/tree/master/packages/autorun-lua) 6 | For access to source sdk bindings for gmod, [autorun-interfaces](https://github.com/thevurv/Autorun-ng/tree/master/packages/autorun-interfaces) 7 | 8 | Don't let their names scare you. They're a part of the new Autorun-ng project, but similar to how rglua was to Autorun-rs, they will be able to be used outside of Autorun-ng. 9 | 10 | Here's an example. 11 | 12 | ```rs 13 | /// A basic example of creating a binary module using `autorun-lua` 14 | /// Add this to your deps 15 | /// { git = "https://github.com/thevurv/Autorun-ng", package = "autorun-lua" } 16 | use autorun_lua::*; 17 | 18 | // Or return anyhow::Result 19 | fn lua_adder(lua: &LuaApi, state: *mut LuaState) -> Result> { 20 | let x = lua.check_number(state, 1); 21 | let y = lua.check_number(state, 2); 22 | 23 | // This pushes it onto lua's stack for you. 24 | // You can return multiple values via a tuple of values 25 | // Additionally, Option values work too, where None pushes nil. 26 | Ok(x + y) 27 | } 28 | 29 | #[unsafe(no_mangle)] 30 | pub extern "C-unwind" fn gmod13_open(state: *mut LuaState) -> std::ffi::c_int { 31 | let lua = autorun_lua::get_api().expect("Failed to get lua api"); 32 | 33 | lua.push_globals(state); // Push _G 34 | 35 | lua.push(state, "adder"); 36 | lua.push(state, as_lua_function!(lua_adder)); 37 | lua.set_table(state, -3); // _G["adder"] = lua_adder 38 | 39 | 0 40 | } 41 | ``` 42 | 43 | # 🌑 ``rglua`` [![cratesio](https://img.shields.io/crates/v/rglua.svg)](https://crates.io/crates/rglua) ![Build Status](https://github.com/Vurv78/rglua/actions/workflows/ci.yml/badge.svg) [![License](https://img.shields.io/github/license/Vurv78/rglua?color=red)](https://opensource.org/licenses/Apache-2.0) [![github/Vurv78](https://img.shields.io/discord/824727565948157963?label=Discord&logo=discord&logoColor=ffffff&labelColor=7289DA&color=2c2f33)](https://discord.gg/epJFC6cNsw) 44 | 45 | This is a crate that allows interop with the (g)luajit c api as well as the source sdk through libloading and vtable bindings. 46 | You can then use these for binary modules or manually injected code, like with [Autorun-rs](https://github.com/Vurv78/Autorun-rs) 47 | 48 | More information on binary modules can be found on the garrysmod wiki: [Creating Binary Modules](https://wiki.facepunch.com/gmod/Creating_Binary_Modules) and examples [can be found here.](https://github.com/Vurv78/rglua/tree/master/examples) 49 | ## Usage 50 | If you are targeting 32 bit make sure to install the toolchain and build to it: 51 | ```bash 52 | rustup target add i686-pc-windows-msvc 53 | cargo build --target=i686-pc-windows-msvc 54 | ``` 55 | 56 | ## Comparison 57 | There are actually a decent amount of libraries out there for gmod development. 58 | Here's a comparison and why you could use this one. 59 | 60 | [rglua]: https://crates.io/crates/rglua 61 | [rust-glua-sys]: https://github.com/SpiralP/rust-glua-sys 62 | [gmod-rs]: https://crates.io/crates/gmod 63 | [gmrs]: https://github.com/diogo464/gmrs 64 | 65 | | Library | [rglua] | [rust-glua-sys] | [gmod-rs] | [gmrs] | 66 | |-----------------------------------|---------|-----------------|-------------|--------| 67 | | *Full* Lua C Api Bindings | ✔️ | ❌ | ❌ | ❌ | 68 | | On Crates.io | ✔️ | ❌ | ✔️ | ❌ | 69 | | Proc Macros | ✔️ | ❌ | ✔️ | ✔️ | 70 | | Interfacing w/ Source SDK | ✔️ | ❌ | ❌ | ❌ | 71 | | Returning Result<> from functions | ✔️ | ❌ | ❌ | ✔️ | 72 | | Can be used on stable | ✔️ | ✔️ | ❌ | ✔️ | 73 | | Real world examples | ✔️ | ❌ | 〰️ | ✔️ | 74 | | Linux / OSX Support | ✔️ | ❌ | ✔️ | ✔️ | 75 | | Github Stars | 😢 | 👍 | 👑 | 🤷‍♂️ | 76 | 77 | __*You can help with that last one 😉*__ 78 | 79 | ## Acknowledgements 80 | ### [garrysmod_common](https://github.com/danielga/garrysmod_common) 81 | This is heavily based off of garrysmod_common, in how we export the lua_shared functions and trying to replicate everything from the Lua C Api. 82 | -------------------------------------------------------------------------------- /rglua/src/interface/mod.rs: -------------------------------------------------------------------------------- 1 | #![allow(non_snake_case)] 2 | 3 | pub(crate) mod prelude { 4 | pub(crate) use viable::vtable; 5 | 6 | pub(crate) use crate::interface::common::PlayerInfo; 7 | pub(crate) use std::os::raw::{ 8 | c_char, c_double, c_float, c_int, c_long, c_uchar, c_uint, c_ushort, c_void 9 | }; 10 | pub(crate) use crate::userdata::Vector; 11 | } 12 | 13 | mod common; 14 | mod cvar; 15 | mod engine; 16 | mod lua; 17 | mod materials; 18 | mod mdl; 19 | mod net; 20 | mod panel; 21 | mod client; 22 | 23 | pub use cvar::{CVar, ConVar}; 24 | pub use engine::{EngineClient, EngineServer}; 25 | pub use lua::{LuaInterface, LuaObject, LuaShared}; 26 | pub use materials::MaterialSystem; 27 | pub use mdl::{MdlCache, MdlCacheNotify}; 28 | pub use net::{NetChannelInfo, NetChannel, NetChannelHandler, NetMessage, CNetChan}; 29 | pub use panel::Panel; 30 | pub use client::Client; 31 | 32 | use crate::try_cstr; 33 | use libloading::{Library, Symbol}; 34 | use std::ffi::c_void; 35 | 36 | pub type CreateInterfaceFn = 37 | extern "system" fn(pName: *const i8, pReturnCode: *mut i32) -> *mut c_void; 38 | 39 | /// Gets a handle to provided source interface 40 | /// You should really use the [iface] macro instead 41 | /// # Arguments 42 | /// * `file` - Filename of the interface dll, linked to gmod. For example "engine.dll" 43 | /// # Safety 44 | /// This function internally gets the symbol to the CreateInterface function and casts it to the desired interface provided 45 | /// So make sure you pass the correct interface type and a valid dll. 46 | /// # Examples 47 | /// ```rust, no_run 48 | /// use rglua::interface::get_interface_handle; 49 | /// unsafe { 50 | /// let vgui = get_interface_handle("vgui2.dll") 51 | /// .expect("Couldn't link to vgui2.dll"); 52 | /// }; 53 | /// ``` 54 | pub unsafe fn get_interface_handle(file: &str) -> Result { 55 | let lib = Library::new(file)?; 56 | let sym: Symbol = lib.get(b"CreateInterface\0".as_ref())?; 57 | 58 | Ok(*sym) 59 | } 60 | 61 | use thiserror::Error; 62 | 63 | #[derive(Debug, Error)] 64 | pub enum Error { 65 | #[error("Libloading error: {0}")] 66 | Libloading(#[from] libloading::Error), 67 | 68 | #[error("Failed to convert interface to c string. {0}")] 69 | BadCString(#[from] std::ffi::NulError), 70 | 71 | #[error("Couldn't find factory of interface {0}!")] 72 | FactoryNotFound(String), 73 | 74 | #[error("Failure in CreateInterface of interface {1}; Code [{0}]")] 75 | CreateInterface(i32, String), 76 | 77 | #[error("Failed to get interface {0} as mutable")] 78 | IFaceMut(String), 79 | 80 | #[error("Failed to get object as mutable")] 81 | AsMut 82 | } 83 | 84 | /// Tries to get source interface from given interface name, and handle to it acquired from [get_interface_handle] 85 | /// You should really use the [iface] macro instead 86 | /// # Arguments 87 | /// * `iface` - name of the interface to get, for example "VGUI_Panel009" 88 | /// * `factory` - handle to the interface, acquired from [get_interface_handle] 89 | /// # Examples 90 | /// Getting the raw PaintTraverse function from vgui: 91 | /// ```no_run 92 | /// // Wrappers to these interfaces are already provided but they do not give raw function pointers which is needed to detour / modify the functions 93 | /// // in any way, which you may want to do here, especially for painttraverse since you can safely run lua here if you queue it from a thread to avoid crashes. 94 | /// use rglua::{prelude::*, interface::Panel}; 95 | /// type PaintTraverseFn = extern "fastcall" fn(&'static Panel, usize, bool, bool); 96 | /// let vgui = iface!(Panel).expect("Couldn't get VGUI interface"); 97 | /// // Transmute the function address from the offset into our known signature 98 | /// // You should use Interface.get_raw for this though 99 | /// let paint_traverse: PaintTraverseFn = unsafe { 100 | /// std::mem::transmute( 101 | /// (vgui.vtable as *mut *mut std::ffi::c_void) 102 | /// .offset(41) // vtable offset as seen in [interface/panel.rs] 103 | /// .read() 104 | /// ) 105 | /// }; 106 | /// ``` 107 | pub fn get_from_interface(iface: &str, factory: CreateInterfaceFn) -> Result<*mut (), Error> { 108 | let mut status = 0; 109 | 110 | let interface = try_cstr!(iface)?; 111 | let result = factory(interface.as_ptr(), &mut status); 112 | 113 | if status == 0 && !result.is_null() { 114 | Ok(result as *mut ()) 115 | } else { 116 | Err(Error::FactoryNotFound(iface.to_owned())) 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /rglua/src/lua/types.rs: -------------------------------------------------------------------------------- 1 | // Maybe replace with libc in the future 2 | pub use std::os::raw::{c_char, c_int, c_void}; 3 | 4 | pub type LuaString = *const c_char; // const i8 5 | pub type SizeT = usize; 6 | 7 | // Lua Types below 8 | 9 | /// All lua numbers < Lua 5.3 are doubles (float 64). GLua is no different as it runs on LuaJIT which mimics 5.1 10 | pub type LuaNumber = f64; 11 | pub type LuaInteger = isize; 12 | 13 | /// This is not an actual lua state, in fact it's just a pointer to it. 14 | /// However you will never have ownership of a lua state here, so I opted to make the type follow suit. 15 | pub type LuaState = *mut c_void; // Raw Lua state. 16 | 17 | /// Lua "C" Functions are C ABI functions that return the number returns that will be passed to the Lua stack. 18 | pub type LuaCFunction = extern "C" fn(LuaState) -> c_int; 19 | pub type LuaHook = extern "C" fn(LuaState, *mut LuaDebug) -> c_int; 20 | pub type LuaAlloc = 21 | extern "C" fn(ud: *mut c_void, ptr: *mut c_void, osize: usize, nsize: usize) -> *mut c_void; 22 | 23 | pub type LuaReader = extern "C" fn(LuaState, ud: *mut c_void, sz: *mut SizeT) -> *const u8; 24 | 25 | /// The type of the writer function used by lua_dump. 26 | /// Every time it produces another piece of chunk, lua_dump calls the writer, passing along the buffer to be written (p), its size (sz), and the data parameter supplied to lua_dump. 27 | /// # Returns 28 | /// The writer returns an error code: 0 means no errors; any other value means an error and stops lua_dump from calling the writer again. 29 | pub type LuaWriter = extern "C" fn(LuaState, p: *const c_void, sz: SizeT, ud: *mut c_void) -> c_int; 30 | 31 | /// luaL_Reg type, used for defining large amounts of functions with names to be - 32 | /// registered into lua with luaL_register / openlibs. 33 | #[repr(C)] 34 | pub struct LuaReg { 35 | pub name: *const i8, // c_schar 36 | pub func: Option 37 | } 38 | 39 | pub type LuaJITProfileCallback = 40 | extern "C" fn(data: *mut c_void, l: LuaState, samples: c_int, vmL: c_int) -> (); 41 | 42 | #[repr(C)] 43 | pub struct LuaBuffer { 44 | pub b: *mut i8, 45 | pub size: SizeT, 46 | pub n: SizeT, // number of chars in buffer 47 | pub state: LuaState, 48 | pub initbuffer: [i8; crate::lua::BUFFERSIZE] 49 | } 50 | 51 | #[derive(Debug, Clone)] 52 | #[repr(C)] 53 | /// Lua's lua_Debug type 54 | pub struct LuaDebug { 55 | /// (n) 56 | pub event: c_int, 57 | /// (n) 58 | pub name: LuaString, // (n) 59 | /// (n) - `global' | `local' | `field' | `method' 60 | pub namewhat: LuaString, 61 | /// (S) - `Lua' | `C' | `main' | `tail' 62 | pub what: LuaString, 63 | /// (S) 64 | pub source: LuaString, 65 | /// (l) 66 | pub currentline: c_int, 67 | /// (u) 68 | pub nups: c_int, 69 | /// (S) 70 | pub linedefined: c_int, 71 | /// (S) 72 | pub lastlinedefined: c_int, 73 | /// (S) 74 | pub short_src: [c_char; crate::lua::IDSIZE], 75 | 76 | /// This should be private but whatever. 77 | pub i_ci: c_int /* active function */ 78 | } 79 | 80 | impl Default for LuaDebug { 81 | fn default() -> Self { 82 | Self { 83 | name: std::ptr::null(), 84 | namewhat: std::ptr::null(), 85 | what: std::ptr::null(), 86 | source: std::ptr::null(), 87 | 88 | event: Default::default(), 89 | currentline: Default::default(), 90 | nups: Default::default(), 91 | linedefined: Default::default(), 92 | lastlinedefined: Default::default(), 93 | short_src: [0; 128], 94 | i_ci: Default::default() 95 | } 96 | } 97 | } 98 | 99 | #[repr(C)] 100 | #[derive(Debug, Clone, Copy)] 101 | /// Taken from 102 | pub enum LuaType { 103 | None = -1, 104 | Nil = 0, 105 | Bool, 106 | LightUserdata, 107 | Number, 108 | String, 109 | Table, 110 | Function, 111 | Userdata, 112 | Thread, 113 | 114 | // End of LUA_T* types 115 | /// Entity and entity sub-classes including Player, Weapon, NPC, Vehicle, CSEnt, and NextBot 116 | Entity, 117 | Vector, 118 | Angle, 119 | PhysObj, 120 | Save, 121 | Restore, 122 | DamageInfo, 123 | EffectData, 124 | MoveData, 125 | RecipientFilter, 126 | UserCmd, 127 | #[deprecated = "Leftover from gmod13 beta"] 128 | ScriptedVehicle, 129 | Material, 130 | Panel, 131 | Particle, 132 | ParticleEmitter, 133 | Texture, 134 | UserMsg, 135 | ConVar, 136 | IMesh, 137 | Matrix, 138 | Sound, 139 | PixelVisHandle, 140 | DLight, 141 | Video, 142 | File, 143 | Locomotion, 144 | Path, 145 | NavArea, 146 | SoundHandle, 147 | NavLadder, 148 | ParticleSystem, 149 | ProjectedTexture, 150 | PhysCollide, 151 | SurfaceInfo, 152 | 153 | /// Amount of LuaType enums (44) 154 | Count 155 | } 156 | 157 | #[repr(C)] 158 | #[derive(Debug, Clone, Copy)] 159 | pub struct Userdata { 160 | pub data: *mut c_void, 161 | pub typ: LuaType 162 | } 163 | -------------------------------------------------------------------------------- /rglua/src/interface/engine/server.rs: -------------------------------------------------------------------------------- 1 | use super::prelude::*; 2 | use crate::interface::net::NetChannelInfo; 3 | 4 | use std::os::raw::c_char; 5 | 6 | // Temp 7 | pub type EDict = c_void; 8 | 9 | #[repr(transparent)] 10 | // Temp 11 | pub struct CSteamID(u64); 12 | 13 | #[vtable] 14 | /// "VEngineServer021" 15 | /// "engine" 16 | pub struct EngineServer { 17 | pub ChangeLevel: extern "C" fn(s1: *const c_char, s2: *const c_char), 18 | pub IsMapValid: extern "C" fn(filename: *const c_char) -> c_int, 19 | pub IsDedicatedServer: extern "C" fn() -> bool, 20 | pub IsInEditMode: extern "C" fn() -> c_int, 21 | pub PrecacheModel: extern "C" fn(s: *const c_char, preload: bool) -> c_int, 22 | pub PrecacheSentenceFile: extern "C" fn(s: *const c_char, preload: bool) -> c_int, 23 | pub PrecacheDecal: extern "C" fn(name: *const c_char, preload: bool) -> c_int, 24 | pub PrecacheGeneric: extern "C" fn(s: *const c_char, preload: bool) -> c_int, 25 | pub IsModelPrecached: extern "C" fn(s: *const c_char) -> c_int, 26 | pub IsDecalPrecached: extern "C" fn(name: *const c_char) -> c_int, 27 | pub IsGenericPrecached: extern "C" fn(s: *const c_char) -> c_int, 28 | pub GetClusterForOrigin: extern "C" fn(origin: &Vector) -> c_int, 29 | pub GetPVSForCluster: 30 | extern "C" fn(cluster: c_int, outputpvslength: c_int, outputpvs: *mut u8) -> c_int, 31 | pub CheckOriginInPVS: 32 | extern "C" fn(origin: &Vector, checkpvs: *const u8, checkpvssize: c_int) -> bool, 33 | pub CheckBoxInPVS: extern "C" fn( 34 | mins: &Vector, 35 | maxs: &Vector, 36 | checkpvs: *const u8, 37 | checkpvssize: c_int 38 | ) -> bool, 39 | pub GetPlayerUserId: extern "C" fn(ent: *const EDict) -> c_int, 40 | pub GetPlayerNetworkIDString: extern "C" fn(ent: *const EDict) -> *const c_char, 41 | pub GetEntityCount: extern "C" fn() -> c_int, 42 | pub IndexOfEDict: extern "C" fn(pEdict: *const EDict) -> c_int, 43 | // Given an entity index, returns the corresponding edict pointer 44 | pub PEntityOfEntIndex: extern "C" fn(iEntIndex: c_int) -> *mut EDict, 45 | pub GetPlayerNetInfo: extern "C" fn(playerIndex: c_int) -> *mut NetChannelInfo, 46 | // Allocate space for string and return index/offset of string in global string list 47 | // If iForceEdictIndex is not -1, then it will return the edict with that index. If that edict index 48 | // is already used, it'll return null. 49 | pub CreateEDict: extern "C" fn(iForceEdictIndex: c_int) -> *mut EDict, 50 | pub RemoveEDict: extern "C" fn(edict: *mut EDict), 51 | pub PvAllocEntPrivateData: extern "C" fn(u: c_long) -> *mut c_void, 52 | 53 | #[offset(36)] 54 | // Issue a command to the command parser as if it was typed at the server console 55 | pub ServerCommand: extern "C" fn(cmd: *const c_char), 56 | // Execute any commands currently in the command parser immediately (instead of once per frame) 57 | pub ServerExecute: extern "C" fn(), 58 | 59 | #[offset(39)] 60 | // Set the lightstyle to the specified value and network the change to any connected clients. 61 | // Note that val must not change place in memory for anything that's not compiled into your mod. 62 | pub LightStyle: extern "C" fn(style: c_int, val: &'static c_void), 63 | pub StaticDecal: extern "C" fn( 64 | origin: &Vector, 65 | decalIndex: c_int, 66 | entityIndex: c_int, 67 | modelIndex: c_int, 68 | lowpriority: bool 69 | ), 70 | 71 | #[offset(45)] 72 | // Print a message to the client's console 73 | pub ClientPrintf: extern "C" fn(pEdict: *const EDict, msg: *const c_char), 74 | 75 | #[offset(49)] 76 | pub Time: extern "C" fn() -> c_float, 77 | // Set the client's crosshair angle 78 | pub CrosshairAngle: extern "C" fn(pEdict: *const EDict, pitch: c_float, yaw: c_float), 79 | pub GetGameDir: extern "C" fn(szGetGameDir: *mut c_char, maxlen: c_int), 80 | 81 | #[offset(53)] 82 | // Locks/unlocks the network string tables (.e.g, when adding bots to server, this needs to happen). 83 | // Be sure to reset the lock after executing your code!!! 84 | pub LockNetworkStringTables: extern "C" fn(lock: bool), 85 | 86 | // Create a bot with the given name. Returns NULL if fake client can't be created 87 | pub CreateFakeClient: extern "C" fn(netname: *const c_char) -> *mut EDict, 88 | 89 | #[offset(55)] 90 | pub GetClientConVarValue: 91 | extern "C" fn(clientIndex: c_int, name: *const c_char) -> *const c_char, 92 | 93 | #[offset(72)] 94 | // Logs a message to the server log file 95 | pub LogPrint: extern "C" fn(msg: *const c_char), 96 | 97 | #[offset(80)] 98 | pub IsPaused: extern "C" fn() -> bool, 99 | // Sets a USERINFO convar for a fake client (bot) 100 | pub SetFakeClientConVarValue: 101 | extern "C" fn(pEdict: *mut EDict, cvar: *const c_char, value: *const c_char), 102 | 103 | #[offset(83)] 104 | pub IsInCommentaryMode: extern "C" fn() -> bool, 105 | 106 | #[offset(89)] 107 | pub IsInternalBuild: extern "C" fn() -> bool, 108 | 109 | #[offset(93)] 110 | pub MultiplayerEndGame: extern "C" fn(), 111 | pub ChangeTeam: extern "C" fn(teamName: *const c_char), 112 | 113 | #[offset(98)] 114 | pub GetAppID: extern "C" fn() -> c_int, 115 | pub IsLowViolence: extern "C" fn() -> bool, 116 | 117 | #[offset(101)] 118 | pub InsertServerCommand: extern "C" fn(str: *const c_char), 119 | // Fill in the player info structure for the specified player index (name, model, etc.) 120 | pub GetPlayerInfo: extern "C" fn(ent_num: c_int, pInfo: *mut PlayerInfo) -> bool, 121 | pub IsClientFullyAuthenticated: extern "C" fn(pEdict: *const EDict) -> bool, 122 | 123 | #[offset(107)] 124 | pub GetClientSteamID: extern "C" fn(pEdict: *const EDict) -> *const CSteamID, 125 | 126 | #[offset(108)] 127 | pub GetServerSteamID: extern "C" fn() -> *const CSteamID, 128 | 129 | #[offset(110)] 130 | pub GetClientSteamIDByPlayerIndex: extern "C" fn(playerIndex: c_int) -> *const CSteamID, 131 | 132 | #[offset(113)] 133 | pub CreateFakeClientEx: 134 | extern "C" fn(netname: *const c_char, reportFakeClient: bool) -> *mut EDict, 135 | pub GetServerVersion: extern "C" fn() -> c_int, 136 | pub GMOD_SetTimeManipulator: extern "C" fn(fScaleFramerate: c_float) -> c_float, 137 | 138 | #[offset(117)] 139 | pub GMOD_SendToClient: extern "C" fn(client: c_int, msg: *const c_char, len: c_int), 140 | pub GMOD_RawServerCommand: extern "C" fn(cmd: *const c_char) 141 | } 142 | -------------------------------------------------------------------------------- /rglua/src/lua/globals.rs: -------------------------------------------------------------------------------- 1 | use crate::lua::types::*; 2 | 3 | /// Index of the lua registry. 4 | /// What you'd get from debug.getregistry() 5 | pub const REGISTRYINDEX: c_int = -10000; 6 | 7 | /// Index of the lua environment. 8 | /// This is like ``getfenv()`` or ``_ENV`` in later lua versions 9 | pub const ENVIRONINDEX: c_int = -10001; 10 | 11 | /// Index of _G 12 | pub const GLOBALSINDEX: c_int = -10002; 13 | 14 | /// Number of returns to use in functions like lua_pcall to represent 0 or more. 15 | pub const MULTRET: c_int = -1; 16 | 17 | /// Number of primitive lua types (excluding garrysmod userdata types) 18 | pub const NUMTYPES: c_int = 9; 19 | pub const NUMTAGS: c_int = NUMTYPES; 20 | 21 | /// 'None' / 'No value' type. 22 | pub const TNONE: c_int = -1; 23 | 24 | /// 'nil' type 25 | pub const TNIL: c_int = 0; 26 | 27 | /// Boolean type 28 | pub const TBOOLEAN: c_int = 1; 29 | 30 | /// 'Light' Userdata type. 31 | /// This is just a pointer to something owned by C without a custom metatable, as a [TUSERDATA] may have. 32 | pub const TLIGHTUSERDATA: c_int = 2; 33 | 34 | /// Number type. 35 | /// This is a double, or [f64] 36 | pub const TNUMBER: c_int = 3; 37 | 38 | /// String type, this is a [LuaString] 39 | pub const TSTRING: c_int = 4; 40 | 41 | /// Table type created by [lua_newtable](super::lua_newtable) 42 | pub const TTABLE: c_int = 5; 43 | 44 | /// Function type created by [lua_pushcfunction](super::lua_pushcfunction), [lua_pushcfunction](super::lua_pushcclosure) or retrieved from lua. 45 | pub const TFUNCTION: c_int = 6; 46 | 47 | /// 'Heavy' Userdata type managed by lua. 48 | /// Created by [lua_newuserdata](super::lua_newuserdata) 49 | pub const TUSERDATA: c_int = 7; 50 | 51 | /// Thread / Coroutine type, created by [lua_newthread](super::lua_newthread) 52 | pub const TTHREAD: c_int = 8; 53 | 54 | /// Minimum number of stack levels guaranteed to C whenever it is called into by lua. 55 | pub const MINSTACK: c_int = 20; 56 | 57 | /// OK status code used by several functions like [lua_status](super::lua_status), [lua_pcall](super::lua_pcall) 58 | pub const OK: c_int = 0; 59 | 60 | /// YIELD status code used by [lua_status](super::lua_status) 61 | pub const YIELD: c_int = 1; 62 | 63 | /// Runtime error, code used by functions like [lua_pcall](super::lua_pcall) 64 | pub const ERRRUN: c_int = 2; 65 | 66 | /// Syntax error, code used by functions like [lua_load](super::lua_load) 67 | pub const ERRSYNTAX: c_int = 3; 68 | 69 | /// Memory allocation, error code used by many functions like [super::lua_load] 70 | pub const ERRMEM: c_int = 4; 71 | 72 | /// Error when running the error handler, code used by functions like [lua_pcall](super::lua_pcall) 73 | pub const ERRERR: c_int = 5; 74 | 75 | /// Enum used with [lua_gc](super::lua_gc) - Stops the garbage collector. 76 | pub const GCSTOP: c_int = 0; 77 | 78 | /// Enum used with [lua_gc](super::lua_gc) - Restarts the garbage collector 79 | pub const GCRESTART: c_int = 1; 80 | 81 | /// Enum used with [lua_gc](super::lua_gc) - Restarts the garbage collector 82 | pub const GCCOLLECT: c_int = 2; 83 | 84 | /// Enum used with [lua_gc](super::lua_gc) - Returns the total number of live Lua objects in the current Lua state 85 | pub const GCCOUNT: c_int = 3; 86 | 87 | /// Enum used with [lua_gc](super::lua_gc) - Returns the total number of live Lua objects in the current Lua state, plus the total number of Lua objects in unreachable threads 88 | pub const GCCOUNTB: c_int = 4; 89 | 90 | /// Enum used with [lua_gc](super::lua_gc) - Performs a single step of the garbage collector. 91 | pub const GCSTEP: c_int = 5; 92 | 93 | /// Enum used with [lua_gc](super::lua_gc) - Sets `lua_gc`'s pause threshold. 94 | pub const GCSETPAUSE: c_int = 6; 95 | 96 | /// Enum used with [lua_gc](super::lua_gc) - Sets `lua_gc`'s step multiplier. 97 | pub const GCSETSTEPMUL: c_int = 7; 98 | 99 | pub const HOOKCALL: c_int = 0; 100 | pub const HOOKRET: c_int = 1; 101 | pub const HOOKLINE: c_int = 2; 102 | pub const HOOKCOUNT: c_int = 3; 103 | pub const HOOKTAILRET: c_int = 4; 104 | 105 | /// Enum used by [lua_sethook](super::lua_sethook) 106 | pub const MASKCALL: c_int = 1 << HOOKCALL; 107 | /// Enum used by [lua_sethook](super::lua_sethook) 108 | pub const MASKRET: c_int = 1 << HOOKRET; 109 | /// Enum used by [lua_sethook](super::lua_sethook) 110 | pub const MASKLINE: c_int = 1 << HOOKLINE; 111 | /// Enum used by [lua_sethook](super::lua_sethook) 112 | pub const MASKCOUNT: c_int = 1 << HOOKCOUNT; 113 | 114 | /// Size of [LuaDebug].short_src 115 | pub const IDSIZE: usize = 128; 116 | 117 | /// This is libc's default so we'll roll with it 118 | /// Used internally for [LuaBuffer]. 119 | pub const BUFFERSIZE: usize = 8192; 120 | 121 | pub const NOREF: c_int = -2; 122 | pub const REFNIL: c_int = -1; 123 | 124 | /// LuaJIT specific global constants 125 | pub mod jit { 126 | use super::c_int; 127 | 128 | /// Version of LuaJIT that garrysmod uses 129 | pub const VERSION: &str = "LuaJIT 2.0.4"; 130 | /// Semver number 131 | pub const VERSION_NUM: c_int = 20004; /* Version 2.0.4 = 02.00.04. */ 132 | 133 | /// Enum used by [luaJIT_setmode](crate::lua::luaJIT_setmode) 134 | pub const MODE_MASK: c_int = 0x00ff; 135 | 136 | /// Enum used by [luaJIT_setmode](crate::lua::luaJIT_setmode) -- Set mode for the whole JIT engine 137 | pub const MODE_ENGINE: c_int = 1; 138 | 139 | /// Enum used by [luaJIT_setmode](crate::lua::luaJIT_setmode) -- Set debug mode (idx = level). 140 | pub const MODE_DEBUG: c_int = 2; 141 | 142 | /// Enum used by [luaJIT_setmode](crate::lua::luaJIT_setmode) -- Change mode for a function. 143 | pub const MODE_FUNC: c_int = 3; 144 | 145 | /// Enum used by [luaJIT_setmode](crate::lua::luaJIT_setmode) -- Recurse into subroutine protos. 146 | pub const MODE_ALLFUNC: c_int = 4; 147 | /// Enum used by [luaJIT_setmode](crate::lua::luaJIT_setmode) -- Change only the subroutines. 148 | pub const MODE_ALLSUBFUNC: c_int = 5; 149 | 150 | /// Enum used by [luaJIT_setmode](crate::lua::luaJIT_setmode) -- Flush a compiled trace. 151 | pub const MODE_TRACE: c_int = 6; 152 | 153 | /// Enum used by [luaJIT_setmode](crate::lua::luaJIT_setmode) -- Set wrapper mode for C function calls. 154 | pub const MODE_WRAPCFUNC: c_int = 0x10; 155 | 156 | pub const MODE_MAX: c_int = MODE_WRAPCFUNC + 1; 157 | 158 | /// Enum used by [luaJIT_setmode](crate::lua::luaJIT_setmode) -- Turn a feature off 159 | pub const MODE_OFF: c_int = 0x0000; 160 | 161 | /// Enum used by [luaJIT_setmode](crate::lua::luaJIT_setmode) -- Turn a feature on 162 | pub const MODE_ON: c_int = 0x0100; 163 | 164 | /// Enum used by [luaJIT_setmode](crate::lua::luaJIT_setmode) -- Flush JIT compiled code 165 | pub const MODE_FLUSH: c_int = 0x0200; 166 | } 167 | -------------------------------------------------------------------------------- /rglua-macros/src/lib.rs: -------------------------------------------------------------------------------- 1 | use proc_macro::TokenStream; 2 | use quote::{quote, ToTokens}; 3 | 4 | use syn::{parse_macro_input, parse_quote, spanned::Spanned, FnArg, ItemFn, ReturnType, Type}; 5 | 6 | fn handle_gmod(item: TokenStream, export: Option<&str>) -> TokenStream { 7 | let mut returns_result: Option<&Box> = None; 8 | 9 | let mut ast = parse_macro_input!(item as ItemFn); 10 | 11 | if ast.sig.asyncness.is_some() { 12 | return syn::Error::new(ast.sig.span(), "Cannot be async").into_compile_error().into(); 13 | } 14 | 15 | if ast.sig.constness.is_some() { 16 | return syn::Error::new(ast.sig.span(), "Cannot be const").into_compile_error().into(); 17 | } 18 | 19 | if ast.sig.inputs.len() != 1 { 20 | return syn::Error::new(ast.sig.span(), "Must have one parameter, being the Lua state (rglua::lua::LuaState)").into_compile_error().into(); 21 | } 22 | 23 | if let ReturnType::Type(_, ty) = &ast.sig.output { 24 | let mut ret = ty.to_token_stream().to_string(); 25 | if ret.starts_with("Result < i32") | ret.starts_with("std :: result :: Result < i32") { 26 | ret.retain(|c| !c.is_whitespace()); 27 | returns_result = Some(ty); 28 | } else { 29 | if ret.as_str() != "i32" { 30 | return syn::Error::new(ast.sig.output.span(), "Exported function must return i32 or Result").into_compile_error().into(); 31 | } 32 | } 33 | } else { 34 | return syn::Error::new(ast.sig.output.span(), "Exported function must return i32 or Result").into_compile_error().into(); 35 | } 36 | 37 | let lua_shared_param; 38 | let lua_shared_ty; 39 | // Make sure parameter is a LuaState 40 | match ast.sig.inputs.first().unwrap() { 41 | FnArg::Receiver(_) => return syn::Error::new(ast.sig.inputs.span(), "Parameter cannot be self").into_compile_error().into(), 42 | FnArg::Typed(arg) => { 43 | // In the future this could check if it is *c_void as well. 44 | match arg.ty.to_token_stream().to_string().as_str() { 45 | "LuaState" | "rglua :: lua :: LuaState" => (), 46 | a => return syn::Error::new(arg.ty.span(), format!("Parameter must be rglua::lua::LuaState. Got {a}")).to_compile_error().into(), 47 | } 48 | 49 | lua_shared_ty = &arg.ty; 50 | 51 | match *arg.pat { 52 | syn::Pat::Ident(ref i) => { 53 | lua_shared_param = &i.ident; 54 | } 55 | syn::Pat::Wild(_) => { 56 | return syn::Error::new(arg.pat.span(), "Parameter must be named. Try _foo").to_compile_error().into(); 57 | } 58 | _ => return syn::Error::new(arg.pat.span(), "Parameter must be in 'ident: ty' format").to_compile_error().into(), 59 | } 60 | } 61 | } 62 | 63 | // Make sure abi is either omitted, "C", or "C-unwind" 64 | if let Some(abi) = &ast.sig.abi { 65 | match abi.name.as_ref().unwrap().value().as_str() { 66 | "C" | "C-unwind" => (), 67 | _ => return syn::Error::new(abi.span(), "Only C or C-unwind are supported").to_compile_error().into(), 68 | } 69 | } else { 70 | ast.sig.abi = Some(parse_quote!(extern "C")) 71 | } 72 | 73 | if let Some(ret) = returns_result { 74 | // We don't need to change the name of the innter function, because the outer function will compile to 75 | // gmod13_(open|close) 76 | let inner_fn = &ast.sig.ident; 77 | let inner_stmts = &ast.block.stmts; 78 | let attrs = &ast.attrs; 79 | 80 | let inner = quote! { 81 | #(#attrs)* 82 | fn #inner_fn(#lua_shared_param: #lua_shared_ty) -> #ret { 83 | #(#inner_stmts)* 84 | } 85 | }; 86 | 87 | let resultant = quote! { 88 | match #inner_fn(#lua_shared_param) { 89 | Err(why) => { 90 | // Your error must implement display / .to_string(). 91 | // I'd recommend ``thiserror``. 92 | let err = why.to_string(); 93 | let err = cstr!(err); 94 | rglua::lua::luaL_error(#lua_shared_param, cstr!("%s"), err.as_ptr()); 95 | }, 96 | Ok(n) => { return n } 97 | } 98 | }; 99 | 100 | ast.block 101 | .stmts 102 | .insert(0, syn::parse2(inner).expect("Error parsing inner fn")); 103 | ast.block 104 | .stmts 105 | .insert(1, syn::parse2(resultant).expect("Error parsing resultant")); 106 | ast.block.stmts.truncate(2); 107 | 108 | ast.sig.output = ReturnType::Type(Default::default(), Box::new(parse_quote!(i32))); 109 | 110 | // Prevent attributes from going onto the generated extern "C" function 111 | // They will be applied to the inner function. 112 | ast.attrs.clear(); 113 | } 114 | 115 | if let Some(export) = export { 116 | ast.sig.ident = quote::format_ident!("{}", export); 117 | } 118 | 119 | for attr in &ast.attrs { 120 | if let Some(id) = attr.path.get_ident() { 121 | if id == "no_mangle" { 122 | return syn::Error::new(id.span(), "Using no_mangle is unnecessary on exported functions").into_compile_error().into(); 123 | } 124 | } 125 | } 126 | 127 | // Attributes will go onto the inner function 128 | ast.attrs.push(parse_quote!(#[no_mangle])); 129 | 130 | ast.into_token_stream().into() 131 | } 132 | 133 | #[proc_macro_attribute] 134 | /// Creates the entrypoint to garrysmod. Compiles down to gmod13_open. 135 | /// 136 | /// Normally you would not be able to return types other than i32 through to gmod13_open, 137 | /// this is still true, but this proc-macro allows it through unwrapping the result and containing attributes on a hidden generated function. 138 | /// # Examples 139 | /// ```rust 140 | /// use rglua::prelude::*; 141 | /// #[gmod_open] 142 | /// fn entry(state: LuaState) -> Result { 143 | /// printgm!(state, "Hello, gmod!"); 144 | /// std::fs::write("foo.txt", "bar")?; 145 | /// 146 | /// // We don't push objects to lua, so return 0 (# of returns) 147 | /// Ok(0) 148 | /// } 149 | /// ``` 150 | pub fn gmod_open(_attr: TokenStream, item: TokenStream) -> TokenStream { 151 | handle_gmod(item, Some("gmod13_open")) 152 | } 153 | 154 | #[proc_macro_attribute] 155 | /// Creates the exitpoint to garrysmod. Compiles down to gmod13_close. 156 | /// 157 | /// Normally you would not be able to return types other than i32 through to gmod13_open, 158 | /// this is still true, but this proc-macro allows it through unwrapping the result and containing attributes on a hidden generated function. 159 | /// # Examples 160 | /// ```rust 161 | /// use rglua::prelude::*; 162 | /// #[gmod_close] 163 | /// fn exit(state: LuaState) -> Result { 164 | /// printgm!(state, "Goodbye, gmod!"); 165 | /// // Do your cleanup stuff here. 166 | /// // We don't push objects to lua, so return 0 (# of returns) 167 | /// Ok(0) 168 | /// } 169 | /// ``` 170 | pub fn gmod_close(_attr: TokenStream, item: TokenStream) -> TokenStream { 171 | handle_gmod(item, Some("gmod13_close")) 172 | } 173 | 174 | #[proc_macro_attribute] 175 | /// Creates a valid function to be passed down to lua. 176 | /// Note this function will not be registered automatically for you, you must use luaL_register or functions like lua_pushcfunction. 177 | /// This may change in the future or allow for something like #[lua_function(name = "foo", auto = true)] 178 | /// # Examples 179 | /// ```rust 180 | /// use rglua::prelude::*; 181 | /// #[lua_function] 182 | /// fn write(state: LuaState) -> Result { 183 | /// printgm!(state, "Hello, lua!"); 184 | /// std::fs::write("foo.txt", "bar")?; 185 | /// Ok(0) 186 | /// } 187 | pub fn lua_function(_attr: TokenStream, item: TokenStream) -> TokenStream { 188 | handle_gmod(item, None) 189 | } 190 | -------------------------------------------------------------------------------- /rglua/src/interface/engine/client.rs: -------------------------------------------------------------------------------- 1 | use crate::interface::common::SkyboxVisibility; 2 | use crate::interface::{MaterialSystem, NetChannelInfo}; 3 | 4 | use super::common::ButtonCode; 5 | use super::materials::Material; 6 | use super::prelude::*; 7 | 8 | use std::os::raw::c_char; 9 | use viable::vtable; 10 | 11 | #[repr(C)] 12 | pub struct ClientTextMessage { 13 | pub effect: c_int, 14 | pub col1: [u8; 4], // rgba 15 | pub col2: [u8; 4], // rgba 16 | pub x: c_float, 17 | pub y: c_float, 18 | pub fadein: c_float, 19 | pub fadeout: c_float, 20 | pub holdtime: c_float, 21 | pub fxtime: c_float, 22 | /// May be null. In that case it is default font. 23 | pub scheme_font_name: *const c_char, 24 | pub ply_name: *const c_char, 25 | pub msg: *const c_char, 26 | pub backdrop_box: bool, 27 | pub fl_box_size: c_float, 28 | pub box_color: [u8; 4], // rgba 29 | 30 | // char const* 31 | pub clear_msg: *mut c_char 32 | } 33 | 34 | #[vtable] 35 | pub struct EngineClient { 36 | #[offset(1)] 37 | 38 | pub GetLightForPoint: extern "C" fn(pos: &Vector, bClamp: bool) -> Vector, 39 | 40 | 41 | pub TraceLineMaterialAndLighting: extern "C" fn( 42 | start: &Vector, 43 | end: &Vector, 44 | diffuseLightColor: &mut Vector, 45 | baseColor: &mut Vector 46 | ) -> *const Material, 47 | 48 | #[offset(5)] 49 | pub GetScreenSize: extern "C" fn(width: &mut c_int, height: &mut c_int), 50 | pub ServerCmd: extern "C" fn(szCmdString: *const c_char, bReliable: bool), 51 | pub ClientCmd: extern "C" fn(szCmdString: *const c_char), 52 | pub GetPlayerInfo: extern "C" fn(player_index: c_int, info: &mut PlayerInfo) -> bool, 53 | pub GetPlayerForUserID: extern "C" fn(userID: c_int) -> c_int, 54 | pub TextMessageGet: extern "C" fn(pName: *const c_char) -> *mut ClientTextMessage, 55 | pub IsConsoleVisible: extern "C" fn() -> bool, 56 | pub GetLocalPlayer: extern "C" fn() -> c_int, 57 | 58 | #[offset(14)] 59 | pub Time: extern "C" fn() -> c_float, 60 | pub GetLastTimeStamp: extern "C" fn() -> c_float, 61 | 62 | #[offset(21)] 63 | pub GetMaxClients: extern "C" fn() -> c_int, 64 | /// Given the string pBinding which may be bound to a key, returns the name of the key to which this string is bound. 65 | /// Returns nullptr if no such binding exists 66 | pub Key_LookupBinding: extern "C" fn(binding: *const c_char) -> *const c_char, 67 | /// Given the string pBinding which may be bound to a key, returns the name of the key to which this string is bound. 68 | /// Returns nullptr if no such binding exists 69 | pub Key_BindingForKey: extern "C" fn(code: ButtonCode) -> *const c_char, 70 | pub StartKeyTrapMode: extern "C" fn(), 71 | pub CheckDoneKeyTrapping: extern "C" fn(code: &mut ButtonCode) -> bool, 72 | pub IsInGame: extern "C" fn() -> bool, 73 | pub IsConnected: extern "C" fn() -> bool, 74 | pub IsDrawingLoadingImage: extern "C" fn() -> bool, 75 | 76 | #[offset(35)] 77 | pub GetGameDirectory: extern "C" fn() -> *const c_char, 78 | 79 | #[offset(38)] 80 | pub GameLumpVersion: extern "C" fn(lump_id: c_int) -> c_int, 81 | pub GameLumpSize: extern "C" fn(lump_id: c_int) -> c_int, 82 | pub LoadGameLump: extern "C" fn(lump_id: c_int, pBuffer: *mut c_void, size: c_int) -> bool, 83 | pub LevelLeafCount: extern "C" fn() -> c_int, 84 | pub GetBSPTreeQuery: extern "C" fn() -> *mut c_void, 85 | pub LinearToGamma: extern "C" fn(linear: c_float, gamma: c_float), 86 | pub LightStyleValue: extern "C" fn(style: c_int) -> c_float, 87 | pub ComputeDynamicLighting: extern "C" fn(pt: &Vector, normal: &Vector, color: &mut Vector), 88 | pub GetAmbientLightColor: extern "C" fn(col: &mut Vector), 89 | pub GetDXSupportLevel: extern "C" fn() -> c_int, 90 | pub SupportsHDR: extern "C" fn() -> bool, 91 | /// Replace current material system pointer 92 | pub Mat_Stub: extern "C" fn(pMatSys: *mut MaterialSystem), 93 | pub GetChapterName: extern "C" fn(pchBuff: *mut c_char, maxlen: c_int), 94 | pub GetLevelName: extern "C" fn() -> *const c_char, 95 | pub GetLevelVersion: extern "C" fn() -> c_int, 96 | 97 | // Might need to look into this 98 | pub GetVoiceTweakApi: extern "C" fn() -> *mut c_void, 99 | pub EngineStats_BeginFrame: extern "C" fn(), 100 | pub EngineStats_EndFrame: extern "C" fn(), 101 | pub FireEvents: extern "C" fn(), 102 | pub GetLeavesArea: extern "C" fn(pLeaves: *mut c_int, nLeaves: c_int) -> c_int, 103 | pub DoesBoxTouchAreaFrustum: extern "C" fn(mins: &Vector, maxs: &Vector, iarea: c_int) -> bool, // 58 104 | 105 | #[offset(67)] 106 | pub ComputeLighting: extern "C" fn( 107 | pt: &Vector, 108 | pNormal: &Vector, 109 | clamp: bool, 110 | pColor: &mut Vector, 111 | pBoxColors: *mut Vector 112 | ), 113 | pub ActivateOccluder: extern "C" fn(iOccluderIndex: c_int, bActive: bool), 114 | pub IsOccluded: extern "C" fn(vecAbsMins: &Vector, vecAbsMaxs: &Vector) -> bool, 115 | pub SaveAllocMemory: extern "C" fn(num: usize, size: usize) -> *mut c_void, 116 | pub SaveFreeMemory: extern "C" fn(pSaveMem: *mut c_void), 117 | 118 | #[check(72)] 119 | pub GetNetChannelInfo: extern "C" fn() -> *mut NetChannelInfo, 120 | #[skip(1)] 121 | pub CheckPoint: extern "C" fn(pname: *const c_char), 122 | pub DrawPortals: extern "C" fn(), 123 | #[check(76)] 124 | pub IsPlayingDemo: extern "C" fn() -> bool, 125 | pub IsRecordingDemo: extern "C" fn() -> bool, 126 | pub IsPlayingTimeDemo: extern "C" fn() -> bool, 127 | pub GetDemoRecordingTick: extern "C" fn() -> c_int, 128 | pub GetDemoPlaybackTick: extern "C" fn() -> c_int, 129 | pub GetDemoPlaybackStartTick: extern "C" fn() -> c_int, 130 | pub GetDemoPlaybackTimeScale: extern "C" fn() -> c_float, 131 | pub GetDemoPlaybackTotalTicks: extern "C" fn() -> c_int, 132 | #[check(84)] 133 | pub IsPaused: extern "C" fn() -> bool, 134 | pub IsTakingScreenshot: extern "C" fn() -> bool, 135 | pub IsHLTV: extern "C" fn() -> bool, 136 | pub IsLevelMainMenuBackground: extern "C" fn() -> bool, 137 | pub GetMainMenuBackgroundName: extern "C" fn(dest: *mut c_char, destlen: c_int), 138 | 139 | #[skip(2)] 140 | #[check(91)] 141 | pub GetUILanguage: extern "C" fn(dest: *mut c_char, destlen: c_int), 142 | pub IsSkyboxVisibleFromPoint: extern "C" fn(vecPoint: &Vector) -> SkyboxVisibility, 143 | pub GetMapEntitiesString: extern "C" fn() -> *const c_char, 144 | pub IsInEditMode: extern "C" fn() -> bool, 145 | pub GetScreenAspectRatio: extern "C" fn() -> c_float, 146 | 147 | #[skip(2)] 148 | pub GetEngineBuildNumber: extern "C" fn() -> c_uint, 149 | pub GetProductVersionString: extern "C" fn() -> *const c_char, 150 | pub GrabPreColorCorrectedFrame: extern "C" fn(x: c_int, y: c_int, width: c_int, height: c_int), 151 | #[check(101)] 152 | pub IsHammerRunning: extern "C" fn() -> bool, 153 | /// This is NOT checked against the FCVAR_CLIENTCMD_CAN_EXECUTE vars 154 | pub ExecuteClientCmd: extern "C" fn(cmd: *const c_char), 155 | pub MapHasHDRLighting: extern "C" fn() -> bool, 156 | pub GetAppID: extern "C" fn() -> c_int, 157 | 158 | 159 | pub GetLightForPointFast: extern "C" fn(pos: &Vector, bClamp: bool) -> Vector, 160 | 161 | #[offset(106)] 162 | /// This is NOT checked against the FCVAR_CLIENTCMD_CAN_EXECUTE vars 163 | pub ClientCmd_Unrestricted: extern "C" fn(cmd: *const c_char), 164 | pub SetRestrictServerCommands: extern "C" fn(bRestrict: bool), 165 | pub SetRestrictClientCommands: extern "C" fn(bRestrict: bool), 166 | pub SetOverlayBindProxy: extern "C" fn(id: c_int, proxy: *mut c_void), 167 | pub CopyFrameBufferToMaterial: extern "C" fn(matname: *const c_char) -> bool, 168 | pub ChangeTeam: extern "C" fn(team: *const c_char), 169 | pub ReadConfiguration: extern "C" fn(readdef: bool), 170 | pub SetAchievementMgr: extern "C" fn(pAchievementMgr: *mut c_void), 171 | pub GetAchievementMgr: extern "C" fn() -> *mut c_void, 172 | pub MapLoadFailed: extern "C" fn() -> bool, 173 | pub SetMapLoadFailed: extern "C" fn(bState: bool), 174 | pub IsLowViolence: extern "C" fn() -> bool, 175 | pub GetMostRecentSaveGame: extern "C" fn() -> *const c_char, 176 | pub SetMostRecentSaveGame: extern "C" fn(lpszFilename: *const c_char) 177 | } 178 | -------------------------------------------------------------------------------- /rglua/src/interface/net/channel.rs: -------------------------------------------------------------------------------- 1 | use super::{prelude::*, NetMessage, NetEnum}; 2 | 3 | #[vtable] 4 | pub struct NetChannelHandler { 5 | #[offset(1)] // Ignore virtual constructor 6 | /// Called on network established 7 | pub ConnectionStart: extern "C" fn(chan: *mut NetChannel), 8 | 9 | /// Closed intentionally 10 | pub ConnectionClosing: extern "C" fn(reason: *const c_char), 11 | 12 | /// Error 13 | pub ConnectionCrashed: extern "C" fn(reason: *const c_char), 14 | 15 | /// Called each time a packet is received 16 | pub PacketStart: extern "C" fn(incoming_seq: c_int, outgoing_ack: c_int), 17 | 18 | pub PacketEnd: extern "C" fn(), 19 | 20 | /// Target is requesting a file 21 | pub FileRequested: extern "C" fn(filename: *const c_char, transfer_id: c_uint), 22 | 23 | /// File received from target 24 | pub FileReceived: extern "C" fn(filename: *const c_char, transfer_id: c_uint), 25 | 26 | /// File request denied by target 27 | pub FileDenied: extern "C" fn(filename: *const c_char, transfer_id: c_uint), 28 | 29 | /// File sent to target acknowledged 30 | pub FileSent: extern "C" fn(filename: *const c_char, transfer_id: c_uint), 31 | pub ShouldAcceptFile: extern "C" fn(filename: *const c_char, transfer_id: c_uint) -> bool, 32 | } 33 | 34 | #[vtable] 35 | pub struct NetChannel { 36 | info: *mut *mut NetChannelInfo, 37 | #[skip(27)] // Set to position 26, pointer after NetChannelInfo 38 | pub SetDataRate: extern "C" fn(rate: c_float), 39 | pub RegisterMessage: extern "C" fn(msg: *mut NetMessage) -> bool, 40 | pub StartStreaming: extern "C" fn(challenge_nr: c_uint) -> bool, 41 | pub ResetStreaming: extern "C" fn(), 42 | pub SetTimeout: extern "C" fn(seconds: c_float), 43 | pub SetDemoRecorder: extern "C" fn(recorder: *mut c_void), 44 | pub SetChallengeNr: extern "C" fn(challenge_nr: c_uint), 45 | pub Reset: extern "C" fn(), 46 | pub Clear: extern "C" fn(), 47 | #[check(36)] 48 | pub Shutdown: extern "C" fn(reason: *const c_char), 49 | pub ProcessPlayback: extern "C" fn(), 50 | pub ProcessStream: extern "C" fn() -> bool, 51 | pub ProcessPacket: extern "C" fn(packet: *mut c_void, has_header: bool) -> bool, 52 | pub SendNetMsg: extern "C" fn(msg: &NetMessage, force_reliable: bool, voice: bool), 53 | #[skip(1)] 54 | pub SendFile: extern "C" fn(filename: *const c_char, transfer_id: c_uint), 55 | pub DenyFile: extern "C" fn(filename: *const c_char, transfer_id: c_uint), 56 | #[deprecated] 57 | pub RequestFile_Old: extern "C" fn(filename: *const c_char, transfer_id: c_uint), 58 | pub SetChoked: extern "C" fn(), 59 | pub SendDatagram: extern "C" fn(data: *mut c_void), 60 | // #[check(49)] 61 | pub Transmit: extern "C" fn(only_reliable: bool) -> bool, 62 | #[skip(1)] 63 | pub GetMsgHandler: extern "C" fn() -> *mut NetChannelHandler, 64 | pub GetDropNumber: extern "C" fn() -> c_int, 65 | pub GetSocket: extern "C" fn() -> c_int, 66 | pub GetChallengeNr: extern "C" fn() -> c_uint, 67 | 68 | // TODO: Rest of the functions 69 | } 70 | 71 | #[vtable] 72 | pub struct NetChannelInfo { 73 | pub ty: NetEnum, 74 | 75 | pub GetName: extern "C" fn() -> *const c_char, 76 | pub GetAddress: extern "C" fn() -> *const c_char, 77 | pub GetTime: extern "C" fn() -> c_float, 78 | pub GetTimeConnected: extern "C" fn() -> c_float, 79 | pub GetBufferSize: extern "C" fn() -> c_int, 80 | pub GetDataRate: extern "C" fn() -> c_int, 81 | pub IsLoopback: extern "C" fn() -> bool, 82 | pub IsTimingOut: extern "C" fn() -> bool, 83 | pub IsPlayback: extern "C" fn() -> bool, 84 | pub GetLatency: extern "C" fn(flow: c_int) -> c_float, 85 | pub GetAvgLatency: extern "C" fn(flow: c_int) -> c_float, 86 | pub GetAvgLoss: extern "C" fn(flow: c_int) -> c_float, 87 | pub GetAvgChoke: extern "C" fn(flow: c_int) -> c_float, 88 | pub GetAvgData: extern "C" fn(flow: c_int) -> c_float, 89 | pub GetAvgPackets: extern "C" fn(flow: c_int) -> c_float, 90 | pub GetTotalData: extern "C" fn(flow: c_int) -> c_int, 91 | pub GetSequenceNr: extern "C" fn(flow: c_int) -> c_int, 92 | pub IsValidPacket: extern "C" fn(flow: c_int, frame_number: c_int) -> bool, 93 | pub GetPacketTime: extern "C" fn(flow: c_int, frame_number: c_int) -> c_float, 94 | pub GetPacketBytes: extern "C" fn(flow: c_int, frame_number: c_int) -> c_int, 95 | pub GetStreamProgress: 96 | extern "C" fn(flow: c_int, received: *mut c_int, total: *mut c_int) -> bool, 97 | pub GetTimeSinceLastReceived: extern "C" fn() -> c_float, 98 | pub GetCommandInterpolationAmount: extern "C" fn(flow: c_int, frame_number: c_int) -> c_float, 99 | pub GetPacketResponseLatency: extern "C" fn( 100 | flow: c_int, 101 | frame_number: c_int, 102 | latencyms: *mut c_int, 103 | pnchoke: *mut c_int 104 | ) -> c_float, 105 | pub GetRemoteFramerate: extern "C" fn( 106 | pflFrameTime: *mut c_float, 107 | pflFrameTimeStdDeviation: *mut c_float 108 | ) -> c_float, 109 | #[check(25)] 110 | pub GetTimeoutSeconds: extern "C" fn() -> c_float 111 | } 112 | 113 | #[vtable] 114 | pub struct CNetChan { 115 | pub GetName: extern "C" fn() -> *const c_char, 116 | pub GetAddress: extern "C" fn() -> *const c_char, 117 | pub GetTime: extern "C" fn() -> c_float, 118 | pub GetTimeConnected: extern "C" fn() -> c_float, 119 | pub GetBufferSize: extern "C" fn() -> c_int, 120 | pub GetDataRate: extern "C" fn() -> c_int, 121 | pub IsLoopback: extern "C" fn() -> bool, 122 | pub IsTimingOut: extern "C" fn() -> bool, 123 | pub IsPlayback: extern "C" fn() -> bool, 124 | pub GetLatency: extern "C" fn(flow: c_int) -> c_float, 125 | pub GetAvgLatency: extern "C" fn(flow: c_int) -> c_float, 126 | pub GetAvgLoss: extern "C" fn(flow: c_int) -> c_float, 127 | pub GetAvgChoke: extern "C" fn(flow: c_int) -> c_float, 128 | pub GetAvgData: extern "C" fn(flow: c_int) -> c_float, 129 | pub GetAvgPackets: extern "C" fn(flow: c_int) -> c_float, 130 | pub GetTotalData: extern "C" fn(flow: c_int) -> c_int, 131 | pub GetSequenceNr: extern "C" fn(flow: c_int) -> c_int, 132 | pub IsValidPacket: extern "C" fn(flow: c_int, frame_number: c_int) -> bool, 133 | pub GetPacketTime: extern "C" fn(flow: c_int, frame_number: c_int) -> c_float, 134 | pub GetPacketBytes: extern "C" fn(flow: c_int, frame_number: c_int) -> c_int, 135 | pub GetStreamProgress: 136 | extern "C" fn(flow: c_int, received: *mut c_int, total: *mut c_int) -> bool, 137 | pub GetTimeSinceLastReceived: extern "C" fn() -> c_float, 138 | pub GetCommandInterpolationAmount: extern "C" fn(flow: c_int, frame_number: c_int) -> c_float, 139 | pub GetPacketResponseLatency: extern "C" fn( 140 | flow: c_int, 141 | frame_number: c_int, 142 | latencyms: *mut c_int, 143 | pnchoke: *mut c_int 144 | ) -> c_float, 145 | pub GetRemoteFramerate: extern "C" fn( 146 | pflFrameTime: *mut c_float, 147 | pflFrameTimeStdDeviation: *mut c_float 148 | ) -> c_float, 149 | #[check(25)] 150 | pub GetTimeoutSeconds: extern "C" fn() -> c_float, 151 | 152 | #[skip(1)] // Skip deconstructor 153 | pub SetDataRate: extern "C" fn(rate: c_float), 154 | pub RegisterMessage: extern "C" fn(msg: *mut NetMessage) -> bool, 155 | pub StartStreaming: extern "C" fn(challenge_nr: c_uint) -> bool, 156 | pub ResetStreaming: extern "C" fn(), 157 | pub SetTimeout: extern "C" fn(seconds: c_float), 158 | pub SetDemoRecorder: extern "C" fn(recorder: *mut c_void), 159 | pub SetChallengeNr: extern "C" fn(challenge_nr: c_uint), 160 | pub Reset: extern "C" fn(), 161 | pub Clear: extern "C" fn(), 162 | #[check(36)] 163 | pub Shutdown: extern "C" fn(reason: *const c_char), 164 | pub ProcessPlayback: extern "C" fn(), 165 | pub ProcessStream: extern "C" fn() -> bool, 166 | pub ProcessPacket: extern "C" fn(packet: *mut c_void, has_header: bool) -> bool, 167 | pub SendNetMsg: extern "C" fn(msg: &NetMessage, force_reliable: bool, voice: bool), 168 | #[skip(1)] 169 | pub SendFile: extern "C" fn(filename: *const c_char, transfer_id: c_uint), 170 | pub DenyFile: extern "C" fn(filename: *const c_char, transfer_id: c_uint), 171 | #[deprecated] 172 | pub RequestFile_Old: extern "C" fn(filename: *const c_char, transfer_id: c_uint), 173 | pub SetChoked: extern "C" fn(), 174 | pub SendDatagram: extern "C" fn(data: *mut c_void), 175 | // #[check(49)] 176 | pub Transmit: extern "C" fn(only_reliable: bool) -> bool, 177 | #[skip(1)] 178 | pub GetMsgHandler: extern "C" fn() -> *mut NetChannelHandler, 179 | pub GetDropNumber: extern "C" fn() -> c_int, 180 | pub GetSocket: extern "C" fn() -> c_int, 181 | pub GetChallengeNr: extern "C" fn() -> c_uint, 182 | } -------------------------------------------------------------------------------- /rglua/src/util/mod.rs: -------------------------------------------------------------------------------- 1 | #![allow(unused)] 2 | 3 | /// Creates *const i8 from a &str 4 | /// This either takes a literal and appends a null char (\0) to it. 5 | /// or if it is an expression, tries to make a CString from it. 6 | /// Will panic if passed an expression that a CString could not be created from. 7 | /// # Examples 8 | /// ```rust 9 | /// use rglua::prelude::*; 10 | /// let a = b"Hello world!".as_ptr() as *const i8; 11 | /// let b = cstr!("Hello world!"); 12 | /// unsafe { assert_eq!(*a, *b) }; 13 | /// 14 | /// let c = "Hello world!"; 15 | /// let d = cstr!(c); // Macro doesn't know this is a literal, so it will try to make a CString 16 | /// unsafe { assert_eq!(*b, *d.as_ptr()) }; 17 | /// ``` 18 | #[macro_export] 19 | macro_rules! cstr { 20 | ($rstring:literal) => { 21 | concat!($rstring, "\0").as_ptr() as *const i8 22 | }; 23 | ($rstring:expr) => { 24 | std::ffi::CString::new($rstring).expect("Couldn't make CString from rust string") 25 | }; 26 | } 27 | 28 | /// Tries to create a *const i8 from a &str 29 | /// This either takes a literal and appends a null char (\0) to it. 30 | /// or if it is a value, makes a cstring and returns the pointer to it. 31 | /// # Examples 32 | /// ```rust, should_panic 33 | /// use rglua::prelude::*; 34 | /// let a = b"Hello world!".as_ptr() as *const i8; 35 | /// let b = try_cstr!("Hello world!"); 36 | /// unsafe { assert_eq!(*a, *b) } ; 37 | /// 38 | /// let c = "Invalid! 👎 \0"; // Cannot have nulls inside of it. 39 | /// let d = try_cstr!(c).unwrap(); 40 | /// ``` 41 | #[macro_export] 42 | macro_rules! try_cstr { 43 | ($rstring:literal) => { 44 | concat!($rstring, "\0").as_ptr() as *const i8 45 | }; 46 | ($rstring:expr) => {{ 47 | std::ffi::CString::new($rstring) 48 | }}; 49 | } 50 | 51 | /// Tries to convert a const char* to a &str 52 | /// Will panic if the const char* is not valid utf-8 53 | /// # Examples 54 | /// ```rust 55 | /// use rglua::prelude::*; 56 | /// let cstr = cstr!("Hello World"); 57 | /// let rust_str = rstr!(cstr); 58 | /// assert_eq!(rust_str, "Hello World"); 59 | /// ``` 60 | #[macro_export] 61 | macro_rules! rstr { 62 | ($cstring:expr) => {{ 63 | #[allow(unused_unsafe)] 64 | let cstr = unsafe { std::ffi::CStr::from_ptr($cstring) }; 65 | cstr.to_str().expect("Couldn't unwrap CString") 66 | }}; 67 | } 68 | 69 | #[macro_export] 70 | /// Tries to convert a const char* to an &str 71 | /// # Examples 72 | /// ```rust 73 | /// use rglua::prelude::*; 74 | /// let cstr = cstr!("Hello World"); 75 | /// let rstr = try_rstr!(cstr); 76 | /// assert!(rstr.is_ok()); // Should be perfectly valid to convert to utf8 77 | /// ``` 78 | macro_rules! try_rstr { 79 | ($cstring:expr) => {{ 80 | #[allow(unused_unsafe)] 81 | let cstr = unsafe { std::ffi::CStr::from_ptr($cstring) }; 82 | cstr.to_str() 83 | }}; 84 | } 85 | 86 | #[allow(unused_macros)] 87 | #[macro_export] 88 | /// Like println!, however it prints to the gmod server's console. 89 | /// First arg is the lua state. 90 | /// Rest are varargs. 91 | /// Can be either a variable storing a str literal, or a referenced String / str variable 92 | /// # Examples 93 | /// ```rust 94 | /// use rglua::prelude::*; 95 | /// fn gmod13_open(l: LuaState) { 96 | /// let world = "world"; 97 | /// printgm!(l, "Hello {}!", world); 98 | /// } 99 | /// ``` 100 | macro_rules! printgm { 101 | ($state:expr, $($x:expr),*) => { 102 | { 103 | let printargs = format!( $($x,)* ); 104 | if let Ok(fmt) = std::ffi::CString::new(printargs) { 105 | $crate::lua::lua_getglobal( $state, $crate::cstr!("print") ); 106 | $crate::lua::lua_pushstring( $state, fmt.as_ptr() ); 107 | $crate::lua::lua_call( $state, 1, 0 ); 108 | } 109 | } 110 | }; 111 | } 112 | 113 | /// Creates an array of LuaRegs for you to be used with luaL_register 114 | /// # Examples 115 | /// Basic usage 116 | /// ```rust 117 | /// use rglua::prelude::*; 118 | /// extern "C" fn max(l: LuaState) -> i32 { 0 } 119 | /// extern "C" fn min(l: LuaState) -> i32 { 0 } 120 | /// let my_library = reg! [ 121 | /// "max" => max, 122 | /// "min" => min 123 | /// ]; 124 | /// assert_eq!(my_library.len(), 3); // 2 functions + 1 internal null terminator 125 | /// unsafe { assert_eq!(my_library[0].name, cstr!("max")) }; // Internally this is turned into &[ LuaReg { name: cstr!("max"), func: max }, ... ]; 126 | /// ``` 127 | /// Returns a &[crate::types::LuaReg] 128 | #[macro_export] 129 | macro_rules! reg { 130 | ( $( $name:expr => $func:expr ),* ) => { 131 | &[ $( $crate::types::LuaReg { name: $crate::cstr!($name), func: Some($func) } ),*, $crate::types::LuaReg { name: std::ptr::null(), func: None } ] 132 | }; 133 | } 134 | 135 | // get_from_interface using literal c strings. 136 | #[cfg(feature = "interfaces")] 137 | fn get_from_interface( 138 | iface: &str, 139 | factory: crate::interface::CreateInterfaceFn 140 | ) -> Result<*mut (), crate::interface::Error> { 141 | let mut status = 0; 142 | 143 | let iface = try_cstr!(iface)?; 144 | let result = factory(iface.as_ptr(), &mut status); 145 | 146 | if status == 0 && !result.is_null() { 147 | Ok(result as *mut ()) 148 | } else { 149 | Err(crate::interface::Error::FactoryNotFound( 150 | iface.to_string_lossy().to_string() 151 | )) 152 | } 153 | } 154 | 155 | /// Quickly retrieves access to a source engine interface for you. 156 | /// You can either use it through iface!(file, name, typename) or iface!(name). 157 | /// # Examples 158 | /// ```rust 159 | /// use rglua::prelude::*; 160 | /// use rglua::interface::{EngineClient, self}; 161 | /// #[gmod_open] 162 | /// fn entry(l: LuaState) -> Result { 163 | /// let engine: &mut EngineClient = iface!("engine", "VEngineClient015", EngineClient)?; 164 | /// println!("Am I in game? {}", engine.IsInGame()); 165 | /// Ok(0) 166 | /// } 167 | /// ``` 168 | /// ```rust 169 | /// use rglua::prelude::*; 170 | /// use rglua::interface; 171 | /// #[gmod_open] 172 | /// fn entry(l: LuaState) -> Result { 173 | /// let engine: &mut interface::EngineClient = iface!(EngineClient)?; 174 | /// println!("Am I in game? {}", engine.IsInGame()); 175 | /// Ok(0) 176 | /// } 177 | /// ``` 178 | #[macro_export] 179 | macro_rules! iface { 180 | ( LuaShared ) => { 181 | iface!("lua_shared", "LUASHARED003", $crate::interface::LuaShared) 182 | }; 183 | ( EngineClient ) => { 184 | iface!( 185 | "engine", 186 | "VEngineClient015", 187 | $crate::interface::EngineClient 188 | ) 189 | }; 190 | ( EngineServer ) => { 191 | iface!( 192 | "engine", 193 | "VEngineServer021", 194 | $crate::interface::EngineServer 195 | ) 196 | }; 197 | ( MdlCache ) => { 198 | iface!("datacache", "MDLCache004", $crate::interface::MdlCache) 199 | }; 200 | ( MaterialSystem ) => { 201 | iface!( 202 | "materialsystem", 203 | "VMaterialSystem080", 204 | $crate::interface::MaterialSystem 205 | ) 206 | }; 207 | ( Panel ) => { 208 | iface!("vgui2", "VGUI_Panel009", $crate::interface::Panel) 209 | }; 210 | ( ConVar ) => { 211 | iface!("vstdlib", "VEngineCvar007", $crate::interface::ConVar) 212 | }; 213 | 214 | ( $name:literal, $iface:literal, $ty:ty ) => {{ 215 | // Would use map and flatten but flatten is unstable. =( 216 | match unsafe { $crate::interface::get_interface_handle($name) } { 217 | Ok(handle) => { 218 | let mut status = 0; 219 | 220 | // Don't need to try_cstr since this is a literal. 221 | let result = handle(cstr!($iface), &mut status); 222 | 223 | if status == 0 && !result.is_null() { 224 | let ptr = result as *mut $ty; 225 | unsafe { ptr.as_mut() } 226 | .ok_or($crate::interface::Error::IFaceMut(String::from($iface))) 227 | } else { 228 | Err($crate::interface::Error::CreateInterface( 229 | status, 230 | String::from($iface), 231 | )) 232 | } 233 | } 234 | Err(why) => Err($crate::interface::Error::Libloading(why)), 235 | } 236 | }}; 237 | } 238 | 239 | use crate::types::LuaState; 240 | /// Returns the current state of the lua stack without affecting it. 241 | /// Comes out in this format: 242 | /// ```text 243 | /// [1] 'number' = 5000 244 | /// [2] 'string' = "hello" 245 | /// [3] 'table' = 0x213542 246 | /// [4] 'function' = 0x138252 247 | /// [5] 'nil' = nil 248 | /// ``` 249 | pub fn dump_stack(l: LuaState) -> Result { 250 | use std::fmt::Write; 251 | 252 | use crate::lua::*; 253 | 254 | let mut buf = String::new(); 255 | 256 | let top = lua_gettop(l); 257 | for i in 1..=top { 258 | write!(&mut buf, "[{}] '{}' = ", i, rstr!(luaL_typename(l, i))); 259 | match lua_type(l, i) { 260 | TNUMBER => write!(&mut buf, "{}", lua_tonumber(l, i)), 261 | TSTRING => write!(&mut buf, "{}", rstr!(lua_tostring(l, i))), 262 | TBOOLEAN => write!( 263 | &mut buf, 264 | "{}", 265 | if lua_toboolean(l, i) == 1 { 266 | "true" 267 | } else { 268 | "false" 269 | } 270 | ), 271 | TNIL => write!(&mut buf, "nil"), 272 | TNONE => write!(&mut buf, "none"), 273 | TUSERDATA | TLIGHTUSERDATA => write!(&mut buf, "{:p}", lua_touserdata(l, i)), 274 | TTHREAD => write!(&mut buf, "{:p}", lua_tothread(l, i)), 275 | _ => write!(&mut buf, "Unknown type") 276 | }? 277 | } 278 | 279 | Ok(buf) 280 | } 281 | -------------------------------------------------------------------------------- /rglua/src/lua/shared.rs: -------------------------------------------------------------------------------- 1 | use crate::{ 2 | lua::{self, *}, 3 | userdata::{Angle, Vector} 4 | }; 5 | 6 | use super::LUA_SHARED_RAW; 7 | use once_cell::sync::Lazy; 8 | 9 | macro_rules! dyn_symbols { 10 | ( 11 | $(#[$outer:meta])* 12 | $vis:vis extern $abi:literal fn $name:ident ( $($arg:ident : $argty:ty),* $(,)? ) -> $ret:ty; $($rest:tt)* 13 | ) => { 14 | $(#[$outer])* 15 | #[allow(non_snake_case)] 16 | $vis fn $name( $($arg: $argty),* ) -> $ret { 17 | unsafe { 18 | let f = LUA_SHARED_RAW.get:: $ret>(stringify!($name).as_bytes()) 19 | .expect(concat!("Couldn't get extern function: ", stringify!($name))); 20 | f( $($arg),* ) 21 | } 22 | } 23 | dyn_symbols!( $($rest)* ); 24 | }; 25 | 26 | ( 27 | $(#[$outer:meta])* 28 | $vis:vis extern $abi:literal fn $name:ident ( $($arg:ident : $argty:ty),+ , ... ) -> $ret:ty; $($rest:tt)* 29 | ) => { 30 | $(#[$outer])* 31 | #[allow(non_upper_case_globals)] 32 | pub static $name: Lazy $ret> = Lazy::new(|| unsafe { 33 | std::mem::transmute( LUA_SHARED_RAW.get:: $ret>( stringify!($name).as_bytes() ).unwrap() ) 34 | }); 35 | dyn_symbols!( $($rest)* ); 36 | }; 37 | 38 | () => (); 39 | } 40 | 41 | macro_rules! lua_macros { 42 | ( 43 | $(#[$outer:meta])* 44 | $vis:vis fn $name:ident ( $($arg:ident : $argty:ty),* $(,)? ) -> $ret:ty $body:block; $($rest:tt)* 45 | ) => { 46 | #[inline(always)] 47 | #[allow(non_snake_case)] 48 | $(#[$outer])* 49 | $vis fn $name( $($arg: $argty),* ) -> $ret $body 50 | lua_macros!( $($rest)* ); 51 | }; 52 | 53 | () => (); 54 | } 55 | 56 | // Create Lazy cells that'll find the functions at runtime when called. 57 | // Credit to https://pgl.yoyo.org/luai/i/about for most of the documentation below here. 58 | // (Of course they were tweaked to be more concise and fit for this library) 59 | 60 | // Loading functions 61 | dyn_symbols! { 62 | /// Function used by [luaL_loadbuffer]. 63 | pub extern "C" fn luaL_loadbufferx( 64 | l: LuaState, 65 | code: LuaString, 66 | size: SizeT, 67 | id: LuaString, 68 | mode: LuaString, 69 | ) -> c_int; 70 | 71 | /// Loads a buffer as a Lua chunk. 72 | /// This function uses [lua_load] to load the chunk in the buffer pointed to by buff with size ``sz``. 73 | pub extern "C" fn luaL_loadbuffer( 74 | l: LuaState, 75 | code: LuaString, 76 | size: SizeT, 77 | id: LuaString, 78 | ) -> c_int; 79 | 80 | /// Loads a Lua chunk. 81 | /// If there are no errors, this pushes the compiled chunk as a Lua function on top of the stack. 82 | /// Otherwise, it pushes an error message. 83 | /// # Parameters 84 | /// * `l` - Lua state, 85 | /// * `reader` - [LuaReader] function used to read the chunk. 86 | /// * `data` - Opaque value (userdata) passed to the reader function 87 | /// * `chunkname` - Name to identify the chunk, used in error messages / debugging. 88 | /// # Returns 89 | /// * 0 - No errors, [OK] 90 | /// * [ERRSYNTAX] - Syntax error, 91 | /// * [ERRMEM] - Memory allocation error, 92 | /// # Notes 93 | /// * This function only loads a chunk; it does not run it. 94 | /// * [lua_load] automatically detects whether the chunk is text or binary, and loads it accordingly. 95 | pub extern "C" fn lua_load( 96 | l: LuaState, 97 | reader: LuaReader, 98 | data: *mut c_void, 99 | chunkname: LuaString 100 | ) -> c_int; 101 | 102 | /// Function used by [lua_load] internally. 103 | /// ``mode`` is whether to take the chunk as bytecode or as text. 104 | /// You should just use [lua_load] instead though. 105 | pub extern "C" fn lua_loadx( 106 | l: LuaState, 107 | reader: LuaReader, 108 | dt: *mut c_void, 109 | chunkname: LuaString, 110 | mode: LuaString, 111 | ) -> c_int; 112 | 113 | /// Loads a string as a Lua chunk. This function uses [lua_load] to load the chunk in the zero-terminated string ``s``. 114 | /// This function returns the same results as [lua_load]. 115 | /// Also as [lua_load], this function only loads the chunk; it does not run it. 116 | pub extern "C" fn luaL_loadstring(l: LuaState, code: LuaString) -> c_int; 117 | 118 | /// Loads a file as a Lua chunk. 119 | /// This function uses [lua_load] to load the chunk in the file named ``filename``. 120 | /// If filename is [std::ptr::null_mut()], then it loads from the standard input. 121 | /// The first line in the file is ignored if it starts with a # (shebang) 122 | pub extern "C" fn luaL_loadfile(l: LuaState, filename: LuaString) -> c_int; 123 | 124 | /// Same as how [lua_loadx] is to [lua_load]. 125 | /// You should probably use [luaL_loadfile] instead. 126 | pub extern "C" fn luaL_loadfilex(l: LuaState, filename: LuaString, mode: LuaString) -> c_int; 127 | } 128 | 129 | // Calling lua code 130 | dyn_symbols! { 131 | /// Calls a function in protected mode. 132 | /// Both nargs and nresults have the same meaning as in [lua_call]. 133 | /// If there are no errors during the call, [lua_pcall] behaves exactly like [lua_call]. 134 | /// 135 | /// However, if there is any error, [lua_pcall] catches it, pushes a single value on the stack (the error message), and returns an error code. 136 | /// Like [lua_call], [lua_pcall] always removes the function and its arguments from the stack. 137 | /// 138 | /// If errfunc is 0, then the error message returned on the stack is exactly the original error message. 139 | /// Otherwise, errfunc is the stack index of an error handler function. (In the current implementation, this index cannot be a pseudo-index like [GLOBALSINDEX]) 140 | /// In case of runtime errors, this function will be called with the error message and its return value will be the message returned on the stack by [lua_pcall]. 141 | /// 142 | /// Typically, the error handler function is used to add more debug information to the error message, such as a stack traceback. 143 | /// Such information cannot be gathered after the return of lua_pcall, since by then the stack has unwound. 144 | /// # Returns 145 | /// This function returns 0 in case of success or these error codes: 146 | /// * [ERRRUN] - There was an error at runtime 147 | /// * [ERRMEM] - There was a memory allocation error 148 | /// * [ERRERR] - Error when running the error handler 149 | pub extern "C" fn lua_pcall(l: LuaState, nargs: c_int, nresults: c_int, errfunc: c_int) -> c_int; 150 | 151 | 152 | /// Calls a function. 153 | /// To call a function you must use the following protocol: first, the function to be called is pushed onto the stack; 154 | /// then, the arguments to the function are pushed in direct order -- that is, the first argument is pushed first. 155 | /// 156 | /// Finally you call [lua_call]. 157 | /// # Params 158 | /// * `l` - The lua state. 159 | /// * `nargs` - The number of arguments that you pushed onto the stack. 160 | /// * `nresults` - Number of expected results to push onto the stack, or [MULTRET] to push all results. 161 | /// # Stack Behavior 162 | /// All arguments and the function value are popped from the stack when the function is called. 163 | /// The function results are pushed onto the stack when the function returns in direct order, so the last result is on the top of the stack. 164 | pub extern "C" fn lua_call(l: LuaState, nargs: c_int, nresults: c_int) -> c_int; 165 | 166 | /// Calls the C function func in protected mode. 167 | /// ``func`` starts with only one element in its stack, a light userdata containing ud. 168 | /// In case of errors, this returns the same error codes as [lua_pcall], plus the error object on the top of the stack. 169 | /// Otherwise, it returns zero, and does not change the stack. 170 | /// All values returned by func are discarded. 171 | pub extern "C" fn lua_cpcall(l: LuaState, func: LuaCFunction, userdata: *mut c_void) -> c_int; 172 | 173 | /// Calls a metamethod. 174 | /// If the object at index obj has a metatable and this metatable has a field e, this function calls this field and passes the object as its only argument. 175 | /// # Returns 176 | /// In this case this function returns 1 and pushes onto the stack the value returned by the call. 177 | /// If there is no metatable or no metamethod, this function returns 0 (without pushing any value on the stack). 178 | pub extern "C" fn luaL_callmeta(l: LuaState, obj: c_int, name: LuaString) -> c_int; 179 | } 180 | 181 | dyn_symbols! { 182 | /// Does the equivalent to t\[k\] = v, where t is the value at the given valid index and v is the value at the top of the stack. 183 | /// This function pops the value from the stack. 184 | /// As in Lua, this function may trigger the __newindex metamethod. 185 | pub extern "C" fn lua_setfield(l: LuaState, idx: c_int, name: LuaString) -> (); 186 | 187 | /// Pops a table from the stack and sets it as the new metatable for the value at the given acceptable index. 188 | pub extern "C" fn lua_setmetatable(l: LuaState, idx: c_int) -> (); 189 | 190 | /// Accepts any acceptable index, or 0, and sets the stack top to this index. 191 | /// If the new top is larger than the old one, then the new elements are filled with nil. 192 | /// If index is 0, then all stack elements are removed. 193 | pub extern "C" fn lua_settop(l: LuaState, ind: c_int) -> (); 194 | 195 | /// Pops a table from the stack and sets it as the new environment for the value at the given index. 196 | /// # Returns 197 | /// If the value at the given index is neither a function nor a thread nor a userdata, returns 0. 198 | /// Otherwise returns 1. 199 | pub extern "C" fn lua_setfenv(l: LuaState, idx: c_int) -> c_int; 200 | 201 | /// Does the equivalent to t\[k\] = v, where t is the value at the given valid index, v is the value at the top of the stack, and k is the value just below the top. 202 | pub extern "C" fn lua_settable(l: LuaState, idx: c_int) -> (); 203 | 204 | /// Same as lua_settable, but without calling any metamethods. 205 | pub extern "C" fn lua_rawset(l: LuaState, idx: c_int) -> (); 206 | 207 | /// Does the equivalent of t\[n\] = v, where t is the value at the given valid index and v is the value at the top of the stack. 208 | /// This function pops the value from the stack. The assignment is raw; that is, it does not invoke metamethods. 209 | pub extern "C" fn lua_rawseti(l: LuaState, idx: c_int, n: c_int) -> (); 210 | } 211 | 212 | // Getters 213 | dyn_symbols! { 214 | /// Pushes onto the stack the value t\[k\], where t is the value at the given valid index and k is the value at the top of the stack. 215 | /// This function pops the key from the stack (putting the resulting value in its place). As in Lua, this function may trigger a metamethod for the "index" event (see §2.8). 216 | pub extern "C" fn lua_gettable(l: LuaState, idx: c_int) -> (); 217 | 218 | /// This is the same as lua_gettable, but without calling any metamethods 219 | pub extern "C" fn lua_rawget(l: LuaState, idx: c_int) -> (); 220 | 221 | /// Pushes onto the stack the value t\[n\], where t is the value at the given valid index. 222 | /// The access is raw; that is, it does not invoke metamethods. 223 | pub extern "C" fn lua_rawgeti(l: LuaState, idx: c_int, n: c_int) -> (); 224 | 225 | /// Pushes onto the stack the environment table of the value at the given index. 226 | pub extern "C" fn lua_getfenv(l: LuaState, idx: c_int) -> (); 227 | 228 | /// Pushes onto the stack the metatable of the value at the given acceptable index. 229 | /// If the index is not valid, or if the value does not have a metatable, the function returns 0 and pushes nothing on the stack. 230 | pub extern "C" fn lua_getmetatable(l: LuaState, idx: c_int) -> c_int; 231 | 232 | /// Pushes onto the stack the value t\[k\], where t is the value at ``idx``. 233 | /// As in Lua, this function may trigger a metamethod for the "index" event. 234 | pub extern "C" fn lua_getfield(l: LuaState, idx: c_int, key: LuaString) -> (); 235 | } 236 | 237 | // Non-stack getters 238 | dyn_symbols! { 239 | /// Returns the type of the value in the given acceptable index, or [TNONE] for a non-valid index (that is, an index to an "empty" stack position). 240 | /// The types returned by lua_type are coded by the following constants: 241 | /// [TNIL], [TNUMBER], [TBOOLEAN], [TSTRING], [TTABLE], [TFUNCTION], [TUSERDATA], [TTHREAD], and [TLIGHTUSERDATA]. 242 | pub extern "C" fn lua_type(l: LuaState, idx: c_int) -> c_int; 243 | 244 | /// Returns the name of the type ``typeid`` which must be one the values returned by [lua_type]. 245 | /// Use [luaL_typename] if you want to get it directly from a value in the stack. 246 | pub extern "C" fn lua_typename(l: LuaState, typeid: c_int) -> LuaString; // To be used with the return value of lua_type 247 | 248 | // Type conversion getters 249 | 250 | /// Converts the Lua value at the given index to a C string. 251 | /// If len is not None, it also sets *len with the string length. 252 | /// The Lua value must be a string or a number; otherwise, the function returns a [std::ptr::null()]. 253 | /// If the value is a number, then lua_tolstring also changes the actual value in the stack to a string. 254 | /// (This change confuses lua_next when lua_tolstring is applied to keys during a table traversal.) 255 | pub extern "C" fn lua_tolstring(l: LuaState, ind: c_int, len: *mut SizeT) -> LuaString; 256 | 257 | /// Converts the Lua value at the given acceptable index to a C boolean value (0 or 1). 258 | /// Like all tests in Lua, lua_toboolean returns 1 for any Lua value different from false and nil; otherwise returning 0. 259 | /// This also returns 0 when called with a non-valid index. (If you want to accept only actual boolean values, use [lua_isboolean] to test the value's type.) 260 | pub extern "C" fn lua_toboolean(l: LuaState, idx: c_int) -> c_int; 261 | 262 | /// Converts a value at the given acceptable index to a C function. 263 | /// That value must be a C function; otherwise, returns None. 264 | /// # Example 265 | /// ```rust 266 | /// use rglua::prelude::*; 267 | /// #[gmod_open] 268 | /// fn entry(l: LuaState) -> i32 { 269 | /// lua_getglobal(l, cstr!("CurTime")); 270 | /// let curtime = lua_tocfunction(l, -1); 271 | /// 0 272 | /// } 273 | /// ``` 274 | pub extern "C" fn lua_tocfunction(l: LuaState, idx: c_int) -> LuaCFunction; 275 | 276 | /// Converts the Lua value at the given acceptable index to the signed integral type [LuaInteger]. 277 | /// The Lua value must be a number or a string convertible to a number; otherwise, this returns 0. 278 | /// If the number is not an integer, it is truncated in some non-specified way. 279 | pub extern "C" fn lua_tointeger(l: LuaState, idx: c_int) -> LuaInteger; 280 | 281 | /// Converts the Lua value at the given acceptable index to a [LuaNumber]. 282 | /// The Lua value must be a number or a string convertible to a number; otherwise, this returns 0. 283 | pub extern "C" fn lua_tonumber(l: LuaState, idx: c_int) -> LuaNumber; 284 | 285 | /// Converts the value at the given acceptable index to a generic C pointer *mut [c_void]. 286 | /// The value can be a userdata, a table, a thread, or a function; otherwise this returns None. 287 | /// Different objects will give different pointers. 288 | /// There is no way to convert the pointer back to its original value. 289 | pub extern "C" fn lua_topointer(l: LuaState, idx: c_int) -> *mut c_void; 290 | 291 | /// Converts the value at the given acceptable index to a Lua thread (represented as [LuaState]). 292 | /// This value must be a thread; otherwise, the function returns None. 293 | pub extern "C" fn lua_tothread(l: LuaState, idx: c_int) -> LuaState; 294 | 295 | /// Returns the value at the given index assuming it is a userdata. 296 | /// # Returns 297 | /// If the value at the given acceptable index is a full userdata, returns its block address. 298 | /// If the value is a light userdata, returns its pointer. 299 | /// Otherwise, returns [std::ptr::null_mut()]. 300 | pub extern "C" fn lua_touserdata(l: LuaState, idx: c_int) -> *mut c_void; 301 | } 302 | 303 | dyn_symbols! { 304 | /// Pushes the zero-terminated string pointed to by s onto the stack. Lua makes (or reuses) an internal copy of the given string, so the memory at s can be freed or reused immediately after the function returns. The string cannot contain embedded zeros; it is assumed to end at the first zero. 305 | pub extern "C" fn lua_pushstring(l: LuaState, s: LuaString) -> (); 306 | 307 | /// Pushes a boolean onto the stack. Note this is still a [c_int] so use 0 for false and 1 for true. 308 | pub extern "C" fn lua_pushboolean(l: LuaState, s: c_int) -> (); 309 | 310 | /// Pushes a string of length ``sz`` onto the stack. 311 | pub extern "C" fn lua_pushlstring(l: LuaState, s: LuaString, sz: SizeT) -> (); 312 | 313 | /// Pushes a `nil` value onto the stack. 314 | pub extern "C" fn lua_pushnil(l: LuaState) -> (); 315 | 316 | /// Pushes the number ``num`` onto the stack. 317 | pub extern "C" fn lua_pushnumber(l: LuaState, num: LuaNumber) -> (); 318 | 319 | /// Pushes a copy of the element at the given valid index onto the stack. 320 | pub extern "C" fn lua_pushvalue(l: LuaState, idx: c_int) -> (); 321 | /// Pushes a c function on the stack with associated values. 322 | /// # Parameters 323 | /// * `l` - LuaState 324 | /// * `f` - Lua function 325 | /// * `n` - Number of upvalues to associate and pull from stack with the function 326 | pub extern "C" fn lua_pushcclosure(l: LuaState, fnc: LuaCFunction, nargs: c_int) -> (); 327 | 328 | /// Pushes a light userdata onto the stack. 329 | /// Userdata represent C values in Lua. 330 | /// A light userdata represents a pointer. 331 | /// It is a value (like a number): you do not create it, it has no individual metatable, and it is not collected (as it was never created). 332 | /// A light userdata is equal to "any" light userdata with the same C address. 333 | pub extern "C" fn lua_pushlightuserdata(l: LuaState, p: *mut c_void) -> (); 334 | 335 | /// Pushes a given thread (representing ``l``) to the stack. 336 | /// # Parameters 337 | /// * `l` - The thread to push. 338 | /// # Returns 339 | /// 1 if the thread is the main thread of the state. 340 | pub extern "C" fn lua_pushthread(l: LuaState) -> c_int; 341 | 342 | /// Pushes a formatted [LuaString] to the stack 343 | /// Note this is not a direct function but instead a Lazy pointer to a function. 344 | /// This is because variadic functions are not yet supported in Rust, besides through external functions and pointers to them. 345 | pub extern "C" fn lua_pushfstring(l: LuaState, fmt: LuaString, ...) -> LuaString; 346 | 347 | /// Pushes a number with value ``n`` onto the stack. 348 | pub extern "C" fn lua_pushinteger(l: LuaState, n: LuaInteger) -> (); 349 | } 350 | 351 | // Type checking getters 352 | dyn_symbols! { 353 | /// Same as luaL_checknumber, but casts it to an integer. 354 | pub extern "C" fn luaL_checkinteger(l: LuaState, narg: c_int) -> LuaInteger; 355 | /// Checks whether the value at stack index 'narg' is a number and returns this number. 356 | /// If it is not a lua number, will throw an error to Lua. 357 | pub extern "C" fn luaL_checknumber(l: LuaState, narg: c_int) -> LuaNumber; 358 | 359 | /// Checks whether the function argument ``narg`` is a string and returns this string. 360 | /// If len is not [std::ptr::null_mut()] fills *len with the string's length. 361 | pub extern "C" fn luaL_checklstring(l: LuaState, narg: c_int, len: *mut SizeT) -> LuaString; 362 | 363 | /// Checks whether the function has an argument of any type (including nil) at position narg. 364 | pub extern "C" fn luaL_checkany(l: LuaState, narg: c_int) -> (); 365 | 366 | /// Checks whether the function argument narg has type ``t``. 367 | /// See [lua_type] for the encoding of types for ``t``. 368 | pub extern "C" fn luaL_checktype(l: LuaState, narg: c_int, typeid: c_int) -> (); 369 | 370 | /// Checks whether the function argument narg is a userdata of the type tname (see luaL_newmetatable). 371 | pub extern "C" fn luaL_checkudata(l: LuaState, ud: c_int, tname: LuaString) -> *mut Userdata; 372 | } 373 | 374 | // Creation 375 | dyn_symbols! { 376 | /// Creates a new Lua state. 377 | /// This calls [lua_newstate] with an allocator based on the standard C realloc function and then sets a panic function (see lua_atpanic) that prints an error message to the standard error output in case of fatal errors. 378 | /// # Returns 379 | /// The newly created [LuaState], or [std::ptr::null_mut()] if the allocation failed (due to memory). 380 | pub extern "C" fn luaL_newstate() -> LuaState; 381 | 382 | /// Creates a new, independent state. 383 | /// Note you might be looking for [luaL_newstate], which has no parameters 384 | /// Returns None if cannot create the state (due to lack of memory). 385 | /// The argument f is the allocator function; 386 | /// Lua does all memory allocation for this state through this function. 387 | /// The second argument, ud, is an opaque pointer that Lua simply passes to the allocator in every call. 388 | pub extern "C" fn lua_newstate(f: LuaAlloc, ud: *mut c_void) -> LuaState; 389 | 390 | /// Creates a new empty table and pushes it onto the stack. 391 | /// The new table has space pre-allocated for ``narr`` array elements and ``nrec`` non-array elements. 392 | /// This pre-allocation is useful when you know exactly how many elements the table will have. 393 | /// Otherwise you can use the function [lua_newtable]. 394 | pub extern "C" fn lua_createtable(l: LuaState, narr: c_int, nrec: c_int) -> (); 395 | } 396 | 397 | // Destruction 398 | dyn_symbols! { 399 | /// Destroys the given lua state. 400 | /// You *probably* don't want to do this, unless you just want to self destruct the server / your client. 401 | pub extern "C" fn lua_close(l: LuaState) -> (); 402 | } 403 | 404 | // LuaJIT 405 | dyn_symbols! { 406 | /// This is a C API extension to allow control of the VM from "C" 407 | /// # Parameters 408 | /// * `l` - Lua state 409 | /// * `idx` - Stack index of the function to set the mode of. `0` to set the mode of the entirety of luajit. 410 | /// * `mode` - The mode to set, 'or'ed with a flag from [lua::jit] 411 | /// # Returns 412 | /// 1 for success, 0 for failure. 413 | pub extern "C" fn luaJIT_setmode(l: LuaState, idx: c_int, jit_mode: c_int) -> c_int; 414 | } 415 | 416 | // Coroutines 417 | dyn_symbols! { 418 | /// Yields a coroutine. 419 | /// This function should only be called as the return expression of a C function, as follows: 420 | /// ```ignore 421 | /// return lua_yield (L, nresults); 422 | /// ``` 423 | /// When a function calls [lua_yield] in that way, the running coroutine suspends its execution, and the call to [lua_resume] that started this coroutine returns. 424 | /// The parameter nresults is the number of values from the stack that are passed as results to [lua_resume]. 425 | pub extern "C" fn lua_yield(l: LuaState, nresults: c_int) -> c_int; 426 | 427 | /// Returns the status of the thread/coroutine l. 428 | /// # Returns 429 | /// 0 for a normal thread, error code if it's finished with an error, or [lua::YIELD] if it is suspended. 430 | pub extern "C" fn lua_status(l: LuaState) -> c_int; 431 | 432 | /// Starts and resumes a coroutine in a given thread. 433 | /// Blame garry for the _real 434 | pub extern "C" fn lua_resume_real(l: LuaState, narg: c_int) -> c_int; 435 | } 436 | 437 | // Comparison 438 | dyn_symbols! { 439 | /// Returns 1 or 0 for if the two values at given indices are equal, calling ``__eq`` metamethods along the way unlike [lua_rawequal]. 440 | /// Also returns 0 if any of the indices are non valid. 441 | pub extern "C" fn lua_equal(l: LuaState, ind1: c_int, ind2: c_int) -> c_int; // Returns 1 or 0 bool 442 | 443 | /// Returns 1 or 0 for if the two values at given indices are equal, without calling metamethods, as [lua_equal] does. 444 | /// Also returns 0 if any of the indices are non valid. 445 | pub extern "C" fn lua_rawequal(l: LuaState, ind1: c_int, ind2: c_int) -> c_int; 446 | } 447 | 448 | dyn_symbols! { 449 | // Raising Errors 450 | /// Generates an error with a message like the following: 451 | /// ```text 452 | /// location: bad argument narg to 'func' (tname expected, got rt) 453 | /// ``` 454 | /// where location is produced by luaL_where, func is the name of the current function, and rt is the type name of the actual argument. 455 | pub extern "C" fn luaL_typerror(l: LuaState, narg: c_int, typename: LuaString) -> !; 456 | 457 | /// Raises an error. 458 | /// The error message format is given by fmt plus any extra arguments, following the same rules of [lua_pushfstring]. 459 | /// It also adds at the beginning of the message the file name and the line number where the error occurred, if this information is available. 460 | /// Note this is not a direct function but instead a Lazy pointer to a function. 461 | /// This is because variadic functions are not yet supported in Rust, besides through external functions and pointers to them. 462 | pub extern "C" fn luaL_error(l: LuaState, fmt: LuaString, ...) -> !; 463 | 464 | /// Raises an error with the following message, where func is retrieved from the call stack: 465 | /// ```text 466 | /// bad argument # to () 467 | /// ``` 468 | /// This function never returns 469 | pub extern "C" fn luaL_argerror(l: LuaState, narg: c_int, extramsg: LuaString) -> !; 470 | 471 | /// Generates a Lua error. 472 | /// The error message (which can actually be a Lua value of any type) must be on the stack top.T 473 | /// This function does a long jump, and therefore never returns. (see [luaL_error]). 474 | pub extern "C" fn lua_error(l: LuaState) -> !; 475 | } 476 | 477 | dyn_symbols! { 478 | // Libraries 479 | /// Opens the standard 'table' library for a lua state 480 | pub extern "C" fn luaopen_table(l: LuaState) -> c_int; 481 | /// Opens the standard 'string' library for a lua state 482 | pub extern "C" fn luaopen_string(l: LuaState) -> c_int; 483 | /// Opens the standard 'package' library for a lua state 484 | pub extern "C" fn luaopen_package(l: LuaState) -> c_int; 485 | /// Opens the standard 'os' library for a lua state 486 | pub extern "C" fn luaopen_os(l: LuaState) -> c_int; 487 | /// Opens the standard 'math' library for a lua state 488 | pub extern "C" fn luaopen_math(l: LuaState) -> c_int; 489 | /// Opens the standard 'jit' library for a lua state 490 | pub extern "C" fn luaopen_jit(l: LuaState) -> c_int; 491 | /// Opens the standard 'debug' library for a lua state 492 | pub extern "C" fn luaopen_debug(l: LuaState) -> c_int; 493 | /// Opens the standard 'bit' library for a lua state 494 | pub extern "C" fn luaopen_bit(l: LuaState) -> c_int; 495 | /// Opens the standard library functions (like assert) for a lua state 496 | pub extern "C" fn luaopen_base(l: LuaState) -> c_int; 497 | /// Opens all of the standard libraries for a lua state 498 | pub extern "C" fn luaL_openlibs(l: LuaState) -> (); 499 | /// Internally called by luaL_register, opens given list of LuaRegs with number of functions provided explicitly 500 | pub extern "C" fn luaL_openlib(l: LuaState, libname: LuaString, reg: *const LuaReg, nup: c_int) -> (); 501 | 502 | /// Registers a ``reg`` of functions onto the LuaState's _G\[libname\]. 503 | /// For example you could set libname to [cstr]!("math") to add functions onto the ``math`` table or create it if it does not exist. 504 | /// 505 | /// When called with libname as std::ptr::null(), it simply registers all functions in the list ``lib`` into the table on the top of the stack. 506 | /// # Example 507 | /// ```rust 508 | /// use rglua::prelude::*; 509 | /// 510 | /// #[lua_function] fn add(l: LuaState) -> i32 {0} 511 | /// #[lua_function] fn sub(l: LuaState) -> i32 {0} 512 | /// 513 | /// #[gmod_open] 514 | /// fn entry(l: LuaState) -> i32 { 515 | /// let lib = reg! [ 516 | /// "add" => add, 517 | /// "subtract" => sub 518 | /// ]; 519 | /// luaL_register(l, cstr!("math"), lib.as_ptr()); 520 | /// 0 521 | /// } 522 | /// ``` 523 | pub extern "C" fn luaL_register(l: LuaState, libname: LuaString, lib: *const LuaReg) -> (); 524 | } 525 | 526 | dyn_symbols! { 527 | /// Creates and returns a reference, in the table at index t, for the object at the top of the stack (and pops the object). 528 | /// A reference is a unique integer key. 529 | /// As long as you do not manually add integer keys into table t, [luaL_ref] ensures the uniqueness of the key it returns. 530 | /// You can retrieve an object referred by reference r by calling [lua_rawgeti](L, t, r). 531 | /// Function luaL_unref frees a reference and its associated object. 532 | /// 533 | /// If the object at the top of the stack is nil, luaL_ref returns the constant [REFNIL]. 534 | /// The constant [NOREF] is guaranteed to be different from any reference returned by this. 535 | pub extern "C" fn luaL_ref(l: LuaState, t: c_int) -> c_int; 536 | 537 | /// Releases reference ref from the table at index t (see [luaL_ref]). 538 | /// The entry is removed from the table, so that the referred object can be collected. 539 | /// The reference ref is also freed to be used again. 540 | /// If ref is [NOREF] or [REFNIL], this does nothing. 541 | pub extern "C" fn luaL_unref(l: LuaState, t: c_int, r: c_int) -> (); 542 | } 543 | 544 | // Metatables 545 | dyn_symbols! { 546 | /// If the registry already has the key tname, returns 0. Otherwise, creates a new table to be used as a metatable for userdata, adds it to the registry with key tname, and returns 1. 547 | /// In both cases pushes onto the stack the final value associated with ``tname`` in the registry. 548 | pub extern "C" fn luaL_newmetatable(l: LuaState, tname: LuaString) -> c_int; 549 | 550 | /// Creates a metatable with type and typeid 551 | /// Same as [luaL_newmetatable], but also sets the MetaName and MetaID fields of the metatable 552 | /// # Parameters 553 | /// * `l` - LuaState 554 | /// * `tname` - TypeName to be added to the metatable 555 | /// * `tid` - TypeID to be applied to the metatable 556 | pub extern "C" fn luaL_newmetatable_type(l: LuaState, tname: LuaString, tid: c_int) -> c_int; 557 | 558 | /// Pushes onto the stack the field ``e`` from the metatable of the object at index ``obj``. 559 | /// If the object does not have a metatable, or if the metatable does not have this field, returns 0 and pushes nothing. 560 | pub extern "C" fn luaL_getmetafield(l: LuaState, obj: c_int, e: LuaString) -> c_int; 561 | } 562 | 563 | // Optional 564 | dyn_symbols! { 565 | /// If the function argument ``narg`` is a number, returns this number cast to a [LuaInteger]. 566 | /// If this argument is absent or is nil, returns d. Otherwise, raises an error. 567 | pub extern "C" fn luaL_optinteger(l: LuaState, narg: c_int, d: LuaInteger) -> c_int; 568 | 569 | /// If the function argument narg is a string, returns this string. 570 | /// If this argument is absent or is nil, returns ``default``. Otherwise, raises an error. 571 | /// 572 | /// If ``len`` is not nullptr, fills the position *``len`` with the results's length. 573 | pub extern "C" fn luaL_optlstring(l: LuaState, arg: c_int, default: LuaString, len: *mut SizeT) 574 | -> LuaString; 575 | 576 | /// If the function argument ``arg`` is a number, returns this number. 577 | /// If this argument is absent or is nil, returns ``default``. Otherwise, raises an error. 578 | pub extern "C" fn luaL_optnumber(l: LuaState, arg: c_int, default: LuaNumber) -> LuaNumber; 579 | } 580 | 581 | dyn_symbols! { 582 | // x / ref functions 583 | /// Converts the Lua value at the given index to the signed integral type [LuaInteger]. 584 | /// The Lua value must be an integer, or a number or string convertible to an integer; otherwise, this returns 0. 585 | /// If ``isnum`` is not [std::ptr::null_mut()], its referent is assigned a boolean value that indicates whether the operation succeeded. 586 | pub extern "C" fn lua_tointegerx(l: LuaState, index: c_int, isnum: *mut c_int) -> LuaInteger; 587 | 588 | 589 | /// Converts the Lua value at the given index to a [LuaNumber]. 590 | /// The Lua value must be a number or a string convertible to a number; otherwise, this returns 0. 591 | /// If ``isnum`` is not [std::ptr::null_mut()], its referent is assigned a boolean value that indicates whether the operation succeeded. 592 | pub extern "C" fn lua_tonumberx(l: LuaState, index: c_int, isnum: *mut c_int) -> LuaNumber; 593 | } 594 | 595 | dyn_symbols! { 596 | /// Creates and pushes a traceback of the stack L1. 597 | /// If msg is not [std::ptr::null_mut()] it is appended at the beginning of the traceback. 598 | /// The level parameter tells at which level to start the traceback. 599 | pub extern "C" fn luaL_traceback( 600 | l: LuaState, 601 | state1: LuaState, 602 | msg: LuaString, 603 | level: c_int, 604 | ) -> (); 605 | 606 | /// Pushes onto the stack a string identifying the current position of the control at level ``lvl`` in the call stack. 607 | /// Typically this string has the following format: 608 | /// ```text 609 | /// chunkname:currentline: 610 | /// ``` 611 | /// Level 0 is the running function, level 1 is the function that called the running function, etc. 612 | /// This function is used to build a prefix for error messages. 613 | pub extern "C" fn luaL_where(l: LuaState, lvl: c_int) -> (); 614 | 615 | /// This function produces the return values for process-related functions in the standard library (os.execute and io.close). 616 | /// Although, those don't exist in gmod.. 617 | pub extern "C" fn luaL_execresult(l: LuaState, stat: c_int) -> c_int; 618 | 619 | /// This function produces the return values for file-related functions in the standard library (like File:seek) 620 | pub extern "C" fn luaL_fileresult(l: LuaState, stat: c_int, fname: LuaString) -> c_int; 621 | 622 | /// Function used internally by lua 623 | pub extern "C" fn luaL_findtable( 624 | l: LuaState, 625 | idx: c_int, 626 | fname: LuaString, 627 | szhint: c_int, 628 | ) -> LuaString; 629 | 630 | /// Pops a key from the stack, and pushes a key-value pair from the table at the given index (the "next" pair after the given key). 631 | /// If there are no more elements in the table, then lua_next returns 0 (and pushes nothing). 632 | /// 633 | /// # Safety 634 | /// Do not call [lua_tolstring] on a string while traversing a table. This will confuse ``next`` since it modifies the key. 635 | /// 636 | /// # Examples 637 | /// ```rust 638 | /// use rglua::prelude::*; 639 | /// #[lua_function] 640 | /// fn table_traverse(l: LuaState) -> i32 { 641 | /// // Assume a table is in the stack at index 1 (first argument of this function) 642 | /// lua_pushnil(l); // first key 643 | /// // This is nil as how ``pairs()`` passes nil to ``next()`` in lua. 644 | /// while lua_next(l, 1) != 0 { 645 | /// // Uses 'key' (at index -2) and 'value' (at index -1) 646 | /// println!("{} - {}", rstr!(luaL_typename(l, -2)), rstr!(luaL_typename(l, -1))); 647 | /// // Removes 'value'; keeps 'key' for next iteration 648 | /// lua_pop(l, 1); 649 | /// } 650 | /// 0 651 | /// } 652 | /// ``` 653 | pub extern "C" fn lua_next(l: LuaState, idx: c_int) -> c_int; 654 | 655 | /// Replaces object at index (idx) with the object at the top of the stack (-1) and pops the stack. 656 | pub extern "C" fn lua_replace(l: LuaState, idx: c_int) -> (); 657 | 658 | /// Returns 1 if the value at acceptable index index1 is smaller than the value at acceptable index index2, 659 | /// following the semantics of the Lua < operator (that is, may call metamethods). 660 | /// 661 | /// Otherwise returns 0. Also returns 0 if any of the indices is non valid. 662 | pub extern "C" fn lua_lessthan(l: LuaState, idx1: c_int, idx2: c_int) -> c_int; 663 | 664 | /// Ensures that there are at least extra free stack slots in the stack. 665 | /// It returns C 'false' if it cannot grow the stack to that size. 666 | /// This function never shrinks the stack; if the stack is already larger than the new size, it is left unchanged. 667 | pub extern "C" fn lua_checkstack(l: LuaState, extra: c_int) -> c_int; 668 | 669 | /// Sets a new panic function and returns the old one. 670 | /// If an error happens outside any protected environment, Lua calls a panic function and then calls exit(EXIT_FAILURE), thus exiting the host application. 671 | /// Your panic function can avoid this exit by never returning (e.g., doing a long jump). 672 | /// The panic function can access the error message at the top of the stack. 673 | /// # Returns 674 | /// The old panic function. 675 | pub extern "C" fn lua_atpanic(l: LuaState, panicf: LuaCFunction) -> LuaCFunction; 676 | 677 | /// Returns the index of the top element in the stack. 678 | /// Because indices start at 1, this result is equal to the number of elements in the stack (and so 0 means an empty stack). 679 | pub extern "C" fn lua_gettop(l: LuaState) -> c_int; 680 | 681 | /// Removes the element at the given valid index, shifting down the elements above this index to fill the gap. 682 | /// Cannot be called with a pseudo-index, because a pseudo-index is not an actual stack position. 683 | /// (Example of pseudoindices are LUA_GLOBALSINDEX and globals::REGISTRYINDEX) 684 | pub extern "C" fn lua_remove(l: LuaState, index: c_int) -> (); 685 | 686 | /// Controls lua's garbage collector 687 | /// Performs different tasks depending on what you provide to the `what` parameter. 688 | /// # Parameters 689 | /// * `l` - LuaState 690 | /// * `what` - c_int 691 | /// * `[GCSTOP]` - Stops the garbage collector. 692 | /// * `[GCRESTART]` - Restarts the garbage collector. 693 | /// * `[GCCOLLECT]` - Performs a full garbage-collection cycle. 694 | /// * `[GCCOUNT]` - Returns the total number of live Lua objects in the current Lua state. 695 | /// * `[GCCOUNTB]` - Returns the total number of live Lua objects in the current Lua state, plus the total number of Lua objects in unreachable threads. 696 | /// * `[GCSTEP]` - Performs a single step of the garbage collector. 697 | /// * `[GCSETPAUSE]` - Sets `lua_gc`'s pause threshold. 698 | /// * `[GCSETSTEPMUL]` - Sets `lua_gc`'s step multiplier. 699 | /// * `data` - c_int 700 | pub extern "C" fn lua_gc(l: LuaState, what: c_int, data: c_int) -> c_int; 701 | 702 | /// Moves the top element into the given valid index, shifting up the elements above this index to open space. 703 | /// Cannot be called with a pseudo-index, because a pseudo-index is not an actual stack position. 704 | pub extern "C" fn lua_insert(l: LuaState, idx: c_int) -> (); 705 | 706 | 707 | /// Creates a new thread, pushes it on the stack, and returns a pointer to a lua_State that represents this new thread. 708 | /// The new state returned by this function shares with the original state all global objects (such as tables), but has an independent execution stack. 709 | /// There is no explicit function to close or to destroy a thread. Threads are subject to garbage collection, like any Lua object. 710 | pub extern "C" fn lua_newthread(l: LuaState) -> LuaState; 711 | 712 | /// This function allocates a new block of memory with the given size, pushes onto the stack a new full userdata with the block address, and returns this address. 713 | /// 714 | /// Userdata represent C values in Lua. 715 | /// A full userdata represents a block of memory. 716 | /// It is an object (like a table): you must create it, it can have its own metatable, and you can detect when it is being collected. 717 | /// A full userdata is only equal to itself (under raw equality). 718 | /// 719 | /// When Lua collects a full userdata with a gc metamethod, Lua calls the metamethod and marks the userdata as finalized. 720 | /// When this userdata is collected again then Lua frees its corresponding memory. 721 | pub extern "C" fn lua_newuserdata(l: LuaState, size: SizeT) -> *mut Userdata; 722 | 723 | /// Returns information about a specific function or function invocation. 724 | /// 725 | /// To get information about a function you push it onto the stack and start the what string with the character '>'. 726 | /// (In that case, lua_getinfo pops the function in the top of the stack.) 727 | /// 728 | /// # Examples 729 | /// To know in which line a function f was defined, you can write the following code: 730 | /// ```rust 731 | /// use rglua::prelude::*; 732 | /// #[gmod_open] 733 | /// fn entry(l: LuaState) -> i32 { 734 | /// let mut ar = LuaDebug::default(); 735 | /// lua_getglobal(l, cstr!("f")); // Get global 'f' 736 | /// lua_getinfo(l, cstr!(">S"), &mut ar); 737 | /// 738 | /// printgm!(l, "{}", ar.linedefined); 739 | /// 0 740 | /// } 741 | /// ``` 742 | pub extern "C" fn lua_getinfo( 743 | l: LuaState, 744 | what: LuaString, 745 | ar: *mut LuaDebug, 746 | ) -> c_int; 747 | 748 | /// Returns the "length" of the value at the given acceptable index. 749 | /// For strings, this is the string length; 750 | /// For tables, this is the result of the length operator ('#'); 751 | /// For userdata, this is the size of the block of memory allocated for the userdata; 752 | /// For other values, it is 0. 753 | pub extern "C" fn lua_objlen(l: LuaState, idx: c_int) -> SizeT; 754 | } 755 | 756 | // Lua Debug Library 757 | dyn_symbols! { 758 | /// Returns the current hook function. 759 | pub extern "C" fn lua_gethook(l: LuaState) -> LuaHook; 760 | /// Returns the current hook count. 761 | pub extern "C" fn lua_gethookcount(l: LuaState) -> c_int; 762 | /// Returns the current hook mask. 763 | pub extern "C" fn lua_gethookmask(l: LuaState) -> c_int; 764 | 765 | /// Sets the debugging hook function. 766 | /// # Parameters 767 | /// 768 | /// * `l` - [LuaState] 769 | /// * `func` [LuaHook] function 770 | /// * `mask` - Specifies on which events the hook will be called: it is formed by a bitwise or of the constants [MASKCALL], [MASKRET], [MASKLINE], and [MASKCOUNT] 771 | /// * `count` - Only meaningful when the mask includes [MASKCOUNT]. For each event, the hook is called as explained below: 772 | /// 773 | /// **The call hook**: called when the interpreter calls a function. The hook is called just after Lua enters the new function, before the function gets its arguments. 774 | /// **The return hook**: called when the interpreter returns from a function. The hook is called just before Lua leaves the function. You have no access to the values to be returned by the function. 775 | /// **The line hook**: is called when the interpreter is about to start the execution of a new line of code, or when it jumps back in the code (even to the same line). (This event only happens while Lua is executing a Lua function.) 776 | /// **The count hook**: is called after the interpreter executes every count instructions. (This event only happens while Lua is executing a Lua function.) 777 | /// 778 | /// A hook is disabled by setting ``mask`` to zero. 779 | pub extern "C" fn lua_sethook(l: LuaState, func: LuaHook, mask: c_int, count: c_int) -> c_int; 780 | 781 | /// Gets information about a local variable of a given activation record. 782 | /// The parameter ar must be a valid activation record that was filled by a previous call to lua_getstack or given as argument to a hook (see lua_Hook). 783 | /// The index n selects which local variable to inspect (1 is the first parameter or active local variable, and so on, until the last active local variable). 784 | /// lua_getlocal pushes the variable's value onto the stack and returns its name. 785 | /// # Returns 786 | /// Returns NULL (and pushes nothing) when the index is greater than the number of active local variables. 787 | pub extern "C" fn lua_getlocal(l: LuaState, ar: *mut LuaDebug, n: c_int) -> LuaString; 788 | 789 | /// Get information about the interpreter runtime stack. 790 | /// This function fills in the priv part of the LuaDebug structure with information about the function that is running at the given level. 791 | pub extern "C" fn lua_getstack(l: LuaState, level: c_int, ar: *mut LuaDebug) -> c_int; 792 | 793 | /// Gets information about a closure's upvalue. This is basically debug.getlocal. 794 | /// (For Lua functions, upvalues are the external local variables that the function uses, and that are consequently included in its closure.) 795 | /// # Parameters 796 | /// * `idx` - Index of the upvalue to push the value of onto the stack and return the name of (like debug.getlocal) 797 | /// * `fidx` - Points to the closure in the stack. 798 | /// # Note 799 | /// Upvalues have no particular order, as they are active through the whole function. 800 | /// So, they are numbered in an arbitrary order. 801 | /// # Returns 802 | /// The name of the upvalue at given index `idx`, or NULL (and pushes nothing) if the index is greater than the number of upvalues. 803 | /// For C functions (functions not created in lua), this returns an empty string for the name of all upvalues 804 | pub extern "C" fn lua_getupvalue(l: LuaState, fidx: c_int, idx: c_int) -> LuaString; 805 | 806 | /// Sets the value of a closure's upvalue. Parameters funcindex and n are as in lua_getupvalue (see lua_getupvalue). It assigns the value at the top of the stack to the upvalue and returns its name. It also pops the value from the stack. 807 | pub extern "C" fn lua_setupvalue(l: LuaState, fidx: c_int, idx: c_int) -> LuaString; 808 | 809 | /// Sets the value of a local variable of a given activation record. 810 | /// Parameters ar and n are as in [lua_getlocal]. 811 | /// lua_setlocal assigns the value at the top of the stack to the variable and returns its name. 812 | /// It also pops the value from the stack. 813 | pub extern "C" fn lua_setlocal(l: LuaState, ar: *mut LuaDebug, n: c_int) -> LuaString; 814 | } 815 | 816 | dyn_symbols! { 817 | /// Creates a copy of string 's' by replacing any occurrence of the string 'p' with the string 'r' 818 | /// Pushes the resulting string on the stack and returns it 819 | pub extern "C" fn luaL_gsub(s: LuaString, pattern: LuaString, replace: LuaString) -> LuaString; 820 | 821 | /// Exchange values between different threads of the same global state. 822 | /// This function pops `n` values from the stack `from`, and pushes them onto the stack `to`. 823 | pub extern "C" fn lua_xmove(from: LuaState, to: LuaState, n: c_int) -> (); 824 | } 825 | 826 | dyn_symbols! { 827 | /// Returns an unique identifier for the upvalue numbered n from the closure at index funcindex. 828 | /// Parameters funcindex and n are as in the [lua_getupvalue] (but n cannot be greater than the number of upvalues). 829 | /// These unique identifiers allow a program to check whether different closures share upvalues. 830 | /// Lua closures that share an upvalue (that is, that access a same external local variable) will return identical ids for those upvalue indices. 831 | pub extern "C" fn lua_upvalueid(l: LuaState, fidx: c_int, n: c_int) -> *mut c_void; 832 | 833 | /// Make the ``n1`` upvalue of the Lua closure at index ``fidx1`` refer to the ``n2`` upvalue of the Lua closure at index ``fidx2``. 834 | pub extern "C" fn lua_upvaluejoin(l: LuaState, fidx1: c_int, n1: c_int, fidx2: c_int, n2: c_int) -> (); 835 | } 836 | 837 | // Buffer functions 838 | dyn_symbols! { 839 | /// Initializes a buffer `b`. 840 | /// This function does not allocate any space; the buffer must be declared as a variable. 841 | pub extern "C" fn luaL_buffinit(l: LuaState, b: *mut LuaBuffer) -> (); 842 | 843 | /// Returns an address to a space of size [$crate::lua::BUFFERSIZE] where you can copy a string to be added to buffer [LuaBuffer] `b`. 844 | /// After copying the string into this space you must call luaL_addsize with the size of the string to actually add it to the buffer. 845 | pub extern "C" fn luaL_prepbuffer(b: *mut LuaBuffer) -> *mut c_char; 846 | 847 | /// Adds the zero-terminated string pointed to by `s` to the [LuaBuffer] `b` (see luaL_Buffer). 848 | /// The string may not contain embedded zeros. 849 | pub extern "C" fn luaL_addstring(b: *mut LuaBuffer, s: LuaString) -> (); 850 | 851 | /// Adds the string pointed to by `s` with length `l` to the [LuaBuffer] `b`. 852 | /// The string may contain embedded zeros. 853 | pub extern "C" fn luaL_addlstring(b: *mut LuaBuffer, s: LuaString, l: SizeT) -> (); 854 | 855 | /// Adds the value at the top of the stack to the buffer [LuaBuffer] `b`. Pops the value. 856 | /// This is the only function on string buffers that can (and must) be called with an extra element on the stack, which is the value to be added to the buffer. 857 | pub extern "C" fn luaL_addvalue(b: *mut LuaBuffer) -> (); 858 | 859 | /// Finishes the use of buffer `b` leaving the final string on the top of the stack. 860 | pub extern "C" fn luaL_pushresult(b: *mut LuaBuffer) -> (); 861 | } 862 | 863 | dyn_symbols! { 864 | /// Returns the memory-allocation function of a given state. 865 | /// If ud is not NULL, Lua stores in *ud the opaque pointer passed to lua_newstate. 866 | pub extern "C" fn lua_getallocf(l: LuaState, ud: *mut *mut c_void) -> LuaAlloc; 867 | 868 | /// Changes the allocator function of a given state to f with user data ud. 869 | pub extern "C" fn lua_setallocf(l: LuaState, f: LuaAlloc, ud: *mut c_void) -> (); 870 | } 871 | 872 | // Misc 873 | dyn_symbols! { 874 | /// Dumps a function as a binary chunk. 875 | /// Receives a Lua function on the top of the stack and produces a binary chunk that, if loaded again, results in a function equivalent to the one dumped. As it produces parts of the chunk, lua_dump calls function writer (see lua_Writer) with the given data to write them. 876 | pub extern "C" fn lua_dump(l: LuaState, writer: LuaWriter, data: *mut c_void) -> c_int; 877 | 878 | /// Grows the stack size to top + sz elements, raising an error if the stack cannot grow to that size. msg is an additional text to go into the error message. 879 | /// # Note 880 | /// You may be looking for [lua_checkstack] 881 | pub extern "C" fn luaL_checkstack(l: LuaState, size: c_int, msg: LuaString) -> (); 882 | } 883 | 884 | dyn_symbols! { 885 | /// Returns 1 if the value at the given acceptable index is a number or a string convertible to a number, and 0 otherwise. 886 | pub extern "C" fn lua_isnumber(l: LuaState, idx: c_int) -> c_int; 887 | 888 | /// Returns 1 if the value at the given acceptable index is a string or a number (which is always convertible to a string), and 0 otherwise. 889 | pub extern "C" fn lua_isstring(l: LuaState, idx: c_int) -> c_int; 890 | 891 | /// Returns 1 if the value at the given acceptable index is a C function, and 0 otherwise. 892 | pub extern "C" fn lua_iscfunction(l: LuaState, idx: c_int) -> c_int; 893 | 894 | /// Returns 1 if the value at the given acceptable index is a userdata (either full or light), and 0 otherwise. 895 | pub extern "C" fn lua_isuserdata(l: LuaState, idx: c_int) -> c_int; 896 | } 897 | 898 | // Inline functions to mirror the C macros that come with the lua api 899 | lua_macros! { 900 | /// Pops n elements from the lua stack. 901 | pub fn lua_pop(l: LuaState, ind: c_int) -> () { 902 | lua_settop(l, -(ind) - 1); 903 | }; 904 | 905 | /// Gets a value from _G 906 | /// Internally calls lua_getfield with [crate::lua::GLOBALSINDEX] 907 | pub fn lua_getglobal(l: LuaState, name: LuaString) -> () { 908 | lua_getfield(l, GLOBALSINDEX, name); 909 | }; 910 | 911 | /// Sets a value in _G 912 | /// Internally calls lua_setfield with [crate::lua::GLOBALSINDEX] 913 | pub fn lua_setglobal(l: LuaState, name: LuaString) -> () { 914 | lua_setfield(l, GLOBALSINDEX, name); 915 | }; 916 | 917 | /// Pushes a "C" function to the stack 918 | pub fn lua_pushcfunction(l: LuaState, fnc: LuaCFunction) -> () { 919 | lua_pushcclosure(l, fnc, 0); 920 | }; 921 | 922 | /// Equivalent to ``lua_tolstring(l, idx, [std::ptr::null_mut()])`` 923 | /// This may return None if the value at ``idx`` is not a string or a number. 924 | /// You should use [luaL_optstring] instead if you are unsure of the value, or [luaL_checkstring] for function arguments. 925 | pub fn lua_tostring(l: LuaState, idx: c_int) -> LuaString { 926 | lua_tolstring(l, idx, std::ptr::null_mut()) 927 | }; 928 | 929 | /// Starts and resumes a coroutine in a given thread 930 | pub fn lua_resume(l: LuaState, narg: c_int) -> c_int { 931 | lua_resume_real(l, narg) 932 | }; 933 | 934 | /// Returns if the value at the given index is a C or Lua function. 935 | pub fn lua_isfunction(l: LuaState, n: c_int) -> bool { 936 | lua_type(l, n) == lua::TFUNCTION 937 | }; 938 | 939 | /// Returns if the value at the given index is a table. 940 | pub fn lua_istable(l: LuaState, n: c_int) -> bool { 941 | lua_type(l, n) == lua::TTABLE 942 | }; 943 | 944 | pub fn lua_islightuserdata(l: LuaState, n: c_int) -> bool { 945 | lua_type(l, n) == lua::TLIGHTUSERDATA 946 | }; 947 | 948 | /// Returns if the value at the given index is nil. 949 | /// You might want to use [lua_isnoneornil] instead. 950 | pub fn lua_isnil(l: LuaState, n: c_int) -> bool { 951 | lua_type(l, n) == lua::TNIL 952 | }; 953 | 954 | /// Returns if the value at the given index is a boolean. 955 | pub fn lua_isboolean(l: LuaState, n: c_int) -> bool { 956 | lua_type(l, n) == lua::TBOOLEAN 957 | }; 958 | 959 | /// Returns if the value at the given index is a thread. 960 | pub fn lua_isthread(l: LuaState, n: c_int) -> bool { 961 | lua_type(l, n) == lua::TTHREAD 962 | }; 963 | 964 | /// Returns if the value at the given index is none (element outside of stack / invalid) 965 | pub fn lua_isnone(l: LuaState, n: c_int) -> bool { 966 | lua_type(l, n) == lua::TNONE 967 | }; 968 | 969 | /// Returns if the value at the given index is none (invalid) or nil. 970 | pub fn lua_isnoneornil(l: LuaState, n: c_int) -> bool { 971 | lua_type(l, n) <= 0 972 | }; 973 | 974 | /// Loads and pcalls a string of lua code 975 | /// Returns if the code was successfully executed 976 | /// Error will be left on the stack if the code failed to execute 977 | pub fn luaL_dostring(l: LuaState, str: LuaString) -> bool { 978 | luaL_loadstring(l, str) == 0 || lua_pcall(l, 0, lua::MULTRET, 0) == 0 979 | }; 980 | 981 | /// Loads and pcalls a file's lua code 982 | /// Returns if the code was successfully executed 983 | /// Error will be left on the stack if the code failed to execute 984 | pub fn luaL_dofile(l: LuaState, filename: LuaString) -> bool { 985 | luaL_loadfile(l, filename) == 0 || lua_pcall(l, 0, lua::MULTRET, 0) == 0 986 | }; 987 | 988 | /// Returns value at [crate::lua::REGISTRYINDEX] with name 'name' 989 | pub fn luaL_getmetatable(l: LuaState, name: LuaString) -> () { 990 | lua_getfield(l, lua::REGISTRYINDEX, name); 991 | }; 992 | 993 | /// If a condition is false, throws an argument error at numarg 994 | pub fn luaL_argcheck(l: LuaState, cond: bool, numarg: c_int, extramsg: LuaString) -> () { 995 | if !cond { 996 | luaL_argerror(l, numarg, extramsg); 997 | } 998 | }; 999 | 1000 | /// Returns the type name of object at index i 1001 | pub fn luaL_typename(l: LuaState, i: c_int) -> LuaString { 1002 | lua_typename(l, lua_type(l, i)) 1003 | }; 1004 | 1005 | /// Asserts that a string argument exists at index 'i' 1006 | pub fn luaL_checkstring(l: LuaState, i: c_int) -> LuaString { 1007 | luaL_checklstring(l, i, std::ptr::null_mut()) 1008 | }; 1009 | 1010 | /// Like lua_tostring or luaL_checkstring, but instead of returning an invalid string / erroring, 1011 | /// It returns the given `default` string. 1012 | pub fn luaL_optstring(l: LuaState, i: c_int, default: LuaString) -> LuaString { 1013 | luaL_optlstring(l, i, default, std::ptr::null_mut()) 1014 | }; 1015 | 1016 | /// Sets the C function ``f`` as the value of global name ``name``. 1017 | pub fn lua_register(l: LuaState, name: LuaString, f: LuaCFunction) -> () { 1018 | lua_pushcfunction(l, f); 1019 | lua_setglobal(l, name); 1020 | }; 1021 | 1022 | /// Creates a new empty table and pushes it onto the stack. 1023 | /// It is equivalent to ``lua_createtable(l, 0, 0)``. 1024 | pub fn lua_newtable(l: LuaState) -> () { 1025 | lua_createtable(l, 0, 0); 1026 | }; 1027 | } 1028 | 1029 | // Userdata helpers 1030 | lua_macros! { 1031 | 1032 | /// Returns a [Vector] on the stack at index ``idx``, or if there is no such value, throws a lua argument error. 1033 | pub fn luaL_checkvector(l: LuaState, idx: c_int) -> Vector { 1034 | unsafe { *( (*luaL_checkudata(l, idx, cstr!("Vector"))).data as *mut _) } 1035 | }; 1036 | 1037 | 1038 | /// Returns an [Angle] on the stack at index ``idx``, or if there is no such value, throws a lua argument error. 1039 | pub fn luaL_checkangle(l: LuaState, idx: c_int) -> crate::userdata::Angle { 1040 | unsafe { *( (*luaL_checkudata(l, idx, cstr!("Angle"))).data as *mut _) } 1041 | }; 1042 | } 1043 | 1044 | /// Pushes a vector onto the stack 1045 | /// # Example 1046 | /// Creates a LuaCFunction that will take three number arguments and return a glua Vector type. 1047 | /// ```rust 1048 | /// use rglua::prelude::*; 1049 | /// #[lua_function] 1050 | /// fn new_vector(l: LuaState) -> i32 { 1051 | /// let x = luaL_checknumber(l, 1) as f32; 1052 | /// let y = luaL_checknumber(l, 2) as f32; 1053 | /// let z = luaL_checknumber(l, 3) as f32; 1054 | /// lua_pushvector(l, Vector::new(x, y, z)); 1055 | /// // Return one value -- the new vector 1056 | /// 1 1057 | /// } 1058 | /// ``` 1059 | 1060 | pub fn lua_pushvector(l: LuaState, v: Vector) { 1061 | let ptr = lua_newuserdata(l, std::mem::size_of::()); 1062 | 1063 | // I am an actual maniac for doing this 1064 | unsafe { 1065 | let ty = std::ptr::addr_of_mut!((*ptr).typ); 1066 | ty.write(LuaType::Vector); 1067 | 1068 | let data = std::ptr::addr_of_mut!((*ptr).data); 1069 | // FIXME: This may leak memory.. need to make sure lua actually cleans it up. 1070 | // I am assuming this will be fine since Vectors are primitive and this is lua managed userdata. 1071 | data.write(Box::into_raw(Box::new(v)) as *mut c_void); 1072 | } 1073 | 1074 | luaL_getmetatable(l, cstr!("Vector")); 1075 | lua_setmetatable(l, -2); 1076 | } 1077 | 1078 | /// Pushes an angle onto the stack. 1079 | 1080 | pub fn lua_pushangle(l: LuaState, v: Angle) { 1081 | let ptr = lua_newuserdata(l, std::mem::size_of::()); 1082 | 1083 | unsafe { 1084 | let ty = std::ptr::addr_of_mut!((*ptr).typ); 1085 | ty.write(LuaType::Angle); 1086 | 1087 | let data = std::ptr::addr_of_mut!((*ptr).data); 1088 | data.write(Box::into_raw(Box::new(v)) as *mut c_void); 1089 | } 1090 | 1091 | luaL_getmetatable(l, cstr!("Angle")); 1092 | lua_setmetatable(l, -2); 1093 | } 1094 | 1095 | #[inline(always)] 1096 | #[allow(non_snake_case)] 1097 | /// Tries to see if the given value at index ``arg`` is nil or none, if so, returns ``default`` value. 1098 | /// Otherwise, runs ``func``, passing the lua state and arg indent and returns the value of that 1099 | /// # Returns 1100 | /// Type ``T`` either from the function or default value. 1101 | pub fn luaL_opt T>(l: LuaState, arg: c_int, default: T, func: F) -> T { 1102 | if lua_isnoneornil(l, arg) { 1103 | default 1104 | } else { 1105 | func(l, arg) 1106 | } 1107 | } 1108 | 1109 | /// This function works like [luaL_checkudata], except that, when the test fails, it returns None instead of throwing an error. 1110 | /// Adapted from Lua 5.3, note this does not actually exist in gluajit 1111 | #[allow(non_snake_case)] 1112 | pub fn luaL_testudata(l: LuaState, arg: c_int, tname: LuaString) -> Option<*mut super::Userdata> { 1113 | if lua_isuserdata(l, arg) == 1 { 1114 | lua_getmetatable(l, arg); // Object metatable 1115 | luaL_getmetatable(l, tname); // Desired global metatable 1116 | if lua_rawequal(l, -1, -2) == 1 { 1117 | return Some(lua_touserdata(l, arg) as *mut super::Userdata); 1118 | } 1119 | } 1120 | None 1121 | } 1122 | 1123 | #[inline(always)] 1124 | #[allow(non_snake_case)] 1125 | 1126 | /// Returns a [Vector] from the stack at index ``i``. 1127 | pub fn lua_tovector<'a>(l: LuaState, i: c_int) -> Option { 1128 | luaL_testudata(l, i, cstr!("Vector")).map(|x: *mut Userdata| unsafe { *(x as *mut Vector) }) 1129 | } 1130 | 1131 | #[inline(always)] 1132 | #[allow(non_snake_case)] 1133 | 1134 | /// Returns an [Angle] from the stack at index ``i``. 1135 | pub fn lua_toangle(l: LuaState, i: c_int) -> Option { 1136 | luaL_testudata(l, i, cstr!("Angle")).map(|x: *mut Userdata| unsafe { *(x as *mut Angle) }) 1137 | } 1138 | --------------------------------------------------------------------------------