Skip to content

Commit 57ad44e

Browse files
committed
Use the class_name for the field when building PropertyInfo
Godot uses the class_name to construct an instance of the right type in a few places, in particular for the PROPERTY_USAGE_EDITOR_INSTANTIATE_OBJECT flag.
1 parent 88a7934 commit 57ad44e

File tree

3 files changed

+112
-16
lines changed

3 files changed

+112
-16
lines changed

godot-macros/src/class/data_models/property.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,8 @@ pub fn make_property_impl(class_name: &Ident, fields: &Fields) -> TokenStream {
6767
continue;
6868
};
6969

70+
let field_variant_type = util::property_variant_type(field_type);
71+
let field_class_name = util::property_variant_class_name(field_type);
7072
let field_name = field_ident.to_string();
7173

7274
// rustfmt wont format this if we put it in the let-else.
@@ -178,8 +180,8 @@ pub fn make_property_impl(class_name: &Ident, fields: &Fields) -> TokenStream {
178180
let usage = #usage_flags;
179181

180182
let property_info = ::godot::builtin::meta::PropertyInfo {
181-
variant_type: <<#field_type as ::godot::bind::property::Property>::Intermediate as ::godot::builtin::meta::VariantMetadata>::variant_type(),
182-
class_name: #class_name_obj,
183+
variant_type: #field_variant_type,
184+
class_name: #field_class_name,
183185
property_name: #field_name.into(),
184186
hint,
185187
hint_string,
@@ -194,7 +196,7 @@ pub fn make_property_impl(class_name: &Ident, fields: &Fields) -> TokenStream {
194196
unsafe {
195197
::godot::sys::interface_fn!(classdb_register_extension_class_property)(
196198
::godot::sys::get_library(),
197-
#class_name::class_name().string_sys(),
199+
#class_name_obj.string_sys(),
198200
std::ptr::addr_of!(property_info_sys),
199201
setter_name.string_sys(),
200202
getter_name.string_sys(),

godot-macros/src/util/mod.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,16 @@ pub fn class_name_obj(class: &impl ToTokens) -> TokenStream {
3232
quote! { <#class as ::godot::obj::GodotClass>::class_name() }
3333
}
3434

35+
pub fn property_variant_type(property_type: &impl ToTokens) -> TokenStream {
36+
let property_type = property_type.to_token_stream();
37+
quote! {<<#property_type as ::godot::bind::property::Property>::Intermediate as ::godot::builtin::meta::VariantMetadata>::variant_type()}
38+
}
39+
40+
pub fn property_variant_class_name(property_type: &impl ToTokens) -> TokenStream {
41+
let property_type = property_type.to_token_stream();
42+
quote! {<<#property_type as ::godot::bind::property::Property>::Intermediate as ::godot::builtin::meta::VariantMetadata>::class_name()}
43+
}
44+
3545
pub fn bail_fn<R, T>(msg: impl AsRef<str>, tokens: T) -> ParseResult<R>
3646
where
3747
T: Spanned,

itest/rust/src/object_tests/property_test.rs

Lines changed: 97 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,10 @@
66

77
use godot::{
88
bind::property::ExportInfo,
9-
engine::{global::PropertyHint, Texture},
9+
engine::{
10+
global::{PropertyHint, PropertyUsageFlags},
11+
Texture,
12+
},
1013
prelude::*,
1114
test::itest,
1215
};
@@ -351,20 +354,101 @@ fn derive_export() {
351354
.iter_shared()
352355
.find(|c| c.get_or_nil("name") == "foo".to_variant())
353356
.unwrap();
354-
assert_eq!(
355-
property.get_or_nil("class_name"),
356-
"DeriveExport".to_variant()
357+
// `class_name` should be empty for non-Object variants.
358+
check_property(&property, "class_name", "");
359+
check_property(&property, "type", VariantType::Int as i32);
360+
check_property(&property, "hint", PropertyHint::PROPERTY_HINT_ENUM.ord());
361+
check_property(&property, "hint_string", "A:0,B:1,C:2");
362+
check_property(
363+
&property,
364+
"usage",
365+
PropertyUsageFlags::PROPERTY_USAGE_DEFAULT.ord(),
357366
);
358-
assert_eq!(
359-
property.get_or_nil("type"),
360-
(VariantType::Int as i32).to_variant()
367+
}
368+
369+
#[derive(GodotClass)]
370+
#[class(init, base=Resource)]
371+
pub struct CustomResource {}
372+
373+
#[godot_api]
374+
impl CustomResource {}
375+
376+
#[godot_api]
377+
impl ResourceVirtual for CustomResource {}
378+
379+
#[derive(GodotClass)]
380+
#[class(init, base=Resource, rename=NewNameCustomResource)]
381+
pub struct RenamedCustomResource {}
382+
383+
#[godot_api]
384+
impl RenamedCustomResource {}
385+
386+
#[godot_api]
387+
impl ResourceVirtual for RenamedCustomResource {}
388+
389+
#[derive(GodotClass)]
390+
#[class(init, base=Node)]
391+
pub struct ExportResource {
392+
#[export]
393+
#[var(usage_flags=[PROPERTY_USAGE_DEFAULT, PROPERTY_USAGE_EDITOR_INSTANTIATE_OBJECT])]
394+
pub foo: Option<Gd<CustomResource>>,
395+
396+
#[export]
397+
pub bar: Option<Gd<RenamedCustomResource>>,
398+
}
399+
400+
#[godot_api]
401+
impl ExportResource {}
402+
403+
#[godot_api]
404+
impl NodeVirtual for ExportResource {}
405+
406+
#[itest]
407+
fn export_resource() {
408+
let class: Gd<ExportResource> = Gd::new_default();
409+
410+
let property = class
411+
.get_property_list()
412+
.iter_shared()
413+
.find(|c| c.get_or_nil("name") == "foo".to_variant())
414+
.unwrap();
415+
check_property(&property, "class_name", "CustomResource");
416+
check_property(&property, "type", VariantType::Object as i32);
417+
check_property(
418+
&property,
419+
"hint",
420+
PropertyHint::PROPERTY_HINT_RESOURCE_TYPE.ord(),
421+
);
422+
check_property(&property, "hint_string", "CustomResource");
423+
check_property(
424+
&property,
425+
"usage",
426+
PropertyUsageFlags::PROPERTY_USAGE_DEFAULT.ord()
427+
| PropertyUsageFlags::PROPERTY_USAGE_EDITOR_INSTANTIATE_OBJECT.ord(),
361428
);
362-
assert_eq!(
363-
property.get_or_nil("hint"),
364-
(PropertyHint::PROPERTY_HINT_ENUM.ord()).to_variant()
429+
430+
let property = class
431+
.get_property_list()
432+
.iter_shared()
433+
.find(|c| c.get_or_nil("name") == "bar".to_variant())
434+
.unwrap();
435+
check_property(&property, "class_name", "NewNameCustomResource");
436+
check_property(&property, "type", VariantType::Object as i32);
437+
check_property(
438+
&property,
439+
"hint",
440+
PropertyHint::PROPERTY_HINT_RESOURCE_TYPE.ord(),
365441
);
366-
assert_eq!(
367-
property.get_or_nil("hint_string"),
368-
"A:0,B:1,C:2".to_variant()
442+
check_property(&property, "hint_string", "NewNameCustomResource");
443+
check_property(
444+
&property,
445+
"usage",
446+
PropertyUsageFlags::PROPERTY_USAGE_DEFAULT.ord(),
369447
);
448+
449+
class.free();
450+
}
451+
452+
fn check_property(property: &Dictionary, key: &str, expected: impl ToVariant) {
453+
assert_eq!(property.get_or_nil(key), expected.to_variant());
370454
}

0 commit comments

Comments
 (0)