FiveM resmon высокие мс: как найти и исправить медленные скрипты

Ресурс показывает высокие мс в resmon? Как читать resmon 1, почему циклы Wait(0) стоят так дорого и как спать далеко, кешировать ped и использовать ox_lib points и zones.

Вы открываете монитор ресурсов и один скрипт показывает это:

text
my_script        0.35 ms

Неработающий скрипт должен быть близко к нулю. Скрипт, который съедает треть миллисекунды или намного больше на каждом кадре, делает вашу игру рывковой, и игроки с более слабыми компьютерами чувствуют это в первую очередь. Это руководство показывает, как увидеть, какой ресурс является проблемой и какие изменения приносят его вниз.

Откройте монитор ресурсов

В консоли F8 игры введите:

text
resmon 1

Оверлей показывает каждый ресурс клиента со своим временем CPU (мс) на кадр и его памятью. Введите resmon 0 чтобы закрыть его. Проверьте эти вещи:

  • Стойте неподвижно в спокойном месте и читайте список. Числа, которые имеют значение, — это те, которые остаются высокими, когда вы ничего не делаете.
  • Посмотрите кто находится в верхней части. Ресурс, который увеличивается только рядом с его маркером или магазином, нормален. Один, который высокий везде, нет.
  • Смотрите его несколько секунд. Единственный пик, когда скрипт запускается, безвреден; постоянное значение — это проблема.

мс — это время на клиенте. Производительность сервера — это отдельная тема: смотрите серверное предупреждение о задержке потока.

Причина 1: цикл с Wait(0)

Наиболее распространенная причина высокого значения — это цикл, который работает на каждом кадре, все время:

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)

Это запускает встроенные функции 60 раз в секунду, даже когда игрок находится на другой стороне карты. Большую часть времени ответ — это «ничего не делать» и эта стоимость потеряна впустую.

Исправление 1: спите далеко

Позвольте циклу спать дольше, когда ничего не близко, и работайте только на каждом кадре, когда игрок рядом:

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)

Цикл проверяет один раз в секунду, когда вы далеко, что стоит почти ничего, и работает на каждом кадре только в 10 метровой области, где он рисует. Используйте #(a - b) со значениями vec3 для расстояния: это быстрее, чем старший встроенный GetDistanceBetweenCoords.

Исправление 2: кешируйте значения, которые вы повторно используете

Вызов встроенной функции на каждом кадре для получения значения, которое редко изменяется — это потеря. PlayerPedId() — это классический. Сохраните его один раз и обновляйте его только когда это может измениться:

lua
local ped = PlayerPedId()

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

Если вы используете ox_lib, это делает это за вас. cache.ped поддерживается в актуальном состоянии, и cache.vehicle и cache.serverId работают одинаково:

lua
local coords = GetEntityCoords(cache.ped)

lib.onCache позволяет вам реагировать, когда кэшированное значение изменяется, без проверки в цикле.

Исправление 3: остановите вызовы встроенных функций на каждом кадре

Проверьте тело цикла и спросите для каждой строки: должно ли это действительно работать на каждом кадре? Выведите то, что не должно.

  • Рисование (текст, маркеры, спрайты) должно работать на каждом кадре, но только пока оно видимо.
  • Чтение данных (работа, деньги, инвентарь) нет: прочитайте это на события и держите его в переменной.
  • Поиск (GetClosestVehicle, GetGamePool, циклы над всеми игроками) дорого. Запустите это один раз в одну или две секунды, не на каждом кадре.
  • Не создавайте вещи в цикле: создание blips, текстовых записей или таблиц на каждом кадре заполняет память и заставляет сборщик мусора работать.
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)

Исправление 4: используйте ox_lib points и zones вместо циклов

Большинство циклов «я рядом с этой точкой» не нужны. ox_lib может выполнить работу расстояния за вас и только запускает ваш код, когда это имеет значение.

Точка вызывает функцию, когда вы входите или выходите из радиуса, и одну на каждом кадре только пока вы находитесь внутри:

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

Зоны делают то же самое для фигур, таких как сфера, коробка или полигон:

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,
})

Для взаимодействия с сущностями и пятнами, целевой ресурс (ox_target, например) заменяет цикл «нажми E» таким же образом. Проверьте документацию ox_lib для точного параметры каждой.

Проверьте результат

Запустите resmon 1 снова. Исправленный скрипт должен сидеть около 0.00 мс, когда вы стоите далеко от его пятен, и подняться только когда вы рядом с ними. Если это все еще высоко, посмотрите для второго цикла в том же ресурсе: один Wait(0) часто не единственный.

Внимание: не устанавливайте долгий сон в цикл, который обрабатывает нажатие клавиши или рисование. Если вы спите 500 мс и игрок нажимает клавишу, скрипт его пропустит. Спите только когда вы знаете, что ничего не происходит, и упадите до Wait(0) когда что-то происходит.

Контрольный список

Симптом Исправление
Высокие мс в режиме ожидания Найдите цикл while true do Wait(0) и добавьте сон на основе расстояния
PlayerPedId() на каждом кадре Кешируйте его или используйте cache.ped из ox_lib
Проверки расстояния в цикле Замените на lib.points.new или lib.zones
Поиск сущностей на каждом кадре Запустите его один раз в секунду и сохраните результат
Чтение данных игрока в цикле Прочитайте это на события фреймворка и сохраните его
Пропущенные нажатия клавиш после добавления сна Используйте Wait(0) только пока игрок рядом

Короткие ответы

Какое хорошее значение resmon для скрипта?

Неработающий скрипт должен сидеть около 0.00 до 0.01 мс. Все, что остается значительно выше этого, когда вы не используете его, имеет цикл, который работает слишком сильно.

Что делает Wait(0) и почему это дорого?

Wait(0) запускает цикл один раз на кадр. При 60 кадрах в секунду это 60 запусков в секунду, и любой встроенный вызов в нем вызывается 60 раз в секунду.

Нужна ли мне ox_lib для исправления высоких мс?

Нет. Исправления работают в обычном Lua. ox_lib только делает их короче, с cache.ped, lib.points и lib.zones.

Скрипты без этой проблемы

CCTV Security CamerasУстанавливаемые камеры, планшет с мультиэкраном в реальном времени и распечатанные фото-улики.Смотреть скрипт →Advanced BoostingУгон машин на заказ через планшет: контракты от класса D до S+, команды и живая очередь.Смотреть скрипт →Arcade MachinesСемь аркадных игр в настоящих автоматах, с таблицами рекордов и ставками.Смотреть скрипт →

Читайте также