Glitched Scripts
Trucking Job

Custom jobs

Create, track, and delete trucking jobs at runtime from other resources.

Use this when another resource should add a job card without you editing Config.Loads (a business script posting a one-off haul, a fuel import, an event). Permanent jobs belong in Config.Loads. The table shape is the same as Jobs & loads.

Jobs are inserted into gs_trucking_custom_jobs and loaded again on resource start. Without MySQL they exist in memory only and vanish on restart.

Create a job

Server only. Returns id, err. On failure id is nil and err is a string (name is required, load.model is required, …).

local id, err = exports['gs-trucking']:CreateJob({
    name = 'Port Run',
    description = 'Haul a flatbed from the docks.',
    icon = 'fas fa-box',
    requiredReputation = 0,
    cooldown = 10,
    illegal = false,
    highlight = true,
    load = {
        model = { `prop_boxpile_08a` },
        coords = {
            vector4(1223.21, -3125.05, 4.99, 89.16),
        },
        modelDist = 2.5,
    },
    trailer = {
        model = `trflat`,
        exactPos = true,
        loadCoords = vector4(1245.32, -3135.93, 5.98, 270.0),
        coords = {
            vector4(965.55, -3210.14, 5.9, 176.36),
        },
        dummy = { x = 0.0, y = -7.0, z = -1.2, rx = 0.0, ry = 0.0, rz = 90.0 },
        attachpoints = {
            { x = 0.0, y = 4.0, z = 0.39, rx = 0.0, ry = 0.0, rz = 0.0 },
        },
    },
    dropoff = {
        { coords = vector4(1121.46, -1461.07, 34.69, 268.21), payout = 2500 },
    },
}, {
    event = 'myresource:truckingUpdate', -- optional. stored and fired on every phase
})

if not id then
    print('CreateJob failed', err)
end

Required: name, load.model, load.coords, trailer.model, trailer.coords, and dropoff as a list of { coords, payout }. Hose, loader, illegal, and the rest of Config.Loads are optional. Missing icon becomes fas fa-truck.

opts.event (alias opts.callbackEvent) is a server event name in your resource. It is saved in the database with the job so it still fires after a restart.

IDs start at 100000 so they never collide with bundled Config.Loads indexes.

Players who pass HasPerm() get a phone / notify (custom_job_available) when the job is created. Anyone with the trucking app open gets the new card on the next refresh.

Listen for progress

Every custom job also fires the global server event gs-trucking:customJob with the same arguments, so you can listen without passing opts.event.

AddEventHandler('myresource:truckingUpdate', function(jobId, phase, data)
    -- data.id, data.phase, data.name
    -- data.source, data.identifier when a player is involved
    -- data.dropoff on enroute / finished (index into the job dropoff list)
    -- data.payout on finished

    -- phase:
    --   started            player accepted
    --   trailer_ready      trailer spawned
    --   trailer_attached   hitched
    --   at_load            trailer on the bay
    --   loading_done       cargo complete, waiting on dropoff
    --   enroute            dropoff assigned (illegal dispatch already fired)
    --   finished           delivered and paid
    --   cancelled          player cancel, timeout, destroyed trailer, or DeleteJob while active

    if phase == 'finished' then
        print(data.source, 'delivered', data.name, data.payout)
    elseif phase == 'cancelled' then
        print(data.source, 'abandoned', jobId)
    end
end)

These phases only fire for custom jobs (CreateJob), not for rows you typed into Config.Loads.

Other exports

local job = exports['gs-trucking']:GetJob(id)
-- nil if this id is not a custom job
-- job.definition = the Config.Loads-shaped table
-- job.creator = resource that called CreateJob
-- job.callbackEvent = opts.event or nil
-- job.busy, job.player, job.cooldown, job.started = live slot

local list = exports['gs-trucking']:GetCustomJobs() -- array of the same snapshots

-- Cancels anyone currently on it (UnFinished reputation), removes the job card, deletes the DB row
local ok, err = exports['gs-trucking']:DeleteJob(id)

Client checks

These cover any job, bundled or custom:

if exports['gs-trucking']:IsJobActive() then
    -- returns the job id (number). falsy when idle
end

local info = exports['gs-trucking']:JobInfo()
-- nil when idle
-- info.name, info.description
-- info.departure = load bay / cargo spawn (vector3)
-- info.destination = nil until dropoff is assigned, then that vector3

On this page