Vehicle Control from GE
How to find, spawn, switch, and send commands to vehicles from Game Engine Lua — the essential operations for any gameplay mod.
Most gameplay mods need to interact with vehicles — finding the player's car, spawning NPCs, sending commands to the vehicle VM, or listening for spawn/destroy events. This guide covers all the essential operations.
Getting Vehicles
Player vehicle
local veh = be:getPlayerVehicle(0)
if veh then
log('I', 'myMod', 'Player vehicle: ' .. veh:getName())
endThe 0 is the player index. In multiplayer scenarios, other players would use 1, 2, etc.
By ID
local veh = be:getObjectByID(vehicleId)All vehicles
local count = be:getObjectCount()
for i = 0, count - 1 do
local veh = be:getObject(i)
log('I', 'myMod', 'Vehicle: ' .. veh:getName())
endVehicle Data
local veh = be:getPlayerVehicle(0)
if not veh then return end
local name = veh:getName() -- internal name (e.g. "clone_0")
local id = veh:getId() -- numeric ID
local pos = veh:getPosition() -- vec3 world position
local vel = veh:getVelocity() -- vec3 velocity
local speed = vel:length() -- speed in m/sSpawning Vehicles
local options = {}
options.model = "pickup"
options.config = "vehicles/pickup/base.pc"
options.pos = vec3(0, 0, 0.5)
options.rot = quat(0, 0, 0, 1)
local veh = spawn.spawnVehicle(options.model, options.config, options.pos, options.rot)Running Code on a Vehicle (GE to VE)
Use queueLuaCommand() to execute Lua inside the vehicle's VM:
local veh = be:getPlayerVehicle(0)
-- Run arbitrary VE code
veh:queueLuaCommand("electrics.values.headlights = 1")
-- Call a vehicle extension function
veh:queueLuaCommand("myVehicleExtension.doThing()")
-- Pass data (serialize to string)
local value = 42
veh:queueLuaCommand("myVehicleExtension.setValue(" .. tostring(value) .. ")")For string arguments, be careful with quoting:
local name = "test"
veh:queueLuaCommand('myVehicleExtension.setName("' .. name .. '")')Switching Vehicles
-- Switch to a vehicle by ID
be:enterVehicle(0, be:getObjectByID(targetId))Listening for Vehicle Events
local M = {}
local function onVehicleSpawned(vehicleId)
log('I', 'myMod', 'Vehicle spawned: ' .. tostring(vehicleId))
end
local function onVehicleSwitched(oldId, newId)
log('I', 'myMod', 'Switched from ' .. tostring(oldId) .. ' to ' .. tostring(newId))
end
local function onVehicleDestroyed(vehicleId)
log('I', 'myMod', 'Vehicle destroyed: ' .. tostring(vehicleId))
end
M.onVehicleSpawned = onVehicleSpawned
M.onVehicleSwitched = onVehicleSwitched
M.onVehicleDestroyed = onVehicleDestroyed
return MTips
:::caution[Always nil-check vehicle references]
be:getPlayerVehicle(0) returns nil when no vehicle is spawned (e.g., walking mode, during loading). Every vehicle operation should start with a nil check.
:::
- Always nil-check vehicle references:
if not veh then return end - Vehicle IDs are stable for the session but not across restarts
queueLuaCommand()is asynchronous - the code runs on the next vehicle physics step- Use
obj:queueGameEngineLua()from VE to send data back to GE
See Also
- Cross-VM Comms - Full GE/VE/UI communication patterns
- Hook Catalog - Vehicle hooks reference
- Common Patterns - Vehicle spawn callback pattern
GUI Hooks Reference
Complete reference for guihooks — sending events to the UI, toast notifications, streaming data, state changes, and common UI event patterns.
VE Architecture Quick Reference
10-second refresher on Vehicle Engine core rules — lifecycle hooks, override patterns, and the no-ghost-values rule.