Files
algodoogle 4e6c645938 fix bug
2026-07-16 22:23:33 +01:00

127 lines
3.7 KiB
GDScript

extends Node3D
## World manager. Owns the multiplayer spawners and the world-space main menu,
## and turns NetworkManager's session events into spawned/despawned players and
## seeded items.
##
## Startup:
## - Command-line session (--server/--join): skip the menu, behave headlessly.
## - Otherwise: embody a local player (so they can point) and show the menu; the
## Host/Join/Solo buttons start the actual session.
const PLAYER_SCENE := preload("res://Player/Player.tscn")
const CUBE_SCENE := "res://Items/PickupCube.tscn"
@onready var _players_spawner: MultiplayerSpawner = $PlayersSpawner
@onready var _items_spawner: MultiplayerSpawner = $ItemsSpawner
@onready var _menu: Node3D = $NetworkMenu
func _ready() -> void:
NetworkManager.register_world(self, _players_spawner, _items_spawner)
NetworkManager.player_joined.connect(_on_player_joined)
NetworkManager.player_left.connect(_on_player_left)
NetworkManager.session_started.connect(_on_session_started)
NetworkManager.connection_failed.connect(_on_connection_failed)
NetworkManager.session_ended.connect(_on_session_ended)
_menu.host_pressed.connect(_on_menu_host)
_menu.join_pressed.connect(_on_menu_join)
_menu.solo_pressed.connect(_on_menu_solo)
# Start any command-line driven session now that we are listening.
NetworkManager.world_ready()
if NetworkManager.is_online():
# Command-line session: no menu.
_menu.hide_menu()
if _owns_spawning():
_spawn_starting_items()
else:
# Show the menu; embody a local player so they can point at it.
_spawn_player(1)
_menu.show_menu()
# --- Menu button handlers --------------------------------------------------
func _on_menu_host() -> void:
_menu.hide_menu()
NetworkManager.host() # keeps the already-spawned local player (id 1)
_spawn_starting_items()
func _on_menu_solo() -> void:
_menu.hide_menu()
_spawn_starting_items()
func _on_menu_join(ip: String) -> void:
_menu.set_status("Connecting to %s ..." % ip)
# Our placeholder id "1" belongs to the host once we join; drop it and let
# the server spawn our real player.
_despawn_player(1)
NetworkManager.join(ip)
func _on_session_started(is_server: bool) -> void:
if not is_server:
# Connected to a host as a client.
_menu.hide_menu()
# Stations are server-authoritative: clients must not run snap zones, or
# they create divergent local copies of snapped items.
_disable_client_snap_zones()
func _on_connection_failed() -> void:
_menu.set_status("Connection failed — check the IP")
_spawn_player(1) # restore embodiment
_menu.show_menu()
# The client lost the server (or left): reload the scene to return to a clean
# main-menu state.
func _on_session_ended() -> void:
get_tree().reload_current_scene.call_deferred()
func _disable_client_snap_zones() -> void:
for station in get_tree().get_nodes_in_group("station"):
var zone = station.get_node_or_null("XRToolsSnapZone")
if zone:
zone.enabled = false
# --- Player / item spawning ------------------------------------------------
func _on_player_joined(peer_id: int) -> void:
if NetworkManager.is_server():
_spawn_player(peer_id)
func _on_player_left(peer_id: int) -> void:
if NetworkManager.is_server():
_despawn_player(peer_id)
func _spawn_player(peer_id: int) -> void:
if has_node(str(peer_id)):
return
var p := PLAYER_SCENE.instantiate()
p.name = str(peer_id)
add_child(p)
func _despawn_player(peer_id: int) -> void:
var n := get_node_or_null(str(peer_id))
if n:
n.queue_free()
func _owns_spawning() -> bool:
return not NetworkManager.is_online() or NetworkManager.is_server()
func _spawn_starting_items() -> void:
NetworkManager.spawn_item(CUBE_SCENE, Transform3D(Basis(), Vector3(-0.705, 1.576, -1.032)))
NetworkManager.spawn_item(CUBE_SCENE, Transform3D(Basis(), Vector3(0.283, 1.561, -1.066)))