1
0
mirror of https://github.com/EDCD/EDMarketConnector.git synced 2025-04-19 10:27:38 +03:00

Merge pull request #1308 from EDCD/enhancement/eddn-CAPIdata-always-use-journal-horizons

EDDN: Ensure we always send `horizons` flag where schema allows
This commit is contained in:
Athanasius 2021-10-18 14:33:16 +01:00 committed by GitHub
commit 1e65b60836
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 79 additions and 42 deletions

View File

@ -659,13 +659,12 @@ New in version 5.0.1:
`Odyssey` boolean based on the presence of such a flag in the `LoadGame`
event. Defaults to `False`, i.e. if no such key in the event.
The previously undocumented`Horizons` boolean is similarly from `LoadGame`,
but blindly retrieves the value rather than having a strict default. There's
The previously undocumented `Horizons` boolean is similarly from `LoadGame`,
but blindly retrieves the value rather than having a strict default. There'd
be an exception if it wasn't there, and the value would be `None`. Note that
this is **NOT** the same as the return from
[plugins/eddn.py:is_horizons()](./plugins/eddn.py). That function is necessary
because CAPI data doesn't (didn't always?) have an indication of Horizons or
not.
[plugins/eddn.py:capi_is_horizons()](./plugins/eddn.py). That function is
necessary because CAPI data doesn't have a simple indication of Horizons-ness.
New in version 5.0.3:

View File

@ -91,7 +91,15 @@ class This:
this = This()
HORIZ_SKU = 'ELITE_HORIZONS_V_PLANETARY_LANDINGS'
# This SKU is tagged on any module or ship that you must have Horizons for.
HORIZONS_SKU = 'ELITE_HORIZONS_V_PLANETARY_LANDINGS'
# ELITE_HORIZONS_V_COBRA_MK_IV_1000` is for the Cobra Mk IV, but
# is also available in the base game, if you have entitlement.
# `ELITE_HORIZONS_V_GUARDIAN_FSDBOOSTER` is for the Guardian FSD Boosters,
# which you need Horizons in order to unlock, but could be on sale even in the
# base game due to entitlement.
# Thus do **NOT** use either of these in addition to the PLANETARY_LANDINGS
# one.
# TODO: a good few of these methods are static or could be classmethods. they should be created as such.
@ -329,16 +337,25 @@ Msg:\n{msg}'''
# LANG: EDDN returned some sort of HTTP error, one we didn't expect. {STATUS} contains a number
return _('EDDN Error: Returned {STATUS} status code').format(status_code)
def export_commodities(self, data: Mapping[str, Any], is_beta: bool, is_odyssey: bool) -> None: # noqa: CCR001
def export_commodities(self, data: Mapping[str, Any], is_beta: bool) -> None: # noqa: CCR001
"""
Update EDDN with the commodities on the current (lastStarport) station.
Once the send is complete, this.commodities is updated with the new data.
NB: This does *not* go through the replaylog, unlike most of the
Journal-sourced data. This kind of timely data is often rejected by
listeners if 'too old' anyway, so little point.
:param data: a dict containing the starport data
:param is_beta: whether or not we're currently in beta mode
:param is_odyssey: whether the account shows as having Odyssey expansion.
"""
modules, ships = self.safe_modules_and_ships(data)
horizons: bool = capi_is_horizons(
data['lastStarport'].get('economies', {}),
modules,
ships
)
commodities: List[OrderedDictT[str, Any]] = []
for commodity in data['lastStarport'].get('commodities') or []:
# Check 'marketable' and 'not prohibited'
@ -373,7 +390,8 @@ Msg:\n{msg}'''
('stationName', data['lastStarport']['name']),
('marketId', data['lastStarport']['id']),
('commodities', commodities),
('odyssey', is_odyssey),
('horizons', horizons),
('odyssey', this.odyssey),
])
if 'economies' in data['lastStarport']:
@ -431,12 +449,16 @@ Msg:\n{msg}'''
return modules, ships
def export_outfitting(self, data: CAPIData, is_beta: bool, is_odyssey: bool) -> None:
def export_outfitting(self, data: CAPIData, is_beta: bool) -> None:
"""
Update EDDN with the current (lastStarport) station's outfitting options, if any.
Once the send is complete, this.outfitting is updated with the given data.
NB: This does *not* go through the replaylog, unlike most of the
Journal-sourced data. This kind of timely data is often rejected by
listeners if 'too old' anyway, so little point.
:param data: dict containing the outfitting data
:param is_beta: whether or not we're currently in beta mode
"""
@ -444,15 +466,15 @@ Msg:\n{msg}'''
# Horizons flag - will hit at least Int_PlanetApproachSuite other than at engineer bases ("Colony"),
# prison or rescue Megaships, or under Pirate Attack etc
horizons: bool = is_horizons(
horizons: bool = capi_is_horizons(
data['lastStarport'].get('economies', {}),
modules,
ships
)
to_search: Iterator[Mapping[str, Any]] = filter(
lambda m: self.MODULE_RE.search(m['name']) and m.get('sku') in (None, HORIZ_SKU) and
m['name'] != 'Int_PlanetApproachSuite',
lambda m: self.MODULE_RE.search(m['name']) and m.get('sku') in (None, HORIZONS_SKU)
and m['name'] != 'Int_PlanetApproachSuite', # noqa: E131
modules.values()
)
@ -471,24 +493,28 @@ Msg:\n{msg}'''
('marketId', data['lastStarport']['id']),
('horizons', horizons),
('modules', outfitting),
('odyssey', is_odyssey),
('odyssey', this.odyssey),
]),
})
this.outfitting = (horizons, outfitting)
def export_shipyard(self, data: CAPIData, is_beta: bool, is_odyssey: bool) -> None:
def export_shipyard(self, data: CAPIData, is_beta: bool) -> None:
"""
Update EDDN with the current (lastStarport) station's outfitting options, if any.
Once the send is complete, this.shipyard is updated to the new data.
NB: This does *not* go through the replaylog, unlike most of the
Journal-sourced data. This kind of timely data is often rejected by
listeners if 'too old' anyway, so little point.
:param data: dict containing the shipyard data
:param is_beta: whether or not we are in beta mode
"""
modules, ships = self.safe_modules_and_ships(data)
horizons: bool = is_horizons(
horizons: bool = capi_is_horizons(
data['lastStarport'].get('economies', {}),
modules,
ships
@ -511,7 +537,7 @@ Msg:\n{msg}'''
('marketId', data['lastStarport']['id']),
('horizons', horizons),
('ships', shipyard),
('odyssey', is_odyssey),
('odyssey', this.odyssey),
]),
})
@ -523,6 +549,10 @@ Msg:\n{msg}'''
As a side effect, it also updates this.commodities with the data.
NB: This does *not* go through the replaylog, unlike most of the
Journal-sourced data. This kind of timely data is often rejected by
listeners if 'too old' anyway, so little point.
:param cmdr: The commander to send data under
:param is_beta: whether or not we're in beta mode
:param entry: the journal entry containing the commodities data
@ -554,7 +584,8 @@ Msg:\n{msg}'''
('stationName', entry['StationName']),
('marketId', entry['MarketID']),
('commodities', commodities),
('odyssey', entry['odyssey'])
('horizons', this.horizons),
('odyssey', this.odyssey),
]),
})
@ -566,6 +597,10 @@ Msg:\n{msg}'''
As a side effect, it also updates this.outfitting with the data.
NB: This does *not* go through the replaylog, unlike most of the
Journal-sourced data. This kind of timely data is often rejected by
listeners if 'too old' anyway, so little point.
:param cmdr: The commander to send data under
:param is_beta: Whether or not we're in beta mode
:param entry: The relevant journal entry
@ -601,6 +636,10 @@ Msg:\n{msg}'''
As a side effect, this.shipyard is updated with the data.
NB: This does *not* go through the replaylog, unlike most of the
Journal-sourced data. This kind of timely data is often rejected by
listeners if 'too old' anyway, so little point.
:param cmdr: the commander to send this update under
:param is_beta: Whether or not we're in beta mode
:param entry: the relevant journal entry
@ -629,7 +668,8 @@ Msg:\n{msg}'''
"""
Update EDDN with an event from the journal.
Additionally if additional lines are cached, it may send those as well.
Additionally if other lines have been saved for retry, it may send
those as well.
:param cmdr: Commander name as passed in through `journal_entry()`.
:param entry: The full journal event dictionary (due to checks in this function).
@ -919,9 +959,14 @@ Msg:\n{msg}'''
#######################################################################
# Elisions
#######################################################################
# WORKAROUND WIP EDDN schema | 2021-09-27: This will reject with the Odyssey flag present
# WORKAROUND WIP EDDN schema | 2021-10-17: This will reject with the Odyssey or Horizons flags present
if 'odyssey' in entry:
del entry['odyssey']
if 'horizons' in entry:
del entry['horizons']
# END WORKAROUND
#######################################################################
#######################################################################
@ -1380,9 +1425,9 @@ def cmdr_data(data: CAPIData, is_beta: bool) -> Optional[str]: # noqa: CCR001
status['text'] = _('Sending data to EDDN...') # LANG: Status text shown while attempting to send data
status.update_idletasks()
this.eddn.export_commodities(data, is_beta, this.odyssey)
this.eddn.export_outfitting(data, is_beta, this.odyssey)
this.eddn.export_shipyard(data, is_beta, this.odyssey)
this.eddn.export_commodities(data, is_beta)
this.eddn.export_outfitting(data, is_beta)
this.eddn.export_shipyard(data, is_beta)
if not old_status:
status['text'] = ''
status.update_idletasks()
@ -1401,31 +1446,24 @@ def cmdr_data(data: CAPIData, is_beta: bool) -> Optional[str]: # noqa: CCR001
MAP_STR_ANY = Mapping[str, Any]
def is_horizons(economies: MAP_STR_ANY, modules: MAP_STR_ANY, ships: MAP_STR_ANY) -> bool:
def capi_is_horizons(economies: MAP_STR_ANY, modules: MAP_STR_ANY, ships: MAP_STR_ANY) -> bool:
"""
Indicate if the supplied data indicates a player has Horizons access.
This is to be used **only** for CAPI-sourced data and **MUST** be used
for CAPI data!!!
If the account has Horizons access then CAPI `/shipyard` will always see
the Horizons-only modules/ships. You can**NOT** use the Journal horizons
flag for this! If logged in to the base game on an account with Horizons,
which is all of them now, CAPI `/shipyard` will *still* return all of the
Horizons-only modules and ships.
:param economies: Economies of where the Cmdr is docked.
:param modules: Modules available at the docked station.
:param ships: Ships available at the docked station.
:return: bool - True if the Cmdr has Horizons access.
"""
# First check the Journal-sourced flag
# NB: This assumes game currently running, rather than "old
# journal file". `LoadGame` determines monitor.cmdr, which determines
# the account used for CAPI, so it *should* match.
#
# For this to be wrong, the user would have had to have, e.g.:
#
# 1. Logged into Cmdr in Horizons/Odyssey, then back out again.
# 2. Logged into Cmdr in base game, either on another machine, or
# have removed the Journal file after.
# 3. Re-run EDMC and triggered a manual CAPI update.
#
# This seems unlikely.
if this.horizons:
return True
economies_colony = False
modules_horizons = False
ship_horizons = False
@ -1437,7 +1475,7 @@ def is_horizons(economies: MAP_STR_ANY, modules: MAP_STR_ANY, ships: MAP_STR_ANY
logger.error(f'economies type is {type(economies)}')
if isinstance(modules, dict):
modules_horizons = any(module.get('sku') == HORIZ_SKU for module in modules.values())
modules_horizons = any(module.get('sku') == HORIZONS_SKU for module in modules.values())
else:
logger.error(f'modules type is {type(modules)}')
@ -1445,7 +1483,7 @@ def is_horizons(economies: MAP_STR_ANY, modules: MAP_STR_ANY, ships: MAP_STR_ANY
if isinstance(ships, dict):
if ships.get('shipyard_list') is not None:
if isinstance(ships.get('shipyard_list'), dict):
ship_horizons = any(ship.get('sku') == HORIZ_SKU for ship in ships['shipyard_list'].values())
ship_horizons = any(ship.get('sku') == HORIZONS_SKU for ship in ships['shipyard_list'].values())
else:
logger.debug('ships["shipyard_list"] is not dict - FC or Damaged Station?')