def set_network_port(self, port): """Sets a new value for client network port""" # port is saved as string due to pychan limitations try: # 0 is not a valid port, but a valid value here (used for default) parse_port(port, allow_zero=True) except ValueError: headline = _("Invalid network port") descr = _("The port you specified is not valid. It must be a number between 1 and 65535.") advice = _("Please check the port you entered and make sure it is in the specified range.") horizons.main._modules.gui.show_error_popup(headline, descr, advice) # reset value and reshow settings dlg self.engine.set_uh_setting("NetworkPort", u"0") ExtScheduler().add_new_object(self._setting.onOptionsPress, self.engine, 0) else: # port is valid try: if NetworkInterface() is None: NetworkInterface.create_instance() NetworkInterface().network_data_changed(connect=False) except Exception as e: headline = _(u"Failed to apply new network settings.") descr = _("Network features could not be initialized with the current configuration.") advice = _("Check the settings you specified in the network section.") if 0 < parse_port(port, allow_zero=True) < 1024: # i18n This is advice for players seeing a network error with the current config advice += u" " + _( "Low port numbers sometimes require special access privileges, try 0 or a number greater than 1024." ) details = unicode(e) horizons.main._modules.gui.show_error_popup(headline, descr, advice, details) ExtScheduler().add_new_object(self._setting.onOptionsPress, self.engine, 0)
def set_network_port(self, port): """Sets a new value for client network port""" # port is saved as string due to pychan limitations try: # 0 is not a valid port, but a valid value here (used for default) parse_port(port) except ValueError: headline = _("Invalid network port") descr = _("The port you specified is not valid. It must be a number between 1 and 65535.") advice = _("Please check the port you entered and make sure it is in the specified range.") horizons.main._modules.gui.show_error_popup(headline, descr, advice) # reset value and reshow settings dlg self.engine.set_uh_setting("NetworkPort", u"0") ExtScheduler().add_new_object(self._setting.onOptionsPress, self.engine, 0) else: # port is valid try: if NetworkInterface() is None: NetworkInterface.create_instance() NetworkInterface().network_data_changed() except Exception as e: headline = _("Failed to apply new network settings.") descr = _("Network features could not be initialized with the current configuration.") advice = _("Check the settings you specified in the network section.") if 0 < parse_port(port) < 1024: #i18n This is advice for players seeing a network error with the current config advice += u" " + \ _("Low port numbers sometimes require special access privileges, try 0 or a number greater than 1024.") details = unicode(e) horizons.main._modules.gui.show_error_popup(headline, descr, advice, details) ExtScheduler().add_new_object(self._setting.onOptionsPress, self.engine, 0)
def _show_change_player_details_popup(self, game): """Shows a dialog where the player can change its name and/or color""" assigned = [ p["color"] for p in NetworkInterface().get_game().get_player_list() if p["name"] != NetworkInterface().get_client_name() ] unused_colors = set(Color) - set(assigned) playerdata = PlayerDataSelection(color_palette=unused_colors) playerdata.set_player_name(NetworkInterface().get_client_name()) playerdata.set_color(NetworkInterface().get_client_color()) dialog = load_uh_widget('set_player_details.xml') dialog.findChild(name="playerdataselectioncontainer").addChild( playerdata.get_widget()) def _change_playerdata(): NetworkInterface().change_name(playerdata.get_player_name()) NetworkInterface().change_color(playerdata.get_player_color().id) dialog.hide() self._update_game_details() def _cancel(): dialog.hide() dialog.mapEvents({ OkButton.DEFAULT_NAME: _change_playerdata, CancelButton.DEFAULT_NAME: _cancel }) dialog.show()
def _on_NetworkPort_changed(self, old, new): """Sets a new value for client network port""" # port is saved as string due to pychan limitations try: # 0 is not a valid port, but a valid value here (used for default) parse_port(new) except ValueError: headline = T("Invalid network port") descr = T("The port you specified is not valid. It must be a number between 1 and 65535.") advice = T("Please check the port you entered and make sure it is in the specified range.") self._windows.open_error_popup(headline, descr, advice) # reset value and reshow settings dlg self._settings.set(SETTINGS.UH_MODULE, 'NetworkPort', u"0") else: # port is valid try: if NetworkInterface() is None: NetworkInterface.create_instance() NetworkInterface().network_data_changed() except Exception as e: headline = T("Failed to apply new network settings.") descr = T("Network features could not be initialized with the current configuration.") advice = T("Check the settings you specified in the network section.") if 0 < parse_port(new) < 1024: #i18n This is advice for players seeing a network error with the current config advice += u" " + \ T("Low port numbers sometimes require special access privileges, try 0 or a number greater than 1024.") details = unicode(e) self._windows.open_error_popup(headline, descr, advice, details)
def _on_NetworkPort_changed(self, old, new): """Sets a new value for client network port""" # port is saved as string due to pychan limitations try: # 0 is not a valid port, but a valid value here (used for default) parse_port(new) except ValueError: headline = _("Invalid network port") descr = _("The port you specified is not valid. It must be a number between 1 and 65535.") advice = _("Please check the port you entered and make sure it is in the specified range.") self._windows.open_error_popup(headline, descr, advice) # reset value and reshow settings dlg self._settings.set(SETTINGS.UH_MODULE, "NetworkPort", u"0") else: # port is valid try: if NetworkInterface() is None: NetworkInterface.create_instance() NetworkInterface().network_data_changed() except Exception as e: headline = _("Failed to apply new network settings.") descr = _("Network features could not be initialized with the current configuration.") advice = _("Check the settings you specified in the network section.") if 0 < parse_port(new) < 1024: # i18n This is advice for players seeing a network error with the current config advice += u" " + _( "Low port numbers sometimes require special access privileges, try 0 or a number greater than 1024." ) details = unicode(e) self._windows.open_error_popup(headline, descr, advice, details)
def __join_game(self, game=None): """Joins a multiplayer game. Displays lobby for that specific game""" if game is None: game = self.__get_selected_game() if game is None: return if game.get_uuid() == -1: # -1 signals no game AmbientSoundComponent.play_special('error') return if game.get_version() != NetworkInterface().get_clientversion(): self.show_popup( _("Wrong version"), #xgettext:python-format _("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.get_version(), own_version=NetworkInterface().get_clientversion())) return # actual join if game.password: self.__enter_password_dialog(game) else: self.__actual_join(game)
def show(self): if not self._check_connection(): return 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()) refresh_worked = self._refresh() if not refresh_worked: self._windows.close() return # FIXME workaround for multiple callback registrations # this happens because subscription is done when the window is showed, unsubscription # only when it is closed. if new windows appear and disappear, show is called multiple # times. the error handler is used throughout the entire mp menu, that's why we can't # unsubscribe in hide. need to find a better solution. NetworkInterface().discard("error", self._on_error) NetworkInterface().subscribe("error", self._on_error) self._gui.show() # TODO Remove once loading a game is implemented again self._gui.findChild(name='load').parent.hide()
def show_multi(self): """Shows main multiplayer menu""" if enet == None: headline = _(u"Unable to find pyenet") descr = _( u'The multiplayer feature requires the library "pyenet", which couldn\'t be found on your system.' ) advice = ( _(u"Linux users: Try to install pyenet through your package manager.") + "\n" + _(u"Windows users: There is currently no reasonable support for Windows.") ) self.show_error_popup(headline, descr, advice) return if NetworkInterface() is None: try: NetworkInterface.create_instance() except RuntimeError as e: headline = _(u"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.show_error_popup(headline, descr, advice, unicode(e)) return if not NetworkInterface().isconnected(): connected = self.__connect_to_server() if not connected: return if NetworkInterface().isjoined(): if not NetworkInterface().leavegame(): return event_map = { "cancel": self.__cancel, "join": self.__join_game, "create": self.__show_create_game, "load": self.__show_load_game, "refresh": self.__refresh, } # store old name and color self.__apply_new_nickname() # reload because changing modes (not yet implemented) will need it self.widgets.reload("multiplayermenu") self._switch_current_widget("multiplayermenu", center=True, event_map=event_map, hide_old=True) refresh_worked = self.__refresh() if not refresh_worked: self.show_main() return self.current.findChild(name="gamelist").capture(self.__update_game_details) self.current.findChild(name="showonlyownversion").capture(self.__show_only_own_version_toggle) self.current.playerdata = PlayerDataSelection(self.current, self.widgets) self.current.show() self.on_escape = event_map["cancel"]
def __get_selected_game(self): try: if NetworkInterface().isjoined(): return NetworkInterface().get_game() else: index = self.current.collectData('gamelist') return self.games[index] except: return None
def _get_unused_colors(): """Returns unused colors list in a game """ assigned = [ p["color"] for p in NetworkInterface().get_game().get_player_list() if p["name"] != NetworkInterface().get_client_name() ] available = set(Color) - set(assigned) return available
def __init__(self, windows): super(GameLobby, self).__init__(windows) self._gui = load_uh_widget('multiplayer_gamelobby.xml') self._gui.mapEvents({ 'cancel': self._cancel, 'ready_btn': NetworkInterface().toggle_ready, }) NetworkInterface().subscribe("game_prepare", self._prepare_game)
def show_multi(self): """Shows main multiplayer menu""" if enet is None: headline = _(u"Unable to find pyenet") descr = _(u'The multiplayer feature requires the library "pyenet", ' u"which could not be found on your system.") advice = _(u"Linux users: Try to install pyenet through your package manager.") self.mainmenu.show_error_popup(headline, descr, advice) return if NetworkInterface() is None: try: NetworkInterface.create_instance() except RuntimeError as e: headline = _(u"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.mainmenu.show_error_popup(headline, descr, advice, unicode(e)) return if not NetworkInterface().is_connected: connected = self.__connect_to_server() if not connected: return if NetworkInterface().is_joined: if not NetworkInterface().leavegame(): return event_map = { 'cancel' : self.__cancel, 'join' : self.__join_game, 'create' : self.__show_create_game, 'load' : self.__show_load_game, 'refresh' : Callback(self.__refresh, play_sound=True) } # store old name and color self.__apply_new_nickname() self.__apply_new_color() # reload because changing modes (not yet implemented) will need it self.widgets.reload('multiplayermenu') self.mainmenu._switch_current_widget('multiplayermenu', center=True, event_map=event_map, hide_old=True) self.current = self.mainmenu.current refresh_worked = self.__refresh() if not refresh_worked: self.mainmenu.show_main() return self.current.findChild(name='gamelist').capture(self.__update_game_details) self.current.findChild(name='showonlyownversion').capture(self.__show_only_own_version_toggle) self.current.playerdata = PlayerDataSelection(self.current, self.widgets) self.current.show() self.mainmenu.on_escape = event_map['cancel']
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 = T("Unable to find pyenet") descr = T('The multiplayer feature requires the library "pyenet", ' "which could not be found on your system.") advice = T("For instructions on installing pyenet see:" "https://github.com/unknown-horizons/unknown-horizons/wiki/Installing-PyEnet") 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 = T("Failed to initialize networking.") descr = T("Network features could not be initialized with the current configuration.") advice = T("Check the settings you specified in the network section.") self._windows.open_error_popup(headline, descr, advice, str(e)) return False if not NetworkInterface().is_connected: try: NetworkInterface().connect() except TypeError as terr: self._windows.close() headline = T("Pyenet type error") descr = T("You are probably using an incompatible pyenet installation") advice = T("For instructions on properly installing pyenet see: " "https://github.com/unknown-horizons/unknown-horizons/wiki/Installing-PyEnet") self._windows.open_error_popup(headline, descr, advice, str(terr)) except Exception as err: self._windows.close() headline = T("Fatal Network Error") descr = T("Could not connect to master server.") advice = T("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, str(err)) return False if NetworkInterface().is_joined: if not NetworkInterface().leavegame(): self._windows.close() return False return True
def open(self): textfield = self._gui.findChild(name="chatTextField") textfield.capture(self._send_chat_message) welcome_string = T("Enter your message") def chatfield_clicked(): if textfield.text == welcome_string: textfield.text = "" textfield.text = welcome_string textfield.capture(chatfield_clicked, event_name="mouseClicked") self._update_game_details() NetworkInterface().subscribe("lobbygame_chat", self._on_chat_message) NetworkInterface().subscribe("lobbygame_join", self._on_player_joined) NetworkInterface().subscribe("lobbygame_leave", self._on_player_left) NetworkInterface().subscribe("lobbygame_kick", self._on_player_kicked) NetworkInterface().subscribe("lobbygame_changename", self._on_player_changed_name) NetworkInterface().subscribe("lobbygame_changecolor", self._on_player_changed_color) NetworkInterface().subscribe("lobbygame_toggleready", self._on_player_toggled_ready) NetworkInterface().subscribe("game_details_changed", self._update_game_details) NetworkInterface().subscribe("error", self._on_error) self.show()
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 close(self): self.hide() NetworkInterface().unsubscribe("lobbygame_chat", self._on_chat_message) NetworkInterface().unsubscribe("lobbygame_join", self._on_player_joined) NetworkInterface().unsubscribe("lobbygame_leave", self._on_player_left) NetworkInterface().unsubscribe("lobbygame_kick", self._on_player_kicked) NetworkInterface().unsubscribe("lobbygame_changename", self._on_player_changed_name) NetworkInterface().unsubscribe("lobbygame_changecolor", self._on_player_changed_color) NetworkInterface().unsubscribe("lobbygame_toggleready", self._on_player_toggled_ready) NetworkInterface().unsubscribe("game_details_changed", self._update_game_details) NetworkInterface().unsubscribe("game_prepare", self._prepare_game)
def prepare_multiplayer(game): """Starts a multiplayer game server TODO: acctual game data parameter passing """ global fife, preloading, db preload_game_join(preloading) # remove cursor while loading fife.cursor.set(fife_module.CURSOR_NONE) fife.engine.pump() fife.cursor.set(fife_module.CURSOR_IMAGE, fife.default_cursor_image) # hide whatever is displayed before the game starts _modules.gui.hide() # destruct old session (right now, without waiting for gc) if _modules.session is not None and _modules.session.is_alive: _modules.session.end() # start new session from mpsession import MPSession # get random seed for game random = sum(game.get_uuid().uuid) _modules.session = MPSession(_modules.gui, db, NetworkInterface(), rng_seed=random) # NOTE: this data passing is only temporary, maybe use a player class/struct _modules.session.load("content/maps/" + game.get_map_name() + ".sqlite", \ game.get_player_list())
def prepare_multiplayer(game, trader_enabled=True, pirate_enabled=True, natural_resource_multiplier=1): """Starts a multiplayer game server TODO: actual game data parameter passing """ _modules.gui.show_loading_screen() preloader.wait_for_finish() # remove cursor while loading horizons.globals.fife.cursor.set(fife_module.CURSOR_NONE) horizons.globals.fife.engine.pump() horizons.globals.fife.set_cursor_image('default') # destruct old session (right now, without waiting for gc) if _modules.session is not None and _modules.session.is_alive: _modules.session.end() # start new session from horizons.mpsession import MPSession # get random seed for game uuid = game.uuid random = sum([int(uuid[i : i + 2], 16) for i in range(0, len(uuid), 2)]) _modules.session = MPSession(horizons.globals.db, NetworkInterface(), rng_seed=random) # NOTE: this data passing is only temporary, maybe use a player class/struct if game.is_savegame: map_file = SavegameManager.get_multiplayersave_map(game.map_name) else: map_file = SavegameManager.get_map(game.map_name) options = StartGameOptions.create_start_multiplayer(map_file, game.get_player_list(), not game.is_savegame) _modules.session.load(options)
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.show_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.show_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.show_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 _cancel(self): """When the lobby is cancelled, close the window and leave the game. We can't do this in `close`, because the window will be closed when a game starts as well, and we don't want to leave the game then. """ self._windows.close() NetworkInterface().leavegame()
def __show_change_player_details_popup(self): """Shows a dialog where the player can change its name and/or color""" def _get_unused_colors(): """Returns unused colors list in a game """ assigned = [ p["color"] for p in NetworkInterface().get_game().get_player_list() if p["name"] != NetworkInterface().get_client_name() ] available = set(Color) - set(assigned) return available set_player_details_dialog = self.widgets['set_player_details'] #remove all children of color and name pop-up and then show them set_player_details_dialog.findChild( name="playerdataselectioncontainer").removeAllChildren() #assign playerdata to self.current.playerdata to use self.__apply_new_color() and __apply_new_nickname() self.current.playerdata = PlayerDataSelection( set_player_details_dialog, self.widgets, color_palette=_get_unused_colors()) self.current.playerdata.set_player_name( NetworkInterface().get_client_name()) self.current.playerdata.set_color( NetworkInterface().get_client_color()) def _change_playerdata(): self.__apply_new_nickname() self.__apply_new_color() set_player_details_dialog.hide() self.__update_game_details() def _cancel(): set_player_details_dialog.hide() events = { OkButton.DEFAULT_NAME: _change_playerdata, CancelButton.DEFAULT_NAME: _cancel } self.on_escape = _cancel set_player_details_dialog.mapEvents(events) set_player_details_dialog.show()
def _add_player_line(player): pname = Label(name="pname_%s" % player['name']) pname.helptext = _("Click here to change your name and/or color") pname.text = player['name'] if player['name'] == NetworkInterface().get_client_name(): pname.capture(Callback( self.__show_change_player_details_popup)) pname.min_size = pname.max_size = (130, 15) pcolor = Label(name="pcolor_%s" % player['name'], text=u" ") pcolor.helptext = _("Click here to change your name and/or color") pcolor.background_color = player['color'] if player['name'] == NetworkInterface().get_client_name(): pcolor.capture( Callback(self.__show_change_player_details_popup)) pcolor.min_size = pcolor.max_size = (15, 15) pstatus = Label(name="pstatus_%s" % player['name']) pstatus.text = "\t\t\t" + player['status'] pstatus.min_size = pstatus.max_size = (120, 15) picon = Icon(name="picon_%s" % player['name']) picon.image = "content/gui/images/background/hr.png" hbox = HBox() hbox.addChild(pname) hbox.addChild(pcolor) hbox.addChild(pstatus) if NetworkInterface().get_client_name() == game.get_creator( ) and player['name'] != game.get_creator(): pkick = CancelButton(name="pkick_%s" % player['name']) pkick.helptext = _("Kick {player}").format( player=player['name']) pkick.capture(Callback(NetworkInterface().kick, player['sid'])) pkick.up_image = "content/gui/images/buttons/delete_small.png" pkick.down_image = "content/gui/images/buttons/delete_small.png" pkick.hover_image = "content/gui/images/buttons/delete_small_h.png" pkick.min_size = pkick.max_size = (20, 15) hbox.addChild(pkick) players_vbox.addChild(hbox) players_vbox.addChild(picon)
def _on_ready_button_pressed(self): ready_button = self._gui.findChild(name="ready_btn") ready_button.toggle() ready_label = self._gui.findChild(name="ready_lbl") if ready_button.is_active: ready_label.text = _("Ready") + ":" else: ready_label.text = _("Not ready") + ":" ready_label.adaptLayout() NetworkInterface().toggle_ready()
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 _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 _check_connection(self): """ Check if all dependencies for multiplayer games are met and we can connect to the master server. """ if enet is None: headline = _(u"Unable to find pyenet") descr = _(u'The multiplayer feature requires the library "pyenet", ' u"which could not be found on your system.") advice = _(u"Linux users: Try to install pyenet through your package manager.") self._mainmenu.show_error_popup(headline, descr, advice) return False if NetworkInterface() is None: try: NetworkInterface.create_instance() except RuntimeError as e: headline = _(u"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._mainmenu.show_error_popup(headline, descr, advice, unicode(e)) return False if not NetworkInterface().is_connected: try: NetworkInterface().connect() except Exception as err: headline = _(u"Fatal Network Error") descr = _(u"Could not connect to master server.") advice = _(u"Please check your Internet connection. If it is fine, " u"it means our master server is temporarily down.") self._mainmenu.show_error_popup(headline, descr, advice, unicode(err)) return False if NetworkInterface().is_joined: if not NetworkInterface().leavegame(): return False return True
def _add_player_line(player): name = player['name'] pname = Label(name="pname_%s" % name) pname.helptext = _("Click here to change your name and/or color") pname.text = name pname.min_size = pname.max_size = (130, 15) if name == NetworkInterface().get_client_name(): pname.capture( Callback(self._show_change_player_details_popup, game)) pcolor = Label(name="pcolor_%s" % name, text=u" ") pcolor.helptext = _("Click here to change your name and/or color") pcolor.background_color = player['color'] pcolor.min_size = pcolor.max_size = (15, 15) if name == NetworkInterface().get_client_name(): pcolor.capture( Callback(self._show_change_player_details_popup, game)) pstatus = Label(name="pstatus_%s" % name) pstatus.text = "\t\t\t" + player['status'] pstatus.min_size = pstatus.max_size = (120, 15) picon = HRule(name="picon_%s" % name) hbox = HBox() hbox.addChildren(pname, pcolor, pstatus) if NetworkInterface().get_client_name( ) == game.creator and name != game.creator: pkick = CancelButton(name="pkick_%s" % name) pkick.helptext = _("Kick {player}").format(player=name) pkick.capture(Callback(NetworkInterface().kick, player['sid'])) pkick.path = "images/buttons/delete_small" pkick.min_size = pkick.max_size = (20, 15) hbox.addChild(pkick) players_vbox.addChildren(hbox, picon)
def _on_player_toggled_ready(self, game, plold, plnew, myself): self._update_players_box(NetworkInterface().get_game()) if myself: if plnew.ready: self._print_event(_("You are now ready")) else: self._print_event(_("You are not ready anymore")) else: if plnew.ready: self._print_event( _("{player} is now ready").format(player=plnew.name)) else: self._print_event( _("{player} not ready anymore").format(player=plnew.name))
def show(self): textfield = self._gui.findChild(name="chatTextField") textfield.capture(self._send_chat_message) self._update_game_details() NetworkInterface().subscribe("lobbygame_chat", self._on_chat_message) NetworkInterface().subscribe("lobbygame_join", self._on_player_joined) NetworkInterface().subscribe("lobbygame_leave", self._on_player_left) NetworkInterface().subscribe("lobbygame_kick", self._on_player_kicked) NetworkInterface().subscribe("lobbygame_changename", self._on_player_changed_name) NetworkInterface().subscribe("lobbygame_changecolor", self._on_player_changed_color) NetworkInterface().subscribe("lobbygame_toggleready", self._on_player_toggled_ready) NetworkInterface().subscribe("game_details_changed", self._update_game_details) self._gui.show()
def _update_game_details(self): """Set map name and other misc data""" game = NetworkInterface().get_game() #xgettext:python-format self._gui.findChild(name="game_map").text = _("Map: {map_name}").format(map_name=game.map_name) #xgettext:python-format self._gui.findChild(name="game_name").text = _("Name: {game_name}").format(game_name=game.name) #xgettext:python-format self._gui.findChild(name="game_creator").text = _("Creator: {game_creator}").format(game_creator=game.creator) #xgettext:python-format self._gui.findChild(name="game_playersnum").text = _("Players: {player_amount}/{player_limit}").format( player_amount=game.player_count, player_limit=game.player_limit) self._update_players_box(game) self._gui.findChild(name="game_info").adaptLayout()
def act(self): mapindex = self._gui.collectData('maplist') mapname = self._maps_display[mapindex] maxplayers = self._gui.collectData('playerlimit') + 2 # 1 is the first entry gamename = self._gui.collectData('gamename') password = self._gui.collectData('password') maphash = "" password = hashlib.sha1(password).hexdigest() if password != "" else "" game = NetworkInterface().creategame(mapname, maxplayers, gamename, maphash, password) if game: # FIXME When canceling the lobby, I'd like the player to return to the main mp # menu, and not see the 'create game' again. We need to close this window, however, # this will trigger the display of the main gui, which will part the game in # `MultiplayerMenu._check_connection` #self._windows.close() window = GameLobby(self._windows) self._windows.show(window)
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 __refresh(self, play_sound=False): """Refresh list of games. Only possible in multiplayer main menu state. @param play_sound: whether to play the refresh sound @return bool, whether refresh worked""" if play_sound: AmbientSoundComponent.play_special('refresh') only_this_version_allowed = self.current.findChild( name='showonlyownversion').marked self.games = NetworkInterface().get_active_games( only_this_version_allowed) if self.games is None: return False gamelist = [self._display_game_name(g) for g in self.games] self.current.distributeInitialData({'gamelist': gamelist}) self.current.distributeData({'gamelist': 0}) # select first map self.__update_game_details() return True
def __actual_join(self, game=None, password=""): """Does the actual joining to the game. This method is called after everything is OK for joining.""" if game is None: return False self.__apply_new_nickname() self.__apply_new_color() fetch = False if game.is_savegame() and SavegameAccessor.get_hash( SavegameManager.get_multiplayersave_map( game.mapname)) != game.get_map_hash(): fetch = True if not NetworkInterface().joingame(game.get_uuid(), password, fetch): return False self.__show_gamelobby() return True
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()
def close(self): # when the connection to the master server fails, the window will be closed before # anything has been setup if not hasattr(self, '_gui'): return self.hide() NetworkInterface().unsubscribe("error", self._on_error) # 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() NetworkInterface().change_name(self._playerdata.get_player_name()) NetworkInterface().change_color(self._playerdata.get_player_color().id)
def __create_game(self, load=None, chosen_map=None): """ Actually create a game, join it, and display the lobby. @param load: game data tuple for creating loaded games @param chosen_map: the name of the map to start a new game on (overrides the gui) """ # create the game if load: mapname, gamename, gamepassword = load path = SavegameManager.get_multiplayersave_map(mapname) maxplayers = SavegameAccessor.get_players_num(path) password = gamepassword maphash = SavegameAccessor.get_hash(path) else: mapindex = None if chosen_map is not None: for i, map in enumerate(self.maps_display): if map == chosen_map: mapindex = i break if mapindex is None: mapindex = self.current.collectData('maplist') mapname = self.maps_display[mapindex] maxplayers = self.current.collectData( 'playerlimit') + 2 # 1 is the first entry gamename = self.current.collectData('gamename') password = self.current.collectData('password') maphash = "" password = hashlib.sha1(password).hexdigest() if password != "" else "" game = NetworkInterface().creategame(mapname, maxplayers, gamename, maphash, password) if game is None: return self.__show_gamelobby()
def start(command_line_arguments): """Starts the horizons. @param command_line_arguments: options object from optparse.OptionParser. see run_uh.py. """ global fife, db, debug, preloading # NOTE: globals are designwise the same thing as singletons. they don't look pretty. # here, we only have globals that are either trivial, or only one instance may ever exist. from engine import Fife # handle commandline globals debug = command_line_arguments.debug if command_line_arguments.restore_settings: # just delete the file, Settings ctor will create a new one os.remove( PATHS.USER_CONFIG_FILE ) if command_line_arguments.mp_master: try: mpieces = command_line_arguments.mp_master.partition(':') NETWORK.SERVER_ADDRESS = mpieces[0] # only change port if port is specified if len(mpieces[2]) > 0: NETWORK.SERVER_PORT = parse_port(mpieces[2], allow_zero=True) except ValueError: print _("Error: Invalid syntax in --mp-master commandline option. Port must be a number between 1 and 65535.") return False # init fife before mp_bind is parsed, since it's needed there fife = Fife() if command_line_arguments.mp_bind: try: mpieces = command_line_arguments.mp_bind.partition(':') NETWORK.CLIENT_ADDRESS = mpieces[0] fife.set_uh_setting("NetworkPort", parse_port(mpieces[2], allow_zero=True)) print 'asdf', fife.get_uh_setting("NetworkPort2") except ValueError: print _("Error: Invalid syntax in --mp-bind commandline option. Port must be a number between 1 and 65535.") return False db = _create_db() # init game parts _init_gettext(fife) client_id = fife.get_uh_setting("ClientID") if client_id is None or len(client_id) == 0: # We need a new client id client_id = "".join("-" if c in (8, 13, 18, 23) else \ random.choice("0123456789abcdef") for c in xrange(0, 36)) from engine import UH_MODULE fife.settings.set(UH_MODULE, "ClientID", client_id) fife.settings.saveSettings() ExtScheduler.create_instance(fife.pump) fife.init() _modules.gui = Gui() SavegameManager.init() try: NetworkInterface.create_instance() except RuntimeError, e: headline = _(u"Failed to initialize networking.") descr = _(u"Networking couldn't be initialised with the current configuration.") advice = _(u"Check the data you entered in the Network section in the settings dialogue.") _modules.gui.show_error_popup(headline, descr, advice, unicode(e))
def start(command_line_arguments): """Starts the horizons. @param command_line_arguments: options object from optparse.OptionParser. see run_uh.py. """ global fife, db, debug, preloading # NOTE: globals are designwise the same thing as singletons. they don't look pretty. # here, we only have globals that are either trivial, or only one instance may ever exist. from engine import Fife # handle commandline globals debug = command_line_arguments.debug if command_line_arguments.restore_settings: # just delete the file, Settings ctor will create a new one os.remove( PATHS.USER_CONFIG_FILE ) if command_line_arguments.mp_master: try: mpieces = command_line_arguments.mp_master.partition(':') NETWORK.SERVER_ADDRESS = mpieces[0] # only change port if port is specified if len(mpieces[2]) > 0: NETWORK.SERVER_PORT = int(mpieces[2]) if NETWORK.SERVER_PORT < 1 or NETWORK.SERVER_PORT > 65535: raise ValueError except ValueError: print _("Error: Invalid syntax in --mp-master commandline option. Port must be a number between 0 and 65535.") return False if command_line_arguments.mp_bind: try: mpieces = command_line_arguments.mp_bind.partition(':') NETWORK.CLIENT_ADDRESS = mpieces[0] NETWORK.CLIENT_PORT = int(mpieces[2]) if NETWORK.CLIENT_PORT < 1 or NETWORK.CLIENT_PORT > 65535: raise ValueError except ValueError: print _("Error: Invalid syntax in --mp-bind commandline option. Port must be a number between 0 and 65535.") return False db = _create_db() # init game parts fife = Fife() _init_gettext(fife) client_id = fife.get_uh_setting("ClientID") if client_id is None or len(client_id) == 0: # We need a new client id client_id = "".join("-" if c in (8, 13, 18, 23) else \ random.choice("0123456789abcdef") for c in xrange(0, 36)) from engine import UH_MODULE fife.settings.set(UH_MODULE, "ClientID", client_id) fife.settings.saveSettings() ExtScheduler.create_instance(fife.pump) fife.init() _modules.gui = Gui() SavegameManager.init() try: NetworkInterface.create_instance() NetworkInterface().add_to_extscheduler() except RuntimeError, e: print "Error during network initialization: %s" % (e) return False