def __init__(self, config_file='config/igm_config.v7.ini', user_config_file=[ 'config/user_igm_config.v7.ini', 'config/user_igm_config.v6.ini' ]): self.config = cp.ConfigParser() self.fallback_config = cp.ConfigParser() self.fallback_config.read(utils2to3.abspathmaker( __file__, config_file)) user_cfg_path = utils2to3.abspathmaker(__file__, user_config_file[0]) if os.path.exists(user_cfg_path): EDRLog().log( u"Using user defined layout at {}.".format( user_config_file[0]), "INFO") self.config.read(user_cfg_path) else: EDRLog().log( u"No user defined layout at {}, using {} instead.".format( user_config_file[0], user_config_file[1]), "INFO") user_cfg_path = utils2to3.abspathmaker(__file__, user_config_file[1]) if os.path.exists(user_cfg_path): EDRLog().log( u"Using user defined layout at {}.".format( user_config_file[1]), "INFO") self.config.read(user_cfg_path) else: EDRLog().log( u"No user defined layout at {} or {}, using {} instead.". format(user_config_file[0], user_config_file[1], config_file), "INFO") self.config = self.fallback_config
def loud(self): self.snd_warn = NSSound.alloc( ).initWithContentsOfFile_byReference_( utils2to3.abspathmaker(__file__, 'sounds', 'snd_warn.wav'), False) self.snd_notify = NSSound.alloc( ).initWithContentsOfFile_byReference_( utils2to3.abspathmaker(__file__, 'sounds', 'snd_notify.wav'), False)
def __init__(self, tips_file=None): global DEFAULT_TIPS if tips_file: self.tips = json.loads( open(utils2to3.abspathmaker(__file__, tips_file)).read()) else: self.tips = DEFAULT_TIPS
def __init__(self): path = utils2to3.abspathmaker(__file__, 'db', 'rawdepletables') try: self.db = sqlite3.connect(path) cursor = self.db.cursor() cursor.execute('''CREATE TABLE IF NOT EXISTS hotspots(id INTEGER PRIMARY KEY, name TEXT, planet TEXT, gravity REAL, distance_to_arrival INTEGER, type TEXT, confirmed INTEGER DEFAULT 0, last_visit INTEGER DEFAULT 0) ''') cursor.execute('''CREATE TABLE IF NOT EXISTS concentrations(id INTEGER PRIMARY KEY, hotspotid INTEGER SECONDARY KEY, resource TEXT, concentration REAL) ''') for hotspot in EDRRawDepletables.HOTSPOTS: check = cursor.execute( "SELECT name, planet from hotspots where name=? and planet=?", (hotspot[0:2])) test = check.fetchone() if not test: cursor.execute( 'insert into hotspots(name, planet, gravity, distance_to_arrival, type, confirmed) values (?,?,?,?,?,?)', hotspot) for concentration in EDRRawDepletables.CONCENTRATIONS: check = cursor.execute( "SELECT hotspotid from concentrations where hotspotid=?", (concentration[0:1])) if not check.fetchone(): cursor.execute( 'insert into concentrations(hotspotid, resource, concentration) values (?,?,?)', concentration) self.db.commit() except: EDRLOG.log(u"Couldn't open/create the depletables database", "ERROR") self.db = None
class EDRLandables(object): MAPS = json.loads( open(utils2to3.abspathmaker(__file__, 'data', 'landable-maps.json')).read()) @staticmethod def map_for(star_system, location_name, location_type): if not star_system or star_system.lower() not in EDRLandables.MAPS: star_system = "*" c_star_system = star_system.lower() c_location_name = location_name.lower() c_location_type = location_type.lower() locations = EDRLandables.MAPS.get(c_star_system, {}) if c_location_name not in locations: c_location_name = "*" landables = locations.get(c_location_name, {}) the_map = landables.get(c_location_type, {}) if not the_map: locations = EDRLandables.MAPS.get("*", {}) landables = locations.get("*", {}) the_map = landables.get(c_location_type, landables.get("soon tm", {})) return the_map
def __init__(self): path = utils2to3.abspathmaker(__file__, 'db', 'fleet') try: self.db = sqlite3.connect(path) cursor = self.db.cursor() cursor.execute('''CREATE TABLE IF NOT EXISTS ships(id INTEGER PRIMARY KEY, type TEXT, localised TEXT, name TEXT, star_system TEXT, ship_market_id INTEGER, value INTEGER, hot INTEGER, piloted INTEGER DEFAULT 0, eta INTEGER DEFAULT 0)''' ) cursor.execute('''CREATE TABLE IF NOT EXISTS transits(id INTEGER PRIMARY KEY AUTOINCREMENT, ship_id INTEGER, eta INTEGER, source_system TEXT, destination_system TEXT, source_market_id INTEGER, destination_market_id INTEGER)''' ) self.db.commit() except: EDRLOG.log(u"Couldn't open/create the fleet database", "ERROR") self.db = None
class RESTFirebaseAuth(object): FIREBASE_ANON_AUTH_CACHE = utils2to3.abspathmaker(__file__, 'private', 'fbaa.v2.p') def __init__(self): self.email = "" self.password = "" self.auth = None self.anonymous = True try: with open(self.FIREBASE_ANON_AUTH_CACHE, 'rb') as handle: self.refresh_token = pickle.load(handle) except: self.refresh_token = None self.timestamp = None self.api_key = "" def authenticate(self): if self.api_key == "": EDRLOG.log(u"can't authenticate: empty api key.", "ERROR") return False if not self.__login(): EDRLOG.log(u"Authentication failed (login)", "ERROR") self.__reset() return False if not self.__refresh_fb_token(): EDRLOG.log(u"Authentication failed (FB token)", "ERROR") self.__reset() return False return True def __login(self): payload = {"returnSecureToken": True} endpoint = "https://www.googleapis.com/identitytoolkit/v3/relyingparty/signupNewUser?key={}".format( self.api_key) self.anonymous = True if self.email != "" and self.password != "": payload["email"] = self.email payload["password"] = self.password self.anonymous = False self.refresh_token = None endpoint = "https://www.googleapis.com/identitytoolkit/v3/relyingparty/verifyPassword?key={}".format( self.api_key) if self.refresh_token: return True requestTime = datetime.datetime.now() resp = requests.post(endpoint, json=payload) if resp.status_code != requests.codes.ok: return False self.timestamp = requestTime auth = json.loads(resp.content) self.refresh_token = auth['refreshToken'] if self.anonymous: try: with open(self.FIREBASE_ANON_AUTH_CACHE, 'wb') as handle: pickle.dump(self.refresh_token, handle, protocol=pickle.HIGHEST_PROTOCOL) except: return False return True def __refresh_fb_token(self): payload = { "grant_type": "refresh_token", "refresh_token": self.refresh_token } endpoint = "https://securetoken.googleapis.com/v1/token?key={}".format( self.api_key) requestTime = datetime.datetime.now() resp = requests.post(endpoint, data=payload) if resp.status_code != requests.codes.ok: EDRLOG.log( u"Refresh of FB token failed. Status code={code}, content={content}" .format(code=resp.status_code, content=resp.content), "ERROR") return False self.auth = json.loads(resp.content) self.timestamp = requestTime self.refresh_token = self.auth["refresh_token"] return True def is_valid_auth_token(self): return (self.auth and 'expires_in' in self.auth and 'id_token' in self.auth) def is_auth_expiring(self): if not self.is_valid_auth_token(): return True now = datetime.datetime.now() near_expiration = datetime.timedelta( seconds=int(self.auth['expires_in']) - 30) return (now - self.timestamp) > near_expiration def renew_auth_if_needed(self): if self.api_key == "": return False if self.is_auth_expiring(): EDRLOG.log( u"Renewing authentication since the token will expire soon.", "INFO") self.clear_authentication() return self.authenticate() return True def id_token(self): if not self.renew_auth_if_needed(): return None if not self.is_valid_auth_token(): return None return self.auth['id_token'] def uid(self): if not self.renew_auth_if_needed(): return None if not self.is_valid_auth_token(): return None return self.auth['user_id'] def clear_authentication(self): self.auth = None self.timestamp = None def __reset(self): self.clear_authentication() try: with open(self.FIREBASE_ANON_AUTH_CACHE, 'rb') as handle: self.refresh_token = pickle.load(handle) except: self.refresh_token = None
class EDRLegalRecords(object): EDR_LEGAL_RECORDS_CACHE = utils2to3.abspathmaker(__file__, 'cache', 'legal_records.v3.p') def __init__(self, server): self.server = server self.timespan = None self.records_check_interval = None config = EDRConfig() try: with open(self.EDR_LEGAL_RECORDS_CACHE, 'rb') as handle: self.records = pickle.load(handle) except: self.records = LRUCache(config.lru_max_size(), config.legal_records_max_age()) self.timespan = config.legal_records_recent_threshold() self.records_check_interval = config.legal_records_check_interval() def persist(self): with open(self.EDR_LEGAL_RECORDS_CACHE, 'wb') as handle: pickle.dump(self.records, handle, protocol=pickle.HIGHEST_PROTOCOL) def summarize(self, cmdr_id): if not cmdr_id: EDRLOG.log(u"No cmdr_id, no records for {}".format(cmdr_id), "INFO") return None self.__update_records_if_stale(cmdr_id) records = self.records.get(cmdr_id)["records"] if self.records.has_key(cmdr_id) else None if not records: EDRLOG.log(u"No legal records for {}".format(cmdr_id), "INFO") return None EDRLOG.log(u"Got legal records for {}".format(cmdr_id), "INFO") overview = None (clean, wanted, bounties, recent_stats) = self.__process(records) timespan = EDTime.pretty_print_timespan(self.timespan, short=True, verbose=True) maxB = u"" lastB = u"" if recent_stats["maxBounty"]: max_bounty = EDFineOrBounty(recent_stats["maxBounty"]).pretty_print() maxB = _(u", max={} cr").format(max_bounty) if "last" in recent_stats and recent_stats["last"].get("value", None) and (recent_stats["last"].get("starSystem", "") not in ["", "unknown", "Unknown"]): tminus = EDTime.t_minus(recent_stats["last"]["timestamp"], short=True) last_bounty = EDFineOrBounty(recent_stats["last"]["value"]).pretty_print() lastB = _(u", last: {} cr in {} {}").format(last_bounty, recent_stats["last"]["starSystem"], tminus) # Translators: this is an overview of a cmdr's recent legal history for the 'last {}' days, number of clean and wanted scans, and optionally max and last bounties overview = _(u"[Past {}] clean:{} / wanted:{}{}{}").format(timespan, recent_stats["clean"], recent_stats["wanted"], maxB, lastB) return {"overview": overview, "clean": clean, "wanted": wanted, "bounties": bounties} def __are_records_stale_for_cmdr(self, cmdr_id): if self.records.get(cmdr_id) is None: return True last_updated = self.records.get(cmdr_id)["last_updated"] now = datetime.datetime.now() epoch_now = time.mktime(now.timetuple()) epoch_updated = time.mktime(last_updated.timetuple()) return (epoch_now - epoch_updated) > self.records_check_interval def __update_records_if_stale(self, cmdr_id): updated = False if self.__are_records_stale_for_cmdr(cmdr_id): now = datetime.datetime.now() records = self.server.legal_stats(cmdr_id) self.records.set(cmdr_id, {"last_updated": now, "records": records}) updated = True return updated def __process(self, legal_stats): last = self.__emptyMonthlyBag() clean = [] wanted = [] bounties = [] recent_stats = {"clean": 0, "wanted": 0, "maxBounty": 0, "last": {"value": 0, "timestamp": None, "starSystem": None}} now_date = datetime.datetime.now() currentYear = now_date.year currentMonth = now_date.month orderly = self.__orderlyMonthNo() monthSpan = int(min(12, round(1 + (self.timespan / (60*60*24) - now_date.day)/30))) for m in orderly: if (m not in legal_stats): clean.append(0) wanted.append(0) bounties.append(0) continue wayTooOld = int(legal_stats[m]["year"]) < currentYear-1 tooOld = (int(legal_stats[m]["year"]) == currentYear-1) and int(m) <= currentMonth if (wayTooOld or tooOld): clean.append(0) wanted.append(0) bounties.append(0) continue if (m in orderly[12-monthSpan:]): recent_stats["clean"] += legal_stats[m]["clean"] recent_stats["wanted"] += legal_stats[m]["wanted"] if legal_stats[m]["max"]: recent_stats["maxBounty"] = max(recent_stats["maxBounty"], legal_stats[m]["max"].get("value", 0)) if legal_stats[m]["last"] and legal_stats[m]["last"].get("value", 0) >= recent_stats["last"]["value"]: recent_stats["last"] = legal_stats[m]["last"] clean.append(legal_stats[m]["clean"]) wanted.append(legal_stats[m]["wanted"]) last[m] = legal_stats[m]["last"] bounties.append(legal_stats[m]["max"]["value"]) return (clean, wanted, bounties, recent_stats) @staticmethod def __orderlyMonthNo(): currentMonthIDX0 = datetime.datetime.now().month-1 return [ str((((currentMonthIDX0 - i) %12) + 12)%12) for i in range(11,-1,-1)] @staticmethod def __emptyMonthlyBag(): return { '0': None, '1': None, '2': None, '3': None, '4': None, '5': None, '6': None, '7': None, '8': None, '9': None, '10': None, '11': None }
class EDRSystems(object): EDR_SYSTEMS_CACHE = utils2to3.abspathmaker(__file__, 'cache', 'systems.v4.p') EDR_RAW_MATERIALS_CACHE = utils2to3.abspathmaker(__file__, 'cache', 'raw_materials.v1.p') EDSM_BODIES_CACHE = utils2to3.abspathmaker(__file__, 'cache', 'edsm_bodies.v1.p') EDSM_SYSTEMS_CACHE = utils2to3.abspathmaker(__file__, 'cache', 'edsm_systems.v3.p') EDSM_STATIONS_CACHE = utils2to3.abspathmaker(__file__, 'cache', 'edsm_stations.v1.p') EDSM_SYSTEMS_WITHIN_RADIUS_CACHE = utils2to3.abspathmaker( __file__, 'cache', 'edsm_systems_radius.v2.p') EDSM_FACTIONS_CACHE = utils2to3.abspathmaker(__file__, 'cache', 'edsm_factions.v1.p') EDSM_TRAFFIC_CACHE = utils2to3.abspathmaker(__file__, 'cache', 'edsm_traffic.v1.p') EDSM_DEATHS_CACHE = utils2to3.abspathmaker(__file__, 'cache', 'edsm_deaths.v1.p') EDR_NOTAMS_CACHE = utils2to3.abspathmaker(__file__, 'cache', 'notams.v2.p') EDR_SITREPS_CACHE = utils2to3.abspathmaker(__file__, 'cache', 'sitreps.v3.p') EDR_TRAFFIC_CACHE = utils2to3.abspathmaker(__file__, 'cache', 'traffic.v2.p') EDR_CRIMES_CACHE = utils2to3.abspathmaker(__file__, 'cache', 'crimes.v2.p') def __init__(self, server): self.reasonable_sc_distance = 1500 self.reasonable_hs_radius = 50 edr_config = edrconfig.EDRConfig() try: with open(self.EDR_SYSTEMS_CACHE, 'rb') as handle: self.systems_cache = pickle.load(handle) except: self.systems_cache = lrucache.LRUCache( edr_config.lru_max_size(), edr_config.systems_max_age()) try: with open(self.EDR_RAW_MATERIALS_CACHE, 'rb') as handle: self.materials_cache = pickle.load(handle) except: self.materials_cache = lrucache.LRUCache( edr_config.lru_max_size(), edr_config.materials_max_age()) try: with open(self.EDR_NOTAMS_CACHE, 'rb') as handle: self.notams_cache = pickle.load(handle) except: self.notams_cache = lrucache.LRUCache(edr_config.lru_max_size(), edr_config.notams_max_age()) try: with open(self.EDR_SITREPS_CACHE, 'rb') as handle: self.sitreps_cache = pickle.load(handle) except: self.sitreps_cache = lrucache.LRUCache( edr_config.lru_max_size(), edr_config.sitreps_max_age()) try: with open(self.EDR_CRIMES_CACHE, 'rb') as handle: self.crimes_cache = pickle.load(handle) except: self.crimes_cache = lrucache.LRUCache(edr_config.lru_max_size(), edr_config.crimes_max_age()) try: with open(self.EDR_TRAFFIC_CACHE, 'rb') as handle: self.traffic_cache = pickle.load(handle) except: self.traffic_cache = lrucache.LRUCache( edr_config.lru_max_size(), edr_config.traffic_max_age()) try: with open(self.EDSM_SYSTEMS_CACHE, 'rb') as handle: self.edsm_systems_cache = pickle.load(handle) except: self.edsm_systems_cache = lrucache.LRUCache( edr_config.lru_max_size(), edr_config.edsm_systems_max_age()) try: with open(self.EDSM_BODIES_CACHE, 'rb') as handle: self.edsm_bodies_cache = pickle.load(handle) except: self.edsm_bodies_cache = lrucache.LRUCache( edr_config.lru_max_size(), edr_config.edsm_bodies_max_age()) try: with open(self.EDSM_STATIONS_CACHE, 'rb') as handle: self.edsm_stations_cache = pickle.load(handle) except: self.edsm_stations_cache = lrucache.LRUCache( edr_config.lru_max_size(), edr_config.edsm_stations_max_age()) try: with open(self.EDSM_FACTIONS_CACHE, 'rb') as handle: self.edsm_factions_cache = pickle.load(handle) except: self.edsm_factions_cache = lrucache.LRUCache( edr_config.lru_max_size(), edr_config.edsm_factions_max_age()) try: with open(self.EDSM_SYSTEMS_WITHIN_RADIUS_CACHE, 'rb') as handle: self.edsm_systems_within_radius_cache = pickle.load(handle) except: self.edsm_systems_within_radius_cache = lrucache.LRUCache( edr_config.edsm_within_radius_max_size(), edr_config.edsm_systems_max_age()) try: with open(self.EDSM_TRAFFIC_CACHE, 'rb') as handle: self.edsm_traffic_cache = pickle.load(handle) except: self.edsm_traffic_cache = lrucache.LRUCache( edr_config.lru_max_size(), edr_config.edsm_traffic_max_age()) try: with open(self.EDSM_DEATHS_CACHE, 'rb') as handle: self.edsm_deaths_cache = pickle.load(handle) except: self.edsm_deaths_cache = lrucache.LRUCache( edr_config.lru_max_size(), edr_config.edsm_deaths_max_age()) self.reports_check_interval = edr_config.reports_check_interval() self.notams_check_interval = edr_config.notams_check_interval() self.timespan = edr_config.sitreps_timespan() self.timespan_notams = edr_config.notams_timespan() self.server = server self.edsm_server = edsmserver.EDSMServer() def system_id(self, star_system, may_create=False, coords=None): if not star_system: return None system = self.systems_cache.get(star_system.lower()) cached = self.systems_cache.has_key(star_system.lower()) if cached and system is None: EDRLOG.log( u"Temporary entry for System {} in the cache".format( star_system), "DEBUG") return None if cached and system: sid = list(system)[0] if may_create and coords and not "coords" in system[sid]: EDRLOG.log( u"System {} is in the cache with id={} but missing coords". format(star_system, sid), "DEBUG") system = self.server.system(star_system, may_create, coords) if system: self.systems_cache.set(star_system.lower(), system) sid = list(system)[0] return sid system = self.server.system(star_system, may_create, coords) if system: self.systems_cache.set(star_system.lower(), system) sid = list(system)[0] EDRLOG.log(u"Cached {}'s info with id={}".format(star_system, sid), "DEBUG") return sid self.systems_cache.set(star_system.lower(), None) EDRLOG.log( u"No match on EDR. Temporary entry to be nice on EDR's server.", "DEBUG") return None def are_stations_stale(self, star_system): if not star_system: return False return self.edsm_stations_cache.is_stale(star_system.lower()) def station(self, star_system, station_name, station_type): stations = self.stations_in_system(star_system) for station in stations: if station["name"] == station_name: return station return None def stations_in_system(self, star_system): if not star_system: return None stations = self.edsm_stations_cache.get(star_system.lower()) cached = self.edsm_stations_cache.has_key(star_system.lower()) if cached or stations: EDRLOG.log( u"Stations for system {} are in the cache.".format( star_system), "DEBUG") return stations stations = self.edsm_server.stations_in_system(star_system) if stations: self.edsm_stations_cache.set(star_system.lower(), stations) EDRLOG.log(u"Cached {}'s stations".format(star_system), "DEBUG") return stations self.edsm_stations_cache.set(star_system.lower(), None) EDRLOG.log( u"No match on EDSM. Temporary entry to be nice on EDSM's server.", "DEBUG") return None def persist(self): with open(self.EDR_SYSTEMS_CACHE, 'wb') as handle: pickle.dump(self.systems_cache, handle, protocol=pickle.HIGHEST_PROTOCOL) with open(self.EDR_RAW_MATERIALS_CACHE, 'wb') as handle: pickle.dump(self.materials_cache, handle, protocol=pickle.HIGHEST_PROTOCOL) with open(self.EDR_NOTAMS_CACHE, 'wb') as handle: pickle.dump(self.notams_cache, handle, protocol=pickle.HIGHEST_PROTOCOL) with open(self.EDR_SITREPS_CACHE, 'wb') as handle: pickle.dump(self.sitreps_cache, handle, protocol=pickle.HIGHEST_PROTOCOL) with open(self.EDR_TRAFFIC_CACHE, 'wb') as handle: pickle.dump(self.traffic_cache, handle, protocol=pickle.HIGHEST_PROTOCOL) with open(self.EDR_CRIMES_CACHE, 'wb') as handle: pickle.dump(self.crimes_cache, handle, protocol=pickle.HIGHEST_PROTOCOL) with open(self.EDSM_SYSTEMS_CACHE, 'wb') as handle: pickle.dump(self.edsm_systems_cache, handle, protocol=pickle.HIGHEST_PROTOCOL) with open(self.EDSM_BODIES_CACHE, 'wb') as handle: pickle.dump(self.edsm_bodies_cache, handle, protocol=pickle.HIGHEST_PROTOCOL) with open(self.EDSM_STATIONS_CACHE, 'wb') as handle: pickle.dump(self.edsm_stations_cache, handle, protocol=pickle.HIGHEST_PROTOCOL) with open(self.EDSM_SYSTEMS_WITHIN_RADIUS_CACHE, 'wb') as handle: pickle.dump(self.edsm_systems_within_radius_cache, handle, protocol=pickle.HIGHEST_PROTOCOL) with open(self.EDSM_FACTIONS_CACHE, 'wb') as handle: pickle.dump(self.edsm_factions_cache, handle, protocol=pickle.HIGHEST_PROTOCOL) with open(self.EDSM_TRAFFIC_CACHE, 'wb') as handle: pickle.dump(self.edsm_traffic_cache, handle, protocol=pickle.HIGHEST_PROTOCOL) with open(self.EDSM_DEATHS_CACHE, 'wb') as handle: pickle.dump(self.edsm_deaths_cache, handle, protocol=pickle.HIGHEST_PROTOCOL) def distance(self, source_system, destination_system): if source_system == destination_system: return 0 source = self.system(source_system) destination = self.system(destination_system) if source and destination: source_coords = source[0]["coords"] dest_coords = destination[0]["coords"] return sqrt((dest_coords["x"] - source_coords["x"])**2 + (dest_coords["y"] - source_coords["y"])**2 + (dest_coords["z"] - source_coords["z"])**2) raise ValueError('Unknown system') def distance_with_coords(self, source_system, dest_coords): source = self.system(source_system) if source: source_coords = source[0]["coords"] return sqrt((dest_coords["x"] - source_coords["x"])**2 + (dest_coords["y"] - source_coords["y"])**2 + (dest_coords["z"] - source_coords["z"])**2) raise ValueError('Unknown system') def system(self, name): if not name: return None the_system = self.edsm_systems_cache.get(name.lower()) if the_system: return the_system the_system = self.edsm_server.system(name) if the_system: self.edsm_systems_cache.set(name.lower(), the_system) return the_system return None def materials_info(self, system_name, body_name, info): if not system_name or not body_name: return None self.materials_cache.set( u"{}:{}".format(system_name.lower(), body_name.lower()), info) def materials_on(self, system_name, body_name): if not system_name or not body_name: return None materials = self.materials_cache.get(u"{}:{}".format( system_name.lower(), body_name.lower())) if not materials: # TODO it would be nice to obtain data from other cmdrs... return None return materials def body(self, system_name, body_name): if not system_name or not body_name: return None bodies = self.edsm_bodies_cache.get(system_name.lower()) if not bodies: bodies = self.edsm_server.bodies(system_name) if bodies: self.edsm_bodies_cache.set(system_name.lower(), bodies) if not bodies: return None for body in bodies: if body.get("name", "").lower() == body_name.lower(): return body return None def are_factions_stale(self, star_system): if not star_system: return False return self.edsm_factions_cache.is_stale(star_system.lower()) def __factions(self, star_system): if not star_system: return None factions = self.edsm_factions_cache.get(star_system.lower()) cached = self.edsm_factions_cache.has_key(star_system.lower()) if cached or factions: EDRLOG.log( u"Factions for system {} are in the cache.".format( star_system), "DEBUG") return factions EDRLOG.log( u"Factions for system {} are NOT in the cache.".format( star_system), "DEBUG") factions = self.edsm_server.factions_in_system(star_system) if factions: self.edsm_factions_cache.set(star_system.lower(), factions) EDRLOG.log(u"Cached {}'s factions".format(star_system), "DEBUG") return factions self.edsm_factions_cache.set(star_system.lower(), None) EDRLOG.log( u"No match on EDSM. Temporary entry to be nice on EDSM's server.", "DEBUG") return None def system_state(self, star_system): factions = self.__factions(star_system) if not factions: return (None, None) if not factions.get('controllingFaction', None) or not factions.get( 'factions', None): EDRLOG.log( u"Badly formed factions data for system {}.".format( star_system), "INFO") return (None, None) controlling_faction_id = factions['controllingFaction']['id'] all_factions = factions['factions'] state = None updated = None for faction in all_factions: if faction['id'] == controlling_faction_id: state = faction['state'] updated = faction['lastUpdate'] break return (state, updated) def system_allegiance(self, star_system): factions = self.__factions(star_system) if not factions: return None if not factions.get('controllingFaction', None): EDRLOG.log( u"Badly formed factions data for system {}.".format( star_system), "INFO") return None return factions['controllingFaction'].get('allegiance', None) def transfer_time(self, origin, destination): dist = self.distance(origin, destination) return int(ceil(dist * 9.75 + 300)) def jumping_time(self, origin, destination, jump_range, seconds_per_jump=55): dist = self.distance(origin, destination) return int(ceil(dist / jump_range) * seconds_per_jump) def timespan_s(self): return edtime.EDTime.pretty_print_timespan(self.timespan, short=True, verbose=True) def crimes_t_minus(self, star_system): if self.has_sitrep(star_system): system_reports = self.sitreps_cache.get( self.system_id(star_system)) if "latestCrime" in system_reports: return edtime.EDTime.t_minus(system_reports["latestCrime"]) return None def traffic_t_minus(self, star_system): if self.has_sitrep(star_system): system_reports = self.sitreps_cache.get( self.system_id(star_system)) if "latestTraffic" in system_reports: return edtime.EDTime.t_minus(system_reports["latestTraffic"]) return None def has_sitrep(self, star_system): if not star_system: return False self.__update_if_stale() sid = self.system_id(star_system) return self.sitreps_cache.has_key(sid) def has_notams(self, star_system, may_create=False, coords=None): self.__update_if_stale() sid = self.system_id(star_system, may_create, coords) return self.notams_cache.has_key(sid) def __has_active_notams(self, system_id): self.__update_if_stale() if not self.notams_cache.has_key(system_id): return False return len(self.__active_notams_for_sid(system_id)) > 0 def active_notams(self, star_system, may_create=False, coords=None): if self.has_notams(star_system, may_create, coords=None): return self.__active_notams_for_sid(self.system_id(star_system)) return None def __active_notams_for_sid(self, system_id): active_notams = [] entry = self.notams_cache.get(system_id) all_notams = entry.get("NOTAMs", {}) js_epoch_now = edtime.EDTime.js_epoch_now() for notam in all_notams: active = True if "from" in notam: active &= notam["from"] <= js_epoch_now if "until" in notam: active &= js_epoch_now <= notam["until"] if active and "text" in notam: EDRLOG.log(u"Active NOTAM: {}".format(notam["text"]), "DEBUG") active_notams.append(_edr(notam["text"])) elif active and "l10n" in notam: EDRLOG.log( u"Active NOTAM: {}".format(notam["l10n"]["default"]), "DEBUG") active_notams.append(_edr(notam["l10n"])) return active_notams def systems_with_active_notams(self): summary = [] self.__update_if_stale() systems_ids = list(self.notams_cache.keys()).copy() for sid in systems_ids: entry = self.notams_cache.get(sid) if not entry: continue star_system = entry.get("name", None) if star_system and self.__has_active_notams(sid): summary.append(star_system) return summary def has_recent_activity(self, system_name, pledged_to=None): return self.has_recent_traffic(system_name) or self.has_recent_crimes( system_name) or self.has_recent_outlaws( system_name) or pledged_to and self.has_recent_enemies( system_name, pledged_to) def systems_with_recent_activity(self, pledged_to=None): systems_with_recent_crimes = {} systems_with_recent_traffic = {} systems_with_recent_outlaws = {} systems_with_recent_enemies = {} self.__update_if_stale() systems_ids = (list(self.sitreps_cache.keys())).copy() for sid in systems_ids: sitrep = self.sitreps_cache.get(sid) star_system = sitrep.get("name", None) if sitrep else None if self.has_recent_outlaws(star_system): systems_with_recent_outlaws[star_system] = sitrep[ "latestOutlaw"] elif pledged_to and self.has_recent_enemies( star_system, pledged_to): latestEnemy = "latestEnemy_{}".format( self.server.nodify(pledged_to)) systems_with_recent_enemies[star_system] = sitrep[latestEnemy] elif self.has_recent_crimes(star_system): systems_with_recent_crimes[star_system] = sitrep["latestCrime"] elif self.has_recent_traffic(star_system): systems_with_recent_traffic[star_system] = sitrep[ "latestTraffic"] summary = {} summary_outlaws = [] systems_with_recent_outlaws = sorted( systems_with_recent_outlaws.items(), key=lambda t: t[1], reverse=True) for system in systems_with_recent_outlaws: summary_outlaws.append(u"{} {}".format( system[0], edtime.EDTime.t_minus(system[1], short=True))) if summary_outlaws: # Translators: this is for the sitreps feature; it's the title of a section to show systems with sighted outlaws summary[_c(u"sitreps section|✪ Outlaws")] = summary_outlaws if pledged_to: summary_enemies = [] systems_with_recent_enemies = sorted( systems_with_recent_enemies.items(), key=lambda t: t[1], reverse=True) for system in systems_with_recent_enemies: summary_enemies.append(u"{} {}".format( system[0], edtime.EDTime.t_minus(system[1], short=True))) if summary_enemies: # Translators: this is for the sitreps feature; it's the title of a section to show systems with sighted enemies (powerplay) summary[_c(u"sitreps section|✪ Enemies")] = summary_enemies summary_crimes = [] systems_with_recent_crimes = sorted(systems_with_recent_crimes.items(), key=lambda t: t[1], reverse=True) for system in systems_with_recent_crimes: summary_crimes.append(u"{} {}".format( system[0], edtime.EDTime.t_minus(system[1], short=True))) if summary_crimes: # Translators: this is for the sitreps feature; it's the title of a section to show systems with reported crimes summary[_c(u"sitreps section|✪ Crimes")] = summary_crimes summary_traffic = [] systems_with_recent_traffic = sorted( systems_with_recent_traffic.items(), key=lambda t: t[1], reverse=True) for system in systems_with_recent_traffic: summary_traffic.append(u"{} {}".format( system[0], edtime.EDTime.t_minus(system[1], short=True))) if summary_traffic: # Translators: this is for the sitreps feature; it's the title of a section to show systems with traffic summary[_c(u"sitreps section|✪ Traffic")] = summary_traffic return summary def has_recent_crimes(self, star_system): if self.has_sitrep(star_system): system_reports = self.sitreps_cache.get( self.system_id(star_system)) if system_reports is None or "latestCrime" not in system_reports: return False edr_config = edrconfig.EDRConfig() return self.is_recent(system_reports["latestCrime"], edr_config.crimes_recent_threshold()) return False def has_recent_outlaws(self, star_system): if self.has_sitrep(star_system): system_reports = self.sitreps_cache.get( self.system_id(star_system)) if system_reports is None or "latestOutlaw" not in system_reports: return False edr_config = edrconfig.EDRConfig() return self.is_recent( system_reports["latestOutlaw"], edr_config.opponents_recent_threshold("outlaws")) return False def has_recent_enemies(self, star_system, pledged_to): if self.has_sitrep(star_system): system_reports = self.sitreps_cache.get( self.system_id(star_system)) latestEnemy = "latestEnemy_{}".format( self.server.nodify(pledged_to)) if system_reports is None or latestEnemy not in system_reports: return False edr_config = edrconfig.EDRConfig() return self.is_recent( system_reports[latestEnemy], edr_config.opponents_recent_threshold("enemies")) return False def recent_crimes(self, star_system): sid = self.system_id(star_system) if not sid: return None recent_crimes = None if self.has_recent_crimes(star_system): if not self.crimes_cache.has_key(sid) or ( self.crimes_cache.has_key(sid) and self.crimes_cache.is_stale(sid)): recent_crimes = self.server.recent_crimes(sid, self.timespan) if recent_crimes: self.crimes_cache.set(sid, recent_crimes) else: recent_crimes = self.crimes_cache.get(sid) return recent_crimes def has_recent_traffic(self, star_system): if self.has_sitrep(star_system): system_reports = self.sitreps_cache.get( self.system_id(star_system)) if system_reports is None or "latestTraffic" not in system_reports: return False edr_config = edrconfig.EDRConfig() return self.is_recent(system_reports["latestTraffic"], edr_config.traffic_recent_threshold()) return False def recent_traffic(self, star_system): sid = self.system_id(star_system) if not sid: return None recent_traffic = None if self.has_recent_traffic(star_system): if not self.traffic_cache.has_key(sid) or ( self.traffic_cache.has_key(sid) and self.traffic_cache.is_stale(sid)): recent_traffic = self.server.recent_traffic(sid, self.timespan) if recent_traffic: self.traffic_cache.set(sid, recent_traffic) else: recent_traffic = self.traffic_cache.get(sid) return recent_traffic def summarize_deaths_traffic(self, star_system): if not star_system: return None traffic = self.edsm_traffic_cache.get(star_system.lower()) if traffic is None: traffic = self.edsm_server.traffic(star_system) self.edsm_traffic_cache.set(star_system.lower(), traffic) deaths = self.edsm_deaths_cache.get(star_system.lower()) if deaths is None: deaths = self.edsm_server.deaths(star_system) self.edsm_deaths_cache.set(star_system.lower(), traffic) if not deaths and not traffic: return None zero = {"total": 0, "week": 0, "day": 0} deaths = { s: self.__pretty_print_number(v) for s, v in deaths.get("deaths", zero).items() } traffic = { s: self.__pretty_print_number(v) for s, v in traffic.get("traffic", {}).items() } if traffic == {}: return None return "Deaths / Traffic: [Day {}/{}] [Week {}/{}] [All {}/{}]".format( deaths.get("day", 0), traffic.get("day"), deaths.get("week", 0), traffic.get("week"), deaths.get("total"), traffic.get("total")) @staticmethod def __pretty_print_number(number): #TODO move out and dedup bounty's code. readable = u"" if number >= 10000000000: # Translators: this is a short representation for a bounty >= 10 000 000 000 credits (b stands for billion) readable = _(u"{} b").format(number // 1000000000) elif number >= 1000000000: # Translators: this is a short representation for a bounty >= 1 000 000 000 credits (b stands for billion) readable = _(u"{:.1f} b").format(number / 1000000000.0) elif number >= 10000000: # Translators: this is a short representation for a bounty >= 10 000 000 credits (m stands for million) readable = _(u"{} m").format(number // 1000000) elif number > 1000000: # Translators: this is a short representation for a bounty >= 1 000 000 credits (m stands for million) readable = _(u"{:.1f} m").format(number / 1000000.0) elif number >= 10000: # Translators: this is a short representation for a bounty >= 10 000 credits (k stands for kilo, i.e. thousand) readable = _(u"{} k").format(number // 1000) elif number >= 1000: # Translators: this is a short representation for a bounty >= 1000 credits (k stands for kilo, i.e. thousand) readable = _(u"{:.1f} k").format(number / 1000.0) else: # Translators: this is a short representation for a bounty < 1000 credits (i.e. shows the whole bounty, unabbreviated) readable = _(u"{}").format(number) return readable def summarize_recent_activity(self, star_system, powerplay=None): #TODO refactor/simplify this mess ;) summary = {} wanted_cmdrs = {} enemies = {} if self.has_recent_traffic(star_system): summary_sighted = [] recent_traffic = self.recent_traffic(star_system) if recent_traffic is not None: # Should always be true... simplify. TODO summary_traffic = collections.OrderedDict() for traffic in recent_traffic: previous_timestamp = summary_traffic.get( traffic["cmdr"], 0) if traffic["timestamp"] < previous_timestamp: continue karma = traffic.get("karma", 0) if not karma > 0: karma = min(karma, traffic.get("dkarma", 0)) bounty = EDFineOrBounty(traffic.get("bounty", 0)) enemy = traffic.get("enemy", False) by_pledge = traffic.get("byPledge", None) if karma < 0 or bounty.is_significant(): wanted_cmdrs[traffic["cmdr"]] = [ traffic["timestamp"], karma ] elif powerplay and enemy and powerplay == by_pledge: enemies[traffic["cmdr"]] = [ traffic["timestamp"], karma ] else: summary_traffic[traffic["cmdr"]] = traffic["timestamp"] for cmdr in summary_traffic: summary_sighted.append(u"{} {}".format( cmdr, edtime.EDTime.t_minus(summary_traffic[cmdr], short=True))) if summary_sighted: # Translators: this is for the sitrep feature; it's a section to show sighted cmdrs in the system of interest summary[_c(u"sitrep section|✪ Sighted")] = summary_sighted if self.has_recent_crimes(star_system): summary_interdictors = [] summary_destroyers = [] recent_crimes = self.recent_crimes(star_system) if recent_crimes is not None: # Should always be true... simplify. TODO summary_crimes = collections.OrderedDict() for crime in recent_crimes: lead_name = crime["criminals"][0]["name"] if lead_name not in summary_crimes or crime[ "timestamp"] > summary_crimes[lead_name][0]: summary_crimes[lead_name] = [ crime["timestamp"], crime["offence"] ] for criminal in crime["criminals"]: previous_timestamp = wanted_cmdrs[ criminal["name"]][0] if criminal[ "name"] in wanted_cmdrs else 0 previous_timestamp = max( previous_timestamp, enemies[criminal["name"]] [0]) if criminal["name"] in enemies else 0 if previous_timestamp > crime["timestamp"]: continue karma = criminal.get("karma", 0) if not karma > 0: karma = min(karma, criminal.get("dkarma", 0)) bounty = EDFineOrBounty(traffic.get("bounty", 0)) enemy = traffic.get("enemy", False) by_pledge = traffic.get("byPledge", None) if karma < 0 or bounty.is_significant(): wanted_cmdrs[criminal["name"]] = [ crime["timestamp"], karma ] elif powerplay and enemy and powerplay == by_pledge: enemies[traffic["cmdr"]] = [ traffic["timestamp"], karma ] for criminal in summary_crimes: if summary_crimes[criminal][1] == "Murder": summary_destroyers.append(u"{} {}".format( criminal, edtime.EDTime.t_minus(summary_crimes[criminal][0], short=True))) elif summary_crimes[criminal][1] in [ "Interdicted", "Interdiction" ]: summary_interdictors.append(u"{} {}".format( criminal, edtime.EDTime.t_minus(summary_crimes[criminal][0], short=True))) if summary_interdictors: # Translators: this is for the sitrep feature; it's a section to show cmdrs who have been reported as interdicting another cmdr in the system of interest summary[_c(u"sitrep section|✪ Interdictors" )] = summary_interdictors if summary_destroyers: # Translators: this is for the sitrep feature; it's a section to show cmdrs who have been reported as responsible for destroying the ship of another cmdr in the system of interest; use a judgement-neutral term summary[_c( u"sitreps section|✪ Destroyers")] = summary_destroyers wanted_cmdrs = sorted(wanted_cmdrs.items(), key=operator.itemgetter(1), reverse=True) if wanted_cmdrs: summary_wanted = [] for wanted in wanted_cmdrs: summary_wanted.append(u"{} {}".format( wanted[0], edtime.EDTime.t_minus(wanted[1][0], short=True))) if summary_wanted: # Translators: this is for the sitrep feature; it's a section to show wanted cmdrs who have been sighted in the system of interest summary[_c(u"sitreps section|✪ Outlaws")] = summary_wanted enemies = sorted(enemies.items(), key=operator.itemgetter(1), reverse=True) if enemies: summary_enemies = [] for enemy in enemies: summary_enemies.append(u"{} {}".format( enemies[0], edtime.EDTime.t_minus(enemies[1][0], short=True))) if summary_enemies: # Translators: this is for the sitrep feature; it's a section to show enemy cmdrs who have been sighted in the system of interest summary[_c(u"sitreps section|✪ Enemies")] = summary_enemies return summary def search_interstellar_factors(self, star_system, callback, with_large_pad=True, override_radius=None, override_sc_distance=None, permits=[]): checker = edrservicecheck.EDRStationServiceCheck( 'Interstellar Factors Contact') checker.name = 'Interstellar Factors Contact' checker.hint = 'Look for low security systems, or stations run by an anarchy faction regardless of system security' self.__search_a_service(star_system, callback, checker, with_large_pad, override_radius, override_sc_distance, permits) def search_raw_trader(self, star_system, callback, with_large_pad=True, override_radius=None, override_sc_distance=None, permits=[]): checker = edrservicecheck.EDRRawTraderCheck() self.__search_a_service(star_system, callback, checker, with_large_pad, override_radius, override_sc_distance, permits) def search_encoded_trader(self, star_system, callback, with_large_pad=True, override_radius=None, override_sc_distance=None, permits=[]): checker = edrservicecheck.EDREncodedTraderCheck() self.__search_a_service(star_system, callback, checker, with_large_pad, override_radius, override_sc_distance, permits) def search_manufactured_trader(self, star_system, callback, with_large_pad=True, override_radius=None, override_sc_distance=None, permits=[]): checker = edrservicecheck.EDRManufacturedTraderCheck() self.__search_a_service(star_system, callback, checker, with_large_pad, override_radius, override_sc_distance, permits) def search_black_market(self, star_system, callback, with_large_pad=True, override_radius=None, override_sc_distance=None, permits=[]): checker = edrservicecheck.EDRBlackMarketCheck() self.__search_a_service(star_system, callback, checker, with_large_pad, override_radius, override_sc_distance, permits) def search_staging_station(self, star_system, callback, permits=[]): checker = edrservicecheck.EDRStagingCheck(15) self.__search_a_service(star_system, callback, checker, with_large_pad=True, override_radius=15, permits=permits) def search_shipyard(self, star_system, callback, with_large_pad=True, override_radius=None, override_sc_distance=None, permits=[]): checker = edrservicecheck.EDRStationFacilityCheck('Shipyard') self.__search_a_service(star_system, callback, checker, with_large_pad, override_radius, override_sc_distance, permits) def search_outfitting(self, star_system, callback, with_large_pad=True, override_radius=None, override_sc_distance=None, permits=[]): checker = edrservicecheck.EDRStationFacilityCheck('Outfitting') self.__search_a_service(star_system, callback, checker, with_large_pad, override_radius, override_sc_distance, permits) def search_market(self, star_system, callback, with_large_pad=True, override_radius=None, override_sc_distance=None, permits=[]): checker = edrservicecheck.EDRStationFacilityCheck('Market') self.__search_a_service(star_system, callback, checker, with_large_pad, override_radius, override_sc_distance, permits) def search_human_tech_broker(self, star_system, callback, with_large_pad=True, override_radius=None, override_sc_distance=None, permits=[]): checker = edrservicecheck.EDRHumanTechBrokerCheck() self.__search_a_service(star_system, callback, checker, with_large_pad, override_radius, override_sc_distance, permits) def search_guardian_tech_broker(self, star_system, callback, with_large_pad=True, override_radius=None, override_sc_distance=None, permits=[]): checker = edrservicecheck.EDRGuardianTechBrokerCheck() self.__search_a_service(star_system, callback, checker, with_large_pad, override_radius, override_sc_distance, permits) def __search_a_service(self, star_system, callback, checker, with_large_pad=True, override_radius=None, override_sc_distance=None, permits=[]): sc_distance = override_sc_distance or self.reasonable_sc_distance sc_distance = max(250, sc_distance) radius = override_radius or self.reasonable_hs_radius radius = min(60, radius) finder = edrservicefinder.EDRServiceFinder(star_system, checker, self, callback) finder.with_large_pad(with_large_pad) finder.within_radius(radius) finder.within_supercruise_distance(sc_distance) finder.permits_in_possesion(permits) finder.start() def systems_within_radius(self, star_system, override_radius=None): if not star_system: return None radius = override_radius or self.reasonable_hs_radius key = u"{}@{}".format(star_system.lower(), radius) systems = self.edsm_systems_within_radius_cache.get(key) cached = self.edsm_systems_within_radius_cache.has_key(key) if cached: if not systems: EDRLOG.log( u"Systems within {} of system {} are not available for a while." .format(radius, star_system), "DEBUG") return None else: EDRLOG.log( u"Systems within {} of system {} are in the cache.".format( radius, star_system), "DEBUG") return sorted(systems, key=lambda i: i['distance']) systems = self.edsm_server.systems_within_radius(star_system, radius) if systems: systems = sorted(systems, key=lambda i: i['distance']) self.edsm_systems_within_radius_cache.set(key, systems) EDRLOG.log( u"Cached systems within {}LY of {}".format( radius, star_system), "DEBUG") return systems self.edsm_systems_within_radius_cache.set(key, None) EDRLOG.log( u"No results from EDSM. Temporary entry to be nice on EDSM's server.", "DEBUG") return None def is_recent(self, timestamp, max_age): if timestamp is None: return False return (edtime.EDTime.js_epoch_now() - timestamp) / 1000 <= max_age def evict(self, star_system): try: del self.systems_cache[star_system] except KeyError: pass def __are_reports_stale(self): return self.__is_stale(self.sitreps_cache.last_updated, self.reports_check_interval) def __are_notams_stale(self): return self.__is_stale(self.notams_cache.last_updated, self.notams_check_interval) def __is_stale(self, updated_at, max_age): if updated_at is None: return True now = datetime.datetime.now() epoch_now = time.mktime(now.timetuple()) epoch_updated = time.mktime(updated_at.timetuple()) return (epoch_now - epoch_updated) > max_age def __update_if_stale(self): updated = False if self.__are_reports_stale(): missing_seconds = self.timespan now = datetime.datetime.now() if self.sitreps_cache.last_updated: missing_seconds = min( self.timespan, (now - self.sitreps_cache.last_updated).total_seconds()) sitreps = self.server.sitreps(missing_seconds) if sitreps: for system_id in sitreps: self.sitreps_cache.set(system_id, sitreps[system_id]) self.sitreps_cache.last_updated = now updated = True if self.__are_notams_stale(): missing_seconds = self.timespan_notams now = datetime.datetime.now() if self.notams_cache.last_updated: missing_seconds = min( self.timespan_notams, (now - self.notams_cache.last_updated).total_seconds()) notams = self.server.notams(missing_seconds) if notams: for system_id in notams: self.notams_cache.set(system_id, notams[system_id]) self.notams_cache.last_updated = now updated = True return updated def closest_destination(self, sysAndSta1, sysAndSta2, override_sc_distance=None): if not sysAndSta1: return sysAndSta2 if not sysAndSta2: return sysAndSta1 sc_distance = override_sc_distance or self.reasonable_sc_distance if sysAndSta1['station'][ 'distanceToArrival'] > sc_distance and sysAndSta2['station'][ 'distanceToArrival'] > sc_distance: if abs(sysAndSta1['distance'] - sysAndSta2['distance']) < 5: return sysAndSta1 if sysAndSta1['station'][ 'distanceToArrival'] < sysAndSta2['station'][ 'distanceToArrival'] else sysAndSta2 else: return sysAndSta1 if sysAndSta1['distance'] < sysAndSta2[ 'distance'] else sysAndSta2 if sysAndSta1['station']['distanceToArrival'] > sc_distance: return sysAndSta2 if sysAndSta2['station']['distanceToArrival'] > sc_distance: return sysAndSta1 return sysAndSta1 if sysAndSta1['distance'] < sysAndSta2[ 'distance'] else sysAndSta2 def in_bubble(self, system_name): try: return self.distance(system_name, 'Sol') <= 500 except ValueError: return False def in_colonia(self, system_name): try: return self.distance(system_name, 'Colonia') <= 500 except ValueError: return False
from __future__ import absolute_import import json import re import os from edrlog import EDRLog import utils2to3 EDRLOG = EDRLog() POWER_DATA = json.loads(open(utils2to3.abspathmaker(__file__, 'data', 'modules_power_data.json')).read()) class EDModule(object): def __init__(self, module): self.power_draw = EDModule.__get_power_draw(module) self.power_generation = EDModule.__get_power_gen(module) self.priority = EDModule.__get_priority(module) self.cname = module["Item"].lower() if "Item" in module else None self.on = module.get("On", False) def update(self, module): prev_power_draw = self.power_draw prev_priority = self.priority prev_cname = self.cname prev_on = self.on EDRLOG.log(u"before: {}, {}, {}, {}".format(prev_cname, prev_power_draw, prev_priority, prev_on), "DEBUG") self.power_draw = module["Power"] if "Power" in module else EDModule.__get_power_draw(module) self.priority = EDModule.__get_priority(module) self.cname = module["Item"].lower() if "Item" in module else None
def loud(self): self.snd_warn = utils2to3.abspathmaker(__file__, 'sounds', 'snd_warn.wav') self.snd_notify = utils2to3.abspathmaker(__file__, 'sounds', 'snd_notify.wav')
class EDROpponents(object): OUTLAWS = "Outlaws" ENEMIES = "Enemies" EDR_OPPONENTS_SIGHTINGS_CACHES = { "Outlaws": utils2to3.abspathmaker(__file__, 'cache', 'outlaws_sigthings.v2.p'), "Enemies": utils2to3.abspathmaker(__file__, 'cache', 'enemies_sigthings.v2.p') } EDR_OPPONENTS_RECENTS_CACHES = { "Outlaws": utils2to3.abspathmaker(__file__, 'cache', 'outlaws_recents.v2.p'), "Enemies": utils2to3.abspathmaker(__file__, 'cache', 'enemies_recents.v2.p') } def __init__(self, server, opponent_kind, client_callback): self.server = server self.kind = opponent_kind self.powerplay = None self.realtime_callback = client_callback self.realtime = None config = edrconfig.EDRConfig() try: with open(self.EDR_OPPONENTS_SIGHTINGS_CACHES[opponent_kind], 'rb') as handle: self.sightings = pickle.load(handle) except: self.sightings = lrucache.LRUCache( config.lru_max_size(), config.opponents_max_age(self.kind)) try: with open(self.EDR_OPPONENTS_RECENTS_CACHES[opponent_kind], 'rb') as handle: self.recents = pickle.load(handle) except: self.recents = deque( maxlen=config.opponents_max_recents(self.kind)) self.timespan = config.opponents_recent_threshold(self.kind) self.reports_check_interval = config.reports_check_interval() def persist(self): with open(self.EDR_OPPONENTS_SIGHTINGS_CACHES[self.kind], 'wb') as handle: pickle.dump(self.sightings, handle, protocol=pickle.HIGHEST_PROTOCOL) with open(self.EDR_OPPONENTS_RECENTS_CACHES[self.kind], 'wb') as handle: pickle.dump(self.recents, handle, protocol=pickle.HIGHEST_PROTOCOL) def pledged_to(self, power, time_pledged): if self.kind is not EDROpponents.ENEMIES: return if not power or self.powerplay is not power: config = edrconfig.EDRConfig() self.recents = deque( maxlen=config.opponents_max_recents(self.kind)) self.sightings = lrucache.LRUCache( config.lru_max_size(), config.opponents_max_age(self.kind)) self.powerplay = power def is_comms_link_up(self): return self.realtime and self.realtime.is_live() def establish_comms_link(self): self.shutdown_comms_link() if self._invalid_state(): return False endpoint = "{}{}".format(self.server.EDR_SERVER, self._node()) self.realtime = edrrealtime.EDRRealtimeUpdates(self.realtime_callback, self.kind, endpoint, self.server.auth_token) if self.server.preflight_realtime(self.kind): self.realtime.start() return True return False def shutdown_comms_link(self): if self.realtime and self.realtime.is_live(): self.realtime.shutdown() def where(self, cmdr_name): if self._invalid_state(): return None self.__update_opponents_if_stale() cname = cmdr_name.lower() report = self.sightings.get(cname) if not report: report = self.server.where(cmdr_name, self.powerplay) if report: self.sightings.set(cname, report) if report: return { "timestamp": report.get("timestamp", None), "readable": self.__readable_opponent_sighting(report) } else: return None def recent_sightings(self): self.__update_opponents_if_stale() if not self.recents: EDRLOG.log(u"No recently sighted {}".format(self.kind), "INFO") return None EDRLOG.log(u"Got recently sighted {}".format(self.kind), "INFO") summary = [] now = datetime.datetime.now() js_epoch_now = int(1000 * time.mktime(now.timetuple())) processed = [] for sighting in self.recents: if (js_epoch_now - sighting["timestamp"]) // 1000 > self.timespan: continue if sighting["cmdr"] not in processed: summary.append( self.__readable_opponent_sighting(sighting, one_liner=True)) processed.append(sighting["cmdr"]) return summary def __readable_opponent_sighting(self, sighting, one_liner=False): EDRLOG.log(u"sighting: {}".format(sighting), "DEBUG") if not sighting: return None t_minus = edtime.EDTime.t_minus(sighting["timestamp"], short=True) if one_liner: cmdr = (sighting["cmdr"][:29] + u'…') if len(sighting["cmdr"]) > 30 else sighting["cmdr"] starSystem = (sighting["starSystem"][:50] + u'…') if len( sighting["starSystem"]) > 50 else sighting["starSystem"] if sighting.get("bounty", 0) > 0: neat_bounty = EDFineOrBounty(sighting["bounty"]).pretty_print() # Translators: this is a one-liner for the recently sighted opponents; Keep it short! T{t:<2} is to show how long ago e.g. T-4H (4 hours ago) return _( u"{t:<2}: {name} in {system}, wanted for {bounty}").format( t=t_minus, name=cmdr, system=starSystem, bounty=neat_bounty) else: # Translators: this is a one-liner for the recently sighted opponents; Keep it short! T{t:<2} is to show how long ago e.g. T-4H (4 hours ago) return _(u"{t:<2}: {name} in {system}").format( t=t_minus, name=cmdr, system=starSystem) readable = [] # Translators: this is for a recently sighted outlaw; T{t} is to show how long ago, e.g. T-2h43m location = _(u"{t} {name} sighted in {system}").format( t=t_minus, name=sighting["cmdr"], system=sighting["starSystem"]) if sighting["place"] and sighting["place"] != sighting["starSystem"]: if sighting["place"].startswith(sighting["starSystem"] + " "): # Translators: this is a continuation of the previous item (location of recently sighted outlaw) and shows a place in the system (e.g. supercruise, Cleve Hub) location += _(u", {place}").format( place=sighting["place"].partition(sighting["starSystem"] + " ")[2]) else: location += _(u", {place}").format(place=sighting["place"]) readable.append(location) if sighting["ship"] != "Unknown": # Translators: this is for the recently sighted outlaw feature; it shows which ship they were flying at the time readable.append(_(u"Spaceship: {}").format(sighting["ship"])) if sighting.get("bounty", 0) > 0: neat_bounty = EDFineOrBounty(sighting["bounty"]).pretty_print() # Translators: this is for the recently sighted outlaw feature; it shows their bounty if any readable.append(_(u"Wanted for {} credits").format(neat_bounty)) return readable def __are_sightings_stale(self): if self.sightings.last_updated is None: return True now = datetime.datetime.now() epoch_now = time.mktime(now.timetuple()) epoch_updated = time.mktime(self.sightings.last_updated.timetuple()) return (epoch_now - epoch_updated) > self.reports_check_interval def __update_opponents_if_stale(self): updated = False if self.__are_sightings_stale(): now = datetime.datetime.now() missing_seconds = self.timespan if self.sightings.last_updated: missing_seconds = int( min(self.timespan, (now - self.sightings.last_updated).total_seconds())) sightings = None if self.kind is EDROpponents.OUTLAWS: sightings = self.server.recent_outlaws(missing_seconds) elif self.kind is EDROpponents.ENEMIES: sightings = self.server.recent_enemies(missing_seconds, self.powerplay) self.sightings.last_updated = now if sightings: updated = True #TODO can we just append the whole thing? sightings = sorted(sightings, key=lambda t: t["timestamp"], reverse=False) for sighting in sightings: previous = self.sightings.get(sighting["cmdr"].lower()) if not previous or (previous and previous["timestamp"] < sighting["timestamp"]): self.sightings.set(sighting["cmdr"].lower(), sighting) self.recents.appendleft(sighting) return updated def _realtime_callback(self, kind, events): if events not in ["cancel", "auth_revoked"]: for report in events.values(): previous = self.sightings.get(report["cmdr"].lower()) if not previous or (previous and previous["timestamp"] < report["timestamp"]): self.sightings.set(report["cmdr"].lower(), report) self.recents.appendleft(report) self.sightings.last_updated = datetime.datetime.now() self.realtime_callback(kind, events) def _node(self): if self.kind is self.OUTLAWS: return "/v1/outlaws/.json" elif self.kind is self.ENEMIES and self.powerplay: return "/v1/powerplay/{}/enemies/.json".format( self.server.nodify(self.powerplay)) else: return None def _invalid_state(self): return self.kind is EDROpponents.ENEMIES and not self.powerplay
def __init__(self, help_file=None): if help_file: self.content = json.loads( open(utils2to3.abspathmaker(__file__, help_file)).read()) else: self.content = HelpContent.DEFAULT_CONTENT
def soft(self): self.snd_warn = utils2to3.abspathmaker(__file__, 'sounds', 'snd_warn_soft.wav') self.snd_notify = utils2to3.abspathmaker(__file__, 'sounds', 'snd_notify_soft.wav')
def __init__(self, config_file='config/config.ini'): self.config = cp.ConfigParser() self.config.read(utils2to3.abspathmaker(__file__, config_file))
class EDRFactions(object): EDR_FACTIONS_CACHE = utils2to3.abspathmaker(__file__, 'cache', 'edr_factions.v1.p') def __init__(self): edr_config = EDRConfig() try: with open(self.EDR_FACTIONS_CACHE, 'rb') as handle: self.factions_cache = pickle.load(handle) except: self.factions_cache = LRUCache(edr_config.lru_max_size(), edr_config.factions_max_age()) def persist(self): with open(self.EDR_FACTIONS_CACHE, 'wb') as handle: pickle.dump(self.factions_cache, handle, protocol=pickle.HIGHEST_PROTOCOL) def process(self, factions, star_system): factions_in_system = {} for faction in factions: factions_in_system[faction["Name"].lower()] = EDRFaction(faction) self.factions_cache.set(star_system.lower(), factions_in_system) def get(self, name, star_system): factions_in_system = self.get_all(star_system) if factions_in_system: return factions_in_system.get(name.lower(), None) return None def get_all(self, star_system): return self.factions_cache.get(star_system.lower()) def assess(self, star_system, security, population): factions_in_system = self.get_all(star_system) assessments = {} for faction in factions_in_system: assessments[faction] = factions_in_system[faction].assess( security, population) return assessments def summarize_yields(self, star_system, security, population, inventory): assessment = self.assess(star_system, security, population) if not assessment: return None yields = {} for faction_name in assessment: if not assessment[faction_name]: continue faction = self.get(faction_name, star_system) faction_chance = faction.influence state_chance = 1.0 / len( faction.active_states) if faction.active_states else 0.0 chance = faction_chance * state_chance outcomes = assessment[faction_name].outcomes for material in outcomes: if yields.get(material, None) is None: yields[material] = 0 yields[material] += chance return [ u"{:.0f}%: {}".format(chance * 100.0, inventory.oneliner(material.title())) for (material, chance ) in sorted(yields.items(), key=lambda x: x[1], reverse=True) ]
#!/usr/bin/env python # coding=utf-8 from __future__ import absolute_import import gettext import os import sys import utils2to3 CONTEXT_SEPARATOR = u"|" L10N_DIR = utils2to3.abspathmaker(__file__, 'l10n') language = None translate = gettext.translation('edr', L10N_DIR, fallback=True, codeset="utf-8") def set_language(lang): global language, translate language = lang if language: translate = gettext.translation('edr', L10N_DIR, fallback=True, languages=[language], codeset="utf-8") else: translate = gettext.translation('edr', L10N_DIR,
class EDRCmdrs(object): #TODO these should be player and/or squadron specific EDR_CMDRS_CACHE = utils2to3.abspathmaker(__file__, 'cache', 'cmdrs.v7.p') EDR_INARA_CACHE = utils2to3.abspathmaker(__file__, 'cache', 'inara.v7.p') EDR_SQDRDEX_CACHE = utils2to3.abspathmaker(__file__, 'cache', 'sqdrdex.v2.p') def __init__(self, edrserver): self.server = edrserver self._player = EDPlayerOne() self.heartbeat_timestamp = None edr_config = EDRConfig() self._edr_heartbeat = edr_config.edr_heartbeat() try: with open(self.EDR_CMDRS_CACHE, 'rb') as handle: self.cmdrs_cache = pickle.load(handle) except: self.cmdrs_cache = LRUCache(edr_config.lru_max_size(), edr_config.cmdrs_max_age()) try: with open(self.EDR_INARA_CACHE, 'rb') as handle: self.inara_cache = pickle.load(handle) except: self.inara_cache = LRUCache(edr_config.lru_max_size(), edr_config.inara_max_age()) try: with open(self.EDR_SQDRDEX_CACHE, 'rb') as handle: self.sqdrdex_cache = pickle.load(handle) except: self.sqdrdex_cache = LRUCache(edr_config.lru_max_size(), edr_config.sqdrdex_max_age()) @property def player(self): return self._player def player_name(self): return self._player.name def set_player_name(self, new_player_name): if (new_player_name != self._player.name): self._player.force_new_name(new_player_name) self.__update_squadron_info(force_update=True) def player_pledged_to(self, power, time_pledged=0): edr_config = EDRConfig() delta = time_pledged - self._player.time_pledged if self._player.time_pledged else time_pledged if power == self._player.power and delta <= edr_config.noteworthy_pledge_threshold( ): EDRLOG.log( u"Skipping pledged_to (not noteworthy): current vs. proposed {} vs. {}; {} vs {}" .format(self._player.power, power, self._player.time_pledged, time_pledged), "DEBUG") return False self._player.pledged_to(power, time_pledged) since = self._player.pledged_since() return self.server.pledged_to(power, since) def __squadron_id(self): self.__update_squadron_info() info = self._player.squadron_info() return info["squadronId"] if info else None def __update_squadron_info(self, force_update=False): if self.server.is_anonymous(): return mark_twain_flag = int( (EDTime.js_epoch_now() - self.heartbeat_timestamp) / 1000) >= self._edr_heartbeat if self.heartbeat_timestamp else True if force_update or mark_twain_flag: info = self.server.heartbeat() if info: self.heartbeat_timestamp = info[ "heartbeat"] if "heartbeat" in info else EDTime.js_epoch_now( ) self._player.squadron_member( info) if "squadronId" in info else self._player.lone_wolf( ) else: self.heartbeat_timestamp = EDTime.js_epoch_now() self._player.lone_wolf() def persist(self): with open(self.EDR_CMDRS_CACHE, 'wb') as handle: pickle.dump(self.cmdrs_cache, handle, protocol=pickle.HIGHEST_PROTOCOL) with open(self.EDR_INARA_CACHE, 'wb') as handle: pickle.dump(self.inara_cache, handle, protocol=pickle.HIGHEST_PROTOCOL) with open(self.EDR_SQDRDEX_CACHE, 'wb') as handle: pickle.dump(self.sqdrdex_cache, handle, protocol=pickle.HIGHEST_PROTOCOL) def evict(self, cmdr): try: del self.cmdrs_cache[cmdr.lower()] except KeyError: pass try: del self.inara_cache[cmdr.lower()] except KeyError: pass try: sqdr_id = self.__squadron_id() if sqdr_id: sq_cmdr_key = u"{}:{}".format(sqdr_id, cmdr.lower()) del self.sqdrdex_cache[sq_cmdr_key] except KeyError: pass def __edr_cmdr(self, cmdr_name, autocreate): profile = self.cmdrs_cache.get(cmdr_name.lower()) cached = self.cmdrs_cache.has_key(cmdr_name.lower()) if cached or profile: EDRLOG.log( u"Cmdr {cmdr} is in the EDR cache with id={cid}".format( cmdr=cmdr_name, cid=profile.cid if profile else 'N/A'), "DEBUG") return profile profile = self.server.cmdr(cmdr_name, autocreate) if not profile: self.cmdrs_cache.set(cmdr_name.lower(), None) EDRLOG.log( u"No match on EDR. Temporary entry to be nice on EDR's server.", "DEBUG") return None dex_profile = self.server.cmdrdex(profile.cid) if dex_profile: EDRLOG.log( u"EDR CmdrDex entry found for {cmdr}: {id}".format( cmdr=cmdr_name, id=profile.cid), "DEBUG") profile.dex(dex_profile) self.cmdrs_cache.set(cmdr_name.lower(), profile) EDRLOG.log( u"Cached EDR profile {cmdr}: {id}".format(cmdr=cmdr_name, id=profile.cid), "DEBUG") return profile def __edr_sqdrdex(self, cmdr_name, autocreate): sqdr_id = self.__squadron_id() if not sqdr_id: return None key = u"{}:{}".format(sqdr_id, cmdr_name.lower()) profile = self.sqdrdex_cache.get(key) if profile: EDRLOG.log( u"Cmdr {cmdr} is in the EDR IFF cache for squadron {sqid} with key {key}" .format(cmdr=cmdr_name, sqid=sqdr_id, key=key), "DEBUG") return profile profile = self.__edr_cmdr(cmdr_name, autocreate) if not profile: return None sqdrdex_dict = self.server.sqdrdex(sqdr_id, profile.cid) if sqdrdex_dict: EDRLOG.log( u"EDR SqdrDex {sqid} entry found for {cmdr}@{cid}".format( sqid=sqdr_id, cmdr=cmdr_name, cid=profile.cid), "DEBUG") profile.sqdrdex(sqdrdex_dict) self.sqdrdex_cache.set(u"{}:{}".format(sqdr_id, cmdr_name.lower()), profile) EDRLOG.log( u"Cached EDR SqdrDex {sqid} entry for {cmdr}@{cid}".format( sqid=sqdr_id, cmdr=cmdr_name, cid=profile.cid), "DEBUG") return profile.sqdrdex_profile def __inara_cmdr(self, cmdr_name, check_inara_server): inara_profile = None stale = self.inara_cache.is_stale(cmdr_name.lower()) cached = self.inara_cache.has_key(cmdr_name.lower()) if cached and not stale: inara_profile = self.inara_cache.get(cmdr_name.lower()) EDRLOG.log( u"Cmdr {} is in the Inara cache (name={})".format( cmdr_name, inara_profile.name if inara_profile else 'N/A'), "DEBUG") elif check_inara_server: EDRLOG.log( u"Stale {} or not cached {} in Inara cache. Inara API call for {}." .format(stale, cached, cmdr_name), "INFO") inara_profile = self.server.inara_cmdr(cmdr_name) if inara_profile and inara_profile.name.lower() == cmdr_name.lower( ): self.inara_cache.set(cmdr_name.lower(), inara_profile) EDRLOG.log( u"Cached Inara profile {}: {},{},{},{}".format( cmdr_name, inara_profile.name, inara_profile.squadron, inara_profile.role, inara_profile.powerplay), "DEBUG") elif self.inara_cache.has_key(cmdr_name.lower()): inara_profile = self.inara_cache.peek(cmdr_name.lower()) self.inara_cache.refresh(cmdr_name.lower()) EDRLOG.log(u"Refresh and re-use stale match in Inara cache.", "INFO") else: inara_profile = None self.inara_cache.set(cmdr_name.lower(), None) EDRLOG.log( u"No match on Inara. Temporary entry to be nice on Inara's server.", "INFO") return inara_profile def cmdr(self, cmdr_name, autocreate=True, check_inara_server=False): profile = self.__edr_cmdr(cmdr_name, autocreate) inara_profile = self.__inara_cmdr(cmdr_name, check_inara_server) if profile is None: if inara_profile is None: EDRLOG.log( u"Failed to retrieve/create cmdr {}".format(cmdr_name), "ERROR") return None else: return inara_profile if inara_profile: EDRLOG.log( u"Combining info from EDR and Inara for cmdr {}".format( cmdr_name), "INFO") profile.complement(inara_profile) squadron_profile = self.__edr_sqdrdex(cmdr_name, autocreate) if squadron_profile: EDRLOG.log( u"Combining info from Squadron for cmdr {}".format(cmdr_name), "INFO") profile.sqdrdex(squadron_profile.sqdrdex_dict()) return profile def is_friend(self, cmdr_name): profile = self.__edr_cmdr(cmdr_name, False) if profile is None: return False return profile.is_friend() def is_ally(self, cmdr_name): sqdr_id = self.__squadron_id() if not sqdr_id: return False profile = self.__edr_sqdrdex(cmdr_name, False) if profile: return profile.is_ally() return False def tag_cmdr(self, cmdr_name, tag): if tag in ["enemy", "ally"]: return self.__squadron_tag_cmdr(cmdr_name, tag) else: return self.__tag_cmdr(cmdr_name, tag) def contracts(self): return self.server.contracts() def contract_for(self, cmdr_name): if not cmdr_name: return False profile = self.cmdr(cmdr_name) if not profile: return False return self.server.contract_for(profile.cid) def place_contract(self, cmdr_name, reward): if not cmdr_name: return False if reward <= 0: return self.remove_contract(cmdr_name) profile = self.cmdr(cmdr_name) if not profile: return False return self.server.place_contract(profile.cid, { "cname": cmdr_name.lower(), "reward": reward }) def remove_contract(self, cmdr_name): if not cmdr_name: return False profile = self.cmdr(cmdr_name) if not profile: return False return self.server.remove_contract(profile.cid) def __tag_cmdr(self, cmdr_name, tag): EDRLOG.log(u"Tagging {} with {}".format(cmdr_name, tag), "DEBUG") profile = self.__edr_cmdr(cmdr_name, False) if profile is None: EDRLOG.log(u"Couldn't find a profile for {}.".format(cmdr_name), "DEBUG") return False tagged = profile.tag(tag) if not tagged: EDRLOG.log( u"Couldn't tag {} with {} (e.g. already tagged)".format( cmdr_name, tag), "DEBUG") self.evict(cmdr_name) return False dex_dict = profile.dex_dict() EDRLOG.log(u"New dex state: {}".format(dex_dict), "DEBUG") success = self.server.update_cmdrdex(profile.cid, dex_dict) self.evict(cmdr_name) return success def __squadron_tag_cmdr(self, cmdr_name, tag): sqdr_id = self.__squadron_id() if not sqdr_id: EDRLOG.log(u"Can't tag: not a member of a squadron", "DEBUG") return False EDRLOG.log(u"Tagging {} with {} for squadron".format(cmdr_name, tag), "DEBUG") profile = self.__edr_sqdrdex(cmdr_name, False) if profile is None: EDRLOG.log( u"Couldn't find a squadron profile for {}.".format(cmdr_name), "DEBUG") return False tagged = profile.tag(tag) if not tagged: EDRLOG.log( u"Couldn't tag {} with {} (e.g. already tagged)".format( cmdr_name, tag), "DEBUG") self.evict(cmdr_name) return False sqdrdex_dict = profile.sqdrdex_dict() EDRLOG.log(u"New dex state: {}".format(sqdrdex_dict), "DEBUG") augmented_sqdrdex_dict = sqdrdex_dict augmented_sqdrdex_dict["level"] = self._player.squadron_info( )["squadronLevel"] augmented_sqdrdex_dict["by"] = self._player.name success = self.server.update_sqdrdex(sqdr_id, profile.cid, augmented_sqdrdex_dict) self.evict(cmdr_name) return success def memo_cmdr(self, cmdr_name, memo): if memo is None: return self.clear_memo_cmdr(cmdr_name) EDRLOG.log(u"Writing a note about {}: {}".format(memo, cmdr_name), "DEBUG") profile = self.__edr_cmdr(cmdr_name, False) if profile is None: EDRLOG.log(u"Couldn't find a profile for {}.".format(cmdr_name), "DEBUG") return False noted = profile.memo(memo) if not noted: EDRLOG.log(u"Couldn't write a note about {}".format(cmdr_name), "DEBUG") self.evict(cmdr_name) return False dex_dict = profile.dex_dict() success = self.server.update_cmdrdex(profile.cid, dex_dict) self.evict(cmdr_name) return success def clear_memo_cmdr(self, cmdr_name): EDRLOG.log(u"Removing a note from {}".format(cmdr_name), "DEBUG") profile = self.__edr_cmdr(cmdr_name, False) if profile is None: EDRLOG.log(u"Couldn't find a profile for {}.".format(cmdr_name), "DEBUG") return False noted = profile.remove_memo() if not noted: EDRLOG.log(u"Couldn't remove a note from {}".format(cmdr_name), "DEBUG") self.evict(cmdr_name) return False dex_dict = profile.dex_dict() success = self.server.update_cmdrdex(profile.cid, dex_dict) self.evict(cmdr_name) return success def untag_cmdr(self, cmdr_name, tag): if tag in ["enemy", "ally"]: return self.__squadron_untag_cmdr(cmdr_name, tag) else: return self.__untag_cmdr(cmdr_name, tag) def __untag_cmdr(self, cmdr_name, tag): EDRLOG.log(u"Removing {} tag from {}".format(tag, cmdr_name), "DEBUG") profile = self.__edr_cmdr(cmdr_name, False) if profile is None: EDRLOG.log(u"Couldn't find a profile for {}.".format(cmdr_name), "DEBUG") return False untagged = profile.untag(tag) if not untagged: EDRLOG.log( u"Couldn't untag {} (e.g. tag not present)".format(cmdr_name), "DEBUG") self.evict(cmdr_name) return False dex_dict = profile.dex_dict() EDRLOG.log(u"New dex state: {}".format(dex_dict), "DEBUG") success = self.server.update_cmdrdex(profile.cid, dex_dict) self.evict(cmdr_name) return success def __squadron_untag_cmdr(self, cmdr_name, tag): sqdr_id = self.__squadron_id() if not sqdr_id: EDRLOG.log(u"Can't untag: not a member of a squadron", "DEBUG") return False EDRLOG.log(u"Removing {} tag from {}".format(tag, cmdr_name), "DEBUG") profile = self.__edr_cmdr(cmdr_name, False) if profile is None: EDRLOG.log(u"Couldn't find a profile for {}.".format(cmdr_name), "DEBUG") return False untagged = profile.untag(tag) if not untagged: EDRLOG.log( u"Couldn't untag {} (e.g. tag not present)".format(cmdr_name), "DEBUG") self.evict(cmdr_name) return False sqdrdex_dict = profile.sqdrdex_dict() EDRLOG.log(u"New dex state: {}".format(sqdrdex_dict), "DEBUG") augmented_sqdrdex_dict = sqdrdex_dict augmented_sqdrdex_dict["level"] = self._player.squadron_info( )["squadronLevel"] augmented_sqdrdex_dict["by"] = self._player.name success = self.server.update_sqdrdex(sqdr_id, profile.cid, augmented_sqdrdex_dict) self.evict(cmdr_name) return success
def __init__(self, config_file='config/user_config.ini'): self.config = cp.ConfigParser() try: self.config.read(utils2to3.abspathmaker(__file__, config_file)) except: self.config = None
class EDRMiningStats(object): MINERALS_LUT = json.loads(open(utils2to3.abspathmaker(__file__, 'data', 'mining.json')).read()) def __init__(self): self.lmh = {"-": 0, "L": 0, "M": 0, "H": 0} self.prospected_nb = 0 self.max_efficiency = 150 now = EDTime.py_epoch_now() self.start = now self.current = now self.last = {"timestamp": now, "raw": None, "materials": None, "minerals_stats": []} self.depleted = False self.of_interest = { "names": set(), "types": set()} self.stats = {} self.refined_nb = 0 self.prospected_raw_history = deque(maxlen=8) # 8 max prospector drones self.efficiency = deque(maxlen=20) self.mineral_types_lut = {} for mineral in self.MINERALS_LUT: name = self.MINERALS_LUT[mineral]["name"] internal_name = self.MINERALS_LUT[mineral]["type"] self.mineral_types_lut[internal_name] = name symbol = self.MINERALS_LUT[mineral]["symbol"] self.of_interest["names"].add(name) self.of_interest["types"].add(internal_name) self.stats[mineral] = EDRMineralStats(name, internal_name, symbol) def reset(self): self.lmh = {"-": 0, "L": 0, "M": 0, "H": 0} self.prospected_nb = 0 self.max_efficiency = 150 now = EDTime.py_epoch_now() self.start = now self.current = now self.refined_nb = 0 self.last = {"timestamp": now, "raw": None, "materials": None, "minerals_stats": []} self.depleted = False self.of_interest = { "names": set(), "types": set()} self.stats = {} self.prospected_raw_history = deque(maxlen=8) # 8 max prospector drones self.mineral_types_lut = {} for mineral in self.MINERALS_LUT: name = self.MINERALS_LUT[mineral]["name"] internal_name = self.MINERALS_LUT[mineral]["type"] self.mineral_types_lut[internal_name] = name symbol = self.MINERALS_LUT[mineral]["symbol"] self.of_interest["names"].add(name) self.of_interest["types"].add(internal_name) self.stats[mineral] = EDRMineralStats(name, internal_name, symbol) def prospected(self, entry): if entry.get("event", None) != "ProspectedAsteroid": return False if entry.get("Remaining", 0) <= 0: self.depleted = True return False self.depleted = False if self.__probably_previously_prospected(entry): return False self.prospected_raw_history.append(entry) now = EDTime.py_epoch_now() self.current = now self.prospected_nb += 1 self.__update_efficiency() lut_content = { "n/a": "-", "$AsteroidMaterialContent_Low;": "L", "$AsteroidMaterialContent_Medium;": "M", "$AsteroidMaterialContent_High;": "H" } key = lut_content.get(entry.get("Content", "-"), "-") self.lmh[key] += 1 materials = entry.get("Materials", []) self.last = { "timestamp": now, "raw": key, "materials": len(materials), "minerals_stats": [] } for material in materials: cname = material.get("Name", "").lower() if cname in self.of_interest["names"]: proportion = material.get("Proportion", 0.0) self.stats[cname].prospected(proportion) self.last["minerals_stats"].append(self.stats[cname]) def __probably_previously_prospected(self, entry): b = entry.copy() b["timestamp"] = "" b["Remaining"] = "" matching_entry = None for previous in self.prospected_raw_history: a = previous.copy() a["timestamp"] = "" a["Remaining"] = "" if a == b and previous["Remaining"] >= entry["Remaining"]: matching_entry = previous break if matching_entry: max_age = 60*5 a_time = EDTime() a_time.from_journal_timestamp(matching_entry["timestamp"]) b_time = EDTime() b_time.from_journal_timestamp(entry["timestamp"]) return (b_time.as_py_epoch() - a_time.as_py_epoch()) <= max_age return False def refined(self, entry): if entry.get("event", None) != "MiningRefined": return now = EDTime.py_epoch_now() self.current = now if entry.get("Type", "").lower() not in self.of_interest["types"]: return self.refined_nb += 1 self.__update_efficiency() cinternal_name = entry.get("Type", "").lower() if cinternal_name in self.of_interest["types"]: cname = self.minerals_types_lut[cinternal_name] self.stats[cname].refined() def last_max(): if not self.last["minerals_stats"]: return self.max return self.last["mineral_stats"][0].max def item_per_hour(self): now = EDTime.py_epoch_now() self.current = now elapsed_time = self.current - self.start if elapsed_time: return self.refined_nb / (elapsed_time / 3600.0) return 0 def last_yield_average(self): if self.prospected_nb <= 0: return 0.0 if not self.last["minerals_stats"]: return (self.sum / self.prospected_nb)*100.0 return self.last["minerals_stats"][0].yield_average(self.prospected_nb) def __update_efficiency(self): now = EDTime.py_epoch_now() efficiency = self.mineral_per_hour() self.efficiency.append((now, efficiency)) self.max_efficiency = max(self.max_efficiency, efficiency) def __repr__(self): return str(self.__dict__)
class EDRAutoUpdater(object): REPO = "lekeno/edr" UPDATES = utils2to3.abspathmaker(__file__, 'updates') LATEST = utils2to3.abspathmaker(__file__, 'updates', 'latest.zip') BACKUP = utils2to3.abspathmaker(__file__, 'backup') EDR_PATH = os.path.abspath(os.path.dirname(__file__)) def __init__(self): self.updates = EDRAutoUpdater.UPDATES self.output = EDRAutoUpdater.LATEST def download_latest(self): if not os.path.exists(self.updates): try: os.makedirs(self.updates) except OSError as e: if e.errno != errno.EEXIST: return False download_url = self.__latest_release_url() if not download_url: return False response = requests.get(download_url, stream=True) response.raise_for_status() if response.status_code != requests.codes.ok: return False with open(self.output, 'wb') as handle: for block in response.iter_content(32768): handle.write(block) return True def clean_old_backups(self): files = os.listdir(EDRAutoUpdater.BACKUP) files = [os.path.join(EDRAutoUpdater.BACKUP, f) for f in files] files.sort(key=lambda x: os.path.getctime(x)) nbfiles = len(files) max_backups = 5 for i in range(0, nbfiles - max_backups): f = files[i] EDRLOG.log(u"Removing backup {}".format(f), "INFO") os.unlink(f) def make_backup(self): if not os.path.exists(EDRAutoUpdater.BACKUP): try: os.makedirs(EDRAutoUpdater.BACKUP) except OSError as e: if e.errno != errno.EEXIST: return False name = datetime.datetime.now().strftime('%Y-%m-%d-%H-%M-%S') + '.zip' backup_file = os.path.join(EDRAutoUpdater.BACKUP, name) zipf = zipfile.ZipFile(backup_file, 'w', zipfile.ZIP_DEFLATED) self.__zipdir(EDRAutoUpdater.EDR_PATH, zipf) zipf.close() def __zipdir(self, path, ziph): for root, dirs, files in os.walk(path): dirs[:] = [d for d in dirs if (("updates" not in d) and ("backup" not in d))] for file in files: if file.endswith(".pyc") or file.endswith(".pyo"): continue fp = os.path.join(root, file) ziph.write(fp, os.path.relpath(fp, EDRAutoUpdater.EDR_PATH)) def extract_latest(self): with zipfile.ZipFile(self.output, "r") as latest: latest.extractall(EDRAutoUpdater.EDR_PATH) def __latest_release_url(self): latest_release_api = "https://api.github.com/repos/{}/releases/latest".format(self.REPO) response = requests.get(latest_release_api) if response.status_code != requests.codes.ok: EDRLOG.log(u"Couldn't check the latest release on github: {}".format(response.status_code), "WARNING") return None json_resp = json.loads(response.content) assets = json_resp.get("assets", None) if not assets: return None return assets[0].get("browser_download_url", None)
import json import re import os import edrlog import edmodule from edri18n import _ import utils2to3 EDRLOG = edrlog.EDRLog() POWER_DATA = json.loads( open(utils2to3.abspathmaker(__file__, 'data', 'modules_power_data.json')).read()) class EDRXzibit(object): def __init__(self, vehicle): EDRLOG.log(u"Xzibit is checking your ship", "DEBUG") self.power_capacity = vehicle.power_capacity EDRLOG.log(u" Power cap: {}".format(self.power_capacity), "DEBUG") self.per_prio = { "1": { "modules": [] }, "2": { "modules": [] }, "3": { "modules": [] }, "4": { "modules": []
class EDVehicleFactory(object): __vehicle_classes = { "sidewinder": EDSidewinder, "eagle": EDEagle, "hauler": EDHauler, "adder": EDAdder, "viper": EDViperMkIII, "cobramkiii": EDCobraMkIII, "type6": EDT6Transporter, "dolphin": EDDolphin, "type7": EDT7Transporter, "asp": EDAspExplorer, "vulture": EDVulture, "empire_trader": EDImperialClipper, "federation_dropship": EDFederalDropship, "orca": EDOrca, "type9": EDT9Heavy, "type9_military": EDT10Defender, "python": EDPython, "belugaliner": EDBelugaLiner, "ferdelance": EDFerDeLance, "anaconda": EDAnaconda, "federation_corvette": EDFederalCorvette, "cutter": EDImperialCutter, "diamondback": EDDiamondbackScout, "empire_courier": EDImperialCourier, "diamondbackxl": EDDiamondbackExplorer, "empire_eagle": EDImperialEagle, "federation_dropship_mkii": EDFederalAssaultShip, "federation_gunship": EDFederalGunship, "viper_mkiv": EDViperMkIV, "cobramkiv": EDCobraMkIV, "independant_trader": EDKeelback, "asp_scout": EDAspScout, "typex": EDAllianceChieftain, "typex_2": EDAllianceCrusader, "typex_3": EDAllianceChallenger, "krait_mkii": EDKraitMkII, "krait_light": EDKraitPhantom, "mamba": EDMamba, "empire_fighter": EDImperialFighter, "federation_fighter": EDF63Condor, "independent_fighter": EDTaipanFighter, "gdn_hybrid_fighter_v1": EDTrident, "gdn_hybrid_fighter_v2": EDJavelin, "gdn_hybrid_fighter_v3": EDLance, "testbuggy": EDSRV, "unknown": EDUnknownVehicle, "unknown (crew)": EDCrewUnknownVehicle, "unknown (captain)": EDCaptainUnknownVehicle } CANONICAL_SHIP_NAMES = json.loads( open(utils2to3.abspathmaker(__file__, 'data', 'shipnames.json')).read()) CANONICAL_MODULE_NAMES = json.loads( open(utils2to3.abspathmaker(__file__, 'data', 'modulenames.json'), encoding="utf-8", errors='ignore').read()) @staticmethod def canonicalize(name): if name is None: return u"Unknown" # Note: this shouldn't be translated if name in EDVehicleFactory.CANONICAL_SHIP_NAMES.values(): return name # Already canonical if name.lower() in EDVehicleFactory.CANONICAL_SHIP_NAMES: return EDVehicleFactory.CANONICAL_SHIP_NAMES[name.lower()] return name.lower() @staticmethod def normalize_module_name(name): normalized = name.lower() # suffix _name or _name; is not used in loadout or afmurepair events if normalized.endswith(u"_name"): useless_suffix_length = len(u"_name") normalized = normalized[:-useless_suffix_length] elif normalized.endswith(u"_name;"): useless_suffix_length = len(u"_name;") normalized = normalized[:-useless_suffix_length] if normalized.startswith(u"$"): normalized = normalized[1:] # just get rid of prefixes because sometimes int_ becomes ext_ depending on the event if normalized.startswith((u"int_", u"ext_", u"hpt_")): normalized = normalized[4:] return normalized @staticmethod def readable_module_names(name): if name is None: return u"Unknown" # Note: this shouldn't be translated if name in EDVehicleFactory.CANONICAL_MODULE_NAMES.values(): return name # Already canonical normalized = EDVehicleFactory.normalize_module_name(name) if normalized in EDVehicleFactory.CANONICAL_MODULE_NAMES: return ( EDVehicleFactory.CANONICAL_MODULE_NAMES[normalized]["name"], EDVehicleFactory.CANONICAL_MODULE_NAMES[normalized] ["shortname"]) match = re.search( '([a-zA-Z_]*)_size([0-9])_class([0-9])_?([a-zA-Z_]*)?', normalized) if match: class_letter = chr(70 - int(match.group(3))) synthetic_name = "" if match.group(4): synthetic_name = u"{} {} ({}{})".format( match.group(1), match.group(4), match.group(2), class_letter) else: synthetic_name = u"{} ({}{})".format(match.group(1), match.group(2), class_letter) return (synthetic_name, synthetic_name) return (normalized.lower(), normalized.lower()) @staticmethod def module_tags(name): if name is None: return {} normalized = EDVehicleFactory.normalize_module_name(name) if normalized not in EDVehicleFactory.CANONICAL_MODULE_NAMES: return {} return EDVehicleFactory.CANONICAL_MODULE_NAMES[normalized].get( "tags", {}) @staticmethod def from_edmc_state(state): name = state.get('ShipType', None) if name is None: name = 'unknown' vehicle_class = EDVehicleFactory.__vehicle_classes.get( name.lower(), None) if vehicle_class is None: raise NotImplementedError( "The requested vehicle has not been implemented") vehicle = vehicle_class() vehicle.id = state.get('ShipID', None) vehicle.identity = state.get('ShipIdent', None) vehicle.name = state.get('ShipName', None) vehicle.hull_value = state.get('HullValue', None) vehicle.rebuy = state.get('Rebuy', None) modules = state.get('Modules', None) if modules: for module in modules: health = modules[module][ 'Health'] * 100.0 if 'Health' in modules[module] else None vehicle.subsystem_health(modules[module].get('Item', None), health) return vehicle @staticmethod def from_internal_name(internal_name): return EDVehicleFactory.__vehicle_classes.get(internal_name.lower(), EDUnknownVehicle)() @staticmethod def from_load_game_event(event): vehicle = EDVehicleFactory.from_internal_name( event.get("Ship", 'unknown')) vehicle.id = event.get('ShipID', None) vehicle.identity = event.get('ShipIdent', None) vehicle.name = event.get('ShipName', None) vehicle.fuel_capacity = event.get('FuelCapacity', None) vehicle.fuel_level = event.get('FuelLevel', None) return vehicle @staticmethod def from_loadout_event(event): vehicle = EDVehicleFactory.from_internal_name( event.get("Ship", 'unknown')) vehicle.id = event.get('ShipID', None) vehicle.identity = event.get('ShipIdent', None) vehicle.name = event.get('ShipName', None) vehicle.hull_health = event.get( 'HullHealth', None) * 100.0 # normalized to 0.0 ... 1.0 vehicle.fuel_capacity = event.get('FuelCapacity', None) #missing from loadout event... vehicle.fuel_level = event.get('FuelLevel', None) #missing from loadout event... if not 'Modules' in event: return vehicle modules = event['Modules'] for module in modules: health = modules[module]['Health'] * 100.0 if 'Health' in modules[ module] else None vehicle.subsystem_health(modules[module].get('Item', None), health) return vehicle @staticmethod def from_stored_ship(ship_info): vehicle = EDVehicleFactory.from_internal_name( ship_info.get("ShipType", 'unknown')) vehicle.id = ship_info.get('ShipID', None) vehicle.name = ship_info.get('Name', None) vehicle.value = ship_info.get('Value', None) vehicle.hot = ship_info.get('Hot', None) return vehicle @staticmethod def is_ship_launched_fighter(vehicle): return isinstance(vehicle, EDShipLaunchedFighter) @staticmethod def is_surface_vehicle(vehicle): return isinstance(vehicle, EDSurfaceVehicle) @staticmethod def unknown_vehicle(): return EDUnknownVehicle() @staticmethod def default_srv(): return EDSRV() @staticmethod def unknown_slf(): return EDShipLaunchedFighter()
class EDPlayerOne(EDPlayer): EDR_FLEET_CARRIER_CACHE = utils2to3.abspathmaker(__file__, 'cache', 'fleet_carrier.v1.p') def __init__(self, name=None): super(EDPlayerOne, self).__init__(name) self.powerplay = None self.game_mode = None self.private_group = None self.previous_mode = None self.previous_wing = set() self.from_genesis = False self.wing = EDWing() self.friends = set() self.crew = None self._target = None self.instance = EDInstance() self.planetary_destination = None self.recon_box = EDReconBox() self.inventory = EDRInventory() self.fleet = edrfleet.EDRFleet() try: with open(self.EDR_FLEET_CARRIER_CACHE, 'rb') as handle: self.fleet_carrier = pickle.load(handle) except: self.fleet_carrier = edrfleetcarrier.EDRFleetCarrier() self.mining_stats = edrminingstats.EDRMiningStats() def __repr__(self): return str(self.__dict__) def persist(self): self.inventory.persist() with open(self.EDR_FLEET_CARRIER_CACHE, 'wb') as handle: pickle.dump(self.fleet_carrier, handle, protocol=pickle.HIGHEST_PROTOCOL) @property def target(self): return self._target @target.setter def target(self, new_target): if self._target: self._target.targeted = False self._target._touch() self._target = new_target if new_target: new_target.targeted = True new_target._touch() self._touch() def lowish_fuel(self): if self.mothership.fuel_level is None or self.mothership.fuel_capacity is None: return True # Better safe than sorry return (self.mothership.fuel_level / self.mothership.fuel_capacity) <= 0.3 def heavily_damaged(self): if self.mothership.hull_health is None: return True # Better safe than sorry return self.mothership.hull_health <= 50 def json(self, fuel_info=False, with_target=False): result = { u"cmdr": self.name, u"timestamp": self.timestamp * 1000, u"wanted": self.wanted, u"bounty": self.bounty, u"starSystem": self.star_system, u"place": self.place, u"wingof": len(self.wing.wingmates), u"wing": self.wing.noteworthy_changes_json(self.instance), u"byPledge": self.powerplay.canonicalize() if self.powerplay else u'', u"ship": self.piloted_vehicle.json(fuel_info=fuel_info), u"mode": self.game_mode, u"group": self.private_group } if with_target: result[u"target"] = self.target.json() if self.target else {} result[u"crew"] = [] if self.crew: result[u"crew"] = [{ u"cmdr": crew_member } for crew_member in self.crew.all_members()] return result def force_new_name(self, new_name): self._name = new_name def in_solo_or_private(self): return self.game_mode in [u"Solo", u"Group"] def in_solo(self): return self.game_mode == u"Solo" def in_open(self): return self.game_mode == u"Open" def inception(self, genesis=False): if genesis: self.from_genesis = True self.previous_mode = None self.previous_wing = set() self.wing = EDWing() self.crew = None self.destroyed = False self.target = None self.wanted = False self.mothership = EDVehicleFactory.unknown_vehicle() self.piloted_vehicle = self.mothership self.srv = None self.slf = None self.location = EDLocation() self._bounty = None self.instance.reset() self.to_normal_space() self._touch() self.reset_mining_stats() def killed(self): super(EDPlayerOne, self).killed() self.previous_mode = self.game_mode self.previous_private_group = self.private_group self.previous_wing = self.wing.wingmates.copy() self.game_mode = None self.private_group = None self.wing = EDWing() self.crew = None self.target = None self.instance.reset() self.recon_box.reset() self._touch() def resurrect(self, rebought=True): self.game_mode = self.previous_mode self.private_group = self.previous_private_group self.wing = EDWing(self.previous_wing) self.previous_mode = None self.previous_wing = set() self.destroyed = False self.target = None self.to_normal_space() self.instance.reset() self._touch() if rebought: self.mothership.reset() if self.slf: self.slf.reset() if self.srv: self.srv.reset() else: self.mothership = EDVehicleFactory.unknown_vehicle() self.piloted_vehicle = self.mothership self.slf = None self.srv = None def is_crew_member(self): if not self.crew: return False return self.crew.captain != self.name def in_a_crew(self): return self.crew is not None def leave_wing(self): self.wing.leave() self._touch() def join_wing(self, others): self.wing.join(others) self.crew = None self._touch() def add_to_wing(self, other): self.wing.add(other) self._touch() def in_a_wing(self): return self.wing.formed() def leave_crew(self): self._touch() if not self.crew: return self.crew = None self.instance.reset() def disband_crew(self): self._touch() if not self.crew: return for member in self.crew.members: self.instance.player_out(member) self.crew.disband() def join_crew(self, captain): self.wing = EDWing() self.instance.reset() self.crew = EDRCrew(captain) self.crew.add(self.name) self.instanced(captain) self.mothership = EDVehicleFactory.unknown_vehicle() self.piloted_vehicle = self.mothership self.slf = None self.srv = None self._touch() def add_to_crew(self, member): self._touch() if not self.crew: self.crew = EDRCrew(self.name) self.wing = EDWing() self.instance.reset() self.instanced(member) return self.crew.add(member) def remove_from_crew(self, member): self._touch() if not self.crew: self.crew = EDRCrew(self.name) self.wing = EDWing() self.instance.reset() self.instance.player_out(member) return self.crew.remove(member) def crew_time_elapsed(self, member): if not self.crew: return 0 return self.crew.duration(member) def is_captain(self, member=None): if not self.crew: return False if not member: member = self.name return self.crew.is_captain(member) def is_friend(self, cmdr_name): return cmdr_name in self.friends def is_wingmate(self, cmdr_name): return cmdr_name in self.wing.wingmates def is_crewmate(self, cmdr_name): if not self.crew: return False return cmdr_name in self.crew.all_members() def is_enemy_with(self, power): if self.is_independent() or not power: return False return self.powerplay.is_enemy(power) def to_normal_space(self): if self.in_normal_space(): return super(EDPlayerOne, self).to_normal_space() self.instance.reset() def to_super_space(self): if self.in_supercruise(): return super(EDPlayerOne, self).to_super_space() self.instance.reset() self.recon_box.reset() def to_hyper_space(self): if self.in_hyper_space(): return super(EDPlayerOne, self).to_hyper_space() self.instance.reset() self.recon_box.reset() def wing_and_crew(self): wing_and_crew = self.wing.wingmates.copy() if self.crew: wing_and_crew.update(self.crew.all_members()) return wing_and_crew def maybe_in_a_pvp_fight(self): if not self.in_a_fight(): return False if self.instance.is_empty(): # Can't PvP if there is no one. return False if not self.instance.anyone_beside(self.wing_and_crew()): return False return True def leave_vehicle(self): self.mothership = EDVehicleFactory.unknown_vehicle() self.piloted_vehicle = self.mothership self.slf = None self.srv = None self.instance.reset() self.recon_box.reset() self._touch() def targeting(self, cmdr): self.instance.player_in(cmdr) self.target = cmdr self._touch() def destroy(self, cmdr): self._touch() cmdr.killed() self.instance.player_out(cmdr.name) if self.target and self.target.name == cmdr.name: self.target = None def interdiction(self, interdicted, success): self._touch() self.to_normal_space() if success: interdicted.location = self.location self.instance.player_in(interdicted) else: self.recon_box.reset() def interdicted(self, interdictor, success): self._touch() if success: self.to_normal_space() interdictor.location = self.location self.instance.player_in(interdictor) else: self.instance.player_out(interdictor.cmdr_name) self.recon_box.reset() def is_instanced_with(self, cmdr_name): return self.instance.player(cmdr_name) != None def instanced(self, cmdr_name, ship_internal_name=None, piloted=True): self._touch() cmdr = self.instance.player(cmdr_name) if not cmdr: cmdr = EDPlayer(cmdr_name) cmdr.location = self.location if ship_internal_name: vehicle = EDVehicleFactory.from_internal_name(ship_internal_name) cmdr.update_vehicle_if_obsolete(vehicle, piloted) self.instance.player_in(cmdr) return cmdr def deinstanced(self, cmdr_name): self._touch() self.instance.player_out(cmdr_name) def attacked(self, target): self._touch() if target == u"Mothership": self.mothership.attacked() elif target == u"Fighter": if self.slf: self.slf.attacked() else: EDRLOG.log(u"SLF attacked but player had none", u"WARNING") elif target == u"You": self.piloted_vehicle.attacked() def update_fleet(self, stored_ships_entry): self.fleet.update(stored_ships_entry) def prospected(self, entry): self.mining_stats.prospected(entry) def refined(self, entry): self.mining_stats.refined(entry) def reset_mining_stats(self): self.mining_stats.reset()
class EDRInventory(object): EDR_INVENTORY_ENCODED_CACHE = utils2to3.abspathmaker( __file__, 'cache', 'encoded_mats.v1.p') EDR_INVENTORY_RAW_CACHE = utils2to3.abspathmaker(__file__, 'cache', 'raw_mats.v1.p') EDR_INVENTORY_MANUFACTURED_CACHE = utils2to3.abspathmaker( __file__, 'cache', 'manufactured_mats.v1.p') MATERIALS_LUT = { "zinc": { "localized": _(u"Zinc"), "raw": "Zinc", "category": "raw", "grade": 2 }, "mercury": { "localized": _(u"Mercury"), "raw": "Mercury", "category": "raw", "grade": 3 }, "polonium": { "localized": _(u"Polonium"), "raw": "Polonium", "category": "raw", "grade": 4 }, "tellurium": { "localized": _(u"Tellurium"), "raw": "Tellurium", "category": "raw", "grade": 4 }, "yttrium": { "localized": _(u"Yttrium"), "raw": "Yttrium", "category": "raw", "grade": 4 }, "antimony": { "localized": _(u"Antimony"), "raw": "Antimony", "category": "raw", "grade": 4 }, "selenium": { "localized": _(u"Selenium"), "raw": "Selenium", "category": "raw", "grade": 4 }, "ruthenium": { "localized": _(u"Ruthenium"), "raw": "Ruthenium", "category": "raw", "grade": 4 }, "zirconium": { "localized": _(u"Zirconium"), "raw": "Zirconium", "category": "raw", "grade": 2 }, "vanadium": { "localized": _(u"Vanadium"), "raw": "Vanadium", "category": "raw", "grade": 2 }, "manganese": { "localized": _(u"Manganese"), "raw": "Manganese", "category": "raw", "grade": 2 }, "chromium": { "localized": _(u"Chromium"), "raw": "Chromium", "category": "raw", "grade": 2 }, "molybdenum": { "localized": _(u"Molybdenum"), "raw": "Molybdenum", "category": "raw", "grade": 3 }, "technetium": { "localized": _(u"Technetium"), "raw": "Technetium", "category": "raw", "grade": 4 }, "tin": { "localized": _(u"Tin"), "raw": "Tin", "category": "raw", "grade": 3 }, "arsenic": { "localized": _(u"Arsenic"), "raw": "Arsenic", "category": "raw", "grade": 2 }, "cadmium": { "localized": _(u"Cadmium"), "raw": "Cadmium", "category": "raw", "grade": 3 }, "iron": { "localized": _(u"Iron"), "raw": "Iron", "category": "raw", "grade": 1 }, "niobium": { "localized": _(u"Niobium"), "raw": "Niobium", "category": "raw", "grade": 3 }, "phosphorus": { "localized": _(u"Phosphorus"), "raw": "Phosphorus", "category": "raw", "grade": 1 }, "germanium": { "localized": _(u"Germanium"), "raw": "Germanium", "category": "raw", "grade": 2 }, "tungsten": { "localized": _(u"Tungsten"), "raw": "Tungsten", "category": "raw", "grade": 3 }, "sulphur": { "localized": _(u"Sulphur"), "raw": "Sulphur", "category": "raw", "grade": 1 }, "carbon": { "localized": _(u"Carbon"), "raw": "Carbon", "category": "raw", "grade": 1 }, "nickel": { "localized": _(u"Nickel"), "raw": "Nickel", "category": "raw", "grade": 1 }, "rhenium": { "localized": _(u"Rhenium"), "raw": "Rhenium", "category": "raw", "grade": 1 }, "boron": { "localized": _(u"Boron"), "raw": "Boron", "category": "raw", "grade": 3 }, "lead": { "localized": _(u"Lead"), "raw": "Lead", "category": "raw", "grade": 1 }, "focuscrystals": { "localized": _(u"Focus Crystals"), "raw": "Focus Crystals", "category": "manufactured", "grade": 3 }, "compoundshielding": { "localized": _(u"Compound Shielding"), "raw": "Compound Shielding", "category": "manufactured", "grade": 4 }, "galvanisingalloys": { "localized": _(u"Galvanising Alloys"), "raw": "Galvanising Alloys", "category": "manufactured", "grade": 2 }, "heatvanes": { "localized": _(u"Heat Vanes"), "raw": "Heat Vanes", "category": "manufactured", "grade": 4 }, "configurablecomponents": { "localized": _(u"Configurable Components"), "raw": "Configurable Components", "category": "manufactured", "grade": 4 }, "biotechconductors": { "localized": _(u"Biotech Conductors"), "raw": "Biotech Conductors", "category": "manufactured", "grade": 5 }, "chemicalmanipulators": { "localized": _(u"Chemical Manipulators"), "raw": "Chemical Manipulators", "category": "manufactured", "grade": 4 }, "mechanicalcomponents": { "localized": _(u"Mechanical Components"), "raw": "Mechanical Components", "category": "manufactured", "grade": 3 }, "fedproprietarycomposites": { "localized": _(u"Proprietary Composites"), "raw": "Proprietary Composites", "category": "manufactured", "grade": 4 }, "highdensitycomposites": { "localized": _(u"High Density Composites"), "raw": "High Density Composites", "category": "manufactured", "grade": 3 }, "protoradiolicalloys": { "localized": _(u"Proto Radiolic Alloys"), "raw": "Proto Radiolic Alloys", "category": "manufactured", "grade": 5 }, "chemicaldistillery": { "localized": _(u"Chemical Distillery"), "raw": "Chemical Distillery", "category": "manufactured", "grade": 3 }, "chemicalprocessors": { "localized": _(u"Chemical Processors"), "raw": "Chemical Processors", "category": "manufactured", "grade": 2 }, "imperialshielding": { "localized": _(u"Imperial Shielding"), "raw": "Imperial Shielding", "category": "manufactured", "grade": 5 }, "gridresistors": { "localized": _(u"Grid Resistors"), "raw": "Grid Resistors", "category": "manufactured", "grade": 1 }, "heatconductionwiring": { "localized": _(u"Heat Conduction Wiring"), "raw": "Heat Conduction Wiring", "category": "manufactured", "grade": 1 }, "militarygradealloys": { "localized": _(u"Military Grade Alloys"), "raw": "Military Grade Alloys", "category": "manufactured", "grade": 5 }, "hybridcapacitors": { "localized": _(u"Hybrid Capacitors"), "raw": "Hybrid Capacitors", "category": "manufactured", "grade": 2 }, "heatexchangers": { "localized": _(u"Heat Exchangers"), "raw": "Heat Exchangers", "category": "manufactured", "grade": 3 }, "conductivepolymers": { "localized": _(u"Conductive Polymers"), "raw": "Conductive Polymers", "category": "manufactured", "grade": 4 }, "shieldingsensors": { "localized": _(u"Shielding Sensors"), "raw": "Shielding Sensors", "category": "manufactured", "grade": 3 }, "heatdispersionplate": { "localized": _(u"Heat Dispersion Plate"), "raw": "Heat Dispersion Plate", "category": "manufactured", "grade": 2 }, "electrochemicalarrays": { "localized": _(u"Electrochemical Arrays"), "raw": "Electrochemical Arrays", "category": "manufactured", "grade": 1 }, "conductiveceramics": { "localized": _(u"Conductive Ceramics"), "raw": "Conductive Ceramics", "category": "manufactured", "grade": 3 }, "conductivecomponents": { "localized": _(u"Conductive Components"), "raw": "Conductive Components", "category": "manufactured", "grade": 2 }, "militarysupercapacitors": { "localized": _(u"Military Supercapacitors"), "raw": "Military Supercapacitors", "category": "manufactured", "grade": 5 }, "mechanicalequipment": { "localized": _(u"Mechanical Equipment"), "raw": "Mechanical Equipment", "category": "manufactured", "grade": 2 }, "phasealloys": { "localized": _(u"Phase Alloys"), "raw": "Phase Alloys", "category": "manufactured", "grade": 3 }, "pharmaceuticalisolators": { "localized": _(u"Pharmaceutical Isolators"), "raw": "Pharmaceutical Isolators", "category": "manufactured", "grade": 5 }, "fedcorecomposites": { "localized": _(u"Core Dynamics Composites"), "raw": "Core Dynamics Composites", "category": "manufactured", "grade": 5 }, "basicconductors": { "localized": _(u"Basic Conductors"), "raw": "Basic Conductors", "category": "manufactured", "grade": 1 }, "mechanicalscrap": { "localized": _(u"Mechanical Scrap"), "raw": "Mechanical Scrap", "category": "manufactured", "grade": 1 }, "salvagedalloys": { "localized": _(u"Salvaged Alloys"), "raw": "Salvaged Alloys", "category": "manufactured", "grade": 1 }, "protolightalloys": { "localized": _(u"Proto Light Alloys"), "raw": "Proto Light Alloys", "category": "manufactured", "grade": 4 }, "refinedfocuscrystals": { "localized": _(u"Refined Focus Crystals"), "raw": "Refined Focus Crystals", "category": "manufactured", "grade": 4 }, "shieldemitters": { "localized": _(u"Shield Emitters"), "raw": "Shield Emitters", "category": "manufactured", "grade": 1 }, "precipitatedalloys": { "localized": _(u"Precipitated Alloys"), "raw": "Precipitated Alloys", "category": "manufactured", "grade": 3 }, "wornshieldemitters": { "localized": _(u"Worn Shield Emitters"), "raw": "Worn Shield Emitters", "category": "manufactured", "grade": 1 }, "exquisitefocuscrystals": { "localized": _(u"Exquisite Focus Crystals"), "raw": "Exquisite Focus Crystals", "category": "manufactured", "grade": 5 }, "polymercapacitors": { "localized": _(u"Polymer Capacitors"), "raw": "Polymer Capacitors", "category": "manufactured", "grade": 4 }, "thermicalloys": { "localized": _(u"Thermic Alloys"), "raw": "Thermic Alloys", "category": "manufactured", "grade": 4 }, "improvisedcomponents": { "localized": _(u"Improvised Components"), "raw": "Improvised Components", "category": "manufactured", "grade": 5 }, "crystalshards": { "localized": _(u"Crystal Shards"), "raw": "Crystal Shards", "category": "manufactured", "grade": 1 }, "heatresistantceramics": { "localized": _(u"Heat Resistant Ceramics"), "raw": "Heat Resistant Ceramics", "category": "manufactured", "grade": 2 }, "temperedalloys": { "localized": _(u"Tempered Alloys"), "raw": "Tempered Alloys", "category": "manufactured", "grade": 1 }, "uncutfocuscrystals": { "localized": _(u"Flawed Focus Crystals"), "raw": "Flawed Focus Crystals", "category": "manufactured", "grade": 2 }, "filamentcomposites": { "localized": _(u"Filament Composites"), "raw": "Filament Composites", "category": "manufactured", "grade": 2 }, "compactcomposites": { "localized": _(u"Compact Composites"), "raw": "Compact Composites", "category": "manufactured", "grade": 1 }, "chemicalstorageunits": { "localized": _(u"Chemical Storage Units"), "raw": "Chemical Storage Units", "category": "manufactured", "grade": 1 }, "protoheatradiators": { "localized": _(u"Proto Heat Radiators"), "raw": "Proto Heat Radiators", "category": "manufactured", "grade": 5 }, "guardian_powerconduit": { "localized": _(u"Guardian Power Conduit"), "raw": "Guardian Power Conduit", "category": "manufactured", "grade": 2 }, "guardian_powercell": { "localized": _(u"Guardian Power Cell"), "raw": "Guardian Power Cell", "category": "manufactured", "grade": 1 }, "guardian_techcomponent": { "localized": _(u"Guardian Technology Component"), "raw": "Guardian Technology Component", "category": "manufactured", "grade": 3 }, "guardian_sentinel_wreckagecomponents": { "localized": _(u"Guardian Wreckage Components"), "raw": "Guardian Wreckage Components", "category": "manufactured", "grade": 1 }, "guardian_sentinel_weaponparts": { "localized": _(u"Guardian Sentinel Weapon Parts"), "raw": "Guardian Sentinel Weapon Parts", "category": "manufactured", "grade": 3 }, "classifiedscandata": { "localized": _(u"Classified Scan Fragment"), "raw": "Classified Scan Fragment", "category": "encoded", "grade": 5 }, "securityfirmware": { "localized": _(u"Security Firmware Patch"), "raw": "Security Firmware Patch", "category": "encoded", "grade": 4 }, "dataminedwake": { "localized": _(u"Datamined Wake Exceptions"), "raw": "Datamined Wake Exceptions", "category": "encoded", "grade": 5 }, "compactemissionsdata": { "localized": _(u"Abnormal Compact Emissions Data"), "raw": "Abnormal Compact Emissions Data", "category": "encoded", "grade": 5 }, "shieldpatternanalysis": { "localized": _(u"Aberrant Shield Pattern Analysis"), "raw": "Aberrant Shield Pattern Analysis", "category": "encoded", "grade": 4 }, "adaptiveencryptors": { "localized": _(u"Adaptive Encryptors Capture"), "raw": "Adaptive Encryptors Capture", "category": "encoded", "grade": 5 }, "emissiondata": { "localized": _(u"Unexpected Emission Data"), "raw": "Unexpected Emission Data", "category": "encoded", "grade": 3 }, "industrialfirmware": { "localized": _(u"Cracked Industrial Firmware"), "raw": "Cracked Industrial Firmware", "category": "encoded", "grade": 3 }, "scandatabanks": { "localized": _(u"Classified Scan Databanks"), "raw": "Classified Scan Databanks", "category": "encoded", "grade": 3 }, "legacyfirmware": { "localized": _(u"Specialised Legacy Firmware"), "raw": "Specialised Legacy Firmware", "category": "encoded", "grade": 1 }, "embeddedfirmware": { "localized": _(u"Modified Embedded Firmware"), "raw": "Modified Embedded Firmware", "category": "encoded", "grade": 5 }, "shieldcyclerecordings": { "localized": _(u"Distorted Shield Cycle Recordings"), "raw": "Distorted Shield Cycle Recordings", "category": "encoded", "grade": 1 }, "decodedemissiondata": { "localized": _(u"Decoded Emission Data"), "raw": "Decoded Emission Data", "category": "encoded", "grade": 4 }, "bulkscandata": { "localized": _(u"Anomalous Bulk Scan Data"), "raw": "Anomalous Bulk Scan Data", "category": "encoded", "grade": 1 }, "scanarchives": { "localized": _(u"Unidentified Scan Archives"), "raw": "Unidentified Scan Archives", "category": "encoded", "grade": 2 }, "shieldsoakanalysis": { "localized": _(u"Inconsistent Shield Soak Analysis"), "raw": "Inconsistent Shield Soak Analysis", "category": "encoded", "grade": 2 }, "encodedscandata": { "localized": _(u"Divergent Scan Data"), "raw": "Divergent Scan Data", "category": "encoded", "grade": 4 }, "shielddensityreports": { "localized": _(u"Untypical Shield Scans"), "raw": "Untypical Shield Scans", "category": "encoded", "grade": 3 }, "shieldfrequencydata": { "localized": _(u"Peculiar Shield Frequency Data"), "raw": "Peculiar Shield Frequency Data", "category": "encoded", "grade": 5 }, "encryptioncodes": { "localized": _(u"Tagged Encryption Codes"), "raw": "Tagged Encryption Codes", "category": "encoded", "grade": 2 }, "consumerfirmware": { "localized": _(u"Modified Consumer Firmware"), "raw": "Modified Consumer Firmware", "category": "encoded", "grade": 2 }, "archivedemissiondata": { "localized": _(u"Irregular Emission Data"), "raw": "Irregular Emission Data", "category": "encoded", "grade": 2 }, "symmetrickeys": { "localized": _(u"Open Symmetric Keys"), "raw": "Open Symmetric Keys", "category": "encoded", "grade": 3 }, "encryptedfiles": { "localized": _(u"Unusual Encrypted Files"), "raw": "Unusual Encrypted Files", "category": "encoded", "grade": 1 }, "scrambledemissiondata": { "localized": _(u"Exceptional Scrambled Emission Data"), "raw": "Exceptional Scrambled Emission Data", "category": "encoded", "grade": 1 }, "fsdtelemetry": { "localized": _(u"Anomalous FSD Telemetry"), "raw": "Anomalous FSD Telemetry", "category": "encoded", "grade": 2 }, "hyperspacetrajectories": { "localized": _(u"Eccentric Hyperspace Trajectories"), "raw": "Eccentric Hyperspace Trajectories", "category": "encoded", "grade": 4 }, "disruptedwakeechoes": { "localized": _(u"Atypical Disrupted Wake Echoes"), "raw": "Atypical Disrupted Wake Echoes", "category": "encoded", "grade": 1 }, "wakesolutions": { "localized": _(u"Strange Wake Solutions"), "raw": "Strange Wake Solutions", "category": "encoded", "grade": 3 }, "encryptionarchives": { "localized": _(u"Atypical Encryption Archives"), "raw": "Atypical Encryption Archives", "category": "encoded", "grade": 4 }, "ancientbiologicaldata": { "localized": _(u"Pattern Alpha Obelisk Data"), "raw": "Pattern Alpha Obelisk Data", "category": "encoded", "grade": 3 }, "ancienthistoricaldata": { "localized": _(u"Pattern Gamma Obelisk Data"), "raw": "Pattern Gamma Obelisk Data", "category": "encoded", "grade": 4 }, "guardian_moduleblueprint": { "localized": _(u"Guardian Module Blueprint Fragment"), "raw": "Guardian Module Blueprint Fragment", "category": "encoded", "grade": 5 }, "ancientculturaldata": { "localized": _(u"Pattern Beta Obelisk Data"), "raw": "Pattern Beta Obelisk Data", "category": "encoded", "grade": 2 }, "ancientlanguagedata": { "localized": _(u"Pattern Delta Obelisk Data"), "raw": "Pattern Delta Obelisk Data", "category": "encoded", "grade": 4 }, "guardian_vesselblueprint": { "localized": _(u"Guardian Starship Blueprint Fragment"), "raw": "Guardian Starship Blueprint Fragment", "category": "encoded", "grade": 5 }, "guardian_weaponblueprint": { "localized": _(u"Guardian Weapon Blueprint Fragment"), "raw": "Guardian Weapon Blueprint Fragment", "category": "encoded", "grade": 5 }, "ancienttechnologicaldata": { "localized": _(u"Pattern Epsilon Obelisk Data"), "raw": "Pattern Epsilon Obelisk Data", "category": "encoded", "grade": 5 }, "tg_shipsystemsdata": { "localized": _(u"Ship Systems Data"), "raw": "Ship Systems Data", "category": "encoded", "grade": 3 }, "tg_shipflightdata": { "localized": _(u"Ship Flight Data"), "raw": "Ship Flight Data", "category": "encoded", "grade": 3 }, "unknownshipsignature": { "localized": _(u"Thargoid Ship Signature"), "raw": "Thargoid Ship Signature", "category": "encoded", "grade": 3 }, "tg_structuraldata": { "localized": _(u"Thargoid Structural Data"), "raw": "Thargoid Structural Data", "category": "encoded", "grade": 2 }, "unknownwakedata": { "localized": _(u"Thargoid Wake Data"), "raw": "Thargoid Wake Data", "category": "encoded", "grade": 4 }, "tg_biomechanicalconduits": { "localized": _(u"Bio-Mechanical Conduits"), "raw": "Bio-Mechanical Conduits", "category": "manufactured", "grade": 3 }, "tg_propulsionelement": { "localized": _(u"Propulsion Elements"), "raw": "Propulsion Elements", "category": "manufactured", "grade": 3 }, "unknowncarapace": { "localized": _(u"Thargoid Carapace"), "raw": "Thargoid Carapace", "category": "manufactured", "grade": 2 }, "unknownenergycell": { "localized": _(u"Thargoid Energy Cell"), "raw": "Thargoid Energy Cell", "category": "manufactured", "grade": 3 }, "unknownorganiccircuitry": { "localized": _(u"Thargoid Organic Circuitry"), "raw": "Thargoid Organic Circuitry", "category": "manufactured", "grade": 5 }, "unknowntechnologycomponents": { "localized": _(u"Thargoid Technological Components"), "raw": "Thargoid Technological Components", "category": "manufactured", "grade": 4 } } INTERNAL_NAMES_LUT = { u'classified scan databanks': 'scandatabanks', u'conductive components': 'conductivecomponents', u'abnormal compact emissions data': 'compactemissionsdata', u'germanium': 'germanium', u'atypical disrupted wake echoes': 'disruptedwakeechoes', u'crystal shards': 'crystalshards', u'selenium': 'selenium', u'technetium': 'technetium', u'galvanising alloys': 'galvanisingalloys', u'improvised components': 'improvisedcomponents', u'cracked industrial firmware': 'industrialfirmware', u'guardian technology component': 'guardian_techcomponent', u'heat resistant ceramics': 'heatresistantceramics', u'unexpected emission data': 'emissiondata', u'tungsten': 'tungsten', u'exceptional scrambled emission data': 'scrambledemissiondata', u'thermic alloys': 'thermicalloys', u'molybdenum': 'molybdenum', u'atypical encryption archives': 'encryptionarchives', u'salvaged alloys': 'salvagedalloys', u'pharmaceutical isolators': 'pharmaceuticalisolators', u'divergent scan data': 'encodedscandata', u'anomalous fsd telemetry': 'fsdtelemetry', u'pattern delta obelisk data': 'ancientlanguagedata', u'worn shield emitters': 'wornshieldemitters', u'strange wake solutions': 'wakesolutions', u'tempered alloys': 'temperedalloys', u'zinc': 'zinc', u'mechanical equipment': 'mechanicalequipment', u'eccentric hyperspace trajectories': 'hyperspacetrajectories', u'grid resistors': 'gridresistors', u'unusual encrypted files': 'encryptedfiles', u'peculiar shield frequency data': 'shieldfrequencydata', u'specialised legacy firmware': 'legacyfirmware', u'flawed focus crystals': 'uncutfocuscrystals', u'pattern beta obelisk data': 'ancientculturaldata', u'antimony': 'antimony', u'untypical shield scans': 'shielddensityreports', u'focus crystals': 'focuscrystals', u'lead': 'lead', u'heat dispersion plate': 'heatdispersionplate', u'irregular emission data': 'archivedemissiondata', u'guardian module blueprint fragment': 'guardian_moduleblueprint', u'yttrium': 'yttrium', u'mechanical scrap': 'mechanicalscrap', u'biotech conductors': 'biotechconductors', u'military grade alloys': 'militarygradealloys', u'basic conductors': 'basicconductors', u'boron': 'boron', u'carbon': 'carbon', u'unidentified scan archives': 'scanarchives', u'imperial shielding': 'imperialshielding', u'chemical distillery': 'chemicaldistillery', u'guardian wreckage components': 'guardian_sentinel_wreckagecomponents', u'proto radiolic alloys': 'protoradiolicalloys', u'proto heat radiators': 'protoheatradiators', u'cadmium': 'cadmium', u'filament composites': 'filamentcomposites', u'exquisite focus crystals': 'exquisitefocuscrystals', u'electrochemical arrays': 'electrochemicalarrays', u'mechanical components': 'mechanicalcomponents', u'pattern alpha obelisk data': 'ancientbiologicaldata', u'arsenic': 'arsenic', u'chromium': 'chromium', u'conductive ceramics': 'conductiveceramics', u'mercury': 'mercury', u'chemical processors': 'chemicalprocessors', u'pattern gamma obelisk data': 'ancienthistoricaldata', u'proprietary composites': 'fedproprietarycomposites', u'proto light alloys': 'protolightalloys', u'datamined wake exceptions': 'dataminedwake', u'adaptive encryptors capture': 'adaptiveencryptors', u'open symmetric keys': 'symmetrickeys', u'nickel': 'nickel', u'ruthenium': 'ruthenium', u'guardian sentinel weapon parts': 'guardian_sentinel_weaponparts', u'decoded emission data': 'decodedemissiondata', u'guardian power cell': 'guardian_powercell', u'chemical storage units': 'chemicalstorageunits', u'sulphur': 'sulphur', u'anomalous bulk scan data': 'bulkscandata', u'refined focus crystals': 'refinedfocuscrystals', u'zirconium': 'zirconium', u'heat vanes': 'heatvanes', u'niobium': 'niobium', u'iron': 'iron', u'conductive polymers': 'conductivepolymers', u'configurable components': 'configurablecomponents', u'rhenium': 'rhenium', u'security firmware patch': 'securityfirmware', u'aberrant shield pattern analysis': 'shieldpatternanalysis', u'modified consumer firmware': 'consumerfirmware', u'military supercapacitors': 'militarysupercapacitors', u'heat conduction wiring': 'heatconductionwiring', u'inconsistent shield soak analysis': 'shieldsoakanalysis', u'distorted shield cycle recordings': 'shieldcyclerecordings', u'shield emitters': 'shieldemitters', u'tin': 'tin', u'chemical manipulators': 'chemicalmanipulators', u'hybrid capacitors': 'hybridcapacitors', u'tagged encryption codes': 'encryptioncodes', u'classified scan fragment': 'classifiedscandata', u'polymer capacitors': 'polymercapacitors', u'precipitated alloys': 'precipitatedalloys', u'heat exchangers': 'heatexchangers', u'polonium': 'polonium', u'core dynamics composites': 'fedcorecomposites', u'high density composites': 'highdensitycomposites', u'modified embedded firmware': 'embeddedfirmware', u'phosphorus': 'phosphorus', u'guardian power conduit': 'guardian_powerconduit', u'vanadium': 'vanadium', u'shielding sensors': 'shieldingsensors', u'compound shielding': 'compoundshielding', u'manganese': 'manganese', u'compact composites': 'compactcomposites', u'tellurium': 'tellurium', u'phase alloys': 'phasealloys', u'thargoid organic circuitry': u'unknownorganiccircuitry', u'thargoid energy cell': u'unknownenergycell', u'thargoid structural data': u'tg_structuraldata', u'thargoid ship signature': u'unknownshipsignature', u'thargoid carapace': u'unknowncarapace', u'propulsion elements': u'tg_propulsionelement', u'guardian weapon blueprint fragment': u'guardian_weaponblueprint', u'guardian starship blueprint fragment': u'guardian_vesselblueprint', u'pattern epsilon obelisk data': u'ancienttechnologicaldata', u'bio-mechanical conduits': u'tg_biomechanicalconduits', u'ship flight data': u'tg_shipflightdata', u'thargoid wake data': u'unknownwakedata', u'thargoid technological components': u'unknowntechnologycomponents', u'ship systems data': u'tg_shipsystemsdata' } def __init__(self): self.initialized = False self.inconsistencies = False try: with open(self.EDR_INVENTORY_ENCODED_CACHE, 'rb') as handle: self.encoded = pickle.load(handle) except: self.encoded = {} try: with open(self.EDR_INVENTORY_RAW_CACHE, 'rb') as handle: self.raw = pickle.load(handle) except: self.raw = {} try: with open(self.EDR_INVENTORY_MANUFACTURED_CACHE, 'rb') as handle: self.manufactured = pickle.load(handle) except: self.manufactured = {} self.__check() def initialize(self, materials): for thing in materials.get("Encoded", []): cname = self.__c_name(thing["Name"]) self.encoded[cname] = thing["Count"] for thing in materials.get("Raw", []): cname = self.__c_name(thing["Name"]) self.raw[cname] = thing["Count"] for thing in materials.get("Manufactured", []): cname = self.__c_name(thing["Name"]) self.manufactured[cname] = thing["Count"] self.initialized = True self.inconsistencies = False def initialize_with_edmc(self, state): for thing in state.get("Encoded", {}): cname = self.__c_name(thing) self.encoded[cname] = state["Encoded"][thing] for thing in state.get("Raw", {}): cname = self.__c_name(thing) self.raw[cname] = state["Raw"][thing] for thing in state.get("Manufactured", {}): cname = self.__c_name(thing) self.manufactured[cname] = state["Manufactured"][thing] self.initialized = True self.inconsistencies = False def stale_or_incorrect(self): return not self.initialized or self.inconsistencies def persist(self): with open(self.EDR_INVENTORY_ENCODED_CACHE, 'wb') as handle: pickle.dump(self.encoded, handle, protocol=pickle.HIGHEST_PROTOCOL) with open(self.EDR_INVENTORY_MANUFACTURED_CACHE, 'wb') as handle: pickle.dump(self.manufactured, handle, protocol=pickle.HIGHEST_PROTOCOL) with open(self.EDR_INVENTORY_RAW_CACHE, 'wb') as handle: pickle.dump(self.raw, handle, protocol=pickle.HIGHEST_PROTOCOL) def collected(self, info): self.add(info["Category"], info["Name"], info["Count"]) def discarded(self, info): self.substract(info["Category"], info["Name"], info["Count"]) def count(self, name): cname = self.__c_name(name) category = self.category(cname) if category == "encoded": return self.encoded.get(cname, 0) elif category == "raw": return self.raw.get(cname, 0) elif category == "manufactured": return self.manufactured.get(cname, 0) return 0 def oneliner(self, name): cname = self.__c_name(name) category = self.category(cname) entry = self.MATERIALS_LUT.get(cname, None) if not category or not entry: return name count = self.count(cname) grades = [u"?", u"Ⅰ", u"Ⅱ", u"Ⅲ", u"Ⅳ", u"Ⅴ"] slots = [u"?", u"300", u"250", u"200", u"150", u"100"] return u"{} (Grade {}; {}/{})".format(_(entry["raw"]), grades[entry["grade"]], count, slots[entry["grade"]]) def __check(self): self.inconsistencies = False for collection in [self.encoded, self.raw, self.manufactured]: for thing in collection: self.__check_item(thing) if self.inconsistencies: return False return True def __check_item(self, name): cname = self.__c_name(name) entry = self.MATERIALS_LUT.get(cname, None) if not entry: return False count = self.count(cname) if count < 0: self.inconsistencies = True return False max_for_slot = self.slots(name) if count > max_for_slot: self.inconsistencies = True return False return True def donated_engineer(self, info): if info["Type"] != "Material": return category = self.category(info["Name"]) if category: self.substract(category, info["Name"], info["Quantity"]) def donated_science(self, info): self.substract(info["Category"], info["Name"], info["Count"]) def consumed(self, ingredients): for ingredient in ingredients: category = ingredient.get("Category", self.category(ingredient["Name"])) if category: self.substract(category, ingredient["Name"], ingredient["Count"]) def traded(self, info): paid = info["Paid"] self.substract(paid["Category"], paid["Material"], paid["Quantity"]) received = info["Received"] self.add(received["Category"], received["Material"], received["Quantity"]) def rewarded(self, info): # TODO Does Search And Rescue give material rewards?? if "MaterialsReward" not in info: return for reward in info["MaterialsReward"]: self.add(reward["Category"], reward["Name"], reward["Count"]) def add(self, category, name, count): ccategory = self.__c_cat(category) cname = self.__c_name(name) if ccategory == "encoded": self.encoded[cname] = min( self.encoded.get(cname, 0) + count, self.slots(name)) elif ccategory == "raw": self.raw[cname] = min( self.raw.get(cname, 0) + count, self.slots(name)) elif ccategory == "manufactured": self.manufactured[cname] = min( self.manufactured.get(cname, 0) + count, self.slots(name)) def slots(self, name): cname = self.__c_name(name) entry = self.MATERIALS_LUT.get(cname, None) if not entry: return 100 slots = [100, 300, 250, 200, 150, 100] return slots[entry["grade"]] def substract(self, category, name, count): ccategory = self.__c_cat(category) cname = self.__c_name(name) if ccategory == "encoded": self.encoded[cname] = max(self.encoded.get(cname, 0) - count, 0) elif ccategory == "raw": self.raw[cname] = max(self.raw.get(cname, 0) - count, 0) elif ccategory == "manufactured": self.manufactured[cname] = max( self.manufactured.get(cname, 0) - count, 0) def category(self, name): cname = self.__c_name(name) entry = self.MATERIALS_LUT.get(cname, None) return entry["category"] if entry else None def __c_cat(self, category): ccat = category.lower() if ccat.endswith(u";"): ccat = ccat[:-1] if ccat.startswith(u"$MICRORESOURCE_CATEGORY_"): useless_prefix_length = len(u"$MICRORESOURCE_CATEGORY_") ccat = ccat[useless_prefix_length:] return ccat def __c_name(self, name): cname = name.lower() if cname in self.MATERIALS_LUT: return cname return self.INTERNAL_NAMES_LUT.get(cname, cname)