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

Samper_Sampovskiy

Участник
47
17
Всем привет. На аризоне появилась система дрифта, при нажатии клавиши "2" на клавиатуре, вылизает диалог, там можно выбрать режим дрифта, и когда вылазиет эта менюшка, я же понимаю это сделано на bitstream? Я просто не знаю как захукать, потому что при появлении ничего не хукается, ни в консоль, ничего, можете помочь разобраться?
 

sep

Известный
681
77
как сделать сохранение скриншотов по другой кнопке в другую папку
то есть нажимаю ф8 обычный скриншот нажимаю другую кринку и скриншот сохраняется в другую папку

if isKeyJustPressed(VK_F9) then makeScreenshot() end
как перенести типо сразу сделанный скриншот в другую папку
 

Орк

Известный
340
304
как сделать сохранение скриншотов по другой кнопке в другую папку
то есть нажимаю ф8 обычный скриншот нажимаю другую кринку и скриншот сохраняется в другую папку

if isKeyJustPressed(VK_F9) then makeScreenshot() end
как перенести типо сразу сделанный скриншот в другую папку
Lua:
local rwcam = ffi.cast("void* *", 0xC97C28)
local TakeScreenshot = ffi.cast("void(__cdecl*)(void *, const char*)", 0x5D0820)
local p = getWorkingDirectory() .. "\\screen.jpg"
TakeScreenshot(rwcam, p)
 
  • Нравится
Реакции: sep

sep

Известный
681
77
Lua:
local rwcam = ffi.cast("void* *", 0xC97C28)
local TakeScreenshot = ffi.cast("void(__cdecl*)(void *, const char*)", 0x5D0820)
local p = getWorkingDirectory() .. "\\screen.jpg"
TakeScreenshot(rwcam, p)

это просто добавить в

if isKeyJustPressed(VK_F9) then
makeScreenshot()

local rwcam = ffi.cast("void* *", 0xC97C28)
local TakeScreenshot = ffi.cast("void(__cdecl*)(void *, const char*)", 0x5D0820)
local p = getWorkingDirectory() .. "\\screen.jpg"
TakeScreenshot(rwcam, p)

end

плиз поподробней ?

и какие библиотеки нужны кроме ffi
 

Орк

Известный
340
304
это просто добавить в

if isKeyJustPressed(VK_F9) then
makeScreenshot()

local rwcam = ffi.cast("void* *", 0xC97C28)
local TakeScreenshot = ffi.cast("void(__cdecl*)(void *, const char*)", 0x5D0820)
local p = getWorkingDirectory() .. "\\screen.jpg"
TakeScreenshot(rwcam, p)

end

плиз поподробней ?

и какие библиотеки нужны кроме ffi
Мне за тебя код писать?
Lua:
--вне main
function screen(path)
    local path = tostring(path)
    local D3D9Device = ffi.cast("void* *", 0xC97C28)
    local TakeScreenshot = ffi.cast("void(__cdecl*)(void *, const char*)", 0x5D0820) -- FUNC_JPegCompressScreenToFile
    TakeScreenshot(D3D9Device, path)
end

if isKeyJustPressed(VK_F9) then
    local ppath = getWorkingDirectory() .. "\\screen.jpg"
    screen(ppath)
end
 
  • Нравится
Реакции: sep

Oki_Bern

Участник
289
7
есть массив со значениями, как сделать, чтоб при обращении к значению(там стоит переменная) оно меняла свое значение. Например cb1 поменяет свое значение, пробовал так, но не вышло:

Lua:
local bizlist = {
    ["1. Palomino Creek 1"] = cb1,
    ["2. Palomino Creek 2"] = cb2,
    ["3. Palomino Creek 3"] = cb3,
    ["4. Palomino Creek 4"] = cb4,
    ["5. Dillimore 1"] = cb5,
    ["6. Dillimore 2"] = cb6,
    ["7. Dillimore 3"] = cb7,
    ["8. Blueberry 1"] = cb8,
    ["9. Blueberry 2"] = cb9,
    ["10. Blueberry 3"] = cb10,
    ["11. Montgomery 1"] = cb11,
    ["12. Montgomery 2"] = cb12,
    ["13. Montgomery 3"] = cb13,
    ["14. Montgomery 4"] = cb14,
    ["15. Fort Carson 1"] = cb15,
    ["16. Fort Carson 2"] = cb16,
    ["17. Fort Carson 3"] = cb17,
    ["18. Fort Carson 4"] = cb18,
    ["19. Fort Carson 5"] = cb19,
    ["20. Fort Carson 6"] = cb20,
    ["21. El Quebrados 1"] = cb21,
    ["22. El Quebrados 2"] = cb22,
    ["23. El Quebrados 3"] = cb23,
    ["24. El Quebrados 4"] = cb24,
    ["25. Las Barrancas 1"] = cb25,
    ["26. Las Barrancas 2"] = cb26,
    ["27. Angel Pine 1"] = cb27,
    ["28. Angel Pine 2"] = cb28,
}
Lua:
    for k, v in pairs(bizlist) do
        if text:find(k.."    %[ %{......%}Warlocks MC%{......%} %]") then
            v = "1"
        end

        if text:find(k.."    %[ %{......%}Mongols MC%{......%} %]") then
            v = "2"
        end

        if text:find(k.."    %[ %{......%}Pagans MC%{......%} %]") then
            v = "3"
        end
    end
 

chapo

tg/inst: @moujeek
Всефорумный модератор
9,129
12,253
есть массив со значениями, как сделать, чтоб при обращении к значению(там стоит переменная) оно меняла свое значение. Например cb1 поменяет свое значение, пробовал так, но не вышло:

Lua:
local bizlist = {
    ["1. Palomino Creek 1"] = cb1,
    ["2. Palomino Creek 2"] = cb2,
    ["3. Palomino Creek 3"] = cb3,
    ["4. Palomino Creek 4"] = cb4,
    ["5. Dillimore 1"] = cb5,
    ["6. Dillimore 2"] = cb6,
    ["7. Dillimore 3"] = cb7,
    ["8. Blueberry 1"] = cb8,
    ["9. Blueberry 2"] = cb9,
    ["10. Blueberry 3"] = cb10,
    ["11. Montgomery 1"] = cb11,
    ["12. Montgomery 2"] = cb12,
    ["13. Montgomery 3"] = cb13,
    ["14. Montgomery 4"] = cb14,
    ["15. Fort Carson 1"] = cb15,
    ["16. Fort Carson 2"] = cb16,
    ["17. Fort Carson 3"] = cb17,
    ["18. Fort Carson 4"] = cb18,
    ["19. Fort Carson 5"] = cb19,
    ["20. Fort Carson 6"] = cb20,
    ["21. El Quebrados 1"] = cb21,
    ["22. El Quebrados 2"] = cb22,
    ["23. El Quebrados 3"] = cb23,
    ["24. El Quebrados 4"] = cb24,
    ["25. Las Barrancas 1"] = cb25,
    ["26. Las Barrancas 2"] = cb26,
    ["27. Angel Pine 1"] = cb27,
    ["28. Angel Pine 2"] = cb28,
}
Lua:
    for k, v in pairs(bizlist) do
        if text:find(k.."    %[ %{......%}Warlocks MC%{......%} %]") then
            v = "1"
        end

        if text:find(k.."    %[ %{......%}Mongols MC%{......%} %]") then
            v = "2"
        end

        if text:find(k.."    %[ %{......%}Pagans MC%{......%} %]") then
            v = "3"
        end
    end
Lua:
for k, v in pairs(bizlist) do
    local pattern = k .. "    %[ %{......%}(.+) MC%{......%} %]");
    if (text:find(pattern)) then
        bizlist[k] = ({Warlocks = 1, Mongols = 2, Pagans = 3})[text:match(pattern)];
    end
end
 
  • Нравится
Реакции: Oki_Bern

Hidetaka

Новичок
14
1
Пытаюсь написать бота по координатам. Нашёл код для реализации бега по координатам, но практически ничего из этого не понимаю. На Луа кодить умею базовые вещи, а тут код стрёмный, что пиздец (непонятный). Поясните, пожалуйста, за что отвечают эти строки конкретно.


function runToPoint(tox, toy)
local x, y, z = getCharCoordinates(PLAYER_PED)
local angle = getHeadingFromVector2d(tox - x, toy - y)
local xAngle = math.random(-50, 50)/100
setCameraPositionUnfixed(xAngle, math.rad(angle - 90))
stopRun = false
while getDistanceBetweenCoords2d(x, y, tox, toy) > 0.8 do
setGameKeyState(1, -255)
--setGameKeyState(16, 1)
wait(1)
x, y, z = getCharCoordinates(PLAYER_PED)
angle = getHeadingFromVector2d(tox - x, toy - y)
setCameraPositionUnfixed(xAngle, math.rad(angle - 90))
if stopRun then
stopRun = false
break
end
end
end
 

еврей

Участник
46
13
привет, кто сможет сейчас помочь с вырезанием 1 функции в скрипте, нужно прям фастом если скинете тг или дс, напишу, там работы очень мало и быстро делается как помне, а мне прям поможете
 

Arahis

Новичок
8
2
Как в mimgui сделать масштабирование колонки в таблице по самой большой?
 

Mockingbird

Новичок
16
2
Всем привет, нужна помощь. Есть такой кусок кода:


Код:
elseif text:find("посадил:") then
        sendtg("Администратор что-то пишет")
Этот функция читает чат сампа и когда вскакивает "посадил" отправляет сообщение в телеграм. Но, мне нужно сделать так, что бы он отправлял, когда "Администратор *ник* посадил в призон игрока *ник*", загвоздка в том, что я не могу понять как сделать так, чтобы он считывал "Администратор *ник* посадил" но, не могу понять как заставить его игнорировать ник админа, так как этот часть меняется. Помогите :/
 

Arahis

Новичок
8
2
Всем привет, нужна помощь. Есть такой кусок кода:


Код:
elseif text:find("посадил:") then
        sendtg("Администратор что-то пишет")
Этот функция читает чат сампа и когда вскакивает "посадил" отправляет сообщение в телеграм. Но, мне нужно сделать так, что бы он отправлял, когда "Администратор *ник* посадил в призон игрока *ник*", загвоздка в том, что я не могу понять как сделать так, чтобы он считывал "Администратор *ник* посадил" но, не могу понять как заставить его игнорировать ник админа, так как этот часть меняется. Помогите :/
 
  • Нравится
Реакции: Mockingbird

dmitry.karle

Известный
364
101
в чём прикол?
Код:
local imgui = require 'mimgui'
local encoding = require 'encoding'
local effil = require 'effil'
local memory = require 'memory'
encoding.default = 'CP1251'
u8 = encoding.UTF8
local new = imgui.new
local renderWindow = new.bool(false)
imgui.OnInitialize(function()
    imgui.GetIO().IniFilename = nil
end)
local newFrame = imgui.OnFrame(
    function() return renderWindow[0] end,
    function(player)
        local resX, resY = getScreenResolution()
        local sizeX, sizeY = 300, 300
        imgui.SetNextWindowPos(imgui.ImVec2(resX / 2, resY / 2), imgui.Cond.FirstUseEver, imgui.ImVec2(0.5, 0.5))
        imgui.SetNextWindowSize(imgui.ImVec2(sizeX, sizeY), imgui.Cond.FirstUseEver)
        imgui.Begin('Main Window', renderWindow)
        imgui.ImageURL("https://items.shinoa.tech/images/model/2296.png", imgui.ImVec2(256, 256), true)
        imgui.End()
    end
)
sampRegisterChatCommand('urlt', function()
    renderWindow[0] = not renderWindow[0]
end)
function handleAsyncHttpRequestThread(runner, resolve, reject)
  local status, err
  repeat
    status, err = runner:status()
    wait(0)
  until status ~= 'running'
  if not err then
    if status == 'completed' then
      local result, response = runner:get()
      if result then
        resolve(response)
      else
        reject(response)
      end
      return
    elseif status == 'canceled' then
      return reject(status)
    end
  else
    return reject(err)
  end
end
function asyncHttpRequest(method, url, args, resolve, reject)
   local request_thread = effil.thread(function (method, url, args)
      local requests = require 'requests'
      local result, response = pcall(requests.request, method, url, args)
      if result then
         response.json, response.xml = nil, nil
         return true, response
      else
         return false, response
      end
   end)(method, url, args)
   -- Если запрос без функций обработки ответа и ошибок.
   if not resolve then resolve = function() end end
   if not reject then reject = function() end end
   -- Проверка выполнения потока
    lua_thread.create(function()
      local runner = request_thread
      while true do
         local status, err = runner:status()
         if not err then
            if status == 'completed' then
               local result, response = runner:get()
               if result then
                  resolve(response)
               else
                  reject(response)
               end
               return
            elseif status == 'canceled' then
               return reject(status)
            end
         else
            return reject(err)
         end
         wait(0)
      end
   end)
end
local md5 = require "md5"

imgui.ImageURL = {
    cache_dir = getWorkingDirectory() .. "/resource/cache",
    download_statuses = {
        INIT = 0,
        DOWNLOADING = 1,
        ERROR = 2,
        SAVED = 3,
        NOT_MODIFIED = 4,
        CACHE_ONLY = 5
    },
    pool = {}
}

function imgui.ImageURL:set_cache(url, image_data, headers)
    if not doesDirectoryExist(self.cache_dir) then
        createDirectory(self.cache_dir)
    end

    local path = ("%s/%s"):format(self.cache_dir, md5.sumhexa(url))
    local file, err = io.open(path, "wb")
    if not file then
        return nil
    end

    local data = { Data = tostring(image_data) }
    if headers["etag"] then
        data["Etag"] = headers["etag"]
    end
    if headers["last-modified"] then
        data["Last-Modified"] = headers["last-modified"]
    end

    file:write(encodeJson(data))
    file:close()
    return path
end

function imgui.ImageURL:get_cache(url)
    local path = ("%s/%s"):format(self.cache_dir, md5.sumhexa(url))
    if not doesFileExist(path) then
        return nil, nil
    end

    local image_data = nil
    local cached_headers = {}

    local file, err = io.open(path, "rb")
    if file then
        local cache = decodeJson(file:read("*a"))
        if type(cache) ~= "table" then
            return nil, nil
        end

        if cache["Data"] ~= nil then
               image_data = cache["Data"]
           end
           if cache["Last-Modified"] ~= nil then
               cached_headers["If-Modified-Since"] = cache["Last-Modified"]
           end
           if cache["Etag"] ~= nil then
               cached_headers["If-None-Match"] = cache["Etag"]
           end

        file:close()
    end
    return image_data, cached_headers
end

function imgui.ImageURL:download(url, preload_cache)
    local st = self.download_statuses
    self.pool[url] = {
        status = st.DOWNLOADING,
        image = nil,
        error = nil
    }
    local cached_image, cached_headers = imgui.ImageURL:get_cache(url)
    local img = self.pool[url]

    if preload_cache and cached_image ~= nil then
        img.image = imgui.CreateTextureFromMemory(memory.strptr(cached_image), #cached_image)
    end

    asyncHttpRequest("GET", url, { headers = cached_headers },
        function(result)
            if result.status_code == 200 then
                img.image = imgui.CreateTextureFromMemory(memory.strptr(result.text), #result.text)
                img.status = st.SAVED
                imgui.ImageURL:set_cache(url, result.text, result.headers)
            elseif result.status_code == 304 then
                img.image = img.image or imgui.CreateTextureFromMemory(memory.strptr(cached_image), #cached_image)
                img.status = st.NOT_MODIFIED
            else
                img.status = img.image and st.CACHE_ONLY or st.ERROR
                img.error = ("Error #%s"):format(result.status_code)
            end
        end,
        function(error)
            img.status = img.image and st.CACHE_ONLY or st.ERROR
            img.error = error
        end
    )
end

function imgui.ImageURL:render(url, size, preload, ...)
    local st = self.download_statuses
    local img = self.pool[url]

    if img == nil then
        self.pool[url] = {
            status = st.INIT,
            error = nil,
            image = nil
        }
        img = self.pool[url]
    end

    if img.status == st.INIT then
        imgui.ImageURL:download(url, preload)
    end
        
    if img.image ~= nil then
        imgui.Image(img.image, size, ...)
    else
        imgui.Dummy(size)
    end
    return img.status, img.error
end

setmetatable(imgui.ImageURL, {
    __call = imgui.ImageURL.render
})
ошибка :168: attempt to call field 'CreateTextureFromMemory' (a nil value)