FiveM resmon alto ms: cómo encontrar y reparar scripts lentos

¿Un recurso muestra ms alto en resmon? Cómo leer resmon 1, por qué los bucles Wait(0) cuestan tanto, y cómo dormir cuando estás lejos, cachear el ped y usar puntos y zonas de ox_lib.

Abres el monitor de recursos y un script muestra esto:

text
my_script        0.35 ms

Un script inactivo debe estar cerca de cero. Un script que come un tercio de un milisegundo, o mucho más, en cada frame hace que tu juego se entrecorte, y los jugadores con computadoras más débiles lo sienten primero. Esta guía muestra cómo ver qué recurso es el problema y los cambios que lo reducen.

Abre el monitor de recursos

En la consola F8 del juego, escribe:

text
resmon 1

Una superposición muestra cada recurso del cliente con su tiempo de CPU (ms) por frame y su memoria. Escribe resmon 0 para cerrarlo. Comprueba estas cosas:

  • Permanece quieto, en un lugar tranquilo, y lee la lista. Los números que importan son los que permanecen altos cuando no haces nada.
  • Mira quién está en la parte superior. Un recurso que solo sube cerca de su propio marcador o tienda es normal. Uno que es alto en todas partes no lo es.
  • Obsérvalo unos segundos. Un solo pico cuando un script se inicia es inofensivo; un valor constante es el problema.

El ms es tiempo en el cliente. El rendimiento del servidor es un tema separado: consulta advertencia de bloqueo de thread del servidor.

Causa 1: un bucle con Wait(0)

La razón más común para un valor alto es un bucle que se ejecuta cada frame, todo el tiempo:

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)

Esto ejecuta los nativos 60 veces por segundo, incluso cuando el jugador está del otro lado del mapa. La mayoría del tiempo la respuesta es «nada que hacer», y ese costo se desperdicia.

Solución 1: duerme cuando estés lejos

Deja que el bucle duerma más tiempo cuando nada está cerca, y solo se ejecute cada frame cuando el jugador esté cerca:

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)

El bucle comprueba una vez por segundo cuando estás lejos, que cuesta casi nada, y se ejecuta cada frame solo dentro del área de 10 metros donde dibuja. Usa #(a - b) con valores vec3 para la distancia: es más rápido que el nativo antiguo GetDistanceBetweenCoords.

Solución 2: cachea valores que reutilizas

Llamar a un nativo cada frame para obtener un valor que rara vez cambia es un desperdicio. PlayerPedId() es el clásico. Almacénalo una vez y actualízalo solo cuando pueda cambiar:

lua
local ped = PlayerPedId()

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

Si usas ox_lib, lo hace por ti. cache.ped se mantiene actualizado, y cache.vehicle y cache.serverId funcionan de la misma manera:

lua
local coords = GetEntityCoords(cache.ped)

lib.onCache te permite reaccionar cuando un valor cacheado cambia, sin comprobar en un bucle.

Solución 3: deja de llamar nativos cada frame

Comprueba el cuerpo del bucle y pregunta por cada línea: ¿esto realmente tiene que ejecutarse cada frame? Mueve lo que no lo hace.

  • Dibujar (texto, marcadores, sprites) tiene que ejecutarse cada frame, pero solo mientras sea visible.
  • Leer datos (trabajo, dinero, inventario) no: léelo en un evento, y mantenlo en una variable.
  • Buscar (GetClosestVehicle, GetGamePool, bucles sobre todos los jugadores) es caro. Ejecútalo una vez cada segundo o dos, no cada frame.
  • No crees cosas en un bucle: crear blips, entradas de texto o tablas cada frame llena la memoria y hace que el recolector de basura funcione.
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)

Solución 4: usa puntos y zonas de ox_lib en lugar de bucles

La mayoría de los bucles «¿estoy cerca de este lugar?» no son necesarios. ox_lib puede hacer el trabajo de distancia por ti, y solo ejecuta tu código cuando importa.

Un punto llama a una función cuando entras o sales de un radio, y uno cada frame solo mientras estés 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

Las zonas hacen lo mismo para formas como una esfera, una caja o un 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 interacción con entidades y lugares, un recurso objetivo (ox_target, por ejemplo) reemplaza el bucle «presiona E» de la misma manera. Comprueba la documentación de ox_lib para las opciones exactas de cada uno.

Comprueba el resultado

Ejecuta resmon 1 nuevamente. Un script arreglado debe sentarse cerca de 0.00 ms cuando te paras lejos de sus lugares, y subir solo cuando estés cerca de ellos. Si sigue siendo alto, busca un segundo bucle en el mismo recurso: a menudo un Wait(0) no es el único.

Cuidado: no establezcas un sueño largo en un bucle que maneja una pulsación de tecla o un dibujo. Si duermes 500 ms y el jugador presiona la tecla, el script la perderá. Duerme solo cuando sepas que nada está pasando, y baja a Wait(0) cuando algo esté.

Lista de verificación

Síntoma Solución
Ms alto cuando está inactivo Encuentra el bucle while true do Wait(0) y añade un sueño basado en distancia
PlayerPedId() en cada frame Cachéalo, o usa cache.ped de ox_lib
Comprobaciones de distancia en un bucle Reemplaza con lib.points.new o lib.zones
Búsqueda de entidades cada frame Ejecútalo una vez por segundo y guarda el resultado
Leer datos del jugador en un bucle Léelo en el evento del framework y almacénalo
Pulsaciones de tecla perdidas después de añadir un sueño Usa Wait(0) solo mientras el jugador esté cerca

Respuestas rápidas

¿Cuál es un buen valor de resmon para un script?

Un script que está inactivo debe sentarse alrededor de 0.00 a 0.01 ms. Cualquier cosa que permanezca bien por encima de eso cuando no la estés usando tiene un bucle que funciona demasiado duro.

¿Qué hace Wait(0) y por qué es costoso?

Wait(0) ejecuta el bucle una vez cada frame. A 60 frames por segundo eso es 60 ejecuciones por segundo, y cualquier nativo que llames en él es llamado 60 veces por segundo.

¿Necesito ox_lib para reparar ms alto?

No. Las soluciones funcionan en Lua simple. ox_lib solo las acorta, con cache.ped, lib.points y lib.zones.

Scripts que evitan este problema

CCTV Security CamerasCámaras colocables, una tablet con vista múltiple en vivo y fotos como prueba.Ver script →Advanced BoostingBoosting de vehículos desde una tablet: contratos de clase D a S+, crews y cola en vivo.Ver script →Arcade MachinesSiete juegos arcade jugables en máquinas reales, con clasificaciones y apuestas.Ver script →

Sigue leyendo