Dynamic Travel Distance / 动态航行距离

by zhe-yan

Planets and space locations keep orbiting while platforms fly, so the distance between two of them changes with the phase. This mod turns that into real space connection lengths: it generates K hidden sampled lanes per vanilla route whose lengths follow the phase, so travel time, ETAs and the starmap stay honest.

Tweaks
7 hours ago
2.1
5
Planets Transportation

Changelog

Version: 0.9.6
Date: 2026-10-12
  Bugfixes:
    - Reduce orbital chart camera zoom and drawing radius to keep the chart within its viewport.
    - Rebuild existing navigation windows for the updated chart layout.
Version: 0.9.5
Date: 2026-10-10
  Features:
    - Unlock orbital navigation through research and support ordinary thrusters with estimated propellant use.
    - Expand the orbit chart and explain planning assumptions and unavailable routes.
  Bugfixes:
    - Rebuild outdated navigation windows while preserving selections and active navigation jobs.
    - Prevent rocks from spawning on chart surfaces and remove existing chart rocks.
    - Avoid applying off-plane distance compensation twice; stop dispatch when the tier interface fails.
    - Require the relevant research before waiting for a departure window and propagate waypoint arrival times.
    - Show a fallback name for unnamed platforms and refresh the platform list while the window is open.
    - Select another available platform when the selected one is destroyed.
Version: 0.9.4
Date: 2026-10-10
  Features:
    - Add orbital navigation for five moving planets and seven routes.
    - Plan legs using predicted arrival times, optional departure waits, and selectable tiers.
    - Add optional waypoint navigation and restore the original schedule when navigation ends.
  Bugfixes:
    - Fold relative phase over a full revolution so opposite planets remain far apart.
    - Preserve travelled distance on reverse connections.
    - Pause before restoring a saved schedule to prevent unintended departure.
    - Prevent waypoint planning from revisiting planets in one navigation job.
  Changes:
    - Translate the changelog and mod description into English.
Version: 0.9.3
Date: 2026-10-10
  Bugfixes:
    - The refresh loop now wraps orbit_text in a pcall. A failure there aborted the whole tick handler, which left every value in the panel blank with no explanation. The reason is now shown in the panel instead.
  Diagnostics:
    - Added a headless self-check that runs the parts of orbit_text which do not need a player (edge lookup, route comparison, lane table) and logs the results. It runs clean on a real save for nauvis-gleba, gleba-aquilo and solar-system-edge-shattered-planet.
Version: 0.9.2
Date: 2026-10-10
  Bugfixes:
    - Fixed every planet collapsing into one clump. 0.9.0 put the shattered planet into the diagram, where its solar-model radius is 17.32 against 0.707 to 2.236 for the five planets, so normalising by it squeezed all five inside 15 pixels of the sun. Normalisation now uses the five landable planets only, and extra locations are drawn only when their radius is at most 1.25 times the core maximum.
    - Fixed the empty value column: the early return for rmax <= 0 in update skipped the text as well, leaving only the row titles. Text is now filled first and sprites are moved afterwards.
    - Frame content moved into an explicit direction="vertical" flow, because frames laid their children out horizontally in testing, which squeezed the header, the state table and the sample table onto one line. The fixed frame width was dropped because it clipped the right-hand column.
  Diagnostics:
    - Added a self-check row at the bottom of the panel: planets drawn, rmax, edges, lane rows and any intercepted error.
    - build_world logs every planet's radius, period and initial phase, plus rmax, with an [orbit] prefix, so a wrong diagram can be checked against the log directly.
    - Each sprite is now added inside its own pcall, so one unknown sprite name no longer discards the whole diagram.
Version: 0.9.1
Date: 2026-10-10
  Bugfixes:
    - Fixed a guaranteed crash when clicking the button. Rewriting orbit_text had removed the local orbit_failed_hint, so it fell back to a nil global and the "build failed" branch threw, taking the game down with it. Restored.
    - Fixed screen elements left behind by 0.8.x never being cleaned up. They used a different set of names that the 0.9.0 cleanup did not know about, so they stayed on screen rendering against renamed locale keys and produced Unknown key errors. Cleanup now sweeps every screen child whose name starts with dtd_orbit_, except the toggle button.
    - The frame no longer passes direction.
  Changes:
    - Every style and layout call in build is now pcall'ed individually: a style that is not supported is recorded instead of discarding the whole panel, and intercepted errors are shown in the panel's note row.
    - on_gui_click is wrapped in a pcall, so a GUI problem prints one line instead of crashing the game.
Version: 0.9.0
Date: 2026-10-10
  Features:
    - The overview is now a real GUI window: frame, header, close button and two tables, instead of a single column of text.
    - A persistent "Orbit overview" button in the top-left corner opens and closes it. The /travel-distance-orbit command was removed.
    - State table with two columns: mode, current leg, length, phase, progress, model best and note.
    - New lane sample table: the rho and kilometres of all K tiers for the current leg, with the tier in effect highlighted in orange. These are the same numbers the lanes actually use. When K is greater than 14, only the 14 rows around the active tier are shown.
    - The diagram and the panel are separate: the diagram is drawn at fixed screen coordinates and the panel sits beside it, so they never overlap.
  Changes:
    - Removed the orbit rings, which merged with the connection lines into a cloud of dots. The three line roles now use two dot sizes and three colours: grey 4 px for vanilla connections, orange 6 px for the leg in use, cyan 4 px for the model's best path.
    - Text switched to default-large (18 instead of 14) and planet sprites enlarged to 40 px.
    - When a leg has an endpoint outside the five-planet model (solar system edge or shattered planet), the diagram and sample table do not apply and the panel says so instead of drawing misleading lines.
Version: 0.8.1
Date: 2026-10-10
  Changes:
    - Redrew the diagram to match orbit-demo.html: grey dotted lines are the seven vanilla connections, orange is the leg actually being flown, cyan is the path the model considers best at this moment, and thin circles are the orbits at true radius ratios.
    - Added information: mode, K and reference period; which edge is in use; this leg's kilometres and its ratio to the vanilla distance; the platform's rho and beta with kilometres flown and remaining; the model's best path and its kilometres; and how much a switch would save right now.
    - Title and close button no longer overlap, and the text became separate lines under the diagram.
    - The data stage registers four tinted dot sprites from a single 16x16 white dot.
  Notes:
    - The lines show connection relationships, not the platform's actual trajectory. The trajectory is decided by the vanilla routes; this mod only changes each leg's effective length.
Version: 0.8.0
Date: 2026-10-10
  Features:
    - Added a screen-level orbit overview, toggled with /travel-distance-orbit. Factorio can draw one: LuaGuiElement.location is writable for direct children of LuaGui::screen (API: "The location of this widget when stored in LuaGui::screen"), so positioning planet sprites by orbital phase every 15 ticks produces a live diagram with no SVG and no HTML.
    - Every angle and radius on the diagram comes from scripts/model.lua, the same kinematics used for lane lengths, so the relative positions always agree with the sampled tiers actually in effect.
    - Below the diagram: the platform in flight, its lane, rho and beta, total, flown and remaining kilometres, and the model's instant direct-versus-detour verdict.
    - The data stage registers six 512x512 starmap icons as 32 px GUI sprites.
    - Elements are not stored in saves, so the panel is rebuilt after each load.
  Notes:
    - Headless runs have no player, so GUI code cannot be exercised in CI and has to be confirmed in game.
Version: 0.7.0
Date: 2026-10-10
  Features:
    - Platform alert upgraded to per-leg reporting plus route competition. It used to fire only at the moment of a lane or tier change, so during long legs the player saw stale numbers and no indication of the current situation.
    - It now reports even when no switch is needed, de-duplicated per leg target so it does not spam.
    - It refreshes about every 30 seconds, keeping the leg length and the route verdict current.
    - Route competition: the direct leg versus the best two-hop detour at the current phase, reported together.
  Analysis tools:
    - tools/route_switch_check.py steps through time and counts route switches for every location pair.
    - tools/route_cause.py separates the three causes: pure geometry, vanilla L0 weights and bucket quantisation.
  Findings (tools/route_cause.py, exact distances, 3600 s):
    - Under pure geometry the weighted triangle inequality keeps the direct route optimal and the number of genuine reversals is zero.
    - Only gleba-aquilo and fulgora-aquilo are ever genuinely beaten by a detour, 26.6 and 37.2 percent of the time and by up to 40 percent, because they are the only edges priced at 30000, so their detours carry unbalanced 15000+30000 weights.
    - Every other direct edge is priced 15000 and never reverses. Vulcanus-Fulgora switches for a different reason: it has no direct edge, so two two-hop routes compete.
    - Bucket quantisation manufactures extra switches: Nauvis-Vulcanus has zero genuine reversals but reports 36 at K=4.
Version: 0.6.0
Date: 2026-10-10
  Features:
    - Added an optional alert on the platform hub showing the real leg length, kilometres flown, remaining, phase tier and off-plane tier (dynamic-travel-distance-alert, on by default, radar icon).
    - The starmap annotation is a static prototype that can only ever show one entry and cannot follow the phase, so the real distance belongs in the alert or in the platform panel.
    - The map anchor now carries a description pointing at where the real number can be read.
Version: 0.5.0
Date: 2026-10-10
  Changes:
    - Removed pace mode entirely. mode is now auto, compose, lanes or off. Scaling the per-tick advance of platform.distance is the same thing as changing speed: it alters travel time, and it makes the platform panel's ETA wrong. This mod expresses real lane lengths only, and there is no remaining path that fakes distance by changing speed or advance rate.
    - auto now resolves to compose when the other mod's off-plane lanes are visible, to lanes when nothing else owns space_connection, and to off (do nothing, with the reason written out) when something else owns it but its lanes cannot be seen.
    - Added an explicit off mode: generates no prototypes, writes no space_connection, changes neither speed nor advance rate.
    - Removed the per-tick on_tick handler that pace needed. Runtime is now a low-frequency recheck plus the departure event.
    - The /travel-distance platform line no longer prints an advance-rate column; it shows the phase tier, off-plane tier, kilometres flown and seconds into the leg.
    - generate-when-inactive now means "generate prototypes even in off mode", for other mods that query the lane table through the remote interface.
  Verified:
    - All three modes measured on their own: compose 168 lanes, lanes 56, off 0 with nothing generated.
    - 20,000 ticks on a real save in compose mode: zero conflicts, zero switch failures, and no occurrence of an advance rate anywhere in the log.
Version: 0.4.2
Date: 2026-10-10
  Bugfixes:
    - compose mode was missing the on_space_platform_changed_state hook. The engine routes a platform over the shortest connection at the moment of departure, usually sd-0, and this mod only corrected it at the next recheck, up to 15 ticks later. lanes mode had the immediate correction and compose did not. The first correction now happens at "0 km flown", before the platform has moved at all.
    - Leg state was keyed by platform.index, and indexes are recycled: a newly built platform could inherit the previous one's leg state. It is now validated against platform.name and reset on a mismatch.
  Changes:
    - The /travel-distance platform line now shows the phase tier, off-plane tier, kilometres flown and the advance multiplier.
    - Added tools/SELFTEST.md: six reproducible checks with expected output, covering the three work modes, asteroid counts, the zero-conflict criterion and an offline recomputation cross-check.
Version: 0.4.1
Date: 2026-10-10
  Features:
    - Added a compose self-check: when leave-ecliptic is running but not a single -offplane-N lane can be found, because it renamed them, changed its implementation, or was replaced by another mod, the mod now degrades to pace mode.
    - Before this, our lane family would be missing its tiers, so every tier switch pointed at a prototype that did not exist: pcall failures in the log and silently broken asteroid and speed tiers.
    - The data stage and runtime use the same criterion, and all three paths were measured: normal compose with 168 lanes, lanes with the other mod disabled at 56 lanes, and the faked missing-lane case which degraded automatically.
Version: 0.4.0
Date: 2026-10-10
  Bugfixes:
    - Fixed the asteroid profile of composed lanes. Each off-plane copy previously copied only the length multiplier and kept the vanilla connection's full asteroid set, which silently broke leave-ecliptic's "tier 2 is small chunks only" and "tier 3 has no asteroids": 21 vanilla spawn points instead of 9 at beta 2 and 0 at beta 3. The copies now inherit asteroid_spawn_definitions from its own -offplane-N prototypes.
  Features:
    - Added dynamic-travel-distance-map-anchor (on by default). When one location pair has several parallel connections, the starmap annotates only one of them, and in testing it picked the longest, about 2.15 to 2.31 times vanilla. A hidden connection of vanilla length, defined and named last, pulls the annotation back to the vanilla distance.
    - Added dynamic-travel-distance-beta-transition (km or fraction), the progress semantics when the off-plane tier changes in flight. km, the default, preserves kilometres flown and arrives immediately if those already exceed the new lane length; fraction preserves the ratio, which is what leave-ecliptic does, and never arrives early but makes the kilometres jump.
    - Following a tier change now writes an explicit log line with the old and new length, kilometres flown and the outcome.
  Verified:
    - 20,000 ticks on a real save: a beta 3 to 1 follow succeeded with the phase tier unchanged, and zero conflicts or failures.
    - Phase tiers change correctly between legs: one platform locked 5/8, 1/8, 4/8, 3/8 and 7/8 in turn.
  Notes:
    - The starmap's exact selection rule is still undetermined: the data fits "defined last", "named last" and "longest" equally well. The anchor satisfies the first two. If the starmap still shows 2.2 times vanilla, the rule is "longest" and it has to be accepted unless tiers above rho 1 are dropped.
Version: 0.3.0
Date: 2026-10-10
  Features:
    - Added compose mode, the twelve-state multiplication: L(j,k) = L0 * rho(j) * beta(k), where rho is the planetary phase tier and beta is the off-plane tier from Escape the Ecliptic.
    - No patch to leave-ecliptic is needed. This mod puts its lanes inside that mod's offplane namespace, as <canonical>-sd<j> and <canonical>-sd<j>-offplane-<k>. Its split_lane sees the base as "<canonical>-sd<j>" and the tier as k, so the target name it computes is exactly the lane already in place, connection.name equals target, and its switch_lane becomes a no-op. It keeps deciding beta, tilt, asteroids and speed tiers, and this mod decides rho, with no field contested either way.
    - Beta values are never hard-coded: the data stage reads them from the existing -offplane-N prototypes as length divided by canonical length, measuring beta 1.250 and 1.500. If the other mod changes its multipliers, this one follows.
    - auto now resolves to compose when external off-plane lanes exist, lanes when they do not, and pace only when explicitly selected.
    - rho is locked at the moment of departure and never changes afterwards, including while leave-ecliptic switches beta. The large kilometre drop a tier change causes is no longer mistaken for a new leg, using a 25 percent collapse threshold.
    - Every lane switch logs both the phase tier and the off-plane tier, so L = L0 * rho * beta can be checked by hand.
  Verified:
    - A 12,000 tick benchmark on a real save with leave-ecliptic fully enabled: this mod wrote gleba-aquilo-sd4-offplane-3, 45000 to 51429 km, which is 30000 * 1.143 * 1.500.
    - In the same test leave-ecliptic had zero failures and zero conflicts, no switch failures and nothing reverted by the engine, and its own tier drop landed inside this mod's lane family: gleba-aquilo-sd4-offplane-3 to gleba-aquilo-sd4.
    - The pace regression passed: with mode=pace explicitly selected the behaviour matched 0.2.0.
  Notes:
    - Twelve states does not mean twelve lanes are available at once. rho is chosen by time and not by the player; what the player chooses is beta, so at any moment there are 1 plus beta lanes available under the current rho. Seven canonical routes times K=8 tiers times 3 off-plane layers gives 168 prototypes, or 84 at K=4.
Version: 0.2.0
Date: 2026-10-10
  Features:
    - Added pace mode, which scaled only the per-tick advance of platform.distance and wrote no space_connection and generated no prototypes, making the planetary phase a factor that multiplies into any other mod: total time equals connection length divided by speed times the phase time ratio, no matter who owns length and speed.
    - auto, the default, picked a mode on its own: pace when something else such as leave-ecliptic was writing space_connection, lanes otherwise. Neither mode needed the other to step aside or overwrote its fields.
    - lanes mode, the 0.1.0 behaviour, was kept: true parallel connections with accurate lengths, ETAs and starmap geometry, at the cost of owning space_connection.
    - Added the dynamic-travel-distance-mode setting (auto, lanes, pace), replacing dynamic-travel-distance-authority from 0.1.0.
    - /travel-distance now shows the resolved mode, the locked bucket, the advance multiplier and progress, and the remote interface gained mode() and time_ratio_for().
    - The actual duration and advance multiplier of each leg are recorded for cross-checking.
  Verified:
    - Real-save benchmark on one leg at one instant: with the multiplier at 1.0 distance was 0.093995 and at 2.0 it was 0.187798, a ratio of 1.998, so the multiplier does multiply exactly.
    - Under pace mode leave-ecliptic's tiers, speed limits, working fluids and asteroids all kept working with zero interaction between the two mods.
    - Pace mode generated no prototypes at all, so it could not pollute the engine's shortest-path routing.
  Notes:
    - The cost of pace mode was that the platform panel's ETA still came from the vanilla connection length and disagreed with the real duration. Use lanes mode when an accurate ETA matters.
    - When used together with leave-ecliptic, its lane switching resets platform.distance proportionally, and the drift correction re-baselines on the following tick.
Version: 0.1.0
Date: 2026-10-10
  Features:
    - Generates K hidden sampled lanes, <name>-sd-0 to -sd-(K-1), for every vanilla space connection, with a length of the geometrical distance ratio for that phase bucket times the vanilla distance. Vanilla connections, schedules and speeds are untouched.
    - The kinematics match ORBITAL_RECONSTRUCTION_CALCULATED.zh-CN: irradiance or starmap radius to circular orbital radius, Kepler's third law to period, two-planet geometrical distance, then equal-time phase buckets.
    - The radius source can be solar, per section H2 of the document, or distance, matching the starmap geometry.
    - K equal-time probability buckets representing phases (k+0.5)*pi/K; the bucket index is floor(fold(theta_j - theta_i) / (pi/K)).
    - The platform locks its lane at departure, with lane-policy frozen, and keeps it for the whole leg. Continuous reselection averages the distance differences over one synodic period and is kept only as a comparison.
    - Lane changes convert progress by kilometres flown rather than by normalised fraction, so the platform never teleports on the starmap.
    - Recomputes every 15 ticks and acts immediately on state changes, giving up and logging after five consecutive failures.
    - Added /travel-distance and /travel-distance-lanes, plus the dynamic-travel-distance remote interface.
    - English and Chinese localisation, startup settings, changelog, and the offline recomputation script tools/lane_table.py.
  Notes:
    - At K=4, solar, normalization=true, Nauvis-Fulgora gives 6543, 13018, 18670 and 21799 km, exactly matching section 6 of the document, and the Lua and Python lane tables agree value for value.
    - Live benchmarks on a real save, 7200 to 14400 ticks, confirm that the engine does not overwrite the space_connection this mod writes and that writing distance takes effect.
  Known issues:
    - The engine routes platforms over the shortest connection, so no lanes are generated while this mod is not in charge; otherwise sd-0 would silently shorten every trip.
    - Multi-leg route selection uses the minimum sampled value of each edge as its weight, which can pick a transfer that is not optimal at the real phase.
    - This mod and leave-ecliptic are mutually exclusive over connection control; auto steps aside by default. See docs/PROBLEMS.zh-CN.md.