127 lines
3.7 KiB
GDScript
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)))
|