Files
qb-core-qbcore-fivem/server/functions.lua
T
2022-08-03 20:40:34 -05:00

436 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)
QBCore.UseableItems[item] = cb
end
function QBCore.Functions.CanUseItem(item)
return QBCore.UseableItems[item]
end
function QBCore.Functions.UseItem(source, item)
QBCore.UseableItems[item.name](source, item)
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)
local Player = QBCore.Functions.GetPlayer(source)
if not Player then return false end
local isTable = type(items) == 'table'
local isArray = isTable and table.type(items) == 'array' or false
local totalItems = #items
local count = 0
local kvIndex = 2
if isTable and not isArray then
totalItems = 0
for _ in pairs(items) do totalItems += 1 end
kvIndex = 1
end
if isTable then
for k, v in pairs(items) do
local itemKV = {k, v}
local item = Player.Functions.GetItemByName(itemKV[kvIndex])
if item and ((amount and item.amount >= amount) or (not isArray and item.amount >= v) or (not amount and isArray)) then
count += 1
end
end
if count == totalItems then
return true
end
else -- Single item as string
local item = Player.Functions.GetItemByName(items)
if item and (not amount or (item and amount and item.amount >= amount)) then
return true
end
end
return false
end