tooling shenanigans
null has a day/night cycle, and during this cycle I wanted the non-playable characters to roam around the world. The way I implemented this was by adding nodes throughout the world indicating the time that a character should start walking to that position.
Soon, it became difficult to remember where all of the nodes are for each character were. I mean, I had to open a hierarchy view:
And not only did I have to rifle through all the nodes to find what I wanted to edit, each node had its own time and character (which might accidentally not actually reference the character the name of the node suggests it is for). Plus, it was hard to visualize what the path would be. This was not ideal, so I tried to write an editor helper.
At first, the editor helper was easy to write. All I needed to do was group the nodes by character, sort them by time, then draw a line between the points in each group:
…but, as you can see, this resulted in a really noisy map that was still hard to parse. Fair enough, I thought, I just need to draw the path that is currently selected. However, finding the currently selected node turned out to be Unity-levels of silly.
As it turns out, you need access to the EditorInterface
in order to find out what node is currently selected. However, you can’t actually get a reference to one unless you make a new editor plugin (it will be null
if you try to access it outside of a plugin). So, I made an editor plugin whose sole purpose is to exist so I can access the EditorInterface
:
@tool
class_name EditorHelper
extends EditorPlugin
static var instance: EditorHelper
func _enter_tree():
instance = self
pass
func _exit_tree():
pass
Then, in the tool script, I can access the currently selected Node
:
func _exit_tree():
if EditorHelper.instance != null:
var s = EditorHelper.instance.get_editor_interface().get_selection().selection_changed
if s.is_connected(queue_redraw):
s.disconnect(queue_redraw)
func _draw():
# We can't simply use `get_selected_nodes` because `_draw` will
# not get called again when the selection is changed.
if Engine.is_editor_hint():
var s = EditorHelper.instance.get_editor_interface().get_selection().selection_changed
if not s.is_connected(queue_redraw):
s.connect(queue_redraw)
internal_draw()
func internal_draw():
var edi = EditorHelper.instance.get_editor_interface()
for selection in edi.get_selection().get_selected_nodes():
if selection == self:
# elided: Draw the path...
And it works!
That’s quite a lot of work for what I wish was just:
func _draw():
if Engine.is_editor_hint() \
&& self.find(EditorHelper.selected_nodes) > -1:
# elided: Draw the path...
But at least it works now, I suppose!