From 11e8ce0e48615924aad7817694cd30fdd2f35b42 Mon Sep 17 00:00:00 2001 From: darshadi Date: Wed, 14 Oct 2020 15:03:33 -0400 Subject: [PATCH] add netcode --- src/scenes/ui/playgame.tscn | 53 +++++----- src/scripts/network.gd | 205 ++++++++++++++++++++++++++++++++++-- src/scripts/playgame.gd | 30 ++++-- 3 files changed, 246 insertions(+), 42 deletions(-) diff --git a/src/scenes/ui/playgame.tscn b/src/scenes/ui/playgame.tscn index a458dd12..65c7b996 100644 --- a/src/scenes/ui/playgame.tscn +++ b/src/scenes/ui/playgame.tscn @@ -2,8 +2,6 @@ [ext_resource path="res://scripts/playgame.gd" type="Script" id=1] - - [node name="PlayGame" type="VBoxContainer"] margin_left = 59.0 margin_top = 34.0 @@ -16,39 +14,46 @@ script = ExtResource( 1 ) __meta__ = { "_edit_use_anchors_": false } +Back = NodePath("Back") +JoinGameDialog = NodePath("JoinGameDialog") +HostnameField = NodePath("JoinGameDialog/JoinGameOptions/HostnameLine/HostnameField") +PortField = NodePath("JoinGameDialog/JoinGameOptions/Port/PortField") +CreatePortField = NodePath("CreateGameDialog/CreateGameOptions/PortLine/PortField") +CreateGameDialog = NodePath("CreateGameDialog") +main = "res://scenes/main.tscn" [node name="Tutorial" type="Button" parent="."] margin_right = 640.0 -margin_bottom = 20.0 +margin_bottom = 28.0 disabled = true text = "TUTORIAL" flat = true [node name="JoinGame" type="Button" parent="."] -margin_top = 36.0 +margin_top = 44.0 margin_right = 640.0 -margin_bottom = 56.0 +margin_bottom = 72.0 text = "JOIN GAME" flat = true [node name="CreateGame" type="Button" parent="."] -margin_top = 72.0 +margin_top = 88.0 margin_right = 640.0 -margin_bottom = 92.0 +margin_bottom = 116.0 text = "CREATE GAME" flat = true [node name="Back" type="Button" parent="."] -margin_top = 108.0 +margin_top = 132.0 margin_right = 640.0 -margin_bottom = 128.0 +margin_bottom = 160.0 text = "BACK" flat = true [node name="JoinGameDialog" type="WindowDialog" parent="."] -margin_top = 144.0 +margin_top = 176.0 margin_right = 640.0 -margin_bottom = 301.0 +margin_bottom = 243.0 size_flags_vertical = 3 window_title = "JOIN_GAME" resizable = true @@ -68,42 +73,42 @@ __meta__ = { [node name="HostnameLine" type="HBoxContainer" parent="JoinGameDialog/JoinGameOptions"] margin_right = 608.0 -margin_bottom = 24.0 +margin_bottom = 32.0 [node name="Hostname" type="Label" parent="JoinGameDialog/JoinGameOptions/HostnameLine"] margin_top = 5.0 -margin_right = 66.0 -margin_bottom = 19.0 +margin_right = 74.0 +margin_bottom = 27.0 text = "Hostname" [node name="HostnameField" type="LineEdit" parent="JoinGameDialog/JoinGameOptions/HostnameLine"] -margin_left = 70.0 +margin_left = 78.0 margin_right = 608.0 -margin_bottom = 24.0 +margin_bottom = 32.0 size_flags_horizontal = 3 text = "localhost" [node name="Port" type="HBoxContainer" parent="JoinGameDialog/JoinGameOptions"] -margin_top = 28.0 +margin_top = 36.0 margin_right = 608.0 -margin_bottom = 52.0 +margin_bottom = 68.0 [node name="Port" type="Label" parent="JoinGameDialog/JoinGameOptions/Port"] margin_top = 5.0 -margin_right = 26.0 -margin_bottom = 19.0 +margin_right = 30.0 +margin_bottom = 27.0 text = "Port" [node name="PortField" type="LineEdit" parent="JoinGameDialog/JoinGameOptions/Port"] -margin_left = 30.0 +margin_left = 34.0 margin_right = 608.0 -margin_bottom = 24.0 +margin_bottom = 32.0 size_flags_horizontal = 3 [node name="Connect" type="Button" parent="JoinGameDialog/JoinGameOptions"] -margin_top = 56.0 +margin_top = 72.0 margin_right = 608.0 -margin_bottom = 76.0 +margin_bottom = 100.0 text = "CONNECT" [node name="CreateGameDialog" type="WindowDialog" parent="."] diff --git a/src/scripts/network.gd b/src/scripts/network.gd index bdd78e5e..c3fb313b 100644 --- a/src/scripts/network.gd +++ b/src/scripts/network.gd @@ -1,11 +1,196 @@ extends Node -enum Connection { - LOCAL, # Local only game, tutorial - DEDICATED_SERVER, # Server only, no local client - CLIENT_SERVER, # Server with a local player - CLIENT # Client only, remote server -} - -var connection = Connection.LOCAL -var host: String = '' -var port: int = 0 + +# Default game port. Can be any number between 1024 and 49151. +const DEFAULT_PORT = 10567 + +# Max number of players. +const MAX_PEERS = 10 + +var peer = null + +# Name for my player. +var player_name = "The Warrior" + +# Names for remote players in id:name format. +var players = {} +var players_ready = [] + +# Signals to let lobby GUI know what's going on. +signal player_list_changed() +signal connection_failed() +signal connection_succeeded() +signal game_ended() +signal game_error(what) + +# Callback from SceneTree. +func _player_connected(id): + # Registration of a client beings here, tell the connected player that we are here. + rpc_id(id, "register_player", player_name) + + +# Callback from SceneTree. +func _player_disconnected(id): + if has_node("/root/World"): # Game is in progress. + if get_tree().is_network_server(): + emit_signal("game_error", "Player " + players[id] + " disconnected") + end_game() + else: # Game is not in progress. + # Unregister this player. + unregister_player(id) + + +# Callback from SceneTree, only for clients (not server). +func _connected_ok(): + # We just connected to a server + emit_signal("connection_succeeded") + + +# Callback from SceneTree, only for clients (not server). +func _server_disconnected(): + emit_signal("game_error", "Server disconnected") + end_game() + + +# Callback from SceneTree, only for clients (not server). +func _connected_fail(): + get_tree().set_network_peer(null) # Remove peer + emit_signal("connection_failed") + + +# Lobby management functions. + +remote func register_player(new_player_name): + var id = get_tree().get_rpc_sender_id() + print(id) + players[id] = new_player_name + emit_signal("player_list_changed") + + +func unregister_player(id): + players.erase(id) + emit_signal("player_list_changed") + + +remote func pre_start_game(spawn_points): + # Change scene. + var world = load("res://world.tscn").instance() + get_tree().get_root().add_child(world) + + get_tree().get_root().get_node("Lobby").hide() + + var player_scene = load("res://player.tscn") + + for p_id in spawn_points: + var spawn_pos = world.get_node("SpawnPoints/" + str(spawn_points[p_id])).position + var player = player_scene.instance() + + player.set_name(str(p_id)) # Use unique ID as node name. + player.position=spawn_pos + player.set_network_master(p_id) #set unique id as master. + + if p_id == get_tree().get_network_unique_id(): + # If node for this peer id, set name. + player.set_player_name(player_name) + else: + # Otherwise set name from peer. + player.set_player_name(players[p_id]) + + world.get_node("Players").add_child(player) + + # Set up score. + world.get_node("Score").add_player(get_tree().get_network_unique_id(), player_name) + for pn in players: + world.get_node("Score").add_player(pn, players[pn]) + + if not get_tree().is_network_server(): + # Tell server we are ready to start. + rpc_id(1, "ready_to_start", get_tree().get_network_unique_id()) + elif players.size() == 0: + post_start_game() + + +remote func post_start_game(): + get_tree().set_pause(false) # Unpause and unleash the game! + + +remote func ready_to_start(id): + assert(get_tree().is_network_server()) + + if not id in players_ready: + players_ready.append(id) + + if players_ready.size() == players.size(): + for p in players: + rpc_id(p, "post_start_game") + post_start_game() + + +func host_game(new_player_name): + player_name = new_player_name + peer = NetworkedMultiplayerENet.new() + peer.create_server(DEFAULT_PORT, MAX_PEERS) + get_tree().set_network_peer(peer) + + +func join_game(ip, new_player_name): + player_name = new_player_name + peer = NetworkedMultiplayerENet.new() + peer.create_client(ip, DEFAULT_PORT) + get_tree().set_network_peer(peer) + + +func get_player_list(): + return players.values() + + +func get_player_name(): + return player_name + + +func begin_game(): + assert(get_tree().is_network_server()) + + # Create a dictionary with peer id and respective spawn points, could be improved by randomizing. + var spawn_points = {} + spawn_points[1] = 0 # Server in spawn point 0. + var spawn_point_idx = 1 + for p in players: + spawn_points[p] = spawn_point_idx + spawn_point_idx += 1 + # Call to pre-start game with the spawn points. + for p in players: + rpc_id(p, "pre_start_game", spawn_points) + + pre_start_game(spawn_points) + + +func end_game(): + if has_node("/root/World"): # Game is in progress. + # End it + get_node("/root/World").queue_free() + + emit_signal("game_ended") + players.clear() + + +func _ready(): + get_tree().connect("network_peer_connected", self, "_player_connected") + get_tree().connect("network_peer_disconnected", self,"_player_disconnected") + get_tree().connect("connected_to_server", self, "_connected_ok") + get_tree().connect("connection_failed", self, "_connected_fail") + get_tree().connect("server_disconnected", self, "_server_disconnected") + + + +#extends Node +#enum Connection { +# LOCAL, # Local only game, tutorial +# DEDICATED_SERVER, # Server only, no local client +# CLIENT_SERVER, # Server with a local player +# CLIENT # Client only, remote server +#} +# +#var connection = Connection.LOCAL +#var host: String = '' +#var port: int = 0 +# diff --git a/src/scripts/playgame.gd b/src/scripts/playgame.gd index 9bf110da..f98bcb1b 100644 --- a/src/scripts/playgame.gd +++ b/src/scripts/playgame.gd @@ -1,22 +1,36 @@ extends VBoxContainer +export (NodePath) var Back = "" +export (NodePath) var JoinGameDialog = "" +export (NodePath) var HostnameField = "" +export (NodePath) var PortField = "" +export (NodePath) var CreatePortField = "" +export (NodePath) var CreateGameDialog = "" +export (String, FILE, "*.tscn") var main = "" + func _ready(): - $Back.connect("pressed", get_node(".."), "_on_Return") + Back = get_node(Back) + JoinGameDialog = get_node(JoinGameDialog) + HostnameField = get_node(HostnameField) + PortField = get_node(PortField) + CreatePortField = get_node(CreatePortField) + CreateGameDialog = get_node(CreateGameDialog) + Back.connect("pressed", get_node(".."), "_on_Return") func _on_JoinGame_pressed(): - $JoinGameDialog.popup() + JoinGameDialog.popup() func _on_Connect_pressed(): Network.connection = Network.Connection.CLIENT - Network.host = $JoinGameDialog/JoinGameOptions/HostnameLine/HostnameField.text - Network.port = $JoinGameDialog/JoinGameOptions/Port/PortField.text - get_tree().change_scene("res://scenes/main.tscn") + Network.host = HostnameField.text + Network.port = PortField.text + get_tree().change_scene(main) func _on_Create_pressed(): Network.connection = Network.Connection.CLIENT_SERVER Network.host = 'localhost' - Network.port = $CreateGameDialog/CreateGameOptions/PortLine/PortField.text - get_tree().change_scene("res://scenes/main.tscn") + Network.port = PortField.text + get_tree().change_scene(main) func _on_CreateGame_pressed(): - $CreateGameDialog.popup() + CreateGameDialog.popup()