From d81e1430845762344dfc5fffa7a86eba418e1c0f Mon Sep 17 00:00:00 2001 From: Luna Date: Mon, 5 Mar 2018 00:44:45 -0500 Subject: [PATCH 01/41] Move to new server --- scripts/lobby.gd | 5 +---- util/server.sh | 2 +- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/scripts/lobby.gd b/scripts/lobby.gd index 1c25097..0f600fb 100644 --- a/scripts/lobby.gd +++ b/scripts/lobby.gd @@ -1,10 +1,7 @@ extends "res://scripts/args.gd" -# class member variables go here, for example: -# var a = 2 -# var b = "textvar" var SERVER_PORT = 54672 -var MAX_PLAYERS = 10 +var MAX_PLAYERS = 50 var player_info = {} var my_info = {} diff --git a/util/server.sh b/util/server.sh index 9959782..d172ca6 100644 --- a/util/server.sh +++ b/util/server.sh @@ -1,2 +1,2 @@ -godot-server -level=2 -silent -server -start-game +godot -level=2 -silent -server -start-game From 535916ad825effc55e04ca944384353c92327b8e Mon Sep 17 00:00:00 2001 From: Luna Date: Sun, 6 May 2018 22:39:27 -0400 Subject: [PATCH 02/41] [Hero 5] Increase portal cost to 75 --- README.md | 8 ++++++-- plans.md | 1 + scenes/heroes/5.tscn | 2 +- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index f0aa270..3fb58c8 100644 --- a/README.md +++ b/README.md @@ -27,14 +27,17 @@ Current heroes: - CARITAS (Margarine) - SUPERBIA (Build portals) -Ideas for Heroes: +Ideas for Heroes / Abilities: - More active - - Blink (Tracer) - no cooldown, but loses all speed on hitting walls + - Blink (like tracer) costs charge - Heavy guy - Slow, but very heavy for the see-saw - Climb and glide abilities - JUMPING - More supportive + - Switch places with a TEAMMATE + - This is awesomely self-regulating because it's zero-sum + - However, it can't really gain charge because it can still be abused - Boost - Area of effect or zarya-like cast, speeds people up - Flop - Changes side of see-saw for each team (should it be mechanic instead??) - Build - Build Zineth-like rails for anyone to use @@ -42,6 +45,7 @@ Ideas for Heroes: - (Combine with LUSSURIA?) Hook and swing on terrain - More offensive - Lay traps + - Freeze a hero. A teammate of that hero must unfreeze them! (Or *n* seconds or whatever) - (Combine with PAZIENZA?) Destroy buildings - (Combine wit LUSSURIA?) Hold, then release to explode enemies away diff --git a/plans.md b/plans.md index e127ec1..88f1138 100644 --- a/plans.md +++ b/plans.md @@ -8,6 +8,7 @@ Big TODOs: - ^ I think you need more abilities for heroes, that combine well - Like, you could combine PAZIENZA with [destroys buildings] - Start making maps and figuring out what works / what you like + - Make just one new main level with the lessons you've learned from this one - I'd love to do a payload map! - More platforming for everyone (It's industria only rn tbh) - Give portals a tilted wall to fuck with acceleration diff --git a/scenes/heroes/5.tscn b/scenes/heroes/5.tscn index 1b5507c..3a57297 100644 --- a/scenes/heroes/5.tscn +++ b/scenes/heroes/5.tscn @@ -30,7 +30,7 @@ margin_left = -160.0 margin_top = -112.0 margin_right = -149.0 margin_bottom = -103.0 -cost = 20 +cost = 75 ability_name = "Build Portal" action = "hero_5_place_portal" From 16aec4ae32d8848748985f8e849534f78b5299e0 Mon Sep 17 00:00:00 2001 From: Luna Date: Mon, 7 May 2018 19:22:22 -0400 Subject: [PATCH 03/41] [WIP] Begin dummy matchmaking code --- scripts/lobby.gd | 24 +++++++++++++++------ scripts/matchmaking.gd | 57 ++++++++++++++++++++++++++++++++++++++++++++++++++ util/matchmaker.sh | 1 + 3 files changed, 76 insertions(+), 6 deletions(-) create mode 100644 scripts/matchmaking.gd create mode 100644 util/matchmaker.sh diff --git a/scripts/lobby.gd b/scripts/lobby.gd index 4f37dc1..faca79f 100644 --- a/scripts/lobby.gd +++ b/scripts/lobby.gd @@ -3,8 +3,7 @@ extends "res://scripts/args.gd" # class member variables go here, for example: # var a = 2 # var b = "textvar" -var SERVER_PORT = 54672 -var MAX_PLAYERS = 10 +var port = null # Defined by command-line argument with default var player_info = {} var my_info = {} @@ -14,13 +13,17 @@ var global_server_ip = "nv.cosinegaming.com" var players_done = [] var is_connected = false # Technically this can be done with ENetcetera but it's easier this way +onready var matchmaking = preload("res://scripts/matchmaking.gd").new() + func setup_options(): var opts = Options.new() opts.set_banner(('A non-violent MOBA inspired by Overwatch and Zineth')) opts.add('-singleplayer', false, 'Whether to run singeplayer, starting immediately') opts.add('-server', false, 'Whether to run as server') + opts.add('-matchmaker', false, 'Whether to be the sole matchmaker') opts.add('-client', false, 'Immediately connect as client') opts.add('-silent', false, 'If the server is not playing, merely serving') + opts.add('-port', 54672, 'The port to run a server on or connect to') opts.add('-hero', 'r', 'Your choice of hero (index)') opts.add('-level', 'r', 'Your choice of level (index) - server only!') opts.add('-start-game', false, 'Join as a client and immediately start the game') @@ -39,6 +42,8 @@ func option_sel(button_name, option): func _ready(): + add_child(matchmaking) + my_info.version = [0,0,0] # Semantic versioning: [0].[1].[2] randomize() @@ -66,8 +71,12 @@ func _ready(): option_sel("CustomGame/LevelSelect", o.get_value("-level")) if o.get_value("-server"): call_deferred("_server_init") + if o.get_value("-matchmaker"): + call_deferred("_matchmaker_init") if o.get_value("-client"): call_deferred("_client_init") + if o.get_value("-port"): + port = o.get_value("-port") if o.get_value("-start-game"): my_info.start_game = true call_deferred("_client_init") @@ -94,14 +103,14 @@ func _client_init(ip=null): if not ip: ip = get_node("CustomGame/IP").get_text() ip = IP.resolve_hostname(ip) - peer.create_client(ip, SERVER_PORT) + peer.create_client(ip, port) get_tree().set_network_peer(peer) get_node("CustomGame/Client").set_text("Clienting!") func _singleplayer_init(): collect_info() var peer = NetworkedMultiplayerENet.new() - peer.create_server(SERVER_PORT, 1) + peer.create_server(port, 1) get_tree().set_network_peer(peer) player_info[1] = my_info start_game() @@ -109,7 +118,7 @@ func _singleplayer_init(): func _server_init(): collect_info() var peer = NetworkedMultiplayerENet.new() - peer.create_server(SERVER_PORT, MAX_PLAYERS) + peer.create_server(port, matchmaking.SERVER_SIZE) get_tree().set_network_peer(peer) is_connected = true get_node("CustomGame/Server").set_text("Serving!") @@ -117,6 +126,9 @@ func _server_init(): if server_playing: player_info[1] = my_info +func _matchmaker_init(): + matchmaking.run_matchmaker() + func _player_connected(id): pass @@ -167,7 +179,7 @@ remote func register_player(new_peer, info): rpc_id(1, "begin_player_deferred", new_peer) # Spawning is deferred var assign_right_team = right_team_count * 2 < player_info.size() rpc("assign_team", new_peer, assign_right_team) - if not begun and player_info.size() == MAX_PLAYERS: + if not begun and player_info.size() == matchmaking.SERVER_SIZE: start_game() if begun: rpc_id(new_peer, "pre_configure_game", my_info.level) diff --git a/scripts/matchmaking.gd b/scripts/matchmaking.gd new file mode 100644 index 0000000..f4e5916 --- /dev/null +++ b/scripts/matchmaking.gd @@ -0,0 +1,57 @@ +extends Node + +var SERVER_TO_SERVER_PORT = 54671 +var MATCHMAKING_PORT = 54672 +var SERVER_SIZE = 6 + +var next_port = 54673 + +# Filled with queue info which contains +# { "netid" } +var queue = [] +var skirmish +# To avoid the confusion of the gameSERVERS being CLIENTS, +# we just call them games whenever possible +var games = [] +var game_connections = [] +var game_streams = [] + +# Matchmaker to game servers +var matchmaker_to_games + +func _ready(): + set_process(false) + +func run_matchmaker(): + skirmish = spawn_server() + matchmaker_to_games = TCP_Server.new() + if matchmaker_to_games.listen(SERVER_TO_SERVER_PORT): + print("Error, could not listen") + set_process(true) + +func _process(delta): + # Manage connection to GAMESERVERS (not clients) + if matchmaker_to_games.is_connection_available(): # check if a gameserver's trying to connect + var game = matchmaker_to_games.take_connection() # accept connection + game_connections.append(game) # store the connection + var stream = PacketPeerStream.new() + stream.set_stream_peer(game) # bind peerstream to new client + game_streams.append(stream) # make new data transfer object for game + print("Server has requested connection") + +master func _queue(info): + queue.push(info) + check_queue() + +func check_queue(): + if queue.size() >= SERVER_SIZE: + var port = spawn_server() + games.push(port) + for p in queue: + rpc_id(p.netid, "join_game", port) + +func spawn_server(): + OS.execute("util/server.sh", [], false) + next_port += 1 + return (next_port - 1) # Return original port + diff --git a/util/matchmaker.sh b/util/matchmaker.sh new file mode 100644 index 0000000..1fb5897 --- /dev/null +++ b/util/matchmaker.sh @@ -0,0 +1 @@ +godot-server -matchmaker From 97b09048a977947a5d53fa512bd7a58107d4fd87 Mon Sep 17 00:00:00 2001 From: Luna Date: Mon, 7 May 2018 19:49:33 -0400 Subject: [PATCH 04/41] Make -start-game work on server as well --- scripts/lobby.gd | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scripts/lobby.gd b/scripts/lobby.gd index 4f37dc1..c2e5b47 100644 --- a/scripts/lobby.gd +++ b/scripts/lobby.gd @@ -70,7 +70,6 @@ func _ready(): call_deferred("_client_init") if o.get_value("-start-game"): my_info.start_game = true - call_deferred("_client_init") if o.get_value("-singleplayer"): call_deferred("_singleplayer_init") if o.get_value("-ai"): @@ -116,6 +115,8 @@ func _server_init(): get_node("JoinedGameLobby").show() if server_playing: player_info[1] = my_info + if "start_game" in my_info and my_info.start_game: + start_game() func _player_connected(id): pass From 1443eb110767b3927aea75ca3321530f045ef5ce Mon Sep 17 00:00:00 2001 From: Luna Date: Mon, 7 May 2018 19:51:36 -0400 Subject: [PATCH 05/41] Make matchmaker start true server without errors i.e., it still doesn't actually do any matchmaking. But it runs the actual server without errors. --- scripts/matchmaking.gd | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/scripts/matchmaking.gd b/scripts/matchmaking.gd index f4e5916..d0d2653 100644 --- a/scripts/matchmaking.gd +++ b/scripts/matchmaking.gd @@ -8,7 +8,7 @@ var next_port = 54673 # Filled with queue info which contains # { "netid" } -var queue = [] +var skirmishing_players = [] var skirmish # To avoid the confusion of the gameSERVERS being CLIENTS, # we just call them games whenever possible @@ -39,15 +39,17 @@ func _process(delta): game_streams.append(stream) # make new data transfer object for game print("Server has requested connection") -master func _queue(info): - queue.push(info) +master func queue(info): + var netid = get_tree().get_rpc_sender_id() + rpc_id(netid, "join_game", skirmish) + skirmishing_players.push(netid) check_queue() func check_queue(): - if queue.size() >= SERVER_SIZE: + if skirmishing_players.size() >= SERVER_SIZE: var port = spawn_server() games.push(port) - for p in queue: + for p in skirmishing_players: rpc_id(p.netid, "join_game", port) func spawn_server(): From 8f5a8417e1313efc932cf7c0d9f841431e897f49 Mon Sep 17 00:00:00 2001 From: Luna Date: Wed, 9 May 2018 13:18:17 -0400 Subject: [PATCH 06/41] Add player to skirmish on connect to matchmaker --- scripts/lobby.gd | 24 ++++++++++++++++-------- scripts/matchmaking.gd | 43 ++++++++++++++++++++++++++++++++++--------- util/server.sh | 2 +- 3 files changed, 51 insertions(+), 18 deletions(-) diff --git a/scripts/lobby.gd b/scripts/lobby.gd index 6a068fe..3c13183 100644 --- a/scripts/lobby.gd +++ b/scripts/lobby.gd @@ -10,6 +10,7 @@ var my_info = {} var begun = false var server_playing = true var global_server_ip = "nv.cosinegaming.com" +var ip = null var players_done = [] var is_connected = false # Technically this can be done with ENetcetera but it's easier this way @@ -47,6 +48,7 @@ func _ready(): my_info.version = [0,0,0] # Semantic versioning: [0].[1].[2] randomize() + parse_args() get_node("GameBrowser/Play").connect("pressed", self, "connect_global_server") get_node("PlayerSettings/HeroSelect").connect("item_selected", self, "select_hero") @@ -57,6 +59,11 @@ func _ready(): get_node("CustomGame/Singleplayer").connect("pressed", self, "_singleplayer_init") get_node("CustomGame/LevelSelect").connect("item_selected", self, "select_level") + 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") + +func parse_args(): var o = setup_options() o.parse() @@ -89,19 +96,19 @@ func _ready(): o.print_help() quit() - 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") - func connect_global_server(): - _client_init(global_server_ip) + ip = global_server_ip + _client_init() -func _client_init(ip=null): +slave func _client_init(given_port=null): collect_info() var peer = NetworkedMultiplayerENet.new() if not ip: ip = get_node("CustomGame/IP").get_text() ip = IP.resolve_hostname(ip) + if given_port: + port = given_port + print("Connecting to " + ip + ":" + str(port)) peer.create_client(ip, port) get_tree().set_network_peer(peer) get_node("CustomGame/Client").set_text("Clienting!") @@ -117,7 +124,8 @@ func _singleplayer_init(): func _server_init(): collect_info() var peer = NetworkedMultiplayerENet.new() - peer.create_server(port, matchmaking.SERVER_SIZE) + print("Starting server on port " + str(port)) + peer.create_server(port, matchmaking.GAME_SIZE) get_tree().set_network_peer(peer) is_connected = true get_node("CustomGame/Server").set_text("Serving!") @@ -180,7 +188,7 @@ remote func register_player(new_peer, info): rpc_id(1, "begin_player_deferred", new_peer) # Spawning is deferred var assign_right_team = right_team_count * 2 < player_info.size() rpc("assign_team", new_peer, assign_right_team) - if not begun and player_info.size() == matchmaking.SERVER_SIZE: + if not begun and player_info.size() == matchmaking.GAME_SIZE: start_game() if begun: rpc_id(new_peer, "pre_configure_game", my_info.level) diff --git a/scripts/matchmaking.gd b/scripts/matchmaking.gd index d0d2653..a758313 100644 --- a/scripts/matchmaking.gd +++ b/scripts/matchmaking.gd @@ -2,7 +2,9 @@ extends Node var SERVER_TO_SERVER_PORT = 54671 var MATCHMAKING_PORT = 54672 -var SERVER_SIZE = 6 +var GAME_SIZE = 6 +# Number of games we can make without blowing up the computer +var MAX_GAMES = 50 # Totally random guess var next_port = 54673 @@ -19,15 +21,33 @@ var game_streams = [] # Matchmaker to game servers var matchmaker_to_games +onready var lobby = get_node("..") + func _ready(): + # By default, having this node doesn't do naything + # You must call run_matchmaker to enable it + # If not called, don't call _process (= don't matchmake) set_process(false) func run_matchmaker(): + # Actually run the matchmaker + set_process(true) + + # Setup skirmish server skirmish = spawn_server() + + # Set up communication between GAMESERVERS + # This is necessary for eg, when a player leaves to backfill matchmaker_to_games = TCP_Server.new() if matchmaker_to_games.listen(SERVER_TO_SERVER_PORT): print("Error, could not listen") - set_process(true) + + # Use ENet for matchmaker because we can (makes client code cleaner) + var matchmaker_to_players = NetworkedMultiplayerENet.new() + print("Starting matchmaker on port " + str(MATCHMAKING_PORT)) + matchmaker_to_players.create_server(MATCHMAKING_PORT, MAX_GAMES) + get_tree().set_network_peer(matchmaker_to_players) + matchmaker_to_players.connect("peer_connected", self, "queue") func _process(delta): # Manage connection to GAMESERVERS (not clients) @@ -39,21 +59,26 @@ func _process(delta): game_streams.append(stream) # make new data transfer object for game print("Server has requested connection") -master func queue(info): - var netid = get_tree().get_rpc_sender_id() - rpc_id(netid, "join_game", skirmish) - skirmishing_players.push(netid) +func queue(netid): + print("Player " + str(netid) + " connected.") + $"..".rpc_id(netid, "_client_init", skirmish) + skirmishing_players.append(netid) check_queue() +# # This is only for clients, but it's in here so we can rpc it easily +# slave func join_game(port): +# # + func check_queue(): - if skirmishing_players.size() >= SERVER_SIZE: + if skirmishing_players.size() >= GAME_SIZE: var port = spawn_server() games.push(port) - for p in skirmishing_players: + for i in range(GAME_SIZE): + var p = skirmishing_players[i] rpc_id(p.netid, "join_game", port) func spawn_server(): - OS.execute("util/server.sh", [], false) + OS.execute("util/server.sh", ['-port='+str(next_port)], false) next_port += 1 return (next_port - 1) # Return original port diff --git a/util/server.sh b/util/server.sh index 9959782..d08c8bb 100644 --- a/util/server.sh +++ b/util/server.sh @@ -1,2 +1,2 @@ -godot-server -level=2 -silent -server -start-game +godot-server -level=2 -silent -server -start-game "$@" From 37cf9e2fcfeb2eaf39b74dd2e10eb013faa9fd53 Mon Sep 17 00:00:00 2001 From: Luna Date: Wed, 9 May 2018 14:08:28 -0400 Subject: [PATCH 07/41] Fix syntax errors in check_queue --- scripts/matchmaking.gd | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/scripts/matchmaking.gd b/scripts/matchmaking.gd index a758313..cd851af 100644 --- a/scripts/matchmaking.gd +++ b/scripts/matchmaking.gd @@ -61,7 +61,7 @@ func _process(delta): func queue(netid): print("Player " + str(netid) + " connected.") - $"..".rpc_id(netid, "_client_init", skirmish) + add_to_game(netid, skirmish) skirmishing_players.append(netid) check_queue() @@ -69,13 +69,17 @@ func queue(netid): # slave func join_game(port): # # +func add_to_game(netid, port): + lobby.rpc_id(netid, "_client_init", port) + func check_queue(): if skirmishing_players.size() >= GAME_SIZE: var port = spawn_server() - games.push(port) + games.append(port) for i in range(GAME_SIZE): var p = skirmishing_players[i] - rpc_id(p.netid, "join_game", port) + print("Moving player " + str(p) + " to game " + str(port)) + add_to_game(p, port) func spawn_server(): OS.execute("util/server.sh", ['-port='+str(next_port)], false) From 955927569c1c7059085a2bd72a40e65ccd0bcbab Mon Sep 17 00:00:00 2001 From: Luna Date: Thu, 10 May 2018 14:20:04 -0400 Subject: [PATCH 08/41] [WIP] Network games, begin move players to game The problem I just encountered is that I have to tell the players who are currently skirmishing that they have a game. This means either: 1. Telling the skirmish server to move them 2. Keeping a connection with players 3. Running the skirmish server on the matchmaker! Three sounds nice because the matchmaker is sitting on this godot instance, it might as well do something with it, right? But it's essentially equivalent to 1, it just doesn't have to think about networking because they're the same instance. So moving from 3 to 1 if I realize it's a bad idea is easy, but 2 becomes pretty entrenched. You're making some pretty big decisions here, take it slow. --- scripts/lobby.gd | 10 ++++++++++ scripts/matchmaking.gd | 34 ++++++++++++++++++++++++++-------- 2 files changed, 36 insertions(+), 8 deletions(-) diff --git a/scripts/lobby.gd b/scripts/lobby.gd index 3c13183..e39ac1a 100644 --- a/scripts/lobby.gd +++ b/scripts/lobby.gd @@ -16,6 +16,8 @@ var is_connected = false # Technically this can be done with ENetcetera but it's onready var matchmaking = preload("res://scripts/matchmaking.gd").new() +var matchmaker_tcp + func setup_options(): var opts = Options.new() opts.set_banner(('A non-violent MOBA inspired by Overwatch and Zineth')) @@ -127,6 +129,14 @@ func _server_init(): print("Starting server on port " + str(port)) peer.create_server(port, matchmaking.GAME_SIZE) get_tree().set_network_peer(peer) + # As soon as we're listening, let the matchmaker know + var matchmaker_peer = StreamPeerTCP.new() + matchmaker_peer.connect_to_host("127.0.0.1", matchmaking.SERVER_TO_SERVER_PORT) + matchmaker_tcp = PacketPeerStream.new() + matchmaker_tcp.set_stream_peer(matchmaker_peer) + # matchmaker_tcp.put_packet([matchmaking.messages.ready_to_connect, port]) + matchmaker_tcp.put_var(matchmaking.messages.ready_to_connect) + matchmaker_tcp.put_var(port) is_connected = true get_node("CustomGame/Server").set_text("Serving!") get_node("JoinedGameLobby").show() diff --git a/scripts/matchmaking.gd b/scripts/matchmaking.gd index cd851af..d5cd778 100644 --- a/scripts/matchmaking.gd +++ b/scripts/matchmaking.gd @@ -14,13 +14,17 @@ var skirmishing_players = [] var skirmish # To avoid the confusion of the gameSERVERS being CLIENTS, # we just call them games whenever possible -var games = [] +# var games = [] var game_connections = [] var game_streams = [] # Matchmaker to game servers var matchmaker_to_games +enum messages { + ready_to_connect, +} + onready var lobby = get_node("..") func _ready(): @@ -57,7 +61,13 @@ func _process(delta): var stream = PacketPeerStream.new() stream.set_stream_peer(game) # bind peerstream to new client game_streams.append(stream) # make new data transfer object for game - print("Server has requested connection") + for stream in game_streams: + if stream.get_available_packet_count(): + var message = stream.get_var() + if message == messages.ready_to_connect: + var port = stream.get_var() + print("Server " + str(port) + " has requested connection") + skirmish_to_game(port, GAME_SIZE) func queue(netid): print("Player " + str(netid) + " connected.") @@ -72,14 +82,22 @@ func queue(netid): func add_to_game(netid, port): lobby.rpc_id(netid, "_client_init", port) +func skirmish_to_game(port, count=1): + print("dropping 'em in") + for i in range(count): + if not skirmishing_players.size(): + return false + print(skirmishing_players[0]) + print("to") + print(port) + add_to_game(skirmishing_players[0], port) + return true + func check_queue(): + # Prefer making a full game to backfilling if skirmishing_players.size() >= GAME_SIZE: - var port = spawn_server() - games.append(port) - for i in range(GAME_SIZE): - var p = skirmishing_players[i] - print("Moving player " + str(p) + " to game " + str(port)) - add_to_game(p, port) + spawn_server() + # games.append(port) func spawn_server(): OS.execute("util/server.sh", ['-port='+str(next_port)], false) From 6bb81381d44e9ebd69afe4072d6c92fea6da7d1a Mon Sep 17 00:00:00 2001 From: Luna Date: Thu, 10 May 2018 19:01:38 -0400 Subject: [PATCH 09/41] [WIP] Split up lobby -> menu, lobby, custom_game lobby.gd had gotten big, bloated, ugly, and hard to read. It needed a refactor. The first thing I did is split up the *GUI* into the logical steps it should be. So the new flow is: - Start the game - Click "Quick Play" - Matchmaking begins on my dedicated server - Start the game - Click "Custom Game" - *Only now* am I presented with server / client options - Start the game - Click "Singleplayer" - Singleplayer NOW, and only now, and NO MATTER WHAT PATH I TAKE, I am taken to the *lobby*, which now is where I: - Choose my name - Choose hero - See list of players - Get my team assigned - Anything else that I might like to put in The point here is that this has *nothing* to do with handshaking / matchmaking / etc! This is just part of the game! At this point I have *already been connected* to the server. I've already been aquainted with my other players. The game has begun. I put the things that don't belong in any of these flows in networking.gd, a sort of model-view sorta thing. All of these flows use some sort of networking thing like `init_server` that tbh should be *completely* abstracted from the UI. It's totally a WIP!!! Above is the IDEA, but below is what I've actually *done*: - Made the scenes, made a passable UI for each one that at least indicates ~what they'll do - Made the corresponding scripts, and split up the lobby script into ABOUT where I think it'll end up, but no promises It still errors all over the place, and it's nowhere near properly organized. PLUS, I'd also like to rewrite a lot of the code / rename things as part of the initial refactor goal of making me able to actually think about networking. --- assets/theme.tres | 16 ++ plans.md | 2 + project.godot | 6 +- scenes/custom_game.tscn | 235 +++++++++++++++++++ scenes/lobby.tscn | 609 +++++++----------------------------------------- scenes/menu.tscn | 142 +++++++++++ scripts/custom_game.gd | 9 + scripts/lobby.gd | 233 +----------------- scripts/matchmaking.gd | 1 - scripts/menu.gd | 83 +++++++ scripts/networking.gd | 164 +++++++++++++ scripts/util.gd | 2 + 12 files changed, 739 insertions(+), 763 deletions(-) create mode 100644 assets/theme.tres create mode 100644 scenes/custom_game.tscn create mode 100644 scenes/menu.tscn create mode 100644 scripts/custom_game.gd create mode 100644 scripts/menu.gd create mode 100644 scripts/networking.gd diff --git a/assets/theme.tres b/assets/theme.tres new file mode 100644 index 0000000..f1d737a --- /dev/null +++ b/assets/theme.tres @@ -0,0 +1,16 @@ +[gd_resource type="Theme" load_steps=3 format=2] + +[ext_resource path="res://assets/DejaVuSansMono.ttf" type="DynamicFontData" id=1] + +[sub_resource type="DynamicFont" id=1] + +size = 18 +use_mipmaps = false +use_filter = false +font_data = ExtResource( 1 ) +_sections_unfolded = [ "Font", "Settings" ] + +[resource] + +default_font = SubResource( 1 ) + diff --git a/plans.md b/plans.md index 88f1138..b857052 100644 --- a/plans.md +++ b/plans.md @@ -26,6 +26,8 @@ Smaller TODOs: - Ira is OP? - Nerfed - 5 walls - Make motion more reactive? +- Remember some player settings, probably in a player.json or something + - I'm mostly thinking of nickname, but also SR eventually Bugs: diff --git a/project.godot b/project.godot index 5d343c5..29645c9 100644 --- a/project.godot +++ b/project.godot @@ -11,13 +11,17 @@ config_version=3 [application] config/name="nv-moba" -run/main_scene="res://scenes/lobby.tscn" +run/main_scene="res://scenes/menu.tscn" config/icon="res://icon.png" [autoload] util="*res://scripts/util.gd" +[display] + +window/stretch/mode="viewport" + [input] move_forwards=[ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":44,"unicode":0,"echo":false,"script":null) diff --git a/scenes/custom_game.tscn b/scenes/custom_game.tscn new file mode 100644 index 0000000..70b1d21 --- /dev/null +++ b/scenes/custom_game.tscn @@ -0,0 +1,235 @@ +[gd_scene load_steps=5 format=2] + +[ext_resource path="res://assets/theme.tres" type="Theme" id=1] +[ext_resource path="res://scripts/custom_game.gd" type="Script" id=2] +[ext_resource path="res://assets/DejaVuSansMono.ttf" type="DynamicFontData" id=3] + +[sub_resource type="DynamicFont" id=1] + +size = 30 +use_mipmaps = false +use_filter = false +font_data = ExtResource( 3 ) + +[node name="CustomGame" type="Control"] + +anchor_left = 0.0 +anchor_top = 0.0 +anchor_right = 0.0 +anchor_bottom = 0.0 +margin_right = 40.0 +margin_bottom = 40.0 +rect_pivot_offset = Vector2( 0, 0 ) +mouse_filter = 0 +mouse_default_cursor_shape = 0 +size_flags_horizontal = 1 +size_flags_vertical = 1 +theme = ExtResource( 1 ) +script = ExtResource( 2 ) + +[node name="VSeparator" type="VSeparator" parent="." index="0"] + +anchor_left = 0.0 +anchor_top = 0.0 +anchor_right = 0.0 +anchor_bottom = 0.0 +margin_left = 498.0 +margin_top = 140.0 +margin_right = 518.0 +margin_bottom = 563.0 +rect_pivot_offset = Vector2( 0, 0 ) +mouse_filter = 0 +mouse_default_cursor_shape = 0 +size_flags_horizontal = 1 +size_flags_vertical = 1 + +[node name="Label" type="Label" parent="." index="1"] + +anchor_left = 0.0 +anchor_top = 0.0 +anchor_right = 0.0 +anchor_bottom = 0.0 +margin_left = 54.0 +margin_top = 66.0 +margin_right = 395.0 +margin_bottom = 102.0 +rect_pivot_offset = Vector2( 0, 0 ) +mouse_filter = 2 +mouse_default_cursor_shape = 0 +size_flags_horizontal = 1 +size_flags_vertical = 4 +custom_fonts/font = SubResource( 1 ) +text = "Custom Game" +percent_visible = 1.0 +lines_skipped = 0 +max_lines_visible = -1 + +[node name="Server" type="Button" parent="." index="2"] + +anchor_left = 0.0 +anchor_top = 0.0 +anchor_right = 0.0 +anchor_bottom = 0.0 +margin_left = 68.0 +margin_top = 261.0 +margin_right = 272.0 +margin_bottom = 331.0 +rect_pivot_offset = Vector2( 0, 0 ) +focus_mode = 2 +mouse_filter = 0 +mouse_default_cursor_shape = 0 +size_flags_horizontal = 1 +size_flags_vertical = 1 +toggle_mode = false +enabled_focus_mode = 2 +shortcut = null +group = null +text = "Host Game" +flat = false +align = 1 + +[node name="LevelSelect" type="OptionButton" parent="." index="3"] + +anchor_left = 0.0 +anchor_top = 0.0 +anchor_right = 0.0 +anchor_bottom = 0.0 +margin_left = 72.0 +margin_top = 201.0 +margin_right = 243.0 +margin_bottom = 236.0 +rect_pivot_offset = Vector2( 0, 0 ) +focus_mode = 2 +mouse_filter = 0 +mouse_default_cursor_shape = 0 +size_flags_horizontal = 1 +size_flags_vertical = 1 +toggle_mode = false +action_mode = 0 +enabled_focus_mode = 2 +shortcut = null +group = null +text = "Platform map" +flat = false +align = 0 +selected = 0 +items = [ "Platform map", null, false, 0, null, "City-like thing", null, false, 1, null, "Slide", null, false, 2, null ] + +[node name="Client" type="Button" parent="." index="4"] + +anchor_left = 0.0 +anchor_top = 0.0 +anchor_right = 0.0 +anchor_bottom = 0.0 +margin_left = 588.0 +margin_top = 258.0 +margin_right = 812.0 +margin_bottom = 332.0 +rect_pivot_offset = Vector2( 0, 0 ) +focus_mode = 2 +mouse_filter = 0 +mouse_default_cursor_shape = 0 +size_flags_horizontal = 1 +size_flags_vertical = 1 +toggle_mode = false +enabled_focus_mode = 2 +shortcut = null +group = null +text = "Join Game" +flat = false +align = 1 + +[node name="IPLabel" type="Label" parent="." index="5"] + +anchor_left = 0.0 +anchor_top = 0.0 +anchor_right = 0.0 +anchor_bottom = 0.0 +margin_left = 592.0 +margin_top = 205.0 +margin_right = 625.0 +margin_bottom = 227.0 +rect_pivot_offset = Vector2( 0, 0 ) +mouse_filter = 2 +mouse_default_cursor_shape = 0 +size_flags_horizontal = 1 +size_flags_vertical = 4 +text = "IP:" +percent_visible = 1.0 +lines_skipped = 0 +max_lines_visible = -1 + +[node name="IP" type="TextEdit" parent="." index="6"] + +anchor_left = 0.0 +anchor_top = 0.0 +anchor_right = 0.0 +anchor_bottom = 0.0 +margin_left = 632.0 +margin_top = 202.0 +margin_right = 783.0 +margin_bottom = 231.0 +rect_pivot_offset = Vector2( 0, 0 ) +focus_mode = 2 +mouse_filter = 0 +mouse_default_cursor_shape = 0 +size_flags_horizontal = 1 +size_flags_vertical = 1 +text = "127.0.0.1" +readonly = false +highlight_current_line = false +syntax_highlighting = false +show_line_numbers = false +highlight_all_occurrences = false +override_selected_font_color = false +context_menu_enabled = true +smooth_scrolling = false +v_scroll_speed = 80.0 +hiding_enabled = 0 +wrap_lines = false +caret_block_mode = false +caret_blink = false +caret_blink_speed = 0.65 +caret_moving_by_right_click = true + +[node name="Label2" type="Label" parent="." index="7"] + +anchor_left = 0.0 +anchor_top = 0.0 +anchor_right = 0.0 +anchor_bottom = 0.0 +margin_left = 72.0 +margin_top = 145.0 +margin_right = 171.0 +margin_bottom = 167.0 +rect_pivot_offset = Vector2( 0, 0 ) +mouse_filter = 2 +mouse_default_cursor_shape = 0 +size_flags_horizontal = 1 +size_flags_vertical = 4 +text = "Host game" +percent_visible = 1.0 +lines_skipped = 0 +max_lines_visible = -1 + +[node name="Label3" type="Label" parent="." index="8"] + +anchor_left = 0.0 +anchor_top = 0.0 +anchor_right = 0.0 +anchor_bottom = 0.0 +margin_left = 577.0 +margin_top = 147.0 +margin_right = 617.0 +margin_bottom = 169.0 +rect_pivot_offset = Vector2( 0, 0 ) +mouse_filter = 2 +mouse_default_cursor_shape = 0 +size_flags_horizontal = 1 +size_flags_vertical = 4 +text = "Join Game" +percent_visible = 1.0 +lines_skipped = 0 +max_lines_visible = -1 + + diff --git a/scenes/lobby.tscn b/scenes/lobby.tscn index 36112b9..a1a6f2b 100644 --- a/scenes/lobby.tscn +++ b/scenes/lobby.tscn @@ -1,18 +1,16 @@ -[gd_scene load_steps=7 format=2] +[gd_scene load_steps=8 format=2] -[ext_resource path="res://scripts/lobby.gd" type="Script" id=1] -[ext_resource path="res://scripts/hero_select.gd" type="Script" id=2] +[ext_resource path="res://assets/theme.tres" type="Theme" id=1] +[ext_resource path="res://scripts/lobby.gd" type="Script" id=2] +[ext_resource path="res://scenes/hero_select.tscn" type="PackedScene" id=3] +[ext_resource path="res://assets/DejaVuSansMono.ttf" type="DynamicFontData" id=4] -[sub_resource type="DynamicFontData" id=1] - -font_path = "res://assets/DejaVuSansMono.ttf" - -[sub_resource type="DynamicFont" id=2] +[sub_resource type="DynamicFont" id=5] size = 30 use_mipmaps = false use_filter = false -font_data = SubResource( 1 ) +font_data = ExtResource( 4 ) [sub_resource type="DynamicFontData" id=3] @@ -31,45 +29,6 @@ anchor_left = 0.0 anchor_top = 0.0 anchor_right = 0.0 anchor_bottom = 0.0 -margin_left = 80.0 -margin_top = 99.0 -margin_right = 120.0 -margin_bottom = 139.0 -rect_pivot_offset = Vector2( 0, 0 ) -mouse_filter = 0 -mouse_default_cursor_shape = 0 -size_flags_horizontal = 1 -size_flags_vertical = 1 -script = ExtResource( 1 ) - -[node name="Title" type="Label" parent="." index="0"] - -anchor_left = 0.0 -anchor_top = 0.0 -anchor_right = 0.0 -anchor_bottom = 0.0 -margin_left = 7.0 -margin_top = -72.0 -margin_right = 195.0 -margin_bottom = -32.0 -rect_pivot_offset = Vector2( 0, 0 ) -mouse_filter = 2 -mouse_default_cursor_shape = 0 -size_flags_horizontal = 1 -size_flags_vertical = 4 -custom_fonts/font = SubResource( 2 ) -text = "VANAGLORIA" -percent_visible = 1.0 -lines_skipped = 0 -max_lines_visible = -1 - -[node name="GameBrowser" type="Control" parent="." index="1"] - -editor/display_folded = true -anchor_left = 0.0 -anchor_top = 0.0 -anchor_right = 0.0 -anchor_bottom = 0.0 margin_right = 40.0 margin_bottom = 40.0 rect_pivot_offset = Vector2( 0, 0 ) @@ -77,158 +36,68 @@ mouse_filter = 0 mouse_default_cursor_shape = 0 size_flags_horizontal = 1 size_flags_vertical = 1 +theme = ExtResource( 1 ) +script = ExtResource( 2 ) -[node name="Play" type="Button" parent="GameBrowser" index="0"] - -anchor_left = 0.0 -anchor_top = 0.0 -anchor_right = 0.0 -anchor_bottom = 0.0 -margin_left = 9.0 -margin_top = -2.0 -margin_right = 405.0 -margin_bottom = 53.0 -rect_pivot_offset = Vector2( 0, 0 ) -focus_mode = 2 -mouse_filter = 0 -mouse_default_cursor_shape = 0 -size_flags_horizontal = 1 -size_flags_vertical = 1 -toggle_mode = false -enabled_focus_mode = 2 -shortcut = null -group = null -text = "Just, Play!" -flat = false -align = 1 - -[node name="PickAGameLabel" type="Label" parent="GameBrowser" index="1"] - -anchor_left = 0.0 -anchor_top = 0.0 -anchor_right = 0.0 -anchor_bottom = 0.0 -margin_left = 10.0 -margin_top = 65.0 -margin_right = 114.0 -margin_bottom = 79.0 -rect_pivot_offset = Vector2( 0, 0 ) -mouse_filter = 2 -mouse_default_cursor_shape = 0 -size_flags_horizontal = 1 -size_flags_vertical = 4 -text = "Or, pick a game:" -percent_visible = 1.0 -lines_skipped = 0 -max_lines_visible = -1 +[node name="HeroSelect" parent="." index="0" instance=ExtResource( 3 )] -[node name="GameList" type="ItemList" parent="GameBrowser" index="2"] +editor/display_folded = true +margin_left = 28.0 +margin_top = 98.0 +margin_right = 28.0 +margin_bottom = 98.0 +color = Color( 0.097229, 0.104696, 0.105469, 0 ) -anchor_left = 0.0 -anchor_top = 0.0 -anchor_right = 0.0 -anchor_bottom = 0.0 -margin_left = 8.0 -margin_top = 87.0 -margin_right = 411.0 -margin_bottom = 208.0 -rect_pivot_offset = Vector2( 0, 0 ) -rect_clip_content = true -focus_mode = 2 -mouse_filter = 0 -mouse_default_cursor_shape = 0 -size_flags_horizontal = 1 -size_flags_vertical = 1 -items = [ "No Games Running", null, false ] -select_mode = 0 -icon_mode = 1 -fixed_icon_size = Vector2( 0, 0 ) +[node name="Hero" parent="HeroSelect" index="0"] -[node name="Join" type="Button" parent="GameBrowser" index="3"] +margin_left = -2.0 +margin_top = 41.0 +margin_right = 370.0 +margin_bottom = 108.0 -anchor_left = 0.0 -anchor_top = 0.0 -anchor_right = 0.0 -anchor_bottom = 0.0 -margin_left = 9.0 -margin_top = 217.0 -margin_right = 163.0 -margin_bottom = 244.0 -rect_pivot_offset = Vector2( 0, 0 ) -focus_mode = 2 -mouse_filter = 0 -mouse_default_cursor_shape = 0 -size_flags_horizontal = 1 -size_flags_vertical = 1 -toggle_mode = false -enabled_focus_mode = 2 -shortcut = null -group = null -text = "Join Selected Game" -flat = false -align = 1 +[node name="Confirm" parent="HeroSelect" index="1"] -[node name="VSeparator" type="VSeparator" parent="." index="2"] - -anchor_left = 0.0 -anchor_top = 0.0 -anchor_right = 0.0 -anchor_bottom = 0.0 -margin_left = 431.0 -margin_top = -3.0 -margin_right = 436.0 -margin_bottom = 234.0 -rect_pivot_offset = Vector2( 0, 0 ) -mouse_filter = 0 -mouse_default_cursor_shape = 0 -size_flags_horizontal = 1 -size_flags_vertical = 1 +visible = false -[node name="PlayerSettings" type="Control" parent="." index="3"] +[node name="HeroDescription" parent="HeroSelect" index="2"] -editor/display_folded = true -anchor_left = 0.0 -anchor_top = 0.0 -anchor_right = 0.0 -anchor_bottom = 0.0 -margin_right = 40.0 -margin_bottom = 40.0 -rect_pivot_offset = Vector2( 0, 0 ) -mouse_filter = 0 -mouse_default_cursor_shape = 0 -size_flags_horizontal = 1 -size_flags_vertical = 1 +margin_left = -2.0 +margin_top = 133.0 +margin_right = 366.0 +margin_bottom = 250.0 +text = "L Let s put oeuntahoeu nthaoeu ntaoheunt aoheunt hoaenth oaentuh Let s put oeuntahoeu nthaoeu ntaoheunt aoheunt hoaenth " -[node name="PlayerSettingsLabel" type="Label" parent="PlayerSettings" index="0"] +[node name="Title" type="Label" parent="HeroSelect" index="3"] anchor_left = 0.0 anchor_top = 0.0 anchor_right = 0.0 anchor_bottom = 0.0 -margin_left = 459.0 -margin_top = -6.0 -margin_right = 564.0 -margin_bottom = 13.0 +margin_left = 6.0 +margin_top = 9.0 +margin_right = 294.0 +margin_bottom = 45.0 rect_pivot_offset = Vector2( 0, 0 ) mouse_filter = 2 mouse_default_cursor_shape = 0 size_flags_horizontal = 1 size_flags_vertical = 4 -text = "Player Settings" +custom_fonts/font = SubResource( 5 ) +text = "Select your hero" percent_visible = 1.0 lines_skipped = 0 max_lines_visible = -1 -[node name="Username" type="TextEdit" parent="PlayerSettings" index="1"] +[node name="Username" type="TextEdit" parent="." index="1"] anchor_left = 0.0 anchor_top = 0.0 anchor_right = 0.0 anchor_bottom = 0.0 -margin_left = 457.0 -margin_top = 27.0 -margin_right = 636.0 -margin_bottom = 47.0 +margin_left = 42.0 +margin_top = 423.0 +margin_right = 383.0 +margin_bottom = 456.0 rect_pivot_offset = Vector2( 0, 0 ) focus_mode = 2 mouse_filter = 0 @@ -252,330 +121,92 @@ caret_blink = false caret_blink_speed = 0.65 caret_moving_by_right_click = true -[node name="HeroSelectLabel" type="Label" parent="PlayerSettings" index="2"] - -anchor_left = 0.0 -anchor_top = 0.0 -anchor_right = 0.0 -anchor_bottom = 0.0 -margin_left = 460.0 -margin_top = 66.0 -margin_right = 538.0 -margin_bottom = 80.0 -rect_pivot_offset = Vector2( 0, 0 ) -mouse_filter = 2 -mouse_default_cursor_shape = 0 -size_flags_horizontal = 1 -size_flags_vertical = 4 -text = "Hero Select:" -percent_visible = 1.0 -lines_skipped = 0 -max_lines_visible = -1 - -[node name="HeroSelect" type="OptionButton" parent="PlayerSettings" index="3"] - -anchor_left = 0.0 -anchor_top = 0.0 -anchor_right = 0.0 -anchor_bottom = 0.0 -margin_left = 457.0 -margin_top = 94.0 -margin_right = 645.0 -margin_bottom = 114.0 -rect_rotation = -0.0115615 -rect_pivot_offset = Vector2( 0, 0 ) -focus_mode = 2 -mouse_filter = 0 -mouse_default_cursor_shape = 0 -size_flags_horizontal = 1 -size_flags_vertical = 1 -toggle_mode = false -action_mode = 0 -enabled_focus_mode = 2 -shortcut = null -group = null -flat = false -align = 0 -selected = -1 -items = [ ] -script = ExtResource( 2 ) - -[node name="TeamLabel" type="Label" parent="PlayerSettings" index="4"] - -anchor_left = 0.0 -anchor_top = 0.0 -anchor_right = 0.0 -anchor_bottom = 0.0 -margin_left = 459.0 -margin_top = 132.0 -margin_right = 558.0 -margin_bottom = 146.0 -rect_pivot_offset = Vector2( 0, 0 ) -mouse_filter = 2 -mouse_default_cursor_shape = 0 -size_flags_horizontal = 1 -size_flags_vertical = 4 -text = "Assigned team:" -percent_visible = 1.0 -lines_skipped = 0 -max_lines_visible = -1 - -[node name="Team" type="Label" parent="PlayerSettings" index="5"] - -anchor_left = 0.0 -anchor_top = 0.0 -anchor_right = 0.0 -anchor_bottom = 0.0 -margin_left = 460.0 -margin_top = 157.0 -margin_right = 500.0 -margin_bottom = 171.0 -rect_pivot_offset = Vector2( 0, 0 ) -mouse_filter = 2 -mouse_default_cursor_shape = 0 -size_flags_horizontal = 1 -size_flags_vertical = 4 -percent_visible = 1.0 -lines_skipped = 0 -max_lines_visible = -1 - -[node name="HeroDescriptionLabel" type="Label" parent="PlayerSettings" index="6"] +[node name="TeamLabel" type="Label" parent="." index="2"] anchor_left = 0.0 anchor_top = 0.0 anchor_right = 0.0 anchor_bottom = 0.0 -margin_left = 677.0 -margin_top = -5.0 -margin_right = 790.0 -margin_bottom = 9.0 +margin_left = 498.0 +margin_top = 87.0 +margin_right = 666.0 +margin_bottom = 111.0 rect_pivot_offset = Vector2( 0, 0 ) mouse_filter = 2 mouse_default_cursor_shape = 0 size_flags_horizontal = 1 size_flags_vertical = 4 -text = "Hero Description:" +text = "Your team:" percent_visible = 1.0 lines_skipped = 0 max_lines_visible = -1 -[node name="HeroDescription" type="RichTextLabel" parent="PlayerSettings" index="7"] - -anchor_left = 0.0 -anchor_top = 0.0 -anchor_right = 0.0 -anchor_bottom = 0.0 -margin_left = 675.0 -margin_top = 15.0 -margin_right = 918.0 -margin_bottom = 245.0 -rect_pivot_offset = Vector2( 0, 0 ) -rect_clip_content = true -mouse_filter = 0 -mouse_default_cursor_shape = 0 -size_flags_horizontal = 1 -size_flags_vertical = 1 -bbcode_enabled = false -bbcode_text = "" -visible_characters = -1 -percent_visible = 1.0 -meta_underlined = true -tab_size = 4 -text = "" -scroll_active = true -scroll_following = false -selection_enabled = false -override_selected_font_color = false - -[node name="HSeparator3" type="HSeparator" parent="." index="4"] +[node name="Team" type="Label" parent="." index="3"] anchor_left = 0.0 anchor_top = 0.0 anchor_right = 0.0 anchor_bottom = 0.0 -margin_left = 19.0 -margin_top = 271.0 -margin_right = 645.0 -margin_bottom = 275.0 -rect_pivot_offset = Vector2( 0, 0 ) -mouse_filter = 0 -mouse_default_cursor_shape = 0 -size_flags_horizontal = 1 -size_flags_vertical = 1 - -[node name="CustomGame" type="Control" parent="." index="5"] - -editor/display_folded = true -anchor_left = 0.0 -anchor_top = 0.0 -anchor_right = 0.0 -anchor_bottom = 0.0 -margin_right = 40.0 -margin_bottom = 40.0 -rect_pivot_offset = Vector2( 0, 0 ) -mouse_filter = 0 -mouse_default_cursor_shape = 0 -size_flags_horizontal = 1 -size_flags_vertical = 1 - -[node name="Label" type="Label" parent="CustomGame" index="0"] - -anchor_left = 0.0 -anchor_top = 0.0 -anchor_right = 0.0 -anchor_bottom = 0.0 -margin_left = 671.0 -margin_top = 275.0 -margin_right = 874.0 -margin_bottom = 289.0 +margin_left = 625.0 +margin_top = 87.0 +margin_right = 665.0 +margin_bottom = 111.0 rect_pivot_offset = Vector2( 0, 0 ) mouse_filter = 2 mouse_default_cursor_shape = 0 size_flags_horizontal = 1 size_flags_vertical = 4 -text = "Or, host or join a custom game:" percent_visible = 1.0 lines_skipped = 0 max_lines_visible = -1 -[node name="Server" type="Button" parent="CustomGame" index="1"] +[node name="Players" type="Control" parent="." index="4"] anchor_left = 0.0 anchor_top = 0.0 anchor_right = 0.0 anchor_bottom = 0.0 -margin_left = 665.0 -margin_top = 300.0 -margin_right = 752.0 -margin_bottom = 335.0 +margin_left = 494.0 +margin_top = 128.0 +margin_right = 534.0 +margin_bottom = 168.0 rect_pivot_offset = Vector2( 0, 0 ) -focus_mode = 2 mouse_filter = 0 mouse_default_cursor_shape = 0 size_flags_horizontal = 1 size_flags_vertical = 1 -toggle_mode = false -enabled_focus_mode = 2 -shortcut = null -group = null -text = "Server" -flat = false -align = 1 -[node name="LevelSelect" type="OptionButton" parent="CustomGame" index="2"] +[node name="PlayerList" type="Label" parent="Players" index="0"] -anchor_left = 0.0 -anchor_top = 0.0 -anchor_right = 0.0 -anchor_bottom = 0.0 -margin_left = 770.0 -margin_top = 300.0 -margin_right = 895.0 -margin_bottom = 335.0 -rect_pivot_offset = Vector2( 0, 0 ) -focus_mode = 2 -mouse_filter = 0 -mouse_default_cursor_shape = 0 -size_flags_horizontal = 1 -size_flags_vertical = 1 -toggle_mode = false -action_mode = 0 -enabled_focus_mode = 2 -shortcut = null -group = null -text = "Platform map" -flat = false -align = 0 -selected = 0 -items = [ "Platform map", null, false, 0, null, "City-like thing", null, false, 1, null, "Slide", null, false, 2, null ] - -[node name="Client" type="Button" parent="CustomGame" index="3"] - -anchor_left = 0.0 -anchor_top = 0.0 -anchor_right = 0.0 -anchor_bottom = 0.0 -margin_left = 667.0 -margin_top = 354.0 -margin_right = 753.0 -margin_bottom = 393.0 -rect_pivot_offset = Vector2( 0, 0 ) -focus_mode = 2 -mouse_filter = 0 -mouse_default_cursor_shape = 0 -size_flags_horizontal = 1 -size_flags_vertical = 1 -toggle_mode = false -enabled_focus_mode = 2 -shortcut = null -group = null -text = "Client" -flat = false -align = 1 - -[node name="IPLabel" type="Label" parent="CustomGame" index="4"] - -anchor_left = 0.0 -anchor_top = 0.0 -anchor_right = 0.0 -anchor_bottom = 0.0 -margin_left = 673.0 -margin_top = 403.0 -margin_right = 698.0 -margin_bottom = 419.0 +anchor_left = 0.5 +anchor_top = 0.5 +anchor_right = 0.5 +anchor_bottom = 0.5 +margin_left = -14.0 +margin_top = 2.0 +margin_right = 487.0 +margin_bottom = 280.0 rect_pivot_offset = Vector2( 0, 0 ) mouse_filter = 2 mouse_default_cursor_shape = 0 size_flags_horizontal = 1 size_flags_vertical = 4 -text = "IP:" +custom_fonts/font = SubResource( 4 ) +text = "Waiting for players to connect...." percent_visible = 1.0 lines_skipped = 0 max_lines_visible = -1 -[node name="IP" type="TextEdit" parent="CustomGame" index="5"] +[node name="StartGame" type="Button" parent="Players" index="1"] anchor_left = 0.0 anchor_top = 0.0 anchor_right = 0.0 anchor_bottom = 0.0 -margin_left = 707.0 -margin_top = 401.0 -margin_right = 851.0 -margin_bottom = 419.0 -rect_pivot_offset = Vector2( 0, 0 ) -focus_mode = 2 -mouse_filter = 0 -mouse_default_cursor_shape = 0 -size_flags_horizontal = 1 -size_flags_vertical = 1 -text = "127.0.0.1" -readonly = false -highlight_current_line = false -syntax_highlighting = false -show_line_numbers = false -highlight_all_occurrences = false -override_selected_font_color = false -context_menu_enabled = true -smooth_scrolling = false -v_scroll_speed = 80.0 -hiding_enabled = 0 -wrap_lines = false -caret_block_mode = false -caret_blink = false -caret_blink_speed = 0.65 -caret_moving_by_right_click = true - -[node name="Singleplayer" type="Button" parent="CustomGame" index="6"] - -anchor_left = 0.0 -anchor_top = 0.0 -anchor_right = 0.0 -anchor_bottom = 0.0 -margin_left = 668.0 -margin_top = 431.0 -margin_right = 760.0 -margin_bottom = 470.0 +margin_left = 2.0 +margin_top = 325.0 +margin_right = 124.0 +margin_bottom = 365.0 rect_pivot_offset = Vector2( 0, 0 ) focus_mode = 2 mouse_filter = 0 @@ -586,105 +217,25 @@ toggle_mode = false enabled_focus_mode = 2 shortcut = null group = null -text = "Singleplayer" +text = "Ready!" flat = false align = 1 -[node name="VSeparator2" type="VSeparator" parent="." index="6"] - -anchor_left = 0.0 -anchor_top = 0.0 -anchor_right = 0.0 -anchor_bottom = 0.0 -margin_left = 653.0 -margin_top = 273.0 -margin_right = 657.0 -margin_bottom = 467.0 -rect_pivot_offset = Vector2( 0, 0 ) -mouse_filter = 0 -mouse_default_cursor_shape = 0 -size_flags_horizontal = 1 -size_flags_vertical = 1 - -[node name="JoinedGameLobby" type="Control" parent="." index="7"] - -editor/display_folded = true -visible = false -anchor_left = 0.0 -anchor_top = 0.0 -anchor_right = 0.0 -anchor_bottom = 0.0 -margin_right = 40.0 -margin_bottom = 40.0 -rect_pivot_offset = Vector2( 0, 0 ) -mouse_filter = 0 -mouse_default_cursor_shape = 0 -size_flags_horizontal = 1 -size_flags_vertical = 1 - -[node name="PlayerListLabel" type="Label" parent="JoinedGameLobby" index="0"] - -anchor_left = 0.0 -anchor_top = 0.0 -anchor_right = 0.0 -anchor_bottom = 0.0 -margin_left = 14.0 -margin_top = 287.0 -margin_right = 136.0 -margin_bottom = 301.0 -rect_pivot_offset = Vector2( 0, 0 ) -mouse_filter = 2 -mouse_default_cursor_shape = 0 -size_flags_horizontal = 1 -size_flags_vertical = 4 -text = "Connected Players:" -percent_visible = 1.0 -lines_skipped = 0 -max_lines_visible = -1 - -[node name="PlayerList" type="Label" parent="JoinedGameLobby" index="1"] - -anchor_left = 0.5 -anchor_top = 0.5 -anchor_right = 0.5 -anchor_bottom = 0.5 -margin_left = -7.0 -margin_top = 287.0 -margin_right = 639.0 -margin_bottom = 433.0 -rect_pivot_offset = Vector2( 0, 0 ) -mouse_filter = 2 -mouse_default_cursor_shape = 0 -size_flags_horizontal = 1 -size_flags_vertical = 4 -custom_fonts/font = SubResource( 4 ) -text = "Waiting for players to connect...." -percent_visible = 1.0 -lines_skipped = 0 -max_lines_visible = -1 - -[node name="StartGame" type="Button" parent="JoinedGameLobby" index="2"] +[node name="VSeparator" type="VSeparator" parent="." index="5"] anchor_left = 0.0 anchor_top = 0.0 anchor_right = 0.0 anchor_bottom = 0.0 -margin_left = 13.0 -margin_top = 443.0 -margin_right = 135.0 -margin_bottom = 483.0 +margin_left = 453.0 +margin_top = 50.0 +margin_right = 471.0 +margin_bottom = 538.0 rect_pivot_offset = Vector2( 0, 0 ) -focus_mode = 2 mouse_filter = 0 mouse_default_cursor_shape = 0 size_flags_horizontal = 1 size_flags_vertical = 1 -toggle_mode = false -enabled_focus_mode = 2 -shortcut = null -group = null -text = "Start game" -flat = false -align = 1 +[editable path="HeroSelect"] diff --git a/scenes/menu.tscn b/scenes/menu.tscn new file mode 100644 index 0000000..fb0d0f4 --- /dev/null +++ b/scenes/menu.tscn @@ -0,0 +1,142 @@ +[gd_scene load_steps=5 format=2] + +[ext_resource path="res://assets/theme.tres" type="Theme" id=1] +[ext_resource path="res://scripts/menu.gd" type="Script" id=2] + +[sub_resource type="DynamicFontData" id=1] + +font_path = "res://assets/DejaVuSansMono.ttf" + +[sub_resource type="DynamicFont" id=2] + +size = 30 +use_mipmaps = false +use_filter = false +font_data = SubResource( 1 ) + +[node name="Menu" type="Control"] + +anchor_left = 0.0 +anchor_top = 0.0 +anchor_right = 0.0 +anchor_bottom = 0.0 +margin_right = 1024.0 +margin_bottom = 600.0 +rect_pivot_offset = Vector2( 0, 0 ) +mouse_filter = 0 +mouse_default_cursor_shape = 0 +size_flags_horizontal = 1 +size_flags_vertical = 1 +theme = ExtResource( 1 ) +script = ExtResource( 2 ) + +[node name="Title" type="Label" parent="." index="0"] + +anchor_left = 0.0 +anchor_top = 0.0 +anchor_right = 0.0 +anchor_bottom = 0.0 +margin_left = 60.0 +margin_top = 50.0 +margin_right = 248.0 +margin_bottom = 90.0 +rect_pivot_offset = Vector2( 0, 0 ) +mouse_filter = 2 +mouse_default_cursor_shape = 0 +size_flags_horizontal = 1 +size_flags_vertical = 4 +custom_fonts/font = SubResource( 2 ) +text = "VANAGLORIA" +percent_visible = 1.0 +lines_skipped = 0 +max_lines_visible = -1 + +[node name="Center" type="Control" parent="." index="1"] + +anchor_left = 0.5 +anchor_top = 0.5 +anchor_right = 0.5 +anchor_bottom = 0.5 +margin_left = -20.0 +margin_top = -20.0 +margin_right = 20.0 +margin_bottom = 20.0 +rect_pivot_offset = Vector2( 0, 0 ) +mouse_filter = 0 +mouse_default_cursor_shape = 0 +size_flags_horizontal = 1 +size_flags_vertical = 1 + +[node name="Play" type="Button" parent="Center" index="0"] + +anchor_left = 0.0 +anchor_top = 0.0 +anchor_right = 0.0 +anchor_bottom = 0.0 +margin_left = -250.0 +margin_top = -70.0 +margin_right = 298.0 +margin_bottom = -10.0 +rect_pivot_offset = Vector2( 0, 0 ) +focus_mode = 2 +mouse_filter = 0 +mouse_default_cursor_shape = 0 +size_flags_horizontal = 1 +size_flags_vertical = 1 +toggle_mode = false +enabled_focus_mode = 2 +shortcut = null +group = null +text = "Quick Play" +flat = false +align = 1 + +[node name="CustomGame" type="Button" parent="Center" index="1"] + +anchor_left = 0.0 +anchor_top = 0.0 +anchor_right = 0.0 +anchor_bottom = 0.0 +margin_left = -252.0 +margin_top = 14.0 +margin_right = 300.0 +margin_bottom = 75.0 +rect_pivot_offset = Vector2( 0, 0 ) +focus_mode = 2 +mouse_filter = 0 +mouse_default_cursor_shape = 0 +size_flags_horizontal = 1 +size_flags_vertical = 1 +toggle_mode = false +enabled_focus_mode = 2 +shortcut = null +group = null +text = "Custom Game" +flat = false +align = 1 + +[node name="Singleplayer" type="Button" parent="Center" index="2"] + +anchor_left = 0.0 +anchor_top = 0.0 +anchor_right = 0.0 +anchor_bottom = 0.0 +margin_left = -251.0 +margin_top = 104.0 +margin_right = 299.0 +margin_bottom = 170.0 +rect_pivot_offset = Vector2( 0, 0 ) +focus_mode = 2 +mouse_filter = 0 +mouse_default_cursor_shape = 0 +size_flags_horizontal = 1 +size_flags_vertical = 1 +toggle_mode = false +enabled_focus_mode = 2 +shortcut = null +group = null +text = "Singleplayer" +flat = false +align = 1 + + diff --git a/scripts/custom_game.gd b/scripts/custom_game.gd new file mode 100644 index 0000000..6cda66e --- /dev/null +++ b/scripts/custom_game.gd @@ -0,0 +1,9 @@ +extends Control + +onready var networking = preload("res://scripts/networking.gd").new() + +func _ready(): + add_child(networking) + + get_node("Server").connect("pressed", networking, server_init) + get_node("Client").connect("pressed", networking, client_init) diff --git a/scripts/lobby.gd b/scripts/lobby.gd index e39ac1a..809c945 100644 --- a/scripts/lobby.gd +++ b/scripts/lobby.gd @@ -1,8 +1,5 @@ -extends "res://scripts/args.gd" +extends Control -# class member variables go here, for example: -# var a = 2 -# var b = "textvar" var port = null # Defined by command-line argument with default var player_info = {} @@ -18,40 +15,10 @@ onready var matchmaking = preload("res://scripts/matchmaking.gd").new() var matchmaker_tcp -func setup_options(): - var opts = Options.new() - opts.set_banner(('A non-violent MOBA inspired by Overwatch and Zineth')) - opts.add('-singleplayer', false, 'Whether to run singeplayer, starting immediately') - opts.add('-server', false, 'Whether to run as server') - opts.add('-matchmaker', false, 'Whether to be the sole matchmaker') - opts.add('-client', false, 'Immediately connect as client') - opts.add('-silent', false, 'If the server is not playing, merely serving') - opts.add('-port', 54672, 'The port to run a server on or connect to') - opts.add('-hero', 'r', 'Your choice of hero (index)') - opts.add('-level', 'r', 'Your choice of level (index) - server only!') - opts.add('-start-game', false, 'Join as a client and immediately start the game') - opts.add('-ai', true, 'Run this client as AI') - opts.add('-no-record', true, "Don't record this play for AI later") - opts.add('-h', false, "Print help") - return opts - -func option_sel(button_name, option): - var button = get_node(button_name) - if option == "r": - option = randi() % button.get_item_count() - else: - option = int(option) - button.select(option) func _ready(): - add_child(matchmaking) - my_info.version = [0,0,0] # Semantic versioning: [0].[1].[2] - - randomize() - parse_args() - get_node("GameBrowser/Play").connect("pressed", self, "connect_global_server") get_node("PlayerSettings/HeroSelect").connect("item_selected", self, "select_hero") get_node("PlayerSettings/Username").connect("text_changed", self, "resend_name") @@ -65,104 +32,6 @@ func _ready(): get_tree().connect("network_peer_disconnected", self, "_player_disconnected") get_tree().connect("connected_to_server", self, "_connected_ok") -func parse_args(): - var o = setup_options() - o.parse() - - if o.get_value("-silent"): - server_playing = false # TODO: Uncaps :( - if o.get_value("-hero"): - var hero = o.get_value("-hero") - option_sel("PlayerSettings/HeroSelect", hero) - # For some reason, calling option_sel doesn't trigger the actual selection - select_hero(get_node("PlayerSettings/HeroSelect").get_selected_id()) - if o.get_value("-level"): - option_sel("CustomGame/LevelSelect", o.get_value("-level")) - if o.get_value("-server"): - call_deferred("_server_init") - if o.get_value("-matchmaker"): - call_deferred("_matchmaker_init") - if o.get_value("-client"): - call_deferred("_client_init") - if o.get_value("-port"): - port = o.get_value("-port") - if o.get_value("-start-game"): - my_info.start_game = true - if o.get_value("-singleplayer"): - call_deferred("_singleplayer_init") - if o.get_value("-ai"): - my_info.is_ai = true - if not o.get_value("-no-record") and not o.get_value("-ai"): - my_info.record = true - if o.get_value('-h'): - o.print_help() - quit() - -func connect_global_server(): - ip = global_server_ip - _client_init() - -slave func _client_init(given_port=null): - collect_info() - var peer = NetworkedMultiplayerENet.new() - if not ip: - ip = get_node("CustomGame/IP").get_text() - ip = IP.resolve_hostname(ip) - if given_port: - port = given_port - print("Connecting to " + ip + ":" + str(port)) - peer.create_client(ip, port) - get_tree().set_network_peer(peer) - get_node("CustomGame/Client").set_text("Clienting!") - -func _singleplayer_init(): - collect_info() - var peer = NetworkedMultiplayerENet.new() - peer.create_server(port, 1) - get_tree().set_network_peer(peer) - player_info[1] = my_info - start_game() - -func _server_init(): - collect_info() - var peer = NetworkedMultiplayerENet.new() - print("Starting server on port " + str(port)) - peer.create_server(port, matchmaking.GAME_SIZE) - get_tree().set_network_peer(peer) - # As soon as we're listening, let the matchmaker know - var matchmaker_peer = StreamPeerTCP.new() - matchmaker_peer.connect_to_host("127.0.0.1", matchmaking.SERVER_TO_SERVER_PORT) - matchmaker_tcp = PacketPeerStream.new() - matchmaker_tcp.set_stream_peer(matchmaker_peer) - # matchmaker_tcp.put_packet([matchmaking.messages.ready_to_connect, port]) - matchmaker_tcp.put_var(matchmaking.messages.ready_to_connect) - matchmaker_tcp.put_var(port) - is_connected = true - get_node("CustomGame/Server").set_text("Serving!") - get_node("JoinedGameLobby").show() - if server_playing: - player_info[1] = my_info - if "start_game" in my_info and my_info.start_game: - start_game() - -func _matchmaker_init(): - matchmaking.run_matchmaker() - -func _player_connected(id): - pass - -func _player_disconnected(id): - if get_tree().is_network_server(): - rpc("unregister_player", id) - call_deferred("render_player_list") - -func _connected_ok(): - rpc("register_player", get_tree().get_network_unique_id(), my_info) - if "start_game" in my_info and my_info.start_game: - rpc_id(1, "start_game") - get_node("JoinedGameLobby").show() - is_connected = true - func collect_info(): if not "username" in my_info: my_info.username = get_node("PlayerSettings/Username").get_text() @@ -171,43 +40,6 @@ func collect_info(): if not "is_right_team" in my_info: my_info.is_right_team = false # Server assigns team, wait for that -remote func register_player(new_peer, info): - player_info[new_peer] = info - render_player_list() - if (get_tree().is_network_server()): - var right_team_count = 0 - # Send current players' info to new player - for old_peer in player_info: - # Send new player, old player's info - rpc_id(new_peer, "register_player", old_peer, player_info[old_peer]) - if old_peer != new_peer: - # We need to assign team later, so count current - if player_info[old_peer].is_right_team: - right_team_count += 1 - # You'd think this part could be met with a simple `rpc(`, but actually it can't - # My best guess is this is because we haven't registered the names yet, but I'm not sure (TODO) - if old_peer != 1: - # Send old player, new player's info (not us, no infinite loop) - rpc_id(old_peer, "register_player", new_peer, info) - if begun: - rpc_id(old_peer, "spawn_player", new_peer) - rpc_id(old_peer, "begin_player_deferred", new_peer) # Spawning is deferred - if not server_playing: - # We didn't catch this in player_info - rpc_id(1, "spawn_player", new_peer) - rpc_id(1, "begin_player_deferred", new_peer) # Spawning is deferred - var assign_right_team = right_team_count * 2 < player_info.size() - rpc("assign_team", new_peer, assign_right_team) - if not begun and player_info.size() == matchmaking.GAME_SIZE: - start_game() - if begun: - rpc_id(new_peer, "pre_configure_game", my_info.level) - rpc_id(new_peer, "post_configure_game") - -sync func unregister_player(peer): - player_info.erase(peer) - get_node("/root/Level/Players/%d" % peer).queue_free() - func select_hero(hero): var description = get_node("PlayerSettings/HeroSelect").hero_text[hero] get_node("PlayerSettings/HeroDescription").set_text(description) @@ -227,15 +59,6 @@ sync func set_name(peer, name): player_info[peer].username = name render_player_list() -sync func assign_team(peer, is_right_team): - player_info[peer].is_right_team = is_right_team - if peer == get_tree().get_network_unique_id(): - if is_right_team: - get_node("PlayerSettings/Team").set_text("Right Team") - else: - get_node("PlayerSettings/Team").set_text("Left Team") - render_player_list() - func render_player_list(): if has_node("PlayerSettings"): var list = "" @@ -250,57 +73,3 @@ func render_player_list(): list += "\n" get_node("JoinedGameLobby/PlayerList").set_text(list) -sync func start_game(): - my_info.level = get_node("CustomGame/LevelSelect").get_selected_id() - rpc("pre_configure_game", my_info.level) - -sync func done_preconfiguring(who): - players_done.append(who) - if players_done.size() == player_info.size(): - # We call deferred in case singleplayer has placing the player in queue still - call_deferred("rpc", "post_configure_game") - -sync func spawn_player(p): - var hero = player_info[p].hero - var player = load("res://scenes/heroes/" + str(hero) + ".tscn").instance() - player.set_name(str(p)) - player.set_network_master(p) - player.player_info = player_info[p] - get_node("/root/Level/Players").call_deferred("add_child", player) - -sync func pre_configure_game(level): - begun = true - my_info.level = level # Remember the level for future player registration - - var self_peer_id = get_tree().get_network_unique_id() - - # Remove the interface so as to not fuck with things - # But we still need the lobby alive to deal with networking! - for element in get_node("/root/Lobby").get_children(): - element.queue_free() - - var world = load("res://scenes/levels/%d.tscn" % level).instance() - get_node("/root").add_child(world) - - # Load all players (including self) - for p in player_info: - player_info[p].level = level - spawn_player(p) - - rpc_id(1, "done_preconfiguring", self_peer_id) - -func begin_player(peer): - get_node("/root/Level/Players/%d" % peer).begin() - -remote func begin_player_deferred(peer): - call_deferred("begin_player", peer) - -sync func reset_state(): - players_done = [] - get_node("/root/Level").queue_free() - -sync func post_configure_game(): - # Begin all players (including self) - for p in player_info: - begin_player_deferred(p) - diff --git a/scripts/matchmaking.gd b/scripts/matchmaking.gd index d5cd778..8e03394 100644 --- a/scripts/matchmaking.gd +++ b/scripts/matchmaking.gd @@ -83,7 +83,6 @@ func add_to_game(netid, port): lobby.rpc_id(netid, "_client_init", port) func skirmish_to_game(port, count=1): - print("dropping 'em in") for i in range(count): if not skirmishing_players.size(): return false diff --git a/scripts/menu.gd b/scripts/menu.gd new file mode 100644 index 0000000..e7dc6e9 --- /dev/null +++ b/scripts/menu.gd @@ -0,0 +1,83 @@ +extends "res://scripts/args.gd" + +func _ready(): + randomize() + _parse_args() + _gui_setup() + +# GUI + +func _gui_setup(): + get_node("Center/Play").connect("pressed", self, "_find_game") + get_node("Center/CustomGame").connect("pressed", self, "_custom_game") + get_node("Center/Singleplayer").connect("pressed", self, "_singleplayer") + +func _find_game(): + print("still refactoring matchmaker") + +func _custom_game(): + get_tree().change_scene("res://scenes/custom_game.tscn") + +func _singleplayer(): + print("still refactoring singleplayer") + +# Command line + +func _set_up_options(): + var opts = Options.new() + opts.set_banner(('A non-violent MOBA inspired by Overwatch and Zineth')) + opts.add('-singleplayer', false, 'Whether to run singeplayer, starting immediately') + opts.add('-server', false, 'Whether to run as server') + opts.add('-matchmaker', false, 'Whether to be the sole matchmaker') + opts.add('-client', false, 'Immediately connect as client') + opts.add('-silent', false, 'If the server is not playing, merely serving') + opts.add('-port', 54672, 'The port to run a server on or connect to') + opts.add('-hero', 'r', 'Your choice of hero (index)') + opts.add('-level', 'r', 'Your choice of level (index) - server only!') + opts.add('-start-game', false, 'Join as a client and immediately start the game') + opts.add('-ai', true, 'Run this client as AI') + opts.add('-no-record', true, "Don't record this play for AI later") + opts.add('-h', false, "Print help") + return opts + +func _option_sel(button_name, option): + var button = get_node(button_name) + if option == "r": + option = randi() % button.get_item_count() + else: + option = int(option) + button.select(option) + +func _parse_args(): + var o = setup_options() + o.parse() + + # if o.get_value("-silent"): + # server_playing = false + # if o.get_value("-hero"): + # var hero = o.get_value("-hero") + # _option_sel("PlayerSettings/HeroSelect", hero) + # # For some reason, calling _option_sel doesn't trigger the actual selection + # select_hero(get_node("PlayerSettings/HeroSelect").get_selected_id()) + # if o.get_value("-level"): + # _option_sel("CustomGame/LevelSelect", o.get_value("-level")) + # if o.get_value("-server"): + # call_deferred("_server_init") + # if o.get_value("-matchmaker"): + # call_deferred("_matchmaker_init") + # if o.get_value("-client"): + # call_deferred("_client_init") + # if o.get_value("-port"): + # port = o.get_value("-port") + # if o.get_value("-start-game"): + # my_info.start_game = true + # if o.get_value("-singleplayer"): + # call_deferred("_singleplayer_init") + # if o.get_value("-ai"): + # my_info.is_ai = true + # if not o.get_value("-no-record") and not o.get_value("-ai"): + # my_info.record = true + # if o.get_value('-h'): + # o.print_help() + # quit() + diff --git a/scripts/networking.gd b/scripts/networking.gd new file mode 100644 index 0000000..5011cc7 --- /dev/null +++ b/scripts/networking.gd @@ -0,0 +1,164 @@ +extends Node + +func connect_global_server(): + ip = global_server_ip + _client_init() + +slave func client_init(given_port=null): + collect_info() + var peer = NetworkedMultiplayerENet.new() + if not ip: + ip = get_node("CustomGame/IP").get_text() + ip = IP.resolve_hostname(ip) + if given_port: + port = given_port + print("Connecting to " + ip + ":" + str(port)) + peer.create_client(ip, port) + get_tree().set_network_peer(peer) + get_node("CustomGame/Client").set_text("Clienting!") + +func singleplayer_init(): + collect_info() + var peer = NetworkedMultiplayerENet.new() + peer.create_server(port, 1) + get_tree().set_network_peer(peer) + player_info[1] = my_info + start_game() + +func server_init(): + collect_info() + var peer = NetworkedMultiplayerENet.new() + print("Starting server on port " + str(port)) + peer.create_server(port, matchmaking.GAME_SIZE) + get_tree().set_network_peer(peer) + # As soon as we're listening, let the matchmaker know + var matchmaker_peer = StreamPeerTCP.new() + matchmaker_peer.connect_to_host("127.0.0.1", matchmaking.SERVER_TO_SERVER_PORT) + matchmaker_tcp = PacketPeerStream.new() + matchmaker_tcp.set_stream_peer(matchmaker_peer) + # matchmaker_tcp.put_packet([matchmaking.messages.ready_to_connect, port]) + matchmaker_tcp.put_var(matchmaking.messages.ready_to_connect) + matchmaker_tcp.put_var(port) + is_connected = true + get_node("CustomGame/Server").set_text("Serving!") + get_node("JoinedGameLobby").show() + if server_playing: + player_info[1] = my_info + if "start_game" in my_info and my_info.start_game: + start_game() + +func matchmaker_init(): + matchmaking.run_matchmaker() + +func player_disconnected(id): + if get_tree().is_network_server(): + rpc("unregister_player", id) + call_deferred("render_player_list") + +func player_connected(): + rpc("register_player", get_tree().get_network_unique_id(), my_info) + if "start_game" in my_info and my_info.start_game: + rpc_id(1, "start_game") + get_node("JoinedGameLobby").show() + is_connected = true + +remote func register_player(new_peer, info): + player_info[new_peer] = info + render_player_list() + if (get_tree().is_network_server()): + var right_team_count = 0 + # Send current players' info to new player + for old_peer in player_info: + # Send new player, old player's info + rpc_id(new_peer, "register_player", old_peer, player_info[old_peer]) + if old_peer != new_peer: + # We need to assign team later, so count current + if player_info[old_peer].is_right_team: + right_team_count += 1 + # You'd think this part could be met with a simple `rpc(`, but actually it can't + # My best guess is this is because we haven't registered the names yet, but I'm not sure (TODO) + if old_peer != 1: + # Send old player, new player's info (not us, no infinite loop) + rpc_id(old_peer, "register_player", new_peer, info) + if begun: + rpc_id(old_peer, "spawn_player", new_peer) + rpc_id(old_peer, "begin_player_deferred", new_peer) # Spawning is deferred + if not server_playing: + # We didn't catch this in player_info + rpc_id(1, "spawn_player", new_peer) + rpc_id(1, "begin_player_deferred", new_peer) # Spawning is deferred + var assign_right_team = right_team_count * 2 < player_info.size() + rpc("assign_team", new_peer, assign_right_team) + if not begun and player_info.size() == matchmaking.GAME_SIZE: + start_game() + if begun: + rpc_id(new_peer, "pre_configure_game", my_info.level) + rpc_id(new_peer, "post_configure_game") + +sync func unregister_player(peer): + player_info.erase(peer) + get_node("/root/Level/Players/%d" % peer).queue_free() + +sync func assign_team(peer, is_right_team): + player_info[peer].is_right_team = is_right_team + if peer == get_tree().get_network_unique_id(): + if is_right_team: + get_node("PlayerSettings/Team").set_text("Right Team") + else: + get_node("PlayerSettings/Team").set_text("Left Team") + render_player_list() + +sync func start_game(): + my_info.level = get_node("CustomGame/LevelSelect").get_selected_id() + rpc("pre_configure_game", my_info.level) + +sync func done_preconfiguring(who): + players_done.append(who) + if players_done.size() == player_info.size(): + # We call deferred in case singleplayer has placing the player in queue still + call_deferred("rpc", "post_configure_game") + +sync func spawn_player(p): + var hero = player_info[p].hero + var player = load("res://scenes/heroes/" + str(hero) + ".tscn").instance() + player.set_name(str(p)) + player.set_network_master(p) + player.player_info = player_info[p] + get_node("/root/Level/Players").call_deferred("add_child", player) + +sync func pre_configure_game(level): + begun = true + my_info.level = level # Remember the level for future player registration + + var self_peer_id = get_tree().get_network_unique_id() + + # Remove the interface so as to not fuck with things + # But we still need the lobby alive to deal with networking! + for element in get_node("/root/Lobby").get_children(): + element.queue_free() + + var world = load("res://scenes/levels/%d.tscn" % level).instance() + get_node("/root").add_child(world) + + # Load all players (including self) + for p in player_info: + player_info[p].level = level + spawn_player(p) + + rpc_id(1, "done_preconfiguring", self_peer_id) + +func begin_player(peer): + get_node("/root/Level/Players/%d" % peer).begin() + +remote func begin_player_deferred(peer): + call_deferred("begin_player", peer) + +sync func reset_state(): + players_done = [] + get_node("/root/Level").queue_free() + +sync func post_configure_game(): + # Begin all players (including self) + for p in player_info: + begin_player_deferred(p) + diff --git a/scripts/util.gd b/scripts/util.gd index 3f49fa8..3e29d0c 100644 --- a/scripts/util.gd +++ b/scripts/util.gd @@ -1,5 +1,7 @@ extends Node +var version = [0,0,0] # Semantic versioning: [0].[1].[2] + func get_master_player(): var path = "/root/Level/Players/%d" % get_tree().get_network_unique_id() if has_node(path): From 04f75a8ca71f6ceecd6a6585a7f0cf948888edc5 Mon Sep 17 00:00:00 2001 From: Luna Date: Thu, 10 May 2018 19:48:29 -0400 Subject: [PATCH 10/41] Fix all /errors/ on networking and custom_game But not all bugs. Only errors. We're taking this a step at a time. --- scenes/custom_game.tscn | 26 +++---- scripts/custom_game.gd | 5 +- scripts/lobby.gd | 11 ++- scripts/matchmaking.gd | 4 +- scripts/menu.gd | 2 +- scripts/networking.gd | 197 ++++++++++++++++++++++++------------------------ 6 files changed, 128 insertions(+), 117 deletions(-) diff --git a/scenes/custom_game.tscn b/scenes/custom_game.tscn index 70b1d21..67599ff 100644 --- a/scenes/custom_game.tscn +++ b/scenes/custom_game.tscn @@ -70,10 +70,10 @@ anchor_left = 0.0 anchor_top = 0.0 anchor_right = 0.0 anchor_bottom = 0.0 -margin_left = 68.0 -margin_top = 261.0 -margin_right = 272.0 -margin_bottom = 331.0 +margin_left = 73.0 +margin_top = 253.0 +margin_right = 366.0 +margin_bottom = 310.0 rect_pivot_offset = Vector2( 0, 0 ) focus_mode = 2 mouse_filter = 0 @@ -94,10 +94,10 @@ anchor_left = 0.0 anchor_top = 0.0 anchor_right = 0.0 anchor_bottom = 0.0 -margin_left = 72.0 -margin_top = 201.0 -margin_right = 243.0 -margin_bottom = 236.0 +margin_left = 74.0 +margin_top = 197.0 +margin_right = 364.0 +margin_bottom = 232.0 rect_pivot_offset = Vector2( 0, 0 ) focus_mode = 2 mouse_filter = 0 @@ -123,8 +123,8 @@ anchor_right = 0.0 anchor_bottom = 0.0 margin_left = 588.0 margin_top = 258.0 -margin_right = 812.0 -margin_bottom = 332.0 +margin_right = 890.0 +margin_bottom = 315.0 rect_pivot_offset = Vector2( 0, 0 ) focus_mode = 2 mouse_filter = 0 @@ -166,9 +166,9 @@ anchor_top = 0.0 anchor_right = 0.0 anchor_bottom = 0.0 margin_left = 632.0 -margin_top = 202.0 -margin_right = 783.0 -margin_bottom = 231.0 +margin_top = 203.0 +margin_right = 891.0 +margin_bottom = 232.0 rect_pivot_offset = Vector2( 0, 0 ) focus_mode = 2 mouse_filter = 0 diff --git a/scripts/custom_game.gd b/scripts/custom_game.gd index 6cda66e..4cacc5a 100644 --- a/scripts/custom_game.gd +++ b/scripts/custom_game.gd @@ -5,5 +5,6 @@ onready var networking = preload("res://scripts/networking.gd").new() func _ready(): add_child(networking) - get_node("Server").connect("pressed", networking, server_init) - get_node("Client").connect("pressed", networking, client_init) + get_node("Server").connect("pressed", networking, "start_server") + get_node("Client").connect("pressed", networking, "start_client") + diff --git a/scripts/lobby.gd b/scripts/lobby.gd index 809c945..e3aa839 100644 --- a/scripts/lobby.gd +++ b/scripts/lobby.gd @@ -2,9 +2,7 @@ extends Control var port = null # Defined by command-line argument with default -var player_info = {} var my_info = {} -var begun = false var server_playing = true var global_server_ip = "nv.cosinegaming.com" var ip = null @@ -73,3 +71,12 @@ func render_player_list(): list += "\n" get_node("JoinedGameLobby/PlayerList").set_text(list) +sync func assign_team(peer, is_right_team): + player_info[peer].is_right_team = is_right_team + if peer == get_tree().get_network_unique_id(): + if is_right_team: + get_node("PlayerSettings/Team").set_text("Right Team") + else: + get_node("PlayerSettings/Team").set_text("Left Team") + render_player_list() + diff --git a/scripts/matchmaking.gd b/scripts/matchmaking.gd index 8e03394..f137556 100644 --- a/scripts/matchmaking.gd +++ b/scripts/matchmaking.gd @@ -29,11 +29,11 @@ onready var lobby = get_node("..") func _ready(): # By default, having this node doesn't do naything - # You must call run_matchmaker to enable it + # You must call start_matchmaker to enable it # If not called, don't call _process (= don't matchmake) set_process(false) -func run_matchmaker(): +func start_matchmaker(): # Actually run the matchmaker set_process(true) diff --git a/scripts/menu.gd b/scripts/menu.gd index e7dc6e9..303ae64 100644 --- a/scripts/menu.gd +++ b/scripts/menu.gd @@ -49,7 +49,7 @@ func _option_sel(button_name, option): button.select(option) func _parse_args(): - var o = setup_options() + var o = _set_up_options() o.parse() # if o.get_value("-silent"): diff --git a/scripts/networking.gd b/scripts/networking.gd index 5011cc7..d7e836b 100644 --- a/scripts/networking.gd +++ b/scripts/networking.gd @@ -1,132 +1,129 @@ extends Node -func connect_global_server(): - ip = global_server_ip - _client_init() +onready var matchmaking = preload("res://scripts/matchmaking.gd").new() -slave func client_init(given_port=null): - collect_info() +var players = [] +# TODO: Should we abstract server so variables like this aren't cluttering everything up? +var players_done = [] +var begun = false +# TODO: This needs to go. It carries nothing of value +# ALL server negotiation should happen before ANY data is investigated (in lobby) +var my_info = {} + +func _ready(): + add_child(matchmaking) + +# func connect_global_server(): TODO +# ip = global_server_ip +# _client_init() + +func start_client(ip, port): + # collect_info() TODO var peer = NetworkedMultiplayerENet.new() - if not ip: - ip = get_node("CustomGame/IP").get_text() - ip = IP.resolve_hostname(ip) - if given_port: - port = given_port + # if not ip: TODO + # ip = get_node("CustomGame/IP").get_text() + # ip = IP.resolve_hostname(ip) + # if given_port: + # port = given_port print("Connecting to " + ip + ":" + str(port)) peer.create_client(ip, port) get_tree().set_network_peer(peer) - get_node("CustomGame/Client").set_text("Clienting!") + # get_node("CustomGame/Client").set_text("Clienting!") TODO -func singleplayer_init(): - collect_info() - var peer = NetworkedMultiplayerENet.new() - peer.create_server(port, 1) - get_tree().set_network_peer(peer) - player_info[1] = my_info - start_game() +# func singleplayer_init(): TODO +# # collect_info() TODO +# var peer = NetworkedMultiplayerENet.new() +# peer.create_server(port, 1) +# get_tree().set_network_peer(peer) +# players[1] = my_info +# start_game() -func server_init(): - collect_info() +func _connect_to_matchmaker(game_port): + var matchmaker_peer = StreamPeerTCP.new() + matchmaker_peer.connect_to_host("127.0.0.1", matchmaking.SERVER_TO_SERVER_PORT) + var matchmaker_tcp = PacketPeerStream.new() + matchmaker_tcp.set_stream_peer(matchmaker_peer) + matchmaker_tcp.put_var(matchmaking.messages.ready_to_connect) + matchmaker_tcp.put_var(game_port) + +func start_server(port): + # collect_info() TODO var peer = NetworkedMultiplayerENet.new() print("Starting server on port " + str(port)) peer.create_server(port, matchmaking.GAME_SIZE) get_tree().set_network_peer(peer) # As soon as we're listening, let the matchmaker know - var matchmaker_peer = StreamPeerTCP.new() - matchmaker_peer.connect_to_host("127.0.0.1", matchmaking.SERVER_TO_SERVER_PORT) - matchmaker_tcp = PacketPeerStream.new() - matchmaker_tcp.set_stream_peer(matchmaker_peer) - # matchmaker_tcp.put_packet([matchmaking.messages.ready_to_connect, port]) - matchmaker_tcp.put_var(matchmaking.messages.ready_to_connect) - matchmaker_tcp.put_var(port) - is_connected = true - get_node("CustomGame/Server").set_text("Serving!") - get_node("JoinedGameLobby").show() - if server_playing: - player_info[1] = my_info - if "start_game" in my_info and my_info.start_game: - start_game() - -func matchmaker_init(): - matchmaking.run_matchmaker() - -func player_disconnected(id): + _connect_to_matchmaker(port) + # is_connected = true TODO + # get_node("CustomGame/Server").set_text("Serving!") + # get_node("JoinedGameLobby").show() + # if server_playing: + # players[1] = my_info + # if "start_game" in my_info and my_info.start_game: TODO + # start_game() + +# sync func start_game(): TODO + # my_info.level = get_node("CustomGame/LevelSelect").get_selected_id() TODO + # rpc("_pre_configure_game", my_info.level) + +func disconnect_player(id): if get_tree().is_network_server(): rpc("unregister_player", id) - call_deferred("render_player_list") + # call_deferred("render_player_list") TODO -func player_connected(): - rpc("register_player", get_tree().get_network_unique_id(), my_info) - if "start_game" in my_info and my_info.start_game: - rpc_id(1, "start_game") - get_node("JoinedGameLobby").show() - is_connected = true +# func connect_player(): + # rpc("register_player", get_tree().get_network_unique_id(), my_info) + # if "start_game" in my_info and my_info.start_game: + # rpc_id(1, "start_game") + # get_node("JoinedGameLobby").show() TODO + # is_connected = true -remote func register_player(new_peer, info): - player_info[new_peer] = info +remote func _register_player(new_peer, info): + players[new_peer] = info render_player_list() if (get_tree().is_network_server()): var right_team_count = 0 # Send current players' info to new player - for old_peer in player_info: + for old_peer in players: # Send new player, old player's info - rpc_id(new_peer, "register_player", old_peer, player_info[old_peer]) + rpc_id(new_peer, "_register_player", old_peer, players[old_peer]) if old_peer != new_peer: # We need to assign team later, so count current - if player_info[old_peer].is_right_team: + if players[old_peer].is_right_team: right_team_count += 1 # You'd think this part could be met with a simple `rpc(`, but actually it can't # My best guess is this is because we haven't registered the names yet, but I'm not sure (TODO) if old_peer != 1: # Send old player, new player's info (not us, no infinite loop) - rpc_id(old_peer, "register_player", new_peer, info) + rpc_id(old_peer, "_register_player", new_peer, info) if begun: - rpc_id(old_peer, "spawn_player", new_peer) - rpc_id(old_peer, "begin_player_deferred", new_peer) # Spawning is deferred - if not server_playing: - # We didn't catch this in player_info - rpc_id(1, "spawn_player", new_peer) - rpc_id(1, "begin_player_deferred", new_peer) # Spawning is deferred - var assign_right_team = right_team_count * 2 < player_info.size() + rpc_id(old_peer, "_spawn_player", new_peer) + rpc_id(old_peer, "_begin_player_deferred", new_peer) # Spawning is deferred + # if not server_playing: TODO + # # We didn't catch this in players + # rpc_id(1, "_spawn_player", new_peer) + # rpc_id(1, "_begin_player_deferred", new_peer) # Spawning is deferred + var assign_right_team = right_team_count * 2 < players.size() rpc("assign_team", new_peer, assign_right_team) - if not begun and player_info.size() == matchmaking.GAME_SIZE: + if not begun and players.size() == matchmaking.GAME_SIZE: start_game() if begun: - rpc_id(new_peer, "pre_configure_game", my_info.level) - rpc_id(new_peer, "post_configure_game") + rpc_id(new_peer, "_pre_configure_game", my_info.level) + rpc_id(new_peer, "_post_configure_game") -sync func unregister_player(peer): - player_info.erase(peer) +sync func _unregister_player(peer): + players.erase(peer) get_node("/root/Level/Players/%d" % peer).queue_free() -sync func assign_team(peer, is_right_team): - player_info[peer].is_right_team = is_right_team - if peer == get_tree().get_network_unique_id(): - if is_right_team: - get_node("PlayerSettings/Team").set_text("Right Team") - else: - get_node("PlayerSettings/Team").set_text("Left Team") - render_player_list() - -sync func start_game(): - my_info.level = get_node("CustomGame/LevelSelect").get_selected_id() - rpc("pre_configure_game", my_info.level) - -sync func done_preconfiguring(who): - players_done.append(who) - if players_done.size() == player_info.size(): - # We call deferred in case singleplayer has placing the player in queue still - call_deferred("rpc", "post_configure_game") - -sync func spawn_player(p): - var hero = player_info[p].hero +sync func _spawn_player(p): + var hero = players[p].hero var player = load("res://scenes/heroes/" + str(hero) + ".tscn").instance() player.set_name(str(p)) player.set_network_master(p) - player.player_info = player_info[p] + player.players = players[p] get_node("/root/Level/Players").call_deferred("add_child", player) -sync func pre_configure_game(level): +sync func _pre_configure_game(level): begun = true my_info.level = level # Remember the level for future player registration @@ -141,24 +138,30 @@ sync func pre_configure_game(level): get_node("/root").add_child(world) # Load all players (including self) - for p in player_info: - player_info[p].level = level + for p in players: + players[p].level = level spawn_player(p) rpc_id(1, "done_preconfiguring", self_peer_id) -func begin_player(peer): +sync func _done_preconfiguring(who): + players_done.append(who) + if players_done.size() == players.size(): + # We call deferred in case singleplayer has placing the player in queue still + call_deferred("rpc", "post_configure_game") + +sync func _post_configure_game(): + # Begin all players (including self) + for p in players: + _begin_player_deferred(p) + +func _begin_player(peer): get_node("/root/Level/Players/%d" % peer).begin() -remote func begin_player_deferred(peer): - call_deferred("begin_player", peer) +remote func _begin_player_deferred(peer): + call_deferred("_begin_player", peer) sync func reset_state(): players_done = [] get_node("/root/Level").queue_free() -sync func post_configure_game(): - # Begin all players (including self) - for p in player_info: - begin_player_deferred(p) - From d265fcde1bc519342fb68592e9aba4d4f2e649be Mon Sep 17 00:00:00 2001 From: Luna Date: Sun, 13 May 2018 20:56:56 -0400 Subject: [PATCH 11/41] Add full functionality to custom_game (untested) Can't test because I haven't added the "start game" button back yet. --- scripts/custom_game.gd | 15 +++++++++++++-- scripts/menu.gd | 24 +----------------------- scripts/networking.gd | 5 ----- scripts/util.gd | 25 +++++++++++++++++++++++++ 4 files changed, 39 insertions(+), 30 deletions(-) diff --git a/scripts/custom_game.gd b/scripts/custom_game.gd index 4cacc5a..881d02d 100644 --- a/scripts/custom_game.gd +++ b/scripts/custom_game.gd @@ -5,6 +5,17 @@ onready var networking = preload("res://scripts/networking.gd").new() func _ready(): add_child(networking) - get_node("Server").connect("pressed", networking, "start_server") - get_node("Client").connect("pressed", networking, "start_client") + get_node("Server").connect("pressed", self, "_start_server") + get_node("Client").connect("pressed", self, "_start_client") + +func _start_server(): + networking.start_server(_get_port()) + +func _start_client(): + var ip = get_node("IP").text + networking.start_client(ip, _get_port()) + +func _get_port(): + var port = util.args.get_value("-port") + return port diff --git a/scripts/menu.gd b/scripts/menu.gd index 303ae64..2e5f122 100644 --- a/scripts/menu.gd +++ b/scripts/menu.gd @@ -1,8 +1,7 @@ -extends "res://scripts/args.gd" +extends Control func _ready(): randomize() - _parse_args() _gui_setup() # GUI @@ -23,23 +22,6 @@ func _singleplayer(): # Command line -func _set_up_options(): - var opts = Options.new() - opts.set_banner(('A non-violent MOBA inspired by Overwatch and Zineth')) - opts.add('-singleplayer', false, 'Whether to run singeplayer, starting immediately') - opts.add('-server', false, 'Whether to run as server') - opts.add('-matchmaker', false, 'Whether to be the sole matchmaker') - opts.add('-client', false, 'Immediately connect as client') - opts.add('-silent', false, 'If the server is not playing, merely serving') - opts.add('-port', 54672, 'The port to run a server on or connect to') - opts.add('-hero', 'r', 'Your choice of hero (index)') - opts.add('-level', 'r', 'Your choice of level (index) - server only!') - opts.add('-start-game', false, 'Join as a client and immediately start the game') - opts.add('-ai', true, 'Run this client as AI') - opts.add('-no-record', true, "Don't record this play for AI later") - opts.add('-h', false, "Print help") - return opts - func _option_sel(button_name, option): var button = get_node(button_name) if option == "r": @@ -48,10 +30,6 @@ func _option_sel(button_name, option): option = int(option) button.select(option) -func _parse_args(): - var o = _set_up_options() - o.parse() - # if o.get_value("-silent"): # server_playing = false # if o.get_value("-hero"): diff --git a/scripts/networking.gd b/scripts/networking.gd index d7e836b..b43c4f3 100644 --- a/scripts/networking.gd +++ b/scripts/networking.gd @@ -20,11 +20,6 @@ func _ready(): func start_client(ip, port): # collect_info() TODO var peer = NetworkedMultiplayerENet.new() - # if not ip: TODO - # ip = get_node("CustomGame/IP").get_text() - # ip = IP.resolve_hostname(ip) - # if given_port: - # port = given_port print("Connecting to " + ip + ":" + str(port)) peer.create_client(ip, port) get_tree().set_network_peer(peer) diff --git a/scripts/util.gd b/scripts/util.gd index 3e29d0c..3d894df 100644 --- a/scripts/util.gd +++ b/scripts/util.gd @@ -2,6 +2,13 @@ extends Node var version = [0,0,0] # Semantic versioning: [0].[1].[2] +var args + +onready var Options = preload("res://scripts/args.gd").new().Options + +func _ready(): + args = _get_args() + func get_master_player(): var path = "/root/Level/Players/%d" % get_tree().get_network_unique_id() if has_node(path): @@ -16,3 +23,21 @@ func is_friendly(player): else: return true # Doesn't matter, we're headless +func _get_args(): + var opts = Options.new() + opts.set_banner(('A non-violent MOBA inspired by Overwatch and Zineth')) + opts.add('-singleplayer', false, 'Whether to run singeplayer, starting immediately') + opts.add('-server', false, 'Whether to run as server') + opts.add('-matchmaker', false, 'Whether to be the sole matchmaker') + opts.add('-client', false, 'Immediately connect as client') + opts.add('-silent', false, 'If the server is not playing, merely serving') + opts.add('-port', 54673, 'The port to run a server on or connect to') + opts.add('-hero', 'r', 'Your choice of hero (index)') + opts.add('-level', 'r', 'Your choice of level (index) - server only!') + opts.add('-start-game', false, 'Join as a client and immediately start the game') + opts.add('-ai', true, 'Run this client as AI') + opts.add('-no-record', true, "Don't record this play for AI later") + opts.add('-h', false, "Print help") + opts.parse() + return opts + From f06eca96f9035d0649f2c729f1822c8aa68f1acb Mon Sep 17 00:00:00 2001 From: Luna Date: Sun, 13 May 2018 21:13:38 -0400 Subject: [PATCH 12/41] Fix errors from lobby (not bugs / functionality) --- project.godot | 2 +- scenes/lobby.tscn | 50 +++++++++++++++++--------------------------------- scripts/custom_game.gd | 5 +++++ scripts/lobby.gd | 16 ++++------------ scripts/networking.gd | 15 +++++++++------ 5 files changed, 36 insertions(+), 52 deletions(-) diff --git a/project.godot b/project.godot index 29645c9..9e4b16b 100644 --- a/project.godot +++ b/project.godot @@ -20,7 +20,7 @@ util="*res://scripts/util.gd" [display] -window/stretch/mode="viewport" +window/stretch/mode="2d" [input] diff --git a/scenes/lobby.tscn b/scenes/lobby.tscn index a1a6f2b..50ccad5 100644 --- a/scenes/lobby.tscn +++ b/scenes/lobby.tscn @@ -5,23 +5,23 @@ [ext_resource path="res://scenes/hero_select.tscn" type="PackedScene" id=3] [ext_resource path="res://assets/DejaVuSansMono.ttf" type="DynamicFontData" id=4] -[sub_resource type="DynamicFont" id=5] +[sub_resource type="DynamicFont" id=1] size = 30 use_mipmaps = false use_filter = false font_data = ExtResource( 4 ) -[sub_resource type="DynamicFontData" id=3] +[sub_resource type="DynamicFontData" id=2] font_path = "res://assets/DejaVuSansMono.ttf" -[sub_resource type="DynamicFont" id=4] +[sub_resource type="DynamicFont" id=3] size = 16 use_mipmaps = false use_filter = false -font_data = SubResource( 3 ) +font_data = SubResource( 2 ) [node name="Lobby" type="Control"] @@ -82,7 +82,7 @@ mouse_filter = 2 mouse_default_cursor_shape = 0 size_flags_horizontal = 1 size_flags_vertical = 4 -custom_fonts/font = SubResource( 5 ) +custom_fonts/font = SubResource( 1 ) text = "Select your hero" percent_visible = 1.0 lines_skipped = 0 @@ -160,53 +160,37 @@ percent_visible = 1.0 lines_skipped = 0 max_lines_visible = -1 -[node name="Players" type="Control" parent="." index="4"] - -anchor_left = 0.0 -anchor_top = 0.0 -anchor_right = 0.0 -anchor_bottom = 0.0 -margin_left = 494.0 -margin_top = 128.0 -margin_right = 534.0 -margin_bottom = 168.0 -rect_pivot_offset = Vector2( 0, 0 ) -mouse_filter = 0 -mouse_default_cursor_shape = 0 -size_flags_horizontal = 1 -size_flags_vertical = 1 - -[node name="PlayerList" type="Label" parent="Players" index="0"] +[node name="PlayerList" type="Label" parent="." index="4"] anchor_left = 0.5 anchor_top = 0.5 anchor_right = 0.5 anchor_bottom = 0.5 -margin_left = -14.0 -margin_top = 2.0 -margin_right = 487.0 -margin_bottom = 280.0 +margin_left = 480.0 +margin_top = 130.0 +margin_right = 981.0 +margin_bottom = 408.0 rect_pivot_offset = Vector2( 0, 0 ) mouse_filter = 2 mouse_default_cursor_shape = 0 size_flags_horizontal = 1 size_flags_vertical = 4 -custom_fonts/font = SubResource( 4 ) +custom_fonts/font = SubResource( 3 ) text = "Waiting for players to connect...." percent_visible = 1.0 lines_skipped = 0 max_lines_visible = -1 -[node name="StartGame" type="Button" parent="Players" index="1"] +[node name="StartGame" type="Button" parent="." index="5"] anchor_left = 0.0 anchor_top = 0.0 anchor_right = 0.0 anchor_bottom = 0.0 -margin_left = 2.0 -margin_top = 325.0 -margin_right = 124.0 -margin_bottom = 365.0 +margin_left = 496.0 +margin_top = 453.0 +margin_right = 618.0 +margin_bottom = 493.0 rect_pivot_offset = Vector2( 0, 0 ) focus_mode = 2 mouse_filter = 0 @@ -221,7 +205,7 @@ text = "Ready!" flat = false align = 1 -[node name="VSeparator" type="VSeparator" parent="." index="5"] +[node name="VSeparator" type="VSeparator" parent="." index="6"] anchor_left = 0.0 anchor_top = 0.0 diff --git a/scripts/custom_game.gd b/scripts/custom_game.gd index 881d02d..653ce27 100644 --- a/scripts/custom_game.gd +++ b/scripts/custom_game.gd @@ -10,10 +10,15 @@ func _ready(): func _start_server(): networking.start_server(_get_port()) + _show_lobby() func _start_client(): var ip = get_node("IP").text networking.start_client(ip, _get_port()) + _show_lobby() + +func _show_lobby(): + get_tree().change_scene("res://scenes/lobby.tscn") func _get_port(): var port = util.args.get_value("-port") diff --git a/scripts/lobby.gd b/scripts/lobby.gd index e3aa839..5056288 100644 --- a/scripts/lobby.gd +++ b/scripts/lobby.gd @@ -2,6 +2,7 @@ extends Control var port = null # Defined by command-line argument with default +var player_info = [] var my_info = {} var server_playing = true var global_server_ip = "nv.cosinegaming.com" @@ -17,18 +18,9 @@ var matchmaker_tcp func _ready(): add_child(matchmaking) - get_node("GameBrowser/Play").connect("pressed", self, "connect_global_server") - get_node("PlayerSettings/HeroSelect").connect("item_selected", self, "select_hero") - get_node("PlayerSettings/Username").connect("text_changed", self, "resend_name") - get_node("JoinedGameLobby/StartGame").connect("pressed", self, "start_game") - get_node("CustomGame/Server").connect("pressed", self, "_server_init") - get_node("CustomGame/Client").connect("pressed", self, "_client_init") - get_node("CustomGame/Singleplayer").connect("pressed", self, "_singleplayer_init") - get_node("CustomGame/LevelSelect").connect("item_selected", self, "select_level") - - 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_node("Username").connect("text_changed", self, "resend_name") + get_node("StartGame").connect("pressed", self, "start_game") + # get_node("CustomGame/LevelSelect").connect("item_selected", self, "select_level") TODO func collect_info(): if not "username" in my_info: diff --git a/scripts/networking.gd b/scripts/networking.gd index b43c4f3..2abab75 100644 --- a/scripts/networking.gd +++ b/scripts/networking.gd @@ -13,6 +13,10 @@ var my_info = {} func _ready(): add_child(matchmaking) + 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") + # func connect_global_server(): TODO # ip = global_server_ip # _client_init() @@ -66,12 +70,11 @@ func disconnect_player(id): rpc("unregister_player", id) # call_deferred("render_player_list") TODO -# func connect_player(): - # rpc("register_player", get_tree().get_network_unique_id(), my_info) - # if "start_game" in my_info and my_info.start_game: - # rpc_id(1, "start_game") - # get_node("JoinedGameLobby").show() TODO - # is_connected = true +func connect_player(): + rpc("_register_player", get_tree().get_network_unique_id(), {}) + if util.args.get_value("-start-game"): + rpc_id(1, "start_game") + # is_connected = true TODO remote func _register_player(new_peer, info): players[new_peer] = info From 8d7e4e23520e45cd48e80349e6f7ac8a610142ab Mon Sep 17 00:00:00 2001 From: Luna Date: Sun, 13 May 2018 21:31:55 -0400 Subject: [PATCH 13/41] Move level select to lobby, [WIP] fix start_game --- scenes/custom_game.tscn | 41 ++++++------------------------- scenes/lobby.tscn | 64 ++++++++++++++++++++++++++++++++++++++++++------- scripts/lobby.gd | 11 ++++++++- scripts/networking.gd | 21 ++++++++-------- 4 files changed, 83 insertions(+), 54 deletions(-) diff --git a/scenes/custom_game.tscn b/scenes/custom_game.tscn index 67599ff..799f501 100644 --- a/scenes/custom_game.tscn +++ b/scenes/custom_game.tscn @@ -71,9 +71,9 @@ anchor_top = 0.0 anchor_right = 0.0 anchor_bottom = 0.0 margin_left = 73.0 -margin_top = 253.0 +margin_top = 195.0 margin_right = 366.0 -margin_bottom = 310.0 +margin_bottom = 252.0 rect_pivot_offset = Vector2( 0, 0 ) focus_mode = 2 mouse_filter = 0 @@ -88,34 +88,7 @@ text = "Host Game" flat = false align = 1 -[node name="LevelSelect" type="OptionButton" parent="." index="3"] - -anchor_left = 0.0 -anchor_top = 0.0 -anchor_right = 0.0 -anchor_bottom = 0.0 -margin_left = 74.0 -margin_top = 197.0 -margin_right = 364.0 -margin_bottom = 232.0 -rect_pivot_offset = Vector2( 0, 0 ) -focus_mode = 2 -mouse_filter = 0 -mouse_default_cursor_shape = 0 -size_flags_horizontal = 1 -size_flags_vertical = 1 -toggle_mode = false -action_mode = 0 -enabled_focus_mode = 2 -shortcut = null -group = null -text = "Platform map" -flat = false -align = 0 -selected = 0 -items = [ "Platform map", null, false, 0, null, "City-like thing", null, false, 1, null, "Slide", null, false, 2, null ] - -[node name="Client" type="Button" parent="." index="4"] +[node name="Client" type="Button" parent="." index="3"] anchor_left = 0.0 anchor_top = 0.0 @@ -139,7 +112,7 @@ text = "Join Game" flat = false align = 1 -[node name="IPLabel" type="Label" parent="." index="5"] +[node name="IPLabel" type="Label" parent="." index="4"] anchor_left = 0.0 anchor_top = 0.0 @@ -159,7 +132,7 @@ percent_visible = 1.0 lines_skipped = 0 max_lines_visible = -1 -[node name="IP" type="TextEdit" parent="." index="6"] +[node name="IP" type="TextEdit" parent="." index="5"] anchor_left = 0.0 anchor_top = 0.0 @@ -192,7 +165,7 @@ caret_blink = false caret_blink_speed = 0.65 caret_moving_by_right_click = true -[node name="Label2" type="Label" parent="." index="7"] +[node name="Label2" type="Label" parent="." index="6"] anchor_left = 0.0 anchor_top = 0.0 @@ -212,7 +185,7 @@ percent_visible = 1.0 lines_skipped = 0 max_lines_visible = -1 -[node name="Label3" type="Label" parent="." index="8"] +[node name="Label3" type="Label" parent="." index="7"] anchor_left = 0.0 anchor_top = 0.0 diff --git a/scenes/lobby.tscn b/scenes/lobby.tscn index 50ccad5..1399c46 100644 --- a/scenes/lobby.tscn +++ b/scenes/lobby.tscn @@ -42,10 +42,10 @@ script = ExtResource( 2 ) [node name="HeroSelect" parent="." index="0" instance=ExtResource( 3 )] editor/display_folded = true -margin_left = 28.0 -margin_top = 98.0 -margin_right = 28.0 -margin_bottom = 98.0 +margin_left = 30.0 +margin_top = 69.0 +margin_right = 30.0 +margin_bottom = 69.0 color = Color( 0.097229, 0.104696, 0.105469, 0 ) [node name="Hero" parent="HeroSelect" index="0"] @@ -94,10 +94,10 @@ anchor_left = 0.0 anchor_top = 0.0 anchor_right = 0.0 anchor_bottom = 0.0 -margin_left = 42.0 -margin_top = 423.0 -margin_right = 383.0 -margin_bottom = 456.0 +margin_left = 44.0 +margin_top = 394.0 +margin_right = 385.0 +margin_bottom = 427.0 rect_pivot_offset = Vector2( 0, 0 ) focus_mode = 2 mouse_filter = 0 @@ -221,5 +221,53 @@ mouse_default_cursor_shape = 0 size_flags_horizontal = 1 size_flags_vertical = 1 +[node name="LevelSelect" type="OptionButton" parent="." index="7"] + +visible = false +anchor_left = 0.0 +anchor_top = 0.0 +anchor_right = 0.0 +anchor_bottom = 0.0 +margin_left = 45.0 +margin_top = 486.0 +margin_right = 411.0 +margin_bottom = 527.0 +rect_pivot_offset = Vector2( 0, 0 ) +focus_mode = 2 +mouse_filter = 0 +mouse_default_cursor_shape = 0 +size_flags_horizontal = 1 +size_flags_vertical = 1 +toggle_mode = false +action_mode = 0 +enabled_focus_mode = 2 +shortcut = null +group = null +text = "Platform map" +flat = false +align = 0 +selected = 0 +items = [ "Platform map", null, false, 0, null, "City-like thing", null, false, 1, null, "Slide", null, false, 2, null ] + +[node name="Label" type="Label" parent="LevelSelect" index="1"] + +anchor_left = 0.0 +anchor_top = 0.0 +anchor_right = 0.0 +anchor_bottom = 0.0 +margin_left = -5.0 +margin_top = -37.0 +margin_right = 39.0 +margin_bottom = -15.0 +rect_pivot_offset = Vector2( 0, 0 ) +mouse_filter = 2 +mouse_default_cursor_shape = 0 +size_flags_horizontal = 1 +size_flags_vertical = 4 +text = "Map:" +percent_visible = 1.0 +lines_skipped = 0 +max_lines_visible = -1 + [editable path="HeroSelect"] diff --git a/scripts/lobby.gd b/scripts/lobby.gd index 5056288..7feb999 100644 --- a/scripts/lobby.gd +++ b/scripts/lobby.gd @@ -11,15 +11,20 @@ var players_done = [] var is_connected = false # Technically this can be done with ENetcetera but it's easier this way onready var matchmaking = preload("res://scripts/matchmaking.gd").new() +onready var networking = preload("res://scripts/networking.gd").new() var matchmaker_tcp func _ready(): add_child(matchmaking) + add_child(networking) + + if get_tree().is_network_server(): + get_node("LevelSelect").show() get_node("Username").connect("text_changed", self, "resend_name") - get_node("StartGame").connect("pressed", self, "start_game") + get_node("StartGame").connect("pressed", self, "_start_game") # get_node("CustomGame/LevelSelect").connect("item_selected", self, "select_level") TODO func collect_info(): @@ -72,3 +77,7 @@ sync func assign_team(peer, is_right_team): get_node("PlayerSettings/Team").set_text("Left Team") render_player_list() +func _start_game(): + var level = 2 # TODO + networking.rpc_id(1, "start_game", level) + diff --git a/scripts/networking.gd b/scripts/networking.gd index 2abab75..d5bb9fd 100644 --- a/scripts/networking.gd +++ b/scripts/networking.gd @@ -2,7 +2,7 @@ extends Node onready var matchmaking = preload("res://scripts/matchmaking.gd").new() -var players = [] +var players = {} # TODO: Should we abstract server so variables like this aren't cluttering everything up? var players_done = [] var begun = false @@ -13,9 +13,9 @@ var my_info = {} func _ready(): add_child(matchmaking) - 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("network_peer_connected", self, "connect_player") + get_tree().connect("network_peer_disconnected", self, "disconnect_player") + get_tree().connect("connected_to_server", self, "_on_connect") # func connect_global_server(): TODO # ip = global_server_ip @@ -61,24 +61,23 @@ func start_server(port): # if "start_game" in my_info and my_info.start_game: TODO # start_game() -# sync func start_game(): TODO - # my_info.level = get_node("CustomGame/LevelSelect").get_selected_id() TODO - # rpc("_pre_configure_game", my_info.level) +sync func start_game(level): + rpc("_pre_configure_game", level) func disconnect_player(id): if get_tree().is_network_server(): rpc("unregister_player", id) # call_deferred("render_player_list") TODO -func connect_player(): - rpc("_register_player", get_tree().get_network_unique_id(), {}) +func _on_connect(): + rpc("_register_player", get_tree().get_network_unique_id(), my_info) if util.args.get_value("-start-game"): rpc_id(1, "start_game") # is_connected = true TODO remote func _register_player(new_peer, info): players[new_peer] = info - render_player_list() + # render_player_list() TODO if (get_tree().is_network_server()): var right_team_count = 0 # Send current players' info to new player @@ -138,7 +137,7 @@ sync func _pre_configure_game(level): # Load all players (including self) for p in players: players[p].level = level - spawn_player(p) + _spawn_player(p) rpc_id(1, "done_preconfiguring", self_peer_id) From 5ffb7541850e9e89521486657d24e9f563da492d Mon Sep 17 00:00:00 2001 From: Luna Date: Tue, 15 May 2018 10:34:32 -0400 Subject: [PATCH 14/41] Make start_game work for the first time! --- scripts/lobby.gd | 52 +++++++++++++++++++++++++++------------------------ scripts/networking.gd | 2 +- 2 files changed, 29 insertions(+), 25 deletions(-) diff --git a/scripts/lobby.gd b/scripts/lobby.gd index 7feb999..f126de1 100644 --- a/scripts/lobby.gd +++ b/scripts/lobby.gd @@ -2,8 +2,7 @@ extends Control var port = null # Defined by command-line argument with default -var player_info = [] -var my_info = {} +# var my_info = {} var server_playing = true var global_server_ip = "nv.cosinegaming.com" var ip = null @@ -23,45 +22,49 @@ func _ready(): if get_tree().is_network_server(): get_node("LevelSelect").show() - get_node("Username").connect("text_changed", self, "resend_name") + get_node("Username").connect("text_changed", self, "_send_name") get_node("StartGame").connect("pressed", self, "_start_game") # get_node("CustomGame/LevelSelect").connect("item_selected", self, "select_level") TODO + _send_name() -func collect_info(): +func _collect_info(): + var my_id = get_tree().get_network_unique_id() + var my_info = networking.players[my_id] if not "username" in my_info: - my_info.username = get_node("PlayerSettings/Username").get_text() + my_info.username = get_node("Username").get_text() if not "hero" in my_info: - my_info.hero = get_node("PlayerSettings/HeroSelect").get_selected_id() + my_info.hero = get_node("HeroSelect/Hero").get_selected_id() if not "is_right_team" in my_info: my_info.is_right_team = false # Server assigns team, wait for that func select_hero(hero): - var description = get_node("PlayerSettings/HeroSelect").hero_text[hero] - get_node("PlayerSettings/HeroDescription").set_text(description) - if is_connected: - rpc("set_hero", get_tree().get_network_unique_id(), hero) + var description = get_node("HeroSelect").hero_text[hero] + get_node("HeroDescription").set_text(description) + var my_id = get_tree().get_network_unique_id() + networking.players[my_id].hero = hero + rpc("set_hero", get_tree().get_network_unique_id(), hero) sync func set_hero(peer, hero): - player_info[peer].hero = hero + networking.players[peer].hero = hero render_player_list() -func resend_name(): +func _send_name(): if is_connected: - var name = get_node("PlayerSettings/Username").get_text() - rpc("set_name", get_tree().get_network_unique_id(), name) + var name = get_node("Username").text + rpc("_set_name", get_tree().get_network_unique_id(), name) -sync func set_name(peer, name): - player_info[peer].username = name +sync func _set_name(peer, name): + networking.players[peer].username = name render_player_list() func render_player_list(): if has_node("PlayerSettings"): var list = "" - var hero_names = get_node("PlayerSettings/HeroSelect").hero_names - for p in player_info: - list += "%-15s" % player_info[p].username - list += "%-20s" % hero_names[player_info[p].hero] - if player_info[p].is_right_team: + var hero_names = get_node("HeroSelect").hero_names + for p in networking.players: + list += "%-15s" % networking.players[p].username + list += "%-20s" % hero_names[networking.players[p].hero] + if networking.players[p].is_right_team: list += "Right Team" else: list += "Left Team" @@ -69,15 +72,16 @@ func render_player_list(): get_node("JoinedGameLobby/PlayerList").set_text(list) sync func assign_team(peer, is_right_team): - player_info[peer].is_right_team = is_right_team + networking.players[peer].is_right_team = is_right_team if peer == get_tree().get_network_unique_id(): if is_right_team: - get_node("PlayerSettings/Team").set_text("Right Team") + get_node("Team").set_text("Right Team") else: - get_node("PlayerSettings/Team").set_text("Left Team") + get_node("Team").set_text("Left Team") render_player_list() func _start_game(): + _collect_info() var level = 2 # TODO networking.rpc_id(1, "start_game", level) diff --git a/scripts/networking.gd b/scripts/networking.gd index d5bb9fd..f06bb4a 100644 --- a/scripts/networking.gd +++ b/scripts/networking.gd @@ -117,7 +117,7 @@ sync func _spawn_player(p): var player = load("res://scenes/heroes/" + str(hero) + ".tscn").instance() player.set_name(str(p)) player.set_network_master(p) - player.players = players[p] + player.player_info = players[p] get_node("/root/Level/Players").call_deferred("add_child", player) sync func _pre_configure_game(level): From a2dabbc37aa72efaebed95186eeda280efd340af Mon Sep 17 00:00:00 2001 From: Luna Date: Tue, 15 May 2018 23:45:19 -0400 Subject: [PATCH 15/41] [WIP] Figure out how the hell I'm gonna do this --- project.godot | 5 +-- scripts/custom_game.gd | 7 ++--- scripts/lobby.gd | 12 ++++++-- scripts/menu.gd | 31 +++++++++++-------- scripts/networking.gd | 82 +++++++++++++++++++++++++------------------------- 5 files changed, 71 insertions(+), 66 deletions(-) diff --git a/project.godot b/project.godot index 9e4b16b..7ba129f 100644 --- a/project.godot +++ b/project.godot @@ -17,10 +17,7 @@ config/icon="res://icon.png" [autoload] util="*res://scripts/util.gd" - -[display] - -window/stretch/mode="2d" +networking="*res://scripts/networking.gd" [input] diff --git a/scripts/custom_game.gd b/scripts/custom_game.gd index 653ce27..57cce07 100644 --- a/scripts/custom_game.gd +++ b/scripts/custom_game.gd @@ -1,15 +1,12 @@ extends Control -onready var networking = preload("res://scripts/networking.gd").new() - func _ready(): - add_child(networking) - get_node("Server").connect("pressed", self, "_start_server") get_node("Client").connect("pressed", self, "_start_client") func _start_server(): - networking.start_server(_get_port()) + # Custom Game can assume we're playing as well + networking.start_server(_get_port(), true) _show_lobby() func _start_client(): diff --git a/scripts/lobby.gd b/scripts/lobby.gd index f126de1..906b5f4 100644 --- a/scripts/lobby.gd +++ b/scripts/lobby.gd @@ -3,30 +3,36 @@ extends Control var port = null # Defined by command-line argument with default # var my_info = {} -var server_playing = true +remote var players = {} var global_server_ip = "nv.cosinegaming.com" var ip = null var players_done = [] var is_connected = false # Technically this can be done with ENetcetera but it's easier this way onready var matchmaking = preload("res://scripts/matchmaking.gd").new() -onready var networking = preload("res://scripts/networking.gd").new() var matchmaker_tcp +var right_team_next = false func _ready(): add_child(matchmaking) - add_child(networking) if get_tree().is_network_server(): get_node("LevelSelect").show() + get_tree().connect("network_peer_connected", self, "_register_player") + get_node("Username").connect("text_changed", self, "_send_name") get_node("StartGame").connect("pressed", self, "_start_game") # get_node("CustomGame/LevelSelect").connect("item_selected", self, "select_level") TODO _send_name() +func _register_player(peer): + players[peer] = {} + if is_network_server(): + rset(peer, "players", players) + func _collect_info(): var my_id = get_tree().get_network_unique_id() var my_info = networking.players[my_id] diff --git a/scripts/menu.gd b/scripts/menu.gd index 2e5f122..578da9f 100644 --- a/scripts/menu.gd +++ b/scripts/menu.gd @@ -3,6 +3,7 @@ extends Control func _ready(): randomize() _gui_setup() + _arg_actions() # GUI @@ -30,6 +31,8 @@ func _option_sel(button_name, option): option = int(option) button.select(option) +func _arg_actions(): + var o = util.args # if o.get_value("-silent"): # server_playing = false # if o.get_value("-hero"): @@ -39,23 +42,25 @@ func _option_sel(button_name, option): # select_hero(get_node("PlayerSettings/HeroSelect").get_selected_id()) # if o.get_value("-level"): # _option_sel("CustomGame/LevelSelect", o.get_value("-level")) - # if o.get_value("-server"): - # call_deferred("_server_init") - # if o.get_value("-matchmaker"): - # call_deferred("_matchmaker_init") - # if o.get_value("-client"): - # call_deferred("_client_init") # if o.get_value("-port"): # port = o.get_value("-port") - # if o.get_value("-start-game"): - # my_info.start_game = true - # if o.get_value("-singleplayer"): - # call_deferred("_singleplayer_init") # if o.get_value("-ai"): # my_info.is_ai = true # if not o.get_value("-no-record") and not o.get_value("-ai"): # my_info.record = true - # if o.get_value('-h'): - # o.print_help() - # quit() + if o.get_value("-server"): + networking.call_deferred("start_server") + get_tree().change_scene("res://scenes/lobby.tscn") + # if o.get_value("-matchmaker"): + # call_deferred("_matchmaker_init") + if o.get_value("-client"): + networking.call_deferred("start_client") + get_tree().change_scene("res://scenes/lobby.tscn") + if o.get_value("-start-game"): + networking.call_deferred("start_game") + # if o.get_value("-singleplayer"): + # networking.call_deferred("start_singleplayer") + if o.get_value('-h'): + o.print_help() + quit() diff --git a/scripts/networking.gd b/scripts/networking.gd index f06bb4a..28bf2a8 100644 --- a/scripts/networking.gd +++ b/scripts/networking.gd @@ -2,20 +2,23 @@ extends Node onready var matchmaking = preload("res://scripts/matchmaking.gd").new() -var players = {} +remote var players = [] # TODO: Should we abstract server so variables like this aren't cluttering everything up? var players_done = [] var begun = false # TODO: This needs to go. It carries nothing of value # ALL server negotiation should happen before ANY data is investigated (in lobby) -var my_info = {} +var my_info = { + hero: 0, + username: "Nickname", +} func _ready(): add_child(matchmaking) - # get_tree().connect("network_peer_connected", self, "connect_player") + get_tree().connect("network_peer_connected", self, "_register_player") get_tree().connect("network_peer_disconnected", self, "disconnect_player") - get_tree().connect("connected_to_server", self, "_on_connect") + # get_tree().connect("connected_to_server", self, "_on_connect") # func connect_global_server(): TODO # ip = global_server_ip @@ -45,7 +48,7 @@ func _connect_to_matchmaker(game_port): matchmaker_tcp.put_var(matchmaking.messages.ready_to_connect) matchmaker_tcp.put_var(game_port) -func start_server(port): +func start_server(port, server_playing=false): # collect_info() TODO var peer = NetworkedMultiplayerENet.new() print("Starting server on port " + str(port)) @@ -53,15 +56,16 @@ func start_server(port): get_tree().set_network_peer(peer) # As soon as we're listening, let the matchmaker know _connect_to_matchmaker(port) + if server_playing: + players[1] = my_info # is_connected = true TODO # get_node("CustomGame/Server").set_text("Serving!") # get_node("JoinedGameLobby").show() - # if server_playing: - # players[1] = my_info # if "start_game" in my_info and my_info.start_game: TODO # start_game() sync func start_game(level): + print(var2str(players)) rpc("_pre_configure_game", level) func disconnect_player(id): @@ -69,51 +73,45 @@ func disconnect_player(id): rpc("unregister_player", id) # call_deferred("render_player_list") TODO -func _on_connect(): - rpc("_register_player", get_tree().get_network_unique_id(), my_info) - if util.args.get_value("-start-game"): - rpc_id(1, "start_game") +# func _on_connect(): +# rpc("_register_player", get_tree().get_network_unique_id(), my_info) +# if util.args.get_value("-start-game"): +# rpc_id(1, "start_game") # is_connected = true TODO -remote func _register_player(new_peer, info): - players[new_peer] = info +remote func _register_player(new_peer): + players.push(new_peer) + if get_tree().is_network_server(): + # I tell new player about all the existing people + rset_id(new_peer, "players", players) # render_player_list() TODO - if (get_tree().is_network_server()): - var right_team_count = 0 + # var right_team_count = 0 # Send current players' info to new player - for old_peer in players: # Send new player, old player's info - rpc_id(new_peer, "_register_player", old_peer, players[old_peer]) - if old_peer != new_peer: - # We need to assign team later, so count current - if players[old_peer].is_right_team: - right_team_count += 1 - # You'd think this part could be met with a simple `rpc(`, but actually it can't - # My best guess is this is because we haven't registered the names yet, but I'm not sure (TODO) - if old_peer != 1: - # Send old player, new player's info (not us, no infinite loop) - rpc_id(old_peer, "_register_player", new_peer, info) - if begun: - rpc_id(old_peer, "_spawn_player", new_peer) - rpc_id(old_peer, "_begin_player_deferred", new_peer) # Spawning is deferred - # if not server_playing: TODO - # # We didn't catch this in players - # rpc_id(1, "_spawn_player", new_peer) - # rpc_id(1, "_begin_player_deferred", new_peer) # Spawning is deferred - var assign_right_team = right_team_count * 2 < players.size() - rpc("assign_team", new_peer, assign_right_team) - if not begun and players.size() == matchmaking.GAME_SIZE: - start_game() - if begun: - rpc_id(new_peer, "_pre_configure_game", my_info.level) - rpc_id(new_peer, "_post_configure_game") + # rpc_id(new_peer, "_register_player", old_peer, players[old_peer]) + # if old_peer != new_peer: + # # We need to assign team later, so count current + # if players[old_peer].is_right_team: + # right_team_count += 1 + # if begun: TODO this should belong to lobby + # rpc_id(old_peer, "_spawn_player", new_peer) + # rpc_id(old_peer, "_begin_player_deferred", new_peer) # Spawning is deferred + # var assign_right_team = right_team_count * 2 < players.size() + # rpc("assign_team", new_peer, assign_right_team) + # if not begun and players.size() == matchmaking.GAME_SIZE: + # start_game() + # if begun: + # rpc_id(new_peer, "_pre_configure_game", my_info.level) + # rpc_id(new_peer, "_post_configure_game") sync func _unregister_player(peer): players.erase(peer) get_node("/root/Level/Players/%d" % peer).queue_free() sync func _spawn_player(p): - var hero = players[p].hero + var hero = 0 + if players[p].has("hero"): # TODO: Rethink how we do this whole shenanigan + hero = players[p].hero var player = load("res://scenes/heroes/" + str(hero) + ".tscn").instance() player.set_name(str(p)) player.set_network_master(p) @@ -121,6 +119,7 @@ sync func _spawn_player(p): get_node("/root/Level/Players").call_deferred("add_child", player) sync func _pre_configure_game(level): + level = 2 # TODO: Remove this!! begun = true my_info.level = level # Remember the level for future player registration @@ -133,6 +132,7 @@ sync func _pre_configure_game(level): var world = load("res://scenes/levels/%d.tscn" % level).instance() get_node("/root").add_child(world) + print("added level!") # Load all players (including self) for p in players: From 1868d03be0486b0eb4ff930466f8ef0e0e7b2ffb Mon Sep 17 00:00:00 2001 From: Luna Date: Fri, 18 May 2018 19:02:32 -0400 Subject: [PATCH 16/41] [WIP] Add spectator button --- scenes/lobby.tscn | 139 +++++++++++++++++++++++++++++--------------------- scripts/lobby.gd | 32 +++--------- scripts/networking.gd | 16 +++--- 3 files changed, 96 insertions(+), 91 deletions(-) diff --git a/scenes/lobby.tscn b/scenes/lobby.tscn index 1399c46..9eb171b 100644 --- a/scenes/lobby.tscn +++ b/scenes/lobby.tscn @@ -23,7 +23,7 @@ use_mipmaps = false use_filter = false font_data = SubResource( 2 ) -[node name="Lobby" type="Control"] +[node name="Lobby" type="Control" index="0"] anchor_left = 0.0 anchor_top = 0.0 @@ -94,10 +94,10 @@ anchor_left = 0.0 anchor_top = 0.0 anchor_right = 0.0 anchor_bottom = 0.0 -margin_left = 44.0 -margin_top = 394.0 -margin_right = 385.0 -margin_bottom = 427.0 +margin_left = 43.0 +margin_top = 348.0 +margin_right = 384.0 +margin_bottom = 381.0 rect_pivot_offset = Vector2( 0, 0 ) focus_mode = 2 mouse_filter = 0 @@ -121,7 +121,78 @@ caret_blink = false caret_blink_speed = 0.65 caret_moving_by_right_click = true -[node name="TeamLabel" type="Label" parent="." index="2"] +[node name="Spectating" type="CheckButton" parent="." index="2"] + +anchor_left = 0.0 +anchor_top = 0.0 +anchor_right = 0.0 +anchor_bottom = 0.0 +margin_left = 36.0 +margin_top = 396.0 +margin_right = 226.0 +margin_bottom = 436.0 +rect_pivot_offset = Vector2( 0, 0 ) +focus_mode = 2 +mouse_filter = 0 +mouse_default_cursor_shape = 0 +size_flags_horizontal = 1 +size_flags_vertical = 1 +toggle_mode = true +enabled_focus_mode = 2 +shortcut = null +group = null +text = "Spectating" +flat = false +align = 0 + +[node name="LevelSelect" type="OptionButton" parent="." index="3"] + +anchor_left = 0.0 +anchor_top = 0.0 +anchor_right = 0.0 +anchor_bottom = 0.0 +margin_left = 45.0 +margin_top = 486.0 +margin_right = 411.0 +margin_bottom = 527.0 +rect_pivot_offset = Vector2( 0, 0 ) +focus_mode = 2 +mouse_filter = 0 +mouse_default_cursor_shape = 0 +size_flags_horizontal = 1 +size_flags_vertical = 1 +toggle_mode = false +action_mode = 0 +enabled_focus_mode = 2 +shortcut = null +group = null +text = "Platform map" +flat = false +align = 0 +selected = 0 +items = [ "Platform map", null, false, 0, null, "City-like thing", null, false, 1, null, "Slide", null, false, 2, null ] + +[node name="Label" type="Label" parent="LevelSelect" index="1"] + +anchor_left = 0.0 +anchor_top = 0.0 +anchor_right = 0.0 +anchor_bottom = 0.0 +margin_left = -5.0 +margin_top = -37.0 +margin_right = 39.0 +margin_bottom = -15.0 +rect_pivot_offset = Vector2( 0, 0 ) +mouse_filter = 2 +mouse_default_cursor_shape = 0 +size_flags_horizontal = 1 +size_flags_vertical = 4 +text = "Map:" +percent_visible = 1.0 +lines_skipped = 0 +max_lines_visible = -1 + +[node name="TeamLabel" type="Label" parent="." index="4"] anchor_left = 0.0 anchor_top = 0.0 @@ -141,7 +212,7 @@ percent_visible = 1.0 lines_skipped = 0 max_lines_visible = -1 -[node name="Team" type="Label" parent="." index="3"] +[node name="Team" type="Label" parent="." index="5"] anchor_left = 0.0 anchor_top = 0.0 @@ -160,7 +231,7 @@ percent_visible = 1.0 lines_skipped = 0 max_lines_visible = -1 -[node name="PlayerList" type="Label" parent="." index="4"] +[node name="PlayerList" type="Label" parent="." index="6"] anchor_left = 0.5 anchor_top = 0.5 @@ -181,7 +252,7 @@ percent_visible = 1.0 lines_skipped = 0 max_lines_visible = -1 -[node name="StartGame" type="Button" parent="." index="5"] +[node name="StartGame" type="Button" parent="." index="7"] anchor_left = 0.0 anchor_top = 0.0 @@ -205,7 +276,7 @@ text = "Ready!" flat = false align = 1 -[node name="VSeparator" type="VSeparator" parent="." index="6"] +[node name="VSeparator" type="VSeparator" parent="." index="8"] anchor_left = 0.0 anchor_top = 0.0 @@ -221,53 +292,5 @@ mouse_default_cursor_shape = 0 size_flags_horizontal = 1 size_flags_vertical = 1 -[node name="LevelSelect" type="OptionButton" parent="." index="7"] - -visible = false -anchor_left = 0.0 -anchor_top = 0.0 -anchor_right = 0.0 -anchor_bottom = 0.0 -margin_left = 45.0 -margin_top = 486.0 -margin_right = 411.0 -margin_bottom = 527.0 -rect_pivot_offset = Vector2( 0, 0 ) -focus_mode = 2 -mouse_filter = 0 -mouse_default_cursor_shape = 0 -size_flags_horizontal = 1 -size_flags_vertical = 1 -toggle_mode = false -action_mode = 0 -enabled_focus_mode = 2 -shortcut = null -group = null -text = "Platform map" -flat = false -align = 0 -selected = 0 -items = [ "Platform map", null, false, 0, null, "City-like thing", null, false, 1, null, "Slide", null, false, 2, null ] - -[node name="Label" type="Label" parent="LevelSelect" index="1"] - -anchor_left = 0.0 -anchor_top = 0.0 -anchor_right = 0.0 -anchor_bottom = 0.0 -margin_left = -5.0 -margin_top = -37.0 -margin_right = 39.0 -margin_bottom = -15.0 -rect_pivot_offset = Vector2( 0, 0 ) -mouse_filter = 2 -mouse_default_cursor_shape = 0 -size_flags_horizontal = 1 -size_flags_vertical = 4 -text = "Map:" -percent_visible = 1.0 -lines_skipped = 0 -max_lines_visible = -1 - [editable path="HeroSelect"] diff --git a/scripts/lobby.gd b/scripts/lobby.gd index 906b5f4..f183605 100644 --- a/scripts/lobby.gd +++ b/scripts/lobby.gd @@ -2,36 +2,17 @@ extends Control var port = null # Defined by command-line argument with default -# var my_info = {} -remote var players = {} -var global_server_ip = "nv.cosinegaming.com" -var ip = null -var players_done = [] -var is_connected = false # Technically this can be done with ENetcetera but it's easier this way - -onready var matchmaking = preload("res://scripts/matchmaking.gd").new() - -var matchmaker_tcp - -var right_team_next = false - func _ready(): - add_child(matchmaking) - if get_tree().is_network_server(): get_node("LevelSelect").show() - get_tree().connect("network_peer_connected", self, "_register_player") - get_node("Username").connect("text_changed", self, "_send_name") get_node("StartGame").connect("pressed", self, "_start_game") - # get_node("CustomGame/LevelSelect").connect("item_selected", self, "select_level") TODO - _send_name() -func _register_player(peer): - players[peer] = {} - if is_network_server(): - rset(peer, "players", players) + get_node("Spectating").pressed = util.args.get_value("-silent") + get_node("Spectating").connect("pressed", self, "_change_spectating") # TODO + # get_node("CustomGame/LevelSelect").connect("item_selected", self, "select_level") TODO + # _send_name() func _collect_info(): var my_id = get_tree().get_network_unique_id() @@ -55,9 +36,8 @@ sync func set_hero(peer, hero): render_player_list() func _send_name(): - if is_connected: - var name = get_node("Username").text - rpc("_set_name", get_tree().get_network_unique_id(), name) + var name = get_node("Username").text + rpc("_set_name", get_tree().get_network_unique_id(), name) sync func _set_name(peer, name): networking.players[peer].username = name diff --git a/scripts/networking.gd b/scripts/networking.gd index 28bf2a8..068e596 100644 --- a/scripts/networking.gd +++ b/scripts/networking.gd @@ -2,16 +2,20 @@ extends Node onready var matchmaking = preload("res://scripts/matchmaking.gd").new() -remote var players = [] -# TODO: Should we abstract server so variables like this aren't cluttering everything up? +remote var players = {} var players_done = [] +var is_connected = false # Technically this can be done with ENetcetera but it's easier this way +# TODO: Should we abstract server so variables like this aren't cluttering everything up? var begun = false # TODO: This needs to go. It carries nothing of value # ALL server negotiation should happen before ANY data is investigated (in lobby) var my_info = { - hero: 0, - username: "Nickname", + "hero": 0, + "username": "Nickname", } +var global_server_ip = "nv.cosinegaming.com" +var matchmaker_tcp +var right_team_next = false func _ready(): add_child(matchmaking) @@ -56,8 +60,6 @@ func start_server(port, server_playing=false): get_tree().set_network_peer(peer) # As soon as we're listening, let the matchmaker know _connect_to_matchmaker(port) - if server_playing: - players[1] = my_info # is_connected = true TODO # get_node("CustomGame/Server").set_text("Serving!") # get_node("JoinedGameLobby").show() @@ -80,7 +82,7 @@ func disconnect_player(id): # is_connected = true TODO remote func _register_player(new_peer): - players.push(new_peer) + players[new_peer] = {} if get_tree().is_network_server(): # I tell new player about all the existing people rset_id(new_peer, "players", players) From 10d760bbf43c77c7db60242336b3688247efc0a5 Mon Sep 17 00:00:00 2001 From: Luna Date: Fri, 18 May 2018 19:19:14 -0400 Subject: [PATCH 17/41] Fix server not playing when not spectating --- scenes/lobby.tscn | 2 +- scripts/lobby.gd | 6 ++++-- scripts/networking.gd | 31 +++++++++++++++++++++++-------- 3 files changed, 28 insertions(+), 11 deletions(-) diff --git a/scenes/lobby.tscn b/scenes/lobby.tscn index 9eb171b..10f49eb 100644 --- a/scenes/lobby.tscn +++ b/scenes/lobby.tscn @@ -23,7 +23,7 @@ use_mipmaps = false use_filter = false font_data = SubResource( 2 ) -[node name="Lobby" type="Control" index="0"] +[node name="Lobby" type="Control"] anchor_left = 0.0 anchor_top = 0.0 diff --git a/scripts/lobby.gd b/scripts/lobby.gd index f183605..ec59d82 100644 --- a/scripts/lobby.gd +++ b/scripts/lobby.gd @@ -9,8 +9,10 @@ func _ready(): get_node("Username").connect("text_changed", self, "_send_name") get_node("StartGame").connect("pressed", self, "_start_game") - get_node("Spectating").pressed = util.args.get_value("-silent") - get_node("Spectating").connect("pressed", self, "_change_spectating") # TODO + var spectating = util.args.get_value("-silent") + get_node("Spectating").pressed = spectating + # + get_node("Spectating").connect("toggled", networking, "set_spectating") # TODO # get_node("CustomGame/LevelSelect").connect("item_selected", self, "select_level") TODO # _send_name() diff --git a/scripts/networking.gd b/scripts/networking.gd index 068e596..8cb125c 100644 --- a/scripts/networking.gd +++ b/scripts/networking.gd @@ -20,8 +20,8 @@ var right_team_next = false func _ready(): add_child(matchmaking) - get_tree().connect("network_peer_connected", self, "_register_player") - get_tree().connect("network_peer_disconnected", self, "disconnect_player") + get_tree().connect("network_peer_disconnected", self, "unregister_player") + get_tree().connect("network_peer_connected", self, "register_player") # get_tree().connect("connected_to_server", self, "_on_connect") # func connect_global_server(): TODO @@ -60,11 +60,13 @@ func start_server(port, server_playing=false): get_tree().set_network_peer(peer) # As soon as we're listening, let the matchmaker know _connect_to_matchmaker(port) + if not util.args.get_value("-silent"): + register_player(get_tree().get_network_unique_id()) # is_connected = true TODO # get_node("CustomGame/Server").set_text("Serving!") # get_node("JoinedGameLobby").show() - # if "start_game" in my_info and my_info.start_game: TODO - # start_game() + if util.args.get_value("-start-game"): + start_game() sync func start_game(level): print(var2str(players)) @@ -81,8 +83,11 @@ func disconnect_player(id): # rpc_id(1, "start_game") # is_connected = true TODO -remote func _register_player(new_peer): - players[new_peer] = {} +remote func register_player(new_peer): + var info = {} + info.is_right_team = right_team_next + right_team_next = not right_team_next + players[new_peer] = info if get_tree().is_network_server(): # I tell new player about all the existing people rset_id(new_peer, "players", players) @@ -106,9 +111,19 @@ remote func _register_player(new_peer): # rpc_id(new_peer, "_pre_configure_game", my_info.level) # rpc_id(new_peer, "_post_configure_game") -sync func _unregister_player(peer): +sync func unregister_player(peer): players.erase(peer) - get_node("/root/Level/Players/%d" % peer).queue_free() + if begun: + get_node("/root/Level/Players/%d" % peer).queue_free() + +func set_spectating(spectating): + var id = get_tree().get_network_unique_id() + if spectating: + if players[id]: + unregister_player(id) + else: + if not players[id]: + register_player(id) sync func _spawn_player(p): var hero = 0 From 6524455822863b0579b425c4e1f9ad762c95b6bb Mon Sep 17 00:00:00 2001 From: Luna Date: Fri, 18 May 2018 21:05:49 -0400 Subject: [PATCH 18/41] Properly networking `players`, render player list --- scripts/hero_select.gd | 11 +++++++++ scripts/lobby.gd | 63 ++++++++++++++++++-------------------------------- scripts/networking.gd | 54 +++++++++++++++++++++++++++++++------------ 3 files changed, 73 insertions(+), 55 deletions(-) diff --git a/scripts/hero_select.gd b/scripts/hero_select.gd index 5fd34df..eeb433a 100644 --- a/scripts/hero_select.gd +++ b/scripts/hero_select.gd @@ -22,3 +22,14 @@ func _ready(): for hero_index in range(hero_names.size()): add_item(hero_names[hero_index], hero_index) + connect("item_selected", self, "set_hero") + +func set_hero(hero): + networking.set_info("hero", hero) + +func random_hero(): + var hero = randi() % hero_names.size() + select(hero) + set_hero(hero) + return hero + diff --git a/scripts/lobby.gd b/scripts/lobby.gd index ec59d82..c3e7622 100644 --- a/scripts/lobby.gd +++ b/scripts/lobby.gd @@ -2,6 +2,8 @@ extends Control var port = null # Defined by command-line argument with default +onready var hero_select = get_node("HeroSelect/Hero") + func _ready(): if get_tree().is_network_server(): get_node("LevelSelect").show() @@ -15,23 +17,17 @@ func _ready(): get_node("Spectating").connect("toggled", networking, "set_spectating") # TODO # get_node("CustomGame/LevelSelect").connect("item_selected", self, "select_level") TODO # _send_name() + # hero_select.set_hero(0) -func _collect_info(): - var my_id = get_tree().get_network_unique_id() - var my_info = networking.players[my_id] - if not "username" in my_info: - my_info.username = get_node("Username").get_text() - if not "hero" in my_info: - my_info.hero = get_node("HeroSelect/Hero").get_selected_id() - if not "is_right_team" in my_info: - my_info.is_right_team = false # Server assigns team, wait for that + networking.connect("info_updated", self, "render_player_list") + get_tree().connect("connected_to_server", self, "_send_settings") + if get_tree().is_network_server(): + _send_settings() -func select_hero(hero): - var description = get_node("HeroSelect").hero_text[hero] - get_node("HeroDescription").set_text(description) - var my_id = get_tree().get_network_unique_id() - networking.players[my_id].hero = hero - rpc("set_hero", get_tree().get_network_unique_id(), hero) +func _send_settings(): + print("sending") + _send_name() + hero_select.random_hero() sync func set_hero(peer, hero): networking.players[peer].hero = hero @@ -39,34 +35,21 @@ sync func set_hero(peer, hero): func _send_name(): var name = get_node("Username").text - rpc("_set_name", get_tree().get_network_unique_id(), name) - -sync func _set_name(peer, name): - networking.players[peer].username = name - render_player_list() + networking.set_info("username", name) func render_player_list(): - if has_node("PlayerSettings"): - var list = "" - var hero_names = get_node("HeroSelect").hero_names - for p in networking.players: - list += "%-15s" % networking.players[p].username - list += "%-20s" % hero_names[networking.players[p].hero] - if networking.players[p].is_right_team: - list += "Right Team" - else: - list += "Left Team" - list += "\n" - get_node("JoinedGameLobby/PlayerList").set_text(list) - -sync func assign_team(peer, is_right_team): - networking.players[peer].is_right_team = is_right_team - if peer == get_tree().get_network_unique_id(): - if is_right_team: - get_node("Team").set_text("Right Team") + print(JSON.print(networking.players)) + var list = "" + var hero_names = hero_select.hero_names + for p in networking.players: + list += "%-15s" % networking.players[p].username + list += "%-20s" % hero_names[networking.players[p].hero] + if networking.players[p].is_right_team: + list += "Right Team" else: - get_node("Team").set_text("Left Team") - render_player_list() + list += "Left Team" + list += "\n" + get_node("PlayerList").set_text(list) func _start_game(): _collect_info() diff --git a/scripts/networking.gd b/scripts/networking.gd index 8cb125c..b49de6c 100644 --- a/scripts/networking.gd +++ b/scripts/networking.gd @@ -9,20 +9,18 @@ var is_connected = false # Technically this can be done with ENetcetera but it's var begun = false # TODO: This needs to go. It carries nothing of value # ALL server negotiation should happen before ANY data is investigated (in lobby) -var my_info = { - "hero": 0, - "username": "Nickname", -} var global_server_ip = "nv.cosinegaming.com" var matchmaker_tcp var right_team_next = false +signal info_updated + func _ready(): add_child(matchmaking) get_tree().connect("network_peer_disconnected", self, "unregister_player") get_tree().connect("network_peer_connected", self, "register_player") - # get_tree().connect("connected_to_server", self, "_on_connect") + get_tree().connect("connected_to_server", self, "_on_connect") # func connect_global_server(): TODO # ip = global_server_ip @@ -69,20 +67,27 @@ func start_server(port, server_playing=false): start_game() sync func start_game(level): - print(var2str(players)) rpc("_pre_configure_game", level) -func disconnect_player(id): - if get_tree().is_network_server(): - rpc("unregister_player", id) - # call_deferred("render_player_list") TODO - # func _on_connect(): # rpc("_register_player", get_tree().get_network_unique_id(), my_info) # if util.args.get_value("-start-game"): # rpc_id(1, "start_game") # is_connected = true TODO +# remote func _set_players(json): +# print(json) +# players = JSON.parse(json).result +# print("setted") +# print(JSON.print(players)) + +func send_all_info(new_peer): + for p in players: + if p != new_peer: + for key in players[p]: + var val = players[p][key] + set_info(key, val, p) + remote func register_player(new_peer): var info = {} info.is_right_team = right_team_next @@ -90,7 +95,9 @@ remote func register_player(new_peer): players[new_peer] = info if get_tree().is_network_server(): # I tell new player about all the existing people - rset_id(new_peer, "players", players) + send_all_info(new_peer) + # rset_id(new_peer, "players", players) + emit_signal("info_updated") # render_player_list() TODO # var right_team_count = 0 # Send current players' info to new player @@ -115,15 +122,32 @@ sync func unregister_player(peer): players.erase(peer) if begun: get_node("/root/Level/Players/%d" % peer).queue_free() + emit_signal("info_updated") func set_spectating(spectating): var id = get_tree().get_network_unique_id() if spectating: if players[id]: - unregister_player(id) + rpc("unregister_player", id) else: if not players[id]: - register_player(id) + rpc("register_player", id) + +sync func _set_info(key, value, peer=0): + if not peer: + peer = get_tree().get_rpc_sender_id() + if peer == 0: + # Was self. See https://github.com/godotengine/godot/issues/19026 + peer = get_tree().get_network_unique_id() + players[peer][key] = value + emit_signal("info_updated") + +func set_info(key, value, peer=0): + rpc("_set_info", str(key), value, peer) + +func _on_connect(): + emit_signal("info_updated") + register_player(get_tree().get_network_unique_id()) sync func _spawn_player(p): var hero = 0 @@ -138,7 +162,7 @@ sync func _spawn_player(p): sync func _pre_configure_game(level): level = 2 # TODO: Remove this!! begun = true - my_info.level = level # Remember the level for future player registration + # my_info.level = level # Remember the level for future player registration var self_peer_id = get_tree().get_network_unique_id() From 5ca1fe9a9d6f06f78808ef330fa0a4c02e9cdef8 Mon Sep 17 00:00:00 2001 From: Luna Date: Fri, 18 May 2018 21:17:13 -0400 Subject: [PATCH 19/41] Fix -server and -client flags --- scripts/custom_game.gd | 8 ++------ scripts/lobby.gd | 2 ++ scripts/menu.gd | 4 ++-- scripts/networking.gd | 10 ++++++++-- scripts/util.gd | 1 + 5 files changed, 15 insertions(+), 10 deletions(-) diff --git a/scripts/custom_game.gd b/scripts/custom_game.gd index 57cce07..15db1f6 100644 --- a/scripts/custom_game.gd +++ b/scripts/custom_game.gd @@ -6,18 +6,14 @@ func _ready(): func _start_server(): # Custom Game can assume we're playing as well - networking.start_server(_get_port(), true) + networking.start_server() _show_lobby() func _start_client(): var ip = get_node("IP").text - networking.start_client(ip, _get_port()) + networking.start_client(ip) _show_lobby() func _show_lobby(): get_tree().change_scene("res://scenes/lobby.tscn") -func _get_port(): - var port = util.args.get_value("-port") - return port - diff --git a/scripts/lobby.gd b/scripts/lobby.gd index c3e7622..a181761 100644 --- a/scripts/lobby.gd +++ b/scripts/lobby.gd @@ -7,6 +7,8 @@ onready var hero_select = get_node("HeroSelect/Hero") func _ready(): if get_tree().is_network_server(): get_node("LevelSelect").show() + else: + get_node("LevelSelect").hide() get_node("Username").connect("text_changed", self, "_send_name") get_node("StartGame").connect("pressed", self, "_start_game") diff --git a/scripts/menu.gd b/scripts/menu.gd index 578da9f..18eed84 100644 --- a/scripts/menu.gd +++ b/scripts/menu.gd @@ -49,12 +49,12 @@ func _arg_actions(): # if not o.get_value("-no-record") and not o.get_value("-ai"): # my_info.record = true if o.get_value("-server"): - networking.call_deferred("start_server") + networking.start_server() get_tree().change_scene("res://scenes/lobby.tscn") # if o.get_value("-matchmaker"): # call_deferred("_matchmaker_init") if o.get_value("-client"): - networking.call_deferred("start_client") + networking.start_client() get_tree().change_scene("res://scenes/lobby.tscn") if o.get_value("-start-game"): networking.call_deferred("start_game") diff --git a/scripts/networking.gd b/scripts/networking.gd index b49de6c..3575425 100644 --- a/scripts/networking.gd +++ b/scripts/networking.gd @@ -26,8 +26,12 @@ func _ready(): # ip = global_server_ip # _client_init() -func start_client(ip, port): +func start_client(ip="", port=0): # collect_info() TODO + if not ip: + ip = util.args.get_value("-ip") + if not port: + port = util.args.get_value("-port") var peer = NetworkedMultiplayerENet.new() print("Connecting to " + ip + ":" + str(port)) peer.create_client(ip, port) @@ -50,8 +54,10 @@ func _connect_to_matchmaker(game_port): matchmaker_tcp.put_var(matchmaking.messages.ready_to_connect) matchmaker_tcp.put_var(game_port) -func start_server(port, server_playing=false): +func start_server(port=0): # collect_info() TODO + if not port: + port = util.args.get_value("-port") var peer = NetworkedMultiplayerENet.new() print("Starting server on port " + str(port)) peer.create_server(port, matchmaking.GAME_SIZE) diff --git a/scripts/util.gd b/scripts/util.gd index 3d894df..318a2fa 100644 --- a/scripts/util.gd +++ b/scripts/util.gd @@ -31,6 +31,7 @@ func _get_args(): opts.add('-matchmaker', false, 'Whether to be the sole matchmaker') opts.add('-client', false, 'Immediately connect as client') opts.add('-silent', false, 'If the server is not playing, merely serving') + opts.add('-ip', '127.0.0.1', 'The ip to connect to (client only!)') opts.add('-port', 54673, 'The port to run a server on or connect to') opts.add('-hero', 'r', 'Your choice of hero (index)') opts.add('-level', 'r', 'Your choice of level (index) - server only!') From dc095e66fc20438f0b8f8109669cefed1db50ddb Mon Sep 17 00:00:00 2001 From: Luna Date: Sun, 20 May 2018 16:27:12 -0400 Subject: [PATCH 20/41] Add level select functionality; remove dead code --- scripts/lobby.gd | 45 +++++++++++++++++++++++++-------------------- scripts/menu.gd | 2 -- scripts/networking.gd | 39 +++++++++------------------------------ util/start-multiple.sh | 2 +- 4 files changed, 35 insertions(+), 53 deletions(-) diff --git a/scripts/lobby.gd b/scripts/lobby.gd index a181761..9dd6aae 100644 --- a/scripts/lobby.gd +++ b/scripts/lobby.gd @@ -3,34 +3,45 @@ extends Control var port = null # Defined by command-line argument with default onready var hero_select = get_node("HeroSelect/Hero") +onready var level_select = get_node("LevelSelect") func _ready(): - if get_tree().is_network_server(): - get_node("LevelSelect").show() - else: - get_node("LevelSelect").hide() get_node("Username").connect("text_changed", self, "_send_name") - get_node("StartGame").connect("pressed", self, "_start_game") + get_node("StartGame").connect("pressed", networking, "start_game") var spectating = util.args.get_value("-silent") get_node("Spectating").pressed = spectating - # - get_node("Spectating").connect("toggled", networking, "set_spectating") # TODO - # get_node("CustomGame/LevelSelect").connect("item_selected", self, "select_level") TODO - # _send_name() - # hero_select.set_hero(0) + get_node("Spectating").connect("toggled", networking, "set_spectating") + + if get_tree().is_network_server(): + # We put level in our players dict because it's automatically broadcast to other players + var level = util.args.get_value("-level") + if level == "r": + level = randi() % level_select.get_item_count() + _set_level(level) + + level_select.show() + level_select.select(level) + level_select.connect("item_selected", self, "_set_level") + else: + level_select.hide() networking.connect("info_updated", self, "render_player_list") - get_tree().connect("connected_to_server", self, "_send_settings") + get_tree().connect("connected_to_server", self, "_connected") if get_tree().is_network_server(): - _send_settings() + _connected() -func _send_settings(): - print("sending") +func _connected(): _send_name() hero_select.random_hero() + if util.args.get_value("-start-game"): + networking.start_game() + +func _set_level(level): + networking.set_info("level", level) + sync func set_hero(peer, hero): networking.players[peer].hero = hero render_player_list() @@ -40,7 +51,6 @@ func _send_name(): networking.set_info("username", name) func render_player_list(): - print(JSON.print(networking.players)) var list = "" var hero_names = hero_select.hero_names for p in networking.players: @@ -53,8 +63,3 @@ func render_player_list(): list += "\n" get_node("PlayerList").set_text(list) -func _start_game(): - _collect_info() - var level = 2 # TODO - networking.rpc_id(1, "start_game", level) - diff --git a/scripts/menu.gd b/scripts/menu.gd index 18eed84..c004be3 100644 --- a/scripts/menu.gd +++ b/scripts/menu.gd @@ -56,8 +56,6 @@ func _arg_actions(): if o.get_value("-client"): networking.start_client() get_tree().change_scene("res://scenes/lobby.tscn") - if o.get_value("-start-game"): - networking.call_deferred("start_game") # if o.get_value("-singleplayer"): # networking.call_deferred("start_singleplayer") if o.get_value('-h'): diff --git a/scripts/networking.gd b/scripts/networking.gd index 3575425..bb5329f 100644 --- a/scripts/networking.gd +++ b/scripts/networking.gd @@ -4,10 +4,8 @@ onready var matchmaking = preload("res://scripts/matchmaking.gd").new() remote var players = {} var players_done = [] -var is_connected = false # Technically this can be done with ENetcetera but it's easier this way # TODO: Should we abstract server so variables like this aren't cluttering everything up? var begun = false -# TODO: This needs to go. It carries nothing of value # ALL server negotiation should happen before ANY data is investigated (in lobby) var global_server_ip = "nv.cosinegaming.com" var matchmaker_tcp @@ -27,7 +25,6 @@ func _ready(): # _client_init() func start_client(ip="", port=0): - # collect_info() TODO if not ip: ip = util.args.get_value("-ip") if not port: @@ -36,7 +33,6 @@ func start_client(ip="", port=0): print("Connecting to " + ip + ":" + str(port)) peer.create_client(ip, port) get_tree().set_network_peer(peer) - # get_node("CustomGame/Client").set_text("Clienting!") TODO # func singleplayer_init(): TODO # # collect_info() TODO @@ -55,7 +51,6 @@ func _connect_to_matchmaker(game_port): matchmaker_tcp.put_var(game_port) func start_server(port=0): - # collect_info() TODO if not port: port = util.args.get_value("-port") var peer = NetworkedMultiplayerENet.new() @@ -66,26 +61,15 @@ func start_server(port=0): _connect_to_matchmaker(port) if not util.args.get_value("-silent"): register_player(get_tree().get_network_unique_id()) - # is_connected = true TODO - # get_node("CustomGame/Server").set_text("Serving!") - # get_node("JoinedGameLobby").show() if util.args.get_value("-start-game"): start_game() -sync func start_game(level): +master func _start_game(): + var level = players[1].level # TODO: Can we guarantee this will have level? rpc("_pre_configure_game", level) -# func _on_connect(): -# rpc("_register_player", get_tree().get_network_unique_id(), my_info) -# if util.args.get_value("-start-game"): -# rpc_id(1, "start_game") - # is_connected = true TODO - -# remote func _set_players(json): -# print(json) -# players = JSON.parse(json).result -# print("setted") -# print(JSON.print(players)) +func start_game(): + rpc_id(1, "_start_game") func send_all_info(new_peer): for p in players: @@ -102,22 +86,18 @@ remote func register_player(new_peer): if get_tree().is_network_server(): # I tell new player about all the existing people send_all_info(new_peer) - # rset_id(new_peer, "players", players) emit_signal("info_updated") - # render_player_list() TODO # var right_team_count = 0 # Send current players' info to new player - # Send new player, old player's info - # rpc_id(new_peer, "_register_player", old_peer, players[old_peer]) # if old_peer != new_peer: # # We need to assign team later, so count current # if players[old_peer].is_right_team: # right_team_count += 1 - # if begun: TODO this should belong to lobby + # if begun: TODO this should belong to lobby? # rpc_id(old_peer, "_spawn_player", new_peer) # rpc_id(old_peer, "_begin_player_deferred", new_peer) # Spawning is deferred # var assign_right_team = right_team_count * 2 < players.size() - # rpc("assign_team", new_peer, assign_right_team) + # set_info("is_right_team", assign_right_team, new_peer) # if not begun and players.size() == matchmaking.GAME_SIZE: # start_game() # if begun: @@ -166,7 +146,6 @@ sync func _spawn_player(p): get_node("/root/Level/Players").call_deferred("add_child", player) sync func _pre_configure_game(level): - level = 2 # TODO: Remove this!! begun = true # my_info.level = level # Remember the level for future player registration @@ -174,12 +153,12 @@ sync func _pre_configure_game(level): # Remove the interface so as to not fuck with things # But we still need the lobby alive to deal with networking! - for element in get_node("/root/Lobby").get_children(): - element.queue_free() + # for element in get_node("/root/Lobby").get_children(): + # element.queue_free() + get_node("/root/Lobby").hide() var world = load("res://scenes/levels/%d.tscn" % level).instance() get_node("/root").add_child(world) - print("added level!") # Load all players (including self) for p in players: diff --git a/util/start-multiple.sh b/util/start-multiple.sh index 1213138..8e4d3d7 100644 --- a/util/start-multiple.sh +++ b/util/start-multiple.sh @@ -10,5 +10,5 @@ fi util/open-multiple.sh $count "$@" sleep 1 -godot -start-game "$@" & +godot -client -start-game "$@" & From 2d93fd4d1e10504e4d7dc1cefd78a9c04536e857 Mon Sep 17 00:00:00 2001 From: Luna Date: Sun, 20 May 2018 16:40:45 -0400 Subject: [PATCH 21/41] Begin players properly --- scripts/networking.gd | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/scripts/networking.gd b/scripts/networking.gd index bb5329f..b092f9c 100644 --- a/scripts/networking.gd +++ b/scripts/networking.gd @@ -147,14 +147,9 @@ sync func _spawn_player(p): sync func _pre_configure_game(level): begun = true - # my_info.level = level # Remember the level for future player registration var self_peer_id = get_tree().get_network_unique_id() - # Remove the interface so as to not fuck with things - # But we still need the lobby alive to deal with networking! - # for element in get_node("/root/Lobby").get_children(): - # element.queue_free() get_node("/root/Lobby").hide() var world = load("res://scenes/levels/%d.tscn" % level).instance() @@ -165,13 +160,13 @@ sync func _pre_configure_game(level): players[p].level = level _spawn_player(p) - rpc_id(1, "done_preconfiguring", self_peer_id) + rpc_id(1, "_done_preconfiguring", self_peer_id) sync func _done_preconfiguring(who): players_done.append(who) if players_done.size() == players.size(): # We call deferred in case singleplayer has placing the player in queue still - call_deferred("rpc", "post_configure_game") + call_deferred("rpc", "_post_configure_game") sync func _post_configure_game(): # Begin all players (including self) From 257346db5a1c2f9665810bfc4f88839cb2286694 Mon Sep 17 00:00:00 2001 From: Luna Date: Sun, 20 May 2018 16:52:34 -0400 Subject: [PATCH 22/41] Add singleplayer functionality; fix -hero arg --- scenes/menu.tscn | 2 +- scenes/singleplayer_lobby.tscn | 82 ++++++++++++++++++++++++++++++++++++++++++ scripts/hero_select.gd | 2 +- scripts/lobby.gd | 7 +++- scripts/menu.gd | 18 +++------- 5 files changed, 94 insertions(+), 17 deletions(-) create mode 100644 scenes/singleplayer_lobby.tscn diff --git a/scenes/menu.tscn b/scenes/menu.tscn index fb0d0f4..830d17b 100644 --- a/scenes/menu.tscn +++ b/scenes/menu.tscn @@ -135,7 +135,7 @@ toggle_mode = false enabled_focus_mode = 2 shortcut = null group = null -text = "Singleplayer" +text = "Practice Range" flat = false align = 1 diff --git a/scenes/singleplayer_lobby.tscn b/scenes/singleplayer_lobby.tscn new file mode 100644 index 0000000..7cc9ac1 --- /dev/null +++ b/scenes/singleplayer_lobby.tscn @@ -0,0 +1,82 @@ +[gd_scene load_steps=4 format=2] + +[ext_resource path="res://scenes/lobby.tscn" type="PackedScene" id=1] +[ext_resource path="res://assets/DejaVuSansMono.ttf" type="DynamicFontData" id=2] + +[sub_resource type="DynamicFont" id=1] + +size = 40 +use_mipmaps = false +use_filter = false +font_data = ExtResource( 2 ) + +[node name="Lobby" instance=ExtResource( 1 )] + +[node name="Label" type="Label" parent="." index="0"] + +anchor_left = 0.0 +anchor_top = 0.0 +anchor_right = 0.0 +anchor_bottom = 0.0 +margin_left = 602.0 +margin_top = 276.0 +margin_right = 938.0 +margin_bottom = 324.0 +rect_pivot_offset = Vector2( 0, 0 ) +mouse_filter = 2 +mouse_default_cursor_shape = 0 +size_flags_horizontal = 1 +size_flags_vertical = 4 +custom_fonts/font = SubResource( 1 ) +text = "Practice Range" +percent_visible = 1.0 +lines_skipped = 0 +max_lines_visible = -1 + +[node name="HeroSelect" parent="." index="1"] + +margin_top = 62.0 +margin_bottom = 62.0 + +[node name="Username" parent="." index="2"] + +visible = false +margin_top = 308.0 +margin_bottom = 341.0 + +[node name="Spectating" parent="." index="3"] + +visible = false + +[node name="LevelSelect" parent="." index="4"] + +margin_top = 401.0 +margin_bottom = 442.0 +items = [ "Platform map", null, false, 0, null, "City-like thing", null, false, 1, null, "Slide", null, false, 2, null ] + +[node name="TeamLabel" parent="." index="5"] + +visible = false + +[node name="Team" parent="." index="6"] + +visible = false + +[node name="PlayerList" parent="." index="7"] + +visible = false + +[node name="StartGame" parent="." index="8"] + +margin_left = 41.0 +margin_top = 486.0 +margin_right = 163.0 +margin_bottom = 526.0 +text = "Play!" + +[node name="VSeparator" parent="." index="9"] + +visible = false + + +[editable path="HeroSelect"] diff --git a/scripts/hero_select.gd b/scripts/hero_select.gd index eeb433a..38b2726 100644 --- a/scripts/hero_select.gd +++ b/scripts/hero_select.gd @@ -25,11 +25,11 @@ func _ready(): connect("item_selected", self, "set_hero") func set_hero(hero): + select(hero) networking.set_info("hero", hero) func random_hero(): var hero = randi() % hero_names.size() - select(hero) set_hero(hero) return hero diff --git a/scripts/lobby.gd b/scripts/lobby.gd index 9dd6aae..b443e86 100644 --- a/scripts/lobby.gd +++ b/scripts/lobby.gd @@ -19,6 +19,7 @@ func _ready(): var level = util.args.get_value("-level") if level == "r": level = randi() % level_select.get_item_count() + level = int(level) _set_level(level) level_select.show() @@ -34,7 +35,11 @@ func _ready(): func _connected(): _send_name() - hero_select.random_hero() + if util.args.get_value("-hero") == "r": + hero_select.random_hero() + else: + print(util.args.get_value("-hero")) + hero_select.set_hero(int(util.args.get_value("-hero"))) if util.args.get_value("-start-game"): networking.start_game() diff --git a/scripts/menu.gd b/scripts/menu.gd index c004be3..55cab18 100644 --- a/scripts/menu.gd +++ b/scripts/menu.gd @@ -19,7 +19,8 @@ func _custom_game(): get_tree().change_scene("res://scenes/custom_game.tscn") func _singleplayer(): - print("still refactoring singleplayer") + networking.start_server() + get_tree().change_scene("res://scenes/singleplayer_lobby.tscn") # Command line @@ -33,17 +34,6 @@ func _option_sel(button_name, option): func _arg_actions(): var o = util.args - # if o.get_value("-silent"): - # server_playing = false - # if o.get_value("-hero"): - # var hero = o.get_value("-hero") - # _option_sel("PlayerSettings/HeroSelect", hero) - # # For some reason, calling _option_sel doesn't trigger the actual selection - # select_hero(get_node("PlayerSettings/HeroSelect").get_selected_id()) - # if o.get_value("-level"): - # _option_sel("CustomGame/LevelSelect", o.get_value("-level")) - # if o.get_value("-port"): - # port = o.get_value("-port") # if o.get_value("-ai"): # my_info.is_ai = true # if not o.get_value("-no-record") and not o.get_value("-ai"): @@ -56,8 +46,8 @@ func _arg_actions(): if o.get_value("-client"): networking.start_client() get_tree().change_scene("res://scenes/lobby.tscn") - # if o.get_value("-singleplayer"): - # networking.call_deferred("start_singleplayer") + if o.get_value("-singleplayer"): + _singleplayer() if o.get_value('-h'): o.print_help() quit() From 7b12180695f4a170b86a3b32cc068d2c4a5a3a63 Mon Sep 17 00:00:00 2001 From: Luna Date: Sun, 20 May 2018 16:56:25 -0400 Subject: [PATCH 23/41] [WIP] Add matchmaking --- scripts/menu.gd | 4 +++- scripts/networking.gd | 9 +-------- 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/scripts/menu.gd b/scripts/menu.gd index 55cab18..2d4d1d6 100644 --- a/scripts/menu.gd +++ b/scripts/menu.gd @@ -13,7 +13,9 @@ func _gui_setup(): get_node("Center/Singleplayer").connect("pressed", self, "_singleplayer") func _find_game(): - print("still refactoring matchmaker") + var ip = networking.global_server_ip + var port = networking.matchmaking.MATCHMAKING_PORT + networking.start_client(ip, port) func _custom_game(): get_tree().change_scene("res://scenes/custom_game.tscn") diff --git a/scripts/networking.gd b/scripts/networking.gd index b092f9c..878bb35 100644 --- a/scripts/networking.gd +++ b/scripts/networking.gd @@ -27,6 +27,7 @@ func _ready(): func start_client(ip="", port=0): if not ip: ip = util.args.get_value("-ip") + ip = IP.resolve_hostname(ip) if not port: port = util.args.get_value("-port") var peer = NetworkedMultiplayerENet.new() @@ -34,14 +35,6 @@ func start_client(ip="", port=0): peer.create_client(ip, port) get_tree().set_network_peer(peer) -# func singleplayer_init(): TODO -# # collect_info() TODO -# var peer = NetworkedMultiplayerENet.new() -# peer.create_server(port, 1) -# get_tree().set_network_peer(peer) -# players[1] = my_info -# start_game() - func _connect_to_matchmaker(game_port): var matchmaker_peer = StreamPeerTCP.new() matchmaker_peer.connect_to_host("127.0.0.1", matchmaking.SERVER_TO_SERVER_PORT) From 054b240c4f20dc6d272ea5e9cdfdbe863cc9d1d0 Mon Sep 17 00:00:00 2001 From: Luna Date: Sun, 20 May 2018 17:55:44 -0400 Subject: [PATCH 24/41] Fix spectating mode by making it a player_info --- scripts/lobby.gd | 26 ++++++++++++++++++-------- scripts/networking.gd | 22 +++++++--------------- 2 files changed, 25 insertions(+), 23 deletions(-) diff --git a/scripts/lobby.gd b/scripts/lobby.gd index b443e86..cc606bf 100644 --- a/scripts/lobby.gd +++ b/scripts/lobby.gd @@ -12,7 +12,7 @@ func _ready(): var spectating = util.args.get_value("-silent") get_node("Spectating").pressed = spectating - get_node("Spectating").connect("toggled", networking, "set_spectating") + get_node("Spectating").connect("toggled", self, "_set_spectating") if get_tree().is_network_server(): # We put level in our players dict because it's automatically broadcast to other players @@ -47,6 +47,9 @@ func _connected(): func _set_level(level): networking.set_info("level", level) +func _set_spectating(is_spectating): + networking.set_info("spectating", is_spectating) + sync func set_hero(peer, hero): networking.players[peer].hero = hero render_player_list() @@ -59,12 +62,19 @@ func render_player_list(): var list = "" var hero_names = hero_select.hero_names for p in networking.players: - list += "%-15s" % networking.players[p].username - list += "%-20s" % hero_names[networking.players[p].hero] - if networking.players[p].is_right_team: - list += "Right Team" - else: - list += "Left Team" - list += "\n" + var player = networking.players[p] + var spectating = player.has("spectating") and player.spectating + # A spectating server is just a dedicated server, ignore it + if not (spectating and p == 1): + list += "%-15s " % player.username + list += "%-20s " % hero_names[player.hero] + var team_format = "%-14s" + if player.is_right_team: + list += team_format % "Right Team" + else: + list += team_format % "Left Team" + if spectating: + list += "Spectating" + list += "\n" get_node("PlayerList").set_text(list) diff --git a/scripts/networking.gd b/scripts/networking.gd index 878bb35..a37779a 100644 --- a/scripts/networking.gd +++ b/scripts/networking.gd @@ -52,10 +52,9 @@ func start_server(port=0): get_tree().set_network_peer(peer) # As soon as we're listening, let the matchmaker know _connect_to_matchmaker(port) - if not util.args.get_value("-silent"): - register_player(get_tree().get_network_unique_id()) - if util.args.get_value("-start-game"): - start_game() + register_player(get_tree().get_network_unique_id()) + if util.args.get_value("-silent"): + set_info("spectating", true) master func _start_game(): var level = players[1].level # TODO: Can we guarantee this will have level? @@ -103,15 +102,6 @@ sync func unregister_player(peer): get_node("/root/Level/Players/%d" % peer).queue_free() emit_signal("info_updated") -func set_spectating(spectating): - var id = get_tree().get_network_unique_id() - if spectating: - if players[id]: - rpc("unregister_player", id) - else: - if not players[id]: - rpc("register_player", id) - sync func _set_info(key, value, peer=0): if not peer: peer = get_tree().get_rpc_sender_id() @@ -151,7 +141,8 @@ sync func _pre_configure_game(level): # Load all players (including self) for p in players: players[p].level = level - _spawn_player(p) + if not (players[p].has("spectating") and players[p].spectating): + _spawn_player(p) rpc_id(1, "_done_preconfiguring", self_peer_id) @@ -164,7 +155,8 @@ sync func _done_preconfiguring(who): sync func _post_configure_game(): # Begin all players (including self) for p in players: - _begin_player_deferred(p) + if not (players[p].has("spectating") and players[p].spectating): + _begin_player_deferred(p) func _begin_player(peer): get_node("/root/Level/Players/%d" % peer).begin() From 996e4e24cc422d9406460557902762d2186b22c4 Mon Sep 17 00:00:00 2001 From: Luna Date: Sun, 20 May 2018 18:08:37 -0400 Subject: [PATCH 25/41] [WIP] Add back matchmaking! One problem remains: start_game behaves the same whether a game has started or not. --- scripts/custom_game.gd | 5 ----- scripts/lobby.gd | 2 +- scripts/matchmaking.gd | 2 +- scripts/menu.gd | 9 ++++----- scripts/networking.gd | 17 +++++++++++++---- 5 files changed, 19 insertions(+), 16 deletions(-) diff --git a/scripts/custom_game.gd b/scripts/custom_game.gd index 15db1f6..ec77fb5 100644 --- a/scripts/custom_game.gd +++ b/scripts/custom_game.gd @@ -7,13 +7,8 @@ func _ready(): func _start_server(): # Custom Game can assume we're playing as well networking.start_server() - _show_lobby() func _start_client(): var ip = get_node("IP").text networking.start_client(ip) - _show_lobby() - -func _show_lobby(): - get_tree().change_scene("res://scenes/lobby.tscn") diff --git a/scripts/lobby.gd b/scripts/lobby.gd index cc606bf..390a257 100644 --- a/scripts/lobby.gd +++ b/scripts/lobby.gd @@ -45,7 +45,7 @@ func _connected(): networking.start_game() func _set_level(level): - networking.set_info("level", level) + networking.level = level func _set_spectating(is_spectating): networking.set_info("spectating", is_spectating) diff --git a/scripts/matchmaking.gd b/scripts/matchmaking.gd index f137556..30e3e4f 100644 --- a/scripts/matchmaking.gd +++ b/scripts/matchmaking.gd @@ -80,7 +80,7 @@ func queue(netid): # # func add_to_game(netid, port): - lobby.rpc_id(netid, "_client_init", port) + networking.rpc_id(netid, "reconnect", port) func skirmish_to_game(port, count=1): for i in range(count): diff --git a/scripts/menu.gd b/scripts/menu.gd index 2d4d1d6..95b6299 100644 --- a/scripts/menu.gd +++ b/scripts/menu.gd @@ -13,7 +13,8 @@ func _gui_setup(): get_node("Center/Singleplayer").connect("pressed", self, "_singleplayer") func _find_game(): - var ip = networking.global_server_ip + # var ip = networking.global_server_ip + var ip = util.args.get_value("-ip") var port = networking.matchmaking.MATCHMAKING_PORT networking.start_client(ip, port) @@ -42,12 +43,10 @@ func _arg_actions(): # my_info.record = true if o.get_value("-server"): networking.start_server() - get_tree().change_scene("res://scenes/lobby.tscn") - # if o.get_value("-matchmaker"): - # call_deferred("_matchmaker_init") + if o.get_value("-matchmaker"): + networking.matchmaking.start_matchmaker() if o.get_value("-client"): networking.start_client() - get_tree().change_scene("res://scenes/lobby.tscn") if o.get_value("-singleplayer"): _singleplayer() if o.get_value('-h'): diff --git a/scripts/networking.gd b/scripts/networking.gd index a37779a..d92c63b 100644 --- a/scripts/networking.gd +++ b/scripts/networking.gd @@ -11,6 +11,8 @@ var global_server_ip = "nv.cosinegaming.com" var matchmaker_tcp var right_team_next = false +var level + signal info_updated func _ready(): @@ -34,6 +36,12 @@ func start_client(ip="", port=0): print("Connecting to " + ip + ":" + str(port)) peer.create_client(ip, port) get_tree().set_network_peer(peer) + get_tree().change_scene("res://scenes/lobby.tscn") + +remote func reconnect(port): + # Reset previously known players + players = {} + start_client("", port) func _connect_to_matchmaker(game_port): var matchmaker_peer = StreamPeerTCP.new() @@ -55,9 +63,9 @@ func start_server(port=0): register_player(get_tree().get_network_unique_id()) if util.args.get_value("-silent"): set_info("spectating", true) + get_tree().change_scene("res://scenes/lobby.tscn") master func _start_game(): - var level = players[1].level # TODO: Can we guarantee this will have level? rpc("_pre_configure_game", level) func start_game(): @@ -108,8 +116,9 @@ sync func _set_info(key, value, peer=0): if peer == 0: # Was self. See https://github.com/godotengine/godot/issues/19026 peer = get_tree().get_network_unique_id() - players[peer][key] = value - emit_signal("info_updated") + if players.has(peer): + players[peer][key] = value + emit_signal("info_updated") func set_info(key, value, peer=0): rpc("_set_info", str(key), value, peer) @@ -140,7 +149,6 @@ sync func _pre_configure_game(level): # Load all players (including self) for p in players: - players[p].level = level if not (players[p].has("spectating") and players[p].spectating): _spawn_player(p) @@ -149,6 +157,7 @@ sync func _pre_configure_game(level): sync func _done_preconfiguring(who): players_done.append(who) if players_done.size() == players.size(): + print("done") # We call deferred in case singleplayer has placing the player in queue still call_deferred("rpc", "_post_configure_game") From a3036de2bb0c8f5736562bce07ccd335a961d71e Mon Sep 17 00:00:00 2001 From: Luna Date: Sun, 20 May 2018 18:50:18 -0400 Subject: [PATCH 26/41] Add "ready" feature --- scenes/lobby.tscn | 35 ++++++++++++++++++++++++++++++----- scripts/lobby.gd | 27 ++++++++++++++++++--------- scripts/networking.gd | 26 ++++++++++++++++++-------- util/server.sh | 2 +- 4 files changed, 67 insertions(+), 23 deletions(-) diff --git a/scenes/lobby.tscn b/scenes/lobby.tscn index 10f49eb..8381d61 100644 --- a/scenes/lobby.tscn +++ b/scenes/lobby.tscn @@ -141,7 +141,7 @@ toggle_mode = true enabled_focus_mode = 2 shortcut = null group = null -text = "Spectating" +text = "Spectating " flat = false align = 0 @@ -252,16 +252,41 @@ percent_visible = 1.0 lines_skipped = 0 max_lines_visible = -1 -[node name="StartGame" type="Button" parent="." index="7"] +[node name="Ready" type="CheckButton" parent="." index="7"] anchor_left = 0.0 anchor_top = 0.0 anchor_right = 0.0 anchor_bottom = 0.0 +margin_left = 493.0 +margin_top = 436.0 +margin_right = 628.0 +margin_bottom = 476.0 +rect_pivot_offset = Vector2( 0, 0 ) +focus_mode = 2 +mouse_filter = 0 +mouse_default_cursor_shape = 0 +size_flags_horizontal = 1 +size_flags_vertical = 1 +toggle_mode = true +enabled_focus_mode = 2 +shortcut = null +group = null +text = "Ready " +flat = false +align = 0 + +[node name="StartGame" type="Button" parent="." index="8"] + +visible = false +anchor_left = 0.0 +anchor_top = 0.0 +anchor_right = 0.0 +anchor_bottom = 0.0 margin_left = 496.0 -margin_top = 453.0 +margin_top = 491.0 margin_right = 618.0 -margin_bottom = 493.0 +margin_bottom = 531.0 rect_pivot_offset = Vector2( 0, 0 ) focus_mode = 2 mouse_filter = 0 @@ -276,7 +301,7 @@ text = "Ready!" flat = false align = 1 -[node name="VSeparator" type="VSeparator" parent="." index="8"] +[node name="VSeparator" type="VSeparator" parent="." index="9"] anchor_left = 0.0 anchor_top = 0.0 diff --git a/scripts/lobby.gd b/scripts/lobby.gd index 390a257..fa2a277 100644 --- a/scripts/lobby.gd +++ b/scripts/lobby.gd @@ -4,15 +4,21 @@ var port = null # Defined by command-line argument with default onready var hero_select = get_node("HeroSelect/Hero") onready var level_select = get_node("LevelSelect") +onready var start_game_button = get_node("StartGame") func _ready(): get_node("Username").connect("text_changed", self, "_send_name") - get_node("StartGame").connect("pressed", networking, "start_game") var spectating = util.args.get_value("-silent") get_node("Spectating").pressed = spectating - get_node("Spectating").connect("toggled", self, "_set_spectating") + get_node("Spectating").connect("toggled", self, "_set_info_callback", ["spectating"]) + get_node("Ready").connect("toggled", self, "_set_info_callback", ["ready"]) + start_game_button.connect("pressed", networking, "start_game") + if get_tree().is_network_server(): + start_game_button.show() + else: + start_game_button.hide() if get_tree().is_network_server(): # We put level in our players dict because it's automatically broadcast to other players @@ -47,8 +53,10 @@ func _connected(): func _set_level(level): networking.level = level -func _set_spectating(is_spectating): - networking.set_info("spectating", is_spectating) +# Because of the annoying way callbacks work (automatic parameter, optional parameter) +# We need a utility function for making these kinds of callbacks for set_info +func _set_info_callback(value, key): + networking.set_info(key, value) sync func set_hero(peer, hero): networking.players[peer].hero = hero @@ -63,17 +71,18 @@ func render_player_list(): var hero_names = hero_select.hero_names for p in networking.players: var player = networking.players[p] - var spectating = player.has("spectating") and player.spectating # A spectating server is just a dedicated server, ignore it - if not (spectating and p == 1): + if not (player.spectating and p == 1): list += "%-15s " % player.username - list += "%-20s " % hero_names[player.hero] - var team_format = "%-14s" + list += "%-10s " % hero_names[player.hero] + var team_format = "%-11s" if player.is_right_team: list += team_format % "Right Team" else: list += team_format % "Left Team" - if spectating: + var ready_text = "Ready" if player.ready else "" + list += "%-6s" % ready_text + if player.spectating: list += "Spectating" list += "\n" get_node("PlayerList").set_text(list) diff --git a/scripts/networking.gd b/scripts/networking.gd index d92c63b..6971a16 100644 --- a/scripts/networking.gd +++ b/scripts/networking.gd @@ -4,9 +4,7 @@ onready var matchmaking = preload("res://scripts/matchmaking.gd").new() remote var players = {} var players_done = [] -# TODO: Should we abstract server so variables like this aren't cluttering everything up? var begun = false -# ALL server negotiation should happen before ANY data is investigated (in lobby) var global_server_ip = "nv.cosinegaming.com" var matchmaker_tcp var right_team_next = false @@ -22,9 +20,7 @@ func _ready(): get_tree().connect("network_peer_connected", self, "register_player") get_tree().connect("connected_to_server", self, "_on_connect") -# func connect_global_server(): TODO -# ip = global_server_ip -# _client_init() + connect("info_updated", self, "_check_info") func start_client(ip="", port=0): if not ip: @@ -81,6 +77,8 @@ func send_all_info(new_peer): remote func register_player(new_peer): var info = {} info.is_right_team = right_team_next + info.ready = false + info.spectating = false right_team_next = not right_team_next players[new_peer] = info if get_tree().is_network_server(): @@ -127,9 +125,21 @@ func _on_connect(): emit_signal("info_updated") register_player(get_tree().get_network_unique_id()) +func _check_info(): + # Check for "everyone is ready" + # Only have 1 person check this, might as well be server + if get_tree().is_network_server(): + var ready = true + for p in players: + if not players[p].spectating: + if not players[p].ready: + ready = false + if ready: + start_game() + sync func _spawn_player(p): var hero = 0 - if players[p].has("hero"): # TODO: Rethink how we do this whole shenanigan + if players[p].has("hero"): hero = players[p].hero var player = load("res://scenes/heroes/" + str(hero) + ".tscn").instance() player.set_name(str(p)) @@ -149,7 +159,7 @@ sync func _pre_configure_game(level): # Load all players (including self) for p in players: - if not (players[p].has("spectating") and players[p].spectating): + if not players[p].spectating: _spawn_player(p) rpc_id(1, "_done_preconfiguring", self_peer_id) @@ -164,7 +174,7 @@ sync func _done_preconfiguring(who): sync func _post_configure_game(): # Begin all players (including self) for p in players: - if not (players[p].has("spectating") and players[p].spectating): + if not players[p].spectating: _begin_player_deferred(p) func _begin_player(peer): diff --git a/util/server.sh b/util/server.sh index d08c8bb..3f24370 100644 --- a/util/server.sh +++ b/util/server.sh @@ -1,2 +1,2 @@ -godot-server -level=2 -silent -server -start-game "$@" +godot-server -level=2 -silent -server "$@" From 345ca3d6fe10d9fe9f1e4c9f93ce4aa52c9821c9 Mon Sep 17 00:00:00 2001 From: Luna Date: Sun, 20 May 2018 19:49:06 -0400 Subject: [PATCH 27/41] Fix joining late! --- scenes/lobby.tscn | 2 +- scripts/heroes/3.gd | 2 +- scripts/heroes/4.gd | 2 +- scripts/heroes/5.gd | 2 +- scripts/heroes/5_portal.gd | 2 +- scripts/lobby.gd | 16 +++++++++++++--- scripts/networking.gd | 22 +++++++++++++--------- scripts/player.gd | 3 ++- scripts/util.gd | 6 +++++- 9 files changed, 38 insertions(+), 19 deletions(-) diff --git a/scenes/lobby.tscn b/scenes/lobby.tscn index 8381d61..66f376c 100644 --- a/scenes/lobby.tscn +++ b/scenes/lobby.tscn @@ -297,7 +297,7 @@ toggle_mode = false enabled_focus_mode = 2 shortcut = null group = null -text = "Ready!" +text = "Start!" flat = false align = 1 diff --git a/scripts/heroes/3.gd b/scripts/heroes/3.gd index b5603af..7f5229e 100644 --- a/scripts/heroes/3.gd +++ b/scripts/heroes/3.gd @@ -90,7 +90,7 @@ func set_boosted(node, is_boosted): sync func merge(node_name): set_boosting(true) - var other = $"/root/Level/Players".get_node(node_name) + var other = util.get_player(node_name) set_boosted(other, true) merged = other diff --git a/scripts/heroes/4.gd b/scripts/heroes/4.gd index 179792a..b76049c 100644 --- a/scripts/heroes/4.gd +++ b/scripts/heroes/4.gd @@ -60,7 +60,7 @@ func _process(delta): sync func stun(net_id, position): # Stun the thing! - var player = get_node("/root/Level/Players/%s" % net_id) + var player = util.get_player(net_id) player.set_linear_velocity(Vector3()) # Show the beam! diff --git a/scripts/heroes/5.gd b/scripts/heroes/5.gd index 72fd2e8..7697230 100644 --- a/scripts/heroes/5.gd +++ b/scripts/heroes/5.gd @@ -66,7 +66,7 @@ func flick_input(): build_charge(flick_charge) sync func flick(player_id, towards): - var who = $"/root/Level/Players".get_node(player_id) + var who = util.get_player(player_id) if who.is_network_master(): var direction = towards - who.translation var impulse = direction.normalized() * flick_strength * who.get_mass() diff --git a/scripts/heroes/5_portal.gd b/scripts/heroes/5_portal.gd index da361b2..757f7d9 100644 --- a/scripts/heroes/5_portal.gd +++ b/scripts/heroes/5_portal.gd @@ -25,7 +25,7 @@ func _exit_tree(): other.queue_free() func init(maker): - + index = maker.placement.placed.size() # If index is odd, we're the second (1, 3...), if even, first (0, 4...) diff --git a/scripts/lobby.gd b/scripts/lobby.gd index fa2a277..31fff35 100644 --- a/scripts/lobby.gd +++ b/scripts/lobby.gd @@ -5,6 +5,7 @@ var port = null # Defined by command-line argument with default onready var hero_select = get_node("HeroSelect/Hero") onready var level_select = get_node("LevelSelect") onready var start_game_button = get_node("StartGame") +onready var ready_button = get_node("Ready") func _ready(): @@ -13,12 +14,12 @@ func _ready(): var spectating = util.args.get_value("-silent") get_node("Spectating").pressed = spectating get_node("Spectating").connect("toggled", self, "_set_info_callback", ["spectating"]) - get_node("Ready").connect("toggled", self, "_set_info_callback", ["ready"]) + ready_button.connect("toggled", self, "_set_info_callback", ["ready"]) start_game_button.connect("pressed", networking, "start_game") + # Shown, maybe, in _check_begun + start_game_button.hide() if get_tree().is_network_server(): start_game_button.show() - else: - start_game_button.hide() if get_tree().is_network_server(): # We put level in our players dict because it's automatically broadcast to other players @@ -40,6 +41,7 @@ func _ready(): _connected() func _connected(): + _send_name() if util.args.get_value("-hero") == "r": hero_select.random_hero() @@ -66,7 +68,15 @@ func _send_name(): var name = get_node("Username").text networking.set_info("username", name) +func _check_begun(): + var game_started = networking.players[1].begun + if game_started: + start_game_button.show() + # The "Ready" toggle doesn't really make sense on a started game + ready_button.hide() + func render_player_list(): + _check_begun() var list = "" var hero_names = hero_select.hero_names for p in networking.players: diff --git a/scripts/networking.gd b/scripts/networking.gd index 6971a16..9e97536 100644 --- a/scripts/networking.gd +++ b/scripts/networking.gd @@ -4,7 +4,6 @@ onready var matchmaking = preload("res://scripts/matchmaking.gd").new() remote var players = {} var players_done = [] -var begun = false var global_server_ip = "nv.cosinegaming.com" var matchmaker_tcp var right_team_next = false @@ -79,6 +78,7 @@ remote func register_player(new_peer): info.is_right_team = right_team_next info.ready = false info.spectating = false + info.begun = false right_team_next = not right_team_next players[new_peer] = info if get_tree().is_network_server(): @@ -104,8 +104,9 @@ remote func register_player(new_peer): sync func unregister_player(peer): players.erase(peer) - if begun: - get_node("/root/Level/Players/%d" % peer).queue_free() + var p = util.get_player(peer) + if p: + p.queue_free() emit_signal("info_updated") sync func _set_info(key, value, peer=0): @@ -148,20 +149,23 @@ sync func _spawn_player(p): get_node("/root/Level/Players").call_deferred("add_child", player) sync func _pre_configure_game(level): - begun = true var self_peer_id = get_tree().get_network_unique_id() - get_node("/root/Lobby").hide() + if not players[self_peer_id].begun: + get_node("/root/Lobby").hide() - var world = load("res://scenes/levels/%d.tscn" % level).instance() - get_node("/root").add_child(world) + var world = load("res://scenes/levels/%d.tscn" % level).instance() + get_node("/root").add_child(world) # Load all players (including self) for p in players: if not players[p].spectating: - _spawn_player(p) + var existing_player = util.get_player(p) + if not players[self_peer_id].begun or not existing_player: + _spawn_player(p) + set_info("begun", true) rpc_id(1, "_done_preconfiguring", self_peer_id) sync func _done_preconfiguring(who): @@ -178,7 +182,7 @@ sync func _post_configure_game(): _begin_player_deferred(p) func _begin_player(peer): - get_node("/root/Level/Players/%d" % peer).begin() + util.get_player(peer).begin() remote func _begin_player_deferred(peer): call_deferred("_begin_player", peer) diff --git a/scripts/player.gd b/scripts/player.gd index 2adddfa..887a7cb 100644 --- a/scripts/player.gd +++ b/scripts/player.gd @@ -56,7 +56,6 @@ func _ready(): get_node("TPCamera/Camera/Ray").add_exception(self) get_node(tp_camera).set_enabled(true) get_node(tp_camera).cam_view_sensitivity = 0.05 - spawn() if "is_ai" in player_info and player_info.is_ai and not ai_instanced: add_child(preload("res://scenes/ai.tscn").instance()) ai_instanced = true @@ -193,6 +192,8 @@ func begin(): for mesh in colored_meshes: get_node(mesh).set_surface_material(0, mat) + spawn() + func toggle_mouse_capture(): if (Input.get_mouse_mode() == Input.MOUSE_MODE_CAPTURED): Input.set_mouse_mode(Input.MOUSE_MODE_VISIBLE) diff --git a/scripts/util.gd b/scripts/util.gd index 318a2fa..4a3b62a 100644 --- a/scripts/util.gd +++ b/scripts/util.gd @@ -10,7 +10,11 @@ func _ready(): args = _get_args() func get_master_player(): - var path = "/root/Level/Players/%d" % get_tree().get_network_unique_id() + return get_player(get_tree().get_network_unique_id()) + +func get_player(netid): + # We not %d? Because sometimes we need to do get_player(thing.get_name()) + var path = "/root/Level/Players/%s" % str(netid) if has_node(path): return get_node(path) else: From fd7b1b9c5eaa0329547c3e3fe0172cb097e73edd Mon Sep 17 00:00:00 2001 From: Luna Date: Tue, 22 May 2018 20:04:36 -0400 Subject: [PATCH 28/41] Add back buttons to all submenus --- scenes/custom_game.tscn | 26 +++++++++++++++++++++++++- scenes/lobby.tscn | 24 ++++++++++++++++++++++++ scenes/menu.tscn | 24 ++++++++++++++++++++++++ scripts/custom_game.gd | 2 +- scripts/lobby.gd | 5 +++++ scripts/menu.gd | 1 + 6 files changed, 80 insertions(+), 2 deletions(-) diff --git a/scenes/custom_game.tscn b/scenes/custom_game.tscn index 799f501..1bc0d28 100644 --- a/scenes/custom_game.tscn +++ b/scenes/custom_game.tscn @@ -36,7 +36,7 @@ anchor_bottom = 0.0 margin_left = 498.0 margin_top = 140.0 margin_right = 518.0 -margin_bottom = 563.0 +margin_bottom = 481.0 rect_pivot_offset = Vector2( 0, 0 ) mouse_filter = 0 mouse_default_cursor_shape = 0 @@ -205,4 +205,28 @@ percent_visible = 1.0 lines_skipped = 0 max_lines_visible = -1 +[node name="Back" type="Button" parent="." index="8"] + +anchor_left = 0.0 +anchor_top = 0.0 +anchor_right = 0.0 +anchor_bottom = 0.0 +margin_left = 437.0 +margin_top = 509.0 +margin_right = 581.0 +margin_bottom = 537.0 +rect_pivot_offset = Vector2( 0, 0 ) +focus_mode = 2 +mouse_filter = 0 +mouse_default_cursor_shape = 0 +size_flags_horizontal = 1 +size_flags_vertical = 1 +toggle_mode = false +enabled_focus_mode = 2 +shortcut = null +group = null +text = "Back to menu" +flat = false +align = 1 + diff --git a/scenes/lobby.tscn b/scenes/lobby.tscn index 66f376c..2458770 100644 --- a/scenes/lobby.tscn +++ b/scenes/lobby.tscn @@ -317,5 +317,29 @@ mouse_default_cursor_shape = 0 size_flags_horizontal = 1 size_flags_vertical = 1 +[node name="Back" type="Button" parent="." index="10"] + +anchor_left = 0.0 +anchor_top = 0.0 +anchor_right = 0.0 +anchor_bottom = 0.0 +margin_left = 834.0 +margin_top = 443.0 +margin_right = 978.0 +margin_bottom = 471.0 +rect_pivot_offset = Vector2( 0, 0 ) +focus_mode = 2 +mouse_filter = 0 +mouse_default_cursor_shape = 0 +size_flags_horizontal = 1 +size_flags_vertical = 1 +toggle_mode = false +enabled_focus_mode = 2 +shortcut = null +group = null +text = "Exit to menu" +flat = false +align = 1 + [editable path="HeroSelect"] diff --git a/scenes/menu.tscn b/scenes/menu.tscn index 830d17b..ce87646 100644 --- a/scenes/menu.tscn +++ b/scenes/menu.tscn @@ -139,4 +139,28 @@ text = "Practice Range" flat = false align = 1 +[node name="Quit" type="Button" parent="Center" index="3"] + +anchor_left = 0.0 +anchor_top = 0.0 +anchor_right = 0.0 +anchor_bottom = 0.0 +margin_left = -252.0 +margin_top = 200.0 +margin_right = 298.0 +margin_bottom = 266.0 +rect_pivot_offset = Vector2( 0, 0 ) +focus_mode = 2 +mouse_filter = 0 +mouse_default_cursor_shape = 0 +size_flags_horizontal = 1 +size_flags_vertical = 1 +toggle_mode = false +enabled_focus_mode = 2 +shortcut = null +group = null +text = "Quit" +flat = false +align = 1 + diff --git a/scripts/custom_game.gd b/scripts/custom_game.gd index ec77fb5..996d758 100644 --- a/scripts/custom_game.gd +++ b/scripts/custom_game.gd @@ -3,6 +3,7 @@ extends Control func _ready(): get_node("Server").connect("pressed", self, "_start_server") get_node("Client").connect("pressed", self, "_start_client") + get_node("Back").connect("pressed", get_tree(), "change_scene", ["res://scenes/menu.tscn"]) func _start_server(): # Custom Game can assume we're playing as well @@ -11,4 +12,3 @@ func _start_server(): func _start_client(): var ip = get_node("IP").text networking.start_client(ip) - diff --git a/scripts/lobby.gd b/scripts/lobby.gd index 31fff35..d96f8d8 100644 --- a/scripts/lobby.gd +++ b/scripts/lobby.gd @@ -16,6 +16,7 @@ func _ready(): get_node("Spectating").connect("toggled", self, "_set_info_callback", ["spectating"]) ready_button.connect("toggled", self, "_set_info_callback", ["ready"]) start_game_button.connect("pressed", networking, "start_game") + get_node("Back").connect("pressed", self, "_exit_to_menu") # Shown, maybe, in _check_begun start_game_button.hide() if get_tree().is_network_server(): @@ -97,3 +98,7 @@ func render_player_list(): list += "\n" get_node("PlayerList").set_text(list) +func _exit_to_menu(): + get_tree().network_peer.close_connection() + get_tree().change_scene("res://scenes/menu.tscn") + diff --git a/scripts/menu.gd b/scripts/menu.gd index 95b6299..e11b912 100644 --- a/scripts/menu.gd +++ b/scripts/menu.gd @@ -11,6 +11,7 @@ func _gui_setup(): get_node("Center/Play").connect("pressed", self, "_find_game") get_node("Center/CustomGame").connect("pressed", self, "_custom_game") get_node("Center/Singleplayer").connect("pressed", self, "_singleplayer") + get_node("Center/Quit").connect("pressed", get_tree(), "quit") func _find_game(): # var ip = networking.global_server_ip From 58b2fdf39fdcb9dd7ddc8b07cb76eafbed63fae1 Mon Sep 17 00:00:00 2001 From: Luna Date: Sat, 26 May 2018 12:31:15 -0400 Subject: [PATCH 29/41] Fix peers not properly sharing other peer's info --- scripts/hero_select.gd | 2 +- scripts/lobby.gd | 22 ++++++++++++++-------- scripts/networking.gd | 26 ++++++++++++++------------ 3 files changed, 29 insertions(+), 21 deletions(-) diff --git a/scripts/hero_select.gd b/scripts/hero_select.gd index 38b2726..ebb7b3c 100644 --- a/scripts/hero_select.gd +++ b/scripts/hero_select.gd @@ -26,7 +26,7 @@ func _ready(): func set_hero(hero): select(hero) - networking.set_info("hero", hero) + networking.set_info_from_server("hero", hero) func random_hero(): var hero = randi() % hero_names.size() diff --git a/scripts/lobby.gd b/scripts/lobby.gd index d96f8d8..7aab4cb 100644 --- a/scripts/lobby.gd +++ b/scripts/lobby.gd @@ -9,14 +9,20 @@ onready var ready_button = get_node("Ready") func _ready(): + # Connect (to networking) get_node("Username").connect("text_changed", self, "_send_name") - - var spectating = util.args.get_value("-silent") - get_node("Spectating").pressed = spectating get_node("Spectating").connect("toggled", self, "_set_info_callback", ["spectating"]) ready_button.connect("toggled", self, "_set_info_callback", ["ready"]) start_game_button.connect("pressed", networking, "start_game") + # Connect (from networking) + networking.connect("info_updated", self, "render_player_list") + get_tree().connect("connected_to_server", self, "_connected") + + # Connect (static) get_node("Back").connect("pressed", self, "_exit_to_menu") + + var spectating = util.args.get_value("-silent") + get_node("Spectating").pressed = spectating # Shown, maybe, in _check_begun start_game_button.hide() if get_tree().is_network_server(): @@ -36,18 +42,18 @@ func _ready(): else: level_select.hide() - networking.connect("info_updated", self, "render_player_list") - get_tree().connect("connected_to_server", self, "_connected") if get_tree().is_network_server(): _connected() func _connected(): _send_name() + networking.set_info_from_server("ready", false) + networking.set_info_from_server("spectating", util.args.get_value("-silent")) + networking.set_info_from_server("begun", false) if util.args.get_value("-hero") == "r": hero_select.random_hero() else: - print(util.args.get_value("-hero")) hero_select.set_hero(int(util.args.get_value("-hero"))) if util.args.get_value("-start-game"): @@ -59,7 +65,7 @@ func _set_level(level): # Because of the annoying way callbacks work (automatic parameter, optional parameter) # We need a utility function for making these kinds of callbacks for set_info func _set_info_callback(value, key): - networking.set_info(key, value) + networking.set_info_from_server(key, value) sync func set_hero(peer, hero): networking.players[peer].hero = hero @@ -67,7 +73,7 @@ sync func set_hero(peer, hero): func _send_name(): var name = get_node("Username").text - networking.set_info("username", name) + networking.set_info_from_server("username", name) func _check_begun(): var game_started = networking.players[1].begun diff --git a/scripts/networking.gd b/scripts/networking.gd index 9e97536..08eda14 100644 --- a/scripts/networking.gd +++ b/scripts/networking.gd @@ -74,13 +74,6 @@ func send_all_info(new_peer): set_info(key, val, p) remote func register_player(new_peer): - var info = {} - info.is_right_team = right_team_next - info.ready = false - info.spectating = false - info.begun = false - right_team_next = not right_team_next - players[new_peer] = info if get_tree().is_network_server(): # I tell new player about all the existing people send_all_info(new_peer) @@ -115,16 +108,25 @@ sync func _set_info(key, value, peer=0): if peer == 0: # Was self. See https://github.com/godotengine/godot/issues/19026 peer = get_tree().get_network_unique_id() - if players.has(peer): - players[peer][key] = value - emit_signal("info_updated") + if not players.has(peer): + players[peer] = {} + players[peer][key] = value + emit_signal("info_updated") -func set_info(key, value, peer=0): +master func set_info(key, value, peer=0): rpc("_set_info", str(key), value, peer) +# When connectivity is not yet guaranteed, the only one we know is always +# connected to everyone is the server. So in initial handshakes, it's better to +# tell the server what to tell everyone to do +func set_info_from_server(key, value, peer=0): + if not peer: + peer = get_tree().get_network_unique_id() + rpc_id(1, "set_info", key, value, peer) + func _on_connect(): - emit_signal("info_updated") register_player(get_tree().get_network_unique_id()) + emit_signal("info_updated") func _check_info(): # Check for "everyone is ready" From 088e18b03c22a3fa549cc31a70c248ba32208815 Mon Sep 17 00:00:00 2001 From: Luna Date: Sat, 26 May 2018 12:40:53 -0400 Subject: [PATCH 30/41] Assign is_right_team correctly --- scripts/networking.gd | 28 +++++++++++----------------- 1 file changed, 11 insertions(+), 17 deletions(-) diff --git a/scripts/networking.gd b/scripts/networking.gd index 08eda14..77a8bba 100644 --- a/scripts/networking.gd +++ b/scripts/networking.gd @@ -71,29 +71,23 @@ func send_all_info(new_peer): if p != new_peer: for key in players[p]: var val = players[p][key] + # TODO: This broadcasts every connected peer, + # which isn't really a problem but it's lazy set_info(key, val, p) +func _right_team_next(): + var right_team_count = 0 + for p in players: + var player = players[p] + if player.has("is_right_team") and player.is_right_team: + right_team_count += 1 + return (right_team_count <= players.size() / 2) + remote func register_player(new_peer): if get_tree().is_network_server(): # I tell new player about all the existing people send_all_info(new_peer) - emit_signal("info_updated") - # var right_team_count = 0 - # Send current players' info to new player - # if old_peer != new_peer: - # # We need to assign team later, so count current - # if players[old_peer].is_right_team: - # right_team_count += 1 - # if begun: TODO this should belong to lobby? - # rpc_id(old_peer, "_spawn_player", new_peer) - # rpc_id(old_peer, "_begin_player_deferred", new_peer) # Spawning is deferred - # var assign_right_team = right_team_count * 2 < players.size() - # set_info("is_right_team", assign_right_team, new_peer) - # if not begun and players.size() == matchmaking.GAME_SIZE: - # start_game() - # if begun: - # rpc_id(new_peer, "_pre_configure_game", my_info.level) - # rpc_id(new_peer, "_post_configure_game") + set_info("is_right_team", _right_team_next(), new_peer) sync func unregister_player(peer): players.erase(peer) From 39544768f2ff0ba889d6185d54f3ff5198c2b9e1 Mon Sep 17 00:00:00 2001 From: Luna Date: Sat, 26 May 2018 15:24:54 -0400 Subject: [PATCH 31/41] Fix non-blocking errors that clutter console --- scripts/lobby.gd | 36 +++++++++++++++++++++--------------- scripts/networking.gd | 4 ++-- 2 files changed, 23 insertions(+), 17 deletions(-) diff --git a/scripts/lobby.gd b/scripts/lobby.gd index 7aab4cb..fc00dd2 100644 --- a/scripts/lobby.gd +++ b/scripts/lobby.gd @@ -76,11 +76,13 @@ func _send_name(): networking.set_info_from_server("username", name) func _check_begun(): - var game_started = networking.players[1].begun - if game_started: - start_game_button.show() - # The "Ready" toggle doesn't really make sense on a started game - ready_button.hide() + if networking.players.has(1) and networking.players[1].has("begun"): + var game_started = networking.players[1].begun + if game_started: + start_game_button.show() + start_game_button.text = "Join game" + # The "Ready" toggle doesn't really make sense on a started game + ready_button.hide() func render_player_list(): _check_begun() @@ -89,17 +91,21 @@ func render_player_list(): for p in networking.players: var player = networking.players[p] # A spectating server is just a dedicated server, ignore it - if not (player.spectating and p == 1): - list += "%-15s " % player.username - list += "%-10s " % hero_names[player.hero] - var team_format = "%-11s" - if player.is_right_team: - list += team_format % "Right Team" - else: - list += team_format % "Left Team" - var ready_text = "Ready" if player.ready else "" + if p and player.has("spectating") and not (player.spectating and p == 1): + var username = player.username if player.has("username") else "Loading..." + list += "%-15s " % username + var hero = hero_names[player.hero] if player.has("hero") else "Loading..." + list += "%-10s " % hero + var team = "Loading..." + if player.has("is_right_team"): + if player.is_right_team: + team = "Right Team" + else: + team = "Left Team" + list += "%-11s" % team + var ready_text = "Ready" if player.has("ready") and player.ready else "" list += "%-6s" % ready_text - if player.spectating: + if player.has("spectating") and player.spectating: list += "Spectating" list += "\n" get_node("PlayerList").set_text(list) diff --git a/scripts/networking.gd b/scripts/networking.gd index 77a8bba..955098d 100644 --- a/scripts/networking.gd +++ b/scripts/networking.gd @@ -128,8 +128,8 @@ func _check_info(): if get_tree().is_network_server(): var ready = true for p in players: - if not players[p].spectating: - if not players[p].ready: + if not players[p].has("spectating") or not players[p].spectating: + if not players[p].has("ready") or not players[p].ready: ready = false if ready: start_game() From 8462031d552cf10427cbef7b9c78951b7b8a8c44 Mon Sep 17 00:00:00 2001 From: Luna Date: Sat, 26 May 2018 15:25:49 -0400 Subject: [PATCH 32/41] Fix spawning infinite players on start Infinite loop in start_game caused by set_info setting the wrong peer's info. Making the RPC more explicit about who we're setting resolves this. --- scripts/networking.gd | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/scripts/networking.gd b/scripts/networking.gd index 955098d..a53fba3 100644 --- a/scripts/networking.gd +++ b/scripts/networking.gd @@ -96,18 +96,15 @@ sync func unregister_player(peer): p.queue_free() emit_signal("info_updated") -sync func _set_info(key, value, peer=0): - if not peer: - peer = get_tree().get_rpc_sender_id() - if peer == 0: - # Was self. See https://github.com/godotengine/godot/issues/19026 - peer = get_tree().get_network_unique_id() +sync func _set_info(key, value, peer): if not players.has(peer): players[peer] = {} players[peer][key] = value emit_signal("info_updated") master func set_info(key, value, peer=0): + if not peer: + peer = get_tree().get_network_unique_id() rpc("_set_info", str(key), value, peer) # When connectivity is not yet guaranteed, the only one we know is always @@ -142,13 +139,14 @@ sync func _spawn_player(p): player.set_name(str(p)) player.set_network_master(p) player.player_info = players[p] - get_node("/root/Level/Players").call_deferred("add_child", player) + get_node("/root/Level/Players").add_child(player) sync func _pre_configure_game(level): var self_peer_id = get_tree().get_network_unique_id() + var self_begun = players[self_peer_id].begun - if not players[self_peer_id].begun: + if not self_begun: get_node("/root/Lobby").hide() var world = load("res://scenes/levels/%d.tscn" % level).instance() @@ -158,31 +156,33 @@ sync func _pre_configure_game(level): for p in players: if not players[p].spectating: var existing_player = util.get_player(p) - if not players[self_peer_id].begun or not existing_player: + if not self_begun or not existing_player: _spawn_player(p) - set_info("begun", true) + # Why do we check first? Weird error. It's because set_info triggers a + # start_game if everyone is ready + # This causes a stack overflow if we call it from here repeatedly + # So we only change it once, only start_game twice, and avoida segfault + if not self_begun: + print("setting my begun to true") + set_info("begun", true) rpc_id(1, "_done_preconfiguring", self_peer_id) sync func _done_preconfiguring(who): players_done.append(who) if players_done.size() == players.size(): print("done") - # We call deferred in case singleplayer has placing the player in queue still - call_deferred("rpc", "_post_configure_game") + rpc("_post_configure_game") sync func _post_configure_game(): # Begin all players (including self) for p in players: if not players[p].spectating: - _begin_player_deferred(p) + _begin_player(p) func _begin_player(peer): util.get_player(peer).begin() -remote func _begin_player_deferred(peer): - call_deferred("_begin_player", peer) - sync func reset_state(): players_done = [] get_node("/root/Level").queue_free() From 85f6fd897b7837024a564a3b6273fdf0d5bf8358 Mon Sep 17 00:00:00 2001 From: Luna Date: Sat, 26 May 2018 15:26:58 -0400 Subject: [PATCH 33/41] Make hero description bigger on lobby --- scenes/lobby.tscn | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/scenes/lobby.tscn b/scenes/lobby.tscn index 2458770..d590f9b 100644 --- a/scenes/lobby.tscn +++ b/scenes/lobby.tscn @@ -41,7 +41,6 @@ script = ExtResource( 2 ) [node name="HeroSelect" parent="." index="0" instance=ExtResource( 3 )] -editor/display_folded = true margin_left = 30.0 margin_top = 69.0 margin_right = 30.0 @@ -62,9 +61,9 @@ visible = false [node name="HeroDescription" parent="HeroSelect" index="2"] margin_left = -2.0 -margin_top = 133.0 +margin_top = 125.0 margin_right = 366.0 -margin_bottom = 250.0 +margin_bottom = 288.0 text = "L Let s put oeuntahoeu nthaoeu ntaoheunt aoheunt hoaenth oaentuh Let s put oeuntahoeu nthaoeu ntaoheunt aoheunt hoaenth " [node name="Title" type="Label" parent="HeroSelect" index="3"] @@ -95,9 +94,9 @@ anchor_top = 0.0 anchor_right = 0.0 anchor_bottom = 0.0 margin_left = 43.0 -margin_top = 348.0 +margin_top = 391.0 margin_right = 384.0 -margin_bottom = 381.0 +margin_bottom = 424.0 rect_pivot_offset = Vector2( 0, 0 ) focus_mode = 2 mouse_filter = 0 @@ -128,9 +127,9 @@ anchor_top = 0.0 anchor_right = 0.0 anchor_bottom = 0.0 margin_left = 36.0 -margin_top = 396.0 -margin_right = 226.0 -margin_bottom = 436.0 +margin_top = 439.0 +margin_right = 237.0 +margin_bottom = 479.0 rect_pivot_offset = Vector2( 0, 0 ) focus_mode = 2 mouse_filter = 0 @@ -152,9 +151,9 @@ anchor_top = 0.0 anchor_right = 0.0 anchor_bottom = 0.0 margin_left = 45.0 -margin_top = 486.0 +margin_top = 529.0 margin_right = 411.0 -margin_bottom = 527.0 +margin_bottom = 570.0 rect_pivot_offset = Vector2( 0, 0 ) focus_mode = 2 mouse_filter = 0 @@ -310,7 +309,7 @@ anchor_bottom = 0.0 margin_left = 453.0 margin_top = 50.0 margin_right = 471.0 -margin_bottom = 538.0 +margin_bottom = 566.0 rect_pivot_offset = Vector2( 0, 0 ) mouse_filter = 0 mouse_default_cursor_shape = 0 From 3f8e61d764e9f9d9e396e6051d898efba3519edf Mon Sep 17 00:00:00 2001 From: Luna Date: Sat, 26 May 2018 15:27:38 -0400 Subject: [PATCH 34/41] [Hero 5] Fix incorrect de facto teleport cost --- scripts/heroes/5.gd | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/scripts/heroes/5.gd b/scripts/heroes/5.gd index 72fd2e8..5314fbd 100644 --- a/scripts/heroes/5.gd +++ b/scripts/heroes/5.gd @@ -1,6 +1,7 @@ extends "res://scripts/player.gd" onready var placement = preload("res://scripts/placement.gd").new(self, "res://scenes/heroes/5_portal.tscn") +onready var portal_ability = get_node("MasterOnly/Portal") onready var teleport_ability = get_node("MasterOnly/Teleport") var radius = 15 @@ -8,7 +9,6 @@ var radius = 15 var first_crosshair = " [..." var second_crosshair = "...] " var no_portal_crosshair = "+" -var portal_cost = 20 var flicking = null var flick_charge = 3 @@ -27,11 +27,11 @@ func _process(delta): if is_network_master(): var is_second = placement.placed.size() % 2 != 0 var portal_crosshair = second_crosshair if is_second else first_crosshair - var crosshair = no_portal_crosshair if switch_charge < portal_cost else portal_crosshair + var crosshair = no_portal_crosshair if switch_charge < portal_ability.cost else portal_crosshair get_node("MasterOnly/Crosshair").set_text(crosshair) - var can_build = switch_charge > portal_cost + var can_build = switch_charge > portal_ability.cost if placement.place_input(radius, can_build, true) and is_second: - switch_charge -= portal_cost + switch_charge -= portal_ability.cost teleport_ability.disabled = placement.placed.size() <= 1 From 725b6166577bfe69a7c8155ea6afef8501ea0486 Mon Sep 17 00:00:00 2001 From: Luna Date: Sat, 26 May 2018 16:11:36 -0400 Subject: [PATCH 35/41] Fix player's color not getting set --- scripts/networking.gd | 16 ++++++++++------ scripts/player.gd | 10 ++++++---- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/scripts/networking.gd b/scripts/networking.gd index a53fba3..a1c12e8 100644 --- a/scripts/networking.gd +++ b/scripts/networking.gd @@ -141,6 +141,10 @@ sync func _spawn_player(p): player.player_info = players[p] get_node("/root/Level/Players").add_child(player) +func _begin_player(p): + var player = util.get_player(p) + player.begin() + sync func _pre_configure_game(level): var self_peer_id = get_tree().get_network_unique_id() @@ -158,6 +162,10 @@ sync func _pre_configure_game(level): var existing_player = util.get_player(p) if not self_begun or not existing_player: _spawn_player(p) + for p in players: + if not players[p].spectating: + # Begin requires all players + _begin_player(p) # Why do we check first? Weird error. It's because set_info triggers a # start_game if everyone is ready @@ -176,12 +184,8 @@ sync func _done_preconfiguring(who): sync func _post_configure_game(): # Begin all players (including self) - for p in players: - if not players[p].spectating: - _begin_player(p) - -func _begin_player(peer): - util.get_player(peer).begin() + # TODO: What do? Maybe, unpause game? + pass sync func reset_state(): players_done = [] diff --git a/scripts/player.gd b/scripts/player.gd index 887a7cb..4d0d66b 100644 --- a/scripts/player.gd +++ b/scripts/player.gd @@ -52,6 +52,7 @@ func _ready(): set_process_input(true) debug_node = get_node("/root/Level/Debug") + _set_color() if is_network_master(): get_node("TPCamera/Camera/Ray").add_exception(self) get_node(tp_camera).set_enabled(true) @@ -59,6 +60,7 @@ func _ready(): if "is_ai" in player_info and player_info.is_ai and not ai_instanced: add_child(preload("res://scenes/ai.tscn").instance()) ai_instanced = true + spawn() else: get_node("PlayerName").set_text(player_info.username) # Remove HUD @@ -175,10 +177,13 @@ func event_to_obj(event): return d func begin(): + _set_color() + +func _set_color(): master_player = util.get_master_player() # Set color to blue (teammate) or red (enemy) var color - if master_player and master_player.player_info.is_right_team == player_info.is_right_team: + if master_player.player_info.is_right_team == player_info.is_right_team: color = friend_color else: color = enemy_color @@ -192,8 +197,6 @@ func begin(): for mesh in colored_meshes: get_node(mesh).set_surface_material(0, mat) - spawn() - func toggle_mouse_capture(): if (Input.get_mouse_mode() == Input.MOUSE_MODE_CAPTURED): Input.set_mouse_mode(Input.MOUSE_MODE_VISIBLE) @@ -305,7 +308,6 @@ sync func switch_hero(hero): get_node("/root/Level/Players").call_deferred("add_child", new_hero) # We must wait until after _ready is called, so that we don't end up at spawn new_hero.call_deferred("set_status", get_status()) - new_hero.call_deferred("begin") queue_free() func write_recording(): From 851014b2192b6692572bccdfec22ec6a5f34b390 Mon Sep 17 00:00:00 2001 From: Luna Date: Sat, 26 May 2018 16:53:00 -0400 Subject: [PATCH 36/41] Use global server ip for reconnect --- scripts/matchmaking.gd | 4 ++-- scripts/menu.gd | 4 ++-- scripts/networking.gd | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/scripts/matchmaking.gd b/scripts/matchmaking.gd index 30e3e4f..43ef50a 100644 --- a/scripts/matchmaking.gd +++ b/scripts/matchmaking.gd @@ -4,7 +4,7 @@ var SERVER_TO_SERVER_PORT = 54671 var MATCHMAKING_PORT = 54672 var GAME_SIZE = 6 # Number of games we can make without blowing up the computer -var MAX_GAMES = 50 # Totally random guess +var MAX_GAMES = 50 # Based on how many ports I decided to forward var next_port = 54673 @@ -80,7 +80,7 @@ func queue(netid): # # func add_to_game(netid, port): - networking.rpc_id(netid, "reconnect", port) + networking.rpc_id(netid, "reconnect", networking.global_server_ip, port) func skirmish_to_game(port, count=1): for i in range(count): diff --git a/scripts/menu.gd b/scripts/menu.gd index e11b912..b5d41e3 100644 --- a/scripts/menu.gd +++ b/scripts/menu.gd @@ -14,8 +14,8 @@ func _gui_setup(): get_node("Center/Quit").connect("pressed", get_tree(), "quit") func _find_game(): - # var ip = networking.global_server_ip - var ip = util.args.get_value("-ip") + var ip = networking.global_server_ip + # var ip = util.args.get_value("-ip") var port = networking.matchmaking.MATCHMAKING_PORT networking.start_client(ip, port) diff --git a/scripts/networking.gd b/scripts/networking.gd index a1c12e8..f3be907 100644 --- a/scripts/networking.gd +++ b/scripts/networking.gd @@ -33,10 +33,10 @@ func start_client(ip="", port=0): get_tree().set_network_peer(peer) get_tree().change_scene("res://scenes/lobby.tscn") -remote func reconnect(port): +remote func reconnect(ip, port): # Reset previously known players players = {} - start_client("", port) + start_client(ip, port) func _connect_to_matchmaker(game_port): var matchmaker_peer = StreamPeerTCP.new() From 26441b49e568157d2de2ffbd9eafedbd8409fcbc Mon Sep 17 00:00:00 2001 From: Luna Date: Sat, 26 May 2018 17:07:40 -0400 Subject: [PATCH 37/41] Fix quit not quitting on arguments --- scripts/menu.gd | 2 +- scripts/networking.gd | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/scripts/menu.gd b/scripts/menu.gd index b5d41e3..3ec2398 100644 --- a/scripts/menu.gd +++ b/scripts/menu.gd @@ -52,5 +52,5 @@ func _arg_actions(): _singleplayer() if o.get_value('-h'): o.print_help() - quit() + get_tree().quit() diff --git a/scripts/networking.gd b/scripts/networking.gd index f3be907..bf04e2c 100644 --- a/scripts/networking.gd +++ b/scripts/networking.gd @@ -172,7 +172,6 @@ sync func _pre_configure_game(level): # This causes a stack overflow if we call it from here repeatedly # So we only change it once, only start_game twice, and avoida segfault if not self_begun: - print("setting my begun to true") set_info("begun", true) rpc_id(1, "_done_preconfiguring", self_peer_id) From 5693bcdab015160182c44c204b6545e345e7c41c Mon Sep 17 00:00:00 2001 From: Luna Date: Sat, 26 May 2018 22:06:10 -0400 Subject: [PATCH 38/41] Organize public and private methods within networking --- scripts/lobby.gd | 6 +-- scripts/networking.gd | 132 +++++++++++++++++++++++++++----------------------- 2 files changed, 74 insertions(+), 64 deletions(-) diff --git a/scripts/lobby.gd b/scripts/lobby.gd index e634d6e..72abc8a 100644 --- a/scripts/lobby.gd +++ b/scripts/lobby.gd @@ -13,7 +13,7 @@ func _ready(): ready_button.connect("toggled", self, "_set_info_callback", ["ready"]) start_game_button.connect("pressed", networking, "start_game") # Connect (from networking) - networking.connect("info_updated", self, "render_player_list") + networking.connect("info_updated", self, "_render_player_list") get_tree().connect("connected_to_server", self, "_connected") # Connect (static) @@ -67,7 +67,7 @@ func _set_info_callback(value, key): sync func set_hero(peer, hero): networking.players[peer].hero = hero - render_player_list() + _render_player_list() func _send_name(): var name = get_node("Username").text @@ -82,7 +82,7 @@ func _check_begun(): # The "Ready" toggle doesn't really make sense on a started game ready_button.hide() -func render_player_list(): +func _render_player_list(): _check_begun() var list = "" var hero_names = hero_select.hero_names diff --git a/scripts/networking.gd b/scripts/networking.gd index bf04e2c..14d15f7 100644 --- a/scripts/networking.gd +++ b/scripts/networking.gd @@ -1,25 +1,20 @@ extends Node +# Public variables +# ================ + onready var matchmaking = preload("res://scripts/matchmaking.gd").new() remote var players = {} -var players_done = [] var global_server_ip = "nv.cosinegaming.com" var matchmaker_tcp -var right_team_next = false var level signal info_updated -func _ready(): - add_child(matchmaking) - - get_tree().connect("network_peer_disconnected", self, "unregister_player") - get_tree().connect("network_peer_connected", self, "register_player") - get_tree().connect("connected_to_server", self, "_on_connect") - - connect("info_updated", self, "_check_info") +# Public methods +# ============== func start_client(ip="", port=0): if not ip: @@ -38,14 +33,6 @@ remote func reconnect(ip, port): players = {} start_client(ip, port) -func _connect_to_matchmaker(game_port): - var matchmaker_peer = StreamPeerTCP.new() - matchmaker_peer.connect_to_host("127.0.0.1", matchmaking.SERVER_TO_SERVER_PORT) - var matchmaker_tcp = PacketPeerStream.new() - matchmaker_tcp.set_stream_peer(matchmaker_peer) - matchmaker_tcp.put_var(matchmaking.messages.ready_to_connect) - matchmaker_tcp.put_var(game_port) - func start_server(port=0): if not port: port = util.args.get_value("-port") @@ -55,18 +42,72 @@ func start_server(port=0): get_tree().set_network_peer(peer) # As soon as we're listening, let the matchmaker know _connect_to_matchmaker(port) - register_player(get_tree().get_network_unique_id()) + _register_player(get_tree().get_network_unique_id()) if util.args.get_value("-silent"): set_info("spectating", true) get_tree().change_scene("res://scenes/lobby.tscn") -master func _start_game(): - rpc("_pre_configure_game", level) +master func set_info(key, value, peer=0): + if not peer: + peer = get_tree().get_network_unique_id() + rpc("_set_info", str(key), value, peer) + +# When connectivity is not yet guaranteed, the only one we know is always +# connected to everyone is the server. So in initial handshakes, it's better to +# tell the server what to tell everyone to do +func set_info_from_server(key, value, peer=0): + if not peer: + peer = get_tree().get_network_unique_id() + rpc_id(1, "set_info", key, value, peer) func start_game(): rpc_id(1, "_start_game") -func send_all_info(new_peer): +sync func reset_state(): + for p in players: + players[p].begun = false + # TODO: Do I in fact want to unready everyone automatically? + players[p].ready = false + get_node("/root/Level").queue_free() + + +# Private methods +# =============== + +func _ready(): + add_child(matchmaking) + + get_tree().connect("network_peer_disconnected", self, "_unregister_player") + get_tree().connect("network_peer_connected", self, "_register_player") + get_tree().connect("connected_to_server", self, "_on_connect") + + connect("info_updated", self, "_check_info") + +remote func _register_player(new_peer): + if get_tree().is_network_server(): + # I tell new player about all the existing people + _send_all_info(new_peer) + set_info("is_right_team", _right_team_next(), new_peer) + +sync func _unregister_player(peer): + players.erase(peer) + var p = util.get_player(peer) + if p: + p.queue_free() + emit_signal("info_updated") + +func _connect_to_matchmaker(game_port): + var matchmaker_peer = StreamPeerTCP.new() + matchmaker_peer.connect_to_host("127.0.0.1", matchmaking.SERVER_TO_SERVER_PORT) + var matchmaker_tcp = PacketPeerStream.new() + matchmaker_tcp.set_stream_peer(matchmaker_peer) + matchmaker_tcp.put_var(matchmaking.messages.ready_to_connect) + matchmaker_tcp.put_var(game_port) + +master func _start_game(): + rpc("_pre_configure_game", level) + +func _send_all_info(new_peer): for p in players: if p != new_peer: for key in players[p]: @@ -83,40 +124,14 @@ func _right_team_next(): right_team_count += 1 return (right_team_count <= players.size() / 2) -remote func register_player(new_peer): - if get_tree().is_network_server(): - # I tell new player about all the existing people - send_all_info(new_peer) - set_info("is_right_team", _right_team_next(), new_peer) - -sync func unregister_player(peer): - players.erase(peer) - var p = util.get_player(peer) - if p: - p.queue_free() - emit_signal("info_updated") - sync func _set_info(key, value, peer): if not players.has(peer): players[peer] = {} players[peer][key] = value emit_signal("info_updated") -master func set_info(key, value, peer=0): - if not peer: - peer = get_tree().get_network_unique_id() - rpc("_set_info", str(key), value, peer) - -# When connectivity is not yet guaranteed, the only one we know is always -# connected to everyone is the server. So in initial handshakes, it's better to -# tell the server what to tell everyone to do -func set_info_from_server(key, value, peer=0): - if not peer: - peer = get_tree().get_network_unique_id() - rpc_id(1, "set_info", key, value, peer) - func _on_connect(): - register_player(get_tree().get_network_unique_id()) + _register_player(get_tree().get_network_unique_id()) emit_signal("info_updated") func _check_info(): @@ -124,11 +139,17 @@ func _check_info(): # Only have 1 person check this, might as well be server if get_tree().is_network_server(): var ready = true + var all_done = true for p in players: if not players[p].has("spectating") or not players[p].spectating: if not players[p].has("ready") or not players[p].ready: ready = false - if ready: + if not players[p].has("begun") or not players[p].begun: + all_done = false + if all_done: + rpc("_post_configure_game") + elif ready: + # If we're all done, then we don't need to even check a start_game start_game() sync func _spawn_player(p): @@ -173,20 +194,9 @@ sync func _pre_configure_game(level): # So we only change it once, only start_game twice, and avoida segfault if not self_begun: set_info("begun", true) - rpc_id(1, "_done_preconfiguring", self_peer_id) - -sync func _done_preconfiguring(who): - players_done.append(who) - if players_done.size() == players.size(): - print("done") - rpc("_post_configure_game") sync func _post_configure_game(): # Begin all players (including self) # TODO: What do? Maybe, unpause game? pass -sync func reset_state(): - players_done = [] - get_node("/root/Level").queue_free() - From 15fbb8a9f88047a5e4c7ad05797461ddc04fe639 Mon Sep 17 00:00:00 2001 From: Luna Date: Sat, 26 May 2018 22:19:43 -0400 Subject: [PATCH 39/41] Remove extraneous commented out lines of code --- scripts/matchmaking.gd | 4 ---- scripts/tp_camera.gd | 1 - 2 files changed, 5 deletions(-) diff --git a/scripts/matchmaking.gd b/scripts/matchmaking.gd index 43ef50a..0528467 100644 --- a/scripts/matchmaking.gd +++ b/scripts/matchmaking.gd @@ -75,10 +75,6 @@ func queue(netid): skirmishing_players.append(netid) check_queue() -# # This is only for clients, but it's in here so we can rpc it easily -# slave func join_game(port): -# # - func add_to_game(netid, port): networking.rpc_id(netid, "reconnect", networking.global_server_ip, port) diff --git a/scripts/tp_camera.gd b/scripts/tp_camera.gd index 9f3d129..2ea1502 100644 --- a/scripts/tp_camera.gd +++ b/scripts/tp_camera.gd @@ -101,7 +101,6 @@ func cam_update(): if cam_ray_result.size() != 0: var a = (cam_ray_result.position-pivot.get_global_transform().origin).normalized(); var b = pivot.get_global_transform().origin.distance_to(cam_ray_result.position); - #pos = cam_ray_result.position; pos = pivot.get_global_transform().origin+a*max(b-0.1, 0); else: pos = cam_pos; From 33a6de2c061b3b1aa24d00ac2173daea25413251 Mon Sep 17 00:00:00 2001 From: Luna Date: Mon, 28 May 2018 18:46:29 -0400 Subject: [PATCH 40/41] Start skirmish server automatically --- scripts/matchmaking.gd | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/scripts/matchmaking.gd b/scripts/matchmaking.gd index 0528467..2f40444 100644 --- a/scripts/matchmaking.gd +++ b/scripts/matchmaking.gd @@ -38,7 +38,7 @@ func start_matchmaker(): set_process(true) # Setup skirmish server - skirmish = spawn_server() + skirmish = spawn_server(true) # Set up communication between GAMESERVERS # This is necessary for eg, when a player leaves to backfill @@ -94,8 +94,12 @@ func check_queue(): spawn_server() # games.append(port) -func spawn_server(): - OS.execute("util/server.sh", ['-port='+str(next_port)], false) +func spawn_server(skirmish=false): + var args = ['-port='+str(next_port)] + if skirmish: + # Begin skirmish immediately, so players "join" instead of "ready" + args.append("-start-game") + OS.execute("util/server.sh", args, false) next_port += 1 return (next_port - 1) # Return original port From db35fdc6f6b6c789b3a7422f10366811207089ac Mon Sep 17 00:00:00 2001 From: Luna Date: Mon, 28 May 2018 18:47:35 -0400 Subject: [PATCH 41/41] Hide ready button on singeplayer lobby I think this makes us all set for merge to master! --- scenes/singleplayer_lobby.tscn | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/scenes/singleplayer_lobby.tscn b/scenes/singleplayer_lobby.tscn index 7cc9ac1..80910e0 100644 --- a/scenes/singleplayer_lobby.tscn +++ b/scenes/singleplayer_lobby.tscn @@ -66,15 +66,20 @@ visible = false visible = false -[node name="StartGame" parent="." index="8"] +[node name="Ready" parent="." index="8"] +visible = false + +[node name="StartGame" parent="." index="9"] + +visible = true margin_left = 41.0 margin_top = 486.0 margin_right = 163.0 margin_bottom = 526.0 text = "Play!" -[node name="VSeparator" parent="." index="9"] +[node name="VSeparator" parent="." index="10"] visible = false