Finding & using an object by hash instead of coords

So, I’ve been trying to make every ATM on the map usable by using the prop name instead of adding hundreds of coords to a table. It does function, but it’s a very resource intensive piece of code… I’ve tried many things, but I’m wondering if there’s some simple method or fix that I’m missing to optimise it.

local atms = {
    "prop_atm_01",
	"prop_atm_02",
	"prop_atm_03",
    "prop_fleeca_atm",
}

local function GiveATMOptions(location, heading)
	if (GetNetworkTime() - atmLastUsed ) >= atmCoolDown then
		_x, _y, _z = table.unpack(location)
		local head = heading
		--DrawMarker(26, _x, _y, _z+.1, 0.0, 0.0, 0.0, 0.0, 0.0, heading+180, 1.0, 1.0, 1.0, 0, 0, 255, 50, false, false, 2, false, nil, nil, false)
		Utils.DrawText3D("Press ~g~ENTER~s~ to use the ATM.", _x, _y, _z+1)
		if IsControlJustPressed(1,201) then
			local editOpen = true	
			DrawMissionText("How much would you like to withdraw?", 5000)
			DisplayOnscreenKeyboard(false, "FMMC_KEY_TIP8", "", "", "", "", "", 64)	
			while UpdateOnscreenKeyboard() == 0 or editOpen do
			  	if UpdateOnscreenKeyboard() == 1 then
			  		editOpen = false
			  		local amt = tonumber(GetOnscreenKeyboardResult())
					if amt > atmMaxWithdraw then
						amt = atmMaxWithdraw
						TriggerEvent("ShowInformationLeft", 5000, "Maxmimum you can withdraw is $<font color='#1bd602'>1500</font>")
					end
					TriggerServerEvent('ATM_withdraw', amt)
					atmLastUsed = tonumber(GetNetworkTime())
			  	end	
			  	if UpdateOnscreenKeyboard() == 2 then
			  		editOpen = false
			  	end
			  	Wait(5)
			end
		end
	else
		DisplayHelpText("You've recently used the ATM and have to wait!")
	end

end

Citizen.CreateThread(function()
	while true do
		Citizen.Wait(8)
		local playerPed = GetPlayerPed(-1)
        local playerCoords = GetEntityCoords(playerPed, true)
        for i = 1, #atms do
			local nearestatm = GetClosestObjectOfType(playerCoords, 1.0, GetHashKey(atms[i]), false)
            if DoesEntityExist(nearestatm) then
                local atmLocation = GetEntityCoords(nearestatm)
				local atmHead = GetEntityHeading(nearestatm)
				local distance = GetDistanceBetweenCoords(playerCoords.x, playerCoords.y, playerCoords.z, atmLocation.x, atmLocation.y, atmLocation.z, true)
				if distance < 2.0 then
					GiveATMOptions(atmLocation, atmHead)
				end
			end
		end
	end
end)

You could use GetClosestObjectOfType() in an other thread in which the delay would be higher than 8 (more like 2000). Do the same with the distance computation.

I don’t know if I’m clear. If you don’t understand I’ll show how to do that in the afternoon.

1 Like

Okay, I think I got it!

local atms = { 'prop_atm_01', 'prop_atm_02', 'prop_atm_03', 'prop_fleeca_atm'}

local function GiveATMOptions(location, heading)
	if (GetNetworkTime() - atmLastUsed ) >= atmCoolDown then
		_x, _y, _z = table.unpack(location)
		local head = heading
		--DrawMarker(26, _x, _y, _z+.1, 0.0, 0.0, 0.0, 0.0, 0.0, heading+180, 1.0, 1.0, 1.0, 0, 0, 255, 50, false, false, 2, false, nil, nil, false)
		Utils.DrawText3D("Press ~g~ENTER~s~ to use the ATM.", _x, _y, _z+1)
		if IsControlJustPressed(1,201) then
			local editOpen = true	
			DrawMissionText("How much would you like to withdraw?", 5000)
			DisplayOnscreenKeyboard(false, "FMMC_KEY_TIP8", "", "", "", "", "", 64)	
			while UpdateOnscreenKeyboard() == 0 or editOpen do
			  	if UpdateOnscreenKeyboard() == 1 then
			  		editOpen = false
			  		local amt = tonumber(GetOnscreenKeyboardResult())
					if amt > atmMaxWithdraw then
						amt = atmMaxWithdraw
						TriggerEvent("ShowInformationLeft", 5000, "Maxmimum you can withdraw is $<font color='#1bd602'>1500</font>")
					end
					TriggerServerEvent('ATM_withdraw', amt)
					atmLastUsed = tonumber(GetNetworkTime())
			  	end	
			  	if UpdateOnscreenKeyboard() == 2 then
			  		editOpen = false
			  	end
			  	Wait(5)
			end
		end
	else
		DisplayHelpText("You've recently used the ATM and have to wait!")
	end

end

Citizen.CreateThread(function()
	while true do
		Citizen.Wait(2000)
		local playerPed = GetPlayerPed(-1)
		local x,y,z = table.unpack(GetEntityCoords(playerPed, true))
		if not IsPlayerNearATM then
			for k,v in pairs(atms) do
				local ATM = GetClosestObjectOfType(x, y, z, 1.0, GetHashKey(v), false)
				   if DoesEntityExist(ATM) then
					currentATM = ATM
					ATMX, ATMY, ATMZ = table.unpack(GetOffsetFromEntityInWorldCoords(ATM, 0.0, -.85, 0.0))
					IsPlayerNearATM = true
				end
			end
		else
			if not DoesEntityExist(currentATM) then
				IsPlayerNearATM = false
			else
				if GetDistanceBetweenCoords(x,y,z, ATMX, ATMY, ATMZ, true) > 2.0 then
					IsPlayerNearATM = false
				end
			end
		end
	end
end)

Citizen.CreateThread(function()
	while true do
		Citizen.Wait(8)
		if IsPlayerNearATM then
            local atmLocation = GetEntityCoords(currentATM)
			local atmHead = GetEntityHeading(currentATM)
			GiveATMOptions(atmLocation, atmHead)
		end
	end
end)

If you see anything weird let me know :wink:

It looks good to me (even if your first thread seems a bit strange, it should work I guess) !

Appreciate the help, have a nice day!

1 Like