81 lines
2.5 KiB
GDScript
81 lines
2.5 KiB
GDScript
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
|