Done by temporarily buffering events before monitor.mode is set, then notifying plugins about them before sending the first event where monitor.mode has a value. LoadGame is currently the only event that sets monitor.mode. Fixes #2286 diff --git a/EDMarketConnector.py b/EDMarketConnector.py index e7bdf490..d53b625d 100644 --- a/EDMarketConnector.py +++ b/EDMarketConnector.py @@ -22,7 +22,7 @@ import threading import webbrowser from os import chdir, environ from time import localtime, strftime, time -from typing import TYPE_CHECKING, Any, Literal +from typing import TYPE_CHECKING, Any, Literal, MutableMapping from constants import applongname, appname, protocolhandler_redirect # Have this as early as possible for people running EDMarketConnector.exe @@ -458,6 +458,8 @@ class AppWindow: def __init__(self, master: tk.Tk): # noqa: C901, CCR001 # TODO - can possibly factor something out + self.early_journal_events: list[MutableMapping[str, Any]] = [] + self.capi_query_holdoff_time = config.get_int('querytime', default=0) + companion.capi_query_cooldown self.capi_fleetcarrier_query_holdoff_time = config.get_int('fleetcarrierquerytime', default=0) \ + companion.capi_fleetcarrier_query_cooldown @@ -1400,6 +1402,19 @@ class AppWindow: self.cooldown() logger.trace_if('capi.worker', '...done') + def handle_plugin_event_error(self, err: str | None) -> None: + """ + Display a plugin's error message at the bottom of the main window. + + If there was no error message passed in, nothing will be done. + + :param err: Message to display, or None for no error. + """ + if err: + self.status['text'] = err + if not config.get_int('hotkey_mute'): + hotkeymgr.play_bad() + def journal_event(self, event: str): # noqa: C901, CCR001 # Currently not easily broken up. """ Handle a Journal event passed through event queue from monitor.py. @@ -1513,15 +1528,21 @@ class AppWindow: if monitor.cmdr and monitor.mode == 'CQC' and entry['event']: err = plug.notify_journal_entry_cqc(monitor.cmdr, monitor.is_beta, entry, monitor.state) - if err: - self.status['text'] = err - if not config.get_int('hotkey_mute'): - hotkeymgr.play_bad() + self.handle_plugin_event_error(err) return # in CQC if not entry['event'] or not monitor.mode: + # Game session has not fully loaded yet. We may be receiving events from the + # journal, but don't know which game mode (Open/CQC/solo etc) we're running in. logger.trace_if('journal.queue', 'Startup, returning') + + if entry['event']: + # Since we don't know which mode the game is in (and therefore whether to send + # the event to a plugin's `journal_event` or `journal_event_cqc` function), + # temporarily queue it so we can pass it on once the mode is known. + self.early_journal_events.append(entry) + return # Startup if entry['event'] in ('StartUp', 'LoadGame') and monitor.started: @@ -1538,6 +1559,25 @@ class AppWindow: if not dashboard.start(self.w, monitor.started): logger.info("Can't start Status monitoring") + # monitor.cmdr should always be set if monitor.mode is set (and monitor.mode must be set + # if we reach this point in the function), but we check monitor.cmdr here so the mypy + # doesn't complain about passing str|None where str is required. + if self.early_journal_events and monitor.cmdr: + for early_entry in self.early_journal_events: + if monitor.mode == 'CQC': + err = plug.notify_journal_entry_cqc(monitor.cmdr, monitor.is_beta, early_entry, monitor.state) + else: + err = plug.notify_journal_entry( + monitor.cmdr, + monitor.is_beta, + monitor.state['SystemName'], + monitor.state['StationName'], + early_entry, + monitor.state + ) + self.handle_plugin_event_error(err) + self.early_journal_events.clear() + # Export loadout if entry['event'] == 'Loadout' and not monitor.state['Captain'] \ and config.get_int('output') & config.OUT_SHIP: @@ -1553,10 +1593,7 @@ class AppWindow: monitor.state ) - if err: - self.status['text'] = err - if not config.get_int('hotkey_mute'): - hotkeymgr.play_bad() + self.handle_plugin_event_error(err) auto_update = False # Only if auth callback is not pending @@ -1638,11 +1675,7 @@ class AppWindow: # Currently we don't do anything with these events if monitor.cmdr: err = plug.notify_dashboard_entry(monitor.cmdr, monitor.is_beta, entry) - - if err: - self.status['text'] = err - if not config.get_int('hotkey_mute'): - hotkeymgr.play_bad() + self.handle_plugin_event_error(err) def plugin_error(self, event=None) -> None: """Display asynchronous error from plugin."""
Any questions or offers of help can be directed to the EDCD Discord #edmc channel:
Elite: Dangerous Market Connector (EDMC)
This application is only of use to PC players of the game Elite Dangerous (and its expansions). It won't work with PS4 or Xbox accounts.
It utilises the Journal files written by the game on the user's computer, together with data from the API Frontier Developments supplies in order to feed this data to various third party sites that the user may find useful.
See the Wiki documentation for more details.
Installation & Uninstall
Please see the Installation & Setup wiki page.
Running from source
Please see the Running from source wiki page.
Plugins
Plugins extend the behaviour of this app. See the Plugins wiki page for more information.
If you would like to write a plugin please see PLUGINS.md.
Troubleshooting
Please see the Troubleshooting wiki page.
Reporting a problem
Please report a problem as a new GitHub issue. See Reporting a problem for further guidance, including how to find the necessary log files to attach to the report.
Packaging for distribution
Please see docs/Releasing.md.
Disclaimer
This app uses the “Companion” web API that Frontier originally supplied for their Elite Dangerous iOS app and now support for third-party apps. If that API ceases to function in the future then much of this application's functionality will be curtailed (although it could still utilise Journal files).
Acknowledgements
Please see the Acknowledgements wiki page.
License
Copyright © 2015-2019 Jonathan Harris, 2020-2024 EDCD
Licensed under the GNU Public License (GPL) version 2 or later.