gmod/
lib.rs

1//! [Available Lua Functions](https://docs.rs/gmod/latest/gmod/lua/struct.State.html)
2
3#![allow(clippy::missing_safety_doc)]
4#![allow(clippy::result_unit_err)]
5
6#![feature(c_unwind)]
7#![feature(thread_id_value)]
8
9#![cfg_attr(feature = "gmcl", feature(internal_output_capture))]
10
11#[cfg(not(all(any(target_os = "windows", target_os = "linux", target_os = "macos"), any(target_pointer_width = "32", target_pointer_width = "64"))))]
12compile_error!("Unsupported platform");
13
14pub use cstr;
15pub use libloading;
16pub use gmod_macros::*;
17
18#[cfg(feature = "hax")]
19mod haxports {
20	#[cfg(not(target_os = "macos"))]
21	pub use skidscan as sigscan;
22
23	#[cfg(target_os = "macos")]
24	compile_error!("Sigscanning is currently not supported on MacOS, please disable the `hax` feature on gmod-rs using `default-features = false` to make a normal module");
25
26	pub use retour as detour;
27	pub use ctor::{ctor as dllopen, dtor as dllclose};
28
29	pub use fn_type_alias::*;
30	pub use fn_abi::*;
31	pub use cfg_table::*;
32	pub use null_fn::*;
33	pub use fn_has_this::*;
34}
35#[cfg(feature = "hax")]
36pub use haxports::*;
37
38/// Lua interface
39pub mod lua;
40
41/// Colorful printing
42pub mod msgc;
43
44/// Advanced dark magic utilities
45pub mod hax;
46
47/// Userdata types
48pub mod userdata;
49
50/// Net library helpers
51pub mod net;
52
53/// Clientside module helpers
54#[cfg(feature = "gmcl")]
55pub mod gmcl;
56
57/// Returns whether this client is running the x86-64 branch
58pub fn is_x86_64() -> bool {
59	#[cfg(target_pointer_width = "64")] {
60		// 64-bit can only be x86-64
61		true
62	}
63	#[cfg(target_pointer_width = "32")] {
64		lazy_static::lazy_static! {
65			static ref IS_X86_64: bool = {
66				use std::path::PathBuf;
67
68				#[cfg(target_os = "macos")] {
69					PathBuf::from("garrysmod/bin/lua_shared.dylib").is_file()
70				}
71				#[cfg(target_os = "windows")] {
72					PathBuf::from("srcds_win64.exe").is_file()
73				}
74				#[cfg(target_os = "linux")] {
75					// Check executable name
76					match std::env::current_exe().expect("Failed to get executable path").file_name().expect("Failed to get executable file name").to_string_lossy().as_ref() {
77						#[cfg(target_os = "windows")]
78						"srcds.exe" => false,
79
80						#[cfg(target_os = "linux")]
81						"srcds_linux" => false,
82
83						#[cfg(target_os = "linux")]
84						"srcds" => true,
85
86						_ => {
87							// Check bin folder
88							#[cfg(target_os = "linux")] {
89								PathBuf::from("bin/linux64").is_dir()
90							}
91							#[cfg(target_os = "windows")] {
92								PathBuf::from("bin/win64").is_dir()
93							}
94						}
95					}
96				}
97			};
98		}
99		*IS_X86_64
100	}
101}
102
103/// Opens & returns a shared library loaded by Garry's Mod using the raw path to the module.
104///
105/// # Example
106/// ```no_run
107/// // This would only work on Windows x86-64 branch in 64-bit mode
108/// let (engine, engine_path): (gmod::libloading::Library, &'static str) = open_library_srv!("bin/win64/engine.dll").expect("Failed to open engine.dll!");
109/// println!("Opened engine.dll from: {}", engine_path);
110/// ```
111#[macro_export]
112macro_rules! open_library_raw {
113	($($path:literal),+) => {
114		match $crate::libloading::Library::new(concat!($($path),+)) {
115			Ok(lib) => Ok((lib, concat!($($path),+))),
116			Err(err) => Err((err, concat!($($path),+)))
117		}
118	}
119}
120
121/// Opens & returns a shared library loaded by Garry's Mod, in "server mode" (will prioritize _srv.so on Linux main branch)
122///
123/// Respects 32-bit/64-bit main/x86-64 branches and finds the correct library.
124///
125/// # Example
126/// ```no_run
127/// let (engine, engine_path): (gmod::libloading::Library, &'static str) = open_library_srv!("engine").expect("Failed to open engine.dll!");
128/// println!("Opened engine.dll from: {}", engine_path);
129/// ```
130#[macro_export]
131macro_rules! open_library_srv {
132	($name:literal) => {{
133		#[cfg(all(target_os = "windows", target_pointer_width = "64"))] {
134			$crate::__private__gmod_rs__try_chained_open! {
135				$crate::open_library_raw!("bin/win64/", $name, ".dll"),
136				$crate::open_library_raw!($name)
137			}
138		}
139		#[cfg(all(target_os = "windows", target_pointer_width = "32"))] {
140			$crate::__private__gmod_rs__try_chained_open! {
141				$crate::open_library_raw!("bin/", $name, ".dll"),
142				$crate::open_library_raw!("garrysmod/bin/", $name, ".dll"),
143				$crate::open_library_raw!($name)
144			}
145		}
146
147		#[cfg(all(target_os = "linux", target_pointer_width = "64"))] {
148			$crate::__private__gmod_rs__try_chained_open! {
149				$crate::open_library_raw!("bin/linux64/", $name, ".so"),
150				$crate::open_library_raw!("bin/linux64/lib", $name, ".so"),
151				$crate::open_library_raw!($name)
152			}
153		}
154		#[cfg(all(target_os = "linux", target_pointer_width = "32"))] {
155			$crate::__private__gmod_rs__try_chained_open! {
156				$crate::open_library_raw!("bin/linux32/", $name, ".so"),
157				$crate::open_library_raw!("bin/linux32/lib", $name, ".so"),
158				$crate::open_library_raw!("bin/", $name, "_srv.so"),
159				$crate::open_library_raw!("bin/lib", $name, "_srv.so"),
160				$crate::open_library_raw!("garrysmod/bin/", $name, "_srv.so"),
161				$crate::open_library_raw!("garrysmod/bin/lib", $name, "_srv.so"),
162				$crate::open_library_raw!("bin/", $name, ".so"),
163				$crate::open_library_raw!("bin/lib", $name, ".so"),
164				$crate::open_library_raw!("garrysmod/bin/", $name, ".so"),
165				$crate::open_library_raw!("garrysmod/bin/lib", $name, ".so"),
166				$crate::open_library_raw!($name)
167			}
168		}
169
170		#[cfg(target_os = "macos")] {
171			$crate::__private__gmod_rs__try_chained_open! {
172				$crate::open_library_raw!("GarrysMod_Signed.app/Contents/MacOS/", $name, ".dylib"),
173				$crate::open_library_raw!("GarrysMod_Signed.app/Contents/MacOS/lib", $name, ".dylib"),
174				$crate::open_library_raw!("bin/", $name, "_srv.dylib"),
175				$crate::open_library_raw!("bin/lib", $name, "_srv.dylib"),
176				$crate::open_library_raw!("garrysmod/bin/", $name, "_srv.dylib"),
177				$crate::open_library_raw!("garrysmod/bin/lib", $name, "_srv.dylib"),
178				$crate::open_library_raw!("bin/", $name, ".dylib"),
179				$crate::open_library_raw!("bin/lib", $name, ".dylib"),
180				$crate::open_library_raw!("garrysmod/bin/", $name, ".dylib"),
181				$crate::open_library_raw!("garrysmod/bin/lib", $name, ".dylib"),
182				$crate::open_library_raw!($name)
183			}
184		}
185	}};
186}
187
188/// Opens & returns a shared library loaded by Garry's Mod. You are most likely looking for `open_library_srv!`, as this will prioritize non-_srv.so libraries on Linux main branch.
189///
190/// Respects 32-bit/64-bit main/x86-64 branches and finds the correct library.
191///
192/// # Example
193/// ```no_run
194/// let (engine, engine_path): (gmod::libloading::Library, &'static str) = open_library!("engine").expect("Failed to open engine.dll!");
195/// println!("Opened engine.dll from: {}", engine_path);
196/// ```
197#[macro_export]
198macro_rules! open_library {
199	($name:literal) => {{
200		#[cfg(all(target_os = "windows", target_pointer_width = "64"))] {
201			$crate::__private__gmod_rs__try_chained_open! {
202				$crate::open_library_raw!("bin/win64/", $name, ".dll"),
203				$crate::open_library_raw!($name)
204			}
205		}
206		#[cfg(all(target_os = "windows", target_pointer_width = "32"))] {
207			$crate::__private__gmod_rs__try_chained_open! {
208				$crate::open_library_raw!("bin/", $name, ".dll"),
209				$crate::open_library_raw!("garrysmod/bin/", $name, ".dll"),
210				$crate::open_library_raw!($name)
211			}
212		}
213
214		#[cfg(all(target_os = "linux", target_pointer_width = "64"))] {
215			$crate::__private__gmod_rs__try_chained_open! {
216				$crate::open_library_raw!("bin/linux64/", $name, ".so"),
217				$crate::open_library_raw!("bin/linux64/lib", $name, ".so"),
218				$crate::open_library_raw!($name)
219			}
220		}
221		#[cfg(all(target_os = "linux", target_pointer_width = "32"))] {
222			$crate::__private__gmod_rs__try_chained_open! {
223				$crate::open_library_raw!("bin/linux32/", $name, ".so"),
224				$crate::open_library_raw!("bin/linux32/lib", $name, ".so"),
225				$crate::open_library_raw!("bin/", $name, ".so"),
226				$crate::open_library_raw!("bin/lib", $name, ".so"),
227				$crate::open_library_raw!("garrysmod/bin/", $name, ".so"),
228				$crate::open_library_raw!("garrysmod/bin/lib", $name, ".so"),
229				$crate::open_library_raw!("bin/", $name, "_srv.so"),
230				$crate::open_library_raw!("bin/lib", $name, "_srv.so"),
231				$crate::open_library_raw!("garrysmod/bin/", $name, "_srv.so"),
232				$crate::open_library_raw!("garrysmod/bin/lib", $name, "_srv.so"),
233				$crate::open_library_raw!($name)
234			}
235		}
236
237		#[cfg(target_os = "macos")] {
238			$crate::__private__gmod_rs__try_chained_open! {
239				$crate::open_library_raw!("GarrysMod_Signed.app/Contents/MacOS/", $name, ".dylib"),
240				$crate::open_library_raw!("GarrysMod_Signed.app/Contents/MacOS/lib", $name, ".dylib"),
241				$crate::open_library_raw!("bin/", $name, ".dylib"),
242				$crate::open_library_raw!("bin/lib", $name, ".dylib"),
243				$crate::open_library_raw!("garrysmod/bin/", $name, ".dylib"),
244				$crate::open_library_raw!("garrysmod/bin/lib", $name, ".dylib"),
245				$crate::open_library_raw!("bin/", $name, "_srv.dylib"),
246				$crate::open_library_raw!("bin/lib", $name, "_srv.dylib"),
247				$crate::open_library_raw!("garrysmod/bin/", $name, "_srv.dylib"),
248				$crate::open_library_raw!("garrysmod/bin/lib", $name, "_srv.dylib"),
249				$crate::open_library_raw!($name)
250			}
251		}
252	}};
253}
254
255#[derive(Default)]
256#[doc(hidden)]
257pub struct OpenGmodLibraryErrs(pub std::collections::HashMap<&'static str, libloading::Error>);
258impl std::error::Error for OpenGmodLibraryErrs {}
259impl std::fmt::Display for OpenGmodLibraryErrs {
260	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
261		writeln!(f)?;
262		for (path, err) in &self.0 {
263			writeln!(f, "{} = {}", path, err)?;
264		}
265		writeln!(f)?;
266		Ok(())
267	}
268}
269impl std::fmt::Debug for OpenGmodLibraryErrs {
270	#[inline]
271	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
272		std::fmt::Display::fmt(self, f)
273	}
274}
275
276#[doc(hidden)]
277#[macro_export]
278macro_rules! __private__gmod_rs__try_chained_open {
279	{$($expr:expr),+} => {
280		loop {
281			let mut errors = $crate::OpenGmodLibraryErrs::default();
282			$(
283				match $expr {
284					Ok(val) => break Ok(val),
285					Err((err, path)) => { errors.0.insert(path, err); }
286				}
287			)+
288			break Err(errors);
289		}
290	};
291}
292
293/// You don't need to use this if you are using the `#[gmod13_open]` macro.
294pub unsafe fn set_lua_state(state: *mut std::ffi::c_void) {
295	lua::__set_state__internal(lua::State(state));
296	lua::load();
297}