Idiomatic way to return structured data from C++ module to GDScript

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By Charlie Micou

I have some structured data within a C++ module.
I’d like to be able to access that data through its structural hierarchy from GDScript.

Example:

class Foo : Object {
  int a;
}

class Bar : Object {
  Foo foo;
}

class SomeNode : Node {
  Bar bar;
}

Bar SomeNode::get_bar() {
  return bar;
}

void SomeNode::_bind_methods() {
  ClassDB::bind_method(D_METHOD("get_bar"), &SomeNode::get_bar);
}

I’d like to be able to do something along the lines of some_node_instance.get_bar().get_foo().get_a().

This seems like it’s probably a very common thing to want to do. What is the ‘correct’/best practices/idiomatic way of approaching this?

Some things that come to mind:

  • Make Bar a Node instead of an Object and make an instance of it child of SomeNode, make Foo a Node instead of an Object and make it a child of an instance of Bar
  • Express a way to serialize the Foo and Bar Objects so that they are valid value return types (though I’m not sure how to approach this)

Follow up question for an edge-case:
I’m expecting that the answer to my question will go along the lines of “make Bar a Node instead of an Object and make it a child of SomeNode” so that the structure is already cleanly expressed.

Unfortunately, the exact situation I’m in is that my SomeNode has an internal data representation based on a third party library. My Bar class is a wrapper around the internal data that allows accessing it in terms of Godot’s primitives. I’d prefer to not keep two representations of the same data around at all times, so would like to be able to return the structured data in a lightweight way without holding on to a child node for the sake of conversion.

:bust_in_silhouette: Reply From: Zylann

They can be all objects if you like. What that means is that they won’t be reference-counted and have to be manually freed by their owner (depending on your ownership model, the module can take care of that as long as the script doesn’t try to access them afterwards).

The way to fix this is to do the following:

  • Bind all those classes and their methods to the scripting API, so GDScript will be able to interact with them. You may need to use the GDCLASS macro as well.
  • Make the methods return pointers instead of values (SomeNode*, Bar* etc)
  • Finally, I would recommend to not store these objects by value in general and if needed create them using memnew/memdelete instead (at least this is not common in Godot so probably not tested much).

Thanks for the answer!

The ownership model I’ve got makes being able pass these around by value much more convenient.

For my particular use case, I’ve gone down a different route from the one I was originally asking after:
I’ve written a piece of code generation to convert a struct based on a schema to a Dictionary type (potentially of other Dictionaries or primitives), so the example would take the form (for a value of ‘a’ of 123):
{"foo":{"a":123}}

Charlie Micou | 2018-12-01 00:31