GE Lua Documentation

Press F to search!

teleportToLastRoadCallback

Definition


-- @/lua/ge/spawn.lua:636

local function teleportToLastRoadCallback(data, options)
  local mapData = map.getMap()
  local legalSide = map.getRoadRules().rightHandDrive and -1 or 1
  local veh = getPlayerVehicle(0)
  local pos, rot
  if tableIsEmpty(mapData.nodes) then
    pos = veh:getPosition()
    rot = quatFromDir(veh:getDirectionVector(), veh:getDirectionVectorUp())
  end

  if not pos and data then
    -- Find the last recovery position on a road and teleport to that road
    for i = data.tail, data.head, -1 do
      local recoveryPoint = data[i]
      if not recoveryPoint then break end
      local n1Id, n2Id, dist = map.findClosestRoad(recoveryPoint.pos)
      if n1Id then
        local n1 = mapData.nodes[n1Id]
        local n2 = mapData.nodes[n2Id]
        if dist <= (n1.radius+n2.radius)/2 then
          -- Found a recovery point on a road

          local oneWay = mapData.nodes[n1Id].links[n2Id].oneWay
          local segmentDir = (n2.pos - n1.pos)
          local drivingDir = segmentDir

          if options.destinationPos then
            -- if there is a destinationPos then always put the vehicle in that direction regardless of other rules

            local routePlanner = require('gameplay/route/route')()
            routePlanner:setupPath(n1.pos, options.destinationPos)

            if routePlanner.path and routePlanner.path[2] then
              if drivingDir:dot(routePlanner.path[2].pos - n1.pos) < 0 then
                drivingDir = -drivingDir
              end
            end
            oneWay = true

          -- if the road is oneWay, flip the drivingDir if it is incorrect
          elseif oneWay and (mapData.nodes[n1Id].links[n2Id].inNode ~= n1Id) then
            drivingDir = -drivingDir
          end

          local perpendicular = drivingDir:cross(n1.normal)

          -- In a oneWay road, always put the vehicle on the legal driving side, otherwise check which side is closer
          local roadSide
          if oneWay then
            roadSide = legalSide
          else

            -- if there are groundmarkers active then choose the side in the direction of the route
            if core_groundMarkers.currentlyHasTarget() then
              core_groundMarkers.routePlanner:trackPosition(recoveryPoint.pos)
              if core_groundMarkers.routePlanner.path[2] then
                local routeDir = core_groundMarkers.routePlanner.path[2].pos - getPlayerVehicle(0):getPosition()
                roadSide = drivingDir:dot(routeDir) > 0 and legalSide or -legalSide
              end
            end

            if not roadSide then
              roadSide = perpendicular:dot(recoveryPoint.pos - n1.pos) > 0 and 1 or -1
            end
          end

          -- Project the recovery point on the road segment
          local segLenSq = segmentDir:length()^2
          local scalarProjection = 0
          if segLenSq > 0 then
            scalarProjection = clamp(segmentDir:dot((recoveryPoint.pos - n1.pos)) / segLenSq, 0, 1)
          end
          local projectedPosition = n1.pos + segmentDir * scalarProjection
          pos = projectedPosition + perpendicular:normalized() * roadSide * (lerp(n1.radius, n2.radius, scalarProjection) - veh.initialNodePosBB:getExtents().x/2)

          -- Find the rotation that puts the vehicle correctly in the driving direction
          rot = quatFromDir(drivingDir * legalSide * roadSide, n1.normal)
          break
        end
      end
    end
  end

  -- If none of the recovery points are on a road, try to find the closest road to the current position
  -- TODO this puts the player in the middle of the road
  if not pos then
    local n1Id, n2Id, dist = map.findClosestRoad(veh:getPosition())
    local n1 = mapData.nodes[n1Id]
    local n2 = mapData.nodes[n2Id]
    if dist < 50 then
      pos = n1.pos
      rot = quatFromDir(n1.pos - n2.pos, n1.normal)
    end
  end

  if not pos then
    pos = veh:getPosition()
    rot = quatFromDir(veh:getDirectionVector(), veh:getDirectionVectorUp())
  end

  safeTeleport(veh, pos, rot, nil, nil, nil, true, options.resetVehicle)
end

Callers