π«Weapon Licenses & Shooting Range
Docs to configure licenses and shooting range

Overview
XeX Weapon License is a premium weapon licensing system for FiveM servers featuring a modern glassmorphism UI for theoretical tests and an interactive shooting range for practical exams. Players must pass a theoretical multiple-choice exam before being allowed to attempt the practical shooting test. An optional practice mode provides a timed shooting range experience.
Supported Frameworks
ESX Legacy
1.6.0+
β Full Support
QBCore
Latest
β Full Support
QBox
Latest
β Full Support
Features Summary
Core Features
UI
Glassmorphism Design
Modern dark translucent glass-effect test interface
UI
Multi-language
Dynamic EN/ES question banks and UI strings
UI
Interactive Options
Clickable card-based answer selection with visual feedback
UI
Animated Progress
Smooth progress bar with section transitions
UI
Result Screens
Animated pass/fail screens with SVG check/cross icons
UI
Countdown Overlay
Full-screen countdown timer before shooting tests
UI
Sound Effects
Countdown siren audio during test preparation
Test
Theoretical Exam
9-question multiple choice test with configurable pass threshold (5/9)
Test
Question Randomization
Questions selected randomly from the pool without repetition
Test
Practical Exam
Timed shooting range with random target spawns at 17 positions
Test
Configurable Timer
Adjustable seconds to complete practical test (0 = unlimited)
Practice
Shooting Practice
Optional practice mode (configurable price or free)
Practice
License Gate
Optionally require weapon license to access practice range
Security
Server Validation
License grants validated server-side with exam state tracking
Security
Anti-Exploit
Players must pay before receiving licenses β playerInExam state tracked
Security
Mutual Exclusion
Cannot be in test and practice simultaneously
Safety
Disarm on Exit
Auto-remove weapon if player leaves shooting area boundary
Safety
NUI Cleanup
Proper cleanup on resource stop to prevent stuck UI overlays
Safety
Target Cleanup
Smart cleanTargets β only removes target props within 30m of player
System
Auto Updater
JSON-based version checker with styled console banner output
System
Blip System
Configurable map blips for all 3 locations (theory, practical, practice)
Config
Fully Configurable
Prices, locations, timers, weapons, blips, target positions
Perf
Optimized
Sleep-based loops (1500ms idle), 1ms only near markers
Installation
Requirements
FiveM Server
ESX Legacy or QBCore
MySQL database (via oxmysql or mysql-async)
esx_license(ESX only β required for license storage)esx_menu_default(ESX only β required for confirmation menus)Optional:
qb-menu(QBCore β for confirmation dialogs)
Quick Start
Extract to your resources/[xex]/ folder and rename folder to 'xex_weaponlicense' if needed.
Import weapon_licenses.sql into your database (ESX only).
Add to server.cfg:
Configure config.lua (framework, prices, locations).
Restart the server.
Recommended Resource Order
Configuration
General Settings
DrawDistance
15.0
Distance in GTA units to start rendering markers and enabling interactions
Language
'en'
Controls all text: locales, UI strings, and question bank
CheckForUpdates
true
Checks GitHub Gist for new versions on startup
Framework Settings
'auto'
Auto-detect: QBCore β ESX (default)
'esx'
ESX Legacy
Requires esx_license for license storage
'qb'
QBCore
Uses player metadata for license storage
GetSharedObjectfunction
Behavior
true
Uses exports["es_extended"]:getSharedObject() (modern ESX)
false
Uses TriggerEvent('esx:getSharedObject', ...) (legacy ESX)
Theoretical Test
Price
15000
Cost in dollars. Set to 0 for free.
Location
vector3(22.0, -1107.2, 29.8)
World position for the interaction marker
Test Parameters (in ui/scripts.js):
nbQuestionToAnswer
9
Total questions per test attempt
nbAnswerNeeded
5
Minimum correct answers to pass
Practical Test
Price
85000
Cost in dollars. Player must have this in cash.
Location
vector3(14.39, -1097.57, 29.83)
Marker position for practical test
TimeToFailTest
12
Seconds to hit all targets. 0 = no time limit. Lower = harder.
TotalTargetsToEnd
10
Number of targets to hit to pass. Targets appear one at a time.
CountDownInterval
5
Seconds of countdown before test begins (5, 4, 3, 2, 1, GO!)
Practice Mode
Enabled
true
Show/hide the practice point entirely
NeedsLicenseToUse
false
When true, player must own practical_weapons license (ESX) or weapon license (QB)
Price
0
Cost per session. 0 = free.
SecondsToEndPractice
20
Duration in seconds. 0 = unlimited.
TotalTargetsToEnd
25
Maximum targets in a session
Weapon
'WEAPON_PISTOL'
Weapon provided during practice
Safety Settings
DisarmIfExits
true
Auto-remove weapon and end session if player approaches the exit door
DoorPointToDisarm
vector3(7.49, -1098.90, 28.80)
Coordinate that triggers disarm when within 1.3 units
Target Positions
The shooting range has 17 predefined target spawn positions. Targets appear randomly at one of these positions, never repeating the same position consecutively:
Blip Configuration
Each location (Theoretical, Practical, Practice) has its own blip settings:
Enabled
bool
Whether to show the blip on the map
Scale
float
Size of the blip icon
Color
int
GTA blip color index (0-85)
Sprite
int
GTA blip sprite ID
Location
vector3
World coordinates for blip placement
Database Setup
ESX Only
Run the SQL file included in the resource (weapon_licenses.sql):
This inserts two new license types into the existing licenses table used by esx_license.
QBCore
No SQL import needed. QBCore stores licenses in player metadata:
Note: QBCore uses
"weapon"(not"practical_weapons") for the practical license key.
How It Works
Complete Flow
Resource Start
ESX: Loads esx_license integration
Server initializes
shootingRangeFree = trueAuto updater checks for new version (5s delay)
Blips created on client for enabled locations
Player Loads (ESX only)
Server fetches player's existing licenses via esx_license
Sends license list to client via
xex_weaponlicense:loadLicensesClient builds
ownedLicensestable for local checks
Near Markers (Player approaches)
Sleep drops from 1500ms to 1ms for responsive interaction
Markers rendered (green arrow, type 2)
Help notification shows "Press [E] to start..."
All markers hidden during active sessions (mutual exclusion)
Theoretical Test
Player presses [E] near theory marker
Confirmation menu with price β Server validates payment
NUI opens with glassmorphism test UI
9 random questions from question bank
Pass (β₯5/9) β License granted server-side
Fail β Can retry (pay again)
Practical Test
Requires theoretical license first
Player presses [E] near practical marker
Server confirms payment + shooting range is free
Countdown (5, 4, 3, 2, 1...) with siren sound
Random targets spawn one at a time
Hit target β next target spawns at random position
Hit all 10 β Pass / Time runs out β Fail
Weapon removed, range freed
Practice Mode
Independent of license flow
Optional license requirement
Same shooting mechanics with different timer/target counts
License Flow (ESX)
Theoretical Test
Price: $15,000
9 questions, pass requires 5/9
On pass: grant
theoretical_weaponslicense (ESX)On fail: can retry (pay again)
Practical Test
Requires
theoretical_weaponsPrice: $85,000
10 targets, 12s timer
On pass: grant
practical_weaponslicense (ESX)On fail: can retry (pay again)
License Flow (QBCore)
Same flow but with different license keys:
Theoretical:
metadata.licences.theoretical_weapons = truePractical:
metadata.licences.weapon = true
Mutual Exclusion
The system prevents overlapping activities with clear checks:
None
β
β
β
Theoretical Test
β
β
β
Practical Test
β
β
β
Practice
β
β
β
Additionally:
All 3 interaction markers are hidden during any active session
The shooting range is globally locked β only one player can use it at a time
Notification shown: "You are already in an activity. Finish it first."
Theoretical Test UI
The NUI test interface has 4 sections with smooth transitions:
Welcome β Info cards showing: 9 questions, 5/9 required, Unlimited time
Questions β One at a time, 4 clickable answer cards, progress bar
Pass β Animated green checkmark, congratulations message
Fail β Animated red cross, "try again" message
Practical Test Mechanics
Player pays β server locks shooting range (
shootingRangeFree = false)Player receives weapon (200 ammo) via
GiveWeaponToPedCountdown overlay: 5... 4... 3... 2... 1... (with siren sound)
First target spawns at random position from 17 predefined slots
Target hit detection via
HasEntityBeenDamagedByAnyPedHit β target destroyed β next spawns at different random position
Pass: All targets hit / Fail: Timer runs out
Weapon removed, target cleanup, range unlocked
Practice Mode Mechanics
Same shooting mechanics as practical test
Configurable independent duration and target count
Can be free or paid
Optionally requires weapon license
Does not grant any license on completion
Shows hit count on completion
NUI Interface
Welcome Section
Header
Shield icon + "Weapon License" + "Theoretical Examination" + "OFFICIAL" badge
Weapon Icon
weapon.png header image
Welcome Text
Explains what the test is about
Info Cards
3 cards: Questions (9), Required (5/9), Time Limit (Unlimited)
Start Button
"Start Test" with arrow icon
Question Section
Question Counter
"Question 1 of 9"
Score Display
"X/Y correct"
Progress Bar
Animated width based on current question
Question Text
Current question text
Answer Options
4 clickable cards. Green highlight on correct, red on incorrect.
Next Button
"Next Question" / "Finish Test" on last question. Disabled until answer selected.
Result Screens
Pass
Animated green checkmark SVG, "Test Passed!", congratulations text, "Close" button β triggers close NUI callback
Fail
Animated red cross SVG, "Test Failed", encouragement text, "Close" button β triggers kick NUI callback
Countdown Counter
Full-screen overlay showing numbers 5... 4... 3... 2... 1... with countdown sound (siren.mp3). Used before both practical test and practice sessions.
Security
Server-Side Validation
License Type Whitelist
Only theoretical_weapons and practical_weapons (ESX) or theoretical_weapons and weapon (QB) are accepted
Exam State Tracking
playerInExam[source] tracks which players have paid β license only granted if player is in exam state
Payment First
Server processes payment before any client action begins
Source Validation
xex_weaponlicense:addLicense validates the source player ID
Disconnect Cleanup
playerInExam[src] cleared on playerDropped event
Console Warnings
Invalid license grant attempts are logged with ^1WARNING messages
Anti-Exploit Measures
Pay-Before-Grant
Players cannot receive licenses without paying β server tracks exam state
Global Range Lock
shootingRangeFree boolean prevents multiple players from using range simultaneously
Smart Target Cleanup
cleanTargets only removes prop_range_target_03 props within 30m of the player β doesn't delete other objects
Disarm on Exit
If Config.DisarmIfExits = true, weapon is removed when player approaches exit point
NUI Cleanup
onResourceStop handler closes NUI, removes weapons, and deletes leftover target objects
Exports & Events
Server Callbacks (ESX)
xex_weaponlicense:isPaid
typeLicense ('theoretical'/'practical'/'practice')
boolean
Validates payment, removes money, sets exam state (theoretical/practical only β practice does not set exam state)
xex_weaponlicense:isPaidAndFreeToShoot
typeLicense
boolean, message?
Same as isPaid but also checks if shooting range is free
xex_weaponlicense:toggleShooting
toggle (bool)
β
Sets shootingRangeFree state and cleans up targets
Server Callbacks (QBCore)
xex_weaponlicense:isPaid
typeLicense
boolean
Validates cash payment via Player.Functions.GetMoney('cash')
xex_weaponlicense:isPaidAndFreeToShoot
typeLicense
boolean, message?
Payment check + range availability
xex_weaponlicense:toggleShooting
toggle
β
Sets range state and cleans targets
Server Events
xex_weaponlicense:addLicense
type (string)
Client β Server
Grants license after server-side validation
esx_license:addLicense
source, type, cb
Internal (ESX)
Triggers client license update
playerDropped
β
FiveM native
Cleans up playerInExam state
Client Events
xex_weaponlicense:loadLicenses
licenses (array)
ESX only β loads player's existing licenses on join
xex_weaponlicense:addLicense
type (string)
ESX only β updates local ownedLicenses table after server grant
xex_weaponlicense:client:confirmMenu
β
QBCore only β handles practical exam payment confirmation from qb-menu
xex_weaponlicense:client:confirmMenuTheoretical
β
QBCore only β handles theoretical exam payment confirmation from qb-menu
xex_weaponlicense:client:confirmMenuPay
β
QBCore only β handles practice session payment confirmation from qb-menu
NUI Callbacks
question
User clicks "Start Test"
Transitions from welcome to first question section
close
User clicks "Close" on pass screen
Stops theory test, grants license, closes NUI
kick
User clicks "Close" on fail screen
Stops theory test without granting license, closes NUI
NUI Messages (Lua β JavaScript)
openQuestion
true/false
Shows/hides the test NUI
language
'en'/'es'
Sets the UI language
counter
number
Shows countdown overlay with value
counterClose
true
Hides countdown overlay
openSection
'question'
Transitions to question section
Server Exports
CheckForUpdates
Programmatically trigger update check from another resource
Console Commands
weaponlicense_update
Server console only (source == 0)
Manually triggers the update checker
Localization
Supported Languages
en
English
es
EspaΓ±ol
Locale Keys Reference
Client Strings
practical_test_blip_text
"Practical Weapons Exam"
Map blip label
theoretical_test_blip_text
"Theoretical Weapons Test"
Map blip label
ammo_practice_blip_text
"Shooting Practice"
Map blip label
practical_started
"Practical Weapons Exam started"
Notification on test start
practice_started
"Shooting practice started!"
Notification on practice start
weapon_license
"Weapon Licenses"
Notification title
practical_exam_notif
"Practical exam: "
Advanced notification subtitle
theoretical_exam_notif
"Theoretical exam: "
Advanced notification subtitle
practical_training_notif
"Shooting practice: "
Advanced notification subtitle
passed_notif
"Passed"
Pass notification
passed_notif_training
"Good Job you hit all the targets!"
Practice complete message
failed_notif_training
"Good Job! You hit %s targets"
Practice result with count
failed_simple_notif
"rFailed"
Theory fail notification
failed_notif
"Failed. You missed %s shots"
Practical fail with remaining count
press_practical_exam
"Press [E] to start practical weapons test"
Help notification
press_theoretical_exam
"Press [E] to start theoretical weapons test"
Help notification
press_to_start_practice
"Press [E] to start shooting practice"
Help notification
practical_exam_confirm
"Confirm Weapon Practical license pay for: %s$?"
Menu title
theoretical_exam_confirm
"Confirm Weapon Theoretical license pay for: %s$?"
Menu title
practice_confirm
"Confirm shooting practice session for: %s$?"
Menu title
yes / no
"Yes" / "No"
Confirmation buttons
no_license
"You don't have weapon license..."
Practice gate message
enough_money
"You don't have enough money"
Payment failure
already_got_practical
"You already have weapon practical license"
Already owned
already_got_theoretical
"You already have weapon theoretical license"
Already owned
obtain_theoretical_before
"Before you have to obtain the theoretical test"
Prerequisite message
remaining_seconds_practical
"You are left with %ss to finish the test"
Timer HUD
remaining_seconds_practice
"You are left with %ss to finish the practice"
Timer HUD
shotting_range_not_free
"There is already someone using the shooting range..."
Range occupied
too_far
"You went too far from the firing zone"
Exit detection
busy_in_activity
"You are already in an activity..."
Mutual exclusion
Server Strings
paid
"You paid: %s$"
Payment confirmation
bought_log
"Exam Purchase"
Transaction log label
UI Text Strings
The NUI interface has its own i18n system in ui/scripts.js:
title
"Weapon License"
"Licencia de Armas"
subtitle
"Theoretical Examination"
"Examen TeΓ³rico"
badge
"OFFICIAL"
"OFICIAL"
welcomeTitle
"Welcome to the License Center"
"Bienvenido al Centro de Licencias"
startBtn
"Start Test"
"Comenzar Test"
nextBtn
"Next Question"
"Siguiente Pregunta"
finishBtn
"Finish Test"
"Finalizar Test"
questionOf
"Question %d of %d"
"Pregunta %d de %d"
scoreLabel
"%d/%d correct"
"%d/%d correctas"
passTitle
"Test Passed!"
"Β‘Test Aprobado!"
failTitle
"Test Failed"
"Test Suspendido"
close
"Close"
"Cerrar"
Adding Languages
Add a new language block in
locales.luawith all keysAdd corresponding questions in
ui/questions.jsunder a new language keyAdd UI text strings in
ui/scripts.jsunderUITextSet
Config.Languageto your new language code
Customizing Questions
Question Bank Structure
Edit ui/questions.js to modify or add questions:
Default Questions (English)
The question bank covers these topics:
Gun permit requirements for public carrying
Maximum weapons for self-protection
Self-defense legal requirements
Criminal record restrictions
Hunting weapon urban use restrictions
And more...
Modifying Test Parameters
Edit CONFIG in ui/scripts.js:
nbQuestionToAnswer
9
How many questions are asked per attempt
nbAnswerNeeded
5
Minimum correct answers required to pass
Note: Ensure your question bank has at least
nbQuestionToAnswerquestions per language.
File Structure
Troubleshooting
NUI stuck on screen
Restart the resource: ensure xex_weaponlicense
Questions not showing
Check Config.Language matches a key in questions.js. Verify the UI HTML is loading.
License not saving (ESX)
Verify esx_license is running and weapon_licenses.sql was imported
License not saving (QB)
Check qb-core metadata system is working. Verify player data persists.
Targets not spawning
Check Config.WeaponLicensePropPosition coordinates are accessible
"Shooting range not free"
Another player is using it. Wait or restart resource to reset shootingRangeFree.
Blips not showing
Set Blip.Enabled = true in the relevant config section
UI not loading fonts
Server needs internet access for Google Fonts (Inter)
Countdown sound not playing
Check ui/sounds/siren.mp3 exists. Browser audio may be blocked.
Weapon not given
Verify Config.Weapon is a valid GTA weapon hash string
Player not disarmed on exit
Check Config.DisarmIfExits = true and DoorPointToDisarm coordinates
"You are already in an activity"
Mutual exclusion β finish current test/practice first
Theory test auto-fails
Ensure player has at least nbAnswerNeeded correct answers (5/9 by default)
ESX getSharedObject error
Set Config.GetSharedObjectfunction = true for modern ESX
qb-menu not opening
Ensure qb-menu resource is started before xex_weaponlicense
Changelog
v2.1.0
Professional UI redesign with glassmorphism design system
New JSON-based auto updater with styled console banner
Mutual exclusion between practice and test modes
Server-side license validation with
playerInExamstate trackingAnti-exploit protection β payment required before license grant
NUI cleanup on
onResourceStopto prevent stuck UIFixed typos and removed unused variables
Improved
cleanTargetsβ only removes target props within 30mMulti-language UI support (EN/ES) with
UITextsystemMerged question banks into single file with language keys
Comprehensive DOCS.md documentation
v2.0.0
Fix weapon reload on each round
Fix language typos
Remove unnecessary validation
v1.1.5
QBCore import fix
v1.1.4
Added support to ESX
getSharedObjectexport
v1.1.3
Fix to prevent targets from getting stuck
v1.1.2
ESX fix on license check + Removed server escrow
v1.1.1
Added readme + versioning fix + notification fix
v1.1.0
Added QBCore integration
Support
Discord
Last updated