XP Ranking System for FiveM
- Designed to emulate the native GTA:O system
- Saves and loads players XP / rank
- Add / remove XP from your own script / job
- Allows you listen for rank changes to reward players
- Fully customisable UI
- Framework agnostic, but supports
ESX
andQBCore
- Install
- Transitioning from esx_xp
- Usage
- Client Side
- Server Side
- Rank Actions
- QBCore Integration
- ESX Integration
- Admin Commands
- Themes
- Custom Themes
- FAQ
- License
Select an option:
- Option 1 - If you want to use
xperience
as a standalone resource then importxperience_standalone.sql
only - Option 2 - If using
ESX
withConfig.UseESX
set totrue
then importxperience_esx.sql
only. This adds thexp
andrank
columns to theusers
table- If you're transitioning from
esx_xp
, then don't importxperience_esx.sql
, instead see Transitioning from esx_xp
- If you're transitioning from
- Option 3 - If using
QBCore
withConfig.UseQBCore
set totrue
then there's no need to import anysql
files as the xp and rank are saved to the player's metadata - see QBCore Integration
then:
- Drop the
xperience
directory into youresources
directory - Add
ensure xperience
to yourserver.cfg
file
By default this resource uses oxmysql
, but if you don't want to use / install it then you can use mysql-async
by following these instructions:
- Uncomment the
'@mysql-async/lib/MySQL.lua',
line infxmanifest.lua
and comment out the'@oxmysql/lib/MySQL.lua'
line
If you previously used esx_xp
and are still using es_extended
then do the following to make your current stored xp / rank data compatible with xperience
- Rename the
rp_xp
column in theusers
table toxp
- Rename the
rp_rank
column in theusers
table torank
- Set
Config.UseESX
totrue
Give XP to player
exports.xperience:AddXP(xp --[[ integer ]])
Take XP from player
exports.xperience:RemoveXP(xp --[[ integer ]])
Set player's XP
exports.xperience:SetXP(xp --[[ integer ]])
Set player's rank
exports.xperience:SetRank(rank --[[ integer ]])
Get player's XP
exports.xperience:GetXP()
Get player's rank
exports.xperience:GetRank()
Get XP required to rank up
exports.xperience:GetXPToNextRank()
Get XP required to reach defined rank
exports.xperience:GetXPToRank(rank --[[ integer ]])
Listen for rank up event on the client
AddEventHandler("xperience:client:rankUp", function(newRank, previousRank, player)
-- do something when player ranks up
end)
Listen for rank down event on the client
AddEventHandler("xperience:client:rankDown", function(newRank, previousRank, player)
-- do something when player ranks down
end)
Get player's XP
exports.xperience:GetPlayerXP(playerId --[[ integer ]])
Get player's rank
exports.xperience:GetPlayerRank(playerId --[[ integer ]])
Get player's required XP to rank up
exports.xperience:GetPlayerXPToNextRank(playerId --[[ integer ]])
Get player's required XP to reach defined rank
exports.xperience:GetPlayerXPToRank(playerId --[[ integer ]], rank --[[ integer ]])
TriggerClientEvent('xperience:client:addXP', playerId --[[ integer ]], xp --[[ integer ]])
TriggerClientEvent('xperience:client:removeXP', playerId --[[ integer ]], xp --[[ integer ]])
TriggerClientEvent('xperience:client:setXP', playerId --[[ integer ]], xp --[[ integer ]])
TriggerClientEvent('xperience:client:setRank', playerId --[[ integer ]], rank --[[ integer ]])
RegisterNetEvent('xperience:server:rankUp', function(newRank, previousRank)
-- do something when player ranks up
end)
RegisterNetEvent('xperience:server:rankDown', function(newRank, previousRank)
-- do something when player ranks down
end)
You can define callbacks on each rank by using the Action
function.
The function will be called both when the player reaches the rank and drops to the rank.
You can check whether the player reached or dropped to the new rank by utilising the rankUp
parameter.
Config.Ranks = {
[1] = { XP = 0 },
[2] = {
XP = 800, -- The XP required to reach this rank
Action = function(rankUp, prevRank, player)
-- rankUp: boolean - whether the player reached or dropped to this rank
-- prevRank: number - the player's previous rank
-- player: integer - The current player
end
},
[3] = { XP = 2100 },
[4] = { XP = 3800 },
...
}
If Config.UseQBCore
is set to true
then the player's xp and rank are stored in their metadata. The metadata is saved whenever a player's xp / rank changes.
local PlayerData = QBCore.Functions.GetPlayerData()
local xp = PlayerData.metadata.xp
local rank = PlayerData.metadata.rank
local Player = QBCore.Functions.GetPlayer(src)
local xp = Player.PlayerData.metadata.xp
local rank = Player.PlayerData.metadata.rank
local xPlayer = ESX.GetPlayerById(src)
local xp = xPlayer.get('xp')
local rank = xPlayer.get('rank')
-- Set the theme
/setXPTheme [theme]
These require ace permissions: e.g. add_ace group.admin command.addXP allow
-- Award XP to player
/addXP [playerId] [xp]
-- Deduct XP from player
/removeXP [playerId] [xp]
-- Set a player's XP
/setXP [playerId] [xp]
-- Set a player's rank
/setRank [playerId] [rank]
The theme can be set by the player using the /setXPTheme [theme]
command. The theme
argument must exist in the Config.Themes
table in config.lua
for it to work:
Config.Theme = 'native' -- Set the default theme (must exist in the Config.Themes table)
Config.Themes = {
native = {
segments = 10, -- Sets the number of segments the XP bar has. Native = 10, Max = 20
width = 532 -- Sets the width of the XP bar in px
},
hitman = {
segments = 80,
width = 800
},
hexagon = {
segments = 16,
width = 400
},
}
Let's say you want to add a theme called myTheme
:
- Add the theme table to the
Config.Themes
table using the name of the theme as the index:
Config.Themes = {
...
myTheme = {
segments = 20,
width = 650
}
}
- Create the theme's
.css
file inui/css
directory with thetheme-
prefix:
ui/css/theme-myTheme.css
- Set
Config.Theme
to read your new theme:
Config.Theme = 'myTheme'
<div class="xperience">
<div class="xperience-inner">
<div class="xperience-rank">
<div>XXXX</div> <!-- CURRENT RANK -->
</div>
<div class="xperience-progress"> <!-- MAIN PROGRESS BAR -->
<div class="xperience-segment"> <!-- BAR SEGMENT (IF YOU'VE SET THE THEME'S SEGMENTS TO 10 THEN THERE'LL BE 10 OF THESE) -->
<div class="xperience-indicator--bar"></div> <!-- SEGMENT INDICATOR (ONLY USED WHEN XP IS UPDATING)-->
<div class="xperience-progress--bar"></div> <!-- SEGMENT PROGRESS -->
</div>
...
</div>
<div class="xperience-rank">
<div>XXXX</div> <!-- NEXT RANK -->
</div>
</div>
<div class="xperience-data">
<span>XXXX</span> <!-- CURRENT XP -->
<span>XXXX</span> <!-- XP REQUIRED FOR NEXT RANK -->
</div>
</div>
Example of awarding players 100XP for every 30mins of playtime
-- Server side
CreateThread(function()
local interval = 30 -- interval in minutes
local xp = 100 -- XP amount to award every interval
while true do
for i, src in pairs(GetPlayers()) do
TriggerClientEvent('xperience:client:addXP', src, xp)
end
Wait(interval * 60 * 1000)
end
end)
Example of giving a player 100 XP for shooting another player
AddEventHandler('gameEventTriggered', function(event, data)
if event == "CEventNetworkEntityDamage" then
local victim = tonumber(data[1])
local attacker = tonumber(data[2])
local weaponHash = tonumber(data[5])
local meleeDamage = tonumber(data[10]) ~= 0 and true or false
-- Don't register melee damage
if not meleeDamage then
-- Check victim and attacker are both players
if (IsEntityAPed(victim) and IsPedAPlayer(victim)) and (IsEntityAPed(attacker) and IsPedAPlayer(attacker)) then
if attacker == PlayerPedId() then -- We are the attacker
exports.xperience:AddXP(100) -- Give player 100 xp for getting a hit
end
end
end
end
end)
You can either utilise Rank Events or Rank Actions.
Example of giving a minigun with 500
bullets to a player for reaching rank 10
:
AddEventHandler("xperience:client:rankUp", function(newRank, previousRank, player)
if newRank == 10 then
local weapon = `WEAPON_MINIGUN`
if not HasPedGotWeapon(player, weapon, false) then
-- Player doesn't have weapon so give it them loaded with 500 bullets
GiveWeaponToPed(player, weapon, 500, false, false)
else
-- Player has the weapon so give them 500 bullets for it
AddAmmoToPed(player, weapon, 500)
end
end
end)
Config.Ranks = {
[1] = { XP = 0 },
[2] = { XP = 800 },
[3] = { XP = 2100 },
[4] = { XP = 3800 },
[5] = { XP = 6100 },
[6] = { XP = 9500 },
[7] = { XP = 12500 },
[8] = { XP = 16000 },
[9] = { XP = 19800 },
[10] = {
XP = 24000,
Action = function(rankUp, prevRank, player)
if rankUp then -- only run when player moved up to this rank
local weapon = `WEAPON_MINIGUN`
if not HasPedGotWeapon(player, weapon, false) then
-- Player doesn't have weapon so give it them loaded with 500 bullets
GiveWeaponToPed(player, weapon, 500, false, false)
else
-- Player has the weapon so give them 500 bullets for it
AddAmmoToPed(player, weapon, 500)
end
end
end
},
[11] = { XP = 28500 },
...
}
xperience - XP Ranking System for FiveM
Copyright (C) 2021 Karl Saunders
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>