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

Unable to bind indexed properties #1182

Closed
mihe opened this issue Jul 17, 2023 · 3 comments · Fixed by #1186
Closed

Unable to bind indexed properties #1182

mihe opened this issue Jul 17, 2023 · 3 comments · Fixed by #1186

Comments

@mihe
Copy link
Contributor

mihe commented Jul 17, 2023

Godot version

4.2-dev (f880892c3)

godot-cpp version

4.2-dev (749b0b9)

System information

Windows 11 (10.0.22621)

Issue description

In Godot itself you have the ability to bind a property with what's called an "index", which essentially just binds an integer (usually an enum value) to the property that will always be passed in as the first argument to its getter and setter functions. You typically do this using the ADD_PROPERTYI macro, as seen here.

In godot-cpp there is an index parameter for ClassDB::add_property, but it seems that it's currently being discarded completely, along with the rest of the (seemingly unused) PropertySetGet struct, as seen here. As far as I can tell this has been the case for as long as GDExtension has been a thing.

Since the index is being discarded currently, it gets the default value of -1 and leads to the binding of the property emitting errors saying ERROR: Invalid function for setter 'MyNode::my_setter for property 'my_property'.

The only workaround is to not use indexed properties, and instead create and bind a bespoke setter/getter method for each property.

Steps to reproduce

Add (and register) the following class in an extension of your choosing:

class MyNode : public Node {
    GDCLASS(MyNode, Node)

    void my_setter(int32_t p_index, real_t p_value) { }
    real_t my_getter(int32_t p_index) const { return 21.0f; }

    static void _bind_methods() {
        ClassDB::bind_method(D_METHOD("my_setter", "index", "value"), &MyNode::my_setter);
        ClassDB::bind_method(D_METHOD("my_getter", "index"), &MyNode::my_getter);
        ClassDB::add_property(get_class_static(), PropertyInfo(Variant::FLOAT, "my_property"), "my_setter", "my_getter", 42);
    }
};

... and then run Godot from within a terminal/console, since the error message is only emitted into stderr when starting the editor, which should look something like this:

ERROR: Invalid function for setter 'MyNode::my_setter for property 'my_property'.
   at: (core\object\class_db.cpp:980)

Minimal reproduction project

N/A

@mihe
Copy link
Contributor Author

mihe commented Jul 17, 2023

The fix here is to either change classdb_register_extension_class_property to also take an index as its last argument, which I presume would be a breaking change, or to introduce a new function called something like classdb_register_extension_class_property_indexed that is identical to the original with the exception of also having an index argument.

Seeing as how this index has a magical default value of -1, which can't really be expressed through the C API other than documenting it, I suppose making a brand new function might be the best course of action.

Let me know which is preferable and I'll be happy to make the pull requests for Godot and godot-cpp.

@mihe mihe changed the title Unable to properly bind indexed properties Unable to bind indexed properties Jul 17, 2023
@dsnopek
Copy link
Collaborator

dsnopek commented Jul 17, 2023

The fix here is to either change classdb_register_extension_class_property to also take an index as its last argument, which I presume would be a breaking change, or to introduce a new function called something like classdb_register_extension_class_property_indexed that is identical to the original with the exception of also having an index argument.

Yep, for compatibility it will have to be a new function. If it would make the implementation simpler, you can have the old function call the new function.

@mihe
Copy link
Contributor Author

mihe commented Jul 17, 2023

Alright, sounds good. I'll throw together some pull requests within the next day or two.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants