> For the complete documentation index, see [llms.txt](https://ccfivem.gitbook.io/ccfivem-docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://ccfivem.gitbook.io/ccfivem-docs/free-resources/job-locations-cc_jobs.md).

# Job Locations (cc\_jobs)

**Free resource · ESX Legacy, QBCore, QBox · Version 1.0.0**

The boss of a job places the duty clock, storage, garage, dispatch and more directly in the game — no coordinates in config files. Other CrankChaos job scripts read these points through exports.

{% hint style="info" %}
cc\_jobs is shipped free with the CrankChaos job scripts (cc\_police/00%20Overview\.md), cc\_ambulance/00%20Overview\.md), cc\_mechanic/00%20Overview\.md), cc\_dispatch/00%20Overview\.md), cc\_evidence/00%20Overview\.md), cc\_prison/00%20Overview\.md), cc\_policetools/00%20Overview\.md), cc\_licenses/00%20Overview\.md)). Without it those scripts fall back to the locations in their own config.
{% endhint %}

## Features

* In-game editor (`/standorte`) for the highest grade of a job, or for admins for any job
* Place and rotate points by looking at the spot (up to 15 m), with a ghost preview
* Per point: name, radius, minimum grade, map blip (sprite/colour/size/name), storage size, NPC model, teleport-to waypoint, move, delete
* 28 point kinds out of the box (duty, stash, locker, wardrobe, armory, garage and spawn points, boss office, dispatch, lifts, paint booth, pharmacy, beds, check-in, evidence, cells, lab, CCTV, kennel …); new kinds and jobs are added in config
* Default points of job scripts appear as "Default (Config)" until the boss places own points
* Stash, locker (one compartment per character) and evidence points are registered as containers in cc\_inventory/00%20Overview\.md)
* Member blips: job members see the places they can use; points with a minimum grade only for those who have it
* Server and client API for other scripts, with change events
* Database table is created automatically

cc\_jobs itself only draws map blips, the editor view and stash-type points (marker + "\[E] open"). Everything else (duty clock, garage, …) is built by the job script through the API.

## Pages

* Installation
* Configuration
* API
* FAQ

Related: cc\_lib/00%20Overview\.md) · Framework Bridge · Support

## Installation

### Dependencies

| Resource                         | Required?               | Purpose                                                                 |
| -------------------------------- | ----------------------- | ----------------------------------------------------------------------- |
| `oxmysql`                        | required (`dependency`) | table `cc_job_points`                                                   |
| ESX Legacy / QBCore / QBox       | required                | jobs and grades                                                         |
| cc\_inventory/00%20Overview\.md) | optional                | stash, locker and evidence points; without it there are no stash points |
| cc\_lib/00%20Overview\.md)       | optional                | shared notifications and hints                                          |

### server.cfg

cc\_jobs **must start before the job scripts** — they register their default points and query points on start.

```cfg
ensure oxmysql
ensure es_extended          # or qb-core / qbx_core
ensure cc_lib               # optional
ensure cc_inventory         # optional, for stash/locker/evidence
ensure cc_jobs
ensure cc_mechanic
ensure cc_ambulance
ensure cc_police
ensure cc_dispatch
ensure cc_licenses
ensure cc_bossmenu
```

### SQL

No SQL file. The table `cc_job_points` is created automatically on first start (`utf8mb4_unicode_ci`).

### ACE permissions

Admins who may edit **any** job:

```cfg
add_ace group.admin cc_jobs.admin allow
```

The ACE name is configurable via `Config.AdminAce`. The highest grade of a job needs no ACE to edit its own job.

### Framework-specific steps

None. The framework is detected automatically. Make sure the jobs you use (`police`, `ambulance`, `mechanic` by default) exist in your framework with grades — see Framework Bridge.

See also: General installation · Dependencies

## Configuration

Editable files: `config/config.lua`, `config/kinds.lua`, `config/ui.lua`, `locales/*.json` and the framework bridge `shared/cc_framework.lua`.

### General (`config/config.lua`)

```lua
Config.Command  = 'standorte'      -- opens the editor; /standorte police for admins
Config.AdminAce = 'cc_jobs.admin'  -- may edit every job
```

The server checks permissions, not the command.

#### Placing

```lua
Config.Place = {
    maxDistance = 15.0,  -- max distance of a point from the player (m)
    serverSlack = 2.0,   -- tolerance for the server's own distance check
    wheelStep = 7.5,     -- rotation per mouse wheel notch (degrees)
    keyStep = 2.0,       -- rotation per frame while holding Q/E
    maxPerJob = 120,     -- max points per job
}
```

#### Rate limits (ms per player)

```lua
Config.RateLimit = { editor = 750, write = 600, sync = 5000, mine = 1500 }
```

#### Stash size

Weight is in **grams**. Defaults for new stash points and the limits the boss may set in the editor.

```lua
Config.Stash = {
    slots = 50, maxWeight = 500000,
    minSlots = 5, maxSlots = 200,
    minWeight = 10000, maxMaxWeight = 2000000,
}
```

#### Display

```lua
Config.Loop = { drawDistance = 30.0, idleWait = 750 }
Config.Marker = {
    type = 1,
    color = { 139, 92, 246, 110 },        -- RGBA
    editor = { 245, 158, 11, 160 },
    ghost = { 139, 92, 246, 140 },
    ghostInvalid = { 239, 68, 68, 140 },
}
Config.InteractKey = 38  -- E
```

#### Member blips

Blips only job members see, for every place they can use. Colour comes from `Config.Jobs[job].blip.colour`. Remove a kind from `kinds` to hide its blip.

```lua
Config.MemberBlips = {
    enabled = true,
    scale = 0.65,
    shortRange = true,
    kinds = { duty = 280, boss = 475, wardrobe = 73, locker = 478, --[[ ... ]] kennel = 442 },
}
```

### Kinds and jobs (`config/kinds.lua`)

A **kind** is *what* stands at a point. Fields:

| Field                     | Meaning                                                            |
| ------------------------- | ------------------------------------------------------------------ |
| `label`                   | Locale key or fixed text                                           |
| `icon`                    | UI icon                                                            |
| `multiple`                | Several points allowed? `false` = placing moves the existing one   |
| `needsHeading`            | Direction matters (spawn point, bed, NPC)                          |
| `defaultRadius`           | Interaction range in metres                                        |
| `hasBlip` / `blipDefault` | May have a map blip / new point has it on                          |
| `hasStash`                | cc\_jobs provides a stash here (cc\_inventory)                     |
| `personal`                | With `hasStash`: one point, one compartment per character (locker) |
| `defaultMinGrade`         | Minimum grade of a new point                                       |
| `hasPed`                  | The job script places an NPC here                                  |

```lua
stash = { label = 'jobs.kind.stash', icon = 'package', multiple = true,
          needsHeading = false, defaultRadius = 1.5, hasBlip = false, hasStash = true },
```

`Config.Jobs` lists which jobs get locations and which kinds their boss may set:

```lua
Config.Jobs = {
    mechanic  = { label = 'Werkstatt',      blip = { sprite = 446, colour = 47, scale = 0.8 },  kinds = { 'blip', 'duty', 'boss', ... } },
    ambulance = { label = 'Rettungsdienst', blip = { sprite = 61,  colour = 1,  scale = 0.85 }, kinds = { ... } },
    police    = { label = 'Polizei',        blip = { sprite = 60,  colour = 29, scale = 0.85 }, kinds = { ... } },
}
```

`label` is only used if the framework provides none. Add a job by adding an entry.

{% hint style="warning" %}
Only add new kinds and jobs in `kinds.lua`. A kind does nothing by itself unless it is a stash kind or a job script uses it through the API.
{% endhint %}

### Appearance (`config/ui.lua`)

Same structure as in every CrankChaos script (`theme`, `primary`, `radius`, `scale`, `locale`, `animations`, `blur`, `sounds`). Default `locale = 'de'` — set `'en'` for English. See cc\_lib configuration/02%20Configuration.md) for the meaning of each field.

## Exports, Events & Commands

### Commands

| Command            | Who                      | Effect                 |
| ------------------ | ------------------------ | ---------------------- |
| `/standorte`       | highest grade of own job | editor for the own job |
| `/standorte <job>` | ACE `cc_jobs.admin`      | editor for any job     |

The command name is set by `Config.Command`.

**Editor controls:** kinds on the left, points on the right. *Place here* closes the window: look at the spot (max 15 m), mouse wheel or Q/E rotates, ENTER / left click places, Backspace / right click / ESC cancels.

### Point object

```lua
point = { id, job, kind, label, coords = vector3, heading, radius, data }
-- coords are at ground level (raycast)
-- data.minGrade, data.blip, data.stash, data.ped (model name, optional)
```

### Server exports

| Export                                 | Returns        | Purpose                                                                                                             |
| -------------------------------------- | -------------- | ------------------------------------------------------------------------------------------------------------------- |
| `GetPoints(job, kind?)`                | `{ point, … }` | Points placed by the boss only                                                                                      |
| `Nearest(job, kind, coords, maxDist?)` | `point \| nil` | Nearest point to coordinates                                                                                        |
| `IsNear(src, job, kind, extra?)`       | `point \| nil` | Measures the player position itself (horizontal, radius + `extra`)                                                  |
| `RegisterDefaults(job, kind, list)`    | —              | Register config points as "Default (Config)"; `list`: vector3/vector4 or `{ coords, heading, label, radius, data }` |
| `OpenEditor(src, job?)`                | `boolean`      | Open the editor for a player; permission is checked again                                                           |

### Client exports

| Export                  | Purpose                                 |
| ----------------------- | --------------------------------------- |
| `GetPoints(job, kind?)` | Placed points (for display)             |
| `OpenEditor(job?)`      | Open the editor, e.g. from a job tablet |

### Events

| Event                           | Side                      | When                                                   |
| ------------------------------- | ------------------------- | ------------------------------------------------------ |
| `cc_jobs:changed` (`job, kind`) | server and client (local) | A point was placed, changed or deleted                 |
| `cc_jobs:ready`                 | server (local)            | cc\_jobs was (re)loaded — register your defaults again |

{% hint style="info" %}
**Fallback:** if `GetPoints` returns nothing for a kind, keep using your own config points.
{% endhint %}

### Example — server (duty clock)

```lua
local function registerDefaults()
    if GetResourceState('cc_jobs') ~= 'started' then return end
    exports.cc_jobs:RegisterDefaults('police', 'duty', Config.DutyPoints)
end

CreateThread(registerDefaults)
AddEventHandler('cc_jobs:ready', registerDefaults)

local function dutyPointNear(src)
    if GetResourceState('cc_jobs') == 'started' and #exports.cc_jobs:GetPoints('police', 'duty') > 0 then
        return exports.cc_jobs:IsNear(src, 'police', 'duty', 1.0) ~= nil
    end
    return nearConfigPoint(src, Config.DutyPoints) -- fallback
end
```

### Example — client (rebuild markers)

```lua
local points = {}
local function reload()
    points = exports.cc_jobs:GetPoints('police', 'duty')
    if #points == 0 then points = Config.DutyPoints end
end

AddEventHandler('cc_jobs:changed', function(job, kind)
    if job == 'police' and kind == 'duty' then reload() end
end)
```

### Stashes

Points of a kind with `hasStash` are registered with cc\_inventory by cc\_jobs itself as `job:<job>:<id>` (locker with `personal = true`). Job and grade are checked by the inventory.

## FAQ & Troubleshooting

**My job script ignores the points I placed.** Check the start order: `ensure cc_jobs` must come **before** the job scripts. Also, placed points only replace config points in scripts that use the cc\_jobs API.

**`/standorte` does nothing / says I have no permission.** Only the highest grade of your own job may edit it. For other jobs you need the ACE: `add_ace group.admin cc_jobs.admin allow`.

**I can't place a point.** Points can only be placed up to 15 m from your view (`Config.Place.maxDistance`). A red ghost means the spot is invalid. The number of points per job is capped by `Config.Place.maxPerJob` (120).

**Placing a point moved my old one.** That kind has `multiple = false` (e.g. `boss`, `jobcard`) — there is only one point of it.

**There is no stash / locker / evidence marker.** Stash points require cc\_inventory/00%20Overview\.md). Also check the point's minimum grade.

**I can't delete a stash.** A stash can only be deleted when it is empty.

**What does "Default (Config)" mean in the editor?** These are the default points the job script registered from its own config. They stay active until the boss places own points for that kind.

**Do I need to import SQL?** No. The table `cc_job_points` is created on first start. `oxmysql` must be running.

**How do I add a new job?** Add an entry to `Config.Jobs` in `config/kinds.lua` with its kinds, then restart.

Still stuck? See Support.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://ccfivem.gitbook.io/ccfivem-docs/free-resources/job-locations-cc_jobs.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
