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

m1racles

Активный
204
35
[ML] (error) function main().lua: E:\GTA 140K BY DAPO SHOW\moonloader\function main().lua:18: '(' expected near 'print'
[ML] (error) function main().lua: Script died due to an error. (14DA5D7C)

Lua:
function main()
    while not isSampAvailable() do wait(0) end
    sampRegisterChatCommand("harddisk", cmd_hard)
    while true do
        wait(0)
        function getHarddiskSerial()
            local handle = io.popen('wmic diskdrive get serialnumber')
            local result = handle:read("*a")
            local serial = result:match('SerialNumber%s+(%d+)')
            handle:close()
            return serial
        end
        function cmd_hard
            print(getHarddiskSerial())
        end
    end
end
что неправильно в 14 строке
 

kizn

\ 0 _ 0 /
Всефорумный модератор
2,408
2,090
[ML] (error) function main().lua: E:\GTA 140K BY DAPO SHOW\moonloader\function main().lua:18: '(' expected near 'print'
[ML] (error) function main().lua: Script died due to an error. (14DA5D7C)

Lua:
function main()
    while not isSampAvailable() do wait(0) end
    sampRegisterChatCommand("harddisk", cmd_hard)
    while true do
        wait(0)
        function getHarddiskSerial()
            local handle = io.popen('wmic diskdrive get serialnumber')
            local result = handle:read("*a")
            local serial = result:match('SerialNumber%s+(%d+)')
            handle:close()
            return serial
        end
        function cmd_hard
            print(getHarddiskSerial())
        end
    end
end
что неправильно в 14 строке
Нахуя ты функции в бесконечный цикл засунул
а еще у cmd_hard должны быть скобочки ()
 
  • Влюблен
Реакции: m1racles

XishE

Новичок
7
2
[11:40:58] Kirill_Evans[110] : {FFCD00}sp
Приходит вот такая строка, как сделать авто-ответ?
lua:
local sampev = require 'lib.samp.events'
local spec = false


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

   sampRegisterChatCommand('fr', function()
      state = not state
      sampAddChatMessage(state and 'enabled' or 'disabled', -1)
   end)

   wait(-1)
end


function sampev.onTogglePlayerSpectating(state)
   spec = state
end

function Y()
    if state and not spec and text:find("[%] %[%]: {FFCD00}%") and not sampIsDialogActive() and not isSampfuncsConsoleActive() and not sampIsChatInputActive() then
        local var1, var2, var3, var4, var5 = REPORT:match("[%] %[%]: {FFCD00}sp")
        time_rep = var1
        report_name = var2
        report_id = var3
        report_text = var5
        sampSendChat("/pm "..report_id.. "Ужаваемый игрок, отправил вас на место спавна. ")
        wait(100)
           sampSendChat("/sp "..report_id)
        end
    end
end
 

Вложения

  • report.lua
    971 байт · Просмотры: 5
Последнее редактирование:

Andrinall

Известный
702
518
Итак, есть у меня значит вот такой вот код:
Lua:
local ffi = require 'ffi'
local winmm = ffi.load('winmm.dll')
if winmm ~= nil and winmm ~= false then
    JOYSTICKID1 = 0
    JOYSTICKID2 = 1
    JOYERR_BASE      = 160
    JOYERR_NOERROR   = 0
    JOYERR_PARMS     = JOYERR_BASE + 5
    JOYERR_NOCANDO   = JOYERR_BASE + 6
    JOYERR_UNPLUGGED = JOYERR_BASE + 7

    joyerr = { [0] = "NO ERROR", [160] = "BASE", [165] = "ERR PARMS", [166] = "ERR NOCANDO", [167] = "ERR UNPLUGGED" }
    JOY_RETURNALL = 0x00000001 or 0x00000002 or 0x00000004 or 0x00000008 or 0x00000010 or 0x00000020 or 0x00000040 or 0x00000080

    ffi.cdef[[
        typedef unsigned long  DWORD;
        typedef unsigned short WORD;
        typedef unsigned int   UINT;
        typedef char            CHAR;
        typedef unsigned int   UINT_PTR;
        typedef int            BOOL;
        typedef UINT           MMRESULT;
        typedef UINT            *LPUINT;
        typedef wchar_t        WCHAR;
        struct HWND__ { int unused; };
        typedef struct HWND__ *HWND;

        int MAXPNAMELEN;
        int MAX_JOYSTICKOEMVXDNAME;
    ]]
    MAXPNAMELEN = ffi.new("int"); MAXPNAMELEN = 32
    MAX_JOYSTICKOEMVXDNAME = ffi.new("int"); MAX_JOYSTICKOEMVXDNAME = 260
    ffi.cdef[[
        typedef struct tagJOYCAPSW {
            WORD    wMid;                                /* manufacturer ID */
            WORD    wPid;                                /* product ID */
            WCHAR   szPname[MAXPNAMELEN];                /* product name (NULL terminated string) */
            UINT    wXmin;                               /* minimum x position value */
            UINT    wXmax;                               /* maximum x position value */
            UINT    wYmin;                               /* minimum y position value */
            UINT    wYmax;                               /* maximum y position value */
            UINT    wZmin;                               /* minimum z position value */
            UINT    wZmax;                               /* maximum z position value */
            UINT    wNumButtons;                         /* number of buttons */
            UINT    wPeriodMin;                          /* minimum message period when captured */
            UINT    wPeriodMax;                          /* maximum message period when captured */
            UINT    wRmin;                               /* minimum r position value */
            UINT    wRmax;                               /* maximum r position value */
            UINT    wUmin;                               /* minimum u (5th axis) position value */
            UINT    wUmax;                               /* maximum u (5th axis) position value */
            UINT    wVmin;                               /* minimum v (6th axis) position value */
            UINT    wVmax;                               /* maximum v (6th axis) position value */
            UINT    wCaps;                               /* joystick capabilites */
            UINT    wMaxAxes;                            /* maximum number of axes supported */
            UINT    wNumAxes;                            /* number of axes in use */
            UINT    wMaxButtons;                         /* maximum number of buttons supported */
            WCHAR   szRegKey[MAXPNAMELEN];                /* registry key */
            WCHAR   szOEMVxD[MAX_JOYSTICKOEMVXDNAME];     /* OEM VxD in use */
        } JOYCAPSW, *PJOYCAPSW, *NPJOYCAPSW, *LPJOYCAPSW; /* Если здесь поставить ... NEAR *NPJOYCAPSW, FAR *LPJOYCAPSW; */
                                                          /* как в оригинале - будет выдавать ошибку "ожидалось ;" или типо того */
    ]]
    ffi.cdef[[
        typedef struct joyinfo_tag {
            UINT wXpos;                 /* x position */
            UINT wYpos;                 /* y position */
            UINT wZpos;                 /* z position */
            UINT wButtons;              /* button states */
        } JOYINFO, *PJOYINFO, *NPJOYINFO, *LPJOYINFO; // near *NPJOYINFO, far *LPJOYINFO
    
        typedef struct joyinfoex_tag {
            DWORD dwSize;                /* size of structure */
            DWORD dwFlags;               /* flags to indicate what to return */
            DWORD dwXpos;                /* x position */
            DWORD dwYpos;                /* y position */
            DWORD dwZpos;                /* z position */
            DWORD dwRpos;                /* rudder/4th axis position */
            DWORD dwUpos;                /* 5th axis position */
            DWORD dwVpos;                /* 6th axis position */
            DWORD dwButtons;             /* button states */
            DWORD dwButtonNumber;        /* current button number pressed */
            DWORD dwPOV;                 /* point of view state */
            DWORD dwReserved1;           /* reserved for communication between winmm & driver */
            DWORD dwReserved2;           /* reserved for future expansion */
        } JOYINFOEX, *PJOYINFOEX, *NPJOYINFOEX, *LPJOYINFOEX; // near *NPJOYINFOEX, far *LPJOYINFOEX
    ]]
    ffi.cdef[[
        UINT joyGetNumDevs(void);
        MMRESULT joyGetDevCapsW(    UINT_PTR uJoyID, LPJOYCAPSW pjc,   UINT cbjc);
        MMRESULT joyGetPos(         UINT uJoyID,       LPJOYINFO pji);
        MMRESULT joyGetPosEx(         UINT uJoyID,       LPJOYINFOEX pji);
    ]]

    joyinfo              = ffi.new("JOYINFO");
    joyinfoex           = ffi.new("JOYINFOEX");
    lpjoycapsw            = ffi.new("JOYCAPSW");
    joyname            = ffi.new("WCHAR");
    joyinfoex.dwSize   = ffi.sizeof(joyinfoex);
    joyinfoex.dwFlags  = JOY_RETURNALL;
    result                  = ffi.new("MMRESULT");
    caps_result        = ffi.new("MMRESULT");

    TrueDeviceID        = -1;
    nums                = {-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
    wDeviceID            = 0;
    wcDeviceID          = false;
    globalErr           = 0;
    JOY_Buttons        = {
        [0]="None",    [1]="A",                 [2]="B",                [4]="X",
        [8]="Y",       [16]="LB",               [32]="RB",               [64]="Back",
        [128]="Start", [256]="LStickButton", [512]="RStickButton"
    }
    JOY_POVS           = {
        [0] = "UP",       [4500] = "RIGHT-UP",      [9000] = "RIGHT", [13500] = "RIGHT-DOWN",
        [18000] = "DOWN", [22500] = "LEFT-DOWN", [27000] = "LEFT", [31500] = "LEFT-UP", [65535] = "None"
    }
else error("Lib WinMM.dll not Found. Script Crashed!"); return false;
end

local font = renderCreateFont('Century Gothic', 13, 0x01+0x04)
local visible = true;

function main()
    while not isSampfuncsLoaded() do wait(100) end
    repeat wait(100) until isSampAvailable()
    wNumDevs = winmm.joyGetNumDevs();

    sampRegisterChatCommand('joytest', function() visible = not visible end)

    while true do wait(0)
        if visible then
            bDev1Attached = winmm.joyGetPos(JOYSTICKID1, joyinfo) ~= JOYERR_UNPLUGGED;
            --if wNumDevs >= 2 and winmm.joyGetPos(JOYSTICKID2, joyinfo) ~= JOYERR_UNPLUGGED then bDev2Attached = wNumDevs end
            if bDev1Attached or bDev2Attached then wDeviceID = bDev1Attached end
        
            if wDeviceID then
                local r;
                for i = 1, #nums do r = winmm.joyGetPosEx(nums[i], joyinfoex); if r ~= 165 and r ~= 166 and r ~= 167 and r == 0 then TrueDeviceID = nums[i]; wcDeviceID = true; end    end
                if not wcDeviceID then globalErr = r; end
            end
        
            if wcDeviceID then
                result = winmm.joyGetPosEx(TrueDeviceID, joyinfoex);
                if result ~= 0 then wcDeviceID = false; end
            
                if wcDeviceID then            
                    if joyinfoex.dwZpos == 127 then joyinfoex.dwZpos = 0 end
                    if joyinfoex.dwZpos == 65407 then joyinfoex.dwZpos = 65535 end
                
                    caps_result = winmm.joyGetDevCapsW(TrueDeviceID, lpjoycapsw, ffi.sizeof(lpjoycapsw));
                    local formated = {
                        [1] = function() return "Device Name: "..caps_result.." > "..tostring(lpjoycapsw.szPname).."" end, -- здесь должно показывать Gamepad F310 (Controller)
                        [2] = function() return string.format("Result: %s | Struct info: %s", joyerr[result], tostring(joyinfoex)) end,
                        [3] = function() return string.format("X: %d%% | Y: %d%% |Z: %d%%",
                                                    (joyinfoex.dwXpos / 1000) * 1.525902189669643,
                                                    (joyinfoex.dwYpos / 1000) * 1.525902189669643,
                                                    (joyinfoex.dwZpos / 1000) * 1.525902189669643)
                              end,
                        [4] = function() return string.format("V: %d%% | U: %d%% | R: %d%%",
                                                    (joyinfoex.dwVpos / 1000) * 1.525902189669643,
                                                    (joyinfoex.dwUpos / 1000) * 1.525902189669643,
                                                    (joyinfoex.dwRpos / 1000) * 1.525902189669643)
                              end,
                        [5] = function() return string.format("Current Buttons: %s ", JOY_Buttons[joyinfo.wButtons]) end,
                        [6] = function() return string.format("POV: %s", JOY_POVS[joyinfoex.dwPOV]) end
                    }
                    for i = 1, #formated do renderFontDrawText(font, tostring(formated[i]()), 20, 430 + (i* 20), 0x99FFFFFF) end
                end
            elseif not wcDeviceID then
                renderFontDrawText(font, "Device Not Found. Error: "..joyerr[globalErr], 20, 430, 0x99FFFFFF)
            end
        end
    end
end

Он вроде как адекватно отображает значения (Оси геймпада).
1624961311963.png
Но... я столкнулся с такой проблемой, что он почему-то отказывается показывать
имя девайса через winmm.joyGetDevCapsW(UINT_PTR uJoyID, LPJOYCAPSW pjc, UINT cbjc); ...
и выдаёт 165 ошибку JOYERR_PARMS или 11 ошибку MMSYSERR_INVALPARAM на все возможные uJoyID.. (не понял от чего зависит ошибка)
Пробовал через ffi.new создавать переменную с типом UINT_PTR, заранее объявив её в ffi.cdef,
пробовал менять типы данных для переменной lpjoycapsw, используемой 2 аргументов в вызове функции.
Ой, да чего только я не пробовал...
Пробовал даже циклом чекать не от -1 до 15(16), а до 500.. Это ничего не дало.

Хотя через winmm.joyGetPosEx(UINT uJoyID, LPJOYINFOEX pji); нормально возвращается MMRESULT == 0
то есть JOYERR_NOERROR или MMSYSERR_NOERROR.

Скрин рендера... В Device Name записывается MMRESULT от вызова winmm.joyGetDevCapsW(TrueDeviceID, lpjoycapsw, ffi.sizeof(lpjoycapsw));
и lpjoycaps.szPname
( "Device Name: "..caps_result.." > "..tostring(lpjoycapsw.szPname).."" )
1624954420591.png

В чём может быть проблема? (Кроме "говнокод", это я и так знаю. Нужно повествование по конкретной проблеме)
 
Последнее редактирование:

Andrinall

Известный
702
518
[11:40:58] Kirill_Evans[110] : {FFCD00}sp
Приходит вот такая строка, как сделать авто-ответ?
lua:
local sampev = require 'lib.samp.events'
local spec = false


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

   sampRegisterChatCommand('fr', function()
      state = not state
      sampAddChatMessage(state and 'enabled' or 'disabled', -1)
   end)

   wait(-1)
end


function sampev.onTogglePlayerSpectating(state)
   spec = state
end

function Y()
    if state and not spec and text:find("[%] %[%]: {FFCD00}%") and not sampIsDialogActive() and not isSampfuncsConsoleActive() and not sampIsChatInputActive() then
        local var1, var2, var3, var4, var5 = REPORT:match("[%] %[%]: {FFCD00}sp")
        time_rep = var1
        report_name = var2
        report_id = var3
        report_text = var5
        sampSendChat("/pm "..report_id.. "Ужаваемый игрок, отправил вас на место спавна. ")
        wait(100)
           sampSendChat("/sp "..report_id)
        end
    end
end
[11:40:58] Kirill_Evans[110] : {FFCD00}sp
Это точная строка?
 

XishE

Новичок
7
2
[11:40:58] Kirill_Evans[110] : {FFCD00}sp
Это точная строка?
да скопировал из чат лога.
Скрипт запускается но не работает, подскажите в чем проблема.
1624967508649.png

report:
local sampev = require 'lib.samp.events'
local spec = false


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

   sampRegisterChatCommand('fr', function()
      state = not state
      sampAddChatMessage(state and 'enabled' or 'disabled', -1)
   end)

   wait(-1)
end


function sampev.onTogglePlayerSpectating(state)
   spec = state
end

function Y()
    if state and not spec and text:find("[%] %[%]: {FFCD00}%") and not sampIsDialogActive() and not isSampfuncsConsoleActive() and not sampIsChatInputActive() then
        local var1, var2, var3, var4, var5 = REPORT:match("[%] %[%]: {FFCD00}sp")
        time_rep = var1
        report_name = var2
        report_id = var3
        report_text = var5
        sampSendChat("/pm "..report_id.. "Ужаваемый игрок, отправил вас на место спавна. ")
        wait(100)
        sampSendChat("/sp "..report_id)
        end
end
 
Последнее редактирование:

Mr.Mastire222

Известный
530
260
Когда активируется эта функция после отыгровки выдаёт ошибку "команда не найдена" вот код
code:
        if imgui.Button(u8"Снять наручники", imgui.ImVec2(120, 50)) then
            if textbuffer.v == "" then
                sampAddChatMessage("Вы не ввели ID", -1)
            else
                lua_thread.create(function()
            sampSendChat("/do На поясе ключи от наручников.")
                wait(1500)
            sampSendChat("/me снял ключи с пояса, вставил ключ в замок и снял их с человека")
                wait(1500)
            sampSendChat("/uncuff" ..tostring(textbuffer.v))
 

bottom_text

Известный
675
320
Когда активируется эта функция после отыгровки выдаёт ошибку "команда не найдена" вот код
code:
        if imgui.Button(u8"Снять наручники", imgui.ImVec2(120, 50)) then
            if textbuffer.v == "" then
                sampAddChatMessage("Вы не ввели ID", -1)
            else
                lua_thread.create(function()
            sampSendChat("/do На поясе ключи от наручников.")
                wait(1500)
            sampSendChat("/me снял ключи с пояса, вставил ключ в замок и снял их с человека")
                wait(1500)
            sampSendChat("/uncuff" ..tostring(textbuffer.v))
Я так понимаю ты про ошибку от сервера, попробуй в последней строчки пробел поставить, как здесь
Lua:
  sampSendChat("/uncuff " ..tostring(textbuffer.v))
Сервер думает, что ты отправил команду к примеру /uncuff228, а не /uncuff 228
 
  • Нравится
Реакции: Mr.Mastire222

Mr.Mastire222

Известный
530
260
как создать меню которое активируется например /commanda id там будут пункты и после выбора будет идти команда /commanda в которой 2 аргрумента и ид (/commanda id 1 2
 

Andrinall

Известный
702
518
да скопировал из чат лога.
Скрипт запускается но не работает, подскажите в чем проблема.
Посмотреть вложение 103088
report:
local sampev = require 'lib.samp.events'
local spec = false


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

   sampRegisterChatCommand('fr', function()
      state = not state
      sampAddChatMessage(state and 'enabled' or 'disabled', -1)
   end)

   wait(-1)
end


function sampev.onTogglePlayerSpectating(state)
   spec = state
end

function Y()
    if state and not spec and text:find("[%] %[%]: {FFCD00}%") and not sampIsDialogActive() and not isSampfuncsConsoleActive() and not sampIsChatInputActive() then
        local var1, var2, var3, var4, var5 = REPORT:match("[%] %[%]: {FFCD00}sp")
        time_rep = var1
        report_name = var2
        report_id = var3
        report_text = var5
        sampSendChat("/pm "..report_id.. "Ужаваемый игрок, отправил вас на место спавна. ")
        wait(100)
        sampSendChat("/sp "..report_id)
        end
end
Как я понял, время отправляет не сервер т.к. это больше на самповский timestamp больше похоже.
Не уверен, что всё 100% будет работать, но попробуй.
 

Вложения

  • report.lua
    927 байт · Просмотры: 8

XishE

Новичок
7
2
Как я понял, время отправляет не сервер т.к. это больше на самповский timestamp больше похоже.
Не уверен, что всё 100% будет работать, но попробуй.
[22:15:24.805118] (system) Loading script 'C:\СМОУК РИВЕРО (СБОРКА GTA)\moonloader\report (4).lua'...
[22:15:24.805118] (debug) New script: 4D748B4C
[22:15:24.811119] (system) report (4).lua: Loaded successfully.
Скрипт загружается но не работает
 

Gorskin

♥ Love Lua ♥
Проверенный
1,332
1,169
[22:15:24.805118] (system) Loading script 'C:\СМОУК РИВЕРО (СБОРКА GTA)\moonloader\report (4).lua'...
[22:15:24.805118] (debug) New script: 4D748B4C
[22:15:24.811119] (system) report (4).lua: Loaded successfully.
Скрипт загружается но не работает
а так?
 

Вложения

  • report.lua
    886 байт · Просмотры: 7