2025-07-18 19:32:37 +01:00
|
|
|
class_name MultiplayerClass
|
|
|
|
extends Node
|
|
|
|
|
|
|
|
const PORT: int = 4516
|
|
|
|
|
|
|
|
var peer: ENetMultiplayerPeer = null
|
2025-08-08 10:57:42 +02:00
|
|
|
var players: Dictionary = {}
|
2025-07-31 13:57:50 +02:00
|
|
|
var fuseboxes: int = 0
|
|
|
|
|
|
|
|
var playerlist_label: Label = null
|
2025-07-18 19:32:37 +01:00
|
|
|
|
2025-08-08 10:57:42 +02:00
|
|
|
var entered_username: String = ""
|
|
|
|
|
2025-07-18 19:32:37 +01:00
|
|
|
## Host Specific
|
|
|
|
|
|
|
|
# Hosts server
|
|
|
|
func host_server() -> void:
|
|
|
|
peer = ENetMultiplayerPeer.new()
|
|
|
|
if peer.create_server(PORT) != OK:
|
|
|
|
peer = null
|
|
|
|
return
|
|
|
|
multiplayer.multiplayer_peer = peer
|
2025-08-08 10:57:42 +02:00
|
|
|
|
2025-07-18 19:32:37 +01:00
|
|
|
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")
|
2025-08-08 10:57:42 +02:00
|
|
|
|
|
|
|
if get_tree().change_scene_to_file("res://ui/lobby.tscn") != OK:
|
|
|
|
print("Failed to change to scene.")
|
|
|
|
|
2025-07-18 19:32:37 +01:00
|
|
|
_on_player_joined(multiplayer.get_unique_id())
|
2025-08-08 10:57:42 +02:00
|
|
|
player_username.rpc_id(1, Options.username)
|
2025-07-18 19:32:37 +01:00
|
|
|
|
|
|
|
# Runs when player joins
|
|
|
|
func _on_player_joined(id: int) -> void:
|
2025-08-08 10:57:42 +02:00
|
|
|
players[id] = {
|
2025-07-18 19:32:37 +01:00
|
|
|
"id": id,
|
2025-08-08 10:57:42 +02:00
|
|
|
"username": "Waiting...",
|
2025-07-18 19:32:37 +01:00
|
|
|
"loaded": false,
|
|
|
|
"hunter": false,
|
2025-07-31 13:57:50 +02:00
|
|
|
"captured": false,
|
|
|
|
"escaped": false,
|
2025-08-08 10:57:42 +02:00
|
|
|
}
|
2025-07-31 13:57:50 +02:00
|
|
|
|
|
|
|
send_playerlist()
|
2025-07-18 19:32:37 +01:00
|
|
|
|
|
|
|
# Runs when player leaves
|
|
|
|
func _on_player_left(id: int) -> void:
|
2025-08-08 10:57:42 +02:00
|
|
|
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
|
2025-07-31 13:57:50 +02:00
|
|
|
send_playerlist()
|
|
|
|
|
|
|
|
# Prepares the label text for the playerlist on the join/host screen
|
|
|
|
func send_playerlist() -> void:
|
|
|
|
var playerlist: String = ""
|
|
|
|
|
2025-08-08 10:57:42 +02:00
|
|
|
for id: int in players:
|
|
|
|
playerlist += players[id].username
|
2025-07-31 13:57:50 +02:00
|
|
|
playerlist += "\n"
|
|
|
|
|
|
|
|
update_playerlist.rpc(playerlist)
|
2025-07-18 19:32:37 +01:00
|
|
|
|
2025-08-08 10:57:42 +02:00
|
|
|
@rpc("any_peer", "call_local", "reliable")
|
|
|
|
func request_playerlist() -> void:
|
|
|
|
if multiplayer.is_server():
|
|
|
|
send_playerlist()
|
|
|
|
|
2025-07-18 19:32:37 +01:00
|
|
|
# Switches the scene, and waits until everyone is fully loaded.
|
|
|
|
@rpc("authority", "call_local", "reliable")
|
|
|
|
func switch_scene(path: String) -> void:
|
2025-07-31 13:57:50 +02:00
|
|
|
playerlist_label = null
|
2025-07-18 19:32:37 +01:00
|
|
|
if multiplayer.is_server():
|
|
|
|
_scene_loaded.rpc_id(1)
|
|
|
|
while true:
|
|
|
|
var loaded: bool = true
|
2025-08-08 10:57:42 +02:00
|
|
|
for id: int in players:
|
|
|
|
if players[id].loaded == false:
|
2025-07-18 19:32:37 +01:00
|
|
|
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():
|
2025-08-08 10:57:42 +02:00
|
|
|
players[multiplayer.get_remote_sender_id()].loaded = true
|
2025-07-18 19:32:37 +01:00
|
|
|
|
2025-07-31 13:57:50 +02:00
|
|
|
func _process(_delta: float) -> void:
|
|
|
|
if multiplayer.multiplayer_peer and multiplayer.is_server() and !players.is_empty():
|
|
|
|
var lost: bool = true
|
2025-08-08 10:57:42 +02:00
|
|
|
for id: int in players:
|
|
|
|
if !(players[id].captured or players[id].escaped) and !players[id].hunter:
|
2025-07-31 13:57:50 +02:00
|
|
|
lost = false
|
|
|
|
if lost:
|
|
|
|
terminate_multiplayer.rpc()
|
|
|
|
|
2025-07-18 19:32:37 +01:00
|
|
|
## Client Specific
|
|
|
|
|
|
|
|
# Joins a server
|
2025-08-08 10:57:42 +02:00
|
|
|
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
|
|
|
|
|
2025-07-18 19:32:37 +01:00
|
|
|
peer = ENetMultiplayerPeer.new()
|
2025-08-08 10:57:42 +02:00
|
|
|
if peer.create_client(ip_address, PORT) != OK:
|
|
|
|
terminate_multiplayer()
|
2025-07-18 19:32:37 +01:00
|
|
|
return
|
|
|
|
multiplayer.multiplayer_peer = peer
|
2025-08-08 10:57:42 +02:00
|
|
|
|
|
|
|
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()
|
2025-07-18 19:32:37 +01:00
|
|
|
|
|
|
|
## Shared
|
|
|
|
|
|
|
|
# Terminates all Multiplayer functionality.
|
2025-07-31 13:57:50 +02:00
|
|
|
@rpc("authority", "call_local", "reliable")
|
2025-07-18 19:32:37 +01:00
|
|
|
func terminate_multiplayer() -> void:
|
|
|
|
multiplayer.multiplayer_peer = null
|
2025-08-08 10:57:42 +02:00
|
|
|
players = {}
|
2025-07-31 13:57:50 +02:00
|
|
|
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
|
2025-08-08 10:57:42 +02:00
|
|
|
|
|
|
|
# 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
|