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

linmsqn

Участник
337
9
Lua:
local ffi = require 'ffi'
local hook = {hooks = {}}
addEventHandler('onScriptTerminate', function(scr)
    if scr == script.this then
        for i, hook in ipairs(hook.hooks) do
            if hook.status then
                hook.stop()
            end
        end
    end
end)

ffi.cdef [[
    int VirtualProtect(void* lpAddress, unsigned long dwSize, unsigned long flNewProtect, unsigned long* lpflOldProtect);
]]

function hook.new(cast, callback, hook_addr, size)
    local size = size or 5
    local new_hook = {}
    local detour_addr = tonumber(ffi.cast('intptr_t', ffi.cast('void*', ffi.cast(cast, callback))))
    local void_addr = ffi.cast('void*', hook_addr)
    local old_prot = ffi.new('unsigned long[1]')
    local org_bytes = ffi.new('uint8_t[?]', size)
    ffi.copy(org_bytes, void_addr, size)
    local hook_bytes = ffi.new('uint8_t[?]', size, 0x90)
    hook_bytes[0] = 0xE9
    ffi.cast('uint32_t*', hook_bytes + 1)[0] = detour_addr - hook_addr - 5
    new_hook.call = ffi.cast(cast, hook_addr)
    new_hook.status = false
    local function set_status(bool)
        new_hook.status = bool
        ffi.C.VirtualProtect(void_addr, size, 0x40, old_prot)
        ffi.copy(void_addr, bool and hook_bytes or org_bytes, size)
        ffi.C.VirtualProtect(void_addr, size, old_prot[0], old_prot)
    end
    new_hook.stop = function() set_status(false) end
    new_hook.start = function() set_status(true) end
    new_hook.start()
    table.insert(hook.hooks, new_hook)
    return setmetatable(new_hook, {
        __call = function(self, ...)
            self.stop()
            local res = self.call(...)
            self.start()
            return res
        end
    })
end

function main()
    while not isSampAvailable() do
        wait(0)
    end 
    sampChatHook = hook.new('void(__thiscall *)(void *this, uint32_t type, const char* text, const char* prefix, uint32_t color, uint32_t pcolor)', ChatHook, getModuleHandle('samp.dll') + 0x64010)
    wait(-1)
end

function ChatHook(HOOKED_CHAT_THIS, HOOKED_CHAT_TYPE, HOOKED_CHAT_TEXT, HOOKED_CHAT_PREFIX, HOOKED_CHAT_COLOR, HOOKED_CHAT_PCOLOR)
    local text = ffi.string(HOOKED_CHAT_TEXT)
    if text:find('Screenshot Taken (-) sa-mp(-)(%d+).png') then
        printStringNow('TEST MSG', 2000)
    end
    sampChatHook(HOOKED_CHAT_THIS, HOOKED_CHAT_TYPE, HOOKED_CHAT_TEXT, HOOKED_CHAT_PREFIX, HOOKED_CHAT_COLOR, HOOKED_CHAT_PCOLOR)
end
неа, не работает. скриню но не выводит на экран тестмсг, а сам скрипт все равно живет и не вырубается
 

Karnado

Новичок
3
0
Есть код:
Lua:
function sampev.onSpectatePlayer(playerId, camType)
    id = playerId
    local res, handlew = sampGetCharHandleBySampPlayerId(playerId)
    sp_window_state.v = true
    imgui.Process = sp_window_state.v
end
Мне нужно получить Handle игрока, который находится в машине, потому что данный код возвращает "-1" (если игрок в машине).
 

Senya.Volin

Участник
67
4
Lua:
require "lib.moonloader"

local vkeys = require "vkeys"
local imgui = require  "imgui"

function imgui.OnDrawFrame()
    imgui.Begin("Main Window")
    imgui.Text("УГОЛОВНЫЙ КОДЕКС ШТАТА")
    imgui.End()
end


function main
 imgui.Process = true
 end

Почему не работает скрипт?
 

accord-

Потрачен
437
79
Обратите внимание, пользователь заблокирован на форуме. Не рекомендуется проводить сделки.
Lua:
require "lib.moonloader"

local vkeys = require "vkeys"
local imgui = require  "imgui"

function imgui.OnDrawFrame()
    imgui.Begin("Main Window")
    imgui.Text("УГОЛОВНЫЙ КОДЕКС ШТАТА")
    imgui.End()
end


function main
 imgui.Process = true
 end

Почему не работает скрипт?
 

ARMOR

Модератор по раксампу
Модератор
4,937
6,736
Lua:
require "lib.moonloader"

local vkeys = require "vkeys"
local imgui = require  "imgui"

function imgui.OnDrawFrame()
    imgui.Begin("Main Window")
    imgui.Text("УГОЛОВНЫЙ КОДЕКС ШТАТА")
    imgui.End()
end


function main
 imgui.Process = true
 end

Почему не работает скрипт?
Вот тебе простой рабочий код который открывает/закрывает imgui окно на клавишу X(Икс)
Lua:
require 'lib.moonloader'
local imgui = require 'imgui'

local main_window_state = imgui.ImBool(false)

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

    imgui.Process = false

    while true do
        wait(0)
        if wasKeyPressed(VK_X) then
            main_window_state.v = not main_window_state.v
            imgui.Process = main_window_state.v
        end
    end
end

function imgui.OnDrawFrame()
    imgui.Begin("Window", main_window_state)
        imgui.Text("Text")
    imgui.End()
end
 

IT clown

Участник
45
2
Lua:
-- RakBot

function onRunCommand(cmd)
    if cmd:match('^!komanda%s*') then -- команды на ракботе начинаются с ! (в данном примере команда - !komanda)
        -- твой код
        return false
    end
end
Cкрипт срабатывает, но в чате ракбота пишет [ERROR] Команда !komanda не найдена, не критично конечно, но если можно исправить не помешало бы. Можешь объяснить для чего ^!komanda%s* эти символы еще нужны?
 

kizn

\ 0 _ 0 /
Всефорумный модератор
2,408
2,090
Cкрипт срабатывает, но в чате ракбота пишет [ERROR] Команда !komanda не найдена, не критично конечно, но если можно исправить не помешало бы. Можешь объяснить для чего ^!komanda%s* эти символы еще нужны?
ой, вместо return false напиши return true

^! - текст команды начинается на !
%s* - ноль или больше пробелов
 
  • Нравится
Реакции: IT clown

Xomyachok-chok-chok

Новичок
16
1
Попробовал сделать луа, но он не работает, почему?

script_name('name')
script_version('0.1')

require 'lib.sampfuncs'
require 'lib.moonloader'
local hook = require 'lib.samp.events'

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


function hook.onServerMessage(color, text) -- Поиск сообщения в чате
if string.match(text, 'искомый текст') then
sampSendChat('вывод сообщения при нахождении текста')
end
end
 

chapo

чопа сребдс // @moujeek
Модератор
8,866
11,562
Попробовал сделать луа, но он не работает, почему?

script_name('name')
script_version('0.1')

require 'lib.sampfuncs'
require 'lib.moonloader'
local hook = require 'lib.samp.events'

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


function hook.onServerMessage(color, text) -- Поиск сообщения в чате
if string.match(text, 'искомый текст') then
sampSendChat('вывод сообщения при нахождении текста')
end
end
при использовании sampSendChat в onServerMessage необходимо добавить задержку хотя бы в 1 мс
Lua:
function hook.onServerMessage(color, text)
    if string.match(text, 'искомый текст') then
        lua_thread.create(function() -- создаем поток (потому что использовать wait() можно либо в потоке, либо в main())
            wait(1) -- ждем 1 мс
            sampSendChat('вывод сообщения при нахождении текста')
        end)
    end
end
 
  • Нравится
Реакции: Xomyachok-chok-chok

Xomyachok-chok-chok

Новичок
16
1
при использовании sampSendChat в onServerMessage необходимо добавить задержку хотя бы в 1 мс
Lua:
function hook.onServerMessage(color, text)
    if string.match(text, 'искомый текст') then
        lua_thread.create(function() -- создаем поток (потому что использовать wait() можно либо в потоке, либо в main())
            wait(1) -- ждем 1 мс
            sampSendChat('вывод сообщения при нахождении текста')
        end)
    end
end
Заработало, спасибо. Ещё вопрос - ответь если не сложно, как сделать чтобы после нахождения текста часть копировалась, а потом вставлялась?
Что-то типо такого:
function hook.onServerMessage(color, text)
if string.match(text, 'Ivan_Ivanov нашёл пакет') then
lua_thread.create(function()
wait(1)
sampSendChat('/me забрал пакет у [Ivan_Ivanov]')
end)
end
end
 
Последнее редактирование:

chapo

чопа сребдс // @moujeek
Модератор
8,866
11,562
Заработало, спасибо. Ещё вопрос - ответь если не сложно, как сделать чтобы после нахождения текста часть копировалась, а потом вставлялась?
 
  • Нравится
Реакции: Xomyachok-chok-chok

Flexxxing

Новичок
19
0
Всем привет, кто может помочь?
Сделать активацию на определенную кнопку что бы вылезало меню с активацией.
Нужно что бы скрипт в N радиусе (5 например) искал ID игрока и вводил команду /sell (например) [ID ближайшего игрока] [значение которое можно поменять в меню]
Итого:
Активация по кнопке, после чего меню, в меню включить выключить, команда которую можно поменять, значение которое можно поменять.

Всем привет, кто может помочь?
Сделать активацию на определенную кнопку что бы вылезало меню с активацией.
Нужно что бы скрипт в N радиусе (5 например) искал ID игрока и вводил команду /sell (например) [ID ближайшего игрока] [значение которое можно поменять в меню]
Итого:
Активация по кнопке, после чего меню, в меню включить выключить, команда которую можно поменять, значение которое можно поменять.
Ещё желательно настраиваемый радиус через это же меню
 

qdIbp

Автор темы
Проверенный
1,435
1,175
Всем привет, кто может помочь?
Сделать активацию на определенную кнопку что бы вылезало меню с активацией.
Нужно что бы скрипт в N радиусе (5 например) искал ID игрока и вводил команду /sell (например) [ID ближайшего игрока] [значение которое можно поменять в меню]
Итого:
Активация по кнопке, после чего меню, в меню включить выключить, команда которую можно поменять, значение которое можно поменять.


Ещё желательно настраиваемый радиус через это же меню