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

klk300

Участник
36
1
Все равно не понимаю, код не мой, а вырезан из собейта от @cover
это вопросы по луа , а не напиши плиз чит
Lua:
local key = require "vkeys"
activate = false
function main()
    while not isSampAvailable() do wait(100) end
    while true do wait(0)
        if isKeyJustPressed(key.VK_RSHIFT) then
            activate = not activate
            local posX, posY, posZ = getCharCoordinates(playerPed)
            airBrkCoords = {posX, posY, posZ, 0.0, 0.0, getCharHeading(playerPed)}
        end
        doWork()
    end
end

function doWork()
    if activate then
        local camCoordX, camCoordY, camCoordZ = getActiveCameraCoordinates()
        local targetCamX, targetCamY, targetCamZ = getActiveCameraPointAt()
        local angle = getHeadingFromVector2d(targetCamX - camCoordX, targetCamY - camCoordY)
        if isCharInAnyCar(playerPed) then difference = 0.79 else difference = 1.0 end
            setCharCoordinates(playerPed, airBrkCoords[1], airBrkCoords[2], airBrkCoords[3] - difference)
            if isKeyDown(VK_W) then
                airBrkCoords[1] = airBrkCoords[1] + 1 * math.sin(-math.rad(angle))
                airBrkCoords[2] = airBrkCoords[2] + 1 * math.cos(-math.rad(angle))
                if not isCharInAnyCar(playerPed) then setCharHeading(playerPed, angle)
                else setCarHeading(storeCarCharIsInNoSave(playerPed), angle) end
            elseif isKeyDown(VK_S) then
                airBrkCoords[1] = airBrkCoords[1] - 1 * math.sin(-math.rad(heading))
                airBrkCoords[2] = airBrkCoords[2] - 1 * math.cos(-math.rad(heading))
            end
            if isKeyDown(VK_A) then
                airBrkCoords[1] = airBrkCoords[1] - 1 * math.sin(-math.rad(heading - 90))
                airBrkCoords[2] = airBrkCoords[2] - 1 * math.cos(-math.rad(heading - 90))
            elseif isKeyDown(VK_D) then
                airBrkCoords[1] = airBrkCoords[1] - 1 * math.sin(-math.rad(heading + 90))
                airBrkCoords[2] = airBrkCoords[2] - 1 * math.cos(-math.rad(heading + 90))
            end
            if isKeyDown(VK_UP) then airBrkCoords[3] = airBrkCoords[3] + 1 / 2.0 end
            if isKeyDown(VK_DOWN) and airBrkCoords[3] > -95.0 then airBrkCoords[3] = airBrkCoords[3] - 1 / 2.0 end
    end
end
это самый простой вариант, вырезал все не понятное
 

FBenz

Активный
328
40
Ты не найдешь ответа на этот вопрос, как минимум потому, что никто не знает причины вылетов от асинхронных запросов, ибо ошибку в лог бьет при краше вообще нелогичную. Если крашит, значит поток встретился с потоком как ты не крути, даже при том, что твою проверку он проходит. Тут нет никакой логики, она сломана. Увеличивай задержку между запросами или еще че нить..
У меня цикличная функа с асинхроном работала так:
Функция, в ней поток, там бесконечный цикл с задержкой 1000 и внутри цикла асинхронный. Крашей не было. Если есть, то, как и говорил - потоки встретились.
Запилил вот такой код, все остальные асинхроны вырубил. Все равно крашит. Что может быть не так? Проверку не обходят, потоки в асинхронной функции успевают завершиться, проверял вручную и при помощи чата, куда выводил состояние асинхронного потока. Перед началом другого он всегда принимал значение Dead. Но все равно крашит. Может что-то не так?
Уже подустал ломать голову над этой задачей. В лог вообще ничего не выводит. Вылетает именно игра.

Асинхроны не встречаются, понятия не имею, что не так.
Lua:
settings.threadtwo = lua_thread.create(onGetCasefile) -- пример запуска. Где-то в onDrawFrame()

function onGetCasefile()


asyncHttpRequest('GET', "ссыль", nil, -- выполняется асинхрон
  function(response)
--ну, тут код х
  end,
  function(err)
     sampAddChatMessage('{6600FF}Нет связи')
  end)
 
  while true do
    wait(5)
     if settings.thread:status() == 'dead' then -- ждем, когда завершится асинхронный поток (аналог settings.thread.dead)
      wait(1000)
       break -- по завершению переходим к другим асинхронам
     end
   end
 
 
  for i = 1, tonumber(casefile.get.count) do -- nick, name, old, frac, sex, status, short, invest, imgur
 
   while true do
    wait(5)
     if settings.thread:status() == 'dead' then -- проверяем, завершился ли асинхронный запрос перед тем, который в цикле
      wait(1000) -- на всякий ждем секунду
       sampAddChatMessage('{6600ff}'..tostring(settings.thread.dead))
       break
     end
   end

    asyncHttpRequest('GET', "ссыль2", nil,
     function(response)
      --ну, тут код х2
      end
     end,
     function(err)
      sampAddChatMessage('{6600FF}Нет связи')
     end)
 
   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
   settings.thread = 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
 
Последнее редактирование:

Anton Nixon

Активный
474
48
Хелпаните по ошибке
Код:
[ML] (error) mo_helper.lua: ...es\Grand Theft Auto San Andreas\moonloader\mo_helper.lua:47: attempt to index global 'main' (a nil value)
stack traceback:
    ...es\Grand Theft Auto San Andreas\moonloader\mo_helper.lua:47: in main chunk
Lua:
local Password             = imgui.ImBuffer(tostring(main.settings.password) or "", 256)
 

Roger Camillo

Известный
51
7
Ребята, вопросик, как сделать так что в диалог автоматически так сказать писался текст, и нажимал 'enter'
За ранее спасибо <3
 

Anton Nixon

Активный
474
48
вот как оно сделано у меня:
Lua:
-- подключаю библиотеку
local sampev = require 'lib.samp.events'
-- загружаю из ini файла переменную с текстом и объявляю ее
local gInfo = inicfg.load({
     info = {
        text = ""
        }
}, "primer.ini")
local Text = imgui.ImBuffer(tostring(gInfo.info.text) or "", 256)
-- cоздаю функцию для этой всей бодяги
function sampev.onShowDialog(dialogId, style, title, button1, button2, text)
    if title:find("название диалога") and text:find("немного текста из окна диалога(2-3 слова)") then
        sampSendDialogResponse(dialogId, 1, 0, u8:decode(Text.v)) -- 1 - клавиша enter; u8:decode(Text.v) - текст который возьмется из файла
        return false
    end
end
Это лишь пример, может и быдлокод, но я делал у себя автологин для АРП, не знаю, вроде работает безотказно ;)
 

Roger Camillo

Известный
51
7
вот как оно сделано у меня:
Lua:
-- подключаю библиотеку
local sampev = require 'lib.samp.events'
-- загружаю из ini файла переменную с текстом и объявляю ее
local gInfo = inicfg.load({
     info = {
        text = ""
        }
}, "primer.ini")
local Text = imgui.ImBuffer(tostring(gInfo.info.text) or "", 256)
-- cоздаю функцию для этой всей бодяги
function sampev.onShowDialog(dialogId, style, title, button1, button2, text)
    if title:find("название диалога") and text:find("немного текста из окна диалога(2-3 слова)") then
        sampSendDialogResponse(dialogId, 1, 0, u8:decode(Text.v)) -- 1 - клавиша enter; u8:decode(Text.v) - текст который возьмется из файла
        return false
    end
end
Это лишь пример, может и быдлокод, но я делал у себя автологин для АРП, не знаю, вроде работает безотказно ;)
Спасибо
 

Dmitriy Makarov

25.05.2021
Проверенный
2,478
1,113
как сделать команду на включение/выключения всего скрипта?
нужна команда /mh для включения и выключения