Chelimbalo/scripts/multiplayer/lobby.gd
2025-11-30 02:54:34 +05:00

168 lines
4.6 KiB
GDScript

extends Node
const MAX_PLAYERS: int = 10
const PORT: int = 7777
signal lobby_created
signal lobby_joined
signal lobby_closed
signal update_teams_state
var in_lobby: bool = false
var attack_team: Array[int] = []
var defence_team: Array[int] = []
var specators_team: Array[int] = []
var validated_players = []
var win_score = 13
var half_rounds = 12
var client_hash: String = ""
const CHUNK_SIZE = 1024
func _ready() -> void:
multiplayer.peer_disconnected.connect(player_left)
multiplayer.server_disconnected.connect(server_disconnected)
multiplayer.peer_connected.connect(add_and_sync_peer)
multiplayer.connected_to_server.connect(send_validation)
var ctx = HashingContext.new()
ctx.start(HashingContext.HASH_SHA256)
var file = FileAccess.open(OS.get_executable_path(),FileAccess.READ)
while file.get_position() < file.get_length():
var remaining = file.get_length() - file.get_position()
ctx.update(file.get_buffer(min(remaining,CHUNK_SIZE)))
client_hash = ctx.finish().hex_encode()
func player_left(id: int) -> void:
if attack_team.has(id):
attack_team.erase(id)
elif defence_team.has(id):
defence_team.erase(id)
elif specators_team.has(id):
specators_team.erase(id)
update_teams_state.emit()
func server_disconnected() -> void:
leave()
func host() -> void:
var peer: ENetMultiplayerPeer = ENetMultiplayerPeer.new()
peer.create_server(PORT,MAX_PLAYERS)
multiplayer.multiplayer_peer = peer
lobby_created.emit()
specators_team.append(multiplayer.get_unique_id())
in_lobby = true
multiplayer.peer_connected.connect(check_player_hash)
multiplayer.peer_disconnected.connect(on_player_left)
func check_player_hash(id: int):
if multiplayer.is_server():
get_tree().create_timer(1).timeout.connect(kick_untrustworthy.bind(id))
func on_player_left(id: int):
if multiplayer.is_server():
if validated_players.has(id):
validated_players.erase(id)
func kick_untrustworthy(id: int):
if multiplayer.is_server() and validated_players.has(id) == false:
multiplayer.disconnect_peer(id)
@rpc("any_peer","call_remote","reliable")
func validate_hash(sender_hash: StringName):
if multiplayer.is_server() == false:
return
if client_hash == sender_hash:
validated_players.append(multiplayer.get_remote_sender_id())
func send_validation():
validate_hash.rpc_id(1,client_hash)
func join(ip: String) -> Error:
var peer: ENetMultiplayerPeer = ENetMultiplayerPeer.new()
var res = peer.create_client(ip,PORT)
if res != 0:
return res
multiplayer.multiplayer_peer = peer
lobby_joined.emit()
in_lobby = true
return Error.OK
func leave() -> void:
if multiplayer.is_server():
multiplayer.peer_connected.disconnect(check_player_hash)
multiplayer.multiplayer_peer = OfflineMultiplayerPeer.new()
attack_team.clear()
defence_team.clear()
specators_team.clear()
lobby_closed.emit()
in_lobby = false
func add_and_sync_peer(id: int) -> void:
if multiplayer.is_server() == false:
return
specators_team.append(id)
update_teams_state.emit()
set_teams.rpc_id(id,attack_team,defence_team,specators_team)
@rpc("any_peer","call_remote","reliable")
func set_teams(attack: Array[int],defence: Array[int],spectators: Array[int]):
attack_team = attack
defence_team = defence
specators_team = spectators
update_teams_state.emit()
func switch_team(team: int) -> void:
team_switch_notification.rpc(multiplayer.get_unique_id(),team)
@rpc("any_peer","call_local","reliable")
func team_switch_notification(id: int, team: int) -> void:
if (team == Session.TEAMS.DEFENCE and len(defence_team) > 4) or (team == Session.TEAMS.ATTACK and len(attack_team) > 4):
return
if team == Session.TEAMS.DEFENCE:
if attack_team.has(id):
attack_team.erase(id)
if specators_team.has(id):
specators_team.erase(id)
defence_team.append(id)
if team == Session.TEAMS.ATTACK:
if defence_team.has(id):
defence_team.erase(id)
if specators_team.has(id):
specators_team.erase(id)
attack_team.append(id)
if team == Session.TEAMS.SPECTATE:
if attack_team.has(id):
attack_team.erase(id)
elif defence_team.has(id):
defence_team.erase(id)
specators_team.append(id)
update_teams_state.emit()
@rpc("authority","call_local","reliable")
func start_game() -> void:
get_tree().change_scene_to_file("res://levels/prototype_scene.tscn")
if multiplayer.is_server():
await get_tree().scene_changed
Session.start_session()
func get_team() -> Session.TEAMS:
var id = multiplayer.get_unique_id()
if attack_team.has(id):
return Session.TEAMS.ATTACK
if defence_team.has(id):
return Session.TEAMS.DEFENCE
if specators_team.has(id):
return Session.TEAMS.SPECTATE
return Session.TEAMS.UNASSIGNED