I probably can’t go through the entire script for you, but little things I can help with…
-- Step 1. reduce the calls to GetHashKey, and use compilation time hashing
-- https://cookbook.fivem.net/2019/06/23/lua-support-for-compile-time-jenkins-hashes/
Config.GarbageObjects = {
`prop_rub_binbag_01`,
`prop_rub_binbag_01b`,
`prop_rub_binbag_03`,
`prop_rub_binbag_03b`,
`prop_rub_binbag_04`,
`prop_rub_binbag_05`,
`prop_rub_binbag_06`,
`prop_rub_binbag_08`,
}
-- Iterate through this loop using
for _, hash in ipairs(Config.GarbageObjects) do
-- Do something with the hash here
print('The hash in garbage is', hash)
end
So accounting for this, you’d end up with something like…
-- Step 1. reduce the calls to GetHashKey, and use compilation time hashing
-- https://cookbook.fivem.net/2019/06/23/lua-support-for-compile-time-jenkins-hashes/
Config.GarbageObjects = {
`prop_rub_binbag_01`,
`prop_rub_binbag_01b`,
`prop_rub_binbag_03`,
`prop_rub_binbag_03b`,
`prop_rub_binbag_04`,
`prop_rub_binbag_05`,
`prop_rub_binbag_06`,
`prop_rub_binbag_08`,
}
CreateThread(function()
while true do
local ped = PlayerPedId()
sleep = 1000
-- Check if ped is on foot before getting player data
if IsPedOnFoot(ped) then
local PlayerJob = QBCore.Functions.GetPlayerData().job
if PlayerJob.name == Config.GarbageCompany['job'] and PlayerJob.onduty then
local playerPos = GetEntityCoords(ped)
-- Updated iteration for garbage hashes
for _, garbageHash in ipairs(Config.GarbageObjects) do
-- Removed the GetHashKey every time the loop runs
local rubbishEntity = GetClosestObjectOfType(playerPos, 2.0, garbageHash, false, false, false)
if DoesEntityExist(rubbishEntity) then
local rubbishCoords = GetEntityCoords(rubbishEntity)
sleep = 5
if #(playerPos - rubbishCoords) <= 1.5 then
DrawText3D(rubbishCoords.x, rubbishCoords.y, rubbishCoords.z, '~g~E~w~ - Pickup Rubbish')
if IsControlJustReleased(0, 38) then
TriggerServerEvent("test-resource:server:deleteObject", rubbishEntity)
end
end
end
end
end
end
Wait(sleep)
end
end)
From best I can tell, your script will also attempt to draw text on the closest entity of every type if they’re in range. So if you have all 8 garbage types next to you, you’re drawing 8x pick up rubbish, and will delete all 8 at once if button is clicked?
If this is not intentional you’ll need to keep track of the closest entity and check if playerPos - rubbishCoords < currentDistance. 
If you want to find and interact only with a singular nearest object you can do something along the lines of…
---Finds a singular closest object from a list of object hashes
---@param playerCoords vector3
---@return integer
---@return vector3
---@return number
function FindNearestGarbageObject(playerCoords)
local closestEntity = nil
local closestCoords = nil
local closestDistance = nil
for _, hash in ipairs(Config.GarbageObjects) do
local entity = GetClosestObjectOfType(playerCoords, 2.0, hash, false, false, false)
if DoesEntityExist(entity) then
local coords = GetEntityCoords(entity)
local distance = #(playerCoords - coords)
if closestDistance == nil or distance < closestDistance then
closestEntity = entity
closestCoords = coords
closestDistance = distance
end
end
end
return closestEntity, closestCoords, closestDistance
end
Last thing from me you might consider is splitting the responsibilities into two separate loops.
- Update global variables for entity / coords for text / interaction (1000ms)
- Draw text & monitor button press when entity/coords are present
That means you consistently check your player’s position, and any objects that are around them, while not doing all the heavy checks in rapid succession just because you’re standing next to some garbage. And you can reset the globals after interacting with an object, to make the text instantly disappear if that’s a concern.