❓How to Create Job2 on ESX

This guide will walk you through the process of adding this functionality directly to your ESX core.

triangle-exclamation

Step 1 - Modify the Database Schema

First, we need to tell the database to store the new job2 and job_grade2 information for each player. We'll do this by adding two new columns to the users table.

Run the following SQL query in your database management tool (like phpMyAdmin, HeidiSQL, or through a console command).

ALTER TABLE `users`
    ADD COLUMN `job2` VARCHAR(20) DEFAULT 'unemployed',
    ADD COLUMN `job_grade2` INT(11) DEFAULT 0;

Step 2 - Add the Client-Side Event Handler

Now, we need to teach the client-side part of the script how to handle updates to the player's secondary job. This ensures the player's data updates in real-time without needing to relog.

  1. Navigate to: es_extended/client/modules/events.lua

  2. Add the following code block to the file. This listens for a secure network event from the server and updates the local player data accordingly.

ESX.SecureNetEvent("esx:setJob2", function(Job2)
    ESX.SetPlayerData('job2', Job2)
end)

Step 3 - Overhaul the Server-Side Player Loading

This is the most involved step. We need to modify the server-side code to load, validate, and manage the secondary job data when a player connects.

3.1. Update the Database Query

We first need to tell the server to request the new job2 and job_grade2 columns from the database.

  1. Navigate to: es_extended/server/main.lua

  2. Find the line that begins with local loadPlayer =.

  3. Replace it with the following line to include the new columns in the selection:

3.2. Integrate Job2 into the Player Object

Next, we need to integrate the loaded data into the ESX player object, mirroring the functionality of the primary job.

  1. Inside the same file, find the function function loadESXPlayer.

  2. Locate the section where the primary job data is loaded and validated (look for local job, grade =).

  3. After the block of code for the primary job (you'll see an end statement), add the following code for job2:

3.3. Modify the Player Constructor

Now, we need to pass this new userData.job2 into the function that creates the player object.

  1. Find the line: local xPlayer = CreateExtendedPlayer(

  2. In the list of arguments being passed, locate userData.job.

  3. Add userData.job2 as a new argument immediately after it.

3.4. Update Server Callbacks

Finally, we need to ensure the job2 data is included when other scripts request player information. We'll update two key callbacks.

  1. Find the callback: ESX.RegisterServerCallback("esx:getPlayerData"

  2. Inside the callback function, locate where the data table is built (cb({...})).

  3. Add a line for job2 right after the line for job.

  1. Repeat this process for the other player data callback: ESX.RegisterServerCallback("esx:getOtherPlayerData".

Step 4 - Ensure Data is Saved Correctly

Now that the server can load job2 data, we must ensure it gets saved back to the database properly. We'll update the functions responsible for saving player data, both for individual players and for bulk saves.

4.1. Update the Single Player Save Function

  1. Navigate to: es_extended/server/functions.lua

  2. Find the function function Core.SavePlayer(xPlayer, cb).

  3. Replace the entire function with the following code. The key changes are adding xPlayer.job2.name and xPlayer.job2.grade to the SQL parameters.

4.2. Update the Bulk Save Function

This function saves all online players at once, typically during a server restart.

  1. In the same file, find the function function Core.SavePlayers(cb).

  2. Replace the entire function with the code below. Again, we add the job2 data to the parameters for every player.

Step 5 - Extend the Player Class

The final step is to fully integrate job2 into the core Player object. This involves modifying its constructor, state bags, and adding methods to get and set the secondary job.

  1. Navigate to: es_extended/server/classes/player.lua

5.1. Modify the Constructor

We need to accept the job2 parameter when a player object is created and store it internally.

  1. Find the CreateExtendedPlayer function definition.

  2. Add job2 to the list of parameters.

  1. Inside the function, find where self.job = job is set.

  2. Add a line directly below it to store the secondary job.

5.2. Add State Bag Support

State bags allow data to be efficiently synchronized between the server and client. We need to add one for job2.

  1. Find the line: stateBag:set("job", self.job, true)

  2. Add a new line below it to create a state bag for job2.

5.3. Create a Getter Function

We need a method for other scripts to retrieve the player's job2 data.

  1. Find the function function self.getJob().

  2. Add a new function directly below it to get the secondary job.

5.4. Create a Setter Function

This is the most crucial part. We need a method to change a player's job2, which will handle validation, update the player object, trigger events, and sync the change to the client instantly.

  1. Find the function function self.setJob(newJob, grade, onDuty).

  2. Add a new function directly below it to set the secondary job. This function mirrors the logic of setJob but for the job2 property.

Step 6 - Create an Admin Command for Testing

Now let's add a convenient admin command. This will allow you to change a player's secondary job on the fly.

  1. Navigate to: es_extended/server/modules/commands.lua

  2. Register a new command by adding the following code block to the file. This leverages the setJob2 function we created in the previous step.

πŸŽ‰ Implementation Complete!

You have now successfully integrated a complete secondary job system into your ESX framework. The functionality includes:

  • Database Storage: Saving and loading from the users table.

  • Client-Sync: Real-time updates via events and state bags.

  • Server-Side API: Methods to get and set a player's job2.

  • Persistence: Data is correctly saved during manual and automatic save operations.

  • Accessibility: An admin command for easy testing and management.

Important Final Note: The job2 system works by reusing your existing jobs and job_grades database tables. This is a efficient design choice. It means you can assign any job you've already defined (e.g., 'police', 'mechanic', 'gang') to a player as either their primary job (job) or their secondary job (job2). They are separate slots that draw from the same list of available occupations.

To test your work:

  1. Restart your server.

  2. Join your server.

  3. Use the command: /setjob2 [PLAYER_ID] [JOB2_NAME] [JOB2_GRADE]

    • Example: /setjob2 1 gang 0

If everything is configured correctly, the target player's secondary job will update immediately, and the change will be saved to the database. You can now use xPlayer.setJob2('gangname', 0) in your server scripts and ESX.PlayerData.job2 in your client scripts, just like you would with the primary job.

Last updated