Skip to main content

rusteal_runtime/
lib.rs

1#![allow(clippy::missing_safety_doc)]
2
3pub use rusteal_core as runtime;
4pub use rusteal_ffi as ffi;
5pub use rusteal_macros::{uclass, uclass_impl, uenum, ustruct};
6pub use rusteal_ue_flags as ue_flags;
7
8#[doc(hidden)]
9pub extern crate inventory as __inventory;
10
11pub mod prelude;
12
13pub use glam;
14
15extern "C" fn real_drop_rust_instance(
16    handle: ffi::UObjectHandle,
17    type_id: u64,
18    _rust_data: *mut u8,
19) {
20    runtime::ffi_boundary((), || {
21        runtime::reify_registry::drop_instance(handle, type_id);
22    });
23}
24
25extern "C" fn real_invoke_rust_function(
26    callback_id: u64,
27    obj: ffi::UObjectHandle,
28    params: *mut u8,
29) {
30    runtime::ffi_boundary((), || {
31        runtime::reify_registry::invoke_function(callback_id, obj, params);
32    });
33}
34
35extern "C" fn real_invoke_delegate_callback(callback_id: u64, params: *mut u8) {
36    runtime::ffi_boundary((), || {
37        runtime::delegate_registry::invoke(callback_id, params);
38    });
39}
40
41extern "C" fn real_construct_rust_instance(obj: ffi::UObjectHandle, type_id: u64, _is_cdo: bool) {
42    runtime::ffi_boundary((), || {
43        runtime::reify_registry::construct_instance(obj, type_id);
44    });
45}
46
47extern "C" fn real_on_shutdown() {
48    runtime::ffi_boundary((), || {
49        runtime::task::shutdown();
50        runtime::reify_registry::clear_all();
51        runtime::delegate_registry::clear_all();
52        runtime::pinned::clear_all();
53    });
54}
55
56extern "C" fn real_notify_pinned_destroyed(handle: ffi::UObjectHandle) {
57    runtime::ffi_boundary((), || {
58        runtime::pinned::notify_pinned_destroyed(handle);
59    });
60}
61
62extern "C" fn real_on_tick(delta_seconds: f32) {
63    runtime::ffi_boundary((), || {
64        runtime::task::tick(delta_seconds);
65    });
66}
67
68#[doc(hidden)]
69pub static __CALLBACKS: ffi::RustealRustCallbacks = ffi::RustealRustCallbacks {
70    drop_rust_instance: real_drop_rust_instance,
71    invoke_rust_function: real_invoke_rust_function,
72    invoke_delegate_callback: real_invoke_delegate_callback,
73    on_shutdown: real_on_shutdown,
74    construct_rust_instance: real_construct_rust_instance,
75    notify_pinned_destroyed: real_notify_pinned_destroyed,
76    on_tick: real_on_tick,
77};
78
79pub unsafe fn init(api_table: *const ffi::RustealApiTable) -> *const ffi::RustealRustCallbacks {
80    std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
81        if api_table.is_null() {
82            return std::ptr::null();
83        }
84
85        if unsafe { (*api_table).version } != ffi::RUSTEAL_VERSION {
86            return std::ptr::null();
87        }
88
89        runtime::init_api(api_table);
90        runtime::task::mark_game_thread();
91        runtime::ffi_guard::install_panic_hook();
92
93        log_greeting();
94        register_all_classes();
95        run_load_hooks();
96
97        &__CALLBACKS as *const ffi::RustealRustCallbacks
98    }))
99    .unwrap_or(std::ptr::null())
100}
101
102fn log_greeting() {
103    let msg = "[Rusteal] Rust side initialized";
104    let bytes = msg.as_bytes();
105
106    unsafe {
107        runtime::ffi_dispatch::logging_log(0, bytes.as_ptr(), bytes.len() as u32);
108    }
109}
110
111fn register_all_classes() {
112    runtime::reify_registry::register_all_from_inventory();
113}
114
115#[doc(hidden)]
116pub struct LoadHook(pub fn());
117inventory::collect!(LoadHook);
118
119fn run_load_hooks() {
120    for hook in inventory::iter::<LoadHook> {
121        (hook.0)();
122    }
123}
124
125#[macro_export]
126macro_rules! on_load {
127    ($function:path) => {
128        $crate::__inventory::submit! { $crate::LoadHook($function) }
129    };
130}
131
132pub fn shutdown() {
133    let _ = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
134        (__CALLBACKS.on_shutdown)();
135    }));
136}
137
138#[macro_export]
139macro_rules! entry {
140    () => {
141        mod __rusteal_native_entry {
142            #[unsafe(no_mangle)]
143            pub extern "C" fn rusteal_init(
144                api_table: *const $crate::ffi::RustealApiTable,
145            ) -> *const $crate::ffi::RustealRustCallbacks {
146                $crate::runtime::error::set_source_root(env!("CARGO_MANIFEST_DIR"));
147                unsafe { $crate::init(api_table) }
148            }
149
150            #[unsafe(no_mangle)]
151            pub extern "C" fn rusteal_shutdown() {
152                $crate::shutdown()
153            }
154
155            #[unsafe(no_mangle)]
156            pub extern "C" fn rusteal_version() -> u32 {
157                $crate::ffi::RUSTEAL_VERSION
158            }
159
160            #[unsafe(no_mangle)]
161            pub extern "C" fn rusteal_callbacks() -> *const $crate::ffi::RustealRustCallbacks {
162                &$crate::__CALLBACKS
163            }
164        }
165    };
166}