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] 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