godotengine / godot-cpp

C++ bindings for the Godot script API
MIT License
1.74k stars 575 forks source link

Runtime classes cannot be cast_to from non runtime classes #1419

Open cridenour opened 7 months ago

cridenour commented 7 months ago

Godot version

4.3.dev (dad6c774b0)

godot-cpp version

4.3.dev (e55b792fea)

System information

Windows 10

Issue description

Noticed this when creating an EditorGizmo for a new node type - a node that is gameplay focused and ideally should be tagged runtime.

bool BuildAnchorGizmoPlugin::_has_gizmo(Node3D *for_node_3d) const {
  return Object::cast_to<BuildAnchor>(for_node_3d) != nullptr;
}

would always return false until I changed the registration.

Steps to reproduce

  1. Create and register a runtime class: e.g. ClassDB::register_runtime_class<BuildAnchor>();

  2. Create and register a non-runtime class: e.g. ClassDB::register_class<BuildAnchorEditorPlugin>();

  3. In second class, attempt to cast a given node: BuildAnchor *anchor = Object::cast_to<BuildAnchor>(gizmo->get_node_3d());

anchor will always be nullptr.

Minimal reproduction project

Can provide if necessary.

pupil1337 commented 6 months ago

If node A is generated in the scene, godot-cpp will new a object, and godot will also new a object, their cache each other's addresses. When godot-cpp call get_node<T> will first execute get_node_internal(), which returns the address p of the node in godot; Then execute cast_to<T>(p), will find p pointed's godot-cpp object, and then dynamimc_cast to type T. So we can find godot-cpp object through the get_node() method.

However, since runtime-class in editor never create an instance in godot-cpp, so it returns nullptr. This issue is caused by the runtime class feature of Godot, need godot fix it.It is best not reference runtime-class nodes during the editor.

dsnopek commented 6 months ago

However, since runtime-class in editor never create an instance in godot-cpp, so it returns nullptr.

This is correct!

The whole idea with runtime classes, is that the editor won't create a real instance of them, instead it creates a placeholder. The placeholder object's type will be the closest native parent, so if your BuildAnchor descends from Node3D, then the placeholder instance will be a Node3D, and you can still interact with it as a Node3D. But since no BuildAnchor instance was actually ever created, you can't cast to BuildAnchor.

This is by design.