Implemented displaying LY values for "Galaxy" plotter.

This commit is contained in:
Cat Lady committed 2025-12-11 19:46:11 +01:00
1 parent 829964f378
commit abfb417878
1 file changed
+108 -40
+108 -40
View File
@@ -606,41 +606,47 @@ class SpanshRouter():
self.show_error("(1) An error occured while reading the file.")
def plot_csv(self, filename, clear_previous_route=True):
with io.open(filename, 'r', encoding='utf-8-sig', newline='') as csvfile:
with io.open(filename, 'r', encoding='utf-8-sig', newline='') as csvfile:
self.roadtoriches = False
self.fleetcarrier = False
self.galaxy = False
if clear_previous_route:
self.clear_route(False)
route_reader = csv.DictReader(csvfile)
# Get column header names as string
headerline = ','.join(route_reader.fieldnames)
# Define the differnt internal formats based on the CSV header row
route_reader = csv.DictReader(csvfile)
# Get column header names as string (preserve order)
headerline = ','.join(route_reader.fieldnames) if route_reader.fieldnames else ""
# Define the different internal formats based on the CSV header row
internalbasicheader1 = "System Name"
internalbasicheader2 = "System Name,Jumps"
internalrichesheader = "System Name,Jumps,Body Name,Body Subtype"
internalfleetcarrierheader = "System Name,Jumps,Restock Tritium"
internalgalaxyheader = "System Name,Refuel"
# Define the differnt import file formats based on the CSV header row
# External/other import formats
neutronimportheader = "System Name,Distance To Arrival,Distance Remaining,Neutron Star,Jumps"
road2richesimportheader = "System Name,Body Name,Body Subtype,Is Terraformable,Distance To Arrival,Estimated Scan Value,Estimated Mapping Value,Jumps"
fleetcarrierimportheader = "System Name,Distance,Distance Remaining,Tritium in tank,Tritium in market,Fuel Used,Icy Ring,Pristine,Restock Tritium"
galaxyimportheader = "System Name,Distance,Distance Remaining,Fuel Left,Fuel Used,Refuel,Neutron Star"
# Handle plain CSVs (two variants) and the neutron-import format separately.
# Helper to check and pick distance keys flexibly
def get_distance_fields(row):
# prefer "Distance To Arrival" (neutron style), fall back to "Distance"
dist_to_arrival = row.get("Distance To Arrival", "") or row.get("Distance", "")
dist_remaining = row.get("Distance Remaining", "") or ""
return dist_to_arrival, dist_remaining
# Handle neutron-import style
if headerline == neutronimportheader:
# CSV has: System Name,Distance To Arrival,Distance Remaining,Neutron Star,Jumps
for row in route_reader:
if row not in (None, "", []):
# Keep index 1 as "jumps" for compatibility with existing code,
# but also store distance_to_arrival and distance_remaining at indexes 2 and 3.
jumps = row.get(self.jumps_header, "")
dist_to_arrival = row.get("Distance To Arrival", "")
dist_remaining = row.get("Distance Remaining", "")
# keep index 1 compatible with existing code (jumps)
self.route.append([
row[self.system_header],
jumps,
@@ -653,23 +659,26 @@ class SpanshRouter():
except:
pass
# legacy/simple CSV: System Name [, Jumps]
elif (headerline == internalbasicheader1) or (headerline == internalbasicheader2):
# legacy/simple CSV: System Name [, Jumps]
for row in route_reader:
if row not in (None, "", []):
self.route.append([
row[self.system_header],
row.get(self.jumps_header, "") # Jumps column is optional
row.get(self.jumps_header, "") # Jumps column is optional
])
if row.get(self.jumps_header): # Jumps column is optional
self.jumps_left += int(row[self.jumps_header])
if row.get(self.jumps_header): # Jumps column is optional
try:
self.jumps_left += int(row[self.jumps_header])
except:
pass
# internal riches format (lists stored as Python-likes)
elif headerline == internalrichesheader:
self.roadtoriches = True
for row in route_reader:
if row not in (None, "", []):
# Convert string representations of lists to actual Lists
bodynames = ast.literal_eval(row[self.bodyname_header])
bodysubtypes = ast.literal_eval(row[self.bodysubtype_header])
@@ -679,8 +688,12 @@ class SpanshRouter():
bodynames,
bodysubtypes
])
self.jumps_left += int(row[self.jumps_header])
try:
self.jumps_left += int(row[self.jumps_header])
except:
pass
# internal fleetcarrier format
elif headerline == internalfleetcarrierheader:
self.fleetcarrier = True
@@ -691,8 +704,12 @@ class SpanshRouter():
row[self.jumps_header],
row[self.restocktritium_header]
])
self.jumps_left += int(row[self.jumps_header])
try:
self.jumps_left += int(row[self.jumps_header])
except:
pass
# road2riches import
elif headerline == road2richesimportheader:
self.roadtoriches = True
@@ -723,29 +740,75 @@ class SpanshRouter():
bodynames.clear()
bodysubtypes.clear()
self.jumps_left += int(row[self.jumps_header])
try:
self.jumps_left += int(row[self.jumps_header])
except:
pass
# external fleetcarrier import
elif headerline == fleetcarrierimportheader:
self.fleetcarrier = True
for row in route_reader:
if row not in (None, "", []):
# treat every row as one jump in this import format
self.route.append([
row[self.system_header],
1, # Jumps is faked as every row is 1 jump
row[self.restocktritium_header]
1, # Jumps is faked as every row is 1 jump
row.get(self.restocktritium_header, "")
])
self.jumps_left += 1 # Jumps is faked as every row is 1 jump
elif (headerline == internalgalaxyheader) or (headerline == galaxyimportheader):
self.jumps_left += 1
# galaxy-type imports: handle both the long upstream format
# and the simpler internal 'System Name,Refuel' header.
# We detect galaxy files by presence of "Refuel" in headerline.
elif "Refuel" in headerline and self.system_header in headerline:
self.galaxy = True
for row in route_reader:
if row not in (None, "", []):
self.route.append([
row[self.system_header],
row[self.refuel_header]
])
self.jumps_left += 1
system = row.get(self.system_header, "")
# keep route[i][1] as Refuel so existing galaxy logic keeps working
refuel = row.get(self.refuel_header, "")
# attempt to read distances if present (either "Distance" or "Distance To Arrival")
dist_to_arrival, dist_remaining = get_distance_fields(row)
# Build route row:
# - always keep [system, refuel] (so update_route / pleaserefuel continue to work)
# - append distances if we have them so compute_distances can display LY
route_row = [system, refuel]
if dist_to_arrival != "" or dist_remaining != "":
route_row.append(dist_to_arrival)
route_row.append(dist_remaining)
self.route.append(route_row)
# galaxy logic: treat each row as one jump for jump counting
try:
self.jumps_left += 1
except:
self.jumps_left += 1
else:
# Unknown header: try a best-effort basic parse as System Name,Jumps
for row in route_reader:
if row not in (None, "", []):
# fallback to first two columns if possible
try:
system = row.get(self.system_header, "")
jumps = row.get(self.jumps_header, "")
except Exception:
# as ultimate fallback, iterate values
vals = list(row.values())
system = vals[0] if len(vals) > 0 else ""
jumps = vals[1] if len(vals) > 1 else ""
self.route.append([system, jumps])
if jumps:
try:
self.jumps_left += int(jumps)
except:
pass
# After loading route, initialize current waypoint
if len(self.route) > 0:
self.offset = 0
@@ -753,7 +816,6 @@ class SpanshRouter():
# Compute LY distances immediately (so GUI shows them before pressing arrows)
self.compute_distances()
self.update_gui()
else:
self.show_error("Could not detect file format")
@@ -988,6 +1050,12 @@ class SpanshRouter():
self.save_offset()
def save_route(self):
"""Save current route to disk.
For galaxy routes we write System Name,Refuel,Distance To Arrival,Distance Remaining
so that distances are preserved across restarts and LY display works like for neutron.
Other formats keep previous behaviour.
"""
# If no route, try to remove saved files and exit
if len(self.route) == 0:
try:
@@ -996,13 +1064,6 @@ class SpanshRouter():
logger.info("No route to delete")
return
# Decide which format to write
# 1) roadtoriches -> write System, Jumps, Body Name, Body Subtype (lists)
# 2) fleetcarrier -> write System, Jumps, Restock Tritium
# 3) galaxy -> write System, Refuel
# 4) if any row has >=4 elements -> write neutron-import style with Distance To Arrival and Distance Remaining
# 5) else -> simple System, Jumps
try:
if self.roadtoriches:
fieldnames = [self.system_header, self.jumps_header, self.bodyname_header, self.bodysubtype_header]
@@ -1023,11 +1084,19 @@ class SpanshRouter():
return
if self.galaxy:
fieldnames = [self.system_header, self.refuel_header]
# Save galaxy routes including distances if present:
# Write header so reload can restore distances: System Name,Refuel,Distance To Arrival,Distance Remaining
fieldnames = [self.system_header, self.refuel_header, "Distance To Arrival", "Distance Remaining"]
with open(self.save_route_path, 'w', newline='') as csvfile:
writer = csv.writer(csvfile)
writer.writerow(fieldnames)
writer.writerows(self.route)
for row in self.route:
# normalize row into 4 columns:
system = row[0] if len(row) > 0 else ""
refuel = row[1] if len(row) > 1 else ""
dist_to_arrival = row[2] if len(row) > 2 else ""
dist_remaining = row[3] if len(row) > 3 else ""
writer.writerow([system, refuel, dist_to_arrival, dist_remaining])
return
# Generic routes: check if any row contains distance columns (len >= 4)
@@ -1063,7 +1132,6 @@ class SpanshRouter():
logger.warning(''.join('!! ' + line for line in lines))
self.show_error("An error occured while writing the route to disk.")
def save_offset(self):
if self.route.__len__() != 0:
with open(self.offset_file_path, 'w') as offset_fh: