Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use the class_name for the field when building PropertyInfo #441

Merged
merged 2 commits into from
Oct 6, 2023

Conversation

HenryWConklin
Copy link
Contributor

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.

Partial fix for #440

@GodotRust
Copy link

API docs are being generated and will be shortly available at: https://godot-rust.github.io/docs/gdext/pr-441

@HenryWConklin
Copy link
Contributor Author

Getting some new errors in unchanged files with the update to rust 1.73.0. Added fixes in a new commit, let me know if you want me to squash them or move it to a separate PR.

Copy link
Member

@Bromeon Bromeon left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! 🙂

The logic around the actual bugfix is solely in property.rs, if I see correctly?
Could you elaborate what precisely was broken and how it's fixed?

Clippy fixes are fine as-is in a separate commit 👍

@@ -68,10 +68,10 @@ macro_rules! impl_builtin_traits_inner {
impl Eq for $Type {}
};

( PartialOrd for $Type:ty => $gd_method:ident ) => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice improvement!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! Clippy actually flagged the whole PartialOrd implementation as "incorrect" because there was an implementation for Ord which was interesting.

Comment on lines 386 to 391
#[godot_api]
impl ResourceVirtual for CustomResource {
fn init(_base: godot::obj::Base<Self::Base>) -> Self {
Self {}
}
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Such blocks can be replaced with #[class(..., init)] (also below).

Comment on lines 440 to 447
// `class_name` should be empty for non-Object variants.
assert_eq!(
property.get_or_nil("class_name"),
"CustomResource".to_variant()
);
assert_eq!(
property.get_or_nil("type"),
(VariantType::Object as i32).to_variant()
);
assert_eq!(
property.get_or_nil("hint"),
(PropertyHint::PROPERTY_HINT_RESOURCE_TYPE.ord()).to_variant()
);
assert_eq!(
property.get_or_nil("hint_string"),
"CustomResource".to_variant()
);
assert_eq!(
property.get_or_nil("usage"),
(PropertyUsageFlags::PROPERTY_USAGE_DEFAULT.ord()
| PropertyUsageFlags::PROPERTY_USAGE_EDITOR_INSTANTIATE_OBJECT.ord())
.to_variant()
);

let property = class
.get_property_list()
.iter_shared()
.find(|c| c.get_or_nil("name") == "bar".to_variant())
.unwrap();
// `class_name` should be empty for non-Object variants.
assert_eq!(
property.get_or_nil("class_name"),
"NewNameCustomResource".to_variant()
);
assert_eq!(
property.get_or_nil("type"),
(VariantType::Object as i32).to_variant()
);
assert_eq!(
property.get_or_nil("hint"),
(PropertyHint::PROPERTY_HINT_RESOURCE_TYPE.ord()).to_variant()
);
assert_eq!(
property.get_or_nil("hint_string"),
"NewNameCustomResource".to_variant()
);
assert_eq!(
property.get_or_nil("usage"),
PropertyUsageFlags::PROPERTY_USAGE_DEFAULT
.ord()
.to_variant()
);
Copy link
Member

@Bromeon Bromeon Oct 6, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You have a lot of code following the same pattern, which can be extracted into a function.

fn check_property(property: &Dictionary, key: &str, expected: impl ToVariant) {
    assert_eq!(property.get_or_nil(key), expected.to_variant());
}

This would then simply the code to:

Suggested change
// `class_name` should be empty for non-Object variants.
assert_eq!(
property.get_or_nil("class_name"),
"CustomResource".to_variant()
);
assert_eq!(
property.get_or_nil("type"),
(VariantType::Object as i32).to_variant()
);
assert_eq!(
property.get_or_nil("hint"),
(PropertyHint::PROPERTY_HINT_RESOURCE_TYPE.ord()).to_variant()
);
assert_eq!(
property.get_or_nil("hint_string"),
"CustomResource".to_variant()
);
assert_eq!(
property.get_or_nil("usage"),
(PropertyUsageFlags::PROPERTY_USAGE_DEFAULT.ord()
| PropertyUsageFlags::PROPERTY_USAGE_EDITOR_INSTANTIATE_OBJECT.ord())
.to_variant()
);
let property = class
.get_property_list()
.iter_shared()
.find(|c| c.get_or_nil("name") == "bar".to_variant())
.unwrap();
// `class_name` should be empty for non-Object variants.
assert_eq!(
property.get_or_nil("class_name"),
"NewNameCustomResource".to_variant()
);
assert_eq!(
property.get_or_nil("type"),
(VariantType::Object as i32).to_variant()
);
assert_eq!(
property.get_or_nil("hint"),
(PropertyHint::PROPERTY_HINT_RESOURCE_TYPE.ord()).to_variant()
);
assert_eq!(
property.get_or_nil("hint_string"),
"NewNameCustomResource".to_variant()
);
assert_eq!(
property.get_or_nil("usage"),
PropertyUsageFlags::PROPERTY_USAGE_DEFAULT
.ord()
.to_variant()
);
// `class_name` should be empty for non-Object variants.
check_property(&property, "class_name", "CustomResource");
check_property(&property, "type", VariantType::Object as i32);
check_property(&property, "hint", PropertyHint::PROPERTY_HINT_RESOURCE_TYPE.ord());
check_property(&property, "hint_string", "CustomResource");
check_property(&property, "usage", PropertyUsageFlags::PROPERTY_USAGE_DEFAULT.ord()
| PropertyUsageFlags::PROPERTY_USAGE_EDITOR_INSTANTIATE_OBJECT.ord());
let property = class
.get_property_list()
.iter_shared()
.find(|c| c.get_or_nil("name") == "bar".to_variant())
.unwrap();
// `class_name` should be empty for non-Object variants.
check_property(&property, "class_name", "NewNameCustomResource");
check_property(&property, "type", VariantType::Object as i32);
check_property(&property, "hint", PropertyHint::PROPERTY_HINT_RESOURCE_TYPE.ord());
check_property(&property, "hint_string", "NewNameCustomResource");
check_property(&property, "usage", PropertyUsageFlags::PROPERTY_USAGE_DEFAULT.ord());

(Maybe check for mistakes)

@Bromeon Bromeon added bug c: register Register classes, functions and other symbols to GDScript labels Oct 6, 2023
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.
@HenryWConklin
Copy link
Contributor Author

Yeah, the fix is just the changes in property.rs. There are some more links to code and things in the issue, but the gist is Godot does a ClassDB::instantiate(property_info.class_name) to make a value to fill in a field when you use the PROPERTY_USAGE_EDITOR_INSTANTIATE_OBJECT flag. Currently that class_name is set to the name of the containing class, but should be set to the name of the property's type. From the test I added, it used to be "ExportResource" for both fields, now it's "CustomResource"/"NewNameCustomResource".

There might be other places where this comes up but that's the case I was running into.

Copy link
Member

@Bromeon Bromeon left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One small comment, but it's not important, we can clean this up once we fix the bug to remove empty impls.

Thanks a lot for this! You said it fixes #440 only partially, so I guess that issue needs to stay open?

Comment on lines +376 to +377
#[godot_api]
impl ResourceVirtual for CustomResource {}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The whole impl is not needed anymore 😉

(the inherent impl above is still required due to a bug, though...)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Neat, when did that happen? Thought I was getting errors for not having that pretty recently

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The inherent one is still needed, but not the trait one.

@Bromeon Bromeon added this pull request to the merge queue Oct 6, 2023
@HenryWConklin
Copy link
Contributor Author

HenryWConklin commented Oct 6, 2023

Yeah #440 should stay open. There's another issue with exported Gd<Resource> fields triggering a bug in the Godot editor doesn't have as obvious of a fix.

Merged via the queue into godot-rust:master with commit de73f39 Oct 6, 2023
14 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug c: register Register classes, functions and other symbols to GDScript
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants