Skip to content

Commit 0812e49

Browse files
committed
Update postinit handling
1 parent e1073bc commit 0812e49

File tree

8 files changed

+102
-12
lines changed

8 files changed

+102
-12
lines changed

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

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

326326
unsafe {
327327
Self::new_with_string_uninit(|string_ptr| {
328+
#[cfg(before_api = "4.3")]
328329
let ctor = interface_fn!(string_new_with_utf8_chars_and_len);
330+
#[cfg(since_api = "4.3")]
331+
let ctor = interface_fn!(string_new_with_utf8_chars_and_len2);
332+
329333
ctor(
330334
string_ptr,
331335
bytes.as_ptr() as *const std::ffi::c_char,

godot-core/src/classes/class_runtime.rs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -60,11 +60,7 @@ pub(crate) fn construct_engine_object<T>() -> Gd<T>
6060
where
6161
T: GodotClass + Bounds<Declarer = bounds::DeclEngine>,
6262
{
63-
// SAFETY: adhere to Godot API; valid class name and returned pointer is an object.
64-
unsafe {
65-
let object_ptr = sys::interface_fn!(classdb_construct_object)(T::class_name().string_sys());
66-
Gd::from_obj_sys(object_ptr)
67-
}
63+
Gd::new_alloc_postinited()
6864
}
6965

7066
pub(crate) fn ensure_object_alive(

godot-core/src/obj/bounds.rs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -389,11 +389,7 @@ impl Declarer for DeclEngine {
389389
where
390390
T: GodotDefault + Bounds<Declarer = Self>,
391391
{
392-
unsafe {
393-
let object_ptr =
394-
sys::interface_fn!(classdb_construct_object)(T::class_name().string_sys());
395-
Gd::from_obj_sys(object_ptr)
396-
}
392+
Gd::new_alloc_postinited()
397393
}
398394
}
399395

godot-core/src/obj/gd.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -560,6 +560,24 @@ impl<T: GodotClass> Gd<T> {
560560
// Do not increment ref-count; assumed to be return value from FFI.
561561
sys::ptr_then(object_ptr, |ptr| Gd::from_obj_sys_weak(ptr))
562562
}
563+
564+
pub(crate) fn new_alloc_postinited() -> Self {
565+
#[cfg(before_api = "4.4")]
566+
unsafe {
567+
let object_ptr = sys::classdb_construct_object(T::class_name().string_sys());
568+
Gd::from_obj_sys(object_ptr)
569+
}
570+
#[cfg(since_api = "4.4")]
571+
unsafe {
572+
let object_ptr =
573+
sys::classdb_construct_object_no_postinit(T::class_name().string_sys());
574+
let obj = Gd::<T>::from_obj_sys(object_ptr);
575+
obj.clone()
576+
.upcast_object()
577+
.notify(crate::classes::notify::ObjectNotification::POSTINITIALIZE);
578+
Gd::from_obj_sys(object_ptr)
579+
}
580+
}
563581
}
564582

565583
/// _The methods in this impl block are only available for objects `T` that are manually managed,

godot-core/src/registry/callbacks.rs

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,14 @@ pub unsafe extern "C" fn create<T: cap::GodotDefault>(
3333
_class_userdata: *mut std::ffi::c_void,
3434
_notify_postinitialize: sys::GDExtensionBool,
3535
) -> sys::GDExtensionObjectPtr {
36-
create_custom(T::__godot_user_init).unwrap_or(std::ptr::null_mut())
36+
if let Ok(object_ptr) = create_custom(T::__godot_user_init) {
37+
let mut obj = Gd::<T>::from_obj_sys_weak(object_ptr).upcast_object();
38+
obj.notify(crate::classes::notify::ObjectNotification::POSTINITIALIZE);
39+
std::mem::forget(obj);
40+
object_ptr
41+
} else {
42+
std::ptr::null_mut()
43+
}
3744
}
3845

3946
#[cfg(before_api = "4.4")]
@@ -92,7 +99,11 @@ where
9299
F: FnOnce(Base<T::Base>) -> T,
93100
{
94101
let base_class_name = T::Base::class_name();
95-
let base_ptr = unsafe { interface_fn!(classdb_construct_object)(base_class_name.string_sys()) };
102+
#[cfg(before_api = "4.4")]
103+
let base_ptr = unsafe { sys::classdb_construct_object(base_class_name.string_sys()) };
104+
#[cfg(since_api = "4.4")]
105+
let base_ptr =
106+
unsafe { sys::classdb_construct_object_no_postinit(base_class_name.string_sys()) };
96107

97108
match create_rust_part_for_existing_godot_part(make_user_instance, base_ptr) {
98109
Ok(_extension_ptr) => Ok(base_ptr),

godot-ffi/src/lib.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -440,6 +440,24 @@ pub fn is_main_thread() -> bool {
440440
std::thread::current().id() == main_thread_id()
441441
}
442442

443+
/// # Safety
444+
/// `class_name` is assumed to be valid.
445+
#[cfg(before_api = "4.4")]
446+
pub unsafe fn classdb_construct_object(
447+
class_name: GDExtensionConstStringNamePtr,
448+
) -> GDExtensionObjectPtr {
449+
interface_fn!(classdb_construct_object)(class_name)
450+
}
451+
452+
/// # Safety
453+
/// `class_name` is assumed to be valid.
454+
#[cfg(since_api = "4.4")]
455+
pub unsafe fn classdb_construct_object_no_postinit(
456+
class_name: GDExtensionConstStringNamePtr,
457+
) -> GDExtensionObjectPtr {
458+
interface_fn!(classdb_construct_object2)(class_name)
459+
}
460+
443461
// ----------------------------------------------------------------------------------------------------------------------------------------------
444462
// Macros to access low-level function bindings
445463

itest/rust/src/engine_tests/node_test.rs

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,11 @@
88
use std::str::FromStr;
99

1010
use godot::builtin::{vslice, NodePath};
11+
use godot::classes::notify::NodeNotification;
1112
use godot::classes::{Node, Node3D, PackedScene, SceneTree};
1213
use godot::global;
1314
use godot::obj::{NewAlloc, NewGd};
15+
use godot::prelude::*;
1416

1517
use crate::framework::{itest, TestContext};
1618

@@ -92,3 +94,46 @@ fn node_call_group(ctx: &TestContext) {
9294
node.add_to_group("group");
9395
tree.call_group("group", "set_name", vslice!["name"]);
9496
}
97+
98+
#[derive(GodotClass, Debug)]
99+
#[class(base=Node)]
100+
struct NodeChild {
101+
child: Gd<Node>,
102+
notifications: Vec<NodeNotification>,
103+
}
104+
105+
#[godot_api]
106+
impl INode for NodeChild {
107+
fn init(_: Base<Node>) -> Self {
108+
let child = Node::new_alloc();
109+
Self {
110+
child,
111+
notifications: vec![],
112+
}
113+
}
114+
115+
fn on_notification(&mut self, what: NodeNotification) {
116+
match what {
117+
NodeNotification::READY => self.notifications.push(NodeNotification::READY),
118+
NodeNotification::PARENTED => self.notifications.push(NodeNotification::PARENTED),
119+
NodeNotification::POSTINITIALIZE => {
120+
self.notifications.push(NodeNotification::POSTINITIALIZE)
121+
}
122+
_ => {}
123+
};
124+
}
125+
}
126+
127+
// https://github.com/godotengine/godot/issues/91023
128+
#[cfg(since_api = "4.4")]
129+
#[itest]
130+
fn node_add_child_in_init() {
131+
let node = NodeChild::new_alloc();
132+
let dup: Gd<NodeChild> = node.duplicate().unwrap().cast();
133+
assert_eq!(
134+
dup.bind().notifications,
135+
vec![NodeNotification::POSTINITIALIZE]
136+
);
137+
node.free();
138+
dup.free();
139+
}

itest/rust/src/object_tests/virtual_methods_test.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -517,6 +517,8 @@ fn test_notifications() {
517517
assert_eq!(
518518
obj.bind().sequence,
519519
vec![
520+
#[cfg(since_api = "4.4")]
521+
ReceivedEvent::Notification(NodeNotification::POSTINITIALIZE),
520522
ReceivedEvent::Notification(NodeNotification::UNPAUSED),
521523
ReceivedEvent::Notification(NodeNotification::EDITOR_POST_SAVE),
522524
ReceivedEvent::Ready,

0 commit comments

Comments
 (0)