Browse docs

Fake Plate Integration

Integrate garages, vehicle keys, persistence systems, Police tools, and custom resources with real and displayed vehicle plates.

Sky Mechanic Job keeps two plate identities while a fake plate is active:

ValuePurpose
Real platePersistent ownership, garage database lookups, keys, and stored vehicle records
Display plateThe plate visible on the vehicle and to Police, radar, dispatch, cameras, and UI

A resource must deliberately choose which identity it needs. Do not apply the real-plate override to every resource.

Choose the plate by operation

The resource name alone does not decide which plate is correct. Choose the identity required by each operation:

OperationPlate identityRecommended integration
Garage, impound, or parking ownership and database lookupReal plateNative override or explicit helper
Vehicle key ownership, lock authorization, and plate-based key grant/removalReal plateNative override or explicit helper
Persistent trunk, glovebox, fuel, mileage, damage, tuning, or service data keyed by plateReal plateNative override or explicit helper
Police, dispatch, radar, camera, plate scanner, or player-facing observationDisplay plateNo native override
Resource that performs both persistent lookups and visible plate outputReal or display plate per operationExplicit helper functions
Garage that despawns and later respawns vehiclesReal plate plus fake-plate stateServer exports in addition to one of the lookup integrations
Load only one compatibility file in a consuming resource. Do not load both files together.

Native override for persistent-identity resources

Add the compatibility file to the resource that reads the vehicle plate, not to the Sky Mechanic Job manifest. This can be a garage, vehicle-key, inventory, fuel, mileage, persistence, or framework resource:

shared_script "@sky_mechanicjob/compat/fakeplates_realplate_native.lua"

dependency "sky_mechanicjob"

When the resource already has a shared_scripts block, add the compatibility file as its first entry and retain its existing entries:

shared_scripts {
    "@sky_mechanicjob/compat/fakeplates_realplate_native.lua",
    "config.lua"
}

dependency "sky_mechanicjob"

Place the compatibility entry before the consuming resource's own shared scripts. It makes calls to GetVehicleNumberPlateText(vehicle) inside that resource return the real plate while a Sky fake plate is active. It also patches common vehicle-property readers loaded by that resource.

FiveM gives every resource its own Lua environment. The override therefore affects only the resource that loads this file.

Patch the resource where the plate is first read. If resource A reads the display plate and passes that string to resource B, loading the override only in resource B cannot change the already-read value. Load it in resource A or use the explicit real-plate helper at the original read site.

Use the native override when every plate read in that resource should represent persistent identity, for example:

  • Granting, checking, or removing vehicle keys by plate
  • Looking up ownership before storing, selling, transferring, or impounding a vehicle
  • Opening persistent trunk or glovebox storage keyed by plate
  • Reading or writing persistent fuel, mileage, damage, tuning, or service records

Do not load this override in:

  • Police resources
  • Dispatch resources
  • Radar or speed-camera resources
  • Plate overlays
  • Other UI that should show the plate visible on the vehicle

Vehicle key resources

Vehicle key systems normally need the real plate so existing keys continue to work while a fake plate is installed. There are two common integration paths:

  1. If the vehicle-key resource calls GetVehicleNumberPlateText(vehicle) itself, load fakeplates_realplate_native.lua in that vehicle-key resource.
  2. If another resource reads the plate and then passes a string to a vehicle-key export or event, integrate the resource that performs that first read. The receiving key resource cannot recover the real plate from the display-plate string alone.

When the calling resource also displays the visible plate, use the explicit helper file instead of overriding every native read:

local real_plate = SkyGetVehicleRealPlateText(vehicle)

exports["your_vehiclekeys"]:GiveKeys(real_plate)

Replace the example resource and export names with the API of your installed vehicle-key resource. The important part is resolving real_plate while the vehicle entity is available, before passing the value across a resource boundary.

Explicit real/display plate helpers

Use the helper file when a resource must choose the identity per operation:

shared_script "@sky_mechanicjob/compat/fakeplates.lua"

dependency "sky_mechanicjob"

The file provides these functions inside the consuming resource:

FunctionReturns
SkyGetVehicleDisplayPlateText(vehicle)The currently displayed plate
SkyGetVehicleRealPlateText(vehicle)The persistent real plate
SkyGetVehicleFakePlateState(vehicle)Active fake-plate metadata, or nil
local real_plate = SkyGetVehicleRealPlateText(vehicle)
local display_plate = SkyGetVehicleDisplayPlateText(vehicle)
local fake_plate = SkyGetVehicleFakePlateState(vehicle)

Use real_plate for ownership and database keys. Use display_plate for player-facing labels and observations.

The helper file is the safer choice for mixed resources. A garage menu, for example, may need the real plate for its database query but the display plate in a nearby-vehicle label. A key resource may need the real plate for authorization but the display plate in a notification.

Persist fake plates through garage storage

The compatibility file corrects plate reads, but it cannot persist entity state after the garage deletes the vehicle. A compatible garage must save the fake-plate state before despawning the entity and restore it after the new networked vehicle exists.

Store

Run this on the server while the vehicle entity still exists:

local resolved = exports["sky_mechanicjob"]:ResolveRealPlateForGarageStore(net_id)

if resolved then
    vehicle_data.plate = resolved.realPlate

    if resolved.resetOnGarageStore then
        exports["sky_mechanicjob"]:ClearFakePlate(net_id, "garage_store")
        vehicle_data.skyFakePlate = nil
    else
        vehicle_data.skyFakePlate = exports["sky_mechanicjob"]:GetFakePlateState(net_id)
    end
end

Persist vehicle_data.skyFakePlate with the garage's other vehicle properties. Never replace the persistent database plate with displayPlate.

Restore

After the garage has spawned the vehicle and its network ID resolves to an existing server entity:

if vehicle_data.skyFakePlate then
    local restored, result = exports["sky_mechanicjob"]:RestoreFakePlateState(
        net_id,
        vehicle_data.skyFakePlate,
        "garage_spawn"
    )

    if not restored then
        print(("[garage] Fake plate restore failed: %s"):format(tostring(result)))
    end
end

RestoreFakePlateState validates the real plate, display plate, active state, vehicle entity, and expiry time. An expired fake plate is not restored.

Configuration

Config.FakePlates.resetOnGarageStore controls the intended storage policy:

ValueBehavior
trueStoring the vehicle removes the fake plate
falseA compatible garage may save and restore the fake plate

The default in version 1.20.0 is false.

Test checklist

  • Store a normal vehicle and confirm its database plate is unchanged.
  • Install a fake plate and confirm the garage still finds the vehicle by its real plate.
  • Confirm keys granted before the fake plate was installed still lock, unlock, and start the vehicle.
  • Grant and remove keys while the fake plate is active and confirm the key resource uses the real plate.
  • Confirm plate-keyed storage and persistence resources do not create new records under the display plate.
  • Confirm Police, radar, dispatch, and visible UI continue to show the display plate.
  • Store and respawn the vehicle and confirm the configured reset/persist policy is respected.
  • Confirm expired fake plates are not restored.
  • Restart each consuming resource and verify its dependency starts after sky_mechanicjob.