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

chapo

tg/inst: @moujeek
Всефорумный модератор
9,258
12,701
Хелп, нужно что бы функция выполнялась каждый раз при входе в игру. При перезапуске скрипта она не должна работать, как это можно сделать?
Lua:
local sampev = require 'lib.samp.events'
local workay_suka = true

function sampev.onSendClientJoin(version, mod, nickname, response, authKey, clientVer, response2)
    if workay_suka then
        workay_suka = false -- что бы не срабатывало после реконнекта
        --code
    end
end
 

barjik

Известный
458
190
Почему при перезагрузке moonloader'a, и при перезаходе в игру значение не сохраняется?
Lua:
require "lib.moonloader"
local imgui = require "imgui"
local encoding = require "encoding"
encoding.default = "CP1251"
u8 = encoding.UTF8

local inicfg = require 'inicfg'
local cfg = inicfg.load({
    settings = {
        rpgun = true
        }
}, "GUNS")

local one_window = imgui.ImBool(false)
local two_window = imgui.ImBool(false)
local imgui = require 'imgui'
checkbox = imgui.ImBool(false)

function main()
    if not isSampLoaded() or not isSampfuncsLoaded() then return end
        while not isSampAvailable() do wait(100) end
        sampRegisterChatCommand("h1", cmd_h1)
        sampRegisterChatCommand("h2", cmd_h2)
        while true do
           wait(0)   

        if lastgun ~= getCurrentCharWeapon(PLAYER_PED) and cfg.settings.rpgun then
            local gun = getCurrentCharWeapon(PLAYER_PED)
            if gun == 23 then
                sampSendChat('/me достал taser-x24 из кобуры')
            elseif gun == 24 then
                sampSendChat('/me достал пистолет Desert Eagle из кобуры')
            elseif gun == 25 then
                sampSendChat('/me достал Shotgun n из-за спины')
            elseif gun == 28 then
                sampSendChat('/me достал Micro Uzi из-за спины')
            elseif gun == 29 then
                sampSendChat('/me взял MP-5 в руки')
            elseif gun == 30 then
                sampSendChat('/me взял автомат АК-47 в руки')
            elseif gun == 31 then
                sampSendChat('/me взял карабин М4А1 в руки')
            elseif gun == 33 then
                sampSendChat('/me взял винтовку в руки')
            elseif gun == 34 then
                sampSendChat('/me взял снайперскую винтовку в руки')
            elseif gun == 0 then
                sampSendChat('/me убрал оружие')
            end
            lastgun = gun   
            
            end
        end
    end           

function cmd_h1()
    one_window.v = not one_window.v
    imgui.Process = one_window.v
end

function cmd_h2()
    two_window.v = not two_window.v
    imgui.Process = two_window.v
end

function imgui.OnDrawFrame()
    if not one_window.v and not two_window.v then
    imgui.Process = false
    end
    
    if one_window.v then
    imgui.Begin(u8"okno1", one_window)
    if imgui.Checkbox(u8' RP guns', checkbox) then
    cfg.settings.rpgun = not cfg.settings.rpgun
    if cfg.settings.rpgun then
      sampAddChatMessage('{FFFFFF}Отыгровка оружия {008000}включена.', -1)   
    else
      sampAddChatMessage('{FFFFFF}Отыгровка оружия {FF0000}выключена.', -1)       
    end
end
imgui.End()
end

    if two_window.v then
    imgui.Begin(u8"okno2", two_window)
    imgui.Text(u8"hi")
    imgui.End()
    end
end

function onScriptTerminate(script, quitGame)
  if script == thisScript() then
    inicfg.save(cfg, "GUNS")
    end
end
 

Sanchez.

Известный
704
190
Почему при перезагрузке moonloader'a, и при перезаходе в игру значение не сохраняется?
Lua:
require "lib.moonloader"
local imgui = require "imgui"
local encoding = require "encoding"
encoding.default = "CP1251"
u8 = encoding.UTF8

local inicfg = require 'inicfg'
local cfg = inicfg.load({
    settings = {
        rpgun = true
        }
}, "GUNS")

local one_window = imgui.ImBool(false)
local two_window = imgui.ImBool(false)
local imgui = require 'imgui'
checkbox = imgui.ImBool(false)

function main()
    if not isSampLoaded() or not isSampfuncsLoaded() then return end
        while not isSampAvailable() do wait(100) end
        sampRegisterChatCommand("h1", cmd_h1)
        sampRegisterChatCommand("h2", cmd_h2)
        while true do
           wait(0)  

        if lastgun ~= getCurrentCharWeapon(PLAYER_PED) and cfg.settings.rpgun then
            local gun = getCurrentCharWeapon(PLAYER_PED)
            if gun == 23 then
                sampSendChat('/me достал taser-x24 из кобуры')
            elseif gun == 24 then
                sampSendChat('/me достал пистолет Desert Eagle из кобуры')
            elseif gun == 25 then
                sampSendChat('/me достал Shotgun n из-за спины')
            elseif gun == 28 then
                sampSendChat('/me достал Micro Uzi из-за спины')
            elseif gun == 29 then
                sampSendChat('/me взял MP-5 в руки')
            elseif gun == 30 then
                sampSendChat('/me взял автомат АК-47 в руки')
            elseif gun == 31 then
                sampSendChat('/me взял карабин М4А1 в руки')
            elseif gun == 33 then
                sampSendChat('/me взял винтовку в руки')
            elseif gun == 34 then
                sampSendChat('/me взял снайперскую винтовку в руки')
            elseif gun == 0 then
                sampSendChat('/me убрал оружие')
            end
            lastgun = gun  
           
            end
        end
    end          

function cmd_h1()
    one_window.v = not one_window.v
    imgui.Process = one_window.v
end

function cmd_h2()
    two_window.v = not two_window.v
    imgui.Process = two_window.v
end

function imgui.OnDrawFrame()
    if not one_window.v and not two_window.v then
    imgui.Process = false
    end
   
    if one_window.v then
    imgui.Begin(u8"okno1", one_window)
    if imgui.Checkbox(u8' RP guns', checkbox) then
    cfg.settings.rpgun = not cfg.settings.rpgun
    if cfg.settings.rpgun then
      sampAddChatMessage('{FFFFFF}Отыгровка оружия {008000}включена.', -1)  
    else
      sampAddChatMessage('{FFFFFF}Отыгровка оружия {FF0000}выключена.', -1)      
    end
end
imgui.End()
end

    if two_window.v then
    imgui.Begin(u8"okno2", two_window)
    imgui.Text(u8"hi")
    imgui.End()
    end
end

function onScriptTerminate(script, quitGame)
  if script == thisScript() then
    inicfg.save(cfg, "GUNS")
    end
end
Lua:
require "lib.moonloader"
local imgui = require "imgui"
local encoding = require "encoding"
encoding.default = "CP1251"
u8 = encoding.UTF8

local inicfg = require 'inicfg'
local cfg = inicfg.load({
    settings = {
        rpgun = true
        }
}, "GUNS")

local one_window = imgui.ImBool(false)
local two_window = imgui.ImBool(false)
local imgui = require 'imgui'
checkbox = imgui.ImBool(cfg.settings.rpgun)

function main()
    if not isSampLoaded() or not isSampfuncsLoaded() then return end
        while not isSampAvailable() do wait(100) end
        sampRegisterChatCommand("h1", cmd_h1)
        sampRegisterChatCommand("h2", cmd_h2)
        while true do
           wait(0)   

        if lastgun ~= getCurrentCharWeapon(PLAYER_PED) and cfg.settings.rpgun then
            local gun = getCurrentCharWeapon(PLAYER_PED)
            if gun == 23 then
                sampSendChat('/me достал taser-x24 из кобуры')
            elseif gun == 24 then
                sampSendChat('/me достал пистолет Desert Eagle из кобуры')
            elseif gun == 25 then
                sampSendChat('/me достал Shotgun n из-за спины')
            elseif gun == 28 then
                sampSendChat('/me достал Micro Uzi из-за спины')
            elseif gun == 29 then
                sampSendChat('/me взял MP-5 в руки')
            elseif gun == 30 then
                sampSendChat('/me взял автомат АК-47 в руки')
            elseif gun == 31 then
                sampSendChat('/me взял карабин М4А1 в руки')
            elseif gun == 33 then
                sampSendChat('/me взял винтовку в руки')
            elseif gun == 34 then
                sampSendChat('/me взял снайперскую винтовку в руки')
            elseif gun == 0 then
                sampSendChat('/me убрал оружие')
            end
            lastgun = gun   
            
            end
        end
    end           

function cmd_h1()
    one_window.v = not one_window.v
    imgui.Process = one_window.v
end

function cmd_h2()
    two_window.v = not two_window.v
    imgui.Process = two_window.v
end

function imgui.OnDrawFrame()
    if not one_window.v and not two_window.v then
    imgui.Process = false
    end
    
    if one_window.v then
    imgui.Begin(u8"okno1", one_window)
    if imgui.Checkbox(u8' RP guns', checkbox) then
    cfg.settings.rpgun = not cfg.settings.rpgun
    inicfg.save(cfg, 'Название твоего файла.ini')
    if cfg.settings.rpgun then
      sampAddChatMessage('{FFFFFF}Отыгровка оружия {008000}включена.', -1)   
    else
      sampAddChatMessage('{FFFFFF}Отыгровка оружия {FF0000}выключена.', -1)       
    end
end
imgui.End()
end

    if two_window.v then
    imgui.Begin(u8"okno2", two_window)
    imgui.Text(u8"hi")
    imgui.End()
    end
end

function onScriptTerminate(script, quitGame)
  if script == thisScript() then
    inicfg.save(cfg, "GUNS")
    end
end
 
  • Влюблен
Реакции: barjik

danywa

Известный
358
50
Lua:
local text = renderCreateFont("Verdana", 12, 9)
local render_text = false

local trainPos =
    {
    [1] = {-2681.2800292969, 2149.919921875, 14.445400238037}; [2] = {-2615.6999511719, 1396.1600341797, 6.4714798927307}; [3] = {-2713.6999511719, 1026.4100341797, 1.7189899682999}; [4] = {-2708.169921875, 634.75799560547, 5.2032399177551}; [5] = {-2702.580078125, 243.10299682617, 8.6877498626709};
    }
    
main = function()
    sampRegisterChatCommand("sps", function() render_text = true end)
    while true do wait(0) 
            if render_text then
                local x, y, z = getCharCoordinates(PLAYER_PED)
                local dist = getDistanceBetweenCoords3d(x, y, z, table.unpack(trainPos[1]))
                local incar = isCharInAnyCar(PLAYER_PED)
                renderFontDrawText(text, 'dist: '..dist, 100, 400, 0xFFFFFFFF)
                if dist < 2 then
                    i = 1
                    i = i + 1
                    dist = getDistanceBetweenCoords3d(x, y, z,  table.unpack(trainPos[i]))
                end
            end
    end
end

Как решить проблему что условие с дистанцией не выполняется и не переходит к следующему значению из массива
 

Biuti

Участник
165
8
есть функция sampSendDialogResponse(int id, int button, int listitem, zstring input), мне нужно пропустить аргумент int listitem, мне вместо него -1 поставить?
 

СоМиК

Известный
456
320
Привет, с массивами и оператором for вчера познакомился :)
К примеру у меня
Lua:
a = {"aboba", "adoda", "abobus"}
for _,v in ipairs(a) do
    sampAddChatMessage(v, -1)
end
Как это вывести не подряд, а в одну строку?)
Lua:
sampAddChatMessage(table.concat(a,", "), -1)
Нашел решение на другом форуме, который посвящен именно луа скриптингу, а не moonloader api, но в любом случае работает, держите кому надо
Где "a" это название массива
 
Последнее редактирование:

SamperJostkiy

Участник
172
19
что тут не так?

я уже замучался с им, это короче типо биндера:
require "lib.moonloader"

local ip = {
"one.monser.ru:7777",
"two.monser.ru:7777",
"three.monser.ru:7777"
}
local keybinds = {
    { VK_1, "/mask"       },
    { VK_2, "/heal"       },
    { VK_3, "/tp"         },
    { VK_5, "/veh 411 1 1"},
    { VK_6, "/veh 510 1 1"},
    { VK_Z, "/anim 8"     },
}

function main()
    if not isSampfuncsLoaded() or not isSampLoaded() then return end
    while not isSampAvailable() do wait(100) end
for k, v in pairs(ip) do
    if server ~= v then -- проверка по ИП.
        sampAddChatMessage('Скрипт работает только на серверах "Monser DM" ', -1)
while true do wait(0)
        if not sampIsChatInputActive() and not isSampfuncsConsoleActive() and not sampIsDialogActive() and activate then
            for i = 1, #keybinds do
                if isKeyJustPressed(keybinds[i][1]) then sampSendChat(keybinds[i][2]) end
else
        thisScript():unload()
        do return end
        end
    end
end
 

wulfandr

Известный
635
259
Lua:
local text = renderCreateFont("Verdana", 12, 9)
local render_text = false

local trainPos =
    {
    [1] = {-2681.2800292969, 2149.919921875, 14.445400238037}; [2] = {-2615.6999511719, 1396.1600341797, 6.4714798927307}; [3] = {-2713.6999511719, 1026.4100341797, 1.7189899682999}; [4] = {-2708.169921875, 634.75799560547, 5.2032399177551}; [5] = {-2702.580078125, 243.10299682617, 8.6877498626709};
    }
  
main = function()
    sampRegisterChatCommand("sps", function() render_text = true end)
    while true do wait(0)
            if render_text then
                local x, y, z = getCharCoordinates(PLAYER_PED)
                local dist = getDistanceBetweenCoords3d(x, y, z, table.unpack(trainPos[1]))
                local incar = isCharInAnyCar(PLAYER_PED)
                renderFontDrawText(text, 'dist: '..dist, 100, 400, 0xFFFFFFFF)
                if dist < 2 then
                    i = 1
                    i = i + 1
                    dist = getDistanceBetweenCoords3d(x, y, z,  table.unpack(trainPos[i]))
                end
            end
    end
end

Как решить проблему что условие с дистанцией не выполняется и не переходит к следующему значению из массива
Lua:
local font = renderCreateFont("Verdana", 12, 9)
local render_text = false

local trainPos =
{
    [1] = {-2681.2800292969, 2149.919921875, 14.445400238037}; [2] = {-2615.6999511719, 1396.1600341797, 6.4714798927307}; [3] = {-2713.6999511719, 1026.4100341797, 1.7189899682999}; [4] = {-2708.169921875, 634.75799560547, 5.2032399177551}; [5] = {-2702.580078125, 243.10299682617, 8.6877498626709};
}
  
function main()
    if not isSampfuncsLoaded() or not isSampLoaded() then return end
    while not isSampAvailable() do wait(100) end
    sampRegisterChatCommand("sps", function()
        render_text = not render_text
        if render_text then
            sampAddChatMessage('script was activated.', -1)
            checkCoords()
        else
            sampAddChatMessage('script was disabled.', -1)
        end
    end)
    wait(-1)
end

function checkCoords()
    lua_thread.create(function()
        local i = 1
        while render_text do
            local x, y, z = getCharCoordinates(PLAYER_PED)
            if #trainPos > 0 then
                if trainPos[i] then
                    local xt, yt, zt = table.unpack(trainPos[i])
                    local dist = getDistanceBetweenCoords3d(x, y, z, xt, yt, zt)
                    local wPosX, wPosY = convert3DCoordsToScreen(x, y, z)
                    local wPosX1, wPosY1 = convert3DCoordsToScreen(xt, yt, zt)
                    if isPointOnScreen(xt, yt, zt, 0.0) then
                        renderDrawLine(wPosX1, wPosY1, wPosX, wPosY, 2, 0xFFEE0000)
                        renderDrawPolygon(wPosX1, wPosY1, 10, 10, 14, 0.0, 0xFFEE0000)
                    end
                    renderFontDrawText(font, 'dist: '..math.floor(dist) .. ' | stock: '..#trainPos - i + 1, 100, 400, 0xFFFFFFFF)
                    if dist < 2 then
                        i = i + 1
                        sampAddChatMessage(table.concat(trainPos[i - 1], ', ')..' was picked up.', -1)
                    end
                end
            end
        wait(0) end return
    end)
end

пойдет?
 
  • Нравится
Реакции: danywa

Sanchez.

Известный
704
190
что тут не так?

я уже замучался с им, это короче типо биндера:
require "lib.moonloader"

local ip = {
"one.monser.ru:7777",
"two.monser.ru:7777",
"three.monser.ru:7777"
}
local keybinds = {
    { VK_1, "/mask"       },
    { VK_2, "/heal"       },
    { VK_3, "/tp"         },
    { VK_5, "/veh 411 1 1"},
    { VK_6, "/veh 510 1 1"},
    { VK_Z, "/anim 8"     },
}

function main()
    if not isSampfuncsLoaded() or not isSampLoaded() then return end
    while not isSampAvailable() do wait(100) end
for k, v in pairs(ip) do
    if server ~= v then -- проверка по ИП.
        sampAddChatMessage('Скрипт работает только на серверах "Monser DM" ', -1)
while true do wait(0)
        if not sampIsChatInputActive() and not isSampfuncsConsoleActive() and not sampIsDialogActive() and activate then
            for i = 1, #keybinds do
                if isKeyJustPressed(keybinds[i][1]) then sampSendChat(keybinds[i][2]) end
else
        thisScript():unload()
        do return end
        end
    end
end
Во первых, работай с табуляцией, с кодом у тебя полная жопа, во вторых, ты else не туда впихнул
P.s блять я опять посмотрел на твой код и он в полнейшей пизде. Советую переписать адекватно
Вот более адекватный код
Lua:
require "lib.moonloader"

local ip = {
"one.monser.ru:7777",
"two.monser.ru:7777",
"three.monser.ru:7777"
}
local keybinds = {
    { VK_1, "/mask"       },
    { VK_2, "/heal"       },
    { VK_3, "/tp"         },
    { VK_5, "/veh 411 1 1"},
    { VK_6, "/veh 510 1 1"},
    { VK_Z, "/anim 8"     },
}

function main()
    if not isSampfuncsLoaded() or not isSampLoaded() then return end
    while not isSampAvailable() do wait(100) end

    for k, v in pairs(ip) do
        if sampGetCurrentServerAddress() ~= v then -- проверка по ИП.
        sampAddChatMessage('Скрипт работает только на серверах "Monser DM" ', -1)
        thisScript():unload()
    end

    while true do
        wait(0)
        if not sampIsChatInputActive() and not isSampfuncsConsoleActive() and not sampIsDialogActive() and activate then
            for i = 1, #keybinds do
                if isKeyJustPressed(keybinds[i][1]) then sampSendChat(keybinds[i][2])
            end                   
        end
    end
end
 
Последнее редактирование:

Next..

Известный
342
136
Во первых, работай с табуляцией, с кодом у тебя полная жопа, во вторых, ты else не туда впихнул
P.s блять я опять посмотрел на твой код и он в полнейшей пизде. Советую переписать адекватно
Вот более адекватный код
Lua:
require "lib.moonloader"

local ip = {
"one.monser.ru:7777",
"two.monser.ru:7777",
"three.monser.ru:7777"
}
local keybinds = {
    { VK_1, "/mask"       },
    { VK_2, "/heal"       },
    { VK_3, "/tp"         },
    { VK_5, "/veh 411 1 1"},
    { VK_6, "/veh 510 1 1"},
    { VK_Z, "/anim 8"     },
}

function main()
    if not isSampfuncsLoaded() or not isSampLoaded() then return end
    while not isSampAvailable() do wait(100) end

    for k, v in pairs(ip) do
        if sampGetCurrentServerAddress() ~= v then -- проверка по ИП.
        sampAddChatMessage('Скрипт работает только на серверах "Monser DM" ', -1)
        thisScript():unload()
    end

    while true do
        wait(0)
        if not sampIsChatInputActive() and not isSampfuncsConsoleActive() and not sampIsDialogActive() and activate then
            for i = 1, #keybinds do
                if isKeyJustPressed(keybinds[i][1]) then sampSendChat(keybinds[i][2])
            end                   
        end
    end
end
Два end'а потерялись
 

четыреста четыре

Известный
130
22
как заспаванить себя через ffi или callfunction ?
void SAMP::CLocalPlayer::RequestSpawn() {
((void(__thiscall *)(CLocalPlayer *))SAMP_ADDROF(0x3EC0))(this);
}

SAMP::CLocalPlayer::CLocalPlayer() {
(void(__thiscall *)(CLocalPlayer *))SAMP_ADDROF(0x4A50))(this);
}


Lua:
разобрался, мб кому надо
function Spawn()
    ffi.cast( 'void ( __thiscall * )( void * )', getModuleHandle("samp.dll") + 0x3AD0)( ffi.cast('struct stSAMPPools*', sampGetSampPoolsPtr()).pPlayer.pLocalPlayer )
end
 
Последнее редактирование: