def end(self, keep_map=False, remove_savegame=True): """ Clean up temporary files. """ super(SPTestSession, self).end() # remove the saved game savegame_db = SavegameAccessor(self.savegame, self.started_from_map) savegame_db.close() if remove_savegame and not self.started_from_map: os.remove(self.savegame)
def end(self, keep_map=False, remove_savegame=True): """ Clean up temporary files. """ super(SPTestSession, self).end() # Find all islands in the map first savegame_db = SavegameAccessor(self.savegame) if not keep_map: for (island_file, ) in savegame_db('SELECT file FROM island'): if not island_file.startswith('random:'): # random islands don't exist as files os.remove(island_file) # Finally remove savegame savegame_db.close() if remove_savegame: os.remove(self.savegame)
def edit_game_map(saved_game_name): """ Start editing the specified map. @param map_name: name of map or path to map @return: bool, whether loading succeeded """ saved_games = SavegameManager.get_saves() saved_game_path = _find_map(saved_game_name, saved_games) if not saved_game_path: return False accessor = SavegameAccessor(saved_game_path, False) map_name = accessor.map_name accessor.close() if isinstance(map_name, list): # a random map represented by a list of island strings return _edit_map(map_name) return edit_map(map_name)
def edit_game_map(saved_game_name): """ Start editing the specified map. @param map_name: name of map or path to map @return: bool, whether loading succeeded """ saved_games = SavegameManager.get_saves() saved_game_path = _find_matching_map(saved_game_name, saved_games) if not saved_game_path: return False accessor = SavegameAccessor(saved_game_path, False) map_name = accessor.map_name accessor.close() if isinstance(map_name, list): # a random map represented by a list of island strings return _edit_map(map_name) return edit_map(map_name)
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 __update_game_details(self, game=None): """Set map name and other misc data in a widget. Only possible in certain states""" if game is None: game = self.__get_selected_game() if game is None: return #xgettext:python-format self.current.findChild(name="game_map").text = _("Map: {map_name}").format(map_name=game.get_map_name()) self.current.findChild(name="game_name").text = _("Name: {game_name}").format(game_name=game.get_name()) self.current.findChild(name="game_creator").text = _("Creator: {game_creator}").format(game_creator=game.get_creator()) #xgettext:python-format self.current.findChild(name="game_playersnum").text = _("Players: {player_amount}/{player_limit}").format( player_amount=game.get_player_count(), player_limit=game.get_player_limit()) vbox_inner = self.current.findChild(name="game_info") if game.is_savegame(): # work around limitations of current systems via messages path = SavegameManager.get_multiplayersave_map(game.mapname) btn_name = "save_missing_help_button" btn = vbox_inner.findChild(name=btn_name) if SavegameAccessor.get_hash(path) != game.get_map_hash(): text = "" if btn is None: btn = Button(name=btn_name) btn.text = _("This savegame is missing (click here)") last_elem = vbox_inner.findChild(name="game_info_last") if last_elem is None: # no last elem -> we are last vbox_inner.addChild( btn ) else: vbox_inner.insertChildBefore( btn, last_elem ) btn_text = _(u"For multiplayer load, it is necessary for you to have the correct savegame file.") + u"\n" btn_text += _(u"The file will be downloaded when the game starts.") btn.btn_text = btn_text def show(): self.show_popup(_("Help"), btn_text, size=1) btn.capture(show) else: text = _(u"This is a savegame.") if btn is not None: btn.hide() if text: self.current.findChild(name="game_isloaded").text = text self.__update_players_box(game) vbox_inner.adaptLayout() # inner vbox always exists vbox = self.current.findChild(name="gamedetailsbox") if vbox is not None: vbox.adaptLayout()
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 test_save_trivial(session, _): """ Let 2 AI players play for a while, then attempt to save the game. Be aware, this is a pretty simple test and it doesn't actually check what is being saved. """ session.run(seconds=4*60) fd, filename = tempfile.mkstemp() os.close(fd) assert session.save(savegamename=filename) SavegameAccessor(filename, False) os.unlink(filename)
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 __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 load_raw_world(map_file): WorldObject.reset() world = World(session=None) world.inited = True world.load_raw_map(SavegameAccessor(map_file, True), preview=True) return world
def load(self, savegame, players, trader_enabled, pirate_enabled, natural_resource_multiplier, is_scenario=False, campaign=None, force_player_id=None, disasters_enabled=True, is_multiplayer=False): """Loads a map. Key method for starting a game. @param savegame: path to the savegame database. @param players: iterable of dictionaries containing id, name, color, local, ai, and difficulty @param is_scenario: Bool whether the loaded map is a scenario or not @param force_player_id: the worldid of the selected human player or default if None (debug option) """ """ TUTORIAL: Here you see how the vital game elements (and some random things that are also required) are initialised. """ if is_scenario: # savegame is a yaml file, that contains reference to actual map file self.scenario_eventhandler = ScenarioEventHandler(self, savegame) # scenario maps can be normal maps or scenario maps: map_filename = self.scenario_eventhandler.get_map_file() savegame = os.path.join(SavegameManager.scenario_maps_dir, map_filename) if not os.path.exists(savegame): savegame = os.path.join(SavegameManager.maps_dir, map_filename) self.campaign = {} if not campaign else campaign self.log.debug("Session: Loading from %s", savegame) savegame_db = SavegameAccessor(savegame) # Initialize new dbreader savegame_data = SavegameManager.get_metadata(savegame) # load how often the game has been saved (used to know the difference between # a loaded and a new game) self.savecounter = savegame_data.get('savecounter', 0) if savegame_data.get('rng_state', None): rng_state_list = json.loads( savegame_data['rng_state'] ) # json treats tuples as lists, but we need tuples here, so convert back def rec_list_to_tuple(x): if isinstance(x, list): return tuple( rec_list_to_tuple(i) for i in x ) else: return x rng_state_tuple = rec_list_to_tuple(rng_state_list) # changing the rng is safe for mp, as all players have to have the same map self.random.setstate( rng_state_tuple ) self.world = World(self) # Load horizons.world module (check horizons/world/__init__.py) self.world._init(savegame_db, force_player_id, disasters_enabled=disasters_enabled) self.view.load(savegame_db) # load view if not self.is_game_loaded(): # NOTE: this must be sorted before iteration, cause there is no defined order for # iterating a dict, and it must happen in the same order for mp games. for i in sorted(players, lambda p1, p2: cmp(p1['id'], p2['id'])): self.world.setup_player(i['id'], i['name'], i['color'], i['clientid'] if is_multiplayer else None, i['local'], i['ai'], i['difficulty']) self.world.set_forced_player(force_player_id) center = self.world.init_new_world(trader_enabled, pirate_enabled, natural_resource_multiplier) self.view.center(center[0], center[1]) else: # try to load scenario data self.scenario_eventhandler.load(savegame_db) self.manager.load(savegame_db) # load the manager (there might me old scheduled ticks). self.world.init_fish_indexer() # now the fish should exist if self.is_game_loaded(): LastActivePlayerSettlementManager().load(savegame_db) # before ingamegui self.ingame_gui.load(savegame_db) # load the old gui positions and stuff for instance_id in savegame_db("SELECT id FROM selected WHERE `group` IS NULL"): # Set old selected instance obj = WorldObject.get_object_by_id(instance_id[0]) self.selected_instances.add(obj) obj.get_component(SelectableComponent).select() for group in xrange(len(self.selection_groups)): # load user defined unit groups for instance_id in savegame_db("SELECT id FROM selected WHERE `group` = ?", group): self.selection_groups[group].add(WorldObject.get_object_by_id(instance_id[0])) # cursor has to be inited last, else player interacts with a not inited world with it. self.current_cursor = 'default' self.cursor = SelectionTool(self) # Set cursor correctly, menus might need to be opened. # Open menus later; they may need unit data not yet inited self.cursor.apply_select() Scheduler().before_ticking() savegame_db.close() assert hasattr(self.world, "player"), 'Error: there is no human player' """
def load(self, options): """Loads a map. Key method for starting a game.""" """ TUTORIAL: Here you see how the vital game elements (and some random things that are also required) are initialised. """ if options.is_scenario: # game_identifier is a yaml file, that contains reference to actual map file self.scenario_eventhandler = ScenarioEventHandler( self, options.game_identifier) # scenario maps can be normal maps or scenario maps: map_filename = self.scenario_eventhandler.get_map_file() options.game_identifier = os.path.join( SavegameManager.scenario_maps_dir, map_filename) if not os.path.exists(options.game_identifier): options.game_identifier = os.path.join( SavegameManager.maps_dir, map_filename) options.is_map = True self.log.debug("Session: Loading from %s", options.game_identifier) savegame_db = SavegameAccessor( options.game_identifier, options.is_map) # Initialize new dbreader savegame_data = SavegameManager.get_metadata(savegame_db.db_path) self.view.resize_layers(savegame_db) # load how often the game has been saved (used to know the difference between # a loaded and a new game) self.savecounter = savegame_data.get('savecounter', 0) if savegame_data.get('rng_state', None): rng_state_list = json.loads(savegame_data['rng_state']) # json treats tuples as lists, but we need tuples here, so convert back def rec_list_to_tuple(x): if isinstance(x, list): return tuple(rec_list_to_tuple(i) for i in x) else: return x rng_state_tuple = rec_list_to_tuple(rng_state_list) # changing the rng is safe for mp, as all players have to have the same map self.random.setstate(rng_state_tuple) self.world = World( self ) # Load horizons.world module (check horizons/world/__init__.py) self.world._init(savegame_db, options.force_player_id, disasters_enabled=options.disasters_enabled) self.view.load(savegame_db) # load view if not self.is_game_loaded(): options.init_new_world(self) else: # try to load scenario data self.scenario_eventhandler.load(savegame_db) self.manager.load( savegame_db ) # load the manager (there might me old scheduled ticks). self.world.init_fish_indexer() # now the fish should exist if self.is_game_loaded(): LastActivePlayerSettlementManager().load( savegame_db) # before ingamegui self.ingame_gui.load( savegame_db) # load the old gui positions and stuff for instance_id in savegame_db( "SELECT id FROM selected WHERE `group` IS NULL" ): # Set old selected instance obj = WorldObject.get_object_by_id(instance_id[0]) self.selected_instances.add(obj) obj.get_component(SelectableComponent).select() for group in xrange(len( self.selection_groups)): # load user defined unit groups for instance_id in savegame_db( "SELECT id FROM selected WHERE `group` = ?", group): self.selection_groups[group].add( WorldObject.get_object_by_id(instance_id[0])) # cursor has to be inited last, else player interacts with a not inited world with it. self.current_cursor = 'default' self.cursor = SelectionTool(self) # Set cursor correctly, menus might need to be opened. # Open menus later; they may need unit data not yet inited self.cursor.apply_select() Scheduler().before_ticking() savegame_db.close() assert hasattr(self.world, "player"), 'Error: there is no human player' """
def __update_game_details(self, game=None): """Set map name and other misc data in a widget. Only possible in certain states""" if game is None: game = self.__get_selected_game() if game is None: return #xgettext:python-format self.current.findChild( name="game_map").text = _("Map: {map_name}").format( map_name=game.get_map_name()) self.current.findChild( name="game_name").text = _("Name: {game_name}").format( game_name=game.get_name()) self.current.findChild( name="game_creator").text = _("Creator: {game_creator}").format( game_creator=game.get_creator()) #xgettext:python-format self.current.findChild(name="game_playersnum").text = _( "Players: {player_amount}/{player_limit}").format( player_amount=game.get_player_count(), player_limit=game.get_player_limit()) vbox_inner = self.current.findChild(name="game_info") if game.is_savegame( ): # work around limitations of current systems via messages path = SavegameManager.get_multiplayersave_map(game.mapname) btn_name = "save_missing_help_button" btn = vbox_inner.findChild(name=btn_name) if SavegameAccessor.get_hash(path) != game.get_map_hash(): text = "" if btn is None: btn = Button(name=btn_name) btn.text = _("This savegame is missing (click here)") last_elem = vbox_inner.findChild(name="game_info_last") if last_elem is None: # no last elem -> we are last vbox_inner.addChild(btn) else: vbox_inner.insertChildBefore(btn, last_elem) btn_text = _( u"For multiplayer load, it is necessary for you to have the correct savegame file." ) + u"\n" btn_text += _( u"The file will be downloaded when the game starts.") btn.btn_text = btn_text def show(): self.show_popup(_("Help"), btn_text, size=1) btn.capture(show) else: text = _(u"This is a savegame.") if btn is not None: btn.hide() if text: self.current.findChild(name="game_isloaded").text = text self.__update_players_box(game) vbox_inner.adaptLayout() # inner vbox always exists vbox = self.current.findChild(name="gamedetailsbox") if vbox is not None: vbox.adaptLayout()
def load(self, options): """Loads a map. Key method for starting a game.""" """ TUTORIAL: Here you see how the vital game elements (and some random things that are also required) are initialized. """ if options.is_scenario: # game_identifier is a yaml file, that contains reference to actual map file self.scenario_eventhandler = ScenarioEventHandler(self, options.game_identifier) # scenario maps can be normal maps or scenario maps: map_filename = self.scenario_eventhandler.get_map_file() options.game_identifier = os.path.join(SavegameManager.scenario_maps_dir, map_filename) if not os.path.exists(options.game_identifier): options.game_identifier = os.path.join(SavegameManager.maps_dir, map_filename) options.is_map = True self.log.debug("Session: Loading from %s", options.game_identifier) savegame_db = SavegameAccessor(options.game_identifier, options.is_map, options) # Initialize new dbreader savegame_data = SavegameManager.get_metadata(savegame_db.db_path) self.view.resize_layers(savegame_db) # load how often the game has been saved (used to know the difference between # a loaded and a new game) self.savecounter = savegame_data.get('savecounter', 0) if savegame_data.get('rng_state', None): rng_state_list = json.loads(savegame_data['rng_state']) # json treats tuples as lists, but we need tuples here, so convert back def rec_list_to_tuple(x): if isinstance(x, list): return tuple(rec_list_to_tuple(i) for i in x) else: return x rng_state_tuple = rec_list_to_tuple(rng_state_list) # changing the rng is safe for mp, as all players have to have the same map self.random.setstate(rng_state_tuple) LoadingProgress.broadcast(self, 'session_create_world') self.world = World(self) # Load horizons.world module (check horizons/world/__init__.py) self.world._init(savegame_db, options.force_player_id, disasters_enabled=options.disasters_enabled) self.view.load(savegame_db, self.world) # load view if not self.is_game_loaded(): options.init_new_world(self) else: # try to load scenario data self.scenario_eventhandler.load(savegame_db) self.manager.load(savegame_db) # load the manager (there might be old scheduled ticks). LoadingProgress.broadcast(self, "session_index_fish") self.world.init_fish_indexer() # now the fish should exist # load the old gui positions and stuff # Do this before loading selections, they need the minimap setup LoadingProgress.broadcast(self, "session_load_gui") self.ingame_gui = self._ingame_gui_class(self) self.ingame_gui.load(savegame_db) Scheduler().before_ticking() savegame_db.close() assert hasattr(self.world, "player"), 'Error: there is no human player' LoadingProgress.broadcast(self, "session_finish") """
def load(self, options): """Loads a map. Key method for starting a game.""" """ TUTORIAL: Here you see how the vital game elements (and some random things that are also required) are initialized. """ if options.is_scenario: # game_identifier is a yaml file, that contains reference to actual map file self.scenario_eventhandler = ScenarioEventHandler( self, options.game_identifier) # scenario maps can be normal maps or scenario maps: map_filename = self.scenario_eventhandler.get_map_file() options.game_identifier = os.path.join( SavegameManager.scenario_maps_dir, map_filename) if not os.path.exists(options.game_identifier): options.game_identifier = os.path.join( SavegameManager.maps_dir, map_filename) options.is_map = True self.log.debug("Session: Loading from %s", options.game_identifier) savegame_db = SavegameAccessor(options.game_identifier, options.is_map, options) # Initialize new dbreader savegame_data = SavegameManager.get_metadata(savegame_db.db_path) self.view.resize_layers(savegame_db) # load how often the game has been saved (used to know the difference between # a loaded and a new game) self.savecounter = savegame_data.get('savecounter', 0) if savegame_data.get('rng_state', None): rng_state_list = json.loads(savegame_data['rng_state']) # json treats tuples as lists, but we need tuples here, so convert back def rec_list_to_tuple(x): if isinstance(x, list): return tuple(rec_list_to_tuple(i) for i in x) else: return x rng_state_tuple = rec_list_to_tuple(rng_state_list) # changing the rng is safe for mp, as all players have to have the same map self.random.setstate(rng_state_tuple) LoadingProgress.broadcast(self, 'session_create_world') self.world = World( self ) # Load horizons.world module (check horizons/world/__init__.py) self.world._init(savegame_db, options.force_player_id, disasters_enabled=options.disasters_enabled) self.view.load(savegame_db, self.world) # load view if not self.is_game_loaded(): options.init_new_world(self) else: # try to load scenario data self.scenario_eventhandler.load(savegame_db) self.manager.load( savegame_db ) # load the manager (there might be old scheduled ticks). LoadingProgress.broadcast(self, "session_index_fish") self.world.init_fish_indexer() # now the fish should exist # load the old gui positions and stuff # Do this before loading selections, they need the minimap setup LoadingProgress.broadcast(self, "session_load_gui") self.ingame_gui = self._ingame_gui_class(self) self.ingame_gui.load(savegame_db) Scheduler().before_ticking() savegame_db.close() assert hasattr(self.world, "player"), 'Error: there is no human player' LoadingProgress.broadcast(self, "session_finish") """
def load(self, options): """Loads a map. Key method for starting a game.""" """ TUTORIAL: Here you see how the vital game elements (and some random things that are also required) are initialised. """ if options.is_scenario: # game_identifier is a yaml file, that contains reference to actual map file self.scenario_eventhandler = ScenarioEventHandler(self, options.game_identifier) # scenario maps can be normal maps or scenario maps: map_filename = self.scenario_eventhandler.get_map_file() options.game_identifier = os.path.join(SavegameManager.scenario_maps_dir, map_filename) if not os.path.exists(options.game_identifier): options.game_identifier = os.path.join(SavegameManager.maps_dir, map_filename) options.is_map = True self.log.debug("Session: Loading from %s", options.game_identifier) savegame_db = SavegameAccessor(options.game_identifier, options.is_map) # Initialize new dbreader savegame_data = SavegameManager.get_metadata(savegame_db.db_path) self.view.resize_layers(savegame_db) # load how often the game has been saved (used to know the difference between # a loaded and a new game) self.savecounter = savegame_data.get('savecounter', 0) if savegame_data.get('rng_state', None): rng_state_list = json.loads(savegame_data['rng_state']) # json treats tuples as lists, but we need tuples here, so convert back def rec_list_to_tuple(x): if isinstance(x, list): return tuple(rec_list_to_tuple(i) for i in x) else: return x rng_state_tuple = rec_list_to_tuple(rng_state_list) # changing the rng is safe for mp, as all players have to have the same map self.random.setstate(rng_state_tuple) self.world = World(self) # Load horizons.world module (check horizons/world/__init__.py) self.world._init(savegame_db, options.force_player_id, disasters_enabled=options.disasters_enabled) self.view.load(savegame_db) # load view if not self.is_game_loaded(): options.init_new_world(self) else: # try to load scenario data self.scenario_eventhandler.load(savegame_db) self.manager.load(savegame_db) # load the manager (there might me old scheduled ticks). self.world.init_fish_indexer() # now the fish should exist if self.is_game_loaded(): LastActivePlayerSettlementManager().load(savegame_db) # before ingamegui self.ingame_gui.load(savegame_db) # load the old gui positions and stuff for instance_id in savegame_db("SELECT id FROM selected WHERE `group` IS NULL"): # Set old selected instance obj = WorldObject.get_object_by_id(instance_id[0]) self.selected_instances.add(obj) obj.get_component(SelectableComponent).select() for group in xrange(len(self.selection_groups)): # load user defined unit groups for instance_id in savegame_db("SELECT id FROM selected WHERE `group` = ?", group): self.selection_groups[group].add(WorldObject.get_object_by_id(instance_id[0])) # cursor has to be inited last, else player interacts with a not inited world with it. self.current_cursor = 'default' self.cursor = SelectionTool(self) # Set cursor correctly, menus might need to be opened. # Open menus later; they may need unit data not yet inited self.cursor.apply_select() Scheduler().before_ticking() savegame_db.close() assert hasattr(self.world, "player"), 'Error: there is no human player' """