Skip to content

optional "chain-delivery" mode (skip depot round-trip between deliveries) #69

Description

@0xHerm

TL;DR
After a train finishes a delivery, let it chain directly to its next delivery instead of returning to a depot to reset — unless its fuel is low, in which case it goes back to a depot (which refuels) exactly as today.

I can link you to a private repo if you want to see it. I have not distributed this at all, I wanted to prove the concept but I will not publish it per your license.

What ?

The depot round-trip between every delivery is pure in-flight overhead. Removing it raises per-train utilization, so you need fewer trains for the same throughput — a real UPS win on a train-heavy base — and it drops the per-delivery depot unload/reset/refuel-pathfind work.

It's fully optional and off by default (new settings; with it disabled, behavior is byte-for-byte stock LTN), and it reuses your existing train pool and dispatcher rather than adding a parallel one. It has to live inside LTN, not a companion mod: a second mod can't touch the dispatcher tables or create a delivery, so it would desync accounting and cause double deliveries.

How it works ("hold-and-chain")
Since the dispatcher only considers trains parked at a stop, the finished train is held at its requester and registered into the available pool there, so your own dispatcher assigns its next delivery straight from that spot — requester → next provider, no depot.

The timing, step by step:

On requester arrival, if chaining is on and fuel is OK, the train gets a short grace wait (~2s) so it lingers after unloading instead of departing, and is marked as a held candidate.
Once it's finished unloading (empty), the original delivery is finalized normally (completion event + removal, so accounting stays correct) and the train is registered into the pool as a "field" train.
The dispatcher picks it up on its next update tick and it leaves directly for the next provider.
If nothing matches within the hold window (default ~30s), the train falls back to a depot.
Field trains are preferred in dispatch, but only as a tiebreaker after cargo-fit — a better-fitting depot train still wins, so throughput quality doesn't regress.

Eviction (so a held train never blocks a dock)
A held train occupies its requester stop, so it's released to a depot the moment it would get in the way:

A new delivery is created inbound to that same requester → the held train is evicted immediately so the incoming train can dock. Deliveries to other stops don't evict it.
Fuel is low on arrival → never held; takes the normal depot path (and refuels there).
Hold window expires (~30s) with no reassignment → released to a depot.
Chaining turned off, or the train leaves/becomes invalid → dropped.
The scan that manages held trains only iterates the small held set on a throttled interval — no global per-tick polling.

Settings (all default to stock behavior)
Master on/off switch (default off).
Minimum fuel % to allow chaining (default 33).
Hold window in ticks before depot fallback (default ~30s).
Prefer field trains toggle (default on, only active when chaining is on).

Lastly, there is a 2nd change that would modify route calculations. However this code is not in my private repo yet, but here is the concept.

It adds a server setting with three choices:

  • Exact (unchanged, stays the default): ask the route calculator about every train, always pick the true closest.
  • Batched: instead of ~300 separate "how far is train #N from the pickup?" questions, ask one question: "from the provider, how far is every parking spot?" The route calculator can answer a multi-destination query in a single pass — LTN
    already uses this exact trick when a train picks which depot to go home to; I just applied it to dispatch too. The catch: it measures routes from the provider to the depots — backwards relative to how the train will actually drive, and
    on one-way rail networks the reverse route isn't identical. So the ranking is approximately right: in testing it always picked from the near end of the pack, but typically a train ~40–60% farther than the true closest — think 1.5km
    instead of 1km, maybe 30 extra seconds of driving. With 157 spares, throughput doesn't notice.
  • Off: don't consider distance at all; rotate among suitable idle trains. Dispatching becomes essentially free; trains drive farther on average.

Why ?
We have a py mega base, and with over 1000 train stops the ticks add up.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions