ESX Installation

Install oxide-police on ESX Legacy — jobs, ox_inventory, radar weapon, job sync, and the ESX compatibility shim.

This guide covers the ESX-specific setup required to install oxide-police on an ESX Legacy server.

Requirements

  • es_extended
  • ox_lib
  • oxmysql
  • ox_inventory
  • ox_target
  • o-link
  • screenshot-basic
  • oxide-dispatch (powers the MDT Dispatch tab; set Config.MDT.dispatchEnabled = false if you run ps-dispatch / cd_dispatch / qs-dispatch / etc.)
  • oxide-police

Optional but recommended:

  • oxide-banking
  • pma-voice

Disable Legacy ESX Police

Do not run esx_policejob with Oxide Police.

Move it out of any folder started by ensure [esx_addons]:

resources/[disabled]/esx_policejob

Do not disable shared ESX resources such as esx_society, esx_service, or esx_billing unless your server no longer uses them for other jobs.

Startup Order

Start dependencies before Oxide Police:

ensure oxmysql
ensure ox_lib
ensure ox_target
ensure [core]
ensure [standalone]
ensure [esx_addons]
ensure ox_inventory
ensure screenshot-basic
ensure o-link
ensure oxide-banking    # optional — fine invoicing and department treasury
ensure oxide-dispatch   # optional — powers the MDT Dispatch tab
ensure oxide-police

The oxide-banking and oxide-dispatch lines are optional — leave them out if you do not run those resources. If using folder ensures, make sure o-link starts before oxide-dispatch and oxide-police, and make sure oxide-dispatch starts before oxide-police.

SQL

Run the Oxide Police SQL before starting the resource:

resources/[oxide]/oxide-police/sql/install.sql

Do not run reset.sql unless you intentionally want to drop all Oxide Police tables.

ESX Jobs

ESX job rows are still required. Oxide Police owns departments, duty, roster, MDT, stations, armory, fleet, custody, and management, but ESX, o-link, ox_inventory, and third-party resources still use framework job names.

Enable the ESX job sync before testing:

Config.Compatibility['es_extended'] = {
    enabled = true,
    jobs = { 'police', 'lspd', 'bcso', 'sasp', 'sheriff', 'statetrooper' },

    jobSync = {
        enabled = true,
        syncOnStart = true,
        syncOnChange = true,
        setSalaryToZero = true,
        jobType = 'leo',
    },

    callbacks = {
        enabled = true,
        registerPoliceJobCallbacks = true,
        registerServiceCallbacks = false,
    },

    inventory = {
        syncInvBusyWithCuffs = true,
    },
}

The sync mirrors Oxide Police departments and grades into ESX jobs and job_grades, then calls ESX.RefreshJobs(). Keep setSalaryToZero = true so ESX does not pay law enforcement jobs in addition to Oxide Police payroll.

Every Oxide Police department name must exist in the ESX jobs table, and every Oxide Police grade rank must exist in job_grades. With jobSync.enabled = true, Oxide Police creates and updates those rows automatically from /padmin.

Common law enforcement job names:

police
lspd
bcso
sasp
sheriff
statetrooper

If your only department is police, only police is required. If you create an Oxide department named lspd, ESX must also have an lspd job.

g-multijob (officers who hold more than one job)

g-multijob lets a player carry several jobs and switch which one is active from an in-game menu. Oxide Police works with it once you turn on a few settings.

Two pieces matter:

  1. Departments must exist as ESX jobs. g-multijob only lists jobs that exist in the ESX jobs table, so the ESX job sync above must be on (jobSync.enabled = true). With it on, every Oxide department is written to jobs / job_grades automatically, and g-multijob can offer it.

  2. Allow more than one department per character. By default a character can only belong to one department; hiring them into a second moves them out of the first. To let an officer hold, say, both LSPD and BCSO at the same time, enable:

    Config.AllowMultiDepartment = true

How it behaves with Config.AllowMultiDepartment = true:

  • Each department the officer belongs to is a separate record — its own badge number, callsign, rank, and payroll.
  • Their active department is whichever police job is currently selected in the g-multijob menu. Duty, the MDT, the boss menu, and field tools all act on that active department.
  • Selecting a non-police job in the menu (mechanic, taxi, etc.) puts them off police duty and removes police access until they switch back to a police job. None of their department records are lost.
  • Hiring or firing through the Oxide Police boss menu (or the /phire / /pfire commands) automatically adds the job to, or removes it from, the player's g-multijob menu. No extra setup — the bridge is on by default whenever g-multijob is installed:
Config.Compatibility['g-multijob'] = {
    enabled = true,
}

Leave Config.AllowMultiDepartment = false if each officer should only ever belong to one department. In that mode Oxide Police manages the police job entirely on its own and does not push it into the g-multijob menu — g-multijob keeps working for your non-police jobs, but a police job is not meant to sit alongside them.

The bridge identifies players by their ESX identifier, which is what g-multijob keys jobs by, so no ID mapping is needed.

ox_inventory

Add law enforcement jobs to the police group:

setr inventory:police ["police", "lspd", "bcso", "sasp", "sheriff", "statetrooper"]

Register Oxide Police items in:

resources/[oxide]/ox_inventory/data/items.lua

Open its item list file and paste these entries into the list. These are the exact item names Oxide Police looks for — do not rename them:

['body_cam'] = { label = 'Body Camera', weight = 250, stack = false, close = true },
['police_radio'] = { label = 'Police Radio', weight = 500, stack = false, close = true },
['megaphone'] = { label = 'Megaphone', weight = 1000, stack = false, close = true },
['evidence_camera'] = { label = 'Evidence Camera', weight = 750, stack = false, close = true },
['breathalyzer'] = { label = 'Breathalyzer', weight = 350, stack = false, close = true },
['cctv_camera'] = { label = 'CCTV Camera', weight = 1500, stack = false, close = true },
['prison_food_tray'] = { label = 'Prison Food Tray', weight = 500, stack = true, close = true },
['ziptie'] = { label = 'Zip Tie', weight = 25, stack = true, close = true },
['scissors'] = { label = 'Scissors', weight = 100, stack = false, close = true },
['wheel_clamp'] = { label = 'Wheel Clamp', weight = 2500, stack = false, close = true },
['mouthtape'] = { label = 'Mouth Tape', weight = 50, stack = true, close = true },
['tracking_band'] = { label = 'Tracking Band', weight = 100, stack = false, close = true },
['headbag'] = { label = 'Headbag', weight = 150, stack = true, close = true },
['lockpick'] = { label = 'Lockpick', weight = 100, stack = true, close = true },
['evidence_blood'] = { label = 'Blood Evidence', weight = 50, stack = false, close = false },
['evidence_bullet'] = { label = 'Bullet Evidence', weight = 25, stack = false, close = false },
['evidence_fingerprint'] = { label = 'Fingerprint Evidence', weight = 25, stack = false, close = false },

The weights and labels above are sensible defaults — change them to taste. After saving, restart ox_inventory (or your server).

Copy item images from:

resources/[oxide]/oxide-police/items

to:

resources/[oxide]/ox_inventory/web/images

Every image file is named after its item (the body_cam item's image is body_cam.png).

For handheld radar, register WEAPON_RADAR in:

resources/[oxide]/ox_inventory/data/weapons.lua

Add this entry inside the weapons list:

['WEAPON_RADAR'] = {
    label = 'Radar Gun',
    weight = 750,
    durability = 0.1,
},

No ammo item is required. The weapon model and meta files are streamed automatically from oxide-police/stream/. The handheld radar only works for officers who are on duty. (The vehicle-mounted radar is separate — it works on fleet vehicles flagged has_radar in /padmin and needs no item.)

ESX Compatibility

Oxide Police includes an ESX compatibility shim:

oxide-police/server/compat/es_extended.lua
oxide-police/client/compat/es_extended.lua

The shim provides passive compatibility for common ESX policejob callbacks and keeps ox_inventory busy state synced while Oxide cuffs are active.

It does not remap old esx_policejob action events such as handcuff, drag, put in vehicle, or take out of vehicle. Those actions should be removed with esx_policejob; Oxide Police provides its own action menu and interaction flow.

Initial In-Game Setup

After SQL is installed and the server starts:

Make sure your account is a server admin (in a group with the admin permission). The same admin setup that works for your other Oxide resources works here. See Admin → Permissions.
Open /padmin.
Create or verify a department.
Make sure the department name matches an ESX job name.
Add grades that match ESX job_grades numbers.
Add at least one station with a clock-in point.
Add radio channels if using Oxide Police radio.
Add garages and vehicles if testing fleet features.
Add custody/prison points if testing jail.
Hire a test officer into the department.
Clock in through Oxide Police before testing MDT, dispatch, evidence, fleet, or prison.

Testing Checklist

  • esx_policejob is not running.
  • SQL has been run.
  • ESX job sync is enabled, or ESX jobs and grades exist manually for every Oxide department.
  • Oxide Police items are registered in ox_inventory.
  • Oxide Police item images exist in ox_inventory/web/images.
  • WEAPON_RADAR is registered if handheld radar is used.
  • o-link starts before Oxide Police.
  • Oxide Dispatch starts before Oxide Police.
  • Officer can be hired, clock in, cuff/search/escort, use bodycam, use evidence camera, open MDT, receive dispatch alerts, and use custody/prison.

Next Steps