How do I find slow/unoptimized function/event?

Hi there everyone!

I’m using a resource I found on the forum here and I’ve learned that you should ask all questions concerning the resource in the topic and since there’s no support being given for it in the topic I figure it’s up to me to try to fix it. So here I am :slight_smile:

The resource works but after about 10 or 15 minutes, it begins to display a 6ms warning, which slowly over time begins to increase. It never goes away once it’s there. Sometimes it does decrease by an ms but overall will keep climbing.

So I wanted to ask how people who actually know how to code lua go about finding the inefficient portions of your code. Do you put something in each function or event to time it’s execution? Since the problem is something that takes a while to show up and then only slowly increases in degradation, it seems to me that it’s storing or stacking values that eventually begin to impact the client’s game(it’s all in the clientside script).

Any help on how you go about finding slow/inefficient functions or events would be greatly appreciated.

Thanks for your time!

bumping for some early morning love. If anyone can point me in the direction of find a problem function/event, I would be very grateful.

Thanks for your time!

Find something that is running often.

Reduce it.

Mainly these are in while true loops or for loops. If you post the scripts to a Git, that could help.

This depends on the resource itself, since any function may be poorly optimized, just by studying the resource itself, it is relative.

If you share the resource maybe we can help.

Hi there guys and thanks very much for your help!

This is the script that I’m trying to optimize. I’ve been trying different things and I just can’t pin down which part is causing the issue.

When running the resource, after about 30 minutes or so, players will get a 6ms warning. That will slowly climb. I’ve been on long enough to get it to 25 ms. All players online(joined the same time as me) were showing almost exact same ms warnings so it’s climbing at the same speed for everyone.

I think you are searching for this?

I could be wrong.

Thanks very much Yad, I did find that and I tried to implement the changes suggested that I understood but all changes either broke the script or caused it to perform poorly.

I tried changing the event tick wait from 0 to 10 but it just delays the issues.

AddEventHandler("onClientMapStart", function()
    Citizen.CreateThread(function()
        while true do
            Citizen.Wait(10)
            
			PopulatePedIndex()
            ResetIndexOnDeath()
            
            for k,v in pairs(pedindex) do
                if DoesEntityExist(k) then
					veh = GetVehiclePedIsIn(k, false)
					if not IsPedInVehicle(k, veh, true) then
						if IsEntityDead(k) then
							SpawnMoneyWithRandomValue(k,5,13)
							pedindex[k] = nil
							HighlightObject(k)
						end
					end
                end
            end
            
            for k,v in pairs(objval) do
                if DoesEntityExist(k) then
                    dist = DistanceBetweenCoords(PlayerPedId(-1), k)
                    if (dist.x < 0.4) and (dist.y < 0.4) and (dist.z < 1) then
                        TriggerServerEvent('getPaid', v.worth)
                        DeleteObject(k)
						PlaySoundFrontend(-1, "PICK_UP", "HUD_FRONTEND_DEFAULT_SOUNDSET")
                        objval[k] = nil
                    end
                    HighlightObject(k)
                end
            end
        end
    end)
end)

Since it’s taking some time for the ms warning to occur and it’s slowly climbing in ms, that would mean that I’m dealing with something that’s not unloading, like a variable, wouldn’t it? Something in one of the functions, no?

function HighlightObject(object)
    x, y, z = table.unpack(GetEntityCoords(object, true))
    SetDrawOrigin(x, y, z, 0)
    RequestStreamedTextureDict("helicopterhud", false)
    DrawSprite("helicopterhud", "hud_corner", -0.01, -0.01, 0.006, 0.006, 0.0, 255, 0, 0, 200)
    DrawSprite("helicopterhud", "hud_corner", 0.01, -0.01, 0.006, 0.006, 90.0, 255, 0, 0, 200)
    DrawSprite("helicopterhud", "hud_corner", -0.01, 0.01, 0.006, 0.006, 270.0, 255, 0, 0, 200)
    DrawSprite("helicopterhud", "hud_corner", 0.01, 0.01, 0.006, 0.006, 180.0, 255, 0, 0, 200)
    ClearDrawOrigin()
end

function DistanceBetweenCoords(ent1, ent2)
    local x1,y1,z1 = table.unpack(GetEntityCoords(ent1, true))
    local x2,y2,z2 = table.unpack(GetEntityCoords(ent2, true))
    local deltax = x1 - x2
    local deltay = y1 - y2
    local deltaz = y1 - y2
    
    dist = math.sqrt((deltax * deltax) + (deltay * deltay) + (deltaz * deltaz))
    xout = math.abs(deltax)
    yout = math.abs(deltay)
    zout = math.abs(deltaz)
    result = {distance = dist, x = xout, y = yout, z = zout}
    
    return result
end
    
function ResetIndexOnDeath()
    if IsEntityDead(GetPlayerPed(-1)) then
        for k,v in pairs(objval) do
            objval[k] = nil
        end
    end
end

function PopulatePedIndex()
    local handle, ped = FindFirstPed()
    local finished = false -- FindNextPed will turn the first variable to false when it fails to find another ped in the index
    repeat
        if not IsEntityDead(ped) then
                pedindex[ped] = {}
        end
        finished, ped = FindNextPed(handle) -- first param returns true while entities are found
    until not finished
    EndFindPed(handle)
end

function SpawnMoneyWithRandomValue(ped, lowlimit, upperlimit)
    value = math.random(lowlimit, upperlimit)
    money, quantity = MoneyVariance(value)
    
    x, y, z = table.unpack(GetEntityCoords(ped, true))
	z = z + 1.3

    i = 0
    while i < quantity do
        

        x2 = math.random() + math.random(-2,2)
        y2 = math.random() + math.random(-2,2)
	    z2 = math.random() + math.random(6,9)
		
        i = i + 1
        
        tempobject = CreateObject(GetCashHash((RoundNumber((money / quantity), 0))), x, y, z, true, false, true)
		SetActivateObjectPhysicsAsSoonAsItIsUnfrozen(tempobject, true)
		SetEntityDynamic(tempobject, true)
        ApplyForceToEntity(tempobject, 1, x2, y2, z2, 0.0, 3.0, 0.0, 0, 0, 1, 1, 0, 1)
        objval[tempobject] = { worth = (RoundNumber((money / quantity), 0)) }
    end
end

function RampTowardsPlayer(entity)
	local t = 0.0
	
	while t < 1.0 do
		Wait(25)
		t = t + 0.01
		vec3 = VectorLerp(GetEntityCoords(entity, true), GetEntityCoords(PlayerPedId(), true), t)
		vehicle = GetRandomVehicleInSphere(vec3,2.0,0,0)

		if DoesEntityExist(entity) and (vehicle < 2) then -- The reason we choose two is because sometimes it returns 1 and I don't know why. I assume it also returns 2 sometimes just incase.
			SetEntityCoords(entity, vec3)			
		elseif not DoesEntityExist(entity) then
			t = 1.0
		end
	end
end

function VectorLerp(vec1, vec2, t)
	vecOut = vec1 - (t * (vec1 - vec2))
	return vecOut
end

function GetCashHash(money)
    local propA = "prop_anim_cash_note"
    local propB = "prop_anim_cash_pile_01"
    local propC = "prop_cash_envelope_01"
    local propD = "prop_cash_pile_02" --smaller prop
    local propE = "prop_cash_pile_01" -- bigger wad of cash
    local propF = "prop_money_bag_01" 
    local model = 0
    
    if (money >= 0) then
        model = propA
    end
    if (money >= 20) then
        model = propB
    end
    if (money >= 100) then
        model = propC
    end    
    if (money >= 250) then
        model = propD
    end    
    if (money >= 500) then
        model = propE
    end    
    if (money >= 1500) then
        model = PropF
    end
   
    return GetHashKey(model)
end

function MoneyVariance(value)
    local RNG = math.random()
    local basevalue = value
    local multiplier = 1.0
    local quantity = math.random(5,6)
    
    
    if (RNG <= 0.75) then
        multiplier = 0.85
        quantity = math.random(2,4)
    end
    if (RNG <= 0.45) then
        multiplier = 1.1
        quantity = math.random(1,2)
    end
    if (RNG >= 0.35) then
        multiplier = 1.3
        quantity = math.random(1,2)
    end
    if (RNG >= 0.20) then
        multiplier = 1.6
        quantity = math.random(1,2)
    end
    if (RNG >= 0.04) then
        multiplier = 2.3
        quantity = math.random(1,2)
    end
    if (RNG >= 0.02) then
        multiplier = 4.0
        quantity = 1
    end
    if(RNG >= 0.009) then
        multiplier = 5.0
        quantity = math.random(1,3)
    end
    
    finalvalue = basevalue * multiplier
    return finalvalue, quantity
end


angleint = 0
function CapsuleCheckForNearbyPed(inputped)
    x, y, z = table.unpack(GetEntityCoords(inputped, true))
    flag = 12
    radius = 60
    Wait(7)
    for i = angleint, 72 do     
        angleint = angleint + 1
        AdjustAngleInt()
        
        local angle = math.rad(i * 5)

        local startX = (60.0 * math.cos(angle)) + x;
        local startY = (60.0 * math.sin(angle)) + y;
                    
        local endX = x - (startX - x)
        local endY = y - (startY - y)
        
        ray = StartShapeTestCapsule(startX,startY,z,endX,endY,z,radius,flag,inputped,7)
        _, _, _, _, result = GetShapeTestResult(ray)

        return result
    end
end

function AdjustAngleInt()    
    if angleint > 72 then
        angleint = 1
    end
end

function DetectNpcByAiming()
    local aiming = false
    local entity
    
    if IsPlayerFreeAiming(PlayerId()) then
        aiming, entity = GetEntityPlayerIsFreeAimingAt(PlayerId())
        if (aiming) then
            if IsEntityAPed(entity) then
                return entity
            end
        end
    end
end

function GetTableLength(temptable)
    local count = 0
    for _ in pairs(temptable) do
        count = count+1
    end
    
    return count
end

function RoundNumber(num, numDecimalPlaces)
    if numDecimalPlaces and numDecimalPlaces>0 then
        local mult = 10^numDecimalPlaces
        return math.floor(num * mult + 0.5) / mult
    end
    
    return math.floor(num + 0.5)
end

I’ve done some more testing and it seems that the resource will begin to show ms warnings even if I log into the server and don’t kill anyone so maybe I can narrow down the problematic function knowing that it’s occurring regardless of whether the resource has to deal with dead peds.

I think this is one of the primary functions that are being run all the time. Does someone see a variable that should be unloaded or something else in it that could be made more efficient?

angleint = 0
function CapsuleCheckForNearbyPed(inputped)
    x, y, z = table.unpack(GetEntityCoords(inputped, true))
    flag = 12
    radius = 60
    Wait(7)
    for i = angleint, 72 do     
        angleint = angleint + 1
        AdjustAngleInt()
        
        local angle = math.rad(i * 5)

        local startX = (60.0 * math.cos(angle)) + x;
        local startY = (60.0 * math.sin(angle)) + y;
                    
        local endX = x - (startX - x)
        local endY = y - (startY - y)
        
        ray = StartShapeTestCapsule(startX,startY,z,endX,endY,z,radius,flag,inputped,7)
        _, _, _, _, result = GetShapeTestResult(ray)

        return result
    end
end
1 Like