Add cmdr_data() hook and _build_loadout_from_capi() to the coriolis
plugin. This sends the current ship loadout to the Coriolis CMDR API
whenever EDMC fetches fresh data from Frontier's CAPI (on docking and
manual sync button press).
This is the primary mechanism for detecting ship changes after a
ShipyardSwap, because the Loadout journal event may not be forwarded
to plugins by EDMC after a catch-up replay.
Also:
- Remove unused json import
- Extract _handle_ship_event and _handle_module_event helpers to
reduce journal_entry complexity below flake8 threshold (C901)
- Add datetime import for CAPI timestamp generation
This currently only affects system colonisation ships, which have '$EXT_PANEL_ColonisationShip;' in their StationName
entries in the journal. Other strings may need to be added in future.
Fixes#2404
diff --git a/L10n/en.template b/L10n/en.template
index faac3259..f670e39c 100644
--- a/L10n/en.template
+++ b/L10n/en.template
@@ -839,3 +839,9 @@
/* edastro_core.py: Settings>EDAstro - Label on checkbox for 'send data'; */
"Send data to EDAstro" = "Send data to EDAstro";
+
+/* common_coreutils.py: Colonisation ship name, with title; In files: common_coreutils.py:81:81 */
+"System Colonisation Ship {NAME}" = "System Colonisation Ship {NAME}";
+
+/* common_coreutils.py: Unidentified colonisation ship; In files: common_coreutils.py:84:84 */
+"System Colonisation Ship" = "System Colonisation Ship";
diff --git a/plugins/common_coreutils.py b/plugins/common_coreutils.py
index 6b90d4dc..a488de46 100644
--- a/plugins/common_coreutils.py
+++ b/plugins/common_coreutils.py
@@ -29,6 +29,7 @@ import gzip
import io
import json
import os
+import re
import myNotebook as nb # noqa: N813
from EDMCLogging import get_main_logger
from companion import CAPIData
@@ -47,6 +48,49 @@ SEPY = 10 # seperator line spacing
STATION_UNDOCKED = '×' # "Station" name to display when not docked = U+00D7
+# Known colonisation ship names match one of the following:
+# "$EXT_PANEL_ColonisationShip;"
+# "$EXT_PANEL_ColonisationShip; <ship name>" with "<ship name>" being eg; "Okawara Horizons"
+# "$EXT_PANEL_ColonisationShip:#index=<number>;"
+# "$EXT_PANEL_ColonisationShip:#index=<number>; <ship name>"
+_RE_COLONISATION_SHIP = re.compile(r'\$EXT_PANEL_ColonisationShip(?::#index=(\d+))?;(?: (.+))?')
+
+
+def localised_name(value: str | None) -> str | None:
+ """
+ Handle localisation of strings in places like station names.
+
+ This is currently an issue for system colonisation ships that have a station name along the
+ lines of "$EXT_PANEL_ColonisationShip; Okawara Horizons" when written to the journal, but would
+ be better displayed as "System Colonisation Ship Okawara Horizona" (or other appropriately
+ localised equivalent).
+
+ If no (known) localisable strings are present, the input will be returned unmodified.
+
+ :param value: The non-localised string.
+ :return: The localised string, or None if the input was None.
+ """
+ if value is None:
+ return None
+
+ colonisation_ship_match = _RE_COLONISATION_SHIP.match(value)
+ if colonisation_ship_match:
+ ship_index = colonisation_ship_match.group(1)
+ ship_name = colonisation_ship_match.group(2)
+ # Use the ship's index as its name if no name was provided.
+ ship_id = ship_name or ship_index
+
+ if ship_id:
+ # LANG: Colonisation ship name, with title
+ value = tr.tl("System Colonisation Ship {NAME}").format(NAME=ship_id)
+
+ else:
+ # LANG: Unidentified colonisation ship
+ value = tr.tl("System Colonisation Ship")
+
+ return value
+
+
def plugin_start3(plugin_dir: str) -> str:
"""
Start the plugin.
@@ -121,7 +165,7 @@ def station_link_common(data: CAPIData, this):
:param this: The module global from the calling module.
"""
if data['commander']['docked'] or this.on_foot and this.station_name:
- this.station_link['text'] = this.station_name
+ this.station_link['text'] = localised_name(this.station_name)
elif data['lastStarport']['name'] and data['lastStarport']['name'] != "":
this.station_link['text'] = STATION_UNDOCKED
else:
@@ -163,12 +207,14 @@ def station_name_setter_common(this):
:param this: The module global from the calling module.
"""
to_set: str = cast(str, this.station_name)
+
if not to_set:
if this.system_population is not None and this.system_population > 0:
to_set = STATION_UNDOCKED
else:
to_set = ''
+ to_set = str(localised_name(to_set))
this.station_link['text'] = to_set
diff --git a/plugins/edsm.py b/plugins/edsm.py
index e1e6b168..902e248b 100644
--- a/plugins/edsm.py
+++ b/plugins/edsm.py
@@ -43,7 +43,7 @@ from ttkHyperlinkLabel import HyperlinkLabel
from l10n import translations as tr
from plugins.common_coreutils import (api_keys_label_common, PADX, PADY, BUTTONX, SEPY, BOXY, STATION_UNDOCKED,
show_pwd_var_common, station_link_common, this_format_common,
- cmdr_data_initial_common)
+ cmdr_data_initial_common, localised_name)
# TODO:
@@ -543,7 +543,7 @@ entry: {entry!r}'''
to_set = ''
if this.station_link:
- this.station_link['text'] = to_set
+ this.station_link['text'] = localised_name(to_set)
this.station_link['url'] = station_url(str(this.system_name), str(this.station_name))
this.station_link.update_idletasks()
Workaround the `.after()` queue being cleared (or invalidated) when the
widget that call was made through is destroyed after that call is made,
which in this case resulted in the EDDN queue not being processed until
some other action re-triggered processing of the EDDN queue.