Shopping Cart
FiveM script Best practice Improve your resource performance Modding Tutorials

[Best practice] Improve your resource performance – Modding Tutorials

[ad_1]

FiveM Modding Tutorial

Abstract

Recently there has been a feature added to FiveM where slow resources will be shown as a warning for all the players. In this guide we will cover some of the basic steps you can perform to prevent the warning from showing up. The guide is mainly targeted to the developers or server owners who feel courageous :yum:

Is your resource running slow and you have tried everything in this guide? Please make a post here to we can further expand this guide with best practices and pin point the issues your script might have. Any other suggestions are much appreciated!

Background!

perf

Before we can solve the performance issue(s), it would be darn handy to know what, when and how the slow resource warning pops up, for anyone who hasn’t seen the warning message:

The message is comprised of 3 critical data points which you will definitely need in order to debug any issues you are having. The message is formatted as:

[resource] is taking [time] ms (or -[fps] FPS @ 60 Hz)

[resource] is the resource name of which resource is being slow, it directly correlates to the folder name in your resource/ directory of your server.

[time] is the time in milliseconds it took to execute the entire resource. Important to note that this is a continuous measurement, this is not a one time thing (i.e. loading in). The time is an average of 64 ticks, if the average of the 64 samples is greater than 5 ms, the warning message will be shown.

[fps] is the total amount of FPS that is being deducted by running this resource. Keep in mind this is on a 60 FPS basis.

Improving performance

Frequency

One of the most obvious but yet a lot of scripts do this, is the frequency the code is being run at. Often I see script using Citizen.Wait(0), this would mean any code inside that while loop would run every tick, which is bad for performance if there so happen to be expensive logic in there. To me this seems the #1 cause on why the warning message pops up. So here the rule of thumb:

  • Only run code that needs to be ran every tick, for example any native containing “ThisFrame” in their name. (there are obiviously more natives that need to be ran every tick).

  • Think about a reasonable interval for a piece of code to execute at, for example you don’t need to check 60 times per second to check if a player died, instead consider using 1 or 2 times per second to check such a thing.

  • Segregate any code that does not require to be ran every frame. You can use for instance a global variable(s) to influence the code that is being ran every tick (without executing the expensive code).

Example:

Intial code -> Runs at 119ms

Citizen.CreateThread(function()
    while(true) do
        if IsPedDeadOrDying(PlayerPedId()) then
            ShowHudComponentThisFrame(9) – street name
        end

        if IsPedInAnyVehicle(PlayerPedId(), true) then
            ShowHudComponentThisFrame(6) – vehicle name
        end
      Citizen.Wait(0)
    end
end)

Improved code -> Runs at 7ms

local isDead = false
local inVehicle = false

Citizen.CreateThread(function()
    while(true) do
        if isDead then
            ShowHudComponentThisFrame(9) – street name
        end

        if inVehicle then
            ShowHudComponentThisFrame(6) – vehicle name
        end
        
        Citizen.Wait(0)
    end
end)

Citizen.CreateThread(function()
    while(true) do
        isDead = IsPedDeadOrDying(PlayerPedId())
        inVehicle = IsPedInAnyVehicle(PlayerPedId(), true)
        Citizen.Wait(500)
    end
end)
the examples are run at 100.000x faster than normal

Natives

Natives are at the core of any script, but do keep in mind that natives are more expensive to call than pure LUA code. Especially when you have a hot path with a lot of natives to be ran, this will acrude the execution time of the natives and increase frame time by quite a bit. So here are the rules of thumb:

  • Think twice before putting (multiple) natives in some hot code path, because they will be slow :mascot:, use alternatives if possible.

  • Cache the result of a native instead of requesting them ad-hoc in a hot code path. A common indicator of wether you should cache something is when you use the same native two or more times in the same scope.

Example

Intial code -> Runs at 346ms

Citizen.CreateThread(function()
  while true do
    local armor = GetPedArmour(PlayerPedId())

    armor = armor + 1
    if armor > 100 then
    armor = 0
    end

    SetPedArmour(PlayerPedId(), armor)

    Citizen.Wait(0)
  end
end)

A slightly better solution -> Runs at 255ms

Citizen.CreateThread(function()
  local armor = GetPedArmour(PlayerPedId())

  while true do

    armor = armor + 1
    if armor > 100 then
        armor = 0
    end
  
    SetPedArmour(PlayerPedId(), armor)
    Citizen.Wait(0)
  end
end)

A even better solution -> Runs at 216 ms

Citizen.CreateThread(function()
  local player = PlayerPedId()
  local armor = GetPedArmour(player)

  while true do
    armor = armor + 1
    if armor > 100 then
    armor = 0
    end

    SetPedArmour(player, armor)

    Citizen.Wait(0)
  end
end)
the examples are run at 50.000x faster than normal

But the question here is; would we really want to set armor every tick? A longer delay might suffice!

Try to keep that in the back of your mind!

DRY

Keep it DRY! Or in other words, don’t repeat yourself. Not only is this a good programming practice, but it sure is handy for gaining performance as well. I suspect this is fairly common sense, but there are resource out there that still seem to have issues with this. :disappointed_relieved:

Keeping it DRY also applies to performance, because we do not want to compute what we already have computed, instead we want to take the result from the previous computation instead of recomputing it again, simple stuff! :slight_smile:

Example

local pedindex = {}

function SetWeaponDrops()
    local handle, ped = FindFirstPed()
    local finished = false
    repeat 
        if not IsEntityDead(ped) then
                pedindex[ped] = {}
        end
        finished, ped = FindNextPed(handle)
    until not finished
    EndFindPed(handle)

    for peds,_ in pairs(pedindex) do
        if peds ~= nil then
            SetPedDropsWeaponsWhenDead(peds, false) 
        end
    end
end

Citizen.CreateThread(function()
    while true do
        Citizen.Wait(0)
        SetWeaponDrops()
    end
end)

A better way of going about it would be:

function SetWeaponDrops()
    local handle, ped = FindFirstPed()
    local finished = false 

    repeat 
        if not IsEntityDead(ped) then
            SetPedDropsWeaponsWhenDead(ped, false) 
        end
        finished, ped = FindNextPed(handle)
    until not finished

    EndFindPed(handle)
end

Citizen.CreateThread(function()
    while true do
        SetWeaponDrops()
        Citizen.Wait(500)
    end
end)

Conclusion

Hopefully this guide will give you some insight on why your resource might have performance issues. Again, if you still experience performance issues, please let me know, i’d appreciate it!

Good luck!

[ad_2]

Original source: https://forum.cfx.re/t/best-practice-improve-your-resource-performance/105509

Leave a Reply
FiveM ESX Scripts

The best scripts and maps

Best support

Problems? We are there to help!

Wide range of products

We have a wide range of products

100% Secure Checkout

Stripe