online multiplayer chess game (note server currently down)
the signal way
bendn 2022-05-30
parent c2153ba · commit d09baa2
-rw-r--r--Grid.gd22
-rw-r--r--Utils.gd2
-rw-r--r--networking/Network.gd59
-rw-r--r--networking/PacketHandler.gd61
-rw-r--r--pieces/Pawn.gd5
-rw-r--r--project.godot6
-rw-r--r--ui/Lobby.gd18
-rw-r--r--ui/Status.gd5
-rw-r--r--ui/barbutton/drawbutton.gd38
-rw-r--r--ui/barbutton/resignbutton.gd6
-rw-r--r--ui/confirmbar.gd2
11 files changed, 106 insertions, 118 deletions
diff --git a/Grid.gd b/Grid.gd
index e1649ec..c7df829 100644
--- a/Grid.gd
+++ b/Grid.gd
@@ -167,7 +167,7 @@ func mat2str(mat: Array = matrix) -> String:
func drawed(reason := "") -> void:
- ui.set_status("draw by " + reason)
+ ui.set_status("draw by " + reason, 0)
Events.emit_signal("game_over")
SoundFx.play("Draw")
yield(get_tree().create_timer(5), "timeout")
@@ -175,7 +175,7 @@ func drawed(reason := "") -> void:
func win(winner: bool, reason := "") -> void:
- ui.set_status("%s won the game by %s" % ["white" if winner else "black", reason]) # black won the game by checkmate
+ ui.set_status("%s won the game by %s" % ["white" if winner else "black", reason], 0) # black won the game by checkmate
Events.emit_signal("game_over")
Log.info("%s won the game in %s turns!" % ["white" if winner else "black", Globals.turns()])
SoundFx.play("Victory")
@@ -329,8 +329,8 @@ func handle_take(position: Vector2) -> void:
if Utils.is_pawn(last_clicked): # if its a pawn
if check_promote(last_clicked, position, "take"):
return
- Globals.network.send_move_packet(
- PoolVector2Array([last_clicked.real_position, position]), Network.MOVEHEADERS.move
+ Globals.network.relay_signal(
+ PoolVector2Array([last_clicked.real_position, position]), Network.MOVEHEADERS.move, "positions"
) # piece taking piece
@@ -340,14 +340,15 @@ func handle_move(position: Vector2) -> void:
var castle_data = last_clicked.can_castle[i]
if castle_data[0] == position:
# send some packet
- Globals.network.send_move_packet(
+ Globals.network.relay_signal(
{
"king": last_clicked.real_position,
"rook": castle_data[1].real_position,
"rookdestination": castle_data[2],
"kingdestination": castle_data[0]
},
- Network.MOVEHEADERS.castle
+ Network.MOVEHEADERS.castle,
+ "positions"
)
return
@@ -358,15 +359,16 @@ func handle_move(position: Vector2) -> void:
var en_passant_data = pawn.enpassant[i]
if en_passant_data[0] == position:
# send some packet
- Globals.network.send_move_packet(
+ Globals.network.relay_signal(
PoolVector2Array([pawn.real_position, position, en_passant_data[1].real_position]),
- Network.MOVEHEADERS.passant
+ Network.MOVEHEADERS.passant,
+ "positions"
)
return
elif check_promote(pawn, position):
return
- Globals.network.send_move_packet(
- PoolVector2Array([last_clicked.real_position, position]), Network.MOVEHEADERS.move
+ Globals.network.relay_signal(
+ PoolVector2Array([last_clicked.real_position, position]), Network.MOVEHEADERS.move, "positions"
) # piece moving
diff --git a/Utils.gd b/Utils.gd
index ec9cdbc..3810ff4 100644
--- a/Utils.gd
+++ b/Utils.gd
@@ -177,7 +177,7 @@ func get_fen() -> String:
func _notification(what: int) -> void:
if what == MainLoop.NOTIFICATION_WM_QUIT_REQUEST or what == MainLoop.NOTIFICATION_WM_GO_BACK_REQUEST:
if get_tree().get_root().has_node("Board"):
- Globals.network.send_packet(Globals.network.game_code, Network.HEADERS.stopgame)
+ Globals.network.stopgame("quit")
yield(get_tree(), "idle_frame") # wait for the packet to send
Log.debug("Bye!")
get_tree().quit()
diff --git a/networking/Network.gd b/networking/Network.gd
index e6fb242..7ac4590 100644
--- a/networking/Network.gd
+++ b/networking/Network.gd
@@ -7,24 +7,24 @@ var game_code := ""
var connected := false
const HEADERS := {
- "move": "M",
"joinrequest": "J",
"hostrequest": "H",
"stopgame": "K",
"ping": "P",
- "startgame": "S",
- "request": "R"
+ "relay": "R", # relay goes to both
+ "signal": "S", # signal is one way
}
-const MOVEHEADERS := {
- "take": "K",
+const MOVEHEADERS := { # subheaders for HEADERS.move
"move": "M",
+ "take": "K",
"castle": "C",
"passant": "P",
"promote": "Q",
}
-const REQUESTHEADERS := {"takeback": "T", "draw": "D", "resign": "R"} # not really a request, but...
+const RELAYHEADERS := {"chat": "C", "startgame": "S"}
+const SIGNALHEADERS := {"takeback": "T", "draw": "D", "resign": "R"} # subheaders for HEADERS.signal
var notation := ""
@@ -33,9 +33,8 @@ signal move_data(data)
signal host_result(result)
signal join_result(result)
signal game_over(problem, isok)
-signal request_result(result)
-signal request(request)
signal connection_established
+signal signal_recieved(what)
const url := "wss://gd-chess-server.herokuapp.com/"
@@ -80,45 +79,49 @@ func _connection_error() -> void:
emit_signal("game_over", "Connection error", false)
-func send_request_answer_packet(request_type: String, answer: bool) -> void:
- var data := {"answering": true, "type": request_type, "gamecode": game_code, "answer": answer}
- send_packet(data, HEADERS.request)
+func signal(body, header: String, keyname := "body", _mainheader := HEADERS.signal) -> Dictionary:
+ var data := {"type": header, "gamecode": game_code, keyname: body}
+ send_packet(data, _mainheader)
+ Log.debug("sending signal %s of type %s" % [body, header])
+ return data
-func send_request_packet(request_type: String, prompt: String) -> void:
- var data := {"answering": false, "type": request_type, "gamecode": game_code, "question": prompt}
- send_packet(data, HEADERS.request)
+func relay_signal(body, header: String, keyname := "body") -> Dictionary: # its really the same thing as signal()
+ return signal(body, header, keyname, HEADERS.relay)
-func send_move_packet(positions, header: String) -> void:
- var packet := {"movetype": header, "gamecode": game_code, "positions": positions}
- Log.debug("sending move packet: %s" % packet)
- send_packet(packet, HEADERS.move) # your move will wait till the server relays back :>
+func stopgame(reason: String) -> void:
+ var packet := {"reason": reason, "gamecode": game_code}
+ send_packet(packet, HEADERS.stopgame)
func _data_recieved() -> void:
var recieve: Dictionary = ws.get_peer(1).get_var()
var header: String = recieve.header
var text = recieve.data
+ if header != HEADERS.ping:
+ Log.debug("recieved %s of header %s" % [text, header])
match header:
HEADERS.hostrequest:
emit_signal("host_result", text)
- HEADERS.move:
- emit_signal("move_data", text)
+ HEADERS.relay:
+ var relay: Dictionary = text
+ if relay.type in MOVEHEADERS.values():
+ emit_signal("move_data", text)
+ else:
+ match relay.type:
+ RELAYHEADERS.startgame:
+ print("Start")
+ emit_signal("start_game")
HEADERS.joinrequest:
emit_signal("join_result", text)
HEADERS.stopgame:
if !PacketHandler.leaving: # dont emit the signal if its a stophost thing (HACK)
emit_signal("game_over", text, true)
PacketHandler.leaving = false
- HEADERS.startgame:
- emit_signal("start_game")
- PacketHandler.emit_signal("set_visible", false)
- HEADERS.request:
- if text.answering:
- emit_signal("request_result", text)
- else:
- emit_signal("request", text)
+ HEADERS.signal:
+ var signal: Dictionary = text
+ emit_signal("signal_recieved", signal)
HEADERS.ping:
pass
_:
diff --git a/networking/PacketHandler.gd b/networking/PacketHandler.gd
index ca0da6d..5034a4b 100644
--- a/networking/PacketHandler.gd
+++ b/networking/PacketHandler.gd
@@ -1,25 +1,14 @@
extends Node
class_name NetManager
-### for the lobby ui
-signal set_buttons(enabled)
-signal set_status(status, err, isok)
-signal set_visible(visibility)
+var lobby: Lobby = null
signal hosting(newhosting)
-
signal game_over
signal game_started
var hosting := false setget set_hosting
var leaving := false
-var status := ["", true, false]
-
-
-func set_buttons(enabled: bool) -> void:
- status[2] = enabled
- emit_signal("set_buttons", enabled)
-
func set_hosting(newhosting: bool) -> void:
hosting = newhosting
@@ -29,17 +18,16 @@ func set_hosting(newhosting: bool) -> void:
func return() -> void: # return to the void
if hosting:
leaving = true
- Globals.network.send_packet(Globals.network.game_code, Network.HEADERS.stopgame) # stop hosting
+ Globals.network.stopgame("") # stop hosting
set_hosting(false)
- set_buttons(true)
- set_status("", true)
+ lobby.set_buttons(true)
+ lobby.set_status("", true)
func _ready() -> void:
get_tree().set_auto_accept_quit(false)
if Utils.internet:
var net := Network.new()
- set_status("Connecting", true)
Events.connect("go_back", self, "_handle_game_over")
net.connect("move_data", self, "_on_data")
net.connect("join_result", self, "_on_join_result")
@@ -49,33 +37,28 @@ func _ready() -> void:
net.connect("connection_established", self, "network_ready")
add_child(net)
Globals.network = net
+ yield(get_tree().create_timer(.1), "timeout")
+ lobby.set_status("Connecting", true)
func requestjoin() -> void:
- set_buttons(false)
+ lobby.set_buttons(false)
Globals.network.send_packet(Globals.network.game_code, Globals.network.HEADERS.joinrequest)
func requesthost() -> void:
- set_buttons(false)
+ lobby.set_buttons(false)
Globals.network.send_packet(Globals.network.game_code, Globals.network.HEADERS.hostrequest)
func network_ready() -> void:
- set_status("", true)
- set_buttons(true)
-
-
-func set_status(text: String, isok: bool) -> void:
- status[0] = text
- status[1] = isok
- emit_signal("set_status", text, isok)
+ lobby.set_status("", true)
+ lobby.set_buttons(true)
func _on_join_result(accepted: String) -> void:
if handle_result(accepted, "Joined!", false):
- emit_signal("set_visible", false)
- Globals.network.send_packet(Globals.network.game_code, Globals.network.HEADERS.startgame)
+ Globals.network.relay_signal("startgame", Network.RELAYHEADERS.startgame)
func _on_host_result(accepted: String) -> void:
@@ -85,21 +68,21 @@ func _on_host_result(accepted: String) -> void:
func handle_result(accepted: String, resultstring: String, team := true) -> bool:
Globals.team = team # what am i doing here???
if accepted == "Y":
- set_status(resultstring, true)
+ lobby.set_status(resultstring, true)
return true
- set_status(accepted, false)
- set_buttons(true)
+ lobby.set_status(accepted, false)
+ lobby.set_buttons(true)
return false
func _handle_game_over(error := "game over", isok := true) -> void:
- Globals.network.send_packet({"gamecode": Globals.network.game_code, "reason": error}, Network.HEADERS.stopgame)
+ Globals.network.stopgame(error)
Globals.reset_vars()
if get_tree().get_root().has_node("Board"):
get_tree().get_root().get_node("Board").queue_free()
- set_status(error, isok)
- emit_signal("set_visible", true)
- set_buttons(true)
+ lobby.set_status(error, isok)
+ lobby.toggle(true)
+ lobby.set_buttons(true)
emit_signal("game_over")
@@ -107,16 +90,16 @@ func _start_game() -> void:
set_hosting(false)
var board: Node2D = load("res://Board.tscn").instance()
get_tree().get_root().add_child(board)
- emit_signal("set_visible", false)
+ lobby.toggle(false)
emit_signal("game_started")
- set_buttons(false)
+ lobby.set_buttons(false)
func _on_data(data: Dictionary) -> void:
Globals.add_turn()
Log.debug([data, " recieved"])
Events.emit_signal("data_recieved")
- match data["movetype"]:
+ match data["type"]:
Network.MOVEHEADERS.passant:
# en passant
var end_pos := dict2vec(data["positions"][1])
@@ -147,6 +130,8 @@ func _on_data(data: Dictionary) -> void:
pawn.took() # kill the pawn
Utils.add_move(dict_data["notation"]) # add a move
Globals.grid.print_matrix_pretty(Globals.grid.matrix)
+ _:
+ Log.err("Wtf")
static func dict2vec(dict: Dictionary) -> Vector2:
diff --git a/pieces/Pawn.gd b/pieces/Pawn.gd
index ab9ea15..a4078ec 100644
--- a/pieces/Pawn.gd
+++ b/pieces/Pawn.gd
@@ -141,7 +141,7 @@ func handle_sprite_input_event(node: Node2D) -> void:
)
Log.debug(promote_to)
var notation := "%s=%s" % [first, promote_to]
- Globals.network.send_move_packet(
+ Globals.network.relay_signal(
{
"start_position": real_position,
"destination": promoteposition,
@@ -149,7 +149,8 @@ func handle_sprite_input_event(node: Node2D) -> void:
"notation": notation,
"white": white
},
- Network.MOVEHEADERS.promote
+ Network.MOVEHEADERS.promote,
+ "positions"
)
diff --git a/project.godot b/project.godot
index 1fe7c99..dcd2743 100644
--- a/project.godot
+++ b/project.godot
@@ -74,6 +74,11 @@ _global_script_classes=[ {
"language": "GDScript",
"path": "res://pieces/Knight.gd"
}, {
+"base": "Control",
+"class": "Lobby",
+"language": "GDScript",
+"path": "res://ui/Lobby.gd"
+}, {
"base": "Node",
"class": "Log",
"language": "GDScript",
@@ -148,6 +153,7 @@ _global_script_class_icons={
"HueSlider": "",
"King": "res://assets/pieces/california/wK.png",
"Knight": "res://assets/pieces/california/wN.png",
+"Lobby": "",
"Log": "",
"NetManager": "",
"Network": "",
diff --git a/ui/Lobby.gd b/ui/Lobby.gd
index bc8dd3f..a696ed5 100644
--- a/ui/Lobby.gd
+++ b/ui/Lobby.gd
@@ -1,4 +1,5 @@
extends Control
+class_name Lobby
onready var address: LineEdit = find_node("Address")
onready var buttons := find_node("buttons")
@@ -11,19 +12,14 @@ func toggle(onoff: bool) -> void:
func _ready() -> void:
- PacketHandler.connect("set_status", self, "_set_status")
- PacketHandler.connect("set_buttons", self, "_set_buttons")
- PacketHandler.connect("set_visible", self, "toggle")
+ PacketHandler.lobby = self
PacketHandler.connect("hosting", find_node("stophost"), "set_visible")
- _set_status(PacketHandler.status[0], PacketHandler.status[1])
if !Utils.internet:
- _set_status("no internet", false)
- _set_buttons(false)
- else:
- _set_buttons(PacketHandler.status[2])
+ set_status("no internet", false)
+ set_buttons(false)
-func _set_status(text: String, isok: bool) -> void: # Simple way to show status.
+func set_status(text: String, isok: bool) -> void: # Simple way to show status.
if isok:
status_ok.set_text(text)
status_fail.set_text("")
@@ -34,7 +30,7 @@ func _set_status(text: String, isok: bool) -> void: # Simple way to show status
status_fail.visible = len(status_fail.text) > 0
-func _set_buttons(enabled := true) -> void:
+func set_buttons(enabled := true) -> void:
for c in buttons.get_children():
c.disabled = !enabled
address.editable = enabled
@@ -65,7 +61,7 @@ func _on_Address_text_entered(new_text: String) -> void:
func _on_tabs_tab_changed(tab: int):
- if tab != get_parent().get_children().find(self):
+ if self != get_parent().get_children()[tab]:
PacketHandler.return()
diff --git a/ui/Status.gd b/ui/Status.gd
index 6a68c79..351f523 100644
--- a/ui/Status.gd
+++ b/ui/Status.gd
@@ -5,5 +5,6 @@ class_name StatusLabel
func set_text(newtext: String, time := 7) -> void:
print("set to ", newtext)
text = newtext
- yield(get_tree().create_timer(time), "timeout")
- text = ""
+ if time != 0:
+ yield(get_tree().create_timer(time), "timeout")
+ text = ""
diff --git a/ui/barbutton/drawbutton.gd b/ui/barbutton/drawbutton.gd
index c5fb8ef..13f4965 100644
--- a/ui/barbutton/drawbutton.gd
+++ b/ui/barbutton/drawbutton.gd
@@ -7,18 +7,21 @@ export(NodePath) onready var confirmbar = get_node(confirmbar) as Confirm
var waiting_on_answer := false
-func _ready() -> void:
- Globals.network.connect("request", self, "draw_request")
- Globals.network.connect("request_result", self, "_on_draw_result")
+func _ready():
+ Globals.network.connect("signal_recieved", self, "_on_signal")
-func draw_request(what: Dictionary):
- if what.type == Network.REQUESTHEADERS.draw:
- if "questions" in what:
- Log.err("Draw request without prompt")
- return
- confirmbar.confirm(self, what.question, 20)
- waiting_on_answer = true
+func _on_signal(what: Dictionary):
+ if what.type == Network.SIGNALHEADERS.draw:
+ if "question" in what:
+ confirmbar.confirm(self, "Your opponent requests a draw", 20)
+ waiting_on_answer = true
+ else:
+ disabled = false
+ if what.accepted:
+ drawed()
+ else:
+ status.set_text("Your opponent rejected the draw")
func drawed() -> GDScriptFunctionState:
@@ -35,25 +38,14 @@ func _pressed() -> void:
confirmbar.stop_looking()
else:
disabled = true
- Globals.network.send_request_packet(
- Network.REQUESTHEADERS.draw, "Your opponent wishes to draw, do you accept?"
- )
+ Globals.network.signal("", Network.SIGNALHEADERS.draw, "question")
status.set_text("Draw request sent")
-func _on_draw_result(accepted: Dictionary) -> void: # called from _handle_confirm
- disabled = false
- if accepted.type == Network.REQUESTHEADERS.draw:
- if accepted.answer:
- drawed()
- else:
- status.set_text("Your opponent has rejected the draw request.")
-
-
func _handle_confirm(yes: bool) -> void: # called from confirmbar.confirmed
if waiting_on_answer:
disabled = false
waiting_on_answer = false
- Globals.network.send_request_answer_packet(Network.REQUESTHEADERS.draw, yes)
+ Globals.network.signal(yes, Network.SIGNALHEADERS.draw, "accepted")
if yes:
drawed()
diff --git a/ui/barbutton/resignbutton.gd b/ui/barbutton/resignbutton.gd
index 3ca7490..2a03c3e 100644
--- a/ui/barbutton/resignbutton.gd
+++ b/ui/barbutton/resignbutton.gd
@@ -9,11 +9,11 @@ var waiting_on_answer = false
func _ready() -> void:
- Globals.network.connect("request", self, "resigned")
+ Globals.network.connect("signal_recieved", self, "resigned")
func resigned(what: Dictionary):
- if what.type == Network.REQUESTHEADERS.resign:
+ if what.type == Network.SIGNALHEADERS.resign:
Globals.grid.win(Globals.team, "resignation")
@@ -36,6 +36,6 @@ func _confirmed(what: bool):
waiting_on_answer = false
drawbutton.disabled = what # dont un disable it if the game is over
if what:
- Globals.network.send_request_packet(Network.REQUESTHEADERS.resign, "")
+ Globals.network.signal("", Network.SIGNALHEADERS.resign)
Globals.grid.win(!Globals.team, "resignation")
disabled = true
diff --git a/ui/confirmbar.gd b/ui/confirmbar.gd
index f378f59..8b188aa 100644
--- a/ui/confirmbar.gd
+++ b/ui/confirmbar.gd
@@ -34,6 +34,8 @@ func confirm(who: Node, what: String, timeout := 5):
func _pressed(what: bool):
+ for i in $H.get_children():
+ i._focused(false)
status.set_text("", 0)
emit_signal("confirmed", what)
stop_looking()