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

hnnssy

Известный
Друг
2,684
2,744
render низя за пределами вызова функции


Я хочу сделать несколько режимов на разные клавиши, без говнокода не обойдется?
сама функция forEachPlayerOnScreen остаётся без изменений, а анонимную функцию, которая передаётся ей в скобках уже изменяешь под свои потребности
 

ShadowBroker

Известный
110
27
Lua:
function main()
sampRegisterChatCommand("cmd", cmd)
   while true do wait(0)
     if isKeyDown(76) then
     local reschar, id = sampGetPlayerIdByCharHandle(playerPed)
       if reschar then
         if id ~= cmdid then
         sampAddChatMessage(string.format("ID %d", id), -1)
         while isKeyDown(76) do wait(0) end
         end
       end
     end
   end
end

function cmd(cmdp)
cmdid = string.match(cmdp, "(%d+)")
sampAddChatMessage(string.format("Ignore ID %d", cmdid), -1)
end

По задумке если я введу /cmd [свой id] при нажатии на L ничего не должно происходить, но на деле все равно показывает мой id
 

FYP

Известный
Автор темы
Администратор
1,757
5,684
Lua:
function main()
sampRegisterChatCommand("cmd", cmd)
   while true do wait(0)
     if isKeyDown(76) then
     local reschar, id = sampGetPlayerIdByCharHandle(playerPed)
       if reschar then
         if id ~= cmdid then
         sampAddChatMessage(string.format("ID %d", id), -1)
         while isKeyDown(76) do wait(0) end
         end
       end
     end
   end
end

function cmd(cmdp)
cmdid = string.match(cmdp, "(%d+)")
sampAddChatMessage(string.format("Ignore ID %d", cmdid), -1)
end

По задумке если я введу /cmd [свой id] при нажатии на L ничего не должно происходить, но на деле все равно показывает мой id
cmdid = tonumber(string.match(cmdp, "(%d+)"))
 
  • Нравится
Реакции: ShadowBroker

CAPTA!N

Новичок
220
48
в общем все пашет кроме этого setCarCruiseSpeed(--[[int]] car, --[[float]] maxSpeed). Фипыч, можешь проверить функу?

Вот значится запись в память в scm:
CLEO:
0A8C: write_memory 9067136 size 4 value 2147483647 virtual_protect 0
А вот в луа:
Lua:
memory.setint32(9067136, 2147483647, false)
и получается вот это:
(error) ...les (x86)\GTA San Andreas\moonloader\global_stab_fps.lua:9: attempt to index global 'memory' (a nil value)
хотя вот так все окей:
Lua:
writeMemory(9067136, 4, 2147483647, false)
Не подскажет кто, что я не так делаю?
 
Последнее редактирование модератором:

FYP

Известный
Автор темы
Администратор
1,757
5,684
Вот значится запись в память в scm:
CLEO:
0A8C: write_memory 9067136 size 4 value 2147483647 virtual_protect 0
А вот в луа:
Lua:
memory.setint32(9067136, 2147483647, false)
и получается вот это:
(error) ...les (x86)\GTA San Andreas\moonloader\global_stab_fps.lua:9: attempt to index global 'memory' (a nil value)
хотя вот так все окей:
Lua:
writeMemory(9067136, 4, 2147483647, false)
Не подскажет кто, что я не так делаю?
модуль memory нужно предварительно подгружать с помощью require:
local memory = require "memory"
в примере на вики это есть.
 
  • Нравится
Реакции: CAPTA!N

4el0ve4ik

Известный
Всефорумный модератор
1,548
1,338
модуль memory нужно предварительно подгружать с помощью require:
local memory = require "memory"
в примере на вики это есть.
Можно ли как то считать текст из ini по строкам?, допустим что бы в таблицу заносилось, допустим первая строка была k = 1, следующая k = 2, v = string?
 

FYP

Известный
Автор темы
Администратор
1,757
5,684
Можно ли как то считать текст из ini по строкам?, допустим что бы в таблицу заносилось, допустим первая строка была k = 1, следующая k = 2, v = string?
из файла читаются сразу все данные, а дальше их можно обрабатывать как вздумается.
 

FYP

Известный
Автор темы
Администратор
1,757
5,684
CLEO:
:CPed__getBonePosition
0A96: 25@ = actor 0@ struct
0AA6: call_method 0x5E4280 struct 25@ num_params 3 pop 0 true 1@ 25@v
0AB2: ret 3 25@ 26@ 27@

Как сделать похожее на Lua?
Lua:
function GetBodyPartCoordinates(id, handle)
  bones = getCharPointer(id)
  callMethod(0x5E4280, bones, 3, 0, true, handle, --[[????]])
  --return ......
end
Lua:
local ffi = require "ffi"
ffi.cdef("struct Vec3D {float f[3];}")
local getBonePosition = ffi.cast("int (__thiscall*)(void*, Vec3D*, int, bool)", 0x5E4280)

function GetBodyPartCoordinates(id, handle)
  local pedptr = getCharPointer(handle)
  local vec = ffi.new("struct Vec3D[1]", {})
  getBonePosition(ffi.cast("void*", pedptr), vec, id, true)
  return vec[0][0], vec[0][1], vec[0][2]
end
вроде так. сложно объяснить что тут происходит, так что просто проверь его. может быть я позже сделаю пару гайдов по FFI.
 
  • Нравится
Реакции: Сэнд

RedBoxWhite

Известный
337
27
И как засунуть в цикл?
Lua:
script_name("221")

require "lib.sampfuncs"
require "lib.moonloader"

function onReceiveRpc(id, bs)
    if id == RPC_SCRCLIENTMESSAGE then
        local color = raknetBitStreamReadInt32(bs)
        local len = raknetBitStreamReadInt32(bs)
        local text = raknetBitStreamReadString(bs, len)
    end
end

function main()
    if not isSampfuncsLoaded() or not isSampLoaded() then return end
    while true do
    wait(0)
        sampAddChatMessage(string.format("%s", text), 0xF0F0F0)
    end
end
 

san0

Известный
Друг
411
267
И как засунуть в цикл?
Lua:
script_name("221")

require "lib.sampfuncs"
require "lib.moonloader"

function onReceiveRpc(id, bs)
    if id == RPC_SCRCLIENTMESSAGE then
        local color = raknetBitStreamReadInt32(bs)
        local len = raknetBitStreamReadInt32(bs)
        local text = raknetBitStreamReadString(bs, len)
    end
end

function main()
    if not isSampfuncsLoaded() or not isSampLoaded() then return end
    while true do
    wait(0)
        sampAddChatMessage(string.format("%s", text), 0xF0F0F0)
    end
end
глобальную переменную объявляй
 
  • Нравится
Реакции: RedBoxWhite

CAPTA!N

Новичок
220
48
Я, видимо, совсем тупой, но ,скорее всего, я просто тупой. Короч вот код:
Lua:
bad = {
   badWord1 = ".ьь",
   badWord2 = "Если мы введем .ьь в чат, то нам автоматически поменяет на /mm"
}
good = {
   goodWord1 = "/mm",
   goodWord2 = "ага"
}

function main()
   if not isSampLoaded() or not isCleoLoaded() or not isSampfuncsLoaded() then return end
   while not isSampAvailable() do wait(100) end
   while true do
     wait(0)
     for k,v in pairs(bad) do
         textInput = sampGetChatInputText()
         if string.match(textInput, v) == v then
             sampSetChatInputText(string.gsub(textInput, v, good.k))
         end
     end
   end
end
При вводе в окно чата .ьь, должно автоматом меняться на /mm, но я ведь тупой, поэтому нихрена не меняется. В логе он не загружен, т.е. его там ваще нет. Буду рад помощи.
 

RedBoxWhite

Известный
337
27
Как это сделать? Н
CLEO:
if 0C18: 1@ = 0@ "Уровень:"
then
0AF8: "%s" -1 1@
end
Использую string.find, но там нет указателя на подстроку
 

CAPTA!N

Новичок
220
48
Как это сделать? Н
CLEO:
if 0C18: 1@ = 0@ "Уровень:"
then
0AF8: "%s" -1 1@
end
Использую string.find, но там нет указателя на подстроку
Потому что string.find возвращает индекс начала вхождения, или nil, а вот string.match ищет первое вхождение "шаблона" в строку, при нахождении, возвращает совпадение, т.е. возвращает подстроку
 
  • Нравится
Реакции: RedBoxWhite

FYP

Известный
Автор темы
Администратор
1,757
5,684
Я, видимо, совсем тупой, но ,скорее всего, я просто тупой. Короч вот код:
Lua:
bad = {
   badWord1 = ".ьь",
   badWord2 = "Если мы введем .ьь в чат, то нам автоматически поменяет на /mm"
}
good = {
   goodWord1 = "/mm",
   goodWord2 = "ага"
}

function main()
   if not isSampLoaded() or not isCleoLoaded() or not isSampfuncsLoaded() then return end
   while not isSampAvailable() do wait(100) end
   while true do
     wait(0)
     for k,v in pairs(bad) do
         textInput = sampGetChatInputText()
         if string.match(textInput, v) == v then
             sampSetChatInputText(string.gsub(textInput, v, good.k))
         end
     end
   end
end
При вводе в окно чата .ьь, должно автоматом меняться на /mm, но я ведь тупой, поэтому нихрена не меняется. В логе он не загружен, т.е. его там ваще нет. Буду рад помощи.
неверное обращение по ключу и несоответствующие ключи
Lua:
bad = {
  mainMenu = ".ьь",
  cyka = "cerf",
  randomShit = "Если мы введем .ьь в чат, то нам автоматически поменяет на /mm"
}
good = {
  mainMenu = "/mm",
  cyka = "сука",
  randomShit = "ага"
}

function main()
  if not isSampLoaded() or not isCleoLoaded() or not isSampfuncsLoaded() then return end
  while not isSampAvailable() do wait(100) end
  while true do
    wait(0)
    for k,v in pairs(bad) do
      textInput = sampGetChatInputText()
      if string.find(textInput, v) ~= nil then
        sampSetChatInputText(string.gsub(textInput, v, good[k]))
      end
    end
  end
end
 
  • Нравится
Реакции: RollUp и CAPTA!N