Runtime Re-parenting

GONet supports runtime re-parenting of networked objects -- attaching a GONetParticipant to another at runtime (e.g., picking up items, mounting vehicles, attaching weapons). The system handles transform sync suspension, physics state management, and position guards automatically.

How It Works

When you call SetParent() on a GONetParticipant's transform, GONet detects the change via OnTransformParentChanged() and publishes a ReparentGONetParticipantEvent to all clients.

// Pick up an item — attach it to the player's hand
item.transform.SetParent(player.handBone);
item.transform.localPosition = Vector3.zero;
item.transform.localRotation = Quaternion.identity;

// Drop the item — detach from parent
item.transform.SetParent(null);

GONet handles the rest: publishing the reparent event, suspending transform sync on the child, managing physics state, and ensuring late-joiners see the correct hierarchy.

Transform Sync Suspension

When a GONetParticipant is reparented under another syncing GONetParticipant, the child's position and rotation sync is automatically suspended. This prevents the child's world-space sync from fighting with the parent's transform sync.

  • Only transform sync is suspended -- All other synced values (health, ammo, custom fields) continue syncing normally.
  • Automatic resume on detach -- When the child is unparented, transform sync resumes automatically.
  • Configurable -- Controlled by EnableTransformSyncSuspensionForNestedGNPs (default: true).

Position Guard

When a child is attached to a parent, GONet stores the intended local offset and re-enforces it every frame. This prevents the child from drifting due to sync or blending applying stale world-space values.

  • Automatic -- Enabled by default via EnableReparentPositionGuard.
  • Per-instance opt-out -- Set disableReparentPositionGuard = true on instances that need to move relative to their parent (e.g., turrets that rotate).
  • Dynamic updates -- Call UpdateReparentGuardValues() to update the stored offset when the child's local position changes intentionally (e.g., turret rotation, attachment point changes).

Physics Auto-Management

When a child GONetParticipant has a Rigidbody, GONet automatically manages its physics state during reparenting:

On Attach

  • • Rigidbody set to kinematic
  • • Gravity disabled
  • • Original state saved for restoration

On Detach

  • • Original kinematic state restored
  • • Original gravity state restored
  • • Transform sync resumes

Controlled by AutoKinematicOnTransformSyncSuspension (default: true). See the Physics Synchronization page for more detail.

Client Drop Fix

When a client drops an object (detaches from parent), there is a brief window where the server's stale position could override the client's accurate drop position. GONet provides MarkLocalDropInitiated() to capture the client's position before sending the drop RPC, ensuring the object appears at the correct location.

Late-Joiner Support

Reparent events are persistent -- they are stored and replayed for clients that join mid-game. A late-joiner will see the correct parent-child hierarchy without any additional synchronization logic.

  • Self-cancellation -- If an object is reparented back to its original parent (a no-op), the reparent event is suppressed to avoid unnecessary replay.
  • Pending queues -- If a reparent event arrives before the target parent exists on the client, it is queued with a 30-second timeout and applied when the parent appears.

Configuration

SettingDefaultDescription
EnableTransformSyncSuspensionForNestedGNPstrueSuspend child transform sync when parented
AutoKinematicOnTransformSyncSuspensiontrueAuto-manage Rigidbody kinematic state
EnableReparentPositionGuardtrueGuard against local position drift
ReparentAutoPublishDelayFrames1Frames to delay before publishing reparent
MaxReparentsPerSecondPerAuthority10Rate limit per authority
PendingReparentTimeoutSeconds30Timeout for pending reparent events

Design-Time Limitation

Important: Nesting GONetParticipants at design time (in the prefab hierarchy) is not supported. Always spawn objects independently and call SetParent() at runtime. Design-time nesting causes multiple known issues with GONetId assignment, sync ordering, and despawn propagation.

Next Steps

Runtime Re-parenting | GONet Docs