rglua/interface/
mod.rs

1#![allow(non_snake_case)]
2
3pub(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
13mod common;
14mod cvar;
15mod engine;
16mod lua;
17mod materials;
18mod mdl;
19mod net;
20mod panel;
21mod client;
22
23pub use cvar::{CVar, ConVar};
24pub use engine::{EngineClient, EngineServer};
25pub use lua::{LuaInterface, LuaObject, LuaShared};
26pub use materials::MaterialSystem;
27pub use mdl::{MdlCache, MdlCacheNotify};
28pub use net::{NetChannelInfo, NetChannel, NetChannelHandler, NetMessage, CNetChan};
29pub use panel::Panel;
30pub use client::Client;
31
32use crate::try_cstr;
33use libloading::{Library, Symbol};
34use std::ffi::c_void;
35
36pub 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/// ```
54pub unsafe fn get_interface_handle(file: &str) -> Result<CreateInterfaceFn, libloading::Error> {
55	let lib = Library::new(file)?;
56	let sym: Symbol<CreateInterfaceFn> = lib.get(b"CreateInterface\0".as_ref())?;
57
58	Ok(*sym)
59}
60
61use thiserror::Error;
62
63#[derive(Debug, Error)]
64pub 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/// ```
107pub 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}