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

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

function CreateExtendedPlayer(playerId, identifier, group, accounts, inventory, weight, job, job2, loadout, name, coords, metadata)

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

self.job = job
self.job2 = job2 -- HERE ADDED

  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)

stateBag:set("job", self.job, true)
stateBag:set("job2", self.job2, true) -- HERE ADDED

  1. Register a new function for job2 below:

function self.getJob2()
    return self.job2
end

  1. Register a new function for job2 below:

function self.setJob2(newJob2, grade2, onDuty)
    grade2 = tostring(grade2)
    local lastJob = self.job2
    if not ESX.DoesJobExist(newJob2, grade2) then
        return print(("[ESX] [^3WARNING^7] Ignoring invalid ^5.setJob2()^7 usage for ID: ^5%s^7, Job2: ^5%s^7"):format(self.source, newJob2))
    end
    local jobObject2, gradeObject2 = ESX.Jobs[newJob2], ESX.Jobs[newJob2].grades[grade2]
    self.job2 = {
        id = jobObject2.id,
        name = jobObject2.name,
        label = jobObject2.label,
        grade = tonumber(grade2),
        grade_name = gradeObject2.name,
        grade_label = gradeObject2.label,
        grade_salary = gradeObject2.salary,
        skin_male = gradeObject2.skin_male and json.decode(gradeObject2.skin_male) or {},
        skin_female = gradeObject2.skin_female and json.decode(gradeObject2.skin_female) or {},
    }
    TriggerEvent("esx:setJob2", self.source, self.job2, lastJob)
    self.triggerEvent("esx:setJob2", self.job2, lastJob)
    Player(self.source).state:set("job2", self.job2, true)
end
STEP 6
  1. Go to your es_extended/server/modules/commands.lua

  1. Register a new command:

ESX.RegisterCommand(
    "setjob2",
    "admin",
    function(xPlayer, args, showError)
        if not ESX.DoesJobExist(args.job2, args.grade2) then
            return showError(TranslateCap("command_setjob_invalid"))
        end

        args.playerId.setJob2(args.job2, args.grade2)
    end,
    true,
    {
        help = TranslateCap("command_setjob"),
        validate = true,
        arguments = {
            { name = "playerId", help = TranslateCap("commandgeneric_playerid"), type = "player" },
            { name = "job2", help = "Job2", type = "string" },
            { name = "grade2", help = "Grade2", type = "number" },
        },
    }
)

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

Was this helpful?