-- 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) player.Functions.Save() TriggerEvent('QBCore:Server:PlayerDropped', src) TriggerEvent('QBCore:Server:OnPlayerUnload', src) QBCore.Player_Buckets[player.PlayerData.license] = nil QBCore.PlayersByCitizenId[player.PlayerData.citizenid] = 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, ...) local ClientCallback = QBCore.ClientCallbacks[name .. source] if ClientCallback then ClientCallback.promise:resolve(...) if ClientCallback.callback then ClientCallback.callback(...) end QBCore.ClientCallbacks[name .. source] = 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 local updateCooldowns = {} RegisterNetEvent('QBCore:UpdatePlayer', function() local src = source local now = GetGameTimer() if updateCooldowns[src] and (now - updateCooldowns[src]) < 10000 then return end updateCooldowns[src] = now 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.PlayerData.metadata['hunger'] = newHunger Player.PlayerData.metadata['thirst'] = newThirst Player.Functions.UpdateClient('metadata', Player.PlayerData.metadata) 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) RegisterNetEvent('QBCore:Server:OnPlayerLoaded', function() local src = source if not QBCore.Players[src] then return end TriggerClientEvent('QBCore:Client:OnPlayerLoaded', src) end) -- Central server-side data change handler — re-fires legacy events for backward compat AddEventHandler('QBCore:Server:OnPlayerUpdated', function(src, key, val) if key == 'job' then TriggerEvent('QBCore:Server:OnJobUpdate', src, val) elseif key == 'gang' then TriggerEvent('QBCore:Server:OnGangUpdate', src, val) elseif key == 'all' then TriggerEvent('QBCore:Server:OnJobUpdate', src, val.job) TriggerEvent('QBCore:Server:OnGangUpdate', src, val.gang) end 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) -- 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(DoesEntityExist(veh) and NetworkGetNetworkIdFromEntity(veh) or nil) 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(DoesEntityExist(veh) and NetworkGetNetworkIdFromEntity(veh) or nil) 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)