Skip to content

Support spawning a prefab of a NetworkObject that has child NetworkObjects (make re-parenting more consistent in Netcode projects) #2700

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

Open
zachstronaut opened this issue Sep 13, 2023 · 7 comments
Labels
type:feature New feature, request or improvement

Comments

@zachstronaut
Copy link

It's possible to have scene objects where a parent NetworkObject has children that are also NetworkObjects. This is particularly notable, because it allows you to re-parent some other NetworkObject onto that nested child NetworkObject in the scene.

When you spawn a prefab of a NetworkObject into the scene, you can only re-parent to the top level of that spawned NetworkObject -- the GameObject that directly has a NetworkObject component -- but none of its children.

This leads to us programmers having to deal with potentially two different code pathways for when a prefab was placed in a scene vs when a prefab was spawned. In some cases we may even have to split prefabs because of this... one that can be placed in scenes and one that can be spawned.

Besides the re-parenting use case, this limitation also gets in the way of modular/nested prefabs in your project. You cannot have a re-usable nested prefab module that is itself spawnable, because then you would not be able to use it on any prefabs that are spawnable themselves.

@zachstronaut zachstronaut added stat:awaiting-triage Status - Awaiting triage from the Netcode team. type:feature New feature, request or improvement labels Sep 13, 2023
@BrotherLavarius
Copy link

^ this tbh

@SubatomicPlanets
Copy link

Yes I need this too. I am making a simple VR multiplayer game. I need to parent objects to the hands when the player picks something up. I could spawn the hands separately but that complicates everything. Right now I have my own parenting system but it's far from perfect. Netcode for GameObjects recently got a lot of improvements to parenting. This is the only thing that's missing for me.

@michalChrobot
Copy link
Collaborator

Hey, it seems that the fix was included in #3013, can you confirm it? Otherwise I will be closing this thread soon-ish

@SubatomicPlanets
Copy link

@michalChrobot
I believe this issue is about nested Network Objects in prefabs (which would greatly help when parenting stuff). #3013 has a lot of improvements in the parenting system but I can't find anything on nested Network Objects being allowed now (please correct me if I'm wrong). #2645 would fix this issue as far as I know.

@michalChrobot
Copy link
Collaborator

Aa, ok, thanks for the information! I will try to follow up on this then

@marcusx2
Copy link

marcusx2 commented Mar 31, 2025

Please. This is a long overdue feature. It's the biggest pain point of netcode for gameobjects. It should be available on the first version. I don't understand how this is not a priority.

@michalChrobot michalChrobot added stat:reply-needed Awaiting reply from Unity account and removed stat:awaiting-triage Status - Awaiting triage from the Netcode team. labels Apr 1, 2025
@NoelStephensUnity
Copy link
Collaborator

Just following up regarding network prefabs with nested NetworkObjects.

The primary issue involved with this has to do with "network prefabs" being associated with a NetworkObject's GlobalObjectIdHash value. There are complexities that revolve around late joining client synchronization (especially if any of the child NetworkObjects are deparented from the root NetworkObject).

A NetworkObject really has a few primary functions:

  • Used to identify a "network thing" that translates to a registered network prefab.
  • Used to identify message routing.
    • The NetworkObjectId is the root part of the destination "address". So, the full "network" address translates down to:
      • Client/server being sent a message associated with a spawned NetworkObject
      • The NetworkObjectId of the spawned NetworkObject.
      • Then the associated NetworkBehaviourId of the final NetworkBehaviour that the message is targeting (i.e. RPCs, NetworkVariables, and NetworkTransforms).
        • As well as notifications for change in ownership and parenting.

Other than this, all of the real "netcode" is handled in NetworkBehaviours which you can have as many NetworkBehaviours nested on child GameObjects under the root prefab GameObject that you want. They will all be associated with the NetworkObject, but you gain nothing other than have a "pre-parented" network prefab. There are a myriad of other internal areas that would need to be refactored for this as well. Not to say it cannot be done, but there is the question as to "why"?

The primary voiced opinion is that it would simplify parenting of NetworkObjects, but we really need to think about what is accomplished when parenting a NetworkObject and the associated thing to contemplate is whether there is a benefit to having a single network prefab with several NetworkObjects in a nested hierarchy =or= is it better to have a single NetworkObject with nested NetworkBehaviours?

The answer to the second part above is that having several NetworkObjects parented under a root network prefab NetworkObject will:

  • Increase the over-all serialization size when instantiating and spawning the network prefab.
  • Each associated NetworkBehaviour nested under each NetworkObject requires a unique message to handle NetworkBehaviour messages.
  • Tracking the relative hierarchy position of each NetworkObject will need to be included.
    • This includes either having to force the NetworkObject parenting rule within the "complex" network prefab where you couldn't have say the Root NetworkObject, a standard GameObject child, and then under that child a NetworkObject on a 2nd generation child GameObject.
    • We could create a "hierarchy" component that provides a way to associate "non-NetworkObject" GameObject, but now either we have to do a depth analysis of the hierarchy and properly (automatically) place these "hierarchy" components on each instance or require you to do this... which starts to become a bit more complicated of a process..
      - (there are several other related issues, but the general idea is there is a lot involved in this kind of approach)

So, this lands us back to what are the benefits of having "complex" network prefabs where there are multiple NetworkObject components of equal or different generation positioning (within the hierarchy)? This really leads me to the more pertinent question as to "what is the benefit of parenting"?

Parenting NetworkObjects (Uses/Benefits)
The primary use cases are things like items to pickup, vehicles, platforms, and things of this nature. There is no benefit of having a single network prefab that has multiple NetworkObjects nested underneath it unless you plan on pulling apart the parenting....as in each NetworkObject represents its own unique "network prefab" that is pertinent in a useful way.

What do we mean by "useful"?

If you have a vehicle that you want to start a player within upon first spawning, this would be "useful" but is it really needed?

When a NetworkObject is spawned, it becomes aware of all NetworkBehaviours within its hierarchy. So, you could have something like this:

  • (Root: "Player + Vehicle") GameObject + NetworkObject + NetworkBehaviours
    • (Child-A: "Vehicle") GameObject + NetworkBehaviours
      • (Child-B: "Vehicle") GameObject + NetworkBehaviours
        • (Child-C: "Player") GameObject + NetworkBehaviours

Where some of the NetworkBehaviour components would be NetworkTransform components and at the Root one of the NetworkBehaviours is a "Player Controller" that simply points to one of the children under the Root.

If you wanted to remove the player from the vehicle you would:

  • Remove Child-C''s parent from its transform (i.e. Child-B)
  • Point the "Player Controller" to Child-C

Now a player's input is controlling the player and the player is no longer parented under the Root. Of course, today you would have to write your own components that use NetworkVariables that track where each child is parented.

  • Child-A could use a NetworkObjectReference or NetworkBehaviour reference.
  • Child-B would most likely just use a NetworkBehaviour reference.
  • Child-C would most likely just use a NetworkBehaviour reference.

Then you would need to make any late joining players check those references to determine if the Children are still under their default parent, have no parent, or are parented under something else. Of course, upon despawning all children would make sure they were parented under their original parent.

The message routing for a player that "got out of their vehicle" would still work...you could chose to change the NetworkTransform of Child-C to be in world space or keep it in local space (as long as the vehicle couldn't be moved by a collision or another player could jump into it and drive off that would make sense...otherwise you would want it to transition into world space).

Of course, if the player's vehicle could be destroyed then this makes no sense...and under that scenario you would want two unique network prefabs... a Player and a Vehicle and would just want to spawn both at the same time (i.e. the player could point to their Vehicle which would automatically spawn it and parent the player under it).

However, the big take away is that you can also have things like:

A weapon item: that can be in-scene placed or randomly spawned at different locations:

  • (Root: "Weapon Item") GameObject + NetworkObject + NetworkTransform
    • (Child-A: "Weapon") GameObject + NetworkBehaviours + Components (visuals)
      The root of the weapon item is for world placement/spawning and (if your game/project allows for it) the ability to "kick around" the weapon or drop the weapon at a different location.

The player:

  • (Root: "Player") GameObject + NetworkObject + NetworkBehaviours
    • (Child-A: "Root Player") GameObject + NetworkBehaviours + Components (visuals)
      • (Child-B: "Player Toso") GameObject
      • (Child-C: "Player Arm") GameObject
        • (Child-D: "Player Hand") GameObject
          • (Child-E: "Player Hand Item Position Node) GameObject

The player (only a small portion...I gave it no head or legs..) is just laid out in a normal fashion with a position to attach a weapon or item being carried.

To "pickup" the weapon you can opt to parent the entire Root "Weapon Item" =or= you can simply use the same technique described earlier and just parent the Weapon Item's Child-A under the Player's Child-E (normal unity parenting) with (of course) some form of component or added script that handles setting the Weapon's Child-A GameObject to having been parented under the Player's Child-E (i.e. so late joining clients would synchronize based on the NetworkVariable's set value when spawning the weapon item and the player.

Using NetworkObject parenting today is the "easiest" but can result in issues with things like handling smooth transitions between parenting and making sure the NetworkTransform's synchronize (all can take time sorting out that side of things) =or= you can use the "Child with NetworkBehaviours" approch but that requires you to write the additional script to handle the assignment of the parented NetworkBehaviour and assure late joining clients properly synchronize... both have pro's and con's...

With this said... the "rules" behind parenting a "Child of a spawned network prefab instance" are that it requires tracking "who its parent is"... but nothing else...it uses standard unity parenting...and can make it less complicated in regards to NetworkTransform since the Weapon's Child-A would have no NetworkTransform... it would just synchronize to the player's hand's motion. The rules behind NetworkObject parenting...well.. it requires you parent directly under another NetworkObject and there are additional complexities there.

So, our near future plan is to provide a component that automatically handles the "Child with NetworkBehaviour(s)" parenting side of things (well it will provide the basic aspects of it with the ability to make your own version for custom solutions) which (I believe) will be a better "fix" for the issue behind not begin able to have "complex network prefabs".

When will this component be avaiable? As soon as possible...but we also want to address other foundational issues in NGO (v2.3.0 contains some improvements to the BufferedLinearInterpolator which provides you with two new interpolation types and the ability to modify aspects of them via NetworkTransform).

But... we are primarily focused on providing an over-all continually improved netcode development experience...and have not forgotten about this specific user pain (and are taking actions to provide something that, we believe, will yield a better over-all result for everyone).

@github-actions github-actions bot added stat:awaiting-response Awaiting response from author. This label should be added manually. and removed stat:reply-needed Awaiting reply from Unity account labels Apr 4, 2025
@michalChrobot michalChrobot removed the stat:awaiting-response Awaiting response from author. This label should be added manually. label Apr 10, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type:feature New feature, request or improvement
Projects
None yet
Development

No branches or pull requests

6 participants