class_name NetPickable extends Node ## Networks an XRToolsPickable (RigidBody3D). Default authority is the server, ## which simulates free items and syncs their transform. Grabbing an item with a ## hand transfers authority to the grabbing client (its local kinematic grab ## driver then drives the synced transform); releasing returns authority and the ## throw velocity to the server. Non-authority peers keep the body frozen and ## follow the synced transform, so only one machine ever simulates an item. @onready var _item: XRToolsPickable = get_parent() as XRToolsPickable var net_held_by := 0 # peer id currently holding (0 = free); kept consistent via NetworkManager var _was_authority := true func _ready() -> void: if not _item: push_error("NetPickable must be a child of an XRToolsPickable") return _item.grabbed.connect(_on_grabbed) _item.released.connect(_on_released) _was_authority = _item.is_multiplayer_authority() _apply_authority_state() func _physics_process(_delta: float) -> void: if not NetworkManager.is_online(): return var mine := _item.is_multiplayer_authority() if mine != _was_authority: _was_authority = mine _apply_authority_state() # Configure physics for whether we own this item or merely mirror it. func _apply_authority_state() -> void: if not _item: return if _item.is_multiplayer_authority(): # We own physics: simulate the item whenever it is not held. if not _item.is_picked_up(): _item.freeze = false else: # Someone else owns it: follow the synced transform kinematically. _item.freeze = true _item.freeze_mode = RigidBody3D.FREEZE_MODE_KINEMATIC func _on_grabbed(_pickable: Node3D, by: Node3D) -> void: if not NetworkManager.is_online(): return # Only hand grabs transfer authority; snap-zone grabs are server-driven. if not (by is XRToolsFunctionPickup): return NetworkManager.request_item_authority.rpc_id(1, _item.get_path()) func _on_released(_pickable: Node3D, by: Node3D) -> void: if not NetworkManager.is_online(): return if not (by is XRToolsFunctionPickup): return NetworkManager.release_item_authority.rpc_id(1, _item.get_path(), _item.linear_velocity, _item.angular_velocity)