744 lines
		
	
	
	
		
			26 KiB
		
	
	
	
		
			Lua
		
	
	
	
	
	
			
		
		
	
	
			744 lines
		
	
	
	
		
			26 KiB
		
	
	
	
		
			Lua
		
	
	
	
	
	
| QBCore.Functions = {}
 | |
| QBCore.Player_Buckets = {}
 | |
| QBCore.Entity_Buckets = {}
 | |
| QBCore.UsableItems = {}
 | |
| 
 | |
| -- 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)
 | |
| ---Gets the coordinates of an entity
 | |
| ---@param entity number
 | |
| ---@return vector4
 | |
| function QBCore.Functions.GetCoords(entity)
 | |
|     local coords = GetEntityCoords(entity, false)
 | |
|     local heading = GetEntityHeading(entity)
 | |
|     return vector4(coords.x, coords.y, coords.z, heading)
 | |
| end
 | |
| 
 | |
| ---Gets player identifier of the given type
 | |
| ---@param source any
 | |
| ---@param idtype string
 | |
| ---@return string?
 | |
| function QBCore.Functions.GetIdentifier(source, idtype)
 | |
|     if GetConvarInt('sv_fxdkMode', 0) == 1 then return 'license:fxdk' end
 | |
|     return GetPlayerIdentifierByType(source, idtype or 'license')
 | |
| end
 | |
| 
 | |
| ---Gets a players server id (source). Returns 0 if no player is found.
 | |
| ---@param identifier string
 | |
| ---@return number
 | |
| 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
 | |
| 
 | |
| ---Get player with given server id (source)
 | |
| ---@param source any
 | |
| ---@return table
 | |
| function QBCore.Functions.GetPlayer(source)
 | |
|     if tonumber(source) ~= nil then -- If a number is a string ("1"), this will still correctly identify the index to use.
 | |
|         return QBCore.Players[tonumber(source)]
 | |
|     else
 | |
|         return QBCore.Players[QBCore.Functions.GetSource(source)]
 | |
|     end
 | |
| end
 | |
| 
 | |
| ---Get player by citizen id
 | |
| ---@param citizenid string
 | |
| ---@return table?
 | |
| 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
 | |
| 
 | |
| ---Get offline player by citizen id
 | |
| ---@param citizenid string
 | |
| ---@return table?
 | |
| function QBCore.Functions.GetOfflinePlayerByCitizenId(citizenid)
 | |
|     return QBCore.Player.GetOfflinePlayer(citizenid)
 | |
| end
 | |
| 
 | |
| ---Get player by license
 | |
| ---@param license string
 | |
| ---@return table?
 | |
| function QBCore.Functions.GetPlayerByLicense(license)
 | |
|     return QBCore.Player.GetPlayerByLicense(license)
 | |
| end
 | |
| 
 | |
| ---Get player by phone number
 | |
| ---@param number number
 | |
| ---@return table?
 | |
| 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
 | |
| 
 | |
| ---Get player by account id
 | |
| ---@param account string
 | |
| ---@return table?
 | |
| function QBCore.Functions.GetPlayerByAccount(account)
 | |
|     for src in pairs(QBCore.Players) do
 | |
|         if QBCore.Players[src].PlayerData.charinfo.account == account then
 | |
|             return QBCore.Players[src]
 | |
|         end
 | |
|     end
 | |
|     return nil
 | |
| end
 | |
| 
 | |
| ---Get player passing property and value to check exists
 | |
| ---@param property string
 | |
| ---@param value string
 | |
| ---@return table?
 | |
| function QBCore.Functions.GetPlayerByCharInfo(property, value)
 | |
|     for src in pairs(QBCore.Players) do
 | |
|         local charinfo = QBCore.Players[src].PlayerData.charinfo
 | |
|         if charinfo[property] ~= nil and charinfo[property] == value then
 | |
|             return QBCore.Players[src]
 | |
|         end
 | |
|     end
 | |
|     return nil
 | |
| end
 | |
| 
 | |
| ---Get all players. Returns the server ids of all players.
 | |
| ---@return table
 | |
| 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
 | |
| ---@return table
 | |
| function QBCore.Functions.GetQBPlayers()
 | |
|     return QBCore.Players
 | |
| end
 | |
| 
 | |
| --- Gets a list of all online players of a specified job or job type and the number
 | |
| --- @param job string
 | |
| --- @param checkOnDuty boolean If true, only players on duty will be returned
 | |
| function QBCore.Functions.GetPlayersByJob(job, checkOnDuty)
 | |
|     local players = {}
 | |
|     local count = 0
 | |
|     for src, Player in pairs(QBCore.Players) do
 | |
|         local playerData = Player.PlayerData
 | |
|         if playerData.job.name == job or playerData.job.type == job then
 | |
|             if checkOnDuty then
 | |
|                 if playerData.job.onduty then
 | |
|                     players[#players + 1] = src
 | |
|                     count += 1
 | |
|                 end
 | |
|             else
 | |
|                 players[#players + 1] = src
 | |
|                 count += 1
 | |
|             end
 | |
|         end
 | |
|     end
 | |
|     return players, count
 | |
| end
 | |
| 
 | |
| ---Gets a list of all on duty players of a specified job and the number
 | |
| ---@param job string
 | |
| ---@return table, number
 | |
| function QBCore.Functions.GetPlayersOnDuty(job)
 | |
|     local players, count = QBCore.Functions.GetPlayersByJob(job, true)
 | |
|     return players, count
 | |
| end
 | |
| 
 | |
| ---Returns only the amount of players on duty for the specified job
 | |
| ---@param job string
 | |
| ---@return number
 | |
| function QBCore.Functions.GetDutyCount(job)
 | |
|     local _, count = QBCore.Functions.GetPlayersByJob(job, true)
 | |
|     return count
 | |
| end
 | |
| 
 | |
| --- @param source number source player's server ID.
 | |
| --- @param coords vector The coordinates to calculate the distance from. Can be a table with x, y, z fields or a vector3. If not provided, the source player's Ped's coordinates are used.
 | |
| --- @return string closestPlayer - The Player that is closest to the source player (or the provided coordinates). Returns -1 if no Players are found.
 | |
| --- @return number closestDistance - The distance to the closest Player. Returns -1 if no Players are found.
 | |
| function QBCore.Functions.GetClosestPlayer(source, coords)
 | |
|     local ped = GetPlayerPed(source)
 | |
|     local players = GetPlayers()
 | |
|     local closestDistance, closestPlayer = -1, -1
 | |
|     if coords then coords = type(coords) == 'table' and vector3(coords.x, coords.y, coords.z) or coords end
 | |
|     if not coords then coords = GetEntityCoords(ped) end
 | |
|     for i = 1, #players do
 | |
|         local playerId = players[i]
 | |
|         local playerPed = GetPlayerPed(playerId)
 | |
|         if playerPed ~= ped then
 | |
|             local playerCoords = GetEntityCoords(playerPed)
 | |
|             local distance = #(playerCoords - coords)
 | |
|             if closestDistance == -1 or distance < closestDistance then
 | |
|                 closestPlayer = playerId
 | |
|                 closestDistance = distance
 | |
|             end
 | |
|         end
 | |
|     end
 | |
|     return closestPlayer, closestDistance
 | |
| end
 | |
| 
 | |
| --- @param source number source player's server ID.
 | |
| --- @param coords vector The coordinates to calculate the distance from. Can be a table with x, y, z fields or a vector3. If not provided, the source player's Ped's coordinates are used.
 | |
| --- @return number closestObject - The Object that is closest to the source player (or the provided coordinates). Returns -1 if no Objects are found.
 | |
| --- @return number closestDistance - The distance to the closest Object. Returns -1 if no Objects are found.
 | |
| function QBCore.Functions.GetClosestObject(source, coords)
 | |
|     local ped = GetPlayerPed(source)
 | |
|     local objects = GetAllObjects()
 | |
|     local closestDistance, closestObject = -1, -1
 | |
|     if coords then coords = type(coords) == 'table' and vector3(coords.x, coords.y, coords.z) or coords end
 | |
|     if not coords then coords = GetEntityCoords(ped) end
 | |
|     for i = 1, #objects do
 | |
|         local objectCoords = GetEntityCoords(objects[i])
 | |
|         local distance = #(objectCoords - coords)
 | |
|         if closestDistance == -1 or closestDistance > distance then
 | |
|             closestObject = objects[i]
 | |
|             closestDistance = distance
 | |
|         end
 | |
|     end
 | |
|     return closestObject, closestDistance
 | |
| end
 | |
| 
 | |
| --- @param source number source player's server ID.
 | |
| --- @param coords vector The coordinates to calculate the distance from. Can be a table with x, y, z fields or a vector3. If not provided, the source player's Ped's coordinates are used.
 | |
| --- @return number closestVehicle - The Vehicle that is closest to the source player (or the provided coordinates). Returns -1 if no Vehicles are found.
 | |
| --- @return number closestDistance - The distance to the closest Vehicle. Returns -1 if no Vehicles are found.
 | |
| function QBCore.Functions.GetClosestVehicle(source, coords)
 | |
|     local ped = GetPlayerPed(source)
 | |
|     local vehicles = GetAllVehicles()
 | |
|     local closestDistance, closestVehicle = -1, -1
 | |
|     if coords then coords = type(coords) == 'table' and vector3(coords.x, coords.y, coords.z) or coords end
 | |
|     if not coords then coords = GetEntityCoords(ped) end
 | |
|     for i = 1, #vehicles do
 | |
|         local vehicleCoords = GetEntityCoords(vehicles[i])
 | |
|         local distance = #(vehicleCoords - coords)
 | |
|         if closestDistance == -1 or closestDistance > distance then
 | |
|             closestVehicle = vehicles[i]
 | |
|             closestDistance = distance
 | |
|         end
 | |
|     end
 | |
|     return closestVehicle, closestDistance
 | |
| end
 | |
| 
 | |
| --- @param source number source player's server ID.
 | |
| --- @param coords vector The coordinates to calculate the distance from. Can be a table with x, y, z fields or a vector3. If not provided, the source player's Ped's coordinates are used.
 | |
| --- @return number closestPed - The Ped that is closest to the source player (or the provided coordinates). Returns -1 if no Peds are found.
 | |
| --- @return number closestDistance - The distance to the closest Ped. Returns -1 if no Peds are found.
 | |
| function QBCore.Functions.GetClosestPed(source, coords)
 | |
|     local ped = GetPlayerPed(source)
 | |
|     local peds = GetAllPeds()
 | |
|     local closestDistance, closestPed = -1, -1
 | |
|     if coords then coords = type(coords) == 'table' and vector3(coords.x, coords.y, coords.z) or coords end
 | |
|     if not coords then coords = GetEntityCoords(ped) end
 | |
|     for i = 1, #peds do
 | |
|         if peds[i] ~= ped then
 | |
|             local pedCoords = GetEntityCoords(peds[i])
 | |
|             local distance = #(pedCoords - coords)
 | |
|             if closestDistance == -1 or closestDistance > distance then
 | |
|                 closestPed = peds[i]
 | |
|                 closestDistance = distance
 | |
|             end
 | |
|         end
 | |
|     end
 | |
|     return closestPed, closestDistance
 | |
| 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
 | |
| ---@return table, table
 | |
| function QBCore.Functions.GetBucketObjects()
 | |
|     return QBCore.Player_Buckets, QBCore.Entity_Buckets
 | |
| end
 | |
| 
 | |
| ---Will set the provided player id / source into the provided bucket id
 | |
| ---@param source any
 | |
| ---@param bucket any
 | |
| ---@return boolean
 | |
| function QBCore.Functions.SetPlayerBucket(source, bucket)
 | |
|     if source and bucket then
 | |
|         local plicense = QBCore.Functions.GetIdentifier(source, 'license')
 | |
|         Player(source).state:set('instance', bucket, true)
 | |
|         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.
 | |
| ---@param entity number
 | |
| ---@param bucket number
 | |
| ---@return boolean
 | |
| function QBCore.Functions.SetEntityBucket(entity, bucket)
 | |
|     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
 | |
| ---@param bucket number
 | |
| ---@return table|boolean
 | |
| function QBCore.Functions.GetPlayersInBucket(bucket)
 | |
|     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)
 | |
| ---@param bucket number
 | |
| ---@return table|boolean
 | |
| function QBCore.Functions.GetEntitiesInBucket(bucket)
 | |
|     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
 | |
| ---@param source any
 | |
| ---@param model any
 | |
| ---@param coords vector
 | |
| ---@param warp boolean
 | |
| ---@return number
 | |
| 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 heading = coords.w and coords.w or 0.0
 | |
|     local veh = CreateVehicle(model, coords.x, coords.y, coords.z, heading, 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!
 | |
| ---comment
 | |
| ---@param source any
 | |
| ---@param model any
 | |
| ---@param coords vector
 | |
| ---@param warp boolean
 | |
| ---@return number
 | |
| function QBCore.Functions.CreateAutomobile(source, model, coords, warp)
 | |
|     model = type(model) == 'string' and joaat(model) or model
 | |
|     if not coords then coords = GetEntityCoords(GetPlayerPed(source)) end
 | |
|     local heading = coords.w and coords.w or 0.0
 | |
|     local CreateAutomobile = `CREATE_AUTOMOBILE`
 | |
|     local veh = Citizen.InvokeNative(CreateAutomobile, model, coords, heading, true, true)
 | |
|     while not DoesEntityExist(veh) do Wait(0) end
 | |
|     if warp then TaskWarpPedIntoVehicle(GetPlayerPed(source), veh, -1) end
 | |
|     return veh
 | |
| end
 | |
| 
 | |
| --- New & more reliable server side native for creating vehicles
 | |
| ---comment
 | |
| ---@param source any
 | |
| ---@param model any
 | |
| ---@param vehtype any
 | |
| -- The appropriate vehicle type for the model info.
 | |
| -- Can be one of automobile, bike, boat, heli, plane, submarine, trailer, and (potentially), train.
 | |
| -- This should be the same type as the type field in vehicles.meta.
 | |
| ---@param coords vector
 | |
| ---@param warp boolean
 | |
| ---@return number
 | |
| function QBCore.Functions.CreateVehicle(source, model, vehtype, coords, warp)
 | |
|     model = type(model) == 'string' and joaat(model) or model
 | |
|     vehtype = type(vehtype) == 'string' and tostring(vehtype) or vehtype
 | |
|     if not coords then coords = GetEntityCoords(GetPlayerPed(source)) end
 | |
|     local heading = coords.w and coords.w or 0.0
 | |
|     local veh = CreateVehicleServerSetter(model, vehtype, coords, heading)
 | |
|     while not DoesEntityExist(veh) do Wait(0) end
 | |
|     if warp then TaskWarpPedIntoVehicle(GetPlayerPed(source), veh, -1) end
 | |
|     return veh
 | |
| end
 | |
| 
 | |
| function PaycheckInterval()
 | |
|     if not next(QBCore.Players) then
 | |
|         SetTimeout(QBCore.Config.Money.PayCheckTimeOut * (60 * 1000), PaycheckInterval) -- Prevent paychecks from stopping forever once 0 players
 | |
|         return
 | |
|     end
 | |
|     for _, Player in pairs(QBCore.Players) do
 | |
|         if not Player then return end
 | |
|         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-banking']:GetAccountBalance(Player.PlayerData.job.name)
 | |
|                 if account ~= 0 then
 | |
|                     if account < payment then
 | |
|                         TriggerClientEvent('QBCore:Notify', Player.PlayerData.source, Lang:t('error.company_too_poor'), 'error')
 | |
|                     else
 | |
|                         Player.Functions.AddMoney('bank', payment, 'paycheck')
 | |
|                         exports['qb-banking']:RemoveMoney(Player.PlayerData.job.name, payment, 'Employee Paycheck')
 | |
|                         TriggerClientEvent('QBCore:Notify', Player.PlayerData.source, Lang:t('info.received_paycheck', { value = payment }))
 | |
|                     end
 | |
|                 else
 | |
|                     Player.Functions.AddMoney('bank', payment, 'paycheck')
 | |
|                     TriggerClientEvent('QBCore:Notify', Player.PlayerData.source, Lang:t('info.received_paycheck', { value = payment }))
 | |
|                 end
 | |
|             else
 | |
|                 Player.Functions.AddMoney('bank', payment, 'paycheck')
 | |
|                 TriggerClientEvent('QBCore:Notify', Player.PlayerData.source, Lang:t('info.received_paycheck', { value = payment }))
 | |
|             end
 | |
|         end
 | |
|     end
 | |
|     SetTimeout(QBCore.Config.Money.PayCheckTimeOut * (60 * 1000), PaycheckInterval)
 | |
| end
 | |
| 
 | |
| -- Callback Functions --
 | |
| 
 | |
| ---Trigger Client Callback
 | |
| ---@param name string
 | |
| ---@param source any
 | |
| ---@param cb function
 | |
| ---@param ... any
 | |
| function QBCore.Functions.TriggerClientCallback(name, source, ...)
 | |
|     local cb = nil
 | |
|     local args = { ... }
 | |
| 
 | |
|     if QBCore.Shared.IsFunction(args[1]) then
 | |
|         cb = args[1]
 | |
|         table.remove(args, 1)
 | |
|     end
 | |
| 
 | |
|     QBCore.ClientCallbacks[name] = {
 | |
|         callback = cb,
 | |
|         promise = promise.new()
 | |
|     }
 | |
| 
 | |
|     TriggerClientEvent('QBCore:Client:TriggerClientCallback', source, name, table.unpack(args))
 | |
| 
 | |
|     if cb == nil then
 | |
|         Citizen.Await(QBCore.ClientCallbacks[name].promise)
 | |
|         return QBCore.ClientCallbacks[name].promise.value
 | |
|     end
 | |
| end
 | |
| 
 | |
| ---Create Server Callback
 | |
| ---@param name string
 | |
| ---@param cb function
 | |
| function QBCore.Functions.CreateCallback(name, cb)
 | |
|     QBCore.ServerCallbacks[name] = cb
 | |
| end
 | |
| 
 | |
| -- Items
 | |
| 
 | |
| ---Create a usable item
 | |
| ---@param item string
 | |
| ---@param data function
 | |
| function QBCore.Functions.CreateUseableItem(item, data)
 | |
|     local rawFunc = nil
 | |
| 
 | |
|     if type(data) == 'table' then
 | |
|         if rawget(data, '__cfx_functionReference') then
 | |
|             rawFunc = data
 | |
|         elseif data.cb and rawget(data.cb, '__cfx_functionReference') then
 | |
|             rawFunc = data.cb
 | |
|         elseif data.callback and rawget(data.callback, '__cfx_functionReference') then
 | |
|             rawFunc = data.callback
 | |
|         end
 | |
|     elseif type(data) == 'function' then
 | |
|         rawFunc = data
 | |
|     end
 | |
| 
 | |
|     if rawFunc then
 | |
|         QBCore.UsableItems[item] = {
 | |
|             func = rawFunc,
 | |
|             resource = GetInvokingResource()
 | |
|         }
 | |
|     end
 | |
| end
 | |
| 
 | |
| ---Checks if the given item is usable
 | |
| ---@param item string
 | |
| ---@return any
 | |
| function QBCore.Functions.CanUseItem(item)
 | |
|     return QBCore.UsableItems[item]
 | |
| end
 | |
| 
 | |
| ---Use item
 | |
| ---@param source any
 | |
| ---@param item string
 | |
| function QBCore.Functions.UseItem(source, item)
 | |
|     if GetResourceState('qb-inventory') == 'missing' then return end
 | |
|     exports['qb-inventory']:UseItem(source, item)
 | |
| end
 | |
| 
 | |
| ---Kick Player
 | |
| ---@param source any
 | |
| ---@param reason string
 | |
| ---@param setKickReason boolean
 | |
| ---@param deferrals boolean
 | |
| 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
 | |
| ---@param source any
 | |
| ---@return boolean
 | |
| 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
 | |
| 
 | |
| ---Add permission for player
 | |
| ---@param source any
 | |
| ---@param permission string
 | |
| function QBCore.Functions.AddPermission(source, permission)
 | |
|     if not IsPlayerAceAllowed(source, permission) then
 | |
|         ExecuteCommand(('add_principal player.%s qbcore.%s'):format(source, permission))
 | |
|         QBCore.Commands.Refresh(source)
 | |
|     end
 | |
| end
 | |
| 
 | |
| ---Remove permission from player
 | |
| ---@param source any
 | |
| ---@param permission string
 | |
| function QBCore.Functions.RemovePermission(source, permission)
 | |
|     if permission then
 | |
|         if IsPlayerAceAllowed(source, permission) then
 | |
|             ExecuteCommand(('remove_principal player.%s qbcore.%s'):format(source, permission))
 | |
|             QBCore.Commands.Refresh(source)
 | |
|         end
 | |
|     else
 | |
|         for _, v in pairs(QBCore.Config.Server.Permissions) do
 | |
|             if IsPlayerAceAllowed(source, v) then
 | |
|                 ExecuteCommand(('remove_principal player.%s qbcore.%s'):format(source, v))
 | |
|                 QBCore.Commands.Refresh(source)
 | |
|             end
 | |
|         end
 | |
|     end
 | |
| end
 | |
| 
 | |
| -- Checking for Permission Level
 | |
| 
 | |
| ---Check if player has permission
 | |
| ---@param source any
 | |
| ---@param permission string
 | |
| ---@return boolean
 | |
| function QBCore.Functions.HasPermission(source, permission)
 | |
|     if type(permission) == 'string' then
 | |
|         if IsPlayerAceAllowed(source, permission) then return true end
 | |
|     elseif type(permission) == 'table' then
 | |
|         for _, permLevel in pairs(permission) do
 | |
|             if IsPlayerAceAllowed(source, permLevel) then return true end
 | |
|         end
 | |
|     end
 | |
| 
 | |
|     return false
 | |
| end
 | |
| 
 | |
| ---Get the players permissions
 | |
| ---@param source any
 | |
| ---@return table
 | |
| 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
 | |
| 
 | |
| ---Get admin messages opt-in state for player
 | |
| ---@param source any
 | |
| ---@return boolean
 | |
| 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
 | |
| 
 | |
| ---Toggle opt-in to admin messages
 | |
| ---@param source any
 | |
| 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
 | |
| ---@param source any
 | |
| ---@return boolean, string?
 | |
| function QBCore.Functions.IsPlayerBanned(source)
 | |
|     local plicense = QBCore.Functions.GetIdentifier(source, 'license')
 | |
|     local result = MySQL.single.await('SELECT id, reason, expire 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
 | |
| 
 | |
| -- Retrieves information about the database connection.
 | |
| --- @return table; A table containing the database information.
 | |
| function QBCore.Functions.GetDatabaseInfo()
 | |
|     local details = {
 | |
|         exists = false,
 | |
|         database = '',
 | |
|     }
 | |
|     local connectionString = GetConvar('mysql_connection_string', '')
 | |
| 
 | |
|     if connectionString == '' then
 | |
|         return details
 | |
|     elseif connectionString:find('mysql://') then
 | |
|         connectionString = connectionString:sub(9, -1)
 | |
|         details.database = connectionString:sub(connectionString:find('/') + 1, -1):gsub('[%?]+[%w%p]*$', '')
 | |
|         details.exists = true
 | |
|         return details
 | |
|     else
 | |
|         connectionString = { string.strsplit(';', connectionString) }
 | |
| 
 | |
|         for i = 1, #connectionString do
 | |
|             local v = connectionString[i]
 | |
|             if v:match('database') then
 | |
|                 details.database = v:sub(10, #v)
 | |
|                 details.exists = true
 | |
|                 return details
 | |
|             end
 | |
|         end
 | |
|     end
 | |
| end
 | |
| 
 | |
| ---Check for duplicate license
 | |
| ---@param license any
 | |
| ---@return boolean
 | |
| function QBCore.Functions.IsLicenseInUse(license)
 | |
|     local players = GetPlayers()
 | |
|     for _, player in pairs(players) do
 | |
|         local playerLicense = QBCore.Functions.GetIdentifier(player, 'license')
 | |
|         if playerLicense == license then return true end
 | |
|     end
 | |
|     return false
 | |
| end
 | |
| 
 | |
| -- Utility functions
 | |
| 
 | |
| ---Check if a player has an item [deprecated]
 | |
| ---@param source any
 | |
| ---@param items table|string
 | |
| ---@param amount number
 | |
| ---@return boolean
 | |
| function QBCore.Functions.HasItem(source, items, amount)
 | |
|     if GetResourceState('qb-inventory') == 'missing' then return end
 | |
|     return exports['qb-inventory']:HasItem(source, items, amount)
 | |
| end
 | |
| 
 | |
| ---Notify
 | |
| ---@param source any
 | |
| ---@param text string
 | |
| ---@param type string
 | |
| ---@param length number
 | |
| function QBCore.Functions.Notify(source, text, type, length)
 | |
|     TriggerClientEvent('QBCore:Notify', source, text, type, length)
 | |
| end
 | |
| 
 | |
| ---???? ... ok
 | |
| ---@param source any
 | |
| ---@param data any
 | |
| ---@param pattern any
 | |
| ---@return boolean
 | |
| function QBCore.Functions.PrepForSQL(source, data, pattern)
 | |
|     data = tostring(data)
 | |
|     local src = source
 | |
|     local player = QBCore.Functions.GetPlayer(src)
 | |
|     local result = string.match(data, pattern)
 | |
|     if not result or string.len(result) ~= string.len(data) then
 | |
|         TriggerEvent('qb-log:server:CreateLog', 'anticheat', 'SQL Exploit Attempted', 'red', string.format('%s attempted to exploit SQL!', player.PlayerData.license))
 | |
|         return false
 | |
|     end
 | |
|     return true
 | |
| end
 | |
| 
 | |
| for functionName, func in pairs(QBCore.Functions) do
 | |
|     if type(func) == 'function' then
 | |
|         exports(functionName, func)
 | |
|     end
 | |
| end
 | |
| -- Access a specific function directly:
 | |
| -- exports['qb-core']:Notify(source, 'Hello Player!')
 | 
