How to set up a TypedArray with a custom type in GDExtension

Godot Version

4.2

Question

I’m a bit confused about the correct use of TypedArrays in gdextension. How can I expose them correctly to gdscript?

Consider a class MyClass : RefCounted.
EDIT: Consider a class MyClass : Resource.

I noticed godot defines a MAKE_TYPED_ARRAY macro, which it uses to create the TypedArrray implementations for it’s Variants.

Is it necessary or beneficial to use this for our own types? For example: MAKE_TYPED_ARRAY(MyClass, Variant::OBJECT)

Does the TypedArray<MyClass> type need to be registered to expose it?

And most of all, why do I still need to cast the bloody values because they seem to be returned as Variant despite the typing of the TypedArray.

It’s all just a little confusing and not a lot of documentation seems to be out there.

See c++ - Creating a new array type compatible with `godot::Variant`? - Stack Overflow for some additional context.

EDIT: after some experimenting it seems like calling MAKE_TYPED_ARRAY(MyClass, Variant::OBJECT) doesn’t seem to make much of a difference either way. At least not from the gdscript user perspective.
The same goes for registering TypedArray<MyClass>

I managed to expose a TypedArray<MyClass>, and assigning an Array[MyClass] from gdscript works just fine.
The editor however is a different story.

Consider the following:

//test.h
class TestObject : public Resource { 
//... 
};

class TypedArrayTest : public Resource {
	GDCLASS(TypedArrayTest, Resource)

private:
	TypedArray<TestObject> test_array;

protected:
	static void _bind_methods();

public:
    TypedArray<TestObject> get_test_array() const;
    void set_test_array(const TypedArray<TestObject> p_value);
};

//test.cpp
void TypedArrayTest::_bind_methods() {
    ClassDB::bind_method(D_METHOD("get_test_array"), &TypedArrayTest::get_test_array);
	ClassDB::bind_method(D_METHOD("set_test_array", "p_value"), &TypedArrayTest::set_test_array);
	ClassDB::add_property("TypedArrayTest", PropertyInfo(Variant::ARRAY, "test_array"), "set_test_array", "get_test_array");
}

//implementation of get and set 

So now we @export this in gdscript.

@export var test:TypedArrayTest

This works, but the array in the property editor shows up like an untyped array.
To assign an element, I first need to select Object as a type. Next I need to assign New TestObject instance to that element.
All this for just one element, that’s a bit cumbersome.
The editor does check the type though, so that is alright. You can’t assign any other type than Object, or any other instance than TestObject.
The most annoying part is that the editor shows the whole list of types in every step of this assignment.

Is there any way to limit this?

When you recreate this whole thing in plain gdscript, the editor does recognize @export var gd_test: Array[TestObjectGdsImplemetation] corretly.
In this case he editor does display the intended behaviour. You can just assign new TestObjectGdsImplemetation instances in one simple step, without going through all the nonsense I described above.

This leads me to believe it should be possible to achieve the same from GDExtension as well.

1 Like

Could property hints be what you’re looking for? More specifically, PROPERTY_HINT_ARRAY_TYPE.

If you scroll down, information on PropertyInfo and using hints is here.

The full list of hints can be found here.

gd_ta_fixed

I finally figured it out! I went down so many rabbit holes, but of course the solution was simple. As it turns out, in my attempt to write a simple test case, I didn’t used the appropriate PropertyHint.

The following solved it:

void TypedArrayTest::_bind_methods() {
    //...

    ClassDB::add_property(
        "TypedArrayTest", 
        PropertyInfo(
            Variant::ARRAY, 
            "test_array", 
            PROPERTY_HINT_TYPE_STRING, 
            String::num(Variant::OBJECT) + "/" + String::num(PROPERTY_HINT_RESOURCE_TYPE) + ":TestObject"
        ), 
        "set_test_array", 
        "get_test_array"
    );
    
}

It had been staring me in the face this whole time, straight from the Godot docs: @GlobalScope — Godot Engine (stable) documentation in English

Instead of using PROPERTY_HINT_TYPE_STRING I tried to use PROPERTY_HINT_ARRAY_TYPE as well, but I couldn’t get that to work. Maybe this one only works with built in types, I’m not sure.

Yes, this was the key!
I hadn’t seen your answer when i finally figured this out. But thank you for the input. It was driving me nuts.

I ended up using PROPERTY_HINT_TYPE_STRING instead of PROPERTY_HINT_ARRAY_TYPE though. More info in my previous post.

I’ll mark your answer as the solution, thank you.

1 Like

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.