Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
This documentation covers everything you need to get your script set up and working as intended. Please make sure to read it carefully—most issues can be avoided by following the steps provided. If all dependencies are installed correctly and you follow the instructions, your script will work as expected.
If you've followed the documentation and are still having issues, head over to our Discord and open a support ticket. The link is in the sidebar (bottom left). We’ll help you out once you’ve confirmed you've run through the docs.
Looking for something more tailored to your server? We offer:
⚙️ Script optimisations and performance tweaks
⚒️ Creation of scripts from idea to production.
🎨 UI creation, edits, and complete redesigns
🧱 Custom features or systems built to your spec
If you’re after something beyond what's available out-of-the-box, open a ticket in Discord to discuss your requirements.
Use to easily communicate between both client and server
Call and await for a response of a server callback
-- Client
lib.callback.await(event, ...)
-- Server
lib.callback.await(event, playerId, ...)event
Server defined event name
playerId
Server Only - source to send request to
cb
Callback function, there must be at least one defined
Register a client callback, this can be used to easily request data from a client from the server
lib.callback.register(event, cb)event
Event name to be called from the server
cb
Callback function, should return values for the callback
The cache is used to store frequent information that scripts will use, this reduces the load of scripts overall as the core library is the only resource gathering these variables.
The cache is simple to access, once you've followed the steps, you will be able to access the following values:
You can simple called cache.x with whichever type you wish anywhere in your code, so long as dirk_lib is imported.
All of the above cache types can be used with lib.onCache, this is essentially a listener that will trigger upon change of the value and at initial set.
Here we will guide you through the basics from downloading the asset from your keymaster to where to put the folder, more specific instructions will be found on the left under resource name.
After purchasing one of our scripts, head over to — this is where all of your purchased assets are managed.
From there, hit Download to grab the latest version.
If this is your first time installing a DirkScripts resource, we recommend creating a folder named:
Place all DirkScripts scripts and their dependencies inside this folder. This keeps everything organised and ensures proper start order.
Example structure:
Add the following to your server.cfg:
The best location is somewhere after your framework and it's dependencies start.
This approach helps avoid loading issues and makes updates easier down the line.
ped
The players ped id
vehicle
Current vehicle entityId if there is one or false
driver
true or false for if the player is driving
seat
The seat the player is in if any
weapon
The weapon the player is holding if any
dead
Is the player dead, this is based off of framework specific death metadata and IsEntityDead()
cuffed
Again this is framework specific.
job
This is in the format of dirk_lib/types/job
playerId
The players PlayerId()
citizenId
The players unique character identifier if they have one
serverId
The players serverId
playerLoaded
Whether or not the player has loaded and selected a character
-- We can replace 'cuffed' with any of the values from above.
lib.onCache('cuffed', function(isCuffed, oldValue)
print(('Player is now cuffed: %s\nPlayer was cuffed before: %s'):format(isCuffed, oldValue))
end)
-- OR IF YOU REALLY WANTED--
AddEventHandler("dirk_lib:cache:cuffed", function(isCuffed, oldValue)
print(('Player is now cuffed: %s\nPlayer was cuffed before: %s'):format(isCuffed, oldValue))
end)[dirk]resources/
└── [dirk]/
├── dirk_inventory
├── dirk_traphouse
└── dirk_dependenciesensure [dirk]

Helpful functions for the player data structure and functions
Used for GTA map location blips, for example a fuel station location
Register a new blip to be shown on the map
lib.blip.register(id, data)id
Unique reference for the blip
data
Options for the blip, see
Get a blip's data via it's id
local blip = lib.blip.get(id)id
Unique reference for the blip
Remove a blip from the map and cache
lib.blip.delete(id)id
Unique reference for the blip
This is the data structure of a blip and the valid options
{
-- Required
pos = vector2(150.0, 100.0), -- Used as the location on the map
name = "Example Blip", -- Label displayed on the map key
sprite = 1, -- Sprite to be displayed
display = 4, -- Display options
scale = 1.0, -- Size of the blip
color = 1, -- Color of the blip
-- Not Required
shortRange = false, -- Is the blip short range
category = 1, -- Category of the blip
alpha = 255, -- Alpha (opacity) of the blip
rotation = 0, -- Rotation
route = false, -- Should the blip be routed to
canSee = function() -- Should the blip render
return true
end,
}FiveM Blip Sprites Reference: https://docs.fivem.net/docs/game-references/blips/#blips
FiveM Native SetBlipDisplay Reference: https://docs.fivem.net/natives/?_0x9029B2F3DA924928
Fivem Blip Colour Reference: https://docs.fivem.net/docs/game-references/blips/#blip-colors
FiveM Native SetBlipCategory Reference: https://docs.fivem.net/natives/?_0x234CDD44D996FD9A
To get started, simply ensure dirk_lib is started after your framework, inventory, and targeting resources.
There’s no complex setup—dirk_lib will automatically detect supported resources and apply the correct bridging logic for your setup.
No extra config needed—just ensure the dependencies are started before dirk_lib.
You can customize the behaviour of dirk_lib by setting server variables (ConVars). These can be placed in your server.cfg or follow the tip below for a cleaner way.
To get started with lib, include the shared script within your resource's fxmanifest.lua
You are able to select modules to be loaded, however they will also dynamically import. This can be done via the dirk_libsmanifest option
This is a list of all the resources that this lib will bridge for, add your own by making a PR or contacting me on discord.
# Example Start Order
ensure qb-core
ensure ox_inventory
ensure ox_target
ensure dirk_lib# The theme below will apply to all UI created by DirkScripts utilising the lib themes.
# Theme starts at 0 and goes to 9
# 0 is the lightest color and 9 is the darkest
# You can set the primary color to custom and set the customTheme to your own colors
# Use this generator in order to make your own custom color palettes https://mantine.dev/colors-generator/?color=7b36b5
# Default mantine colors can be found here https://mantine.dev/theming/colors/#default-colors
setr dirk_lib:primaryColor dirk # Set to custom to use customTheme
setr dirk_lib:primaryShade 9 # 0-9
setr dirk_lib:customTheme [
"#e5f8ff",
"#d0ecff",
"#a0d7fc",
"#6dc1fa",
"#47aef9",
"#32a2f9",
"#259cfa",
"#1888df",
"#0179c8",
"#0068b1"
]
setr dirk_lib:language en
setr dirk_lib:debug true
setr dirk_lib:currency $
setr dirk_lib:serverName DirkRP
setr dirk_lib:logo https://via.placeholder.com/150
# Configure the resources you want to use will autodetect otherwise [OPTIONAL]
setr dirk_lib:framework qbx_core
setr dirk_lib:inventory dirk_inventory
setr dirk_lib:itemImgPath nui://dirk_inventory/web/images/
setr dirk_lib:primaryIdentifier license
setr dirk_lib:target ox_target
setr dirk_lib:interact sleepless_interact
setr dirk_lib:time dirk_weather
setr dirk_lib:phone lb-phone
setr dirk_lib:keys dirk_keys
setr dirk_lib:garage dirk_vehicles
setr dirk_lib:fuel dirk_fuel
setr dirk_lib:ambulance dirk_ambulance
setr dirk_lib:prison dirk_prison
setr dirk_lib:dispatch dirk_dispatch
# NOTIFICATIONS
setr dirk_lib:notify dirk_lib
setr dirk_lib:notifyPosition top-right
setr dirk_lib:notifyAudio true
# Context Menu
setr dirk_lib:contextMenu dirk_lib
setr dirk_lib:contextClickSounds true
setr dirk_lib:contextHoverSounds true
# Dialog
setr dirk_lib:dialog dirk_lib
setr dirk_lib:dialogClickSounds true
setr dirk_lib:dialogHoverSounds true
# showTextUI
setr dirk_lib:showTextUI dirk_lib
setr dirk_lib:showTextPosition bottom-center
# progressBar
setr dirk_lib:progress dirk_lib
setr dirk_lib:progBarPosition bottom-center
# Groups
setr dirk_groups:maxMembers 5
setr dirk_groups:maxDistanceInvite 5
setr dirk_groups:inviteValidTime 5
setr dirk_groups:maxLogOffTime 5
shared_scripts {
'@dirk_lib/init.lua'
}dirk_libs {
'math',
'objects'
}Used to request models and textures
Load a model with timeout checks
local success = lib.request.model(model, timeout)model
Model(s) to load
timeout
Timeout for the model loads, default 20s
Request texture dictionary
local success = lib.request.streamedTextureDict(txd, timeout)txd
Texture(s) to load
timeout
Timeout for the texture loads, default 20s
Helpful functions for the player data structure and functions
Fixed issue with qbx_core not picking up license2 natively, resulting in no characters being shown.
Consolidated and reworked all logic for clothing/appearance menus to dirk_lib for simpler adding of more.
With illenium and all major clothing including rcore_clothing the characters will now properly display.
Added ability to use existing character_slots table from es_extended for vipSlots
Added better support for finding player cars/houses including for qs-housing.
Added ability to disable deleting of characters.
Fixed loadEvent stuff from preventing peoples HUDs showing up.
Helpful functions for the player data structure and functions
Added group/license/discordRole support for both the entire store or per individual product.
Fixed the scrolling issue. BurningLight127
Payment Methods
Added 'black_money' as a payment method instead of placeholder 'crypto'
Added documentation for this script, feel free to let me know if anything is missing.
Add metadata field to stock instead of having to use metadataGenerators.lua.
Used to register and remove object spawning, from peds to vehicles.
Create a new object
Get information regarding an object
Completely remove an object
This is the data structure of an object and the valid options
DEPENDENCIES
You will need the following resources installed to be able to use this script properly. My Library
Please follow these instructions carefully if you do so you should have no issues, if you do still experience issues after reading through all of this then please make a ticket in discord.
DEPENDENCIES
You will need the following resources installed to be able to use this script properly, please ensure this is possible before buying the script My Library
Please grab your old projectCars.json and place it in the root directory of dirk_projectCars. The script will auto-detect it on startup and convert any old vehicles to the new SQL table.
In order for this to work you will need to add all the data in INSTALLATION/itemsToAdd/ox_items.lua to ox_inventory/data/items.lua
For all QB based inventory systems you can find the items in the following folder
INSTALLATION/itemsToAdd/qb_items.lua should you wish to manually add them
For the supported clothingSystems/Frameworks this will be drag and drop for most users, with no effect to players characters etc.
DEPENDENCIES
You will need the following resources installed to be able to use this script properly, please ensure this is possible before buying the script My Library
All the properties of a stock item within your stock table for a store.
These are all the properties available per category for your store, you can disable categories for a store by removing the categories table entirely.
lib.objects.register(name, new_data)name
Unique reference for object
new_data
Options for the object, refer to Data Structure
local obj = lib.objects.get(name)id
Unique reference for the object
lib.object.destroy(id)id
Unique reference for the object
{
type = "ped", -- This can be: ped, vehicle or object
model = `a_f_m_bevhills_01`, -- Model to be spawned, must be the model hash
pos = vector4(0, 0, 0, 0), -- Position of the object
-- This also can be a polyzone for a set render area
renderDist = 50, -- When to render the object
}lib.print(_type, ...)
-- Example
lib.print("debug", "Example print")_type
Type of print - info, warn, error or debug
...
Debug info
lib.addPrintType(_type, prefix, condition)_type
Unique print type
prefix
What should be prefixed in front of the debug
condition
Callback to check if it should print
id
string
Unique identifier for the store.
type
'buy'
id
string
Unique identifier for the store.
type
'buy'
['windscreen'] = {
['weight'] = 1000,
['label'] = 'Windscreen',
},['windscreen'] = {
['description'] = 'Vehicle Part',
['useable'] = true,
['weight'] = 1000,
['shouldClose'] = false,
['type'] = 'item',
['label'] = 'Windscreen',
['unique'] = false,
['name'] = 'windscreen',
},

Used to create target zones (Third Eye)
Create a simple box zone
lib.target.box(id, data)id
Unique zone reference
data
Zone options
Create a polrzone
This documentation isn't confirmed / is not implimented yet
lib.target.polyzone(id, data)id
Unique zone reference
data
Zone options
Remove a created zone
lib.target.removeZone(id)id
Unique zone reference
Create an entity and allow targeting
lib.target.entity(entity, data)entity
Unique zone reference
data
Zone options
Remove an entity zone
lib.target.removeEntity(entity, net)id
Unique zone reference
net
Is the entity networked
All configuration will be done via the files within the settings folder.
Used to register and control any player interaction
Create a new player interaction
lib.interact.register(name, data)name
Unique reference for the interaction
data
Options for the interact, refer to
Get information regarding an interaction
local interaction = lib.interact.get(name)name
Unique reference for the interaction
Completely remove an interaction
lib.interact.destroy(name)name
Unique reference for the interaction
This is the data structure of an interaction and the valid options
There are multiple different interactions seen below:
{
zone_type = "circle",
pos = vector4(10, 10, 20, 10),
radius = 10
}{
zone_type = "poly",
polygon = {
vector3(0, 0, 0),
vector3(0, 0, 0),
vector3(0, 0, 0),
},
}{
zone_type = "box",
pos = vector4(10, 10, 20, 10),
size = vector3(1, 1, 1)
}{
zone_type = "marker",
pos = vector4(10, 10, 20, 10),
color = vector4(255, 255, 255, 255), -- RGBA
scale = vector3(1, 1, 1),
-- Not Required
dir = vector3(0, 0, 0),
rot = vector3(0, 0, 0),
bob = false,
face = false,
txd = false,
txn = false,
drawEnts = false
}This documentation is pending confirmation
{
zone_type = "text",
text = "Hello World"
pos = vector4(10, 10, 20, 10),
size = vector3(1, 1, 1)
}A free, simple, and flexible store system for FiveM, styled natively and designed to be themed easily to fit your server’s aesthetic.
Default Stores Has most if not all of the default stores configured with basic items from major inventories/frameworks but is fully adjustable.
Categories Optionally have categories for your stores for easier navigation.
Metadata Generators Supports adding unique metadata to specific items, even if your inventory system doesn’t handle it natively.
Group/License Locking Lock the entire store or certain items to different groups or licenses within your city.
Payment Methods Easily add new payment methods to use in any store via the settings/paymentMethods.lua. Here you can define an add and a remove function to implement any sort of currency you wish.
Dynamic Store Creation Register new stores at runtime from the server, giving you complete control over when and where stores appear.
Theming Change the color scheme globally or per store. Don't like green? Pick something that matches your vibe. To set a new global theme for all dirk_scripts see
Used to request models and textures
Used to quickly copy a table, useful for global state values
Check through a table for a set key
Check if a value is present in a table
Convert data to different formats
Count a table and sub tables
Dynamically creates a store at runtime, syncing to all clients for use straight away, when the resource that creates it is stopped the store will be deleted and unregistered from all clients.
The storeData parameter is based upon the .
This will spawn a very basic shop with a store clerk at the coordinates listed.
label
string
✅
Display name of the item.
weight
integer
✅
Weight in grams (e.g. 1000 = 1kg).
description
string
✅
Description text shown in item UI.
chanceOfBreak
integer
❌
Percent chance (0–100) the tool breaks on use.
holdRotation
vector3
❌
Adjusts the rotation of the held object.
holdOffset
vector3
❌
Adjusts the position offset when held.
model
string
❌
Model name of the object to hold (e.g. "prop_tool_box_04").
useable
function
❌
Function to execute when the item is used.
strength
integer
❌
Max supported vehicle weight (in grams). Limits what vehicles this item works on.
tools = {
wrench = {
label = "Wrench",
weight = 1000,
description = "A sturdy wrench for basic repairs.",
chanceOfBreak = 25, -- 25% chance of breaking
holdRotation = vector3(90.0, 0.0, 0.0),
holdOffset = vector3(0.0, -0.15, -0.02),
model = "prop_tool_wrench",
strength = 2000,
useable = function(src)
-- custom usage logic here
end
}
}local copiedTable = lib.table.deepClone(table)table
Table to be copied
local foundData = lib.table.findKeyInTable(tbls, key)tbls
Table to be searched
key
Key to be found
local found = lib.table.includes(table, value, recursive)table
Table to be searched
value
Value to be found
recursive
Check sub tables too
local data = lib.table.convert(_type, data)_type
Type of data - vectors, items_sql, string, item_ox, convert_idexes
data
Data to be converted
local count = lib.table.count(table)table
Table to be counted
local storeData = {
id = 'myNewTestStore',
type = 'buy',
name = 'My Test Store',
description = 'My Short Test Description',
icon = 'fas fa-store',
modelType = 'ped',
models = {'mp_m_shopkeep_01'},
locations = {
vector4(0,0,0,0),
},
paymentMethods = {'cash', 'bank'},
stock = {
{
name = 'bread',
price = 100,
}
},
}
exports.dirk_stores:registerStore(storeData)
You can allow players to purchase labs via tebex instead of in-game for some labs should you wish players can join the server after purchase and use the Config.RedeemCommand (/ClaimLab) in order to claim their new lab this will give them keys into their inventory and ownership.
First you will need to ensure you have linked your tebex to your FiveM server there are many guides for this on Google. You will then need to make a new package with the deliverable product being a Game Server command setup like so: The name of this package you create must be the name of the index of the lab in the config. So in the example below it would have to be "Downtown Cocaine Lab"

Helpful functions for the player data structure and functions
Get the player's information
local player = lib.player.get(source)src
Source of the target
Returns the identifier (CitizenID) of the player
local citizenid = lib.player.identifier(src)src
Source of the target
Returns the name of the character
local firstName, lastName = lib.player.name(src)src
Source of the target
Return the phone number of the character
local phoneNumber = lib.player.phone_number(src)src
Source of the target
Return the gender of the character
local gender = lib.player.gender(src)src
Source of the target
Check if a player is online by their CitizenID
local isOnline = lib.player.checkOnline(identifier)identifier
Identifier to be checked for
Send a player to jail
lib.player.jail(trg, data)trg
Source to be targeted
data
Data to be used, for example time
Add money to a player
lib.player.addMoney(src, acc, amount, reason)src
Source to be targeted
acc
Account to be deposited in
amount
Amount to be moved
reason
Transaction reason
Remove money to a player
lib.player.removeMoney(src, acc, amount, reason)src
Source to be targeted
acc
Account to be removed
amount
Amount to be moved
reason
Transaction reason
Add item to a player
lib.player.addItem(src, item, amount, md, slot)src
Source to be targeted
item
Item spawncode
amount
Quantity
md
Metadata for the item
slot
Slot to be placed in, default is next available
Remove an item for a player
lib.player.removeItem(src, item, amount, md, slot)src
Source to be targeted
item
Item spawncode
amount
Quantity
md
Metadata for the item
slot
Slot to be placed in, default is next available
Edit the metadata of an item
lib.player.editItem(src, slot, new_data)src
Source to be targeted
slot
Item slot to be targeted
new_data
Data to be set
Returns the inventory of the player
local inventory = lib.player.getInventory(src)Example Return:
{
{
name = "example",
label = "Example Item",
count = 10,
info = {
metadata = true,
},
slot = 1
}
}src
Source to be targeted
Each part is defined as an entry in your parts table with configurable fields for how it behaves during installation, usage, and interaction with vehicles.
label
string
✅
The display name of the part.
searchChance
number
✅
Chance this item is found in a search. Set to 0 to make it unsearchable. Think of it like names in a hat—more entries = higher odds.
weight
number
✅
Weight of the part in the inventory (e.g., 1000 = 1kg).
tools
table
❌
Tools required to fit this part. Format: { itemName = quantity }.
consumables
table
❌
Items that will be consumed when installing this part. Same format as tools.
anim
table
❌
Animation config when applying the part.
→ dict
string
⚠️
Animation dictionary. Must specify either dict or scenario.
→ clip
string
✅
Animation clip name.
→ flag
number
❌
Optional animation flags.
→ time
number
❌
Time in seconds to complete the install animation.
reqParts
array
❌
Names of other parts required before this one can be installed.
model
string
❌
Prop model name shown in hand or placed during install (e.g. "prop_oilcan_01a").
applyRange
number
❌
Max distance from the vehicle to allow this part to be installed.
applyAtBone
string
❌
The bone name where this part applies (e.g., "engine").
canStart
function
❌
Function run to check if the car can start based on this part. Parameters:<br/>→ itemExists: boolean (is part installed?)<br/>→ _type: string (part name)<br/>Should return: boolean, message.
removePart
function
❌
Function triggered when removing the part. Parameters:<br/>→ self: vehicle object<br/>→ entity: number (vehicle entity ID)<br/>→ _type: string (part name).
addPart
function
❌
Function triggered when adding the part. Same parameters as removePart.
luaCopyEditparts = {
oil_filter = {
label = "Oil Filter",
searchChance = 15,
weight = 250,
tools = { wrench = 1 },
consumables = { oil = 1 },
anim = {
dict = "anim@amb@clubhouse@tutorial@bkr_tut_ig3@",
clip = "machinic_loop_mechandplayer",
flag = 16,
time = 5
},
reqParts = { "engine_cover" },
model = "prop_oilcan_01a",
applyRange = 2.0,
applyAtBone = "engine",
canStart = function(installed, part)
return installed, installed and "" or "Engine won't start without oil filter."
end,
removePart = function(self, entity, part)
-- custom logic to clean up or detach
end,
addPart = function(self, entity, part)
-- apply tuning or set vars
end
}
}Follow this guide to install the resource.
Dependencies
dirk_lib (REQUIRED)
There is a folder within the script called 'install' within that is another folder called 'itemsToAdd' please choose the format you require for your framework/inventory
Used to create and manage polyzones
Create a new zone
lib.zones.register(id, data)name
Unique zone reference
data
Zone options, refer to
lib.zone.register("exampleZone", {
type = "circle",
pos = vector3(0, 0, 0),
radius = 5.0,
onEnter = function(data)
lib.print("debug", "Entered Zone")
end,
onExit = function(data)
lib.print("debug", "Exited Zone")
end,
})lib.zone.register("exampleZone", {
type = "circle2D",
pos = vector2(0, 0),
radius = 5.0,
onEnter = function(data)
lib.print("debug", "Entered Zone")
end,
onExit = function(data)
lib.print("debug", "Exited Zone")
end,
})local polyPoints = {
vector2(0, 0),
vector2(10, 10),
vector2(20, 20),
vector2(0, 30),
vector2(-10, 15),
}
lib.zone.register("exampleZone", {
type = "poly",
pos = polyPoints,
onEnter = function(data)
lib.print("debug", "Entered Zone")
end,
onExit = function(data)
lib.print("debug", "Exited Zone")
end,
})lib.zone.register("exampleZone", {
type = "box",
pos = vector4(0, 0, 0, 0),
size = vector3(0, 0, 0),
onEnter = function(data)
lib.print("debug", "Entered Zone")
end,
onExit = function(data)
lib.print("debug", "Exited Zone")
end,
})lib.zone.register("exampleZone", {
type = "game_zone",
gameZone = "ALTA"
onEnter = function(data)
lib.print("debug", "Entered Zone")
end,
onExit = function(data)
lib.print("debug", "Exited Zone")
end,
})Get zone information
local zone = lib.zones.get(name)name
Unique zone reference
Remove a created zone
lib.zones.delete(name)name
Unique zone reference
Check whether a position lies inside a zone(s)
local isInside, zoneName = lib.zones.isInsideZone(name, pos)name
Unique zone reference(s)
pos
Position to be checked
This is the data structure of a blip and the valid options
{
-- Required
type = "circle", -- Type of zone: circle, circle2D, poly, box, game_zone
-- Not Required
onEnter = function(data)
-- Callback for entering the zone
end,
onExit = function(data)
-- Callback for exiting the zone
end,
}Some zones have different requirements, see below:
{
pos = vector3(0, 0, 0), -- Position of the zone
radius = 5.0, -- Size of the zone radially from the point
}{
pos = vector2(0, 0), -- Position of the zone
radius = 5.0, -- Size of the zone radially from the point
}{
points = { -- Boundy marks for the polyzone
vector2(0, 0),
vector2(2, 1),
vector2(3, 3),
}
}{
pos = vector4(0,0,0,0), -- Position of the zone, x, y, z, heading
size = vector3(0,0,0) -- Size of the zone from the center point
}{
gameZone = "ALTA"
}Game Zones: https://docs.fivem.net/natives/?_0xCD90657D4C30E1CA
System for creating player groups and managing them. Used in clean_pause and other clean jobs.
This defines the structure for creating a store, either via your config or dynamically through an export. Stores support job/role restrictions, time-based spawning, custom themes, and more.
id
string
✅
Unique identifier for the store.
type
'buy' or 'sell'
✅
Determines whether the store is for buying or selling.
name
string
✅
Store display name (e.g. "24/7 Store").
description
string
✅
Short UI description shown at the top of the store interface.
icon
string (FontAwesomeIcon)
✅
Icon shown in the UI (FontAwesome class name).
modelType
'ped' | 'vehicle' | 'object'
❌
Type of entity used to spawn the store.
models
string[]
✅
Array of model names (e.g. "s_m_m_storeclerk_01").
locations
vector4[]
✅
Array of spawn locations with heading.
paymentMethods
string[]
✅
IDs referencing valid payment methods.
categories
category[]
❌
List of item categories shown in the UI.
stock
stockItem[]
✅
Inventory for the store.
openingHours
[number, number]
❌
Time range when store is available (e.g. {6, 22} for 6AM–10PM).
groups
string | string[] | Record<string, number>
❌
Job, gang, or grade restrictions.
licenses
string | string[]
❌
Player must have these licenses to access the store.
discordRoles
string | string[]
❌
Discord roles required to open the store.
canOpen
function(src: number)
❌
Server-side function to determine if the player can open the store.
theme
themeObject
❌
Optional override for this store’s visual theme.
onExchange
function(src, items, totalPrice)
❌
Called on attempted transaction. Return false to cancel. Return a second param as reason.
BaseStores = BaseStores or {}
BaseStore.gunshop = {
id = "gunshop",
type = "buy",
name = "Ammu-Nation",
description = "Everything you need to stay protected.",
icon = "fa-solid fa-gun",
modelType = "ped",
models = { "s_m_m_ammucountry" },
locations = {
vec4(17.8, -1108.6, 29.8, 160.0)
},
paymentMethods = { "cash", "bank" },
categories = {
{
}
},
stock = {
{ item = "pistol", price = 2500 },
{ item = "pistol_ammo", price = 100 }
},
openingHours = { 9, 21 },
groups = { police = 0, sheriff = 0 },
licenses = { "weapon_license" },
canOpen = function(src)
return true
end,
onExchange = function(src, items, price)
if price > 10000 then
return false, "Transaction limit exceeded"
end
return true
end
}
Some useful commands that are locked to admin only by default. All of these commands will list the arguments required if you type them in the chat.
Will delete the nearest projectCar entirely from the database and the world.
Will complete the nearest projectCar requiring the player to just get in and start it
This will give you an engine with the correct metadata dependant on the class you supply.
Will give you all the items you need to complete a car.