Skip to content
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

Duplicating a node should result in either a true Instance or true unique copy, not a mix of both #317

Open
golddotasksquestions opened this issue Dec 18, 2019 · 32 comments

Comments

@golddotasksquestions
Copy link

golddotasksquestions commented Dec 18, 2019

Describe the project you are working on:
In all my projects I'm duplicating and instancing nodes all the time.

Describe the problem or limitation you are having in your project:
When I duplicate nodes, they are neither unique (aka independent or disconnected from their original), nor are they completely connected: a pure instance where changing one thing in any one of the duplicates results in the same change happening to all of the duplicates.
instance_or_duplicate

Describe how this feature / enhancement will help you overcome this problem or limitation:
Having either true Instances of nodes or true unique duplicates would prevent confusion, unintentional changes, self inflicted bugs.
Ideally I would like to be able to do something like

  • rightclick on a node in the Scene Panel for the context menu and select "create Duplicate (Ctrl+D)" to create a unique duplicate
  • and "create Instance (Ctrl + I )" (or Ctrl+Shift+D) to create a true Instance of the Node I just created.

If I would want a specific Resource to be shared, by multiple nodes, I would like to Save the resource as a .res for instance, and then load it into any another node (already possible).
This would be intentional driven design for me.

Show a mock up screenshots/video or a flow diagram explaining how your proposal will work:
Imagine either both color changing and shapes changing in the gif above (true instance) or both color and shape changes stay independent from the original (unique duplicate)

Describe implementation detail for your proposal (in code), if possible:
for me not possible

If this enhancement will not be used often, can it be worked around with a few lines of script?:
Would be used a lot because duplication of nodes is a very common thing in Godot.

Is there a reason why this should be core and not an add-on in the asset library?:
It's about existing core functionality

@Xrayez
Copy link
Contributor

Xrayez commented Dec 18, 2019

Setting up resources to be unique across instances is possible by enabling Local To Scene option:

godot-local-to-scene-duplicate

It works for scenes only though. I wish I knew about this feature from the moment I started using Godot!

Resources are shared by default to improve re-usability and performance. Scripts are also resources and they 99% of the time have to be shared. One can take a conscious advantage of this so that changes to a single resource can affect some behavior of existing nodes at run-time so you don't have to go through each node to change a particular property (say friction, see PhysicsMaterial).

I think there's much confusion as to how duplicating works in Godot, for instance see godotengine/godot#33824.

So yeah I think it's necessary to distinguish between shallow/deep/instance duplication across the editor. Adding an additional submenu popup for this could be a step forward:

godot-duplicate-unique

@Zireael07
Copy link

Related to @Xrayez's comment: godotengine/godot#6258, godotengine/godot#6922, godotengine/godot#9037

@golddotasksquestions
Copy link
Author

golddotasksquestions commented Dec 18, 2019

Thank you @Xrayez for sharing your thoughts!
Thanks @Zireael07 for the links!

I totally get why it is good and important to allow resources to be shared.
What I don't get is the fact that this is the default. It's currently is opt-out, but strongly feel it should be opt in.

Or clearly differentiate between instancing (everything shared) and duplication (everything unique).

The shapes resource is just a visual example you can easily miss until many many commits later. I actually have and had much more problems with scripts and animations before I learned never to share scripts and never to save animations.

It should not be like that. Sharing scripts with nodes should not threat to override your work if you did not know about that checkbox or forgot to tick it. Neither should saving animations or changing CollisionShapes be a threat to the work you already created.

@Feniks-Gaming
Copy link

I agree with the naming change. Duplicate doesn't suggest the linked copy. When I duplicate the file on computer it doesn't change because I change original or more importantly even original doesn't change because I edited a copy. Separating instance and duplicate would be clearer

@willnationsdev
Copy link
Contributor

@Calinou I believe the topic:core label is also relevant here as they are suggesting that these changes also be applied even when executed from code. It isn't an editor-specific issue.

@jasonwinterpixel
Copy link

If we implement this proposal, would that help with your issue?

#2737

The workflow would be Duplicate Node -> Make Subresources Unique

@chottokite
Copy link

Duplicating a node merely duplicates its node tree. Perhaps it doesn't do what you expect it to with some idea on mind but, it does what it says it does and not more. This behavior should stay as is. When in the editor, I think you should consider making these nodes you duplicate a separate scene and instance them in the main scene. If needed, mark those particular resources that you want to make unique with "Make local to scene". If duplicating nodes in GDScript, you should consider again separate scenes instances and duplicating nodes with the DUPLICATE_USE_INSTANCING flag.

@jasonwinterpixel
Copy link

This behavior should stay as is.

My proposal #2737 keeps duplicating a node the same. I'm referring to the behaviour of Make Subresources Unique which only operates on 1 layer of subresources. I'm suggesting that Make Subresources Unique should truly make all the subresources unique.

@jordanlis
Copy link

jordanlis commented Sep 9, 2021

Duplicating a node merely duplicates its node tree. Perhaps it doesn't do what you expect it to with some idea on mind but, it does what it says it does and not more. This behavior should stay as is. When in the editor, I think you should consider making these nodes you duplicate a separate scene and instance them in the main scene. If needed, mark those particular resources that you want to make unique with "Make local to scene". If duplicating nodes in GDScript, you should consider again separate scenes instances and duplicating nodes with the DUPLICATE_USE_INSTANCING flag.

The important thing to understand is not that the software should do what it says it will do.

You have to be in empathy with the user. Here is at least one use case that leads to say that ctrl + D should create unique instances :

  • When you instanciate a new scene, let's say a tree in your level, you start by doing it
  • Then, you probably have multiple trees in your levels, so you don't wan't to go through the whole process to instanciate your next trees, because it takes time and that you want to do your level design fast. So you select the node and make control + D

In this process, you will have exactly duplicated nodes, but you want to have true differents instances because each tree can be configurable with for examples values in the editor.
SO : if you used ctrl + D, and that you modify a parameter of one tree in the inspector, it will affect all the others trees whereas it is not what is expected by the level designer, because he want's to create chaos like in nature and put different parameters for each tree.

The user experience is the most important, not the pure logic of the software because it's used by human beings

I'm not saying that this particular solution should be implemented, but at least we should have the possibility to easily duplicate an instance without making it linked to the original one.

@lukostello
Copy link

lukostello commented Oct 19, 2021

I find this post confusing because there are 5 ways it could be implemented and I'm having track of which methods are being called what.

  1. When you make a copy it wouldn't share resources if "make_local" on that resource is checked (then either A: recursive subresources arn't shared as well if they are checked as "make_local" or B: Subresources even when marked "make local" will still be shared among all the unique parent resources that were made) but do share resources otherwise. This (B version at least) is what happens when you instance a packed scene right now so I hope this is what is being called instance. But sometimes it seems like the next one is what other people are talking about when they say instance
  2. When you make a copy it not only would it share resources (even ones that weren't made local) but every variable the would be the same as well. As the OP seems to expect seeing as how canvas item is inherited from the base class not a resource. But this simply wouldn't make sense because if we did that they would have to share translation data as well which would make them look like one object. We could do it like this:
  3. When you make a duplicate it turns the original into a resource that contains every variable except for translation data, unless you are performing it on something that is already a duplicate in which case it would give that reference to the new duplicate. But this gets messy real quick because The duplicates would have to be like spatial nodes with a reference to whatever class is now a resource, which would make it a different class than the original. Just very strange to think about.
  4. Similar to 1 but as though all resources (and subresources) are not checked make local (even if they are)
  5. Similar to 1 but as though all resources (and subresources) are checked make local (even if they aren't)

I'd hope 1. would be called instancing because its what happens when we instance a packed scene. I'd expect duplicate to mean 4

@golddotasksquestions
Copy link
Author

golddotasksquestions commented Oct 24, 2021

I think you have to approach this more form "what a user wants and expects" rather than "how or why the system currently works as it does". I know how and why the system works the way it does, it just makes no sense from a user perspective.

If I duplicate a body with a CollisionShape and change it's extends, I don't expect or want any other CollisionShape to change too, unless I explicitly told it to. This should be opt in, rather than opt out, as it currently is.

@lukostello
Copy link

lukostello commented Oct 25, 2021

I just had an idea: introduce more flags to the node.duplicate() 1 flag for how it treats resources marked local to scene (true duplicates them false doesn't) 1 flag for how it treats resources that are not marked local to scene (true duplicates them false doesn't) 1 flag for how to treat sub resources (recursive)marked local (true duplicates them false doesn't) 1 flag for how to treat sub resources (recursive) not marked local. We could have the same flags for instance() too. That way the user could define just about any behavior they want. Maybe even another flag for linking variables of the node such as canvas item like they were expecting but idk that might get weird because its not a resource so passing it by reference might not be possible in gdscript. There is already that DUPLICATE_USE_INSTANCING flag which sounds like what I just described but from my experiments its not.

@jordanlis
Copy link

I did some mockups and feature suggestion here, if you want to take a look at it. I hope it helps for the debate ;p

@CookieBadger
Copy link

CookieBadger commented Dec 17, 2022

As a level designer, I cannot describe how often the current duplication behavior has been driving me crazy, especially since I do not know such behavior from any other 3D software. To give you a perspective on the importance of fixing this here is an example of how annoying this is:
I have an area that defines camera movement. It contains 3 Collision shapes for:

  • confining the camera
  • detecting when the player has entered the area
  • detecting when the player has exited (usually bigger than the "entered" area, to avoid switching too fast between scenes, or continuous switching when the player is on the edge)

Now when want to add such a zone, I often duplicate an existing one, since it is probably not far away in the viewport and has similar sizes. I then have to make three resources unique every time I make a new area. This is time-consuming. But the worst part is, that it is very easy to forget, and when the old area is not in view any more or hidden, there is no way of noticing, that you are overriding carefully placed colliders. Repeat this a few times and you can lose several minutes of work and feel very frustrated. This problem applies to a multitude of similar systems. I think for beginners, this behavior is particularly unintuitive and off-putting.

One way of fixing this could also be to have a setting on a resource field, next to "Local to Scene" that would say "Make unique on duplication" or something like "Unique for instance" which would make sure that this resource is unique for every instance. Reading the solution from @lukostello, I want to mention that this might not only apply to objects that have been "Made local", but also for objects with "Editable children" applied.

@beyarkay
Copy link

What is the current state of this proposal? Has it been accepted, or does it need more work to clarify what exactly will change and how that change will be implemented? I'm also being bitten by the fact that doing a deep copy isn't easily available.

@Calinou
Copy link
Member

Calinou commented Jul 27, 2023

What is the current state of this proposal? Has it been accepted, or does it need more work to clarify what exactly will change and how that change will be implemented? I'm also being bitten by the fact that doing a deep copy isn't easily available.

#4672 contains more recent discussion on the subject. (If you are looking into doing this from code, I assume #4672 will also expose a method/flag to do the same operation from code.)

That said, you can see it's quite a controversial subject, so I wouldn't expect significant movement on this anytime soon. Feel free to open a pull request following #4672, but there's no guarantee it would be merged without significant changes.

@jordanlis
Copy link

Controversial maybe, and much more about the solution to apply. But in the issue you linked, many people appears to agree on the fact that things are really confusing at the moment about shared ressources and the default behavior of copy paste of a node.
Maybe small things can be done to fix it, but I think a lot of people at least agree that a change somewhere should be done no?

@luislodosm
Copy link

luislodosm commented Sep 2, 2023

For me, the expected behavior when using ctrl+d or copy/paste on a node is:

  • If the node has references to external resources stored on the Filesystem, I expect the references to be maintained.
  • If the node has built-in resources, I expect new internal resources to be created in the new node.

Fortunately, Godot is very open, so my solution is this:

@tool # <- Important
class_name MyClass

@export var my_external_resource: MyResource
@export var my_built_in_resource: MyResource

func _enter_tree():
	var im_duplicating = Input.is_action_just_pressed("ui_graph_duplicate")
	var im_pasting = Input.is_action_just_pressed("ui_paste")
	if im_duplicating or im_pasting:
		my_built_in_resource = MyResource.duplicate() # or MyResource.new()

@Malleator
Copy link

I still can't believe how many years that this issue has sat here; furthermore, I can't believe that, 'Duplicate,' makes a reference instead of a unique actual duplicate in the first place. Seems like an incredible oversight in design. 99% of the time the user is gonna want and expect a duplicate, not a reference. And the fact that the only alternative, seemingly at this time, to actually duplicating a node is manually recreating it is simply preposterous in my opinion

@golddotasksquestions
Copy link
Author

@Malleator

What is confusing, is that duplicate does make an actual duplicate, but only of the node itself, not of the Resources this node uses.

So to not be completely confused and fucked by this issue, you first have to have a really good understanding of what Godot means by "Resource" and how this is different from the node.

Nodes use Resources.

Take a Sprite for example. When we see a graphic in a 2D game most people would call this a Sprite. When in fact what we see is a texture (= Resource) displayed by a Sprite Node. If the user duplicates this Sprite, Godot will create a new Sprite instance from the Sprite class and assign it the same Resource by reference. Meaning the user can change all Sprite properties individually for each Sprite, but as soon as the user fiddles with the Resource of one Sprite, all Sprites will suddenly adopt these changes.

Now for a Sprite using a Texture resource this might be desired behaviour. For a CollisionShape using a Shape resource however, or an AnimationPlayer using an Animation resource, or a Node using a Script resource, ... this might not be desired in the most cases.

The biggest problem Godot has in this regard imho, is the silence. The total lack of transparency and feedback in communicating this to the user via the Editor GUI. You basically have to be an expert Godot user to fully understand this behavior which is very specific to Godot. Would it be more transparent (for example with a giant icon and large fat text next to the resource in the Inspector making it crystal clear this resource is shared or unique, I think this issue would be much less of a problem.

@jordanlis
Copy link

@Malleator

What is confusing, is that duplicate does make an actual duplicate, but only of the node itself, not of the Resources this node uses.

So to not be completely confused and fucked by this issue, you first have to have a really good understanding of what Godot means by "Resource" and how this is different from the node.

Nodes use Resources.

Take a Sprite for example. When we see a graphic in a 2D game most people would call this a Sprite. When in fact what we see is a texture (= Resource) displayed by a Sprite Node. If the user duplicates this Sprite, Godot will create a new Sprite instance from the Sprite class and assign it the same Resource by reference. Meaning the user can change all Sprite properties individually for each Sprite, but as soon as the user fiddles with the Resource of one Sprite, all Sprites will suddenly adopt these changes.

Now for a Sprite using a Texture resource this might be desired behaviour. For a CollisionShape using a Shape resource however, or an AnimationPlayer using an Animation resource, or a Node using a Script resource, ... this might not be desired in the most cases.

The biggest problem Godot has in this regard imho, is the silence. The total lack of transparency and feedback in communicating this to the user via the Editor GUI. You basically have to be an expert Godot user to fully understand this behavior which is very specific to Godot. Would it be more transparent (for example with a giant icon and large fat text next to the resource in the Inspector making it crystal clear this resource is shared or unique, I think this issue would be much less of a problem.

I understand your point of view, but imho your overcomplicate things. There are so many simple solutions and different level of answer for this user's needs.

Level 0 : Explain to the customer in some way how it works when duplicating a node (resource will not be duplicated, but reference will be kept for each node).
Level 1 : Ctrl + D is duplicating the node, ctrl + MAJ + D will duplicate the node AND its ressources. And we can add "Duplicate node and ressources" entry in the sub-menu.
Level 2 : Ability to set default behavior for this feature in the project settings. See this proposal #3072
Level 3 : managing resources for all the nodes of a scene in a pop-in
Level 4 : Add wathever you can imagine ^^

In fact, the issue here is not wether this user's need is relevant or not. Many people are convinced that this IS relevant (but not very critical maybe). It is only a question of wether a developer would like to make any of these modifications above or not, because this project is open source so I guess we just have to wait for a developer to make a small modification to answer this issue.

@maridany1999
Copy link

maridany1999 commented Oct 4, 2023

I came across the same issue while duplicating nodes via code. Duplicating a parent node, especially one with exported variables, retains references from the original parent node, which I consider a bug.

I've observed similar problems in other related issues here in GitHub, where users are confused, negatively impacting the user experience (UX) for some. Currently, I can only see a few practical uses using this behavior. In most software applications, duplicating something typically creates a unique copy.

A potential solution could involve offering two options: "Duplicate as New" and "Duplicate (Use Original References)". This approach would not only help users understand the intended functionality, but also improve the overall UX (similar to the "Duplicate" and "Duplicate Link" function in Blender, but a little different in this case from what I understand).

Edited: Additionally, duplicating a scene (.tscn) via the Scene Window, the same bug will happen, making it difficult for level designers, since the exported variables of the duplicated scene will reference the children of the previous scene duplicated.

Edited Again: The same can happen even if it's a simple node, meaning its NOT only the .tscn; I think my issue here is with the exported variables. The reference of the path node will always reference the previous duplicated node for some reason. I don't think that is intended behaviour. I should probably open a new issue for this?

@CoyanCardenas
Copy link

CoyanCardenas commented Oct 18, 2023

As someone who is new to Godot, I just want to say I've lost many hours of work due to this. It is counter-intuitive to what I believe most new users will expect when they duplicate something. Although there are times when you want shared data between the two - you would never want a script duplicated on two nodes for example - I think the majority of the time the expected behaviour is that a duplication is completely seperate and changes to one wont affect the other.
If I want to have instances, where changes made to the base will affect all instances, I will create a new scene and instantiate that scene, and can see in the editor they are instances. Knowing full well that any change to the base will change all instances, and any change to individual instances only affects that specific instance.
The fact that the current state of things means people can easily and unknowingly lose work, even if they understand how it works but just forget to check local to scene on every single sub resource, is testiment to something needing to be done about this.

@Kalto-Mate
Copy link

I think the biggest offender here is the user being betrayed by terminology. In any other situation when working with a computer, duplicating something with Ctrl + D(uplicate) creates an independent copy of whatever was duplicated.

If I duplicate a document that references external images, I expect edition of font size in the copy to just happen there while those external images remain existing only once. If I duplicate a node tree I expect the resources it may reference to be shared, but not internal settings like bounding size to be entangled. Specially if they are like this silently with no indication about them being connected.

Regardless of the debate about what should be the default, a non-independent copy umbilically connected to it's brothers should absolutely be called an INSTANCE, not a duplicate, and the context menus and even keyboard shortcuts should reflect this nuance. I too have lost work to this intuitiveness and sneaky undisclosed behavior behind my back.

At the very least add a way to quickly make true unconnected duplicates of stuff If we are this dead set on having the main default way be secretly instances but enjoy the term "duplicate"

@JackVania
Copy link

I agree with what everyone else is saying. "Duplicate" does not imply "Instance", "Shared" - it implies a unique copy - because that's literally how everything else works. If we create copies of our applications in various states as forms of backup, we do not expect any changes we make to the current to be applied to the former backup. That is absurd. This isn't even about game engines, this is about consistency of expectation that is shared across multiple pieces of software going back as far as I can remember.

In a DAW if I copy a piano roll and make edits to a single measure, I do not expect those changes to apply to previous piano rolls in earlier measures. No software does this. When you copy or duplicate it becomes its own unique entity. Imagine if Photoshop does this with layers, DAWs do this with edits, NLE's do this with video editing, effects, timeline - mass hysteria.

A LOT of what Godot does changes the game for development in a good way but there's corners here and there that make absolutely no sense in any context you try to give it. An actual "duplicate" as everyone else understands because they've been making duplicates or copy/pasting across multiple pieces of software for decades is the expectation, the current behavior is not and does not improve the workflow in any way, it hinders it.

@Cyan232
Copy link

Cyan232 commented Dec 18, 2023

same here, would it be possible to add a enum DuplicateFlags, to chose if a copy or copy of instance is duplicated ?
https://docs.godotengine.org/en/stable/classes/class_node.html#enum-node-duplicateflags

@pc9098
Copy link

pc9098 commented Jan 2, 2024

image
I'll propose something like this:
Ctrl + Shft + D = Duplicate
Ctrl + D = Independent Duplicate

@PLyczkowski
Copy link

Maybe a popup when duplicating?
image

@Calinou
Copy link
Member

Calinou commented Jan 5, 2024

Maybe a popup when duplicating?

Duplicating is a frequent operation, so I don't think it should spawn a dialog every time you try to duplicate something.

At most, it should display a toast to mention a resource is shared when you duplicate it (specifically if we go for #4672).

@amarraff
Copy link

amarraff commented Jan 11, 2024

I ran into this problem today when working with UI. Users in the Godot Discord were also confused about how to fix it when I asked for help.

I have a "button" scene with a script attached. The script assigns information to the button's labels based on other info in my project. I dragged the button scene into the node hierarchy, and then duplicated it twice. So, there was "button," "button2," and "button3." All three buttons should grab different information and assign it to themselves. On _ready(), my code for all three buttons ran, but applied everything to the labels of "button." Buttons "button2" and "button3" remained blank. This default behavior is extremely confusing. It led to me trying to debug my code, only to realize my code was fine.

Echoing what others here have said, duplication or copy/pasting should not create a linked instance; it should create a unique copy, similar to just dragging the scene into the hierarchy multiple times (which fixed the issue for me. The buttons all grabbed their own information, as expected). Providing a separate button/shortcut for "Make Linked Instance" would alleviate a lot of confusion.

@pc9098
Copy link

pc9098 commented Jan 15, 2024

Since making a new button to create an independent duplicate isn't a popular option
and popping a window where you can select which resources should be unique isn't a popular option
I propose making this option in the editor's option like this:
image
So next time you copy a node you get what you chose in the editor

@amarraff
Copy link

Just ran into another issue that appears to be linked to this issue, with resources. I have two resource types - for simplicity, let's call them apple and pear.

I had an apple in my file system, and I wanted to create a pear. So, I duplicated my apple resource, removed the "apple.gd" script, and added pear.gd. So now, functionally, from the end-user's perspective, it has been converted into a pear.

Unfortunately, when I went to "quick load" the pear resource for an export in the inspector, it wouldn't show up. Only once I deleted the pear, created a new pear resource from scratch, and assigned pear.gd to it, did it finally show up in quick load.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests