extends Network var lobby: Lobby = null var reconnecting = false signal hosting(newhosting) signal signal_recieved(what) signal chat(text) 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 signal rematch_result(what) ## for accounts(mostly) signal signinresult(what) signal signupresult(what) const DEFAULT_ERROR_MESSAGE = "Error. Please report this issue to bendn." const HEADERS := { "joinrequest": "J", "hostrequest": "H", "signup": "C", "signin": ">", "relay": "R", # relay goes to both "signal": "S", # signal is one way "loadpgn": "L", # server telling me to load a pgn "info": "I", "move": "M", "undo": "<", "rematch": "r", "spectate": "0" # its a eye you see } var game_code := "" const RELAYHEADERS := {chat = "C"} const SIGNALHEADERS := {takeback = "T", draw = "D", resign = "R", info = "I"} # subheaders for HEADERS.signal 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: hosting = newhosting emit_signal("hosting", newhosting) func return() -> void: # return to the void if hosting: leaving = true set_hosting(false) 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_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: var data = ws.get_peer(1).get_var() Log.net(["RECIEVED:", data]) var header: String = data.header var text = data.data match header: HEADERS.undo: emit_signal("undo", text) HEADERS.move: if !OS.is_window_focused() and !Debug.debug: # dont be annoying in debug mode OS.request_attention() emit_signal("move_data", text.move) HEADERS.hostrequest: host_result(text) HEADERS.relay: var relay: Dictionary = text match relay.type: RELAYHEADERS.chat: emit_signal("chat", relay) HEADERS.joinrequest: join_result(text) HEADERS.info: yield(get_tree().create_timer(.5), "timeout") emit_signal("info_recieved", text) HEADERS.spectate: spectate_result(text) HEADERS.loadpgn: emit_signal("load_pgn", text) HEADERS.signal: var signal: Dictionary = text match signal.type: _: emit_signal("signal_recieved", signal) HEADERS.signup: emit_signal("signupresult", text) HEADERS.signin: emit_signal("signinresult", text) HEADERS.rematch: emit_signal("rematch_result", text) _: Log.err("unknown header %s" % header) func _connection_established(protocol) -> void: ._connection_established(protocol) func _connection_closed(_was_clean_closed) -> void: ._connection_closed(_was_clean_closed) 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() var err = yield(rejoin(), "completed") if err: go_back("Connection error, please check your internet, and reload the game.", false) const join_err_table := { "FULL": "This game is full. Double check your spelling, or host your own game..", "NOT_EXIST": "This game does not exist. Double check your spelling, or host it.", "NO_GAMECODE": "Your game name is empty.", "NO_ID": "Your id is undefined. Please report this issue to bendn." } func join_result(accepted) -> void: handle_result(accepted, "Joined!", join_err_table) const host_err_table := { "ALREADY_EXISTS": "This game name is taken. Pick a new name.", # game is full "ALREADY_EXISTS_EMPTY": "This game name is taken. Pick a new name, or join.", # someone else hosted, but noone is joining them :( "NO_GAMECODE": "Your game name is empty.", "NO_ID": "Your id is undefined. Please report this issue to bendn." } func host_result(accepted) -> void: set_hosting(handle_result(accepted, "Hosted!", host_err_table)) const spectate_err_table := {"NOT_EXIST": "This game does not exist. Double check your spelling, or host it."} func spectate_result(accepted) -> void: if handle_result(accepted, "Watching", spectate_err_table, true): Globals.spectating = true _start_game() yield(get_tree().create_timer(.5), "timeout") Globals.grid.load_pgn(accepted.pgn) emit_signal("info_recieved", accepted) func handle_result(accepted, resultstring: String, err_table: Dictionary, quick_return := false) -> bool: var err = accepted.get("err", false) emit_signal("request_result", false if err else true) if !err: if quick_return: return true Globals.team = "w" if accepted.idx == 0 else "b" Log.debug("Team set to " + Utils.expand_color(Globals.team)) set_lobby_status(resultstring, true) return true set_lobby_status(err_table.get(err, "Error. Please report this issue to bendn."), false) lobby.set_buttons(true) return false func go_back(error: String, isok: bool) -> void: Globals.reset_vars() if Globals.playing: $"/root/Game".queue_free() set_lobby_status(error, isok) lobby.toggle(true) lobby.focus() lobby.set_buttons(true) func _start_game() -> void: set_hosting(false) Log.debug("Created board") var ui: GameUI = load("res://ui/board/Game.tscn").instance() var b: Grid = ui.get_board() as Grid b.team = Globals.team Log.debug("Set board team to %s" % Utils.expand_color(b.team)) get_tree().get_root().add_child(ui) b.spectating = Globals.spectating lobby.toggle(false) emit_signal("start_game") lobby.set_buttons(false) SoundFx.play("Victory") yield(get_tree(), "idle_frame") b.auto_flip() 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) func signup(data): send_packet(data, HEADERS.signup) func signal(body: Dictionary, header: String, _mainheader := HEADERS.signal) -> Dictionary: var data: Dictionary = Utils.append_dict({"type": header}, body) send_packet(data, _mainheader) return data func join_game(game: String = game_code) -> void: send_gamecode_packet(Creds.get_public(), HEADERS.joinrequest, game) func host_game(game: String = game_code, white := true, moves_array: PoolStringArray = []) -> void: var pckt = Utils.append_dict(Creds.get_public(), {team = white, moves = moves_array}) send_gamecode_packet(pckt, HEADERS.hostrequest, game) func spectate(game: String = game_code) -> void: send_gamecode_packet(Creds.get_public(), HEADERS.spectate, game) func send_gamecode_packet(data: Dictionary, header: String, gamecode: String = game_code): send_packet(Utils.append_dict({"gamecode": gamecode}, data), header) func relay_signal(body: Dictionary, header: String) -> Dictionary: # its really the same thing as signal() return signal(body, header, HEADERS.relay) func send_mov(mov: String) -> void: send_packet({move = mov}, HEADERS.move) static func construct_errstr(packet, err_table, default_message := DEFAULT_ERROR_MESSAGE) -> String: var errstr: String = "" var err: String = packet.get("err", false) if err: errstr = err_table.get(err, default_message) var stack = packet.get("stack", false) if stack: errstr += " (Stack trace: %s) " % stack return errstr