-
-
Notifications
You must be signed in to change notification settings - Fork 21.3k
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
Node duplicate()
doesn't copy internal variables values
#3393
Comments
Related issue but with signals: #1888 |
I'm not sure if this should be a bug or not.. internal state is internal state.. |
@reduz Well I don't know this as well... I'm coming from java world, where default 'clone' method is shallow copy (copying all the values and references), if developer want different behaviour then he is implementing his own clone() method. Don't really know how it's in python world, but as far as I remember it's basically the same (and I think gdscript should follow python convention). |
Also I think that shallow copy is not necessary the best solution since internal node references will point to nodes in original scene... I would solve this by checking if reference is pointing to the node that is on the lower scene level or not (lower from the point of duplicate root are duplicated with deep copy). When it comes to value variables like int or String the situation for me is clear (I think they should be copied). |
I was searching for a bug in my game for quite some time, until I saw this thread and noticed that it wasn't a bug at all... I find the way it is currently done unintuitive. The way it is right now, And it's not about shallow vs. deep copy. A "shallow copy" B of an object A (which is an instance of the un-instanced class C) in most C-like languages means that the member variables of B point to the values of the instance A, not to a copy of the variables of C. If I wanted a new object with the values I hard-coded into C, I simply would make a new instance of C. Which is the equivalent of calling 'preload(S).instance()' in gdscript, at least that's what it seems to me. I would suggest to change the API to the following: N.duplicate(use_instancing=false, deep_duplicate=true) Makes a copy of the instance of N. If Anyway, I would call the method that does what your preload(S) # Returns an un-instanced class
load(S) # This too
File # This is an uninstanced class as well
# To instance a class, call "instance()"
var t = preload(S).instance()
var k = load(S).instance()
f = File.instance() # Instead of new(), for consistency
f.load(xyz)
# And to do this what duplicate currently does:
t.new_instance()
# or
t.get_root_class().instance() # Bad name, but it's about the idea
# This could be used to spawn multiple new nodes of t:
t_root_class = t.get_packed_scene()
for i in range(10):
add_child(t_root_class.instance()) |
Note this comes from Since script variables get only A few solutions come to mind:
|
@bojidar-bg I prefer selective no-storage than having to manually set everything for storage all the time (which may be more error prone), but not sure of the keyword for that. |
duplicate() for nodes is hackish, and not generally recommended. It's there
because some people insists it can be of use, because otherwise i would
have removed it long ago. Using preload().instance() is always the better
choice.
The reason is that some nodes create subnodes (ie, a list creates it's
scrollbars), so a simple duplicate() function has to be able to tell to a
certain degree what to duplicate and what not to duplicate. This is not
always obvious.
Maybe the best it would be to document what the function can actually does,
or just add more flexibility to it, not really sure what you guys prefer.
…On Mon, Jun 12, 2017 at 11:02 AM, eon-s ***@***.***> wrote:
@bojidar-bg <https://github.com/bojidar-bg> I prefer selective no-storage
than having to manually set everything for storage all the time (which may
be more error prone), but not sure of the keyword for that.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#3393 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AF-Z290qBZIy62N7XjfODdHQDbHRhC9Xks5sDUT1gaJpZM4HIicK>
.
|
I currently use
|
@rminderhoud Just do this:
|
Thanks @akien-mga, in that case maybe |
I have different tiles inheriting from a base tile. The other solution is to test which type the node is and instantiate the appropriate packaged scene! This is a use case for Alternative is having one type of tile which will change its behavior depending on some internal state. |
I second the notion that .duplicate() absolutely has many use cases and is a much quicker and easier solution than instancing preloaded scenes. But it would need an improvement to also duplicate children. Or, create an official clone() method which does that, leaving duplicate to make only a shallow copy as it does right now. |
Or add a DuplicateFlags for cloning rather than creating a new method that might make more confusion. |
Couldn't you do something like...
...and you can always debug by writing out the PackedScene with the ResourceSaver? |
It is still misleading name in my opinion. Duplicate mean "duplicate" for me. If I wanted another instance of same class I would just make that instead, even if duplication would be very heavy operation, or loop indefinitely or it would cause some flaw - it's my problem - it still should duplicate 1:1 untill it crashes or finishes this operation. I read docs on duplicate() and DuplicateFlags multiple times, in description there is note, but it don't mention fact that internal states aren't duplicated and it is counterintuitive for me. I'm on older version, but in online docs there is also no mention about it. Perhaps in other languages cloning or duplicates are meant to be shallow copies - but I never wrote in high level programing language and for my primitive mind meaning is clear - it duplicates object. Edit : on the other hand - what you can do is overwrite duplicate() to copy some selected variables. |
I agree that as it is, it's counter-intuitive and I just lost a couple of hours troubleshooting an issue caused by duplicate() not duplicating internal variables. If there's a use-case where internal vars should not be copied, then there should be another DuplicateFlags to set to avoid it. |
Just a quick note, Current logic: List<_NodeReplaceByPair> replace_data;
if (p_keep_data) {
List<PropertyInfo> plist;
get_property_list(&plist);
for (List<PropertyInfo>::Element *E = plist.front(); E; E = E->next()) {
_NodeReplaceByPair rd;
if (!(E->get().usage & PROPERTY_USAGE_STORAGE)) {
continue;
}
rd.name = E->get().name;
rd.value = get(rd.name);
} Notice that _NodeReplaceByPair value for (List<_NodeReplaceByPair>::Element *E = replace_data.front(); E; E = E->next()) {
p_node->set(E->get().name, E->get().value);
} is basically a no-op. |
Cant attach Godot4 reproduction by editing first post (some unknown error), attaching the Godot4 reproduction here: Also to clarify: the issue is about usage of Object.duplicate() method and the fact that variables of returned object (even simple types) are different then in the original one. |
Also my view of this issue has not changed, we should either document it in documentation of duplicate() method or fix it. |
duplicate()
doesn't copy internal variables values
I had the same issue. I had a card game where I wanted to buff some cards and duplicate them. It was frustrating to know that the only way to duplicate the internal states was to manually create a dictionary and copy each variable over to the new card instance. It would be much better to just do card_instance.duplicate() if it also copies the buffs on them. BUT LUCKILY, I found a solution for me that worked. JUST add |
Does it would be the same for SyleBox ressources ? (#80797) I was trying to duplicate some StyleBoxes to change only some limited variables, to make style overrides (like override only background color), but I have an empty ressource instead (so of course draw center is at false). |
Exactly what bit me today, and I found the issue specifically related to duplicating nodes with references to child nodes: It even affects the editor node duplicate: |
This comment was marked as off-topic.
This comment was marked as off-topic.
@ChknNugz Please don't bump without contributing significant new information. Use the 👍 reaction button on the first post instead. |
I hit this issue with a Resource that I had created in code at run-time in GDScript. I just wanted to clone the created Resource - in this case it isn't possible to use For now I just set all the values to be |
Bugsquad edit: This bug has been confirmed several times already. No need to confirm it further.
Duplicate method don't take into account variable values of duplication root as well as internal nodes.
I have prepared small test project that can be used to detect some issues related to duplication:
DuplicateTests.zip
it test various scenarios and report results in output console in the following form:
17.08.2022 UPDATE
I converted test project from Godot1? to Godot4 . I can confirm I still get the same result:
Godot4 reproduction here: #3393 (comment)
Also to clarify: the issue is about usage of Object.duplicate() method and the fact that variables of returned object (even simple types) are different then in the original one.
The text was updated successfully, but these errors were encountered: