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

Мира

Известный
456
9
Lua:
local specc = false
function se.onTogglePlayerSpectating(state)
    specc = state
end

function se.onSpectatePlayer(id, type)
    if specc then
        if sampGetPlayerNickname(id) ==
    end
end
если без проверок нажатия, то не работает. как исправить?
Lua:
function sampev.onTogglePlayerSpectating(state)

    spect = state

end

function sampev.onSpectatePlayer(playerId, camType)

    if spect then
        if isKeyJustPressed(VK_LSHIFT) and not sampIsChatInputActive() and not sampIsDialogActive() then
            --sampSendChat('/re '..playerId)
            sampAddChatMessage('++')
        end
    end

end
 

dendy.

Активный
347
68

Установка​

Ручная установка — .rar архив

Все файлы из папки ОБТ переместить в папку moonloader.
Файл port.luac сконвертирует профили от ScriptPatrol для SnailMatic.
Папка lib содержит все нужные для работы биндера библиотеки.
После успешного запуска биндера в игре создастся папка с настройками и профилями биндера по пути «C:\Users\user\Documents\GTA San Andreas User Files\SAMP»

Требования для биндера и его запуск​

Требования​

Для работы биндера требуется MoonLoader версии 0.26.5+ и библиотеки Moonloader: mimgui, fa-icons, copas. (скачивать библиотеки отдельно не нужно, всё идет в архиве с биндером)

Биндер совместим с SA-MP 0.3.7 R1, R3, 0.3DL, CRMP и независим от SAMPFUNCS и CLEO.
Работает на лаунчерах, где разрешено устанавливать моды (в частности moonloader).
 

Мира

Известный
456
9
нашёл такой опкод, но не могу найти на lua (если это тоже луа, то не знаю как работать с опкодами).
есть тоже взаимодействие с игроком через таб?
1634065800538.png
 

bottom_text

Известный
676
325

linmsqn

Известный
331
10
как сделать closebutton вечно активной? типо мне нужно чтобы она была вечно с вот таким крестиком
1634066675443.png
даже без наведения на нее, а то у меня она вечно без наведения вот такая
1634066697307.png
 
Последнее редактирование:

Anton Nixon

Известный
474
48
вопрос такого характера, есть такой вот код чекера

lua:
if imgui_imbool.friend_online.v then -- друзья в сети
                FriendTitle = "Друзья в сети:"
                renderFontDrawText(friendfont, FriendTitle, check_X, check_Y, 4211081215)
                local string_friend_height = renderGetFontDrawHeight(friendfont)
                local new_Y = string_friend_height + 0.5
                check_Y = check_Y - new_Y
                local last_friend_list = ""
                local count = 1
                local FriendText = ""
                for k, v in pairs(friends) do
                    friendStreamed = sampGetCharHandleBySampPlayerId(idbynick(v.nick))
                    friendPaused = sampIsPlayerPaused(idbynick(v.nick))
                    friendColor = sampGetPlayerColor(idbynick(v.nick))
                    local aa, rr, gg, bb = explode_argb(friendColor)
                    if sampIsLocalPlayerSpawned() then
                        if sampIsPlayerConnected(idbynick(v.nick)) then
                            if friendStreamed then
                                if friendPaused then
                                    friendList = string.format("{%0.2X%0.2X%0.2X}%i. %s [%i] {FF0000}[AFK] {808080}[#]", rr, gg, bb, count, v.nick, idbynick(v.nick))
                                else
                                    friendList = string.format("{%0.2X%0.2X%0.2X}%i. %s [%i] {808080}[#]", rr, gg, bb, count, v.nick, idbynick(v.nick))
                                end
                            else
                                friendList = string.format("{%0.2X%0.2X%0.2X}%i. %s [%i]", rr, gg, bb, count, v.nick, idbynick(v.nick))
                            end
                            count = count + 1
                            FriendText = string.format("%s\n", friendList)
                        end
                    end
                    local string_lead_height = renderGetFontDrawHeight(friendfont)
                    if last_friend_list ~= friendList then
                        local new_Y = string_friend_height + 0.5
                        check_Y = check_Y + new_Y
                        renderFontDrawText(friendfont, FriendText, check_X, check_Y, 4294967295)
                    end
                    last_friend_list = friendList
                end
                if FriendText:len() <= 0 then
                    FriendText = '{808080}Друзей в сети нет'
                    local new_Y = string_friend_height + 0.5
                    check_Y = check_Y + new_Y
                    renderFontDrawText(friendfont, FriendText, check_X, check_Y, 1694498815)
                end
                local string_friend_height = renderGetFontDrawHeight(friendfont)
                local new_Y = string_friend_height * 1.3
                check_Y = check_Y + new_Y
            end
Вот так это выглядит
sa-mp-000.png

Все работает +- хорошо, но когда сети всего лишь один человек из списка, то ничего не отображается
9FHLnmBfqPA.jpg

Помогите исправить, чтобы все ровно отображалось
 

qwеty

Известный
490
158
Чего так мало отступов, можно было бы побольше сделать...
Примерное такое:
mimgui:
function imgui.TextButton(text, bool)
    imgui.TextColoredRGB(string.format('[  %s', bool[0] and '{00ff00}ON' or '{ff0000}OFF'))
    if imgui.IsItemClicked() then bool[0] = not bool[0] end
    imgui.SameLine()
    imgui.Text('] '..text)
    return bool[0]
end

--Usage:
local active = imgui.new.bool(false)

--render
imgui.TextButton('func', active)
moonimgui:
function imgui.TextButton(text, bool)
    imgui.TextColoredRGB(string.format('[  %s', bool.v and '{00ff00}ON' or '{ff0000}OFF'))
    if imgui.IsItemClicked() then bool.v = not bool.v end
    imgui.SameLine()
    imgui.Text('] '..text)
    return bool.v
end

--Usage:
local active = imgui.ImBool(false)

--render
imgui.TextButton('func', active)
В чём проблема? При нажатии на imgui.TextButton в конфиг сохраняется значение true, нажимаю ещё раз и значение в конфиге должно было бы измениться на false, но оно не изменяется, а остается положительным, то есть true (после нажатия функция всё время возвращает true). В свою очередь, с imgui.Checkbox всё нормально работает, значения сохраняються как и должны сохраняться.
jopa:
require 'lib.moonloader'

local imgui = require 'imgui'
local encoding = require 'encoding'
encoding.default = 'CP1251'
u8 = encoding.UTF8
local inicfg = require 'inicfg'

local window_menu = imgui.ImBool(false)
local sw, sh = getScreenResolution()

local directIni = 'moonloader/config/imguihui.ini'
local mainIni = inicfg.load({
    config = {
            func = false,
            func1 = false
        }
}, directIni)

local func = imgui.ImBool(mainIni.config.func)
local func1 = imgui.ImBool(mainIni.config.func1)

function main()
    while not isSampAvailable() do wait(100) end
        if not doesFileExist('moonloader/config/imguihui.ini') then inicfg.save(mainIni, 'imguihui.ini') end
        sampRegisterChatCommand('window', windowmenu)
        while true do
            wait(0)
        end
end

function windowmenu()
    window_menu.v = not window_menu.v
    imgui.Process = window_menu.v
end

function imgui.TextColoredRGB(text)
    local style = imgui.GetStyle()
    local colors = style.Colors
    local ImVec4 = imgui.ImVec4

    local explode_argb = function(argb)
        local a = bit.band(bit.rshift(argb, 24), 0xFF)
        local r = bit.band(bit.rshift(argb, 16), 0xFF)
        local g = bit.band(bit.rshift(argb, 8), 0xFF)
        local b = bit.band(argb, 0xFF)
        return a, r, g, b
    end

    local getcolor = function(color)
        if color:sub(1, 6):upper() == 'SSSSSS' then
            local r, g, b = colors[1].x, colors[1].y, colors[1].z
            local a = tonumber(color:sub(7, 8), 16) or colors[1].w * 255
            return ImVec4(r, g, b, a / 255)
        end
        local color = type(color) == 'string' and tonumber(color, 16) or color
        if type(color) ~= 'number' then return end
        local r, g, b, a = explode_argb(color)
        return imgui.ImColor(r, g, b, a):GetVec4()
    end

    local render_text = function(text_)
        for w in text_:gmatch('[^\r\n]+') do
            local text, colors_, m = {}, {}, 1
            w = w:gsub('{(......)}', '{%1FF}')
            while w:find('{........}') do
                local n, k = w:find('{........}')
                local color = getcolor(w:sub(n + 1, k - 1))
                if color then
                    text[#text], text[#text + 1] = w:sub(m, n - 1), w:sub(k + 1, #w)
                    colors_[#colors_ + 1] = color
                    m = n
                end
                w = w:sub(1, n - 1) .. w:sub(k + 1, #w)
            end
            if text[0] then
                for i = 0, #text do
                    imgui.TextColored(colors_[i] or colors[1], u8(text[i]))
                    imgui.SameLine(nil, 0)
                end
                imgui.NewLine()
            else imgui.Text(u8(w)) end
        end
    end
        render_text(text)
end

function imgui.TextButton(text, bool)
    imgui.TextColoredRGB(string.format('[    %s', bool.v and '{00ff00}ON' or '{ff0000}OFF'))
    if imgui.IsItemClicked() then bool.v = not bool.v end
    imgui.SameLine()
    imgui.Text('  ]  '..text)
    return bool.v
end

function imgui.OnDrawFrame()
        if window_menu.v then
            imgui.SetNextWindowSize(imgui.ImVec2(180, 320), imgui.Cond.FirstUseEver)
            imgui.SetNextWindowPos(imgui.ImVec2(sw / 2, sh / 2), imgui.Cond.FirstUseEver, imgui.ImVec2(0.5, 0.5))
            imgui.ShowCursor = true
            imgui.Begin('Window')
            if imgui.TextButton('gmcar1', func1) then
                mainIni.config.func1 = func1.v
                inicfg.save(mainIni, 'imguihui.ini')
            end
            if imgui.Checkbox('gmcar', func) then
                mainIni.config.func = func.v
                inicfg.save(mainIni, 'imguihui.ini')
            end
        else
            imgui.ShowCursor = false
        end
        imgui.End()
end
 
Последнее редактирование:

ARMOR

God has forsaken us
Модератор
5,067
7,436
В чём проблема? При нажатии на imgui.TextButton в конфиг сохраняется значение true, нажимаю ещё раз и значение в конфиге должно было бы измениться на false, но оно не изменяеться, а остаеться положительным, то есть true. В свою очередь, с imgui.Checkbox всё нормально работает, значения сохраняються как и должны сохраняться.
jopa:
require 'lib.moonloader'

local imgui = require 'imgui'
local encoding = require 'encoding'
encoding.default = 'CP1251'
u8 = encoding.UTF8
local inicfg = require 'inicfg'

local window_menu = imgui.ImBool(false)
local sw, sh = getScreenResolution()

local directIni = 'moonloader/config/imguihui.ini'
local mainIni = inicfg.load({
    config = {
            func = false,
            func1 = false
        }
}, directIni)

local func = imgui.ImBool(mainIni.config.func)
local func1 = imgui.ImBool(mainIni.config.func1)

function main()
    while not isSampAvailable() do wait(100) end
        if not doesFileExist('moonloader/config/imguihui.ini') then inicfg.save(mainIni, 'imguihui.ini') end
        sampRegisterChatCommand('window', windowmenu)
        while true do
            wait(0)
        end
end

function windowmenu()
    window_menu.v = not window_menu.v
    imgui.Process = window_menu.v
end

function imgui.TextColoredRGB(text)
    local style = imgui.GetStyle()
    local colors = style.Colors
    local ImVec4 = imgui.ImVec4

    local explode_argb = function(argb)
        local a = bit.band(bit.rshift(argb, 24), 0xFF)
        local r = bit.band(bit.rshift(argb, 16), 0xFF)
        local g = bit.band(bit.rshift(argb, 8), 0xFF)
        local b = bit.band(argb, 0xFF)
        return a, r, g, b
    end

    local getcolor = function(color)
        if color:sub(1, 6):upper() == 'SSSSSS' then
            local r, g, b = colors[1].x, colors[1].y, colors[1].z
            local a = tonumber(color:sub(7, 8), 16) or colors[1].w * 255
            return ImVec4(r, g, b, a / 255)
        end
        local color = type(color) == 'string' and tonumber(color, 16) or color
        if type(color) ~= 'number' then return end
        local r, g, b, a = explode_argb(color)
        return imgui.ImColor(r, g, b, a):GetVec4()
    end

    local render_text = function(text_)
        for w in text_:gmatch('[^\r\n]+') do
            local text, colors_, m = {}, {}, 1
            w = w:gsub('{(......)}', '{%1FF}')
            while w:find('{........}') do
                local n, k = w:find('{........}')
                local color = getcolor(w:sub(n + 1, k - 1))
                if color then
                    text[#text], text[#text + 1] = w:sub(m, n - 1), w:sub(k + 1, #w)
                    colors_[#colors_ + 1] = color
                    m = n
                end
                w = w:sub(1, n - 1) .. w:sub(k + 1, #w)
            end
            if text[0] then
                for i = 0, #text do
                    imgui.TextColored(colors_[i] or colors[1], u8(text[i]))
                    imgui.SameLine(nil, 0)
                end
                imgui.NewLine()
            else imgui.Text(u8(w)) end
        end
    end
        render_text(text)
end

function imgui.TextButton(text, bool)
    imgui.TextColoredRGB(string.format('[    %s', bool.v and '{00ff00}ON' or '{ff0000}OFF'))
    if imgui.IsItemClicked() then bool.v = not bool.v end
    imgui.SameLine()
    imgui.Text('  ]  '..text)
    return bool.v
end

function imgui.OnDrawFrame()
        if window_menu.v then
            imgui.SetNextWindowSize(imgui.ImVec2(180, 320), imgui.Cond.FirstUseEver)
            imgui.SetNextWindowPos(imgui.ImVec2(sw / 2, sh / 2), imgui.Cond.FirstUseEver, imgui.ImVec2(0.5, 0.5))
            imgui.ShowCursor = true
            imgui.Begin('Window')
            if imgui.TextButton('gmcar1', func1) then
                mainIni.config.func1 = func1.v
                inicfg.save(mainIni, 'imguihui.ini')
            end
            if imgui.Checkbox('gmcar', func) then
                mainIni.config.func = func.v
                inicfg.save(mainIni, 'imguihui.ini')
            end
        else
            imgui.ShowCursor = false
        end
        imgui.End()
end
jopa:
require 'lib.moonloader'

local imgui = require 'imgui'
local encoding = require 'encoding'
encoding.default = 'CP1251'
u8 = encoding.UTF8
local inicfg = require 'inicfg'

local window_menu = imgui.ImBool(false)
local sw, sh = getScreenResolution()

local directIni = 'moonloader/config/imguihui.ini'
local mainIni = inicfg.load({
    config = {
            func = false,
            func1 = false
        }
}, directIni)

local func = imgui.ImBool(mainIni.config.func)
local textbutton = imgui.ImBool(mainIni.config.func)

function main()
    while not isSampAvailable() do wait(100) end
        if not doesFileExist('moonloader/config/imguihui.ini') then inicfg.save(mainIni, 'imguihui.ini') end
        sampRegisterChatCommand('window', windowmenu)
        while true do
            wait(0)
        end
end

function windowmenu()
    window_menu.v = not window_menu.v
    imgui.Process = window_menu.v
end

function imgui.TextColoredRGB(text)
    local style = imgui.GetStyle()
    local colors = style.Colors
    local ImVec4 = imgui.ImVec4

    local explode_argb = function(argb)
        local a = bit.band(bit.rshift(argb, 24), 0xFF)
        local r = bit.band(bit.rshift(argb, 16), 0xFF)
        local g = bit.band(bit.rshift(argb, 8), 0xFF)
        local b = bit.band(argb, 0xFF)
        return a, r, g, b
    end

    local getcolor = function(color)
        if color:sub(1, 6):upper() == 'SSSSSS' then
            local r, g, b = colors[1].x, colors[1].y, colors[1].z
            local a = tonumber(color:sub(7, 8), 16) or colors[1].w * 255
            return ImVec4(r, g, b, a / 255)
        end
        local color = type(color) == 'string' and tonumber(color, 16) or color
        if type(color) ~= 'number' then return end
        local r, g, b, a = explode_argb(color)
        return imgui.ImColor(r, g, b, a):GetVec4()
    end

    local render_text = function(text_)
        for w in text_:gmatch('[^\r\n]+') do
            local text, colors_, m = {}, {}, 1
            w = w:gsub('{(......)}', '{%1FF}')
            while w:find('{........}') do
                local n, k = w:find('{........}')
                local color = getcolor(w:sub(n + 1, k - 1))
                if color then
                    text[#text], text[#text + 1] = w:sub(m, n - 1), w:sub(k + 1, #w)
                    colors_[#colors_ + 1] = color
                    m = n
                end
                w = w:sub(1, n - 1) .. w:sub(k + 1, #w)
            end
            if text[0] then
                for i = 0, #text do
                    imgui.TextColored(colors_[i] or colors[1], u8(text[i]))
                    imgui.SameLine(nil, 0)
                end
                imgui.NewLine()
            else imgui.Text(u8(w)) end
        end
    end
        render_text(text)
end

function imgui.TextButton(text, bool)
    imgui.TextColoredRGB(string.format('[    %s', bool.v and '{00ff00}ON' or '{ff0000}OFF'))
    if imgui.IsItemClicked() then bool.v = not bool.v end
    imgui.SameLine()
    imgui.Text('  ]  '..text)
    return bool.v
end

function imgui.OnDrawFrame()
        if window_menu.v then
            imgui.SetNextWindowSize(imgui.ImVec2(180, 320), imgui.Cond.FirstUseEver)
            imgui.SetNextWindowPos(imgui.ImVec2(sw / 2, sh / 2), imgui.Cond.FirstUseEver, imgui.ImVec2(0.5, 0.5))
            imgui.ShowCursor = true
            imgui.Begin('Window')
            if imgui.TextButton('gmcar1', func1) then
                textbutton = not textbutton
                mainIni.config.func1 = textbutton
                inicfg.save(mainIni, 'imguihui.ini')
            end
            if imgui.Checkbox('gmcar', func) then
                mainIni.config.func = func.v
                inicfg.save(mainIni, 'imguihui.ini')
            end
        else
            imgui.ShowCursor = false
        end
        imgui.End()
end
 

Shepi

Активный
177
36
Как можно через testCheat на одну клавишу показать курсор и скрыть его?
 

Dmitriy Makarov

25.05.2021
Проверенный
2,512
1,139
как выровнять кнопки по длине?
В смысле? Не особо понял, поэтому лови эти 3 варианта. Надеюсь там подходящий тебе есть.
ezgif-4-eebfeba75cf9.gif

Lua:
imgui.Button("Button 1", imgui.ImVec2(80, 50)) -- Тут меняется размер кнопки по X(80) и Y(50)

imgui.SetCursorPos(imgui.ImVec2(100, 100)) -- Меняем расположение кнопки ниже по X(100) и Y(100)
imgui.Button("Button 2") -- Изменится расположение этой кнопки.
-- Если хочешь только по X или только по Y, то есть функции: imgui.SetCursorPosX(pos), imgui.SetCursorPosY(pos)

imgui.Button("Button 3", imgui.ImVec2(-1, 50)) -- Если -1 поставить то будет так как на видео (хз как объяснить это)

Как можно через testCheat на одну клавишу показать курсор и скрыть его?
Lua:
-- while true do
if testCheat("C") then -- На английскую C курсор будет активироваться/деактивироваться
    cursorEnabled = not cursorEnabled
    showCursor(cursorEnabled)
end
 
Последнее редактирование:
  • Влюблен
Реакции: Shepi

Rice.

Известный
Модератор
1,758
1,714
Как узнать уровень игрока? Использовал sampGetPlayerScore и оно то нормально работает, то крашит. Есть ли другой способ?
Код:
sampRegisterChatCommand('score', function(arg)
    if sampIsPlayerConnected(tonumber(arg)) then
        sampAddChatMessage(sampGetPlayerScore(tonumber(arg)), -1)
    end
end)
P.S. Краш скрипта происходит из-за того, что ты пытаешься вывести уровень человека, которого нет в игре
 
Последнее редактирование:

nightaiga

Известный
301
120
Lua:
openStats = true
sampSendChat('/stats')

function sampev.onShowDialog(dialogid, style, title, button1, button2, text)
    if openStats and dialogid == 1500 then
        text:match('{66FFCC}Эксперт')
    else
        thisScript():unload()
        openStats = false
        return false
   end
что не так? скрипт оффается ещё до того как игрок не зашёл на сервер