For the complete documentation index, see llms.txt. This page is also available as Markdown.

Creating job2 on ESX

If you want to use the gang menu, but don't have job2 registered on your server, here is a step-by-step tutorial on how to register it.


Important

STEP 1

Create new columns for your users table.

Not sure how to do it?

ALTER TABLE `users`
    ADD COLUMN `job2` VARCHAR(20) DEFAULT 'unemployed',
    ADD COLUMN `job_grade2` INT(11) DEFAULT 0;
STEP 2
  1. Go to your es_extended/client/modules/events.lua

  2. Register a new event:

ESX.SecureNetEvent("esx:setJob2", function(Job2)
    ESX.SetPlayerData('job2', Job2)
end)
STEP 3
  1. Go to your es_extended/server/main.lua

  2. Find local loadPlayer (will be available in the first lines)

  3. Replace with the following code:

local loadPlayer = "SELECT `accounts`, `job`, `job_grade`, `job2`, `job_grade2`, `group`, `position`, `inventory`, `skin`, `loadout`, `metadata`"

  1. Inside this function, find local job, grade =

  2. Find the job registration end here and add the following code:

-- Job2
local job2, grade2 = result.job2, tostring(result.job_grade2)

if not ESX.DoesJobExist(job2, grade2) then
    print(("[^3WARNING^7] Ignoring invalid job2 for ^5%s^7 [job2: ^5%s^7, grade: ^5%s^7]"):format(identifier, job2, grade2))
    job2, grade2 = "unemployed", "0"
end

local job2Object, grade2Object = ESX.Jobs[job2], ESX.Jobs[job2].grades[grade2]

userData.job2 = {
    id = job2Object.id,
    name = job2Object.name,
    label = job2Object.label,
    
    grade = tonumber(grade),
    grade_name = grade2Object.name,
    grade_label = grade2Object.label,
    grade_salary = grade2Object.salary,
    
    skin_male = grade2Object.skin_male and json.decode(grade2Object.skin_male) or {},
    skin_female = grade2Object.skin_female and json.decode(grade2Object.skin_female) or {},
}

  1. Just after userData.job add userData.job2

local xPlayer = CreateExtendedPlayer(
    playerId,
    identifier,
    userData.group,
    userData.accounts,
    userData.inventory,
    userData.weight,
    userData.job,
    userData.job2, -- HERE ADDED
    userData.loadout,
    GetPlayerName(playerId),
    userData.coords,
    userData.metadata
)

  1. Add job2 = xPlayer.getJob2(), to callback data:

ESX.RegisterServerCallback("esx:getPlayerData", function(source, cb)
    local xPlayer = ESX.GetPlayerFromId(source)

    cb({
        identifier = xPlayer.identifier,
        accounts = xPlayer.getAccounts(),
        inventory = xPlayer.getInventory(),
        job = xPlayer.getJob(),
        job2 = xPlayer.getJob2(), -- HERE ADDED
        loadout = xPlayer.getLoadout(),
        money = xPlayer.getMoney(),
        position = xPlayer.getCoords(true),
        metadata = xPlayer.getMeta(),
    })
end)

  1. Add job2 = xPlayer.getJob2(), to callback data:

ESX.RegisterServerCallback("esx:getOtherPlayerData", function(_, cb, target)
    local xPlayer = ESX.GetPlayerFromId(target)

    cb({
        identifier = xPlayer.identifier,
        accounts = xPlayer.getAccounts(),
        inventory = xPlayer.getInventory(),
        job = xPlayer.getJob(),
        job2 = xPlayer.getJob2(), -- HERE ADDED
        loadout = xPlayer.getLoadout(),
        money = xPlayer.getMoney(),
        position = xPlayer.getCoords(true),
        metadata = xPlayer.getMeta(),
    })
end)
STEP 4
  1. Go to your es_extended/server/functions.lua

  2. Replace with the following code:

function Core.SavePlayer(xPlayer, cb)
    if not xPlayer.spawned then
        return cb and cb()
    end

    updateHealthAndArmorInMetadata(xPlayer)
    local parameters <const> = {
        json.encode(xPlayer.getAccounts(true)),
        xPlayer.job.name,
        xPlayer.job.grade,
        xPlayer.job2.name, -- HERE ADDED
        xPlayer.job2.grade, -- HERE ADDED
        xPlayer.group,
        json.encode(xPlayer.getCoords(false, true)),
        json.encode(xPlayer.getInventory(true)),
        json.encode(xPlayer.getLoadout(true)),
        json.encode(xPlayer.getMeta()),
        xPlayer.identifier,
    }

    MySQL.prepare( -- HERE ADDED
        "UPDATE `users` SET `accounts` = ?, `job` = ?, `job_grade` = ?, `job2` = ?, `job_grade2` = ?, `group` = ?, `position` = ?, `inventory` = ?, `loadout` = ?, `metadata` = ? WHERE `identifier` = ?",
        parameters,
        function(affectedRows)
            if affectedRows == 1 then
                print(('[^2INFO^7] Saved player ^5"%s^7"'):format(xPlayer.name))
                TriggerEvent("esx:playerSaved", xPlayer.playerId, xPlayer)
            end
            if cb then
                cb()
            end
        end
    )
end

  1. Replace with the following code:

function Core.SavePlayers(cb)
    local xPlayers <const> = ESX.Players
    if not next(xPlayers) then
        return
    end

    local startTime <const> = os.time()
    local parameters = {}

    for _, xPlayer in pairs(ESX.Players) do
        updateHealthAndArmorInMetadata(xPlayer)
        parameters[#parameters + 1] = {
            json.encode(xPlayer.getAccounts(true)),
            xPlayer.job.name,
            xPlayer.job.grade,
            xPlayer.job2.name, -- HERE ADDED
            xPlayer.job2.grade, -- HERE ADDED
            xPlayer.group,
            json.encode(xPlayer.getCoords(false, true)),
            json.encode(xPlayer.getInventory(true)),
            json.encode(xPlayer.getLoadout(true)),
            json.encode(xPlayer.getMeta()),
            xPlayer.identifier,
        }
    end

    MySQL.prepare( -- HERE ADDED
        "UPDATE `users` SET `accounts` = ?, `job` = ?, `job_grade` = ?, `job2` = ?, `job_grade2` = ?,`group` = ?, `position` = ?, `inventory` = ?, `loadout` = ?, `metadata` = ? WHERE `identifier` = ?",
        parameters,
        function(results)
            if not results then
                return
            end

            if type(cb) == "function" then
                return cb()
            end

            print(("[^2INFO^7] Saved ^5%s^7 %s over ^5%s^7 ms"):format(#parameters, #parameters > 1 and "players" or "player", ESX.Math.Round((os.time() - startTime) / 1000000, 2)))
        end
    )
end
STEP 5
  1. Go to your es_extended/server/classes/player.lua

  2. Enter inside the parameters of the job2 function just after the job

  1. A few lines below find self.job = job and just below it add self.job2 = job2

  1. Another few lines below find stateBag:set("job", self.job, true)

  2. And under it, add job2 statebag registration - stateBag:set("job2", self.job2, true)

  1. Register a new function for job2 below:

  1. Register a new function for job2 below:

STEP 6
  1. Go to your es_extended/server/modules/commands.lua

  2. Register a new command:

Done! Restart the server and test. 🎉 Use the /setjob2 [PLAYER_ID] [JOB2_NAME] [JOB2_GRADE] command.

Job2 works on a job basis, but is separate, so you still use the jobs table and job_grades in your database. You can set the jobs you have there as both jobs and job2.

Last updated