def convert_to_version(state, version): """Convert a savegame AIstate to the next version. :param dict state: savegame state, modified in function :param int version: Version to convert to """ debug("Trying to convert savegame state to version %d..." % version) current_version = state.get("version", -1) debug(" Current version: %d" % current_version) if current_version == version: raise ConversionError("Can't convert AI savegame to the same compatibility version.") if current_version > version: raise ConversionError("Can't convert AI savegame to an older compatibility version.") if version != current_version + 1: raise ConversionError("Can't skip a compatibility version when converting AI savegame.") # Starting with version 3, we switched from pickle to json-style encoding # Do not try to load an older savegame even if it magically passed the encoder. if version <= 3: raise ConversionError("The AI savegame version is no longer supported.") if version == 4: del state['qualifyingOutpostBaseTargets'] del state['qualifyingColonyBaseTargets'] state['orbital_colonization_manager'] = ColonisationAI.OrbitalColonizationManager() if version == 5: state['last_turn_played'] = 0 # state["some_new_member"] = some_default_value # del state["some_removed_member"] # state["list_changed_to_set"] = set(state["list_changed_to_set"]) debug(" All updates set. Setting new version number.") state["version"] = version
def __init__(self, aggression): # Do not allow to create AIstate instances with an invalid version number. if not hasattr(AIstate, 'version'): raise ConversionError("AIstate must have an integer version attribute for savegame compatibility") if not isinstance(AIstate.version, int): raise ConversionError("Version attribute of AIstate must be an integer!") if AIstate.version < 0: raise ConversionError("AIstate savegame compatibility version must be a positive integer!") # need to store the version explicitly as the class variable "version" is only stored in the # self.__class__.__dict__ while we only pickle the object (i.e. self.__dict__ ) self.version = AIstate.version # Debug info # unique id for game self.uid = self.generate_uid(first=True) # unique ids for turns. {turn: uid} self.turn_uids = {} # see AIstate docstring re importance of int cast for aggression self._aggression = int(aggression) # 'global' (?) variables self.colonisablePlanetIDs = odict() self.colonisableOutpostIDs = odict() # self.__aiMissionsByFleetID = {} self.__shipRoleByDesignID = {} self.__fleetRoleByID = {} self.diplomatic_logs = {} self.__priorityByType = {} # initialize home system knowledge universe = fo.getUniverse() empire = fo.getEmpire() self.empireID = empire.empireID homeworld = universe.getPlanet(empire.capitalID) self.__origin_home_system_id = homeworld.systemID if homeworld else INVALID_ID self.visBorderSystemIDs = {self.__origin_home_system_id} self.visInteriorSystemIDs = set() self.exploredSystemIDs = set() self.unexploredSystemIDs = {self.__origin_home_system_id} self.fleetStatus = {} # keys: 'sysID', 'nships', 'rating' # systemStatus keys: # 'name', 'neighbors' (sysIDs), '2jump_ring' (sysIDs), '3jump_ring', '4jump_ring', 'enemy_ship_count', # 'fleetThreat', 'planetThreat', 'monsterThreat' (specifically, immobile nonplanet threat), 'totalThreat', # 'localEnemyFleetIDs', 'neighborThreat', 'max_neighbor_threat', 'jump2_threat' (up to 2 jumps away), # 'jump3_threat', 'jump4_threat', 'regional_threat', 'myDefenses' (planet rating), 'myfleets', # 'myFleetsAccessible'(not just next desitination), 'myFleetRating', 'my_neighbor_rating' (up to 1 jump away), # 'my_jump2_rating', 'my_jump3_rating', my_jump4_rating', 'local_fleet_threats', # 'regional_fleet_threats' <== these are only for mobile fleet threats self.systemStatus = {} self.needsEmergencyExploration = [] self.newlySplitFleets = {} self.militaryRating = 0 self.shipCount = 4 self.misc = {} # Keys: "enemies_sighted" (dict[turn: list[fleetIDs]]), # "observed_empires" (set[enemy empire IDs]), # "ReassignedFleetMissions" (list[FleetMissions]) self.orbital_colonization_manager = ColonisationAI.OrbitalColonizationManager() self.qualifyingTroopBaseTargets = {} # TODO: track on a per-empire basis self.__empire_standard_enemy = CombatRatingsAI.default_ship_stats().get_stats(hashable=True) self.empire_standard_enemy_rating = 0 # TODO: track on a per-empire basis self.character = create_character(aggression, self.empireID) self.last_turn_played = 0