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