use crate as sys;
#[cfg(not(target_family = "wasm"))] #[cfg_attr(published_docs, doc(cfg(not(target_family = "wasm"))))]
use crate::toolbox::read_version_string;
#[cfg(target_family = "wasm")] #[cfg_attr(published_docs, doc(cfg(target_family = "wasm")))]
pub fn ensure_static_runtime_compatibility(
_get_proc_address: sys::GDExtensionInterfaceGetProcAddress,
) {
}
#[cfg(not(target_family = "wasm"))] #[cfg_attr(published_docs, doc(cfg(not(target_family = "wasm"))))]
pub fn ensure_static_runtime_compatibility(
get_proc_address: sys::GDExtensionInterfaceGetProcAddress,
) {
let api_version_str = crate::GdextBuild::godot_static_version_string();
let get_proc_address = get_proc_address.expect("get_proc_address unexpectedly null");
let data_ptr = get_proc_address as *const u32;
let major = unsafe { data_ptr.read() };
if major == 4 {
let minor = unsafe { data_ptr.offset(1).read() };
if minor == 0 {
let data_ptr = get_proc_address as *const sys::GDExtensionGodotVersion;
let runtime_version_str = unsafe {
let data_ref = &*data_ptr;
read_version_string(data_ref.string)
};
panic!(
"godot-rust compiled against a newer Godot version: {api_version_str}\n\
but loaded by legacy Godot binary, with version: {runtime_version_str}\n\
\n\
Update your Godot engine version, or read https://godot-rust.github.io/book/toolchain/compatibility.html.\n\
\n"
);
}
}
let static_version = crate::GdextBuild::godot_static_version_triple();
let (runtime_version_raw, _) = unsafe { runtime_version(get_proc_address) };
let runtime_version = (
runtime_version_raw.major as u8,
runtime_version_raw.minor as u8,
runtime_version_raw.patch as u8,
);
if runtime_version < static_version {
let runtime_version_str = unsafe { read_version_string(runtime_version_raw.string) };
let runtime_minor = runtime_version.1;
panic!(
"godot-rust compiled against newer Godot version: {api_version_str}\n\
but loaded by older Godot binary, with version: {runtime_version_str}\n\
\n\
Compile godot-rust with feature `api-4-{runtime_minor}` or update Godot engine.\n\
For more information, read https://godot-rust.github.io/book/toolchain/compatibility.html.\n\
\n"
);
}
}
type GetProcAddress =
unsafe extern "C" fn(*const std::ffi::c_char) -> sys::GDExtensionInterfaceFunctionPtr;
unsafe fn fetch_version<V>(
get_proc_address: GetProcAddress,
fn_name: &std::ffi::CStr,
) -> Option<V> {
let fn_ptr = unsafe { get_proc_address(fn_name.as_ptr()) };
let fn_ptr = fn_ptr?;
let caller: unsafe extern "C" fn(*mut V) = unsafe {
std::mem::transmute::<unsafe extern "C" fn(), unsafe extern "C" fn(*mut V)>(fn_ptr)
};
let mut version = std::mem::MaybeUninit::<V>::zeroed();
unsafe { caller(version.as_mut_ptr()) };
Some(unsafe { version.assume_init() })
}
pub(crate) unsafe fn runtime_version(
get_proc_address: GetProcAddress,
) -> (sys::GDExtensionGodotVersion, bool) {
let version1: Option<sys::GDExtensionGodotVersion> =
unsafe { fetch_version(get_proc_address, c"get_godot_version") };
if let Some(version1) = version1 {
return (version1, true);
}
#[cfg(since_api = "4.5")]
{
let version2: Option<sys::GDExtensionGodotVersion2> =
unsafe { fetch_version(get_proc_address, c"get_godot_version2") };
if let Some(version2) = version2 {
let version = sys::GDExtensionGodotVersion {
major: version2.major,
minor: version2.minor,
patch: version2.patch,
string: version2.string,
};
return (version, false);
}
}
panic!("None of `get_godot_version`, `get_godot_version2` function pointers available")
}
pub unsafe fn load_interface(
get_proc_address: sys::GDExtensionInterfaceGetProcAddress,
) -> sys::GDExtensionInterface {
unsafe { sys::GDExtensionInterface::load(get_proc_address) }
}