diff --git a/EDMarketConnector.py b/EDMarketConnector.py index 26202b29..5dee2330 100755 --- a/EDMarketConnector.py +++ b/EDMarketConnector.py @@ -420,7 +420,7 @@ class AppWindow: self.status['text'] = _("What are you flying?!") # Shouldn't happen elif monitor.cmdr and data['commander']['name'] != monitor.cmdr: raise companion.CmdrError() # Companion API return doesn't match Journal - elif (auto_update and not data['commander'].get('docked')) or (monitor.system and data['lastSystem']['name'] != monitor.system) or (monitor.shipid and data['ship']['id'] != monitor.shipid) or (monitor.shiptype and data['ship']['name'].lower() != monitor.shiptype): + elif (auto_update and not data['commander'].get('docked')) or (monitor.system and data['lastSystem']['name'] != monitor.system) or (monitor.state['ShipID'] and data['ship']['id'] != monitor.state['ShipID']) or (monitor.state['ShipType'] and data['ship']['name'].lower() != monitor.state['ShipType']): raise companion.ServerLagging() else: @@ -431,9 +431,9 @@ class AppWindow: h.write(json.dumps(data, ensure_ascii=False, indent=2, sort_keys=True, separators=(',', ': ')).encode('utf-8')) self.ship['text'] = companion.ship_map.get(data['ship']['name'].lower(), data['ship']['name']) - if not monitor.shiptype: # Started game in SRV or fighter - monitor.shipid = data['ship']['id'] - monitor.shiptype = data['ship']['name'].lower() + if not monitor.state['ShipType']: # Started game in SRV or fighter + monitor.state['ShipID'] = data['ship']['id'] + monitor.state['ShipType'] = data['ship']['name'].lower() if not monitor.system: self.system['text'] = data['lastSystem']['name'] self.system['image'] = '' @@ -503,8 +503,9 @@ class AppWindow: if config.getint('output') & config.OUT_SYS_EDSM: try: if data['commander'].get('credits') is not None: - monitor.credits = (data['commander']['credits'], data['commander'].get('debt', 0)) - self.edsm.setcredits(monitor.credits) + monitor.state['Credits'] = data['commander']['credits'] + monitor.state['Loan'] = data['commander'].get('debt', 0) + self.edsm.setcredits(monitor.state['Credits'], monitor.state['Loan']) ship = companion.ship(data) if ship == self.edsm.lastship: props = [] @@ -515,14 +516,14 @@ class AppWindow: ('linkToCoriolis', coriolis.url(data)), ('linkToEDShipyard', edshipyard.url(data)), ] - if monitor.shippaint is None: + if monitor.state['PaintJob'] is None: # Companion API server can lag, so prefer Journal. But paintjob only reported in Journal on change. - monitor.shipid = data['ship']['id'] - monitor.shiptype = data['ship']['name'].lower() - monitor.shippaint = data['ship']['modules']['PaintJob'] and data['ship']['modules']['PaintJob']['module']['name'].lower() or '' - props.append(('paintJob', monitor.shippaint)) + monitor.state['ShipID'] = data['ship']['id'] + monitor.state['ShipType'] = data['ship']['name'].lower() + monitor.state['PaintJob'] = data['ship']['modules']['PaintJob'] and data['ship']['modules']['PaintJob']['module']['name'].lower() or '' + props.append(('paintJob', monitor.state['PaintJob'])) if props: - self.edsm.updateship(monitor.shipid, monitor.shiptype, props) + self.edsm.updateship(monitor.state['ShipID'], monitor.state['ShipType'], props) self.edsm.lastship = ship except Exception as e: # Not particularly important so silent on failure @@ -580,7 +581,7 @@ class AppWindow: # Update main window self.cmdr['text'] = monitor.cmdr and monitor.group and ' / '.join([monitor.cmdr, monitor.group]) or monitor.cmdr or '' - self.ship['text'] = monitor.shiptype and companion.ship_map.get(monitor.shiptype, monitor.shiptype) or '' + self.ship['text'] = monitor.state['ShipType'] and companion.ship_map.get(monitor.state['ShipType'], monitor.state['ShipType']) or '' self.station['text'] = monitor.station or (EDDB.system(monitor.system) and self.STATION_UNDOCKED or '') if system_changed or station_changed: self.status['text'] = '' @@ -601,26 +602,26 @@ class AppWindow: # Send credits to EDSM on new game (but not on startup - data might be old) if entry['event'] == 'LoadGame': - self.edsm.setcredits(monitor.credits) + self.edsm.setcredits(monitor.state['Credits'], monitor.state['Loan']) # Send rank info to EDSM on startup or change - if entry['event'] in ['StartUp', 'Progress', 'Promotion'] and monitor.ranks: - self.edsm.setranks(monitor.ranks) + if entry['event'] in ['StartUp', 'Progress', 'Promotion'] and monitor.state['Rank']: + self.edsm.setranks(monitor.state['Rank']) # Send ship info to EDSM on startup or change - if entry['event'] in ['StartUp', 'LoadGame', 'ShipyardNew', 'ShipyardSwap'] and monitor.shipid: - self.edsm.setshipid(monitor.shipid) - self.edsm.updateship(monitor.shipid, monitor.shiptype, monitor.shippaint and [('paintJob', monitor.shippaint)] or []) + if entry['event'] in ['StartUp', 'LoadGame', 'ShipyardNew', 'ShipyardSwap'] and monitor.state['ShipID']: + self.edsm.setshipid(monitor.state['ShipID']) + self.edsm.updateship(monitor.state['ShipID'], monitor.state['ShipType'], monitor.state['PaintJob'] is not None and [('paintJob', monitor.state['PaintJob'])] or []) elif entry['event'] in ['ShipyardBuy', 'ShipyardSell']: self.edsm.sellship(entry.get('SellShipID')) # Send paintjob info to EDSM on change if entry['event'] in ['ModuleBuy', 'ModuleSell'] and entry['Slot'] == 'PaintJob': - self.edsm.updateship(monitor.shipid, monitor.shiptype, [('paintJob', monitor.shippaint)]) + self.edsm.updateship(monitor.state['ShipID'], monitor.state['ShipType'], [('paintJob', monitor.state['PaintJob'])]) # Write EDSM log on change if monitor.mode and entry['event'] in ['Location', 'FSDJump']: - self.edsm.writelog(timegm(strptime(entry['timestamp'], '%Y-%m-%dT%H:%M:%SZ')), monitor.system, monitor.coordinates, monitor.shipid) + self.edsm.writelog(timegm(strptime(entry['timestamp'], '%Y-%m-%dT%H:%M:%SZ')), monitor.system, monitor.coordinates, monitor.state['ShipID']) except Exception as e: if __debug__: print_exc() @@ -647,7 +648,7 @@ class AppWindow: return # Startup or in CQC # Plugins - plug.notify_journal_entry(monitor.cmdr, monitor.system, monitor.station, entry) + plug.notify_journal_entry(monitor.cmdr, monitor.system, monitor.station, entry, monitor.state) if system_changed: # Backwards compatibility plug.notify_system_changed(timegm(strptime(entry['timestamp'], '%Y-%m-%dT%H:%M:%SZ')), monitor.system, monitor.coordinates) diff --git a/PLUGINS.md b/PLUGINS.md index 054f4309..4e378148 100644 --- a/PLUGINS.md +++ b/PLUGINS.md @@ -77,10 +77,12 @@ Your events all get called on the main tkinter loop so be sure not to block for ### Journal Entry -This gets called when EDMC sees a new entry in the game's journal. A special 'StartUp' event is sent when EDMC is started while the game is already running. +This gets called when EDMC sees a new entry in the game's journal. `state` is a dictionary containing information about the Cmdr and their ship and cargo (including the effect of the current journal entry). + +A special 'StartUp' entry is sent if EDMC is started while the game is already running. In this case you won't receive initial events such as "LoadGame", "Rank", "Location", etc. However the `state` dictionary will reflect the cumulative effect of these missed events. ``` -def journal_entry(cmdr, system, station, entry): +def journal_entry(cmdr, system, station, entry, state): if entry['event'] == 'FSDJump': # We arrived at a new system! if 'StarPos' in entry: diff --git a/edsm.py b/edsm.py index 79f6a1f8..226b10e6 100644 --- a/edsm.py +++ b/edsm.py @@ -206,9 +206,9 @@ class EDSM: if args: self.call('api-commander-v1/set-ranks', args) - def setcredits(self, credits): - if credits: - self.call('api-commander-v1/set-credits', '&balance=%d&loan=%d' % credits) + def setcredits(self, balance, loan): + if balance is not None: + self.call('api-commander-v1/set-credits', '&balance=%d&loan=%d' % (balance, loan)) def setshipid(self, shipid): if shipid is not None: diff --git a/monitor.py b/monitor.py index 129f42fc..6f1d6841 100644 --- a/monitor.py +++ b/monitor.py @@ -86,15 +86,20 @@ class EDLogs(FileSystemEventHandler): self.mode = None self.group = None self.cmdr = None - self.shipid = None - self.shiptype = None - self.shippaint = None self.body = None self.system = None self.station = None self.coordinates = None - self.ranks = None - self.credits = None + + # Cmdr state shared with EDSM and plugins + self.state = { + 'Credits' : None, + 'Loan' : None, + 'PaintJob' : None, + 'Rank' : { 'Combat': None, 'Trade': None, 'Explore': None, 'Empire': None, 'Federation': None, 'CQC': None }, + 'ShipID' : None, + 'ShipType' : None, + } def set_callback(self, name, callback): if name in self.callbacks: @@ -251,29 +256,32 @@ class EDLogs(FileSystemEventHandler): self.cmdr = entry['Commander'] self.mode = entry.get('GameMode') # 'Open', 'Solo', 'Group', or None for CQC self.group = entry.get('Group') - self.shiptype = 'Ship' in entry and entry['Ship'] not in ['TestBuggy', 'Empire_Fighter', 'Federation_Fighter', 'Independent_Fighter'] and entry['Ship'].lower() or None # None in CQC. TestBuggy or *_Fighter if game starts in SRV/fighter. - self.shipid = self.shiptype and entry.get('ShipID') or None # None in CQC - self.shippaint = None + self.state = { + 'Credits' : entry['Credits'], + 'Loan' : entry['Loan'], + 'PaintJob' : None, + 'Rank' : { 'Combat': None, 'Trade': None, 'Explore': None, 'Empire': None, 'Federation': None, 'CQC': None }, + 'ShipID' : entry.get('ShipID') if entry.get('Ship') not in ['TestBuggy', 'Empire_Fighter', 'Federation_Fighter', 'Independent_Fighter'] else None # None in CQC or if game starts in SRV/fighter + } + self.state['ShipType'] = self.state['ShipID'] and entry.get('Ship').lower() self.body = None self.system = None self.station = None self.coordinates = None - self.ranks = { "Combat": None, "Trade": None, "Explore": None, "Empire": None, "Federation": None, "CQC": None } - self.credits = ( entry['Credits'], entry['Loan'] ) elif entry['event'] == 'NewCommander': self.cmdr = entry['Name'] self.group = None elif entry['event'] == 'ShipyardNew': - self.shipid = entry['NewShipID'] - self.shiptype = entry['ShipType'].lower() - self.shippaint = None + self.state['ShipID'] = entry['NewShipID'] + self.state['ShipType'] = entry['ShipType'].lower() + self.state['PaintJob'] = None elif entry['event'] == 'ShipyardSwap': - self.shipid = entry['ShipID'] - self.shiptype = entry['ShipType'].lower() - self.shippaint = None + self.state['ShipID'] = entry['ShipID'] + self.state['ShipType'] = entry['ShipType'].lower() + self.state['PaintJob'] = None elif entry['event'] in ['ModuleBuy', 'ModuleSell'] and entry['Slot'] == 'PaintJob': symbol = re.match('\$(.+)_name;', entry.get('BuyItem', '')) - self.shippaint = symbol and symbol.group(1).lower() or entry.get('BuyItem', '') + self.state['PaintJob'] = symbol and symbol.group(1).lower() or entry.get('BuyItem', '') elif entry['event'] in ['Undocked']: self.station = None elif entry['event'] in ['Location', 'FSDJump', 'Docked']: @@ -289,14 +297,15 @@ class EDLogs(FileSystemEventHandler): self.body = entry.get('BodyType') == 'Planet' and entry.get('Body') elif entry['event'] == 'SupercruiseEntry': self.body = None - elif entry['event'] in ['Rank', 'Promotion'] and self.ranks: + elif entry['event'] in ['Rank', 'Promotion']: for k,v in entry.iteritems(): - if k in self.ranks: - self.ranks[k] = (v,0) - elif entry['event'] == 'Progress' and self.ranks: + if k in self.state['Rank']: + self.state['Rank'][k] = (v,0) + elif entry['event'] == 'Progress': for k,v in entry.iteritems(): - if self.ranks.get(k) is not None: - self.ranks[k] = (self.ranks[k][0], min(v, 100)) # perhaps not taken promotion mission yet + if self.state['Rank'].get(k) is not None: + self.state['Rank'][k] = (self.state['Rank'][k][0], min(v, 100)) # perhaps not taken promotion mission yet + return entry except: if __debug__: diff --git a/plug.py b/plug.py index 73a34205..efdb30a2 100644 --- a/plug.py +++ b/plug.py @@ -101,13 +101,14 @@ def notify_prefs_changed(): print plugerr -def notify_journal_entry(cmdr, system, station, entry): +def notify_journal_entry(cmdr, system, station, entry, state): """ Send a journal entry to each plugin. :param cmdr: The Cmdr name, or None if not yet known :param system: The current system, or None if not yet known :param station: The current station, or None if not docked or not yet known :param entry: The journal entry as a dictionary + :param state: A dictionary containing info about the Cmdr, current ship and cargo :return: """ for plugname in PLUGINS: @@ -115,7 +116,10 @@ def notify_journal_entry(cmdr, system, station, entry): if journal_entry: try: # Pass a copy of the journal entry in case the callee modifies it - journal_entry(cmdr, system, station, dict(entry)) + if journal_entry.func_code.co_argcount == 4: + journal_entry(cmdr, system, station, dict(entry)) + else: + journal_entry(cmdr, system, station, dict(entry), dict(state)) except Exception as plugerr: print plugerr diff --git a/plugins/About/load.py b/plugins/About/load.py index b7c6b432..23927da1 100644 --- a/plugins/About/load.py +++ b/plugins/About/load.py @@ -46,13 +46,14 @@ def plugin_app(parent): return plugin_app.status -def journal_entry(cmdr, system, station, entry): +def journal_entry(cmdr, system, station, entry, state): """ E:D client made a journal entry :param cmdr: The Cmdr name, or None if not yet known :param system: The current system, or None if not yet known :param station: The current station, or None if not docked or not yet known :param entry: The journal entry as a dictionary + :param state: A dictionary containing info about the Cmdr, current ship and cargo :return: """ if entry['event'] == 'FSDJump':