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

kreyN

Известный
78
13
Можете подсказать как сделать так
/команда id причина
Если не введен id то
"Введите id"
Если не введена причина то
"введите причину"
Lua:
function main()
    if not isSampfuncsLoaded() or not isSampLoaded() then return end
    while not isSampAvailable() do wait(100) end
    wait(100)
    sampRegisterChatCommand("команда ввода в чат", cmd)
end

function cmd(id, reas)
    if tonumber(id) ~= nil and tonumber(id) ~= '' then
        if reas ~= nil and reas ~= '' then
            -- code
        else
            sampAddChatMessage('Вы не ввели причину', -1)
        end
    else
        sampAddChatMessage('Вы не ввели ID, либо ввели его неправильно', -1)
    end
end
примерно так
Исправляюсь. Вот новый код, который работает(проверил)
Lua:
function cmd(arg)
    if #arg > 0 then
        if arg:find('%d+ .*') then
            local id, reason = arg:match('(%d+) (.*)')
            sampAddChatMessage(id .. " | " .. reason, -1)
        else
            sampAddChatMessage('Вы ввели аргументы неправильно', -1)
        end
    else
        sampAddChatMessage('Вы не ввели аргументы', -1)
    end
end
вставь вместо прошлой function cmd
 

ImPasha

Software Developer & System Administrator
Друг
1,788
2,143
Пишу сбив,консоль жалуется на ошибку sbiv.lua: Script died due to an error. (070FD61C) я уже заебался с этой проблемой вот код:
Lua:
function main()
  if not isSampfuncsLoaded() or not isSampLoaded() then return end
  while not isSampAvailable()
    do
        wait(400)
    end

  while true do
      wait(0)
      if
        isKeyJustPressed(82)
        then
            freezeCharPosition(playerHandle, true)
            setPlayerControl(playerPed, false)
            freezeCharPosition(playerHandle, false)
            setPlayerControl(playerPed, true)
            wait(200)
        end
    end
end
Позвольте мне тоже помочь с написанием приватного сбива:
Lua:
function main()
    while true do
        if wasKeyPressed(0x52) then
            clearCharTasksImmediately(PLAYER_PED)
            setPlayerControl(PLAYER_HANDLE, true)
        end
        wait(0)
    end
end
 
  • Ха-ха
  • Нравится
Реакции: Leatington и backloop

Мира

Участник
455
9
что не так? не понимаю!
Код:
[18:10:41.507137] (error)    New sctript: cannot resume non-suspended coroutine
stack traceback:
    [C]: in function 'sampGetPlayerNickname'
    D:\1337SAMP_ADIDAS_EDITION\moonloader\DH.lua:43: in function <D:\1337SAMP_ADIDAS_EDITION\moonloader\DH.lua:36>
[18:10:41.507137] (error)    New sctript: Script died due to an error. (1F960A54)
Lua:
script_name('New sctript') -- название скрипта
script_author('FORMYS') -- автор скрипта
script_description('Command') -- описание скрипта

require "lib.moonloader" -- подключение библиотеки
local keys = require "vkeys"
local imgui = require 'imgui'
local encoding = require 'encoding'
encoding.default = 'CP1251'
u8 = encoding.UTF8

local fa = require 'faIcons'
local fa_glyph_ranges = imgui.ImGlyphRanges({ fa.min_range, fa.max_range })

local tag = '[My First Script]:' -- локальная переменная
local main_color = 0xffc0cb
local main_color_text = "{ffc0cb}"
local white_color = "{FFFFFF}"

local main_window_state = imgui.ImBool(false)

function imgui.BeforeDrawFrame()
    if fa_font == nil then
        local font_config = imgui.ImFontConfig() -- to use 'imgui.ImFontConfig.new()' on error
        font_config.MergeMode = true
        fa_font = imgui.GetIO().Fonts:AddFontFromFileTTF('moonloader/resource/fonts/fontawesome-webfont.ttf', 14.0, font_config, fa_glyph_ranges)
    end
end

local text_buffer = imgui.ImBuffer(256)

local sw, sh = getScreenResolution()

local img = imgui.CreateTextureFromFile(getGameDirectory() .. "\\moonloader\\images\\dh.png")

function main()
    if not isSampLoaded() or not isSampfuncsLoaded() then return end
    while not isSampAvailable() do wait(100) end
    
    sampRegisterChatCommand("imgui", cmd_imgui)
    
    _, id = sampGetPlayerIdByCharHandle(PLAYRE_PED)
    nick = sampGetPlayerNickname(id)
    
    imgui.Process = false
    
    -- Блок выполнняющийся один раз после старта сампа
    
    while true do
        wait(0)
        
        if main_window_state.v == false then
            imgui.Process = false
        end
        
        if isKeyJustPresser(VK_F3) then
            sampAddChatMessage("Вы нажали клавишу {FFFFFF}F3." .. main_color_text .. "Ваш ник: {FFFFFF}" .. nick .. "," .. main_color_text .. "ваш ID: {FFFFFF}" .. id, main_color)
        end
        
        if isKeyDown(VK_MENU) and isKeyJustPresser(VK_9) then
            sampAddChatMessage("Вы крут, вы хажали комбинацию клавиш!", main_color)
        end
        
        -- Блок выполнняющийся бесконечно (пока самп активен)
        
    end
end

function cmd_imgui(arg)
    main_window_state.v = not main_window_state.v
    imgui.Process = main_window_state.v
end

function imgui.OnDrawFrame()
    
    imgui.SetNextWindowSize(imgui.ImVec2(500, 500), imgui.Cond.FirstUseEver)
    imgui.SetNextWindowPos(imgui.ImVec2(sw / 2, sh / 2), imgui.Cond.FirstUseEver, imgui.ImVec2(0.5, 0.5))
    
    
    
    imgui.Begin(fa.ICON_HOME .. u8" DH for Mafia", main_window_state)
    imgui.SetCursorPosY(25)
    imgui.SetCursorPosX(100)
    imgui.Image(img, imgui.ImVec2(300, 200))
    imgui.Separator()
    imgui.InputText(u8'Вводить текст сюда', text_buffer)
    imgui.Text(text_buffer.v)
    if imgui.Button('Press me') then
        sampAddChatMessage(u8:decode(text_buffer.v), -1)
    end
    imgui.End()
end
 

damag

Женюсь на официантке в моем любимом баре
Проверенный
1,152
1,202
что не так? не понимаю!
Код:
[18:10:41.507137] (error)    New sctript: cannot resume non-suspended coroutine
stack traceback:
    [C]: in function 'sampGetPlayerNickname'
    D:\1337SAMP_ADIDAS_EDITION\moonloader\DH.lua:43: in function <D:\1337SAMP_ADIDAS_EDITION\moonloader\DH.lua:36>
[18:10:41.507137] (error)    New sctript: Script died due to an error. (1F960A54)
Lua:
script_name('New sctript') -- название скрипта
script_author('FORMYS') -- автор скрипта
script_description('Command') -- описание скрипта

require "lib.moonloader" -- подключение библиотеки
local keys = require "vkeys"
local imgui = require 'imgui'
local encoding = require 'encoding'
encoding.default = 'CP1251'
u8 = encoding.UTF8

local fa = require 'faIcons'
local fa_glyph_ranges = imgui.ImGlyphRanges({ fa.min_range, fa.max_range })

local tag = '[My First Script]:' -- локальная переменная
local main_color = 0xffc0cb
local main_color_text = "{ffc0cb}"
local white_color = "{FFFFFF}"

local main_window_state = imgui.ImBool(false)

function imgui.BeforeDrawFrame()
    if fa_font == nil then
        local font_config = imgui.ImFontConfig() -- to use 'imgui.ImFontConfig.new()' on error
        font_config.MergeMode = true
        fa_font = imgui.GetIO().Fonts:AddFontFromFileTTF('moonloader/resource/fonts/fontawesome-webfont.ttf', 14.0, font_config, fa_glyph_ranges)
    end
end

local text_buffer = imgui.ImBuffer(256)

local sw, sh = getScreenResolution()

local img = imgui.CreateTextureFromFile(getGameDirectory() .. "\\moonloader\\images\\dh.png")

function main()
    if not isSampLoaded() or not isSampfuncsLoaded() then return end
    while not isSampAvailable() do wait(100) end
 
    sampRegisterChatCommand("imgui", cmd_imgui)
 
    _, id = sampGetPlayerIdByCharHandle(PLAYRE_PED)
    nick = sampGetPlayerNickname(id)
 
    imgui.Process = false
 
    -- Блок выполнняющийся один раз после старта сампа
 
    while true do
        wait(0)
     
        if main_window_state.v == false then
            imgui.Process = false
        end
     
        if isKeyJustPresser(VK_F3) then
            sampAddChatMessage("Вы нажали клавишу {FFFFFF}F3." .. main_color_text .. "Ваш ник: {FFFFFF}" .. nick .. "," .. main_color_text .. "ваш ID: {FFFFFF}" .. id, main_color)
        end
     
        if isKeyDown(VK_MENU) and isKeyJustPresser(VK_9) then
            sampAddChatMessage("Вы крут, вы хажали комбинацию клавиш!", main_color)
        end
     
        -- Блок выполнняющийся бесконечно (пока самп активен)
     
    end
end

function cmd_imgui(arg)
    main_window_state.v = not main_window_state.v
    imgui.Process = main_window_state.v
end

function imgui.OnDrawFrame()
 
    imgui.SetNextWindowSize(imgui.ImVec2(500, 500), imgui.Cond.FirstUseEver)
    imgui.SetNextWindowPos(imgui.ImVec2(sw / 2, sh / 2), imgui.Cond.FirstUseEver, imgui.ImVec2(0.5, 0.5))
 
 
 
    imgui.Begin(fa.ICON_HOME .. u8" DH for Mafia", main_window_state)
    imgui.SetCursorPosY(25)
    imgui.SetCursorPosX(100)
    imgui.Image(img, imgui.ImVec2(300, 200))
    imgui.Separator()
    imgui.InputText(u8'Вводить текст сюда', text_buffer)
    imgui.Text(text_buffer.v)
    if imgui.Button('Press me') then
        sampAddChatMessage(u8:decode(text_buffer.v), -1)
    end
    imgui.End()
end

_, id = sampGetPlayerIdByCharHandle(playerPed)
 

moreveal

Известный
Проверенный
927
622
Lua:
while true do
    wait(0)

    if pfd ~= nil then
       if not isPauseMenuActive() and sampIsPlayerConnected(tonumber(pfd)) then
          local result, handle = sampGetCharHandleBySampPlayerId(pfd)

          if result and doesCharExist(handle) and isCharOnScreen(handle) then
             local px, py, pz = getCharCoordinates(PLAYER_PED)
             local tpx, tpy, tpz = getBodyPartCoordinates(5, handle)

             local result, _ = processLineOfSight(px, py, pz, tpx, tpy, tpz, true, false, false, true, false, true, false, false)
             if not result then
                local wposX, wposY = convert3DCoordsToScreen(tpx, tpy, tpz)

                renderDrawLine(wposX - 3, wposY - 3, wposX + 3, wposY + 3, 1, 0xFFFFFFFF)
                renderDrawLine(wposX - 3, wposY + 3, wposX + 3, wposY - 3, 1, 0xFFFFFFFF)
             end
          end
       end
    end
end

local ffi = require "ffi"
local getBonePosition = ffi.cast("int (__thiscall*)(void*, float*, int, bool)", 0x5E4280)

function getBodyPartCoordinates(id, handle)
  vec = ffi.new("float[3]")
  getBonePosition(ffi.cast("void*", getCharPointer(handle)), vec, id, true)
  return vec[0], vec[1], vec[2]
end
Скрипт крашится (cannot resume non-suspended coroutine) после того, как игрок заходит за препятствие. Как фиксить?
 

backloop

Участник
152
14
Хотел сделать fake /uval или /demote типо для понтов и что то пошло не так

Lua:
function main()
    sampRegisterChatCommand('dell', function(arg)
    if not tonumber(arg) then
    changeSkin(tonumber(arg), 18)
    end
    wait(-1)

    function dell(arg)
    if #arg > 0 then
        if arg:find('%d+ .*') then
            local id, reason = arg:match('(%d+) (.*)')
            sampAddChatMessage(id .. " | " .. reason, -1)
        else
            sampAddChatMessage('Вы ввели аргументы неправильно', -1)
        end
    else
        sampAddChatMessage('Вы не ввели аргументы', -1)
    end
function changeSkin(id,skinId)
    bs = raknetNewBitStream()
    if id == -1 then _, id = sampGetPlayerIdByCharHandle(PLAYER_PED) end
    raknetBitStreamWriteInt32(bs, id)
    raknetBitStreamWriteInt32(bs, skinId)
    raknetEmulRpcReceiveBitStream(153, bs)
    raknetDeleteBitStream(bs)
end
end
end)
end
визуально?
 

backloop

Участник
152
14
скинь код ошибки если он есть
Хотел сделать fake /uval или /demote типо для понтов и что то пошло не так

Lua:
function main()
    sampRegisterChatCommand('dell', function(arg)
    if not tonumber(arg) then
    changeSkin(tonumber(arg), 18)
    end
    wait(-1)

    function dell(arg)
    if #arg > 0 then
        if arg:find('%d+ .*') then
            local id, reason = arg:match('(%d+) (.*)')
            sampAddChatMessage(id .. " | " .. reason, -1)
        else
            sampAddChatMessage('Вы ввели аргументы неправильно', -1)
        end
    else
        sampAddChatMessage('Вы не ввели аргументы', -1)
    end
function changeSkin(id,skinId)
    bs = raknetNewBitStream()
    if id == -1 then _, id = sampGetPlayerIdByCharHandle(PLAYER_PED) end
    raknetBitStreamWriteInt32(bs, id)
    raknetBitStreamWriteInt32(bs, skinId)
    raknetEmulRpcReceiveBitStream(153, bs)
    raknetDeleteBitStream(bs)
end
end
end)
end
и да добавь вот это на начало
Lua:
local sampev = require 'lib.samp.events'
 

damag

Женюсь на официантке в моем любимом баре
Проверенный
1,152
1,202
Можешь подсказать код тогда, раз у меня руки из попки растут
По типу ввожу команду /dell id причина
Пример: /dell 15 Бревно

И на выбранный id, визуально одевается 18id скинa, и можешь подсказать где можно учить Lua
Lua:
function main()
    repeat wait(0) until isSampAvailable()
    sampRegisterChatCommand("dell", dell)
    wait(-1)
end

function dell(arg)
    if #arg > 0 then
        if arg:find('%d+ .*') then
            local id, reason = arg:match('(%d+) (.*)')
            sampAddChatMessage(id .. " | " .. reason, -1)
            changeSkin(id, 18)
        else
            sampAddChatMessage('Вы ввели аргументы неправильно', -1)
        end
    else
        sampAddChatMessage('Вы не ввели аргументы', -1)
    end
end

function changeSkin(id,skinId)
    bs = raknetNewBitStream()
    if id == -1 then _, id = sampGetPlayerIdByCharHandle(PLAYER_PED) end
    raknetBitStreamWriteInt32(bs, id)
    raknetBitStreamWriteInt32(bs, skinId)
    raknetEmulRpcReceiveBitStream(153, bs)
    raknetDeleteBitStream(bs)
end
 
  • Нравится
Реакции: Batya2020

kreyN

Известный
78
13
Хотел сделать fake /uval или /demote типо для понтов и что то пошло не так

Lua:
function main()
    sampRegisterChatCommand('dell', function(arg)
    if not tonumber(arg) then
    changeSkin(tonumber(arg), 18)
    end
    wait(-1)

    function dell(arg)
    if #arg > 0 then
        if arg:find('%d+ .*') then
            local id, reason = arg:match('(%d+) (.*)')
            sampAddChatMessage(id .. " | " .. reason, -1)
        else
            sampAddChatMessage('Вы ввели аргументы неправильно', -1)
        end
    else
        sampAddChatMessage('Вы не ввели аргументы', -1)
    end
function changeSkin(id,skinId)
    bs = raknetNewBitStream()
    if id == -1 then _, id = sampGetPlayerIdByCharHandle(PLAYER_PED) end
    raknetBitStreamWriteInt32(bs, id)
    raknetBitStreamWriteInt32(bs, skinId)
    raknetEmulRpcReceiveBitStream(153, bs)
    raknetDeleteBitStream(bs)
end
end
end)
end
Зачем все пихать в main(), это 1) некрасиво, 2) неразборчиво. Разбей все на составляющие, потом юзай

Lua:
function main()
    if not isSampfuncsLoaded() or not isSampLoaded() then return end
    while not isSampAvailable() do wait(100) end
        wait(100)
        sampRegisterChatCommand('dell', dell)
    while true do
        wait(0)
    end
end

function dell(arg)
    if #arg > 0 then
        if arg:find('%d+ %d+ .*') then
            local sid, id, reason = arg:match('(%d+) (%d+) (.*)')
            sampAddChatMessage('ты фейк уволил челопупса', -1)
            sampAddChatMessage(id .. " | " .. reason, -1)
            changeSkin(id, sid)
        else
            sampAddChatMessage('Вы ввели аргументы неправильно. 1 - skin, 2 - id, 3 - reason', -1)
        end
    else
        sampAddChatMessage('Вы не ввели аргументы', -1)
    end
end

function changeSkin(id,skinId)
    bs = raknetNewBitStream()
    if id == -1 then _, id = sampGetPlayerIdByCharHandle(PLAYER_PED) end
    raknetBitStreamWriteInt32(bs, id)
    raknetBitStreamWriteInt32(bs, skinId)
    raknetEmulRpcReceiveBitStream(153, bs)
    raknetDeleteBitStream(bs)
end
Тут 1 аргументом ты пишешь айди скина, который дается после фейк увала, вторым пишешь айди человека, третьим причину
 

moreveal

Известный
Проверенный
927
622
Lua:
local result, _ = processLineOfSight(px, py, pz, tpx, tpy, tpz, false, false, false, true, false, true, false, false) -- попробуй
По-прежнему крашит, стоит человеку скрыться за каким-нибудь столбом, и ставит маркер, когда человек находится за объектом, что мне не нужно)