Just a feature suggestion. X)
I use tool script quite a lot in my projects, and it is one of the big highlights for me. However, there are situations where a lot of extra work is needed to prevent code from colliding. Walling off code that is editor only versus code for run time only.
For some scripts this is exactly fine, because almost all the same code is used. Though quite often in other situations the code gets littered with extra branches, and the logic of the tool takes almost entirely different turns. It can get very bloated and difficult to organize, especially when they have different start up behaviors.
I was thinking it would be a nice added option if nodes could optionally have a resource slot for Editor Only Script. Something that specifically only executes in the editor, and can be discarded when a project is exported.
_Note:_ Leaving the old way intact though, because there would be some trade off between code duplication and branch complexity.
Last time I thought about this I thought it could be done with #ifdef macros, although they only get rid of execution bloat, not maintainance. On the other hand you could use a child editor-only node (or a mere script) and put tool functionality in it, I used to do that in my game for debugging in order to keep code separate (leaving only one if
in my main gameplay script)
@Zylann I like that idea. Thanks for sharing it.
I had idea of EditorOnlyNode
, that would be stripped when doing Export.
Mare idea never consulted it with anybody.
@n-pigeon That also sounds interesting. Especially for addon custom nodes that act as editor only helper nodes.
See #12453
Related to #8735. Copy-pasting my proposal here:
element.gd
:
tool "element_tool.gd"
# This script isn't tool by itself, but is replaced by the other in-editor
extends Node2D
export(int, "Fire", "Water", "Ice") var element_type = 0
func get_damage():
return ConfigAutoload.elements[type].damage
element_tool.gd
:
tool # Might be unnesesary, discuss
extends "element.gd"
# extends is not required, but better if you do this so you would get all the exported vars
# Discuss: do we really need to extend the other script for that?
# We might handle it like placeholder scripts, exporting/autocompleting the same, but
# having different in-editor logic.
export(bool) var debug = true setget set_debug
func _ready():
set_debug(debug)
func _draw():
if debug:
pass # Draw circles, whatever..
# Needed since we don't have a cool way to observe property changes yet
func set_debug(new_debug):
debug = new_debug
update()
Would this work with C# and GDNative?
Well, it would work as long as there is some way to specify the target tool script. So, attributes in C#, and some additional registration function in GDNative. Examples:
```c#
// c#
namespace X {
[Godot.Tool(typeof(ElementTool))]
class Element { /* ... */ }
class ElementTool : Element { /* ... */ }
}
```c++
// C++
NATIVESCRIPT_INIT() {
register_class<Element, ElementTool>(); // Not sure if it would be here. This is just an example.
register_class<ElementTool>();
}
Likely, it would be done internally as Ref<Script> Script::get_tool_mode_script() {}
, with the current implementation being equivalent to Ref<Script> GDScript::get_tool_mode_script() {return this;}
.
Also it must be taken into account that we may want to not include such editor stuff when exporting ;)
As an aside, one of the unhappy things I keep bumping into with tool script (and why splitting would be handy), is that they will not allow you to reference Autoload Singletons. Even if it isn't being called directly by tool code, it will flag it when it parses.
This doesn't compile:
extends Node2D
func _ready():
if(not get_tree().is_editor_hint()):
Utils.my_utility_function(123)
@avencherus That's a bug, #4236
Closing this. Appears a different and more robust feature/direction is being considered going forward.
As an aside, one of the unhappy things I keep bumping into with tool script (and why splitting would be handy), is that they will not allow you to reference Autoload Singletons.
This was very thankfully resolved: https://github.com/godotengine/godot/pull/18545
Most helpful comment
Related to #8735. Copy-pasting my proposal here:
element.gd
:element_tool.gd
: