Skip to content

Commit b5aebaf

Browse files
committed
Don't panic if godot_nativescript_init is called again
If this happens, the .gdnlib should probably be marked as not-reloadable for other reasons, but we should at least avoid panicking here.
1 parent 5937067 commit b5aebaf

File tree

2 files changed

+31
-7
lines changed

2 files changed

+31
-7
lines changed

gdnative-core/src/nativescript/init.rs

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -55,22 +55,32 @@ pub use self::method::{
5555
Method, MethodBuilder, RpcMode, ScriptMethod, ScriptMethodAttributes, ScriptMethodFn, Varargs,
5656
};
5757
pub use self::property::{Export, ExportInfo, PropertyBuilder, Usage as PropertyUsage};
58+
use std::any::TypeId;
59+
use std::collections::HashSet;
60+
use std::sync::Mutex;
5861

5962
/// A handle that can register new classes to the engine during initialization.
6063
///
6164
/// See [`godot_nativescript_init`](macro.godot_nativescript_init.html) and
6265
/// [`godot_init`](macro.godot_init.html).
6366
#[derive(Copy, Clone)]
64-
pub struct InitHandle {
67+
pub struct InitHandle<'a> {
6568
#[doc(hidden)]
6669
handle: *mut libc::c_void,
70+
registered_classes: &'a Mutex<HashSet<TypeId>>,
6771
}
6872

69-
impl InitHandle {
73+
impl<'a> InitHandle<'a> {
7074
#[doc(hidden)]
7175
#[inline]
72-
pub unsafe fn new(handle: *mut libc::c_void) -> Self {
73-
InitHandle { handle }
76+
pub unsafe fn new(
77+
handle: *mut libc::c_void,
78+
registered_classes: &'a Mutex<HashSet<TypeId>>,
79+
) -> Self {
80+
InitHandle {
81+
handle,
82+
registered_classes,
83+
}
7484
}
7585

7686
/// Registers a new class to the engine.
@@ -96,12 +106,20 @@ impl InitHandle {
96106
where
97107
C: NativeClassMethods,
98108
{
99-
if !class_registry::register_class::<C>() {
109+
if !self
110+
.registered_classes
111+
.lock()
112+
.unwrap()
113+
.insert(TypeId::of::<C>())
114+
{
100115
panic!(
101-
"`{type_name}` has already been registered",
116+
"`{type_name}` has already been registered with this handle",
102117
type_name = std::any::type_name::<C>()
103118
);
104119
}
120+
if !class_registry::register_class::<C>() {
121+
// perhaps the library was kept alive while no NativeScripts referenced it
122+
}
105123
unsafe {
106124
let class_name = CString::new(C::class_name()).unwrap();
107125
let base_name = CString::new(C::Base::class_name()).unwrap();

gdnative-core/src/nativescript/macros.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,13 @@ macro_rules! godot_nativescript_init {
3636
}
3737

3838
let __result = ::std::panic::catch_unwind(|| {
39-
$callback($crate::nativescript::init::InitHandle::new(handle));
39+
let mut registered_classes = ::std::sync::Mutex::new(
40+
::std::collections::HashSet::<::std::any::TypeId>::new(),
41+
);
42+
$callback($crate::nativescript::init::InitHandle::new(
43+
handle,
44+
&registered_classes,
45+
));
4046
});
4147

4248
if __result.is_err() {

0 commit comments

Comments
 (0)