Skip to Content
Resourcesqb-jewelery Reference

qb-jewelery

qb-jewelery is the jewelry store robbery. Players smash display cases, each case grants one item drawn from a weighted table, and the whole store locks out for a configured timeout afterwards.

Three spellings, and which one to use where

This resource is spelled inconsistently upstream. All three forms are correct in their own place:

ContextSpelling
Repository and resource folder nameqb-jewelery, one l
Every event, callback, and namespace inside the codeqb-jewellery:, two l
The official documentation page and the qb-scoreboard activity keyqb-jewelry and jewellery respectively

Use qb-jewelery when cloning and in server.cfg. Use qb-jewellery: when writing an event handler. The activity key that qb-scoreboard expects is jewellery, which is what this resource sends.

The manifest at the commit linked above declares version 1.5.0.

There is no qbcore-fivem/qb-jewelry repository. A link using that spelling will 404.

Dependencies and start order

From the manifest:

  • Shared: @qb-core/shared/locale.lua, locale/*.lua, config.lua
  • Client: @PolyZone/client.lua, @PolyZone/BoxZone.lua, client.lua
  • Server: @oxmysql/lib/MySQL.lua, server.lua

From the implementation, additionally: qb-core exports, qb-inventory for AddItem and the item box, and qb-log for the ban log entry.

Start order: oxmysql, qb-core, PolyZone, qb-inventory, then qb-jewelery.

Configuration

KeyDefaultMeaning
Config.UseTargetGetConvar('UseTarget', 'false') == 'true'Set setr UseTarget true in server.cfg rather than editing the file
Config.Timeout30 * (60 * 2000)Milliseconds before display cases reset. The shipped expression evaluates to 3,600,000 ms, which is 60 minutes, not the 30 the shape of the expression suggests
Config.RequiredCops2On-duty law enforcement required
Config.JewelleryLocationtableStore position
Config.WhitelistedWeaponstableWeapons that can break a case
Config.VitrineRewardstableItem pool with per-entry probability and amount.min / amount.max
Config.LocationstableIndividual display cases with coords, isOpened, isBusy

Duty counting here accepts job.name == 'police' or job.type == 'leo', so custom law enforcement jobs count as long as their type is leo.

Persistence

This resource has no table of its own and ships no SQL file, but it writes to the bans table:

INSERT INTO bans (name, license, discord, ip, reason, expire, bannedby) VALUES (?, ?, ?, ?, ?, ?, ?)

That table comes from your framework or admin stack, not from this resource. Confirm it exists with those seven columns before enabling the resource, otherwise the ban path errors instead of banning. Bans are written with expire = 2147483647 and bannedby = 'qb-jewelery'.

Server surface

HandlerKindArguments
qb-jewellery:server:getCopscallbacknone, returns the on-duty count and caches it per source
qb-jewellery:server:getVitrineStatecallbacknone, returns Config.Locations
qb-jewellery:server:vitrineRewardnet eventvitrineIndex
qb-jewellery:server:setVitrineStatenet eventstateType, state, k
qb-jewellery:server:setTimeoutnet eventnone

Reward validation

vitrineReward is unusually aggressive compared to the other robbery resources. At this commit it:

  1. Permanently bans the source if the index is unknown or the case is already opened.
  2. Drops the source if getCops was never called first, because the cached police count is nil.
  3. Requires the cached police count to be at least Config.RequiredCops.
  4. Requires the player to be within 25.0 units of the case coordinates.

Failures of steps 3 and 4 increment a per-license flag counter and drop the player. At three flags it escalates to a permanent ban.

Two consequences to plan for:

  • The police count is whatever the client last caused to be cached through the callback. A player who calls the callback while enough officers are on duty, then robs after they log off, passes the check.
  • Step 1 is a ban, not a kick. A legitimate desync where two players open the same case can ban the second one. Test this before going live on a busy server.

At this commit the escalation branch calls exploitBan with a single argument, so the value lands in the function’s id parameter and reason is nil. That call path does not behave as the surrounding code reads. Treat the three-flag escalation as untested upstream and rely on the earlier checks.

Timeout and scoreboard

setTimeout sets the store busy on qb-scoreboard under the key jewellery, waits Config.Timeout, resets every case to not-opened, clears the alert, and marks the activity free again. It guards against overlapping timers with a module-level timeOut flag, but the event itself is a RegisterNetEvent with no source check, so any client can start the timeout.

Integration example

Reading the current case state from your own client resource:

-- client side QBCore.Functions.TriggerCallback('qb-jewellery:server:getVitrineState', function(locations) for index, case in pairs(locations) do if not case.isOpened then print(('case %s is still intact'):format(index)) end end end)

Troubleshooting

SymptomLikely cause
Players banned during a normal robberyTwo players triggered the same case, or a case index arrived that is not in Config.Locations. Check the bans table for bannedby = 'qb-jewelery'
”Exploiting” drops with no banThe client never ran the getCops callback, so the cached count was nil
Server error on banThe bans table is missing or has different columns
Cases never resetsetTimeout was never fired, or timeOut is still true from a prior run. Restarting the resource resets in-memory state
Scoreboard never shows jewellery as busyqb-scoreboard is not started, or its Config.IllegalActions no longer has the jewellery key
Nothing happens when hitting a caseThe equipped weapon is not in Config.WhitelistedWeapons

Proposed manual smoke test

Not yet executed. On staging, and with a database backup:

  1. Confirm the bans table exists with the seven columns listed above.
  2. Rob one case with enough officers on duty and confirm the reward arrives.
  3. Confirm the case cannot be robbed twice, and check whether that path bans you.
  4. Confirm qb-scoreboard shows jewellery busy, then free after Config.Timeout.
  5. Review bans afterwards and clear any test bans.

Sources