Skip to content

Runtime Reliability and Performance

noteMASTER11 edited this page Nov 12, 2026 · 5 revisions

Runtime Reliability and Performance

TaxiDriver 3.4.0 Beta introduces a defensive runtime layer around the authoritative GE extension. Every contained failure is still written through the structured [TaxiDriver] logger, but an optional service, stale vehicle callback, or expensive export job can no longer stop unrelated gameplay work.

Runtime decomposition

taxiDriver.lua remains the public extension and phase-state owner, while reusable rules and infrastructure are delegated to smaller files:

Module Responsibility
rideRules.lua ETA, fare, pickup deadline, rating bonus, and passenger phase rules
offerPlan.lua Regular, rush, multi-stop, and cargo composition for a dispatcher pool
vehicleBridgeGuard.lua Generation-checked asynchronous vehicle reads and guarded writes
faultBoundary.lua Per-subsystem protected calls, circuit breaking, and independent cleanup
optionalLanBridge.lua Lazy and failure-contained Connected Phone loading

The main Lua chunk must remain below LuaJIT's 200-local compilation limit. Keep new independent rules and infrastructure in focused modules.

flowchart LR
  UI["UI commands and BeamNG hooks"] --> Main["taxiDriver.lua orchestrator"]
  Main --> Rules["rideRules and offerPlan"]
  Main --> VehicleGuard["vehicleBridgeGuard"]
  Main --> Boundary["faultBoundary"]
  Main --> OptionalLAN["optionalLanBridge"]
  OptionalLAN -.->|loaded only when sharing is enabled| LAN["lanBridge"]
  Boundary --> History["vehicle and shift history"]
  Boundary --> Fleet["Fleet manager"]
  Boundary --> Gameplay["active trip update"]
  Boundary --> HUD["HUD publisher"]
Loading

Tick fault boundaries

Periodic services no longer share one unprotected call chain. faultBoundary executes each named subsystem with pcall. A failed service:

  1. writes a structured error containing the subsystem name and failure count;
  2. opens only that service's circuit for one second;
  3. allows the rest of the current tick to continue;
  4. retries automatically after the cooldown.

Core state remains authoritative. Circuit breaking is limited to periodic and optional work and does not invent replacement gameplay results.

sequenceDiagram
  participant Tick as onUpdate
  participant Guard as faultBoundary
  participant Fleet as Fleet update
  participant LAN as LAN update
  participant Game as Active trip
  participant HUD as HUD patch

  Tick->>Guard: call Fleet
  Guard->>Fleet: protected update
  Fleet--xGuard: Lua error
  Guard-->>Tick: failed, circuit open
  Tick->>Guard: call LAN
  Guard->>LAN: protected update
  LAN-->>Tick: success
  Tick->>Guard: call active trip
  Guard->>Game: protected update
  Game-->>Tick: success
  Tick->>Guard: publish HUD patch
  Guard->>HUD: protected publish
Loading

Mission and extension shutdown use independent cleanup calls. LAN shutdown, Fleet persistence, AI shutdown, energy cleanup, profile writes, and navigation restoration no longer depend on every earlier cleanup succeeding.

Vehicle VM generation guard

BeamNG can destroy and rebuild the selected vehicle VM while a Vehicle Bridge request is pending. A Lua object captured before a parts change, reset, vehicle replacement, or level transition must not be used when the callback arrives.

vehicleBridgeGuard records:

  • the requested vehicle ID;
  • the current vehicleScanGuard generation;
  • whether Vehicle Config or the VM settle window is active.

The callback compares the generation, requires a stable VM, resolves the vehicle again with getObjectByID, and invokes domain code only for the same live object.

sequenceDiagram
  participant Fuel as Fuel or shift service
  participant Guard as vehicleBridgeGuard
  participant Bridge as core_vehicleBridge
  participant VM as Vehicle VM

  Fuel->>Guard: request energyStorage
  Guard->>Guard: capture vehicle ID and generation
  Guard->>Bridge: requestValue
  VM-->>Bridge: asynchronous response
  Bridge->>Guard: callback
  Guard->>Guard: compare generation and resolve live object
  alt same stable vehicle VM
    Guard->>Fuel: data plus current vehicle
  else reset, replacement, or Vehicle Config
    Guard-->>Fuel: reject stale callback
  end
Loading

Dashboard energy, Realistic Mode initialization, the cheat fuel/charge slider, paid refueling, Magic Fuel routing, and shift restoration share this path. Realistic Mode and the cheat control both apply energy through the same setEnergyStorageEnergy implementation.

Vehicle Config suspension remains in vehicleScanGuard:

  • onUiChangedState stops vehicle-side work before parts are applied;
  • spawn/reset lifecycle events increment the generation;
  • a 1.5-second settle window lets controllers and energy storages register;
  • pending energy flags are invalidated before lazy refresh resumes.

HUD publication

A full HUD snapshot is sent after explicit state-changing commands and when a client requests resynchronization. Periodic updates use TaxiDriverHUDPatch.

The fast state contains scalar trip values such as distance, timers, phase, fuel, rating, and active notification. Expensive collections are excluded unless their owner reports a real change:

  • dispatcher offers;
  • shift history;
  • Fleet drivers and markers;
  • garage vehicle previews;
  • settings.
flowchart TD
  Event{"Explicit command or resync?"}
  Event -->|yes| Full["Build complete state"]
  Event -->|no| Fast["Build fast scalar state"]
  Full --> Snapshot["TaxiDriverHUDState"]
  Fast --> Dirty{"Fleet or shift collection dirty?"}
  Dirty -->|yes| Collections["Add changed collections"]
  Dirty -->|no| Patch["Partial revisioned patch"]
  Collections --> Patch
  Patch --> Client["Merge changed keys"]
Loading

Epoch, base revision, and revision validation remain unchanged. A dropped or discontinuous patch causes the client to request a new full snapshot.

Polled Connected Phone map export

Connected Phone is loaded through optionalLanBridge; failure to load its socket or server dependencies cannot prevent taxi gameplay from starting.

Large road graphs are not built in one frame. A coroutine:

  1. captures the current level map;
  2. examines at most 500 links before yielding;
  3. resumes on later updates;
  4. discards its result if the level key changed;
  5. exposes a consistent cached road revision only after the build completes.

Since 4.0.1, the external browser polls through an engineLua callback because BeamNG 0.39 does not reliably forward the former custom map hooks to external peers. Vehicle position is returned on each visible-map poll; large roads, terrain, and route data are included only when the browser's revision is stale. Terrain-setting changes cancel an in-progress build. lan.json writes and LAN method calls are protected. The LAN server stops at mission shutdown and restarts on the next mission only when sharing is enabled.

AI safety cadence

The current native-AI traffic guard uses one accumulator per vehicle:

  • the player observer updates every 100 ms and samples twelve positions along a steering arc;
  • each Fleet observer updates every 200 ms and samples six positions;
  • Fleet route progress remains a separate 250 ms staggered monitor.

No traffic-guard scan is tied directly to render FPS. Speed limiting is jerk-controlled, and the observer releases its temporary native speed cap after the path remains clear. The previous 50 ms exact-approach/recovery ray controllers and 330 ms strategic spatial model are not started by the current AI runtime.

Logging and lifecycle filtering

Extended operation logging filters onVehicleResetted events to the player's or active TaxiDriver vehicle. Traffic vehicles no longer flood the BeamNG log.

BeamNG's native AI exposes Route Done only through AIStatusChange. TaxiDriver installs a protected observer only while an AI route is actively watched. The original guihooks.trigger is restored when route watching stops, so no permanent global modification remains after AI shutdown.

Native and external heartbeat intervals stop on early document shutdown, UI destruction, and mission shutdown. Persisted browser back/forward-cache pages are exempt so a restored Connected Phone page can continue its session.

Regression coverage

Version 5.0.0 validation:

  • 45 JavaScript/UI tests passed.
  • 33 local Lua regression files passed in the final preflight. Development validation on BeamNG 0.40.5 passed 33 isolated game-LuaJIT regression files and compiled 45 runtime Lua files. The final game-MCP rerun could not connect because the game was closed.
  • Actual native CEF checks covered Home controls and map toolbar placement; a full game-process restart verified preset persistence.
  • Repeated model mount/dispose cycles covered removal of listeners, timers, watchdogs and animation frames, including late callbacks.
  • The .NET LAN self-test did not run because dotnet was unavailable. The full Playwright visual suite was not run because browser launch was unavailable under the environment policy. Neither is reported as passed.
  • New in-game AI drives were not part of this audit; route/indicator claims are supported by isolated regressions and installed-module checks.

These checks do not establish a general FPS improvement or guarantee behavior on every map/vehicle.

Dispatcher and client recovery in 5.0.0

Dispatcher steps use a cooperative 1 ms / 16-resume budget and eight-second offer-job timeout. Native route calls cannot be preempted. Planner-owned road and semantic warmup survives an offer-job cancellation and resets at map/planner reset, preventing repeated large-map warmup restarts. Nearest-pickup sorting reuses prepared distance data.

Connected Phone polling has a five-second in-flight watchdog and request generations. A missing callback permits a retry; replies from earlier generations are ignored. A new HUD epoch resets reused offer/notification IDs and local deadlines. Full snapshots clear absent nullable fields such as nextOffer, preventing stale cards or restarted countdowns.

Vue disposal releases owned resources and ignores late callbacks. Persisted BFCache page transitions preserve the phone session; restoration resumes polling/heartbeat behavior. Negative shift income and final energy snapshots survive persistence, while timed refuel/repair completion revalidates wallet affordability.

Earth work and validation (5.0.2)

  • Keep a separate bounded request-only connection to the existing Earth companion; world route requests use download=off rather than prefetching a complete route corridor.
  • Prioritise cached settlement labels, bound candidate discovery/retries/caches and keep one world-route request active at a time. Retain only route summary/endpoints in regular HUD state.
  • Address enrichment has at most 24 queued lookups, starts at most one request every 3 seconds and caches at most 128 addresses for 10 minutes. It does not delay publishing offers.
  • Tick the installed Earth road renderer in the private minimap environment only while its renderer is active. Keep its incremental graph-index work separate from stock camera/texture state.
  • Update street text and personal-route HUD summaries once per second. A street lookup reads Earth API state, not a new geocoder query.
  • Stop panel heartbeats/edits on owner loss, unmount or leaving Earth. Personal route cleanup retains another manually selected GPS destination.

Publication preflight passed 80 UI tests, compiled 52 runtime Lua files and passed 43 Lua regressions in the local compatibility runner. The game was closed during publication. Earlier live development verification compiled 52 files and passed 43 isolated regressions in game LuaJIT, alongside map, personal-route and service-form checks. See Changelog for the distinction.

This release does not claim a general FPS improvement. For performance reports, distinguish Lua callback time, GPU rendering, world-streaming hitches and foreground/background FPS caps; comparisons made on different terrain, at different speeds or without matching window focus are not conclusive.

Clone this wiki locally