def __init__(self, dbfile): self.upgrader = SavegameUpgrader(dbfile) super(SavegameAccessor, self).__init__(dbfile=self.upgrader.get_path()) self._load_building() self._load_settlement() self._load_concrete_object() self._load_production() self._load_storage() self._load_storage_slot_limit() self._load_wildanimal() self._load_unit() self._load_building_collector() self._load_production_line() self._load_unit_path() self._load_component() self._load_storage_global_limit()
def __init__(self, game_identifier, is_map, options=None): is_random_map = False if is_map: self.upgrader = None handle, self._temp_path = tempfile.mkstemp() os.close(handle) super(SavegameAccessor, self).__init__(dbfile=self._temp_path) with open('content/savegame_template.sql') as savegame_template: self.execute_script(savegame_template.read()) if isinstance(game_identifier, list): is_random_map = True random_island_sequence = game_identifier else: self._map_path = game_identifier else: self.upgrader = SavegameUpgrader(game_identifier) self._temp_path = None game_identifier = self.upgrader.get_path() super(SavegameAccessor, self).__init__(dbfile=game_identifier) map_name_data = self('SELECT value FROM metadata WHERE name = ?', 'map_name') if not map_name_data: is_random_map = True random_island_sequence = self('SELECT value FROM metadata WHERE name = ?', 'random_island_sequence')[0][0].split(' ') else: map_name = map_name_data[0][0] if map_name.startswith('USER_MAPS_DIR:'): self._map_path = PATHS.USER_MAPS_DIR + map_name[len('USER_MAPS_DIR:'):] elif os.path.isabs(map_name): self._map_path = map_name else: self._map_path = SavegameManager.get_filename_from_map_name(map_name) if is_random_map: handle, self._temp_path2 = tempfile.mkstemp() os.close(handle) random_map_db = DbReader(self._temp_path2) with open('content/map-template.sql') as map_template: random_map_db.execute_script(map_template.read()) for island_id, island_string in enumerate(random_island_sequence): create_random_island(random_map_db, island_id, island_string) random_map_db.close() self._map_path = self._temp_path2 self('INSERT INTO metadata VALUES(?, ?)', 'random_island_sequence', ' '.join(random_island_sequence)) if options is not None: if options.map_padding is not None: self("INSERT INTO map_properties VALUES(?, ?)", 'padding', options.map_padding) self('ATTACH ? AS map_file', self._map_path) if is_random_map: self.map_name = random_island_sequence elif os.path.isabs(self._map_path): self.map_name = self._map_path else: self.map_name = SavegameManager.get_savegamename_from_filename(self._map_path) map_padding = self("SELECT value FROM map_properties WHERE name = 'padding'") self.map_padding = int(map_padding[0][0]) if map_padding else MAP.PADDING self._load_building() self._load_settlement() self._load_concrete_object() self._load_production() self._load_storage() self._load_wildanimal() self._load_unit() self._load_building_collector() self._load_production_line() self._load_unit_path() self._load_storage_global_limit() self._load_health() self._load_fish_data() self._hash = None
class SavegameAccessor(DbReader): """ SavegameAccessor is the class used for loading saved games. Frequent select queries are preloaded for faster access. """ def __init__(self, game_identifier, is_map, options=None): is_random_map = False if is_map: self.upgrader = None handle, self._temp_path = tempfile.mkstemp() os.close(handle) super(SavegameAccessor, self).__init__(dbfile=self._temp_path) with open('content/savegame_template.sql') as savegame_template: self.execute_script(savegame_template.read()) if isinstance(game_identifier, list): is_random_map = True random_island_sequence = game_identifier else: self._map_path = game_identifier else: self.upgrader = SavegameUpgrader(game_identifier) self._temp_path = None game_identifier = self.upgrader.get_path() super(SavegameAccessor, self).__init__(dbfile=game_identifier) map_name_data = self('SELECT value FROM metadata WHERE name = ?', 'map_name') if not map_name_data: is_random_map = True random_island_sequence = self('SELECT value FROM metadata WHERE name = ?', 'random_island_sequence')[0][0].split(' ') else: map_name = map_name_data[0][0] if map_name.startswith('USER_MAPS_DIR:'): self._map_path = PATHS.USER_MAPS_DIR + map_name[len('USER_MAPS_DIR:'):] elif os.path.isabs(map_name): self._map_path = map_name else: self._map_path = SavegameManager.get_filename_from_map_name(map_name) if is_random_map: handle, self._temp_path2 = tempfile.mkstemp() os.close(handle) random_map_db = DbReader(self._temp_path2) with open('content/map-template.sql') as map_template: random_map_db.execute_script(map_template.read()) for island_id, island_string in enumerate(random_island_sequence): create_random_island(random_map_db, island_id, island_string) random_map_db.close() self._map_path = self._temp_path2 self('INSERT INTO metadata VALUES(?, ?)', 'random_island_sequence', ' '.join(random_island_sequence)) if options is not None: if options.map_padding is not None: self("INSERT INTO map_properties VALUES(?, ?)", 'padding', options.map_padding) self('ATTACH ? AS map_file', self._map_path) if is_random_map: self.map_name = random_island_sequence elif os.path.isabs(self._map_path): self.map_name = self._map_path else: self.map_name = SavegameManager.get_savegamename_from_filename(self._map_path) map_padding = self("SELECT value FROM map_properties WHERE name = 'padding'") self.map_padding = int(map_padding[0][0]) if map_padding else MAP.PADDING self._load_building() self._load_settlement() self._load_concrete_object() self._load_production() self._load_storage() self._load_wildanimal() self._load_unit() self._load_building_collector() self._load_production_line() self._load_unit_path() self._load_storage_global_limit() self._load_health() self._load_fish_data() self._hash = None def close(self): super(SavegameAccessor, self).close() if self.upgrader is not None: self.upgrader.close() if self._temp_path is not None: os.unlink(self._temp_path) if hasattr(self, '_temp_path2'): os.unlink(self._temp_path2) def _load_building(self): self._building = {} for row in self("SELECT rowid, x, y, location, rotation, level FROM building"): self._building[int(row[0])] = row[1:] def get_building_row(self, worldid): """Returns (x, y, location, rotation, level)""" return self._building[int(worldid)] def get_building_location(self, worldid): return self._building[int(worldid)][2] def _load_settlement(self): self._settlement = {} for row in self("SELECT rowid, owner, island FROM settlement"): self._settlement[int(row[0])] = row[1:] def get_settlement_owner(self, worldid): """Returns the id of the owner of the settlement or None otherwise""" return self._settlement.get(int(worldid), [None])[0] def get_settlement_island(self, worldid): return self._settlement[int(worldid)][1] def _load_concrete_object(self): self._concrete_object = {} for row in self("SELECT id, action_runtime, action_set_id FROM concrete_object"): self._concrete_object[int(row[0])] = int(row[1]), row[2] def get_concrete_object_data(self, worldid): return self._concrete_object[int(worldid)] def _load_production(self): self._productions_by_worldid = {} self._production_lines_by_owner = {} self._productions_by_id_and_owner = {} db_data = self("SELECT rowid, state, owner, prod_line_id, remaining_ticks, _pause_old_state, creation_tick FROM production") for row in db_data: rowid = int(row[0]) data = row[1:] self._productions_by_worldid[rowid] = data owner = int(row[2]) line = int(row[3]) if not line in self._productions_by_id_and_owner: self._productions_by_id_and_owner[line] = {} # in the line dict, the owners are unique self._productions_by_id_and_owner[line][owner] = data if owner not in self._production_lines_by_owner: self._production_lines_by_owner[owner] = [line] else: self._production_lines_by_owner[owner].append(line) self._production_lines_by_owner[owner].append self._production_state_history = defaultdict(lambda: deque()) for object_id, production_id, tick, state in self("SELECT object_id, production, tick, state FROM production_state_history ORDER BY object_id, production, tick"): self._production_state_history[int(object_id), int(production_id)].append((tick, state)) def get_production_by_id_and_owner(self, id, ownerid): # owner means worldid of entity return self._productions_by_id_and_owner[id][ownerid] def get_production_line_id(self, production_worldid): """Returns the prod_line_id of the given production""" return self._productions_by_worldid[int(production_worldid)][2] def get_production_lines_by_owner(self, owner): """Returns the prod_line_id of the given production""" return self._production_lines_by_owner.get(owner, []) def get_production_state_history(self, worldid, prod_id): return self._production_state_history[int(worldid), int(prod_id)] def _load_storage(self): self._storage = {} for row in self("SELECT object, resource, amount FROM storage"): ownerid = int(row[0]) if ownerid in self._storage: self._storage[ownerid].append(row[1:]) else: self._storage[ownerid] = [row[1:]] def get_storage_rowids_by_ownerid(self, ownerid): """Returns potentially empty list of worldids referencing storages""" return self._storage.get(int(ownerid), []) def _load_wildanimal(self): self._wildanimal = {} for row in self("SELECT rowid, health, can_reproduce FROM wildanimal"): self._wildanimal[int(row[0])] = row[1:] def get_wildanimal_row(self, worldid): """Returns (health, can_reproduce)""" return self._wildanimal[int(worldid)] def _load_unit(self): self._unit = {} for row in self("SELECT rowid, owner FROM unit"): self._unit[int(row[0])] = int(row[1]) def get_unit_owner(self, worldid): return self._unit[int(worldid)] def _load_building_collector(self): self._building_collector = {} for row in self("SELECT rowid, home_building, creation_tick FROM building_collector"): self._building_collector[int(row[0])] = (int(row[1]) if row[1] is not None else None, row[2]) self._building_collector_job_history = defaultdict(lambda: deque()) for collector_id, tick, utilization in self("SELECT collector, tick, utilisation FROM building_collector_job_history ORDER BY collector, tick"): self._building_collector_job_history[int(collector_id)].append((tick, utilization)) def get_building_collectors_data(self, worldid): """Returns (id of the building collector's home or None otherwise, creation_tick)""" return self._building_collector.get(int(worldid)) def get_building_collector_job_history(self, worldid): return self._building_collector_job_history[int(worldid)] def _load_production_line(self): self._production_line = {} for row in self("SELECT for_worldid, type, res, amount FROM production_line"): id = int(row[0]) if id not in self._production_line: self._production_line[id] = [] self._production_line[id].append(row[1:]) def get_production_line_row(self, for_worldid): return self._production_line[int(for_worldid)] def _load_unit_path(self): self._unit_path = {} for row in self("SELECT unit, x, y FROM unit_path ORDER BY 'index'"): id = int(row[0]) if id not in self._unit_path: self._unit_path[id] = [] self._unit_path[id].append(row[1:]) def get_unit_path(self, worldid): return self._unit_path.get(int(worldid)) def _load_storage_global_limit(self): self._storage_global_limit = {} for row in self("SELECT object, value FROM storage_global_limit"): self._storage_global_limit[(int(row[0]))] = int(row[1]) def get_storage_global_limit(self, worldid): return self._storage_global_limit[int(worldid)] def _load_health(self): self._health = dict( self("SELECT owner_id, health FROM unit_health") ) def get_health(self, owner): return self._health[owner] def _load_fish_data(self): self._fish_data = {} for row in self("SELECT rowid, last_usage_tick FROM fish_data"): self._fish_data[int(row[0])] = int(row[1]) def get_last_fish_usage_tick(self, worldid): return self._fish_data[worldid] # Random savegamefile related utility that i didn't know where to put @classmethod def get_players_num(cls, savegamefile): """Return number of regular human and ai players""" return DbReader(savegamefile)("SELECT count(rowid) FROM player WHERE is_trader = 0 AND is_pirate = 0")[0][0] @classmethod def get_hash(cls, savegamefile): if not os.path.exists(savegamefile): return False fd = open(savegamefile, "rb") h = hashlib.sha1() h.update(fd.read()) filehash = h.hexdigest() fd.close() return filehash
def __init__(self, game_identifier, is_map, options=None): is_random_map = False if is_map: self.upgrader = None handle, self._temp_path = tempfile.mkstemp() os.close(handle) super().__init__(dbfile=self._temp_path) with open('content/savegame_template.sql') as savegame_template: self.execute_script(savegame_template.read()) if isinstance(game_identifier, list): is_random_map = True random_island_sequence = game_identifier else: self._map_path = game_identifier else: self.upgrader = SavegameUpgrader(game_identifier) self._temp_path = None game_identifier = self.upgrader.get_path() super().__init__(dbfile=game_identifier) map_name_data = self('SELECT value FROM metadata WHERE name = ?', 'map_name') if not map_name_data: is_random_map = True random_island_sequence = self( 'SELECT value FROM metadata WHERE name = ?', 'random_island_sequence')[0][0].split(' ') else: map_name = map_name_data[0][0] if map_name.startswith('USER_MAPS_DIR:'): self._map_path = PATHS.USER_MAPS_DIR + map_name[ len('USER_MAPS_DIR:'):] elif os.path.isabs(map_name): self._map_path = map_name else: self._map_path = SavegameManager.get_filename_from_map_name( map_name) if is_random_map: handle, self._temp_path2 = tempfile.mkstemp() os.close(handle) random_map_db = DbReader(self._temp_path2) with open('content/map-template.sql') as map_template: random_map_db.execute_script(map_template.read()) for island_id, island_string in enumerate(random_island_sequence): create_random_island(random_map_db, island_id, island_string) random_map_db.close() self._map_path = self._temp_path2 self('INSERT INTO metadata VALUES(?, ?)', 'random_island_sequence', ' '.join(random_island_sequence)) if options is not None: if options.map_padding is not None: self("INSERT INTO map_properties VALUES(?, ?)", 'padding', options.map_padding) if not os.path.exists(self._map_path): raise MapFileNotFound("Map file " + str(self._map_path) + " not found!") self('ATTACH ? AS map_file', self._map_path) if is_random_map: self.map_name = random_island_sequence elif os.path.isabs(self._map_path): self.map_name = self._map_path else: self.map_name = SavegameManager.get_savegamename_from_filename( self._map_path) map_padding = self( "SELECT value FROM map_properties WHERE name = 'padding'") self.map_padding = int( map_padding[0][0]) if map_padding else MAP.PADDING self._load_building() self._load_settlement() self._load_concrete_object() self._load_production() self._load_storage() self._load_wildanimal() self._load_unit() self._load_building_collector() self._load_production_line() self._load_unit_path() self._load_storage_global_limit() self._load_health() self._load_fish_data() self._hash = None
class SavegameAccessor(DbReader): """ SavegameAccessor is the class used for loading saved games. Frequent select queries are preloaded for faster access. """ def __init__(self, game_identifier, is_map, options=None): is_random_map = False if is_map: self.upgrader = None handle, self._temp_path = tempfile.mkstemp() os.close(handle) super().__init__(dbfile=self._temp_path) with open('content/savegame_template.sql') as savegame_template: self.execute_script(savegame_template.read()) if isinstance(game_identifier, list): is_random_map = True random_island_sequence = game_identifier else: self._map_path = game_identifier else: self.upgrader = SavegameUpgrader(game_identifier) self._temp_path = None game_identifier = self.upgrader.get_path() super().__init__(dbfile=game_identifier) map_name_data = self('SELECT value FROM metadata WHERE name = ?', 'map_name') if not map_name_data: is_random_map = True random_island_sequence = self( 'SELECT value FROM metadata WHERE name = ?', 'random_island_sequence')[0][0].split(' ') else: map_name = map_name_data[0][0] if map_name.startswith('USER_MAPS_DIR:'): self._map_path = PATHS.USER_MAPS_DIR + map_name[ len('USER_MAPS_DIR:'):] elif os.path.isabs(map_name): self._map_path = map_name else: self._map_path = SavegameManager.get_filename_from_map_name( map_name) if is_random_map: handle, self._temp_path2 = tempfile.mkstemp() os.close(handle) random_map_db = DbReader(self._temp_path2) with open('content/map-template.sql') as map_template: random_map_db.execute_script(map_template.read()) for island_id, island_string in enumerate(random_island_sequence): create_random_island(random_map_db, island_id, island_string) random_map_db.close() self._map_path = self._temp_path2 self('INSERT INTO metadata VALUES(?, ?)', 'random_island_sequence', ' '.join(random_island_sequence)) if options is not None: if options.map_padding is not None: self("INSERT INTO map_properties VALUES(?, ?)", 'padding', options.map_padding) if not os.path.exists(self._map_path): raise MapFileNotFound("Map file " + str(self._map_path) + " not found!") self('ATTACH ? AS map_file', self._map_path) if is_random_map: self.map_name = random_island_sequence elif os.path.isabs(self._map_path): self.map_name = self._map_path else: self.map_name = SavegameManager.get_savegamename_from_filename( self._map_path) map_padding = self( "SELECT value FROM map_properties WHERE name = 'padding'") self.map_padding = int( map_padding[0][0]) if map_padding else MAP.PADDING self._load_building() self._load_settlement() self._load_concrete_object() self._load_production() self._load_storage() self._load_wildanimal() self._load_unit() self._load_building_collector() self._load_production_line() self._load_unit_path() self._load_storage_global_limit() self._load_health() self._load_fish_data() self._hash = None def close(self): super().close() if self.upgrader is not None: self.upgrader.close() if self._temp_path is not None: os.unlink(self._temp_path) if hasattr(self, '_temp_path2'): os.unlink(self._temp_path2) def _load_building(self): self._building = {} for row in self( "SELECT rowid, x, y, location, rotation, level FROM building"): self._building[int(row[0])] = row[1:] def get_building_row(self, worldid): """Returns (x, y, location, rotation, level)""" return self._building[int(worldid)] def get_building_location(self, worldid): return self._building[int(worldid)][2] def _load_settlement(self): self._settlement = {} for row in self("SELECT rowid, owner, island FROM settlement"): self._settlement[int(row[0])] = row[1:] def get_settlement_owner(self, worldid): """Returns the id of the owner of the settlement or None otherwise""" return self._settlement.get(int(worldid), [None])[0] def get_settlement_island(self, worldid): return self._settlement[int(worldid)][1] def _load_concrete_object(self): self._concrete_object = {} for row in self( "SELECT id, action_runtime, action_set_id FROM concrete_object" ): self._concrete_object[int(row[0])] = int(row[1]), row[2] def get_concrete_object_data(self, worldid): return self._concrete_object[int(worldid)] def _load_production(self): self._productions_by_worldid = {} self._production_lines_by_owner = {} self._productions_by_id_and_owner = {} db_data = self( "SELECT rowid, state, owner, prod_line_id, remaining_ticks, _pause_old_state, creation_tick FROM production" ) for row in db_data: rowid = int(row[0]) data = row[1:] self._productions_by_worldid[rowid] = data owner = int(row[2]) line = int(row[3]) if line not in self._productions_by_id_and_owner: self._productions_by_id_and_owner[line] = {} # in the line dict, the owners are unique self._productions_by_id_and_owner[line][owner] = data if owner not in self._production_lines_by_owner: self._production_lines_by_owner[owner] = [line] else: self._production_lines_by_owner[owner].append(line) self._production_lines_by_owner[owner].append self._production_state_history = defaultdict(deque) for object_id, production_id, tick, state in self( "SELECT object_id, production, tick, state FROM production_state_history ORDER BY object_id, production, tick" ): self._production_state_history[int(object_id), int(production_id)].append( (tick, state)) def get_production_by_id_and_owner(self, id, ownerid): # owner means worldid of entity return self._productions_by_id_and_owner[id][ownerid] def get_production_line_id(self, production_worldid): """Returns the prod_line_id of the given production""" return self._productions_by_worldid[int(production_worldid)][2] def get_production_lines_by_owner(self, owner): """Returns the prod_line_id of the given production""" return self._production_lines_by_owner.get(owner, []) def get_production_state_history(self, worldid, prod_id): return self._production_state_history[int(worldid), int(prod_id)] def _load_storage(self): self._storage = {} for row in self("SELECT object, resource, amount FROM storage"): ownerid = int(row[0]) if ownerid in self._storage: self._storage[ownerid].append(row[1:]) else: self._storage[ownerid] = [row[1:]] def get_storage_rowids_by_ownerid(self, ownerid): """Returns potentially empty list of worldids referencing storages""" return self._storage.get(int(ownerid), []) def _load_wildanimal(self): self._wildanimal = {} for row in self("SELECT rowid, health, can_reproduce FROM wildanimal"): self._wildanimal[int(row[0])] = row[1:] def get_wildanimal_row(self, worldid): """Returns (health, can_reproduce)""" return self._wildanimal[int(worldid)] def _load_unit(self): self._unit = {} for row in self("SELECT rowid, owner FROM unit"): self._unit[int(row[0])] = int(row[1]) def get_unit_owner(self, worldid): return self._unit[int(worldid)] def _load_building_collector(self): self._building_collector = {} for row in self( "SELECT rowid, home_building, creation_tick FROM building_collector" ): self._building_collector[int( row[0])] = (int(row[1]) if row[1] is not None else None, row[2]) self._building_collector_job_history = defaultdict(deque) for collector_id, tick, utilization in self( "SELECT collector, tick, utilisation FROM building_collector_job_history ORDER BY collector, tick" ): self._building_collector_job_history[int(collector_id)].append( (tick, utilization)) def get_building_collectors_data(self, worldid): """Returns (id of the building collector's home or None otherwise, creation_tick)""" return self._building_collector.get(int(worldid)) def get_building_collector_job_history(self, worldid): return self._building_collector_job_history[int(worldid)] def _load_production_line(self): self._production_line = {} for row in self( "SELECT for_worldid, type, res, amount FROM production_line"): id = int(row[0]) if id not in self._production_line: self._production_line[id] = [] self._production_line[id].append(row[1:]) def get_production_line_row(self, for_worldid): return self._production_line[int(for_worldid)] def _load_unit_path(self): self._unit_path = {} for row in self("SELECT unit, x, y FROM unit_path ORDER BY 'index'"): id = int(row[0]) if id not in self._unit_path: self._unit_path[id] = [] self._unit_path[id].append(row[1:]) def get_unit_path(self, worldid): return self._unit_path.get(int(worldid)) def _load_storage_global_limit(self): self._storage_global_limit = {} for row in self("SELECT object, value FROM storage_global_limit"): self._storage_global_limit[(int(row[0]))] = int(row[1]) def get_storage_global_limit(self, worldid): return self._storage_global_limit[int(worldid)] def _load_health(self): self._health = dict(self("SELECT owner_id, health FROM unit_health")) def get_health(self, owner): return self._health[owner] def _load_fish_data(self): self._fish_data = {} for row in self("SELECT rowid, last_usage_tick FROM fish_data"): self._fish_data[int(row[0])] = int(row[1]) def get_last_fish_usage_tick(self, worldid): return self._fish_data[worldid] # Random savegamefile related utility that i didn't know where to put @classmethod def get_players_num(cls, savegamefile): """Return number of regular human and ai players""" return DbReader( savegamefile )("SELECT count(rowid) FROM player WHERE is_trader = 0 AND is_pirate = 0" )[0][0] @classmethod def get_hash(cls, savegamefile): if not os.path.exists(savegamefile): return False with open(savegamefile, "rb") as f: h = hashlib.sha1() h.update(f.read()) filehash = h.hexdigest() return filehash
def tmp_show_details(): """Fetches details of selected savegame and displays it""" gui.findChild(name="screenshot").image = None map_file = None map_file_index = gui.collectData(savegamelist) savegame_details_box = gui.findChild(name="savegame_details") savegame_details_parent = savegame_details_box.parent if map_file_index == -1: if savegame_details_box not in savegame_details_parent.hidden_children: savegame_details_parent.hideChild(savegame_details_box) return else: savegame_details_parent.showChild(savegame_details_box) try: map_file = map_files[map_file_index] except IndexError: # this was a click in the savegame list, but not on an element # it happens when the savegame list is empty return savegame_info = SavegameManager.get_metadata(map_file) if savegame_info.get('screenshot'): # try to find a writable location, that is accessible via relative paths # (required by fife) fd, filename = tempfile.mkstemp() try: path_rel = os.path.relpath(filename) except ValueError: # the relative path sometimes doesn't exist on win os.close(fd) os.unlink(filename) # try again in the current dir, it's often writable fd, filename = tempfile.mkstemp(dir=os.curdir) try: path_rel = os.path.relpath(filename) except ValueError: fd, filename = None, None if fd: with os.fdopen(fd, "w") as f: f.write(savegame_info['screenshot']) # fife only supports relative paths gui.findChild(name="screenshot").image = path_rel os.unlink(filename) # savegamedetails details_label = gui.findChild(name="savegamedetails_lbl") details_label.text = u"" if savegame_info['timestamp'] == -1: details_label.text += _("Unknown savedate") else: savetime = time.strftime("%c", time.localtime(savegame_info['timestamp'])) #xgettext:python-format details_label.text += _("Saved at {time}").format(time=savetime.decode('utf-8')) details_label.text += u'\n' counter = savegame_info['savecounter'] # N_ takes care of plural forms for different languages #xgettext:python-format details_label.text += N_("Saved {amount} time", "Saved {amount} times", counter).format(amount=counter) details_label.text += u'\n' from horizons.constants import VERSION try: #xgettext:python-format details_label.text += _("Savegame version {version}").format( version=savegame_info['savegamerev']) if savegame_info['savegamerev'] != VERSION.SAVEGAMEREVISION: if not SavegameUpgrader.can_upgrade(savegame_info['savegamerev']): details_label.text += u" " + _("(probably incompatible)") except KeyError: # this should only happen for very old savegames, so having this unfriendly # error is ok (savegame is quite certainly fully unusable). details_label.text += u" " + _("Incompatible version") gui.adaptLayout()
def tmp_show_details(): """Fetches details of selected savegame and displays it""" gui.findChild(name="screenshot").image = None map_file = None map_file_index = gui.collectData(savegamelist) savegame_details_box = gui.findChild(name="savegame_details") savegame_details_parent = savegame_details_box.parent if map_file_index == -1: if (Fife.getVersion() >= (0, 4, 0)): savegame_details_parent.hideChild(savegame_details_box) else: if savegame_details_box not in savegame_details_parent.hidden_children: savegame_details_parent.hideChild(savegame_details_box) return else: savegame_details_parent.showChild(savegame_details_box) try: map_file = map_files[map_file_index] except IndexError: # this was a click in the savegame list, but not on an element # it happens when the savegame list is empty return savegame_info = SavegameManager.get_metadata(map_file) if savegame_info.get('screenshot'): # try to find a writable location, that is accessible via relative paths # (required by fife) fd, filename = tempfile.mkstemp() try: path_rel = os.path.relpath(filename) except ValueError: # the relative path sometimes doesn't exist on win os.close(fd) os.unlink(filename) # try again in the current dir, it's often writable fd, filename = tempfile.mkstemp(dir=os.curdir) try: path_rel = os.path.relpath(filename) except ValueError: fd, filename = None, None if fd: with os.fdopen(fd, "w") as f: f.write(savegame_info['screenshot']) # fife only supports relative paths gui.findChild(name="screenshot").image = path_rel os.unlink(filename) # savegamedetails details_label = gui.findChild(name="savegamedetails_lbl") details_label.text = u"" if savegame_info['timestamp'] == -1: details_label.text += T("Unknown savedate") else: savetime = time.strftime( "%c", time.localtime(savegame_info['timestamp'])) details_label.text += T("Saved at {time}").format( time=savetime.decode('utf-8')) details_label.text += u'\n' counter = savegame_info['savecounter'] # NT takes care of plural forms for different languages details_label.text += NT("Saved {amount} time", "Saved {amount} times", counter).format(amount=counter) details_label.text += u'\n' from horizons.constants import VERSION try: details_label.text += T("Savegame version {version}").format( version=savegame_info['savegamerev']) if savegame_info['savegamerev'] != VERSION.SAVEGAMEREVISION: if not SavegameUpgrader.can_upgrade( savegame_info['savegamerev']): details_label.text += u" " + T( "(probably incompatible)") except KeyError: # this should only happen for very old savegames, so having this unfriendly # error is ok (savegame is quite certainly fully unusable). details_label.text += u" " + T("Incompatible version") gui.adaptLayout()
class SavegameAccessor(DbReader): """ SavegameAccessor is the class used for loading saved games. Frequent select queries are preloaded for faster access. """ def __init__(self, dbfile): self.upgrader = SavegameUpgrader(dbfile) dbfile = self.upgrader.get_path() super(SavegameAccessor, self).__init__(dbfile=dbfile) self._load_building() self._load_settlement() self._load_concrete_object() self._load_production() self._load_storage() self._load_wildanimal() self._load_unit() self._load_building_collector() self._load_production_line() self._load_unit_path() self._load_storage_global_limit() self._load_health() self._hash = None def close(self): super(SavegameAccessor, self).close() self.upgrader.close() def _load_building(self): self._building = {} for row in self("SELECT rowid, x, y, location, rotation, level FROM building"): self._building[int(row[0])] = row[1:] def get_building_row(self, worldid): """Returns (x, y, location, rotation, level)""" return self._building[int(worldid)] def get_building_location(self, worldid): return self._building[int(worldid)][2] def _load_settlement(self): self._settlement = {} for row in self("SELECT rowid, owner, island FROM settlement"): self._settlement[int(row[0])] = row[1:] def get_settlement_owner(self, worldid): """Returns the id of the owner of the settlement or None otherwise""" return self._settlement.get(int(worldid), [None])[0] def get_settlement_island(self, worldid): return self._settlement[int(worldid)][1] def _load_concrete_object(self): self._concrete_object = {} for row in self("SELECT id, action_runtime, action_set_id FROM concrete_object"): self._concrete_object[int(row[0])] = int(row[1]), row[2] def get_concrete_object_data(self, worldid): return self._concrete_object[int(worldid)] def _load_production(self): self._productions_by_worldid = {} self._production_lines_by_owner = {} self._productions_by_id_and_owner = {} db_data = self("SELECT rowid, state, owner, prod_line_id, remaining_ticks, _pause_old_state, creation_tick FROM production") for row in db_data: rowid = int(row[0]) data = row[1:] self._productions_by_worldid[rowid] = data owner = int(row[2]) line = int(row[3]) if not line in self._productions_by_id_and_owner: self._productions_by_id_and_owner[line] = {} # in the line dict, the owners are unique self._productions_by_id_and_owner[line][owner] = data if owner not in self._production_lines_by_owner: self._production_lines_by_owner[owner] = [line] else: self._production_lines_by_owner[owner].append(line) self._production_lines_by_owner[owner].append self._production_state_history = defaultdict(lambda: deque()) for object_id, production_id, tick, state in self("SELECT object_id, production, tick, state FROM production_state_history ORDER BY object_id, production, tick"): self._production_state_history[int(object_id), int(production_id)].append((tick, state)) def get_production_by_id_and_owner(self, id, ownerid): # owner means worldid of entity return self._productions_by_id_and_owner[id][ownerid] def get_production_line_id(self, production_worldid): """Returns the prod_line_id of the given production""" return self._productions_by_worldid[int(production_worldid)][2] def get_production_lines_by_owner(self, owner): """Returns the prod_line_id of the given production""" return self._production_lines_by_owner.get(owner, []) def get_production_state_history(self, worldid, prod_id): return self._production_state_history[int(worldid), int(prod_id)] def _load_storage(self): self._storage = {} for row in self("SELECT object, resource, amount FROM storage"): ownerid = int(row[0]) if ownerid in self._storage: self._storage[ownerid].append(row[1:]) else: self._storage[ownerid] = [row[1:]] def get_storage_rowids_by_ownerid(self, ownerid): """Returns potentially empty list of worldids referencing storages""" return self._storage.get(int(ownerid), []) def _load_wildanimal(self): self._wildanimal = {} for row in self("SELECT rowid, health, can_reproduce FROM wildanimal"): self._wildanimal[int(row[0])] = row[1:] def get_wildanimal_row(self, worldid): """Returns (health, can_reproduce)""" return self._wildanimal[int(worldid)] def _load_unit(self): self._unit = {} for row in self("SELECT rowid, owner FROM unit"): self._unit[int(row[0])] = int(row[1]) def get_unit_owner(self, worldid): return self._unit[int(worldid)] def _load_building_collector(self): self._building_collector = {} for row in self("SELECT rowid, home_building, creation_tick FROM building_collector"): self._building_collector[int(row[0])] = (int(row[1]) if row[1] is not None else None, row[2]) self._building_collector_job_history = defaultdict(lambda: deque()) for collector_id, tick, utilisation in self("SELECT collector, tick, utilisation FROM building_collector_job_history ORDER BY collector, tick"): self._building_collector_job_history[int(collector_id)].append((tick, utilisation)) def get_building_collectors_data(self, worldid): """Returns (id of the building collector's home or None otherwise, creation_tick)""" return self._building_collector.get(int(worldid)) def get_building_collector_job_history(self, worldid): return self._building_collector_job_history[int(worldid)] def _load_production_line(self): self._production_line = {} for row in self("SELECT for_worldid, type, res, amount FROM production_line"): id = int(row[0]) if id not in self._production_line: self._production_line[id] = [] self._production_line[id].append(row[1:]) def get_production_line_row(self, for_worldid): return self._production_line[int(for_worldid)] def _load_unit_path(self): self._unit_path = {} for row in self("SELECT unit, x, y FROM unit_path ORDER BY 'index'"): id = int(row[0]) if id not in self._unit_path: self._unit_path[id] = [] self._unit_path[id].append(row[1:]) def get_unit_path(self, worldid): return self._unit_path.get(int(worldid)) def _load_storage_global_limit(self): self._storage_global_limit = {} for row in self("SELECT object, value FROM storage_global_limit"): self._storage_global_limit[(int(row[0]))] = int(row[1]) def get_storage_global_limit(self, worldid): return self._storage_global_limit[int(worldid)] def _load_health(self): self._health = dict( self("SELECT owner_id, health FROM unit_health") ) def get_health(self, owner): return self._health[owner] # Random savegamefile related utility that i didn't know where to put @classmethod def get_players_num(cls, savegamefile): """Return number of regular human and ai players""" return DbReader(savegamefile)("SELECT count(rowid) FROM player WHERE is_trader = 0 AND is_pirate = 0")[0][0] @classmethod def get_hash(cls, savegamefile): if not os.path.exists(savegamefile): return False fd = open(savegamefile, "rb") h = hashlib.sha1() h.update(fd.read()) filehash = h.hexdigest() fd.close() return filehash
class SavegameAccessor(DbReader): """ SavegameAccessor is the class used for loading saved games. Frequent select queries are preloaded for faster access. """ def __init__(self, dbfile): self.upgrader = SavegameUpgrader(dbfile) super(SavegameAccessor, self).__init__(dbfile=self.upgrader.get_path()) self._load_building() self._load_settlement() self._load_concrete_object() self._load_production() self._load_storage() self._load_storage_slot_limit() self._load_wildanimal() self._load_unit() self._load_building_collector() self._load_production_line() self._load_unit_path() self._load_component() self._load_storage_global_limit() def close(self): super(SavegameAccessor, self).close() self.upgrader.close() def _load_building(self): self._building = {} for row in self("SELECT rowid, x, y, location, rotation, level FROM building"): self._building[int(row[0])] = row[1:] def get_building_row(self, worldid): """Returns (x, y, location, rotation, level)""" return self._building[int(worldid)] def get_building_location(self, worldid): return self._building[int(worldid)][2] def _load_settlement(self): self._settlement = {} for row in self("SELECT rowid, owner, island FROM settlement"): self._settlement[int(row[0])] = row[1:] def get_settlement_owner(self, worldid): """Returns the id of the owner of the settlement or None otherwise""" worldid = int(worldid) return None if worldid not in self._settlement else self._settlement[worldid][0] def get_settlement_island(self, worldid): return self._settlement[int(worldid)][1] def _load_concrete_object(self): self._concrete_object = {} for row in self("SELECT id, action_runtime FROM concrete_object"): self._concrete_object[int(row[0])] = int(row[1]) def get_concrete_object_action_runtime(self, worldid): return self._concrete_object[int(worldid)] def _load_production(self): self._production = {} self._productions_by_id_and_owner = {} db_data = self("SELECT rowid, state, owner, prod_line_id, remaining_ticks, _pause_old_state, creation_tick FROM production") for row in db_data: rowid = int(row[0]) data = row[1:] self._production[rowid] = data owner = int(row[2]) line = int(row[3]) if not line in self._productions_by_id_and_owner: self._productions_by_id_and_owner[line] = {} # in the line dict, the owners are unique self._productions_by_id_and_owner[line][owner] = data self._production_state_history = defaultdict(lambda: deque()) for production_id, tick, state in self("SELECT production, tick, state FROM production_state_history ORDER BY production, tick"): self._production_state_history[int(production_id)].append((tick, state)) def get_production_by_id_and_owner(self, id, ownerid): # owner means worldid of entity return self._productions_by_id_and_owner[id][ownerid] def get_production_line_id(self, production_worldid): """Returns the prod_line_id of the given production""" return self._production[int(production_worldid)][2] def get_production_state_history(self, worldid): return self._production_state_history[int(worldid)] def _load_storage(self): self._storage = {} for row in self("SELECT object, resource, amount FROM storage"): ownerid = int(row[0]) if ownerid in self._storage: self._storage[ownerid].append(row[1:]) else: self._storage[ownerid] = [row[1:]] def get_storage_rowids_by_ownerid(self, ownerid): """Returns potentially empty list of worldids referencing storages""" ownerid = int(ownerid) return [] if ownerid not in self._storage else self._storage[ownerid] def _load_storage_slot_limit(self): self._storage_slot_limit = {} for row in self("SELECT object, slot, value FROM storage_slot_limit"): key = (int(row[0]), int(row[1])) self._storage_slot_limit[key] = int(row[2]) def get_storage_slot_limit(self, ownerid, slot): return self._storage_slot_limit[(int(ownerid), int(slot))] def _load_wildanimal(self): self._wildanimal = {} for row in self("SELECT rowid, health, can_reproduce FROM wildanimal"): self._wildanimal[int(row[0])] = row[1:] def get_wildanimal_row(self, worldid): """Returns (health, can_reproduce)""" return self._wildanimal[int(worldid)] def _load_unit(self): self._unit = {} for row in self("SELECT rowid, owner FROM unit"): self._unit[int(row[0])] = int(row[1]) def get_unit_owner(self, worldid): return self._unit[int(worldid)] def _load_building_collector(self): self._building_collector = {} for row in self("SELECT rowid, home_building, creation_tick FROM building_collector"): self._building_collector[int(row[0])] = (int(row[1]) if row[1] is not None else None, row[2]) self._building_collector_job_history = defaultdict(lambda: deque()) for collector_id, tick, utilisation in self("SELECT collector, tick, utilisation FROM building_collector_job_history ORDER BY collector, tick"): self._building_collector_job_history[int(collector_id)].append((tick, utilisation)) def get_building_collectors_data(self, worldid): """Returns (id of the building collector's home or None otherwise, creation_tick)""" worldid = int(worldid) return None if worldid not in self._building_collector else self._building_collector[worldid] def get_building_collector_job_history(self, worldid): return self._building_collector_job_history[int(worldid)] def _load_production_line(self): self._production_line = {} for row in self("SELECT for_worldid, type, res, amount FROM production_line"): id = int(row[0]) if id not in self._production_line: self._production_line[id] = [] self._production_line[id].append(row[1:]) def get_production_line_row(self, for_worldid): return self._production_line[int(for_worldid)] def _load_unit_path(self): self._unit_path = {} for row in self("SELECT unit, x, y FROM unit_path ORDER BY 'index'"): id = int(row[0]) if id not in self._unit_path: self._unit_path[id] = [] self._unit_path[id].append(row[1:]) def get_unit_path(self, worldid): worldid = int(worldid) return self._unit_path[worldid] if worldid in self._unit_path else None def _load_component(self): self._component = {} for row in self("SELECT worldid, name, module, class FROM component"): id = int(row[0]) if id not in self._component: self._component[id] = [] self._component[id].append(row[1:]) def get_component_row(self, worldid): worldid = int(worldid) return self._component[worldid] if worldid in self._component else [] def _load_storage_global_limit(self): self._storage_global_limit = {} for row in self("SELECT object, value FROM storage_global_limit"): self._storage_global_limit[(int(row[0]))] = int(row[1]) def get_storage_global_limit(self, worldid): return self._storage_global_limit[int(worldid)]
def __init__(self, game_identifier, is_map): is_random_map = False if is_map: self.upgrader = None handle, self._temp_path = tempfile.mkstemp() os.close(handle) super(SavegameAccessor, self).__init__(dbfile=self._temp_path) with open("content/savegame_template.sql") as savegame_template: self.execute_script(savegame_template.read()) if isinstance(game_identifier, list): is_random_map = True random_island_sequence = game_identifier else: self._map_path = game_identifier else: self.upgrader = SavegameUpgrader(game_identifier) self._temp_path = None game_identifier = self.upgrader.get_path() super(SavegameAccessor, self).__init__(dbfile=game_identifier) map_name_data = self("SELECT value FROM metadata WHERE name = ?", "map_name") if not map_name_data: is_random_map = True random_island_sequence = self("SELECT value FROM metadata WHERE name = ?", "random_island_sequence")[0][ 0 ].split(" ") else: map_name = map_name_data[0][0] if os.path.isabs(map_name): self._map_path = map_name else: self._map_path = SavegameManager.get_filename_from_map_name(map_name) if is_random_map: handle, self._temp_path2 = tempfile.mkstemp() os.close(handle) random_map_db = DbReader(self._temp_path2) with open("content/map-template.sql") as map_template: random_map_db.execute_script(map_template.read()) for island_id, island_string in enumerate(random_island_sequence): create_random_island(random_map_db, island_id, island_string) random_map_db.close() self._map_path = self._temp_path2 self("INSERT INTO metadata VALUES(?, ?)", "random_island_sequence", " ".join(random_island_sequence)) self("ATTACH ? AS map_file", self._map_path) if is_random_map: self.map_name = random_island_sequence elif os.path.isabs(self._map_path): self.map_name = self._map_path else: self.map_name = SavegameManager.get_savegamename_from_filename(self._map_path) self._load_building() self._load_settlement() self._load_concrete_object() self._load_production() self._load_storage() self._load_wildanimal() self._load_unit() self._load_building_collector() self._load_production_line() self._load_unit_path() self._load_storage_global_limit() self._load_health() self._load_fish_data() self._hash = None
def __init__(self, game_identifier, is_map): is_random_map = False if is_map: self.upgrader = None handle, self._temp_path = tempfile.mkstemp() os.close(handle) super(SavegameAccessor, self).__init__(dbfile=self._temp_path) with open('content/savegame_template.sql') as savegame_template: self.execute_script(savegame_template.read()) if isinstance(game_identifier, list): is_random_map = True random_island_sequence = game_identifier else: self._map_path = game_identifier else: self.upgrader = SavegameUpgrader(game_identifier) self._temp_path = None game_identifier = self.upgrader.get_path() super(SavegameAccessor, self).__init__(dbfile=game_identifier) map_name_data = self('SELECT value FROM metadata WHERE name = ?', 'map_name') if not map_name_data: is_random_map = True random_island_sequence = self( 'SELECT value FROM metadata WHERE name = ?', 'random_island_sequence')[0][0].split(' ') else: map_name = map_name_data[0][0] if os.path.isabs(map_name): self._map_path = map_name else: self._map_path = SavegameManager.get_filename_from_map_name( map_name) if is_random_map: handle, self._temp_path2 = tempfile.mkstemp() os.close(handle) random_map_db = DbReader(self._temp_path2) with open('content/map-template.sql') as map_template: random_map_db.execute_script(map_template.read()) for island_id, island_string in enumerate(random_island_sequence): create_random_island(random_map_db, island_id, island_string) random_map_db.close() self._map_path = self._temp_path2 self('INSERT INTO metadata VALUES(?, ?)', 'random_island_sequence', ' '.join(random_island_sequence)) self('ATTACH ? AS map_file', self._map_path) if is_random_map: self.map_name = random_island_sequence elif os.path.isabs(self._map_path): self.map_name = self._map_path else: self.map_name = SavegameManager.get_savegamename_from_filename( self._map_path) self._load_building() self._load_settlement() self._load_concrete_object() self._load_production() self._load_storage() self._load_wildanimal() self._load_unit() self._load_building_collector() self._load_production_line() self._load_unit_path() self._load_storage_global_limit() self._load_health() self._load_fish_data() self._hash = None