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
Most values are also editable live from the admin panel, where they are stored as overrides and survive restarts.
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.0= unlimited. When the limit is hit, the owner's oldest parked vehicle stops being persistentPersistDestroyed: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 = 150Persisted vehicles are held in memory and only spawned into the world when a player comes close, then despawned once everyone leaves. This is what allows hundreds of saved vehicles without filling the world with entities.
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: What happens when another resource deletes a persisted vehicle (an admin/dv, a garage, a cleanup script).falsetreats it as a real removal and drops the vehicle from persistence, so a plain/dvdeletes the car like every other script expects.truebrings it back on its saved spot, so a saved car can never be lost
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: Warn the owner when only one parking slot is leftonLimitReached: Warn the owner when the oldest vehicle drops out of persistence
World Vehicles
1Config.WorldVehicles = {
2 enabled = true,
3 countTowardLimit = true,
4 notifyOnClaim = true,
5}enabled: Any unowned vehicle becomes persistent when first driven; the first driver becomes its ownercountTowardLimit: Claimed vehicles count towardConfig.MaxVehiclesPerPlayernotifyOnClaim: Tell the player the vehicle is now theirs
Scripts that spawn temporary vehicles (missions, rentals) exclude them with exports.ml_vehicle_persistence:DoNotSave(plateOrNetId, reason).
Decay
1Config.Decay = {
2 enabled = false,
3 graceDays = 2,
4 bodyPerDay = 40.0,
5 enginePerDay = 40.0,
6 healthFloor = 150.0,
7}enabled: Parked vehicles lose health while untouched. Applied when the record is loaded at restartgraceDays: Days without a save before decay startsbodyPerDay: 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 = true,
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 owned vehicles throughOpenServer.ImpoundVehicle;'delete'removes them. Claimed vehicles are always deleted, since they have no garage recordimpoundLot: 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}Housekeeping sweep that drops persisted vehicles a server would rather not keep. Rules are read from the saved record, so a burnt-out or out-of-bounds vehicle is pruned even when nobody has it streamed.
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: Sanctuaries. A vehicle inside one is never pruned, whatever the other rules saykeepPlates: 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.
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 straight from that weapon, so it does not break if the prop name changes.boneis the attach boneworkAnim: Animation played while ripping the GPS out or bolting a new module inbeep: Scanner sound. Heard by anyone withinrangemeters, so bystanders notice the sweep
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 dedicated ACE node.nilgrants access to anyml_bridgeadminAdmin.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 full list 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 any command name to false to disable it. All four also run from the server console and RCON, where the admin panel is not reachable.
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'
Set any webhook to false to disable that log entirely.