godotengine / godot-cpp

C++ bindings for the Godot script API
MIT License
1.68k stars 509 forks source link

[NativeScript 1.1] Crash attempting to get physics inside of a local resource #175

Open BastiaanOlij opened 6 years ago

BastiaanOlij commented 6 years ago

I'm probably stretching the possibilities of time and space here but I'm trying to get access to the physics engine inside of a resource.

So I have the following code:

            printf("Procedural mesh raycast, obtaining local scene\n");
            Node * localscene = get_local_scene();
            if (localscene == NULL) {
                printf("Procedural mesh raycast, no local scene found, is this a local resource?\n");
                return false;
            };
            printf("Procedural mesh raycast, obtaining viewport\n");
            Viewport * vp = localscene->get_viewport();
            if (vp == NULL) {
                printf("Procedural mesh raycast, Couldn't obtain local viewport\n");
                return false;
            }
            printf("Procedural mesh raycast, obtaining world\n");
            Ref<World> world = vp->find_world();
            if (world.is_null()) {
                printf("Procedural mesh raycast, Couldn't obtain world\n");
                return false;
            }
            printf("Procedural mesh raycast, obtaining state\n");
            PhysicsDirectSpaceState * state = world->get_direct_space_state();
            if (state == NULL) {
                printf("Procedural mesh raycast, Couldn't obtain state\n");
                return false;               
            }

Which seems to crash on that final get_direct_space_state() call:

Procedural mesh raycast, obtaining local scene
Procedural mesh raycast, obtaining viewport
Procedural mesh raycast, obtaining world
Procedural mesh raycast, obtaining state
ERROR: HashMap<class StringName,void const *,struct HashMapHasherDefault,struct HashMapComparatorDefault<class StringName>,3,8>::get: Condition ' !res ' is true. returned: *res
   At: c:\users\basti\development\godot3-git\core\hash_map.h:306
CrashHandlerException: Program crashed
Dumping the backtrace. Please include this when reporting the bug on https://github.com/godotengine/godot/issues
[0] NativeScriptLanguage::get_instance_binding_data (c:\users\basti\development\godot3-git\modules\gdnative\nativescript\nativescript.cpp:1236)
[1] NativeScriptLanguage::get_instance_binding_data (c:\users\basti\development\godot3-git\modules\gdnative\nativescript\nativescript.cpp:1236)
[2] godot_nativescript_get_instance_binding_data (c:\users\basti\development\godot3-git\modules\gdnative\nativescript\godot_nativescript.cpp:366)
[3] godot_nativescript_init
[4] godot_nativescript_init
[5] godot_nativescript_init
[6] godot_nativescript_init
[7] godot_nativescript_init
[8] godot_nativescript_init
[9] godot_nativescript_init
[10] godot_nativescript_init
[11] godot_nativescript_init
[12] NativeScriptInstance::call (c:\users\basti\development\godot3-git\modules\gdnative\nativescript\nativescript.cpp:736)
[13] Object::call (c:\users\basti\development\godot3-git\core\object.cpp:947)
[14] MessageQueue::_call_function (c:\users\basti\development\godot3-git\core\message_queue.cpp:260)
[15] MessageQueue::flush (c:\users\basti\development\godot3-git\core\message_queue.cpp:307)
[16] SceneTree::iteration (c:\users\basti\development\godot3-git\scene\main\scene_tree.cpp:477)
[17] Main::iteration (c:\users\basti\development\godot3-git\main\main.cpp:1777)
[18] OS_Windows::run (c:\users\basti\development\godot3-git\platform\windows\os_windows.cpp:2605)
[19] widechar_main (c:\users\basti\development\godot3-git\platform\windows\godot_win.cpp:150)
[20] _main (c:\users\basti\development\godot3-git\platform\windows\godot_win.cpp:172)
[21] main (c:\users\basti\development\godot3-git\platform\windows\godot_win.cpp:184)
[22] __scrt_common_main_seh (f:\dd\vctools\crt\vcstartup\src\startup\exe_common.inl:283)
[23] BaseThreadInitThunk
-- END OF BACKTRACE --

Not sure why...

SG7 commented 6 years ago

This is unrelated, but instead of

            Ref<World> world = vp->find_world();
            if (world.is_null()) {

to increase the protection maybe:

            Ref<World> world = vp->find_world();
            if (world == NULL || !(vp->find_world().is_valid())) {
karroffel commented 6 years ago

world is not a pointer, so world == NULL won't do anything useful.

I think it might be a problem with classes not being added to the typemap properly? The error is in Godot in a HashMap lookup.

marcelofg55 commented 5 years ago

I've also stumbled upon this problem, it used to work fine on nativescript-1.0 for me with this code: Physics2DDirectSpaceState *space_state = get_world_2d()->get_direct_space_state(); Now with the exact same code I'm getting a crash on the get_direct_space_state call.

BastiaanOlij commented 5 years ago

I'll have to retest this, might have been fixed upstream :)

m4nu3lf commented 5 years ago

Could this be linked to a crash I'm experiencing when trying to bind _integrate_forces() in a GDNative script inheriting from RigidBody?

[1] /usr/lib/libc.so.6(+0x37e00) [0x7fd345137e00] (??:0)
[2] NativeScriptLanguage::get_instance_binding_data(int, Object*) (??:0)
[3] ./Game(godot_nativescript_get_instance_binding_data+0x28) [0x557830304c37] (??:0)
[4] godot_variant godot::__wrapped_method<godot::RigidPart, void, godot::PhysicsDirectBodyState*>(void*, void*, void*, int, godot_variant**) (??:0)
[5] NativeScriptInstance::call(StringName const&, Variant const**, int, Variant::CallError&) (??:0)
[6] ScriptInstance::call(StringName const&, Variant const&, Variant const&, Variant const&, Variant const&, Variant const&) (??:0)
[7] RigidBody::_direct_state_changed(Object*) (??:0)
m4nu3lf commented 5 years ago

Any updates on this? This seem to still be an issue, I saw some updates on the related Godot issue https://github.com/godotengine/godot/issues/17401

Acclution commented 5 years ago

I seem to get this also. It crashes at HashMap::get function because it could not get the correct name for a class. I rigged so that it prints the names of the classes with a warning. This is my debug log:

OpenGL ES 2.0 Renderer: GeForce GTX 960M/PCIe/SSE2
WARNING: NativeScriptLanguage::get_instance_binding_data: TileSet
     At: modules\gdnative\nativescript\nativescript.cpp:1345
WARNING: NativeScriptLanguage::get_instance_binding_data: TileSet
     At: modules\gdnative\nativescript\nativescript.cpp:1345
WARNING: NativeScriptLanguage::get_instance_binding_data: Viewport
     At: modules\gdnative\nativescript\nativescript.cpp:1345
WARNING: NativeScriptLanguage::get_instance_binding_data: _File
     At: modules\gdnative\nativescript\nativescript.cpp:1345
Game Start
WARNING: NativeScriptLanguage::get_instance_binding_data: CanvasLayer
     At: modules\gdnative\nativescript\nativescript.cpp:1345
WARNING: NativeScriptLanguage::get_instance_binding_data: Node2D
     At: modules\gdnative\nativescript\nativescript.cpp:1345
WARNING: NativeScriptLanguage::get_instance_binding_data: NativeScript
     At: modules\gdnative\nativescript\nativescript.cpp:1345
WARNING: NativeScriptLanguage::get_instance_binding_data: GDNativeLibrary
     At: modules\gdnative\nativescript\nativescript.cpp:1345
WARNING: NativeScriptLanguage::get_instance_binding_data: Node2D
     At: modules\gdnative\nativescript\nativescript.cpp:1345
WARNING: NativeScriptLanguage::get_instance_binding_data: ResourceInteractiveLoader
     At: modules\gdnative\nativescript\nativescript.cpp:1345
WARNING: NativeScriptLanguage::get_instance_binding_data: Node2D
     At: modules\gdnative\nativescript\nativescript.cpp:1345
WARNING: NativeScriptLanguage::get_instance_binding_data: StreamTexture
     At: modules\gdnative\nativescript\nativescript.cpp:1345
WARNING: NativeScriptLanguage::get_instance_binding_data: Sprite
     At: modules\gdnative\nativescript\nativescript.cpp:1345
WARNING: NativeScriptLanguage::get_instance_binding_data: Physics2DShapeQueryParameters
     At: modules\gdnative\nativescript\nativescript.cpp:1345
WARNING: NativeScriptLanguage::get_instance_binding_data: RectangleShape2D
     At: modules\gdnative\nativescript\nativescript.cpp:1345
WARNING: NativeScriptLanguage::get_instance_binding_data: PackedScene
     At: modules\gdnative\nativescript\nativescript.cpp:1345
WARNING: NativeScriptLanguage::get_instance_binding_data: CollisionShape2D
     At: modules\gdnative\nativescript\nativescript.cpp:1345
WARNING: NativeScriptLanguage::get_instance_binding_data: CollisionShape2D
     At: modules\gdnative\nativescript\nativescript.cpp:1345
WARNING: NativeScriptLanguage::get_instance_binding_data: Area2D
     At: modules\gdnative\nativescript\nativescript.cpp:1345
WARNING: NativeScriptLanguage::get_instance_binding_data: World2D
     At: modules\gdnative\nativescript\nativescript.cpp:1345
WARNING: NativeScriptLanguage::get_instance_binding_data: Physics2DDirectSpaceStateSW
     At: modules\gdnative\nativescript\nativescript.cpp:1345
ERROR: HashMap<class StringName,void const *,struct HashMapHasherDefault,structHashMapComparatorDefault<class StringName>,3,8>::get: Condition ' !res ' is true
. returned: *res
   At: E:\Git\godot\core/hash_map.h:306
CrashHandlerException: Program crashed
Dumping the backtrace. Please include this when reporting the bug on https://github.com/godotengine/godot/issues
[0] NativeScriptLanguage::get_instance_binding_data (e:\git\godot\modules\gdnative\nativescript\nativescript.cpp:1346)
[1] NativeScriptLanguage::get_instance_binding_data (e:\git\godot\modules\gdnative\nativescript\nativescript.cpp:1346)
[2] godot_nativescript_get_instance_binding_data (e:\git\godot\modules\gdnative\nativescript\godot_nativescript.cpp:366)
[3] godot::___godot_icall_Object (e:\git\godot-cpp\src\gen\__icalls.cpp:5389)
[4] godot::World2D::get_direct_space_state (e:\git\godot-cpp\src\gen\world2d.cpp:44)
[5] Acclution::Melee::Attack (e:\git\abyssofalethea\code\weapon\melee.cpp:73)
[6] Acclution::Weapon::ReleaseAttack (e:\git\abyssofalethea\code\weapon\weapon.cpp:31)
[7] Acclution::Player::ProcessWeapon (e:\git\abyssofalethea\code\entities\player.cpp:217)
[8] Acclution::Player::_Process (e:\git\abyssofalethea\code\entities\player.cpp:127)
[9] godot::_WrappedMethod<Acclution::Player,void,float>::apply<0> (e:\git\godot-cpp\include\core\godot.hpp:194)
[10] godot::__wrapped_method<Acclution::Player,void,float> (e:\git\godot-cpp\include\core\godot.hpp:210)
[11] NativeScriptInstance::call_multilevel (e:\git\godot\modules\gdnative\nativescript\nativescript.cpp:882)
[12] Node::_notification (e:\git\godot\scene\main\node.cpp:54)
[13] Node::_notificationv (e:\git\godot\scene\main\node.h:46)
[14] CanvasItem::_notificationv (e:\git\godot\scene\2d\canvas_item.h:166)
[15] Node2D::_notificationv (e:\git\godot\scene\2d\node_2d.h:38)
[16] CollisionObject2D::_notificationv (e:\git\godot\scene\2d\collision_object_2d.h:39)
[17] PhysicsBody2D::_notificationv (e:\git\godot\scene\2d\physics_body_2d.h:43)
[18] KinematicBody2D::_notificationv (e:\git\godot\scene\2d\physics_body_2d.h:290)
[19] Object::notification (e:\git\godot\core\object.cpp:957)
[20] SceneTree::_notify_group_pause (e:\git\godot\scene\main\scene_tree.cpp:969)
[21] SceneTree::idle (e:\git\godot\scene\main\scene_tree.cpp:510)
[22] Main::iteration (e:\git\godot\main\main.cpp:1865)
[23] OS_Windows::run (e:\git\godot\platform\windows\os_windows.cpp:2754)
[24] widechar_main (e:\git\godot\platform\windows\godot_win.cpp:150)
[25] _main (e:\git\godot\platform\windows\godot_win.cpp:172)
[26] main (e:\git\godot\platform\windows\godot_win.cpp:184)
[27] __scrt_common_main_seh (f:\dd\vctools\crt\vcstartup\src\startup\exe_common.inl:288)
[28] BaseThreadInitThunk
-- END OF BACKTRACE --

and as you can see Physics2DDirectSpaceState has the name Physics2DDirectSpaceStateSW but in the generated __register_types.cpp it registers with: godot::_TagDB::register_global_type("Physics2DDirectSpaceState", typeid(Physics2DDirectSpaceState).hash_code(), typeid(Object).hash_code());

So is this a compiler quirk? I think it works fine on my linux machine (if i remember correctly).

Acclution commented 5 years ago

no there seems to exist a SW implementation of physics. SoftWare or server implementation?

Acclution commented 5 years ago

So I added godot::_TagDB::register_global_type("Physics2DDirectSpaceStateSW", typeid(Physics2DDirectSpaceState).hash_code(), typeid(Object).hash_code()); to __register_types.cpp and my project does not crash anymore though I do not think this is an acceptable solution in the long run?

Acclution commented 5 years ago

Yea so when I call get_direct_space_state it puts the implementation of Physics2DDirectSpaceState which in my case is Physics2DDirectSpaceStateSW in a godot::Object. So when nativescript tries to get binding data it tries to get it from Physics2DDirectSpaceStateSW instead of Physics2DDirectSpaceState.

Though I do not know why it needs to call godot_nativescript_get_instance_binding_data on the data when it already has the data?

Object *___godot_icall_Object(godot_method_bind *mb, const Object *inst) {
    godot_object *ret;
    ret = nullptr;
    const void *args[1] = {
    };

    godot::api->godot_method_bind_ptrcall(mb, inst->_owner, args, &ret);
    if (ret) {
                // Why do this when ret already has the Physics2DDirectSpaceState?
        return (Object *) godot::nativescript_1_1_api->godot_nativescript_get_instance_binding_data(godot::_RegisterState::language_index, ret);
    }

    return (Object *) ret;
}
aqnuep commented 5 years ago

I ran into the same issue and after some investigation and some help from @karroffel I discovered the following:

Strictly speaking this is not a binding issue, but an engine issue, as it breaks as follows:

  1. Godot does not register the implementations of the abstract classes providing the server interfaces with the ClassDB (e.g. Physics2DDirectSpaceStateSW in the above case, which implements the PhysicsDirectSpaceState abstract interface)
  2. Godot generates the JSON API information about the classes using the ClassDB, which is missing the server implementation classes
  3. As a result the JSON API file in godot_headers is missing the server implementation classes
  4. The final consequence is that the C++ bindings generate the TagDB data based on the JSON file, which again, is missing the information about the server implementation classes

The only safe solution seems to be to:

  1. Modify Godot itself to register the server implementation classes
  2. Update godot_headers with a newly generated JSON API file

After that the C++ bindings should just work.

aqnuep commented 5 years ago

Created PR https://github.com/godotengine/godot/pull/27936 to fix this.