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

imring

Ride the Lightning
Всефорумный модератор
2,362
2,545
Чем можно заменить write_samp_memory?
 

Moonlight_Ru

Известный
66
21
Как создать замороженный поток, а потом запустить его так, чтобы он работал, пока игра на паузе? Пробовал поставить script_properties("work-in-pause"), в первый раз поток запускается с этим свойством, а при повторном запуске уже нет.
Я читал статью в вики про скриптовые потоки, но не могу понять, как присвоение параметра lua_thread.work_in_pause должно выглядеть в коде?
 

ufdhbi

Известный
Проверенный
1,459
866
Как создать замороженный поток, а потом запустить его так, чтобы он работал, пока игра на паузе? Пробовал поставить script_properties("work-in-pause"), в первый раз поток запускается с этим свойством, а при повторном запуске уже нет.
Я читал статью в вики про скриптовые потоки, но не могу понять, как присвоение параметра lua_thread.work_in_pause должно выглядеть в коде?
lua_thread.work_in_pause(true)
 

Moonlight_Ru

Известный
66
21
никак

@Moonlight_Ru @A1K8M4
Lua:
local mythread = lua_thread.create_suspended()
mythread.work_in_pause = true

Спасибо, а то я голову ломал, как только не пробовал :)

Но вторая проблема остаётся. Если поток перезапустить, то он перестанет работать, когда игра на паузе.
Если максимально упростить код, то получится как-то так:
Lua:
local hook = require 'lib.samp.events'

function main()
    thread = lua_thread.create_suspended(threadFunc)
    var1 = firstFunc()
    thread.work_in_pause = true
    thread:run(var1) -- После этого запуска текст видно в меню паузы.
    wait(-1)
end

function threadFunc(arg)
    while true do
        wait(0)
        renderFontDrawText(font, string, posX, posY, color)
    end
end

function hook.onServerMessage(color, text)
    if string.match(text, "^Тест %d+$") then
        var2 = string.match(text, "^Тест (%d+)$")
        thread:run(var2) -- После этого запуска текст в меню паузы уже не видно.
    end
end
 

штейн

Известный
Проверенный
1,003
688
Помогите пожалуйста, вроде всё сделал правильно, в игре нормально открывает диалог и т.п., но функции не выполняет.

Lua:
            if isKeyDown(VK_0) and isKeyDown(VK_Y) and not sampIsChatInputActive() and not sampIsDialogActive() and not isPauseMenuActive() then
                res, handle = getCharPlayerIsTargeting(playerHandle)
                if res then
                    resid, Rid = sampGetPlayerIdByCharHandle(handle)
                    Rname = sampGetPlayerNickname(Rid)
                    sampShowDialog(906, string.format("{ffffff}Меню взаимодействия с {00cc99}%s[%d]", Rname, Rid), hmenu, "Далее", "Закрыть", 2)
                    sampAddChatMessage(string.format("{ffffff}Меню взаимодействия с {00cc99}%s[%d]", Rname, Rid), 0xC1C1C1)
                end
            end
        end
        local re, bu, li, inp = sampHasDialogRespond(906)
        if re == true and bu == 1 then
            if li == 0 then sampSendChat(string.format("/arest %d", Rid)) end
            if li == 1 then sampSendChat(string.format("/cuff %d", Rid)) end
            if li == 2 then sampSendChat(string.format("/frisk %d", Rid)) end
            if li == 3 then sampSendChat(string.format("/findgun %d", Rid)) end
            if li == 4 then sampSendChat(string.format("/invte %d", Rid)) end
            if li == 5 then sampSendChat(string.format("/w %d 123", Rid)) end
        end





        hmenu = [[
{00cc99}• {ffffff}Арестовать {ffffff}[ {00cc99}/arest {ffffff}].
{00cc99}• {ffffff}Надеть наручники {ffffff}[ {00cc99}/cuff {ffffff}].
{00cc99}• {ffffff}Обыскать {ffffff}[ {00cc99}/frisk {ffffff}].
{00cc99}• {ffffff}Обыскать оружие {ffffff}[ {00cc99}/findgun {ffffff}].
{00cc99}• {ffffff}Принять во фракцию {ffffff}[ {00cc99}/invite {ffffff}].
{00cc99}• {ffffff}Test
]]

По идее, скрипт должен был открывать диалоговое окно, в котором бы можно было взаимодействовать с игроком на которого я навел правой кнопкой мыши, он открывает диалоговое окно, прекрасно выводит ID персонажа и ник, но почему-то когда я вписываю эти функции в команды - они не работают.
- Rid - ID персонажа, а Rname - ник.
 
Последнее редактирование:

Moonlight_Ru

Известный
66
21
@rewzeisch
Ты единожды проверяешь отправку события от диалога, конечно у тебя не работает ничего.
Lua:
while not dialogBool do
    wait(0)
    dialogBool, dialogButton, dialogListItem, dialogInput = sampHasDialogRespond(dialogId)
end
if dialogButton ~= 0 then
    if dialogListItem == 0 then
        --
    elseif dialogListItem == 1 then
        --
    end
end
 
Последнее редактирование:
  • Нравится
Реакции: штейн

ishi

Известный
493
110
Столкнулся с проблемой. Некоторые функции в C++ аргументы принимают как структуру, и если отправить в качестве аргумента - таблицу, в неё ничего не сохранится.

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

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

Пробовал через callMethod т.к. там надо указывать структуру (подумал, что это для таких случаев), но либо ошибся, либо оно не работает:
Lua:
getCPresult = callMethod(GetCursorPosAddress,point,0,0)
 

BlackKnigga

Известный
BH Team
922
446
Столкнулся с проблемой. Некоторые функции в C++ аргументы принимают как структуру, и если отправить в качестве аргумента - таблицу, в неё ничего не сохранится.

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

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

Пробовал через callMethod т.к. там надо указывать структуру (подумал, что это для таких случаев), но либо ошибся, либо оно не работает:
Lua:
getCPresult = callMethod(GetCursorPosAddress,point,0,0)
GetCursorPos это stdcall функция. А callMethod вызывает функцию thiscall типа. Тебе нужна callFunction
А про таблицу хз, подозреваю что нужно передавать указатель на таблицу чтобы функция могла записать в нее что-то. Не умею в луа, сорь. Ну и еще возможно имеет смысл передавать параметры в обратном порядке.
 

GGOLVER

Известный
280
60
Извините что ещё раз пишу.
Помогите активировать скрипт (модераторы, не понижайте репутацию. Это просто единственная активная тема, а не то что вы мне предлагаете)
Короче, есть скрипт. Мне его необходимо активировать.
Вот код :
Lua:
function main()
    gameGetWeaponInfo = ffi.cast('struct CWeaponInfo* (__cdecl*)(int, int)', 0x743C60)

    while true do
        wait(0)
        if isPlayerPlaying(playerHandle) and isCharOnFoot(playerPed) then
            if testCheat(cheatToggle) then
                activated = not activated
                printStringNow('RapidFire ' .. (activated and '~g~activated' or '~r~deactivated') .. '.~n~~y~Made by FYP~n~~w~blast.hk', 2000)

                if activated then
                    weaponOrigData = {}
                    for skill = 1, 3 do
                        weaponOrigData[skill] = {}
                        for id, value in pairs(amplification) do
                            local weap = gameGetWeaponInfo(id, skill - 1)
                            weaponOrigData[skill][id] = {accuracy = weap.m_fAccuracy,
                                                        animLoopStart = weap.m_fAnimLoopStart,
                                                        animLoopFire = weap.m_fAnimLoopFire,
                                                        animLoopEnd = weap.m_fAnimLoopEnd,
                                                        animLoopStart2 = weap.m_fAnimLoop2Start,
                                                        animLoopFire2 = weap.m_fAnimLoop2Fire,
                                                        animLoopEnd2 = weap.m_fAnimLoop2End}
                            -- magic
                            local mul = 1 / value
                            if id ~= 25 and id ~= 26 and id ~= 27 then
                                weap.m_fAccuracy = weap.m_fAccuracy / (mul * 1.4)
                            end
                            weap.m_fAnimLoopStart = weap.m_fAnimLoopFire - (weap.m_fAnimLoopFire - weap.m_fAnimLoopStart) * mul
                            weap.m_fAnimLoop2Start = weap.m_fAnimLoop2Fire - (weap.m_fAnimLoop2Fire - weap.m_fAnimLoop2Start) * mul
                            weap.m_fAnimLoopEnd = weap.m_fAnimLoopFire + (weap.m_fAnimLoopEnd - weap.m_fAnimLoopFire) * mul
                            weap.m_fAnimLoop2End = weap.m_fAnimLoop2Fire + (weap.m_fAnimLoop2End - weap.m_fAnimLoop2Fire) * mul
                        end
                    end
                else
                    restoreOriginalWeaponData()
                    weaponOrigData = nil
                end
            end
        end
    end
end


--- Events
function onExitScript()
    restoreOriginalWeaponData()
end


--- Functions
function restoreOriginalWeaponData()
    if weaponOrigData ~= nil then
        for skill, weaponsOrig in pairs(weaponOrigData) do
            for id, orig in pairs(weaponsOrig) do
                local weap = gameGetWeaponInfo(id, skill - 1)
                weap.m_fAccuracy              = orig.accuracy
                weap.m_fAnimLoopStart  = orig.animLoopStart
                weap.m_fAnimLoopFire   = orig.animLoopFire
                weap.m_fAnimLoopEnd    = orig.animLoopEnd
                weap.m_fAnimLoop2Start = orig.animLoopStart2
                weap.m_fAnimLoop2Fire  = orig.animLoopFire2
                weap.m_fAnimLoop2End   = orig.animLoopEnd2
            end
        end
    end
end

Я делаю что то не так. Убираю некоторые строки, ставлю local activated = true. Никера.
Вот такой код я оставляю:
Lua:
function main()
    gameGetWeaponInfo = ffi.cast('struct CWeaponInfo* (__cdecl*)(int, int)', 0x743C60)
    while true do
        wait(0)
        if isPlayerPlaying(playerHandle) and isCharOnFoot(playerPed) then
            if testCheat(cheatToggle) then
                if activated then
                    weaponOrigData = {}
                    for skill = 1, 3 do
                        weaponOrigData[skill] = {}
                        for id, value in pairs(amplification) do
                            local weap = gameGetWeaponInfo(id, skill - 1)
                            weaponOrigData[skill][id] = {accuracy = weap.m_fAccuracy,
                                                        animLoopStart = weap.m_fAnimLoopStart,
                                                        animLoopFire = weap.m_fAnimLoopFire,
                                                        animLoopEnd = weap.m_fAnimLoopEnd,
                                                        animLoopStart2 = weap.m_fAnimLoop2Start,
                                                        animLoopFire2 = weap.m_fAnimLoop2Fire,
                                                        animLoopEnd2 = weap.m_fAnimLoop2End}
                            -- magic
                            local mul = 1 / value
                            if id ~= 25 and id ~= 26 and id ~= 27 then
                                weap.m_fAccuracy = weap.m_fAccuracy / (mul * 1.4)
                            end
                            weap.m_fAnimLoopStart = weap.m_fAnimLoopFire - (weap.m_fAnimLoopFire - weap.m_fAnimLoopStart) * mul
                            weap.m_fAnimLoop2Start = weap.m_fAnimLoop2Fire - (weap.m_fAnimLoop2Fire - weap.m_fAnimLoop2Start) * mul
                            weap.m_fAnimLoopEnd = weap.m_fAnimLoopFire + (weap.m_fAnimLoopEnd - weap.m_fAnimLoopFire) * mul
                            weap.m_fAnimLoop2End = weap.m_fAnimLoop2Fire + (weap.m_fAnimLoop2End - weap.m_fAnimLoop2Fire) * mul
                        end
                    end
                end
            end
        end
    end
end
И... Скрипт накрен перестает работать.
Хелпаните codekid'у.
 

Moonlight_Ru

Известный
66
21
@happydan Я так понял, тебе нужен тот же скрипт, только чтобы он изначально был активирован?
В смысл написанного кода я особо не вдавался, попробуй так.

Lua:
function main()
local kakayaToPeremennaya = true -- Создаём "одноразовую" переменную.
gameGetWeaponInfo = ffi.cast('struct CWeaponInfo* (__cdecl*)(int, int)', 0x743C60)

    while true do
        wait(0)
        if isPlayerPlaying(playerHandle) and isCharOnFoot(playerPed) then
            if testCheat(cheatToggle) or kakayaToPeremennaya then -- Если значение нашей переменной равно true, то это заменяет введение чит-кода.
                kakayaToPeremennaya = false -- Устанавливаем нашей переменной значение false, чтобы она больше не влияла на работу скрипта.
                activated = not activated
                printStringNow('RapidFire ' .. (activated and '~g~activated' or '~r~deactivated') .. '.~n~~y~Made by FYP~n~~w~blast.hk', 2000)

                if activated then
                    weaponOrigData = {}
                    for skill = 1, 3 do
                        weaponOrigData[skill] = {}
                        for id, value in pairs(amplification) do
                            local weap = gameGetWeaponInfo(id, skill - 1)
                            weaponOrigData[skill][id] = {accuracy = weap.m_fAccuracy,
                                                                                    animLoopStart = weap.m_fAnimLoopStart,
                                                                                    animLoopFire = weap.m_fAnimLoopFire,
                                                                                    animLoopEnd = weap.m_fAnimLoopEnd,
                                                                                    animLoopStart2 = weap.m_fAnimLoop2Start,
                                                                                    animLoopFire2 = weap.m_fAnimLoop2Fire,
                                                                                    animLoopEnd2 = weap.m_fAnimLoop2End}
                            -- magic
                            local mul = 1 / value
                            if id ~= 25 and id ~= 26 and id ~= 27 then
                                weap.m_fAccuracy = weap.m_fAccuracy / (mul * 1.4)
                            end
                            weap.m_fAnimLoopStart = weap.m_fAnimLoopFire - (weap.m_fAnimLoopFire - weap.m_fAnimLoopStart) * mul
                            weap.m_fAnimLoop2Start = weap.m_fAnimLoop2Fire - (weap.m_fAnimLoop2Fire - weap.m_fAnimLoop2Start) * mul
                            weap.m_fAnimLoopEnd = weap.m_fAnimLoopFire + (weap.m_fAnimLoopEnd - weap.m_fAnimLoopFire) * mul
                            weap.m_fAnimLoop2End = weap.m_fAnimLoop2Fire + (weap.m_fAnimLoop2End - weap.m_fAnimLoop2Fire) * mul
                        end
                    end
                else
                    restoreOriginalWeaponData()
                    weaponOrigData = nil
                end
            end
        end
    end
end
 
  • Нравится
Реакции: GGOLVER