Skip to content

Commit 1662122

Browse files
committed
Hot reload: work around #[class(no_init)] limitation before Godot 4.5
1 parent 30cd060 commit 1662122

File tree

3 files changed

+50
-0
lines changed

3 files changed

+50
-0
lines changed

godot-core/src/registry/callbacks.rs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,24 @@ pub unsafe extern "C" fn create<T: cap::GodotDefault>(
4343
create_custom(T::__godot_user_init).unwrap_or(std::ptr::null_mut())
4444
}
4545

46+
/// Workaround for <https://github.com/godot-rust/gdext/issues/874> before Godot 4.5.
47+
///
48+
/// Godot expects a creator function, but doesn't require an actual object to be instantiated.
49+
#[cfg(all(since_api = "4.4", before_api = "4.5"))]
50+
pub unsafe extern "C" fn create_null<T>(
51+
_class_userdata: *mut std::ffi::c_void,
52+
_notify_postinitialize: sys::GDExtensionBool,
53+
) -> sys::GDExtensionObjectPtr {
54+
std::ptr::null_mut()
55+
}
56+
57+
#[cfg(before_api = "4.4")]
58+
pub unsafe extern "C" fn create_null<T>(
59+
_class_userdata: *mut std::ffi::c_void,
60+
) -> sys::GDExtensionObjectPtr {
61+
std::ptr::null_mut()
62+
}
63+
4664
/// Godot FFI function for recreating a GDExtension instance, e.g. after a hot reload.
4765
///
4866
/// If the `init()` constructor panics, null is returned.
@@ -55,6 +73,17 @@ pub unsafe extern "C" fn recreate<T: cap::GodotDefault>(
5573
.unwrap_or(std::ptr::null_mut())
5674
}
5775

76+
/// Workaround for <https://github.com/godot-rust/gdext/issues/874> before Godot 4.5.
77+
///
78+
/// Godot expects a creator function, but doesn't require an actual object to be instantiated.
79+
#[cfg(all(since_api = "4.2", before_api = "4.5"))]
80+
pub unsafe extern "C" fn recreate_null<T>(
81+
_class_userdata: *mut std::ffi::c_void,
82+
_object: sys::GDExtensionObjectPtr,
83+
) -> sys::GDExtensionClassInstancePtr {
84+
std::ptr::null_mut()
85+
}
86+
5887
pub(crate) fn create_custom<T, F>(
5988
make_user_instance: F,
6089
) -> Result<sys::GDExtensionObjectPtr, PanicPayload>

godot-core/src/registry/plugin.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,10 @@ pub struct Struct {
147147

148148
/// Godot low-level `create` function, wired up to library-generated `init`.
149149
///
150+
/// For `#[class(no_init)]`, behavior depends on Godot version:
151+
/// - 4.5 and later: `None`
152+
/// - until 4.4: a dummy function that fails, to not break hot reloading.
153+
///
150154
/// This is mutually exclusive with [`ITraitImpl::user_create_fn`].
151155
pub(crate) generated_create_fn: Option<GodotCreateFn>,
152156

@@ -222,6 +226,19 @@ impl Struct {
222226
self
223227
}
224228

229+
// Workaround for https://github.com/godot-rust/gdext/issues/874, before https://github.com/godotengine/godot/pull/99133 is merged in 4.5.
230+
#[cfg(before_api = "4.5")]
231+
pub fn with_generated_no_default<T: GodotClass>(mut self) -> Self {
232+
set(&mut self.generated_create_fn, callbacks::create_null::<T>);
233+
234+
#[cfg(since_api = "4.2")]
235+
set(
236+
&mut self.generated_recreate_fn,
237+
callbacks::recreate_null::<T>,
238+
);
239+
self
240+
}
241+
225242
pub fn with_default_get_virtual_fn<T: GodotClass + UserClass>(mut self) -> Self {
226243
set(
227244
&mut self.default_get_virtual_fn,

godot-macros/src/class/derive_godot_class.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,10 @@ pub fn derive_godot_class(item: venial::Item) -> ParseResult<TokenStream> {
122122
}
123123
InitStrategy::Absent => {
124124
is_instantiable = false;
125+
126+
// Workaround for https://github.com/godot-rust/gdext/issues/874 before Godot 4.5.
127+
#[cfg(before_api = "4.5")]
128+
modifiers.push(quote! { with_generated_no_default::<#class_name> });
125129
}
126130
};
127131
if is_instantiable {

0 commit comments

Comments
 (0)