Вопросы по 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
 
Последнее редактирование:

bottom_text

Известный
675
320
рофлишь? мэйби я додик. но они визуальные. каким образом они могут отображаться у других игроков?
В исходящей синхре с ног будут отправляться эти анимации и, соответственно, другие игроки будут видить эту анимацию
 
  • Нравится
Реакции: mzxer и paulohardy

HpP

Известный
368
119
У меня есть файл random.txt, в нем есть переменная random, с которой рядом стоит значение, что она равна 5(random=5).
Как мне достать это значение?
 

mzxer

Активный
83
119
У меня есть файл random.txt, в нем есть переменная random, с которой рядом стоит значение, что она равна 5(random=5).
Как мне достать это значение?

Lua:
local file_path = getGameDirectory() .. "\\my_txt_file.txt" -- путь к файлу. представим, что он находится в папке с игрой и носит название my_txt_file
local file = io.open(file_path, "r") -- открываем файл с правами чтения
local file_content = file:read('*a') -- записываем содержимое файла в переменную
file:close() -- закрываем файл

local random_value = file_content:match("random=(%d+)\n*") -- ищем значение с помощью регулярного выражения. если ничего не найдется - string.match вернёт nil

if random_value then -- если переменная random_value не равна nil (если string.match нашла число). эквивалентно 'if random_value ~= nil then'
    print("random_value = " .. random_value) -- выведем нашу переменную в консоль
else -- если всё таки random_value равна nil. можно запихнуть запись в файл сюда например
    print("я не смог найти нужное значение в файле :(")
end

но вообще, для таких задач лучше подходит inicfg (click)
 
  • Нравится
Реакции: HpP

m1racles

Активный
204
35
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)
                update_state = true
            end
        end
    end)
    while true do
        wait(0)
        if update_state then
            downloadUrlToFile(script_url, script_path, function(id, status)
                if status == dlstatus.STATUS_ENDDOWNLOADDATA then
                    sampAddChatMessage('Обновление успешно загружено.', 0xA9A9A9)
                    thisScript():reload()
                end
            end)
            break
        end
    end
end
скрипт загружается успешно, в чате выводится "есть обновление" и версия которая указана в .ini на гитхабе
после этого обнова не загружается, скрипт крашится, сообщение "обновление успешно загружено" не выводится
не могу пофиксить уже час
 

mzxer

Активный
83
119
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)
                update_state = true
            end
        end
    end)
    while true do
        wait(0)
        if update_state then
            downloadUrlToFile(script_url, script_path, function(id, status)
                if status == dlstatus.STATUS_ENDDOWNLOADDATA then
                    sampAddChatMessage('Обновление успешно загружено.', 0xA9A9A9)
                    thisScript():reload()
                end
            end)
            break
        end
    end
end
скрипт загружается успешно, в чате выводится "есть обновление" и версия которая указана в .ini на гитхабе
после этого обнова не загружается, скрипт крашится, сообщение "обновление успешно загружено" не выводится
не могу пофиксить уже час
нет смысла чекать переменную в бесконечном цикле, если можно в ту функцию всё разом запихнуть :)
сталкивался я как-то с тем, что на место существующего файла функа 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)
 
  • Нравится
Реакции: m1racles

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,278
718
Возможно ли провести отладку кода lua? (естественно скриптов для samp)
 

Questel

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