While trying to make some reusable nodes I came upon needing to define some exported properties that should hold actions from the InputMap so I could have the reusable element in a scene multiple times with each instance responding to separate input events. I did this simply by doing:
@export var pan_left_action = ""
func _process(delta: float) -> void:
if pan_left_action != "" and Input.action_pressed(pan_left_action):
// do panning here
But my… let’s say ‘slightly compulsive tendencies’ wanted a nicer solution, so I looked at the tutorial for making selector plugins in the editor and spent a couple of hours wasting my time making said plugin.
I left in the original text box to demo the value as it is on the object.
Now my issue is on how to properly/idiomatically allow you to “enable” the plugin on a specific field. What I’ve done now is pick a random number above PROPERTY_HINT_MAX (for example 12345) and in the node using it doing:
@export_custom(12345, "")
var some_action = ""
But that just feels icky, it could easily collide with another selector plugin hint if other editor plugins use the same strategy. Another option could be to use the default string type hint and use some kind of custom hint_string value to “enable” the custom control on the property and the final option I’ve considered is instead of using a string to hold the action to use some custom Resource class to hold the value but that kind of feels like overkill.
I don’t think there’s a proper way to do this. I’d use the hint_string path to avoid possible collisions with engine updates or other plugins and possible issues if the plugin fails to load for some reason. something like @export_custom(PROPERTY_HINT_NONE, "input_action") which should be safe.
As a side note, a plugin for this is not needed (as long as you are only need it in a couple places) You can achieve a similar result with Object._validate_property()
Example:
@tool
@tool
extends Node
@export var input_action:String
func _validate_property(property: Dictionary) -> void:
if property.name == "input_action":
property.hint = PROPERTY_HINT_ENUM_SUGGESTION
# Filter the inputs and map their names to remove input/
var entries = ProjectSettings.get_property_list().filter(func(entry):
return entry.name.begins_with("input/") and entry.name.find(".") == -1
).map(func(entry):
return entry.name.replace("input/", "")
)
property.hint_string = ",".join(entries)
I was aware of doing it via Object._get_property_list() but _validate_property seems much easier, thanks. I went the plugin route primarily because I didn’t want to make the Node in question a @tool and have to sprinkle most methods with if Engine.is_editor_hint().
I think I’ll go the hint_string-route. Maybe Godot should have a “custom”/“plugin” property hint with a well defined format for the hint_string so multiple selector plugins / addons can work together (somethig like a comma seperated list of <AddonName>:<SelectorName>. But maybe I’m overestimating the necessity of preventing many addons adding many selector plugins that collide.