class ClientHandler: def __init__(self, sock): self.__socket = sock self.__message_parser = MessageParser() self.__lobby_model = LobbyModel() # name of the game self.__game = None # player number (1 or 2) self.__player = None # player id lol self.__id = self.__get_own_player_id() # add client as player self.__lobby_model.add_player(self.__id) # register callbacks self.__lobby_model.register_callback(LobbyEvent.on_update, self.on_update_lobby) self.__lobby_model.register_callback(LobbyEvent.on_chat, self.on_chat) def handle(self): logging.info("Client {} connected.".format( self.__socket.getpeername())) while True: logging.debug("handle({}) loop.".format( self.__socket.getpeername())) # receive 2 bytes size header size = self.__recv(2) if not size: logging.debug("Did not receive 2 bytes header.") break size = struct.unpack('>H', size)[0] logging.debug("Size: " + str(size)) # receive message body msg = self.__recv(size) if not msg: logging.debug("Did not receive {} bytes body.".format( str(size))) break # explode received data into message type and parameters msgtype, msgparams = self.__message_parser.decode(msg.decode()) logging.debug("Msg type: " + msgtype) logging.debug("Msg parameters: " + repr(msgparams)) # dispatch message type if msgtype == messages.CREATE_GAME: self.__create_game(msgparams) elif msgtype == messages.JOIN_GAME: self.__join_game(msgparams) elif msgtype == messages.SET_NICK: self.__set_nickname(msgparams) elif msgtype == messages.LEAVE_GAME: self.__leave_game() elif msgtype == messages.INIT_BOARD: self.__init_board(msgparams) elif msgtype == messages.FIRE: self.__fire(msgparams) elif msgtype == messages.NUKE: self.__nuke(msgparams) elif msgtype == messages.MOVE: self.__move(msgparams) elif msgtype == messages.SURRENDER: self.__surrender() elif msgtype == messages.CHAT_SEND: self.__chat(msgparams) else: self.__unknown_msg() # # Callbacks # def on_update_lobby(self): logging.debug("on_update_lobby()") # Get required data for update lobby msg number_of_clients = self.__lobby_model.get_number_of_players() number_of_games = self.__lobby_model.get_number_of_games() games_info = self.__lobby_model.get_games_info() players_info = self.__lobby_model.get_players_info() # Update_Lobby data = { 'status': 16, 'number_of_clients': number_of_clients, 'number_of_games': number_of_games[0] } i = 0 weirdkey = 'game_name_{}' moreweirdkeys = 'game_players_count_{}' whatevenisthis = 'game_player_{}_{}' waitwhat = 'player_name_{}' yetanotherkey = 'player_identifier_{}' for game in games_info: # game stuff data[weirdkey.format(i)] = game['game_name'] data[moreweirdkeys.format(i)] = game['number_of_players'] # player 1 stuff data[whatevenisthis.format(i, 0)] = game['ids'][0] # player 2 stuff if game['number_of_players'] == 2: data[whatevenisthis.format(i, 1)] = game['ids'][1] i += 1 i = 0 for player in players_info: # player stuff data[yetanotherkey.format(i)] = player['id'] data[waitwhat.format(i)] = player['nickname'] i += 1 msg = self.__message_parser.encode('report', data) self.__send(msg) def on_game_abort(self): # delete game self.__lobby_model.delete_game(self.__game) self.__game = None self.__send(self.__message_parser.encode('report', {'status': '19'})) def on_game_ended(self, winner, id0, id1, timestamp): msg = { 'status': '17', 'winner': winner - 1, 'name_of_game': self.__game, 'timestamp': timestamp, 'identifier_0': id0, 'identifier_1': id1, 'reason_for_game_end': 'Because of reasons.' } # delete game self.__lobby_model.delete_game(self.__game) self.__game = None self.__send(self.__message_parser.encode('report', msg)) def on_ship_edit(self): logging.debug('on_ship_edit()') self.__send(self.__message_parser.encode('report', {'status': '18'})) def on_game_start(self): logging.debug('on_game_start()') self.__send(self.__message_parser.encode('report', {'status': '48'})) def on_host_begins(self): logging.debug('on_host_begins()') self.__begin_turn() def on_guest_begins(self): logging.debug('on_guest_begins()') self.__begin_turn() def on_attack(self, x, y, condition): logging.debug('on_attack()') msg = None # if player is enemy if self.__lobby_model.get_game( self.__game).get_turn() == self.__player: # update own field msg = { 'status': 13, 'was_special_attack': 'false', 'coordinate_x': x, 'coordinate_y': y } self.__send(self.__message_parser.encode('report', msg)) # trigger next turn wtf self.__begin_turn() else: # update enemy field msg = { 'status': 14, 'number_of_updated_fields': '1', 'field_0_x': x, 'field_0_y': y, 'field_0_condition': condition } self.__send(self.__message_parser.encode('report', msg)) def on_special_attack(self, x, y, updates): logging.debug('on_special_attack()') msg = None if self.__lobby_model.get_game( self.__game).get_turn() == self.__player: # update own field msg = { 'status': 13, 'was_special_attack': 'true', 'coordinate_x': x, 'coordinate_y': y } self.__send(self.__message_parser.encode('report', msg)) # trigger next turn wtf self.__begin_turn() else: # update enemy field msg = {'status': 14, 'number_of_updated_fields': len(updates)} i = 0 for j in updates: msg['field_{}_x'.format(i)] = j['field'].x msg['field_{}_y'.format(i)] = j['field'].y msg['field_{}_condition'.format(i)] = j['status'] i += 1 self.__send(self.__message_parser.encode('report', msg)) def on_move(self, updates): logging.debug('on_move()') msg = None if self.__lobby_model.get_game( self.__game).get_turn() == self.__player: # update enemy field if len(updates) > 0: msg = {'status': 14, 'number_of_updated_fields': len(updates)} i = 0 for j in updates: msg['field_{}_x'.format(i)] = j['field'].x msg['field_{}_y'.format(i)] = j['field'].y msg['field_{}_condition'.format(i)] = j['status'] i += 1 self.__send(self.__message_parser.encode('report', msg)) # trigger next turn wtf self.__begin_turn() def on_chat(self, timestamp, player, msg): logging.debug('on_chat()') msg = { 'status': '15', 'author_id': player, 'timestamp': timestamp, 'message_content': msg } self.__send(self.__message_parser.encode('report', msg)) def get_socket(self): return self.__socket def finish(self): logging.info("Client disconnected.") # remove any left callbacks self.__lobby_model.remove_callback(LobbyEvent.on_update, self.on_update_lobby) self.__lobby_model.remove_callback(LobbyEvent.on_chat, self.on_chat) # end running game if any if self.__game and self.__lobby_model.get_game( self.__game) is not None: # remove callbacks of disconnected player self.__lobby_model.get_game(self.__game).remove_callback( GameEvent.on_ship_edit, self.on_ship_edit) self.__lobby_model.get_game(self.__game).remove_callback( GameEvent.on_game_start, self.on_game_start) self.__lobby_model.get_game(self.__game).remove_callback( GameEvent.on_attack, self.on_attack) self.__lobby_model.get_game(self.__game).remove_callback( GameEvent.on_special_attack, self.on_special_attack) self.__lobby_model.get_game(self.__game).remove_callback( GameEvent.on_move, self.on_move) #self.__lobby_model.get_game(self.__game).remove_callback(GameEvent.on_host_begins, self.on_host_begins) #self.__lobby_model.get_game(self.__game).remove_callback(GameEvent.on_guest_begins, self.on_guest_begins) self.__lobby_model.get_game(self.__game).remove_callback( GameEvent.on_game_ended, self.on_game_ended) self.__lobby_model.get_game(self.__game).remove_callback( GameEvent.on_game_abort, self.on_game_abort) # surrender if self.__lobby_model.get_game(self.__game).is_ongoing(): logging.debug("Surrender by disconnect.") self.__lobby_model.get_game(self.__game).surrender( self.__player) # abort elif self.__lobby_model.get_game(self.__game).is_ready(): logging.debug("Abort by disconnect.") self.__lobby_model.get_game(self.__game).abort() # remove player from lobby self.__lobby_model.delete_player(self.__id) def __create_game(self, params): # make sure parameter list is complete if not self.__expect_parameter(['name'], params): return # check if client is already in a game if self.__game: logging.debug("Client already in some game.") # 31 is the new 42 self.__send( self.__message_parser.encode('report', {'status': '31'})) return # check game name length if 1 > len(params['name']) or len(params['name']) > 64: logging.debug("Game name too long.") self.__send( self.__message_parser.encode('report', {'status': '37'})) return # create the game game = self.__lobby_model.add_lobby(params['name'], self.__id) if not game: self.__send( self.__message_parser.encode('report', {'status': '37'})) return self.__game = params['name'] self.__player = 1 self.__send(self.__message_parser.encode('report', {'status': '28'})) # register game callbacks self.__lobby_model.get_game(self.__game).register_callback( GameEvent.on_ship_edit, self.on_ship_edit) self.__lobby_model.get_game(self.__game).register_callback( GameEvent.on_game_start, self.on_game_start) self.__lobby_model.get_game(self.__game).register_callback( GameEvent.on_attack, self.on_attack) self.__lobby_model.get_game(self.__game).register_callback( GameEvent.on_special_attack, self.on_special_attack) self.__lobby_model.get_game(self.__game).register_callback( GameEvent.on_move, self.on_move) self.__lobby_model.get_game(self.__game).register_callback( GameEvent.on_host_begins, self.on_host_begins) self.__lobby_model.get_game(self.__game).register_callback( GameEvent.on_game_ended, self.on_game_ended) self.__lobby_model.get_game(self.__game).register_callback( GameEvent.on_game_abort, self.on_game_abort) def __join_game(self, params): # make sure parameter list is complete if not self.__expect_parameter(['name'], params): return # check if client is already in a game if self.__game: logging.debug("Client already in some game.") self.__send( self.__message_parser.encode('report', {'status': '31'})) return # join the game game, e = self.__lobby_model.join_lobby(params['name'], self.__id) # handle game join errors if e: if e == LobbyError.game_is_full: self.__send( self.__message_parser.encode('report', {'status': '47'})) return elif e == LobbyError.game_does_not_exist: self.__send( self.__message_parser.encode('report', {'status': '37'})) return # ack game join self.__send(self.__message_parser.encode('report', {'status': '27'})) self.__game = params['name'] self.__player = 2 # register game callbacks self.__lobby_model.get_game(self.__game).register_callback( GameEvent.on_ship_edit, self.on_ship_edit) self.__lobby_model.get_game(self.__game).register_callback( GameEvent.on_game_start, self.on_game_start) self.__lobby_model.get_game(self.__game).register_callback( GameEvent.on_attack, self.on_attack) self.__lobby_model.get_game(self.__game).register_callback( GameEvent.on_special_attack, self.on_special_attack) self.__lobby_model.get_game(self.__game).register_callback( GameEvent.on_move, self.on_move) self.__lobby_model.get_game(self.__game).register_callback( GameEvent.on_guest_begins, self.on_guest_begins) self.__lobby_model.get_game(self.__game).register_callback( GameEvent.on_game_ended, self.on_game_ended) self.__lobby_model.get_game(self.__game).register_callback( GameEvent.on_game_abort, self.on_game_abort) self.__lobby_model.get_game( self.__game).just_begin_ship_placement_already() def __set_nickname(self, params): if not self.__expect_parameter(['name'], params): return if len(params['name']) > 64: logging.debug("Nickname too long.") self.__send( self.__message_parser.encode('report', {'status': '36'})) return # tell lobby to set nickname and hope for the best self.__lobby_model.set_nickname(self.__id, params['name']) def __get_own_player_id(self): addr, port = self.__socket.getpeername() playerid = hashlib.sha1(b(addr + str(port))).hexdigest() return playerid def __init_board(self, params): logging.debug('__init_board()') # not in any game if self.__game is None: self.__send( self.__message_parser.encode('report', {'status': '43'})) return shipx = 'ship_{}_x' shipy = 'ship_{}_y' shipdir = 'ship_{}_direction' # make sure that all parameters exist if not self.__expect_parameter( [shipx.format(i) for i in range(0, 10)] + [shipy.format(i) for i in range(0, 10)] + [shipdir.format(i) for i in range(0, 10)], params): return # init board left = True for id in range(0, 10): x = int(params[shipx.format(id)]) y = int(params[shipy.format(id)]) dir = params[shipdir.format(id)] logging.debug('self.__lobby_model :: {}'.format( repr(self.__lobby_model))) logging.debug( 'self.__lobby_model.get_game(self.__game) :: {}'.format( repr(self.__lobby_model.get_game(self.__game)))) logging.debug('self.__game :: {}'.format(repr(self.__game))) suc, left = self.__lobby_model.get_game(self.__game).place_ship( self.__player, x, y, dir, id) # catch illegal placement if suc == -1: logging.debug("Nonsense ship placement.") self.__send( self.__message_parser.encode('report', {'status': '38'})) return if left: logging.debug("Something is still wrong with ship placement.") self.__send( self.__message_parser.encode('report', {'status': '38'})) return # ack init board self.__send(self.__message_parser.encode('report', {'status': '29'})) # trigger random begin return message self.__lobby_model.get_game(self.__game).start() def __leave_game(self): # not in any game if self.__game is None: self.__send( self.__message_parser.encode('report', {'status': '43'})) return # make sure the game has not started yet if self.__lobby_model.get_game(self.__game).is_ongoing(): self.__send( self.__message_parser.encode('report', {'status': '43'})) logging.debug("Too late to leave the game.") return # abort self.__lobby_model.get_game(self.__game).abort() def __fire(self, params): if not self.__expect_parameter(['coordinate_x', 'coordinate_y'], params): return # not in any game if self.__game is None: self.__send( self.__message_parser.encode('report', {'status': '43'})) return # check if it's actually your turn if self.__lobby_model.get_game( self.__game).get_turn() != self.__player: self.__send( self.__message_parser.encode('report', {'status': '41'})) return # check if coordinates are valid if not ((0 <= int(params['coordinate_x']) <= 15) and (0 <= int(params['coordinate_y']) <= 15)): self.__send( self.__message_parser.encode('report', {'status': '39'})) return # save move _, updated = self.__lobby_model.get_game(self.__game).fire( self.__player, params['coordinate_x'], params['coordinate_y']) logging.debug("Fire: updated is {}.".format(updated)) #if not updated: # self.__send(self.__message_parser.encode('report', {'status': '39'})) # return # successful attack self.__send(self.__message_parser.encode('report', {'status': '22'})) # check if game over self.__lobby_model.get_game(self.__game).check_if_game_over( self.__player) def __nuke(self, params): if not self.__expect_parameter(['coordinate_x', 'coordinate_y'], params): return # check if coordinates are valid if not ((0 <= int(params['coordinate_x']) <= 13) and (0 <= int(params['coordinate_y']) <= 13)): self.__send( self.__message_parser.encode('report', {'status': '32'})) return # not in any game if self.__game is None: self.__send( self.__message_parser.encode('report', {'status': '43'})) return # check if it's actually your turn if self.__lobby_model.get_game( self.__game).get_turn() != self.__player: self.__send( self.__message_parser.encode('report', {'status': '41'})) return # save move updated = self.__lobby_model.get_game(self.__game).nuke( self.__player, params['coordinate_x'], params['coordinate_y']) # special attack failed if updated is False: self.__send( self.__message_parser.encode('report', {'status': '32'})) return logging.debug("Nuke: updated {} fields.".format(len(updated))) #if len(updated) == 0: # self.__send(self.__message_parser.encode('report', {'status': '32'})) # return # successful special attack self.__send(self.__message_parser.encode('report', {'status': '24'})) # check if game over self.__lobby_model.get_game(self.__game).check_if_game_over( self.__player) def __move(self, params): if not self.__expect_parameter(['ship_id', 'direction'], params): return # not in any game if self.__game is None: self.__send( self.__message_parser.encode('report', {'status': '43'})) return # check if it's actually your turn if self.__lobby_model.get_game( self.__game).get_turn() != self.__player: self.__send( self.__message_parser.encode('report', {'status': '41'})) return # save move result = self.__lobby_model.get_game(self.__game).move_ship( self.__player, int(params['ship_id']), params['direction']) if result is False: self.__send( self.__message_parser.encode('report', {'status': '31'})) return # successful move self.__send(self.__message_parser.encode('report', {'status': '21'})) def __surrender(self): # not in any game if self.__game is None: self.__send( self.__message_parser.encode('report', {'status': '43'})) return # make sure the game is ongoing if not self.__lobby_model.get_game(self.__game).is_ongoing(): self.__send( self.__message_parser.encode('report', {'status': '43'})) return # surrender self.__lobby_model.get_game(self.__game).surrender(self.__player) # surrender accepted lol self.__send(self.__message_parser.encode('report', {'status': '23'})) def __begin_turn(self): self.__send(self.__message_parser.encode('report', {'status': '11'})) def __chat(self, params): if not self.__expect_parameter(['text'], params): return self.__lobby_model.chat(self.__id, params['text']) def __unknown_msg(self): self.__send(self.__message_parser.encode('report', {'status': '40'})) def __expect_parameter(self, expected, actual): keys = list(actual.keys()) for p in expected: if p not in keys: self.__unknown_msg() return False return True def __recv(self, count): try: msg = self.__socket.recv(count) except socket.error as e: logging.debug("Client already dead: ".format(repr(e))) return logging.debug(b"Raw in: " + msg) return msg def __send(self, msg): try: self.__socket.sendall(msg) except socket.error as e: logging.debug("Client already dead: ".format(repr(e))) return logging.debug(b"Raw out: " + msg)
class ClientHandler: def __init__(self, sock): self.__socket = sock self.__message_parser = MessageParser() self.__lobby_model = LobbyModel() # name of the game self.__game = None # player number (1 or 2) self.__player = None # player id lol self.__id = self.__get_own_player_id() # add client as player self.__lobby_model.add_player(self.__id) # register callbacks self.__lobby_model.register_callback(LobbyEvent.on_update, self.on_update_lobby) self.__lobby_model.register_callback(LobbyEvent.on_chat, self.on_chat) def handle(self): logging.info("Client {} connected.".format(self.__socket.getpeername())) while True: logging.debug("handle({}) loop.".format(self.__socket.getpeername())) # receive 2 bytes size header size = self.__recv(2) if not size: logging.debug("Did not receive 2 bytes header.") break size = struct.unpack('>H', size)[0] logging.debug("Size: " + str(size)) # receive message body msg = self.__recv(size) if not msg: logging.debug("Did not receive {} bytes body.".format(str(size))) break # explode received data into message type and parameters msgtype, msgparams = self.__message_parser.decode(msg.decode()) logging.debug("Msg type: " + msgtype) logging.debug("Msg parameters: " + repr(msgparams)) # dispatch message type if msgtype == messages.CREATE_GAME: self.__create_game(msgparams) elif msgtype == messages.JOIN_GAME: self.__join_game(msgparams) elif msgtype == messages.SET_NICK: self.__set_nickname(msgparams) elif msgtype == messages.LEAVE_GAME: self.__leave_game() elif msgtype == messages.INIT_BOARD: self.__init_board(msgparams) elif msgtype == messages.FIRE: self.__fire(msgparams) elif msgtype == messages.NUKE: self.__nuke(msgparams) elif msgtype == messages.MOVE: self.__move(msgparams) elif msgtype == messages.SURRENDER: self.__surrender() elif msgtype == messages.CHAT_SEND: self.__chat(msgparams) else: self.__unknown_msg() # # Callbacks # def on_update_lobby(self): logging.debug("on_update_lobby()") # Get required data for update lobby msg number_of_clients = self.__lobby_model.get_number_of_players() number_of_games = self.__lobby_model.get_number_of_games() games_info = self.__lobby_model.get_games_info() players_info = self.__lobby_model.get_players_info() # Update_Lobby data = { 'status': 16, 'number_of_clients': number_of_clients, 'number_of_games': number_of_games[0] } i = 0 weirdkey = 'game_name_{}' moreweirdkeys = 'game_players_count_{}' whatevenisthis = 'game_player_{}_{}' waitwhat = 'player_name_{}' yetanotherkey = 'player_identifier_{}' for game in games_info: # game stuff data[weirdkey.format(i)] = game['game_name'] data[moreweirdkeys.format(i)] = game['number_of_players'] # player 1 stuff data[whatevenisthis.format(i, 0)] = game['ids'][0] # player 2 stuff if game['number_of_players'] == 2: data[whatevenisthis.format(i, 1)] = game['ids'][1] i += 1 i = 0 for player in players_info: # player stuff data[yetanotherkey.format(i)] = player['id'] data[waitwhat.format(i)] = player['nickname'] i += 1 msg = self.__message_parser.encode('report', data) self.__send(msg) def on_game_abort(self): # delete game self.__lobby_model.delete_game(self.__game) self.__game = None self.__send(self.__message_parser.encode('report', {'status': '19'})) def on_game_ended(self, winner, id0, id1, timestamp): msg = { 'status': '17', 'winner': winner - 1, 'name_of_game': self.__game, 'timestamp': timestamp, 'identifier_0': id0, 'identifier_1': id1, 'reason_for_game_end': 'Because of reasons.' } # delete game self.__lobby_model.delete_game(self.__game) self.__game = None self.__send(self.__message_parser.encode('report', msg)) def on_ship_edit(self): logging.debug('on_ship_edit()') self.__send(self.__message_parser.encode('report', {'status': '18'})) def on_game_start(self): logging.debug('on_game_start()') self.__send(self.__message_parser.encode('report', {'status': '48'})) def on_host_begins(self): logging.debug('on_host_begins()') self.__begin_turn() def on_guest_begins(self): logging.debug('on_guest_begins()') self.__begin_turn() def on_attack(self, x, y, condition): logging.debug('on_attack()') msg = None # if player is enemy if self.__lobby_model.get_game(self.__game).get_turn() == self.__player: # update own field msg = { 'status': 13, 'was_special_attack': 'false', 'coordinate_x': x, 'coordinate_y': y } self.__send(self.__message_parser.encode('report', msg)) # trigger next turn wtf self.__begin_turn() else: # update enemy field msg = { 'status': 14, 'number_of_updated_fields': '1', 'field_0_x': x, 'field_0_y': y, 'field_0_condition': condition } self.__send(self.__message_parser.encode('report', msg)) def on_special_attack(self, x, y, updates): logging.debug('on_special_attack()') msg = None if self.__lobby_model.get_game(self.__game).get_turn() == self.__player: # update own field msg = { 'status': 13, 'was_special_attack': 'true', 'coordinate_x': x, 'coordinate_y': y } self.__send(self.__message_parser.encode('report', msg)) # trigger next turn wtf self.__begin_turn() else: # update enemy field msg = { 'status': 14, 'number_of_updated_fields': len(updates) } i = 0 for j in updates: msg['field_{}_x'.format(i)] = j['field'].x msg['field_{}_y'.format(i)] =j['field'].y msg['field_{}_condition'.format(i)] = j['status'] i += 1 self.__send(self.__message_parser.encode('report', msg)) def on_move(self, updates): logging.debug('on_move()') msg = None if self.__lobby_model.get_game(self.__game).get_turn() == self.__player: # update enemy field if len(updates) > 0: msg = { 'status': 14, 'number_of_updated_fields': len(updates) } i = 0 for j in updates: msg['field_{}_x'.format(i)] = j['field'].x msg['field_{}_y'.format(i)] =j['field'].y msg['field_{}_condition'.format(i)] = j['status'] i += 1 self.__send(self.__message_parser.encode('report', msg)) # trigger next turn wtf self.__begin_turn() def on_chat(self, timestamp, player, msg): logging.debug('on_chat()') msg = { 'status': '15', 'author_id': player, 'timestamp': timestamp, 'message_content': msg } self.__send(self.__message_parser.encode('report', msg)) def get_socket(self): return self.__socket def finish(self): logging.info("Client disconnected.") # remove any left callbacks self.__lobby_model.remove_callback(LobbyEvent.on_update, self.on_update_lobby) self.__lobby_model.remove_callback(LobbyEvent.on_chat, self.on_chat) # end running game if any if self.__game and self.__lobby_model.get_game(self.__game) is not None: # remove callbacks of disconnected player self.__lobby_model.get_game(self.__game).remove_callback(GameEvent.on_ship_edit, self.on_ship_edit) self.__lobby_model.get_game(self.__game).remove_callback(GameEvent.on_game_start, self.on_game_start) self.__lobby_model.get_game(self.__game).remove_callback(GameEvent.on_attack, self.on_attack) self.__lobby_model.get_game(self.__game).remove_callback(GameEvent.on_special_attack, self.on_special_attack) self.__lobby_model.get_game(self.__game).remove_callback(GameEvent.on_move, self.on_move) #self.__lobby_model.get_game(self.__game).remove_callback(GameEvent.on_host_begins, self.on_host_begins) #self.__lobby_model.get_game(self.__game).remove_callback(GameEvent.on_guest_begins, self.on_guest_begins) self.__lobby_model.get_game(self.__game).remove_callback(GameEvent.on_game_ended, self.on_game_ended) self.__lobby_model.get_game(self.__game).remove_callback(GameEvent.on_game_abort, self.on_game_abort) # surrender if self.__lobby_model.get_game(self.__game).is_ongoing(): logging.debug("Surrender by disconnect.") self.__lobby_model.get_game(self.__game).surrender(self.__player) # abort elif self.__lobby_model.get_game(self.__game).is_ready(): logging.debug("Abort by disconnect.") self.__lobby_model.get_game(self.__game).abort() # remove player from lobby self.__lobby_model.delete_player(self.__id) def __create_game(self, params): # make sure parameter list is complete if not self.__expect_parameter(['name'], params): return # check if client is already in a game if self.__game: logging.debug("Client already in some game.") # 31 is the new 42 self.__send(self.__message_parser.encode('report', {'status': '31'})) return # check game name length if 1 > len(params['name']) or len(params['name']) > 64: logging.debug("Game name too long.") self.__send(self.__message_parser.encode('report', {'status': '37'})) return # create the game game = self.__lobby_model.add_lobby(params['name'], self.__id) if not game: self.__send(self.__message_parser.encode('report', {'status': '37'})) return self.__game = params['name'] self.__player = 1 self.__send(self.__message_parser.encode('report', {'status': '28'})) # register game callbacks self.__lobby_model.get_game(self.__game).register_callback(GameEvent.on_ship_edit, self.on_ship_edit) self.__lobby_model.get_game(self.__game).register_callback(GameEvent.on_game_start, self.on_game_start) self.__lobby_model.get_game(self.__game).register_callback(GameEvent.on_attack, self.on_attack) self.__lobby_model.get_game(self.__game).register_callback(GameEvent.on_special_attack, self.on_special_attack) self.__lobby_model.get_game(self.__game).register_callback(GameEvent.on_move, self.on_move) self.__lobby_model.get_game(self.__game).register_callback(GameEvent.on_host_begins, self.on_host_begins) self.__lobby_model.get_game(self.__game).register_callback(GameEvent.on_game_ended, self.on_game_ended) self.__lobby_model.get_game(self.__game).register_callback(GameEvent.on_game_abort, self.on_game_abort) def __join_game(self, params): # make sure parameter list is complete if not self.__expect_parameter(['name'], params): return # check if client is already in a game if self.__game: logging.debug("Client already in some game.") self.__send(self.__message_parser.encode('report', {'status': '31'})) return # join the game game, e = self.__lobby_model.join_lobby(params['name'], self.__id) # handle game join errors if e: if e == LobbyError.game_is_full: self.__send(self.__message_parser.encode('report', {'status': '47'})) return elif e == LobbyError.game_does_not_exist: self.__send(self.__message_parser.encode('report', {'status': '37'})) return # ack game join self.__send(self.__message_parser.encode('report', {'status': '27'})) self.__game = params['name'] self.__player = 2 # register game callbacks self.__lobby_model.get_game(self.__game).register_callback(GameEvent.on_ship_edit, self.on_ship_edit) self.__lobby_model.get_game(self.__game).register_callback(GameEvent.on_game_start, self.on_game_start) self.__lobby_model.get_game(self.__game).register_callback(GameEvent.on_attack, self.on_attack) self.__lobby_model.get_game(self.__game).register_callback(GameEvent.on_special_attack, self.on_special_attack) self.__lobby_model.get_game(self.__game).register_callback(GameEvent.on_move, self.on_move) self.__lobby_model.get_game(self.__game).register_callback(GameEvent.on_guest_begins, self.on_guest_begins) self.__lobby_model.get_game(self.__game).register_callback(GameEvent.on_game_ended, self.on_game_ended) self.__lobby_model.get_game(self.__game).register_callback(GameEvent.on_game_abort, self.on_game_abort) self.__lobby_model.get_game(self.__game).just_begin_ship_placement_already() def __set_nickname(self, params): if not self.__expect_parameter(['name'], params): return if len(params['name']) > 64: logging.debug("Nickname too long.") self.__send(self.__message_parser.encode('report', {'status': '36'})) return # tell lobby to set nickname and hope for the best self.__lobby_model.set_nickname(self.__id, params['name']) def __get_own_player_id(self): addr, port = self.__socket.getpeername() playerid = hashlib.sha1(b(addr + str(port))).hexdigest() return playerid def __init_board(self, params): logging.debug('__init_board()') # not in any game if self.__game is None: self.__send(self.__message_parser.encode('report', {'status': '43'})) return shipx = 'ship_{}_x' shipy = 'ship_{}_y' shipdir = 'ship_{}_direction' # make sure that all parameters exist if not self.__expect_parameter( [shipx.format(i) for i in range(0, 10)] + [shipy.format(i) for i in range(0, 10)] + [shipdir.format(i) for i in range(0, 10)], params): return # init board left = True for id in range(0, 10): x = int(params[shipx.format(id)]) y = int(params[shipy.format(id)]) dir = params[shipdir.format(id)] logging.debug('self.__lobby_model :: {}'.format(repr(self.__lobby_model))) logging.debug('self.__lobby_model.get_game(self.__game) :: {}'.format(repr(self.__lobby_model.get_game(self.__game)))) logging.debug('self.__game :: {}'.format(repr(self.__game))) suc, left = self.__lobby_model.get_game(self.__game).place_ship(self.__player, x, y, dir, id) # catch illegal placement if suc == -1: logging.debug("Nonsense ship placement.") self.__send(self.__message_parser.encode('report', {'status': '38'})) return if left: logging.debug("Something is still wrong with ship placement.") self.__send(self.__message_parser.encode('report', {'status': '38'})) return # ack init board self.__send(self.__message_parser.encode('report', {'status': '29'})) # trigger random begin return message self.__lobby_model.get_game(self.__game).start() def __leave_game(self): # not in any game if self.__game is None: self.__send(self.__message_parser.encode('report', {'status': '43'})) return # make sure the game has not started yet if self.__lobby_model.get_game(self.__game).is_ongoing(): self.__send(self.__message_parser.encode('report', {'status': '43'})) logging.debug("Too late to leave the game.") return # abort self.__lobby_model.get_game(self.__game).abort() def __fire(self, params): if not self.__expect_parameter(['coordinate_x', 'coordinate_y'], params): return # not in any game if self.__game is None: self.__send(self.__message_parser.encode('report', {'status': '43'})) return # check if it's actually your turn if self.__lobby_model.get_game(self.__game).get_turn() != self.__player: self.__send(self.__message_parser.encode('report', {'status': '41'})) return # check if coordinates are valid if not ((0 <= int(params['coordinate_x']) <= 15) and (0 <= int(params['coordinate_y']) <= 15)): self.__send(self.__message_parser.encode('report', {'status': '39'})) return # save move _, updated = self.__lobby_model.get_game(self.__game).fire(self.__player, params['coordinate_x'], params['coordinate_y']) logging.debug("Fire: updated is {}.".format(updated)) #if not updated: # self.__send(self.__message_parser.encode('report', {'status': '39'})) # return # successful attack self.__send(self.__message_parser.encode('report', {'status': '22'})) # check if game over self.__lobby_model.get_game(self.__game).check_if_game_over(self.__player) def __nuke(self, params): if not self.__expect_parameter(['coordinate_x', 'coordinate_y'], params): return # check if coordinates are valid if not ((0 <= int(params['coordinate_x']) <= 13) and (0 <= int(params['coordinate_y']) <= 13)): self.__send(self.__message_parser.encode('report', {'status': '32'})) return # not in any game if self.__game is None: self.__send(self.__message_parser.encode('report', {'status': '43'})) return # check if it's actually your turn if self.__lobby_model.get_game(self.__game).get_turn() != self.__player: self.__send(self.__message_parser.encode('report', {'status': '41'})) return # save move updated = self.__lobby_model.get_game(self.__game).nuke(self.__player, params['coordinate_x'], params['coordinate_y']) # special attack failed if updated is False: self.__send(self.__message_parser.encode('report', {'status': '32'})) return logging.debug("Nuke: updated {} fields.".format(len(updated))) #if len(updated) == 0: # self.__send(self.__message_parser.encode('report', {'status': '32'})) # return # successful special attack self.__send(self.__message_parser.encode('report', {'status': '24'})) # check if game over self.__lobby_model.get_game(self.__game).check_if_game_over(self.__player) def __move(self, params): if not self.__expect_parameter(['ship_id', 'direction'], params): return # not in any game if self.__game is None: self.__send(self.__message_parser.encode('report', {'status': '43'})) return # check if it's actually your turn if self.__lobby_model.get_game(self.__game).get_turn() != self.__player: self.__send(self.__message_parser.encode('report', {'status': '41'})) return # save move result = self.__lobby_model.get_game(self.__game).move_ship(self.__player, int(params['ship_id']), params['direction']) if result is False: self.__send(self.__message_parser.encode('report', {'status': '31'})) return # successful move self.__send(self.__message_parser.encode('report', {'status': '21'})) def __surrender(self): # not in any game if self.__game is None: self.__send(self.__message_parser.encode('report', {'status': '43'})) return # make sure the game is ongoing if not self.__lobby_model.get_game(self.__game).is_ongoing(): self.__send(self.__message_parser.encode('report', {'status': '43'})) return # surrender self.__lobby_model.get_game(self.__game).surrender(self.__player) # surrender accepted lol self.__send(self.__message_parser.encode('report', {'status': '23'})) def __begin_turn(self): self.__send(self.__message_parser.encode('report', {'status': '11'})) def __chat(self, params): if not self.__expect_parameter(['text'], params): return self.__lobby_model.chat(self.__id, params['text']) def __unknown_msg(self): self.__send(self.__message_parser.encode('report', {'status': '40'})) def __expect_parameter(self, expected, actual): keys = list(actual.keys()) for p in expected: if p not in keys: self.__unknown_msg() return False return True def __recv(self, count): try: msg = self.__socket.recv(count) except socket.error as e: logging.debug("Client already dead: ".format(repr(e))) return logging.debug(b"Raw in: " + msg) return msg def __send(self, msg): try: self.__socket.sendall(msg) except socket.error as e: logging.debug("Client already dead: ".format(repr(e))) return logging.debug(b"Raw out: " + msg)