-
-
Notifications
You must be signed in to change notification settings - Fork 97
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
Add support for Resource inheritance (prototypal inheritance) #4089
Comments
I think this proposal is missing an explanation of what you want to have in Godot and how it is supposed to work. If you don’t have a concrete actionable proposal, please open a discussion instead. Or clarify what and how do you propose to implement. Furthermore, you need to explain in more detail what limitation there is that you cannot overcome. What you describe is solved by extending classes normally in Godot, be it nodes or resources. |
He wants not to enter common fields in resources. AFAICT you have to enter data by hand every time you create a new resource, extending doesn't help. Something like having default values for export variables. Alternatively, the use case could be served by the spreadsheet proposal? |
Default values should be taken from the property declaration, the get method implementation, and the property_get_revert method implementation. There may be some limitations or bugs, which needs addressing and fixing, but I still don’t understand what exactly is the problem and what exactly is the proposal.
Also, possibly related to this #2280? |
No this is different than default property definition. I would like to benefit from the editor to define the default values. |
Unless you change the value of a property in the child scene, this is already how it works in Godot. So, again, please provide a more concrete description of the issue, and a description of a solution that you want to implement in Godot. If this is a general idea without any of those, then please open a discussion instead. Proposal must define a problem and a solution, relative to Godot. Linking private forums and examples from other engines is not enough, I'm afraid. |
I'm not talking about scenes here, talking about resources. |
Scene is a type of resource. All resources work the same. Unless you change the value, it's not saved. If it's not saved, whatever is the default for the parent class is the default for the child class. |
@pycbouh: Whoa, that's very poorly documented then. I always thought resources and scenes were completely separate concepts... |
Scenes are Looking at https://forum.unity.com/threads/asset-inheritance-no-boilerplate-material-and-scriptableobject-variants.1191088/ I think is something possible to replicate that behaviour playing with property list and |
Looking that the OP posts examples. What OP appears to be looking for is: Resource inheritance. Like we have inherited scenes, where we load a tree of nodes with properties, and can then change those properties and save it as yet another scene. https://gameprogrammingpatterns.com/prototype.html#prototypes-for-data-modeling This is a more comprehensive example. Inheritance, for Data, not Classes. This does have real world applications. For example if I define a Resource called "EnemyData". And create and save an instance of this Resource to disk as "GoblinData", but now want to make several more Goblins that share common properties. My only way to do so is to manually update all the values I want to keep the same. With Resource Inheritance, I could define a new instance of EnemyData, save it as GoblinKingData, and have it refer to GoblinData for any property I do not manually set. This could be achieved via code by creating a GoblinData resource class that extends EnemyData, and sets these defaults. But now we are asking a game designer to open up an IDE just to tweak those base values. |
I guess I see what you're saying. So instead of inheriting in the OOP sense, this idea is about inheriting data itself? Basically, use one instance as fallback for another instance? If so, I think this pattern can be implemented in userland where the script for your resource would have a field to reference another instance of the same data script. I'm not entirely sure this needs to be implemented in the core somehow, though I guess it is similar to how materials have the next pass member. We don't have a designer-only way to create a data resource, it requires coding anyway, so at this moment it doesn't seem unreasonable to expect that the programmer would be able to set it up for the designer. Either way, without an implementation detail, this a discussion material, not a proposal material. |
It's doable. But extremely ugly in the inspector to the point I'd rather not give that to a designer. Every property now needs an "override" boolean that your getters need to check for. Checking that the assigned base resource is of the same type as the new one also requires use of get_script() since you can't use your own class name due to the cyclic reference problem. This kind of editor tooling actually already exists in godot as well, for control nodes that implement custom constants. (At least visually that is what property fields in an inherited resource would need to look like.) If necessary I can hack together a functional example in GDScript. |
@TheDuriel: I said literally the same thing a couple comments above yours, that the data has to be entered by hand every time... thanks for explaining it to @pycbouh more clearly |
You also said that it's like default values for export variables, which is a thing that exists and which side-tracked me 🙃
Oh, I think exposing something like this is doable and can be useful indeed. The only problem is that currently it works from I.e. we need to allow self references (if it's still not a thing in 4), we need to expose This is where I'd draw the line between what we can do in core, and what we should leave to users who need it this way. |
The exact details of how this works are very obtuse. But my attempt at reproducing what control nodes do proves that this is technically achievable for developers. But needs documentation. For example I am uncertain how to retain the checked status after saving the resource. Changing the value of 64 to something else does automatically check the box. Furthermore loading the resource does correctly load the new value, but the box does not remain checked. TL:DR: If _get_property_list() gets thorough documentation, then what the initial proposal desires can be relatively easily implemented by developers. Also, you need to override _get_property_list(), instead of get_property_list() A full implementation would look something like this:
|
You need to update it manually, from
What I meant here was doing something similar to what Duriel did, but taking care about the revert value. Now, looking at this issue again (and #4089 (comment)) godotengine/godot#52943 is probably the necessary tool for this, where pinned properties will ignore changes if the parent change the property value, but that pinned value will be applied to inherited objects if they haven't modified the value (wich is kinda similar to what is currently implemented, so is a tool, but not a really necessary one for now). Literally, doing: class ClassA extends Resource
# extends Resource because we want to save it to disk
var foo_int:int := 1 setget set_foo_int
func _init() -> void:
set_meta("foo_int_default", 1) # yeah, let's play with meta dark magic
func set_foo_int(value:int) -> void:
foo_int = value
emit_changed()
func property_can_revert(property:String) -> void:
if property == "foo_int":
return true
return false
func property_get_revert(property:String): # -> Variant
if property == "foo_int":
var default_value = 1
if has_meta(property):
# <property>_default is defined by the class on its constructor, to tell inherited classes what is the default value
# probably this will not work in all cases, but for now is the idea that crosses my mind. There should be a better one.
default_value = get_meta(property+"_default")
return default_value
func _get_property_list() -> Array:
return [{"name":"foo_int","type":TYPE_INT,"usage":PROPERTY_USAGE_DEFAULT}]
class ClassB extends ClassA:
pass
class ClassC extends ClassB:
pass Will (kinda) replicate the behaviour of https://forum.unity.com/threads/asset-inheritance-no-boilerplate-material-and-scriptableobject-variants.1191088/ , the part where modified values from parent and modified default values will be set from inherited classes too. Edit: Probably is better to |
I'd like to have resource inheritance like this:
Say we have resource A and resource B which is inherited from A. |
Here is another use case: animations. I export my models with animations from Blender. They are imported as a scene, which I can either inherit or include as an instance in another scene. That scene has animations. In those animations in addition to bones movement I would like to have other stuff, e.g. a methods be called (like I think, supporting inheritance for resources would be a good symmetry to scene inheritance and would enable new and better workflows. As of implementation, I think it should be possible to
|
I would finetune this rule a bit: "If we change any property of resource A, it is also changed in B unless B has overridden it". |
If this could work for materials, that would be great. It was a huge workflow improvement when material inheritance was added to Unity. I typically create a default master material, have level materials inherit from that master, and have unique variants inherit from level materials. It also helped that shader-based batching was added to Unity, making extra materials less costly. But, that's another topic. |
Heh, I ended up using a customized shader and a ton of instance uniforms to achieve a similar effect to what you're describing. I have no idea how the performance worked out, but it did let me have basically just one material for most of the game. |
Describe the project you are working on
Examining Godot as a potential engine for a project.
Describe the problem or limitation you are having in your project
I have a number of skills, abilities, and would like to base one resource on another. As it stands common fields must be re-entered in each similar resource.
Describe the feature / enhancement and how it helps to overcome the problem or limitation
This is often referred to as prototypical inheritance.
One Godot developer mentioned this feature on our forum.
https://discord.com/channels/212250894228652034/610347507222052867/944622534819733545
Highly sought-after feature in Unity and would give Godot a competitive advantage.
https://forum.unity.com/threads/suggestion-prefab-variants-for-any-object-scriptableobject-variants.585268/
https://github.com/GieziJo/ScriptableObjectVariant
https://www.reddit.com/r/Unity3D/comments/fn5db2/is_there_some_sort_of_scriptableobjects_variants/
https://blog.gemserk.com/2020/05/26/using-unity-prefabs-and-gameobjects-only-for-data/
Describe how your proposal will work, with code, pseudo-code, mock-ups, and/or diagrams
This should be easier than the current scene inheritance Godot has.
We could keep a list of dirty property names (strings), a reference from instance to the parent, and a reference from parent to instance. In the editor when the parent is modified, the property could be propagated to the children. The links could be forgotten at runtime. This would prevent having any cost at runtime.
If this enhancement will not be used often, can it be worked around with a few lines of script?
No.
Is there a reason why this should be core and not an add-on in the asset library?
This is because this feature could be used in more than custom resource types. For example Material Inheritances.
Keywords
Templates, Resource Inheritances, Prototypal Inheritance, ScriptableObject Variants
The text was updated successfully, but these errors were encountered: