godotengine / godot-cpp

C++ bindings for the Godot script API
MIT License
1.71k stars 574 forks source link

[gdextensions] Registered classes are ticking in editor #709

Closed RedwanFox closed 7 months ago

RedwanFox commented 2 years ago

Godot-cpp commit 8ead641b086b4c3034fc611854f38e516659aec1 godot4 commit be52c5bf6ee7f8e1181f42f7c68fca9f8aaaa2b6 Windows 10

Using example code below place Example node in scene tree in editor and it will be spamming in log as if it was tool class.

Are there any flags or other correct way to register runtime only class?

#include <godot/gdnative_interface.h>
#include <godot_cpp/core/class_db.hpp>
#include <godot_cpp/core/defs.hpp>
#include <godot_cpp/godot.hpp>
#include <godot_cpp/variant/utility_functions.hpp>
#include <godot_cpp/classes/node.hpp>

using namespace godot;

class Example : public Node {
    GDCLASS(Example, Node);

    Example() = default;
    ~Example() = default;

public:
    void _init()
    {
        godot::UtilityFunctions::print("Init!");
    };
    void _process(float delta) {
        godot::UtilityFunctions::print("Delta ", delta, " seconds");
    }

protected:
    static void _bind_methods() {
//      ClassDB::bind_method(D_METHOD("_init"), &Example::_init);
        godot::UtilityFunctions::print("Bind methods!");
    }
};

void register_types()
{
    ClassDB::register_class<Example>();
}

void unregister_types()
{
}

extern "C"
{
    // Initialization.

    GDNativeBool GDN_EXPORT library_init(const GDNativeInterface* p_interface, const GDNativeExtensionClassLibraryPtr p_library, GDNativeInitialization* r_initialization)
    {
        godot::GDExtensionBinding::InitObject init_obj(p_interface, p_library, r_initialization);

        init_obj.register_scene_initializer(register_types);
        init_obj.register_scene_terminator(unregister_types);

        return init_obj.init();
    }
}
Calinou commented 2 years ago

You probably need to check for Engine::get_singleton()->is_editor_hint() before printing in _process (or perform an early return this way).

RedwanFox commented 2 years ago

Read about it, I think it should be mentioned in documentation. Or maybe some helper functions. Godot documentation also mentions that it's possible to check via feature tags https://docs.godotengine.org/en/latest/tutorials/export/feature_tags.html

Something like:

bool is_in_editor() const; // true in editor
bool is_play_in_editor() const; // true if game is played from editor  ( or run from build with "editor" feature)
bool is_client() const; // standalone build
bool is_dedicated() const; // or is_server().  headless server build

or

enum class PlayType
{
    Editor,
    PlayInEditor,
    Standalone,
    Server
}

PlayType get_play_type() const;
Calinou commented 2 years ago

Godot documentation also mentions that it's possible to check via feature tags docs.godotengine.org/en/latest/tutorials/export/feature_tags.html

Built-in feature tags are defined at compile-time. The editor feature tag does not behave like Engine.is_editor_hint(), as the editor feature tag will always be true whenever a project is run from an editor binary.

RedwanFox commented 2 years ago

That's why I have separated is_in_editor and is_play_in_editor in my example of helpers

Klaim commented 1 year ago

As mentionned there I think the behavior should be the same as not-tool GDScript, unless a runtime or at least creation time accessor stating if the note type in question is or not a tool, is handled by the engine.

dsnopek commented 1 year ago

GDExtensions are ideally meant to work like Godot modules. In a Godot module, nodes always run as if they are marked with @tool, and they use Engine::get_singleton()->is_editor_hint() (as mentioned by Calinou in the first comment) to check if they are currently running in the editor. Yes, this is different than GDScript, but I believe this is by design.

Klaim commented 1 year ago

GDExtensions are ideally meant to work like Godot modules. In a Godot module, nodes always run as if they are marked with @tool, and they use Engine::get_singleton()->is_editor_hint() (as mentioned by Calinou in the first comment) to check if they are currently running in the editor. Yes, this is different than GDScript, but I believe this is by design.

Ok thanks that explains it, I wasnt aware of that.