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

Julimba

Участник
108
10
qq, как сделать, чтобы данная функция выдавала расстояние в целых числах, без десятичных.

getDistanceBetweenCoords3d(x, y, z, mX, mY, mZ)
 

whyega52

Гений, миллионер, плейбой, долбаеб
Модератор
2,778
2,598
qq, как сделать, чтобы данная функция выдавала расстояние в целых числах, без десятичных.

getDistanceBetweenCoords3d(x, y, z, mX, mY, mZ)
math.floor(getDistanceBetweenCoords3d(x, y, z, mX, mY, mZ))

inicfg

inicfg:
local cfg = inicfg.load({
    -- cfg
}, cfg_path)
люто насрал, но в теории должно работать,

Lua:
local cfg = inicfg.load({
    -- cfg
}, cfg_path)
local proxyCfg = {}
setmetatable(proxyCfg, {
    __index = function(self, k) -- вызывается тогда, когда ты вызываешь какое-либо значение
        -- это говнокод люти, но если я сяду приводить его в порядок, то я засну
        inicfg.save(cfg, "file.ini")
        return cfg[k]
    end,
    __newindex = function(self, k, v) -- вызывается, когда создаешь значение
        -- это говнокод люти, но если я сяду приводить его в порядок, то я засну
        inicfg.save(cfg, "file.ini")
        cfg[k] = v
   end
})

-- теперь чтобы измененить значение в конфиге, обращайся не к cfg, а к proxyCfg
proxyCfg.config.zalupa = true -- и т.д.
 
Последнее редактирование:
  • Нравится
  • Влюблен
Реакции: Revavi и Julimba

chapo

чопа сребдс // @moujeek
Модератор
8,861
11,547
math.floor(getDistanceBetweenCoords3d(x, y, z, mX, mY, mZ))


люто насрал, но в теории должно работать,

Lua:
local cfg = inicfg.load({
    -- cfg
}, cfg_path)
local proxyCfg = {}
setmetatable(proxyCfg, {
    __index = function (t, k) -- вызывается тогда, когда ты вызываешь какое-либо значение
        -- это говнокод люти, но если я сяду приводить его в порядок, то я засну
        inicfg.save(cfg, "file.ini")
        return cfg[k]
    end,
    __newindex = function (t, k, v) -- вызывается, когда создаешь значение
        -- это говнокод люти, но если я сяду приводить его в порядок, то я засну
        inicfg.save(cfg, "file.ini")
        cfg[k] = v
   end
})

-- теперь чтобы измененить значение в конфиге, обращайся не к cfg, а к proxyCfg
proxyCfg.config.zalupa = true -- и т.д.
эти методы не вызываются при смене значения
1684518688131.png
 

whyega52

Гений, миллионер, плейбой, долбаеб
Модератор
2,778
2,598
эти методы не вызываются при смене значения
Посмотреть вложение 202046
у меня прокси-таблица, в твоем примере ты создаешь мета-методы для дефолт таблицы
кстати, в моем примере не будут работать функции pairs, поэтому если есть нужда в них, то добавь еще один мета-метод:
__pairs = function() return pairs(cfg) end

а, ну и для того, что бы можно было получать длину таблицы, добавь еще один мета-метод
__len = function() return #cfg end
 
Последнее редактирование:
  • Нравится
Реакции: chapo

joumey

Активный
195
43
Как мне повернуть drawlist:AddImage
 
Последнее редактирование:

ch1ps

Участник
101
3
[ML] (error) spcar.lua: cannot resume non-suspended coroutine
stack traceback:
[C]: in function 'setGameKeyState'
C:\Games\GRAY SEANSIZE [REBUILT]\moonloader\spcar.lua:6: in function <C:\Games\GRAY SEANSIZE [REBUILT]\moonloader\spcar.lua:3>
[ML] (error) spcar.lua: Script died due to an error. (315B280C)

в:
require "lib.moonloader"

function main()
    while true do wait(40)
        if isCharInAnyCar(PLAYER_PED) and (isKeyDown(VK_SHIFT) and isKeyDown(VK_W)) then
            setGameKeyState(16, 255)
            wait(10)
            setGameKeyState(16, 0)
        end
    end
end

в чём трабл?
 

whyega52

Гений, миллионер, плейбой, долбаеб
Модератор
2,778
2,598
[ML] (error) spcar.lua: cannot resume non-suspended coroutine
stack traceback:
[C]: in function 'setGameKeyState'
C:\Games\GRAY SEANSIZE [REBUILT]\moonloader\spcar.lua:6: in function <C:\Games\GRAY SEANSIZE [REBUILT]\moonloader\spcar.lua:3>
[ML] (error) spcar.lua: Script died due to an error. (315B280C)

в:
require "lib.moonloader"

function main()
    while true do wait(40)
        if isCharInAnyCar(PLAYER_PED) and (isKeyDown(VK_SHIFT) and isKeyDown(VK_W)) then
            setGameKeyState(16, 255)
            wait(10)
            setGameKeyState(16, 0)
        end
    end
end

в чём трабл?
Это весь код?
 

Moorell

Участник
55
12
Помогите народ.
Как мне узнать умер ли персонаж, эвент
onPlayerDeath тупо не работает на аризоне, либо я что то не так делаю, хотя на других проектах все работает отлично.
 

Andrinall

Известный
702
518
Помогите народ.
Как мне узнать умер ли персонаж, эвент
onPlayerDeath тупо не работает на аризоне, либо я что то не так делаю, хотя на других проектах все работает отлично.
Можно попробовать хукать CTaskSimpleDie::StartAnim
UPD: ещё можно хукнуть CTaskSimpleDie::CreateFirstSubTask - эффект примерно тот же
hooks.jmp.new('void*(__thiscall*)(int, int)', onPedDie, 0x6302D0)
(но если умирает серверный актёр то координаты через getCharCoordinates будут не верны,
да и в целом с актёрами работает так себе)
Lua:
local hooks = require 'hooks'
function onPedPlayingDieAnim(this, cped)
    pcall(function(cped) -- pcall чтоб не крашить игру в случае косяков в коде)
        local hped = getCharPointerHandle(cped)
        if hped == -1 then return end -- игнор невалидных педов
        --if hped == PLAYER_PED then return end -- игнорить свою смерть
        local res, pid = sampGetPlayerIdByCharHandle(hped)
        --if not res then return end -- игнорить смерть игровых актёров, вывод только смертей игроков
        local x, y, z = getCharCoordinates(hped)

        print("=============================")
        print("Ped is dead")
        print("CPed :", tostring(cped))
        print("Handle:", hped)
        print("IsLocal:", hped == PLAYER_PED)
        print("Coordinates:{", x, y, z ,"}")
        print("IsPlayer:", tostring(res), "ID:", pid)
        if res then print("IsNPC:", sampIsPlayerNPC(pid)) end
        print("=============================")

    end, cped)
    return hook_CTaskSimpleDie_StartAnim(this, cped) -- вызов ориг.метода
end


function main()
    hook_CTaskSimpleDie_StartAnim = hooks.jmp.new('int(__thiscall*)(int, int)', onPedPlayingDieAnim, 0x637520)
    if hook_CTaskSimpleDie_StartAnim then print("hook_CTaskSimpleDie_StartAnim Installed") end
    repeat wait(100) until isSampAvailable()
    -- ... code
end

function onScriptTerminate(sc, qg)
    if sc == thisScript() then
        if hook_CTaskSimpleDie_StartAnim then
            hook_CTaskSimpleDie_StartAnim.stop()
            onPedPlayingDieAnim = nil
            hook_CTaskSimpleDie_StartAnim = nil
        end
        collectgarbage()
        collectgarbage()
    end
end
изображение_2023-05-20_091831534.png


или через samp.Lua обрабатывать ApplyActorAnimation
Lua:
local ev = require 'lib.samp.events'
function ev.onApplyActorAnimation(actorId, animLib, animName, fDelta, bLoop, bLockX, bLockY, bFreeze, time)
    if animLib == "PED" and animName == "KO_SHOT_FRONT" then
        -- вместо PED KO_SHOT_FRONT ту анимку, которая ставится актёру(почекать через print(animLib, animName))
        sampAddChatMessage("Actor is dead", -1)
    end
end
 
Последнее редактирование:
  • Нравится
Реакции: Moorell и whyega52

whyega52

Гений, миллионер, плейбой, долбаеб
Модератор
2,778
2,598
Можно попробовать хукать CTaskSimpleDie::StartAnim
UPD: ещё можно хукнуть CTaskSimpleDie::CreateFirstSubTask - эффект примерно тот же
hooks.jmp.new('void*(__thiscall*)(int, int)', onPedDie, 0x6302D0)
(но если умирает серверный актёр то координаты через getCharCoordinates будут не верны,
да и в целом с актёрами работает так себе)
Lua:
local hooks = require 'hooks'
function onPedPlayingDieAnim(this, cped)
    pcall(function(cped) -- pcall чтоб не крашить игру в случае косяков в коде)
        local hped = getCharPointerHandle(cped)
        if hped == -1 then return end -- игнор невалидных педов
        --if hped == PLAYER_PED then return end -- игнорить свою смерть
        local res, pid = sampGetPlayerIdByCharHandle(hped)
        --if not res then return end -- игнорить смерть игровых актёров, вывод только смертей игроков
        local x, y, z = getCharCoordinates(hped)

        print("=============================")
        print("Ped is dead")
        print("CPed :", tostring(cped))
        print("Handle:", hped)
        print("IsLocal:", hped == PLAYER_PED)
        print("Coordinates:{", x, y, z ,"}")
        print("IsPlayer:", tostring(res), "ID:", pid)
        if res then print("IsNPC:", sampIsPlayerNPC(pid)) end
        print("=============================")

    end, cped)
    return hook_CTaskSimpleDie_StartAnim(this, cped) -- вызов ориг.метода
end


function main()
    hook_CTaskSimpleDie_StartAnim = hooks.jmp.new('int(__thiscall*)(int, int)', onPedPlayingDieAnim, 0x637520)
    if hook_CTaskSimpleDie_StartAnim then print("hook_CTaskSimpleDie_StartAnim Installed") end
    repeat wait(100) until isSampAvailable()
    -- ... code
end

function onScriptTerminate(sc, qg)
    if sc == thisScript() then
        if hook_CTaskSimpleDie_StartAnim then
            hook_CTaskSimpleDie_StartAnim.stop()
            onPedPlayingDieAnim = nil
            hook_CTaskSimpleDie_StartAnim = nil
        end
        collectgarbage()
        collectgarbage()
    end
end
Посмотреть вложение 202089


или через samp.Lua обрабатывать ApplyActorAnimation
Lua:
local ev = require 'lib.samp.events'
function ev.onApplyActorAnimation(actorId, animLib, animName, fDelta, bLoop, bLockX, bLockY, bFreeze, time)
    if animLib == "PED" and animName == "KO_SHOT_FRONT" then
        -- вместо PED KO_SHOT_FRONT ту анимку, которая ставится актёру(почекать через print(animLib, animName))
        sampAddChatMessage("Actor is dead", -1)
    end
end
если пошла тема с хуками, то можно попробовать хукать этот метод
C++:
// R1
BOOL CActor::IsDead() {
    return ((BOOL(__thiscall*)(CActor*))GetAddress(0x98020))(this);
}
правда я хрен знает, как он работает и работает ли так, как нужно
 
  • Нравится
Реакции: Andrinall

ArtemHaker228

Новичок
18
3
Хочу задать очень интересный вопрос!
Возможно ли как-то через Lua сделать скрипт который будет заменять текстуру автомобиля в котором сидит игрок? Или другие способа реализовать это идею есть ли?
 

whyega52

Гений, миллионер, плейбой, долбаеб
Модератор
2,778
2,598
Хочу задать очень интересный вопрос!
Возможно ли как-то через Lua сделать скрипт который будет заменять текстуру автомобиля в котором сидит игрок? Или другие способа реализовать это идею есть ли?
Можно изменить модельку автомобиля