diff options
Diffstat (limited to 'network')
| -rw-r--r-- | network/GameCoordinatorClient.gd | 209 | ||||
| -rw-r--r-- | network/GameCoordinatorTester.gd | 2 | ||||
| -rw-r--r-- | network/WSClient.tscn | 6 | ||||
| -rw-r--r-- | network/websocket_client_basic.gd | 5 |
4 files changed, 192 insertions, 30 deletions
diff --git a/network/GameCoordinatorClient.gd b/network/GameCoordinatorClient.gd index 3d87b7b..eac86e8 100644 --- a/network/GameCoordinatorClient.gd +++ b/network/GameCoordinatorClient.gd @@ -1,32 +1,80 @@ +class_name GCClient extends Node # CONNECTION DATA -enum { NONE, SERVER_BROWSER, LOBBY, VOICE } + +enum { NONE, SERVER_BROWSER, LOBBY_WAITING, LOBBY, VOICE } +var connection_type : int = NONE + var socket_client: WebSocketClient = null var socket: WebSocketPeer = null -var state: int = 0 # -1 = CONNECTION_FAILED, 0 = CONNECTION_DISCONNECTED, 1 = CONNECTION_CONNECTING, 2 = CONNECTION_CONNECTED, 3 = CONNECTION_DISCONNECTING + +enum { CONNECTION_FAILED, CONNECTION_DISCONNECTED, CONNECTION_CONNECTING, CONNECTION_CONNECTED, CONNECTION_DISCONNECTING } +var state: int = CONNECTION_DISCONNECTED + var message_queue : Array = [] # messages to be sent upon connection -var connection_type : int = NONE + +# END CONNECTION DATA # GC DATA + +# connected from menus +signal gc_connection_failed() +signal lobby_list_acquired(lobbies) # connected before calling get_lobby_list to retrieve result +signal join_request_success() +signal join_failure(reason) +signal join_success(args) +signal host_failure(reason) +signal host_success() + +# connected from in game +signal disconnected_from_lobby(reason) +signal join_request_received(player_id, args) +signal connection_closed_dirty() # game should be quit for unexpected reasons + var is_host : bool -var host_id : String -var lobby_id : String -var player_id : String -var rejoin_key : String +var host_id : String = "" +var lobby_id : String = "" +var player_id : String = "" +var rejoin_key : String = "" var players : Array = [] +var max_players : int = -1 +var lobby_name : String = "" +var is_private : bool = false +var lobby_password : String = "" + +const GC_MSG_TYPES : Array = ["join_request_ok", "join_ok", "join_fail", + "rejoin_ok", "rejoin_fail", "host_ok", "host_fail", + "disconnected", "join_request", "lobby_closing"] + + +# END GC DATA func _ready(): socket_client = WebSocketClient.new() socket_client.connect("connection_established", self, "on_connection_success") - socket_client.connect("connection_closed", self, "on_connection_close_success") + socket_client.connect("connection_closed", self, "on_connection_close") socket_client.connect("connection_error", self, "on_connection_error") #socket_client.connect("data_received", self, "receive") +func gc_client_reset(): + self.player_id = "" + self.lobby_id = "" + self.host_id = "" + self.rejoin_key = "" + self.players.clear() + self.is_host = false + self.connection_type = NONE + self.max_players = -1 + self.lobby_name = "" + self.is_private = false + func connect_to_gc(c_type: int): - if !(c_type in [SERVER_BROWSER, LOBBY, VOICE]): + if !(c_type in [SERVER_BROWSER, LOBBY_WAITING, VOICE]): print("Invalid connection type!") return + + gc_client_reset() connection_type = c_type var url : String = Globals.GC_URL print("Connecting to game coordinator: %s..." % url) @@ -35,67 +83,172 @@ func connect_to_gc(c_type: int): if error != OK: return error - state = 1 # CONNECTING + state = CONNECTION_CONNECTING return OK -func sock_close(code = 1000, reason = ""): +func close_socket(code = 1000, reason = ""): + if state == CONNECTION_DISCONNECTED or state == CONNECTION_FAILED: return print("Closing websocket...") socket_client.disconnect_from_host(code, reason) - state = 3 # DISCONNECTING + state = CONNECTION_DISCONNECTING # DISCONNECTING func on_connection_success(protocol): print("WebSocket connection success with protocol %s." % protocol) socket = socket_client.get_peer(1) socket.set_write_mode(WebSocketPeer.WRITE_MODE_TEXT) # defaults to text mode - state = 2 # CONNECTED + state = CONNECTION_CONNECTED # CONNECTED while len(message_queue) > 0: var msg = message_queue.pop_at(0) send(msg) -func on_connection_close_success(clean): +func on_connection_close(clean): print("WebSocket closed successfully.") socket = null connection_type = NONE if clean: - state = 0 # DISCONNECTED + state = CONNECTION_DISCONNECTED # DISCONNECTED else: - state = -1 # DISCONNECT DIRTY + emit_signal("connection_closed_dirty") + state = CONNECTION_FAILED # DISCONNECT DIRTY func on_connection_error(): # connection failed print("WebSocket connection failed!") socket = null - state = -1 # DISCONNECT DIRTY + state = CONNECTION_FAILED # DISCONNECT DIRTY connection_type = NONE + emit_signal("gc_connection_failed") func send(message, as_bytes=false) -> int: - if state != 2: + if state != CONNECTION_CONNECTED: message_queue.push_back(message) return -1 return socket.put_packet(message) - func send_json(message) -> int: - if state != 2: + if state != CONNECTION_CONNECTED: message_queue.push_back(JSON.print(message).to_utf8()) return -1 var message_json = JSON.print(message).to_utf8() return socket.put_packet(message_json) -func receive(string_to_json=false): - if state != 2: return null +func receive(): + if state != CONNECTION_CONNECTED: return null if socket.get_available_packet_count() < 1: return null var packet : PoolByteArray = socket.get_packet() if socket.was_string_packet(): var message = packet.get_string_from_utf8() - if string_to_json: - var json = JSON.parse(message) - if json.error: - return null - message = json.result + var json = JSON.parse(message) + if json.error: + return null + message = json.result + process_gc_message(message) return message - return bytes2var(packet) + return null # bytes2var(packet) + +# process GC state specific message/content of messages +# returns false in the case of game-breaking invalid message receipt +func process_gc_message(message): + # always update player information whenever an update is received from the GC + if "current_players" in message: + for player in players: + if player["is_host"] and self.host_id != player["player_id"]: + self.host_id = player["player_id"] + self.is_host = self.host_id == self.player_id + + if "type" in message and (message["type"] in GC_MSG_TYPES): # validate GC message format + if message["type"] == "join_request_ok": + if !("player_id" in message and "rejoin_key" in message): + close_socket() # GC did not provide necessary info + self.player_id = message["player_id"] + self.rejoin_key = message["rejoin_key"] + self.lobby_name = message["lobby_name"] + self.max_players = message["max_players"] + self.is_private = message["private"] + emit_signal("join_request_success") + elif message["type"] == "join_ok": + self.connection_type = LOBBY + var join_args = {} + if "args" in message: + join_args = message["args"] + + emit_signal("join_success", join_args) + elif message["type"] == "join_fail": + var reason = "Unknown failure." if not ("message" in message) else message["message"] + gc_client_reset() + emit_signal( "join_failure", reason ) + + elif message["type"] == "disconnected": + state = CONNECTION_DISCONNECTING # socket will be closed soon + close_socket() + gc_client_reset() + emit_signal( "disconnected_from_lobby", message["reason"] ) + + elif message["type"] == "host_ok": + if !(("player_id" in message) and ("rejoin_key" in message) and ("lobby_id" in message)): + close_socket() # GC did not provide necessary info + self.lobby_id = message["lobby_id"] + self.player_id = message["player_id"] + self.rejoin_key = message["rejoin_key"] + self.is_host = true + self.connection_type = LOBBY + emit_signal("host_success") + elif message["type"] == "host_fail": + var reason = "Unknown failure." if not ("message" in message) else message["message"] + close_socket() + gc_client_reset() + emit_signal("host_failure", reason) + + elif message["type"] == "join_request": + if !("player_id" in message and "args" in message): + print("Invalid join request received.") + return + emit_signal("join_request_received", message["player_id"], message["args"]) + + elif message["type"] == "lobby_list": + emit_signal("lobby_list_acquired", message["lobby_list"]) + gc_client_reset() + close_socket() + + elif message["type"] == "lobby_closing": + emit_signal("disconnected_from_lobby", "Lobby closing.") + gc_client_reset() + close_socket() + + return + +func get_lobby_list(): + gc_client_reset() + var message = {"type" : "list_open_lobbies"} + if state != CONNECTION_CONNECTED: + connect_to_gc(SERVER_BROWSER) + send_json( message ) + else: + send_json( message ) +func host_lobby(lobby_name : String, username : String, max_players : int, private : bool, password : String = ""): + close_socket() + gc_client_reset() + + var request = {"type" : "host_lobby", "lobby_name" : lobby_name, "game_type" : Globals.GAME_TYPE, "lobby_id" : lobby_id, "username" : username, "max_players" : max_players, "private" : private, "password" : password} + connect_to_gc(LOBBY_WAITING) + self.lobby_name = lobby_name + self.max_players = max_players + self.is_private = private + self.lobby_password = password + send_json(request) + +func join_lobby(lobby_id : String, password : String, username : String, args = null): + close_socket() + gc_client_reset() + + var request = {"type" : "join_lobby", "game_type" : Globals.GAME_TYPE, "lobby_id" : lobby_id, "password" : password, "username" : username} + if args: request["args"] = args + connect_to_gc(LOBBY_WAITING) + self.lobby_id = lobby_id + self.is_host = false + self.lobby_password = password + send_json(request) func _process(_delta): socket_client.poll() diff --git a/network/GameCoordinatorTester.gd b/network/GameCoordinatorTester.gd index 12f92ab..bae0e82 100644 --- a/network/GameCoordinatorTester.gd +++ b/network/GameCoordinatorTester.gd @@ -3,7 +3,7 @@ extends Control onready var ws_client_template : PackedScene = preload("res://network/WSClient.tscn") -var game_coordinator_url : String = "ws://192.168.7.112:8181" +var game_coordinator_url : String = "ws://acetyl.net:8181" var gc_client_menus : Dictionary = {} var latest_gccid : int = 0 diff --git a/network/WSClient.tscn b/network/WSClient.tscn new file mode 100644 index 0000000..bfb9383 --- /dev/null +++ b/network/WSClient.tscn @@ -0,0 +1,6 @@ +[gd_scene load_steps=2 format=2] + +[ext_resource path="res://network/websocket_client_basic.gd" type="Script" id=1] + +[node name="WSClient" type="Node"] +script = ExtResource( 1 ) diff --git a/network/websocket_client_basic.gd b/network/websocket_client_basic.gd index 353dd81..846e721 100644 --- a/network/websocket_client_basic.gd +++ b/network/websocket_client_basic.gd @@ -39,12 +39,13 @@ func on_connection_success(protocol): send(msg) func on_connection_close_success(clean): - print("WebSocket closed successfully.") socket = null if clean: state = 0 # DISCONNECTED + print("WebSocket closed successfully.") else: state = -1 # DISCONNECT DIRTY + print("WebSocket closed unsuccessfully!") func on_connection_error(): # connection failed print("WebSocket connection failed!") @@ -59,7 +60,9 @@ func send(message, as_bytes=false) -> int: func send_json(message) -> int: + print("sending") if state != 2: + print("adding to queue") message_queue.push_back(JSON.print(message).to_utf8()) return -1 var message_json = JSON.print(message).to_utf8() |
