From 297a01e9aec0367b4b21639464af6be5e3bdd6a1 Mon Sep 17 00:00:00 2001 From: Linden <65407488+thelindat@users.noreply.github.com> Date: Thu, 10 Mar 2022 00:56:50 +1100 Subject: [PATCH 1/2] feat(esx/server): onesync entity spawning and iterators --- [esx]/es_extended/fxmanifest.lua | 2 + [esx]/es_extended/server/onesync.lua | 203 +++++++++++++++++++++++++++ 2 files changed, 205 insertions(+) create mode 100644 [esx]/es_extended/server/onesync.lua diff --git a/[esx]/es_extended/fxmanifest.lua b/[esx]/es_extended/fxmanifest.lua index baf5c145..be327f6f 100644 --- a/[esx]/es_extended/fxmanifest.lua +++ b/[esx]/es_extended/fxmanifest.lua @@ -5,6 +5,7 @@ game 'gta5' description 'ES Extended' version '1.5.0' +lua54 'yes' shared_scripts { 'locale.lua', @@ -20,6 +21,7 @@ server_scripts { 'server/common.lua', 'server/classes/player.lua', 'server/functions.lua', + 'server/onesync.lua', 'server/paycheck.lua', 'server/main.lua', 'server/commands.lua', diff --git a/[esx]/es_extended/server/onesync.lua b/[esx]/es_extended/server/onesync.lua new file mode 100644 index 00000000..49ea47fc --- /dev/null +++ b/[esx]/es_extended/server/onesync.lua @@ -0,0 +1,203 @@ +ESX.OneSync = {} + +---@class vector3 +---@field x number +---@field y number +---@field z number + +local function getNearbyPlayers(source, closest, distance, ignore) + local result = {} + local count = 0 + if not distance then distance = 100 end + if type(source) == 'number' then + source = GetPlayerPed(source) + + if not source then + error("Received invalid first argument (source); should be playerId or vector3 coordinates") + end + + source = GetEntityCoords(GetPlayerPed(source)) + end + + for _, xPlayer in pairs(ESX.Players) do + if not ignore or not ignore[xPlayer.source] then + local entity = GetPlayerPed(xPlayer.source) + local coords = GetEntityCoords(entity) + + if not closest then + local dist = #(source - coords) + if dist <= distance then + count += 1 + result[count] = {id = xPlayer.source, ped = entity, coords = coords, dist = dist} + end + else + local dist = #(source - coords) + if dist <= (result.dist or distance) then + result = {id = xPlayer.source, ped = entity, coords = coords, dist = dist} + end + end + end + end + + return result +end + +---@param source vector3|number playerId or vector3 coordinates +---@param maxDistance number +---@param ignore table playerIds to ignore, where the key is playerId and value is true +function ESX.OneSync.GetPlayersInArea(source, maxDistance, ignore) + return getNearbyPlayers(source, false, maxDistance, ignore) +end + +---@param source vector3|number playerId or vector3 coordinates +---@param maxDistance number +---@param ignore table playerIds to ignore, where the key is playerId and value is true +function ESX.OneSync.GetClosestPlayer(source, maxDistance, ignore) + return getNearbyPlayers(source, true, maxDistance, ignore) +end + +---@param model number|string +---@param coords vector3|table +---@param heading number +---@param cb function +function ESX.OneSync.SpawnVehicle(model, coords, heading, cb) + if type(model) == 'string' then model = GetHashKey(model) end + CreateThread(function() + local entity = Citizen.InvokeNative(`CREATE_AUTOMOBILE`, model, coords.x, coords.y, coords.z, heading) + while not DoesEntityExist(entity) do Wait(50) end + + -- Sometimes peds can spawn in the vehicle + local ped = GetPedInVehicleSeat(entity, -1) + if ped > 0 then + for i = -1, 6 do + ped = GetPedInVehicleSeat(entity, i) + local popType = GetEntityPopulationType(ped) + if popType <= 5 or popType >= 1 then + DeleteEntity(ped) + end + end + end + + cb(entity) + end) +end + +---@param model number|string +---@param coords vector3|table +---@param heading number +---@param cb function +function ESX.OneSync.SpawnObject(model, coords, heading, cb) + if type(model) == 'string' then model = GetHashKey(model) end + CreateThread(function() + local entity = CreateObject(model, coords, true, true) + while not DoesEntityExist(entity) do Wait(50) end + SetEntityHeading(entity, heading) + cb(entity) + end) +end + +---@param model number|string +---@param coords vector3|table +---@param heading number +---@param cb function +function ESX.OneSync.SpawnPed(model, coords, heading, cb) + if type(model) == 'string' then model = GetHashKey(model) end + CreateThread(function() + local entity = CreatePed(0, model, coords.x, coords.y, coords.z, heading, true, true) + while not DoesEntityExist(entity) do Wait(50) end + cb(entity) + end) +end + +---@param model number|string +---@param vehicle number entityId +---@param seat number +---@param cb function +function ESX.OneSync.SpawnPedInVehicle(model, vehicle, seat, cb) + if type(model) == 'string' then model = GetHashKey(model) end + CreateThread(function() + local entity = CreatePedInsideVehicle(vehicle, 1, model, seat, true, true) + while not DoesEntityExist(entity) do Wait(50) end + cb(entity) + end) +end + +local function getNearbyEntities(entities, coords, modelFilter, maxDistance, isPed) + local nearbyEntities = {} + coords = type(coords) == 'number' and GetEntityCoords(GetPlayerPed(coords)) or vector3(coords.x, coords.y, coords.z) + for _, entity in pairs(entities) do + if not isPed or (isPed and not IsPedAPlayer(entity)) then + if not modelFilter or modelFilter[GetEntityModel(entity)] then + local entityCoords = GetEntityCoords(entity) + if not maxDistance or #(coords - entityCoords) <= maxDistance then + nearbyEntities[#nearbyEntities+1] = {entity=entity, coords=entityCoords} + end + end + end + end + + return nearbyEntities +end + +---@param coords vector3 +---@param maxDistance number +---@param modelFilter table models to ignore, where the key is the model hash and the value is true +---@return table +function ESX.OneSync.GetPedsInArea(coords, maxDistance, modelFilter) + return getNearbyEntities(GetAllPeds(), coords, modelFilter, maxDistance, true) +end + +---@param coords vector3 +---@param maxDistance number +---@param modelFilter table models to ignore, where the key is the model hash and the value is true +---@return table +function ESX.OneSync.GetObjectsInArea(coords, maxDistance, modelFilter) + return getNearbyEntities(GetAllObjects(), coords, modelFilter, maxDistance) +end + +---@param coords vector3 +---@param maxDistance number +---@param modelFilter table models to ignore, where the key is the model hash and the value is true +---@return table +function ESX.OneSync.GetVehiclesInArea(coords, maxDistance, modelFilter) + return getNearbyEntities(GetAllVehicles(), coords, modelFilter, maxDistance) +end + +local function getClosestEntity(entities, coords, modelFilter, isPed) + local distance, closestEntity, closestCoords = maxDistance or 100, nil, nil + coords = type(coords) == 'number' and GetEntityCoords(GetPlayerPed(coords)) or vector3(coords.x, coords.y, coords.z) + + for _, entity in pairs(entities) do + if not isPed or (isPed and not IsPedAPlayer(entity)) then + if not modelFilter or modelFilter[GetEntityModel(entity)] then + local entityCoords = GetEntityCoords(entity) + local dist = #(coords - entityCoords) + if dist < distance then + closestEntity, distance, closestCoords = entity, dist, entityCoords + end + end + end + end + return closestEntity, distance, closestCoords +end + +---@param coords vector3 +---@param modelFilter table models to ignore, where the key is the model hash and the value is true +---@return number entityId, number distance, vector3 coords +function ESX.OneSync.GetClosestPed(coords, modelFilter) + return getClosestEntity(GetAllPeds(), coords, modelFilter, true) +end + +---@param coords vector3 +---@param modelFilter table models to ignore, where the key is the model hash and the value is true +---@return number entityId, number distance, vector3 coords +function ESX.OneSync.GetClosestObject(coords, modelFilter) + return getClosestEntity(GetAllObjects(), coords, modelFilter) +end + +---@param coords vector3 +---@param modelFilter table models to ignore, where the key is the model hash and the value is true +---@return number entityId, number distance, vector3 coords +function ESX.OneSync.GetClosestVehicle(coords, modelFilter) + return getClosestEntity(GetAllVehicles(), coords, modelFilter) +end From 771a4509bdd0f77ffa61d6b678f51a818e4da91e Mon Sep 17 00:00:00 2001 From: Linden <65407488+thelindat@users.noreply.github.com> Date: Fri, 11 Mar 2022 02:40:20 +1100 Subject: [PATCH 2/2] refactor: remove unneccessary ESX.GetPlayerData calls es_extended/imports.lua already syncs these values with an event --- [esx]/esx_identity/client/main.lua | 2 +- [esx_addons]/esx_accessories/client/main.lua | 2 +- [esx_addons]/esx_ambulancejob/client/job.lua | 6 +++--- [esx_addons]/esx_animations/client/main.lua | 4 ++-- [esx_addons]/esx_property/client/main.lua | 6 +++--- [esx_addons]/esx_taxijob/client/main.lua | 4 ++-- 6 files changed, 12 insertions(+), 12 deletions(-) diff --git a/[esx]/esx_identity/client/main.lua b/[esx]/esx_identity/client/main.lua index 097815b8..4a2df13c 100644 --- a/[esx]/esx_identity/client/main.lua +++ b/[esx]/esx_identity/client/main.lua @@ -38,7 +38,7 @@ if not Config.UseDeferrals then AddEventHandler('esx_identity:showRegisterIdentity', function() TriggerEvent('esx_skin:resetFirstSpawn') - if not ESX.GetPlayerData().dead then + if not ESX.PlayerData.dead then EnableGui(true) end end) diff --git a/[esx_addons]/esx_accessories/client/main.lua b/[esx_addons]/esx_accessories/client/main.lua index 59f5f774..126f09f3 100644 --- a/[esx_addons]/esx_accessories/client/main.lua +++ b/[esx_addons]/esx_accessories/client/main.lua @@ -229,7 +229,7 @@ end) if Config.EnableControls then RegisterCommand("accessory", function(src) - if not ESX.GetPlayerData().dead then + if not ESX.PlayerData.dead then OpenAccessoryMenu() end end) diff --git a/[esx_addons]/esx_ambulancejob/client/job.lua b/[esx_addons]/esx_ambulancejob/client/job.lua index 98034580..005e1730 100644 --- a/[esx_addons]/esx_ambulancejob/client/job.lua +++ b/[esx_addons]/esx_ambulancejob/client/job.lua @@ -6,7 +6,7 @@ isInShopMenu = false function OpenAmbulanceActionsMenu() local elements = {{label = _U('cloakroom'), value = 'cloakroom'}} - if Config.EnablePlayerManagement and ESX.GetPlayerData().job.grade_name == 'boss' then + if Config.EnablePlayerManagement and ESX.PlayerData.job.grade_name == 'boss' then table.insert(elements, {label = _U('boss_actions'), value = 'boss_actions'}) end @@ -184,7 +184,7 @@ CreateThread(function() while true do local sleep = 1500 - if ESX.GetPlayerData().job and ESX.GetPlayerData().job.name == 'ambulance' then + if ESX.PlayerData.job and ESX.PlayerData.job.name == 'ambulance' then local playerCoords = GetEntityCoords(PlayerPedId()) local isInMarker, hasExited = false, false local currentHospital, currentPart, currentPartNum @@ -373,7 +373,7 @@ CreateThread(function() end) RegisterCommand("ambulance", function(src) - if ESX.GetPlayerData().job and ESX.GetPlayerData().job.name == 'ambulance' and not ESX.GetPlayerData().dead then + if ESX.PlayerData.job and ESX.PlayerData.job.name == 'ambulance' and not ESX.PlayerData.dead then OpenMobileAmbulanceActionsMenu() end end) diff --git a/[esx_addons]/esx_animations/client/main.lua b/[esx_addons]/esx_animations/client/main.lua index eced6445..49d7531d 100644 --- a/[esx_addons]/esx_animations/client/main.lua +++ b/[esx_addons]/esx_animations/client/main.lua @@ -78,13 +78,13 @@ end -- Key Controls RegisterCommand('animmenu', function() - if not ESX.GetPlayerData().dead then + if not ESX.PlayerData.dead then OpenAnimationsMenu() end end, false) RegisterCommand('cleartasks', function() - if not ESX.GetPlayerData().dead then + if not ESX.PlayerData.dead then ClearPedTasks(PlayerPedId()) end end, false) diff --git a/[esx_addons]/esx_property/client/main.lua b/[esx_addons]/esx_property/client/main.lua index 0dbdadb0..93ba3f6a 100644 --- a/[esx_addons]/esx_property/client/main.lua +++ b/[esx_addons]/esx_property/client/main.lua @@ -253,7 +253,7 @@ function OpenPropertyMenu(property) menu.close() if data.current.value == 'enter' then - TriggerEvent('instance:create', 'property', {property = property.name, owner = ESX.GetPlayerData().identifier}) + TriggerEvent('instance:create', 'property', {property = property.name, owner = ESX.PlayerData.identifier}) elseif data.current.value == 'leave' then TriggerServerEvent('esx_property:removeOwnedProperty', property.name) elseif data.current.value == 'buy' then @@ -329,7 +329,7 @@ function OpenGatewayOwnedPropertiesMenu(property) menu2.close() if data2.current.value == 'enter' then - TriggerEvent('instance:create', 'property', {property = data.current.value, owner = ESX.GetPlayerData().identifier}) + TriggerEvent('instance:create', 'property', {property = data.current.value, owner = ESX.PlayerData.identifier}) ESX.UI.Menu.CloseAll() elseif data2.current.value == 'leave' then TriggerServerEvent('esx_property:removeOwnedProperty', data.current.value) @@ -690,7 +690,7 @@ AddEventHandler('esx:onPlayerSpawn', function() end end - TriggerEvent('instance:create', 'property', {property = propertyName, owner = ESX.GetPlayerData().identifier}) + TriggerEvent('instance:create', 'property', {property = propertyName, owner = ESX.PlayerData.identifier}) end end end) diff --git a/[esx_addons]/esx_taxijob/client/main.lua b/[esx_addons]/esx_taxijob/client/main.lua index ff7c4571..d2bb1bf1 100644 --- a/[esx_addons]/esx_taxijob/client/main.lua +++ b/[esx_addons]/esx_taxijob/client/main.lua @@ -720,7 +720,7 @@ CreateThread(function() while true do Wait(0) - if CurrentAction and not ESX.GetPlayerData().dead then + if CurrentAction and not ESX.PlayerData.dead then ESX.ShowHelpNotification(CurrentActionMsg) if IsControlJustReleased(0, 38) and ESX.PlayerData.job and ESX.PlayerData.job.name == 'taxi' then @@ -740,7 +740,7 @@ CreateThread(function() end end) RegisterCommand('taximenu', function() - if not ESX.GetPlayerData().dead and Config.EnablePlayerManagement and ESX.PlayerData.job and ESX.PlayerData.job.name == 'taxi' then + if not ESX.PlayerData.dead and Config.EnablePlayerManagement and ESX.PlayerData.job and ESX.PlayerData.job.name == 'taxi' then OpenMobileTaxiActionsMenu() end end, false)