# esx_mechanicjob (/docs/addons/esx_mechanicjob)

esx_mechanicjob adds a `mechanic` job with a workshop, harvesting and crafting of repair items, a mobile F6 menu (bill, lockpick, repair, clean, impound, tow, place props) and NPC towing missions that pay into the society account. Use it for a basic mechanic or tow company on an ESX Legacy server.

<Callout type="warn">
The official ESX documentation warns that this resource has known issues and that a rewrite is planned. The version described here already has server-side checks and rate limits on its events, but test it on a staging server first.
</Callout>

## Overview [#overview]

| | |
| --- | --- |
| Resource | `esx_mechanicjob` (version `1.0`) |
| Side | client + server |
| Job name | `mechanic` (grades `recrue`, `novice`, `experimente`, `chief`, `boss`) |
| Society | `society_mechanic`, registered as a private society |
| Dependencies | `esx_lib`, `es_extended`, [esx_society](/docs/addons/esx_society), [esx_billing](/docs/addons/esx_billing) |
| Also used | `oxmysql`, [esx_service](/docs/addons/esx_service) (when `MaxInService` is set), `esx_garage` (impound) |
| Items | `gazbottle`, `fixtool`, `carotool`, `blowpipe`, `fixkit`, `carokit` |

### Gameplay loop [#gameplay-loop]

1. **Harvest** tools at the `Garage` zone: gas bottles, repair tools and bodywork tools, one every 4 seconds, up to 5 of each.
2. **Craft** at the `Craft` zone: a gas bottle becomes a blowtorch (`blowpipe`), repair tools become a `fixkit`, bodywork tools become a `carokit`.
3. **Use** the kits on vehicles or use the F6 menu actions.
4. **NPC missions**: tow random parked cars from `Config.Towables` back to `VehicleDelivery` for a society payout.

The `MechanicActions` marker opens the vehicle list, work and civilian clothes, stock deposit and withdraw, and, for the `boss` grade, the esx_society boss menu.

## Installation [#installation]

<Steps>
<Step>
### Import the SQL [#import-the-sql]

Run `esx_mechanicjob.sql`. It creates the society rows, the `mechanic` job with five grades and default uniforms, and the six items.

If you installed an older version whose grades have empty skins, also run `update_mechanic_uniforms.sql`. It only fills `skin_male` and `skin_female` where they are empty or `{}`.
</Step>
<Step>
### Start it [#start-it]

```bash title="server.cfg"
ensure esx_society
ensure esx_billing
ensure esx_mechanicjob
```
</Step>
</Steps>

<Callout type="warn" title="txAdmin recipe installs">
The ESX recipe already creates `society_mechanic` and the mechanic items. Importing `esx_mechanicjob.sql` on top of it fails with duplicate key errors. Check which rows already exist and import only the missing ones.
</Callout>

## Configuration [#configuration]

| Key | Default | Description |
| --- | --- | --- |
| `Config.Locale` | `GetConvar('esx:locale', 'en')` | Language. |
| `Config.Controls.mechanicMenu` | `"F6"` | Default key for the `mechanicMenu` command. |
| `Config.Controls.toggleNPCJob` | `"F7"` | Default key for the `mechanicjob` command. |
| `Config.DrawDistance` | `10.0` | Distance at which markers are drawn. |
| `Config.MaxInService` | `-1` | Service limit through esx_service. `-1` disables the service check. |
| `Config.EnablePlayerManagement` | `true` | Enables the boss menu, the `slamvan3` vehicle for higher grades, and blocks `recrue` from harvesting and crafting. |
| `Config.EnableSocietyOwnedVehicles` | `false` | Uses vehicles stored in the esx_society garage instead of the fixed list. |
| `Config.NPCSpawnDistance` | `500.0` | The NPC target vehicle spawns once the player is closer than this to the target zone. |
| `Config.NPCNextToDistance` | `25.0` | How close you must get to the NPC target vehicle. |
| `Config.NPCJobEarnings` | `{ min = 15, max = 40 }` | Random reward per completed NPC mission. Doubled for grade 3 and higher. |
| `Config.ActionVehicleDistance` | `2.0` | How close a vehicle must be for mobile actions. |
| `Config.OxInventory` | `ESX.GetConfig().OxInventory` | Read from es_extended. |
| `Config.Vehicles` | `{ 'adder', 'asea', 'asterope', 'banshee', 'buffalo', 'sultan', 'baller3' }` | Models used for NPC tow targets. The server only accepts these models. |
| `Config.Zones` | see below | Marker positions. |
| `Config.Towables` | 40 `vector3` positions | NPC mission pickup points. Each one is turned into a `Towable<n>` zone at load. |

`Config.Zones` contains `MechanicActions`, `Garage` (harvest), `Craft`, `VehicleSpawnPoint`, `VehicleDeleter` and `VehicleDelivery`. Each zone has `Pos`, `Size`, `Color` (optional) and `Type` (marker type, `-1` hides it).

<Callout type="info">
The default `Garage` harvest zone is in Paleto Bay (`-97.5, 6496.1`), far from the workshop in the city. Move it if you want a compact job loop.
</Callout>

## Commands and keybinds [#commands-and-keybinds]

| Command | Default key | Description |
| --- | --- | --- |
| `mechanicMenu` | `F6` | Opens the mobile actions menu (mechanic job only, not while dead). |
| `mechanicjob` | `F7` | Starts the NPC towing mission when you sit in a `flatbed`, or cancels it. Cancelling is limited to once every 5 minutes. |

Both are registered with `RegisterKeyMapping`, so players can rebind them in the FiveM key settings.

## Usable items [#usable-items]

Registered on the server with `ESX.RegisterUsableItem`. Each use removes one item and triggers a client event on the user.

| Item | Client event | Effect |
| --- | --- | --- |
| `blowpipe` | `esx_mechanicjob:onHijack` | Tries to unlock the closest vehicle (about a 66% success chance; about one in three attempts also sets off the alarm). |
| `fixkit` | `esx_mechanicjob:onFixkit` | Repairs the closest vehicle. |
| `carokit` | `esx_mechanicjob:onCarokit` | Repairs the closest vehicle's bodywork. |

## Server events [#server-events]

All handlers check that the caller has the `mechanic` job and apply a per-player rate limit.

| Event | Arguments | Notes |
| --- | --- | --- |
| `esx_mechanicjob:startHarvest` / `stopHarvest` | none | Gas bottles at `Garage`. |
| `esx_mechanicjob:startHarvest2` / `stopHarvest2` | none | Repair tools at `Garage`. |
| `esx_mechanicjob:startHarvest3` / `stopHarvest3` | none | Bodywork tools at `Garage`. |
| `esx_mechanicjob:startCraft` / `stopCraft` | none | Blowtorch at `Craft`. |
| `esx_mechanicjob:startCraft2` / `stopCraft2` | none | Repair kit at `Craft`. |
| `esx_mechanicjob:startCraft3` / `stopCraft3` | none | Body kit at `Craft`. |
| `esx_mechanicjob:startNPCJob` | none | Player must sit in a `flatbed`. Picks a random `Towable` zone. |
| `esx_mechanicjob:stopNPCJob` | none | Clears the mission. |
| `esx_mechanicjob:npcJobTargetSpawned` | `targetNetId` | Registers the spawned target vehicle. |
| `esx_mechanicjob:npcJobTargetReached` | `targetNetId` | Marks the target as reached. |
| `esx_mechanicjob:onNPCJobMissionCompleted` | `targetNetId, flatbedNetId` | Pays the reward to `society_mechanic` after distance, model and timing checks (minimum 30 seconds, 60 seconds between rewards). |
| `esx_mechanicjob:impoundOwnedVehicle` | `plate, vehicleNetId` | Calls `exports['esx_garage']:impoundVehicle(plate)` if the vehicle is within 8 units. |
| `esx_mechanicjob:getStockItem` | `itemName, count` | Withdraws from `society_mechanic`. |
| `esx_mechanicjob:putStockItems` | `itemName, count` | Deposits into `society_mechanic`. |

Harvest and craft actions are validated on the server: the player must be a mechanic above `recrue` (when player management is on) and stay within 3 units of the zone. The server stops the loop as soon as they walk away.

<Callout type="warn" title="Security">
`getStockItem` and `putStockItems` check the job and a rate limit, but not the player's position or grade. Any mechanic with a modified client can withdraw society stock from anywhere on the map. If your society inventory holds valuable items, add a distance check to `Config.Zones.MechanicActions.Pos` in `server/modules/stock.lua`.
</Callout>

## Server callbacks [#server-callbacks]

| Callback | Returns |
| --- | --- |
| `esx_mechanicjob:getStockItems` | Items in the `society_mechanic` inventory (mechanic job only). |
| `esx_mechanicjob:getPlayerInventory` | `{ items = ... }` of the caller (mechanic job only). |

## Client events [#client-events]

| Event | Arguments | Description |
| --- | --- | --- |
| `esx_mechanicjob:npcJobStarted` | `targetZone` | Server accepted the mission start. |
| `esx_mechanicjob:npcJobCompleted` | `targetNetId` | Mission paid out. |
| `esx_mechanicjob:npcJobCompletionFailed` | `message` | Completion rejected (wrong place, wrong vehicle, no flatbed, cooldown). |

## Integration tips [#integration-tips]

- Bills from the F6 menu are sent with `esx_billing:sendBill` to `society_mechanic`. Paid bills go to the society account, not to the mechanic.
- To give mechanics repair kits from a shop instead of crafting, add `fixkit` and `carokit` to an [esx_shops](/docs/addons/esx_shops) store. The usable item handlers work regardless of how the item was obtained.
- With ox_inventory, add the six items to ox_inventory's item list as well, otherwise they do not show up.

## Common issues [#common-issues]

- **F7 says "you must be in a flatbed".** The NPC mission only starts from a vehicle with the `flatbed` model.
- **NPC mission never pays.** The target must be one of `Config.Vehicles`, delivered within 25 units of `VehicleDelivery`, with the flatbed nearby, and at least 30 seconds after the start.
- **Boss menu missing.** It only appears for the grade named `boss` with `Config.EnablePlayerManagement = true`.
- **Uniform does not change.** The work clothes come from `skin_male` / `skin_female` in `job_grades`. Run `update_mechanic_uniforms.sql` if they are empty.

## Related [#related]

- [esx_society](/docs/addons/esx_society)
- [esx_billing](/docs/addons/esx_billing)
- [esx_lscustom](/docs/addons/esx_lscustom)
- [Create a job](/docs/guides/create-a-job)
- [Add items](/docs/guides/add-items)
