extends Node3D ## One instance per connected peer. The owning peer is the multiplayer ## authority. The local (authority) player builds the full XR rig from ## XROrigin.tscn and feeds its head/hand poses into synced properties; remote ## players show a lightweight avatar driven by those synced poses. const RIG_SCENE := preload("res://XROrigin.tscn") # Synced avatar pose. Authority writes these from the XR trackers each frame; # remotes read them onto the Avatar. net_heartbeat is a monotonic counter used # to confirm replication is live (also handy for debugging). @export var head_xform: Transform3D = Transform3D.IDENTITY @export var left_xform: Transform3D = Transform3D.IDENTITY @export var right_xform: Transform3D = Transform3D.IDENTITY @export var net_heartbeat: int = 0 var _rig: Node3D var _camera: Node3D var _left: Node3D var _right: Node3D var _is_local := false @onready var _avatar: Node3D = $Avatar @onready var _avatar_head: Node3D = $Avatar/Head @onready var _avatar_left: Node3D = $Avatar/LeftHand @onready var _avatar_right: Node3D = $Avatar/RightHand func _enter_tree() -> void: # The spawner names each player by its owning peer id. set_multiplayer_authority(str(name).to_int()) # (replication config is authored in Player.tscn's MultiplayerSynchronizer) func _ready() -> void: _is_local = is_multiplayer_authority() if _is_local: _setup_local() else: _setup_remote() if Engine.has_singleton("NetworkManager") or get_node_or_null("/root/NetworkManager"): NetworkManager.log_line("Player %s ready (authority=%d local=%s)" % [name, get_multiplayer_authority(), str(_is_local)]) func _setup_local() -> void: # We see through the headset; hide our own avatar mesh. _avatar.visible = false _rig = RIG_SCENE.instantiate() add_child(_rig) _camera = _rig.get_node_or_null("XRCamera3D") _left = _rig.get_node_or_null("XRControllerLeftHand") _right = _rig.get_node_or_null("XRControllerRightHand") _enable_xr() func _enable_xr() -> void: var xr := XRServer.find_interface("OpenXR") if xr and xr.is_initialized(): get_viewport().use_xr = true DisplayServer.window_set_vsync_mode(DisplayServer.VSYNC_DISABLED) func _setup_remote() -> void: _avatar.visible = true func _process(_delta: float) -> void: if _is_local: if _camera: head_xform = _camera.global_transform left_xform = _left.global_transform right_xform = _right.global_transform net_heartbeat += 1 else: _avatar_head.global_transform = head_xform _avatar_left.global_transform = left_xform _avatar_right.global_transform = right_xform