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

imring

Ride the Lightning
Всефорумный модератор
2,363
2,550
Неработает у меня это!
Всё работает.
p.s. Создавал для теста моего кода
Lua:
function main()
    while not isSampAvailable() do wait(0) end
    sampRegisterChatCommand('test', function()
        local weapon = getCurrentCharWeapon(playerPed)
        if weapon == 24 then
            sampSendChat('/me достал дигл.')
        end
    end)
    wait(-1)
end
Lua:
function main()
    while not isSampAvailable() do wait(0) end
    sampRegisterChatCommand('test', test)
    wait(-1)
end

function test()
    local weapon = getCurrentCharWeapon(playerPed)
    if weapon == 24 then
        sampSendChat('/me достал дигл.')
    end
end
 

RTD

Потужно
Модератор
399
470
Всё работает.
p.s. Создавал для теста моего кода
Lua:
function main()
    while not isSampAvailable() do wait(0) end
    sampRegisterChatCommand('test', function()
        local weapon = getCurrentCharWeapon(playerPed)
        if weapon == 24 then
            sampSendChat('/me достал дигл.')
        end
    end)
    wait(-1)
end
Lua:
function main()
    while not isSampAvailable() do wait(0) end
    sampRegisterChatCommand('test', test)
    wait(-1)
end

function test()
    local weapon = getCurrentCharWeapon(playerPed)
    if weapon == 24 then
        sampSendChat('/me достал дигл.')
    end
end
Слишком много if будет, думаю лучше вот так. Только коректировок много нужно сделать.
Lua:
weaponNames = {[0] = "Fist",[1] = "Brass Knuckles",[2] = "Golf Club",[3] = "Nightstick",[4] = "Knife",[5] = "Baseball Bat",[6] = "Shovel",[7] = "Pool Cue",[8] = "Katana",[9] = "Chainsaw",[10] = "Purple Dildo",[11] = "Dildo",[12] = "Vibrator",[13] = "Silver Vibrator",[14] = "Flowers",[15] = "Cane",[16] = "Grenade",[17] = "Tear Gas",[18] = "Molotov Cocktail",[19] = "",[20] = "",[21] = "",[22] = "9mm",[23] = "Silenced 9mm",[24] = "Desert Eagle",[25] = "Shotgun",[26] = "Sawnoff Shotgun",[27] = "Combat Shotgun",[28] = "Micro SMG/Uzi",[29] = "MP5",[30] = "AK-47",[31] = "M4",[32] = "Tec-9",[33] = "Country Rifle",[34] = "Sniper Rifle",[35] = "RPG",[36] = "HS Rocket",[37] = "Flamethrower",[38] = "Minigun",[39] = "Satchel Charge",[40] = "Detonator",[41] = "Spraycan",[42] = "Fire Extinguisher",[43] = "Camera",[44] = "Night Vis Goggles",[45] = "Thermal Goggles",[46] = "Parachute"}
function main()
    if not isSampLoaded() or not isSampfuncsLoaded() then return end
    while not isSampAvailable() do wait(100) end
    while true do
        wait(0)
        local curentWeapon = getCurrentCharWeapon(playerPed)
        if curentWeapon ~= lastWeapon then
            sampSendChat('/me достал ' .. weaponNames[curentWeapon], -1)
            lastWeapon = curentWeapon
        end
     end
end
 

itsLegend

Фонд борьбы за жуков 🐞
Администратор
2,696
1,468
Наверно будет лучше вот так (c версии .023-beta):
Lua:
local game_weapons = require 'game.weapons'

function main()
    if not isSampLoaded() or not isSampfuncsLoaded() then return end
    while not isSampAvailable() do wait(100) end
    while true do
        wait(0)
        local currentWeapon = getCurrentCharWeapon(playerPed)
        if currentWeapon ~= lastWeapon then
            sampAddChatMessage('/me достал ' .. game_weapons.get_name(currentWeapon), -1)
            lastWeapon = currentWeapon
        end
     end
end
 
  • Нравится
Реакции: RTD

RTD

Потужно
Модератор
399
470
Наверно будет лучше вот так (c версии .023-beta):
Lua:
local game_weapons = require 'game.weapons'

function main()
    if not isSampLoaded() or not isSampfuncsLoaded() then return end
    while not isSampAvailable() do wait(100) end
    while true do
        wait(0)
        local currentWeapon = getCurrentCharWeapon(playerPed)
        if currentWeapon ~= lastWeapon then
            sampAddChatMessage('/me достал ' .. game_weapons.get_name(currentWeapon), -1)
            lastWeapon = currentWeapon
        end
     end
end
Только вот изменить имя оружия будет не удобно.
 

FYP

Известный
Автор темы
Администратор
1,764
5,922
@yuy111 иди учи основы программирования и синтаксис луа. ты засираешь тему тупейшими вопросами.

В клео есть прикольный опкод
Код:
0C74: 2@ = create_timer_interval 0@ on_label 1@
Он создает таймер, который работает даже когда игра свернута. (Чтобы например сделать таймер нарко, и он не сбивался пока ты АФК)
В луа я к сожалению пока такое не нашел, кто знает помогите. Очень нужно чтобы скрипт продолжал работу когда свернута игра.

lua - luathread | BlastHack — DEV_WIKI(https://blast.hk/wiki/lua:luathread)
Тут читаю про work_in_pause не могу сделать это в коде, не вижу примеров
Но кажется с этим параметром поток будет работать только когда окно GTA активно, даже если пауза
На свернутой наверно не будет
это недочёт опкода, а не фича. в луа такого нет.
скрипты не должны работать, если сама игра не работает - так задумано.

Lua:
if imgui.MenuItem('Load Setting') then
      ini.load(cfg, "setting test")
end
if imgui.MenuItem('Save Setting') then
      ini.save(cfg, "setting test")
end
[ML] (exception) Test.lua: error saving ini file: D:\Games\SAMP\moonloader\config\setting test.ini: cannot open file
Собственно при вызове сохранения настроек мун выдает ошибку. Админ права стоя. Путь без кирилицы. Параметр только чтение убран со всех ключевых файлов.
такая ошибка может возникать только если файл действительно невозможно открыть, она генерируется даже не самим муном, а из буста. может файл заблокирован для чтения другим процессом?
 
Последнее редактирование:
  • Нравится
Реакции: memir, RTD и obitashka

serhiyrubin

Известный
396
106
это недочёт опкода, а не фича. в луа такого нет.
скрипты не должны работать, если сама игра не работает - так задумано.
Я на этом недочете в клео сделал уведомление о АФК для одного и нескольких окон samp)
Уведомление через MsgBox когда все GTAшки свернуты, и если играю в другом окне GTA - уведомление через Чат/Диалог по выбору.
Когда доделаю выложу скрипт. Хотелось перевести на луа, получается что не выйдет(


Это получается на луа даже анти афк нельзя сделать, чтобы шел таймер пока игра свернута
Может добавите эту функцию в луа?)
 

AnWu

Известный
Всефорумный модератор
4,777
5,398
Всем привет, написал небольшой скрипт для своего сервера, что бы легко телепортироваться между бизнесами. Написал просто основу, еще не делал сам телепорт, уже нашел проблему.
Команда срабатывает только 1 раз, после чего скрипт крашится с вот таким сообщением в лог.
Код:
[12:07:00.097947] (system)    Business Teleport: Script terminated. (0C65B09C)
[12:07:00.097947] (debug)    Remove thread 17047015 from SCM-thread queue
Вот сам скрипт, помогите понять, в чем проблема, спасибо)
Lua:
script_name("Business Teleport")
script_authors("#Maddison")
script_version_number(1)

business_list =
[[
{FF9900}1. Казино г.Los-Santos
{AFAF00}2. Риэлторское агентство
{AFAF00}3. Управление статистики
{5FB404}4. Центральный отель г.Los-Santos
{5FB404}5. Отель "Jefferson"
{5FB404}6. Отель г.San-Fierro
{5FB404}7. Отель в р.Bayside
{5FB404}8. Отель в д.Fort Carson
{5FB404}8. Отель в д.Blueberry
{5FB404}9. Пиратский отель в г.Las-Venturas
{5FB404}10. Отель "Visage"
{5FB404}11. Отель г.Las-Venturas
{0099d6}12. Развлекательный центр
{0099d6}13. 24/7 у ТЦЛС
{0099d6}14. Салон красоты в ТЦЛС
{0099d6}15. Магазин одежды в ТЦЛС
]]

function main()
    if not isSampLoaded() or not isSampfuncsLoaded() then return end
    while not isSampAvailable() do wait(100) end
       
    sampAddChatMessage("> [BizTeleport] {FFFFFF}Скрипт загружен. Разработчик: {0099FF}Michael Maddison.",0x0099FF)
    sampAddChatMessage("> [BizTeleport] {FFFFFF}Для вызова меню бизнесов используйте команду: {0099FF}/biztp",0x0099FF)
   
    sampRegisterChatCommand("biztp",cmd_biztp)
   
    repeat wait(0) result, button, listitem = sampHasDialogRespond(50) until result
    gotoBusiness(listitem,button)
end

function cmd_biztp()
    sampShowDialog(50, "{FFFF00}Список бизнесов", business_list, "Телепорт", "Закрыть", 2)
end

function gotoBusiness(id,bt)
    if bt then
        if id == 0 then
            sampAddChatMessage("> [BizTeleport] {FFFFFF}Вы успешно телепортировались в {0099FF}Казино г.Los-Santos.",0x0099FF)
        end
        if id == 2 then
            sampAddChatMessage("> [BizTeleport] {FFFFFF}Вы успешно телепортировались в {0099FF}Риэлторское агентство.",0x0099FF)
        end
        if id == 3 then
            sampAddChatMessage("> [BizTeleport] {FFFFFF}Вы успешно телепортировались в {0099FF}Управление статистики.",0x0099FF)
        end
        if id == 4 then
            sampAddChatMessage("> [BizTeleport] {FFFFFF}Вы успешно телепортировались в {0099FF}Центральный отель г.Los-Santos.",0x0099FF)
        end
        if id == 5 then
            sampAddChatMessage("> [BizTeleport] {FFFFFF}Вы успешно телепортировались в {0099FF}Отель \"Jefferson\".",0x0099FF)
        end
        if id == 6 then
            sampAddChatMessage("> [BizTeleport] {FFFFFF}Вы успешно телепортировались в {0099FF}Отель г.San-Fierro.",0x0099FF)
        end
        if id == 7 then
            sampAddChatMessage("> [BizTeleport] {FFFFFF}Вы успешно телепортировались в {0099FF}Отель в р.Bayside.",0x0099FF)
        end
        if id == 8 then
            sampAddChatMessage("> [BizTeleport] {FFFFFF}Вы успешно телепортировались в {0099FF}Отель в д.Fort Carson.",0x0099FF)
        end
        if id == 9 then
            sampAddChatMessage("> [BizTeleport] {FFFFFF}Вы успешно телепортировались в {0099FF}Отель в д.Blueberry.",0x0099FF)
        end
        if id == 10 then
            sampAddChatMessage("> [BizTeleport] {FFFFFF}Вы успешно телепортировались в {0099FF}Отель г.Las-Venturas.",0x0099FF)
        end
        if id == 11 then
            sampAddChatMessage("> [BizTeleport] {FFFFFF}Вы успешно телепортировались в {0099FF}Развлекательный центр.",0x0099FF)
        end
        if id == 12 then
            sampAddChatMessage("> [BizTeleport] {FFFFFF}Вы успешно телепортировались в {0099FF}24/7 у ТЦЛС.",0x0099FF)
        end
        if id == 13 then
            sampAddChatMessage("> [BizTeleport] {FFFFFF}Вы успешно телепортировались в {0099FF}Салон красоты в ТЦЛС.",0x0099FF)
        end
        if id == 14 then
            sampAddChatMessage("> [BizTeleport] {FFFFFF}Вы успешно телепортировались в {0099FF}Магазин одежды в ТЦЛС.",0x0099FF)
        end
    end
end
Все таки сегодня первый день, как я решил что то на lua сделать, вообще не шарю в этой шайтан-машине, пока что ;с
Lua:
    repeat wait(0) result, button, listitem = sampHasDialogRespond(50) until result
    gotoBusiness(listitem,button)


Ошибка именно тут. Если ты хочешь чтобы скрипт работал постоянно, нужно держать main() активным.
Lua:
while true do
    wait(0)
       local result, button, listitem = sampHasDialogRespond(50)
       if(result) then
             gotoBusiness(listitem,button)
       end
    end