Skip to content

Commit 7a7ffdc

Browse files
committed
[WIP] Emit POSTINITIALIZE notification after init()
In godot 4.4 and later
1 parent 8526478 commit 7a7ffdc

File tree

7 files changed

+69
-9
lines changed

7 files changed

+69
-9
lines changed

godot-core/src/builtin/string/gstring.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -328,7 +328,11 @@ impl From<&str> for GString {
328328

329329
unsafe {
330330
Self::new_with_string_uninit(|string_ptr| {
331+
#[cfg(before_api = "4.3")]
331332
let ctor = interface_fn!(string_new_with_utf8_chars_and_len);
333+
#[cfg(since_api = "4.3")]
334+
let ctor = interface_fn!(string_new_with_utf8_chars_and_len2);
335+
332336
ctor(
333337
string_ptr,
334338
bytes.as_ptr() as *const std::ffi::c_char,

godot-core/src/classes/class_runtime.rs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -170,10 +170,15 @@ pub(crate) fn construct_engine_object<T>() -> Gd<T>
170170
where
171171
T: GodotClass + Bounds<Declarer = bounds::DeclEngine>,
172172
{
173-
// SAFETY: adhere to Godot API; valid class name and returned pointer is an object.
174173
unsafe {
175-
let object_ptr = sys::interface_fn!(classdb_construct_object)(T::class_name().string_sys());
176-
Gd::from_obj_sys(object_ptr)
174+
let object_ptr = sys::classdb_construct_object(T::class_name().string_sys());
175+
let obj = Gd::<T>::from_obj_sys(object_ptr);
176+
if cfg!(since_api = "4.4") {
177+
obj.clone()
178+
.upcast_object()
179+
.notify(crate::classes::notify::ObjectNotification::POSTINITIALIZE);
180+
}
181+
obj
177182
}
178183
}
179184

godot-core/src/obj/bounds.rs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -398,11 +398,7 @@ impl Declarer for DeclEngine {
398398
where
399399
T: GodotDefault + Bounds<Declarer = Self>,
400400
{
401-
unsafe {
402-
let object_ptr =
403-
sys::interface_fn!(classdb_construct_object)(T::class_name().string_sys());
404-
Gd::from_obj_sys(object_ptr)
405-
}
401+
crate::classes::construct_engine_object()
406402
}
407403
}
408404

godot-core/src/registry/callbacks.rs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,19 @@ pub unsafe extern "C" fn create<T: cap::GodotDefault>(
3535
_class_userdata: *mut std::ffi::c_void,
3636
_notify_postinitialize: sys::GDExtensionBool,
3737
) -> sys::GDExtensionObjectPtr {
38-
create_custom(T::__godot_user_init).unwrap_or(std::ptr::null_mut())
38+
if let Ok(object_ptr) = create_custom(T::__godot_user_init) {
39+
let mut obj = Gd::<Object>::from_obj_sys_weak(object_ptr);
40+
obj.notify(crate::classes::notify::ObjectNotification::POSTINITIALIZE);
41+
42+
// Mark initialization as complete, now that user constructor has finished.
43+
// base.mark_initialized();
44+
45+
std::mem::forget(obj);
46+
47+
object_ptr
48+
} else {
49+
std::ptr::null_mut()
50+
}
3951
}
4052

4153
#[cfg(before_api = "4.4")]

godot-ffi/src/lib.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -471,6 +471,18 @@ pub unsafe fn discover_main_thread() {
471471
}
472472
}
473473

474+
/// # Safety
475+
/// `class_name` is assumed to be valid.
476+
pub unsafe fn classdb_construct_object(
477+
class_name: GDExtensionConstStringNamePtr,
478+
) -> GDExtensionObjectPtr {
479+
if cfg!(before_api = "4.4") {
480+
interface_fn!(classdb_construct_object)(class_name)
481+
} else {
482+
interface_fn!(classdb_construct_object2)(class_name)
483+
}
484+
}
485+
474486
// ----------------------------------------------------------------------------------------------------------------------------------------------
475487
// Macros to access low-level function bindings
476488

itest/rust/src/object_tests/base_init_test.rs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,10 @@
77

88
use godot::builtin::real_consts::FRAC_PI_3;
99
use godot::builtin::Vector2;
10+
use godot::classes::notify::ObjectNotification;
1011
use godot::classes::{ClassDb, RefCounted};
1112
use godot::obj::{Gd, InstanceId, NewAlloc, NewGd, WithBaseField};
13+
use godot::prelude::*;
1214
use godot::task::TaskHandle;
1315

1416
use crate::framework::{expect_panic, itest, next_frame};
@@ -168,3 +170,30 @@ fn base_init_to_gd() {
168170
});
169171
});
170172
}
173+
174+
#[derive(GodotClass)]
175+
#[class(init)]
176+
struct RefcPostinit {
177+
pub base: Base<RefCounted>,
178+
}
179+
180+
#[godot_api]
181+
impl IRefCounted for RefcPostinit {
182+
fn on_notification(&mut self, what: ObjectNotification) {
183+
#[cfg(since_api = "4.4")]
184+
{
185+
if what == ObjectNotification::POSTINITIALIZE {
186+
self.base
187+
.to_init_gd()
188+
.set_meta("meta", &"inited".to_variant());
189+
} else if what == ObjectNotification::PREDELETE {
190+
assert_eq!(self.base().get_meta("meta"), "inited".to_variant())
191+
}
192+
}
193+
}
194+
}
195+
196+
#[itest]
197+
fn base_postinit_refcounted() {
198+
RefcPostinit::new_gd();
199+
}

itest/rust/src/object_tests/virtual_methods_test.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -520,6 +520,8 @@ fn test_notifications() {
520520
assert_eq!(
521521
obj.bind().sequence,
522522
vec![
523+
#[cfg(since_api = "4.4")]
524+
ReceivedEvent::Notification(NodeNotification::POSTINITIALIZE),
523525
ReceivedEvent::Notification(NodeNotification::UNPAUSED),
524526
ReceivedEvent::Notification(NodeNotification::EDITOR_POST_SAVE),
525527
ReceivedEvent::Ready,

0 commit comments

Comments
 (0)