+2 votes

I am trying to define and register a subclass within Godot. I would like to be able to pass complex structures into the engine itself using NativeScript. The principle is a "User" might have lots of data and be used in many places in the engine and I do not want to pass each variable individually.

I thought that maybe a Godot-derived object could be passed through another, but I cannot seem to register the object directly. I am receiving the error:

The issue stems from registration with register_property<>

Does anyone know how to solve this problem?

Error:

Godot.hpp: In instantiation of 'void godot::register_property(const char*, P T::*, P, godot_method_rpc_mode, godot_property_usage_flags, godot_property_hint, godot::String) [with T = godot::GdUserManager; P = godot::GdUser]':

Godot.hpp:314:10: error: conversion from 'godot::GdUser' to non-scalar type 'godot::Variant' requested
     Variant def_val = default_value;
             ^~~~~~~

Source:

gd-user-manager.h

#ifndef _GD_USER_MANAGER_H_
#define _GD_USER_MANAGER_H_

#include <Godot.hpp>
#include <Object.hpp>

#include "gd-user.h"

namespace godot {
class GdUserManager : public Object {
    GODOT_CLASS(GdUserManager, Object)

public:
    GdUser m_user;

public:
    static void _register_methods() {
        GdUser blah;
        // Doesn't work
        register_property<GdUserManager, GdUser>("user", &GdUserManager::m_user, blah);
        // Getter-setter variant also doesn't work
        //register_property<GdUserManager, GdUser>("user", &GdUserManager::set_user, &GdUserManager::get_user);
    }

    GdUserManager();
    ~GdUserManager();

    void _init() { }

    GdUser get_user() {
        return m_user;
    }
    void set_user(GdUser user) {
        m_user = user;
    }
};
}

#endif

gd-user.h

#ifndef _GD_USER_H_
#define _GD_USER_H_

#include <Godot.hpp>
#include <Object.hpp>

namespace godot {
class GdUser : public Object {
    GODOT_CLASS(GdUser, Object)

private:
    int m_test = 42;

public:
    static void _register_methods() {
        register_property<GdUser, int>("test", &GdUser::set_test, &GdUser::get_test, 41);
    }

    GdUser();
    ~GdUser();

    void _init() {}

    int get_test() {
        return m_test;
    }
    void set_test(int test) {
        m_test = test;
    }
};
}
#endif

Edit - including the *.gdns file
user-manager.gdns

[gd_resource type="NativeScript" load_steps=2 format=2]

[ext_resource path="res://lib/user-manager/bin/user-manager.gdnlib" type="GDNativeLibrary" id=1]

[resource]

resource_name = "user-manager"
class_name = "GdUserManager"
library = ExtResource( 1 )
_sections_unfolded = [ "Object" ]
asked Jun 8 in Engine by Chekr (22 points)
edited Jun 13 by Chekr

1 Answer

0 votes

Try casting your object to a Variant

answered Jun 8 by sparkart (326 points)

I tried casting to a Variant type, but that comes with problems. The second field of the template for register_property defines the property type, and that same template type also applies to the default field (property 3 of the function call). Casting the default also requites the type of the template be changed, losing the intended reference entirely. Likewise, the custom type isn't castable to a variant to begin with.

Meanwhile, the first line of the register_property function (Godot.hpp:313) tries treating the default directly as a Variant. However, the standard types (Object, Reference, etc.) can't be handled this way. Looking at "Variant.hpp", it seem that it itself handles resolution of types passed in and they are hard coded (unless I'm misinterpreting). There are also fields as part of the register_property function to define the properties, but it will never get that far without the variant being resolved.

Sorry, I forgot to clarify about the fact that Custom type is derived from Object, which creates a common interface for you to work with:

Variant has the following constructor:

Variant::Variant(const Object *p_object) {

    type = OBJECT;

    memnew_placement(_data._mem, ObjData);
    _get_obj().obj = const_cast<Object *>(p_object);
}



Encapsulate on the C++ end and use Object* as a common interface.

Since GDUser is derived from Object, use that instead for the template:

register_property<GdUserManager, Object*>



Let me know how it works out, I haven't tested this out and just going off of reading the source code.

I changed the definition to be a pointer and refined the property registration that way. The clue being that "Object" is cast as a pointer, not a direct object:

class GdUserManager : Object{
// [...]
GdUser* m_user;

public:
    static void _register_methods() {
    GdUser* user = new GdUser();
    register_property<GdUserManager, GdUser*>("user", &GdUserManager::m_user, user);

After doing that everything builds fine. However, the second I open the project in the Godot Editor, the entire editor crashes with an error after doing a directory scan and finding the lib.

Dump:

[1] /lib/x86_64-linux-gnu/libc.so.6(+0x3ef20) [0x7f0e57d79f20] (??:0)
[2] Object::get_script_instance_binding(int) (/home/chekr/git/third_party/godot/core/object.cpp:1932 (discriminator 4))
[3] NativeScriptLanguage::get_instance_binding_data(int, Object*) (/home/chekr/git/third_party/godot/modules/gdnative/nativescript/nativescript.cpp:1352)
[4] /home/chekr/git/third_party/godot/bin/godot.x11.tools.64(godot_nativescript_get_instance_binding_data+0x28) [0x1afbe99] (/home/chekr/git/third_party/godot/modules/gdnative/nativescript/godot_nativescript.cpp:366)
[5] godot::Object* godot::get_wrapper<godot::Object>(void*) (??:0)
[6] void godot::register_property<godot::GdUserManager, godot::Object*>(char const*, godot::Object* godot::GdUserManager::*, godot::Object*, godot_method_rpc_mode, godot_property_usage_flags, godot_property_hint, godot::String) (??:0)
[7] godot::GdUserManager::_register_methods() (??:0)
[8] void godot::register_class<godot::GdUserManager>() (??:0)
[9] /home/chekr/git/chekr/segfault-gd/lib/user-manager/bin/x11/libuser-manager.so(godot_nativescript_init+0x13) [0x7f0dffa27c48] (??:0)
[10] NativeScriptLanguage::init_library(Ref<GDNativeLibrary> const&) (/home/chekr/git/third_party/godot/modules/gdnative/nativescript/nativescript.cpp:1507)
[11] NativeScriptLanguage::frame() (/home/chekr/git/third_party/godot/modules/gdnative/nativescript/nativescript.cpp:1582 (discriminator 2))
[12] Main::iteration() (/home/chekr/git/third_party/godot/main/main.cpp:1940)
[13] OS_X11::run() (/home/chekr/git/third_party/godot/platform/x11/os_x11.cpp:3034)
[14] /home/chekr/git/third_party/godot/bin/godot.x11.tools.64(main+0xdc) [0x1386fa3] (/home/chekr/git/third_party/godot/platform/x11/godot_x11.cpp:56)
[15] /lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xe7) [0x7f0e57d5cb97] (??:0)
[16] /home/chekr/git/third_party/godot/bin/godot.x11.tools.64(_start+0x2a) [0x1386e0a] (??:?)

Any ideas why this might be failing to cast?

Further update:

New object instantiation cannot use the "new" keyword with Godot objects. I uses up using:

GdUser *user = new GdUser();

... instead based on a reccomentaiton from the git repo. The Godot editor no longer crashes at me, but I now get a runtime crash when calling the module with:

var test = load("res://lib/user-manager/bin/user-manager.gdns").new();

And I get:

Dumping the backtrace. Please include this when reporting the bug on https://github.com/godotengine/godot/issues
[1] /lib/x86_64-linux-gnu/libc.so.6(+0x3ef20) [0x7ff488790f20] (??:0)
[2] godot::Variant::Variant(godot::Object const*) (??:0)
[3] godot::_PropertyDefaultGetFunc<godot::GdUserManager, godot::GdUser*>::_wrapped_getter(void*, void*, void*) (??:0)
[4] NativeScriptInstance::get(StringName const&, Variant&) const (/home/chekr/git/third_party/godot/modules/gdnative/nativescript/nativescript.cpp:607)
[5] Object::get(StringName const&, bool*) const (/home/chekr/git/third_party/godot/core/object.cpp:486)
[6] encode_variant(Variant const&, unsigned char*, int&, bool) (/home/chekr/git/third_party/godot/core/io/marshalls.cpp:1128 (discriminator 3))
[7] ScriptDebuggerRemote::_put_variable(String const&, Variant const&) (/home/chekr/git/third_party/godot/core/script_debugger_remote.cpp:111)
[8] ScriptDebuggerRemote::debug(ScriptLanguage*, bool) (/home/chekr/git/third_party/godot/core/script_debugger_remote.cpp:226)
[9] GDScriptLanguage::debug_break(String const&, bool) (/home/chekr/git/third_party/godot/modules/gdscript/gdscript_editor.cpp:237)
[10] GDScriptFunction::call(GDScriptInstance*, Variant const**, int, Variant::CallError&, GDScriptFunction::CallState*) (/home/chekr/git/third_party/godot/modules/gdscript/gdscript_function.cpp:1519 (discriminator 3))
[11] GDScriptInstance::_ml_call_reversed(GDScript*, StringName const&, Variant const**, int) (/home/chekr/git/third_party/godot/modules/gdscript/gdscript.cpp:1206)
[12] GDScriptInstance::call_multilevel_reversed(StringName const&, Variant const**, int) (/home/chekr/git/third_party/godot/modules/gdscript/gdscript.cpp:1215)
[13] Node::_notification(int) (/home/chekr/git/third_party/godot/scene/main/node.cpp:139)
[14] Node::_notificationv(int, bool) (/home/chekr/git/third_party/godot/./scene/main/node.h:46 (discriminator 14))
[15] CanvasItem::_notificationv(int, bool) (/home/chekr/git/third_party/godot/./scene/2d/canvas_item.h:166 (discriminator 3))
[16] Control::_notificationv(int, bool) (/home/chekr/git/third_party/godot/./scene/gui/control.h:51 (discriminator 3))
[17] Object::notification(int, bool) (/home/chekr/git/third_party/godot/core/object.cpp:954)
[18] Node::_propagate_ready() (/home/chekr/git/third_party/godot/scene/main/node.cpp:184)
[19] Node::_propagate_ready() (/home/chekr/git/third_party/godot/scene/main/node.cpp:173 (discriminator 2))
[20] Node::_set_tree(SceneTree*) (/home/chekr/git/third_party/godot/scene/main/node.cpp:2548)
[21] SceneTree::init() (/home/chekr/git/third_party/godot/scene/main/scene_tree.cpp:457)
[22] OS_X11::run() (/home/chekr/git/third_party/godot/platform/x11/os_x11.cpp:3000)
[23] /home/chekr/git/third_party/godot/bin/godot.x11.tools.64(main+0xdc) [0x117c333] (/home/chekr/git/third_party/godot/platform/x11/godot_x11.cpp:56)
[24] /lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xe7) [0x7ff488773b97] (??:0)
[25] /home/chekr/git/third_party/godot/bin/godot.x11.tools.64(_start+0x2a) [0x117c19a] (??:?)
Welcome to Godot Engine Q&A, where you can ask questions and receive answers from other members of the community.

Please make sure to read How to use this Q&A? before posting your first questions.