-
-
Notifications
You must be signed in to change notification settings - Fork 21.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implement Resource State Inheritance #86779
base: master
Are you sure you want to change the base?
Conversation
Is a inherited Resource still its own thing at run-time? That is, at run-time, modifying any property of a Resource does not affect any inherited Resource, is that correct? By the way this would allow closing godotengine/godot-proposals#8094 |
@Mickeon It is its own thing. The only thing I did not implement in this PR is, if while during the editor, changing the base resource should change the inherited ones (basically something editor-only to check if the property edited in the base one is the same value as in the inherited ones, then change the inherited ones). This should not be hard to do. During run-time, however, the inherited ones are its own thing and only fetch the non-modified properties from the base one. |
That is excellent, and simple to describe, too. Users that want properties to propagate at run-time can listen for the Not sure about the current names, but this overall looks like a surprisingly simple yet powerful feature. |
It would be nice to have some kind of logo in the corner of inherited resources to let the user know that it depends on something else. And maybe we could highlight the parent resource if the "sub-resource-icon" is pressed? Oh, it would also be nice if the inspector would some show (e.g. with a different background color) which fields the sub resource overwrites. And a way to un_overwrite a field would probably also be necessary. |
@Ansraer yeah I could put the instance logo in the inspector. Regarding the editor, anything that has the revert button is what it has been overriden. |
Does this store only changes from the original or is it a unique instance that is easily revertable to the original? The context I'm thinking about is a vertex painting tool, which is not practical to use in Godot due to the current design. As we've discussed at length, the only safe option is to keep meshes tied to GLBs so they can be reimported on demand. But the meshes are locked, so we can't paint vertices. In order to do so, we need unique resources, but then we have disassociated ArrayMeshes and when the format inevitably changes, we have a problem. We can reimport the GLBs, but Godot will complain about the old format on the disassociated ArrayMeshes in all mesh instances we have painted. Does this PR help solve this dilemma for vertex painting? |
A different solution is needed, similar to the existing UV2 caching system used for lightmap unwraps: godotengine/godot-proposals#6486 |
Vertex painting is far more involved and I have the feeling it should need a separate implementation (not even using vertex arrays). I will open a proposal soon about this. |
552e162
to
859e28b
Compare
This is ready for review. |
Variant default_value = ClassDB::class_get_default_property_value(E->get_class(), F.name); | ||
|
||
if (default_value.get_type() != Variant::NIL && bool(Variant::evaluate(Variant::OP_EQUAL, p.value, default_value))) { | ||
if (!E->is_property_value_saved(F.name, p.value)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since we have this now, shouldn't we also replace the same sort of check done in gdextension here with this?
So there is a limitation in the current implementation that only the same type can be inherited by a resource. But I think we should allow narrowing types. I can imagine a situation where I have a base StyleBox with some content margins configured, and then have a StyleBoxFlat and a StyleBoxEmpty inheriting it, but adding their own unique properties as well. In fact, this is definitely a use case we want to be able to handle in various multistate controls, like buttons. |
@YuriSizov The limitation is because by default it may lead to mistakes, but it definitely could be more lean (as in, if the resource class also inherits the base class its should be fine). I can modify it for this as you suggest. |
Yes, please do, I think it would be useful and expected. |
* Ability to inherit a resource and do local changes to it. * Ability to customize in each resource how inheritance happens.
859e28b
to
64f0c42
Compare
I applied the suggested changes. Also renamed the feature to "state inheritance" which makes more sense and is less confusing vs regular inheritance. |
@reduz Were we expecting to queue this for merging in 4.3? You mentioned letting this bake in the last Pipeline and Animations meeting. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
-
This works as expected for materials.
-
The usability of this PR is poor. It would be better to have a way to create an inherited resource from the filesystem, similar to creating an inherited scene.
-
The option to set
resource_inherits_state
is available forPacketScene
(opening thePacketScene
in the inspector, not editing the scene), and it does not work. I believe it should not be visible to the inspector. -
I tested this in the context this proposal of mine: Add animation inheritance godot-proposals#9802 and found it lacking for animations, but I believe that could be addressed separately.
Point 2 doesn't seem like a dealbreaker - better a bad UX than no UX for this sort of thing - but on the other hand, now that it's missed the deadline for inclusion in 4.3, it does sound like something that should be addressed in time for 4.4. |
None of what I said is a deal breaker. I didn't say it was. Addendum: I'm glad people are looking at this, because I need it. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is my realization ONLY NOW that the below comments have always been pending and Github never reminded me of this.
@@ -448,6 +540,9 @@ void Resource::_bind_methods() { | |||
ClassDB::bind_method(D_METHOD("is_local_to_scene"), &Resource::is_local_to_scene); | |||
ClassDB::bind_method(D_METHOD("get_local_scene"), &Resource::get_local_scene); | |||
ClassDB::bind_method(D_METHOD("setup_local_to_scene"), &Resource::setup_local_to_scene); | |||
ClassDB::bind_method(D_METHOD("set_inherits", "base"), &Resource::set_inherits); | |||
ClassDB::bind_method(D_METHOD("get_inherits"), &Resource::get_inherits); | |||
ClassDB::bind_method(D_METHOD("is_property_value_saved", "property", "value"), &Resource::is_property_value_saved); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What would be the benefit of exposing is_property_value_saved
to the scripting languages, at least with the given name? Would it not be better for users to know whether or not a given property
's value is being inherited or not? That is the information users are after.
This may also be easily confused with @export
or PROPERTY_EXPORT_STORAGE
.
doc/classes/EditorSettings.xml
Outdated
<member name="resource_inherits" type="Resource" setter="set_inherits" getter="get_inherits"> | ||
</member> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe it's better not to expose new features, without a bit of information at least. This is to not leave users that do not religiously follow the blogposts wandering in confusion.
<member name="resource_inherits" type="Resource" setter="set_inherits" getter="get_inherits"> | |
</member> | |
<member name="resource_inherits" type="Resource" setter="set_inherits" getter="get_inherits"> | |
The resource inherited by this resource, or [code]null[/code] if it does not exist. | |
In the editor, a new inherited resource can be created by clicking on "Inherit" in the Inspector's popup menu. | |
</member> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wait a minute, EditorSettings? Why is this property here? What is it for?
<description> | ||
</description> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ditto.
<description> | |
</description> | |
<description> | |
Returns [code]true[/code] if the given [param property] would be saved inside this resource's file, given the specified [param value]. | |
</description> |
But you can notice a bit of struggle when attempting to properly document this method. Mainly, "saved" is a vague term here. Hence my questions in the above reviews.
This comment was marked as off-topic.
This comment was marked as off-topic.
@CsloudX Please don't bump issues without contributing significant new information. Use the 👍 reaction button on the first post instead. |
return true; // Not a default value, so save. | ||
} | ||
|
||
if (default_value.get_type() != Variant::NIL && bool(Variant::evaluate(Variant::OP_EQUAL, p_value, default_value))) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is the reason for skipping bool Variant::operator==(const Variant&)
here? I don't understand why it's not written as p_value == default_value
. Can you elaborate?
An inherited resource has a reference to the original one and shows the values of the original one. It can override these values and only those overrides are saved, otherwise the values in the original resource are used. This allows to have a base resource with a lot of parameters customized, and then inherited ones that may tweak one thing or two.
Ideally, this feature will also allow to tweak animations and animationlibraries from imported scenes (without having to do the hack of saving them to disk), although this needs other code changes that will happen in separate PRs.
How it looks:
This PR is intended to play together with this one and this proposal, to allow much better editing and usage of imported assets.
and closes Allow defining inheriting Styleboxes using a parent Stylebox with overrides godot-proposals#8094.