octod
January 10, 2024, 2:58pm
1
Godot Version
4.2.x
Question
Hello, I am porting my extension to c++ and I need to mark several functions as virtuals in gdscript.
What I tried
I tried using the BIND_VIRTUAL_METHOD but it does not mark my method as virtual in gdscript.
If I try to create an empty method in the header file called for example _foo
, then bind it in the static method _bind_methods
as
BIND_VIRTUAL_METHOD(MyClass, _foo)
it does not appear in the methods listed by gdscript.
Could somebody give me a hint? Thanks in advance
1 Like
coder
January 10, 2024, 4:42pm
2
These issues are related. They all seem to mention using call instead.
opened 09:11PM - 24 Sep 23 UTC
bug
topic:gdextension
### Godot version
4.1.1
### System information
Pop!_OS 22.04
### Iss… ue description
Using `BIND_VIRTUAL_METHOD` script in `_bind_methods()` doesn't create a virtual function in GDScript.
### Steps to reproduce
1. Create simple GDextension
2. Build it
3. Add to the project
```C++
//MyClass.h
#ifndef MYCLASS_H
#define MYCLASS_H
#include <godot_cpp/classes/node.hpp>
namespace godot{
class MyClass : public Node{
GDCLASS(MyClass, Node)
protected:
static void _bind_methods();
void foo();
};
}
#endif
//MyClass.cpp
#include "my_class.h"
#include <godot_cpp/core/class_db.hpp>
#include <godot_cpp/variant/variant.hpp>
using namespace godot;
void MyClass::_bind_methods(){
BIND_VIRTUAL_METHOD(MyClass, foo);
}
void MyClass::foo(){
}
```
After building the extension, you can `MyClass` in the editor. However, you can't override `foo()` function as GDscript doesn't see it and it isn't shown in documentation section.
### Minimal reproduction project
N/A
opened 03:34PM - 04 Aug 23 UTC
### Godot version
4.1 stable
### godot-cpp version
4.1 stable
### Sy… stem information
Windows 10 and Linux Mint
### Issue description
When binding a virtual function in a custom class, things become rather *finicky*. For the purposes of explanation I will exemplify things using `Resource` as base class, but this behavior occurs with any other base.
Suppose I have this:
```
class CustomResource : public Resource {
....
static void _bind_methods() {
BIND_VIRTUAL_METHOD(CustomResource, perform_task);
}
...
virtual void perform_task() { some_default_behavior... }
};
```
When in GDScript, if I attempt to directly call that virtual function with `some_instance.perform_task()` I will get an error telling that the function does not exist. Yet, If I do `some_instance.call("perform_task")` then the function will be called and the default behavior will occur. I can then create a derived class in GDScript and override `perform_task()` without any problem. In that case either `.perform_task()` or `call("perform_task")` will work in GDScript.
Now, from the C++ code:
1 - If I directly call `->perform_task()`, then the default behavior will occur. If I create a derived class in C++ and override that virtual function, then I will get the overridden code. However if I override that function in a GDScript class then I will still get the C++ default behavior.
2 - If I call the function with `->call("perform_task")` I will be able to override that function from GDScript but not in a C++ class.
The workaround that I'm currently using is something like this:
```
class CustomResource : public Resource {
...
static void _bind_methods() {
BIND_VIRTUAL_METHOD(CustomResource, _perform_task);
ClassDB::bind_method(D_METHOD("perform_task"), &CustomResource::perform_task);
}
...
virtual void _perform_task() { some_default_behavior... }
void perform_task() { call("_perform_task"); }
};
```
This does present the intuitive `.perform_task()` way of calling the function from GDScript and `->perform-task()` from C++. However there are problems here.
1 - Using `call()` does not work in a const function. Well, not without some *"hacky"* code (casting the `this` into a non cost version).
2 - In a C++ derived class I need to do this:
```
class SpecialCustomResource : public CustomResource {
...
static void _bind_methods() {
ClassDB::bind_method(D_METHOD("_perform_task"), &SpecialCustomResource::_perform_task);
}
...
virtual void _perform_task() override { some_other_behavior... }
};
```
If I don't bind the overridden function as a normal one then the `call()` will not find the desired function. Another thing that occurs when the function is not registered is that if you are expecting a return value `nullptr` will be the result.
Is the described intended behavior?
### Steps to reproduce
The entire explanation is, in a way, steps to reproduce the problem.
### Minimal reproduction project
I don't have one in hand. If really absolutely necessary I can work on one
opened 07:19PM - 22 Mar 23 UTC
Looks like these two macroses are used by godot to call gdscript methods.
Can t… hese two be added into godot-cpp?
octod
January 11, 2024, 8:40am
3
Ok, so as a TLDR, it is not possible at the moment without using ugly and fragile workarounds.
Thank you!
1 Like
coder
January 14, 2024, 5:45pm
4
Yes. BIND_VIRTUAL_METHOD only seems to be used in the godot_cpp bindings and I believe it’s very different from what the engine uses to expose the methods like _ready and _process. If you’re a module developer , you may have more to work with than with GDExtension.
octod
March 21, 2024, 3:02pm
5
2024-03-21 Update
In Godot 4.3 there will be a new ClassDB
method called add_virtual_method
The signature is simple:
static void godot::ClassDB::add_virtual_method(const godot::StringName &p_class, const godot::MethodInfo &p_method, const godot::Vector<godot::StringName> &p_arg_names = godot::Vector<godot::StringName>())
If you need to expose virtuals which can be called from your code, this is the way.
1 Like