Configuration
Overview
shared/config.lua: persistence behavior, world streaming, world-vehicle claiming, decay, cleanup, GPS items, admin panelserver/config_server.lua: Discord webhooks and log provideropen/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
1Config.Debug = false
2Config.locale = 'en'
3Config.PersistThroughRestart = true
4Config.MaxVehiclesPerPlayer = 5
5Config.PersistDestroyed = falseDebug: Prints gate decisions and lifecycle events to the server consolelocale: Active language. Files live inlocales/PersistThroughRestart: Respawn every persisted vehicle in its saved spot after a server restartMaxVehiclesPerPlayer: 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:truebrings a wreck back as a wreck (burnt body, dead engine, burst tyres) on respawn and after a restart.falsedrops a destroyed vehicle from persistence for good
World Streaming
1Config.SpawnDistance = 250.0
2Config.ScanInterval = 5
3Config.SpawnStaggerMs = 150The 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 thisScanInterval: Seconds between world scans. Lower is snappier for spawns and position updates, higher is lighter on the serverSpawnStaggerMs: Delay in milliseconds between two vehicle spawns inside a scan, to spread the load
External Deletes
1Config.RespawnOnExternalDelete = falseRespawnOnExternalDelete: Controls what happens when another resource deletes a persisted vehicle (an admin/dv, a garage, a cleanup script).falseremoves the saved record, including when an admin uses/dv.truerespawns the vehicle at its saved position unless the deletion uses the delete hook or PurgeVehicle export.
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
1Config.PersistTypes = {
2 automobile = true,
3 bike = true,
4 bicycle = true,
5 quadbike = true,
6 amphibious_automobile = true,
7 amphibious_quadbike = true,
8 submarinecar = true,
9 boat = true,
10 heli = true,
11 blimp = true,
12 plane = true,
13 submarine = false,
14 trailer = true,
15}- Only categories set to
trueare persisted. The key is the server-side vehicle archetype
1Config.BlacklistedModels = {
2 -- 'police', 'ambulance',
3}
4
5Config.BlacklistedPlates = {
6 -- 'MECH', 'RENT',
7}BlacklistedModels: Spawn names that never persist, even when player-ownedBlacklistedPlates: Plate fragments that never persist. Partial match, case-insensitive, made for job and rental prefixes
Notifications
1Config.Notifications = {
2 onParked = false,
3 onLimitWarning = true,
4 onLimitReached = true,
5}onParked: Popup on every park confirming the vehicle will stayonLimitWarning: 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 rowonLimitReached: Warn the owner when a new vehicle cannot be saved because the limit is full.
World Vehicles
1Config.WorldVehicles = {
2 enabled = true,
3 countTowardLimit = true,
4 notifyOnClaim = true,
5}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 towardConfig.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
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
1Config.BaseIntegration = {
2 enabled = true,
3 protectInBase = true,
4 blockStoreDuringRaid = true,
5 crewGps = true,
6}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
1Config.Decay = {
2 enabled = false,
3 graceDays = 2,
4 bodyPerDay = 40.0,
5 enginePerDay = 40.0,
6 healthFloor = 150.0,
7}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 periodenginePerDay: Engine health lost per day after the grace periodhealthFloor: Decay never drops health below this value. A vehicle already saved below the floor is left alone
Orphaned Vehicles
1Config.OrphanedVehicles = {
2 enabled = false,
3 thresholdDays = 7,
4 action = 'impound',
5 impoundLot = 'impound',
6 feePerDay = 100,
7 maxFee = 1500,
8}enabled: Clean up vehicles whose owner has not been seen forthresholdDaysthresholdDays: Days of owner absence before a vehicle is orphanedaction: 'impound' routes database-owned vehicles through OpenServer.ImpoundVehicle; 'delete' removes them. With 'impound', claimed World Vehicles stay in persistence; only 'delete' removes them.
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 hookfeePerDay: Fee charged per orphaned daymaxFee: Maximum impound fee
Cleanup
1Config.Cleanup = {
2 enabled = false,
3 engineBelow = nil,
4 underZ = nil,
5 clearZones = {
6 -- { coords = vector3(0.0, 0.0, 0.0), radius = 20.0 },
7 },
8 safeZones = {
9 -- { coords = vector3(0.0, 0.0, 0.0), radius = 20.0 },
10 },
11 keepPlates = {
12 -- 'STAFF',
13 },
14 keepModels = {
15 -- 'adder',
16 },
17 schedule = {
18 -- { hour = 4, minute = 0 },
19 -- { day = 3, hour = 16, minute = 0 },
20 },
21 runOnStart = false,
22}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 sweepengineBelow: Prune vehicles whose engine dropped to or under this value. A dead engine sits around0, a blown-up one goes deeply negative.nilkeeps every vehicleunderZ: Prune vehicles that ended up under this height, for cars dropped through the map or sunk.nilto skipclearZones: Any vehicle sitting inside one of these circles is prunedsafeZones: Vehicles inside these zones are excluded from the cleanup sweep.keepPlates: Plate fragments immune to the sweep. Partial match, case-insensitivekeepModels: Spawn names the sweep never touchesschedule: When to run, on the server clock.dayis optional (0= Sunday through6= 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
1Config.MyVehicles = {
2 enabled = true,
3 command = 'myvehicles',
4 item = false,
5}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:falseremoves the panel, the command and the item bindingcommand: Chat command that opens the panel. Rename it, or set it tofalseto leave players with the item onlyitem: Optional usable item that opens the same panel, for a registration papers prop.falseleaves it command-only. Any item already registered in your inventory works, nothing to install
GPS Item
1Config.GpsItem = 'vehicle_gps'GpsItem: Usable item that lists the owner's persisted and garaged vehicles and sets a waypoint. Set tofalseto disable
GPS Scanner
1Config.GpsScanner = {
2 enabled = true,
3 scannerItem = 'gps_scanner',
4 moduleItem = 'gps_module',
5 range = 8.0,
6 tamperTime = 6000,
7 installTime = 5000,
8 scanSeconds = 20,
9 consumeScannerOnTamper = false,
10 screen = true,
11 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) },
12 workAnim = { dict = 'anim@amb@clubhouse@tutorial@bkr_tut_ig3@', name = 'machinic_loop_mechandplayer' },
13 beep = { name = 'IDLE_BEEP', set = 'EPSILONISM_04_SOUNDSET', range = 5.0 },
14}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 featurescannerItem: Reusable detector and remover carried by the thiefmoduleItem: Consumed by the owner to reinstall a removed GPSrange: Meters at which the scanner picks a vehicle uptamperTime: Milliseconds held next to the vehicle to rip the GPS outinstallTime: Milliseconds held to install a new modulescanSeconds: How long one scanner use stays activeconsumeScannerOnTamper: Also burn one scanner item per removalscreen: Draw the live proximity bars on the device screenanim: Device held in hand while sweeping.weapontakes the device model from that weapon.boneis the attach boneworkAnim: Animation played while ripping the GPS out or bolting a new module inbeep: scanner sound, heard by anyone withinbeep.rangemeters
Only the vehicle's owner can install a module. The GPS stays frozen until they do.
Admin Panel
1Config.AdminAcePermission = nil
2Config.Admin = {
3 command = 'vpadmin',
4 theme = 'default',
5 MinimizeKey = 'F9',
6}AdminAcePermission: optional ACE that grants panel access in addition toml_bridgeadminsAdmin.command: Command that opens the panelAdmin.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
1Config.Commands = {
2 list = 'vpcount',
3 remove = 'vpremove',
4 clear = 'vpclear',
5 save = 'vpsave',
6}list: print the persisted vehicle count and the first 50 vehicles in the server consoleremove:/vpremove <plate>drops one vehicle from persistenceclear:/vpclearwipes every persisted vehicle./vpclear <radius>only clears persisted vehicles within that many meters of the adminsave: Force-save all tracked vehicles to the database
Set a command name to false to disable it. The commands also run from the server console and RCON, except /vpclear <radius>, which needs an admin in game.
UI Theme
1Config.UITheme = {
2 preset = nil,
3 colors = {
4 primary = nil,
5 accent = nil,
6 background = nil,
7 surface = nil,
8 text = nil,
9 },
10}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
1Config.DiscordWebhook = {
2 Default = 'INSERT_WEBHOOK_LINK_HERE',
3 Parked = 'INSERT_WEBHOOK_LINK_HERE',
4 Claimed = 'INSERT_WEBHOOK_LINK_HERE',
5 Removed = 'INSERT_WEBHOOK_LINK_HERE',
6 Destroyed = 'INSERT_WEBHOOK_LINK_HERE',
7 Impounded = 'INSERT_WEBHOOK_LINK_HERE',
8 Restored = 'INSERT_WEBHOOK_LINK_HERE',
9 SpawnFailed = 'INSERT_WEBHOOK_LINK_HERE',
10 GpsTampered = 'INSERT_WEBHOOK_LINK_HERE',
11 GpsInstalled = 'INSERT_WEBHOOK_LINK_HERE',
12 AdminAction = 'INSERT_WEBHOOK_LINK_HERE',
13}
14Config.LogProvider = 'discord'- Each action has its own webhook. Unset actions fall back to
Default LogProvider:'discord','fivemanage','ox_lib','both', or'all'
An action without a valid URL uses Default. With no valid URL at all, nothing is logged, whatever the provider.