Configuration
Overview
shared/config.lua: UI behavior, XP curves, listeners, prestige, admin permissionserver/config_server.lua: Webhooks, log provider, rate-limit cooldown
Most servers never need to touch the listener caps. The defaults match a balanced survival/RP economy.
UI / Open Behavior
1Config.OpenCommand = 'skills'
2Config.OpenKey = 'J'
3Config.DefaultCategory = 'personal'
4Config.UnifiedView = trueOpenCommand: Chat command that opens the treeOpenKey: Keybind that opens the tree. Any FiveM input name is acceptedDefaultCategory: Category shown when the UI opens.'all'opens the unified view; any category UID jumps straight to that treeUnifiedView: Whentrue, all categories render on one scrollable canvas. Whenfalse, the sidebar switches between separate canvases per category
Theme & Visuals
1Config.Theme = 'default'
2Config.MainColor = nil
3Config.UIOpacity = 0.85
4Config.LockedPreviewGrayscale = trueTheme: One of'default','cyberpunk','wasteland','noir','fantasy'MainColor: Hex string (e.g.'#ff8800') that overrides the theme accent.nilfalls back to the theme defaultUIOpacity: Background opacity of the tree panel, from0.0to1.0LockedPreviewGrayscale: Whentrue, the hover preview image renders grayscale until the skill is unlockable
XP Notifications
1Config.XpNotification = 'toast'
2Config.XpToastPosition = 'bottom'
3Config.XpToastDuration = 3000XpNotification:'toast'shows the floating in-panel toast;'bridge'routes throughBridge.Notifyfor system-style notifications;falsedisables XP notifications entirelyXpToastPosition:'top','bottom', or'center'XpToastDuration: Toast display time in ms
Performance / LOD
1Config.PerformanceMode = 'auto'
2Config.LodZoomThreshold = 0.45
3Config.LodNodeThreshold = 120PerformanceMode:'auto'(recommended),'quality'(always full detail),'performance'(LOD always on for low-end rigs)LodZoomThreshold: Below this zoom level the canvas switches to simple nodesLodNodeThreshold: When more than this many nodes are visible, heavy animations pause
XP Curve
1Config.DefaultXpBase = 400
2Config.DefaultXpMultiplier = 1.12
3Config.DefaultMaxLevel = 50
4Config.PointsPerLevel = 1
5Config.UnifiedPoints = false
6Config.XpPerLevelCap = 20000DefaultXpBase: Base XP required for level 1DefaultXpMultiplier: Exponential scaling per level. Required XP for level N isbase * multiplier^NDefaultMaxLevel: Global maximum levelPointsPerLevel: Skill points granted per level upUnifiedPoints: Whentrue, all categories share one point pool. Whenfalse, each category has its own poolXpPerLevelCap: Hard cap on the XP required to clear a single level. Once the exponential curve crosses this value, every later level costs exactlyXpPerLevelCap. Set0to disable
Each category in Config.Categories can override xpBase, xpMultiplier and maxLevel.
Categories
1Config.Categories = {
2 personal = { label = _L('cat_personal'), icon = 'user', xpBase = 400, xpMultiplier = 1.12, maxLevel = 50 },
3}
4
5Config.DisabledCategories = {}- Each entry keys on the category UID, the same string used everywhere in the API
label: Display name, supports_L('key')for localizationicon: Lucide icon name (user,anvil,swords,crosshair, etc.)xpBase,xpMultiplier,maxLevel: Per-category overrides for the curveDisabledCategories: Keys listed here are stripped at boot fromConfig.Categories,Config.DefaultTreesandConfig.XpListeners. Useful to ship a default tree but hide it on a specific server
XP Listeners
Passive XP awarded by the client when the player performs an action. The server validates the timing, the movement, and enforces the daily cap.
1Config.XpListeners = {
2 driving = {
3 category = 'personal',
4 xp = 1,
5 interval = 30000,
6 intervalJitter = 6000,
7 condition = function()
8 local veh = cache.vehicle
9 if not veh or veh == 0 then return false end
10 if GetPedInVehicleSeat(veh, -1) ~= cache.ped then return false end
11 return GetEntitySpeed(veh) > 5.0
12 end,
13 },
14}category: Category UID the XP is awarded toxp: XP amount per triggerinterval: Base check interval in msintervalJitter: Random±jitter added on every wait. Each tick waits betweeninterval - jitterandinterval + jittercondition: Function returningtruewhen the activity is happening. Usescache.pedandcache.vehiclefromox_librequiresMovement: Optional. Defaults totrue. Setfalsefor an activity done standing still (shooting from cover, or a kill relayed by another resource), otherwise the server drops the claim as AFK farmingmovementDistance: Optional metres the ped must cover between two grants of this listener. Default0.5cooldown: Optional minimum ms between two grants of this listener. Defaults tointerval - intervalJittercapped at5000, and never goes below1000
Built-in listeners: driving, swimming, sprinting, shooting, flying. Replace, extend, or remove any of them.
A listener with no interval and no condition never fires by itself. It is the whitelist entry a client script requests by name through exports.ml_skills:RequestXp(categoryUid, amount, listenerName), which is how a client-side event awards XP without trusting the client with an amount.
Listener Anti-Abuse
1Config.XpListenerCapPerMinute = 60
2Config.XpListenerDailyCapPerCategory = 50000
3Config.XpListenerMovementCheck = trueXpListenerCapPerMinute: Hard cap on listener XP per minute per category, server-enforced. Listeners are activity hints sent by the client, so this value is what bounds a spoofed claim. Size it on the listeners a single player can trigger at once: the shipped set stays under 40 per minuteXpListenerDailyCapPerCategory: Daily hard cap per categoryXpListenerMovementCheck: Whentrue, the server rejects listener XP if the ped has not moved since the previous fire. Listeners that set requiresMovement = false are exempt
Daily XP Cap
1Config.DailyXpCap = {
2 enabled = false,
3 globalPerDay = 0,
4 perCategoryPerDay = 0,
5 resetMode = 'fixed',
6 resetHour = 0,
7 showInUI = true,
8 notifyOnCap = true,
9}Opt-in ceiling on how much XP a player can earn per day. It applies to every gain routed through AddXp (listeners, integrations, skill events); admin give/remove and SetLevel are exempt.
enabled: Master switch. Off by default, so there is no daily cap until you turn it on.globalPerDay: Max total XP per day across all categories.0= unlimited.perCategoryPerDay: Default daily ceiling per category.0= unlimited. Override one category withConfig.Categories[uid].dailyXpCap, or scale it by level withConfig.Categories[uid].dailyXpCapTiers(a list of{ minLevel, cap }bands; the highest band at or below the player level wins). Tiers take precedence over a flat cap.resetMode:'fixed'resets every day atresetHour;'rolling'resets 24h after the player's first XP of the cycle.resetHour: Hour (0-23, server local time) of the fixed reset.showInUI: Show the Daily XP usage indicator inside the skill UI.notifyOnCap: Notify the player when the daily limit is reached.
Admin Permission
1Config.AdminPermission = {
2 level = 'admin',
3 ace = nil,
4}level:ml_bridgepermission level required for the Player Manager and the tree editor. Common values:'admin','god','mod'or'mod'ace: Optional ACE permission (e.g.'ml_skills.admin'). When set, ACE takes precedence over the Bridge level
Reset & Wipe Permissions
1Config.AllowReset = false
2Config.AdminAllowResetSkills = true
3Config.AdminAllowFullWipe = trueAllowReset: Whentrue, players can reset their own skill points from the UIAdminAllowResetSkills: Whentrue, the Player Manager exposes the per-category reset actionAdminAllowFullWipe: Whentrue, the Player Manager exposes the full wipe action
Prestige
1Config.PrestigeEnabled = false
2Config.PrestigeBonus = 0.10
3Config.MaxPrestige = 5PrestigeEnabled: Master switch. Whenfalse, no prestige UI shows upPrestigeBonus: XP multiplier added per prestige level.0.10=+10%per tierMaxPrestige: Maximum prestige levels achievable
External Export Gate
1Config.EnableUnlockSkillExport = trueEnableUnlockSkillExport: Whentrue, other resources can callexports.ml_skills:UnlockSkill(catUid, skillUid, src). Setfalseto lock unlocks to the in-UI flow
Skill Default Values
1Config.SkillDefaultValues = {
2 moreStamina = 100.0,
3 moreMaxHp = 200,
4 timeUnderwater = 10.0,
5}GTA-default values used by open/effects.lua handlers as the baseline for percentage-based skill effects. Override these only when another resource modifies the same natives.
HP Regeneration
1Config.HpRegen = {
2 idleSeconds = 300,
3 maxRegenPercent = 25,
4 tickHp = 1,
5 tickMs = 5000,
6 breakOnSprint = true,
7 breakOnShoot = true,
8 breakOnVehicle = true,
9 breakOnDamage = true,
10 notifyOnStart = true,
11 disableNativeRegen = false,
12}Powers the hpRegeneration perks in the personal tree: a slow out-of-combat heal that begins after the player has been still for idleSeconds and tops out at maxRegenPercent of the playable HP range.
idleSeconds: Idle time before regen begins (300= 5 minutes).maxRegenPercent: Regen ceiling as a percent of the HP range (25stops at 125 HP).tickHp/tickMs: HP restored per tick (multiplied by the skill effect) and the tick interval.breakOnSprint/breakOnShoot/breakOnVehicle/breakOnDamage: Any of these resets the idle timer.notifyOnStart: Notify the player the moment regen kicks in.disableNativeRegen: Suppresses GTA's native HP regen. Leavefalseif another script (ml_healthsystem, esx_basicneeds) manages regen; ml_skills auto-skips it when ml_healthsystem is detected.
Achievements
1Config.Achievements = {
2 firstSkill = {
3 label = _L('achievement_first_step'),
4 description = _L('achievement_first_step_desc'),
5 icon = 'star',
6 condition = { type = 'skills_unlocked', count = 1 },
7 rewards = {
8 { item = 'bread', count = 3 },
9 },
10 },
11}Achievements declared here are seeded into the ml_skills_achievements table on first start. After seeding, the in-game achievement editor becomes the source of truth.
condition.type:'skills_unlocked','skill_unlocked', or'level_reached'condition.count: Used by'skills_unlocked'and'level_reached'condition.skillId/condition.category: Used by'skill_unlocked'rewards: Array of{ item, count }or{ cash = N }/{ bank = N }
Webhooks
1ServerConfig.Webhook = ''
2
3ServerConfig.Webhooks = {
4 player_skill_unlock = '',
5 player_claim_reward = '',
6 player_claim_achievement = '',
7 player_prestige = '',
8 player_reset_skills = '',
9 player_reset_category = '',
10 admin_give_xp = '',
11 admin_remove_xp = '',
12 admin_set_level = '',
13 admin_give_points = '',
14 admin_remove_points = '',
15 admin_reset_skills = '',
16 admin_full_wipe = '',
17 admin_unlock_skill = '',
18 admin_save_tree = '',
19 admin_save_categories = '',
20 admin_save_achievement = '',
21 admin_delete_achievement = '',
22 external_unlock_skill = '',
23 security_devtools = '',
24}
25
26ServerConfig.LogProvider = 'discord'
27ServerConfig.RateLimitCooldown = 1000Webhook: Generic fallback used when a specific slot is emptyWebhooks.<action>: Dedicated webhook per action categoryLogProvider:'discord','fivemanage','ox_lib','both', or'all'RateLimitCooldown: Minimum ms between two UI actions from the same player
Set any webhook to false to disable that log entirely.