online multiplayer chess game (note server currently down)
rejoins
bendn 2022-08-02
parent f1f748b · commit f76191b
-rw-r--r--Globals.gd2
-rw-r--r--Square.gd2
-rw-r--r--networking/Network.gd47
-rw-r--r--networking/PacketHandler.gd81
-rw-r--r--ui/board/Board.gd1
-rw-r--r--ui/chat/Chat.gd2
6 files changed, 106 insertions, 29 deletions
diff --git a/Globals.gd b/Globals.gd
index b9e9cfd..b60db79 100644
--- a/Globals.gd
+++ b/Globals.gd
@@ -5,6 +5,7 @@ var piece_set := "california"
var board_color1: Color = Color(0.870588, 0.890196, 0.901961)
var board_color2: Color = Color(0.54902, 0.635294, 0.678431)
var spectating := false
+var playing := false
var chat: Chat = null
var grid: Grid = null
@@ -14,6 +15,7 @@ func reset_vars() -> void:
grid = null
chat = null
spectating = false
+ playing = false
func _ready() -> void:
diff --git a/Square.gd b/Square.gd
index cf31961..d8e1124 100644
--- a/Square.gd
+++ b/Square.gd
@@ -28,7 +28,7 @@ func size():
func check_piece_above() -> bool:
- return is_instance_valid(Globals.grid.get_piece(square))
+ return is_instance_valid(Globals.grid.get_piece(square)) if Globals.playing else false
func _gui_input(event: InputEvent):
diff --git a/networking/Network.gd b/networking/Network.gd
index aa3f13d..8091cb8 100644
--- a/networking/Network.gd
+++ b/networking/Network.gd
@@ -3,23 +3,20 @@ class_name Network
const url := "wss://gd-chess-server.herokuapp.com/"
-var ws := WebSocketClient.new()
-var connected := false
-
+var ws = WebSocketClient.new()
signal connection_established
-func _ready():
+func _init():
SaveLoad.save_string("user://network_log.log", "") # overwrite last log
+ connect_ws_signals()
-func open() -> void:
- ws.connect_to_url(url)
+func connect_ws_signals():
ws.connect("connection_established", self, "_connection_established")
ws.connect("connection_closed", self, "_connection_closed")
ws.connect("connection_error", self, "_connection_error")
ws.connect("data_received", self, "_data_recieved")
- Log.net("OPEN NETWORK: " + url)
func close() -> void:
@@ -27,36 +24,56 @@ func close() -> void:
func _connection_established(_protocol) -> void:
- Log.net("CONNECTED TO %s" % url)
+ Log.net("CONNECTED: %s" % url)
emit_signal("connection_established") # bubble the signal up
- connected = true
func _connection_closed(_was_clean_closed) -> void:
- connected = false
- Log.net("DISCONNECTED FROM %s" % url)
+ Log.net("DISCONNECTED: %s" % url)
Log.err("Connection closed")
func _connection_error() -> void:
- connected = false
+ Log.net("DISCONNECTED: %s" % url)
Log.err("Connection error")
- Log.net("DISCONNECTED FROM %s" % url)
func _data_recieved():
pass
+func is_open_connection():
+ return ws.get_connection_status() == ws.CONNECTION_CONNECTED
+
+
+func open_connection(tries := 5, interval := 1.0) -> int:
+ yield(get_tree(), "idle_frame")
+ if is_open_connection():
+ return OK
+ for try in tries + 1:
+ if Utils.request() == OK:
+ var err = ws.connect_to_url(url)
+ if !err:
+ yield(ws, "connection_established")
+ if is_open_connection():
+ return OK
+ else:
+ Log.net("CONNECT: failed(%s)" % err)
+ if try != tries:
+ yield(get_tree().create_timer(interval), "timeout")
+ Log.net("CONNECT: failed")
+ return ERR_CANT_CONNECT
+
+
func _process(_delta: float) -> void:
- var wsstatus := ws.get_connection_status()
+ var wsstatus: int = ws.get_connection_status()
if wsstatus == ws.CONNECTION_CONNECTING or wsstatus == ws.CONNECTION_CONNECTED:
ws.poll()
func send_packet(variant, header: String) -> int:
var pckt = {header = header, data = variant}
- if ws.get_peer(1).is_connected_to_host():
+ if is_open_connection():
ws.get_peer(1).put_var(pckt)
Log.net("SENT: %s" % pckt)
return OK
diff --git a/networking/PacketHandler.gd b/networking/PacketHandler.gd
index 550eb37..c974907 100644
--- a/networking/PacketHandler.gd
+++ b/networking/PacketHandler.gd
@@ -1,6 +1,7 @@
extends Network
var lobby: Lobby = null
+var reconnecting = false
signal hosting(newhosting)
signal signal_recieved(what)
signal chat(text)
@@ -8,6 +9,8 @@ signal undo(undo)
signal info_recieved(info)
signal start_game
signal move_data(data)
+signal load_pgn(pgn)
+signal request_result(what) # join/host true accepted, false rejected
## for accounts(mostly)
signal signinresult(what)
signal signupresult(what)
@@ -34,6 +37,12 @@ const SIGNALHEADERS := {takeback = "T", draw = "D", resign = "R", info = "I"} #
var hosting := false setget set_hosting
var leaving := false
+var lock_lobby_status := false
+
+
+func set_lobby_status(status: String, isok: bool) -> void:
+ if !lock_lobby_status:
+ lobby.set_status(status, isok)
func set_hosting(newhosting: bool) -> void:
@@ -52,8 +61,16 @@ func _ready() -> void:
Events.connect("go_back", self, "go_back")
if Utils.internet and get_tree().get_root().has_node("StartMenu"):
yield(get_tree().create_timer(.1), "timeout")
- open() # open connection
- lobby.set_status("Connecting", true)
+ open_connection()
+ set_lobby_status("Connecting", true)
+ connect("load_pgn", self, "load_pgn")
+
+
+func load_pgn(pgn: String) -> void:
+ if !Globals.grid:
+ _start_game()
+ yield(get_tree(), "idle_frame")
+ Globals.grid.load_pgn(pgn) # call deferred wont work since grid obj may be null
func _data_recieved() -> void:
@@ -83,7 +100,7 @@ func _data_recieved() -> void:
HEADERS.spectate:
# handle spectate here
if typeof(text) == TYPE_STRING: # ew error
- lobby.set_status(text, false)
+ set_lobby_status(text, false)
lobby.set_buttons(true)
return
Globals.spectating = true
@@ -92,10 +109,7 @@ func _data_recieved() -> void:
Globals.grid.load_pgn(text.pgn)
emit_signal("info_recieved", text)
HEADERS.loadpgn:
- _start_game()
- yield(get_tree().create_timer(.5), "timeout")
- Log.info("load pgn " + text)
- Globals.grid.load_pgn(text) # call deferred wont work since grid obj may be null
+ emit_signal("load_pgn", text)
HEADERS.stopgame:
if !Globals.grid.chess.game_over(): # dont go back if its a stophost thing or the game is over by the st (HACK)
go_back(text, true)
@@ -118,12 +132,16 @@ func _connection_established(protocol) -> void:
func _connection_closed(_was_clean_closed) -> void:
._connection_closed(_was_clean_closed)
- go_back("Connection closed, please reload the game", false)
+ var err = yield(rejoin(), "completed")
+ if err:
+ go_back("Connection closed, please check your internet, and reload the game.", false)
func _connection_error() -> void:
._connection_error()
- go_back("Connection error, please reload the game", false)
+ var err = yield(rejoin(), "completed")
+ if err:
+ go_back("Connection error, please check your internet, and reload the game.", false)
func join_result(accepted) -> void:
@@ -135,12 +153,13 @@ func host_result(accepted) -> void:
func handle_result(accepted, resultstring: String) -> bool:
+ emit_signal("request_result", false if typeof(accepted) != TYPE_DICTIONARY else true)
if typeof(accepted) == TYPE_DICTIONARY:
Globals.team = "w" if accepted.idx == 0 else "b"
Log.debug("Team set to " + Utils.expand_color(Globals.team))
- lobby.set_status(resultstring, true)
+ set_lobby_status(resultstring, true)
return true
- lobby.set_status(accepted, false)
+ set_lobby_status(accepted, false)
lobby.set_buttons(true)
return false
@@ -149,13 +168,14 @@ func go_back(error: String, isok: bool) -> void:
Globals.reset_vars()
if has_node("/root/Game"):
$"/root/Game".queue_free()
- lobby.set_status(error, isok)
+ set_lobby_status(error, isok)
lobby.toggle(true)
lobby.focus()
lobby.set_buttons(true)
func _start_game() -> void:
+ Globals.playing = true
set_hosting(false)
var board: Control = load("res://ui/board/Game.tscn").instance()
get_tree().get_root().add_child(board)
@@ -169,6 +189,43 @@ func _start_game() -> void:
board.get_board().flip_board()
+func rejoin(tries := 5, interval := 2) -> int: # on disconnect, try to rejoin
+ var err = yield(open_connection(tries, interval), "completed")
+ if reconnecting == true:
+ return ERR_ALREADY_IN_USE
+ reconnecting = true
+ Log.info("reconnecting...")
+ if not err:
+ if Globals.playing:
+ Log.info("reconnecting(rejoining)...")
+ lock_lobby_status = true
+ var rejoined = false
+ for try in tries + 1:
+ join_game()
+ var result = yield(self, "request_result")
+ if result:
+ disconnect("load_pgn", self, "load_pgn")
+ var pgn = yield(self, "load_pgn")
+ if Globals.grid.chess.pgn() != pgn:
+ Log.info("attempting to load %s" % pgn)
+ Globals.grid.load_pgn(pgn)
+ connect("load_pgn", self, "load_pgn")
+ Log.info("reconnected(rejoined)!")
+ rejoined = true
+ break
+ lock_lobby_status = false
+ if rejoined == false:
+ Log.err("reconnect failed(rejoin)!")
+ reconnecting = false
+ return ERR_INVALID_DATA
+ else: # not playing: just reconnect
+ Log.info("reconnected!")
+ else:
+ Log.err("reconnect failed!")
+ reconnecting = false
+ return err
+
+
## packet sending wrapper functions
func signin(data):
send_packet(data, HEADERS.signin)
diff --git a/ui/board/Board.gd b/ui/board/Board.gd
index 001be50..176f804 100644
--- a/ui/board/Board.gd
+++ b/ui/board/Board.gd
@@ -322,6 +322,7 @@ func load_pgn(pgn: String) -> void:
emit_signal("clear_pgn")
var movs: PoolStringArray = Pgn.parse(pgn).moves
emit_signal("load_pgn", movs)
+ Log.info("load pgn " + pgn)
Events.emit_signal("turn_over")
diff --git a/ui/chat/Chat.gd b/ui/chat/Chat.gd
index a8d44a7..5f4eae8 100644
--- a/ui/chat/Chat.gd
+++ b/ui/chat/Chat.gd
@@ -46,7 +46,7 @@ func send(t: String) -> void:
t = md2bb(t)
var name = Creds.get("name") if Creds.get("name") else "Anonymous"
name += "(%s)" % ("Spectator" if Globals.spectating else Globals.team)
- if PacketHandler.connected:
+ if PacketHandler.is_open_connection():
PacketHandler.relay_signal({"text": t, "who": name}, PacketHandler.RELAYHEADERS.chat)
else:
add_label_with({text = t, who = name}) # for testing