godotengine / godot

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

Splitting editor and runtime scripts. #12837

Closed ghost closed 6 years ago

ghost commented 7 years ago

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.

Zylann commented 7 years ago

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)

ghost commented 7 years ago

@Zylann I like that idea. Thanks for sharing it.

SirPigeonz commented 7 years ago

I had idea of EditorOnlyNode, that would be stripped when doing Export. Mare idea never consulted it with anybody.

ghost commented 7 years ago

@n-pigeon That also sounds interesting. Especially for addon custom nodes that act as editor only helper nodes.

Zylann commented 7 years ago

See #12453

bojidar-bg commented 7 years ago

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()
Zylann commented 7 years ago

Would this work with C# and GDNative?

bojidar-bg commented 7 years ago

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#
namespace X {
    [Godot.Tool(typeof(ElementTool))]
    class Element { /* ... */ }

    class ElementTool : Element { /* ... */ }
}
// 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;}.

Zylann commented 7 years ago

Also it must be taken into account that we may want to not include such editor stuff when exporting ;)

ghost commented 7 years ago

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:

tool
extends Node2D

func _ready(): 
    if(not get_tree().is_editor_hint()):
        Utils.my_utility_function(123)
bojidar-bg commented 6 years ago

@avencherus That's a bug, #4236

ghost commented 6 years ago

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