GDNative: What do complex data structures look like to the code?

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

Hey all,

I am considering using GDNative to help with performance issues with part of my code. However, I am handling some pretty complex data structures, and I’m wondering how feasible it will be for me to use a low level language like C or possibly Rust to work with those structures.

It would be difficult for me to go into detail on what exactly I’m doing, but a minimal example would be the following. Let’s assume I have a script called data.gd with the following code:

var foo = 6
var bar = "baz"

And then I have another script called structure.gdwith the following code:

var data_preload = preload("res://data.gd")
var data_list = []

for i in range(0, 20):
    var tmp = data_preload.new()
    tmp.foo = i

data_list.append(tmp)

(I am aware that class_name is now a syntax. However, if possible, I’d like to accomplish this with the current preload() syntax.)

Now I want to make a GDNative module that might, for example, have a function that takes an instance of structure.gd as an argument, loops through data_list and sums up all of the foos, and then return the sum. What type should I give to the argument, what type should I give to the return type, and how should I access the properties of structure.gd or data.gd?

Any help is appreciated.

:bust_in_silhouette: Reply From: KohuGaly

I’ve recently did my first project in GDNative rust. What you describe is most definitely feasible. Internally, the source code is free to use any types. Only the methods that get binded need to have native godot types (except some primitive types like int, float and bool, which get casted automatically).
To some extend, it is possible to circumvent the godot api and access fields and methods of another gdnative object directly.

In your specific example, the function would look something like this (note: there are probably some errors):

use gdnative::*
#[export]
fn my_function(
        &mut self, mut _owner: gdnative::Node, 
        structure: gdnative::Variant
        ) -> i64 {

let func_name_get_data_list=GodotString::from_str("get_data_list");
if structure.has_method( function_name ) {
    let func_name_get_foo=GodotString::from_str("get_foo");
    let sum: i64 = 0;
    // data_list=structure.get_data_list()
    let data_list = structure.call( func_name_get_data_list , &[] ).to_array();
    for i in 0..data_list.len() {
          // sum+= data_list[i].get_foo()
          sum+=data_list.get( i ).unwrap().call( func_name_get_foo, &[] ).to_i64();
    }

sum
}

Does godot automatically generate the getter functions (e.g. get_data_list())?
Are the .call()s required, or can I use the simpler lines above them?
Thanks for the response, it’s already helped me a lot.

Bush2Tree | 2020-05-15 01:37

The getter/setter functions are automatically generated for the native types/classes from godot headers. You may have to declare them manually for custom scripts.
The .call() semantic in needed because it is not possible to infer custom types at compile time (rust is statically typed). The commented simpler lines are gdscript equivalents, to show what’s happening.
You may notice that the input of the function is of type Variant. It is possible to cast this type into native types, but it has to be done manually. It’s a price you pay for using compiled statically typed language. You are trading convenience for performance.

KohuGaly | 2020-05-15 14:23

Forgot to check inbox for a while, didn’t notice your reply. Thanks for putting the time into making such a detailed response. I’ve managed to significantly improve my performance with pure GDScript, but I may still use GDNative if I need the improvement. It seems like its definitely feasible, thanks for showing me how!

Bush2Tree | 2020-05-29 01:03