FiveM resmon high ms: como encontrar e corrigir scripts lentos

Um recurso mostra high ms em resmon? Como ler resmon 1, por que Wait(0) loops custam tanto, e como dormir quando longe, cache do ped e usar ox_lib points e zones.

Você abre o resource monitor e um script mostra isso:

text
my_script        0.35 ms

Um script idle deve estar perto de zero. Um script que come um terço de um milissegundo, ou muito mais, em cada frame faz seu jogo stutterar, e os jogadores com computadores mais fracos sentem primeiro. Este guia mostra como ver qual recurso é o problema e as mudanças que o trazem para baixo.

Abra o resource monitor

No console F8 do jogo, digite:

text
resmon 1

Uma overlay mostra cada recurso do cliente com seu tempo de CPU (ms) por frame e sua memória. Digite resmon 0 para fechá-la. Verifique essas coisas:

  • Fica em pé, em um lugar quiet, e leia a lista. Os números que importam são os que ficam altos quando você não faz nada.
  • Olhe para quem está no topo. Um recurso que sobe apenas perto de seu próprio marker ou shop é normal. Um que é alto em todos os lugares não é.
  • Assista alguns segundos. Um único pico quando um script começa é inofensivo; um valor constante é o problema.

O ms é tempo no cliente. Performance do server é um tópico separado: veja server thread hitch warning.

Causa 1: um loop com Wait(0)

A razão mais comum para um valor alto é um loop que roda cada frame, o tempo todo:

lua
CreateThread(function()
    while true do
        Wait(0)
        local ped = PlayerPedId()
        local coords = GetEntityCoords(ped)
        local dist = #(coords - vec3(215.0, -810.0, 30.7))
        if dist < 3.0 then
            DrawText3D(215.0, -810.0, 30.7, 'Press E')
        end
    end
end)

Isso roda os natives 60 vezes por segundo, mesmo quando o jogador está no outro lado do mapa. A maioria do tempo a resposta é "nada a fazer", e aquele custo é desperdiçado.

Solução 1: durma quando você está longe

Deixe o loop dormir mais quando nada está perto, e roda cada frame apenas quando o jogador está perto:

lua
CreateThread(function()
    local target = vec3(215.0, -810.0, 30.7)
    while true do
        local sleep = 1000
        local coords = GetEntityCoords(PlayerPedId())
        local dist = #(coords - target)

        if dist < 10.0 then
            sleep = 0
            if dist < 3.0 then
                DrawText3D(target.x, target.y, target.z, 'Press E')
            end
        elseif dist < 50.0 then
            sleep = 250
        end

        Wait(sleep)
    end
end)

O loop checa uma vez por segundo quando você está longe, que custa quase nada, e roda cada frame apenas dentro da área de 10 metro onde desenha. Use #(a - b) com valores vec3 para a distância: é mais rápido que o native antigo GetDistanceBetweenCoords.

Solução 2: cache valores que você reutiliza

Chamar um native cada frame para pegar um valor que raramente muda é um desperdício. PlayerPedId() é o clássico. Armazene uma vez e atualize apenas quando pode mudar:

lua
local ped = PlayerPedId()

CreateThread(function()
    while true do
        Wait(500)
        ped = PlayerPedId()
    end
end)

Se você usa ox_lib, ele faz isso para você. cache.ped é mantido atualizado, e cache.vehicle e cache.serverId funcionam da mesma forma:

lua
local coords = GetEntityCoords(cache.ped)

lib.onCache deixa você reagir quando um valor em cache muda, sem checar em um loop.

Solução 3: pare de chamar natives cada frame

Verifique o corpo do loop e pergunte para cada linha: isso realmente tem que rodar cada frame? Mova o que não.

  • Drawing (texto, markers, sprites) tem que rodar cada frame, mas apenas enquanto é visível.
  • Lendo dados (job, dinheiro, inventory) não: leia em um evento, e mantenha em uma variável.
  • Procurando (GetClosestVehicle, GetGamePool, loops sobre todos os jogadores) é caro. Execute uma vez por segundo ou dois, não cada frame.
  • Não crie coisas em um loop: criar blips, text entries ou tabelas cada frame preenche memória e faz o garbage collector trabalhar.
lua
-- run once per second
local closest = nil
CreateThread(function()
    while true do
        closest = GetClosestVehicle(GetEntityCoords(cache.ped), 5.0, 0, 70)
        Wait(1000)
    end
end)

Solução 4: use ox_lib points e zones em vez de loops

A maioria dos loops "estou perto deste spot" não são necessários. ox_lib pode fazer o trabalho de distância para você, e apenas roda seu código quando importa.

Um point chama uma função quando você entra ou deixa um raio, e um cada frame apenas enquanto você está dentro:

lua
local point = lib.points.new({
    coords = vec3(215.0, -810.0, 30.7),
    distance = 10.0,
})

function point:onEnter()
    print('entered')
end

function point:onExit()
    print('left')
end

function point:nearby()
    DrawText3D(self.coords.x, self.coords.y, self.coords.z, 'Press E')
    if self.currentDistance < 2.0 and IsControlJustReleased(0, 38) then
        print('used')
    end
end

Zones fazem o mesmo para formas como uma esfera, uma box ou um polígono:

lua
local zone = lib.zones.sphere({
    coords = vec3(215.0, -810.0, 30.7),
    radius = 3.0,
    onEnter = function() print('in') end,
    onExit = function() print('out') end,
})

Para interação com entidades e spots, um recurso de target (ox_target, por exemplo) substitui o loop "press E" do mesmo jeito. Verifique a documentação do ox_lib para as opções exatas de cada um.

Verifique o resultado

Execute resmon 1 novamente. Um script consertado deve ficar perto de 0.00 ms quando você fica longe de seus spots, e suba apenas quando você está perto deles. Se ainda está alto, procure por um segundo loop no mesmo recurso: um Wait(0) frequentemente não é o único.

Atenção: não defina um sleep longo em um loop que lida com uma key press ou um drawing. Se você dorme 500 ms e o jogador pressiona a key, o script a perderá. Durma apenas quando você sabe que nada está acontecendo, e caia para Wait(0) quando algo está.

Checklist

Sintoma Solução
High ms quando idle Encontre o loop while true do Wait(0) e adicione um sleep baseado em distância
PlayerPedId() em cada frame Cache-o, ou use cache.ped de ox_lib
Verificações de distância em um loop Substitua com lib.points.new ou lib.zones
Procurando entidades cada frame Execute uma vez por segundo e mantenha o resultado
Lendo dados do jogador em um loop Leia no evento do framework e armazene
Key presses faltando depois de adicionar um sleep Use Wait(0) apenas enquanto o jogador está perto

Respostas rápidas

Qual é um bom valor de resmon para um script?

Um script que está idle deve ficar ao redor de 0.00 a 0.01 ms. Qualquer coisa que fica bem acima disso quando você não está usando tem um loop que funciona muito.

O que Wait(0) faz e por que é custoso?

Wait(0) roda o loop uma vez cada frame. A 60 frames por segundo são 60 runs por segundo, e qualquer native que você chama nele é chamado 60 vezes por segundo.

Preciso de ox_lib para corrigir high ms?

Não. As correções funcionam em Lua puro. ox_lib apenas as torna mais curtas, com cache.ped, lib.points e lib.zones.

Scripts sem esse problema

CCTV Security CamerasCâmeras posicionáveis, um tablet com várias telas ao vivo e fotos impressas como prova.Ver script →Advanced BoostingBoosting de veículos pelo tablet: contratos da classe D à S+, crews e fila ao vivo.Ver script →Arcade MachinesSete jogos de fliperama jogáveis em máquinas de verdade, com rankings e apostas.Ver script →

Continue lendo