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

Gorskin

I shit on you
Проверенный
1,247
1,043
Как можно проверить выполнится ли функция без ошибок без ее выполнения?
Например мне нужно проверить вернет ли этот код ошибку:
Lua:
imgui.GetStyle().Colors.I_LOVE_ERRORS = imgui.ImVec4(1, 0, 0, 1)
без выполнения этого кода. Конкретно это вернет ошибку и ничего не произойдет, однако если вставить туда например
Lua:
imgui.GetStyle().Colors.Text= imgui.ImVec4(1, 0, 0, 1)
то ошибки не будет, однако из-за того что код выполнится весь текст в имгуи окне будет красится в красный.

Более понятное объяснение:
например у меня есть 2 строки которые нужно "проверить на краш":
Lua:
imgui.GetStyle().Colors[imgui.Col.Text] = imgui.ImVec4(1, 0, 0, 1) -- ok
mgui.GetStyle().Colors[imgui.Col._____Text] = imgui.ImVec4(1, 0, 0, 1) -- ERROR
если вызывать их через pcall, то скрипт может определить вызовут ли эти строки ошибку, однако если строка не вызывает ошибку, то код выполняется (например вызов первый строки перекрасит текст в менюшке, а мне надо этого избежать)
Как вариант создать список и сверять с содержимым? Допустим в словаре есть слово Text, Button но нет слова Child, значит строку с этим словом нужно выделить. Возможно этот метод костыль, но я ничего другого не вижу.
 
  • Вау
Реакции: why ega

Andrinall

Известный
678
531
Как вариант создать список и сверять с содержимым? Допустим в словаре есть слово Text, Button но нет слова Child, значит строку с этим словом нужно выделить. Возможно этот метод костыль, но я ничего другого не вижу.
Если я правильно понял, то этот костыль будет примерно так выглядеть.

upd: Хотя нет, только на половину я понял, ну да ладно пусть лежит.
Lua:
local col = {
    Text=0,
    TextDisabled=0,
    WindowBg=0,
    ChildBg=0,
    PopupBg=0,
    Border=0,
    BorderShadow=0,
    FrameBg=0,
    FrameBgHovered=0,
    FrameBgActive=0,
    TitleBg=0,
    TitleBgActive=0,
    TitleBgCollapsed=0,
    MenuBarBg=0,
    ScrollbarBg=0,
    ScrollbarGrab=0,
    ScrollbarGrabHovered=0,
    ScrollbarGrabActive=0,
    CheckMark=0,
    SliderGrab=0,
    SliderGrabActive=0,
    Button=0,
    ButtonHovered=0,
    ButtonActive=0,
    Header=0,
    HeaderHovered=0,
    HeaderActive=0,
    Separator=0,
    SeparatorHovered=0,
    SeparatorActive=0,
    ResizeGrip=0,
    ResizeGripHovered=0,
    ResizeGripActive=0,
    Tab=0,
    TabHovered=0,
    TabActive=0,
    TabUnfocused=0,
    TabUnfocusedActive=0,
    PlotLines=0,
    PlotLinesHovered=0,
    PlotHistogram=0,
    PlotHistogramHovered=0,
    TextSelectedBg=0,
    DragDropTarget=0,
    NavHighlight=0,
    NavWindowingHighlight=0,
    NavWindowingDimBg=0,
    ModalWindowDimBg=0
}

imgui.OnInitialize(function()
    imgui.GetIO().IniFilename = nil

    local style = imgui.GetStyle()
    style:SetColor("Text", imgui.ImVec4(1, 0.0, 0.0, 1))
    style:SetColor("____COLORS", imgui.ImVec4(0,0,0,1)) -- ничего не установит и не крашнет скрипт
end)

local wnd = imgui.OnFrame(function() return true end, function()
    imgui.Begin("Test")

    imgui.Text("Tested Text")

    imgui.End()
end)
wnd.HideCursor = true

function imgui.ImGuiStyle.__index:SetColor(name, value)
    if col[name] == nil then return false end
    self.Colors[imgui.Col[name]] = value
    return true
end
 

windranger

Новичок
28
4
Lua:
local state = false -- По умолчанию выключено
Если тебе интерфейс не нужен, то вот на команду активация
Lua:
-- В начало кода
local state = false

-- В функцию main()
sampRegisterChatCommand("act", function()
    state = not state -- Переключение активации
    sampAddChatMessage("Автоответчик "..(state and "включён" or "выключен"), -1) -- Сообщение в чат, чтобы знать, включён или выключен автоответчик
end)

-- Ну и это там, где у тебя происходит сама ловля сообщений.
if state then
    -- Тут сам код ловли
end
Screenshot_64.1676798095.png

теперь не могу понять, почему автоответчик не хочет отключаться
вот отрывок из кода
Lua:
require "lib.moonloader"
local sampevents = require "lib.samp.events"
local onoff = false

function main()
    repeat wait(100) until isSampAvailable()
        sampRegisterChatCommand("am", act)
end

function act()
    onoff = not onoff
    sampAddChatMessage("Автоответчик "..(act and "включён" or "выключен"), -1)
end

function sampevents.onServerMessage(color, text)
    if act and text:find("%[Жалоба%] (.+)%[(%d+)%]: {FFFFFF}спасибо") and not sampIsDialogActive() then
        lua_thread.create(function()
            local nickname, id = text:match("%[Жалоба%] (.+)%[(%d+)%]: {FFFFFF}спасибо")
            wait(500)
            sampSendChat("/pm ".. id .." Приятного времяпровождения на сервере.")
        end)
    end
end
 

why ega

РП игрок
Модератор
2,540
2,233
Screenshot_64.1676798095.png

теперь не могу понять, почему автоответчик не хочет отключаться
вот отрывок из кода
Lua:
require "lib.moonloader"
local sampevents = require "lib.samp.events"
local onoff = false

function main()
    repeat wait(100) until isSampAvailable()
        sampRegisterChatCommand("am", act)
end

function act()
    onoff = not onoff
    sampAddChatMessage("Автоответчик "..(act and "включён" or "выключен"), -1)
end

function sampevents.onServerMessage(color, text)
    if act and text:find("%[Жалоба%] (.+)%[(%d+)%]: {FFFFFF}спасибо") and not sampIsDialogActive() then
        lua_thread.create(function()
            local nickname, id = text:match("%[Жалоба%] (.+)%[(%d+)%]: {FFFFFF}спасибо")
            wait(500)
            sampSendChat("/pm ".. id .." Приятного времяпровождения на сервере.")
        end)
    end
end
Lua:
local sampevents = require "lib.samp.events"
local onoff = false

function main()
    repeat wait(100) until isSampAvailable()
        sampRegisterChatCommand("am", act)
end

function act()
    onoff = not onoff
    sampAddChatMessage("Автоответчик "..(onoff and "включён" or "выключен"), -1)
end

function sampevents.onServerMessage(color, text)
    if onoff and text:find("%[Жалоба%] (.+)%[(%d+)%]: {FFFFFF}спасибо") and not sampIsDialogActive() then
        lua_thread.create(function()
            local nickname, id = text:match("%[Жалоба%] (.+)%[(%d+)%]: {FFFFFF}спасибо")
            wait(500)
            sampSendChat("/pm ".. id .." Приятного времяпровождения на сервере.")
        end)
    end
end
 

windranger

Новичок
28
4
Lua:
local sampevents = require "lib.samp.events"
local onoff = false

function main()
    repeat wait(100) until isSampAvailable()
        sampRegisterChatCommand("am", act)
end

function act()
    onoff = not onoff
    sampAddChatMessage("Автоответчик "..(onoff and "включён" or "выключен"), -1)
end

function sampevents.onServerMessage(color, text)
    if onoff and text:find("%[Жалоба%] (.+)%[(%d+)%]: {FFFFFF}спасибо") and not sampIsDialogActive() then
        lua_thread.create(function()
            local nickname, id = text:match("%[Жалоба%] (.+)%[(%d+)%]: {FFFFFF}спасибо")
            wait(500)
            sampSendChat("/pm ".. id .." Приятного времяпровождения на сервере.")
        end)
    end
end
бля, спасибо за сохранённые нервы, которые были бы потрачены из-за невнимательности) лучший
 
  • Нравится
Реакции: why ega

Pashyka

Участник
220
17
Парни, привет, вопрос открытый опять, после ввода команды он начинает флдить отыгровкой, а мне нужно чтобы отыгровка прошла один раз, return false вводил после потока ничего не изменилось


Lua:
function hook.onSendCommand(command)
    cmd, cmdtext = command:match("^/(%S+) (.*)$")
    if cmd == "fwarn" then
        --if player.rank < 9 then chatmsg("Команда /fwarn доступна с 9+ ранга.") return end
        local id, arg = cmdtext:match("(%d+) (.*)$")
        if not tonumber(id) or not arg or arg:gsub(" ", "") == '' then chatmsg("Используйте: /fwarn [ID] [Причина]") return end
        if not sampIsPlayerConnected(id) then chatmsg("Игрок не подключен или указан свой ID!") return end
        if ToggleButton.offwarn.v then
            lua_thread.create(function()
                sampSendChat(string.format("/me %s в руки планшет управления составом", (player.female and "взяла" or "взял")))
                wait(1600)
                sampSendChat(string.format("/me %s пункт 'Выговоры'", (player.female and "выбрала" or "выбрал")))
                wait(1600)
                sampSendChat(string.format("/me %s сотруднику '%s' выговор", (player.female and "выдала" or "выдал"), sampGetPlayerNickname(id):gsub("_", " ")))
                wait(1600)
                sampSendChat(string.format("/fwarn %d %s", tonumber(id), arg))
            end)
        else
            sampSendChat(string.format("/fwarn %d %s", tonumber(id), arg))
        end
    end
end
 

windranger

Новичок
28
4
Lua:
local sampevents = require "lib.samp.events"
local onoff = false

function main()
    repeat wait(100) until isSampAvailable()
        sampRegisterChatCommand("am", act)
end

function act()
    onoff = not onoff
    sampAddChatMessage("Автоответчик "..(onoff and "включён" or "выключен"), -1)
end

function sampevents.onServerMessage(color, text)
    if onoff and text:find("%[Жалоба%] (.+)%[(%d+)%]: {FFFFFF}спасибо") and not sampIsDialogActive() then
        lua_thread.create(function()
            local nickname, id = text:match("%[Жалоба%] (.+)%[(%d+)%]: {FFFFFF}спасибо")
            wait(500)
            sampSendChat("/pm ".. id .." Приятного времяпровождения на сервере.")
        end)
    end
end
решил сделать настройки, чтоб при перезаходе, например, ничего не менялось, но ничего не вышло: значения true или false не сохраняются в ini. что может быть не так?
исходный код скрипта:
Lua:
require "lib.moonloader"
local sampevents = require "lib.samp.events"
local onoff = false
local ini = require "inicfg"
local nastry = "moonloader//open-source-autoresponder.ini"
local mini = ini.load(nil, nastry)
local sini = ini.save(mini, nastry)

function main()
    repeat wait(100) until isSampAvailable()
        sampRegisterChatCommand("ar", act)
        sampAddChatMessage('{6495ED}[{ABCDEF}AUTORESPONDER{6495ED}]: {FFFFFF}Бета-версия {00FF00}успешно {FFFFFF}инициализирована. Автор — {ABCDEF}windranger{FFFFFF}.', 0xFFFFFF)
        sampAddChatMessage('{6495ED}[{ABCDEF}AUTORESPONDER{6495ED}]: {FFFFFF}Активация автоответчика {FF4040}автоматическая{FFFFFF}.', 0xFFFFFF)
end

function act()
    onoff = not onoff
    mini.config.bool = onoff
    sampAddChatMessage("{6495ED}[{ABCDEF}AUTORESPONDER{6495ED}]: {FFFFFF}Автоответчик "..(onoff and "{00FF00}включён{FFFFFF}." or "{FF4040}выключен{FFFFFF}."), -1)
end
ини к этому скрипту:
INI:
[config]
bool=
 

Pashyka

Участник
220
17
решил сделать настройки, чтоб при перезаходе, например, ничего не менялось, но ничего не вышло: значения true или false не сохраняются в ini. что может быть не так?
исходный код скрипта:
Lua:
require "lib.moonloader"
local sampevents = require "lib.samp.events"
local onoff = false
local ini = require "inicfg"
local nastry = "moonloader//open-source-autoresponder.ini"
local mini = ini.load(nil, nastry)
local sini = ini.save(mini, nastry)

function main()
    repeat wait(100) until isSampAvailable()
        sampRegisterChatCommand("ar", act)
        sampAddChatMessage('{6495ED}[{ABCDEF}AUTORESPONDER{6495ED}]: {FFFFFF}Бета-версия {00FF00}успешно {FFFFFF}инициализирована. Автор — {ABCDEF}windranger{FFFFFF}.', 0xFFFFFF)
        sampAddChatMessage('{6495ED}[{ABCDEF}AUTORESPONDER{6495ED}]: {FFFFFF}Активация автоответчика {FF4040}автоматическая{FFFFFF}.', 0xFFFFFF)
end

function act()
    onoff = not onoff
    mini.config.bool = onoff
    sampAddChatMessage("{6495ED}[{ABCDEF}AUTORESPONDER{6495ED}]: {FFFFFF}Автоответчик "..(onoff and "{00FF00}включён{FFFFFF}." or "{FF4040}выключен{FFFFFF}."), -1)
end
ини к этому скрипту:
INI:
[config]
bool=

Тут написано под мой скрипт, там уже подставишь по аналогии все
Создаем табличку в начале скрипта, далее проверяем на наличие файла в директории, если нет его то создаем.
Lua:
local mainIni = inicfg.load({
    Toggle = {
        offad = false,
        offr = false,
        offefir = false,
        rpsituation = false,
        offint = false,
        reddiag = false,
        autolov = false,
        vipad = false,
        ----------------------
        offinvite = true,
        offuninvite = true,
        offgiverank = true,
        offwarn = true,
        offunwarn = true,
        offblacklist = true,
        offunblacklist = true,
        ----------------------
        timeefir = false
    },
}, "Название ini")
if not doesFileExist("moonloader/config/Название ини.ini") then
    inicfg.save(mainIni, "Название ини.ini")
end

Тут после таблички сразу даем значения переменным с скрипта из ini файла

Lua:
-------------------------------------------------------- For settings
ToggleButton.offad.v = mainIni.Toggle.offad
ToggleButton.offr.v = mainIni.Toggle.offr
ToggleButton.offefir.v = mainIni.Toggle.offefir
ToggleButton.rpsituation.v = mainIni.Toggle.rpsituation
ToggleButton.offint.v = mainIni.Toggle.offint
ToggleButton.reddiag.v = mainIni.Toggle.reddiag
ToggleButton.vipad.v = mainIni.Toggle.vipad
ToggleButton.autolov.v = mainIni.Toggle.autolov
-------------------------------------------------------- For rp
ToggleButton.offinvite.v = mainIni.Toggle.offinvite
ToggleButton.offuninvite.v = mainIni.Toggle.offuninvite
ToggleButton.offgiverank.v = mainIni.Toggle.offgiverank
ToggleButton.offwarn.v = mainIni.Toggle.offwarn
ToggleButton.offunwarn.v = mainIni.Toggle.offunwarn
ToggleButton.offblacklist.v = mainIni.Toggle.offblacklist
ToggleButton.offunblacklist.v = mainIni.Toggle.offunblacklist
-------------------------------------------------------- For efirs
ToggleButton.timeefir.v = mainIni.Toggle.timeefir

Тут прописано именно сохранение ini

Lua:
if imgui.ToggleButton(u8"Отыгровка invite", ToggleButton.offinvite) then mainIni.Toggle.offinvite = ToggleButton.offinvite.v end
if imgui.ToggleButton(u8"Отыгровка uninvite", ToggleButton.offuninvite) then mainIni.Toggle.offuninvite = ToggleButton.offuninvite.v end
if imgui.ToggleButton(u8"Отыгровка giverank", ToggleButton.offgiverank) then mainIni.Toggle.offgiverank = ToggleButton.offgiverank.v end
if imgui.ToggleButton(u8"Отыгровка fwarn", ToggleButton.offwarn) then mainIni.Toggle.offwarn = ToggleButton.offwarn.v end
if imgui.ToggleButton(u8"Отыгровка unfwarn", ToggleButton.offunwarn) then mainIni.Toggle.offunwarn = ToggleButton.offunwarn.v end
if imgui.ToggleButton(u8"Отыгровка blacklist", ToggleButton.offblacklist) then mainIni.Toggle.offblacklist = ToggleButton.offblacklist.v end
if imgui.ToggleButton(u8"Отыгровка unblacklist", ToggleButton.offunblacklist) then mainIni.Toggle.offunblacklist = ToggleButton.offunblacklist.v end

А в конце кода можешь написать просто:
Это если скрипт ляжет он сохранит все

Lua:
function onScriptTerminate(scr, is_quit)
    if scr == thisScript() then
        inicfg.save(mainIni, "Название ини.ini")
    end
end
 
  • Нравится
Реакции: YarikVL

why ega

РП игрок
Модератор
2,540
2,233
решил сделать настройки, чтоб при перезаходе, например, ничего не менялось, но ничего не вышло: значения true или false не сохраняются в ini. что может быть не так?
исходный код скрипта:
Lua:
require "lib.moonloader"
local sampevents = require "lib.samp.events"
local onoff = false
local ini = require "inicfg"
local nastry = "moonloader//open-source-autoresponder.ini"
local mini = ini.load(nil, nastry)
local sini = ini.save(mini, nastry)

function main()
    repeat wait(100) until isSampAvailable()
        sampRegisterChatCommand("ar", act)
        sampAddChatMessage('{6495ED}[{ABCDEF}AUTORESPONDER{6495ED}]: {FFFFFF}Бета-версия {00FF00}успешно {FFFFFF}инициализирована. Автор — {ABCDEF}windranger{FFFFFF}.', 0xFFFFFF)
        sampAddChatMessage('{6495ED}[{ABCDEF}AUTORESPONDER{6495ED}]: {FFFFFF}Активация автоответчика {FF4040}автоматическая{FFFFFF}.', 0xFFFFFF)
end

function act()
    onoff = not onoff
    mini.config.bool = onoff
    sampAddChatMessage("{6495ED}[{ABCDEF}AUTORESPONDER{6495ED}]: {FFFFFF}Автоответчик "..(onoff and "{00FF00}включён{FFFFFF}." or "{FF4040}выключен{FFFFFF}."), -1)
end
ини к этому скрипту:
INI:
[config]
bool=
Ты забыл сохранять эти значения в само ини при помощи ini.save(mini, nastry) после 18 строки
А в конце кода можешь написать просто:
Это если скрипт ляжет он сохранитстроки
@ARMOR говорил, что у этого способа есть недочеты, насколько помню, один из них это то, что если установлен плагин, который фиксить выход с игры, то ини не сохранится
 
  • Нравится
Реакции: ARMOR

why ega

РП игрок
Модератор
2,540
2,233
пробовал что-то делать с именно сейвом, но ничего тоже не вышло. как это по-хорошему сделать?
Писал с телефона, мог где-то ошибиться
Lua:
local sampevents = require "lib.samp.events"
local inicfg = require "inicfg"

local iniPath = "то, что было в nastry"
local mainIni = inicfg.load({
    config = {
        bool = false
    }
}, iniPath)
local saveIni = inicfg.save(mainIni, iniPath)

local onoff = false

function main()
    repeat wait(100) until isSampAvailable()
        sampRegisterChatCommand("ar", act)
        sampAddChatMessage('{6495ED}[{ABCDEF}AUTORESPONDER{6495ED}]: {FFFFFF}Бета-версия {00FF00}успешно {FFFFFF}инициализирована. Автор — {ABCDEF}windranger{FFFFFF}.', 0xFFFFFF)
        sampAddChatMessage('{6495ED}[{ABCDEF}AUTORESPONDER{6495ED}]: {FFFFFF}Активация автоответчика {FF4040}автоматическая{FFFFFF}.', 0xFFFFFF)
end

function act()
    onoff = not onoff
    mainIni.config.bool = onoff
    saveIni()
    sampAddChatMessage("{6495ED}[{ABCDEF}AUTORESPONDER{6495ED}]: {FFFFFF}Автоответчик "..(onoff and "{00FF00}включён{FFFFFF}." or "{FF4040}выключен{FFFFFF}."), -1)
end