Skip to Content
Resourcesqb-hotdogjob Reference

qb-hotdogjob

qb-hotdogjob is a stand-based selling job. The player pays a deposit for a hot dog stand, restocks it, sells to NPCs, and builds a hotdog reputation stored in player metadata. Returning the stand refunds the deposit.

It is one of the few QBCore job resources that writes to the reputation metadata rather than only granting money or items.

Before deploying it, read The sale price comes from the client. The payout event trusts a price argument sent by the client.

The manifest at the commit linked above declares version 1.5.0.

Dependencies and start order

From the manifest: @qb-core/shared/locale.lua and locales as shared scripts, PolyZone client.lua, BoxZone.lua, EntityZone.lua, plus client.lua and server.lua, with ui_page 'html/ui.html'.

From the implementation: qb-core for GetCoreObject({ 'Functions', 'Commands' }), player money, item, and reputation methods, and exports['qb-core']:ExploitBan.

Start order: qb-core, PolyZone, then qb-hotdogjob. The hotdog item must exist in your shared items list.

Configuration

KeyDefaultMeaning
Config.UseTargetfrom the UseTarget convarSet setr UseTarget true in server.cfg
Config.StandDeposit250Bank charge for the stand, refunded on return
Config.MyLevel1Starting level reference
Config.MaxReputation200Ceiling for the hotdog reputation
Config.LocationstableWhere a stand can be collected and placed
Config.StocktableRestock definitions

Commands and key mapping

BindingRegistered withNotes
letgostandRegisterCommand plus RegisterKeyMapping(..., 'keyboard', 'G')Client side, lets the player drop the stand. Players can rebind it in the FiveM settings menu
/removestandQBCore.Commands.Add(..., 'admin')Server side, admin only, removes a stuck stand

See Commands and key mappings for the difference between those two registration paths.

Server surface

HandlerKindArguments
qb-hotdogjob:server:HasMoneycallbacknone
qb-hotdogjob:server:BringBackcallbacknone
qb-hotdogjob:server:Sellnet eventcoords, amount, price
qb-hotdogjob:server:UpdateReputationnet eventquality

Deposit

HasMoney charges Config.StandDeposit from the bank and records the citizen ID in a server-side Bail table. BringBack refunds the same amount if that entry exists. The table is in memory only, so a server restart between taking and returning a stand loses the refund.

The sale price comes from the client

qb-hotdogjob:server:Sell is worth reading carefully, because it mixes good and bad practice in one handler:

RegisterNetEvent('qb-hotdogjob:server:Sell', function(coords, amount, price) local src = source local pCoords = GetEntityCoords(GetPlayerPed(src)) ... if #(pCoords - coords) > 4 then exports['qb-core']:ExploitBan(src, 'hotdog job') end local sellAmount = math.floor(tonumber(amount) or 0) local sellPrice = tonumber(price) or 0 if sellAmount <= 0 or sellPrice <= 0 then return end ... Player.AddMoney('cash', sellAmount * sellPrice, 'sold hotdog') end)

What it does right: it reads the ped position on the server, it verifies the player actually holds enough hotdog items, and it only pays after RemoveItem succeeds.

What it does not do: it never compares price against anything. sellPrice is only checked for being a positive number, so any positive value a client sends becomes the per-unit payout. The amount is bounded by the player’s real inventory, but the price is not bounded at all.

Two further details:

  • coords is the client’s claimed position, compared against the server-read pCoords. Because both endpoints come from opposite sides, this check does catch a naive teleport, but a client that forges coords to match its real position passes it.
  • The ExploitBan branch has no return, so execution continues into the sale on the same tick.

If you run this resource, clamp the price server side against your own table:

-- patched into server.lua local HOTDOG_UNIT_PRICE = 12 Player.AddMoney('cash', sellAmount * HOTDOG_UNIT_PRICE, 'sold hotdog')

Reputation

UpdateReputation accepts a quality string of exotic, rare, or common, granting 3, 2, or 1 reputation and clamping at Config.MaxReputation. It then sends the player’s full PlayerData.metadata['rep'] back to the client. quality is unvalidated beyond the three string comparisons, so a client can pick its own tier, but the per-call gain is capped at 3 and the total is capped by Config.MaxReputation.

Troubleshooting

SymptomLikely cause
Deposit not refundedThe Bail table is in memory. A restart between taking and returning clears it
Players earning implausible amountsThe price is accepted from the client. Clamp it
Bans during normal sellingThe claimed coords and the server-read position diverged by more than 4 units, which can happen on a laggy client
Stand stuck in the worldUse the admin /removestand command
Sale does nothingThe player does not hold enough hotdog items, or the item is missing from your shared items

Proposed manual smoke test

Not yet executed. On staging:

  1. Take a stand, confirm the bank charge, return it, confirm the refund.
  2. Restart the server between those two steps and confirm the refund is lost.
  3. Sell with an empty inventory and confirm nothing is paid.
  4. Confirm reputation increases and stops at Config.MaxReputation.
  5. After clamping the price, confirm the payout matches your own table.

Sources