Skip to content

Order Generation and Routing

noteMASTER11 edited this page Jul 14, 2026 · 6 revisions

Order Generation and Routing

Dispatcher pool

Going online creates a target pool of 10–12 offers. The plan is shuffled and normally includes:

  • 2–4 rush requests;
  • 2–3 multi-stop requests when the map has enough semantic candidates;
  • regular requests for the remaining slots.

Offers are inserted one at a time. The initial delay is 1.5 seconds and completed offers are separated by a random 1.2–2.2 seconds.

Incremental graph work

Offer creation can involve map-object scans, road projection, random paths, and route-distance validation. These operations run inside a coroutine job managed by offerGenerator.lua.

  • A suspended job is resumed at most once per configured work interval (0.08 s).
  • Semantic object scans yield every six objects.
  • Semantic candidate and random road attempts yield between attempts.
  • Generation pauses with dtSim when the game is paused.

This design reduces sustained per-frame load. It deliberately trades dispatcher fill time for smoother gameplay.

Candidate sources

The semantic cache is built once per level from:

  1. BeamNGTrigger objects whose type is busstop;
  2. parking spots from current-level sites files, excluding mission, quickrace, and scenario data;
  3. BeamNGPointOfInterest objects.

Candidates within the same 8 × 8 metre cell are deduplicated. Banned site parking spots are ignored.

Road-edge projection

A semantic anchor is mapped to its closest usable road segment. The projection then:

  1. rejects anchors farther than 120 m from the road centre;
  2. applies controlled longitudinal jitter along the segment;
  3. keeps an endpoint margin;
  4. chooses the side nearest to the semantic anchor;
  5. offsets toward the road edge using interpolated node radius;
  6. requests legal traffic direction through trafficUtils.finalizeSpawnPoint.

The lateral offset is clamped to 1.5–14 m. This is intended to place a taxi at the outer road edge rather than an inner lane.

Road fallback

If no semantic point passes route validation, the generator asks BeamNG's graph path system for a random route from the closest road. A desired distance is selected with a short-distance bias and the result is projected to the road edge.

Usable public road links require:

  • drivability of at least 0.7;
  • node radius of at least 2.4 m;
  • a non-private link.

Semantic parking and related anchors may allow private links with a lower minimum radius of 1.8 m.

Distance rules

Segment Minimum Maximum
Pickup from current vehicle 400 m 3,500 m
Regular passenger ride 1,000 m 25,000 m
Multi-stop segment normally 3,000 m 7,000 m

After repeated multi-stop failures, the minimum segment length can relax in 500 m steps, but never below 1,500 m.

All distances are route distances calculated by BeamNG's Route planner, not straight-line distances.

Multi-stop protection

A multi-stop ride requires at least 20 semantic stop candidates. If that requirement fails, or a multi-stop request cannot be generated, the dispatcher falls back to regular work for the rest of the pool.

Multi-stop rides are never marked as rush rides.

Repetition control

The last 24 accepted pickup, stop, and destination positions are remembered. A newly generated point is considered recent when it is within 90 m of one of them.

The generator prefers unused positions but retains a recent valid candidate as a fallback. This prevents variety rules from emptying the dispatcher on small maps.

Navigation ownership

The GE extension sends the selected target to core_groundMarkers with cutOffDrivability = 0.7. It temporarily controls road guidance visibility and restores the previous settings after the route ends.

The native minimap is shown only during toPickup, toStop, toDestination, and toFuelStation. The UI reports a normalized rectangle and occlusion regions so the stock minimap renders inside the phone without covering ETA, speed-limit, or notification overlays.

Dynamic zoom wraps the stock player-drawing path while TaxiDriver owns the minimap, then restores the original implementation when the map is hidden.

Clone this wiki locally