# Configuration > Configuration reference for ML Vehicle Persistence Category: VEHICLE PERSISTENCE · Source: https://miciomods.it/docs/ml-vehicle-persistence-configuration · Last updated: 2026-09-26 ## Overview - `shared/config.lua`: persistence behavior, world streaming, world-vehicle claiming, decay, cleanup, GPS items, admin panel - `server/config_server.lua`: Discord webhooks and log provider - `open/server.lua`: ownership, garage and impound hooks The admin panel stores overrides for the settings shown on its Settings page. Other values remain in shared/config.lua. ## General **shared/config.lua** ```lua Config.Debug = false Config.locale = 'en' Config.PersistThroughRestart = true Config.MaxVehiclesPerPlayer = 5 Config.PersistDestroyed = false ``` - `Debug`: Prints gate decisions and lifecycle events to the server console - `locale`: Active language. Files live in `locales/` - `PersistThroughRestart`: Respawn every persisted vehicle in its saved spot after a server restart - `MaxVehiclesPerPlayer`: Maximum parked vehicles persisted per owner. At the limit, a new vehicle is not saved; existing saved vehicles remain. Protected vehicles and claimed vehicles with countTowardLimit set to false do not count. 0 = unlimited. - `PersistDestroyed`: `true` brings a wreck back as a wreck (burnt body, dead engine, burst tyres) on respawn and after a restart. `false` drops a destroyed vehicle from persistence for good ## World Streaming **shared/config.lua** ```lua Config.SpawnDistance = 250.0 Config.ScanInterval = 5 Config.SpawnStaggerMs = 150 ``` The script keeps saved vehicle records in memory, spawns the vehicles when a player comes close and despawns them when players leave the area. Distant saved vehicles do not need an active world entity. - `SpawnDistance`: Distance in meters at which a saved vehicle is spawned. Despawn happens 60 meters beyond this - `ScanInterval`: Seconds between world scans. Lower is snappier for spawns and position updates, higher is lighter on the server - `SpawnStaggerMs`: Delay in milliseconds between two vehicle spawns inside a scan, to spread the load ## External Deletes **shared/config.lua** ```lua Config.RespawnOnExternalDelete = false ``` - `RespawnOnExternalDelete`: Controls what happens when another resource deletes a persisted vehicle (an admin `/dv`, a garage, a cleanup script). `false` removes the saved record, including when an admin uses `/dv`. `true` respawns the vehicle at its saved position unless the deletion uses the delete hook or PurgeVehicle export. > **WARNING:** Using true > > With `true`, intentional deletes only stick if the deleting resource is routed through the script. Add `shared_script '@ml_vehicle_persistence/deletehook.lua'` as the **first** script line in the `fxmanifest.lua` of every resource that deletes vehicles (admin menu, garage), or call the `PurgeVehicle` export. Otherwise every `/dv` respawns the vehicle. ## Vehicle Types **shared/config.lua** ```lua Config.PersistTypes = { automobile = true, bike = true, bicycle = true, quadbike = true, amphibious_automobile = true, amphibious_quadbike = true, submarinecar = true, boat = true, heli = true, blimp = true, plane = true, submarine = false, trailer = true, } ``` - Only categories set to `true` are persisted. The key is the server-side vehicle archetype **shared/config.lua** ```lua Config.BlacklistedModels = { -- 'police', 'ambulance', } Config.BlacklistedPlates = { -- 'MECH', 'RENT', } ``` - `BlacklistedModels`: Spawn names that never persist, even when player-owned - `BlacklistedPlates`: Plate fragments that never persist. Partial match, case-insensitive, made for job and rental prefixes ## Notifications **shared/config.lua** ```lua Config.Notifications = { onParked = false, onLimitWarning = true, onLimitReached = true, } ``` - `onParked`: Popup on every park confirming the vehicle will stay - `onLimitWarning`: Tell the owner how many slots are in use once they reach the last free slot and again once they are full. The same count is never repeated twice in a row - `onLimitReached`: Warn the owner when a new vehicle cannot be saved because the limit is full. ## World Vehicles **shared/config.lua** ```lua Config.WorldVehicles = { enabled = true, countTowardLimit = true, notifyOnClaim = true, } ``` - `enabled`: An eligible unowned vehicle can be claimed by its first driver. Vehicle type, blacklist, exclusion, CanClaim and limit checks still apply. - `countTowardLimit`: Claimed vehicles count toward `Config.MaxVehiclesPerPlayer`. When the limit is full, the new claim is refused. Set this to false to exempt claimed vehicles from that limit. - `notifyOnClaim`: Tell the player the vehicle is now theirs > **TIP:** Opt a vehicle out > > Vehicles spawned by other scripts can be claimed if they pass the normal checks. Mark mission, rental, staff or temporary spawns with `exports.ml_vehicle_persistence:DoNotSave(plateOrNetId, reason)` on the server after spawning them. The exclusion clears when that entity is deleted. ## Base Building **shared/config.lua** ```lua Config.BaseIntegration = { enabled = true, protectInBase = true, blockStoreDuringRaid = true, crewGps = true, } ``` - `enabled`: Link parked vehicles to an active ml_base_building flag. The integration is ignored when that resource is not running. - `protectInBase`: Linked vehicles skip cleanup, decay and orphan removal. - `blockStoreDuringRaid`: Prevent a linked vehicle from being stored while its base is under raid. - `crewGps`: Crew members with vehicle driving permission can see linked vehicles on their GPS. ## Decay **shared/config.lua** ```lua Config.Decay = { enabled = false, graceDays = 2, bodyPerDay = 40.0, enginePerDay = 40.0, healthFloor = 150.0, } ``` - `enabled`: Apply decay at restart restore, based on time since the vehicle was last saved. It does not tick continuously while the server runs. - `graceDays`: Days since the vehicle's last save before decay starts. - `bodyPerDay`: Body health lost per day after the grace period - `enginePerDay`: Engine health lost per day after the grace period - `healthFloor`: Decay never drops health below this value. A vehicle already saved below the floor is left alone ## Orphaned Vehicles **shared/config.lua** ```lua Config.OrphanedVehicles = { enabled = true, thresholdDays = 7, action = 'impound', impoundLot = 'impound', feePerDay = 100, maxFee = 1500, } ``` - `enabled`: Clean up vehicles whose owner has not been seen for `thresholdDays` - `thresholdDays`: Days of owner absence before a vehicle is orphaned - `action`: 'impound' routes database-owned vehicles through OpenServer.ImpoundVehicle; 'delete' removes them. Claimed World Vehicles are deleted for either action because they have no garage record. `OpenServer.ImpoundVehicle` updates the Qbox/QBCore player_vehicles table by default. Adapt the hook for an ESX or custom impound system. - `impoundLot`: Impound lot name passed to the hook - `feePerDay`: Fee charged per orphaned day - `maxFee`: Maximum impound fee ## Cleanup **shared/config.lua** ```lua Config.Cleanup = { enabled = false, engineBelow = nil, underZ = nil, clearZones = { -- { coords = vector3(0.0, 0.0, 0.0), radius = 20.0 }, }, safeZones = { -- { coords = vector3(0.0, 0.0, 0.0), radius = 20.0 }, }, keepPlates = { -- 'STAFF', }, keepModels = { -- 'adder', }, schedule = { -- { hour = 4, minute = 0 }, -- { day = 3, hour = 16, minute = 0 }, }, runOnStart = false, } ``` The cleanup sweep removes saved vehicles that match your rules. It checks the saved records, including vehicles that are not currently spawned. - `enabled`: Master switch for the sweep - `engineBelow`: Prune vehicles whose engine dropped to or under this value. A dead engine sits around `0`, a blown-up one goes deeply negative. `nil` keeps every vehicle - `underZ`: Prune vehicles that ended up under this height, for cars dropped through the map or sunk. `nil` to skip - `clearZones`: Any vehicle sitting inside one of these circles is pruned - `safeZones`: Vehicles inside these zones are excluded from the cleanup sweep. - `keepPlates`: Plate fragments immune to the sweep. Partial match, case-insensitive - `keepModels`: Spawn names the sweep never touches - `schedule`: When to run, on the server clock. `day` is optional (`0` = Sunday through `6` = Saturday) - `runOnStart`: Run one pass a few seconds after the resource boots The sweep can also be triggered from another resource with the `RunCleanup` export. ## My Vehicles **shared/config.lua** ```lua Config.MyVehicles = { enabled = true, command = 'myvehicles', item = false, } ``` A small panel where a player sees the vehicles they have parked: plate, model and, when `Config.MaxVehiclesPerPlayer` is set, how many of their slots are in use. It carries no positions and no waypoints on purpose, so knowing where a car sits stays the job of the GPS item and can be taken away from a player by stealing the tracker. - `enabled`: `false` removes the panel, the command and the item binding - `command`: Chat command that opens the panel. Rename it, or set it to `false` to leave players with the item only - `item`: Optional usable item that opens the same panel, for a registration papers prop. `false` leaves it command-only. Any item already registered in your inventory works, nothing to install ## GPS Item **shared/config.lua** ```lua Config.GpsItem = 'vehicle_gps' ``` - `GpsItem`: Usable item that lists the owner's persisted and garaged vehicles and sets a waypoint. Set to `false` to disable ## GPS Scanner **shared/config.lua** ```lua Config.GpsScanner = { enabled = true, scannerItem = 'gps_scanner', moduleItem = 'gps_module', range = 8.0, tamperTime = 6000, installTime = 5000, scanSeconds = 20, consumeScannerOnTamper = false, screen = true, anim = { dict = 'cellphone@', name = 'cellphone_text_read_base', weapon = 'weapon_digiscanner', bone = 28422, offset = vector3(0.0, 0.0, 0.0), rot = vector3(0.0, 0.0, 0.0) }, workAnim = { dict = 'anim@amb@clubhouse@tutorial@bkr_tut_ig3@', name = 'machinic_loop_mechandplayer' }, beep = { name = 'IDLE_BEEP', set = 'EPSILONISM_04_SOUNDSET', range = 5.0 }, } ``` A thief sweeps around a vehicle with the scanner item; the closer they get, the faster it beeps. Holding the scan rips the GPS out, and the owner's GPS item then freezes on the last known position with a tampered badge until a new module is installed on the recovered vehicle. - `enabled`: Master switch for the scanner and tamper feature - `scannerItem`: Reusable detector and remover carried by the thief - `moduleItem`: Consumed by the owner to reinstall a removed GPS - `range`: Meters at which the scanner picks a vehicle up - `tamperTime`: Milliseconds held next to the vehicle to rip the GPS out - `installTime`: Milliseconds held to install a new module - `scanSeconds`: How long one scanner use stays active - `consumeScannerOnTamper`: Also burn one scanner item per removal - `screen`: Draw the live proximity bars on the device screen - `anim`: Device held in hand while sweeping. `weapon` takes the device model straight from that weapon, so it does not break if the prop name changes. `bone` is the attach bone - `workAnim`: Animation played while ripping the GPS out or bolting a new module in - `beep`: Scanner sound. Heard by anyone within `range` meters, so bystanders notice the sweep > **INFO:** Reinstalling > > Only the vehicle's owner can install a module. The GPS stays frozen until they do. ## Admin Panel **shared/config.lua** ```lua Config.AdminAcePermission = nil Config.Admin = { command = 'vpadmin', theme = 'default', minimizeKey = 'F9', } ``` - `AdminAcePermission`: Optional dedicated ACE node. `nil` grants access to any `ml_bridge` admin - `Admin.command`: Command that opens the panel - `Admin.theme`: Panel theme: `'default'`, `'wasteland'`, `'cyberpunk'`, `'noir'`, `'fantasy'` - `Admin.minimizeKey`: Key that hides and restores the panel (F1-F12 or a single letter/digit) ## Commands **shared/config.lua** ```lua Config.Commands = { list = 'vpcount', remove = 'vpremove', clear = 'vpclear', save = 'vpsave', demoSeed = 'vpseed', demoClear = 'vpdemoclear', } ``` - `list`: Print the persisted-vehicle count and the full list in the server console - `remove`: `/vpremove ` drops one vehicle from persistence - `clear`: `/vpclear` wipes every persisted vehicle. `/vpclear ` only clears persisted vehicles within that many meters of the admin - `save`: Force-save all tracked vehicles to the database - `demoSeed`: Seed synthetic persisted vehicles for an admin demo. Requires `Config.Demo.enabled`. - `demoClear`: Remove the synthetic demo dataset. Set a command name to false to disable it. The four maintenance commands also run from the server console and RCON. Demo commands require Config.Demo.enabled and admin access. ## Demo Data **shared/config.lua** ```lua Config.Demo = { enabled = true, defaultCount = 2573, maxCount = 2573, ownerPrefix = 'VPDEMO_', } ``` - `enabled`: Allow the admin demo commands. - `defaultCount`: Number of synthetic records added when no count is passed to the seed command. - `maxCount`: Upper limit for the seed command, also capped by available demo spawn points. - `ownerPrefix`: Prefix used for synthetic owner identifiers. ## UI Theme **shared/config.lua** ```lua Config.UITheme = { preset = nil, colors = { primary = nil, accent = nil, background = nil, surface = nil, text = nil, }, } ``` - `preset`: Resource UI preset, or nil to inherit the global preset. - `colors`: Optional CSS hex overrides for the listed UI colors. nil inherits the global value. ## Logging **server/config_server.lua** ```lua Config.DiscordWebhook = { Default = 'INSERT_WEBHOOK_LINK_HERE', Parked = 'INSERT_WEBHOOK_LINK_HERE', Claimed = 'INSERT_WEBHOOK_LINK_HERE', Removed = 'INSERT_WEBHOOK_LINK_HERE', Destroyed = 'INSERT_WEBHOOK_LINK_HERE', Impounded = 'INSERT_WEBHOOK_LINK_HERE', Restored = 'INSERT_WEBHOOK_LINK_HERE', SpawnFailed = 'INSERT_WEBHOOK_LINK_HERE', GpsTampered = 'INSERT_WEBHOOK_LINK_HERE', GpsInstalled = 'INSERT_WEBHOOK_LINK_HERE', AdminAction = 'INSERT_WEBHOOK_LINK_HERE', } Config.LogProvider = 'discord' ``` - Each action has its own webhook. Unset actions fall back to `Default` - `LogProvider`: `'discord'`, `'fivemanage'`, `'ox_lib'`, `'both'`, or `'all'` Set any webhook to `false` to disable that log entirely.