📝Configuration
Client config
local tabletEntity = nil -- DO NOT CHANGE
local tabletModel = "pp_tablet"
local tabletDict = "amb@world_human_seat_wall_tablet@female@base"
local tabletAnim = "base"
local imagePromise = nil
local items = nil
return {
locale = 'en', -- EN | PL
keybind = true,
startTabletAnimation = function()
lib.requestAnimDict(tabletDict)
if tabletEntity then
stopTabletAnimation()
end
lib.requestModel(tabletModel)
tabletEntity = CreateObject(GetHashKey(tabletModel), 1.0, 1.0, 1.0, 1, 1, 0)
AttachEntityToEntity(tabletEntity, cache.ped, GetPedBoneIndex(cache.ped, 57005), 0.12, 0.10, -0.13, 25.0, 170.0, 160.0, true, true, false, true, 1, true)
TaskPlayAnim(cache.ped, tabletDict, tabletAnim, 8.0, -8.0, -1, 50, 0, false, false, false)
end,
stopTabletAnimation = function()
if tabletEntity then
StopAnimTask(cache.ped, tabletDict, tabletAnim ,8.0, -8.0, -1, 50, 0, false, false, false)
DeleteEntity(tabletEntity)
tabletEntity = nil
end
end,
getWeaponData = function(weapon)
if not items then
items = exports.ox_inventory:Items()
end
return {
model = items[weapon['weapon']].label,
img = ("https://cfx-nui-ox_inventory/web/images/%s.png"):format(weapon['weapon'])
}
end,
cameraTextUI = '[BACKSPACE] - Cancel \n[ENTER] - Confirm',
camerasOffsets = {
prop_cctv_cam_01a = {
initialCamCoord = vector3(0.14, -0.62, 0.21),
initialCamRot = vector3(-30.0, 0.0, 209.4)
},
prop_cctv_cam_01b = {
initialCamCoord = vector3(-0.04, -1.29, 0.22),
initialCamRot = vector3(-30.0, 0.0, 139.50)
},
prop_cctv_cam_03a = {
initialCamCoord = vector3(-0.47, -0.45, 0.28),
initialCamRot = vector3(0.0, 0.0, 118.0)
},
prop_cctv_cam_05a = {
initialCamCoord = vector3(0.05, -0.19, 0.1),
initialCamRot = vector3(-20.0, 0.0, 175.5)
},
prop_cctv_cam_06a = {
initialCamCoord = vector3(0.01, -0.07, 0.14),
initialCamRot = vector3(0.0, 0.0, 178.0)
}
}
}
UI config
return {
homepage = {
dispatchlimit = 10,
maxSearchResults = 20
},
announcements = {
minContentLength = 30
},
citizen = {
licensePrefix = {
["Boat License"] = "BOAT"
}
},
patrols = {
statusTypes = {"Patrol", "Break", "Own Intervention", "Responding", "Other", "Transporting a detainee"},
patrolTypes = {
{ value = "heli", label = "Helicopter" },
{ value = "car", label = "Car" },
{ value = "walk", label = "Walk" },
{ value = "boat", label = "Boat" },
{ value = "bike", label = "Bike" },
{ value = "motorbike", label = "Motorbike" },
},
statusColorMap = {
['Patrol'] = "blue",
['Break'] = "orange",
['Own Intervention'] = "purple",
['Responding'] = "green",
['Other'] = "gray",
['Transporting a detainee'] = "cyan"
}
},
dispatch = {
distanceCalculate = {
unit = "miles",
useRoadDistance = true
},
weaponColors = {
['handgun'] = "blue",
['smg'] = "red",
['rifle'] = "gray",
['sniper_rifle'] = "orange",
['shotgun'] = "purple",
['heavy'] = "black",
['thrown'] = "green"
},
timeLabels = {
seconds = {
{ min = 0, max = 1, label = "a second" },
{ min = 2, max = 59, label = "x seconds" }
},
minutes = {
{ min = 1, max = 1, label = "a minute" },
{ min = 2, max = 59, label = "x minutes" }
},
hours = {
{ min = 1, max = 1, label = "an hour" },
{ min = 2, max = 23, label = "x hours" }
},
days = {
{ min = 1, max = 1, label = "a day" },
{ min = 2, max = 6, label = "x days" }
},
weeks = {
{ min = 1, max = 1, label = "a week" },
{ min = 2, max = 4, label = "x weeks" }
},
months = {
{ min = 1, max = 1, label = "a month" },
{ min = 2, max = 11, label = "x months" }
},
years = {
{ min = 1, max = 1, label = "a year" },
{ min = 2, max = 100, label = "x years" }
}
}
}
}
Server config
exports.ox_inventory:registerHook('buyItem', function(payload)
if payload.metadata and payload.metadata.serial then
local xPlayer = Bridge.getPlayerFromId(payload.source)
local coords = GetEntityCoords(GetPlayerPed(payload.source))
MySQL.Async.execute('INSERT INTO `mdt_weapons` (weapon, serialnumber, identifier, coords) VALUES (?, ?, ?, ?)', {payload.itemName, payload.metadata.serial, Bridge.getIdentifier(xPlayer), json.encode({x = coords.x, y = coords.y})})
end
return true
end, {
print = false,
})
return {
locales = 'en', -- EN | PL
imageUpload = {
type = 'fivemanage', -- fivemanage | fmsdk | discord | custom
token = '', -- fivemanage token | discord webhook
custom = function(source)
return nil --return url
end
},
jobsWithAccess = {
'police'
},
cameras = {
enable = true,
limit = 10
},
homePage = {
getOfficerData = function(player)
local radiochannel = Player(player.PlayerData.source).state.radioChannel
local image = player.PlayerData.metadata.mdt_image
local badge = player.PlayerData.metadata.callsign or 0
return {
radio = radiochannel,
img = image,
badge = badge
}
end,
getPhoto = function(identifier)
local player = exports.qbx_core:GetPlayerByCitizenId(identifier) or exports.qbx_core:GetOfflinePlayer(identifier)
if not player then return false end
return player.PlayerData.metadata.mdt_image
end
},
citizen = {
updatePhoto = function(identifier, url)
local player = exports.qbx_core:GetPlayerByCitizenId(identifier) or exports.qbx_core:GetOfflinePlayer(identifier)
if not player then return false end
player.Functions.SetMetaData('mdt_image', url)
return true
end,
getCitizenDetails = function(identifier)
local player = exports.qbx_core:GetPlayerByCitizenId(identifier) or exports.qbx_core:GetOfflinePlayer(identifier)
if not player or not player.PlayerData then return {} end
local data = player.PlayerData
local licenses = {}
for name, value in pairs(data.metadata.licences) do
table.insert(licenses, {
label = name,
owns = value
})
end
return {
name = data.charinfo.firstname .. ' ' .. data.charinfo.lastname,
dob = data.charinfo.birthdate,
img = data.metadata.mdt_image,
ssn = identifier,
nationality = data.charinfo.nationality,
licenses = licenses
}
end
},
vehicle = {
getVehicleDetails = function(plate)
local dbdata = MySQL.query.await([[
SELECT
pv.citizenid AS identifier,
pv.hash,
pv.mdt_image AS img,
JSON_UNQUOTE(JSON_EXTRACT(p.charinfo, '$.firstname')) AS firstname,
JSON_UNQUOTE(JSON_EXTRACT(p.charinfo, '$.lastname')) AS lastname
FROM
`player_vehicles` pv
LEFT JOIN
`players` p ON pv.citizenid = p.citizenid
WHERE
pv.plate = ?
]], {
plate
})
if dbdata and #dbdata > 0 then
local vehicleData = dbdata[1]
vehicleData.name = vehicleData.firstname .. " " .. vehicleData.lastname
return vehicleData
else
return {}
end
end,
updatePhoto = function(plate, url)
local affectedRows = MySQL.update.await('UPDATE `player_vehicles` SET `mdt_image` = ? WHERE `plate` = ?', {
url, plate
})
return affectedRows > 0 and true or false
end
},
case = {
mugshot = {
enable = true,
title = "Los Santos Police Department",
subtitle = "Case #%s",
updatePhoto = function(identifier, url)
local player = exports.qbx_core:GetPlayerByCitizenId(identifier) or exports.qbx_core:GetOfflinePlayer(identifier)
if not player then return false end
player.Functions.SetMetaData('mdt_image', url)
return true
end,
},
sendToJail = function(identifier, months, fine, data)
-- fill with your own jail system
end,
giveTicket = function(identifier, fine, data)
-- fill with your own ticket system
end,
charges = {
{
id = 1,
label = 'Speeding (Minor)',
description = 'Exceeding the speed limit by up to 10 mph.',
fine = 100,
months = 0,
level = 'low',
},
{
id = 2,
label = 'Speeding (Moderate)',
description = 'Exceeding the speed limit by 11-20 mph.',
fine = 500,
months = 0,
level = 'medium',
},
{
id = 3,
label = 'Speeding (Severe)',
description = 'Exceeding the speed limit by over 20 mph.',
fine = 1500,
months = 1,
level = 'high',
},
{
id = 4,
label = 'Reckless Driving',
description = 'Operating a vehicle in a manner that endangers others.',
fine = 3000,
months = 3,
level = 'high',
},
{
id = 5,
label = 'DUI (First Offense)',
description = 'Driving under the influence of alcohol or drugs.',
fine = 2000,
months = 6,
level = 'medium',
},
{
id = 6,
label = 'DUI (Repeat Offense)',
description = 'Repeated offense of driving under the influence.',
fine = 5000,
months = 12,
level = 'critical',
},
{
id = 7,
label = 'Assault (Minor)',
description = 'Physical attack causing minor injuries.',
fine = 1000,
months = 6,
level = 'low',
},
{
id = 8,
label = 'Assault (Severe)',
description = 'Physical attack causing severe injuries.',
fine = 5000,
months = 24,
level = 'high',
},
{
id = 9,
label = 'Robbery',
description = 'Taking property from another person by force or threat.',
fine = 10000,
months = 36,
level = 'critical',
},
{
id = 10,
label = 'Murder',
description = 'Unlawful killing of another person.',
fine = 25000,
months = 60,
level = 'critical',
},
}
},
patrols = {
inviteExpiration = 60000, -- 1 minute
},
dispatch = {
getGender = function(frPlayer)
return frPlayer.PlayerData.charinfo.gender and "Male" or "Female"
end,
ignoreJobsWithAccess = true,
gunShots = {
enable = true,
delay = 5000,
locales = {
title = 'Shots fired',
description = 'Gun shots reported',
code = '10-71',
blip = '# 10-71 - Shots Fired'
},
monitoredWeapons = {
['Handgun'] = {
['WEAPON_PISTOL'] = true,
['WEAPON_COMBATPISTOL'] = true,
['WEAPON_HEAVYPISTOL'] = true,
['WEAPON_VINTAGEPISTOL'] = true,
['WEAPON_SNSPISTOL'] = true,
['WEAPON_PISTOL50'] = true,
['WEAPON_REVOLVER'] = true,
['WEAPON_REVOLVER_MK2'] = true,
['WEAPON_DOUBLEACTION'] = true,
['WEAPON_APPISTOL'] = true,
['WEAPON_STUNGUN'] = true,
['WEAPON_FLAREGUN'] = true,
['WEAPON_MARKSMANPISTOL'] = true,
['WEAPON_RAYPISTOL'] = true,
['WEAPON_CERAMICPISTOL'] = true,
['WEAPON_NAVYREVOLVER'] = true
},
['SMG'] = {
['WEAPON_MICROSMG'] = true,
['WEAPON_SMG'] = true,
['WEAPON_SMG_MK2'] = true,
['WEAPON_ASSAULTSMG'] = true,
['WEAPON_MINISMG'] = true,
['WEAPON_MACHINEPISTOL'] = true,
['WEAPON_COMBATPDW'] = true
},
['Rifle'] = {
['WEAPON_ASSAULTRIFLE'] = true,
['WEAPON_ASSAULTRIFLE_MK2'] = true,
['WEAPON_CARBINERIFLE'] = true,
['WEAPON_CARBINERIFLE_MK2'] = true,
['WEAPON_ADVANCEDRIFLE'] = true,
['WEAPON_SPECIALCARBINE'] = true,
['WEAPON_SPECIALCARBINE_MK2'] = true,
['WEAPON_BULLPUPRIFLE'] = true,
['WEAPON_BULLPUPRIFLE_MK2'] = true,
['WEAPON_COMPACTRIFLE'] = true,
['WEAPON_MILITARYRIFLE'] = true,
['WEAPON_HEAVYRIFLE'] = true,
['WEAPON_TACTICALRIFLE'] = true
},
['Sniper rifle'] = {
['WEAPON_SNIPERRIFLE'] = true,
['WEAPON_HEAVYSNIPER'] = true,
['WEAPON_HEAVYSNIPER_MK2'] = true,
['WEAPON_MARKSMANRIFLE'] = true,
['WEAPON_MARKSMANRIFLE_MK2'] = true
},
['Shotgun'] = {
['WEAPON_PUMPSHOTGUN'] = true,
['WEAPON_PUMPSHOTGUN_MK2'] = true,
['WEAPON_SAWNOFFSHOTGUN'] = true,
['WEAPON_BULLPUPSHOTGUN'] = true,
['WEAPON_ASSAULTSHOTGUN'] = true,
['WEAPON_MUSKET'] = true,
['WEAPON_HEAVYSHOTGUN'] = true,
['WEAPON_DBSHOTGUN'] = true,
['WEAPON_AUTOSHOTGUN'] = true,
['WEAPON_COMBATSHOTGUN'] = true
},
['Heavy rifle'] = {
['WEAPON_GRENADELAUNCHER'] = true,
['WEAPON_RPG'] = true,
['WEAPON_MINIGUN'] = true,
['WEAPON_FIREWORK'] = true,
['WEAPON_RAILGUN'] = true,
['WEAPON_HOMINGLAUNCHER'] = true,
['WEAPON_COMPACTLAUNCHER'] = true,
['WEAPON_RAYMINIGUN'] = true,
['WEAPON_EMPLAUNCHER'] = true
},
['Thrown'] = {
['WEAPON_GRENADE'] = true,
['WEAPON_STICKYBOMB'] = true,
['WEAPON_PROXMINE'] = true,
['WEAPON_BZGAS'] = true,
['WEAPON_MOLOTOV'] = true,
['WEAPON_FIREEXTINGUISHER'] = true,
['WEAPON_PETROLCAN'] = true,
['WEAPON_BALL'] = true,
['WEAPON_SNOWBALL'] = true,
['WEAPON_FLARE'] = true,
['WEAPON_PIPEBOMB'] = true
}
}
}
},
permissions = {
[1] = { -- [grade] = { permissions }
announcements = {
'view',
},
patrols = {
'view',
},
citizens = {
'view'
},
citizen = {
'view',
},
vehicles = {
'view'
},
vehicle = {
'view'
},
weapons = {
'view'
},
weapon = {
'view'
},
evidences = {
'view',
},
cases = {
'view',
},
case = {
'view',
},
cameras = {
'view',
},
notes = {
'view',
},
note = {
'view',
},
settings = {
'view'
}
},
[2] = {
homepage = {
'viewchat',
'chatmessage',
'search'
},
announcements = {
'create',
},
announcement = {
'edit',
'remove'
},
patrols = {
'create'
},
citizen = {
'takephoto',
'removephoto',
'viewcases',
'viewnotes',
'viewvehicles'
},
vehicle = {
'takephoto',
'removephoto',
'viewcases',
'viewnotes'
},
weapon = {
'viewcases',
'viewnotes'
},
evidences = {
'listview',
'create'
},
cases = {
'listview',
'create'
},
case = {
'edit',
'delete'
},
cameras = {
'create'
},
notes = {
'listview',
'create'
},
note = {
'edit',
'remove'
}
}
},
queries = {
['searchCitizens'] = [[
SELECT
COUNT(*) as count
FROM
players
WHERE
JSON_UNQUOTE(JSON_EXTRACT(charinfo, '$.firstname')) LIKE @search
OR JSON_UNQUOTE(JSON_EXTRACT(charinfo, '$.lastname')) LIKE @search
]],
['getCitizens'] = [[
SELECT
citizenid AS identifier,
citizenid AS ssn,
JSON_UNQUOTE(JSON_EXTRACT(charinfo, '$.firstname')) AS firstname,
JSON_UNQUOTE(JSON_EXTRACT(charinfo, '$.lastname')) AS lastname,
JSON_UNQUOTE(JSON_EXTRACT(metadata, '$.mdt_image')) AS image
FROM
players
WHERE
JSON_UNQUOTE(JSON_EXTRACT(charinfo, '$.firstname')) LIKE @search
OR JSON_UNQUOTE(JSON_EXTRACT(charinfo, '$.lastname')) LIKE @search
LIMIT @limit OFFSET @offset
]],
['countVehicles'] = [[
SELECT COUNT(*) as count
FROM `player_vehicles`
WHERE `plate` LIKE @search
]],
['getVehicles'] = [[
SELECT
pv.plate,
pv.citizenid,
pv.vehicle,
pv.hash,
pv.mdt_image AS image,
JSON_UNQUOTE(JSON_EXTRACT(p.charinfo, '$.firstname')) AS firstname,
JSON_UNQUOTE(JSON_EXTRACT(p.charinfo, '$.lastname')) AS lastname
FROM
`player_vehicles` pv
LEFT JOIN
`players` p ON pv.citizenid = p.citizenid
WHERE
pv.plate LIKE @search
LIMIT
@limit OFFSET @offset
]],
['getCitizenVehicles'] = 'SELECT `hash`, `plate` FROM `player_vehicles` WHERE `citizenid` = ?',
['getAuthor'] = [[
SELECT
JSON_UNQUOTE(JSON_EXTRACT(charinfo, '$.firstname')) AS firstname,
JSON_UNQUOTE(JSON_EXTRACT(charinfo, '$.lastname')) AS lastname
FROM
players
WHERE
citizenid = ?
]],
['getCitizensByIdentifiers'] = [[
SELECT
citizenid AS identifier,
JSON_UNQUOTE(JSON_EXTRACT(charinfo, '$.firstname')) AS firstname,
JSON_UNQUOTE(JSON_EXTRACT(charinfo, '$.lastname')) AS lastname
FROM
players
WHERE
citizenid IN (?)
]],
weapons = {
['usersSearch'] = 'SELECT citizenid FROM players WHERE JSON_EXTRACT(charinfo, "$.firstname") LIKE @search OR JSON_EXTRACT(charinfo, "$.lastname") LIKE @search',
['usersFullName'] = 'CONCAT(JSON_UNQUOTE(JSON_EXTRACT(p.charinfo, "$.firstname")), " ", JSON_UNQUOTE(JSON_EXTRACT(p.charinfo, "$.lastname")))',
['usersJoin'] = 'LEFT JOIN players p ON w.identifier = p.citizenid'
},
search = {
['citizens'] = [[
SELECT
citizenid AS identifier,
JSON_UNQUOTE(JSON_EXTRACT(charinfo, '$.firstname')) AS firstname,
JSON_UNQUOTE(JSON_EXTRACT(charinfo, '$.lastname')) AS lastname
FROM
players
WHERE
JSON_UNQUOTE(JSON_EXTRACT(charinfo, '$.firstname')) LIKE @query
OR JSON_UNQUOTE(JSON_EXTRACT(charinfo, '$.lastname')) LIKE @query
LIMIT 20
]],
['vehicles'] = [[
SELECT
plate, hash
FROM
player_vehicles
WHERE
plate LIKE @query
LIMIT 20
]],
['officers'] = [[
SELECT
p.citizenid AS identifier,
JSON_UNQUOTE(JSON_EXTRACT(p.charinfo, '$.firstname')) AS firstname,
JSON_UNQUOTE(JSON_EXTRACT(p.charinfo, '$.lastname')) AS lastname
FROM
players p
WHERE
JSON_UNQUOTE(JSON_EXTRACT(p.job, '$.name')) = @job
AND (
JSON_UNQUOTE(JSON_EXTRACT(p.charinfo, '$.firstname')) LIKE @query
OR JSON_UNQUOTE(JSON_EXTRACT(p.charinfo, '$.lastname')) LIKE @query
)
LIMIT 20
]],
['weapons'] = [[
SELECT
mw.serialnumber,
JSON_UNQUOTE(JSON_EXTRACT(p.charinfo, '$.firstname')) AS firstname,
JSON_UNQUOTE(JSON_EXTRACT(p.charinfo, '$.lastname')) AS lastname
FROM
mdt_weapons mw
INNER JOIN
players p ON mw.identifier = p.citizenid
WHERE
mw.serialnumber LIKE @query
OR (
JSON_UNQUOTE(JSON_EXTRACT(p.charinfo, '$.firstname')) LIKE @query
OR JSON_UNQUOTE(JSON_EXTRACT(p.charinfo, '$.lastname')) LIKE @query
)
LIMIT 20
]]
}
},
}
Last updated