class_name MultiplayerClass extends Node const PORT: int = 4516 var peer: ENetMultiplayerPeer = null var players: Dictionary = {} var fuseboxes: int = 0 var playerlist_label: Label = null var entered_username: String = "" ## Host Specific # Hosts server func host_server() -> void: peer = ENetMultiplayerPeer.new() if peer.create_server(PORT) != OK: peer = null return multiplayer.multiplayer_peer = peer if multiplayer.peer_connected.connect(_on_player_joined) != OK: print("Failed to connect signal") if multiplayer.peer_disconnected.connect(_on_player_left) != OK: print("Failed to connect signal") if get_tree().change_scene_to_file("res://ui/lobby.tscn") != OK: print("Failed to change to scene.") _on_player_joined(multiplayer.get_unique_id()) player_username.rpc_id(1, Options.username) # Runs when player joins func _on_player_joined(id: int) -> void: players[id] = { "id": id, "username": "Waiting...", "loaded": false, "hunter": false, "captured": false, "escaped": false, } send_playerlist() # Runs when player leaves func _on_player_left(id: int) -> void: if !players.erase(id): print("Player was never registered!") send_playerlist() # Receives the players username @rpc("any_peer", "call_local", "reliable") func player_username(username: String) -> void: players[multiplayer.get_remote_sender_id()].username = username send_playerlist() # Prepares the label text for the playerlist on the join/host screen func send_playerlist() -> void: var playerlist: String = "" for id: int in players: playerlist += players[id].username playerlist += "\n" update_playerlist.rpc(playerlist) @rpc("any_peer", "call_local", "reliable") func request_playerlist() -> void: if multiplayer.is_server(): send_playerlist() # Switches the scene, and waits until everyone is fully loaded. @rpc("authority", "call_local", "reliable") func switch_scene(path: String) -> void: playerlist_label = null if multiplayer.is_server(): _scene_loaded.rpc_id(1) while true: var loaded: bool = true for id: int in players: if players[id].loaded == false: loaded = false break if loaded: break await get_tree().create_timer(0.1).timeout if get_tree().change_scene_to_file(path) != OK: print("Failed to change to scene.") else: if get_tree().change_scene_to_file(path) != OK: print("Failed to change to scene.") _scene_loaded.rpc_id(1) # Callback to switch_scene from the remote peer @rpc("any_peer", "call_local", "reliable") func _scene_loaded() -> void: if multiplayer.is_server(): players[multiplayer.get_remote_sender_id()].loaded = true func _process(_delta: float) -> void: if multiplayer.multiplayer_peer and multiplayer.is_server() and !players.is_empty(): var lost: bool = true for id: int in players: if !(players[id].captured or players[id].escaped) and !players[id].hunter: lost = false if lost: terminate_multiplayer.rpc() ## Client Specific # Joins a server func join_server(username: String = Options.username, ip_address: String = Options.ip_address) -> void: if !username: username = Options.username if !ip_address: ip_address = Options.ip_address entered_username = username peer = ENetMultiplayerPeer.new() if peer.create_client(ip_address, PORT) != OK: terminate_multiplayer() return multiplayer.multiplayer_peer = peer if multiplayer.connected_to_server.connect(_on_server_joined) != OK: print("Failed to connect signal") if multiplayer.connection_failed.connect(_on_server_join_failed) != OK: print("Failed to connect signal") # After successful join func _on_server_joined() -> void: if get_tree().change_scene_to_file("res://ui/lobby.tscn") != OK: print("Failed to change to scene.") player_username.rpc_id(1, entered_username) # After unsuccessful join func _on_server_join_failed() -> void: terminate_multiplayer() ## Shared # Terminates all Multiplayer functionality. @rpc("authority", "call_local", "reliable") func terminate_multiplayer() -> void: multiplayer.multiplayer_peer = null players = {} fuseboxes = 0 Input.set_mouse_mode(Input.MOUSE_MODE_VISIBLE) if get_tree().change_scene_to_file("res://ui/main_menu.tscn") != OK: print("Failed to change to scene.") # Updates the player list @rpc("authority", "call_local", "reliable") func update_playerlist(list: String) -> void: if playerlist_label != null: playerlist_label.text = list # Adds Fusebox @rpc("authority", "call_local", "reliable") func add_fusebox() -> void: fuseboxes += 1 # Removes Fusebox @rpc("authority", "call_local", "reliable") func remove_fusebox() -> void: fuseboxes -= 1