Script docs
Weapon Licenses
A theory test and a timed shooting exam for weapon licenses, graded on the server.

- Version
- v3.0.0
- Frameworks
- ESX · QBCore · Qbox
- Requires
- ox_lib, esx_license (ESX only)
- Source
- Escrow
- resmon
- 0.00 ms idle · 0.01 ms theory exam open
- Updated
- 6 Oct 2026
Weapon licenses earned the right way: a theory test and a timed shooting-range exam, plus an optional practice mode. ESX, QBCore and Qbox. Everything that grants a license is validated on the server.
Requirements
- ox_lib
- One framework: ESX (with
esx_license), QBCore or Qbox - Optional: ox_inventory (supported: the range weapon is enabled through its weapon wheel)
Install
- Drop
xex_weaponlicenseinto your resources folder. - ESX only: run
install/esx.sql(adds the two license types). - Add to
server.cfgafter your framework and ox_lib:ensure xex_weaponlicense - Set the language for UI and notifications with
setr ox:locale en(ores).
ox_inventory
Nothing to change. The range weapon works through ox_inventory’s public weaponWheel export, which pauses its
“weapon not in inventory” check for that player only while the exam or practice lasts. Do not add the range
weapon to inventory:ignoreweapons: that would let anyone hold that weapon without owning it.
If you used an older version that required editing ox_inventory, you can revert that change.
Configure
Everything lives in config.lua:
| Setting | What it does |
|---|---|
Config.Framework |
auto, or force esx / qb / qbox |
Config.Key |
Control that opens each point (38 = E) |
Config.Licenses |
License names. Change them to match your existing license system |
Config.RequiredLicense |
Optional license required before the theory test (e.g. a medical check) |
Config.UI |
Brand name, title, accent colour and optional rules link shown in the test |
Config.Theory |
Location, price, number of questions and correct answers needed |
Config.Practical |
Location, price, weapon, ammo, targets, time limit and countdown |
Config.Practice |
Optional training mode with its own price and settings |
Config.Range |
One player at a time or shared, exit point, target model, target positions and anti-cheat pace |
Texts (prompts, notifications, UI and blip names) are in locales/*.json. The theory test is only charged when the
player presses Start, so closing the intro is free.
Questions are in questions/<locale>.lua. They are loaded only on the server, so players can never read the answers.
Upgrading from v2 (ESX)
v2 used the license names theoretical_weapons and practical_weapons. Keep them so your players don’t lose their
licenses:
Config.Licenses = {
theory = 'theoretical_weapons',
practical = 'practical_weapons',
}
In that case you don’t need to run install/esx.sql. Delete the old resource folder before adding v3.
For developers
-- server
local hasLicense = exports.xex_weaponlicense:HasWeaponLicense(source)
bridge/server.lua is open: adapt it if you use a custom framework or license system.
Security
- The server picks the questions, grades the answers and grants the license.
- The shooting exam is started, charged and timed on the server; results that are too fast or too slow are rejected.
- Targets are local objects, so there is nothing to clean up and no entity can be deleted by other players.