Pass a GDScript class as reference in a CPP Module

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By gutomaia
:warning: Old Version Published before Godot 3 was released.

How do I manage do pass a GDScript class instance as reference to a custom CPP module?

example:

Given the GDScript class

class InputHandler:
    func getInputs():
         return 1

var game = Game.new()
game.processInput(InputHandler.new())    

What would be a valid CPP?

class Game : public Reference {
    GDCLASS(Game, Reference);

protected:
    static void _bind_methods();
public:
	void processInput(?? input);
};

void Game::processInput(?? input){
      int data = input.getInputs();
}

Is that possible? If it is, i think we should document improve the documents on the custom CPP modules. I might send a PR on the docs if I manage it to work.

:bust_in_silhouette: Reply From: Zylann

I’m not certain if that’s going to work, but considering that any kind of script instance in Godot is actually a generic C++ object inheriting Reference on which is attached the script, your function could be this:

void Game::processInput(Ref<Reference> customScriptInstance) {
	Variant ret = customScriptInstance->call("getInputs");
	// and stuff
}

I dont know if that’s 1:1 the code you should write, I simplified from what I remember but you should have a look at the functions you can call on Object (because Reference inherits Object and the script instance is attached inside there).

Or, a more detailed way here in a module I wrote: https://github.com/Zylann/godot_voxel/blob/master/voxel_provider.cpp#L6
That one is a bit different case (because in my code the script is attached to the C++ class itself and I check its existence) but you can also get the ScriptInstance from the Reference you receive in your Game class.

Amazing! It does work! Really thanks!

BTW, I’m looking for more information on the Variant CPP stuf, like, what’ s the best/proper way to cast it an int variable.

To make it simple, let’s just improve the previous example with getInputs returning and array of integers a single integer.

Thanks again!

gutomaia | 2017-12-13 17:30

Hello Zylann/gutomaia
I managed to make it work with a single integer, but not with an array of integers.
If I use pass an array as a reference I get printed 0’s instead elements pushed in Godot script (see below)
Do you guys know how to return array of int elements as a reference?

C++ Module:

        Variant ret = customScriptInstance->call("getInputs");
        switch (ret.get_type()) {
             case Variant::Type::ARRAY: {
                 Variant   args_a[2] = {customScriptInstance->call("getInputs")};
                 printf("gslave_main::processInput: returned value: %i \n" , (int)args_a[0]);
                 printf("gslave_main::processInput: returned value: %i \n" , (int)args_a[1]);
                 break;

Godot:

class InputHandler
     func getInputs():
     var retLocal = []
     retLocal.append(111)
     retLocal.append(112)
     return retLocal

agotovac | 2020-04-02 11:09

Your C++ code could be like this instead:

Variant ret = customScriptInstance->call("getInputs");
switch (ret.get_type()) {
	case Variant::ARRAY: {
		Array args = ret;
		printf("gslave_main::processInput: returned value: %i \n" , args[0].operator int());
		printf("gslave_main::processInput: returned value: %i \n" , args[1].operator int());
		} break;

Alternatively, your prints could be:

print_line(String("gslave_main::processInput: returned value: {0}").format(varray(args[0]));
print_line(String("gslave_main::processInput: returned value: {1}").format(varray(args[1]));

Then if you want to return that array from C++ to GDScript, simply make your function return an Array, and write return args;.

Zylann | 2020-04-02 12:42