FiveM Docs
Addons

esx_society

esx_society adds shared job accounts, the boss menu, hiring, salaries, grade labels, uniforms and money washing to ESX Legacy. Full API and config reference.

esx_society turns an ESX job into a company. It links a job to a shared bank account, adds a boss menu for hiring, firing, promotions, salaries, grade labels and uniforms, and lets bosses launder black money into the company account. Job resources such as esx_policejob, esx_taxijob and esx_mechanicjob register their society with it and open its boss menu.

Overview

FactValue
Resourceesx_society
SideServer (API, validation, money) and client (boss menu)
Dependenciesesx_lib, es_extended, cron, esx_addonaccount
Uses at runtimeoxmysql, esx_datastore (society garage), skinchanger (uniform saving)
SQLesx_society.sql (society_moneywash table)

A society is a plain record kept in memory:

FieldTypeDescription
namestringJob name, for example taxi. Must match jobs.name.
labelstringDisplay name.
accountstringShared esx_addonaccount account, usually society_<job>.
datastorestringShared esx_datastore store, usually society_<job>. Used for the society garage.
inventorystringShared esx_addoninventory inventory, usually society_<job>.
datatableFree-form options. The official jobs pass { type = 'public' } or { type = 'private' }. esx_society stores this table but does not read it.

Societies are not saved in the database. Every job resource must register its society again on every start.

Installation

Install the dependencies

Make sure oxmysql, es_extended, esx_lib, cron and esx_addonaccount are installed. Install esx_datastore and esx_addoninventory too, because the official job resources create society datastores and inventories.

Import the SQL

Import esx_society.sql. It creates the society_moneywash table. On start, esx_society also creates society_moneywash_operations and an index esx_society_employees on users (job, job_grade, identifier) by itself.

esx_society.sql
CREATE TABLE `society_moneywash` (
	`id` int NOT NULL AUTO_INCREMENT,
	`identifier` varchar(60) NOT NULL,
	`society` varchar(60) NOT NULL,
	`amount` int NOT NULL,
	PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

Start it before every job resource

server.cfg
ensure cron
ensure esx_addonaccount
ensure esx_datastore
ensure esx_addoninventory
ensure esx_society
# job resources after this line
ensure esx_policejob
ensure esx_taxijob

InnoDB required for money washing

On start the money wash module checks that users, society_moneywash and addon_account_data use the InnoDB engine. If one does not, it prints [esx_society] Moneywash disabled: ... and every wash request fails with "invalid amount". The rest of the resource keeps working.

Configuration

All keys live in config.lua.

KeyDefaultDescription
Config.LocaleGetConvar('esx:locale', 'en')Language of the menus and notifications.
Config.EnableESXIdentitytrueShow firstname lastname from the users table in the employee list. Set to false if you do not use esx_identity.
Config.MaxSalary3500Highest salary a boss can set for a grade. Must be a whole number from 0 up to this value.
Config.MaxJobGradeLabelLength40Grade labels set by bosses are trimmed to this length.
Config.JobGradeUpdateCooldown1500Minimum delay in ms between two salary or label changes by the same boss for the same job. 0 disables the limit.
Config.SocietyGarageDistance12.0Max distance in meters from a garage zone for the society garage events.
Config.SocietyGarageZonesmechanic and taxi zonesPer-society list of vector3 points where the society garage may be used.
Config.BossGrades{ ['boss'] = true }Grade names (job_grades.name) that get boss access. Add more names to give access to several grades.
Config.EnableUniformManagementfalseShow uniform management in every boss menu. You can also enable it per job with the uniforms option.
Config.UniformSaveCooldown30000Minimum delay in ms between two uniform saves for the same job.
Config.UniformDrawableMax2000Highest accepted drawable ID for clothing components. Keep it high for custom clothing packs.
Config.UniformTextureMax255Highest accepted texture ID (components ending in _2).
Config.UniformPropMax255Highest accepted prop ID for helmet_1, glasses_1, watches_1, bracelets_1 and ears_1. Props may also be -1 (none).
Config.UniformComponentLimits{}Per-component overrides, for example helmet_1 = { min = -1, max = 250 }.
Config.UniformComponents30 skin keysThe skinchanger components that make up a uniform: tshirt_1 … ears_2. A saved uniform must contain every one of them.
config.lua
Config.BossGrades = {
    ['boss'] = true,
    ['chef'] = true,   -- give a second grade access to the boss menu
}

How it works

  • Boss check: a player has boss access to a society when xPlayer.getJob().name == society.name and the grade name is in Config.BossGrades. Every server event and callback repeats this check. The client menu is only a view.
  • Account: balance, deposits and withdrawals go through the shared esx_addonaccount account named in society.account.
  • Salaries and labels are written to job_grades and then reloaded with ESX.RefreshJob(job) (or ESX.RefreshJobs() as fallback), so changes apply without a restart.
  • Employees are listed in pages of 50: online players first, then offline players from the users table.
  • Money washing is queued in society_moneywash_operations and paid by a cron task every day at 03:00 (TriggerEvent('cron:runAt', 3, 0, WashMoneyCRON)).
  • Society payouts: when es_extended's Config.EnableSocietyPayouts is true, the paycheck module calls esx_society:getSociety and pays salaries from the society account. See Money and accounts.

Server API

registerSociety (export and event)

Registers a job as a society. Call it once when your job resource starts.

exports.esx_society:registerSociety(name, label, account, datastore, inventory, data)
TriggerEvent('esx_society:registerSociety', name, label, account, datastore, inventory, data)
NameTypeDescription
namestringJob name.
labelstringDisplay label.
accountstringShared addon account name.
datastorestringShared datastore name.
inventorystringShared addon inventory name.
datatableFree options, for example { type = 'private' }.

Returns nothing. Registering the same name twice prints a warning and keeps the first entry.

server/main.lua
exports.esx_society:registerSociety('taxi', 'Taxi', 'society_taxi', 'society_taxi', 'society_taxi', { type = 'public' })

The event is a local server event (AddEventHandler). Clients cannot trigger it.

GetSociety (export)

local society = exports.esx_society:GetSociety(name)
NameTypeDescription
namestringSociety (job) name.

Returns the society table or nil.

server/main.lua
local society = exports.esx_society:GetSociety('police')

if society then
    TriggerEvent('esx_addonaccount:getSharedAccount', society.account, function(account)
        print(('%s has $%s'):format(society.label, account.money))
    end)
end

esx_society:getSociety (event)

Callback style lookup, used by es_extended's paycheck module.

TriggerEvent('esx_society:getSociety', name, cb)
NameTypeDescription
namestringSociety name.
cbfunctionReceives the society table or nil.

esx_society:getSocieties (event)

TriggerEvent('esx_society:getSocieties', function(societies)
    for _, society in ipairs(societies) do
        print(society.name, society.account)
    end
end)

Returns the array of all registered societies.

Client API

esx_society:openBossMenu

Opens the boss menu (ESX context menu). Use it from a marker or target zone in your job resource.

TriggerEvent('esx_society:openBossMenu', society, close, options)
NameTypeDescription
societystringSociety name. Must equal the player's job name.
closefunction or nilPassed to ESX.OpenContext as the close handler of the main menu. Called when the player closes it.
optionstable or nilMenu entries to show. Missing keys use the defaults below.
OptionDefaultEntry
checkBaltrueCheck society balance
withdrawtrueWithdraw money
deposittrueDeposit money
washtrueWash black money
employeestrueEmployee list and recruiting
salarytrueSalary per grade
gradestrueRename grade labels
uniformsConfig.EnableUniformManagementSave the worn outfit as a grade uniform
client/main.lua
TriggerEvent('esx_society:openBossMenu', 'taxi', function()
    ESX.CloseContext()
end, { wash = false, uniforms = true })

The menu first asks the server through the esx_society:isBoss callback. Non-bosses see nothing.

Network events (client to server)

These are RegisterServerEvent handlers, so any client can send them. All of them validate on the server.

Security

Each event below is reachable from a modified client. The checks listed are what protects you. If you fork esx_society, keep them.

EventParametersServer checks
esx_society:checkSocietyBalancesocietyBoss access to that society. Shows the balance as a notification.
esx_society:withdrawMoneysociety, amountSociety exists, amount is a positive number (rounded), boss access, account has enough money.
esx_society:depositMoneysociety, amountSociety exists, positive amount, player's job equals the society (any grade), player has the cash.
esx_society:washMoneysociety, amountPositive amount, boss access, enough black_money, wash module ready.
esx_society:putVehicleInGaragesociety, vehicleSame job, within Config.SocietyGarageDistance of a Config.SocietyGarageZones point, valid plate, the player is in or next to (10 m) a vehicle with that plate and model. Deletes the entity and stores it in the society datastore key garage.
esx_society:removeVehicleFromGaragesociety, vehicleSame job and garage zone checks, valid plate. Removes the entry from garage.
client/main.lua
TriggerServerEvent('esx_society:depositMoney', 'taxi', 500)

depositMoney only requires the job, not a boss grade. Every employee can pay into the company account, even though the boss menu shows the button only to bosses.

Server callbacks

Registered with xLib.callback.registerCompat. Call them with ESX.TriggerServerCallback, ESX.AwaitServerCallback or xLib.callback. See Callbacks.

CallbackArgumentsReturnsAccess
esx_society:isBossjobbooleanCaller's own job and boss grade.
esx_society:getSocietyMoneysocietynumber (0 when denied)Boss of that society.
esx_society:getEmployeessociety, cursor?employees, nextCursorBoss of that society. One request per player at a time.
esx_society:getOnlinePlayerssocietyarray of { source, identifier, name, job = { name, grade, grade_name } }Boss of that society. Cached for 1 second.
esx_society:getJobjobjob table with grades sorted by grade, or falseNo check. Returns public job data.
esx_society:setJobidentifier, job, grade, actionTypebooleanBoss. See below.
esx_society:setJobSalaryjob, grade, salarybooleanBoss of that job, valid grade, salary 0 to Config.MaxSalary, cooldown.
esx_society:setJobLabeljob, grade, labelbooleanBoss of that job, valid grade, label trimmed to Config.MaxJobGradeLabelLength, cooldown.
esx_society:setJobUniformjob, grade, skinbooleanBoss of that job, complete and in-range skin, sex matches identity, Config.UniformSaveCooldown. grade = -1 saves for all grades.
esx_society:getVehiclesInGaragesocietyarray of stored vehiclesSame job, inside a garage zone.

esx_society:setJob rules

actionType must be 'hire', 'promote' or 'fire'.

  • hire / promote: job must be the boss's own job and grade must exist and be lower than or equal to the boss's grade. Hiring needs the target online.
  • fire: job must be 'unemployed' and grade must be 0.
  • Offline targets (promote or fire) are updated in the users table only if they currently work for the boss's job.
client/main.lua
local ok = ESX.AwaitServerCallback('esx_society:setJob', targetIdentifier, 'taxi', 2, 'promote')

if ok then
    ESX.ShowNotification('Promoted')
end

Reading the balance in a HUD

client/main.lua
local job = ESX.PlayerData.job

ESX.TriggerServerCallback('esx_society:getSocietyMoney', function(money)
    print(('Company balance: $%s'):format(money))
end, job.name)

Money washing in detail

  1. The boss enters an amount. The server checks boss access and the player's black_money.
  2. Inside WithPlayerPersistence, the amount is removed from black_money and a row is written to society_moneywash_operations with state queued in one transaction. If that fails, the money is refunded.
  3. Every day at 03:00 the cron task adds each queued amount to the society account and marks it paid.

There is no washing fee: 1,000 black money becomes 1,000 in the society account. Old rows in society_moneywash are migrated into the new table on start.

Integration tips

  • Create the SQL rows first. A society needs society_<job> in addon_account (shared = 1). The official job SQL files also add the same name to datastore and addon_inventory.
  • Register the society at the top of your server file, after esx_society started. With ensure order this is guaranteed.
  • To give a second grade boss rights, add its job_grades.name to Config.BossGrades. The check uses the name, not the grade number.
  • Uniforms are stored in job_grades.skin_male and skin_female and are read by job scripts that dress players from the grade skin.

Common issues

  • Menu shows nothing: the grade name is not in Config.BossGrades, or the job name passed to openBossMenu differs from the player's job. The server log shows esx_society: <identifier> attempted open a society boss menu!.
  • "Society has no shared account" in the console: the addon_account row for society_<job> is missing or not marked shared = 1.
  • Salary change does nothing: the value is above Config.MaxSalary, not a whole number, equal to the current value, or sent within Config.JobGradeUpdateCooldown.
  • Washed money never arrives: the cron resource is not running, the server was offline at 03:00, or the wash module was disabled because a table is not InnoDB. Queued entries stay queued and are paid on the next run.
  • Employee list empty for offline players: with Config.EnableESXIdentity = true the query selects firstname and lastname. Without esx_identity those columns may not exist; set the option to false.

Frequently asked questions

Independent documentation

esx-fivem.com is a community project and is not affiliated with the ESX Framework team. Facts on this page were checked against the upstream source. Official resources: docs.esx-framework.org and github.com/esx-framework.
Edit on GitHub

Last updated on

On this page