Koja Scripts

Installation

Step-by-step setup of koja-dispatcher: server.cfg order, database, first-time setup in /dispatchadmin, dispatchcheck, optional pieces and the startup banner.

Installation

  1. Install the dependencies

    koja-dispatcher needs these resources started before it:
    • oxmysql
    • your framework (es_extended, qb-core or qbx_core)
    • koja-lib
    The manifest declares oxmysql and koja-lib as dependencies, so the resource does not start without them.
  2. Add the resource

    Use the release zip. It already contains the built interface in web/build, the caller voices and the scanned 3D map data, so there is nothing to build. Put the koja-dispatcher folder in your resources directory. If you work from the source code instead of a release, build the interface once:
    cd web
    npm install
    npm run build
    Own code that should run inside the resource goes into server/custom/*.lua and client/custom/*.lua. The manifest loads those folders after the built-in files, so your files survive updates as long as you keep the folders.
  3. Edit server.cfg

    server.cfg
    ensure oxmysql
    ensure es_extended   # or qb-core / qbx_core
    ensure koja-lib
    ensure koja-mdt      # optional, before koja-dispatcher
    ensure pma-voice     # optional, for voice 911 calls
    ensure koja-dispatcher
    Optional resources (koja-mdt, a voice resource, a phone) can start before or after koja-dispatcher; it picks them up when they start. Starting them first avoids a short gap after a restart.
  4. Database

    Nothing to import. On start the resource runs CREATE TABLE IF NOT EXISTS for every table it uses, so restarts are safe. The core tables (koja_dispatch_shifts, koja_dispatch_callsigns, koja_dispatch_settings, koja_dispatch_avatars) are created first; the modules create their own tables (career, history, scenarios, fleet editor, BOLOs, patrol zones). See Database. If a statement fails, the console prints migration failed with the SQL error, and the admin settings fall back to the config.lua defaults until the database works.
  5. Give yourself admin access

    The admin menu opens with /dispatchadmin for players in one of the framework groups in Config.Admin.groups (admin, god, superadmin) or with the ACE koja-dispatcher.admin:
    server.cfg
    add_ace group.admin koja-dispatcher.admin allow
    add_principal identifier.license:xxxxxxxxxxxxxxxx group.admin
  6. First-time setup in /dispatchadmin

    Join the server and open /dispatchadmin. Changes are saved in the database and apply at once.
    1. Access & jobs. Pick which jobs may work as dispatcher and from which grade. The defaults are dispatch (grade 0), police (grade 4) and ambulance (grade 4). If your server has no dispatch job, create one with Create job (ESX and QBCore) and hire players into it with Hire.
    2. Stations. Walk to the desk where dispatchers should sit or stand and press Place a station. A see-through copy of your character plays the pose, and you line it up with a 3D gizmo. The default station is at Mission Row.
    3. Modes. Choose where calls come from (generated, real or mixed), which units are dispatched (AI, players or mixed) and what happens to a player's /911 when nobody is on shift (reject, auto-dispatch or send to koja-mdt).
    Details for every page are in Admin menu. Until something is saved in the menu, Config.Consoles, Config.Dispatcher.jobs and Config.Modes are used.
  7. Run dispatchcheck

    Type dispatchcheck in the server console. It prints [ OK ] or [FAIL] with a hint for each check:
    CheckFails when
    koja-lib started, oxmysql startedThe resource is not started. Fix the ensure order.
    framework detectedkoja-lib did not detect ESX or QBCore.
    database tablesThe migration failed. See the error above it.
    dispatcher job "name" existsA job in the dispatcher access list does not exist in the framework.
    AI fleetConfig.AiUnits.enabled is on but no AI unit spawned. Check the fleet stations and unit types.
    locationsNo locations for generated calls.
    web UI builtweb/build/index.html is missing.
    AI callersOnly when Config.AI.enabled: the OpenAI key, and the ElevenLabs key when tts = 'elevenlabs'.
    settings loaded from the databaseThe database was not ready, so the config defaults are used.
    stationsThere is no station and the remote CAD is off.
    koja-mdt integrationkoja-mdt is installed and the integration is on, but koja-mdt is not started.
    It also prints the current modes. To ring a test call while you are on shift, run dispatchtest (random scenario) or dispatchtest store_robbery.
  8. Optional pieces

    Install and start koja-mdt. Nothing has to be changed in the MDT. The link turns on by itself and is configured on the Integrations page of the admin menu. See Integrations.

    Start pma-voice or mumble-voip. With pma-voice, call channels must stay enabled (the pma-voice convar voice_enableCalls, which is on by default). koja-dispatcher puts the caller and the dispatcher on call channel 91100 and up; keep that range away from your phone script. See Integrations.

    lb-phone and npwd work without changes: calling or texting the service number (911 by default) rings at the dispatcher, on lb-phone also the police, ambulance and fire company apps. Any other phone can use the generic event or export. See Integrations.

    If other scripts call exports of ps-dispatch, cd_dispatch, core_dispatch or qs-dispatch, stop the original resource, copy the folder from koja-dispatcher/compat/<name> into your resources (keep the folder name) and ensure <name> after koja-dispatcher. See Integrations.

    Add webhook URLs as server convars with set:

    server.cfg
    set koja_dispatcher_webhook_shifts "https://discord.com/api/webhooks/..."
    set koja_dispatcher_webhook_incidents "https://discord.com/api/webhooks/..."
    set koja_dispatcher_webhook_admin "https://discord.com/api/webhooks/..."
    set koja_dispatcher_webhook_default "https://discord.com/api/webhooks/..."

    See Integrations.

    Live AI callers are off by default and cost money per request. Put your keys in server.cfg with set, never setr and never in a config file:

    server.cfg
    set koja_dispatch_openai_key "sk-..."
    set koja_dispatch_elevenlabs_key "..."

    Then set Config.AI.enabled = true in shared/config.lua (or turn on AI callers on the Features page of the admin menu) and restart. Without the OpenAI key AI callers stay off and the scripted calls are used. dispatchcheck reports whether the keys were found. Options are in Configuration.

    Privacy and cost. With AI callers on, what the dispatcher types and says into the microphone during a call is sent to OpenAI, and caller lines are sent to ElevenLabs or OpenAI for speech. Every AI reply is a paid request. Tell your players, and set usage limits in both dashboards.

  9. Restart and read the startup banner

    A few seconds after start the console prints a banner. The values below are examples; yours show your server:
      Version v1.1.0 · Framework ESX · koja-lib 1.x · Locale en
      Database connected (MariaDB 10.11) · Settings saved
      Modes calls mixed · units mixed · no dispatcher reject
      Stations 1 · Dispatcher jobs 3 · Remote CAD off · Admin /dispatchadmin
      AI fleet 19 · Scenarios 169 · Voices 20 · AI callers off
      Roads 4664 junctions · 6906 roads · 3D terrain scanned
      Integrations mdt koja-mdt · target ox_target
    LineWhat to look for
    Databaseconnected with the server version. not ready or unreachable means oxmysql is not working.
    Settingssaved when values were loaded from the database, config defaults otherwise.
    Modes, Stations, Dispatcher jobsThe current admin menu values.
    AI fleetAI unit count and how many are off duty.
    VoicesNumber of recorded caller voices. not built means web/build/voices is missing.
    AI callersoff, on, or on, no OpenAI key.
    RoadsRoad graph size. straight lines means data/roads.json was not loaded and AI units drive in a straight line.
    3D terrainscanned with the shipped heightmap. flat means web/build/terrain/height.json is missing. See Troubleshooting.
    Integrationskoja-mdt state and the target resource found, none when there is none.
    After the banner the version check runs through koja-lib (it needs koja-lib started and waits up to 20 seconds for its report):
    MessageMeaning
    Up to dateYou run the latest release.
    Update availableA newer version exists. Up to three changelog lines and the download link follow.
    CRITICAL UPDATE REQUIREDYour version is below the minimum supported version.
    Development buildYour version is newer than the latest release.
    Version check: no release informationThe version service has nothing for this version yet.
    Turn the check off with Config.VersionCheck.enabled = false.

First-run checklist

  • Server starts without migration failed in the console.
  • koja-lib, oxmysql and your framework start before koja-dispatcher.
  • dispatchcheck shows no [FAIL] line.
  • You can open /dispatchadmin.
  • At least one job is allowed to dispatch, and you have it at the minimum grade.
  • A station is placed where you want it, or the remote CAD (/cad) is on.
  • Modes match your server: on a small server keep units on mixed or ai.
  • Walk up to the station and start a shift. The intro plays and the CAD opens.
  • Press Space to answer a call, ask for the location, dispatch it and send a unit.
  • Set Config.Locale to your language. See Translations.
  • With a police job on duty, check that you appear as a unit in the CAD.