Skip to Content
Resourcesqb-scoreboard Reference

qb-scoreboard

qb-scoreboard renders a panel showing the player count, the on-duty police count, and which illegal activities are currently available or busy. It also draws server IDs above nearby players who opted in.

It is a read-only display plus one shared busy flag. It does not gate any robbery itself. The robbery resources decide independently whether to run, and only some of them report their state back here. Compare with qb-hud, which shows the local player’s own status rather than server state.

The manifest at the commit linked above declares version 1.2.1.

Dependencies and start order

The manifest declares no dependency entry, but both scripts call exports['qb-core']:GetCoreObject({ 'Functions' }) at load time, so qb-core is a hard runtime dependency. Start qb-core first.

The server script also calls QBCore.Functions.IsOptin(source). That method exists in qb-core at commit 9b3cddc. On an older or forked core that lacks it, the callback errors and the panel never opens.

Configuration

config.lua is loaded as a shared_script, so both sides see the same table.

KeyDefaultMeaning
Config.Toggletruetrue registers a single scoreboard command that toggles. false registers +scoreboard and -scoreboard, so the panel is only visible while the key is held
Config.OpenKey'HOME'Default key passed to RegisterKeyMapping. Players can rebind it in the FiveM settings menu
Config.ShowIDforALLfalseWhen true, IDs are drawn above every nearby player regardless of their opt-in state
Config.MaxPlayersGetConvarInt('sv_maxclients', 48)Read from your server convar, not hardcoded
Config.IllegalActionstableActivity key to { minimumPolice, busy, label }

The shipped Config.IllegalActions keys are storerobbery, bankrobbery, jewellery, pacific, and paleto, with minimum police counts of 1, 3, 2, 5, and 4. These numbers are display values for this panel. Each robbery resource carries its own police requirement in its own config, so changing a number here does not change what a robbery actually permits. Keep the two in sync by hand.

Commands and key mapping

With Config.Toggle = true:

  • RegisterCommand('scoreboard', ...) toggles the panel.
  • RegisterKeyMapping('scoreboard', 'Open Scoreboard', 'keyboard', Config.OpenKey).

With Config.Toggle = false, +scoreboard and -scoreboard are registered instead and the mapping targets +scoreboard. See Commands and key mappings for why the plus and minus prefix pair behaves that way.

Server callback

QBCore.Functions.CreateCallback('qb-scoreboard:server:GetScoreboardData', function(_, cb)

Returns three values to the client, in this order:

PositionTypeContent
1numberTotal online QBCore players
2numberPlayers whose job.name is exactly police and whose job.onduty is true
3tableKeyed by player source, each entry { optin = <boolean> }

Note the duty count matches the literal job name police only. It does not use job.type == 'leo'. Other resources audited on this site, for example qb-jewelery and qb-truckrobbery, count either job.name == 'police' or job.type == 'leo'. If you run additional law enforcement jobs, the number shown here will be lower than the number those resources actually require.

Events

EventSideArguments
qb-scoreboard:server:SetActivityBusyserveractivity, bool
qb-scoreboard:client:SetActivityBusyclientactivity, busy

The server handler sets Config.IllegalActions[activity].busy and broadcasts the client event to everyone.

Integration example

Another server script marks an activity busy while it runs:

-- server side, inside your own resource TriggerEvent('qb-scoreboard:server:SetActivityBusy', 'bankrobbery', true) -- later, when the heist resets TriggerEvent('qb-scoreboard:server:SetActivityBusy', 'bankrobbery', false)

TriggerEvent on the server is the correct call here. The handler is registered with RegisterNetEvent, so it is also reachable from a client with TriggerServerEvent, and at this commit it performs no source check and no validation of activity or bool.

Two consequences worth planning for:

  • Any client can flip any activity’s busy flag for every player.
  • An activity key that is not in Config.IllegalActions raises a Lua error on the server, because the handler indexes the table without checking.

If that matters on your server, wrap the event in your own guarded handler and stop broadcasting the raw one, or validate activity against Config.IllegalActions before forwarding.

Troubleshooting

SymptomLikely cause
Panel does not openThe qb-scoreboard:server:GetScoreboardData callback errored. Check the server console, and confirm your qb-core build provides QBCore.Functions.IsOptin
Player count is right, police count is always 0Your law enforcement job is not literally named police, or nobody has job.onduty set
Max players shows 48 on a larger serversv_maxclients is not set before the resource starts, so the convar default is used
Client error about optin being nilA nearby player is not present in the opt-in table returned by the callback. This happens when the panel is open while a player joins
Activity always shows busySomething set the busy flag and never cleared it. Restarting the resource resets Config.IllegalActions to its file defaults

Proposed manual smoke test

Not yet executed. On staging:

  1. Open and close the panel with the configured key and with /scoreboard.
  2. Put one player on duty as police and confirm the count increments.
  3. Fire qb-scoreboard:server:SetActivityBusy for one activity and confirm every connected client sees it flip.
  4. Set Config.Toggle = false, restart, and confirm hold-to-view behaves.
  5. Set Config.ShowIDforALL = true and confirm IDs draw above nearby players.

Sources