Вопросы по Lua скриптингу

Общая тема для вопросов по разработке скриптов на языке программирования Lua, в частности под MoonLoader.
  • Задавая вопрос, убедитесь, что его нет в списке частых вопросов и что на него ещё не отвечали (воспользуйтесь поиском).
  • Поищите ответ в теме посвященной разработке Lua скриптов в MoonLoader
  • Отвечая, убедитесь, что ваш ответ корректен.
  • Старайтесь как можно точнее выразить мысль, а если проблема связана с кодом, то обязательно прикрепите его к сообщению, используя блок [code=lua]здесь мог бы быть ваш код[/code].
  • Если вопрос связан с MoonLoader-ом первым делом желательно поискать решение на wiki.

Частые вопросы

Как научиться писать скрипты? С чего начать?
Информация - Гайд - Всё о Lua скриптинге для MoonLoader(https://blast.hk/threads/22707/)
Как вывести текст на русском? Вместо русского текста у меня какие-то каракули.
Изменить кодировку файла скрипта на Windows-1251. В Atom: комбинация клавиш Ctrl+Shift+U, в Notepad++: меню Кодировки -> Кодировки -> Кириллица -> Windows-1251.
Как получить транспорт, в котором сидит игрок?
Lua:
local veh = storeCarCharIsInNoSave(PLAYER_PED)
Как получить свой id или id другого игрока?
Lua:
local _, id = sampGetPlayerIdByCharHandle(PLAYER_PED) -- получить свой ид
local _, id = sampGetPlayerIdByCharHandle(ped) -- получить ид другого игрока. ped - это хендл персонажа
Как проверить, что строка содержит какой-то текст?
Lua:
if string.find(str, 'текст', 1, true) then
-- строка str содержит "текст"
end
Как эмулировать нажатие игровой клавиши?
Lua:
local game_keys = require 'game.keys' -- где-нибудь в начале скрипта вне функции main

setGameKeyState(game_keys.player.FIREWEAPON, -1) -- будет сэмулировано нажатие клавиши атаки
Все иды клавиш находятся в файле moonloader/lib/game/keys.lua.
Подробнее о функции setGameKeyState здесь: lua - setgamekeystate | BlastHack — DEV_WIKI(https://www.blast.hk/wiki/lua:setgamekeystate)
Как получить id другого игрока, в которого целюсь я?
Lua:
local valid, ped = getCharPlayerIsTargeting(PLAYER_HANDLE) -- получить хендл персонажа, в которого целится игрок
if valid and doesCharExist(ped) then -- если цель есть и персонаж существует
  local result, id = sampGetPlayerIdByCharHandle(ped) -- получить samp-ид игрока по хендлу персонажа
  if result then -- проверить, прошло ли получение ида успешно
    -- здесь любые действия с полученным идом игрока
  end
end
Как зарегистрировать команду чата SAMP?
Lua:
-- До бесконечного цикла/задержки
sampRegisterChatCommand("mycommand", function (param)
     -- param будет содержать весь текст введенный после команды, чтобы разделить его на аргументы используйте string.match()
    sampAddChatMessage("MyCMD", -1)
end)
Крашит игру при вызове sampSendChat. Как это исправить?
Это происходит из-за бага в SAMPFUNCS, когда производится попытка отправки пакета определенными функциями изнутри события исходящих RPC и пакетов. Исправления для этого бага нет, но есть способ не провоцировать его. Вызов sampSendChat изнутри обработчика исходящих RPC/пакетов нужно обернуть в скриптовый поток с нулевой задержкой:
Lua:
function onSendRpc(id)
  -- крашит:
  -- sampSendChat('Send RPC: ' .. id)

  -- норм:
  lua_thread.create(function()
    wait(0)
    sampSendChat('Send RPC: ' .. id)
  end)
end
 
Последнее редактирование:

mzxer

Активный
83
119
Могу ли я получить dialog зная кол-во записанных байтов и битов в битстриме? Пытаюсь авторег сделать, но у всех диалогов одинаковый id
[RECV] > [ShowDialog(61)] -> lenBytes: 532 | lenBits: 4249
вовсе не обязательно искать нужный диалог по айди. можно проверять по титлам, тексту диалога, стилю, названию кнопок и т.д.
даже если у всех диалогов одинаковый title, не думаю, что текст будет тоже одинаковый. вот тебе прекрасный пример с использованием samp.events:

Lua:
local sampev = require("lib.samp.events")

function sampev.onShowDialog(dialogId, style, title, button1, button2, text)
    if dialogId == 666 then -- сюда нужный айди диалога
        if text:find("Придумайте пароль") then -- диалог с паролем
            sampSendDialogResponse(dialogId, 1, -1, "password") -- отправляем нажатие 1 (левой(0 - правая)) кнопки и введенный в инпут текст "password"
        elseif text:find("Выберите пол") then -- диалог с выбором пола
            sampSendDialogResponse(dialogId, 1, -1, -1) -- отправляем нажатие 1 (левой) кнопки в диалог. (наверное мужской пол)
        end
        return false -- возвращаем false, т.е. отменяем показ диалога
    end
end

но если ты лёгких путей не ищешь... тоо:
Lua:
function onReceiveRpc(rpc_id, bs)
    if rpc_id == 61 then --onShowDialog RPC
        local id = raknetBitStreamReadInt16(bs)
        if id == 666 then -- айди диалога
            local bits = raknetBitStreamGetNumberOfBitsUsed(bs) -- количество записанных битов в битстриме
            local bytes = raknetBitStreamGetNumberOfBytesUsed(bs) -- количество записанных байтов в битстриме
            if bits == 4249 and bytes == 532 then -- думаю объяснять не нужно
                -- code
            end
        end
    end
end
 

meowprd

Тот самый Котовский
Проверенный
1,280
715
Возможно ли провести отладку кода lua? (естественно скриптов для samp)
 

Questel

Участник
151
13
Привет пацаны, кто сможет написать мне стиллер? Ну то есть чекер айпи и сбор пароля. Могу скинуть 100 рублей. ВК - questelek
 

Sanchez.

Известный
704
187
sorry, натупил немного.
Lua:
local sampev = require("lib.samp.events")

function sampev.onSendCommand(text)
    local cmd_arg = text:match("/vr (.+)")
    if cmd_arg and cmd_arg == cmd_arg:upper() then
        sampAddChatMessage("Не капси!", -1)
    end
end

проверил, работает.
А как сделать так, чтобы если было больше 3 символов капсом, то работала эта функция? А то я только одну заглавную букву пишу, уже пишет не капси
 

McLore

Известный
560
280
Подскажите как сделать адекватную проверку на кол-во введенных русских букв в InputText
Хуйня по типу text.v < 20 тригерится на 10 символов, а англ букв тригерится на 20 -_-
 

m1racles

Активный
199
32
нет смысла чекать переменную в бесконечном цикле, если можно в ту функцию всё разом запихнуть :)
сталкивался я как-то с тем, что на место существующего файла функа downloadUrlToFile отказывалась скачивать файл. решил проблему тем, что удалил файл, а потом уже скачал нужный. думаю, что тебе нужно скачивать актуальную версию скрипта под другим названием, подгружать его, удалять действующий скрипт и выгружать, так как игрок может закрыть игру и загрузка прервётся, а твой скрипт уже удалён.
Lua:
local dlstatus = require('moonloader').download_status
local inicfg = require 'inicfg'
local keys = require "vkeys"
update_state = false
local script_vers = 1
local script_vers_text = "1.00"
local update_url = "https://raw.githubusercontent.com/thedxrkway/script/main/update.ini"
local update_path = getWorkingDirectory() .. "/update.ini"
local script_url = "https://github.com/thedxrkway/script/blob/main/animwinlose.luac?raw=true"
local script_path = thisScript().path
function main()
    while not isSampAvailable() do wait(0) end
    sampRegisterChatCommand("lanim", function(arg)
        if arg == "" then
            sampAddChatMessage('Используйте /lanim 1-3', 0xA9A9A9)
        elseif arg == "1" then
        requestAnimation("CASINO")
        taskPlayAnim(1, "ROULETTE_WIN", "CASINO", 9, false, false, false, false, -1)
        elseif arg == "2" then
            requestAnimation("CASINO")
            taskPlayAnim(1, "ROULETTE_LOSE", "CASINO", 9, false, false, false, false, -1)
        elseif arg == "3" then
            requestAnimation("PAULNMAC")
            taskPlayAnim(1, "WANK_LOOP", "PAULNMAC", 9, false, false, false, false, -1)
        end
    end)
    downloadUrlToFile(update_url, update_path, function(id, status)
        if status == dlstatus.STATUS_ENDDOWNLOADDATA then
            updateIni = inicfg.load(nil, update_path)
            if tonumber(updateIni.info.vers) > script_vers then
                sampAddChatMessage('Есть обновление. Версия: ' .. updateIni.info.vers_text, 0xA9A9A9)
              
                local new_script_path = getGameDirectory() .. "\\moonloader\\namescript" .. updateIni.info.vers_text .. ".lua"
                downloadUrlToFile(script_url, new_script_path, function(id, status)
                    if status == dlstatus.STATUS_ENDDOWNLOADDATA then
                        sampAddChatMessage('Обновление успешно загружено.', 0xA9A9A9)
                        script.load(new_script_path) -- подгружаем новый скрипт
                        os.remove(script_path) -- удаляем этот скрипт
                        thisScript():unload() -- выгружаемся
                    end
                end)
              
            end
        end
    end)
  
    wait(-1)
end

я бы сделал так, надеюсь суть ясна

upd: если имя файла не хочешь менять, можно при подгрузке переименовываться с помощью функции os.rename(old_name, new_name)
[ML] (error) animwinlose.luac: device or resource busy: device or resource busy
stack traceback:
[C]: in function 'downloadUrlToFile'
E:\GTA 140K BY DAPO SHOW\moonloader\animwinlose.luac: in function <E:\GTA 140K BY DAPO SHOW\moonloader\animwinlose.luac:0>
 

mzxer

Активный
83
119
[ML] (error) animwinlose.luac: device or resource busy: device or resource busy
stack traceback:
[C]: in function 'downloadUrlToFile'
E:\GTA 140K BY DAPO SHOW\moonloader\animwinlose.luac: in function <E:\GTA 140K BY DAPO SHOW\moonloader\animwinlose.luac:0>
у меня заработало без костылей с преименовыванием файла, тестируй у себя. ошибку выше исправил создав поток
Lua:
local dlstatus = require('moonloader').download_status
local inicfg = require 'inicfg'
local keys = require "vkeys"
update_state = false
local script_vers = 1
local script_vers_text = "1.00"
local update_url = "https://raw.githubusercontent.com/thedxrkway/script/main/update.ini"
local update_path = getWorkingDirectory() .. "/update.ini"
local script_url = "https://github.com/thedxrkway/script/blob/main/animwinlose.luac?raw=true"
local script_path = thisScript().path
function main()
    while not isSampAvailable() do wait(0) end
    sampRegisterChatCommand("lanim", function(arg)
        if arg == "" then
            sampAddChatMessage('Используйте /lanim 1-3', 0xA9A9A9)
        elseif arg == "1" then
        requestAnimation("CASINO")
        taskPlayAnim(1, "ROULETTE_WIN", "CASINO", 9, false, false, false, false, -1)
        elseif arg == "2" then
            requestAnimation("CASINO")
            taskPlayAnim(1, "ROULETTE_LOSE", "CASINO", 9, false, false, false, false, -1)
        elseif arg == "3" then
            requestAnimation("PAULNMAC")
            taskPlayAnim(1, "WANK_LOOP", "PAULNMAC", 9, false, false, false, false, -1)
        end
    end)
    
    downloadUrlToFile(update_url, update_path, function(id, status)
        if status == dlstatus.STATUS_ENDDOWNLOADDATA then
            updateIni = inicfg.load(nil, update_path)
            if tonumber(updateIni.info.vers) > script_vers then
                sampAddChatMessage('Есть обновление. Версия: ' .. updateIni.info.vers_text, 0xA9A9A9)
                lua_thread.create(function()
                    wait(100)
                    -- local new_script_path = getGameDirectory() .. "\\moonloader\\newscriptname" .. updateIni.info.vers_text .. ".lua"
                    downloadUrlToFile(script_url, script_path, function(id, status)
                        if status == dlstatus.STATUS_ENDDOWNLOADDATA then
                            sampAddChatMessage('Обновление успешно загружено.', 0xA9A9A9)
                            --script.load(new_script_path) -- подгружаем новый скрипт
                            --os.remove(script_path) -- удаляем этот скрипт
                            --thisScript():unload() -- выгружаемся
                            thisScript():reload()
                        end
                    end)
                end)
            end
        end
    end)
 
    wait(-1)
end