DutyKit
DutyKit turns approved duty vehicles into configurable gear access points for your server-defined items, weapons, outfits, kits, and refill flows. Use it for police, EMS, fire, DOT, mechanics, roadside support, or custom jobs that should collect duty equipment from vehicles instead of carrying everything at all times.
Requirements
Section titled “Requirements”-
ox_libv3.30.0or newer. -
One supported framework running on the server:
ox_coreqbx_coreqb-corees_extended
-
One supported inventory adapter set in
Config.inventory:ox_inventorycodem-inventoryqb-inventoryorigen_inventory
-
One supported target adapter set in
Config.target:ox_targetqb-targetsleepless_interact
Installation
Section titled “Installation”-
Download DutyKit
Section titled “Download DutyKit”Download the latest granted asset from the Cfx.re Portal.
-
Install dependencies
Section titled “Install dependencies”Install and start your selected framework, inventory, target resource, and
ox_lib. -
Add DutyKit to your resources
Section titled “Add DutyKit to your resources”Place the
kf-dutykitfolder in your server resources directory. -
Start resources in
Section titled “Start resources in server.cfg”server.cfgStart dependencies before DutyKit.
server.cfg ensure ox_lib# Start your framework.ensure qbx_core# ensure qb-core# ensure es_extended# ensure ox_core# Start your inventory.ensure ox_inventory# Start your target resource.ensure ox_targetensure kf-dutykit -
Configure adapters
Section titled “Configure adapters”Open
config.luaand set the inventory, target, and notification adapters for your server.config.lua Config.inventory = 'ox_inventory'Config.target = 'ox_target'Config.notifications = trueConfig.notify = 'ox_lib' -
Configure your loadouts
Section titled “Configure your loadouts”Add or edit loadout files in
loadouts/, then register those files inloadouts/index.lua.
How DutyKit works
Section titled “How DutyKit works”DutyKit adds vehicle interactions for loadouts and refills through your configured target resource. Players open the interaction from an approved vehicle, then use the menu to browse Quick Access, all loadouts, or the custom categories defined in Config.categories.
A loadout can contain either inventory items or clothing. DutyKit checks vehicle access, ped model access, group access, distance, and item limits server-side before giving equipment or applying an outfit.
Quick Access is controlled per item or clothing entry with quick = true. allowEquipAll = true enables the bulk equip option for a loadout.
Core configuration
Section titled “Core configuration”Config.inventory = 'ox_inventory'Config.target = 'ox_target'
Config.notifications = trueConfig.notify = 'ox_lib'
Config.categories = { 'Items', 'Outfits' }
Config.debug = false
Config.loadoutMenuThemeDefaultPreset = 'police'
Config.autoEquipWeapon = trueConfig.checkVehicleLocked = trueConfig.refillTime = '1 hour'| Option | Purpose |
|---|---|
Config.inventory | Selects the inventory adapter. |
Config.target | Selects the target adapter used for vehicle interactions. |
Config.notifications | Enables or disables DutyKit notifications. |
Config.notify | Selects the notification adapter. Supported values are ox_lib, esx_notify, qb-core, qbx_core, okokNotify, and wasabi_notify. |
Config.categories | Adds custom menu categories after Quick Access and Loadouts. Loadout category values should match these labels. |
Config.debug | Enables debug logging and the /dumpappearance helper command. Disable this in production. |
Config.loadoutMenuThemeDefaultPreset | Default UI theme preset used by the custom DutyKit menu. |
Config.autoEquipWeapon | Auto-equips retrieved weapon items when the inventory adapter supports slot use. |
Config.checkVehicleLocked | Blocks access when the target vehicle is locked. |
Config.refillTime | Cooldown text parsed by the refill flow, for example 10 minutes, 1 hour, or 2 days. |
Menu themes
Section titled “Menu themes”DutyKit includes configurable menu theme presets in Config.loadoutMenuThemePresets. The default config includes presets such as default, police, ems, and fire.
Set a loadout theme by name:
theme = 'police'Or add your own preset in Config.loadoutMenuThemePresets:
Config.loadoutMenuThemePresets.custom = { selectedColor = 'rgba(10, 10, 10, 0.7)', selectedBorderColor = 'rgba(255, 255, 255, 0.7)', selectedColorLine = 'rgba(255, 255, 255, 1.0)', buttonGradientFrom = 'rgba(30, 30, 30, 0.7)', buttonGradientTo = 'rgba(50, 50, 50, 0.5)', textColor = 'rgba(240, 240, 240, 1.0)', disabledTextColor = 'rgba(150, 150, 150, 1.0)', indicatorColor = 'rgba(240, 240, 240, 1.0)',}Group filters
Section titled “Group filters”Use groups to restrict a loadout or refill station to jobs, gangs, or framework groups.
-- Any listed group can access.groups = { 'police', 'sheriff' }
-- Minimum grade requirements.groups = { police = 2, sheriff = 1 }
-- Mixed plain and graded access.groups = { police = 2, sheriff = true }
-- ESX also supports grade name checks.groups = { police = 'boss' }Framework behavior:
| Framework | Group source |
|---|---|
ox_core | Ox player groups. |
qbx_core | Player job, gang, or native Qbox groups. |
qb-core | Player job and gang. |
es_extended | Player job, including numeric grade or grade name. |
In-game loadout editor
Section titled “In-game loadout editor”DutyKit includes an in-game loadout editor for creating and maintaining loadouts. This is the expected workflow for most server owners because it avoids manually writing each loadout table from scratch.
Use the /dutykit command in-game to open the editor. From there, you can build loadouts, assign categories, items, outfits, vehicles, groups, limits, Quick Access entries, and themes, then save the result. DutyKit stores those saved loadouts as Lua files inside loadouts/.
Loadout files
Section titled “Loadout files”DutyKit stores loadouts as individual Lua files in loadouts/. The in-game editor can create and update these files for you, but understanding the structure is useful for developers, Git review, and advanced manual edits.
DutyKit loads loadouts from loadouts/index.lua. Each index entry points to a Lua file in loadouts/, and each loadout file returns one table.
When manually adding, renaming, or removing loadout files, run /dutykit rebuild in-game to rebuild loadouts/index.lua so DutyKit knows which loadout files should be loaded.
return { { file = 'ld_police_patrol-kit.lua', id = 'ld_police_patrol', },}Item loadout example
Section titled “Item loadout example”return { category = 'Items', label = 'Patrol Weapon Kit', type = 'police', theme = 'police',
groups = { 'police', 'sheriff', },
allowedVehicles = { 'police', 'police2', 'police3', 'sheriff', 'sheriff2', },
allowEquipAll = true,
items = { { itemName = 'WEAPON_COMBATPISTOL', ammo = 72, componentItemNames = { 'at_flashlight', }, tint = 0, max = 1, quick = true, }, { itemName = 'WEAPON_STUNGUN', max = 1, quick = true, }, { itemName = 'ammo-9', max = 8, }, },}Outfit loadout example
Section titled “Outfit loadout example”return { category = 'Outfits', label = 'Patrol Uniform', type = 'police', theme = 'police',
groups = { 'police', 'sheriff', },
allowedVehicles = { 'police', 'police2', 'police3', 'sheriff', 'sheriff2', },
allowedPeds = { 'mp_m_freemode_01', 'mp_f_freemode_01', },
allowEquipAll = true,
clothing = { { label = 'Short Sleeve Arms', componentId = 3, drawable = 19, texture = 0, quick = true, }, { label = 'Duty Pants', componentId = 4, drawable = 35, texture = 0, quick = true, }, { label = 'Duty Cap', propId = 0, drawable = 46, texture = 0, quick = true, }, },}Loadout fields
Section titled “Loadout fields”| Field | Description |
|---|---|
category | Menu category. Should match a value in Config.categories. |
label | Display name shown in the DutyKit menu. |
type | Optional family key used to pair loadouts with refill stations. |
theme | Theme preset name or inline theme table. |
groups | Optional access filter. Omit it for unrestricted access. |
allowedVehicles | Vehicle spawn names allowed to open this loadout. Omit or leave empty to allow any vehicle. |
allowedPeds | Optional ped model allowlist for outfit or role-specific loadouts. |
allowEquipAll | Enables Equip All or Equip Quick menu actions. |
items | Inventory items, weapons, ammo, supplies, or tools. |
clothing | Outfit components and props. |
resetMissingClothing | For outfit loadouts, set false to avoid clearing missing clothing slots during Equip All. |
Item fields
Section titled “Item fields”| Field | Description |
|---|---|
itemName | Inventory item name. Use the exact item key from your inventory. |
max | Maximum number of this item that can be retrieved from the same vehicle state before it is returned or refilled. |
ammo | Weapon ammo metadata. |
componentItemNames | Weapon component item names. |
tint | Weapon tint metadata. |
quick | Shows the item in Quick Access. |
autoEquipWeapon | Set false to prevent auto-equip for this item when Config.autoEquipWeapon is enabled. |
Clothing fields
Section titled “Clothing fields”| Field | Description |
|---|---|
label | Display label in the menu. |
componentId | GTA clothing component ID. |
propId | GTA prop ID. Use propId = -1 to clear all props for that entry. |
drawable | Drawable variation. |
texture | Texture variation. |
quick | Shows the clothing entry in Quick Access. |
Refill stations
Section titled “Refill stations”Configure static refill points in Config.refillStations. Use matching type values when a station should only refill a specific loadout family.
Config.refillStations = { { label = 'Police Armory', type = { 'police' }, groups = { 'police', 'sheriff' },
coords = vector3(-1833.0654, -3150.6802, 13.0), distance = 3.0,
marker = { enabled = true, scale = vector3(3.0, 3.0, 3.0), type = 1, color = { r = 255, g = 0, b = 0, a = 70 }, },
drawText = true,
blip = { enabled = true, sprite = 110, color = 3, scale = 0.8, }, },}| Field | Description |
|---|---|
label | Menu, marker, or blip label. |
type | Optional station type. Pair it with loadout type values. |
groups | Optional access filter for the station. |
coords | World position for the refill station. |
distance | Interaction distance. Defaults to 10 if omitted. |
drawText | Enables station draw text when supported by the client flow. |
marker | Optional FiveM marker configuration. See Marker fields. |
blip | Optional map blip configuration. See Blip fields. |
Marker fields
Section titled “Marker fields”Use marker to draw a FiveM marker at the refill station.
marker = { enabled = true, scale = vector3(3.0, 3.0, 3.0), type = 1, direction = vector3(0.0, 0.0, 0.0), rot = vector3(0.0, 0.0, 0.0), color = { r = 255, g = 0, b = 0, a = 70 }, bobUpAndDown = false, faceCamera = false, rotate = false, textureDict = nil, textureName = nil,}Blip fields
Section titled “Blip fields”Use blip to create a map blip for the refill station.
blip = { enabled = true, sprite = 110, color = 3, scale = 0.8, label = 'Police Armory',}| Field | Description |
|---|---|
enabled | Enables or disables the map blip. |
sprite | Blip sprite ID. Defaults to 110 if omitted. |
color | Blip color ID. Defaults to 3 if omitted. |
scale | Blip size. Defaults to 0.8 if omitted. |
label | Optional custom blip label. If omitted, DutyKit uses the refill station label. |
Vehicle interaction notes
Section titled “Vehicle interaction notes”- DutyKit adds target options to vehicle boot/trunk access for loadouts and refills.
- Vehicle access checks are performed again on the server before giving items or applying loadouts.
- The server rejects access when the player is too far from the target vehicle.
- If
Config.checkVehicleLockedis enabled, locked vehicles cannot be opened for DutyKit access. - If the configured trunk door is unavailable, DutyKit falls back to rear doors where possible.
Advanced adapter overrides
Section titled “Advanced adapter overrides”The following files are escrow-ignored so you can adapt DutyKit to custom server stacks without editing locked code:
config.lualoadouts/*.luaserver/framework/*.luaserver/inventory/*.luaclient/framework/*.luaclient/inventory/*.luaclient/interface/*.luaclient/target/*.lua
Inventory adapters are expected to provide:
-- ClientClientFramework.getItem(itemName)ClientFramework.getItems()ClientFramework.useSlot(slot)
-- ServerServerFramework.getItem(itemName)ServerFramework.getItems()ServerFramework.addInventoryItem(player, itemName, amount, metadata)ServerFramework.removeInventoryItem(player, itemName, amount, metadata, slot)ServerFramework.getInventoryItemBySlot(player, slot)ServerFramework.getSlotIdWithItem(player, itemName, metadata)Framework adapters are expected to provide:
GetPlayer(source)ServerFramework.IsPlayerInGroup(player, groups)ClientFramework.IsPlayerInGroup(groups)Troubleshooting
Section titled “Troubleshooting”The target option does not appear
Section titled “The target option does not appear”Check that:
Config.targetmatches the target resource you are running.- The target resource starts before
kf-dutykit. - The vehicle spawn name is listed in
allowedVehicles. - The player is in one of the configured
groups. - The player’s ped model is allowed by
allowedPeds, if set. - The vehicle is not locked when
Config.checkVehicleLocked = true.
Items show as missing or have no labels
Section titled “Items show as missing or have no labels”Check that:
Config.inventorymatches your inventory resource.- The inventory resource starts before
kf-dutykit. - Every
itemNameexactly matches an item registered in your inventory. - Weapon component item names exist in your inventory when using
componentItemNames.
Outfit values are wrong
Section titled “Outfit values are wrong”Enable debug mode, put on the desired outfit, run /dumpappearance, then copy the printed component and prop rows into your outfit loadout file.
Players can see a loadout but cannot retrieve items
Section titled “Players can see a loadout but cannot retrieve items”Check server logs for access-denied or inventory adapter errors. The server validates the entity, distance, group filter, vehicle allowlist, ped allowlist, and inventory add result before completing the request.