From 0219098d054af7ade6e8461ca5b35a8bd1e50a5e Mon Sep 17 00:00:00 2001 From: Athanasius Date: Fri, 21 May 2021 11:42:03 +0100 Subject: [PATCH 1/6] UI Suit: Keep line hidden if Odyssey not detected Else we'll show the line with '' always in Horizons --- EDMarketConnector.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/EDMarketConnector.py b/EDMarketConnector.py index 77ae8772..2f94f660 100755 --- a/EDMarketConnector.py +++ b/EDMarketConnector.py @@ -620,6 +620,11 @@ class AppWindow(object): def update_suit_text(self) -> None: """Update the suit text for current type and loadout.""" + if not monitor.state['Odyssey']: + # Odyssey not detected, no text should be set so it will hide + self.suit['text'] = '' + return + if (suit := monitor.state.get('SuitCurrent')) is None: self.suit['text'] = f'<{_("Unknown")}>' return From 3a92ff9f96b861e8c49a4be7c89bd8e5089a0b21 Mon Sep 17 00:00:00 2001 From: Athanasius Date: Fri, 21 May 2021 11:42:59 +0100 Subject: [PATCH 2/6] SwitchSuitLoadout: Example from 4.0.0.101 added in comments --- monitor.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/monitor.py b/monitor.py index 907ccf04..4f56d7f5 100644 --- a/monitor.py +++ b/monitor.py @@ -1087,6 +1087,19 @@ class EDLogs(FileSystemEventHandler): # type: ignore # See below self.state['SuitCurrent'] = new_suit elif event_type == 'SwitchSuitLoadout': + # 4.0.0.101 + # + # { "timestamp":"2021-05-21T10:39:43Z", "event":"SwitchSuitLoadout", + # "SuitID":1700217809818876, "SuitName":"utilitysuit_class1", + # "SuitName_Localised":"Maverick Suit", "LoadoutID":4293000002, + # "LoadoutName":"K/P", "Modules":[ { "SlotName":"PrimaryWeapon1", + # "SuitModuleID":1700217863661544, + # "ModuleName":"wpn_m_assaultrifle_kinetic_fauto", + # "ModuleName_Localised":"Karma AR-50" }, + # { "SlotName":"SecondaryWeapon", "SuitModuleID":1700216180036986, + # "ModuleName":"wpn_s_pistol_plasma_charged", + # "ModuleName_Localised":"Manticore Tormentor" } ] } + # loadoutid = entry['LoadoutID'] new_slot = self.suit_loadout_id_from_loadoutid(loadoutid) # If this application is run with the latest Journal showing such an event then we won't From f923ef64ca568f5c8237690e3c1a786930cbb5c9 Mon Sep 17 00:00:00 2001 From: Athanasius Date: Fri, 21 May 2021 12:08:22 +0100 Subject: [PATCH 3/6] Suits: Refactor 'SuitLoadout' to also be used in 'SwitchSuitLoadout' --- monitor.py | 91 ++++++++++++++++++++++-------------------------------- 1 file changed, 37 insertions(+), 54 deletions(-) diff --git a/monitor.py b/monitor.py index 4f56d7f5..4374e368 100644 --- a/monitor.py +++ b/monitor.py @@ -1057,34 +1057,7 @@ class EDLogs(FileSystemEventHandler): # type: ignore # See below # this version of the docs: "SuitLoadout": # when starting on foot, or # when disembarking from a ship, with the same info as found in "CreateSuitLoadout" elif event_type == 'SuitLoadout': - suit_slotid = self.suit_loadout_id_from_loadoutid(entry['LoadoutID']) - # Initial suit containing just the data that is then embedded in - # the loadout - new_suit = { - 'name': entry['SuitName'], - 'locName': entry.get('SuitName_Localised', entry['SuitName']), - 'suitId': entry['SuitID'], - } - - # Make the new loadout, in the CAPI format - new_loadout = { - 'loadoutSlotId': suit_slotid, - 'suit': new_suit, - 'name': entry['LoadoutName'], - 'slots': self.suit_loadout_slots_array_to_dict(entry['Modules']), - } - - # Assign this loadout into our state - self.state['SuitLoadouts'][new_loadout['loadoutSlotId']] = new_loadout - self.state['SuitLoadoutCurrent'] = new_loadout - - # Now add in the extra fields for new_suit to be a 'full' Suit structure - new_suit['id'] = None # Not available in 4.0.0.100 journal event - new_suit['slots'] = new_loadout['slots'] # 'slots', not 'Modules', to match CAPI - - # Ensure new_suit is in self.state['Suits'] - self.state['Suits'][suit_slotid] = new_suit - self.state['SuitCurrent'] = new_suit + self.store_suitloadout_from_event(entry) elif event_type == 'SwitchSuitLoadout': # 4.0.0.101 @@ -1100,32 +1073,7 @@ class EDLogs(FileSystemEventHandler): # type: ignore # See below # "ModuleName":"wpn_s_pistol_plasma_charged", # "ModuleName_Localised":"Manticore Tormentor" } ] } # - loadoutid = entry['LoadoutID'] - new_slot = self.suit_loadout_id_from_loadoutid(loadoutid) - # If this application is run with the latest Journal showing such an event then we won't - # yet have the CAPI data, so no idea about Suits or Loadouts. - if self.state['Suits'] and self.state['SuitLoadouts']: - try: - self.state['SuitLoadoutCurrent'] = self.state['SuitLoadouts'][f'{new_slot}'] - - except KeyError: - logger.debug(f"KeyError getting suit loadout after switch, bad slot: {new_slot} ({loadoutid})") - self.state['SuitCurrent'] = None - self.state['SuitLoadoutCurrent'] = None - - else: - try: - new_suitid = self.state['SuitLoadoutCurrent']['suit']['suitId'] - - except KeyError: - logger.debug(f"KeyError getting switched-to suit ID from slot {new_slot} ({loadoutid})") - - else: - try: - self.state['SuitCurrent'] = self.state['Suits'][f'{new_suitid}'] - - except KeyError: - logger.debug(f"KeyError getting switched-to suit from slot {new_slot} ({loadoutid}") + self.store_suitloadout_from_event(entry) elif event_type == 'CreateSuitLoadout': # We know we won't have data for this new one @@ -1649,6 +1597,41 @@ class EDLogs(FileSystemEventHandler): # type: ignore # See below logger.debug(f'Invalid journal entry:\n{line!r}\n', exc_info=ex) return {'event': None} + def store_suitloadout_from_event(self, entry) -> None: + """ + Store Suit and SuitLoadout data from a journal event. + + Also use set currently in-use instances of them as being as per this + event. + + :param entry: Journal entry - 'SwitchSuitLoadout' or 'SuitLoadout' + """ + suit_slotid = self.suit_loadout_id_from_loadoutid(entry['LoadoutID']) + # Initial suit containing just the data that is then embedded in + # the loadout + new_suit = { + 'name': entry['SuitName'], + 'locName': entry.get('SuitName_Localised', entry['SuitName']), + 'suitId': entry['SuitID'], + } + # Make the new loadout, in the CAPI format + new_loadout = { + 'loadoutSlotId': suit_slotid, + 'suit': new_suit, + 'name': entry['LoadoutName'], + 'slots': self.suit_loadout_slots_array_to_dict( + entry['Modules']), + } + # Assign this loadout into our state + self.state['SuitLoadouts'][f"{new_loadout['loadoutSlotId']}"] = new_loadout + self.state['SuitLoadoutCurrent'] = new_loadout + # Now add in the extra fields for new_suit to be a 'full' Suit structure + new_suit['id'] = None # Not available in 4.0.0.100 journal event + new_suit['slots'] = new_loadout['slots'] # 'slots', not 'Modules', to match CAPI + # Ensure new_suit is in self.state['Suits'] + self.state['Suits'][f"{suit_slotid}"] = new_suit + self.state['SuitCurrent'] = new_suit + # TODO: *This* will need refactoring and a proper validation infrastructure # designed for this in the future. This is a bandaid for a known issue. def event_valid_engineerprogress(self, entry) -> bool: # noqa: CCR001 C901 From 43d261f290e4753aa01bdd9f76ed5aff47ea620d Mon Sep 17 00:00:00 2001 From: Athanasius Date: Fri, 21 May 2021 12:14:18 +0100 Subject: [PATCH 4/6] CreateSuitLoadout: 4.0.0.101 example comment --- monitor.py | 32 +++++++++++--------------------- 1 file changed, 11 insertions(+), 21 deletions(-) diff --git a/monitor.py b/monitor.py index 4374e368..a108d7df 100644 --- a/monitor.py +++ b/monitor.py @@ -1076,27 +1076,17 @@ class EDLogs(FileSystemEventHandler): # type: ignore # See below self.store_suitloadout_from_event(entry) elif event_type == 'CreateSuitLoadout': - # We know we won't have data for this new one - # Parameters: - # • SuitID - # • SuitName - # • LoadoutID - # • LoadoutName - # alpha4: - # { "timestamp":"2021-04-29T09:37:08Z", "event":"CreateSuitLoadout", "SuitID":1698364940285172, - # "SuitName":"tacticalsuit_class1", "SuitName_Localised":"Dominator Suit", "LoadoutID":4293000001, - # "LoadoutName":"Dom L/K/K", "Modules":[ - # { - # "SlotName":"PrimaryWeapon1", - # "SuitModuleID":1698364962722310, - # "ModuleName":"wpn_m_assaultrifle_laser_fauto", - # "ModuleName_Localised":"TK Aphelion" - # }, - # { "SlotName":"PrimaryWeapon2", - # "SuitModuleID":1698364956302993, "ModuleName":"wpn_m_assaultrifle_kinetic_fauto", - # "ModuleName_Localised":"Karma AR-50" }, { "SlotName":"SecondaryWeapon", - # "SuitModuleID":1698292655291850, "ModuleName":"wpn_s_pistol_kinetic_sauto", - # "ModuleName_Localised":"Karma P-15" } ] } + # 4.0.0.101 + # + # { "timestamp":"2021-05-21T11:13:15Z", "event":"CreateSuitLoadout", "SuitID":1700216165682989, + # "SuitName":"tacticalsuit_class1", "SuitName_Localised":"Dominator Suit", "LoadoutID":4293000004, + # "LoadoutName":"P/P/K", "Modules":[ { "SlotName":"PrimaryWeapon1", "SuitModuleID":1700216182854765, + # "ModuleName":"wpn_m_assaultrifle_plasma_fauto", "ModuleName_Localised":"Manticore Oppressor" }, + # { "SlotName":"PrimaryWeapon2", "SuitModuleID":1700216190363340, + # "ModuleName":"wpn_m_shotgun_plasma_doublebarrel", "ModuleName_Localised":"Manticore Intimidator" }, + # { "SlotName":"SecondaryWeapon", "SuitModuleID":1700217869872834, + # "ModuleName":"wpn_s_pistol_kinetic_sauto", "ModuleName_Localised":"Karma P-15" } ] } + # new_loadout = { 'loadoutSlotId': self.suit_loadout_id_from_loadoutid(entry['LoadoutID']), 'suit': { From 7e064374d21404615612d8f096b82e60b802dd49 Mon Sep 17 00:00:00 2001 From: Athanasius Date: Fri, 21 May 2021 12:27:16 +0100 Subject: [PATCH 5/6] Suits: Refactor suit/loadout set-current away from store This way we can have common code for SuitLoadout, SwitchSuitLoadout and CreateSuitLoadout, with the first two then calling the new `self.suit_and_loadout_setcurrent()` to set the seen data as also the currently in use suit/loadout. --- monitor.py | 48 ++++++++++++++++++++++++++++++++---------------- 1 file changed, 32 insertions(+), 16 deletions(-) diff --git a/monitor.py b/monitor.py index a108d7df..ad0385d9 100644 --- a/monitor.py +++ b/monitor.py @@ -1057,7 +1057,8 @@ class EDLogs(FileSystemEventHandler): # type: ignore # See below # this version of the docs: "SuitLoadout": # when starting on foot, or # when disembarking from a ship, with the same info as found in "CreateSuitLoadout" elif event_type == 'SuitLoadout': - self.store_suitloadout_from_event(entry) + suit_slotid, suitloadout_slotid = self.suitloadout_store_from_event(entry) + self.suit_and_loadout_setcurrent(suit_slotid, suitloadout_slotid) elif event_type == 'SwitchSuitLoadout': # 4.0.0.101 @@ -1073,7 +1074,8 @@ class EDLogs(FileSystemEventHandler): # type: ignore # See below # "ModuleName":"wpn_s_pistol_plasma_charged", # "ModuleName_Localised":"Manticore Tormentor" } ] } # - self.store_suitloadout_from_event(entry) + suit_slotid, suitloadout_slotid = self.suitloadout_store_from_event(entry) + self.suit_and_loadout_setcurrent(suit_slotid, suitloadout_slotid) elif event_type == 'CreateSuitLoadout': # 4.0.0.101 @@ -1087,17 +1089,7 @@ class EDLogs(FileSystemEventHandler): # type: ignore # See below # { "SlotName":"SecondaryWeapon", "SuitModuleID":1700217869872834, # "ModuleName":"wpn_s_pistol_kinetic_sauto", "ModuleName_Localised":"Karma P-15" } ] } # - new_loadout = { - 'loadoutSlotId': self.suit_loadout_id_from_loadoutid(entry['LoadoutID']), - 'suit': { - 'name': entry['SuitName'], - 'locName': entry.get('SuitName_Localised', entry['SuitName']), - 'suitId': entry['SuitID'], - }, - 'name': entry['LoadoutName'], - 'slots': self.suit_loadout_slots_array_to_dict(entry['Modules']), - } - self.state['SuitLoadouts'][new_loadout['loadoutSlotId']] = new_loadout + _, _ = self.suitloadout_store_from_event(entry) elif event_type == 'DeleteSuitLoadout': # alpha4: @@ -1587,7 +1579,7 @@ class EDLogs(FileSystemEventHandler): # type: ignore # See below logger.debug(f'Invalid journal entry:\n{line!r}\n', exc_info=ex) return {'event': None} - def store_suitloadout_from_event(self, entry) -> None: + def suitloadout_store_from_event(self, entry) -> Tuple[int, int]: """ Store Suit and SuitLoadout data from a journal event. @@ -1595,6 +1587,7 @@ class EDLogs(FileSystemEventHandler): # type: ignore # See below event. :param entry: Journal entry - 'SwitchSuitLoadout' or 'SuitLoadout' + :return Tuple[suit_slotid, suitloadout_slotid]: The IDs we set data for. """ suit_slotid = self.suit_loadout_id_from_loadoutid(entry['LoadoutID']) # Initial suit containing just the data that is then embedded in @@ -1614,13 +1607,36 @@ class EDLogs(FileSystemEventHandler): # type: ignore # See below } # Assign this loadout into our state self.state['SuitLoadouts'][f"{new_loadout['loadoutSlotId']}"] = new_loadout - self.state['SuitLoadoutCurrent'] = new_loadout + # Now add in the extra fields for new_suit to be a 'full' Suit structure new_suit['id'] = None # Not available in 4.0.0.100 journal event new_suit['slots'] = new_loadout['slots'] # 'slots', not 'Modules', to match CAPI # Ensure new_suit is in self.state['Suits'] self.state['Suits'][f"{suit_slotid}"] = new_suit - self.state['SuitCurrent'] = new_suit + + return suit_slotid, new_loadout['loadoutSlotId'] + + def suit_and_loadout_setcurrent(self, suit_slotid: int, suitloadout_slotid: int) -> bool: + """ + Set self.state for SuitCurrent and SuitLoadoutCurrent as requested. + + If the specified slots are unknown we abort and return False, else + return True. + + :param suit_slotid: Numeric ID of the slot for the suit. + :param suitloadout_slotid: Numeric ID of the slot for the suit loadout. + :return: True if we could do this, False if not. + """ + str_suitid = f"{suit_slotid}" + str_suitloadoutid = f"{suitloadout_slotid}" + + if (self.state['Suits'].get(str_suitid, False) + and self.state['SuitLoadouts'].get(str_suitloadoutid, False)): + self.state['SuitCurrent'] = self.state['Suits'][str_suitid] + self.state['SuitLoadoutCurrent'] = self.state['SuitLoadouts'][str_suitloadoutid] + return True + + return False # TODO: *This* will need refactoring and a proper validation infrastructure # designed for this in the future. This is a bandaid for a known issue. From da94b729bd553a8c3fbc7adbd1dc987fdd6ad369 Mon Sep 17 00:00:00 2001 From: Athanasius Date: Fri, 21 May 2021 12:31:08 +0100 Subject: [PATCH 6/6] Suits: Log if we try to set unknown suit/loadout --- monitor.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/monitor.py b/monitor.py index ad0385d9..eeedfbd6 100644 --- a/monitor.py +++ b/monitor.py @@ -1058,7 +1058,8 @@ class EDLogs(FileSystemEventHandler): # type: ignore # See below # when disembarking from a ship, with the same info as found in "CreateSuitLoadout" elif event_type == 'SuitLoadout': suit_slotid, suitloadout_slotid = self.suitloadout_store_from_event(entry) - self.suit_and_loadout_setcurrent(suit_slotid, suitloadout_slotid) + if not self.suit_and_loadout_setcurrent(suit_slotid, suitloadout_slotid): + logger.error(f"Event was: {entry}") elif event_type == 'SwitchSuitLoadout': # 4.0.0.101 @@ -1075,7 +1076,8 @@ class EDLogs(FileSystemEventHandler): # type: ignore # See below # "ModuleName_Localised":"Manticore Tormentor" } ] } # suit_slotid, suitloadout_slotid = self.suitloadout_store_from_event(entry) - self.suit_and_loadout_setcurrent(suit_slotid, suitloadout_slotid) + if not self.suit_and_loadout_setcurrent(suit_slotid, suitloadout_slotid): + logger.error(f"Event was: {entry}") elif event_type == 'CreateSuitLoadout': # 4.0.0.101 @@ -1636,6 +1638,8 @@ class EDLogs(FileSystemEventHandler): # type: ignore # See below self.state['SuitLoadoutCurrent'] = self.state['SuitLoadouts'][str_suitloadoutid] return True + logger.error(f"Tried to set a suit and suitloadout where we didn't know about both: {suit_slotid=}, " + f"{str_suitloadoutid=}") return False # TODO: *This* will need refactoring and a proper validation infrastructure