Files
qb-core/client/events.lua
T
Kakarot 1cee09a394 Support partial player data updates
Add support for sending single-field player data updates to clients to reduce bandwidth. Added a new client event QBCore:Player:UpdatePlayerDataField that updates a single key on QBCore.PlayerData. Modified server QBCore.Player.CreatePlayer UpdatePlayerData to accept an optional key and value; when provided it triggers the new per-field client event, otherwise it falls back to sending the full player data. Updated various player functions to call UpdatePlayerData with specific keys (job, gang, metadata, money, etc.) instead of always triggering a full sync. Files changed: client/events.lua, server/player.lua.
2026-04-20 19:18:48 -05:00

286 lines
9.1 KiB
Lua

-- Player load and unload handling
-- New method for checking if logged in across all scripts (optional)
-- if LocalPlayer.state['isLoggedIn'] then
RegisterNetEvent('QBCore:Client:OnPlayerLoaded', function()
ShutdownLoadingScreenNui()
LocalPlayer.state:set('isLoggedIn', true, false)
if not QBCore.Config.Server.PVP then return end
SetCanAttackFriendly(PlayerPedId(), true, false)
NetworkSetFriendlyFireOption(true)
end)
RegisterNetEvent('QBCore:Client:OnPlayerUnload', function()
LocalPlayer.state:set('isLoggedIn', false, false)
end)
RegisterNetEvent('QBCore:Client:PvpHasToggled', function(pvp_state)
SetCanAttackFriendly(PlayerPedId(), pvp_state, false)
NetworkSetFriendlyFireOption(pvp_state)
end)
-- Teleport Commands
RegisterNetEvent('QBCore:Command:TeleportToPlayer', function(coords)
local ped = PlayerPedId()
SetPedCoordsKeepVehicle(ped, coords.x, coords.y, coords.z)
end)
RegisterNetEvent('QBCore:Command:TeleportToCoords', function(x, y, z, h)
local ped = PlayerPedId()
SetPedCoordsKeepVehicle(ped, x, y, z)
SetEntityHeading(ped, h or GetEntityHeading(ped))
end)
RegisterNetEvent('QBCore:Command:GoToMarker', function()
local PlayerPedId = PlayerPedId
local GetEntityCoords = GetEntityCoords
local GetGroundZFor_3dCoord = GetGroundZFor_3dCoord
local blipMarker <const> = GetFirstBlipInfoId(8)
if not DoesBlipExist(blipMarker) then
QBCore.Functions.Notify(Lang:t('error.no_waypoint'), 'error', 5000)
return 'marker'
end
-- Fade screen to hide how clients get teleported.
DoScreenFadeOut(650)
while not IsScreenFadedOut() do
Wait(0)
end
local ped, coords <const> = PlayerPedId(), GetBlipInfoIdCoord(blipMarker)
local vehicle = GetVehiclePedIsIn(ped, false)
local oldCoords <const> = GetEntityCoords(ped)
-- Unpack coords instead of having to unpack them while iterating.
-- 825.0 seems to be the max a player can reach while 0.0 being the lowest.
local x, y, groundZ, Z_START = coords['x'], coords['y'], 850.0, 950.0
local found = false
if vehicle > 0 then
FreezeEntityPosition(vehicle, true)
else
FreezeEntityPosition(ped, true)
end
for i = Z_START, 0, -25.0 do
local z = i
if (i % 2) ~= 0 then
z = Z_START - i
end
NewLoadSceneStart(x, y, z, x, y, z, 50.0, 0)
local curTime = GetGameTimer()
while IsNetworkLoadingScene() do
if GetGameTimer() - curTime > 1000 then
break
end
Wait(0)
end
NewLoadSceneStop()
SetPedCoordsKeepVehicle(ped, x, y, z)
while not HasCollisionLoadedAroundEntity(ped) do
RequestCollisionAtCoord(x, y, z)
if GetGameTimer() - curTime > 1000 then
break
end
Wait(0)
end
-- Get ground coord. As mentioned in the natives, this only works if the client is in render distance.
found, groundZ = GetGroundZFor_3dCoord(x, y, z, false);
if found then
Wait(0)
SetPedCoordsKeepVehicle(ped, x, y, groundZ)
break
end
Wait(0)
end
-- Remove black screen once the loop has ended.
DoScreenFadeIn(650)
if vehicle > 0 then
FreezeEntityPosition(vehicle, false)
else
FreezeEntityPosition(ped, false)
end
if not found then
-- If we can't find the coords, set the coords to the old ones.
-- We don't unpack them before since they aren't in a loop and only called once.
SetPedCoordsKeepVehicle(ped, oldCoords['x'], oldCoords['y'], oldCoords['z'] - 1.0)
QBCore.Functions.Notify(Lang:t('error.tp_error'), 'error', 5000)
end
-- If Z coord was found, set coords in found coords.
SetPedCoordsKeepVehicle(ped, x, y, groundZ)
QBCore.Functions.Notify(Lang:t('success.teleported_waypoint'), 'success', 5000)
end)
-- Vehicle Commands
RegisterNetEvent('QBCore:Command:SpawnVehicle', function(vehName)
local ped = PlayerPedId()
local hash = joaat(vehName)
local veh = GetVehiclePedIsUsing(ped)
if not IsModelInCdimage(hash) then return end
RequestModel(hash)
while not HasModelLoaded(hash) do
Wait(0)
end
if IsPedInAnyVehicle(ped) then
SetEntityAsMissionEntity(veh, true, true)
DeleteVehicle(veh)
end
local vehicle = CreateVehicle(hash, GetEntityCoords(ped), GetEntityHeading(ped), true, false)
TaskWarpPedIntoVehicle(ped, vehicle, -1)
SetVehicleFuelLevel(vehicle, 100.0)
SetVehicleDirtLevel(vehicle, 0.0)
SetModelAsNoLongerNeeded(hash)
TriggerEvent('vehiclekeys:client:SetOwner', QBCore.Functions.GetPlate(vehicle))
end)
RegisterNetEvent('QBCore:Command:DeleteVehicle', function()
local ped = PlayerPedId()
local veh = GetVehiclePedIsUsing(ped)
if veh ~= 0 then
SetEntityAsMissionEntity(veh, true, true)
DeleteVehicle(veh)
else
local pcoords = GetEntityCoords(ped)
local vehicles = GetGamePool('CVehicle')
for _, v in pairs(vehicles) do
if #(pcoords - GetEntityCoords(v)) <= 5.0 then
SetEntityAsMissionEntity(v, true, true)
DeleteVehicle(v)
end
end
end
end)
RegisterNetEvent('QBCore:Client:VehicleInfo', function(info)
local plate = QBCore.Functions.GetPlate(info.vehicle)
local hasKeys = true
if GetResourceState('qb-vehiclekeys') == 'started' then
hasKeys = exports['qb-vehiclekeys']:HasKeys(plate)
end
local data = {
vehicle = info.vehicle,
seat = info.seat,
name = info.modelName,
plate = plate,
driver = GetPedInVehicleSeat(info.vehicle, -1),
inseat = GetPedInVehicleSeat(info.vehicle, info.seat),
haskeys = hasKeys
}
TriggerEvent('QBCore:Client:' .. info.event .. 'Vehicle', data)
end)
-- Other stuff
RegisterNetEvent('QBCore:Player:SetPlayerData', function(val)
QBCore.PlayerData = val
end)
RegisterNetEvent('QBCore:Player:UpdatePlayerDataField', function(key, val)
if QBCore.PlayerData and key then
QBCore.PlayerData[key] = val
end
end)
RegisterNetEvent('QBCore:Player:UpdatePlayerData', function()
TriggerServerEvent('QBCore:UpdatePlayer')
end)
RegisterNetEvent('QBCore:Notify', function(text, type, length, icon)
QBCore.Functions.Notify(text, type, length, icon)
end)
-- This event is exploitable and should not be used. It has been deprecated, and will be removed soon.
RegisterNetEvent('QBCore:Client:UseItem', function(item)
QBCore.Debug(string.format('%s triggered QBCore:Client: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(), GetPlayerServerId(PlayerId())))
QBCore.Debug(item)
end)
RegisterNUICallback('getNotifyConfig', function(_, cb)
cb(QBCore.Config.Notify)
end)
-- Callback Events --
-- Client Callback
RegisterNetEvent('QBCore:Client:TriggerClientCallback', function(name, ...)
if not QBCore.ClientCallbacks[name] then return end
QBCore.ClientCallbacks[name](function(...)
TriggerServerEvent('QBCore:Server:TriggerClientCallback', name, ...)
end, ...)
end)
-- Server Callback
RegisterNetEvent('QBCore:Client:TriggerCallback', function(name, ...)
if QBCore.ServerCallbacks[name] then
QBCore.ServerCallbacks[name].promise:resolve(...)
if QBCore.ServerCallbacks[name].callback then
QBCore.ServerCallbacks[name].callback(...)
end
QBCore.ServerCallbacks[name] = nil
end
end)
-- Me command
local function Draw3DText(coords, str)
local onScreen, worldX, worldY = World3dToScreen2d(coords.x, coords.y, coords.z)
local camCoords = GetGameplayCamCoord()
local scale = 200 / (GetGameplayCamFov() * #(camCoords - coords))
if onScreen then
SetTextScale(1.0, 0.5 * scale)
SetTextFont(4)
SetTextColour(255, 255, 255, 255)
SetTextEdge(2, 0, 0, 0, 150)
SetTextProportional(1)
SetTextOutline()
SetTextCentre(1)
BeginTextCommandDisplayText('STRING')
AddTextComponentSubstringPlayerName(str)
EndTextCommandDisplayText(worldX, worldY)
end
end
RegisterNetEvent('QBCore:Command:ShowMe3D', function(senderId, msg)
local sender = GetPlayerFromServerId(senderId)
CreateThread(function()
local displayTime = 5000 + GetGameTimer()
while displayTime > GetGameTimer() do
local targetPed = GetPlayerPed(sender)
local tCoords = GetEntityCoords(targetPed)
Draw3DText(tCoords, msg)
Wait(0)
end
end)
end)
-- Listen to Shared being updated
RegisterNetEvent('QBCore:Client:OnSharedUpdate', function(tableName, key, value)
QBCore.Shared[tableName][key] = value
TriggerEvent('QBCore:Client:UpdateObject')
end)
RegisterNetEvent('QBCore:Client:OnSharedUpdateMultiple', function(tableName, values)
for key, value in pairs(values) do
QBCore.Shared[tableName][key] = value
end
TriggerEvent('QBCore:Client:UpdateObject')
end)
RegisterNetEvent('QBCore:Client:SharedUpdate', function(table)
QBCore.Shared = table
end)