[Release] esx-ecobottles, retrieve bottles, sell bottles

do a pull request and either i could make it configurable what items you could have, but do an pr and see if i can make it better or i just merge it. :slight_smile:

Fantastic script, only issue is that it is easily abusable. Find to trash cans, push them close together, run between them and get infinite bottles. Very hard to balance around this.

Is there a same script but LUA?

This is lua?

Ye, this is in lua?

Where can I edit esx_jobs so that you donā€™t need the job from the job center to start working like your script?

What? This is not associated with esx_jobs.:joy:

Yes but do you know how I can make for example the lumberjack job working without taking the job in the job center?

Whitelist it and set the job on you??

No I mean that I can do for example the miner or lumberjack job with for example the police job.

I only want to knok how I can do that the job blips are shown on the map all the time and I can do jobs like miner, slaughter or lumberjack as a employed people.

Um hi, I added this to my server and put the sql in my data base and its not working. Can you tell me anything i could have done wrong?

Update

  • Major performance fix.
  • Fixed formatting.
  • Fixed configurable things in the config.lua
1 Like

I hope i can help improve this incredible nice script.
Feel free to comment if my additions are welcome.

Below are allmost all trashcans extracted from all props available in the game.
Please add this into the ā€œconfig.luaā€ of esx-ecobottles:

Config.BinsAvailable = {
	"v_serv_tc_bin1_",
	"v_serv_tc_bin2_",
	"prop_cs_bin_02",
	"prop_cs_bin_03",
	"prop_cs_rub_binbag_01",
	"prop_fbibombbin",
	"prop_ld_binbag_01",
	"prop_ld_rub_binbag_01",
	"prop_rub_binbag_sd_01",
	"prop_rub_binbag_sd_02",
	"prop_cs_street_binbag_01",
	"prop_snow_bin_01",
	"prop_snow_bin_02",
	"p_rub_binbag_test",
	"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",
	"prop_gas_smallbin01",
	"prop_bin_01a",
	"prop_bin_02a",
	"prop_bin_03a",
	"prop_bin_04a",
	"prop_bin_05a",
	"prop_bin_06a",
	"prop_bin_07a",
	"prop_bin_07b",
	"prop_bin_07c",
	"prop_bin_07d",
	"prop_bin_08a",
	"prop_bin_08open",
	"prop_bin_09a",
	"prop_bin_10a",
	"prop_bin_10b",
	"prop_bin_11a",
	"prop_bin_11b",
	"prop_bin_12a",
	"prop_bin_13a",
	"prop_bin_14a",
	"prop_bin_14b",
	"prop_bin_beach_01a",
	"prop_bin_beach_01d",
	"prop_bin_delpiero",
	"prop_bin_delpiero_b",
	"prop_recyclebin_01a",
	"prop_recyclebin_02_c",
	"prop_recyclebin_02_d",
	"prop_recyclebin_02a",
	"prop_recyclebin_02b",
	"prop_recyclebin_03_a",
	"prop_recyclebin_04_a",
	"prop_recyclebin_04_b",
	"prop_recyclebin_05_a",
	"zprop_bin_01a_old"
}
2 Likes

Another hopefull contribution, since the trashcan list is long and I noticed it lags on the server. With my little fresh gained knowledge of LUA scripting, Iā€™ve altered the script to be far more efficient and never takes framerate hits anymore (which was over 25 fps):

Below is the client side main.lua script and only the part to optimize.
Please use it in the next update if your tests also give better performance.

Note: my optimization is that by using only the player coords and one entity coords instead of checking the whole list every update cycle, the fps gain is huge. Before my update I noticed FiveM warnings about >25fps drops and after no fps drops.

Citizen.CreateThread(function()
	Citizen.Wait(100)
	while true do
		local playerPed = PlayerPedId()
		local playerCoords = GetEntityCoords(playerPed)
		local entity, entityDst = ESX.Game.GetClosestObject(Config.BinsAvailable)
		local binCoords = GetEntityCoords(entity)
		if DoesEntityExist(entity) then
			while GetDistanceBetweenCoords(playerCoords,binCoords) <= 1.0 do
				binCoords = GetEntityCoords(entity)
				playerCoords = GetEntityCoords(playerPed)
				ESX.Game.Utils.DrawText3D(binCoords + vector3(0.0, 0.0, 0.5), "[~g~E~s~] Search Trashbin", 0.4)
				if IsControlJustReleased(0, 38) then
					if not cachedBins[entity] then
						cachedBins[entity] = true
						OpenTrashCan()
					else
						ESX.ShowNotification("You've already searched this bin!")
					end
				end
				Citizen.Wait(0)
			end
		end
		Citizen.Wait(1000)
	end
end)
6 Likes

Another note:
After my just posted optimization and some ingame testing on my server, I noticed the script now remembers a lot of previous searched trashbins. So exploiting the script by pulling a bunch of trashbins together and hop from one to a previous one does not work anymore :slight_smile:

All reactions are welcome and I hope I can be of any help.

Can I add tools before work?

thank you very much probe the code you put and really there is a very good improvement in both performance and fuides, the eco bottle came to a point that with 3-2 people reach 4-6ms

now there are estalas 0.27 -0.50

a way to implement that apart from the fact that ā€œbottleā€ comes out when you search in a container, you also get a ā€œweapon_bottleā€?

iā€™m stuck in the same, I wish to add WEAPON_BOTTLE with

GiveWeaponToPed(GetPlayerPed(-1), GetHashKey("WEAPON_BOTTLE"), false, true)

but when it comes to the math, it throw me this error:

Error running system event handling function for resource esx-ecobottles: citizen:/scripting/lua/scheduler.lua:41: Failed to execute thread: @esx-ecobottles/server/main.lua:34: attempt to call a nil value (global 'PlayerPedId')
stack traceback:
        @esx-ecobottles/server/main.lua:34: in upvalue 'handler'
        citizen:/scripting/lua/scheduler.lua:219: in function <citizen:/scripting/lua/scheduler.lua:218>
stack traceback:
        [C]: in function 'error'
        citizen:/scripting/lua/scheduler.lua:41: in field 'CreateThreadNow'
        citizen:/scripting/lua/scheduler.lua:218: in function <citizen:/scripting/lua/scheduler.lua:182>

This is my client.lua -->

ESX                           = nil

local cachedBins = {}

Citizen.CreateThread(function ()
    while ESX == nil do
        TriggerEvent('esx:getSharedObject', function(obj) 
            ESX = obj 
        end)

        Citizen.Wait(5)
    end
end)

Citizen.CreateThread(function()
    Citizen.Wait(100)

    for locationIndex = 1, #Config.SellBottleLocations do
        local locationPos = Config.SellBottleLocations[locationIndex]

        local blip = AddBlipForCoord(locationPos)

        SetBlipSprite (blip, 409)
        SetBlipDisplay(blip, 4)
        SetBlipScale  (blip, 0.8)
        SetBlipColour (blip, 48)
        SetBlipAsShortRange(blip, true)

        BeginTextCommandSetBlipName("STRING")
        AddTextComponentString("Vender Botellas Vacias")
        EndTextCommandSetBlipName(blip)
    end

    while true do
        local sleepThread = 500

        local ped = PlayerPedId()
        local pedCoords = GetEntityCoords(ped)

        for locationIndex = 1, #Config.SellBottleLocations do
            local locationPos = Config.SellBottleLocations[locationIndex]

            local dstCheck = GetDistanceBetweenCoords(pedCoords, locationPos, true)

            if dstCheck <= 5.0 then
                sleepThread = 5

                local text = "Vender Botellas Vacias"

                if dstCheck <= 1.5 then
                    text = "[~g~E~s~] " .. text

                    if IsControlJustReleased(0, 38) then
                        TriggerServerEvent("esx-ecobottles:sellBottles")
                    end
                end
                
                ESX.Game.Utils.DrawText3D(locationPos, text, 0.8)
            end
        end

        Citizen.Wait(sleepThread)
    end
end)



Citizen.CreateThread(function()
	Citizen.Wait(100)
	while true do
		local playerPed = PlayerPedId()
		local playerCoords = GetEntityCoords(playerPed)
		local entity, entityDst = ESX.Game.GetClosestObject(Config.BinsAvailable)
		local binCoords = GetEntityCoords(entity)
		if DoesEntityExist(entity) then
			while GetDistanceBetweenCoords(playerCoords,binCoords) <= 2.0 do
				binCoords = GetEntityCoords(entity)
				playerCoords = GetEntityCoords(playerPed)
				ESX.Game.Utils.DrawText3D(binCoords + vector3(0.0, 0.0, 0.5), "[~g~E~s~] Revisar basura", 0.8)
				if IsControlJustReleased(0, 38) then
					if not cachedBins[entity] then
						cachedBins[entity] = true
						OpenTrashCan()
					else
						ESX.ShowNotification("~r~Ya revisaste esta basura!")
					end
				end
				Citizen.Wait(0)
			end
		end
		Citizen.Wait(1000)
	end
end)


         
-- Citizen.CreateThread(function()
    -- Citizen.Wait(100)

    -- while true do
        -- local sleepThread = 1000

        -- local entity, entityDst = ESX.Game.GetClosestObject(Config.BinsAvailable)

        -- if DoesEntityExist(entity) and entityDst <= 2.0 then
            -- sleepThread = 5

            -- local binCoords = GetEntityCoords(entity)

            -- ESX.Game.Utils.DrawText3D(binCoords + vector3(0.0, 0.0, 0.5), "[~g~E~s~] Revisar basura", 0.8)

            -- if IsControlJustReleased(0, 38) then
                -- if not cachedBins[entity] then
                    -- cachedBins[entity] = true

                    -- OpenTrashCan()
                -- else
                    -- ESX.ShowNotification("Ya revisaste esta basura!")
                -- end
            -- end
        -- end

        -- Citizen.Wait(sleepThread)
    -- end
-- end)

function OpenTrashCan()
    TaskStartScenarioInPlace(PlayerPedId(), "PROP_HUMAN_BUM_BIN", 0, true)

    Citizen.Wait(10000)

    TriggerServerEvent("esx-ecobottles:retrieveBottle")

    ClearPedTasks(PlayerPedId())
end

Server.lua ā€”>

local ESX = nil

TriggerEvent("esx:getSharedObject", function(obj) 
    ESX = obj 
end)

RegisterServerEvent("esx-ecobottles:sellBottles")
AddEventHandler("esx-ecobottles:sellBottles", function()
    local player = ESX.GetPlayerFromId(source)

    local currentBottles = player.getInventoryItem("bottle")["count"]
    
    if currentBottles > 0 then
        math.randomseed(os.time())
        local randomMoney = math.random((Config.BottleReward[1] or 10), (Config.BottleReward[2] or 40))

        player.removeInventoryItem("bottle", currentBottles)
        player.addMoney(randomMoney * currentBottles)

        TriggerClientEvent("esx:showNotification", source, ("Entregaste al local %s botellas y recibiste como pago $%s."):format(currentBottles, currentBottles * randomMoney))
    else
        TriggerClientEvent("esx:showNotification", source, "No tenes botellas vacias para entregarle al local.")
    end
end)

RegisterServerEvent("esx-ecobottles:retrieveBottle")
AddEventHandler("esx-ecobottles:retrieveBottle", function()
    local player = ESX.GetPlayerFromId(source)

    math.randomseed(os.time())
    local luck = math.random(0, 100)
    local randomBottle = math.random((Config.BottleRecieve[1] or 1), (Config.BottleRecieve[2] or 6))
	local randomBandage = math.random((Config.BandageRecieve[1] or 1), (Config.BandageRecieve[2] or 2))--
    --local weaponbottle = math.random ((Config.WeaponBottle[1] or 1), (Config.WeaponBottle[1] or 1)) -- 
	

	
    if luck >= 0 and luck <= 29 then

        TriggerClientEvent("esx:showNotification", source, "No habia nada interesante en la basura.")
		
	end

    if luck >= 30 and luck <= 35 then
		
		player.addInventoryItem("bandage", randomBandage)
		TriggerClientEvent("esx:showNotification", source, ("Encontraste x%s ~y~Vendaje!"):format(randomBandage))
	end
	

	if luck >= 36 and luck <= 42 then

		player.addInventoryItem("bandage", randomBandage)
		TriggerClientEvent("esx:showNotification", source, ("Encontraste x%s ~y~Vendaje!"):format(randomBandage))        
		player.addInventoryItem("bottle", randomBottle)
        TriggerClientEvent("esx:showNotification", source, ("Encontraste x%s ~g~Botellas vacia"):format(randomBottle))
	end
	
	--if luck >= 42 and luck <= 64 then 
		--local player = GetPlayerPed(-1)
		
	TriggerClientEvent("esx:showNotification", source, "No habia nada interesante en la basura.(BOTELLA ERROR)")
	--	TriggerClientEvent("esx:showNotification", source, ("Encontraste x%s ~o~Botella Partida! estĆ” afilada!"):format(weaponbottle))
	--end	
	
	if luck >= 65 and luck <= 100 then
        
		player.addInventoryItem("bottle", randomBottle)
        TriggerClientEvent("esx:showNotification", source, ("Encontraste x%s ~g~Botellas vacia"):format(randomBottle))
    
	end
end)