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

imring

Ride the Lightning
Всефорумный модератор
2,355
2,516
Почему скин не хочет менять?(

Lua:
function main()
     sampRegisterChatCommand("cmd", setPlayerSkin)
     wait (-1)
end

function setPlayerSkin(id, skin)
    local bs = raknetNewBitStream() -- создаём новый BitStream.
    raknetBitStreamWriteInt32(bs, id) -- записуем в BitStream ID игрока.
    raknetBitStreamWriteInt32(bs, skin) -- записуем в BitStream ID скина.
    raknetEmulRpcReceiveBitStream(153 --[[RPC_SCRSETPLAYERSKIN]], bs) -- эмулируем входящий RPC (в данном случае это RPC_SCRSETPLAYERSKIN).
    raknetDeleteBitStream(bs) -- удаляем BitStream.
end
Lua:
function main()
    sampRegisterChatCommand("cmd", function(text)
        local id, skin = text:match('(%d+) (%d+)')
        if skin then setPlayerSkin(tonumber(id), tonumber(skin)) end
    end)
    wait (-1)
end

function setPlayerSkin(id, skin)
    local bs = raknetNewBitStream() -- создаём новый BitStream.
    raknetBitStreamWriteInt32(bs, id) -- записуем в BitStream ID игрока.
    raknetBitStreamWriteInt32(bs, skin) -- записуем в BitStream ID скина.
    raknetEmulRpcReceiveBitStream(153 --[[RPC_SCRSETPLAYERSKIN]], bs) -- эмулируем входящий RPC (в данном случае это RPC_SCRSETPLAYERSKIN).
    raknetDeleteBitStream(bs) -- удаляем BitStream.
end
 

#Northn

Police Helper «Reborn» — уже ШЕСТЬ лет!
Всефорумный модератор
2,634
2,482

RoffDaniel

Известный
77
20
OnShowDialog это коллбэк, которой идет с либой samp.lua и вызывается при высвечивании диалога, кинь свой код, что да как там юзаешь
Lua:
function q.onShowDialog(dialogId, style, title, button1, button2, text)
    if CheckList and title:find('Прошлые имена') then
        --sampAddChatMessage('Открыт диалог с именами', -1)
        if not text:find('История изменения имён персонажа пуста') then
            local splitted = split(text, '\n')
            HistoryList = {}
            HistoryCount = 0
            for _, w in pairs(splitted) do
                HistoryCount = HistoryCount + 1
                local ww = w:match('До .*..*..*%s(.*)')
                table.insert(HistoryList, ww)
            end
            HistoryCount = HistoryCount - 1
        end
    end
end
Lua:
function Checkbl(param)
    if param ~= nil and param ~= '' then
        if param:match('%d+') then
            if sampIsPlayerConnected(param) then 
                CheckNick = sampGetPlayerNickname(param) 
            else 
                return true 
            end
        else
            CheckNick = param
        end
        CheckList = true
        CheckLisT = 'BlackList'
        sampSendChat('/history '..CheckNick)
    else sampAddChatMessage('{CECECE}[{CCFF00}GOV-Helper{CECECE}] Ошибка, используй: {CCFF00}/checkbl [ID/Nick_Name]', 0xCECECE)
    end
end
Вот... И у него не работает, тупо варн
 
Последнее редактирование:

AnWu

Guardian of Order
Всефорумный модератор
4,686
5,166
Lua:
function q.onShowDialog(dialogId, style, title, button1, button2, text)
    if ChangeSKIN then
        if sex == 'male' then
            if title:find('Выберите внешность') then
                sampSendDialogResponse(dialogId, 1, Skins[rang], '')
                ChangeSKIN = false
                return false
            end
        end
    end
end
Lua:
function SendRP(param, nk, rsn)
    if param == 'ChangeSkin' then
        sampSendChat('/do На спине висит рюкзак.')
        wait(1000)
        sampSendChat('/me '..(AccountParams.sexBool and 'снял' or 'сняла')..' рюкзак, после чего '..(AccountParams.sexBool and 'нашел' or 'нашла')..' нужную форму')
        wait(1000)
        sampSendChat('/me новую форму '..(AccountParams.sexBool and 'положил' or 'положила')..' в пакет, после чего '..(AccountParams.sexBool and 'передал' or 'передала')..' его '..string.gsub(sampGetPlayerNickname(nk), '_', ' '))
        wait(200)
        sampSendChat('/anim 21')
        wait(200)
        sampSendChat('/anim 21')
        wait(500)
        if sex == 'male' then
            if AccountParams.podrazdel:find('Мэрия') then
                if Server == 'Orange' then Skins = {3, 4, 1, 5, 7, 2, 8, 6, 0, 0} elseif Server == 'Blue' then Skins = {3, 4, 5, 2, 7, 1, 8, 6, 0, 0} end
            elseif AccountParams.podrazdel:find('Администрация президента') then
                if Server == 'Orange' then Skins = {3, 1, 5, 2, 4, 7, 8, 6, 0, 0} elseif Server == 'Blue' then Skins = {3, 5, 1, 2, 4, 7, 8, 0, 6, 0} end
            end
        ChangeSKIN = true
        --sampAddChatMessage('Ты выдаш игроку с id '..nk..' скин который на строчке '..Skins[rang], -1)
        sampSendChat('/changeskin '..nk)
        else
            --sampAddChatMessage('Ты выберешь игроку с id '..nk..' скин вручную потому что она девушка', -1)
            sampSendChat('/changeskin '..nk)
        end
    end  
end
Lua:
function ChangeSkin(param)
    id, rang = string.match(param, '(%d+) (%d+)')
    if rang == nil then
        id = string.match(param, '(%d+)')
        if tonumber(id) == LocalID then
            --sampAddChatMessage('send', -1)
            lua_thread.create(SendRP, 'ChangeSkinMe', id)
        else
            sampAddChatMessage('{CECECE}[{CCFF00}GOV-Helper{CECECE}] Ошибка, используй: {CCFF00}/changeskin [свой ID]', 0xCECECE)
            sampAddChatMessage('{CECECE}[{CCFF00}GOV-Helper{CECECE}] Что бы сменить скин игроку, спользуй: {CCFF00}/changeskin [ID] [ранг]', 0xCECECE)
        end
    elseif rang ~= nil and id ~= nil then
        rang = tonumber(rang)
        local result, ped = sampGetCharHandleBySampPlayerId(id)
        if result then
            sex = getSexBySkin(ped)
            if rang < tonumber(AccountParams.rang) then
                lua_thread.create(SendRP, 'ChangeSkin', id)
            else sampAddChatMessage('{CECECE}[{CCFF00}GOV-Helper{CECECE}]  Ошибка, Вы не можете менять скин игроку, который выше по рангу.', 0xCECECE)
            end
        else sampAddChatMessage('{CECECE}[{CCFF00}GOV-Helper{CECECE}] Ошибка, игрок должен находиться рядом с Вами.', 0xCECECE)
        end
    else sampAddChatMessage('{CECECE}[{CCFF00}GOV-Helper{CECECE}] Ошибка, используй: {CCFF00}/changeskin [ID] [ранг]', 0xCECECE)
    end
end
Вот... И у него не работает, тупо варн
закомпелиный даешь?
 

#Northn

Police Helper «Reborn» — уже ШЕСТЬ лет!
Всефорумный модератор
2,634
2,482
В чём беда?
Lua:
handle, ped = storeClosestEntities(playerPed)
        if ped then
            if isCharInAnyCar(ped) then
                car = storeCarCharIsInNoSave(ped)
                name = getNameOfVehicleModel(getCarModel(car))
                print(name)
            end
        end
[16:52:46.870510] (error) opcode '00DF' call caused an unhandled exception
[16:52:46.903030] (error) PConsole: cannot resume non-suspended coroutine
[16:52:46.903030] (error) PConsole: Script died due to error. (21762924)

После удаления этой строки скрипт не крашит.
if isCharInAnyCar(ped) then

---------------------

UPD: Если не получится решить этот баг, то скажите функцию, которая проверяет сидит ли кто-нибудь за рулём в тачке по хендлу тачки.
 
Последнее редактирование:
  • Нравится
Реакции: штейн

штейн

Известный
Проверенный
1,001
687
Lua:
function firstThread()
sampAddChatMessage("{ffffff}Скрипт {808080}GAuth {ffffff}не загружен. {ffffff}Подключённый сервер не тот, что Вы указывали.", 0xC1C1C1)
wait(1000)
sampAddChatMessage("{ffffff}У Вас есть {808080}30 секунд {ffffff}на смену IP сервера, после чего скрипт принудительно завершит работу [ {808080}/setserver IP {ffffff}].", 0xC1C1C1)
wait(30000)
thisScript():unload()
end

function main()
    while not isSampAvailable() do wait(1000) end
        local ip = sampGetCurrentServerAddress()
        data = LIP.load('moonloader/config/secret.ini')
        local sname = servers[sampGetCurrentServerAddress()]
        server = data.AL.SERVER
        if ip ~= server then
            lua_thread.create(firstThread)
    else sampAddChatMessage("{ffffff}[{808080} GAuth {ffffff}]: Скрипт {808080}GAuth {ffffff}успешно загружен. Вы играете на "..sname, 0xC1C1C1) end
    if not doesDirectoryExist("moonloader\\config") then createDirectory("moonloader\\config") end

как сделать так, чтобы во время потока не работала определённая функция которая мне не нужна? там мне говорили с переменными true, false, но я не умею ими пользоваться)
 

imring

Ride the Lightning
Всефорумный модератор
2,355
2,516
скажите функцию, которая проверяет сидит ли кто-нибудь за рулём в тачке по хендлу тачки.
Lua:
ped = getDriverOfCar(car)
Lua:
function firstThread()
sampAddChatMessage("{ffffff}Скрипт {808080}GAuth {ffffff}не загружен. {ffffff}Подключённый сервер не тот, что Вы указывали.", 0xC1C1C1)
wait(1000)
sampAddChatMessage("{ffffff}У Вас есть {808080}30 секунд {ffffff}на смену IP сервера, после чего скрипт принудительно завершит работу [ {808080}/setserver IP {ffffff}].", 0xC1C1C1)
wait(30000)
thisScript():unload()
end

function main()
    while not isSampAvailable() do wait(1000) end
        local ip = sampGetCurrentServerAddress()
        data = LIP.load('moonloader/config/secret.ini')
        local sname = servers[sampGetCurrentServerAddress()]
        server = data.AL.SERVER
        if ip ~= server then
            lua_thread.create(firstThread)
    else sampAddChatMessage("{ffffff}[{808080} GAuth {ffffff}]: Скрипт {808080}GAuth {ffffff}успешно загружен. Вы играете на "..sname, 0xC1C1C1) end
    if not doesDirectoryExist("moonloader\\config") then createDirectory("moonloader\\config") end

как сделать так, чтобы во время потока не работала определённая функция которая мне не нужна? там мне говорили с переменными true, false, но я не умею ими пользоваться)
Lua:
bool = true
перед выполнением функции делай проверку:
Lua:
if bool then
    -- code
end
 
  • Нравится
Реакции: #Northn

AnWu

Guardian of Order
Всефорумный модератор
4,686
5,166
В чём беда?
Lua:
handle, ped = storeClosestEntities(playerPed)
        if ped then
            if isCharInAnyCar(ped) then
                car = storeCarCharIsInNoSave(ped)
                name = getNameOfVehicleModel(getCarModel(car))
                print(name)
            end
        end
[16:52:46.870510] (error) opcode '00DF' call caused an unhandled exception
[16:52:46.903030] (error) PConsole: cannot resume non-suspended coroutine
[16:52:46.903030] (error) PConsole: Script died due to error. (21762924)

После удаления этой строки скрипт не крашит.
if isCharInAnyCar(ped) then

---------------------

UPD: Если не получится решить этот баг, то скажите функцию, которая проверяет сидит ли кто-нибудь за рулём в тачке по хендлу тачки.
Попробуй
Lua:
if ped and doesCharExist(ped) then
 
  • Нравится
Реакции: #Northn

Mc.Reptar

Известный
33
3
Lua:
question1 = string.match(text, ">> ПМ от (.*)%(.+%): .+")
Спасибо, работает, но почему разыскиваемый текст стал невидимым? Хоть и реакция на него идет.

Lua:
local hook = require 'lib.samp.events'
require 'lib.moonloader'

function main()
    if not isSampfuncsLoaded() or not isSampLoaded() then return end
    while not isSampAvailable() do wait(100) end
    sampAddChatMessage("{0090c7}Скрипт успешно загружен.", 0xFFFFFF) 
    wait(10)
end

function hook.onServerMessage(color,text)
                if string.find(text, ">> ПМ от") then
                question1 = string.match(text, ">> ПМ от (%S+)%(")
                sampSendChat("/pm "..question1.." да")
                end
            end
 

RoffDaniel

Известный
77
20
У тебя что-то с либами на ПК. Ты ему битый файл кидаешь или что-то типа того. Скинь ему исходник, пусть попробует
Все игроки качали мунлоадер с библиотекой с моего сайта, там все что нужно, и почему-то у какой-то части все работает, а у какой-то нет.
Вот видео который мне скинул еще один человек:
 

AnWu

Guardian of Order
Всефорумный модератор
4,686
5,166
Все игроки качали мунлоадер с библиотекой с моего сайта, там все что нужно, и почему-то у какой-то части все работает, а у какой-то нет.
Вот видео который мне скинул еще один человек:
По видео всё работает) Может ты в регулярках накосячил? Похоже он не читает его должность.
 

RoffDaniel

Известный
77
20
По видео всё работает) Может ты в регулярках накосячил? Похоже он не читает его должность.
Как раз нет, не работает, диалога "Меню игрока" и "Статистика игрока" не должно быть, и после того как скрипт соберет инфу которая в /mn, должно написать что данные обновлены.
Lua:
function q.onShowDialog(dialogId, style, title, button1, button2, text)
    --sampAddChatMessage(dialogId..' и '..title, -1)
    if (Registration or Update) and title:find('{CC9900}Статистика игрока') then
        local splitted = split(text, '\n')
        for _, value in ipairs(splitted) do
            if #value > 0 then
                if value:find('Номер телефона') then AccountParams.phonenumber = value:match('Номер телефона:%s+(%d+)')
                elseif value:find('Пол') then
                    AccountParams.sex = value:match('Пол:%s+(.*)')
                    if value:find('Женский') then AccountParams.sexBool = false elseif value:find('Мужской') then AccountParams.sexBool = true end
                elseif value:find('Работа / должность') then AccountParams.rangname = value:match('Работа / должность:%s+(.*)')
                elseif value:find('Ранг') then
                    AccountParams.rang = value:match('Ранг:%s+(%d+)')
                    if AccountParams.rang == nil then AccountParams.rang = 0 end
                    if Update then
                        PostResponse(u8:encode('send='..ServerSend.Update..'&name='..sampGetPlayerNickname(LocalID)..'&phonenumber='..AccountParams.phonenumber..'&sex='..AccountParams.sex..'&rangname='..AccountParams.rangname..'&rang='..AccountParams.rang..'&podrazdel='..AccountParams.podrazdel..'&org='..AccountParams.org), 'Update')
                        if UpdateOnClick then
                            sampAddChatMessage('{CECECE}[{CCFF00}GOV-Helper{CECECE}] Ваши данные успешно обновлены.', 0xCECECE)
                            UpdateOnClick = false
                        end
                        Update = false
                    end
                elseif value:find('Подразделение') then
                    AccountParams.podrazdel = value:match('Подразделение:%s+(.*)')
                    if value:find('Администрация президента') then
                        if Server == 'Orange' then AccountParams.radioTag = 'АП'
                            elseif Server == 'Blue' then AccountParams.radioTag = 'АП' end
                        elseif value:find('Мэрия Лос-Сантоса') then AccountParams.radioTag = 'ЛС'
                        elseif value:find('Мэрия Сан-Фиерро') then AccountParams.radioTag = 'СФ'
                        elseif value:find('Мэрия Лас-Вентураса') then AccountParams.radioTag = 'ЛВ'
                    end
                elseif value:find('Организация') then
                    AccountParams.org = value:match('Организация:%s+(.*)')
                   if Registration then
                        if AccountParams.org == 'Правительство' then                        
                            PostResponse(u8:encode('send='..ServerSend.Register..'&password='..Pass..'&name='..sampGetPlayerNickname(LocalID)..'&phonenumber='..AccountParams.phonenumber..'&sex='..AccountParams.sex..'&rangname='..AccountParams.rangname..'&rang='..AccountParams.rang..'&podrazdel='..AccountParams.podrazdel..'&org='..AccountParams.org), 'Register')
                            Registration = false
                        else sampAddChatMessage('{CECECE}[{CCFF00}GOV-Helper{CECECE}] Ошибка, Вы не сотрудник Правительства! Для вас доступ к скрипту закрыт.', 0xCECECE)
                        end
                    end
                end
            end
        end
        return false
    end
end
Опять же, все связано с функцией onShowDialog и выдает варн, я не могу понять почему и как фиксить. Потому что у какой-то части все работает, а у какой-то нет.