godotengine / godot

Godot Engine – Multi-platform 2D and 3D game engine
https://godotengine.org
MIT License
88.14k stars 19.95k forks source link

Using class_name in a newly created script does not register it in the node creation dialog, if under addons/ (unless part of an enabled editor plugin) #30048

Open Zylann opened 5 years ago

Zylann commented 5 years ago

Godot 3.1.1 Windows 10 64 bits

I suspect there is a scenario where it doesnt get registered at all. I was writing a new prototype this evening and the script still hasn't registered.

Here is what I remember doing: 1) Create a new project (no new scene) 2) Create a subfolder addons/zylann.scatter/ 2) Right-click in the FileSystem dock and choose "New Script" into that folder 3) Write the following (I wrote it by hand so might have had a few errors while doing so, but the end result was the same):

tool
class_name Scatter3D
extends Spatial

var _scenes = []

func _ready():
    # TODO Temporary test
    _scenes.append(load("res://props/placeholder_tree.tscn"))

4) Save the script (still no scene in the project, I don't use the default Ctrl+S, instead I save the script only) 5) Create a new scene, open the node creation dialog, search for Scatter: it's nowhere to be found, despite the class name being recognized by the script editor and saved in project.godot.

Even after restarting the editor, the node can't be found. No particular messages in the console. Did I miss something obvious? image

Here is the project, apparently you should be able to see directly what happens, since restart doesnt fix it: Scatter.zip

Edit: It would seem any script I create under addons/zylann.scatter/ never get registered, but they do if I they are under the project root Oo According to TheDuriel it's intented. Registration works in other systems, just not in the node dialog. I guess it's because plugins can be enabled/disabled, so it would make sense for them to no longer clutter the dialogs. However, it's not documented...

jonri commented 5 years ago

@Zylann can you clarify exactly what behavior is intended? In your example project and my own project, I have discovered that the script with class_name gets registered in the node dialog if you enable the plugin and is removed if you disable the plugin. This seems to be the intent of the code here.

To me this says that class_name could be considered a replacement for using add_custom_type() to register your plugin unless you need something beyond enabling/disabling the type with the plugin. If this is officially the case, I think it should be added to the documentation on creating plugins, with the auto-enable/disable feature explicitly mentioned as well.

Zylann commented 5 years ago

I have discovered that the script with class_name gets registered in the node dialog if you enable the plugin and is removed if you disable the plugin

That's what I realized later on, it's only hidden or shown from the dialog, other class_name functionality works (and should). If it's properly shown when the plugin gets enabled, then that issue could be closed, but could be worth documenting that I think.

Xrayez commented 4 years ago

I just stumbled upon this when creating a plugin which exposes a new Resource via class_name, and it doesn't show up in the Create New Resource dialog either.

But I noticed it does show up in dialogs when the script resides directly under addons/my_plugin. Disabling a plugin prevents the class_name scripts to show up in dialogs too.

So, to reproduce the issue, you need to put a script directly under addons folder. Those kind of scripts will never be visible by creation dialogs as it doesn't belong to neither plugin. It creates a problem when I want to create a global script which can be accessible by other plugins, and be exposed to user.

This is another instance of godotengine/godot-proposals#22 @willnationsdev.

Calinou commented 4 years ago

I can confirm this on 3.2 stable.

willnationsdev commented 4 years ago

At the time that script classes were first introduced, I'd heard people wanting to make sure that only active plugins' nodes would actually show up (so that installing a plugin, but keeping it inactive, wouldn't make those nodes appear as options).

However, if people consider that a bug, I can submit a PR to fix it. These 5 lines are the offending code. Simply remove that, and they should show up as normal.

Edit: Since it's merely a half-measure, as it doesn't actually prevent the name from being a script class in the first place, it should probably be classified as a bug. The more proper way of fixing the "problem" that this was solving is to introduce actual namespaces into Godot's scripting API via #21215.

Calinou commented 4 years ago

However, if people consider that a bug, I can submit a PR to fix it. These 5 lines are the offending code. Simply remove that, and they should show up as normal.

Please do, I'd prefer using class_name over the "oldschool" custom type system (although it's not a strict requirement for my use case).

akien-mga commented 4 years ago

Classes registered in a disabled plugin should not be available. If they're currently only unavailable in the Create New Node dialog, but still registered in the global namespace, that's the bug which needs to be solved.

willnationsdev commented 4 years ago

@akien-mga @Calinou

For reference, I'd fixed this issue previously in #32434, but because there was no way to distinguish between addons and plugins, even addons that were not plugins (which have no way of being enabled or disabled) would get excluded from the scan.

Should I just recreate this PR, but set it to enable plugin-less addons' script classes by default? Or do we want some mechanism whereby the plugins tab can actually perceive all "namespaces" of addons in the project and enable users to toggle on/off each addon, regardless of whether it has a plugin or not?

Also, isn't this in some way related to the whole sub-project proposal whereby the addon system would no longer be based on the res://addons/** directories, but rather would detect addons wherever they are in the project based on project.godot files or something? If we hardcode a check that iterates through the res://addons/ directory to find addons, it won't cooperate with any revisions to the addon system that break that assumption.

adamscoble commented 1 year ago

The title isn't accurate for me in 4.1.beta1. I have my plugin enabled and none of my Node-extending classes are available in the Add Node dialogue. I also tried restarting the editor but they remained unavailable.

CactiChameleon9 commented 1 year ago

So I have an Addon on the asset store and I want the class_name to appear in the Add Node dialogue. How am I supposed do make this happen? Do I ignore the convention of using addons folder? Do I need to turn my asset into a plugin so I can enable it?

Things in the addons folder that are not plugins should be enabled by default to make this simpler.

edit: figured it out with plugin config and (basically empty) plugin script - still seems a little unintuitive

donn-xx commented 1 year ago

Not 100% sure this is the right thread, but I am on 4.1.1 and writing an addon in gdscript and when I use class_name it seems random as to whether Godot will recognize it moments or minutes later.

Example:

@tool
class_name Foo
extends Resource

The error messages vary, but the essence is that "Foo" is not registered anywhere. ProjectSettings.get_global_class_list() does not contain Foo, at all.

Specifically, in my addon, I am making the script in code:

var s = "@tool\nclass_name Foo\nextends Resource"
#save s to file 
var obj = load(path).new()

At this point I have an object obj, but it is not in the get_global_class_list()

I have also tried call_deffered to break-up the pacing of the code. I figured a few frames between the save and the load().new() etc. would give Godot a chance to register the class. It does not seem to matter.

Is there a way to force Godot to accept a new script class?

wareya commented 10 months ago

In Godot 4, what is the current recommended way to add custom types from an addon to the node creation dialogue? I've been looking through the documentation and issues for the past half hour and can't find anything that works.

donn-xx commented 10 months ago

Seems OT, but: https://docs.godotengine.org/en/stable/tutorials/plugins/editor/making_plugins.html#a-custom-node

wareya commented 10 months ago

Tried it, didn't work.

donn-xx commented 10 months ago

Hmm. Here's some code I am using now:

@tool
extends EditorPlugin

func _enter_tree() -> void:
    add_custom_type(
        "dab3D", # *seems* must be the same as the class_name in the gdscript
        "Node3D", # or whatever
        preload("res://addons/dabber/dab3dnode/dab3d.gd"), # this seems to be the magic
    )

hth

ETA: You can find me on Mastodon at @dbat@mastodon.gamedev.place and I'll see if I can help over there.

hsandt commented 4 months ago

So I have an Addon on the asset store and I want the class_name to appear in the Add Node dialogue. How am I supposed do make this happen? Do I ignore the convention of using addons folder? Do I need to turn my asset into a plugin so I can enable it?

Things in the addons folder that are not plugins should be enabled by default to make this simpler.

edit: figured it out with plugin config and (basically empty) plugin script - still seems a little unintuitive

Thanks, that's why I needed for my custom non-tool add-on, which is literally a collection of scripts meant to be added to my repos as submodule for personal use, so I never created a plugin.cfg for it. To enable it and recognize class_names I had to do as you said anyway. To get a nice template I did Project Settings > Plugins > Create New Plugin then copied the two files into my existing addon subfolder:

plugin.cfg content doesn't matter if you only use your add-on locally like me, but better fill it with meaningful info so you can recognize it in the Plugins list.

[plugin]

# Customize to your needs
name="Hyper Godot Commons"
description="A collection of utility scripts for Godot 4"
author="hsandt"
version="1.0"
# Keep this
script="plugin.gd"

plugin.gd

@tool
extends EditorPlugin

(you can remove _enter_tree and _exit_tree methods, but you must keep @tool and extends EditorPlugin or Godot will complain if you restart the editor and try to enable the plugin).

Then enable the plugin.

So to fix this specific sub-issue natively, it would be nice to have either of these: a. Add-on subfolders without a plugin.cfg / plugin.gd are automatically parsed like a collection of scripts & assets, and all class_names are registered for usage in Add Node popup. b. Add-on subfolders without a plugin.cfg / plugin.gd are still added in the Plugins list in a special category for non-tool plugins, which is much more simple with only columns Name (filled with folder name since there is no .cfg to define a readable name) and a Status column containing checkboxes to "Register class names" instead of "Enable".

That said, I understand that it's easier to work with a uniform setup / a standard for all add-ons, so if Godot devs decide that all add-ons should have even a dummy plugin.cfg and plugin.gd for clarity, I'm okay with that. However it may be nice to have a warning in the Plugins list (or the FileSystem tree) that some add-on subfolder lacks a plugin.cfg / plugin.gd, esp. if it has some scripts with class_name (since add-ons meant to be cloned but that don't contain any scripts like https://github.com/paddy-exe/ShaderFunction-Extras should be OK without a plugin.cfg).