class SingleplayerMenu(Window): def __init__(self, windows): super(SingleplayerMenu, self).__init__(windows) self._mode = None self._gui = load_uh_widget('singleplayermenu.xml') self._gui.mapEvents({ 'cancel' : self._windows.close, 'okay' : self.act, 'scenario' : Callback(self._select_mode, 'scenario'), 'random' : Callback(self._select_mode, 'random'), 'free_maps': Callback(self._select_mode, 'free_maps') }) self._playerdata = PlayerDataSelection() self._aidata = AIDataSelection() self._gui.findChild(name="playerdataselectioncontainer").addChild(self._playerdata.get_widget()) self._gui.findChild(name="aidataselectioncontainer").addChild(self._aidata.get_widget()) def hide(self): # Save the player-data on hide so that other menus gets updated data self._playerdata.save_settings() self._gui.hide() def show(self): self._playerdata.update_data() self._gui.findChild(name='scenario').marked = True self._select_mode('scenario') def on_return(self): self.act() def _select_mode(self, mode): self._gui.hide() modes = { 'random': RandomMapWidget, 'free_maps': FreeMapsWidget, 'scenario': ScenarioMapWidget, } # remove old widget if self._mode: self._mode.end() self._gui.findChild(name="right_side_box").removeChild(self._mode.get_widget()) self._mode = modes[mode](self._windows, self, self._aidata) self._mode.show() self._gui.findChild(name="right_side_box").addChild(self._mode.get_widget()) self._gui.show() def act(self): """Start the game. Called when OK button is pressed.""" player_color = self._playerdata.get_player_color() player_name = self._playerdata.get_player_name() if not player_name: self._windows.open_popup(_("Invalid player name"), _("You entered an invalid playername.")) return horizons.globals.fife.set_uh_setting("Nickname", player_name) self._windows.close() self._mode.act(player_name, player_color)
class MultiplayerMenu(Window): def __init__(self, mainmenu, windows): super(MultiplayerMenu, self).__init__(windows) self._mainmenu = mainmenu self._gui = load_uh_widget('multiplayermenu.xml') self._gui.mapEvents({ 'cancel' : self._windows.close, 'join' : self._join_game, 'create' : self._create_game, 'refresh': Callback(self._refresh, play_sound=True) }) self._gui.findChild(name='gamelist').capture(self._update_game_details) self._playerdata = PlayerDataSelection() self._gui.findChild(name="playerdataselectioncontainer").addChild(self._playerdata.get_widget()) # to track if the menu window is opened or not. self._is_open = False def hide(self): # Save the player-data on hide so that other menus gets updated data self._playerdata.save_settings() self._gui.hide() ExtScheduler().rem_all_classinst_calls(self) def show(self): if not self._check_connection(): return if not self._refresh(): self._windows.close() return if not self._is_open: self._is_open = True # subscribe "error" when this menu window is firstly opened # only unsubscribe if this menu window is closed NetworkInterface().subscribe("error", self._on_error) # get updated player data self._playerdata.update_data() self._gui.show() # TODO: Remove once loading a game is implemented again self._gui.findChild(name='load').parent.hide() ExtScheduler().add_new_object(self._refresh, self, run_in=5, loops=-1) def close(self): # if the window is not open (due to connection errors), just do nothing if not self._is_open: return self.hide() NetworkInterface().unsubscribe("error", self._on_error) self._is_open = False # the window is also closed when a game starts, don't disconnect in that case if NetworkInterface().is_connected and not NetworkInterface().is_joined: NetworkInterface().disconnect() def on_return(self): self._join_game() def _check_connection(self): """ Check if all dependencies for multiplayer games are met and we can connect to the master server. If any dependency is not met, the window is closed. """ # It is important to close this window before showing the error popup. # Otherwise closing the popup will trigger `show` again, a new attempt # to connect is made, which ends up in an endless loop. if enet is None: self._windows.close() headline = _("Unable to find pyenet") descr = _('The multiplayer feature requires the library "pyenet", ' "which could not be found on your system.") advice = _("Linux users: Try to install pyenet through your package manager.") self._windows.open_error_popup(headline, descr, advice) return False if NetworkInterface() is None: try: NetworkInterface.create_instance() except RuntimeError as e: self._windows.close() headline = _("Failed to initialize networking.") descr = _("Network features could not be initialized with the current configuration.") advice = _("Check the settings you specified in the network section.") self._windows.open_error_popup(headline, descr, advice, unicode(e)) return False if not NetworkInterface().is_connected: try: NetworkInterface().connect() except Exception as err: self._windows.close() headline = _("Fatal Network Error") descr = _("Could not connect to master server.") advice = _("Please check your Internet connection. If it is fine, " "it means our master server is temporarily down.") self._windows.open_error_popup(headline, descr, advice, unicode(err)) return False if NetworkInterface().is_joined: if not NetworkInterface().leavegame(): self._windows.close() return False return True def _on_error(self, exception, fatal=True): """Error callback""" if not fatal: self._windows.open_popup(_("Error"), unicode(exception)) else: self._windows.open_popup(_("Fatal Network Error"), _("Something went wrong with the network:") + u'\n' + unicode(exception) ) # FIXME: this shouldn't be necessary, the main menu window is still somewhere # in the stack and we just need to get rid of all MP related windows self._mainmenu.show_main() def _display_game_name(self, game): same_version = game.version == NetworkInterface().get_clientversion() template = u"{password}{gamename}: {name} ({players}, {limit}){version}" return template.format( password="******" if game.has_password else "", name=game.map_name, gamename=game.name, players=game.player_count, limit=game.player_limit, version=u" " + _("Version differs!") if not same_version else u"") def _refresh(self, play_sound=False): """Refresh list of games. @param play_sound: whether to play the refresh sound @return bool, whether refresh worked """ if play_sound: AmbientSoundComponent.play_special('refresh') self._games = NetworkInterface().get_active_games() if self._games is None: return False gamelist = [self._display_game_name(g) for g in self._games] self._gui.distributeInitialData({'gamelist': gamelist}) self._gui.distributeData({'gamelist': 0}) self._update_game_details() return True def _update_game_details(self): """Set map name and other misc data in a widget.""" try: index = self._gui.collectData('gamelist') game = self._games[index] except IndexError: return self._gui.findChild(name="game_map").text = _("Map: {map_name}").format(map_name=game.map_name) self._gui.findChild(name="game_name").text = _("Name: {game_name}").format(game_name=game.name) self._gui.findChild(name="game_creator").text = _("Creator: {game_creator}").format(game_creator=game.creator) self._gui.findChild(name="game_playersnum").text = _("Players: {player_amount}/{player_limit}").format( player_amount=game.player_count, player_limit=game.player_limit) vbox_inner = self._gui.findChild(name="game_info") vbox_inner.adaptLayout() def _join_game(self): """Joins a multiplayer game. Displays lobby for that specific game""" try: index = self._gui.collectData('gamelist') game = self._games[index] except IndexError: return if game.uuid == -1: # -1 signals no game AmbientSoundComponent.play_special('error') return if game.version != NetworkInterface().get_clientversion(): self._windows.open_popup(_("Wrong version"), _("The game's version differs from your version. " "Every player in a multiplayer game must use the same version. " "This can be fixed by every player updating to the latest version. " "Game version: {game_version} Your version: {own_version}").format( game_version=game.version, own_version=NetworkInterface().get_clientversion())) return NetworkInterface().change_name(self._playerdata.get_player_name()) NetworkInterface().change_color(self._playerdata.get_player_color().id) if game.password: # ask the player for the password popup = PasswordInput(self._windows) password = self._windows.open(popup) if password is None: return password = hashlib.sha1(password).hexdigest() success = NetworkInterface().joingame(game.uuid, password) if not success: return elif not NetworkInterface().joingame(game.uuid, ''): return window = GameLobby(self._windows) self._windows.open(window) def _create_game(self): NetworkInterface().change_name(self._playerdata.get_player_name()) NetworkInterface().change_color(self._playerdata.get_player_color().id) self._windows.open(CreateGame(self._windows))
class MultiplayerMenu(Window): def __init__(self, mainmenu, windows): super(MultiplayerMenu, self).__init__(windows) self._mainmenu = mainmenu self._gui = load_uh_widget('multiplayermenu.xml') self._gui.mapEvents({ 'cancel': self._windows.close, 'join': self._join_game, 'create': self._create_game, 'refresh': Callback(self._refresh, play_sound=True) }) self._gui.findChild(name='gamelist').capture(self._update_game_details) self._playerdata = PlayerDataSelection() self._gui.findChild(name="playerdataselectioncontainer").addChild( self._playerdata.get_widget()) # to track if the menu window is opened or not. self._is_open = False def hide(self): # Save the player-data on hide so that other menus gets updated data self._playerdata.save_settings() self._gui.hide() ExtScheduler().rem_all_classinst_calls(self) def show(self): if not self._check_connection(): return if not self._refresh(): self._windows.close() return if not self._is_open: self._is_open = True # subscribe "error" when this menu window is firstly opened # only unsubscribe if this menu window is closed NetworkInterface().subscribe("error", self._on_error) # get updated player data self._playerdata.update_data() self._gui.show() # TODO: Remove once loading a game is implemented again self._gui.findChild(name='load').parent.hide() ExtScheduler().add_new_object(self._refresh, self, run_in=5, loops=-1) def close(self): # if the window is not open (due to connection errors), just do nothing if not self._is_open: return self.hide() NetworkInterface().unsubscribe("error", self._on_error) self._is_open = False # the window is also closed when a game starts, don't disconnect in that case if NetworkInterface( ).is_connected and not NetworkInterface().is_joined: NetworkInterface().disconnect() def on_return(self): self._join_game() def _check_connection(self): """ Check if all dependencies for multiplayer games are met and we can connect to the master server. If any dependency is not met, the window is closed. """ # It is important to close this window before showing the error popup. # Otherwise closing the popup will trigger `show` again, a new attempt # to connect is made, which ends up in an endless loop. if enet is None: self._windows.close() headline = _("Unable to find pyenet") descr = _('The multiplayer feature requires the library "pyenet", ' "which could not be found on your system.") advice = _( "Linux users: Try to install pyenet through your package manager." ) self._windows.open_error_popup(headline, descr, advice) return False if NetworkInterface() is None: try: NetworkInterface.create_instance() except RuntimeError as e: self._windows.close() headline = _("Failed to initialize networking.") descr = _( "Network features could not be initialized with the current configuration." ) advice = _( "Check the settings you specified in the network section.") self._windows.open_error_popup(headline, descr, advice, unicode(e)) return False if not NetworkInterface().is_connected: try: NetworkInterface().connect() except Exception as err: self._windows.close() headline = _("Fatal Network Error") descr = _("Could not connect to master server.") advice = _( "Please check your Internet connection. If it is fine, " "it means our master server is temporarily down.") self._windows.open_error_popup(headline, descr, advice, unicode(err)) return False if NetworkInterface().is_joined: if not NetworkInterface().leavegame(): self._windows.close() return False return True def _on_error(self, exception, fatal=True): """Error callback""" if not fatal: self._windows.open_popup(_("Error"), unicode(exception)) else: self._windows.open_popup( _("Fatal Network Error"), _("Something went wrong with the network:") + u'\n' + unicode(exception)) # FIXME: this shouldn't be necessary, the main menu window is still somewhere # in the stack and we just need to get rid of all MP related windows self._mainmenu.show_main() def _display_game_name(self, game): same_version = game.version == NetworkInterface().get_clientversion() template = u"{password}{gamename}: {name} ({players}, {limit}){version}" return template.format( password="******" if game.has_password else "", name=game.map_name, gamename=game.name, players=game.player_count, limit=game.player_limit, version=u" " + _("Version differs!") if not same_version else u"") def _refresh(self, play_sound=False): """Refresh list of games. @param play_sound: whether to play the refresh sound @return bool, whether refresh worked """ if play_sound: AmbientSoundComponent.play_special('refresh') self._games = NetworkInterface().get_active_games() if self._games is None: return False gamelist = [self._display_game_name(g) for g in self._games] self._gui.distributeInitialData({'gamelist': gamelist}) self._gui.distributeData({'gamelist': 0}) self._update_game_details() return True def _update_game_details(self): """Set map name and other misc data in a widget.""" try: index = self._gui.collectData('gamelist') game = self._games[index] except IndexError: return self._gui.findChild( name="game_map").text = _("Map: {map_name}").format( map_name=game.map_name) self._gui.findChild( name="game_name").text = _("Name: {game_name}").format( game_name=game.name) self._gui.findChild( name="game_creator").text = _("Creator: {game_creator}").format( game_creator=game.creator) self._gui.findChild(name="game_playersnum").text = _( "Players: {player_amount}/{player_limit}").format( player_amount=game.player_count, player_limit=game.player_limit) vbox_inner = self._gui.findChild(name="game_info") vbox_inner.adaptLayout() def _join_game(self): """Joins a multiplayer game. Displays lobby for that specific game""" try: index = self._gui.collectData('gamelist') game = self._games[index] except IndexError: return if game.uuid == -1: # -1 signals no game AmbientSoundComponent.play_special('error') return if game.version != NetworkInterface().get_clientversion(): self._windows.open_popup( _("Wrong version"), _("The game's version differs from your version. " "Every player in a multiplayer game must use the same version. " "This can be fixed by every player updating to the latest version. " "Game version: {game_version} Your version: {own_version}"). format(game_version=game.version, own_version=NetworkInterface().get_clientversion())) return NetworkInterface().change_name(self._playerdata.get_player_name()) NetworkInterface().change_color(self._playerdata.get_player_color().id) if game.password: # ask the player for the password popup = PasswordInput(self._windows) password = self._windows.open(popup) if password is None: return password = hashlib.sha1(password).hexdigest() success = NetworkInterface().joingame(game.uuid, password) if not success: return elif not NetworkInterface().joingame(game.uuid, ''): return window = GameLobby(self._windows) self._windows.open(window) def _create_game(self): NetworkInterface().change_name(self._playerdata.get_player_name()) NetworkInterface().change_color(self._playerdata.get_player_color().id) self._windows.open(CreateGame(self._windows))
class SingleplayerMenu(Window): def __init__(self, windows): super(SingleplayerMenu, self).__init__(windows) self._mode = None self._gui = load_uh_widget('singleplayermenu.xml') self._gui.mapEvents({ 'cancel': self._windows.close, 'okay': self.act, 'scenario': Callback(self._select_mode, 'scenario'), 'random': Callback(self._select_mode, 'random'), 'free_maps': Callback(self._select_mode, 'free_maps') }) self._playerdata = PlayerDataSelection() self._aidata = AIDataSelection() self._gui.findChild(name="playerdataselectioncontainer").addChild( self._playerdata.get_widget()) self._gui.findChild(name="aidataselectioncontainer").addChild( self._aidata.get_widget()) def hide(self): # Save the player-data on hide so that other menus gets updated data self._playerdata.save_settings() self._gui.hide() def show(self): self._playerdata.update_data() self._gui.findChild(name='scenario').marked = True self._select_mode('scenario') def on_return(self): self.act() def _select_mode(self, mode): self._gui.hide() modes = { 'random': RandomMapWidget, 'free_maps': FreeMapsWidget, 'scenario': ScenarioMapWidget, } # remove old widget if self._mode: self._mode.end() self._gui.findChild(name="right_side_box").removeChild( self._mode.get_widget()) self._mode = modes[mode](self._windows, self, self._aidata) self._mode.show() self._gui.findChild(name="right_side_box").addChild( self._mode.get_widget()) self._gui.show() def act(self): """Start the game. Called when OK button is pressed.""" player_color = self._playerdata.get_player_color() player_name = self._playerdata.get_player_name() if not player_name: self._windows.open_popup(_("Invalid player name"), _("You entered an invalid playername.")) return horizons.globals.fife.set_uh_setting("Nickname", player_name) self._windows.close() self._mode.act(player_name, player_color)