Fix Connected Phone map not rendering on BeamNG 0.39 - #4
Merged
noteMASTER11 merged 9 commits intoJul 29, 2026
Conversation
BeamNG 0.39 fails to bind the native LAN server to non-loopback interfaces (lws SO_BINDTODEVICE ENODEV), pushing Connected Phone sessions onto the lua_proxy fallback transport. That proxy only relayed one read/write per connection per game frame, so bursty payloads like road/map chunks could trickle out slowly or stall instead of being forwarded as soon as they arrive. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
BeamNG 0.39's UI/menu engine rewrite changed the availability/timing of the beamng.ingame global for external WebSocket clients, so app.js's externalPhoneMode detection silently evaluated false. That disabled the external map canvases (ng-if="externalPhoneMode") and made the TaxiDriverExternalRoadData/MapData handlers early-return with no error, while the rest of the phone UI kept working normally off other code paths. external.js only ever bootstraps the Connected Phone browser client (the in-game phone loads app.js directly), so it can set a flag we fully control instead of relying on BeamNG's own global. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
TaxiDriverHUDState/HUDPatch keep arriving on the external Connected
Phone client, but TaxiDriverExternalVehicleState/RoadData/MapData
never do, despite both families going through the identical
guihooks.trigger() call with no Lua-side error and all publishing
gates satisfied. The only remaining difference is the one-time
subscribeToEvents("{}") call in external.js: an empty filter may
have meant "subscribe to everything" pre-0.39, but BeamNG 0.39's
bridge appears to now require (or default to) an explicit list.
This is an experiment pending in-game confirmation, not a verified
fix - BeamNG doesn't publicly document this bridge's subscription
filter format.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Diagnosing a BeamNG 0.39 regression where TaxiDriverExternalVehicleState/ RoadData/MapData guihooks.trigger calls never reach the Connected Phone browser client, despite no Lua-side errors and canPublishNavigation() gating checking out. This logs (every 2s while gated open) the active transport, current phase, cached road count, pending road chunk index, and whether a vehicle snapshot is available, to confirm from the game log whether Lua is actually attempting to publish. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Confirmed via BeamNG's own ui-vue bridge source that subscribeToEvents
feeds StreamManager's vehicle-telemetry "streams" concept, which is
unrelated to bridge.events' plain named-event pub/sub (how
TaxiDriverHUDState/HUDPatch/VehicleChange etc. already arrive with no
subscription needed). The array payload from the previous commit was
also the wrong shape for this call regardless - BeamNG 0.39 logs
"Wrong data stream request format" and rejects it outright, so it was
actively harmful, not just ineffective. Reverting to keep the original
"{}" call BeamNG's own Angular bootstrap uses.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
BeamNG 0.39's native external (non-CEF) Connected Phone client stopped
receiving lanBridge.lua's guihooks.trigger("TaxiDriverExternal...")
pushes for vehicle position, road geometry, and map/route data - with
no error on either side, confirmed via debug logging that Lua kept
firing them every cycle and via browser devtools that nothing ever
arrived over the WebSocket, while other guihooks.trigger events
(TaxiDriverHUDState/HUDPatch) kept working fine over the same bridge.
Replace the push path with a pull one, reusing the bngApi.engineLua
request/response channel that view-switching and heartbeats already
use reliably in this build:
- lanBridge.lua: drop the chunked road-publish/guihooks.trigger
machinery; add M.pollExternalState(clientRoadRevision,
clientMapRevision), a plain getter over the same cached map/road
data (still kept warm by M.update() every frame). Road/terrain data
is only included when the client's known revision is stale.
- taxiDriver.lua / optionalLanBridge.lua: wire the new entry point
through, per this mod's lazy-load whitelist requirement.
- app.js: external client now self-schedules a poll (125-500ms,
matching the existing quality setting) via
taxiDriver_taxiDriver.pollExternalState(...) instead of listening
for the three dead push events, which are removed.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
bngApi.engineLua(code, callback) splices code in as an argument to
guihooks.trigger("onBNGAPICallback", ...), so it must be a single Lua
expression, not an "if ... then ... end" statement - the latter
crashed the GE Lua VM outright ("unexpected symbol near 'if'"). Use
the `x and x.method(...)` short-circuit idiom instead, matching the
only other callback-style engineLua call in this file.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Revert the LAN proxy multi-pass drain rewrite in lanBridge.lua back to main's original single-pass loop, and drop an external.js comment narrating it - both were an earlier, disproven hypothesis (the map was confirmed still broken after that fix shipped) rather than part of the actual fix, which was switching push to poll delivery. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Pulls in upstream's Release 4.0.0 RC (new UI/CSS, AI/autopilot
overhaul, updated baselines). Merged cleanly with no conflicts; the
map/bridge fix (externalPhoneMode detection + poll-based
TaxiDriverExternal* delivery) is unaffected since upstream's only
touches to lanBridge.lua/external.js were asset-revision version
bumps ("341-rc" -> "400-rc"), and its taxiDriver.lua/app.js changes
landed in unrelated areas (autopilot, offers, native heartbeat
visibility handling).
Note: tests/lua/combinatorics.lua:252 fails on this merge, but was
verified to already fail identically on plain upstream main
(b6c4f15) before merging - a pre-existing issue in their release,
not introduced here.
Contributor
Author
|
@noteMASTER11 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes the external Connected Phone map no longer working after updating to BeamNG.drive 0.39.
The rest of the Connected Phone UI continued to work normally, but the map either remained completely empty or rendered without roads and the vehicle marker.
Root cause
BeamNG 0.39 introduced changes to the external client bridge that affected the map in two ways:
beamng.ingamecheck no longer reliably identified the external Connected Phone client, preventing the external map canvas from being initialized.guihooks.triggerevents previously used to send road, map, and vehicle data no longer reached external browser clients, while other HUD events continued to work normally.Fix
External-client detection is now explicitly initialized by
external.js, with the previousbeamng.ingamecheck retained as a fallback.Map data delivery was changed from the no longer working
guihooks.triggerpush mechanism to a pull-based approach using the existingbngApi.engineLua(...)channel.The external client periodically requests the current map state through
pollExternalState(). Vehicle position is returned on every poll, while larger road and terrain data is only transferred when its revision changes.The existing map rendering logic remains unchanged and now receives its data through the new polling mechanism.
This restores the road network and live vehicle position/heading on the external Connected Phone client with BeamNG.drive 0.39.
The map was also tested inside BeamNG's in-game phone app to ensure that the changes do not affect the existing in-game implementation. Both the external Connected Phone map and the in-game map are working correctly.