Developer

2 min readUpdated Today

Overview

ml_recoil exposes no public exports and no commands. Integration happens through four overridable hooks on the client (client/main_open.lua) and four on the server (server/server_open.lua), plus a single internal callback the client uses to fetch a server-resolved multiplier. All hooks are plain global functions you edit in place; both files are escrow-ignored.

How the multiplier flows

On weapon equip, the client reads Config.XPSystem.Type. With 'client' it calls GetClientSkillMultiplier(skillName) locally. With 'server' it triggers the callback ml_recoil:getSkillMultiplier, which runs GetPlayerSkillMultiplier(source, skillName) on the server. The returned number scales every recoil value: below 1.0 steadies the aim, above 1.0 makes recoil harder.

Client Hooks

Defined in client/main_open.lua.

  • GetClientSkillMultiplier(skillName): returns the local multiplier. Ships an ml_skills integration that trims 10% recoil per betterAccuracy rank.
  • OnWeaponEquipped(weaponHash, weaponData): fires when a configured weapon is equipped. Return false to skip recoil for it.
  • OnShotFired(weaponHash, totalMultiplier): fires after every shot with the final applied multiplier. A good place to award shooting XP.
  • OnAimStateChanged(weaponHash, isAiming): fires when the player starts or stops aiming down sights.
client/main_open.lua
1function GetClientSkillMultiplier(skillName)
2    local multiplier = 1.0
3
4    if Config.XPSystem.Enabled and GetResourceState('ml_skills') == 'started' then
5        local ok, effect = pcall(function()
6            return exports.ml_skills:GetActiveEffect('betterAccuracy')
7        end)
8        if ok and type(effect) == 'number' and effect > 0 then
9            multiplier = math.max(0.1, 1.0 - (0.1 * effect))
10        end
11    end
12
13    return multiplier
14end

Server Hooks

Defined in server/server_open.lua. Used when Config.XPSystem.Type = 'server'.

  • GetPlayerSkillMultiplier(source, skillName): returns the multiplier for a player. Wire your own skill lookup here.
  • ServerSkillToMultiplier(level): helper that maps a 0-100 level to a multiplier (1.5 untrained, 1.0 default, 0.5 master).
  • ValidateWeaponAccess(source, weaponHash): return false to force the maximum recoil penalty (2.0) on a player as an anti-cheat gate.
  • LogWeaponUsage(source, weaponHash, skillName, multiplier): called once per skill lookup; hook analytics or logging here.
server/server_open.lua
1function GetPlayerSkillMultiplier(source, skillName)
2    if not Config.XPSystem.Enabled then return 1.0 end
3
4    -- local level = exports.ml_skills:GetPlayerLevel(skillName, source)
5    -- return ServerSkillToMultiplier(level)
6
7    return 1.0
8end

Examples

Edit OnShotFired in client/main_open.lua.

client/main_open.lua
1function OnShotFired(weaponHash, totalMultiplier)
2    exports.ml_skills:RequestXp('personal', 2, 'shooting')
3end

Set Config.XPSystem.Type = 'server' and edit GetPlayerSkillMultiplier.

server/server_open.lua
1function GetPlayerSkillMultiplier(source, skillName)
2    if not Config.XPSystem.Enabled then return 1.0 end
3    local level = exports.ml_skills:GetPlayerLevel(skillName, source)
4    return ServerSkillToMultiplier(level)
5end

Return false from OnWeaponEquipped for the hashes you want untouched.

client/main_open.lua
1function OnWeaponEquipped(weaponHash, weaponData)
2    if weaponHash == `WEAPON_REVOLVER` then return false end
3    return true
4end