summaryrefslogtreecommitdiff
path: root/network
diff options
context:
space:
mode:
authorAnson Bridges <bridges.anson@gmail.com>2025-08-15 23:04:40 -0700
committerAnson Bridges <bridges.anson@gmail.com>2025-08-15 23:04:40 -0700
commitf087c6a98b1da55525a6e3c1d7c82477f82eb5cd (patch)
tree0e2b517bedb3dd475c2b82a1b05800e5b7593854 /network
parentd558a9add0e183219a7a9ff482807bdcd677e21a (diff)
Game Coordinator now mostly (~90%) functional
Diffstat (limited to 'network')
-rw-r--r--network/GameCoordinatorTester.gd144
-rw-r--r--network/GameCoordinatorTester.tscn19
-rw-r--r--network/WSClient.tscn6
-rw-r--r--network/WebSocketTest.gd17
-rw-r--r--network/WebSocketTest.tscn12
-rw-r--r--network/websocket_client.gd33
6 files changed, 190 insertions, 41 deletions
diff --git a/network/GameCoordinatorTester.gd b/network/GameCoordinatorTester.gd
new file mode 100644
index 0000000..12f92ab
--- /dev/null
+++ b/network/GameCoordinatorTester.gd
@@ -0,0 +1,144 @@
+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 gc_client_menus : Dictionary = {}
+var latest_gccid : int = 0
+
+const HOST_JSON_TEMPLATE_STR : String = '{ "lobby_name" : "",\n "game_type" : "test",\n "username" : "",\n "private" : false,\n "password" : "",\n "max_players" : 4 } '
+const JOIN_JSON_TEMPLATE_STR : String = '{ "lobby_id" : "",\n "game_type" : "test",\n "username" : "",\n "password" : "",\n "args": {} }'
+
+func _ready():
+ pass
+
+
+func _process(_delta):
+
+ # read from all open sockets
+ for gccid in gc_client_menus.keys():
+ var gc_client_menu = gc_client_menus[gccid]
+ gc_client_menu["state"].text = str( gc_client_menu["ws_client"].state )
+ if gc_client_menu["ws_client"].state == 2:
+ var recv_message = gc_client_menu["ws_client"].receive(true) # true argument means expect + convert to JSON
+ if recv_message:
+ gc_client_menu["output"].text += str(recv_message) + "\n"
+
+func host_lobby(gccid : int):
+ var gccm = gc_client_menus[gccid]
+ var json_parse_result : JSONParseResult = JSON.parse(gccm["input"].text)
+ if json_parse_result.error:
+ gccm["input"].text = HOST_JSON_TEMPLATE_STR # fill with template for ease if invalid json is provided
+ return
+ else:
+ var message = json_parse_result.result
+ message["type"] = "host_lobby"
+ gccm["ws_client"].sock_connect_to_url(game_coordinator_url)
+ gccm["ws_client"].send_json(message)
+
+func join_lobby(gccid : int):
+ var gccm = gc_client_menus[gccid]
+ var json_parse_result : JSONParseResult = JSON.parse(gccm["input"].text)
+ if json_parse_result.error:
+ gccm["input"].text = JOIN_JSON_TEMPLATE_STR # fill with template for ease if invalid json is provided
+ return
+ else:
+ var message = json_parse_result.result
+ message["type"] = "join_lobby"
+ gccm["ws_client"].sock_connect_to_url(game_coordinator_url)
+ gccm["ws_client"].send_json(message)
+
+func send_message(gccid : int):
+ var gccm = gc_client_menus[gccid]
+ var json_parse_result : JSONParseResult = JSON.parse(gccm["input"].text)
+ if json_parse_result.error:
+ gccm["input"].text = JOIN_JSON_TEMPLATE_STR # fill with template for ease if invalid json is provided
+ return
+ else:
+ var message = json_parse_result.result
+ gccm["ws_client"].send_json(message)
+
+func disconnect_client(gccid : int):
+ var gccm : Dictionary = gc_client_menus[gccid]
+ var disconnect_message = {"type" : "lobby_control", "command" : "disconnect"}
+ gccm["ws_client"].send_json(disconnect_message)
+
+func reset_ws_client(gccid : int):
+ var gccm : Dictionary = gc_client_menus[gccid]
+
+ gccm["ws_client"].queue_free()
+ gccm["ws_client"] = ws_client_template.instance()
+ gccm["menu"].add_child( gccm["ws_client"] )
+
+ gccm["host"].disabled = false
+ gccm["join"].disabled = false
+ gccm["disconnect"].disabled = true
+ gccm["send"].disabled = true
+
+
+func delete_gc_client(gccid : int):
+ var gc_client_menu : Dictionary = gc_client_menus[gccid]
+ gc_client_menu["parent"].queue_free() # remove HBoxContainer and all of its children, which together represent a gc client
+ gc_client_menus.erase(gccid)
+
+func create_gc_client():
+ latest_gccid += 1
+ var new_gc_index : int = latest_gccid
+ # container for all buttons
+ var gc_client_menu : HBoxContainer = HBoxContainer.new()
+
+ var ws_client : Node = ws_client_template.instance()
+ gc_client_menu.add_child(ws_client)
+
+ var delete_button : Button = Button.new()
+ delete_button.text = "X"
+ delete_button.connect("pressed", self, "delete_gc_client", [new_gc_index])
+ gc_client_menu.add_child(delete_button)
+
+ var connection_state : Label = Label.new()
+ connection_state.text = "0"
+ gc_client_menu.add_child(connection_state)
+
+ var input : TextEdit = TextEdit.new()
+ input.rect_min_size = Vector2(400, 100)
+ gc_client_menu.add_child(input)
+
+ var output : TextEdit = TextEdit.new()
+ output.text = "---CONNECTION OUTPUT---\n"
+ output.rect_min_size = Vector2(400, 100)
+ output.readonly = true
+ gc_client_menu.add_child(output)
+
+ var join_btn : Button = Button.new()
+ join_btn.text = "Join"
+ join_btn.connect("pressed", self, "join_lobby", [new_gc_index])
+ gc_client_menu.add_child(join_btn)
+
+ var host_btn : Button = Button.new()
+ host_btn.text = "Host"
+ host_btn.connect("pressed", self, "host_lobby", [new_gc_index])
+ gc_client_menu.add_child(host_btn)
+
+ var send_msg_btn : Button = Button.new()
+ send_msg_btn.text = "Send"
+ #send_msg_btn.disabled = true
+ send_msg_btn.connect("pressed", self, "send_message", [new_gc_index])
+ gc_client_menu.add_child(send_msg_btn)
+
+ var disconnect_btn : Button = Button.new()
+ disconnect_btn.text = "Disconnect"
+ #disconnect_btn.disabled = true
+ disconnect_btn.connect("pressed", self, "disconnect_client", [new_gc_index])
+ gc_client_menu.add_child(disconnect_btn)
+
+ var reset_btn : Button = Button.new()
+ reset_btn.text = "Reset WS"
+ reset_btn.disabled = true
+ reset_btn.connect("pressed", self, "reset_ws_client", [new_gc_index])
+ gc_client_menu.add_child(reset_btn)
+
+ var gc_client : Dictionary = {"parent": gc_client_menu, "state" : connection_state, "ws_client" : ws_client, "join" : join_btn, "host" : host_btn, "send" : send_msg_btn, "disconnect" : disconnect_btn, "reset" : reset_btn, "input" : input, "output" : output}
+ gc_client_menus[new_gc_index] = gc_client
+ add_child(gc_client_menu)
diff --git a/network/GameCoordinatorTester.tscn b/network/GameCoordinatorTester.tscn
new file mode 100644
index 0000000..9b34186
--- /dev/null
+++ b/network/GameCoordinatorTester.tscn
@@ -0,0 +1,19 @@
+[gd_scene load_steps=2 format=2]
+
+[ext_resource path="res://network/GameCoordinatorTester.gd" type="Script" id=2]
+
+[node name="GameCoordinatorTester" type="VBoxContainer"]
+anchor_right = 1.0
+anchor_bottom = 1.0
+script = ExtResource( 2 )
+
+[node name="ControlsHBox" type="HBoxContainer" parent="."]
+margin_right = 1600.0
+margin_bottom = 20.0
+
+[node name="AddClientBtn" type="Button" parent="ControlsHBox"]
+margin_right = 77.0
+margin_bottom = 20.0
+text = "Add client"
+
+[connection signal="pressed" from="ControlsHBox/AddClientBtn" to="." method="create_gc_client"]
diff --git a/network/WSClient.tscn b/network/WSClient.tscn
new file mode 100644
index 0000000..2224ed5
--- /dev/null
+++ b/network/WSClient.tscn
@@ -0,0 +1,6 @@
+[gd_scene load_steps=2 format=2]
+
+[ext_resource path="res://network/websocket_client.gd" type="Script" id=1]
+
+[node name="WSClient" type="Node"]
+script = ExtResource( 1 )
diff --git a/network/WebSocketTest.gd b/network/WebSocketTest.gd
deleted file mode 100644
index 49520dd..0000000
--- a/network/WebSocketTest.gd
+++ /dev/null
@@ -1,17 +0,0 @@
-extends Node
-
-onready var client = $WebSocketClient
-var sent = false
-
-func _ready():
- client.sock_connect_to_url("ws://127.0.0.1:8181")
-
-func _process(_delta):
- if client.state == 2 and not sent:
- client.send("test string".to_utf8(), true)
- client.send(JSON.print({"items" : [1, "test_dictionary"]}).to_utf8(), true)
- sent = true
- if client.state == 2:
- var message = client.receive()
- if message:
- print(message)
diff --git a/network/WebSocketTest.tscn b/network/WebSocketTest.tscn
deleted file mode 100644
index 3b02263..0000000
--- a/network/WebSocketTest.tscn
+++ /dev/null
@@ -1,12 +0,0 @@
-[gd_scene load_steps=3 format=2]
-
-[ext_resource path="res://network/WebSocketTest.gd" type="Script" id=1]
-[ext_resource path="res://network/websocket_client.gd" type="Script" id=2]
-
-[node name="WebSocketTest" type="Spatial"]
-script = ExtResource( 1 )
-
-[node name="WebSocketClient" type="Node" parent="."]
-script = ExtResource( 2 )
-
-[node name="Camera" type="Camera" parent="."]
diff --git a/network/websocket_client.gd b/network/websocket_client.gd
index 4583dc3..d10f518 100644
--- a/network/websocket_client.gd
+++ b/network/websocket_client.gd
@@ -5,6 +5,7 @@ var socket: WebSocketPeer = null
var state: int = 0 # -1 = CONNECTION_FAILED, 0 = CONNECTION_DISCONNECTED, 1 = CONNECTION_CONNECTING, 2 = CONNECTION_CONNECTED, 3 = CONNECTION_DISCONNECTING
var id
+var message_queue : Array = [] # messages to be sent upon connection
func _ready():
socket_client = WebSocketClient.new()
@@ -15,6 +16,7 @@ func _ready():
func sock_connect_to_url(url):
print("Connecting to %s..." % url)
+ message_queue.clear()
var error = socket_client.connect_to_url(url)
if error != OK:
return error
@@ -30,7 +32,12 @@ func sock_close(code = 1000, reason = ""):
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
+
+ while len(message_queue) > 0:
+ var msg = message_queue.pop_at(0)
+ send(msg)
func on_connection_close_success(clean):
print("WebSocket closed successfully.")
@@ -45,29 +52,31 @@ func on_connection_error(): # connection failed
socket = null
state = -1 # DISCONNECT DIRTY
-func send(message, as_string=false):
- if state != 2: return null
- if as_string:
- socket.set_write_mode(WebSocketPeer.WRITE_MODE_TEXT)
- return socket.put_packet(message)
- else:
- socket.set_write_mode(WebSocketPeer.WRITE_MODE_BINARY)
- return socket.put_packet(var2bytes(message))
+func send(message, as_bytes=false) -> int:
+ if state != 2:
+ message_queue.push_back(message)
+ return -1
+ return socket.put_packet(message)
+
func send_json(message) -> int:
- if state != 2: return -1
+ if state != 2:
+ message_queue.push_back(JSON.print(message).to_utf8())
+ return -1
var message_json = JSON.print(message).to_utf8()
- socket.set_write_mode(WebSocketPeer.WRITE_MODE_TEXT)
return socket.put_packet(message_json)
func receive(string_to_json=false):
if state != 2: return null
if socket.get_available_packet_count() < 1: return null
- print("receive")
var packet : PoolByteArray = socket.get_packet()
if socket.was_string_packet():
var message = packet.get_string_from_utf8()
- if string_to_json: message = JSON.parse(message)
+ if string_to_json:
+ var json = JSON.parse(message)
+ if json.error:
+ return null
+ message = json.result
return message
return bytes2var(packet)