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

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

Участник
30
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

whyega52

Гений, миллионер, плейбой, долбаеб
Модератор
2,756
2,576
решил сделать настройки, чтоб при перезаходе, например, ничего не менялось, но ничего не вышло: значения 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

whyega52

Гений, миллионер, плейбой, долбаеб
Модератор
2,756
2,576
пробовал что-то делать с именно сейвом, но ничего тоже не вышло. как это по-хорошему сделать?
Писал с телефона, мог где-то ошибиться
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
 

Pashyka

Участник
220
17
Ты забыл сохранять эти значения в само ини при помощи ini.save(mini, nastry) после 18 строки

@ARMOR говорил, что у этого способа есть недочеты, насколько помню, один из них это то, что если установлен плагин, который фиксить выход с игры, то ини не сохранится

То есть лучше сохранять сразу после изменения? Точнее не лучше, а безопаснее
 

whyega52

Гений, миллионер, плейбой, долбаеб
Модератор
2,756
2,576
То есть лучше сохранять сразу после изменения? Точнее не лучше, а безопаснее
Да, думаю безопаснее будет сохранять сразу после изменения, но это и минус к производительности
 

Pashyka

Участник
220
17
Да, думаю безопаснее будет сохранять сразу после изменения, но это и минус к производительности
Тогда желательно делать в JSON, хотя у меня и сохранение JSON тоже в onTerminate стоит)

Да, думаю безопаснее будет сохранять сразу после изменения, но это и минус к производительности

Вопросик такой, не знаешь как окно imgui сделать всегда на переднем плане, чтобы другие окна его не перекрывали?

Вот такое окно к примеру, как бы окно ошибки, оно должно всегда быть перед главным окном

Lua:
if errorwin.v then
    custom_Style()
    local X, Y = getScreenResolution()
    imgui.SetNextWindowPos(imgui.ImVec2(X / 2, Y / 2), imgui.Cond.FirstUseEver, imgui.ImVec2(0.5, 0.5))
    imgui.SetNextWindowSize(imgui.ImVec2(270,80), imgui.Cond.FirstUseEver)
    imgui.Begin(u8'Введите айди игрока для собеседования', errorwin, imgui.WindowFlags.NoCollapse + imgui.WindowFlags.NoResize + imgui.WindowFlags.NoScrollbar + imgui.WindowFlags.NoMove)
    imgui.PushItemWidth(30)
    imgui.InputInt("##idplayersobes", idplayersobes, 0, 0)
    imgui.SameLine()
    imgui.TextColoredRGB(u8"{FF6347}ID игрока")
    imgui.PopItemWidth()
    imgui.SameLine()
    if imgui.Button(u8"Готово", imgui.ImVec2(100, 0)) then
        nameped = sampGetPlayerNickname(idplayersobes.v)
        id = idplayersobes.v
        errorwin.v = false
    end
    imgui.End()
end
 
  • Ха-ха
Реакции: whyega52

whyega52

Гений, миллионер, плейбой, долбаеб
Модератор
2,756
2,576
Вопросик такой, не знаешь как окно imgui сделать всегда на переднем плане, чтобы другие окна его не перекрывали?
В инете не нашел инфы об этом, поэтому предполагаю, что можно сделать через костыль (если я правильно понимаю логику приоритета рендера окон) : при появлении окна, которое перекрывает нужное, выключай и тут же включай окно, которое должно быть поверх
 
  • Нравится
Реакции: Pashyka

Dmitriy Makarov

25.05.2021
Проверенный
2,500
1,130
Вопросик такой, не знаешь как окно imgui сделать всегда на переднем плане, чтобы другие окна его не перекрывали?
На Гите нашёл. Поэкспериментируй с этими функциями.
Комментарии тоже переведи.
C++:
IMGUI_API void          SetNextWindowFocus();        // set next window to be focused / front-most. call before Begin()
IMGUI_API void          SetWindowFocus();        // (not recommended) set current window to be focused / front-most. prefer using SetNextWindowFocus().
IMGUI_API void          SetWindowFocus(const char* name);        // set named window to be focused / front-most. use NULL to remove focus.
 
  • Нравится
  • Вау
Реакции: Pashyka, ARMOR и whyega52

Pashyka

Участник
220
17
Спасибки)

Решил использовать PopupModal, все отлично, ноо, можно ли сделать чтобы было замыливание окна с которого был открыт Popup
1676826779155.png


Lua:
if imgui.BeginPopupModal(u8("Ввод айди"), _, imgui.WindowFlags.NoCollapse + imgui.WindowFlags.NoScrollbar + imgui.WindowFlags.AlwaysAutoResize) then
    imgui.PushItemWidth(30)
    imgui.InputInt("##idplayersobes", idplayersobes, 0, 0)
    imgui.SameLine()
    imgui.TextColoredRGB(u8"{FF6347}ID игрока")
    imgui.PopItemWidth()
    imgui.SameLine()
    if imgui.Button(u8"Готово", imgui.ImVec2(100, 0)) then
        nameped = sampGetPlayerNickname(idplayersobes.v)
        id = idplayersobes.v
        imgui.CloseCurrentPopup()
    end
    imgui.EndPopup()
end
 
Последнее редактирование:

Sadow

Известный
1,428
592
Как получать кастомный айди объекта? Тоесть айди заменки на объект которого нет в сампе
 
Последнее редактирование:

Smeruxa

Известный
1,350
719
Спасибки)

Решил использовать PopupModal, все отлично, ноо, можно ли сделать чтобы было замыливание окна с которого был открыт Popup
Посмотреть вложение 190625

Lua:
if imgui.BeginPopupModal(u8("Ввод айди"), _, imgui.WindowFlags.NoCollapse + imgui.WindowFlags.NoScrollbar + imgui.WindowFlags.AlwaysAutoResize) then
    imgui.PushItemWidth(30)
    imgui.InputInt("##idplayersobes", idplayersobes, 0, 0)
    imgui.SameLine()
    imgui.TextColoredRGB(u8"{FF6347}ID игрока")
    imgui.PopItemWidth()
    imgui.SameLine()
    if imgui.Button(u8"Готово", imgui.ImVec2(100, 0)) then
        nameped = sampGetPlayerNickname(idplayersobes.v)
        id = idplayersobes.v
        imgui.CloseCurrentPopup()
    end
    imgui.EndPopup()
end
Lua:
if imgui.BeginPopupModal(u8("Ввод айди"), _, imgui.WindowFlags.NoCollapse + imgui.WindowFlags.NoScrollbar + imgui.WindowFlags.AlwaysAutoResize) then
на
Lua:
if imgui.BeginPopup(u8("Ввод айди"), _, imgui.WindowFlags.NoCollapse + imgui.WindowFlags.NoScrollbar + imgui.WindowFlags.AlwaysAutoResize) then

минус к производительности
практически не повлияет, не беспокойся
 
  • Вау
Реакции: whyega52