mirror of
https://github.com/qbcore-fivem/qb-core.git
synced 2026-08-28 23:01:29 +00:00
Remove old server files
This commit is contained in:
@@ -1,323 +0,0 @@
|
||||
QBCore.Commands = {}
|
||||
QBCore.Commands.List = {}
|
||||
QBCore.Commands.IgnoreList = { -- Ignore old perm levels while keeping backwards compatibility
|
||||
['god'] = true, -- We don't need to create an ace because god is allowed all commands
|
||||
['user'] = true -- We don't need to create an ace because builtin.everyone
|
||||
}
|
||||
|
||||
CreateThread(function() -- Add ace to node for perm checking
|
||||
local permissions = QBCore.Config.Server.Permissions
|
||||
for i = 1, #permissions do
|
||||
local permission = permissions[i]
|
||||
ExecuteCommand(('add_ace qbcore.%s %s allow'):format(permission, permission))
|
||||
end
|
||||
end)
|
||||
|
||||
-- Register & Refresh Commands
|
||||
|
||||
function QBCore.Commands.Add(name, help, arguments, argsrequired, callback, permission, ...)
|
||||
local restricted = true -- Default to restricted for all commands
|
||||
if not permission then permission = 'user' end -- some commands don't pass permission level
|
||||
if permission == 'user' then restricted = false end -- allow all users to use command
|
||||
|
||||
RegisterCommand(name, function(source, args, rawCommand) -- Register command within fivem
|
||||
if argsrequired and #args < #arguments then
|
||||
return TriggerClientEvent('chat:addMessage', source, {
|
||||
color = { 255, 0, 0 },
|
||||
multiline = true,
|
||||
args = { 'System', Lang:t('error.missing_args2') }
|
||||
})
|
||||
end
|
||||
callback(source, args, rawCommand)
|
||||
end, restricted)
|
||||
|
||||
local extraPerms = ... and table.pack(...) or nil
|
||||
if extraPerms then
|
||||
extraPerms[extraPerms.n + 1] = permission -- The `n` field is the number of arguments in the packed table
|
||||
extraPerms.n += 1
|
||||
permission = extraPerms
|
||||
for i = 1, permission.n do
|
||||
if not QBCore.Commands.IgnoreList[permission[i]] then -- only create aces for extra perm levels
|
||||
ExecuteCommand(('add_ace qbcore.%s command.%s allow'):format(permission[i], name))
|
||||
end
|
||||
end
|
||||
permission.n = nil
|
||||
else
|
||||
permission = tostring(permission:lower())
|
||||
if not QBCore.Commands.IgnoreList[permission] then -- only create aces for extra perm levels
|
||||
ExecuteCommand(('add_ace qbcore.%s command.%s allow'):format(permission, name))
|
||||
end
|
||||
end
|
||||
|
||||
QBCore.Commands.List[name:lower()] = {
|
||||
name = name:lower(),
|
||||
permission = permission,
|
||||
help = help,
|
||||
arguments = arguments,
|
||||
argsrequired = argsrequired,
|
||||
callback = callback
|
||||
}
|
||||
end
|
||||
|
||||
function QBCore.Commands.Refresh(source)
|
||||
local src = source
|
||||
local Player = QBCore.Functions.GetPlayer(src)
|
||||
local suggestions = {}
|
||||
if Player then
|
||||
for command, info in pairs(QBCore.Commands.List) do
|
||||
local hasPerm = IsPlayerAceAllowed(tostring(src), 'command.' .. command)
|
||||
if hasPerm then
|
||||
suggestions[#suggestions + 1] = {
|
||||
name = '/' .. command,
|
||||
help = info.help,
|
||||
params = info.arguments
|
||||
}
|
||||
else
|
||||
TriggerClientEvent('chat:removeSuggestion', src, '/' .. command)
|
||||
end
|
||||
end
|
||||
TriggerClientEvent('chat:addSuggestions', src, suggestions)
|
||||
end
|
||||
end
|
||||
|
||||
-- Teleport
|
||||
QBCore.Commands.Add('tp', Lang:t('command.tp.help'), { { name = Lang:t('command.tp.params.x.name'), help = Lang:t('command.tp.params.x.help') }, { name = Lang:t('command.tp.params.y.name'), help = Lang:t('command.tp.params.y.help') }, { name = Lang:t('command.tp.params.z.name'), help = Lang:t('command.tp.params.z.help') } }, false, function(source, args)
|
||||
if args[1] and not args[2] and not args[3] then
|
||||
if tonumber(args[1]) then
|
||||
local target = GetPlayerPed(tonumber(args[1]))
|
||||
if target ~= 0 then
|
||||
local coords = GetEntityCoords(target)
|
||||
TriggerClientEvent('QBCore:Command:TeleportToPlayer', source, coords)
|
||||
else
|
||||
TriggerClientEvent('QBCore:Notify', source, Lang:t('error.not_online'), 'error')
|
||||
end
|
||||
else
|
||||
local location = QBShared.Locations[args[1]]
|
||||
if location then
|
||||
TriggerClientEvent('QBCore:Command:TeleportToCoords', source, location.x, location.y, location.z, location.w)
|
||||
else
|
||||
TriggerClientEvent('QBCore:Notify', source, Lang:t('error.location_not_exist'), 'error')
|
||||
end
|
||||
end
|
||||
else
|
||||
if args[1] and args[2] and args[3] then
|
||||
local x = tonumber((args[1]:gsub(',', ''))) + .0
|
||||
local y = tonumber((args[2]:gsub(',', ''))) + .0
|
||||
local z = tonumber((args[3]:gsub(',', ''))) + .0
|
||||
local heading = args[4] and tonumber((args[4]:gsub(',', ''))) + .0 or false
|
||||
if x ~= 0 and y ~= 0 and z ~= 0 then
|
||||
TriggerClientEvent('QBCore:Command:TeleportToCoords', source, x, y, z, heading)
|
||||
else
|
||||
TriggerClientEvent('QBCore:Notify', source, Lang:t('error.wrong_format'), 'error')
|
||||
end
|
||||
else
|
||||
TriggerClientEvent('QBCore:Notify', source, Lang:t('error.missing_args'), 'error')
|
||||
end
|
||||
end
|
||||
end, 'admin')
|
||||
|
||||
QBCore.Commands.Add('tpm', Lang:t('command.tpm.help'), {}, false, function(source)
|
||||
TriggerClientEvent('QBCore:Command:GoToMarker', source)
|
||||
end, 'admin')
|
||||
|
||||
QBCore.Commands.Add('togglepvp', Lang:t('command.togglepvp.help'), {}, false, function()
|
||||
QBCore.Config.Server.PVP = not QBCore.Config.Server.PVP
|
||||
TriggerClientEvent('QBCore:Client:PvpHasToggled', -1, QBCore.Config.Server.PVP)
|
||||
end, 'admin')
|
||||
|
||||
-- Permissions
|
||||
|
||||
QBCore.Commands.Add('addpermission', Lang:t('command.addpermission.help'), { { name = Lang:t('command.addpermission.params.id.name'), help = Lang:t('command.addpermission.params.id.help') }, { name = Lang:t('command.addpermission.params.permission.name'), help = Lang:t('command.addpermission.params.permission.help') } }, true, function(source, args)
|
||||
local Player = QBCore.Functions.GetPlayer(tonumber(args[1]))
|
||||
local permission = tostring(args[2]):lower()
|
||||
if Player then
|
||||
QBCore.Functions.AddPermission(Player.PlayerData.source, permission)
|
||||
else
|
||||
TriggerClientEvent('QBCore:Notify', source, Lang:t('error.not_online'), 'error')
|
||||
end
|
||||
end, 'god')
|
||||
|
||||
QBCore.Commands.Add('removepermission', Lang:t('command.removepermission.help'), { { name = Lang:t('command.removepermission.params.id.name'), help = Lang:t('command.removepermission.params.id.help') }, { name = Lang:t('command.removepermission.params.permission.name'), help = Lang:t('command.removepermission.params.permission.help') } }, true, function(source, args)
|
||||
local Player = QBCore.Functions.GetPlayer(tonumber(args[1]))
|
||||
local permission = tostring(args[2]):lower()
|
||||
if Player then
|
||||
QBCore.Functions.RemovePermission(Player.PlayerData.source, permission)
|
||||
else
|
||||
TriggerClientEvent('QBCore:Notify', source, Lang:t('error.not_online'), 'error')
|
||||
end
|
||||
end, 'god')
|
||||
|
||||
-- Open & Close Server
|
||||
|
||||
QBCore.Commands.Add('openserver', Lang:t('command.openserver.help'), {}, false, function(source)
|
||||
if not QBCore.Config.Server.Closed then
|
||||
TriggerClientEvent('QBCore:Notify', source, Lang:t('error.server_already_open'), 'error')
|
||||
return
|
||||
end
|
||||
if QBCore.Functions.HasPermission(source, 'admin') then
|
||||
QBCore.Config.Server.Closed = false
|
||||
TriggerClientEvent('QBCore:Notify', source, Lang:t('success.server_opened'), 'success')
|
||||
else
|
||||
QBCore.Functions.Kick(source, Lang:t('error.no_permission'), nil, nil)
|
||||
end
|
||||
end, 'admin')
|
||||
|
||||
QBCore.Commands.Add('closeserver', Lang:t('command.closeserver.help'), { { name = Lang:t('command.closeserver.params.reason.name'), help = Lang:t('command.closeserver.params.reason.help') } }, false, function(source, args)
|
||||
if QBCore.Config.Server.Closed then
|
||||
TriggerClientEvent('QBCore:Notify', source, Lang:t('error.server_already_closed'), 'error')
|
||||
return
|
||||
end
|
||||
if QBCore.Functions.HasPermission(source, 'admin') then
|
||||
local reason = args[1] or 'No reason specified'
|
||||
QBCore.Config.Server.Closed = true
|
||||
QBCore.Config.Server.ClosedReason = reason
|
||||
for k in pairs(QBCore.Players) do
|
||||
if not QBCore.Functions.HasPermission(k, QBCore.Config.Server.WhitelistPermission) then
|
||||
QBCore.Functions.Kick(k, reason, nil, nil)
|
||||
end
|
||||
end
|
||||
TriggerClientEvent('QBCore:Notify', source, Lang:t('success.server_closed'), 'success')
|
||||
else
|
||||
QBCore.Functions.Kick(source, Lang:t('error.no_permission'), nil, nil)
|
||||
end
|
||||
end, 'admin')
|
||||
|
||||
-- Vehicle
|
||||
|
||||
QBCore.Commands.Add('car', Lang:t('command.car.help'), { { name = Lang:t('command.car.params.model.name'), help = Lang:t('command.car.params.model.help') } }, true, function(source, args)
|
||||
TriggerClientEvent('QBCore:Command:SpawnVehicle', source, args[1])
|
||||
end, 'admin')
|
||||
|
||||
QBCore.Commands.Add('dv', Lang:t('command.dv.help'), {}, false, function(source)
|
||||
TriggerClientEvent('QBCore:Command:DeleteVehicle', source)
|
||||
end, 'admin')
|
||||
|
||||
QBCore.Commands.Add('dvall', Lang:t('command.dvall.help'), {}, false, function()
|
||||
local vehicles = GetAllVehicles()
|
||||
for _, vehicle in ipairs(vehicles) do
|
||||
DeleteEntity(vehicle)
|
||||
end
|
||||
end, 'admin')
|
||||
|
||||
-- Peds
|
||||
|
||||
QBCore.Commands.Add('dvp', Lang:t('command.dvp.help'), {}, false, function()
|
||||
local peds = GetAllPeds()
|
||||
for _, ped in ipairs(peds) do
|
||||
DeleteEntity(ped)
|
||||
end
|
||||
end, 'admin')
|
||||
|
||||
-- Objects
|
||||
|
||||
QBCore.Commands.Add('dvo', Lang:t('command.dvo.help'), {}, false, function()
|
||||
local objects = GetAllObjects()
|
||||
for _, object in ipairs(objects) do
|
||||
DeleteEntity(object)
|
||||
end
|
||||
end, 'admin')
|
||||
|
||||
-- Money
|
||||
|
||||
QBCore.Commands.Add('givemoney', Lang:t('command.givemoney.help'), { { name = Lang:t('command.givemoney.params.id.name'), help = Lang:t('command.givemoney.params.id.help') }, { name = Lang:t('command.givemoney.params.moneytype.name'), help = Lang:t('command.givemoney.params.moneytype.help') }, { name = Lang:t('command.givemoney.params.amount.name'), help = Lang:t('command.givemoney.params.amount.help') } }, true, function(source, args)
|
||||
local Player = QBCore.Functions.GetPlayer(tonumber(args[1]))
|
||||
if Player then
|
||||
Player.Functions.AddMoney(tostring(args[2]), tonumber(args[3]), 'Admin give money')
|
||||
else
|
||||
TriggerClientEvent('QBCore:Notify', source, Lang:t('error.not_online'), 'error')
|
||||
end
|
||||
end, 'admin')
|
||||
|
||||
QBCore.Commands.Add('setmoney', Lang:t('command.setmoney.help'), { { name = Lang:t('command.setmoney.params.id.name'), help = Lang:t('command.setmoney.params.id.help') }, { name = Lang:t('command.setmoney.params.moneytype.name'), help = Lang:t('command.setmoney.params.moneytype.help') }, { name = Lang:t('command.setmoney.params.amount.name'), help = Lang:t('command.setmoney.params.amount.help') } }, true, function(source, args)
|
||||
local Player = QBCore.Functions.GetPlayer(tonumber(args[1]))
|
||||
if Player then
|
||||
Player.Functions.SetMoney(tostring(args[2]), tonumber(args[3]))
|
||||
else
|
||||
TriggerClientEvent('QBCore:Notify', source, Lang:t('error.not_online'), 'error')
|
||||
end
|
||||
end, 'admin')
|
||||
|
||||
-- Job
|
||||
|
||||
QBCore.Commands.Add('job', Lang:t('command.job.help'), {}, false, function(source)
|
||||
local PlayerJob = QBCore.Functions.GetPlayer(source).PlayerData.job
|
||||
TriggerClientEvent('QBCore:Notify', source, Lang:t('info.job_info', { value = PlayerJob.label, value2 = PlayerJob.grade.name, value3 = PlayerJob.onduty }))
|
||||
end, 'user')
|
||||
|
||||
QBCore.Commands.Add('setjob', Lang:t('command.setjob.help'), { { name = Lang:t('command.setjob.params.id.name'), help = Lang:t('command.setjob.params.id.help') }, { name = Lang:t('command.setjob.params.job.name'), help = Lang:t('command.setjob.params.job.help') }, { name = Lang:t('command.setjob.params.grade.name'), help = Lang:t('command.setjob.params.grade.help') } }, true, function(source, args)
|
||||
local Player = QBCore.Functions.GetPlayer(tonumber(args[1]))
|
||||
if Player then
|
||||
Player.Functions.SetJob(tostring(args[2]), tonumber(args[3]))
|
||||
else
|
||||
TriggerClientEvent('QBCore:Notify', source, Lang:t('error.not_online'), 'error')
|
||||
end
|
||||
end, 'admin')
|
||||
|
||||
-- Gang
|
||||
|
||||
QBCore.Commands.Add('gang', Lang:t('command.gang.help'), {}, false, function(source)
|
||||
local PlayerGang = QBCore.Functions.GetPlayer(source).PlayerData.gang
|
||||
TriggerClientEvent('QBCore:Notify', source, Lang:t('info.gang_info', { value = PlayerGang.label, value2 = PlayerGang.grade.name }))
|
||||
end, 'user')
|
||||
|
||||
QBCore.Commands.Add('setgang', Lang:t('command.setgang.help'), { { name = Lang:t('command.setgang.params.id.name'), help = Lang:t('command.setgang.params.id.help') }, { name = Lang:t('command.setgang.params.gang.name'), help = Lang:t('command.setgang.params.gang.help') }, { name = Lang:t('command.setgang.params.grade.name'), help = Lang:t('command.setgang.params.grade.help') } }, true, function(source, args)
|
||||
local Player = QBCore.Functions.GetPlayer(tonumber(args[1]))
|
||||
if Player then
|
||||
Player.Functions.SetGang(tostring(args[2]), tonumber(args[3]))
|
||||
else
|
||||
TriggerClientEvent('QBCore:Notify', source, Lang:t('error.not_online'), 'error')
|
||||
end
|
||||
end, 'admin')
|
||||
|
||||
-- Out of Character Chat
|
||||
QBCore.Commands.Add('ooc', Lang:t('command.ooc.help'), {}, false, function(source, args)
|
||||
local message = table.concat(args, ' ')
|
||||
local Players = QBCore.Functions.GetPlayers()
|
||||
local Player = QBCore.Functions.GetPlayer(source)
|
||||
local playerCoords = GetEntityCoords(GetPlayerPed(source))
|
||||
for _, v in pairs(Players) do
|
||||
if v == source then
|
||||
TriggerClientEvent('chat:addMessage', v, {
|
||||
color = QBCore.Config.Commands.OOCColor,
|
||||
multiline = true,
|
||||
args = { 'OOC | ' .. GetPlayerName(source), message }
|
||||
})
|
||||
elseif #(playerCoords - GetEntityCoords(GetPlayerPed(v))) < 20.0 then
|
||||
TriggerClientEvent('chat:addMessage', v, {
|
||||
color = QBCore.Config.Commands.OOCColor,
|
||||
multiline = true,
|
||||
args = { 'OOC | ' .. GetPlayerName(source), message }
|
||||
})
|
||||
elseif QBCore.Functions.HasPermission(v, 'admin') then
|
||||
if QBCore.Functions.IsOptin(v) then
|
||||
TriggerClientEvent('chat:addMessage', v, {
|
||||
color = QBCore.Config.Commands.OOCColor,
|
||||
multiline = true,
|
||||
args = { 'Proximity OOC | ' .. GetPlayerName(source), message }
|
||||
})
|
||||
TriggerEvent('qb-log:server:CreateLog', 'ooc', 'OOC', 'white', '**' .. GetPlayerName(source) .. '** (CitizenID: ' .. Player.PlayerData.citizenid .. ' | ID: ' .. source .. ') **Message:** ' .. message, false)
|
||||
end
|
||||
end
|
||||
end
|
||||
end, 'user')
|
||||
|
||||
-- Me command
|
||||
|
||||
QBCore.Commands.Add('me', Lang:t('command.me.help'), { { name = Lang:t('command.me.params.message.name'), help = Lang:t('command.me.params.message.help') } }, false, function(source, args)
|
||||
if #args < 1 then
|
||||
TriggerClientEvent('QBCore:Notify', source, Lang:t('error.missing_args2'), 'error')
|
||||
return
|
||||
end
|
||||
local ped = GetPlayerPed(source)
|
||||
local pCoords = GetEntityCoords(ped)
|
||||
local msg = table.concat(args, ' '):gsub('[~<].-[>~]', '')
|
||||
local Players = QBCore.Functions.GetPlayers()
|
||||
for i = 1, #Players do
|
||||
local Player = Players[i]
|
||||
local target = GetPlayerPed(Player)
|
||||
local tCoords = GetEntityCoords(target)
|
||||
if target == ped or #(pCoords - tCoords) < 20 then
|
||||
TriggerClientEvent('QBCore:Command:ShowMe3D', Player, source, msg)
|
||||
end
|
||||
end
|
||||
end, 'user')
|
||||
@@ -1,44 +0,0 @@
|
||||
local function tPrint(tbl, indent)
|
||||
indent = indent or 0
|
||||
if type(tbl) == 'table' then
|
||||
for k, v in pairs(tbl) do
|
||||
local tblType = type(v)
|
||||
local formatting = ('%s ^3%s:^0'):format(string.rep(' ', indent), k)
|
||||
|
||||
if tblType == 'table' then
|
||||
print(formatting)
|
||||
tPrint(v, indent + 1)
|
||||
elseif tblType == 'boolean' then
|
||||
print(('%s^1 %s ^0'):format(formatting, v))
|
||||
elseif tblType == 'function' then
|
||||
print(('%s^9 %s ^0'):format(formatting, v))
|
||||
elseif tblType == 'number' then
|
||||
print(('%s^5 %s ^0'):format(formatting, v))
|
||||
elseif tblType == 'string' then
|
||||
print(("%s ^2'%s' ^0"):format(formatting, v))
|
||||
else
|
||||
print(('%s^2 %s ^0'):format(formatting, v))
|
||||
end
|
||||
end
|
||||
else
|
||||
print(('%s ^0%s'):format(string.rep(' ', indent), tbl))
|
||||
end
|
||||
end
|
||||
|
||||
RegisterServerEvent('QBCore:DebugSomething', function(tbl, indent, resource)
|
||||
print(('\x1b[4m\x1b[36m[ %s : DEBUG]\x1b[0m'):format(resource))
|
||||
tPrint(tbl, indent)
|
||||
print('\x1b[4m\x1b[36m[ END DEBUG ]\x1b[0m')
|
||||
end)
|
||||
|
||||
function QBCore.Debug(tbl, indent)
|
||||
TriggerEvent('QBCore:DebugSomething', tbl, indent, GetInvokingResource() or 'qb-core')
|
||||
end
|
||||
|
||||
function QBCore.ShowError(resource, msg)
|
||||
print('\x1b[31m[' .. resource .. ':ERROR]\x1b[0m ' .. msg)
|
||||
end
|
||||
|
||||
function QBCore.ShowSuccess(resource, msg)
|
||||
print('\x1b[32m[' .. resource .. ':LOG]\x1b[0m ' .. msg)
|
||||
end
|
||||
@@ -1,285 +0,0 @@
|
||||
-- Event Handler
|
||||
|
||||
AddEventHandler('chatMessage', function(_, _, message)
|
||||
if string.sub(message, 1, 1) == '/' then
|
||||
CancelEvent()
|
||||
return
|
||||
end
|
||||
end)
|
||||
|
||||
AddEventHandler('playerDropped', function(reason)
|
||||
local src = source
|
||||
if not QBCore.Players[src] then return end
|
||||
local Player = QBCore.Players[src]
|
||||
TriggerEvent('qb-log:server:CreateLog', 'joinleave', 'Dropped', 'red', '**' .. GetPlayerName(src) .. '** (' .. Player.PlayerData.license .. ') left..' .. '\n **Reason:** ' .. reason)
|
||||
TriggerEvent('QBCore:Server:PlayerDropped', Player)
|
||||
Player.Functions.Save()
|
||||
QBCore.Player_Buckets[Player.PlayerData.license] = nil
|
||||
QBCore.Players[src] = nil
|
||||
end)
|
||||
|
||||
AddEventHandler("onResourceStop", function(resName)
|
||||
for i,v in pairs(QBCore.UsableItems) do
|
||||
if v.resource == resName then
|
||||
QBCore.UsableItems[i] = nil
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
-- Player Connecting
|
||||
local readyFunction = MySQL.ready
|
||||
local databaseConnected, bansTableExists = readyFunction == nil, readyFunction == nil
|
||||
if readyFunction ~= nil then
|
||||
MySQL.ready(function()
|
||||
databaseConnected = true
|
||||
|
||||
local DatabaseInfo = QBCore.Functions.GetDatabaseInfo()
|
||||
if not DatabaseInfo or not DatabaseInfo.exists then return end
|
||||
|
||||
local result = MySQL.query.await('SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = ? AND TABLE_NAME = "bans";', {DatabaseInfo.database})
|
||||
if result and result[1] then
|
||||
bansTableExists = true
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
local function onPlayerConnecting(name, _, deferrals)
|
||||
local src = source
|
||||
deferrals.defer()
|
||||
|
||||
if QBCore.Config.Server.Closed and not IsPlayerAceAllowed(src, 'qbadmin.join') then
|
||||
return deferrals.done(QBCore.Config.Server.ClosedReason)
|
||||
end
|
||||
|
||||
if not databaseConnected then
|
||||
return deferrals.done(Lang:t('error.connecting_database_error'))
|
||||
end
|
||||
|
||||
if QBCore.Config.Server.Whitelist then
|
||||
Wait(0)
|
||||
deferrals.update(string.format(Lang:t('info.checking_whitelisted'), name))
|
||||
if not QBCore.Functions.IsWhitelisted(src) then
|
||||
return deferrals.done(Lang:t('error.not_whitelisted'))
|
||||
end
|
||||
end
|
||||
|
||||
Wait(0)
|
||||
deferrals.update(string.format('Hello %s. Your license is being checked', name))
|
||||
local license = QBCore.Functions.GetIdentifier(src, 'license')
|
||||
|
||||
if not license then
|
||||
return deferrals.done(Lang:t('error.no_valid_license'))
|
||||
elseif QBCore.Config.Server.CheckDuplicateLicense and QBCore.Functions.IsLicenseInUse(license) then
|
||||
return deferrals.done(Lang:t('error.duplicate_license'))
|
||||
end
|
||||
|
||||
Wait(0)
|
||||
deferrals.update(string.format(Lang:t('info.checking_ban'), name))
|
||||
|
||||
if not bansTableExists then
|
||||
return deferrals.done(Lang:t('error.ban_table_not_found'))
|
||||
end
|
||||
|
||||
local success, isBanned, reason = pcall(QBCore.Functions.IsPlayerBanned, src)
|
||||
if not success then return deferrals.done(Lang:t('error.connecting_database_error')) end
|
||||
if isBanned then return deferrals.done(reason) end
|
||||
|
||||
Wait(0)
|
||||
deferrals.update(string.format(Lang:t('info.join_server'), name))
|
||||
deferrals.done()
|
||||
|
||||
TriggerClientEvent('QBCore:Client:SharedUpdate', src, QBCore.Shared)
|
||||
end
|
||||
|
||||
AddEventHandler('playerConnecting', onPlayerConnecting)
|
||||
|
||||
-- Open & Close Server (prevents players from joining)
|
||||
|
||||
RegisterNetEvent('QBCore:Server:CloseServer', function(reason)
|
||||
local src = source
|
||||
if QBCore.Functions.HasPermission(src, 'admin') then
|
||||
reason = reason or 'No reason specified'
|
||||
QBCore.Config.Server.Closed = true
|
||||
QBCore.Config.Server.ClosedReason = reason
|
||||
for k in pairs(QBCore.Players) do
|
||||
if not QBCore.Functions.HasPermission(k, QBCore.Config.Server.WhitelistPermission) then
|
||||
QBCore.Functions.Kick(k, reason, nil, nil)
|
||||
end
|
||||
end
|
||||
else
|
||||
QBCore.Functions.Kick(src, Lang:t('error.no_permission'), nil, nil)
|
||||
end
|
||||
end)
|
||||
|
||||
RegisterNetEvent('QBCore:Server:OpenServer', function()
|
||||
local src = source
|
||||
if QBCore.Functions.HasPermission(src, 'admin') then
|
||||
QBCore.Config.Server.Closed = false
|
||||
else
|
||||
QBCore.Functions.Kick(src, Lang:t('error.no_permission'), nil, nil)
|
||||
end
|
||||
end)
|
||||
|
||||
-- Callback Events --
|
||||
|
||||
-- Client Callback
|
||||
RegisterNetEvent('QBCore:Server:TriggerClientCallback', function(name, ...)
|
||||
if QBCore.ClientCallbacks[name] then
|
||||
QBCore.ClientCallbacks[name].promise:resolve(...)
|
||||
|
||||
if QBCore.ClientCallbacks[name].callback then
|
||||
QBCore.ClientCallbacks[name].callback(...)
|
||||
end
|
||||
|
||||
QBCore.ClientCallbacks[name] = nil
|
||||
end
|
||||
end)
|
||||
|
||||
-- Server Callback
|
||||
RegisterNetEvent('QBCore:Server:TriggerCallback', function(name, ...)
|
||||
if not QBCore.ServerCallbacks[name] then return end
|
||||
|
||||
local src = source
|
||||
|
||||
QBCore.ServerCallbacks[name](src, function(...)
|
||||
TriggerClientEvent('QBCore:Client:TriggerCallback', src, name, ...)
|
||||
end, ...)
|
||||
end)
|
||||
|
||||
-- Player
|
||||
|
||||
RegisterNetEvent('QBCore:UpdatePlayer', function()
|
||||
local src = source
|
||||
local Player = QBCore.Functions.GetPlayer(src)
|
||||
if not Player then return end
|
||||
local newHunger = Player.PlayerData.metadata['hunger'] - QBCore.Config.Player.HungerRate
|
||||
local newThirst = Player.PlayerData.metadata['thirst'] - QBCore.Config.Player.ThirstRate
|
||||
if newHunger <= 0 then
|
||||
newHunger = 0
|
||||
end
|
||||
if newThirst <= 0 then
|
||||
newThirst = 0
|
||||
end
|
||||
Player.Functions.SetMetaData('thirst', newThirst)
|
||||
Player.Functions.SetMetaData('hunger', newHunger)
|
||||
TriggerClientEvent('hud:client:UpdateNeeds', src, newHunger, newThirst)
|
||||
Player.Functions.Save()
|
||||
end)
|
||||
|
||||
RegisterNetEvent('QBCore:ToggleDuty', function()
|
||||
local src = source
|
||||
local Player = QBCore.Functions.GetPlayer(src)
|
||||
if not Player then return end
|
||||
if Player.PlayerData.job.onduty then
|
||||
Player.Functions.SetJobDuty(false)
|
||||
TriggerClientEvent('QBCore:Notify', src, Lang:t('info.off_duty'))
|
||||
else
|
||||
Player.Functions.SetJobDuty(true)
|
||||
TriggerClientEvent('QBCore:Notify', src, Lang:t('info.on_duty'))
|
||||
end
|
||||
|
||||
TriggerEvent('QBCore:Server:SetDuty', src, Player.PlayerData.job.onduty)
|
||||
TriggerClientEvent('QBCore:Client:SetDuty', src, Player.PlayerData.job.onduty)
|
||||
end)
|
||||
|
||||
-- BaseEvents
|
||||
|
||||
-- Vehicles
|
||||
RegisterServerEvent('baseevents:enteringVehicle', function(veh, seat, modelName)
|
||||
local src = source
|
||||
local data = {
|
||||
vehicle = veh,
|
||||
seat = seat,
|
||||
name = modelName,
|
||||
event = 'Entering'
|
||||
}
|
||||
TriggerClientEvent('QBCore:Client:VehicleInfo', src, data)
|
||||
end)
|
||||
|
||||
RegisterServerEvent('baseevents:enteredVehicle', function(veh, seat, modelName)
|
||||
local src = source
|
||||
local data = {
|
||||
vehicle = veh,
|
||||
seat = seat,
|
||||
name = modelName,
|
||||
event = 'Entered'
|
||||
}
|
||||
TriggerClientEvent('QBCore:Client:VehicleInfo', src, data)
|
||||
end)
|
||||
|
||||
RegisterServerEvent('baseevents:enteringAborted', function()
|
||||
local src = source
|
||||
TriggerClientEvent('QBCore:Client:AbortVehicleEntering', src)
|
||||
end)
|
||||
|
||||
RegisterServerEvent('baseevents:leftVehicle', function(veh, seat, modelName)
|
||||
local src = source
|
||||
local data = {
|
||||
vehicle = veh,
|
||||
seat = seat,
|
||||
name = modelName,
|
||||
event = 'Left'
|
||||
}
|
||||
TriggerClientEvent('QBCore:Client:VehicleInfo', src, data)
|
||||
end)
|
||||
|
||||
-- Items
|
||||
|
||||
-- This event is exploitable and should not be used. It has been deprecated, and will be removed soon.
|
||||
RegisterNetEvent('QBCore:Server:UseItem', function(item)
|
||||
print(string.format('%s triggered QBCore:Server:UseItem by ID %s with the following data. This event is deprecated due to exploitation, and will be removed soon. Check qb-inventory for the right use on this event.', GetInvokingResource(), source))
|
||||
QBCore.Debug(item)
|
||||
end)
|
||||
|
||||
-- This event is exploitable and should not be used. It has been deprecated, and will be removed soon. function(itemName, amount, slot)
|
||||
RegisterNetEvent('QBCore:Server:RemoveItem', function(itemName, amount)
|
||||
local src = source
|
||||
print(string.format('%s triggered QBCore:Server:RemoveItem by ID %s for %s %s. This event is deprecated due to exploitation, and will be removed soon. Adjust your events accordingly to do this server side with player functions.', GetInvokingResource(), src, amount, itemName))
|
||||
end)
|
||||
|
||||
-- This event is exploitable and should not be used. It has been deprecated, and will be removed soon. function(itemName, amount, slot, info)
|
||||
RegisterNetEvent('QBCore:Server:AddItem', function(itemName, amount)
|
||||
local src = source
|
||||
print(string.format('%s triggered QBCore:Server:AddItem by ID %s for %s %s. This event is deprecated due to exploitation, and will be removed soon. Adjust your events accordingly to do this server side with player functions.', GetInvokingResource(), src, amount, itemName))
|
||||
end)
|
||||
|
||||
-- Non-Chat Command Calling (ex: qb-adminmenu)
|
||||
|
||||
RegisterNetEvent('QBCore:CallCommand', function(command, args)
|
||||
local src = source
|
||||
if not QBCore.Commands.List[command] then return end
|
||||
local Player = QBCore.Functions.GetPlayer(src)
|
||||
if not Player then return end
|
||||
local hasPerm = QBCore.Functions.HasPermission(src, 'command.' .. QBCore.Commands.List[command].name)
|
||||
if hasPerm then
|
||||
if QBCore.Commands.List[command].argsrequired and #QBCore.Commands.List[command].arguments ~= 0 and not args[#QBCore.Commands.List[command].arguments] then
|
||||
TriggerClientEvent('QBCore:Notify', src, Lang:t('error.missing_args2'), 'error')
|
||||
else
|
||||
QBCore.Commands.List[command].callback(src, args)
|
||||
end
|
||||
else
|
||||
TriggerClientEvent('QBCore:Notify', src, Lang:t('error.no_access'), 'error')
|
||||
end
|
||||
end)
|
||||
|
||||
-- Use this for player vehicle spawning
|
||||
-- Vehicle server-side spawning callback (netId)
|
||||
-- use the netid on the client with the NetworkGetEntityFromNetworkId native
|
||||
-- convert it to a vehicle via the NetToVeh native
|
||||
QBCore.Functions.CreateCallback('QBCore:Server:SpawnVehicle', function(source, cb, model, coords, warp)
|
||||
local veh = QBCore.Functions.SpawnVehicle(source, model, coords, warp)
|
||||
cb(NetworkGetNetworkIdFromEntity(veh))
|
||||
end)
|
||||
|
||||
-- Use this for long distance vehicle spawning
|
||||
-- vehicle server-side spawning callback (netId)
|
||||
-- use the netid on the client with the NetworkGetEntityFromNetworkId native
|
||||
-- convert it to a vehicle via the NetToVeh native
|
||||
QBCore.Functions.CreateCallback('QBCore:Server:CreateVehicle', function(source, cb, model, coords, warp)
|
||||
local veh = QBCore.Functions.CreateAutomobile(source, model, coords, warp)
|
||||
cb(NetworkGetNetworkIdFromEntity(veh))
|
||||
end)
|
||||
|
||||
--QBCore.Functions.CreateCallback('QBCore:HasItem', function(source, cb, items, amount)
|
||||
-- https://github.com/qbcore-framework/qb-inventory/blob/e4ef156d93dd1727234d388c3f25110c350b3bcf/server/main.lua#L2066
|
||||
--end)
|
||||
@@ -1,336 +0,0 @@
|
||||
-- Add or change (a) method(s) in the QBCore.Functions table
|
||||
local function SetMethod(methodName, handler)
|
||||
if type(methodName) ~= 'string' then
|
||||
return false, 'invalid_method_name'
|
||||
end
|
||||
|
||||
QBCore.Functions[methodName] = handler
|
||||
|
||||
TriggerEvent('QBCore:Server:UpdateObject')
|
||||
|
||||
return true, 'success'
|
||||
end
|
||||
|
||||
QBCore.Functions.SetMethod = SetMethod
|
||||
exports('SetMethod', SetMethod)
|
||||
|
||||
-- Add or change (a) field(s) in the QBCore table
|
||||
local function SetField(fieldName, data)
|
||||
if type(fieldName) ~= 'string' then
|
||||
return false, 'invalid_field_name'
|
||||
end
|
||||
|
||||
QBCore[fieldName] = data
|
||||
|
||||
TriggerEvent('QBCore:Server:UpdateObject')
|
||||
|
||||
return true, 'success'
|
||||
end
|
||||
|
||||
QBCore.Functions.SetField = SetField
|
||||
exports('SetField', SetField)
|
||||
|
||||
-- Single add job function which should only be used if you planning on adding a single job
|
||||
local function AddJob(jobName, job)
|
||||
if type(jobName) ~= 'string' then
|
||||
return false, 'invalid_job_name'
|
||||
end
|
||||
|
||||
if QBCore.Shared.Jobs[jobName] then
|
||||
return false, 'job_exists'
|
||||
end
|
||||
|
||||
QBCore.Shared.Jobs[jobName] = job
|
||||
|
||||
TriggerClientEvent('QBCore:Client:OnSharedUpdate', -1, 'Jobs', jobName, job)
|
||||
TriggerEvent('QBCore:Server:UpdateObject')
|
||||
return true, 'success'
|
||||
end
|
||||
|
||||
QBCore.Functions.AddJob = AddJob
|
||||
exports('AddJob', AddJob)
|
||||
|
||||
-- Multiple Add Jobs
|
||||
local function AddJobs(jobs)
|
||||
local shouldContinue = true
|
||||
local message = 'success'
|
||||
local errorItem = nil
|
||||
|
||||
for key, value in pairs(jobs) do
|
||||
if type(key) ~= 'string' then
|
||||
message = 'invalid_job_name'
|
||||
shouldContinue = false
|
||||
errorItem = jobs[key]
|
||||
break
|
||||
end
|
||||
|
||||
if QBCore.Shared.Jobs[key] then
|
||||
message = 'job_exists'
|
||||
shouldContinue = false
|
||||
errorItem = jobs[key]
|
||||
break
|
||||
end
|
||||
|
||||
QBCore.Shared.Jobs[key] = value
|
||||
end
|
||||
|
||||
if not shouldContinue then return false, message, errorItem end
|
||||
TriggerClientEvent('QBCore:Client:OnSharedUpdateMultiple', -1, 'Jobs', jobs)
|
||||
TriggerEvent('QBCore:Server:UpdateObject')
|
||||
return true, message, nil
|
||||
end
|
||||
|
||||
QBCore.Functions.AddJobs = AddJobs
|
||||
exports('AddJobs', AddJobs)
|
||||
|
||||
-- Single Remove Job
|
||||
local function RemoveJob(jobName)
|
||||
if type(jobName) ~= 'string' then
|
||||
return false, 'invalid_job_name'
|
||||
end
|
||||
|
||||
if not QBCore.Shared.Jobs[jobName] then
|
||||
return false, 'job_not_exists'
|
||||
end
|
||||
|
||||
QBCore.Shared.Jobs[jobName] = nil
|
||||
|
||||
TriggerClientEvent('QBCore:Client:OnSharedUpdate', -1, 'Jobs', jobName, nil)
|
||||
TriggerEvent('QBCore:Server:UpdateObject')
|
||||
return true, 'success'
|
||||
end
|
||||
|
||||
QBCore.Functions.RemoveJob = RemoveJob
|
||||
exports('RemoveJob', RemoveJob)
|
||||
|
||||
-- Single Update Job
|
||||
local function UpdateJob(jobName, job)
|
||||
if type(jobName) ~= 'string' then
|
||||
return false, 'invalid_job_name'
|
||||
end
|
||||
|
||||
if not QBCore.Shared.Jobs[jobName] then
|
||||
return false, 'job_not_exists'
|
||||
end
|
||||
|
||||
QBCore.Shared.Jobs[jobName] = job
|
||||
|
||||
TriggerClientEvent('QBCore:Client:OnSharedUpdate', -1, 'Jobs', jobName, job)
|
||||
TriggerEvent('QBCore:Server:UpdateObject')
|
||||
return true, 'success'
|
||||
end
|
||||
|
||||
QBCore.Functions.UpdateJob = UpdateJob
|
||||
exports('UpdateJob', UpdateJob)
|
||||
|
||||
-- Single add item
|
||||
local function AddItem(itemName, item)
|
||||
if type(itemName) ~= 'string' then
|
||||
return false, 'invalid_item_name'
|
||||
end
|
||||
|
||||
if QBCore.Shared.Items[itemName] then
|
||||
return false, 'item_exists'
|
||||
end
|
||||
|
||||
QBCore.Shared.Items[itemName] = item
|
||||
|
||||
TriggerClientEvent('QBCore:Client:OnSharedUpdate', -1, 'Items', itemName, item)
|
||||
TriggerEvent('QBCore:Server:UpdateObject')
|
||||
return true, 'success'
|
||||
end
|
||||
|
||||
QBCore.Functions.AddItem = AddItem
|
||||
exports('AddItem', AddItem)
|
||||
|
||||
-- Single update item
|
||||
local function UpdateItem(itemName, item)
|
||||
if type(itemName) ~= 'string' then
|
||||
return false, 'invalid_item_name'
|
||||
end
|
||||
if not QBCore.Shared.Items[itemName] then
|
||||
return false, 'item_not_exists'
|
||||
end
|
||||
QBCore.Shared.Items[itemName] = item
|
||||
TriggerClientEvent('QBCore:Client:OnSharedUpdate', -1, 'Items', itemName, item)
|
||||
TriggerEvent('QBCore:Server:UpdateObject')
|
||||
return true, 'success'
|
||||
end
|
||||
|
||||
QBCore.Functions.UpdateItem = UpdateItem
|
||||
exports('UpdateItem', UpdateItem)
|
||||
|
||||
-- Multiple Add Items
|
||||
local function AddItems(items)
|
||||
local shouldContinue = true
|
||||
local message = 'success'
|
||||
local errorItem = nil
|
||||
|
||||
for key, value in pairs(items) do
|
||||
if type(key) ~= 'string' then
|
||||
message = 'invalid_item_name'
|
||||
shouldContinue = false
|
||||
errorItem = items[key]
|
||||
break
|
||||
end
|
||||
|
||||
if QBCore.Shared.Items[key] then
|
||||
message = 'item_exists'
|
||||
shouldContinue = false
|
||||
errorItem = items[key]
|
||||
break
|
||||
end
|
||||
|
||||
QBCore.Shared.Items[key] = value
|
||||
end
|
||||
|
||||
if not shouldContinue then return false, message, errorItem end
|
||||
TriggerClientEvent('QBCore:Client:OnSharedUpdateMultiple', -1, 'Items', items)
|
||||
TriggerEvent('QBCore:Server:UpdateObject')
|
||||
return true, message, nil
|
||||
end
|
||||
|
||||
QBCore.Functions.AddItems = AddItems
|
||||
exports('AddItems', AddItems)
|
||||
|
||||
-- Single Remove Item
|
||||
local function RemoveItem(itemName)
|
||||
if type(itemName) ~= 'string' then
|
||||
return false, 'invalid_item_name'
|
||||
end
|
||||
|
||||
if not QBCore.Shared.Items[itemName] then
|
||||
return false, 'item_not_exists'
|
||||
end
|
||||
|
||||
QBCore.Shared.Items[itemName] = nil
|
||||
|
||||
TriggerClientEvent('QBCore:Client:OnSharedUpdate', -1, 'Items', itemName, nil)
|
||||
TriggerEvent('QBCore:Server:UpdateObject')
|
||||
return true, 'success'
|
||||
end
|
||||
|
||||
QBCore.Functions.RemoveItem = RemoveItem
|
||||
exports('RemoveItem', RemoveItem)
|
||||
|
||||
-- Single Add Gang
|
||||
local function AddGang(gangName, gang)
|
||||
if type(gangName) ~= 'string' then
|
||||
return false, 'invalid_gang_name'
|
||||
end
|
||||
|
||||
if QBCore.Shared.Gangs[gangName] then
|
||||
return false, 'gang_exists'
|
||||
end
|
||||
|
||||
QBCore.Shared.Gangs[gangName] = gang
|
||||
|
||||
TriggerClientEvent('QBCore:Client:OnSharedUpdate', -1, 'Gangs', gangName, gang)
|
||||
TriggerEvent('QBCore:Server:UpdateObject')
|
||||
return true, 'success'
|
||||
end
|
||||
|
||||
QBCore.Functions.AddGang = AddGang
|
||||
exports('AddGang', AddGang)
|
||||
|
||||
-- Multiple Add Gangs
|
||||
local function AddGangs(gangs)
|
||||
local shouldContinue = true
|
||||
local message = 'success'
|
||||
local errorItem = nil
|
||||
|
||||
for key, value in pairs(gangs) do
|
||||
if type(key) ~= 'string' then
|
||||
message = 'invalid_gang_name'
|
||||
shouldContinue = false
|
||||
errorItem = gangs[key]
|
||||
break
|
||||
end
|
||||
|
||||
if QBCore.Shared.Gangs[key] then
|
||||
message = 'gang_exists'
|
||||
shouldContinue = false
|
||||
errorItem = gangs[key]
|
||||
break
|
||||
end
|
||||
|
||||
QBCore.Shared.Gangs[key] = value
|
||||
end
|
||||
|
||||
if not shouldContinue then return false, message, errorItem end
|
||||
TriggerClientEvent('QBCore:Client:OnSharedUpdateMultiple', -1, 'Gangs', gangs)
|
||||
TriggerEvent('QBCore:Server:UpdateObject')
|
||||
return true, message, nil
|
||||
end
|
||||
|
||||
QBCore.Functions.AddGangs = AddGangs
|
||||
exports('AddGangs', AddGangs)
|
||||
|
||||
-- Single Remove Gang
|
||||
local function RemoveGang(gangName)
|
||||
if type(gangName) ~= 'string' then
|
||||
return false, 'invalid_gang_name'
|
||||
end
|
||||
|
||||
if not QBCore.Shared.Gangs[gangName] then
|
||||
return false, 'gang_not_exists'
|
||||
end
|
||||
|
||||
QBCore.Shared.Gangs[gangName] = nil
|
||||
|
||||
TriggerClientEvent('QBCore:Client:OnSharedUpdate', -1, 'Gangs', gangName, nil)
|
||||
TriggerEvent('QBCore:Server:UpdateObject')
|
||||
return true, 'success'
|
||||
end
|
||||
|
||||
QBCore.Functions.RemoveGang = RemoveGang
|
||||
exports('RemoveGang', RemoveGang)
|
||||
|
||||
-- Single Update Gang
|
||||
local function UpdateGang(gangName, gang)
|
||||
if type(gangName) ~= 'string' then
|
||||
return false, 'invalid_gang_name'
|
||||
end
|
||||
|
||||
if not QBCore.Shared.Gangs[gangName] then
|
||||
return false, 'gang_not_exists'
|
||||
end
|
||||
|
||||
QBCore.Shared.Gangs[gangName] = gang
|
||||
|
||||
TriggerClientEvent('QBCore:Client:OnSharedUpdate', -1, 'Gangs', gangName, gang)
|
||||
TriggerEvent('QBCore:Server:UpdateObject')
|
||||
return true, 'success'
|
||||
end
|
||||
|
||||
QBCore.Functions.UpdateGang = UpdateGang
|
||||
exports('UpdateGang', UpdateGang)
|
||||
|
||||
local resourceName = GetCurrentResourceName()
|
||||
local function GetCoreVersion(InvokingResource)
|
||||
local resourceVersion = GetResourceMetadata(resourceName, 'version')
|
||||
if InvokingResource and InvokingResource ~= '' then
|
||||
print(('%s called qbcore version check: %s'):format(InvokingResource or 'Unknown Resource', resourceVersion))
|
||||
end
|
||||
return resourceVersion
|
||||
end
|
||||
|
||||
QBCore.Functions.GetCoreVersion = GetCoreVersion
|
||||
exports('GetCoreVersion', GetCoreVersion)
|
||||
|
||||
local function ExploitBan(playerId, origin)
|
||||
local name = GetPlayerName(playerId)
|
||||
MySQL.insert('INSERT INTO bans (name, license, discord, ip, reason, expire, bannedby) VALUES (?, ?, ?, ?, ?, ?, ?)', {
|
||||
name,
|
||||
QBCore.Functions.GetIdentifier(playerId, 'license'),
|
||||
QBCore.Functions.GetIdentifier(playerId, 'discord'),
|
||||
QBCore.Functions.GetIdentifier(playerId, 'ip'),
|
||||
origin,
|
||||
2147483647,
|
||||
'Anti Cheat'
|
||||
})
|
||||
DropPlayer(playerId, Lang:t('info.exploit_banned', { discord = QBCore.Config.Server.Discord }))
|
||||
TriggerEvent('qb-log:server:CreateLog', 'anticheat', 'Anti-Cheat', 'red', name .. ' has been banned for exploiting ' .. origin, true)
|
||||
end
|
||||
|
||||
exports('ExploitBan', ExploitBan)
|
||||
@@ -1,739 +0,0 @@
|
||||
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 on duty players of a specified job and the number
|
||||
---@param job string
|
||||
---@return table, 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
|
||||
---@param job string
|
||||
---@return number
|
||||
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
|
||||
|
||||
--- @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!')
|
||||
@@ -1,49 +0,0 @@
|
||||
QBCore = {}
|
||||
QBCore.Config = QBConfig
|
||||
QBCore.Shared = QBShared
|
||||
QBCore.ClientCallbacks = {}
|
||||
QBCore.ServerCallbacks = {}
|
||||
|
||||
-- Get the full QBCore object (default behavior):
|
||||
-- local QBCore = GetCoreObject()
|
||||
|
||||
-- Get only specific parts of QBCore:
|
||||
-- local QBCore = GetCoreObject({'Players', 'Config'})
|
||||
|
||||
local function GetCoreObject(filters)
|
||||
if not filters then return QBCore end
|
||||
local results = {}
|
||||
for i = 1, #filters do
|
||||
local key = filters[i]
|
||||
if QBCore[key] then
|
||||
results[key] = QBCore[key]
|
||||
end
|
||||
end
|
||||
return results
|
||||
end
|
||||
exports('GetCoreObject', GetCoreObject)
|
||||
|
||||
local function GetSharedItems()
|
||||
return QBShared.Items
|
||||
end
|
||||
exports('GetSharedItems', GetSharedItems)
|
||||
|
||||
local function GetSharedVehicles()
|
||||
return QBShared.Vehicles
|
||||
end
|
||||
exports('GetSharedVehicles', GetSharedVehicles)
|
||||
|
||||
local function GetSharedWeapons()
|
||||
return QBShared.Weapons
|
||||
end
|
||||
exports('GetSharedWeapons', GetSharedWeapons)
|
||||
|
||||
local function GetSharedJobs()
|
||||
return QBShared.Jobs
|
||||
end
|
||||
exports('GetSharedJobs', GetSharedJobs)
|
||||
|
||||
local function GetSharedGangs()
|
||||
return QBShared.Gangs
|
||||
end
|
||||
exports('GetSharedGangs', GetSharedGangs)
|
||||
@@ -1,666 +0,0 @@
|
||||
QBCore.Players = {}
|
||||
QBCore.Player = {}
|
||||
|
||||
-- On player login get their data or set defaults
|
||||
-- Don't touch any of this unless you know what you are doing
|
||||
-- Will cause major issues!
|
||||
|
||||
local resourceName = GetCurrentResourceName()
|
||||
function QBCore.Player.Login(source, citizenid, newData)
|
||||
if source and source ~= '' then
|
||||
if citizenid then
|
||||
local license = QBCore.Functions.GetIdentifier(source, 'license')
|
||||
local PlayerData = MySQL.prepare.await('SELECT * FROM players where citizenid = ?', { citizenid })
|
||||
if PlayerData and license == PlayerData.license then
|
||||
PlayerData.money = json.decode(PlayerData.money)
|
||||
PlayerData.job = json.decode(PlayerData.job)
|
||||
PlayerData.gang = json.decode(PlayerData.gang)
|
||||
PlayerData.position = json.decode(PlayerData.position)
|
||||
PlayerData.metadata = json.decode(PlayerData.metadata)
|
||||
PlayerData.charinfo = json.decode(PlayerData.charinfo)
|
||||
QBCore.Player.CheckPlayerData(source, PlayerData)
|
||||
else
|
||||
DropPlayer(source, Lang:t('info.exploit_dropped'))
|
||||
TriggerEvent('qb-log:server:CreateLog', 'anticheat', 'Anti-Cheat', 'white', GetPlayerName(source) .. ' Has Been Dropped For Character Joining Exploit', false)
|
||||
end
|
||||
else
|
||||
QBCore.Player.CheckPlayerData(source, newData)
|
||||
end
|
||||
return true
|
||||
else
|
||||
QBCore.ShowError(resourceName, 'ERROR QBCORE.PLAYER.LOGIN - NO SOURCE GIVEN!')
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
function QBCore.Player.GetOfflinePlayer(citizenid)
|
||||
if citizenid then
|
||||
local PlayerData = MySQL.prepare.await('SELECT * FROM players where citizenid = ?', { citizenid })
|
||||
if PlayerData then
|
||||
PlayerData.money = json.decode(PlayerData.money)
|
||||
PlayerData.job = json.decode(PlayerData.job)
|
||||
PlayerData.gang = json.decode(PlayerData.gang)
|
||||
PlayerData.position = json.decode(PlayerData.position)
|
||||
PlayerData.metadata = json.decode(PlayerData.metadata)
|
||||
PlayerData.charinfo = json.decode(PlayerData.charinfo)
|
||||
return QBCore.Player.CheckPlayerData(nil, PlayerData)
|
||||
end
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
function QBCore.Player.GetPlayerByLicense(license)
|
||||
if license then
|
||||
local source = QBCore.Functions.GetSource(license)
|
||||
if source > 0 then
|
||||
return QBCore.Players[source]
|
||||
else
|
||||
return QBCore.Player.GetOfflinePlayerByLicense(license)
|
||||
end
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
function QBCore.Player.GetOfflinePlayerByLicense(license)
|
||||
if license then
|
||||
local PlayerData = MySQL.prepare.await('SELECT * FROM players where license = ?', { license })
|
||||
if PlayerData then
|
||||
PlayerData.money = json.decode(PlayerData.money)
|
||||
PlayerData.job = json.decode(PlayerData.job)
|
||||
PlayerData.gang = json.decode(PlayerData.gang)
|
||||
PlayerData.position = json.decode(PlayerData.position)
|
||||
PlayerData.metadata = json.decode(PlayerData.metadata)
|
||||
PlayerData.charinfo = json.decode(PlayerData.charinfo)
|
||||
return QBCore.Player.CheckPlayerData(nil, PlayerData)
|
||||
end
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
local function applyDefaults(playerData, defaults)
|
||||
for key, value in pairs(defaults) do
|
||||
if type(value) == 'function' then
|
||||
playerData[key] = playerData[key] or value()
|
||||
elseif type(value) == 'table' then
|
||||
playerData[key] = playerData[key] or {}
|
||||
applyDefaults(playerData[key], value)
|
||||
else
|
||||
playerData[key] = playerData[key] or value
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function QBCore.Player.CheckPlayerData(source, PlayerData)
|
||||
PlayerData = PlayerData or {}
|
||||
local Offline = not source
|
||||
|
||||
if source then
|
||||
PlayerData.source = source
|
||||
PlayerData.license = PlayerData.license or QBCore.Functions.GetIdentifier(source, 'license')
|
||||
PlayerData.name = GetPlayerName(source)
|
||||
end
|
||||
|
||||
local validatedJob = false
|
||||
if PlayerData.job and PlayerData.job.name ~= nil and PlayerData.job.grade and PlayerData.job.grade.level ~= nil then
|
||||
local jobInfo = QBCore.Shared.Jobs[PlayerData.job.name]
|
||||
|
||||
if jobInfo then
|
||||
local jobGradeInfo = jobInfo.grades[tostring(PlayerData.job.grade.level)]
|
||||
if jobGradeInfo then
|
||||
PlayerData.job.label = jobInfo.label
|
||||
PlayerData.job.grade.name = jobGradeInfo.name
|
||||
PlayerData.job.payment = jobGradeInfo.payment
|
||||
PlayerData.job.grade.isboss = jobGradeInfo.isboss or false
|
||||
PlayerData.job.isboss = jobGradeInfo.isboss or false
|
||||
validatedJob = true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if validatedJob == false then
|
||||
-- set to nil, as the default job (unemployed) will be added by `applyDefaults`
|
||||
PlayerData.job = nil
|
||||
end
|
||||
|
||||
local validatedGang = false
|
||||
if PlayerData.gang and PlayerData.gang.name ~= nil and PlayerData.gang.grade and PlayerData.gang.grade.level ~= nil then
|
||||
local gangInfo = QBCore.Shared.Gangs[PlayerData.gang.name]
|
||||
|
||||
if gangInfo then
|
||||
local gangGradeInfo = gangInfo.grades[tostring(PlayerData.gang.grade.level)]
|
||||
if gangGradeInfo then
|
||||
PlayerData.gang.label = gangInfo.label
|
||||
PlayerData.gang.grade.name = gangGradeInfo.name
|
||||
PlayerData.gang.payment = gangGradeInfo.payment
|
||||
PlayerData.gang.grade.isboss = gangGradeInfo.isboss or false
|
||||
PlayerData.gang.isboss = gangGradeInfo.isboss or false
|
||||
validatedGang = true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if validatedGang == false then
|
||||
-- set to nil, as the default gang (unemployed) will be added by `applyDefaults`
|
||||
PlayerData.gang = nil
|
||||
end
|
||||
|
||||
applyDefaults(PlayerData, QBCore.Config.Player.PlayerDefaults)
|
||||
|
||||
if GetResourceState('qb-inventory') ~= 'missing' then
|
||||
PlayerData.items = exports['qb-inventory']:LoadInventory(PlayerData.source, PlayerData.citizenid)
|
||||
end
|
||||
|
||||
return QBCore.Player.CreatePlayer(PlayerData, Offline)
|
||||
end
|
||||
|
||||
-- On player logout
|
||||
|
||||
function QBCore.Player.Logout(source)
|
||||
TriggerClientEvent('QBCore:Client:OnPlayerUnload', source)
|
||||
TriggerEvent('QBCore:Server:OnPlayerUnload', source)
|
||||
TriggerClientEvent('QBCore:Player:UpdatePlayerData', source)
|
||||
Wait(200)
|
||||
QBCore.Players[source] = nil
|
||||
end
|
||||
|
||||
-- Create a new character
|
||||
-- Don't touch any of this unless you know what you are doing
|
||||
-- Will cause major issues!
|
||||
|
||||
function QBCore.Player.CreatePlayer(PlayerData, Offline)
|
||||
local self = {}
|
||||
self.Functions = {}
|
||||
self.PlayerData = PlayerData
|
||||
self.Offline = Offline
|
||||
|
||||
function self.Functions.UpdatePlayerData()
|
||||
if self.Offline then return end
|
||||
TriggerEvent('QBCore:Player:SetPlayerData', self.PlayerData)
|
||||
TriggerClientEvent('QBCore:Player:SetPlayerData', self.PlayerData.source, self.PlayerData)
|
||||
end
|
||||
|
||||
function self.Functions.SetJob(job, grade)
|
||||
job = job:lower()
|
||||
grade = grade or '0'
|
||||
if not QBCore.Shared.Jobs[job] then return false end
|
||||
self.PlayerData.job = {
|
||||
name = job,
|
||||
label = QBCore.Shared.Jobs[job].label,
|
||||
onduty = QBCore.Shared.Jobs[job].defaultDuty,
|
||||
type = QBCore.Shared.Jobs[job].type or 'none',
|
||||
grade = {
|
||||
name = 'No Grades',
|
||||
level = 0,
|
||||
payment = 30,
|
||||
isboss = false
|
||||
}
|
||||
}
|
||||
local gradeKey = tostring(grade)
|
||||
local jobGradeInfo = QBCore.Shared.Jobs[job].grades[gradeKey]
|
||||
if jobGradeInfo then
|
||||
self.PlayerData.job.grade.name = jobGradeInfo.name
|
||||
self.PlayerData.job.grade.level = tonumber(gradeKey)
|
||||
self.PlayerData.job.grade.payment = jobGradeInfo.payment
|
||||
self.PlayerData.job.grade.isboss = jobGradeInfo.isboss or false
|
||||
self.PlayerData.job.isboss = jobGradeInfo.isboss or false
|
||||
end
|
||||
|
||||
if not self.Offline then
|
||||
self.Functions.UpdatePlayerData()
|
||||
TriggerEvent('QBCore:Server:OnJobUpdate', self.PlayerData.source, self.PlayerData.job)
|
||||
TriggerClientEvent('QBCore:Client:OnJobUpdate', self.PlayerData.source, self.PlayerData.job)
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
function self.Functions.SetGang(gang, grade)
|
||||
gang = gang:lower()
|
||||
grade = grade or '0'
|
||||
if not QBCore.Shared.Gangs[gang] then return false end
|
||||
self.PlayerData.gang = {
|
||||
name = gang,
|
||||
label = QBCore.Shared.Gangs[gang].label,
|
||||
grade = {
|
||||
name = 'No Grades',
|
||||
level = 0,
|
||||
isboss = false
|
||||
}
|
||||
}
|
||||
local gradeKey = tostring(grade)
|
||||
local gangGradeInfo = QBCore.Shared.Gangs[gang].grades[gradeKey]
|
||||
if gangGradeInfo then
|
||||
self.PlayerData.gang.grade.name = gangGradeInfo.name
|
||||
self.PlayerData.gang.grade.level = tonumber(gradeKey)
|
||||
self.PlayerData.gang.grade.isboss = gangGradeInfo.isboss or false
|
||||
self.PlayerData.gang.isboss = gangGradeInfo.isboss or false
|
||||
end
|
||||
|
||||
if not self.Offline then
|
||||
self.Functions.UpdatePlayerData()
|
||||
TriggerEvent('QBCore:Server:OnGangUpdate', self.PlayerData.source, self.PlayerData.gang)
|
||||
TriggerClientEvent('QBCore:Client:OnGangUpdate', self.PlayerData.source, self.PlayerData.gang)
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
function self.Functions.Notify(text, type, length)
|
||||
TriggerClientEvent('QBCore:Notify', self.PlayerData.source, text, type, length)
|
||||
end
|
||||
|
||||
function self.Functions.HasItem(items, amount)
|
||||
return QBCore.Functions.HasItem(self.PlayerData.source, items, amount)
|
||||
end
|
||||
|
||||
function self.Functions.GetName()
|
||||
local charinfo = self.PlayerData.charinfo
|
||||
return charinfo.firstname .. ' ' .. charinfo.lastname
|
||||
end
|
||||
|
||||
function self.Functions.SetJobDuty(onDuty)
|
||||
self.PlayerData.job.onduty = not not onDuty
|
||||
TriggerEvent('QBCore:Server:OnJobUpdate', self.PlayerData.source, self.PlayerData.job)
|
||||
TriggerClientEvent('QBCore:Client:OnJobUpdate', self.PlayerData.source, self.PlayerData.job)
|
||||
self.Functions.UpdatePlayerData()
|
||||
end
|
||||
|
||||
function self.Functions.SetPlayerData(key, val)
|
||||
if not key or type(key) ~= 'string' then return end
|
||||
self.PlayerData[key] = val
|
||||
self.Functions.UpdatePlayerData()
|
||||
end
|
||||
|
||||
function self.Functions.SetMetaData(meta, val)
|
||||
if not meta or type(meta) ~= 'string' then return end
|
||||
if meta == 'hunger' or meta == 'thirst' then
|
||||
val = val > 100 and 100 or val
|
||||
end
|
||||
self.PlayerData.metadata[meta] = val
|
||||
self.Functions.UpdatePlayerData()
|
||||
end
|
||||
|
||||
function self.Functions.GetMetaData(meta)
|
||||
if not meta or type(meta) ~= 'string' then return end
|
||||
return self.PlayerData.metadata[meta]
|
||||
end
|
||||
|
||||
function self.Functions.AddRep(rep, amount)
|
||||
if not rep or not amount then return end
|
||||
local addAmount = tonumber(amount)
|
||||
local currentRep = self.PlayerData.metadata['rep'][rep] or 0
|
||||
self.PlayerData.metadata['rep'][rep] = currentRep + addAmount
|
||||
self.Functions.UpdatePlayerData()
|
||||
end
|
||||
|
||||
function self.Functions.RemoveRep(rep, amount)
|
||||
if not rep or not amount then return end
|
||||
local removeAmount = tonumber(amount)
|
||||
local currentRep = self.PlayerData.metadata['rep'][rep] or 0
|
||||
if currentRep - removeAmount < 0 then
|
||||
self.PlayerData.metadata['rep'][rep] = 0
|
||||
else
|
||||
self.PlayerData.metadata['rep'][rep] = currentRep - removeAmount
|
||||
end
|
||||
self.Functions.UpdatePlayerData()
|
||||
end
|
||||
|
||||
function self.Functions.GetRep(rep)
|
||||
if not rep then return end
|
||||
return self.PlayerData.metadata['rep'][rep] or 0
|
||||
end
|
||||
|
||||
function self.Functions.AddMoney(moneytype, amount, reason)
|
||||
reason = reason or 'unknown'
|
||||
moneytype = moneytype:lower()
|
||||
amount = tonumber(amount)
|
||||
if amount < 0 then return end
|
||||
if not self.PlayerData.money[moneytype] then return false end
|
||||
self.PlayerData.money[moneytype] = self.PlayerData.money[moneytype] + amount
|
||||
|
||||
if not self.Offline then
|
||||
self.Functions.UpdatePlayerData()
|
||||
if amount > 100000 then
|
||||
TriggerEvent('qb-log:server:CreateLog', 'playermoney', 'AddMoney', 'lightgreen', '**' .. GetPlayerName(self.PlayerData.source) .. ' (citizenid: ' .. self.PlayerData.citizenid .. ' | id: ' .. self.PlayerData.source .. ')** $' .. amount .. ' (' .. moneytype .. ') added, new ' .. moneytype .. ' balance: ' .. self.PlayerData.money[moneytype] .. ' reason: ' .. reason, true)
|
||||
else
|
||||
TriggerEvent('qb-log:server:CreateLog', 'playermoney', 'AddMoney', 'lightgreen', '**' .. GetPlayerName(self.PlayerData.source) .. ' (citizenid: ' .. self.PlayerData.citizenid .. ' | id: ' .. self.PlayerData.source .. ')** $' .. amount .. ' (' .. moneytype .. ') added, new ' .. moneytype .. ' balance: ' .. self.PlayerData.money[moneytype] .. ' reason: ' .. reason)
|
||||
end
|
||||
TriggerClientEvent('hud:client:OnMoneyChange', self.PlayerData.source, moneytype, amount, false)
|
||||
TriggerClientEvent('QBCore:Client:OnMoneyChange', self.PlayerData.source, moneytype, amount, 'add', reason)
|
||||
TriggerEvent('QBCore:Server:OnMoneyChange', self.PlayerData.source, moneytype, amount, 'add', reason)
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
function self.Functions.RemoveMoney(moneytype, amount, reason)
|
||||
reason = reason or 'unknown'
|
||||
moneytype = moneytype:lower()
|
||||
amount = tonumber(amount)
|
||||
if amount < 0 then return end
|
||||
if not self.PlayerData.money[moneytype] then return false end
|
||||
for _, mtype in pairs(QBCore.Config.Money.DontAllowMinus) do
|
||||
if mtype == moneytype then
|
||||
if (self.PlayerData.money[moneytype] - amount) < 0 then
|
||||
return false
|
||||
end
|
||||
end
|
||||
end
|
||||
if self.PlayerData.money[moneytype] - amount < QBCore.Config.Money.MinusLimit then return false end
|
||||
self.PlayerData.money[moneytype] = self.PlayerData.money[moneytype] - amount
|
||||
|
||||
if not self.Offline then
|
||||
self.Functions.UpdatePlayerData()
|
||||
if amount > 100000 then
|
||||
TriggerEvent('qb-log:server:CreateLog', 'playermoney', 'RemoveMoney', 'red', '**' .. GetPlayerName(self.PlayerData.source) .. ' (citizenid: ' .. self.PlayerData.citizenid .. ' | id: ' .. self.PlayerData.source .. ')** $' .. amount .. ' (' .. moneytype .. ') removed, new ' .. moneytype .. ' balance: ' .. self.PlayerData.money[moneytype] .. ' reason: ' .. reason, true)
|
||||
else
|
||||
TriggerEvent('qb-log:server:CreateLog', 'playermoney', 'RemoveMoney', 'red', '**' .. GetPlayerName(self.PlayerData.source) .. ' (citizenid: ' .. self.PlayerData.citizenid .. ' | id: ' .. self.PlayerData.source .. ')** $' .. amount .. ' (' .. moneytype .. ') removed, new ' .. moneytype .. ' balance: ' .. self.PlayerData.money[moneytype] .. ' reason: ' .. reason)
|
||||
end
|
||||
TriggerClientEvent('hud:client:OnMoneyChange', self.PlayerData.source, moneytype, amount, true)
|
||||
if moneytype == 'bank' then
|
||||
TriggerClientEvent('qb-phone:client:RemoveBankMoney', self.PlayerData.source, amount)
|
||||
end
|
||||
TriggerClientEvent('QBCore:Client:OnMoneyChange', self.PlayerData.source, moneytype, amount, 'remove', reason)
|
||||
TriggerEvent('QBCore:Server:OnMoneyChange', self.PlayerData.source, moneytype, amount, 'remove', reason)
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
function self.Functions.SetMoney(moneytype, amount, reason)
|
||||
reason = reason or 'unknown'
|
||||
moneytype = moneytype:lower()
|
||||
amount = tonumber(amount)
|
||||
if amount < 0 then return false end
|
||||
if not self.PlayerData.money[moneytype] then return false end
|
||||
local difference = amount - self.PlayerData.money[moneytype]
|
||||
self.PlayerData.money[moneytype] = amount
|
||||
|
||||
if not self.Offline then
|
||||
self.Functions.UpdatePlayerData()
|
||||
TriggerEvent('qb-log:server:CreateLog', 'playermoney', 'SetMoney', 'green', '**' .. GetPlayerName(self.PlayerData.source) .. ' (citizenid: ' .. self.PlayerData.citizenid .. ' | id: ' .. self.PlayerData.source .. ')** $' .. amount .. ' (' .. moneytype .. ') set, new ' .. moneytype .. ' balance: ' .. self.PlayerData.money[moneytype] .. ' reason: ' .. reason)
|
||||
TriggerClientEvent('hud:client:OnMoneyChange', self.PlayerData.source, moneytype, math.abs(difference), difference < 0)
|
||||
TriggerClientEvent('QBCore:Client:OnMoneyChange', self.PlayerData.source, moneytype, amount, 'set', reason)
|
||||
TriggerEvent('QBCore:Server:OnMoneyChange', self.PlayerData.source, moneytype, amount, 'set', reason)
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
function self.Functions.GetMoney(moneytype)
|
||||
if not moneytype then return false end
|
||||
moneytype = moneytype:lower()
|
||||
return self.PlayerData.money[moneytype]
|
||||
end
|
||||
|
||||
function self.Functions.Save()
|
||||
if self.Offline then
|
||||
QBCore.Player.SaveOffline(self.PlayerData)
|
||||
else
|
||||
QBCore.Player.Save(self.PlayerData.source)
|
||||
end
|
||||
end
|
||||
|
||||
function self.Functions.Logout()
|
||||
if self.Offline then return end
|
||||
QBCore.Player.Logout(self.PlayerData.source)
|
||||
end
|
||||
|
||||
function self.Functions.AddMethod(methodName, handler)
|
||||
self.Functions[methodName] = handler
|
||||
end
|
||||
|
||||
function self.Functions.AddField(fieldName, data)
|
||||
self[fieldName] = data
|
||||
end
|
||||
|
||||
if self.Offline then
|
||||
return self
|
||||
else
|
||||
QBCore.Players[self.PlayerData.source] = self
|
||||
QBCore.Player.Save(self.PlayerData.source)
|
||||
TriggerEvent('QBCore:Server:PlayerLoaded', self)
|
||||
self.Functions.UpdatePlayerData()
|
||||
end
|
||||
end
|
||||
|
||||
-- Add a new function to the Functions table of the player class
|
||||
-- Use-case:
|
||||
--[[
|
||||
AddEventHandler('QBCore:Server:PlayerLoaded', function(Player)
|
||||
QBCore.Functions.AddPlayerMethod(Player.PlayerData.source, "functionName", function(oneArg, orMore)
|
||||
-- do something here
|
||||
end)
|
||||
end)
|
||||
]]
|
||||
|
||||
function QBCore.Functions.AddPlayerMethod(ids, methodName, handler)
|
||||
local idType = type(ids)
|
||||
if idType == 'number' then
|
||||
if ids == -1 then
|
||||
for _, v in pairs(QBCore.Players) do
|
||||
v.Functions.AddMethod(methodName, handler)
|
||||
end
|
||||
else
|
||||
if not QBCore.Players[ids] then return end
|
||||
|
||||
QBCore.Players[ids].Functions.AddMethod(methodName, handler)
|
||||
end
|
||||
elseif idType == 'table' and table.type(ids) == 'array' then
|
||||
for i = 1, #ids do
|
||||
QBCore.Functions.AddPlayerMethod(ids[i], methodName, handler)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Add a new field table of the player class
|
||||
-- Use-case:
|
||||
--[[
|
||||
AddEventHandler('QBCore:Server:PlayerLoaded', function(Player)
|
||||
QBCore.Functions.AddPlayerField(Player.PlayerData.source, "fieldName", "fieldData")
|
||||
end)
|
||||
]]
|
||||
|
||||
function QBCore.Functions.AddPlayerField(ids, fieldName, data)
|
||||
local idType = type(ids)
|
||||
if idType == 'number' then
|
||||
if ids == -1 then
|
||||
for _, v in pairs(QBCore.Players) do
|
||||
v.Functions.AddField(fieldName, data)
|
||||
end
|
||||
else
|
||||
if not QBCore.Players[ids] then return end
|
||||
|
||||
QBCore.Players[ids].Functions.AddField(fieldName, data)
|
||||
end
|
||||
elseif idType == 'table' and table.type(ids) == 'array' then
|
||||
for i = 1, #ids do
|
||||
QBCore.Functions.AddPlayerField(ids[i], fieldName, data)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Save player info to database (make sure citizenid is the primary key in your database)
|
||||
|
||||
function QBCore.Player.Save(source)
|
||||
local ped = GetPlayerPed(source)
|
||||
local pcoords = GetEntityCoords(ped)
|
||||
local PlayerData = QBCore.Players[source].PlayerData
|
||||
if PlayerData then
|
||||
MySQL.insert('INSERT INTO players (citizenid, cid, license, name, money, charinfo, job, gang, position, metadata) VALUES (:citizenid, :cid, :license, :name, :money, :charinfo, :job, :gang, :position, :metadata) ON DUPLICATE KEY UPDATE cid = :cid, name = :name, money = :money, charinfo = :charinfo, job = :job, gang = :gang, position = :position, metadata = :metadata', {
|
||||
citizenid = PlayerData.citizenid,
|
||||
cid = tonumber(PlayerData.cid),
|
||||
license = PlayerData.license,
|
||||
name = PlayerData.name,
|
||||
money = json.encode(PlayerData.money),
|
||||
charinfo = json.encode(PlayerData.charinfo),
|
||||
job = json.encode(PlayerData.job),
|
||||
gang = json.encode(PlayerData.gang),
|
||||
position = json.encode(pcoords),
|
||||
metadata = json.encode(PlayerData.metadata)
|
||||
})
|
||||
if GetResourceState('qb-inventory') ~= 'missing' then exports['qb-inventory']:SaveInventory(source) end
|
||||
QBCore.ShowSuccess(resourceName, PlayerData.name .. ' PLAYER SAVED!')
|
||||
else
|
||||
QBCore.ShowError(resourceName, 'ERROR QBCORE.PLAYER.SAVE - PLAYERDATA IS EMPTY!')
|
||||
end
|
||||
end
|
||||
|
||||
function QBCore.Player.SaveOffline(PlayerData)
|
||||
if PlayerData then
|
||||
MySQL.insert('INSERT INTO players (citizenid, cid, license, name, money, charinfo, job, gang, position, metadata) VALUES (:citizenid, :cid, :license, :name, :money, :charinfo, :job, :gang, :position, :metadata) ON DUPLICATE KEY UPDATE cid = :cid, name = :name, money = :money, charinfo = :charinfo, job = :job, gang = :gang, position = :position, metadata = :metadata', {
|
||||
citizenid = PlayerData.citizenid,
|
||||
cid = tonumber(PlayerData.cid),
|
||||
license = PlayerData.license,
|
||||
name = PlayerData.name,
|
||||
money = json.encode(PlayerData.money),
|
||||
charinfo = json.encode(PlayerData.charinfo),
|
||||
job = json.encode(PlayerData.job),
|
||||
gang = json.encode(PlayerData.gang),
|
||||
position = json.encode(PlayerData.position),
|
||||
metadata = json.encode(PlayerData.metadata)
|
||||
})
|
||||
if GetResourceState('qb-inventory') ~= 'missing' then exports['qb-inventory']:SaveInventory(PlayerData, true) end
|
||||
QBCore.ShowSuccess(resourceName, PlayerData.name .. ' OFFLINE PLAYER SAVED!')
|
||||
else
|
||||
QBCore.ShowError(resourceName, 'ERROR QBCORE.PLAYER.SAVEOFFLINE - PLAYERDATA IS EMPTY!')
|
||||
end
|
||||
end
|
||||
|
||||
-- Delete character
|
||||
|
||||
local playertables = { -- Add tables as needed
|
||||
{ table = 'players' },
|
||||
{ table = 'apartments' },
|
||||
{ table = 'bank_accounts' },
|
||||
{ table = 'crypto_transactions' },
|
||||
{ table = 'phone_invoices' },
|
||||
{ table = 'phone_messages' },
|
||||
{ table = 'playerskins' },
|
||||
{ table = 'player_contacts' },
|
||||
{ table = 'player_houses' },
|
||||
{ table = 'player_mails' },
|
||||
{ table = 'player_outfits' },
|
||||
{ table = 'player_vehicles' }
|
||||
}
|
||||
|
||||
function QBCore.Player.DeleteCharacter(source, citizenid)
|
||||
local license = QBCore.Functions.GetIdentifier(source, 'license')
|
||||
local result = MySQL.scalar.await('SELECT license FROM players where citizenid = ?', { citizenid })
|
||||
if license == result then
|
||||
local query = 'DELETE FROM %s WHERE citizenid = ?'
|
||||
local tableCount = #playertables
|
||||
local queries = table.create(tableCount, 0)
|
||||
|
||||
for i = 1, tableCount do
|
||||
local v = playertables[i]
|
||||
queries[i] = { query = query:format(v.table), values = { citizenid } }
|
||||
end
|
||||
|
||||
MySQL.transaction(queries, function(result2)
|
||||
if result2 then
|
||||
TriggerEvent('qb-log:server:CreateLog', 'joinleave', 'Character Deleted', 'red', '**' .. GetPlayerName(source) .. '** ' .. license .. ' deleted **' .. citizenid .. '**..')
|
||||
end
|
||||
end)
|
||||
else
|
||||
DropPlayer(source, Lang:t('info.exploit_dropped'))
|
||||
TriggerEvent('qb-log:server:CreateLog', 'anticheat', 'Anti-Cheat', 'white', GetPlayerName(source) .. ' Has Been Dropped For Character Deletion Exploit', true)
|
||||
end
|
||||
end
|
||||
|
||||
function QBCore.Player.ForceDeleteCharacter(citizenid)
|
||||
local result = MySQL.scalar.await('SELECT license FROM players where citizenid = ?', { citizenid })
|
||||
if result then
|
||||
local query = 'DELETE FROM %s WHERE citizenid = ?'
|
||||
local tableCount = #playertables
|
||||
local queries = table.create(tableCount, 0)
|
||||
local Player = QBCore.Functions.GetPlayerByCitizenId(citizenid)
|
||||
|
||||
if Player then
|
||||
DropPlayer(Player.PlayerData.source, 'An admin deleted the character which you are currently using')
|
||||
end
|
||||
for i = 1, tableCount do
|
||||
local v = playertables[i]
|
||||
queries[i] = { query = query:format(v.table), values = { citizenid } }
|
||||
end
|
||||
|
||||
MySQL.transaction(queries, function(result2)
|
||||
if result2 then
|
||||
TriggerEvent('qb-log:server:CreateLog', 'joinleave', 'Character Force Deleted', 'red', 'Character **' .. citizenid .. '** got deleted')
|
||||
end
|
||||
end)
|
||||
end
|
||||
end
|
||||
|
||||
-- Inventory Backwards Compatibility
|
||||
|
||||
function QBCore.Player.SaveInventory(source)
|
||||
if GetResourceState('qb-inventory') == 'missing' then return end
|
||||
exports['qb-inventory']:SaveInventory(source, false)
|
||||
end
|
||||
|
||||
function QBCore.Player.SaveOfflineInventory(PlayerData)
|
||||
if GetResourceState('qb-inventory') == 'missing' then return end
|
||||
exports['qb-inventory']:SaveInventory(PlayerData, true)
|
||||
end
|
||||
|
||||
function QBCore.Player.GetTotalWeight(items)
|
||||
if GetResourceState('qb-inventory') == 'missing' then return end
|
||||
return exports['qb-inventory']:GetTotalWeight(items)
|
||||
end
|
||||
|
||||
function QBCore.Player.GetSlotsByItem(items, itemName)
|
||||
if GetResourceState('qb-inventory') == 'missing' then return end
|
||||
return exports['qb-inventory']:GetSlotsByItem(items, itemName)
|
||||
end
|
||||
|
||||
function QBCore.Player.GetFirstSlotByItem(items, itemName)
|
||||
if GetResourceState('qb-inventory') == 'missing' then return end
|
||||
return exports['qb-inventory']:GetFirstSlotByItem(items, itemName)
|
||||
end
|
||||
|
||||
-- Util Functions
|
||||
|
||||
function QBCore.Player.CreateCitizenId()
|
||||
local CitizenId = tostring(QBCore.Shared.RandomStr(3) .. QBCore.Shared.RandomInt(5)):upper()
|
||||
local result = MySQL.prepare.await('SELECT EXISTS(SELECT 1 FROM players WHERE citizenid = ?) AS uniqueCheck', { CitizenId })
|
||||
if result == 0 then return CitizenId end
|
||||
return QBCore.Player.CreateCitizenId()
|
||||
end
|
||||
|
||||
function QBCore.Functions.CreateAccountNumber()
|
||||
local AccountNumber = 'US0' .. math.random(1, 9) .. 'QBCore' .. math.random(1111, 9999) .. math.random(1111, 9999) .. math.random(11, 99)
|
||||
local result = MySQL.prepare.await('SELECT EXISTS(SELECT 1 FROM players WHERE JSON_UNQUOTE(JSON_EXTRACT(charinfo, "$.account")) = ?) AS uniqueCheck', { AccountNumber })
|
||||
if result == 0 then return AccountNumber end
|
||||
return QBCore.Functions.CreateAccountNumber()
|
||||
end
|
||||
|
||||
function QBCore.Functions.CreatePhoneNumber()
|
||||
local PhoneNumber = math.random(100, 999) .. math.random(1000000, 9999999)
|
||||
local result = MySQL.prepare.await('SELECT EXISTS(SELECT 1 FROM players WHERE JSON_UNQUOTE(JSON_EXTRACT(charinfo, "$.phone")) = ?) AS uniqueCheck', { PhoneNumber })
|
||||
if result == 0 then return PhoneNumber end
|
||||
return QBCore.Functions.CreatePhoneNumber()
|
||||
end
|
||||
|
||||
function QBCore.Player.CreateFingerId()
|
||||
local FingerId = tostring(QBCore.Shared.RandomStr(2) .. QBCore.Shared.RandomInt(3) .. QBCore.Shared.RandomStr(1) .. QBCore.Shared.RandomInt(2) .. QBCore.Shared.RandomStr(3) .. QBCore.Shared.RandomInt(4))
|
||||
local result = MySQL.prepare.await('SELECT EXISTS(SELECT 1 FROM players WHERE JSON_UNQUOTE(JSON_EXTRACT(metadata, "$.fingerprint")) = ?) AS uniqueCheck', { FingerId })
|
||||
if result == 0 then return FingerId end
|
||||
return QBCore.Player.CreateFingerId()
|
||||
end
|
||||
|
||||
function QBCore.Player.CreateWalletId()
|
||||
local WalletId = 'QB-' .. math.random(11111111, 99999999)
|
||||
local result = MySQL.prepare.await('SELECT EXISTS(SELECT 1 FROM players WHERE JSON_UNQUOTE(JSON_EXTRACT(metadata, "$.walletid")) = ?) AS uniqueCheck', { WalletId })
|
||||
if result == 0 then return WalletId end
|
||||
return QBCore.Player.CreateWalletId()
|
||||
end
|
||||
|
||||
function QBCore.Player.CreateSerialNumber()
|
||||
local SerialNumber = math.random(11111111, 99999999)
|
||||
local result = MySQL.prepare.await('SELECT EXISTS(SELECT 1 FROM players WHERE JSON_UNQUOTE(JSON_EXTRACT(metadata, "$.phonedata.SerialNumber")) = ?) AS uniqueCheck', { SerialNumber })
|
||||
if result == 0 then return SerialNumber end
|
||||
return QBCore.Player.CreateSerialNumber()
|
||||
end
|
||||
|
||||
PaycheckInterval() -- This starts the paycheck system
|
||||
Reference in New Issue
Block a user