name = u"client-%u" % (os.getpid()) onname() client = Client(name, version, [host, port], None) client.register_callback("lobbygame_chat", cb_onchat) client.register_callback("lobbygame_join", cb_onjoin) client.register_callback("lobbygame_leave", cb_onleave) client.register_callback("lobbygame_changename", cb_onchangename) client.register_callback("lobbygame_starts", cb_ongameprepare) client.register_callback("game_starts", cb_ongamestarts) client.register_callback("game_data", cb_ongamedata) print prompt, while True: try: if client.isconnected(): client.ping() text = nbrawinput() if text is None: continue pieces = filter(lambda x: len(x.strip()) > 0, text.strip().split(' ')) if len(pieces) <= 0: print prompt, continue cmd = pieces.pop(0) if cmd not in commands: print "[ERROR] Unknown command" else: commands[cmd](*pieces)
class NetworkInterface(object): """Interface for low level networking""" __metaclass__ = ManualConstructionSingleton log = logging.getLogger("network") PING_INTERVAL = 0.5 # ping interval in seconds def __init__(self): self.__setup_client() # cbs means callbacks self.cbs_game_details_changed = [] self.cbs_game_prepare = [] self.cbs_game_starts = [] self.cbs_error = [] # callbacks on error that looks like this: error(exception, fatal=True) self._client.register_callback("lobbygame_join", self._cb_game_details_changed) self._client.register_callback("lobbygame_leave", self._cb_game_details_changed) self._client.register_callback("lobbygame_changename", self._cb_game_details_changed) self._client.register_callback("lobbygame_toggleready", self._cb_game_details_changed) self._client.register_callback("lobbygame_kickplayer", self._cb_game_details_changed) self._client.register_callback("lobbygame_changecolor", self._cb_game_details_changed) self._client.register_callback("lobbygame_starts", self._cb_game_prepare) self._client.register_callback("game_starts", self._cb_game_starts) self._client.register_callback("game_data", self._cb_game_data) self.received_packets = [] ExtScheduler().add_new_object(self.ping, self, self.PING_INTERVAL, -1) def get_game(self): game = self._client.game if game is None: return None return self.game2mpgame(game) def isconnected(self): return self._client.isconnected() def isjoined(self): return self._client.game is not None def network_data_changed(self, connect=False): """Call in case constants like client address or client port changed. @param connect: whether to connect after the data updated @throws RuntimeError in case of invalid data or an NetworkException forwarded from connect""" if self.isconnected(): self.disconnect() self.__setup_client() if connect: self.connect() def __setup_client(self): name = self.__get_player_name() color = self.__get_player_color() serveraddress = [NETWORK.SERVER_ADDRESS, NETWORK.SERVER_PORT] clientaddress = None client_port = parse_port(horizons.main.fife.get_uh_setting("NetworkPort"), allow_zero=True) if NETWORK.CLIENT_ADDRESS is not None or client_port > 0: clientaddress = [NETWORK.CLIENT_ADDRESS, client_port] try: self._client = Client( name, VERSION.RELEASE_VERSION, serveraddress, clientaddress, color, self.__get_client_id() ) except NetworkException as e: raise RuntimeError(e) def __get_player_name(self): return horizons.main.fife.get_uh_setting("Nickname") def __get_player_color(self): return horizons.main.fife.get_uh_setting("ColorID") def __get_client_id(self): return horizons.main.fife.get_uh_setting("ClientID") def get_client_id(self): return self._client.clientid def get_client_name(self): return self._client.name def get_client_color(self): return self._client.color def connect(self): """ @throws: NetworkError """ try: self._client.connect() except NetworkException as e: self.disconnect() raise e def disconnect(self): self._client.disconnect() def ping(self): """calls _client.ping until all packets are received""" if self._client.isconnected(): try: while self._client.ping(): # ping receives packets pass except NetworkException as e: self._handle_exception(e) def creategame(self, mapname, maxplayers, name, load=None, password=None): self.log.debug("[CREATEGAME] %s, %s, %s, %s", mapname, maxplayers, name, load) try: game = self._client.creategame(mapname, maxplayers, name, load, password) except NetworkException as e: fatal = self._handle_exception(e) return None return self.game2mpgame(game) def joingame(self, uuid): """Join a game with a certain uuid""" i = 2 try: while i < 10: # try 10 different names and colors try: self._client.joingame(uuid) return True except CommandError as e: self.log.debug("NetworkInterface: failed to join") if "name" in e.message: self.change_name(self.__get_player_name() + unicode(i), save=False) elif "color" in e.message: self.change_color(self.__get_player_color() + i, save=False) i += 1 self._client.joingame(uuid) except NetworkException as e: self._handle_exception(e) return False def leavegame(self): try: self._client.leavegame() except NetworkException as e: fatal = self._handle_exception(e) if fatal: return False return True def chat(self, message): try: self._client.chat(message) except NetworkException as e: self._handle_exception(e) return False return True def change_name(self, new_nick, save=True): """ see network/client.py -> changename() for _important_ return values""" if save: horizons.main.fife.set_uh_setting("Nickname", new_nick) horizons.main.fife.save_settings() try: return self._client.changename(new_nick) except NetworkException as e: self._handle_exception(e) return False def change_color(self, new_color, save=True): """ see network/client.py -> changecolor() for _important_ return values""" if new_color > len(set(Color)): new_color %= len(set(Color)) if save: horizons.main.fife.set_uh_setting("ColorID", new_color) horizons.main.fife.save_settings() try: return self._client.changecolor(new_color) except NetworkException as e: self._handle_exception(e) return False def register_chat_callback(self, function): self._client.register_callback("lobbygame_chat", function) def register_player_joined_callback(self, function): self._client.register_callback("lobbygame_join", function) def register_player_left_callback(self, function): self._client.register_callback("lobbygame_leave", function) def register_player_toggle_ready_callback(self, function): self._client.register_callback("lobbygame_toggleready", function) def register_player_kick_player_callback(self, function): self._client.register_callback("lobbygame_kickplayer", function) def register_player_changed_name_callback(self, function): self._client.register_callback("lobbygame_changename", function) def register_player_changed_color_callback(self, function): self._client.register_callback("lobbygame_changecolor", function) def register_player_fetch_game_callback(self, function): self._client.register_callback("savegame_data", function) def register_game_details_changed_callback(self, function, unique=True): if unique and function in self.cbs_game_details_changed: return self.cbs_game_details_changed.append(function) def _cb_game_details_changed(self, game, player, *args, **kwargs): for callback in self.cbs_game_details_changed: callback() def register_game_prepare_callback(self, function, unique=True): if unique and function in self.cbs_game_prepare: return self.cbs_game_prepare.append(function) def _cb_game_prepare(self, game): for callback in self.cbs_game_prepare: callback(self.get_game()) def register_game_starts_callback(self, function, unique=True): if unique and function in self.cbs_game_starts: return self.cbs_game_starts.append(function) def _cb_game_starts(self, game): for callback in self.cbs_game_starts: callback(self.get_game()) def _cb_game_data(self, data): self.received_packets.append(data) def register_error_callback(self, function, unique=True): if unique and function in self.cbs_error: return self.cbs_error.append(function) def _cb_error(self, exception=u"", fatal=True): for callback in self.cbs_error: callback(exception, fatal) def get_active_games(self, only_this_version_allowed=False): """Returns a list of active games or None on fatal error""" ret_mp_games = [] try: games = self._client.listgames(onlyThisVersion=only_this_version_allowed) except NetworkException as e: fatal = self._handle_exception(e) return [] if not fatal else None for game in games: ret_mp_games.append(self.game2mpgame(game)) self.log.debug("NetworkInterface: found active game %s", game.mapname) return ret_mp_games def send_to_all_clients(self, packet): """ Sends packet to all players, that are part of the game """ if self._client.isconnected(): try: self._client.send(packet) except NetworkException as e: self._handle_exception(e) def receive_all(self): """ Returns list of all packets, that have arrived until now (since the last call) @return: list of packets """ try: while self._client.ping(): # ping receives packets pass except NetworkException as e: self.log.debug("ping in receive_all failed: " + str(e)) self._handle_exception(e) raise CommandError(e) ret_list = self.received_packets self.received_packets = [] return ret_list def game2mpgame(self, game): return MPGame( game.uuid, game.creator, game.mapname, game.maxplayers, game.playercnt, game.players, self._client.name, game.clientversion, game.name, game.load, game.password, game.ready_players, ) def get_clientversion(self): return self._client.version def _handle_exception(self, e): try: raise e except FatalError as e: self._cb_error(e, fatal=True) self.disconnect() return True except NetworkException as e: self._cb_error(e, fatal=False) return False def send_toggle_ready(self, player): self._client.send_toggle_ready(player) def send_kick_player(self, player): self._client.send_kick_player(player) def send_fetch_game(self, clientversion, uuid): self._client.send_fetch_game(clientversion, uuid)
name = u"client-{}".format(os.getpid()) onname() client = Client(name, version, [host, port], None) client.register_callback("lobbygame_chat", cb_onchat) client.register_callback("lobbygame_join", cb_onjoin) client.register_callback("lobbygame_leave", cb_onleave) client.register_callback("lobbygame_changename", cb_onchangename) client.register_callback("lobbygame_starts", cb_ongameprepare) client.register_callback("game_starts", cb_ongamestarts) client.register_callback("game_data", cb_ongamedata) print(prompt, end=' ') while True: try: if client.isconnected(): client.ping() text = nbrawinput() if text is None: continue pieces = filter(lambda x: len(x.strip()) > 0, text.strip().split(' ')) if len(pieces) <= 0: print(prompt, end=' ') continue cmd = pieces.pop(0) if cmd not in commands: print("[ERROR] Unknown command") else: commands[cmd](*pieces)
class NetworkInterface(object): """Interface for low level networking""" __metaclass__ = ManualConstructionSingleton log = logging.getLogger("network") PING_INTERVAL = 0.5 # ping interval in seconds def __init__(self): self.__setup_client() # cbs means callbacks self.cbs_game_details_changed = [] self.cbs_game_prepare = [] self.cbs_game_starts = [] self.cbs_error = [ ] # callbacks on error that looks like this: error(exception, fatal=True) # create a game_details_changed meta callback metacb = self._cb_game_details_changed self.register_player_joined_callback(metacb) self.register_player_left_callback(metacb) self.register_player_changed_name_callback(metacb) self.register_player_changed_color_callback(metacb) self.register_player_toggle_ready_callback(metacb) self._client.register_callback("lobbygame_starts", self._cb_game_prepare) self._client.register_callback("game_starts", self._cb_game_starts) self._client.register_callback("game_data", self._cb_game_data) self.received_packets = [] ExtScheduler().add_new_object(self.ping, self, self.PING_INTERVAL, -1) def get_game(self): game = self._client.game if game is None: return None return self.game2mpgame(game) def isconnected(self): return self._client.isconnected() def isjoined(self): return self._client.game is not None def network_data_changed(self, connect=False): """Call in case constants like client address or client port changed. @param connect: whether to connect after the data updated @throws RuntimeError in case of invalid data or an NetworkException forwarded from connect""" if self.isconnected(): self.disconnect() self.__setup_client() if connect: self.connect() def __setup_client(self): name = self.__get_player_name() color = self.__get_player_color() serveraddress = [NETWORK.SERVER_ADDRESS, NETWORK.SERVER_PORT] clientaddress = None client_port = parse_port( horizons.globals.fife.get_uh_setting("NetworkPort")) if NETWORK.CLIENT_ADDRESS is not None or client_port > 0: clientaddress = [NETWORK.CLIENT_ADDRESS, client_port] try: self._client = Client(name, VERSION.RELEASE_VERSION, serveraddress, clientaddress, color, self.__get_client_id()) except NetworkException as e: raise RuntimeError(e) def __get_player_name(self): return horizons.globals.fife.get_uh_setting("Nickname") def __get_player_color(self): return horizons.globals.fife.get_uh_setting("ColorID") def __get_client_id(self): try: return uuid.UUID( horizons.globals.fife.get_uh_setting("ClientID")).hex except (ValueError, TypeError): # We need a new client id client_id = uuid.uuid4() horizons.globals.fife.set_uh_setting("ClientID", client_id) horizons.globals.fife.save_settings() return client_id.hex def get_client_id(self): return self._client.clientid def get_client_name(self): return self._client.name def get_client_color(self): return self._client.color def connect(self): """ @throws: NetworkError """ try: self._client.connect() self.set_client_language() except NetworkException as e: self.disconnect() raise e def disconnect(self): self._client.disconnect() def ping(self): """calls _client.ping until all packets are received""" if self._client.isconnected(): try: while self._client.ping(): # ping receives packets pass except NetworkException as e: self._handle_exception(e) def set_props(self, props): try: self._client.setprops(props) except NetworkException as e: self._handle_exception(e) return False return True def set_client_language(self): lang = LANGUAGENAMES.get_by_value( horizons.globals.fife.get_uh_setting("Language")) if len(lang): return self.set_props({'lang': lang}) return True def creategame(self, mapname, maxplayers, name, maphash="", password=""): self.log.debug("[CREATEGAME] %s(h=%s), %s, %s, %s", mapname, maphash, maxplayers, name) try: game = self._client.creategame(mapname, maxplayers, name, maphash, password) except NetworkException as e: fatal = self._handle_exception(e) return None return self.game2mpgame(game) def joingame(self, uuid, password="", fetch=False): """Join a game with a certain uuid""" i = 2 try: while i < 10: # FIXME: try 10 different names and colors try: self._client.joingame(uuid, password, fetch) return True except CommandError as e: self.log.debug("NetworkInterface: failed to join") if 'name' in e.message: self.change_name(self.__get_player_name() + unicode(i), save=False) elif 'color' in e.message: self.change_color(self.__get_player_color() + i, save=False) else: raise i += 1 self._client.joingame(uuid, password, fetch) except NetworkException as e: self._handle_exception(e) return False def leavegame(self): try: self._client.leavegame() except NetworkException as e: fatal = self._handle_exception(e) if fatal: return False return True def chat(self, message): try: self._client.chat(message) except NetworkException as e: self._handle_exception(e) return False return True def change_name(self, new_nick, save=True): """ see network/client.py -> changename() for _important_ return values""" if save: horizons.globals.fife.set_uh_setting("Nickname", new_nick) horizons.globals.fife.save_settings() try: return self._client.changename(new_nick) except NetworkException as e: self._handle_exception(e) return False def change_color(self, new_color, save=True): """ see network/client.py -> changecolor() for _important_ return values""" if new_color > len(set(Color)): new_color %= len(set(Color)) if save: horizons.globals.fife.set_uh_setting("ColorID", new_color) horizons.globals.fife.save_settings() try: return self._client.changecolor(new_color) except NetworkException as e: self._handle_exception(e) return False def register_chat_callback(self, function): self._client.register_callback("lobbygame_chat", function) def register_player_joined_callback(self, function): self._client.register_callback("lobbygame_join", function) def register_player_left_callback(self, function): self._client.register_callback("lobbygame_leave", function) def register_game_terminated_callback(self, function): self._client.register_callback("lobbygame_terminate", function) def register_player_toggle_ready_callback(self, function): self._client.register_callback("lobbygame_toggleready", function) def register_kick_callback(self, function): self._client.register_callback("lobbygame_kick", function) def register_player_changed_name_callback(self, function): self._client.register_callback("lobbygame_changename", function) def register_player_changed_color_callback(self, function): self._client.register_callback("lobbygame_changecolor", function) def register_player_fetch_game_callback(self, function): self._client.register_callback("savegame_data", function) def register_game_details_changed_callback(self, function, unique=True): if unique and function in self.cbs_game_details_changed: return self.cbs_game_details_changed.append(function) def _cb_game_details_changed(self, game, player, *args, **kwargs): for callback in self.cbs_game_details_changed: callback() def register_game_prepare_callback(self, function, unique=True): if unique and function in self.cbs_game_prepare: return self.cbs_game_prepare.append(function) def _cb_game_prepare(self, game): for callback in self.cbs_game_prepare: callback(self.get_game()) def register_game_starts_callback(self, function, unique=True): if unique and function in self.cbs_game_starts: return self.cbs_game_starts.append(function) def _cb_game_starts(self, game): for callback in self.cbs_game_starts: callback(self.get_game()) def _cb_game_data(self, data): self.received_packets.append(data) def register_error_callback(self, function, unique=True): if unique and function in self.cbs_error: return self.cbs_error.append(function) def _cb_error(self, exception=u"", fatal=True): for callback in self.cbs_error: callback(exception, fatal) def get_active_games(self, only_this_version_allowed=False): """Returns a list of active games or None on fatal error""" ret_mp_games = [] try: games = self._client.listgames( only_this_version=only_this_version_allowed) except NetworkException as e: fatal = self._handle_exception(e) return [] if not fatal else None for game in games: ret_mp_games.append(self.game2mpgame(game)) self.log.debug("NetworkInterface: found active game %s", game.mapname) return ret_mp_games def send_to_all_clients(self, packet): """ Sends packet to all players, that are part of the game """ if self._client.isconnected(): try: self._client.send(packet) except NetworkException as e: self._handle_exception(e) def receive_all(self): """ Returns list of all packets, that have arrived until now (since the last call) @return: list of packets """ try: while self._client.ping(): # ping receives packets pass except NetworkException as e: self.log.debug("ping in receive_all failed: " + str(e)) self._handle_exception(e) raise CommandError(e) ret_list = self.received_packets self.received_packets = [] return ret_list def game2mpgame(self, game): return MPGame(game, self) def get_clientversion(self): return self._client.version def _handle_exception(self, e): try: raise e except FatalError as e: self._cb_error(e, fatal=True) self.disconnect() return True except NetworkException as e: self._cb_error(e, fatal=False) return False def toggle_ready(self): self._client.toggleready() def kick(self, player_sid): self._client.kick(player_sid) #TODO def send_fetch_game(self, clientversion, uuid): self._client.send_fetch_game(clientversion, uuid)