Macro quake3_native_vm::native_vm
source · macro_rules! native_vm { ($ty:ident) => { ... }; }
Expand description
Create required extern "C" fn
s to load a impl NativeVM
as shared library
Can only be used once per Rust lib. Each module (qagame
etc.) needs its own shared library.
Examples
Also see examples/hello.rs
of this crate.
Add the following section to your Cargo.toml
:
[lib]
name = "q3hi"
crate-type = ["cdylib"]
Then implement a module by using the macro as such:
use std::ffi::CString;
use quake3_native_vm::*;
struct HelloQuake3 {
syscall: Syscall,
}
/// See [ioquake3's `game/g_public.h`](https://github.com/ioquake/ioq3/blob/master/code/game/g_public.h)
const G_ERROR: ffi::intptr_t = 1;
const GAME_INIT: ffi::c_int = 0;
const GAME_SHUTDOWN: ffi::c_int = 1;
impl NativeVM for HelloQuake3 {
fn dll_entry(syscall: Syscall) -> Box<HelloQuake3> {
Box::new(HelloQuake3 { syscall: syscall })
}
fn vm_main(&self,
command: ffi::c_int,
arg0: ffi::c_int,
arg1: ffi::c_int,
arg2: ffi::c_int,
arg3: ffi::c_int,
arg4: ffi::c_int,
arg5: ffi::c_int,
arg6: ffi::c_int,
arg7: ffi::c_int,
arg8: ffi::c_int,
arg9: ffi::c_int,
arg10: ffi::c_int,
arg11: ffi::c_int)
-> ffi::intptr_t {
match command {
GAME_INIT => {
let msg = CString::new("Hello, World!").unwrap();
(self.syscall)(G_ERROR, msg.as_ptr());
unreachable!()
}
GAME_SHUTDOWN => {
// Just return a dummy value here for clean shutdown
0
},
_ => panic!("Game command not implemented"),
}
}
}
native_vm!(HelloQuake3);
Finally build the shared library, put it in the right place for Quake 3 and load it:
cargo build
mkdir -p ~/.q3a/rust/
cp target/debug/libq3hi.so ~/.q3a/rust/qagamex86_64.so
ioq3ded +set fs_game rust +set vm_game 0 +map q3dm6
See Sys_LoadGameDll
in ioquake3’s sys/sys_main.c
.