[RELEASE] Having 2 jobs

jobs

#1

Hi dear community
After months I finaly decided to release this stuff but I’ll not support you guys, so please as always help others :slight_smile:
A special thanks to @Cheleber for his incredible support

Working:
Everything, you simply have 2 jobs and can be the boss of 2 companies. You have the access to all functions, markers, spawners,menus etc.

What I have done:

  • I’m using the job and job grades tables to pick my 2nd job from this list.
  • The second job will be stored in the users table as job2 and job2_grade. Again these are pointing the jobs/name columns.
  • Duplicate all job and job grade function/variables in es_extended
  • Detect 2 jobs in the paycheck function and getting 2 paychecks (depending of job, job_grage, job2 and job2_grade

Modifications have to be done for:

  • es_extended
  • esx_society
  • DBG_LesterJobs (the second job office from Santagain, for which I’ve never asked permission for editing and releasing modifications) or you can copy the esx_joblisting
  • Each job

RELEASE:

1)Most of modifications have been made few month ago so scripts haven’t been updated since. You may have new variables, callbacks or functions that didn’t exist when I did that.
2)These modifications request also to modify all the jobs you want to be accessible as your second job
3) If you want that the job 2 is taking into account in scoreboards (to count policemen) you will have to edit the code etc…
4) If you implement this, forget automatic updates or it will erase your modifications.
5) If your mysql is already near saturation, forgot it, this increase the amount of request and callbacks.
6) Its not optimized, specially the paycheck function (becarefull, just take a look on it, don’t use it like the one I’m showing to you!)
7) I’m not using DBG_LesterJobs from Santagain anymore because I’m doing it in another way Can be found here

Let’s have fun:

1) Create a new job
Database -> jobs table -> add a new job in the jobs table (unemployed is for the job 1, unemployed2 will be used for the job 2)
2

2) Create a new job grade
Database -> job_grades table -> add a new grade

3) Create new columns for Users
Database -> users table
bdd

4) es_extended\client\main.lua

RegisterNetEvent('esx:playerLoaded')
AddEventHandler('esx:playerLoaded', function(xPlayer)

  ESX.PlayerLoaded  = true
  ESX.PlayerData    = xPlayer
  TriggerServerEvent("esx:updateConnexion")
  for i=1, #xPlayer.accounts, 1 do

    local accountTpl = '<div><img src="img/accounts/' .. xPlayer.accounts[i].name .. '.png"/>&nbsp;{{money}}</div>'

    ESX.UI.HUD.RegisterElement('account_' .. xPlayer.accounts[i].name, i-1, 0, accountTpl, {
      money = 0
    })

    ESX.UI.HUD.UpdateElement('account_' .. xPlayer.accounts[i].name, {
      money = xPlayer.accounts[i].money
    })

  end

  local jobTpl = '<div>{{job_label}} - {{grade_label}}</div>'
 
  if xPlayer.job.grade_label == '' then
    jobTpl = '<div>{{job_label}}</div>'
  end

  ESX.UI.HUD.RegisterElement('job', #xPlayer.accounts, 0, jobTpl, {
    job_label   = '',
    grade_label = ''
  })

  ESX.UI.HUD.UpdateElement('job', {
    job_label   = xPlayer.job.label,
    grade_label = xPlayer.job.grade_label
  })

	local job2Tpl = '<div>{{job2_label}} - {{grade2_label}}</div>' 

    if xPlayer.job2.grade_label == '' then
    job2Tpl = '<div>{{job2_label}}</div>'
	end
  
  ESX.UI.HUD.RegisterElement('job2', #xPlayer.accounts, 0, job2Tpl, {
    job2_label   = '',
    grade2_label = ''
  })
  
	  ESX.UI.HUD.UpdateElement('job2', {
    job2_label   = xPlayer.job2.label,
    grade2_label = xPlayer.job2.grade_label
  })

end)
RegisterNetEvent('esx:setJob')
AddEventHandler('esx:setJob', function(job)
  ESX.PlayerData.job = job
end)
RegisterNetEvent('esx:setJob2')
AddEventHandler('esx:setJob2', function(job2)
  ESX.PlayerData.job2 = job2
end)
RegisterNetEvent('esx:setJob')
AddEventHandler('esx:setJob', function(job)
  ESX.UI.HUD.UpdateElement('job', {
    job_label   = job.label,
    grade_label = job.grade_label
  })
end)
RegisterNetEvent('esx:setJob2')
AddEventHandler('esx:setJob2', function(job2)
  ESX.UI.HUD.UpdateElement('job2', {
    job2_label   = job2.label,
    grade2_label = job2.grade_label
  })
end)

5) es_extended\server\classes\player.lua

function CreateExtendedPlayer(player, accounts, inventory, job, job2, loadout, name, lastPosition)

  local self = {}

  self.player       = player
  self.accounts     = accounts
  self.inventory    = inventory
  self.job          = job
  self.job2         = job2
  self.loadout      = loadout
  self.name         = name
  self.lastPosition = lastPosition

  self.source     = self.player.get('source')
  self.identifier = self.player.get('identifier')

  self.setMoney = function(m)
    self.player.setMoney(m)
  end
self.getInventory = function()
    return self.inventory
  end

  self.getJob = function()
    return self.job
  end
  self.getJob2 = function()
    return self.job2
  end
  self.getLoadout = function()
    return self.loadout
  end
  self.setJob = function(name, grade)

    local lastJob = json.decode(json.encode(self.job))

    MySQL.Async.fetchAll(
      'SELECT * FROM `jobs` WHERE `name` = @name',
      {
        ['@name'] = name
      },
      function(result)

        self.job['id']    = result[1].id
        self.job['name']  = result[1].name
        self.job['label'] = result[1].label

        MySQL.Async.fetchAll(
          'SELECT * FROM `job_grades` WHERE `job_name` = @job_name AND `grade` = @grade',
          {
            ['@job_name'] = name,
            ['@grade']    = grade
          },
          function(result)

            self.job['grade']        = grade
            self.job['grade_name']   = result[1].name
            self.job['grade_label']  = result[1].label
            self.job['grade_salary'] = result[1].salary

            self.job['skin_male']    = nil
            self.job['skin_female']  = nil

            if result[1].skin_male ~= nil then
              self.job['skin_male'] = json.decode(result[1].skin_male)
            end

            if result[1].skin_female ~= nil then
              self.job['skin_female'] = json.decode(result[1].skin_female)
            end

            TriggerEvent("esx:setJob", self.source, self.job, lastJob)
            TriggerClientEvent("esx:setJob", self.source, self.job)

          end
        )

      end
    )

  end
  self.setJob2 = function(name, grade)

    local lastJob2 = json.decode(json.encode(self.job2))

    MySQL.Async.fetchAll(
      'SELECT * FROM `jobs` WHERE `name` = @name',
      {
        ['@name'] = name
      },
      function(result)

        self.job2['id']    = result[1].id
        self.job2['name']  = result[1].name
        self.job2['label'] = result[1].label

        MySQL.Async.fetchAll(
          'SELECT * FROM `job_grades` WHERE `job_name` = @job_name AND `grade` = @grade',
          {
            ['@job_name'] = name,
            ['@grade']    = grade
          },
          function(result)

            self.job2['grade']        = grade
            self.job2['grade_name']   = result[1].name
            self.job2['grade_label']  = result[1].label
            self.job2['grade_salary'] = result[1].salary

            self.job2['skin_male']    = nil
            self.job2['skin_female']  = nil

            if result[1].skin_male ~= nil then
              self.job2['skin_male'] = json.decode(result[1].skin_male)
            end

            if result[1].skin_female ~= nil then
              self.job2['skin_female'] = json.decode(result[1].skin_female)
            end

            TriggerEvent("esx:setJob2", self.source, self.job2, lastJob2)
            TriggerClientEvent("esx:setJob2", self.source, self.job2)

          end
        )

      end
    )

  end

6) es_extended\server/commands.lua

TriggerEvent('es:addGroupCommand', 'setjob2', 'jobmaster', function(source, args, user)
  local xPlayer = ESX.GetPlayerFromId(args[1])
  xPlayer.setJob2(args[2], tonumber(args[3]))
end, function(source, args, user)
  TriggerClientEvent('chatMessage', source, "SYSTEM", {255, 0, 0}, "Insufficient Permissions.")
end, {help = _U('setjob'), params = {{name = "id", help = _U('id_param')}, {name = "job", help = _U('setjob_param2')}, {name = "grade_id", help = _U('setjob_param3')}}})

7) es_extended\server/functions.lua

  -- Job, loadout and position
  table.insert(asyncTasks, function(cb)

    MySQL.Async.execute(
      'UPDATE users SET `job` = @job, `job2` = @job2, `job_grade` = @job_grade, `job2_grade` = @job2_grade, `loadout` = @loadout, `position` = @position WHERE identifier = @identifier',
      {
        ['@job']        = xPlayer.job.name,
		['@job2']       = xPlayer.job2.name,
        ['@job_grade']  = xPlayer.job.grade,
		['@job2_grade']  = xPlayer.job2.grade,
        ['@loadout']    = json.encode(xPlayer.loadout),
        ['@position']   = json.encode(xPlayer.lastPosition),
        ['@identifier'] = xPlayer.identifier
      },
      function(rowsChanged)
        cb()
      end
    )

  end)

8) es_extended\server/main.lua

AddEventHandler('es:playerLoaded', function(source, _player)

  local _source = source
  local tasks   = {}

  local userData = {
    accounts     = {},
    inventory    = {},
    job          = {},
	job2          = {},
    loadout      = {},
    playerName   = GetPlayerName(_source),
    lastPosition = nil
  }
-- Get job and loadout
    table.insert(tasks, function(cb)

      local tasks2 = {}

      -- Get job name, grade and last position
      table.insert(tasks2, function(cb2)

        MySQL.Async.fetchAll(
          'SELECT * FROM `users` WHERE `identifier` = @identifier',
          {
            ['@identifier'] = player.getIdentifier()
          },
          function(result)

            userData.job['name']  = result[1].job
			userData.job2['name']  = result[1].job2
            userData.job['grade'] = result[1].job_grade
			userData.job2['grade'] = result[1].job2_grade

            if result[1].loadout ~= nil then
              userData.loadout = json.decode(result[1].loadout)
            end

            if result[1].position ~= nil then
              userData.lastPosition = json.decode(result[1].position)
            end

            cb2()

          end
        )

      end)
 table.insert(tasks2, function(cb2)

        MySQL.Async.fetchAll(
          'SELECT * FROM `jobs` WHERE `name` = @name',
          {
            ['@name'] = userData.job.name
          },
          function(result)

            userData.job['label'] = result[1].label

            cb2()

          end
        )

      end)
      -- Get job2 label
      table.insert(tasks2, function(cb2)

        MySQL.Async.fetchAll(
          'SELECT * FROM `jobs` WHERE `name` = @name',
          {
            ['@name'] = userData.job2.name
          },
          function(result)

            userData.job2['label'] = result[1].label

            cb2()

          end
        )

      end)
-- Get job grade data
      table.insert(tasks2, function(cb2)

        MySQL.Async.fetchAll(
          'SELECT * FROM `job_grades` WHERE `job_name` = @job_name AND `grade` = @grade',
          {
            ['@job_name'] = userData.job.name,
            ['@grade']    = userData.job.grade
          },
          function(result)

            userData.job['grade_name']   = result[1].name
            userData.job['grade_label']  = result[1].label
            userData.job['grade_salary'] = result[1].salary

            userData.job['skin_male']   = {}
            userData.job['skin_female'] = {}

            if result[1].skin_male ~= nil then
              userData.job['skin_male'] = json.decode(result[1].skin_male)
            end

            if result[1].skin_female ~= nil then
              userData.job['skin_female'] = json.decode(result[1].skin_female)
            end

            cb2()

          end
        )

      end)
	  
	  table.insert(tasks2, function(cb2)

        MySQL.Async.fetchAll(
          'SELECT * FROM `job_grades` WHERE `job_name` = @job_name AND `grade` = @grade',
          {
            ['@job_name'] = userData.job2.name,
            ['@grade']    = userData.job2.grade
          },
          function(result)

            userData.job2['grade_name']   = result[1].name
            userData.job2['grade_label']  = result[1].label
            userData.job2['grade_salary'] = result[1].salary

            userData.job2['skin_male']   = {}
            userData.job2['skin_female'] = {}

            if result[1].skin_male ~= nil then
              userData.job2['skin_male'] = json.decode(result[1].skin_male)
            end

            if result[1].skin_female ~= nil then
              userData.job2['skin_female'] = json.decode(result[1].skin_female)
            end

            cb2()

          end
        )

      end)

      Async.series(tasks2, cb)

    end)
-- Run Tasks
    Async.parallel(tasks, function(results)

      local xPlayer = CreateExtendedPlayer(player, userData.accounts, userData.inventory, userData.job, userData.job2, userData.loadout, userData.playerName, userData.lastPosition)

      xPlayer.getMissingAccounts(function(missingAccounts)

        if #missingAccounts > 0 then

          for i=1, #missingAccounts, 1 do
            table.insert(xPlayer.accounts, {
              name  = missingAccounts[i],
              money = 0,
              label = Config.AccountLabels[missingAccounts[i]]
            })
          end

          xPlayer.createAccounts(missingAccounts)
        end

        ESX.Players[_source] = xPlayer

        TriggerEvent('esx:playerLoaded', _source)

        TriggerClientEvent('esx:playerLoaded', _source, {
          identifier   = xPlayer.identifier,
          accounts     = xPlayer.getAccounts(),
          inventory    = xPlayer.getInventory(),
          job          = xPlayer.getJob(),
		  job2          = xPlayer.getJob2(),
          loadout      = xPlayer.getLoadout(),
          lastPosition = xPlayer.getLastPosition(),
          money        = xPlayer.get('money')
        })

        xPlayer.player.displayMoney(xPlayer.get('money'))

      end)

    end)

  end)

end)

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(),
    loadout      = xPlayer.getLoadout(),
    lastPosition = xPlayer.getLastPosition(),
    money        = xPlayer.get('money')
  })

end)

ESX.RegisterServerCallback('esx:getOtherPlayerData', function(source, cb, target)

  local xPlayer = ESX.GetPlayerFromId(target)

  cb({
    identifier   = xPlayer.identifier,
    accounts     = xPlayer.getAccounts(),
    inventory    = xPlayer.getInventory(),
    job          = xPlayer.getJob(),
    job2          = xPlayer.getJob2(),
    loadout      = xPlayer.getLoadout(),
    lastPosition = xPlayer.getLastPosition(),
    money        = xPlayer.get('money')
  })

end)

9) es_extended\server/paycheck.lua

ESX.StartPayCheck = function ()

  function payCheck ()
    local xPlayers = ESX.GetPlayers()

    for i=1, #xPlayers, 1 do
      local xPlayer = ESX.GetPlayerFromId(xPlayers[i])
      -- if xPlayer.job.grade_name == 'interim' or xPlayer.job.grade_name == 'rsa' or xPlayer.job.grade_name == 'employee' or xPlayer.job.grade_name == 'agent0' or xPlayer.job2.grade_name == 'agent0' or xPlayer.job2.grade_name == 'rsa' then -- Si il n'est pas dans une société, je prends chez l'état
        -- if xPlayer.job.grade_salary > 0 then
			-- xPlayer.addAccountMoney('bank',xPlayer.job.grade_salary)
			-- TriggerClientEvent('esx:showNotification', xPlayer.source, ('L\'état vous a payé ') .. '~g~$' .. xPlayer.job.grade_salary)
		
			-- TriggerEvent('esx_addonaccount:getSharedAccount', 'society_president', function (account)
			-- account.removeMoney(xPlayer.job.grade_salary)
			-- end)
		
        -- end
		-- end
     -- else -- Sinon je prends l'argent dans la société
	  for j=1,2,1 do
		if j ==1 then 
		if xPlayer.job.grade_name == 'interim' or xPlayer.job.grade_name == 'rsa' or xPlayer.job.grade_name == 'employee' or xPlayer.job.grade_name == 'agent0'  then -- Si il n'est pas dans une société, je prends chez l'état
			if xPlayer.job.grade_salary > 0 then
				xPlayer.addAccountMoney('bank',xPlayer.job.grade_salary)
				TriggerClientEvent('esx:showNotification', xPlayer.source, ('~b~SUBVENTION~s~<br>L\'état vous a payé : ~g~') .. xPlayer.job.grade_salary .. ' $')
			
				TriggerEvent('esx_addonaccount:getSharedAccount', 'society_president', function (account)
				account.removeMoney(xPlayer.job.grade_salary)
				end)
			
			end
		else
			TriggerEvent('esx_society:getSociety', xPlayer.job.name, function (society)
				TriggerEvent('esx_addonaccount:getSharedAccount', society.account, function (account)
					if account.money >= xPlayer.job.grade_salary then
					  xPlayer.addAccountMoney('bank',xPlayer.job.grade_salary)
					  account.removeMoney(xPlayer.job.grade_salary)
					 TriggerClientEvent('esx:showNotification', xPlayer.source,"~y~SALAIRE~s~<br>" .. xPlayer.job.label .. " vous a payé :" .. '<br>~g~' .. xPlayer.job.grade_salary .. ' $')
					else
					  TriggerClientEvent('esx:showNotification', xPlayer.source, 'Votre entreprise n\'a plus d\'argent pour vous payer !')
					end
			
				end)
			end) 
		end
	 else
	 if xPlayer.job2.grade_name == 'agent0' or xPlayer.job2.grade_name == 'rsa' then -- Si il n'est pas dans une société, je prends chez l'état
        if xPlayer.job2.grade_salary > 0 then
			xPlayer.addAccountMoney('bank',xPlayer.job2.grade_salary)
			TriggerClientEvent('esx:showNotification', xPlayer.source, ('~b~SUBVENTION~s~<br>L\'état vous a payé : ~g~') .. xPlayer.job2.grade_salary .. ' $')
		
			TriggerEvent('esx_addonaccount:getSharedAccount', 'society_president', function (account)
			account.removeMoney(xPlayer.job2.grade_salary)
			end)
		
        end
		else
        TriggerEvent('esx_society:getSociety', xPlayer.job2.name, function (society)
			TriggerEvent('esx_addonaccount:getSharedAccount', society.account, function (account)
				if account.money >= xPlayer.job2.grade_salary then
					xPlayer.addAccountMoney('bank',xPlayer.job2.grade_salary)
					account.removeMoney(xPlayer.job2.grade_salary)
					TriggerClientEvent('esx:showNotification', xPlayer.source,"~y~SALAIRE~s~<br>" .. xPlayer.job2.label .. " vous a payé :" .. '<br>~g~' .. xPlayer.job2.grade_salary .. ' $')
				else
					TriggerClientEvent('esx:showNotification', xPlayer.source, 'Votre entreprise n\'a plus d\'argent pour vous payer !')
				end
		
			end)
		end) 	  
	  end
	  
	end
    end
    --end
	end
	

    SetTimeout(Config.PaycheckInterval, payCheck)
  end
  SetTimeout(Config.PaycheckInterval, payCheck)
end

10) esx_society\client/client.lua

function OpenEmployeeList2(society)

  ESX.TriggerServerCallback('esx_society:getEmployees2', function(employees)

    local elements = {
      head = {_U('employee'), _U('grade'), _U('actions'),'Principal ou Secondaire'},
      rows = {}
    }

    for i=1, #employees, 1 do

      local gradeLabel = (employees[i].job2.grade_label == '' and employees[i].job2.label or employees[i].job2.grade_label)

      table.insert(elements.rows, {
        data = employees[i],
        cols = {
          employees[i].name,
          gradeLabel,
          '{{' .. _U('promote') .. '|promote}} {{' .. _U('fire') .. '|fire}}',"Emploi Secondaire"
        }
      })
    end

    ESX.UI.Menu.Open(
      'list', GetCurrentResourceName(), 'employee_list_' .. society,
      elements,
      function(data, menu)

        local employee = data.data

        if data.value == 'promote' then
          menu.close()
          OpenPromoteMenu2(society, employee)
        end

        if data.value == 'fire' then

          TriggerEvent('esx:showNotification', _U('you_have_fired', employee.name))

          ESX.TriggerServerCallback('esx_society:setJob2', function()
            OpenEmployeeList2(society)
          end, employee.identifier, 'unemployed2', 0, 'fire')

        end

      end,
      function(data, menu)
        menu.close()
        OpenManageEmployeesMenu2(society)
      end
    )

  end, society)

end

function OpenRecruitMenu2(society)

  ESX.TriggerServerCallback('esx_society:getOnlinePlayers', function(players)

    local elements = {}

    for i=1, #players, 1 do
      if players[i].job2.name ~= society then
        table.insert(elements, {label = players[i].name, value = players[i].source, name = players[i].name, identifier = players[i].identifier})
      end
    end

    ESX.UI.Menu.Open(
      'default', GetCurrentResourceName(), 'recruit_' .. society,
      {
        title    = _U('recruiting'),
        elements = elements
      },
      function(data, menu)

        ESX.UI.Menu.Open(
          'default', GetCurrentResourceName(), 'recruit_confirm_' .. society,
          {
            title    = _U('do_you_want_to_recruit', data.current.name),
            elements = {
              {label = _U('yes'), value = 'yes'},
              {label = _U('no'),  value = 'no'},
            }
          },
          function(data2, menu2)

            menu2.close()

            if data2.current.value == 'yes' then

              TriggerEvent('esx:showNotification', _U('you_have_hired', data.current.name))

              ESX.TriggerServerCallback('esx_society:setJob2', function()
                OpenRecruitMenu2(society)
              end, data.current.identifier, society, 0, 'hire')

            end

          end,
          function(data2, menu2)
            menu2.close()
          end
        )

      end,
      function(data, menu)
        menu.close()
      end
    )

  end)

end

function OpenPromoteMenu2(society, employee)

  ESX.TriggerServerCallback('esx_society:getJob2', function(job2)

    local elements = {}

    for i=1, #job2.grades, 1 do
      local gradeLabel = (job2.grades[i].label == '' and job2.label or job2.grades[i].label)
      table.insert(elements, {label = gradeLabel, value = job2.grades[i].grade, selected = (employee.job2.grade == job2.grades[i].grade)})
    end

    ESX.UI.Menu.Open(
      'default', GetCurrentResourceName(), 'promote_employee_' .. society,
      {
        title    = _U('promote_employee', employee.name),
        elements = elements
      },
      function(data, menu)
        menu.close()

        TriggerEvent('esx:showNotification', _U('you_have_promoted', employee.name, data.current.label))

        ESX.TriggerServerCallback('esx_society:setJob2', function()
          OpenEmployeeList2(society)
        end, employee.identifier, society, data.current.value, 'promote')

      end,
      function(data, menu)
        menu.close()
        OpenEmployeeList2(society)
      end
    )

  end, society)

end

function OpenManageGradesMenu2(society)

  ESX.TriggerServerCallback('esx_society:getJob2', function(job2)

    local elements = {}

    for i=1, #job2.grades, 1 do
      local gradeLabel = (job2.grades[i].label == '' and job2.label or job2.grades[i].label)
      table.insert(elements, {label = gradeLabel .. ' $' .. job2.grades[i].salary, value = job2.grades[i].grade})
    end

    ESX.UI.Menu.Open(
      'default', GetCurrentResourceName(), 'manage_grades_' .. society,
      {
        title    = _U('salary_management'),
        elements = elements
      },
      function(data, menu)

        ESX.UI.Menu.Open(
          'dialog', GetCurrentResourceName(), 'manage_grades_amount_' .. society,
          {
            title = _U('salary_amount')
          },
          function(data2, menu2)

            local amount = tonumber(data2.value)

            if amount == nil then
              ESX.ShowNotification(_U('invalid_amount'))
            elseif amount >= Config.MaxSalary then
              ESX.ShowNotification(_U('invalid_amount_max'))
            else
              menu2.close()

              ESX.TriggerServerCallback('esx_society:setJobSalary', function()
                OpenManageGradesMenu(society)
              end, society, data.current.value, amount)
            end

          end,
          function(data2, menu2)
            menu2.close()
          end
        )

      end,
      function(data, menu)
        menu.close()
      end
    )

  end, society)

end
RegisterNetEvent('esx:playerLoaded')
AddEventHandler('esx:playerLoaded', function(xPlayer)
  
  PlayerData = xPlayer

  DisableSocietyMoneyHUDElement()
  DisableSociety2MoneyHUDElement()

  if PlayerData.job.grade_name == 'boss' then
    
    EnableSocietyMoneyHUDElement()
  
    ESX.TriggerServerCallback('esx_society:getSocietyMoney', function(money)
      UpdateSocietyMoneyHUDElement(money)
    end, PlayerData.job.name)

  end
    if PlayerData.job2.grade_name == 'boss' then
    
    EnableSociety2MoneyHUDElement()
  
    ESX.TriggerServerCallback('esx_society:getSocietyMoney', function(money)
      UpdateSociety2MoneyHUDElement(money)
    end, PlayerData.job2.name)

  end

end)

RegisterNetEvent('esx:setJob')
AddEventHandler('esx:setJob', function(job)

  PlayerData.job = job

  DisableSocietyMoneyHUDElement()
 -- DisableSociety2MoneyHUDElement()

  if PlayerData.job.grade_name == 'boss' then
    
    EnableSocietyMoneyHUDElement()
  
    ESX.TriggerServerCallback('esx_society:getSocietyMoney', function(money)
      UpdateSocietyMoneyHUDElement(money)
    end, PlayerData.job.name)

  end


end)
RegisterNetEvent('esx:setJob2')
AddEventHandler('esx:setJob2', function(job)

  PlayerData.job2 = job


  DisableSociety2MoneyHUDElement()


  if PlayerData.job2.grade_name == 'boss' then
    
    EnableSociety2MoneyHUDElement()
  
    ESX.TriggerServerCallback('esx_society:getSocietyMoney', function(money)
      UpdateSociety2MoneyHUDElement(money)
    end, PlayerData.job2.name)

  end

end)
RegisterNetEvent('esx_addonaccount:setMoney')
AddEventHandler('esx_addonaccount:setMoney', function(society, money)

  if PlayerData.job ~= nil and PlayerData.job.grade_name == 'boss' and 'society_' .. PlayerData.job.name == society then
    UpdateSocietyMoneyHUDElement(money)
  end
  if PlayerData.job2 ~= nil and PlayerData.job2.grade_name == 'boss' and 'society_' .. PlayerData.job2.name == society then
    UpdateSociety2MoneyHUDElement(money)
  end
end)

11) DBG_LesterJobs/server/main.lua - This is where you can pick your second job

RegisterServerEvent('DBG_LesterJobs:setJob')
AddEventHandler('DBG_LesterJobs:setJob', function(job)
	local _source = source
	local xPlayer = ESX.GetPlayerFromId(_source)
	xPlayer.setJob2(job, 0)
end)

12) Modify your job client script
a- always add this:

RegisterNetEvent('esx:setJob2')
AddEventHandler('esx:setJob2', function(job2)
  ESX.PlayerData.job2 = job2
end)

b- remplace

if PlayerData.job ~=nil and PlayerData.job.name=='police' then

with

if (PlayerData.job ~=nil and PlayerData.job.name=='police') or (PlayerData.job2 ~=nil and PlayerData.job2.name=='police') then

13)esx_society client/main.lua

function EnableSocietyMoneyHUDElement()

  local societyMoneyHUDElementTpl = '<div><img src="' .. base64MoneyIcon .. '" style="width:20px; height:20px; vertical-align:middle;">&nbsp;{{money}}</div>'

  ESX.UI.HUD.RegisterElement('society_money', 3, 0, societyMoneyHUDElementTpl, {
    money = 0
  })

end
function EnableSociety2MoneyHUDElement()

  local society2MoneyHUDElementTpl = '<div><img src="' .. base64MoneyIcon .. '" style="width:20px; height:20px; vertical-align:middle;">&nbsp;{{money}}</div>'

  ESX.UI.HUD.RegisterElement('society2_money', 3, 0, society2MoneyHUDElementTpl, {
    money = 0
  })

end
function DisableSocietyMoneyHUDElement()
  ESX.UI.HUD.RemoveElement('society_money')
end
function DisableSociety2MoneyHUDElement()
  ESX.UI.HUD.RemoveElement('society2_money')
end
function UpdateSocietyMoneyHUDElement(money)

  ESX.UI.HUD.UpdateElement('society_money', {
    money = money
  })

end
function UpdateSociety2MoneyHUDElement(money)

  ESX.UI.HUD.UpdateElement('society2_money', {
    money = money
  })

end
  if options.employees then
    table.insert(elements, {label = _U('employee_management'), value = 'manage_employees'})
  end
  if options.employees then
    table.insert(elements, {label = 'Gestion employés 2', value = 'manage_employees2'})
  end

then had where you have to

 if data.current.value == 'manage_employees2' then
        OpenManageEmployeesMenu2(society)
      end
function OpenManageEmployeesMenu2(society)

  ESX.UI.Menu.Open(
    'default', GetCurrentResourceName(), 'manage_employees2_' .. society,
    {
      title    = _U('employee_management'),
      elements = {
        {label = _U('employee_list'), value = 'employee_list'},
        {label = _U('recruit'),       value = 'recruit'},
      }
    },
    function(data, menu)

      if data.current.value == 'employee_list' then
        OpenEmployeeList2(society)
      end

      if data.current.value == 'recruit' then
        OpenRecruitMenu2(society)
      end

    end,
    function(data, menu)
      menu.close()
    end
  )

end

14)Enjoy


[Request] I need a Faction system or 2 jobs system... [In ESX]
#2

For the Load problem you should not being getting the second job the right way when the player connects, show me this function in es_extended/server.lua:

AddEventHandler('es:playerLoaded', function(source, _player)

#3

Already done :cry: but you may have put your finger on the issue. I may have an issue while calling results with [1] that I dont understand very well

** L1-L14 es_extended/server/main.lua**

AddEventHandler('es:playerLoaded', function(source, _player)

  local _source = source
  local tasks   = {}

  local userData = {
    accounts     = {},
    inventory    = {},
    job          = {},
    job2          = {},
    loadout      = {},
    playerName   = GetPlayerName(_source),
    lastPosition = nil
  }

**L149-243 es_extended/server/main.lua **

    -- Get job and loadout
    table.insert(tasks, function(cb)

      local tasks2 = {}

      -- Get job name, grade and last position
      table.insert(tasks2, function(cb2)

        MySQL.Async.fetchAll(
          'SELECT * FROM `users` WHERE `identifier` = @identifier',
          {
            ['@identifier'] = player.getIdentifier()
          },
          function(result)

            userData.job['name']  = result[1].job
			userData.job2['name']  = result[1].job2
            userData.job['grade'] = result[1].job_grade
			userData.job2['grade'] = result[1].job2_grade

            if result[1].loadout ~= nil then
              userData.loadout = json.decode(result[1].loadout)
            end

            if result[1].position ~= nil then
              userData.lastPosition = json.decode(result[1].position)
            end

            cb2()

          end
        )

      end)

      -- Get job label
      table.insert(tasks2, function(cb2)

        MySQL.Async.fetchAll(
          'SELECT * FROM `jobs` WHERE `name` = @name', 
          {
            ['@name'] = userData.job.name,
			['@name'] = userData.job2.name
          },
          function(result)

            userData.job['label'] = result[1].label
			userData.job2['label'] = result[1].label

            cb2()

          end
        )

      end)

      -- Get job grade data
      table.insert(tasks2, function(cb2)

        MySQL.Async.fetchAll(
          'SELECT * FROM `job_grades` WHERE `job_name` = @job_name AND `grade` = @grade',
          {
            ['@job_name'] = userData.job.name,
			['@job_name'] = userData.job2.name,
            ['@grade']    = userData.job.grade,
			['@grade']    = userData.job2.grade
          },
          function(result)

            userData.job['grade_name']   = result[1].name
            userData.job['grade_label']  = result[1].label
            userData.job['grade_salary'] = result[1].salary
			userData.job2['grade_name']   = result[1].name
            userData.job2['grade_label']  = result[1].label
            userData.job2['grade_salary'] = result[1].salary
            userData.job['skin_male']   = {}
            userData.job['skin_female'] = {}

            if result[1].skin_male ~= nil then
              userData.job['skin_male'] = json.decode(result[1].skin_male)
            end

            if result[1].skin_female ~= nil then
              userData.job['skin_female'] = json.decode(result[1].skin_female)
            end

            cb2()

          end
        )

      end)

      Async.series(tasks2, cb)

    end)

 -- Run Tasks
    Async.parallel(tasks, function(results)

      local xPlayer = CreateExtendedPlayer(player, userData.accounts, userData.inventory, userData.job, userData.job2, userData.loadout, userData.playerName, userData.lastPosition)

      xPlayer.getMissingAccounts(function(missingAccounts)

        if #missingAccounts > 0 then

          for i=1, #missingAccounts, 1 do
            table.insert(xPlayer.accounts, {
              name  = missingAccounts[i],
              money = 0,
              label = Config.AccountLabels[missingAccounts[i]]
            })
          end

          xPlayer.createAccounts(missingAccounts)
        end

        ESX.Players[_source] = xPlayer

        TriggerEvent('esx:playerLoaded', _source)

        TriggerClientEvent('esx:playerLoaded', _source, {
          identifier   = xPlayer.identifier,
          accounts     = xPlayer.getAccounts(),
          inventory    = xPlayer.getInventory(),
          job          = xPlayer.getJob(),
		  job2          = xPlayer.getJob2(),
          loadout      = xPlayer.getLoadout(),
          lastPosition = xPlayer.getLastPosition(),
          money        = xPlayer.get('money')
        })

        xPlayer.player.displayMoney(xPlayer.get('money'))

      end)

    end)

  end)

end)

#4

I think this may solve the problem, test it

-- Get job label
      table.insert(tasks2, function(cb2)

        MySQL.Async.fetchAll(
          'SELECT * FROM `jobs` WHERE `name` = @name',
          {
            ['@name'] = userData.job.name
          },
          function(result)

            userData.job['label'] = result[1].label

            cb2()

          end
        )

      end)
      -- Get job2 label
      table.insert(tasks2, function(cb2)

        MySQL.Async.fetchAll(
          'SELECT * FROM `jobs` WHERE `name` = @name',
          {
            ['@name'] = userData.job2.name
          },
          function(result)

            userData.job2['label'] = result[1].label

            cb2()

          end
        )

      end)

      -- Get job grade data
      table.insert(tasks2, function(cb2)

        MySQL.Async.fetchAll(
          'SELECT * FROM `job_grades` WHERE `job_name` = @job_name AND `grade` = @grade',
          {
            ['@job_name'] = userData.job.name,
            ['@grade']    = userData.job.grade
          },
          function(result)

            userData.job['grade_name']   = result[1].name
            userData.job['grade_label']  = result[1].label
            userData.job['grade_salary'] = result[1].salary

            userData.job['skin_male']   = {}
            userData.job['skin_female'] = {}

            if result[1].skin_male ~= nil then
              userData.job['skin_male'] = json.decode(result[1].skin_male)
            end

            if result[1].skin_female ~= nil then
              userData.job['skin_female'] = json.decode(result[1].skin_female)
            end

            cb2()

          end
        )

      end)
	  
	  table.insert(tasks2, function(cb2)

        MySQL.Async.fetchAll(
          'SELECT * FROM `job_grades` WHERE `job_name` = @job_name AND `grade` = @grade',
          {
            ['@job_name'] = userData.job2.name,
            ['@grade']    = userData.job2.grade
          },
          function(result)

            userData.job2['grade_name']   = result[1].name
            userData.job2['grade_label']  = result[1].label
            userData.job2['grade_salary'] = result[1].salary

            userData.job2['skin_male']   = {}
            userData.job2['skin_female'] = {}

            if result[1].skin_male ~= nil then
              userData.job2['skin_male'] = json.decode(result[1].skin_male)
            end

            if result[1].skin_female ~= nil then
              userData.job2['skin_female'] = json.decode(result[1].skin_female)
            end

            cb2()

          end
        )

      end)

      Async.series(tasks2, cb)

    end)

#5

Man I even don’t have words to say thank you … The minimum I can do is to credit you for the release !

Thank you @Cheleber


#6

No problem mate, you were getting the job1 for the two jobs! Awesome release by the way!


#7

Let me until tomorrow to prepare a correct post with all the modifications to be done.
-I will include modifications for 1 complete job usable as job2 (as an exemple that others could use for others scripts and jobs)
-I have to finish the boss management when getting the job2.grade=boss

Its should not be hard, just including most of function in a bigger loop like

for j=1,2,1 do
local job=job[j]

functions...

end

#8

Nice!

For the second thing i dont know if i get you, but how about this idea:

Create a function equal to “OpenBossMenu” .

function OpenBossMenu2(society, close, options)

AddEventHandler('esx_society:openBossMenu2', function(society, close, options)
  OpenBossMenu2(society, close, options)
end)

EDIT: Other functions that maybe need to be replicate:

function OpenManageGradesMenu(society)
function OpenPromoteMenu(society, employee)
function OpenRecruitMenu(society)
function OpenEmployeeList(society)
function OpenManageEmployeesMenu(society)

#9

How you do to get in job2 in the database?


#10

He created a job2 and jo2_grade column in the table users


#11

It’s a good idea. Its there a way to not getting limitations when checking the job2 for players getting the same job but as job1

function OpenBossMenu(society, close, options)

AddEventHandler('esx_society:openBossMenu', function(society, close, options)
  OpenBossMenu(society, close, options)
end)

function OpenManageGradesMenu(society)
function OpenPromoteMenu(society, employee)
function OpenRecruitMenu(society)
function OpenEmployeeList(society)
function OpenManageEmployeesMenu(society)

Correct, for this reason OpenBossMenu Should check players’s jobs 1 and 2.
To be able to Promote/Recruit/get list/and manage all players getting the job as job1 or job2

Or do you think that it would be better to split it as 2 different functions openbossmenu and openbossmenu ?


#12

job2.sql

ALTER TABLE users ADD job2 varchar(255) NULL DEFAULT 'unemployed2' AFTER job_grade;
ALTER TABLE users ADD job2_grade INT NULL DEFAULT 0 AFTER job2;

Unemployed 2 was added to the jobs and job_grades tables

table jobs:
55 unemployed2 unemploi 0 1

table job_grades:
247 unemployed2 0 rsa Citoyen 0 {} {}


#13

For now i cant answer your question, what is better or not, I just took a look and I did not see anything very premonized!
Here it’s late and I’m tired, I’ll take a closer look tomorrow if you have not already done this of course!

EDITED:
And i have take another look now, and yes you probably dont need to replicate the OpenBossMenu function, but you need to send the information if it is a job1 or a job2! And then just replicate the promote/recruit/get list/manage functions!

Like this

function OpenBossMenu(society, close, options, jobnumber)

AddEventHandler('esx_society:openBossMenu', function(society, close, options, jobnumber)
  OpenBossMenu(society, close, options, jobnumber)
end)

#14

Update 3

Its working with the modified job esx_ambulancejob !


#15

is this something you want to share?


#16

Where is the release. i so need this.


#17

Maybe it will be shared, its finished for our servers, but we need to do a release resource, so everybody can use it, right now i am away from fivem, maybe @Tomtom wants to continue the work


#18

So whaat upp guys ??!? any major bugs or can we get this sexy thing soon :smiley: :yum: Look’s rly great !


#19

can’t wait to test it


#20

I hope this will be available soon for a testing period, it looks great and would be really good to have.