1. Trouble with the game?
    Try the troubleshooter!

    Dismiss Notice
  2. Issues with the game?
    Check the Known Issues list before reporting!

    Dismiss Notice

Update Speculation thread

Discussion in 'General Discussion' started by crazikyle, Jan 26, 2016.

  1. Métronome

    Métronome
    Expand Collapse

    Joined:
    Jul 6, 2023
    Messages:
    607
    I hope the new update will bring us a better traffic. But I doubt it.
     
    • Agree Agree x 1
  2. hacker420

    hacker420
    Expand Collapse

    Joined:
    Dec 29, 2017
    Messages:
    1,183
    I personally suspect it's either something with the lighting system or weather (maybe improved particles for stuff like rain too?)
     
    • Agree Agree x 2
  3. Driver2210

    Driver2210
    Expand Collapse

    Joined:
    Jan 7, 2021
    Messages:
    17
    I wonder if the devs decided to put extra emphasis on improving the optimization during this run to minimize potential FPS drops that come with the possible lighting system revamp.
     
    • Agree Agree x 8
  4. sduncil95

    sduncil95
    Expand Collapse

    Joined:
    Jun 28, 2016
    Messages:
    72
    I'd imagine they would put heavy emphesis on making sure this lighting update doesn't turn everyone's computers into instant air friers.
     
    • Agree Agree x 1
  5. CrashHavenBNG

    CrashHavenBNG
    Expand Collapse

    Joined:
    Aug 1, 2025
    Messages:
    3,281
    Code for a working taxi system.

    C:\Program Files (x86)\Steam\steamapps\common\BeamNG.drive\lua\ge\extensions\gameplay
     

    Attached Files:

    • Screenshot463.png
    • Like Like x 6
  6. Baggylobster

    Baggylobster
    Expand Collapse

    Joined:
    Mar 18, 2026
    Messages:
    106
    Is it new code? Though a taxi system would be cool!
     
    • Agree Agree x 1
  7. CrashHavenBNG

    CrashHavenBNG
    Expand Collapse

    Joined:
    Aug 1, 2025
    Messages:
    3,281
    I dont know how new it is
     
    • Like Like x 1
  8. DaveBro

    DaveBro
    Expand Collapse

    Joined:
    Jul 11, 2024
    Messages:
    1,212
    It’s probably going to come next update from the looks of it.
     
    • Agree Agree x 1
  9. CrashHavenBNG

    CrashHavenBNG
    Expand Collapse

    Joined:
    Aug 1, 2025
    Messages:
    3,281
    Im going to see if I can get it working
     
    • Like Like x 3
  10. Baggylobster

    Baggylobster
    Expand Collapse

    Joined:
    Mar 18, 2026
    Messages:
    106
    good luck
     
    • Like Like x 1
  11. CrashHavenBNG

    CrashHavenBNG
    Expand Collapse

    Joined:
    Aug 1, 2025
    Messages:
    3,281
    Could someone please message me to help get it working?

    Code:
    -- This Source Code Form is subject to the terms of the bCDDL, v. 1.1.
    -- If a copy of the bCDDL was not distributed with this
    -- file, You can obtain one at http://beamng.com/bCDDL-1.1.txt
    local M = {}
    
    -- taxi management
    local taxiIdsList = {}
    local ignoreTaxiIdsList = {}
    local nearestTaxiId = nil
    local currentTaxiId = nil
    local maxDistanceToTaxi = 20
    
    local destinationPos = nil
    
    -- to manage walking away from the taxi
    local maxDistToTaxiForAbandon = math.huge
    local wiggleRoom = 6
    
    -- to manage pulling over at the destination
    local almostArrivedDist = 100
    local pullOverDistToDestination = 30
    
    local delayToOpenBigMap = 0.4
    
    -- blinker system
    local maxPullOverSpeed = 2 --km/h
    local maxTaxiSpeed = 150
    local blinkersDuration = 3
    local blinkerStates = {}
    
    -- idle camera system
    local idleCameraDelay = 7 -- seconds
    local idleCameraActive = false
    local previousCameraName
    local disableIdleCamera = false
    local fadeToBlackDuration = 0.5
    
    local distanceToTarget = 150
    local skipPosition = nil
    local skipRotation = nil
    local accelerationTime = 1 -- seconds
    
    
    -- makes it easier to manage the different stages of a taxi ride
    local steps = {
      nothing = {id = 0, name = "Nothing"},
      taxiCalled = {id = 1, name = "Taxi Called"},
      chooseDestination = {id = 2, name = "Choose Destination"},
      taxiDriving = {id = 3, name = "Taxi Driving"},
      taxiPullingOver = {id = 4, name = "Taxi Pulling Over"},
    }
    local currentStep = steps.nothing
    
    local function resetData()
      currentStep = steps.nothing
      disableIdleCamera = false
    end
    
    local function showMessage(message, clear)
      if clear == nil then clear = true end
      local helper = {
        ttl = 2,
        msg = message,
        category = "taxiNearby",
        clear = clear
      }
      guihooks.trigger('Message',helper)
    end
    
    local function activateSignal(veh, rightForRightHand)
      veh:queueLuaCommand('electrics.stop_turn_signal()')
      local isRightHand = map.getRoadRules().rightHandDrive
      local useRight = (isRightHand and rightForRightHand) or (not isRightHand and not rightForRightHand)
      veh:queueLuaCommand('electrics.toggle_' .. (useRight and 'left' or 'right') .. '_signal()')
    end
    
    local function activatePullOverBlinkers(veh)
      activateSignal(veh, true)
    end
    
    local function activateMergeBlinkers(veh)
      core_jobsystem.create(function(job)
        activateSignal(veh, false)
        job.sleep(blinkersDuration)
        veh:queueLuaCommand('electrics.stop_turn_signal()')
      end, 1)
    end
    
    local function getNearestRoadSpeedLimit(pos)
      if not pos then return nil end
    
      local closestNode1, closestNode2 = map.findClosestRoad(pos)
      if not (closestNode1 and closestNode2) then return nil end
    
      local nodes = map.getMap().nodes
      if not (nodes[closestNode1] and nodes[closestNode2]) then return nil end
    
      -- Get the connection/link between the two nodes
      local connection = nodes[closestNode1].links[closestNode2] or nodes[closestNode2].links[closestNode1]
      if not connection then return nil end
    
      -- Speed limit is in m/s, convert to km/h if needed
      return connection.speedLimit and (connection.speedLimit * 3.6) or nil
    end
    
    local function notifyBlinkerSysOfPullOver(vehId)
      blinkerStates[vehId] = "pullingOver"
      activatePullOverBlinkers(getObjectByID(vehId))
    end
    
    local function setIdleCamera(value)
      if not core_camera then return end
      idleCameraActive = value
      if value then
        core_jobsystem.create(function(job)
          previousCameraName = core_camera.getActiveCamName()
          ui_fadeScreen.start(fadeToBlackDuration)
          job.sleep(fadeToBlackDuration+0.1)
          core_camera.setByName(0, "external")
          ui_fadeScreen.stop(fadeToBlackDuration)
        end, 1)
      else
        core_camera.setByName(0, previousCameraName)
      end
    end
    
    local function setCurrentStep(step)
      currentStep = step
      if currentStep == steps.taxiPullingOver then
        setIdleCamera(false)
        disableIdleCamera = true
      end
    end
    
    local function updateBlinkerSys()
      local taxisToDiscard = {}
      for vehId, state in pairs(blinkerStates) do
        local veh = getObjectByID(vehId)
        local taxiSpeed = veh:getVelocity():len() * 3.6
        if state == "pullingOver" and taxiSpeed < maxPullOverSpeed then
          veh:queueLuaCommand('electrics.set_warn_signal(1)')
          if currentStep == steps.taxiPullingOver then
            showMessage("You can climb out of the taxi now", false)
          end
          blinkerStates[vehId] = "stopped"
        elseif state == "stopped" and taxiSpeed > maxPullOverSpeed then
          activateMergeBlinkers(veh)
          table.insert(taxisToDiscard, vehId)
        end
      end
      for _, vehId in ipairs(taxisToDiscard) do
        blinkerStates[vehId] = nil
      end
    end
    
    local function checkIdleCamera()
      if not core_camera then return end
      local timeSinceRotation = core_camera.timeSinceLastRotation()
    
      -- Check if camera has been idle for longer than our delay
      if timeSinceRotation / 1000 > idleCameraDelay then
        if not idleCameraActive and not disableIdleCamera then
          setIdleCamera(true)
        end
      else
        if idleCameraActive then
          setIdleCamera(false)
        end
      end
    end
    
    local function getAiPath(path, veh)
      local aiPath = {}
      if not veh then return nil end
      local firstWpAdded = false
      local vehPos = veh:getPosition()
      local vehFwd = veh:getDirectionVector()
      local bestDist = math.huge
      local prevDot = nil
      local prevWp = nil
      local startDist = path[1].distToTarget
      -- find the first valid waypoint
      for i, marker in ipairs(path) do
        if marker.wp then
          if (marker.distToTarget < distanceToTarget) and not skipPosition then
            skipPosition = marker.pos
            if path[i+1] and path[i+1].pos then
              local direction = (path[i+1].pos - marker.pos):normalized()
              skipRotation = quatFromDir(direction, vec3(0, 0, 1))
            end
          end
          if not firstWpAdded then
            local toWp = (marker.pos - vehPos):normalized()
            local dot = toWp:dot(vehFwd)
            -- If we have a previous dot product and this one is lower, we found our local maximum
            if prevDot and dot < prevDot and prevDot > 0 then
              --log('I', 'quickaccess', 'Adding waypoint ' .. prevWp .. ' because it is the local maximum, dot: ' .. dot .. ', prevDot: ' .. prevDot .. ', startDist: ' .. startDist .. ', marker.distToTarget: ' .. marker.distToTarget)
              table.insert(aiPath, prevWp)
              firstWpAdded = true
            end
            prevDot = dot
            prevWp = marker.wp
          else
            table.insert(aiPath, marker.wp)
          end
        end
      end
      -- If we haven't found a local maximum but have a positive dot product, use the last one
      if not firstWpAdded and prevDot and prevDot > 0 then
        table.insert(aiPath, prevWp)
        firstWpAdded = true
      end
      -- fallback: if no waypoint is in front of vehicle, use the first waypoint that's 25m away and all other waypoints
      if not firstWpAdded then
        for _, marker in ipairs(path) do
          if marker.wp and startDist - marker.distToTarget > 25 then
            table.insert(aiPath, marker.wp)
          end
        end
      end
      return aiPath
    end
    
    local function getCurrentRoute(veh)
      local rp = core_groundMarkers.routePlanner
      if not rp or not rp.path or not rp.path[1] then
        return
      end
    
      local aiPath = getAiPath(rp.path, veh)
      destinationPos = rp.path[#rp.path].pos
      local str = '{wpTargetList = '..serialize(aiPath)
      str = str..', noOfLaps = 1, aggression = 0.3, avoidCars = "on", driveInLane = "on", speedMode = "limit"}'
      return str
    end
    
    
    local function startTaxiWithCurrentRoute(skipWait)
      if skipWait == nil then skipWait = false end
      core_jobsystem.create(function(job)
        freeroam_bigMapMode.exitBigMap(false, true, true)
        local plVeh = be:getPlayerVehicle(0)
        if not plVeh then
          return
        end
    
        local routeStr = getCurrentRoute(plVeh)
        if not routeStr then
          return
        end
    
        freeroam_bigMapMode.setNavFocus(nil)
        if not skipWait then
          job.sleep(2)
        end
    
        plVeh:queueLuaCommand('ai.driveUsingPath('..routeStr..')')
    
        setCurrentStep(steps.taxiDriving)
      end, 1)
    end
    
    
    local function isTaxi(vehId)
      local obj = scenetree.findObjectById(vehId)
      if not obj then return false end
    
      local configName = obj.partConfig or ""
    
      -- Check if "taxi" appears anywhere in the config name for now
      return string.find(string.lower(configName), "taxi") ~= nil
    end
    
    local function extractTaxiIds()
      for vehId, _ in pairs(map.objects) do
        if isTaxi(vehId) then
          taxiIdsList[vehId] = true
        end
      end
    end
    
    local function checkAndFindNearestTaxi()
      local playerPos = be:getPlayerVehicle(0):getPosition()
      local nearestDist = math.huge
      local found = false
      local missingVehIds = {}
      for vehId, _ in pairs(taxiIdsList) do
        if not ignoreTaxiIdsList[vehId] then
          if vehId ~= be:getPlayerVehicleID(0) then
          local veh = map.objects[vehId]
          if veh then
            local vehPos = veh.pos
            local dist = playerPos:distance(vehPos)
            if dist < nearestDist and dist < maxDistanceToTaxi and getNearestRoadSpeedLimit(vehPos) < maxTaxiSpeed then
                nearestDist = dist
                nearestTaxiId = vehId
                found = true
              end
            end
          else
            table.insert(missingVehIds, vehId)
          end
        end
      end
    
      if not found then
        nearestTaxiId = nil
      end
      for _, vehId in ipairs(missingVehIds) do
        taxiIdsList[vehId] = nil
      end
    end
    
    local function setPullOver(veh)
      notifyBlinkerSysOfPullOver(veh:getID())
      veh:queueLuaCommand('ai.setPullOver(true)')
    end
    
    local function setTrafficMode(veh)
      veh:queueLuaCommand('ai.setPullOver(false)')
      veh:queueLuaCommand('ai.setState({mode = "traffic"})')
    end
    
    local function callAndStopTaxi()
      -- simply stop the AI for now
      if not nearestTaxiId then return end
      currentTaxiId = nearestTaxiId
      local veh = getObjectByID(currentTaxiId)
      if not veh then return end
    
      local trafficVeh = gameplay_traffic.getTrafficData()[currentTaxiId]
      if trafficVeh and trafficVeh.role then
        setPullOver(veh)
      end
    
      -- make the taxi climbable
      gameplay_walk.removeVehicleFromBlacklist(currentTaxiId)
      getObjectByID(currentTaxiId).playerUsable = true
    
      showMessage("Taxi heard you and is pulling over", false)
      setCurrentStep(steps.taxiCalled)
    end
    
    local function leaveTaxi(message)
      local veh = getObjectByID(currentTaxiId)
      if not veh then return end
      setTrafficMode(veh)
      ignoreTaxiIdsList[currentTaxiId] = true
      gameplay_walk.addVehicleToBlacklist(currentTaxiId)
      getObjectByID(currentTaxiId).playerUsable = false
    
      if message then
        showMessage(message, false)
      end
    
      setCurrentStep(steps.nothing)
      maxDistToTaxiForAbandon = math.huge
      currentTaxiId = nil
    end
    
    local function makeTaxiPullOverWhileDriving(message)
      if not currentTaxiId then return end
      local veh = getObjectByID(currentTaxiId)
      if not veh then return end
      local trafficVeh = gameplay_traffic.getTrafficData()[currentTaxiId]
      if trafficVeh and trafficVeh.role then
        setTrafficMode(veh)
        setPullOver(veh)
        setCurrentStep(steps.taxiPullingOver)
    
        if message then
          showMessage(message, false)
        end
      end
    end
    
    local function isTaxiDrivingWithPlayer()
      if not currentTaxiId then return false end
      local veh = getObjectByID(currentTaxiId)
      if not veh then return false end
      return veh:getVelocity():len() > 5 and currentStep == steps.taxiDriving
    end
    
    local function isTaxiAvailable()
      return currentStep == steps.nothing and gameplay_walk.isWalking() and nearestTaxiId
    end
    
    local function onUpdate(dtReal, dtSim, dtRaw)
      if not be:getPlayerVehicle(0) then return end
    
      extractTaxiIds()
      checkAndFindNearestTaxi()
      updateBlinkerSys()
    
      if isTaxiAvailable() then
        showMessage("There's a taxi in service. Press [action=gameplay_interact] to stop it", false)
      end
    
      if currentStep == steps.taxiCalled and gameplay_walk.isWalking() and getObjectByID(currentTaxiId):getVelocity():len() < 1 then
        local dist = be:getPlayerVehicle(0):getPosition():distance(map.objects[currentTaxiId].pos)
        local newMaxDistToTaxiForAbandon = dist + wiggleRoom
        if newMaxDistToTaxiForAbandon < maxDistToTaxiForAbandon then
          maxDistToTaxiForAbandon = newMaxDistToTaxiForAbandon
        end
    
        if dist > maxDistToTaxiForAbandon then
          leaveTaxi("Taxi has abandoned you and is driving away")
        end
      end
    
      if currentTaxiId and currentStep == steps.taxiDriving then
        checkIdleCamera()
        local distToDest = map.objects[currentTaxiId].pos:distance(destinationPos)
        if currentStep == steps.taxiDriving and distToDest < almostArrivedDist then
          showMessage("You have almost arrived at your destination", false)
        end
    
        if currentStep == steps.taxiDriving and distToDest < pullOverDistToDestination then
          makeTaxiPullOverWhileDriving("Taxi has arrived at your destination")
        end
      end
    
      if isTaxiDrivingWithPlayer() then
        showMessage("Press [action=gameplay_interact] to stop the taxi", false)
      end
    end
    
    local function onVehicleSwitched(oldId, newId)
      -- player entered the taxi
      if newId == currentTaxiId then
        core_jobsystem.create(function(job)
          job.sleep(delayToOpenBigMap)
          setCurrentStep(steps.chooseDestination)
          freeroam_bigMapMode.enterBigMap({mode = "taxi"})
        end, 1)
      end
    
      -- player exited the taxi
      if oldId == currentTaxiId then
        leaveTaxi()
      end
    end
    
    local function onChangeDestinationCalled()
      if currentStep == steps.taxiDriving then
        setIdleCamera(false)
        freeroam_bigMapMode.enterBigMap({mode = "taxi"})
      end
    end
    
    local function onHurryUpCalled()
      if currentStep == steps.taxiDriving then
      end
    end
    
    local function onSkipCalled()
      if currentStep == steps.taxiDriving then
        core_jobsystem.create(function(job)
          ui_fadeScreen.start(fadeToBlackDuration)
          job.sleep(fadeToBlackDuration + 0.1)
    
          setIdleCamera(false)
          job.sleep(0.1)
    
          disableIdleCamera = true
          freeroam_bigMapMode.setNavFocus(destinationPos)
          startTaxiWithCurrentRoute(true)
          spawn.safeTeleport(getObjectByID(currentTaxiId), skipPosition, skipRotation, true, nil, false)
    
          be:setPhysicsSpeedFactor(2) --so that the taxi gets up to speed faster
          job.sleep(accelerationTime)
          be:setPhysicsSpeedFactor(0)
    
          ui_fadeScreen.stop(fadeToBlackDuration)
        end, 1)
      end
    end
    
    local function onGameplayInteract()
      if isTaxiDrivingWithPlayer() then
        makeTaxiPullOverWhileDriving("Taxi is pulling over ...")
      elseif isTaxiAvailable() then
        callAndStopTaxi()
      end
    end
    
    local function onTrafficVehicleRespawned(id)
      ignoreTaxiIdsList[id] = nil
    end
    
    M.startTaxiWithCurrentRoute = startTaxiWithCurrentRoute
    
    M.onChangeDestinationCalled = onChangeDestinationCalled
    M.onHurryUpCalled = onHurryUpCalled
    M.onSkipCalled = onSkipCalled
    
    M.onTrafficVehicleRespawned = onTrafficVehicleRespawned
    M.onVehicleSwitched = onVehicleSwitched
    M.onGameplayInteract = onGameplayInteract
    M.onUpdate = onUpdate
    
    return M
     
    • Agree Agree x 2
  12. Cookiehead

    Cookiehead
    Expand Collapse

    Joined:
    Mar 20, 2023
    Messages:
    529
    File date looks to be December 2025 so maybe from around then
     
  13. Vantello

    Vantello
    Expand Collapse

    Joined:
    Sep 1, 2018
    Messages:
    559

    Add this line
    M.callAndStopTaxi = callAndStopTaxi

    under
    M.startTaxiWithCurrentRoute = startTaxiWithCurrentRoute

    save the file, press ctrl+L.
    Spawn traffic make sure a taxi spawns, get near a taxi and put this into the console
    extensions.gameplay_taxi.callAndStopTaxi()

    once you get in and you set a route put this into the console
    extensions.gameplay_taxi.startTaxiWithCurrentRoute()
     
    #78133 Vantello, Apr 27, 2026
    Last edited: Apr 27, 2026
    • Like Like x 4
  14. CrashHavenBNG

    CrashHavenBNG
    Expand Collapse

    Joined:
    Aug 1, 2025
    Messages:
    3,281
    Ill see if that works, thanks
    --- Post updated ---
    It works!

     
    • Like Like x 20
  15. ITHEPUNISHER

    ITHEPUNISHER
    Expand Collapse

    Joined:
    Sep 23, 2018
    Messages:
    667
  16. CrashHavenBNG

    CrashHavenBNG
    Expand Collapse

    Joined:
    Aug 1, 2025
    Messages:
    3,281
    Its 3 hours till any teaser
     
    • Agree Agree x 5
  17. silverhpkey.official

    silverhpkey.official
    Expand Collapse

    Joined:
    Feb 7, 2025
    Messages:
    15
    Do you wish we had a teaser
     
  18. Miura22402

    Miura22402
    Expand Collapse

    Joined:
    Oct 1, 2025
    Messages:
    110
    More like at least 3 weeks :/
     
    • Agree Agree x 11
  19. Purple Gibbon

    Purple Gibbon
    Expand Collapse

    Joined:
    Oct 15, 2022
    Messages:
    34
    Times up, no teaser for today.
    This def going to be big Update, something taking this long to tease can only mean a whole rework on something (like when they changed from cry engine to torque3d, but oriented to skybox and all about weather update), taking enough time to have the whole team working.
    Also think about a new day-night cycle, they might be working on lights to show up at night on the main maps as WCU.
    It will worth the wait. I guess. It always do.
     

    Attached Files:

    • noteaser.jpg
    • Agree Agree x 4
  20. ShakeandBake

    ShakeandBake
    Expand Collapse

    Joined:
    Apr 8, 2025
    Messages:
    455
    The sudden radio silence from the devs is working on me. These dudes are marketing geniuses, I'm convinced. They put so much anticipation and hype in my bones. Very Steve Jobs-esque. Bravo.
     
    #78140 ShakeandBake, Apr 29, 2026
    Last edited: Apr 29, 2026
    • Agree Agree x 19
  1. This site uses cookies to help personalise content, tailor your experience and to keep you logged in if you register.
    By continuing to use this site, you are consenting to our use of cookies.
    Dismiss Notice