Documentation
avr_skilltree
Config-driven skill trees for FiveM. Qbox, QBCore, ESX and standalone.
One dependency: ox_lib.
Install
- Drop
avr_skilltreein your resources folder. ensure ox_libandensure oxmysqlbefore it, thenensure avr_skilltree.- Start the server once. The
avr_skilltreetable is created automatically.
Open the UI with /skills or F7. Both are configurable in config/config.lua.
On first start the resource validates your config and prints anything wrong: unknown parent ids, two nodes sharing a grid slot, effects that do not exist. A broken tree fails loudly at boot instead of quietly in game.
Editions
Same features, same updates, same support. Both cover one server. The only difference is which two files are escrowed.
| File | Standard | Open |
|---|---|---|
| config/*.lua | open | open |
| bridge/*.lua | open | open |
| client/effects.lua | open | open |
| web/* (whole UI) | open | open |
| locales/*.json | open | open |
| server/main.lua | escrowed | open |
| client/main.lua | escrowed | open |
Building a tree
Trees live in config/trees.lua. A node looks like this:
{ id = 'pacer', label = 'Pacer', description = 'Move a little quicker on foot.',
icon = 'boot', pos = { x = 1, y = 1 },
parents = { 'second_wind' }, -- any one unless requireAll = true
excludes = { 'riptide' }, -- taking this permanently locks riptide
requires = { level = 10, job = 'police', gang = 'lost' },
cost = 1, maxRank = 5,
effects = { { type = 'sprint_mult', value = 0.01 } } }, -- per rank
posis a grid coordinate, not pixels.xis the column,yis the row. The UI centres and links the constellation for you.pointCapon a tree limits total points spendable in it. Setfalsefor uncapped.prestige = { level = 50, bonus = { type = 'xp_mult', value = 0.05 } }enables prestige on that tree.- Remove a node from the config and its points refund automatically on the player's next load.
Icons
Built in: pulse, wind, boot, flame, wave, droplet, shield, crosshair, hand, reload, fist, feather. Add your own in web/app.js under ICONS.
Effects
Fourteen are built in:
stamina_regen, sprint_mult, sprint_drain,
swim_mult, lung_capacity, health_regen,
melee_mult, weapon_damage, recoil_mult,
noise_mult, fall_damage, max_armor,
max_health, xp_mult.
Every one is wired to a native and does something in game.
There is no reload-speed effect. GTA does not expose reload timing, so a config that asks for one gets a console warning rather than a node that silently does nothing.
Values are fractions: 0.10 is +10%. Negative reduces, so recoil_mult = -0.08 is 8% less recoil. Effects stack additively across ranks and nodes.
Custom effects
Register your own from any resource:
exports.avr_skilltree:RegisterEffect('carry_weight', function(value)
-- value is the total across every unlocked rank; 0 means "remove it"
exports.ox_inventory:setPlayerWeight(100000 * (1.0 + value))
end)
API
Server exports:
exports.avr_skilltree:AddXP(src, 'endurance', 250)
exports.avr_skilltree:SetXP(src, 'endurance', 0)
exports.avr_skilltree:GetXP(src, 'endurance')
exports.avr_skilltree:GetLevel(src, 'endurance')
exports.avr_skilltree:GetPoints(src, 'endurance')
exports.avr_skilltree:HasNode(src, 'endurance', 'marathon') --> boolean
exports.avr_skilltree:GetNodeRank(src, 'endurance', 'pacer') --> number
exports.avr_skilltree:GetModifier(src, 'sprint_mult') --> number
exports.avr_skilltree:GetPlayerData(src) --> full table
exports.avr_skilltree:Respec(src, 'endurance')
Events
AddEventHandler('avr_skilltree:server:nodeUnlocked', function(src, treeId, nodeId, rank) end)
AddEventHandler('avr_skilltree:server:levelUp', function(src, treeId, level) end)
AddEventHandler('avr_skilltree:server:respec', function(src, treeId) end)
AddEventHandler('avr_skilltree:server:prestige', function(src, treeId, prestige) end)
Statebags
Read a build from any resource without depending on this one:
local mods = Player(src).state.avr_mods -- { sprint_mult = 0.05, ... }
local nodes = Player(src).state.avr_nodes -- { ['endurance:pacer'] = 2, ... }
Theming
web/ is plain HTML, CSS and JS. No build step, no bundler.
Everything themeable is in the :root block at the top of web/style.css. Open web/index.html directly in a browser: it loads sample data so you can retheme without launching the game.
Frameworks
bridge/server.lua auto-detects Qbox, QBCore and ESX, and falls back to standalone using the license identifier with no economy. Both bridge files are open in every edition: five functions to adapt for a custom framework.
Performance
0.00ms idle on both sides. No ticks while the UI is closed. Effects are applied from statebag changes, and the one managed thread only runs while a stamina effect is active. Saves are batched, 15 seconds by default, and flushed on drop and resource stop.