Developer
Overview
Other resources integrate through server exports and the open/server.lua hooks. Exports coordinate with garages, tow jobs, mechanics and dealerships so a vehicle is never saved or deleted twice. The open/ folder holds the ownership and garage-state logic, which the server owner adapts to their framework.
Server Exports
Coordination
DoNotSave(plateOrNetId, reason?): Exclude a vehicle from persistence and remove it if already tracked. Accepts a plate, a network id, or an entity handleExcludeFromPersistence(plateOrNetId, reason?): Alias ofDoNotSaveRemoveExclusion(plate): Clear an exclusionIsExcludedFromPersistence(plate): Returnstrueif excludedLockVehicle(plate): Temporarily block persistence (during towing, mechanic work). Auto-expires after 5 minutesUnlockVehicle(plate): Release a lockIsVehicleLocked(plate): Returnstrueif locked
Vehicle Control
PurgeVehicle(plateOrNetId, keepInWorld?): Remove a vehicle from persistence. Despawns it unlesskeepInWorldistrueUpdateVehicle(plateOrNetId): Force a save and refresh the vehicle's stored properties from its owner clientClaimVehicle(plateOrNetId, src): Register a vehicle as persistent and owned by the playersrcTransferPersistedVehicle(plate, newOwner): Reassign a persisted vehicle to another owner identifierPurgeOwner(ownerId): Remove every persisted vehicle belonging to an identifier. Returns the count removedSetVehiclePlate(plateOrNetId, newPlate): Move persistence to a new plate after a plate changeRemovePersistedVehicle(plate): Drop a vehicle from persistence, keeping it in the world
Pause
PausePersistence(state): Pause or resume all saving and claiming. Returns the new stateIsPersistencePaused(): Returns the current pause state
Maintenance
RunCleanup(): Run theConfig.Cleanupsweep once, outside its schedule. Returns the number of vehicles removed
Query
IsVehiclePersisted(plate): Returnstrueif the plate is persistedGetWorldVehicles(): Returns every tracked vehicleGetVehicleStatus(plate): Returns{ isPersisted, isExcluded, isLocked, exclusion, lock, vehicle }GetVehicleCoords(plate): Returns the live or saved coordinates of a persisted vehicle. Always the real position, even when the owner's GPS is tamperedGetVehiclesCoords(plates): Returns a map of plate to coordinates
Client Exports
PurgeVehicle(plateOrNetId): Drop a vehicle from persistence and delete it from the client side. Used by resources that delete vehicles on the client. Returnstruewhen the request was accepted
Deleting Vehicles From Another Resource
With Config.RespawnOnExternalDelete = false (the default) nothing is needed: a plain DeleteEntity or an admin /dv drops the vehicle from persistence like every other script expects.
With Config.RespawnOnExternalDelete = true every delete is undone by the respawn engine unless it is routed through the script. Either call the PurgeVehicle export, or add the shipped hook as the first script line of the deleting resource:
1shared_script '@ml_vehicle_persistence/deletehook.lua'The hook replaces the DeleteEntity and DeleteVehicle natives. A resource that caches them in a local before the hook loads bypasses it, so the shared_script line must come before every other script entry.
The request is validated server-side: a tracked vehicle is only removed by an admin or by its own owner, and a locked vehicle is never touched.
Server Handlers
Located in open/server.lua.
CanPersist
1function OpenServer.CanPersist(src, vehicle, plate, owner)
2 return nil
3endOwnership gate before a vehicle becomes persistent. Return false to block, true to force-allow for custom ownership systems, nil for the default owned-vehicles check.
CanClaim
1function OpenServer.CanClaim(src, vehicle, plate)
2 return nil
3endGate before a world vehicle is claimed by its first driver. Return false to block the claim, for example to require a hotwire item.
FetchOwnedPlates
1function OpenServer.FetchOwnedPlates()
2 return {}
3endReturns an array of plate strings from the ownership database. Claiming never touches these plates. The default reads player_vehicles or owned_vehicles.
IsPlateOwned
1function OpenServer.IsPlateOwned(plate)
2 return false
3endAuthoritative single-plate check, consulted when a plate is missing from the cached registry, such as a car bought seconds earlier. Return true if the plate belongs to a player.
FetchGaragedVehicles
1function OpenServer.FetchGaragedVehicles(src, owner)
2 return {}
3endVehicles the player owns that are sitting in a garage right now, so the GPS item shows them as stored instead of a dead waypoint. Return an array of { plate, model?, garage? }. The garage value is shown to the player as-is, so raw ids can be mapped to friendly names here. The default reads player_vehicles with state = 1.
OnVehicleRestored
1function OpenServer.OnVehicleRestored(plate, owner)
2endFires for every vehicle put back into the world after a restart. The default marks the vehicle as out of the garage so garage scripts stay consistent.
ImpoundVehicle
1function OpenServer.ImpoundVehicle(plate, owner, fee, impoundLot)
2endOrphan cleanup with action = 'impound' routes here. Adapt it to your impound system.
Lifecycle Hooks
1function OpenServer.OnVehiclePersisted(plate, owner) end
2function OpenServer.OnVehicleClaimed(plate, owner, src) end
3function OpenServer.OnVehicleRemoved(plate, owner, reason) end
4function OpenServer.OnGpsTampered(plate, owner, src) end
5function OpenServer.OnGpsInstalled(plate, owner, src) endOnVehicleRemoved fires with reason one of: stored, excluded, destroyed, limit, entity_removed, impounded, orphan_deleted, owner_purged, cleanup, admin_remove, admin_clear, deleted_by_client_hook, removed_by_<resource>, deleted_by_<resource>.
OnGpsTampered fires when a thief rips a vehicle's GPS out with the scanner item; OnGpsInstalled fires when the owner restores live tracking with a module.
Client Handlers
Located in open/client.lua. These listen for garage store events and drop the stored vehicle from persistence. Add your garage's event here:
1function OpenClient.NotifyStored(plate)
2 TriggerServerEvent('ml_vehicle_persistence:server:vehicleStored', plate)
3endExamples
1local netId = NetworkGetNetworkIdFromEntity(vehicle)
2exports.ml_vehicle_persistence:DoNotSave(netId, 'mission')1exports.ml_vehicle_persistence:UpdateVehicle(plate)1exports.ml_vehicle_persistence:ClaimVehicle(netId, src)