I’m currently working through making an Inspector Plugin that allows for custom editing of my own Resource types. I’ve already gotten one working. Let’s call it Money, and it has a single exposed property. Now, I have a Resource that contains an array of things, amongst which is a Money. What I’m trying to do is make Money “transparent” in the inspector, such that it shows up alongside its other properties, rather than with the little sub-prompt. I’ve included a picture which kinda shows what I mean. “Price 2” has two elements, because I left the default one in for clarity. What I want is the top one, which I’ve achieved, except I can’t seem to find a way to save the value – it never sticks (i.e. the value is never actually set in the resource).
As I mentioned, I already wrote a Money inspector editor, in which the key lines are:
…but that didn’t work. Directly setting the value did work, but I get the impression I’m not supposed to that:
func _on_value_changed(value: float) -> void:
get_edited_object()[get_edited_property()]._value = value
However, because the object I’m changing isn’t the one being edited, I’m having trouble making it work. I feel like I should be able to somehow just drop in my MoneyEditorProperty directly and have it just work.
@tool
class_name MyResource extends Resource
var money:Money = Money.new()
func _get(property: StringName) -> Variant:
# redirect the "price" property to money.price
match property:
"price":
return money.price
return null
func _set(property: StringName, value: Variant) -> bool:
# redirect the "price" property to money.price
match property:
"price":
money.price = value
return true
return false
func _get_property_list() -> Array[Dictionary]:
var properties:Array[Dictionary] = []
# set the money property as storage so it gets serialized to disk
properties.push_back({
"name": "money",
"type": TYPE_OBJECT,
"usage": PROPERTY_USAGE_STORAGE
})
# create our price property that will only be used in the editor and
# it won't be serialized to disk
properties.push_back({
"name": "price",
"type": TYPE_FLOAT,
"hint": PROPERTY_HINT_RANGE,
"hint_string": "0,1000,0.01,or_greater,suffix:$",
"usage": PROPERTY_USAGE_EDITOR
})
return properties
Money is just:
class_name Money extends Resource
@export var price:float = 4.00
First off, thanks for bringing in the lower-tech solution. I do consider inspector plugins a last resort, and I hadn’t considered this for my use-case.
With that in mind, I’m trying to piece together how to do what I’d like to do now. My Money class is a little more complex, and I’ve already written a custom inspector plugin for that (which you helped me with in another thread). That comes with a custom SpinBox, and works well enough if I create a resource on its own.
So your example above will get me a standard range display for that passthrough, but is it possible to combine these two things? In other words, can I use _get_property_list() to display my custom MoneySpinBox (that extends SpinBox)?
Interesting. So the magic bits there are the signals, and then object.set() on that custom property. That looks quite similar to the effect I thought I “wasn’t supposed to do” in my initial post, but you seem to know a lot better than I do, so perhaps it’s fine after all.
Once I can take a step back, I’m going to better evaluate your suggestion using _get, _set, and _get_property_list. I’m doing some funky stuff in my inspector plugin that I can probably at the very least offload and abstract behind that facade.
One interesting thing I noted that deviates from the limited code examples the docs give: you used _enter_tree() instead of _init() in the editor property. Is that important, or more personal preference?
Well, you need to update the value somehow. Looks like you need to call emit_changed() after modifying the value too. At least the documentation says so (probably so the inspector knows that something changed and updates the other properties if needed) I missed that in my test.
Not really, I just didn’t try with _init() but it should be fine either way.