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

ШPEK

Известный
1,476
525
Сделайте пример кода, если в чате будет [AguilarGang] тогда sampAddChatMessage("сообщение", 063971)

Код:
x, y, z = 1, 2, 3, 4
Код:
x, y = bar('zaphod')
Объясни это пожалуйста
Код:
x, y = bar('zaphod')
 
Последнее редактирование модератором:

штейн

Известный
Проверенный
1,001
687
Сделайте пример кода, если в чате будет [AguilarGang] тогда sampAddChatMessage("сообщение", 063971)

Lua:
local sampev = require 'lib.samp.events'  

function sampev.onServerMessage(color, text)
          if text:find('[AguilarGang]') then
            sampAddChatMessage("сообщение", -1)
        end
    end
 
Последнее редактирование:

ШPEK

Известный
1,476
525
Как сделать чтобы если игрок встанет на определенную позицию на карте, то будет какое-то действие?
 

brackets

Новичок
12
4
Как сделать чтобы если игрок встанет на определенную позицию на карте, то будет какое-то действие?
Lua:
function main()
  if not isSampfuncsLoaded() or not isSampLoaded() then return end
  while not isSampAvailable() do wait(100) end
        activate = true
    while true do
    wait(0)
            local x, y, z = getCharCoordinates(PLAYER_PED)
            if x == 1 and y == 1 and z == 1 and activate then
                sampAddChatMessage("Вы прибыли в точку назначения", -1)
                activate = false
            end
    end
end
 
  • Нравится
Реакции: ШPEK

ШPEK

Известный
1,476
525
Как рисовать gui окна?

Как использовать несколько переменных в sampsendchat?
 
Последнее редактирование модератором:

штейн

Известный
Проверенный
1,001
687
Lua:
function hitman()
    submenus_show(mod_submenus_sa, '{800000}Hitman Help v'..thisScript().version..'', 'Выбрать', 'Закрыть', 'Назад')
end
mod_submenus_sa = {
    {
        title = 'Информация о скрипте',
        onclick = function()
            sinfo()
        end
    },
    {
        title = 'Связаться с автором',
        onclick = function()
            svyaz()
        end
    },
    {
        title = ' '
    },
    {
        title = '{AAAAAA}Настройки'
    },
    {
        title = 'Настройки скрипта',
        submenu = {
            {
                title = 'Включить/выключить горячие клавиши.',
                onclick = function()
                    hotkey()
                end
            },
            {
                title = 'Включить/выключить автоматический скриншот при выполнение заказа.',
                onclick = function()
                    autoscr()
                end
            },
            {
                title = 'Включить/выключить сообщения скрипта в чат.',
                onclick = function()
                    messages()
                end
            },

            {
                title = 'Включить/выключить автоматическое обновление.',
                onclick = function()
                    haupd()
                end
            },
            {
                title = 'Включить/выключить мониторинг игроков в зоне стрима.',
                onclick = function()
                    stream()
                end
            },
        }
    },
    {
        title = ' '
    },
    {
        title = '{AAAAAA}Обновления'
    },
    {
        title = 'Принудительно обновить',
        onclick = function()
            lua_thread.create(goupdate)
        end
    },

}

function submenus_show(menu, caption, select_button, close_button, back_button)
    select_button, close_button, back_button = select_button or 'Select', close_button or 'Close', back_button or 'Back'
    prev_menus = {}
    function display(menu, id, caption)
        local string_list = {}
        for i, v in ipairs(menu) do
            table.insert(string_list, type(v.submenu) == 'table' and v.title .. '  >>' or v.title)
        end
        sampShowDialog(id, caption, table.concat(string_list, '\n'), select_button, (#prev_menus > 0) and back_button or close_button, 4)
        repeat
            wait(0)
            local result, button, list = sampHasDialogRespond()
            if result then
                if button == 1 and list ~= -1 then
                    local item = menu[list + 1]
                    if type(item.submenu) == 'table' then -- submenu
                        table.insert(prev_menus, {menu = menu, caption = caption})
                        if type(item.onclick) == 'function' then
                            item.onclick(menu, list + 1, item.submenu)
                        end
                        return display(item.submenu, id + 1, item.submenu.title and item.submenu.title or item.title)
                    elseif type(item.onclick) == 'function' then
                        local result = item.onclick(menu, list + 1)
                        if not result then return result end
                        return display(menu, id, caption)
                    end
                else -- if button == 0
                    if #prev_menus > 0 then
                        local prev_menu = prev_menus[#prev_menus]
                        prev_menus[#prev_menus] = nil
                        return display(prev_menu.menu, id - 1, prev_menu.caption)
                    end
                    return false
                end
            end
        until result
    end
    return display(menu, 31337, caption or menu.title)
end

почему он не хочет работать, короче сам диалог запускается, но когда пытаюсь прожать что-то, то ничего не происходит.
 

imring

Ride the Lightning
Всефорумный модератор
2,355
2,518
Как рисовать gui окна?
Что такое ImGui?
Начнём с самого элементарного:
Lua:
local imgui = require 'imgui' -- загружаем библиотеку

-- в этой функции осуществляется вся работа с ImGui
-- она вызывается каждый кадр, но только если imgui.Process равен true
function imgui.OnDrawFrame()
  imgui.Begin('My window') -- новое окно с заголовком 'My window'
  imgui.Text('Hello world') -- простой текст внутри этого окна
  imgui.End() -- конец окна
end

function main()
  imgui.Process = true -- ImGui будет обрабатываться, пока imgui.Process равен true
  -- в этом примере мы просто активируем ImGui сразу же после загрузки игры
end
Результат:
Посмотреть вложение 10002

Это работает, но что-то не впечатляет, согласитесь. Окно изначально маленькое, показывается сразу при старте и его нельзя закрыть.
Сделаем его побольше, добавим активацию и какое-нибудь действие:
Lua:
local imgui = require 'imgui'
local key = require 'vkeys'

-- одно из основных отличий от оригинального апи
-- все переменные, значения которых записываются в ImGui по указателю, могут использоваться только через специальные типы
local main_window_state = imgui.ImBool(false)
function imgui.OnDrawFrame()
  if main_window_state.v then -- чтение и запись значения такой переменной осуществляется через поле v (или Value)
    imgui.SetNextWindowSize(imgui.ImVec2(150, 200), imgui.Cond.FirstUseEver) -- меняем размер
    -- но для передачи значения по указателю - обязательно напрямую
    -- тут main_window_state передаётся функции imgui.Begin, чтобы можно было отследить закрытие окна нажатием на крестик
    imgui.Begin('My window', main_window_state)
    imgui.Text('Hello world')
    if imgui.Button('Press me') then -- а вот и кнопка с действием
      -- условие будет выполнено при нажатии на неё
      printStringNow('Button pressed!', 1000)
    end
    imgui.End()
  end
end

function main()
  while true do
    wait(0)
    if wasKeyPressed(key.VK_X) then -- активация по нажатию клавиши X
        main_window_state.v = not main_window_state.v -- переключаем статус активности окна, не забываем про .v
    end
    imgui.Process = main_window_state.v -- теперь значение imgui.Process всегда будет задаваться в зависимости от активности основного окна
  end
end
Теперь окно выглядит так и его можно скрыть:
Посмотреть вложение 10003

Работа с другими языками на примере русского
В MoonLoader v.025 были добавлены библиотеки lua-iconv и encoding, они призваны помочь в работе с разными кодировками текста.
Следующий пример показывает как использовать текст на русском в ImGui:
Скрипт должен быть сохранён в кодировке Windows-1251
Lua:
local imgui = require 'imgui'
local encoding = require 'encoding' -- загружаем библиотеку
encoding.default = 'CP1251' -- указываем кодировку по умолчанию, она должна совпадать с кодировкой файла. CP1251 - это Windows-1251
u8 = encoding.UTF8 -- и создаём короткий псевдоним для кодировщика UTF-8

local test_text_buffer = imgui.ImBuffer(256)
function imgui.OnDrawFrame()
  imgui.Begin(u8'Основное окно') -- обратите внимание на u8 перед текстом, это и есть преобразование кодировки
  if imgui.InputText(u8'Вводить текст сюда', test_text_buffer) then -- условие будет срабатывать при изменении текста
    -- здесь первая строка передаётся по-обычному, без u8
    -- но введённый текст при выводе преобразуется обратно из UTF-8 в кодировку по умолчанию, т.е. в Windows-1251
    print('Введённый текст:', u8:decode(test_text_buffer.v)) -- при работе с ImBuffer тоже не забывайте о .v
  end
  imgui.Text(u8'Введённый текст: ' .. test_text_buffer.v) -- но тут обратное преобразование введённого текста не требуется, т.к. текст буфера и так в UTF-8
  imgui.Text(u8(string.format('Текущая дата: %s', os.date()))) -- u8 - это функция, её можно использовать и с неконстантными строками
  imgui.End()
end

function main()
  imgui.Process = true
end
Результат:
Посмотреть вложение 10004
Как использовать несколько переменных в sampsendchat?
Lua:
local a = 'ti '
local b = '...'
sampSendChat(a..b)
 
  • Нравится
Реакции: Quasper

rraggerr

проверенный какой-то
1,626
847
Обратите внимание, пользователь заблокирован на форуме. Не рекомендуется проводить сделки.
Ищи проблему у себя. Код ниже полностью рабочий.
imgui._VERSION = '1.1.2'
MoonLoader v.026.3-beta loaded.
Lua:
local imgui = require 'imgui';

local show_main_window = imgui.ImBool(true);

local sliderValue = imgui.ImFloat(0.0)
local fixedValue = 15.5

function main()
    while true do
        wait(0)
        imgui.Process = show_main_window.v
    end
end

function imgui.OnDrawFrame()
    if show_main_window.v then
        imgui.SetNextWindowSize(imgui.ImVec2(350,560), imgui.Cond.FirstUseEver)
        imgui.Begin(script.this.name, show_main_window)
        if imgui.Button('Test') then
            sliderValue.Value = fixedValue
        end

        imgui.SliderFloat('testSlider', sliderValue, 0.0, 60.0)

        imgui.End()
    end
end
та не, ошибка оказалась именно в конфиге) Враг напал оттуда откуда я его не ожидал)
 

itsLegend

Фонд борьбы за жуков 🐞
Администратор
2,696
1,462
Lua:
function hitman()
    submenus_show(mod_submenus_sa, '{800000}Hitman Help v'..thisScript().version..'', 'Выбрать', 'Закрыть', 'Назад')
end
mod_submenus_sa = {
    {
        title = 'Информация о скрипте',
        onclick = function()
            sinfo()
        end
    },
    {
        title = 'Связаться с автором',
        onclick = function()
            svyaz()
        end
    },
    {
        title = ' '
    },
    {
        title = '{AAAAAA}Настройки'
    },
    {
        title = 'Настройки скрипта',
        submenu = {
            {
                title = 'Включить/выключить горячие клавиши.',
                onclick = function()
                    hotkey()
                end
            },
            {
                title = 'Включить/выключить автоматический скриншот при выполнение заказа.',
                onclick = function()
                    autoscr()
                end
            },
            {
                title = 'Включить/выключить сообщения скрипта в чат.',
                onclick = function()
                    messages()
                end
            },

            {
                title = 'Включить/выключить автоматическое обновление.',
                onclick = function()
                    haupd()
                end
            },
            {
                title = 'Включить/выключить мониторинг игроков в зоне стрима.',
                onclick = function()
                    stream()
                end
            },
        }
    },
    {
        title = ' '
    },
    {
        title = '{AAAAAA}Обновления'
    },
    {
        title = 'Принудительно обновить',
        onclick = function()
            lua_thread.create(goupdate)
        end
    },

}

function submenus_show(menu, caption, select_button, close_button, back_button)
    select_button, close_button, back_button = select_button or 'Select', close_button or 'Close', back_button or 'Back'
    prev_menus = {}
    function display(menu, id, caption)
        local string_list = {}
        for i, v in ipairs(menu) do
            table.insert(string_list, type(v.submenu) == 'table' and v.title .. '  >>' or v.title)
        end
        sampShowDialog(id, caption, table.concat(string_list, '\n'), select_button, (#prev_menus > 0) and back_button or close_button, 4)
        repeat
            wait(0)
            local result, button, list = sampHasDialogRespond()
            if result then
                if button == 1 and list ~= -1 then
                    local item = menu[list + 1]
                    if type(item.submenu) == 'table' then -- submenu
                        table.insert(prev_menus, {menu = menu, caption = caption})
                        if type(item.onclick) == 'function' then
                            item.onclick(menu, list + 1, item.submenu)
                        end
                        return display(item.submenu, id + 1, item.submenu.title and item.submenu.title or item.title)
                    elseif type(item.onclick) == 'function' then
                        local result = item.onclick(menu, list + 1)
                        if not result then return result end
                        return display(menu, id, caption)
                    end
                else -- if button == 0
                    if #prev_menus > 0 then
                        local prev_menu = prev_menus[#prev_menus]
                        prev_menus[#prev_menus] = nil
                        return display(prev_menu.menu, id - 1, prev_menu.caption)
                    end
                    return false
                end
            end
        until result
    end
    return display(menu, 31337, caption or menu.title)
end

почему он не хочет работать, короче сам диалог запускается, но когда пытаюсь прожать что-то, то ничего не происходит.
submenus_show должна вызываться из main, либо в другом потоке.
 

штейн

Известный
Проверенный
1,001
687
submenus_show должна вызываться из main, либо в другом потоке.
if menutrigger ~= nil then menu() menutrigger = nil end
стоит в бесконечном, но как ты понимаешь всё равно не хочет, не оч шарю в submenus
 
Последнее редактирование:

Quasper

Известный
834
354
Ребят, подсобите. Как получить ид 3d текста? хочу оттуда вытащить текст
 

rraggerr

проверенный какой-то
1,626
847
Обратите внимание, пользователь заблокирован на форуме. Не рекомендуется проводить сделки.
  • Нравится
Реакции: Quasper

Cameron_Bawerman

Участник
99
1
Подскажите или исправте что у меня не так что диалог не работает, или работает один раз а после перезапускать скрипт нужно
Lua:
local sampev = require "lib.samp.events"
local key = require "vkeys"

function main()
    if not isSampfuncsLoaded() or not isSampLoaded() then
        return
    end
    while not isSampAvailable() do wait (0) end
    sampAddChatMessage("{ffffff}• {4682B4}[Goska LVPD] {ffffff}Скрипт готов к работе.",-1)
    sampRegisterChatCommand("te", testih)
end


function testih() -- 11 строка
sampShowDialog(102, "{4682B4}[Goska DRP]: {ffffff}Гос.Новости", string.format("{4682B4}1. 22\n{4682B4}2.  33\n{4682B4}3.44"), "Ok", "Exit", 2)
repeat
wait (0)
result, button, list, input = sampHasDialogRespond(102)
lua_thread.create(function() -- Создаем новый поток
wait(1000)
until result
if list == 0 and button == 1 then
sampSendChat("Ку епта2")
elseif list == 1 and button == 1 then
sampSendChat("Ку епта2")
elseif list == 2 and button == 1 then
sampSendChat("Ку епта3")
end -- 23строка
end
 

RTD

Нестандартное звание
Модератор
391
414
Подскажите или исправте что у меня не так что диалог не работает, или работает один раз а после перезапускать скрипт нужно
Lua:
local sampev = require "lib.samp.events"
local key = require "vkeys"

function main()
    if not isSampfuncsLoaded() or not isSampLoaded() then
        return
    end
    while not isSampAvailable() do wait (0) end
    sampAddChatMessage("{ffffff}• {4682B4}[Goska LVPD] {ffffff}Скрипт готов к работе.",-1)
    sampRegisterChatCommand("te", testih)
end


function testih() -- 11 строка
sampShowDialog(102, "{4682B4}[Goska DRP]: {ffffff}Гос.Новости", string.format("{4682B4}1. 22\n{4682B4}2.  33\n{4682B4}3.44"), "Ok", "Exit", 2)
repeat
wait (0)
result, button, list, input = sampHasDialogRespond(102)
lua_thread.create(function() -- Создаем новый поток
wait(1000)
until result
if list == 0 and button == 1 then
sampSendChat("Ку епта2")
elseif list == 1 and button == 1 then
sampSendChat("Ку епта2")
elseif list == 2 and button == 1 then
sampSendChat("Ку епта3")
end -- 23строка
end
Lua:
function testih()
    sampShowDialog(102, "{4682B4}[Goska DRP]: {ffffff}Гос.Новости", string.format("{4682B4}1. 22\n{4682B4}2.  33\n{4682B4}3.44"), "Ok", "Exit", 2)
    lua_thread.create(function() -- Создаем новый поток
        repeat
        wait(0)
        result, button, list, input = sampHasDialogRespond(102)
        until result
        if button == 1 then
            if list == 0 then
                sampSendChat("Ку епта2")
            elseif list == 1 then
                sampSendChat("Ку епта2")
            elseif list == 2 then
                sampSendChat("Ку епта3")
            end
        end
    end)
end
 
  • Нравится
Реакции: Cameron_Bawerman