mirror of
https://github.com/qbcore-fivem/qb-core.git
synced 2026-08-29 16:01:29 +00:00
434 lines
15 KiB
Lua
434 lines
15 KiB
Lua
QBCore.Functions = {}
|
|
QBCore.Player_Buckets = {}
|
|
QBCore.Entity_Buckets = {}
|
|
|
|
-- Getters
|
|
-- Get your player first and then trigger a function on them
|
|
-- ex: local player = QBCore.Functions.GetPlayer(source)
|
|
-- ex: local example = player.Functions.functionname(parameter)
|
|
|
|
function QBCore.Functions.GetCoords(entity)
|
|
local coords = GetEntityCoords(entity, false)
|
|
local heading = GetEntityHeading(entity)
|
|
return vector4(coords.x, coords.y, coords.z, heading)
|
|
end
|
|
|
|
function QBCore.Functions.GetIdentifier(source, idtype)
|
|
local identifiers = GetPlayerIdentifiers(source)
|
|
for _, identifier in pairs(identifiers) do
|
|
if string.find(identifier, idtype) then
|
|
return identifier
|
|
end
|
|
end
|
|
return nil
|
|
end
|
|
|
|
function QBCore.Functions.GetSource(identifier)
|
|
for src, _ in pairs(QBCore.Players) do
|
|
local idens = GetPlayerIdentifiers(src)
|
|
for _, id in pairs(idens) do
|
|
if identifier == id then
|
|
return src
|
|
end
|
|
end
|
|
end
|
|
return 0
|
|
end
|
|
|
|
function QBCore.Functions.GetPlayer(source)
|
|
if type(source) == 'number' then
|
|
return QBCore.Players[source]
|
|
else
|
|
return QBCore.Players[QBCore.Functions.GetSource(source)]
|
|
end
|
|
end
|
|
|
|
function QBCore.Functions.GetPlayerByCitizenId(citizenid)
|
|
for src in pairs(QBCore.Players) do
|
|
if QBCore.Players[src].PlayerData.citizenid == citizenid then
|
|
return QBCore.Players[src]
|
|
end
|
|
end
|
|
return nil
|
|
end
|
|
|
|
function QBCore.Functions.GetOfflinePlayerByCitizenId(citizenid)
|
|
return QBCore.Player.GetOfflinePlayer(citizenid)
|
|
end
|
|
|
|
function QBCore.Functions.GetPlayerByPhone(number)
|
|
for src in pairs(QBCore.Players) do
|
|
if QBCore.Players[src].PlayerData.charinfo.phone == number then
|
|
return QBCore.Players[src]
|
|
end
|
|
end
|
|
return nil
|
|
end
|
|
|
|
function QBCore.Functions.GetPlayers()
|
|
local sources = {}
|
|
for k in pairs(QBCore.Players) do
|
|
sources[#sources+1] = k
|
|
end
|
|
return sources
|
|
end
|
|
|
|
-- Will return an array of QB Player class instances
|
|
-- unlike the GetPlayers() wrapper which only returns IDs
|
|
function QBCore.Functions.GetQBPlayers()
|
|
return QBCore.Players
|
|
end
|
|
|
|
--- Gets a list of all on duty players of a specified job and the number
|
|
function QBCore.Functions.GetPlayersOnDuty(job)
|
|
local players = {}
|
|
local count = 0
|
|
for src, Player in pairs(QBCore.Players) do
|
|
if Player.PlayerData.job.name == job then
|
|
if Player.PlayerData.job.onduty then
|
|
players[#players + 1] = src
|
|
count += 1
|
|
end
|
|
end
|
|
end
|
|
return players, count
|
|
end
|
|
|
|
-- Returns only the amount of players on duty for the specified job
|
|
function QBCore.Functions.GetDutyCount(job)
|
|
local count = 0
|
|
for _, Player in pairs(QBCore.Players) do
|
|
if Player.PlayerData.job.name == job then
|
|
if Player.PlayerData.job.onduty then
|
|
count += 1
|
|
end
|
|
end
|
|
end
|
|
return count
|
|
end
|
|
|
|
-- Routing buckets (Only touch if you know what you are doing)
|
|
|
|
-- Returns the objects related to buckets, first returned value is the player buckets, second one is entity buckets
|
|
function QBCore.Functions.GetBucketObjects()
|
|
return QBCore.Player_Buckets, QBCore.Entity_Buckets
|
|
end
|
|
|
|
-- Will set the provided player id / source into the provided bucket id
|
|
function QBCore.Functions.SetPlayerBucket(source --[[ int ]], bucket --[[ int ]])
|
|
if source and bucket then
|
|
local plicense = QBCore.Functions.GetIdentifier(source, 'license')
|
|
SetPlayerRoutingBucket(source, bucket)
|
|
QBCore.Player_Buckets[plicense] = {id = source, bucket = bucket}
|
|
return true
|
|
else
|
|
return false
|
|
end
|
|
end
|
|
|
|
-- Will set any entity into the provided bucket, for example peds / vehicles / props / etc.
|
|
function QBCore.Functions.SetEntityBucket(entity --[[ int ]], bucket --[[ int ]])
|
|
if entity and bucket then
|
|
SetEntityRoutingBucket(entity, bucket)
|
|
QBCore.Entity_Buckets[entity] = {id = entity, bucket = bucket}
|
|
return true
|
|
else
|
|
return false
|
|
end
|
|
end
|
|
|
|
-- Will return an array of all the player ids inside the current bucket
|
|
function QBCore.Functions.GetPlayersInBucket(bucket --[[ int ]])
|
|
local curr_bucket_pool = {}
|
|
if QBCore.Player_Buckets and next(QBCore.Player_Buckets) then
|
|
for _, v in pairs(QBCore.Player_Buckets) do
|
|
if v.bucket == bucket then
|
|
curr_bucket_pool[#curr_bucket_pool + 1] = v.id
|
|
end
|
|
end
|
|
return curr_bucket_pool
|
|
else
|
|
return false
|
|
end
|
|
end
|
|
|
|
-- Will return an array of all the entities inside the current bucket (not for player entities, use GetPlayersInBucket for that)
|
|
function QBCore.Functions.GetEntitiesInBucket(bucket --[[ int ]])
|
|
local curr_bucket_pool = {}
|
|
if QBCore.Entity_Buckets and next(QBCore.Entity_Buckets) then
|
|
for _, v in pairs(QBCore.Entity_Buckets) do
|
|
if v.bucket == bucket then
|
|
curr_bucket_pool[#curr_bucket_pool + 1] = v.id
|
|
end
|
|
end
|
|
return curr_bucket_pool
|
|
else
|
|
return false
|
|
end
|
|
end
|
|
|
|
-- Server side vehicle creation with optional callback
|
|
-- the CreateVehicle RPC still uses the client for creation so players must be near
|
|
function QBCore.Functions.SpawnVehicle(source, model, coords, warp)
|
|
local ped = GetPlayerPed(source)
|
|
model = type(model) == 'string' and joaat(model) or model
|
|
if not coords then coords = GetEntityCoords(ped) end
|
|
local veh = CreateVehicle(model, coords.x, coords.y, coords.z, coords.w, true, true)
|
|
while not DoesEntityExist(veh) do Wait(0) end
|
|
if warp then
|
|
while GetVehiclePedIsIn(ped) ~= veh do
|
|
Wait(0)
|
|
TaskWarpPedIntoVehicle(ped, veh, -1)
|
|
end
|
|
end
|
|
while NetworkGetEntityOwner(veh) ~= source do Wait(0) end
|
|
return veh
|
|
end
|
|
|
|
-- Server side vehicle creation with optional callback
|
|
-- the CreateAutomobile native is still experimental but doesn't use client for creation
|
|
-- doesn't work for all vehicles!
|
|
function QBCore.Functions.CreateVehicle(source, model, coords, warp)
|
|
model = type(model) == 'string' and joaat(model) or model
|
|
if not coords then coords = GetEntityCoords(GetPlayerPed(source)) end
|
|
local CreateAutomobile = `CREATE_AUTOMOBILE`
|
|
local veh = Citizen.InvokeNative(CreateAutomobile, model, coords, coords.w, true, true)
|
|
while not DoesEntityExist(veh) do Wait(0) end
|
|
if warp then TaskWarpPedIntoVehicle(GetPlayerPed(source), veh, -1) end
|
|
return veh
|
|
end
|
|
|
|
-- Paychecks (standalone - don't touch)
|
|
function PaycheckInterval()
|
|
if next(QBCore.Players) then
|
|
for _, Player in pairs(QBCore.Players) do
|
|
if Player then
|
|
local payment = QBShared.Jobs[Player.PlayerData.job.name]['grades'][tostring(Player.PlayerData.job.grade.level)].payment
|
|
if not payment then payment = Player.PlayerData.job.payment end
|
|
if Player.PlayerData.job and payment > 0 and (QBShared.Jobs[Player.PlayerData.job.name].offDutyPay or Player.PlayerData.job.onduty) then
|
|
if QBCore.Config.Money.PayCheckSociety then
|
|
local account = exports['qb-management']:GetAccount(Player.PlayerData.job.name)
|
|
if account ~= 0 then -- Checks if player is employed by a society
|
|
if account < payment then -- Checks if company has enough money to pay society
|
|
TriggerClientEvent('QBCore:Notify', Player.PlayerData.source, Lang:t('error.company_too_poor'), 'error')
|
|
else
|
|
Player.Functions.AddMoney('bank', payment)
|
|
exports['qb-management']:RemoveMoney(Player.PlayerData.job.name, payment)
|
|
TriggerClientEvent('QBCore:Notify', Player.PlayerData.source, Lang:t('info.received_paycheck', {value = payment}))
|
|
end
|
|
else
|
|
Player.Functions.AddMoney('bank', payment)
|
|
TriggerClientEvent('QBCore:Notify', Player.PlayerData.source, Lang:t('info.received_paycheck', {value = payment}))
|
|
end
|
|
else
|
|
Player.Functions.AddMoney('bank', payment)
|
|
TriggerClientEvent('QBCore:Notify', Player.PlayerData.source, Lang:t('info.received_paycheck', {value = payment}))
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
SetTimeout(QBCore.Config.Money.PayCheckTimeOut * (60 * 1000), PaycheckInterval)
|
|
end
|
|
|
|
-- Callback Functions --
|
|
|
|
-- Client Callback
|
|
function QBCore.Functions.TriggerClientCallback(name, source, cb, ...)
|
|
QBCore.ClientCallbacks[name] = cb
|
|
TriggerClientEvent('QBCore:Client:TriggerClientCallback', source, name, ...)
|
|
end
|
|
|
|
-- Server Callback
|
|
function QBCore.Functions.CreateCallback(name, cb)
|
|
QBCore.ServerCallbacks[name] = cb
|
|
end
|
|
|
|
function QBCore.Functions.TriggerCallback(name, source, cb, ...)
|
|
if not QBCore.ServerCallbacks[name] then return end
|
|
QBCore.ServerCallbacks[name](source, cb, ...)
|
|
end
|
|
|
|
-- Items
|
|
|
|
function QBCore.Functions.CreateUseableItem(item, cb)
|
|
if GetResourceState('qb-inventory') == 'missing' then return end
|
|
|
|
if GetResourceState('qb-inventory') ~= 'started' then
|
|
CreateThread(function()
|
|
repeat
|
|
Wait(1000)
|
|
until GetResourceState('qb-inventory') == 'started'
|
|
exports['qb-inventory']:CreateUsableItem(item, cb)
|
|
end)
|
|
else
|
|
exports['qb-inventory']:CreateUsableItem(item, cb)
|
|
end
|
|
end
|
|
|
|
function QBCore.Functions.CanUseItem(item)
|
|
if GetResourceState('qb-inventory') == 'missing' then return end
|
|
return exports['qb-inventory']:GetUsableItem(item)
|
|
end
|
|
|
|
function QBCore.Functions.UseItem(source, item)
|
|
if GetResourceState('qb-inventory') == 'missing' then return end
|
|
exports['qb-inventory']:UseItem(source, item)
|
|
end
|
|
|
|
exports('SetUseableItems', function(val)
|
|
QBCore.UseableItems = val
|
|
end)
|
|
|
|
exports('SetUseableItem', function(item, cb)
|
|
QBCore.UseableItems[item] = cb
|
|
end)
|
|
|
|
exports('GetUseableItems', function() return QBCore.UseableItems end)
|
|
|
|
-- Kick Player
|
|
|
|
function QBCore.Functions.Kick(source, reason, setKickReason, deferrals)
|
|
reason = '\n' .. reason .. '\n🔸 Check our Discord for further information: ' .. QBCore.Config.Server.Discord
|
|
if setKickReason then
|
|
setKickReason(reason)
|
|
end
|
|
CreateThread(function()
|
|
if deferrals then
|
|
deferrals.update(reason)
|
|
Wait(2500)
|
|
end
|
|
if source then
|
|
DropPlayer(source, reason)
|
|
end
|
|
for _ = 0, 4 do
|
|
while true do
|
|
if source then
|
|
if GetPlayerPing(source) >= 0 then
|
|
break
|
|
end
|
|
Wait(100)
|
|
CreateThread(function()
|
|
DropPlayer(source, reason)
|
|
end)
|
|
end
|
|
end
|
|
Wait(5000)
|
|
end
|
|
end)
|
|
end
|
|
|
|
-- Check if player is whitelisted, kept like this for backwards compatibility or future plans
|
|
|
|
function QBCore.Functions.IsWhitelisted(source)
|
|
if not QBCore.Config.Server.Whitelist then return true end
|
|
if QBCore.Functions.HasPermission(source, QBCore.Config.Server.WhitelistPermission) then return true end
|
|
return false
|
|
end
|
|
|
|
-- Setting & Removing Permissions
|
|
|
|
function QBCore.Functions.AddPermission(source, permission)
|
|
local src = source
|
|
local license = QBCore.Functions.GetIdentifier(src, 'license')
|
|
ExecuteCommand(('add_principal identifier.%s qbcore.%s'):format(license, permission))
|
|
QBCore.Commands.Refresh(src)
|
|
end
|
|
|
|
function QBCore.Functions.RemovePermission(source, permission)
|
|
local src = source
|
|
local license = QBCore.Functions.GetIdentifier(src, 'license')
|
|
if permission then
|
|
if IsPlayerAceAllowed(src, permission) then
|
|
ExecuteCommand(('remove_principal identifier.%s qbcore.%s'):format(license, permission))
|
|
QBCore.Commands.Refresh(src)
|
|
end
|
|
else
|
|
for _, v in pairs(QBCore.Config.Server.Permissions) do
|
|
if IsPlayerAceAllowed(src, v) then
|
|
ExecuteCommand(('remove_principal identifier.%s qbcore.%s'):format(license, v))
|
|
QBCore.Commands.Refresh(src)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
-- Checking for Permission Level
|
|
|
|
function QBCore.Functions.HasPermission(source, permission)
|
|
local src = source
|
|
if IsPlayerAceAllowed(src, permission) then return true end
|
|
return false
|
|
end
|
|
|
|
function QBCore.Functions.GetPermission(source)
|
|
local src = source
|
|
local perms = {}
|
|
for _, v in pairs (QBCore.Config.Server.Permissions) do
|
|
if IsPlayerAceAllowed(src, v) then
|
|
perms[v] = true
|
|
end
|
|
end
|
|
return perms
|
|
end
|
|
|
|
-- Opt in or out of admin reports
|
|
|
|
function QBCore.Functions.IsOptin(source)
|
|
local license = QBCore.Functions.GetIdentifier(source, 'license')
|
|
if not license or not QBCore.Functions.HasPermission(source, 'admin') then return false end
|
|
local Player = QBCore.Functions.GetPlayer(source)
|
|
return Player.PlayerData.optin
|
|
end
|
|
|
|
function QBCore.Functions.ToggleOptin(source)
|
|
local license = QBCore.Functions.GetIdentifier(source, 'license')
|
|
if not license or not QBCore.Functions.HasPermission(source, 'admin') then return end
|
|
local Player = QBCore.Functions.GetPlayer(source)
|
|
Player.PlayerData.optin = not Player.PlayerData.optin
|
|
Player.Functions.SetPlayerData('optin', Player.PlayerData.optin)
|
|
end
|
|
|
|
-- Check if player is banned
|
|
|
|
function QBCore.Functions.IsPlayerBanned(source)
|
|
local plicense = QBCore.Functions.GetIdentifier(source, 'license')
|
|
local result = MySQL.single.await('SELECT * FROM bans WHERE license = ?', { plicense })
|
|
if not result then return false end
|
|
if os.time() < result.expire then
|
|
local timeTable = os.date('*t', tonumber(result.expire))
|
|
return true, 'You have been banned from the server:\n' .. result.reason .. '\nYour ban expires ' .. timeTable.day .. '/' .. timeTable.month .. '/' .. timeTable.year .. ' ' .. timeTable.hour .. ':' .. timeTable.min .. '\n'
|
|
else
|
|
MySQL.query('DELETE FROM bans WHERE id = ?', { result.id })
|
|
end
|
|
return false
|
|
end
|
|
|
|
-- Check for duplicate license
|
|
|
|
function QBCore.Functions.IsLicenseInUse(license)
|
|
local players = GetPlayers()
|
|
for _, player in pairs(players) do
|
|
local identifiers = GetPlayerIdentifiers(player)
|
|
for _, id in pairs(identifiers) do
|
|
if string.find(id, 'license') then
|
|
if id == license then
|
|
return true
|
|
end
|
|
end
|
|
end
|
|
end
|
|
return false
|
|
end
|
|
|
|
-- Utility functions
|
|
|
|
function QBCore.Functions.HasItem(source, items, amount)
|
|
if GetResourceState('qb-inventory') == 'missing' then return end
|
|
return exports['qb-inventory']:HasItem(source, items, amount)
|
|
end
|
|
|
|
function QBCore.Functions.Notify(source, text, type, length)
|
|
TriggerClientEvent('QBCore:Notify', source, text, type, length)
|
|
end
|