qb-garbagejob
qb-garbagejob is a route-based job. The player pays a truck deposit, the server generates a
randomized route, and each completed stop accrues pay. The deposit is returned only if the whole
route is finished.
The distinguishing feature compared with the other jobs in this set is that route state and accrued
pay live on the server, keyed by citizenid, rather than being reported by the client at the end.
The manifest at the commit linked above declares version 1.5.0.
The README at this commit describes the rework: randomized stop count and stops, server-side reward tracking, an optional crypto stick find, and per-bag pay.
Dependencies and start order
From the manifest: @qb-core/shared/locale.lua and locales as shared scripts, the PolyZone client
files, client.lua, and server.lua.
From the implementation: qb-core for the core object, commands and player methods, and
qb-inventory for the crypto stick reward.
Start order: qb-core, qb-inventory, PolyZone, then qb-garbagejob.
Configuration
| Key | Default | Meaning |
|---|---|---|
Config.UseTarget | from the UseTarget convar | Set setr UseTarget true in server.cfg |
Config.Jobname | 'garbage' | The job name checked against |
Config.TruckPrice | 250 | Bank deposit charged at shift start, refunded on full completion |
Config.GiveCryptoStick | true | Enable the optional find |
Config.CryptoStickChance | 75 | See the note below, this is a threshold, not a percentage |
Config.MinStops | 5 | Lower bound on route length |
Config.MinBagsPerStop | 2 | Lower bound on bags at a stop |
Config.MaxBagsPerStop | 5 | Upper bound on bags at a stop |
Config.BagLowerWorth | 50 | Lower bound of pay per bag |
Config.BagUpperWorth | 100 | Upper bound of pay per bag |
Config.UsePreconfiguredRoutes | false | Use the fixed route list instead of randomizing |
Config.Peds | table | Job NPCs |
Config.Locations | table | Trashcan stops and depot |
Config.Vehicle | 'trash2' | Truck model |
Config.CryptoStickChance is compared as math.random(100) >= Config.CryptoStickChance, so the
default of 75 means roughly a 26 percent chance, not 75 percent. Lowering the number makes the find
more likely, which is the opposite of what the name suggests.
The maximum stop count is math.random(Config.MinStops, #Config.Locations['trashcan']), so it is
bounded by how many trashcan locations you configured.
Server surface
| Handler | Kind | Arguments | Returns |
|---|---|---|---|
qb-garbagejob:server:NewShift | callback | continue | shouldContinue, nextStop, bagNum, totalNumberOfStops |
qb-garbagejob:server:NextStop | callback | currentStop, currentStopNum, currLocation | shouldContinue, newStop, newBagAmount |
qb-garbagejob:server:EndShift | callback | none | status boolean |
qb-garbagejob:server:payDeposit | net event | none | |
qb-garbagejob:server:PayShift | net event | continue |
Route state
NewShift builds the route and stores it in a server-side Routes table keyed by citizenid:
Routes[CitizenId] = {
stops = allStops,
currentStop = 1,
started = true,
currentDistance = 0,
depositPay = Config.TruckPrice,
actualPay = 0,
stopsCompleted = 0,
totalNumberOfStops = #allStops
}NextStop verifies the player’s supplied currLocation against the configured coordinates of
currentStop and only advances when the distance is 20 or less. Pay accrues on the server from
Config.BagLowerWorth and Config.BagUpperWorth, not from anything the client sends.
currLocation is still a client-supplied value, so the distance check proves the client claims to be
near the stop rather than that it is. Reading the ped position on the server, as
qb-busjob does, would close that gap.
Payout
PayShift pays depositPay + actualPay into the bank with the reason garbage-payslip, then
clears the route. depositPay is zeroed when stopsCompleted is below totalNumberOfStops, or
when the player chose to continue with another route, so quitting early forfeits the deposit.
Note that the deposit charge and the shift start are two separate calls. NewShift checks the
player can pay, but the money is only removed by the separate payDeposit event. A client that
starts a shift without firing payDeposit gets a route for free and is still refunded
Config.TruckPrice at the end. If that matters, move the charge into the NewShift callback.
Admin command
/cleargarbroutes [id]Registered through QBCore.Commands.Add with the admin permission, it clears the stored route for
the given player ID. At this commit the handler calls GetPlayer(tonumber(args[1])) without a nil
check, so running it against an offline or invalid ID raises a server-side Lua error. See
Commands and key mappings for how permissions on these commands work.
Troubleshooting
| Symptom | Likely cause |
|---|---|
| ”Not enough money” at shift start | Bank balance below Config.TruckPrice |
| Deposit never refunded | stopsCompleted was below the route length, which is the intended behaviour for quitting early |
| Crypto sticks appear constantly or never | Config.CryptoStickChance is a threshold, see the note above |
| Route never advances | The client’s reported location was more than 20 units from the configured stop |
Server error on /cleargarbroutes | The target ID is not an online player |
| Route survives a disconnect | Routes is keyed by citizenid and has no playerDropped cleanup at this commit. Use the admin command to clear it |
Proposed manual smoke test
Not yet executed. On staging:
- Start a shift with insufficient bank funds and confirm the refusal.
- Complete a full route and confirm the deposit is refunded on top of the per-bag pay.
- Quit mid route and confirm only the accrued pay arrives.
- Disconnect mid route, reconnect, and confirm what happens to the stored route.
- Run
/cleargarbroutesagainst an online ID and confirm the count reported.