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

sizeoftrickster

Известный
Проверенный
139
557
как изменить раскладку клавиатуры без эмуляции нажатия SHIFT + ALT?
Lua:
require( "moonloader" )

local ffi = require( "ffi" )

ffi.cdef[[
    typedef unsigned int BOOL;
    typedef void *HWND;
    typedef unsigned int UINT;
    typedef unsigned int LONG;

    typedef UINT UINT_PTR, *PUINT_PTR;
    typedef LONG        LONG_PTR, *PLONG_PTR;


    typedef UINT_PTR WPARAM;
    typedef LONG_PTR LPARAM;


    // https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-postmessagea
    BOOL PostMessageA(
        HWND hWnd,
        UINT Msg,
        WPARAM wParam,
        LPARAM lParam
    );

    // https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getactivewindow
    HWND GetActiveWindow();
]]

function main()

    sampRegisterChatCommand("emulShiftAlt=)", function()
        local hWnd = ffi.C.GetActiveWindow()
        local WM_INPUTLANGCHANGEREQUEST = 0x0050
        local INPUTLANGCHANGE_SYSCHARSET = 0x0001
        -- полный список https://docs.microsoft.com/en-us/windows/win32/msi/localizing-the-error-and-actiontext-tables
        local english = 0x409
        local russian = 0x419

        ffi.C.PostMessageA(
            hWnd,
            WM_INPUTLANGCHANGEREQUEST,
            INPUTLANGCHANGE_SYSCHARSET,
            russian -- или же english
        )

    end)

   wait( -1 )
end
 
  • Нравится
  • Влюблен
Реакции: YarikVL и chapo

Andrinall

Известный
702
518
Как получить версию SAMP?
Уже не помню откуда я это брал, лежало в одном из скриптов.
Вроде из полезных сниппетов когда-то выцепил с какой-то переделкой.
Lua:
function get_samp_version()
    local versions = { [0x31df13]="0.3.7-R1", [0xcc4d0]="0.3.7-R3", [0xcbcb0]="0.3.7-R4", [0xfdb60]="0.3.DL-R1" }
    local samp_base = getModuleHandle("samp.dll")
    if samp_base == 0 then return "not loaded" end
   
    local e_lfanew = ffi.cast("long*", samp_base + 60)[0]
    local nt_header = samp_base + e_lfanew
    local entry_point_addr = ffi.cast("unsigned int*", nt_header + 40)[0]
    return (versions[entry_point_addr] ~= nil and versions[entry_point_addr] or "unknown")
end
 

F L I P S T A R

Участник
62
1
Появился вопрос. Есть скрипт с циклом, который срабатывает, если хп персонажа меньше определенного значения и вводит определенную команду в чат. Мне нужно, чтобы как только здоровье опустится ниже 45, скрипт сработал 1 раз и после этого цикл обновился и дальше ждал момента, пока хп опять настанет ниже 45. Как мне это сделать? Пробовал return false, break, но тогда скрипт выключался полностью и только после рестарта скрипта он начинал работать заново. Сейчас у меня он работает так: если хп меньше 45, он бесконечно выводит команду в чат без остановки(выключается, только если принудительно отключить его через команду /hp).
Можете помочь?
Code::
act = false

function main()
    repeat
        wait(0)
    until isSampAvailable()
    sampRegisterChatCommand("hp",function() act = not act printStringNow(act and "~b~[AUTOHILL]: ~g~ON" or "~b~[AUTOHILL]: ~r~OFF", 1000) end)
    while true do
        wait(0)
        hp = getCharHealth(PLAYER_PED)
        if act and hp < 45 then
            sampSendChat("/healme")
        end
    end
end
 

Dmitriy Makarov

25.05.2021
Проверенный
2,500
1,131
Появился вопрос. Есть скрипт с циклом, который срабатывает, если хп персонажа меньше определенного значения и вводит определенную команду в чат. Мне нужно, чтобы как только здоровье опустится ниже 45, скрипт сработал 1 раз и после этого цикл обновился и дальше ждал момента, пока хп опять настанет ниже 45. Как мне это сделать? Пробовал return false, break, но тогда скрипт выключался полностью и только после рестарта скрипта он начинал работать заново. Сейчас у меня он работает так: если хп меньше 45, он бесконечно выводит команду в чат без остановки(выключается, только если принудительно отключить его через команду /hp).
Можете помочь?
Code::
act = false

function main()
    repeat
        wait(0)
    until isSampAvailable()
    sampRegisterChatCommand("hp",function() act = not act printStringNow(act and "~b~[AUTOHILL]: ~g~ON" or "~b~[AUTOHILL]: ~r~OFF", 1000) end)
    while true do
        wait(0)
        hp = getCharHealth(PLAYER_PED)
        if act and hp < 45 then
            sampSendChat("/healme")
        end
    end
end
Поставь задержку на 100-200 миллисекунд после отправки команды.
 
  • Bug
Реакции: Rice.

Rice.

Известный
Модератор
1,754
1,618
Пробовал, но нет смысла, команды все равно отправляются без остановки, хоть и с задержкой в 100-200 мс.
Потому что бесконечный цикл выполняется бесконечно, а не один раз.
Я предложу один вариант решения проблемы: в тот момент, когда у тебя меньше 45 хп, то сохраняй последнее ХП персонажа. А если ХП в данный момент не равно ХП в последний момент, то проверяй ХП в данный момент.
Lua:
local last_hp = nil

function main()
    repeat wait(0) until isSampAvailable()
    while true do wait(0)
        local hp = getCharHealth(PLAYER_PED)
        if last_hp ~= hp then
            if hp < 45 then
                sampSendChat('/healme')
                last_hp = hp
            end
        end
    end
end

Поставь задержку на 100-200 миллисекунд после отправки команды.
И как это должно помочь с бесконечном цикле?
 
Последнее редактирование:

F L I P S T A R

Участник
62
1
Потому что бесконечный цикл выполняется бесконечно, а не один раз.
Я предложу один вариант решения проблемы: в тот момент, когда у тебя меньше 45 хп, то сохраняй последнее ХП персонажа. А если ХП в данный момент не равно ХП в последний момент, то проверяй ХП в данный момент.
Lua:
local last_hp = nil

function main()
    repeat wait(0) until isSampAvailable()
    while true do wait(0)
        local hp = getCharHealth(PLAYER_PED)
        if last_hp ~= hp then
            if hp < 45 then
                sampSendChat('/healme')
                last_hp = hp
            end
        end
    end
end


И как это должно помочь с бесконечном цикле?
Интересное решение, попробую проверить на деле, спасибо!
 

Rice.

Известный
Модератор
1,754
1,618
Интересное решение, попробую проверить на деле, спасибо!
Может быть не эффективное, потому что из-за лагов сервера может не сразу ХП начислиться. Подумаю ещё над решением этой проблемы

@F L I P S T A R
Думаем логически:
1) Мы получаем ХП игрока
2) Мы сравниваем прошлое ХП игрока (при первом запуске оно nil)
3) Если старое ХП ~= с нынешним, то мы идем дальше
4) Если нынешнее ХП меньше 45, то пишем команду в чат
5) Записываем нынешнее ХП до прописывания команды в чат

Пример:
1) Нам нанесли урон, у нас 40 ХП
2) Скрипт смотрит на старое ХП и видит, что оно не равно с нынешним
3) Скрипт видит, что у нас меньше 45 ХП и выполняет хилл + записывает прошлое ХП (в нашем случае 40)
4) Если из-за лагов сервера не обновилось ХП, то все равно у нас записалось старое ХП и повторного хила не будет
5) Если ХП пополнилось, то старое ХП не будет равно с нынешним, но хилла нового не будет, т.к. ХП больше 45.
6) Если ХП изменилось, но оно остается меньше 45, то будет хилл.
7) Скрипт выполняет всю логическую цепочку, которую ожидает автор

Если я что-то упустил, то можно сюда написать, будем думать
 
Последнее редактирование:
  • Нравится
Реакции: F L I P S T A R

F L I P S T A R

Участник
62
1
Может быть не эффективное, потому что из-за лагов сервера может не сразу ХП начислиться. Подумаю ещё над решением этой проблемы

@F L I P S T A R
Думаем логически:
1) Мы получаем ХП игрока
2) Мы сравниваем прошлое ХП игрока (при первом запуске оно nil)
3) Если старое ХП ~= с нынешним, то мы идем дальше
4) Если нынешнее ХП меньше 45, то пишем команду в чат
5) Записываем нынешнее ХП до прописывания команды в чат

Пример:
1) Нам нанесли урон, у нас 40 ХП
2) Скрипт смотрит на старое ХП и видит, что оно не равно с нынешним
3) Скрипт видит, что у нас меньше 45 ХП и выполняет хилл + записывает прошлое ХП (в нашем случае 40)
4) Если из-за лагов сервера не обновилось ХП, то все равно у нас записалось старое ХП и повторного хила не будет
5) Если ХП пополнилось, то старое ХП не будет равно с нынешним, но хилла нового не будет, т.к. ХП больше 45.
6) Если ХП изменилось, но оно остается меньше 45, то будет хилл.
7) Скрипт выполняет всю логическую цепочку, которую ожидает автор

Если я что-то упустил, то можно сюда написать, будем думать
Очень интересное мышление и выстроенная цепочка, а так же необычный обходный путь для правильной работы скрипта. Большое спасибо за помощь, все работает исправно!
 

Dmitriy Makarov

25.05.2021
Проверенный
2,500
1,131
И как это должно помочь с бесконечном цикле?
Lua:
require "lib.moonloader"

function main()
    while not isSampAvailable() do wait(100) end
    while true do wait(0)
        if getCharHealth(PLAYER_PED) <= 90 then
            sampSendChat("/healme")
            wait(300)
        end
    end
end
Ну как видишь - помогло. Флуда нет.
 

Rice.

Известный
Модератор
1,754
1,618
Lua:
require "lib.moonloader"

function main()
    while not isSampAvailable() do wait(100) end
    while true do wait(0)
        if getCharHealth(PLAYER_PED) <= 90 then
            sampSendChat("/healme")
            wait(300)
        end
    end
end
Ну как видишь - помогло. Флуда нет.
Хорошо, а если у нас дудосят сервер? И твоё ХП придет через +- секунд 5, но при этом ты отправишь на сервер миллиард запросов на ввод команды /healme.
К этому использовать wait в бесконечном цикле без создания отдельных циклов, либо проверки через os.clock() это ебаный бред.
 

vegas

Известный
648
461
Появился вопрос. Есть скрипт с циклом, который срабатывает, если хп персонажа меньше определенного значения и вводит определенную команду в чат. Мне нужно, чтобы как только здоровье опустится ниже 45, скрипт сработал 1 раз и после этого цикл обновился и дальше ждал момента, пока хп опять настанет ниже 45. Как мне это сделать? Пробовал return false, break, но тогда скрипт выключался полностью и только после рестарта скрипта он начинал работать заново. Сейчас у меня он работает так: если хп меньше 45, он бесконечно выводит команду в чат без остановки(выключается, только если принудительно отключить его через команду /hp).
Можете помочь?
Code::
act = false

function main()
    repeat
        wait(0)
    until isSampAvailable()
    sampRegisterChatCommand("hp",function() act = not act printStringNow(act and "~b~[AUTOHILL]: ~g~ON" or "~b~[AUTOHILL]: ~r~OFF", 1000) end)
    while true do
        wait(0)
        hp = getCharHealth(PLAYER_PED)
        if act and hp < 45 then
            sampSendChat("/healme")
        end
    end
end
Lua:
-- Пример с таймером в беск. цикле
local active = false
local time = 0

local function switchState()
    active = not active
    printStringNow(active and "~b~[AUTOHILL]: ~g~ON" or "~b~[AUTOHILL]: ~r~OFF", 1000)
end

function main()
    repeat wait(0) until isSampAvailable()

    sampRegisterChatCommand("hp", switchState)

    while true do wait(0)
        if active and time < os.clock() then
            time = os.clock() + 1 -- Каждую секунду будет отправляться команда
            sampSendChat("/healme")
        end
    end
end
 
  • Нравится
Реакции: F L I P S T A R

Daddyy

Известный
239
53
Вопрос по ракботу. Как получить координаты отправляемые сервером 12 RPC? Имею вот это но оно не работает

Lua:
function onRecvRpc(id, data, size)
    if id == 12 then
        local x, y, z = float x, float y, float z
        setPosition(x, y, z)
    end
end
 

Revavi

Участник
101
24
Как сохранять информацию от сайта в переменные без создания файла? Например, на сайте такой текст:
Сайт:
var = 1
var2 = 1.00
И мне надо это сохранить в переменные test и test2, как?
 

chapo

чопа сребдс // @moujeek
Модератор
8,861
11,547
Как сохранять информацию от сайта в переменные без создания файла? Например, на сайте такой текст:
Сайт:
var = 1
var2 = 1.00
И мне надо это сохранить в переменные test и test2, как?
в каком виде сайт дает ответ? json?