Server functions for callbacks, players, jobs, money and licences.
They work the same on ESX, QBCore, QBX and a custom framework.

## Callbacks

```lua
-- The handler returns its answer (several values are fine) and may yield.
ObsiLib.callback.register('my_script:getPrice', function(source, itemName)
    return Prices[itemName] or 0
end)

ObsiLib.callback.unregister('my_script:getPrice')
ObsiLib.callback.call('my_script:getPrice', source, 'water')   -- run a handler directly

-- Ask a handler registered on the client and wait for the answer.
local heading = ObsiLib.callback.awaitClient(source, 'my_script:heading', nil, 5000)
```

:::hint{type="success" title="Built-in protection"}
Each player can have at most 32 requests in flight.
Answers to `awaitClient` are only accepted from the player who was asked.
:::

## Players

```lua
ObsiLib.player.get(source)                -- xPlayer / QBCore Player / custom object
ObsiLib.player.list()                     -- { 1, 4, 7 }
ObsiLib.player.identifier(source)         -- ESX identifier / citizenid
ObsiLib.player.name(source)               -- 'John Smith'
ObsiLib.player.group(source)              -- 'admin'
ObsiLib.player.gender(source)             -- 'male' | 'female'
ObsiLib.player.fromIdentifier('ABC123')   -- source or nil
ObsiLib.player.isAdmin(source)            -- ACE, identifiers and groups from ObsiConfig.Admin
ObsiLib.player.isAdmin(source, { ace = 'myscript.admin', groups = { 'god' }, identifiers = { 'discord:123' } })
```

## Jobs

```lua
local job = ObsiLib.job.get(source)       -- { name, label, grade, gradeLabel, onDuty }
ObsiLib.job.is(source, 'police')          -- also takes { 'police', 'sheriff' } or { police = true }
ObsiLib.job.set(source, 'mechanic', 2)
ObsiLib.job.setOffline('ABC123', 'unemployed', 0)   -- uses job.set when the character is online
ObsiLib.job.setDuty(source, true)
ObsiLib.job.all()                         -- { police = { label, type, grades = { [0] = { label, payment, isboss } } } }
ObsiLib.job.copsOnline()                  -- jobs from ObsiConfig.PoliceJobs
```

`copsOnline` counts only officers on duty when `ObsiConfig.CopsRequireDuty` is `true`.

## Money

Accounts are `'cash'` (default), `'bank'`, `'black'`, or any account name your framework knows.

```lua
ObsiLib.money.get(source, 'bank')
ObsiLib.money.add(source, 250, 'cash', 'job payout')
ObsiLib.money.remove(source, 100, 'bank', 'fine')   -- false when the balance is too low
ObsiLib.money.has(source, 1000, 'cash')
```

## Licences

```lua
ObsiLib.license.has(source, 'weapon')   -- esx_license on ESX, metadata.licences on QBCore / QBX
```
