fix: Instantiate() behavior for Prefab and Entity references#2914
fix: Instantiate() behavior for Prefab and Entity references#2914Eideren merged 5 commits intostride3d:masterfrom
Conversation
|
Another nasty issue I just found which would be fixed by this PR, when your prefabs contain a circular reference like in the following case: Prefab#0:
Entity#0:
Component#0:
MyPrefab: ref to Prefab#0Instantiating this prefab returns the following hierarchy Entity#1:
Component#1:
MyPrefab: ref to Prefab#1
Prefab#1:
Entity#1:
...Surprise ! The very same entity that was just instantiated and is now part of the scene ! |
|
How do you even find these issues? 🙂 |
|
That's my secret ;) |
|
I'll have to check manually for that one. Reading from my phone doesn't compute in my head. Just to be sure, this doesn't break nested prefabs and archetypes (at design time)? Or copy/pasting a prefab in the asset explorer? |
|
@Kryptos-FR Have a look at the new test I setup, might make more sense to read through that than my nonsense :) |
Forgot to answer, nope, it does not :P Do you have time to take a quick look at this one ? |
|
I'll try early next week, it's late today. |
Kryptos-FR
left a comment
There was a problem hiding this comment.
Looks ok to me.
However I discovered a regression in the editor regarding copy/pasting nested prefabs. That regression doesn't seem related to this fix (I could reproduce it with earlier version), but it didn't occur in Stride 4.0. I'll investigate more to find where the regression was introduced and try to apply your fix to a version without the regression to figure out if there are other potential regressions hidden by that one.
| /// <param name="prefab">The prefab to clone.</param> | ||
| /// <returns>A cloned prefab</returns> | ||
| public static Prefab Clone(Prefab prefab) | ||
| public static List<Entity> Instantiate(Prefab prefab) |
There was a problem hiding this comment.
Maybe update the documentation since the method name has changed.
| cloneSerializerSelector = new SerializerSelector(true, false, "Default", "Clone"); | ||
| } | ||
|
|
||
| if (entitySerializerSelector == null) |
There was a problem hiding this comment.
nit: simplify with the ??= operator.
| { | ||
| public required Prefab Prefab { get; set; } | ||
| public required Entity ExternalEntityRef { get; set; } | ||
| /*public required TransformComponent ExternalComponentRef { get; set; }*/ |
There was a problem hiding this comment.
Add a comment around the commented out code to explain why it is kept around (maybe reference the issue/PR id as well).
|
Took care of the review - I think we can merge this fix regardless of the regression you mentioned ? If this specific change ends up compromising that regression we can always modify it through the PR for that regression ? |
|
Yes, it looks the bug is related to copy/paste processors and unlikely to be affected by this change. |
| /// <summary> | ||
| /// Clones the specified prefab. | ||
| /// <see cref="Entity"/>, children <see cref="Entity"/> and their <see cref="EntityComponent"/> will be cloned. | ||
| /// Instantiate the content of the prefab provided. |
There was a problem hiding this comment.
nit: Instantiate**s** method comments are in third-person by convention
Kryptos-FR
left a comment
There was a problem hiding this comment.
Aside from the latest nit-picking, looks good to me.
|
Done, thanks for the review @Kryptos-FR ! |
commit aaae940 Merge: ee81d20 325a7fa Author: xen2 <virgile@stride3d.net> Date: Thu Oct 23 18:22:23 2025 +0900 Merge pull request stride3d#1664 from vvvv/dev/joreg/add-touch-to-winforms Adds touch support to Winforms based GameForm commit ee81d20 Author: Eideren <contact@eideren.com> Date: Wed Oct 22 16:18:35 2025 +0200 fix: Instantiate() behavior for Prefab and Entity references (stride3d#2914) commit 325a7fa Merge: 77e2101 82f7fae Author: joreg <joreg@vvvv.org> Date: Wed Oct 22 11:13:44 2025 +0200 Merge branch 'dev/joreg/add-touch-to-winforms' of https://github.com/vvvv/stride into dev/joreg/add-touch-to-winforms commit 77e2101 Author: joreg <joreg@vvvv.org> Date: Wed Oct 22 11:13:35 2025 +0200 fixed potentially problematic cast commit 82f7fae Author: joreg <joreg@vvvv.org> Date: Wed Oct 22 11:12:19 2025 +0200 Update sources/engine/Stride.Games/Desktop/GameForm.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> commit 1956f70 Author: joreg <joreg@vvvv.org> Date: Tue Oct 21 14:37:15 2025 +0200 Update sources/engine/Stride.Input/Windows/PointerWinforms.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> commit 2c1bc62 Author: joreg <joreg@vvvv.org> Date: Tue Oct 14 15:22:12 2025 +0200 Touch position is now normalized 0..1 like in other implementations commit 13d11c8 Merge: c73271b b74a54d Author: joreg <joreg@vvvv.org> Date: Tue Oct 14 14:05:36 2025 +0200 Merge branch 'master' into dev/joreg/add-touch-to-winforms commit c73271b Author: joreg <joreg@vvvv.org> Date: Thu May 18 13:03:58 2023 +0200 PointerSDL now uses GetFingerId() from baseclass (to be in line with Winforms implementation) commit 4ab9f70 Author: joreg <joreg@vvvv.org> Date: Thu May 18 13:03:10 2023 +0200 add touch support for Winforms based GameForm
(cherry picked from commit ee81d20)
|
I have created #2953 to track the regression I mentioned earlier (which is not caused by this PR). |
PR Details
Prefab instantiation clones the prefab itself and returns only its content, changed it so that prefab clones its list of entities and returns that.
There doesn't seem to be that much of a difference initially, but let's dive deeper:
When cloning an object through
EntityCloner, the engine, for a given property it will do one of two thingsIt does so depending on the type of the object and some other misc logic.
For objects that are fully cloned, like our Prefab, the system keeps track of the newly created object to swap any other references it finds in component properties that point to the source object by our newly created clone of that object.
Meaning that if the prefab contains a component that has a prefab property pointing to that same prefab, after cloning, the property would now point to the newly created clone of the prefab instead of the original prefab.
This may seem like expected behavior, until you consider the fact that
Instantiate()does not return a new prefab, but a list of entities instead.Entity References
The other part of this PR is to ensure that references in components to
Entitythat lay outside the hierarchy are not cloned. Instantiation is about cloning a hierarchy under an entity, not every entity ever referenced in the components of said entity.I would have liked to include
EntityComponentreferences too, but I couldn't fit them in yet, it requires a larger amount of change I'm not as confident wouldn't break users game, but at least this time around it will throw an exception in that case instead of duplicating the reference.The reason it's not as simple is because
EntityComponentdo not have a specific serializer, we would need one that derive fromDataContentSerializerWithReuse, the serializer forTransformComponentderives from a simpleDataSerializerfor example.Also refactored a test which used a goto for no good reason. Don't get me wrong, I like gotos, but using it here just doesn't make sense.
Related Issue
Couldn't find any.
Types of changes
Checklist