Configuration

8 min readUpdated Today

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

Most values are also editable live from the admin panel, where they are stored as overrides and survive restarts.

General

shared/config.lua
1Config.Debug = false
2Config.locale = 'en'
3Config.PersistThroughRestart = true
4Config.MaxVehiclesPerPlayer = 5
5Config.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. 0 = unlimited. When the limit is hit, the owner's oldest parked vehicle stops being persistent
  • 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
1Config.SpawnDistance = 250.0
2Config.ScanInterval = 5
3Config.SpawnStaggerMs = 150

Persisted 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 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
1Config.RespawnOnExternalDelete = false
  • RespawnOnExternalDelete: What happens when another resource deletes a persisted vehicle (an admin /dv, a garage, a cleanup script). false treats it as a real removal and drops the vehicle from persistence, so a plain /dv deletes the car like every other script expects. true brings it back on its saved spot, so a saved car can never be lost
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
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 true are persisted. The key is the server-side vehicle archetype
shared/config.lua
1Config.BlacklistedModels = {
2    -- 'police', 'ambulance',
3}
4
5Config.BlacklistedPlates = {
6    -- 'MECH', 'RENT',
7}
  • 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
1Config.Notifications = {
2    onParked       = false,
3    onLimitWarning = true,
4    onLimitReached = true,
5}
  • onParked: Popup on every park confirming the vehicle will stay
  • onLimitWarning: Warn the owner when only one parking slot is left
  • onLimitReached: Warn the owner when the oldest vehicle drops out of persistence

World Vehicles

shared/config.lua
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 owner
  • countTowardLimit: Claimed vehicles count toward Config.MaxVehiclesPerPlayer
  • notifyOnClaim: Tell the player the vehicle is now theirs
Opt a vehicle out

Scripts that spawn temporary vehicles (missions, rentals) exclude them with exports.ml_vehicle_persistence:DoNotSave(plateOrNetId, reason).

Decay

shared/config.lua
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 restart
  • graceDays: Days without a 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
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 for thresholdDays
  • thresholdDays: Days of owner absence before a vehicle is orphaned
  • action: 'impound' routes owned vehicles through OpenServer.ImpoundVehicle; 'delete' removes them. Claimed vehicles are always deleted, since they have no garage record
  • impoundLot: Impound lot name passed to the hook
  • feePerDay: Fee charged per orphaned day
  • maxFee: Maximum impound fee

Cleanup

shared/config.lua
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 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: Sanctuaries. A vehicle inside one is never pruned, whatever the other rules say
  • 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.

GPS Item

shared/config.lua
1Config.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
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 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
Reinstalling

Only the vehicle's owner can install a module. The GPS stays frozen until they do.

Admin Panel

shared/config.lua
1Config.AdminAcePermission = nil
2Config.Admin = {
3    command     = 'vpadmin',
4    theme       = 'default',
5    minimizeKey = 'F9',
6}
  • 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
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 console
  • remove: /vpremove <plate> drops one vehicle from persistence
  • clear: /vpclear wipes every persisted vehicle. /vpclear <radius> only clears persisted vehicles within that many meters of the admin
  • save: 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

server/config_server.lua
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.