mirror of
https://github.com/EDCD/EDMarketConnector.git
synced 2025-04-22 20:00:29 +03:00
monitor: Track all System and Body state in monitor.state
* Minor grammar edit only in PLUGINS.md (I was checking if it explicitly stated what data is expected in the synthetic 'StartUp' event, it doesn't). * First changes to move some monitor properties into the monitor.state dictionary. This is for system or body data. * Re-factored the generation of 'StartUp' event into `EDLogs.synthesize_startup_event()`. It's done in two places, so was anti-DRY. * In general any bulk setting of system & body data is now done in the same order for comparison clarity. * A little of the location tracking has been duplicated from plugins/eddn.py. This is with a view to switching *it* to using the state version.
This commit is contained in:
parent
6bd0b042b1
commit
86b0aa4550
@ -771,7 +771,7 @@ ___
|
||||
|
||||
A special "StartUp" entry is sent if EDMarketConnector 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
|
||||
"LoadGame", "Rank", "Location", etc. However, the `state` dictionary will
|
||||
reflect the cumulative effect of these missed events.
|
||||
|
||||
**NB: Any of the values in this might be `None` if the Cmdr has loaded into
|
||||
|
181
monitor.py
181
monitor.py
@ -14,9 +14,7 @@ from collections import OrderedDict, defaultdict
|
||||
from os import SEEK_END, SEEK_SET, listdir
|
||||
from os.path import basename, expanduser, getctime, isdir, join
|
||||
from time import gmtime, localtime, mktime, sleep, strftime, strptime, time
|
||||
from typing import TYPE_CHECKING, Any, BinaryIO, MutableMapping
|
||||
from typing import OrderedDict as OrderedDictT
|
||||
from typing import Tuple
|
||||
from typing import TYPE_CHECKING, Any, BinaryIO, MutableMapping, Tuple
|
||||
|
||||
if TYPE_CHECKING:
|
||||
import tkinter
|
||||
@ -118,14 +116,14 @@ class EDLogs(FileSystemEventHandler): # type: ignore # See below
|
||||
self.mode: str | None = None
|
||||
self.group: str | None = None
|
||||
self.cmdr: str | None = None
|
||||
self.planet: str | None = None
|
||||
self.system: str | None = None
|
||||
self.systemaddress: int | None = None
|
||||
self.coordinates: Tuple[float, float, float] | None = None
|
||||
self.systempopulation: int | None = None
|
||||
self.planet: str | None = None
|
||||
self.station: str | None = None
|
||||
self.station_marketid: int | None = None
|
||||
self.stationtype: str | None = None
|
||||
self.coordinates: Tuple[float, float, float] | None = None
|
||||
self.systemaddress: int | None = None
|
||||
self.systempopulation: int | None = None
|
||||
self.started: int | None = None # Timestamp of the LoadGame event
|
||||
|
||||
self._navroute_retries_remaining = 0
|
||||
@ -195,7 +193,9 @@ class EDLogs(FileSystemEventHandler): # type: ignore # See below
|
||||
'Taxi': None, # True whenever we are _in_ a taxi. ie, this is reset on Disembark etc.
|
||||
'Dropship': None, # Best effort as to whether or not the above taxi is a dropship.
|
||||
'StarPos': None, # Best effort current system's galaxy position.
|
||||
'SystemAddress': None,
|
||||
'Body': None,
|
||||
'BodyID': None,
|
||||
'BodyType': None,
|
||||
|
||||
'NavRoute': None,
|
||||
@ -306,19 +306,19 @@ class EDLogs(FileSystemEventHandler): # type: ignore # See below
|
||||
self.mode = None
|
||||
self.group = None
|
||||
self.cmdr = None
|
||||
self.planet = None
|
||||
self.system = None
|
||||
self.state['SystemAddress'] = self.systemaddress = None
|
||||
self.coordinates = None
|
||||
self.planet = self.state['Body'] = None
|
||||
self.state['BodyID'] = None
|
||||
self.state['BodyType'] = None
|
||||
self.station = None
|
||||
self.station_marketid = None
|
||||
self.stationtype = None
|
||||
self.stationservices = None
|
||||
self.coordinates = None
|
||||
self.systemaddress = None
|
||||
self.is_beta = False
|
||||
self.state['OnFoot'] = False
|
||||
self.state['IsDocked'] = False
|
||||
self.state['Body'] = None
|
||||
self.state['BodyType'] = None
|
||||
|
||||
if self.observed:
|
||||
logger.debug('self.observed: Calling unschedule_all()')
|
||||
@ -416,24 +416,7 @@ class EDLogs(FileSystemEventHandler): # type: ignore # See below
|
||||
if self.live:
|
||||
if self.game_was_running:
|
||||
# Game is running locally
|
||||
entry: OrderedDictT[str, Any] = OrderedDict([
|
||||
('timestamp', strftime('%Y-%m-%dT%H:%M:%SZ', gmtime())),
|
||||
('event', 'StartUp'),
|
||||
('StarSystem', self.system),
|
||||
('StarPos', self.coordinates),
|
||||
('SystemAddress', self.systemaddress),
|
||||
('Population', self.systempopulation),
|
||||
])
|
||||
|
||||
if self.planet:
|
||||
entry['Body'] = self.planet
|
||||
|
||||
entry['Docked'] = bool(self.station)
|
||||
|
||||
if self.station:
|
||||
entry['StationName'] = self.station
|
||||
entry['StationType'] = self.stationtype
|
||||
entry['MarketID'] = self.station_marketid
|
||||
entry = self.synthesize_startup_event()
|
||||
|
||||
self.event_queue.put(json.dumps(entry, separators=(', ', ':')))
|
||||
|
||||
@ -534,6 +517,41 @@ class EDLogs(FileSystemEventHandler): # type: ignore # See below
|
||||
|
||||
logger.debug('Done.')
|
||||
|
||||
def synthesize_startup_event(self) -> dict[str, Any]:
|
||||
"""
|
||||
Synthesize a 'StartUp' event to notify plugins of initial state.
|
||||
|
||||
May be called, e.g. after 'catch up' loading of current latest
|
||||
journal file on startup, or when a new journal file is detected without
|
||||
the game running locally.
|
||||
|
||||
:return: Synthesized event as a dict
|
||||
"""
|
||||
entry: dict[str, Any] = {
|
||||
'timestamp': strftime('%Y-%m-%dT%H:%M:%SZ', gmtime()),
|
||||
'event': 'StartUp',
|
||||
'StarSystem': self.system,
|
||||
'StarPos': self.coordinates,
|
||||
'SystemAddress': self.systemaddress,
|
||||
'Population': self.systempopulation,
|
||||
}
|
||||
|
||||
if self.planet:
|
||||
entry['Body'] = self.planet
|
||||
entry['BodyID'] = self.state['BodyID']
|
||||
entry['BodyType'] = self.state['BodyType']
|
||||
|
||||
if self.station:
|
||||
entry['Docked'] = True
|
||||
entry['MarketID'] = self.station_marketid
|
||||
entry['StationName'] = self.station
|
||||
entry['StationType'] = self.stationtype
|
||||
|
||||
else:
|
||||
entry['Docked'] = False
|
||||
|
||||
return entry
|
||||
|
||||
def parse_entry(self, line: bytes) -> MutableMapping[str, Any]: # noqa: C901, CCR001
|
||||
"""
|
||||
Parse a Journal JSON line.
|
||||
@ -563,14 +581,15 @@ class EDLogs(FileSystemEventHandler): # type: ignore # See below
|
||||
self.cmdr = None
|
||||
self.mode = None
|
||||
self.group = None
|
||||
self.planet = None
|
||||
self.system = None
|
||||
self.state['SystemAddress'] = self.systemaddress = None
|
||||
self.state['StarPos'] = self.coordinates = None
|
||||
self.state['Body'] = self.planet = None
|
||||
self.state['BodyID'] = None
|
||||
self.station = None
|
||||
self.station_marketid = None
|
||||
self.stationtype = None
|
||||
self.stationservices = None
|
||||
self.coordinates = None
|
||||
self.systemaddress = None
|
||||
self.started = None
|
||||
self.__init_state()
|
||||
|
||||
@ -599,34 +618,34 @@ class EDLogs(FileSystemEventHandler): # type: ignore # See below
|
||||
self.mode = entry.get('GameMode')
|
||||
|
||||
self.group = entry.get('Group')
|
||||
self.planet = None
|
||||
self.system = None
|
||||
self.state['SystemAddress'] = self.systemaddress = None
|
||||
self.state['StarPos'] = self.coordinates = None
|
||||
self.status['Body'] = self.planet = None
|
||||
self.status['BodyID'] = None
|
||||
self.status['BodyType'] = None
|
||||
self.station = None
|
||||
self.station_marketid = None
|
||||
self.stationtype = None
|
||||
self.stationservices = None
|
||||
self.coordinates = None
|
||||
self.systemaddress = None
|
||||
self.started = timegm(strptime(entry['timestamp'], '%Y-%m-%dT%H:%M:%SZ'))
|
||||
# Don't set Ship, ShipID etc since this will reflect Fighter or SRV if starting in those
|
||||
self.state.update({
|
||||
'Captain': None,
|
||||
'Credits': entry['Credits'],
|
||||
'FID': entry.get('FID'), # From 3.3
|
||||
'Horizons': entry['Horizons'], # From 3.0
|
||||
'Odyssey': entry.get('Odyssey', False), # From 4.0 Odyssey
|
||||
'Loan': entry['Loan'],
|
||||
'Captain': None,
|
||||
'Credits': entry['Credits'],
|
||||
'FID': entry.get('FID'), # From 3.3
|
||||
'Horizons': entry['Horizons'], # From 3.0
|
||||
'Odyssey': entry.get('Odyssey', False), # From 4.0 Odyssey
|
||||
'Loan': entry['Loan'],
|
||||
# For Odyssey, by 4.0.0.100, and at least from Horizons 3.8.0.201 the order of events changed
|
||||
# to LoadGame being after some 'status' events.
|
||||
# 'Engineers': {}, # 'EngineerProgress' event now before 'LoadGame'
|
||||
# 'Rank': {}, # 'Rank'/'Progress' events now before 'LoadGame'
|
||||
# 'Reputation': {}, # 'Reputation' event now before 'LoadGame'
|
||||
'Statistics': {}, # Still after 'LoadGame' in 4.0.0.903
|
||||
'Role': None,
|
||||
'Taxi': None,
|
||||
'Dropship': None,
|
||||
'Body': None,
|
||||
'BodyType': None,
|
||||
# 'Engineers': {}, # 'EngineerProgress' event now before 'LoadGame'
|
||||
# 'Rank': {}, # 'Rank'/'Progress' events now before 'LoadGame'
|
||||
# 'Reputation': {}, # 'Reputation' event now before 'LoadGame'
|
||||
'Statistics': {}, # Still after 'LoadGame' in 4.0.0.903
|
||||
'Role': None,
|
||||
'Taxi': None,
|
||||
'Dropship': None,
|
||||
})
|
||||
if entry.get('Ship') is not None and self._RE_SHIP_ONFOOT.search(entry['Ship']):
|
||||
self.state['OnFoot'] = True
|
||||
@ -808,6 +827,18 @@ class EDLogs(FileSystemEventHandler): # type: ignore # See below
|
||||
self.state['Taxi'] = False
|
||||
self.state['Dropship'] = False
|
||||
|
||||
elif event_type == 'supercruiseexit':
|
||||
# For any orbital station we have no way of determining the body
|
||||
# it orbits:
|
||||
#
|
||||
# In-ship Status.json doesn't specify this.
|
||||
# On-foot Status.json lists the station itself as Body.
|
||||
# Location for stations (on-foot or in-ship) has station as Body.
|
||||
# SupercruiseExit (own ship or taxi) lists the station as the Body.
|
||||
if entry['BodyType'] == 'Station':
|
||||
self.state['Body'] = None
|
||||
self.state['BodyID'] = None
|
||||
|
||||
elif event_type == 'docked':
|
||||
self.state['IsDocked'] = True
|
||||
self.station = entry.get('StationName') # May be None
|
||||
@ -828,6 +859,7 @@ class EDLogs(FileSystemEventHandler): # type: ignore # See below
|
||||
if event_type in ('location', 'carrierjump'):
|
||||
self.planet = entry.get('Body') if entry.get('BodyType') == 'Planet' else None
|
||||
self.state['Body'] = entry.get('Body')
|
||||
self.state['BodyID'] = entry.get('BodyID')
|
||||
self.state['BodyType'] = entry.get('BodyType')
|
||||
|
||||
if event_type == 'location':
|
||||
@ -838,13 +870,14 @@ class EDLogs(FileSystemEventHandler): # type: ignore # See below
|
||||
elif event_type == 'fsdjump':
|
||||
self.planet = None
|
||||
self.state['Body'] = None
|
||||
self.state['BodyID'] = None
|
||||
self.state['BodyType'] = None
|
||||
|
||||
if 'StarPos' in entry:
|
||||
# Plugins need this as well, so copy in state
|
||||
self.state['StarPos'] = self.coordinates = tuple(entry['StarPos']) # type: ignore
|
||||
|
||||
self.systemaddress = entry.get('SystemAddress')
|
||||
self.state['SystemAddress'] = self.systemaddress = entry.get('SystemAddress')
|
||||
|
||||
self.systempopulation = entry.get('Population')
|
||||
|
||||
@ -872,11 +905,16 @@ class EDLogs(FileSystemEventHandler): # type: ignore # See below
|
||||
elif event_type == 'approachbody':
|
||||
self.planet = entry['Body']
|
||||
self.state['Body'] = entry['Body']
|
||||
self.state['BodyID'] = entry.get('BodyID')
|
||||
self.state['BodyType'] = 'Planet' # Best guess. Journal says always planet.
|
||||
|
||||
elif event_type in ('leavebody', 'supercruiseentry'):
|
||||
# FIXME: In the plugins/eddn.py version of this tracking we
|
||||
# explicitly do NOT clear this information for `supercruiseentry',
|
||||
# but it is also doing some Status.jon checking.
|
||||
self.planet = None
|
||||
self.state['Body'] = None
|
||||
self.state['BodyID'] = None
|
||||
self.state['BodyType'] = None
|
||||
|
||||
elif event_type in ('rank', 'promotion'):
|
||||
@ -1562,14 +1600,15 @@ class EDLogs(FileSystemEventHandler): # type: ignore # See below
|
||||
elif event_type == 'joinacrew':
|
||||
self.state['Captain'] = entry['Captain']
|
||||
self.state['Role'] = 'Idle'
|
||||
self.planet = None
|
||||
self.state['Body'] = self.planet = None
|
||||
self.state['BodyID'] = None
|
||||
self.system = None
|
||||
self.station = None
|
||||
self.station_marketid = None
|
||||
self.stationtype = None
|
||||
self.stationservices = None
|
||||
self.coordinates = None
|
||||
self.systemaddress = None
|
||||
self.state['SystemAddress'] = self.systemaddress = None
|
||||
self.state['OnFoot'] = False
|
||||
|
||||
self.state['Body'] = None
|
||||
@ -1581,17 +1620,17 @@ class EDLogs(FileSystemEventHandler): # type: ignore # See below
|
||||
elif event_type == 'quitacrew':
|
||||
self.state['Captain'] = None
|
||||
self.state['Role'] = None
|
||||
self.planet = None
|
||||
self.state['Body'] = self.planet = None
|
||||
self.state['BodyID'] = None
|
||||
self.state['BodyType'] = None
|
||||
self.system = None
|
||||
self.station = None
|
||||
self.station_marketid = None
|
||||
self.stationtype = None
|
||||
self.stationservices = None
|
||||
self.coordinates = None
|
||||
self.systemaddress = None
|
||||
self.state['SystemAddress'] = self.systemaddress = None
|
||||
|
||||
self.state['Body'] = None
|
||||
self.state['BodyType'] = None
|
||||
# TODO: on_foot: Will we get an event after this to know ?
|
||||
|
||||
elif event_type == 'friends':
|
||||
@ -1979,31 +2018,7 @@ class EDLogs(FileSystemEventHandler): # type: ignore # See below
|
||||
if not self.live and entry['event'] not in (None, 'Fileheader'):
|
||||
# Game not running locally, but Journal has been updated
|
||||
self.live = True
|
||||
if self.station:
|
||||
entry = OrderedDict([
|
||||
('timestamp', strftime('%Y-%m-%dT%H:%M:%SZ', gmtime())),
|
||||
('event', 'StartUp'),
|
||||
('Docked', True),
|
||||
('MarketID', self.station_marketid),
|
||||
('StationName', self.station),
|
||||
('StationType', self.stationtype),
|
||||
('StarSystem', self.system),
|
||||
('StarPos', self.coordinates),
|
||||
('SystemAddress', self.systemaddress),
|
||||
])
|
||||
|
||||
else:
|
||||
entry = OrderedDict([
|
||||
('timestamp', strftime('%Y-%m-%dT%H:%M:%SZ', gmtime())),
|
||||
('event', 'StartUp'),
|
||||
('Docked', False),
|
||||
('StarSystem', self.system),
|
||||
('StarPos', self.coordinates),
|
||||
('SystemAddress', self.systemaddress),
|
||||
])
|
||||
|
||||
if entry['event'] == 'Location':
|
||||
logger.trace_if('journal.locations', 'Appending "Location" event to event_queue')
|
||||
entry = self.synthesize_startup_event()
|
||||
|
||||
self.event_queue.put(json.dumps(entry, separators=(', ', ':')))
|
||||
|
||||
|
@ -2208,6 +2208,14 @@ def journal_entry( # noqa: C901, CCR001
|
||||
entry
|
||||
)
|
||||
|
||||
# TODO - uncomment this, i.e. use monitor.py tracking, not also here
|
||||
# Copy some state into module-held variables because we might need it
|
||||
# outside of this function.
|
||||
# this.body_name = state['Body']
|
||||
# this.body_id = state['BodyID']
|
||||
# this.coordinates = state['StarPos']
|
||||
# this.systemaddress = state['SystemAddress']
|
||||
|
||||
# Track location
|
||||
if event_name == 'supercruiseexit':
|
||||
# For any orbital station we have no way of determining the body
|
||||
@ -2360,6 +2368,7 @@ def journal_entry( # noqa: C901, CCR001
|
||||
|
||||
# add planet to Docked event for planetary stations if known
|
||||
if event_name == 'docked' and this.body_name:
|
||||
# FIXME - Is this correct if using monitor.py tracking ?
|
||||
entry['Body'] = this.body_name
|
||||
entry['BodyType'] = 'Planet'
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user