class_name PlayerSpawnService extends Node const PlayerScene: PackedScene = preload("res://player/player.tscn") signal avatar_spawned(peer_id: int, avatar: Player) signal avatar_removed(peer_id: int) var _players_root: Node3D var _local_player: Player var _spawn_transform: Transform3D var _avatars: Dictionary[int, Player] = {} var _local_peer_id: int = 1 func setup( players_root: Node3D, local_player: Player, spawn_transform: Transform3D, ) -> void: _players_root = players_root _local_player = local_player _spawn_transform = spawn_transform func register_local_player(peer_id: int) -> void: if _local_player == null: return for existing_id: int in _avatars.keys(): if _avatars[existing_id] == _local_player: _avatars.erase(existing_id) _local_peer_id = peer_id _avatars[peer_id] = _local_player _local_player.name = "Player_%d" % peer_id _local_player.set_local_control(true) _local_player.set_network_peer_id(peer_id) func spawn_remote_player( peer_id: int, transform: Transform3D, authoritative_simulation: bool = false, ) -> Player: if peer_id <= 0 or peer_id == _local_peer_id: return null var existing: Player = _avatars.get(peer_id) if existing != null and is_instance_valid(existing): return existing var avatar := PlayerScene.instantiate() as Player avatar.name = "Player_%d" % peer_id avatar.set_local_control(false) avatar.set_network_peer_id(peer_id) _players_root.add_child(avatar) avatar.global_transform = transform avatar.configure_network_remote(authoritative_simulation) _avatars[peer_id] = avatar avatar_spawned.emit(peer_id, avatar) return avatar func remove_peer(peer_id: int) -> void: if peer_id == _local_peer_id: return var avatar: Player = _avatars.get(peer_id) _avatars.erase(peer_id) if avatar != null and is_instance_valid(avatar): avatar.queue_free() avatar_removed.emit(peer_id) func clear_remote_players() -> void: for peer_id: int in _avatars.keys(): if peer_id != _local_peer_id: remove_peer(peer_id) func get_avatar(peer_id: int) -> Player: return _avatars.get(peer_id) func set_peer_presentation_visible(peer_id: int, should_be_visible: bool) -> void: var avatar: Player = _avatars.get(peer_id) if avatar != null and is_instance_valid(avatar): avatar.set_remote_presentation_visible(should_be_visible) func get_peer_ids() -> Array[int]: var result: Array[int] = [] for peer_id: int in _avatars: result.append(peer_id) result.sort() return result func get_spawn_transform_for_index(index: int) -> Transform3D: if index <= 0: return _spawn_transform var angle: float = float(index) * 2.3999632297 var ring: float = 1.4 + floor(float(index - 1) / 8.0) * 1.2 var result: Transform3D = _spawn_transform result.origin += Vector3(cos(angle) * ring, 0.0, sin(angle) * ring) return result