# This file is part of open-fpsz. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . class_name Multiplayer extends Node @export_category("Parameters") @export var MAP : PackedScene @export var PLAYER : PackedScene @export var FLAG : PackedScene @export var MAX_CLIENTS : int = 24 @export var RESPAWN_TIME : float = 3.0 @onready var players : Node = $Players @onready var objectives : Node = $Objectives @onready var map : Node = $Map @onready var scoreboard : Scoreboard = $Scoreboard @onready var scoreboard_ui : Node = $ScoreboardUI var _map_manager : Map var _flag : Flag var _flag_carrier_scoring_timer : Timer = Timer.new() signal connected_to_server signal connection_failed func _ready() -> void: _flag_carrier_scoring_timer.wait_time = 10.0 _flag_carrier_scoring_timer.timeout.connect(_on_flag_carrier_scoring_timer_timeout) add_child(_flag_carrier_scoring_timer) func start_server(port : int, nickname : String) -> void: var peer : ENetMultiplayerPeer = ENetMultiplayerPeer.new() peer.create_server(port, MAX_CLIENTS) multiplayer.multiplayer_peer = peer _load_map.call_deferred(MAP, nickname) multiplayer.peer_disconnected.connect(remove_player) func join_server(host : String, port : int, nickname : String) -> void: var peer : ENetMultiplayerPeer = ENetMultiplayerPeer.new() peer.create_client(host, port) multiplayer.connected_to_server.connect(_on_connected_to_server.bind(nickname)) multiplayer.connection_failed.connect(_on_connection_failed) multiplayer.multiplayer_peer = peer func _on_connected_to_server(nickname : String) -> void: connected_to_server.emit() scoreboard.request_scoreboard_from_authority.rpc() _join_match.rpc(nickname) func _on_connection_failed() -> void: connection_failed.emit() func _on_player_died(player : Player, killer_id : int) -> void: if player.player_id != killer_id: var node_name : String = str(killer_id) if players.has_node(node_name): var killer : Player = players.get_node(node_name) scoreboard.increment_kill_count(killer) scoreboard.add_score_to_player(killer, 10) scoreboard.broadcast_player_score_update(killer) await get_tree().create_timer(RESPAWN_TIME).timeout respawn_player(player) func respawn_player(player : Player) -> void: var spawn_location : Vector3 = _map_manager.get_player_spawn().position player.respawn(spawn_location) func add_player(peer_id : int, nickname : String) -> void: var player : Player = PLAYER.instantiate() player.name = str(peer_id) player.player_id = peer_id player.nickname = nickname player.global_position = _map_manager.get_player_spawn().position players.add_child(player) player.died.connect(_on_player_died) scoreboard.add_entry(player) print("Peer `%s` connected" % player.name) func remove_player(peer_id : int) -> void: var node_name : String = str(peer_id) if players.has_node(node_name): var player : Player = players.get_node(node_name) scoreboard.remove_entry(player) player.die(-1) player.queue_free() print("Peer `%s` disconnected" % node_name) func _load_map(scene : PackedScene, nickname : String) -> void: var map_scene : Node = scene.instantiate() _map_manager = map_scene map_scene.ready.connect(_add_flag) if DisplayServer.get_name() != "headless": add_player(1, nickname) map.add_child(map_scene) func _add_flag() -> void: _flag = FLAG.instantiate() _flag.grabbed.connect(_on_flag_grabbed) _flag.dropped.connect(_on_flag_dropped) _flag.global_position = _map_manager.get_flagstand().global_position objectives.add_child(_flag) func _unhandled_input(event : InputEvent) -> void: if event.is_action_pressed("scoreboard"): var entries : Array = scoreboard.get_entries() for entry : Scoreboard.ScoreboardEntry in entries: var entry_label : Label = Label.new() entry_label.text = "%s | kills: %s | score: %s" % [entry.nickname, entry.kills, entry.score] %Scores.add_child(entry_label) scoreboard_ui.show() elif event.is_action_released("scoreboard"): scoreboard_ui.hide() for score_label in %Scores.get_children(): score_label.queue_free() @rpc("any_peer") func _join_match(nickname : String) -> void: if is_multiplayer_authority(): add_player(multiplayer.get_remote_sender_id(), nickname) func _on_flag_grabbed(grabber : Player) -> void: scoreboard.add_score_to_player(grabber, 10) scoreboard.broadcast_player_score_update(grabber) _flag_carrier_scoring_timer.start() func _on_flag_dropped() -> void: _flag_carrier_scoring_timer.stop() func _on_flag_carrier_scoring_timer_timeout() -> void: scoreboard.add_score_to_player(_flag.last_carrier, 10) scoreboard.broadcast_player_score_update(_flag.last_carrier) func _exit_tree() -> void: if is_multiplayer_authority(): multiplayer.peer_disconnected.disconnect(remove_player)