godot: Godot errors/crashes after inspecting two different objects handled by the same plugin

Godot version

Godot 4 rc2

System information

Windows 10 64 bits NVIDIA GeForce GTX 1060

Issue description

I was trying to reproduce a nasty error I started having since stuff got changed in some areas of editor plugins, but in RC2 instead of reproducing my issue, I ended up finding this crash. So I thought I’d report it…

I wrote a simple test plugin that adds a bottom panel with two buttons:

  • “Edit Sprite”: edits the last selected sprite
  • “Edit Texture”: edits the texture of the last selected sprite

This plugin handles BOTH Sprite2D and Texture2D.

Steps to reproduce

After testing the plugin a bit, I turned it off, then clicked on the Script tab: Godot crashes. No information popup or logs, just shuts down.

Minimal reproduction project

EditorPluginEditAnotherHandled.zip

This project has the plugin enabled by default.

  • Open the main scene and go to the 2D view
  • Select the sprite
  • In the bottom bar, click “Test plugin” to show the custom panel
  • In the custom panel, click “Edit Texture” and “Edit Sprite” alternatively a bunch of times
  • Go to Project Settings and turn off the plugin: Godot might crash already.
  • If no crash occurred, click on the “Script” tab: observe crash.

Secondary note: I was told that one of the changes to EditorPlugin was that _edit(null) can be called when “there is no longer any selected object handled by this plugin” (seen in the doc). But if you look in the console while alternating the two buttons (which ask the editor to inspect two different objects handled by the plugin), you will notice that edit(null) occurs half of the time, I dont understand why.

Third note: When testing this repro in master 9c960a8c2494eb826a557a7ffc96dd4547f9d31e, if I select the sprite and then click on the “Edit Texture” button, I get an error:

ERROR: Condition "plugins_list.has(p_plugin)" is true.
   at: EditorPluginList::add_plugin (editor\editor_node.cpp:8119)

Which I dont understand either.

About this issue

  • Original URL
  • State: closed
  • Created a year ago
  • Comments: 29 (24 by maintainers)

Commits related to this issue

Most upvoted comments

Well that error appears when you try to edit multiple objects by the same plugin within the same editor context, which is very likely to happen when your plugin handles any resource.

@Zylann mentioned this error occurs when handling the same object by two different plugins, but I have the exact same error when handling subresources with just one plugin.

In my plugin I override _handles(object) like so:

func _handles(object: Object) -> bool:
	return object is Resource

But whenever I select a subresource in the inspector, I get:

editor/editor_node.cpp:8240 - Condition "plugins_list.has(p_plugin)" is true.

What’s more, the subresource closes in the inspector, preventing me to edit it any further.

Had a look at the patch, it really looks like a hack. Seeing stuff like this in those functions makes things confusing compared to what they are meant for. Notably handles, which in theory should only depend on the passed object, and not some state of the plugin, which now results in race conditions. The hack in make_visible is now also a source of race conditions. Everytime there is a call_deferred, it opens the door for more problems in the future. I wouldn’t have come up with this idea because it goes against what the methods are meant to do and seems to rather exploit Godot’s implementation details (which I’m not much aware of, I dont often inspect the editor’s core logic).

I feel like Godot should have cleaner ways to code things for contextes like this. It constantly happens for me and it’s tiring to keep adding hacks because it feels like I’m loosing control and could break some random day. But not sure what would have to change… as I described earlier, the logic seems too restrictive, partially ill-formed or unclear (both in docs and error messages). Because even though the API could still assume only one “thing” is edited at a time, in practice it doesn’t always exist alone in a void, and may be nested in related resources, nodes or objects, which may be part of a whole context with interacting UIs. The sole fact you can have a node selected in the scene tree and a different object edited in the inspector is an example of this, but it goes beyond that of course.

I gave your patch a try, and seems to work when I select a graph resource in a terrain. Although I suppose the same hack must be added in other places as well: errors keep happening after I select nodes of the graph: clicking on a node uses the inspector to “edit” a custom object representing it (mostly because we can’t have extra inspectors). Then clicking on the background is supposed to “edit” the graph resource itself in the inspector. But when the graph gets edited that way, the error occurs everytime editor\editor_node.cpp:8240 - Condition "plugins_list.has(p_plugin)" is true.. I suppose that’s because the graph editor plugin has to handle both graph resource and graph nodes to function properly but Godot doesnt like that (no idea why tho), but again I’m really confused about how else to cleanly handle that without messing up all the UIs that are supposed to be shown in this nested editing context.

Actually, that second case I just described is indirectly triggered by my own code, which simply needs to use the inspector to edit a specific “sub-object” of my graph resource, while keeping the graph editing context: https://github.com/Zylann/godot_voxel/blob/cee2a86af4e6e9d76398856c868a20cf27b7052f/editor/graph/voxel_graph_editor_plugin.cpp#L195

get_editor_interface()->inspect_object(*wrapper);

Therefore, there might be a simpler solution than your hack here. I noticed this had a parameter p_inspector_only, which the doc describes:

If inspector_only is true, plugins will not attempt to edit object.

Which sounds like it would solve this specific case, and I would be able to remove this sub-object class from handles, getting rid of the error I had before. But when I provide true, it makes no difference… edit(null) and make_visible(false) are still called, so selecting a graph node now hides the whole graph editor (so plugins are NOT ignored), which defeats the whole point for me. Though in this case I could workardound with this:

	_ignore_edit_null = true;
	_ignore_make_visible = true;
	get_editor_interface()->inspect_object(*wrapper, String(), true);
	_ignore_edit_null = false;
	_ignore_make_visible = false;

Which luckily seems to be working because neither edit nor make_visible are deferred calls. (but of course using inspector prev/next arrows still break and hide the editor)

No longer crashes on master. I guess the issue is resolved? You can’t handle the same object by two plugins at the same time, this is expected limitation.