Гайд Написание Lua скриптов для MoonLoader

AnWu

https://t.me/anwublog
Автор темы
Всефорумный модератор
4,771
5,376
moonloader.png

Данная тема посвящена нюансам и особенностям разработки Lua скриптов для MoonLoader.

Список вопросов:
Начало разработки.
Взаимодействие с игроками.
Работа с переменными.
Работа с командами.

c184o.png


Начало разработки.
Каждый Lua скрипт при запуске создает поток "main" который и является основным местом работы со скриптом.
Сразу обговорим - скрипт "жив" пока "жив" поток main(), поэтому если мы хотим продолжать работать со скриптом после запуска - будем держать поток активным:
Lua:
function main() -- Объявляем поток main()
    wait(-1) -- Устанавливаем бесконечное ожидание
end -- закрываем функцию

Запускаем скрипт - работает!
Что ж, поставим себе цель - при запуске выводить сообщение "Привет мир" в чат.
Что нам для этого нужно?
Заходим на WIKI (Раздел "Функции" moonloader`a) и ищем функции чата - Поиск -> "Chat". Видим функцию sampAddChatMessage(message, color) - то что надо.
Вставляем:
Lua:
function main()
    sampAddChatMessage("Привет мир!", 0xFFFFFFFF) -- Выводим сообщение в чат
    wait(-1) -- Устанавливаем бесконечное ожидание
end
Запускаем скрипт - ошибка?
Код:
(error) test.lua: opcode '0AF8' call caused an unhandled exception
Бежим на WIKI (Опять раздел "Функции" moonloader`a) и в поиск вводим наш опкод "0AF8".
Находим нашу функцию sampAddChatMessage()
Что это значит? Дело в том что нельзя вызывать функции для работы с SA:MP пока сам SA:MP не готов. Что делать? Добавим перед выводом сообщения такой код:
Lua:
if not isSampfuncsLoaded() or not isSampLoaded() then -- Если SF или SA:MP не загружены
    return -- Завершаем работу скрипта
end
while not isSampAvailable() do -- Ждём пока функция isSampAvailable() вернет true
    wait(0) -- Устанавливаем минимальное ожидание, что бы наша игра не зависла
    -- значение 0 говорит что мы ждём следующий кадр (Frame)
end
Теперь наш скрипт будет ждать пока самп полностью не загрузится и продолжит выполнение кода.
Что такое wait() и с чем его едят?
Wait позволяет ставить поток в режим ожидания на указанное количество мили-секунд (ms)
Wait нельзя в CallBack-функциях, это приведет к ошибке, а в последствии и смерти, скрипта.
Почему мы ставим 0? Потому-что это минимальная задержка.

Подведем краткий итог кода:
Lua:
function main()
    if not isSampfuncsLoaded() or not isSampLoaded() then
        return
    end
    while not isSampAvailable() do
        wait(0)
    end
    sampAddChatMessage("Привет мир!", 0xFFFFFFFF)
    wait(-1)
end
Теперь при входе в игру / перезапуске скрипта в чат будет выводиться сообщение "Привет мир".
К списку вопросов

c184o.png


Взаимодействие с игроками
Перейдем к примерам посложнее - попробуем получить ник, ид и счет игрока в которого мы прицелились.
Цель поставили, какие нам нужны средства?
Опять бежим к WIKI, всё в тот же раздел функций и ищем функции связанные с целями, Поиск -> Target.
Смотрим в списке есть getCharPlayerIsTargeting(ped).
Она возвращает 2 значения - result, ped.
Первое значение - возвращает результат проверки на целится ли указанный Ped в кого-либо.
Второе - если указанный Ped целится - возвращает саму цель.
Как нам это использовать? Всё просто, уберем бесконечное ожидание и будем проверять значение result.
Lua:
function main()
    if not isSampfuncsLoaded() or not isSampLoaded() then
        return
    end
    while not isSampAvailable() do
        wait(0)
    end
    sampAddChatMessage("Привет мир!", 0xFFFFFFFF)
    while true do -- Создаем бесконечный цикл, вместо бесконечного ожидания
        wait(0) -- Опять таки чтобы наша игра не зависла, ждем след кадр
        local result, ped = getCharPlayerIsTargeting(PLAYER_HANDLE) -- Каждый кадр получаем данные функции, PLAYER_HANDLE - возвращает ваш Handle
        if result then -- Если result вернет true
            print("True!") -- Выведем сообщение в лог / консоль
        end
    end
end
Что мы можем с этим делать? Теперь если мы целимся в кого-либо, мы увидим сообщения в moonloader.log об этом. Мы получили Ped игрока в которого мы целимся. Давайте используем эту информацию.
Lua:
function main()
    if not isSampfuncsLoaded() or not isSampLoaded() then
        return
    end
    while not isSampAvailable() do
        wait(0)
    end
    sampAddChatMessage("Привет мир!", 0xFFFFFFFF)
    while true do
        wait(0)
        local result, ped = getCharPlayerIsTargeting(playerPed)
        if result then
            local result2, id = sampGetPlayerIdByCharHandle(ped) -- Попробуем получить ID игрока по его Ped
            if result2 then -- Если получилось
                local nickname = sampGetPlayerNickname(id) -- Запишем его ник
                local score = sampGetPlayerScore(id) -- и счет
                sampAddChatMessage(string.format("%s[%d] имеет счет %d", nickname, id, score), -1) -- И выведем это в чат
            end
        end
    end
end
К списку вопросов

c184o.png


Работа с переменными
Что у нас получилось? Мы будем получать кучу сообщений в чат о игрока по пока целимся в кого-либо, но как убрать этот флуд?
Давайте создадим переменную перед main(), например targeting, и присвоим ей значение false.
И задействуем её в коде
Lua:
local targeting = false -- Создаем булевую переменную
function main()
    if not isSampfuncsLoaded() or not isSampLoaded() then
        return
    end
    while not isSampAvailable() do
        wait(0)
    end
    sampAddChatMessage("Привет мир!", 0xFFFFFFFF)
    while true do
        wait(0)
        local result, ped = getCharPlayerIsTargeting(playerPed)
        if result and not targeting then -- Если мы целимся, но ранее ни в кого не целились
            local result2, id = sampGetPlayerIdByCharHandle(ped)
            if result2 then
                local nickname = sampGetPlayerNickname(id)
                local score = sampGetPlayerScore(id)
                sampAddChatMessage(string.format("%s[%d] имеет счет %d", nickname, id, score), -1)
                targeting = true -- запишем что мы целимся в кого либо и наше условие выше станет ложным
            end
        elseif not result and targeting then -- Если условие обратное - скажем скрипту что мы не целимся
            targeting = false
        end
    end
end
Отлично, теперь если мы целимся в игрока - получаем одно сообщение, меняем цель или заново целимся в того же игрока - снова получим о нём информацию.
К списку вопросов

c184o.png


Работа с командами.
Уже лучше, давайте теперь работаем с командами.
Уберем лишний код и оставим следующее:
Lua:
function main()
    if not isSampfuncsLoaded() or not isSampLoaded() then
        return
    end
    while not isSampAvailable() do
        wait(0)
    end
    while true do
        wait(0)
    end
end

Как добавить команду? Давайте опять порыщем на WIKI, Поиск -> Command
Нашли sampRegisterChatCommand(command, callback)? Отлично, можно уже приступать.
Зарегистрируем нашу команду, например "toster":
Lua:
function main()
    if not isSampfuncsLoaded() or not isSampLoaded() then
        return
    end
    while not isSampAvailable() do
        wait(0)
    end

    sampRegisterChatCommand("toster", tosterCallBack) -- Регистрируем ДО бесконечного цикла.
    -- Первый параметр - команда, без слэша.
    -- Второй - функция-callback которая будет вызваться если будет введена команда.

    wait(-1) -- Уберем бесконечный цикл, он тут вовсе не нужен, но нам же нужно чтобы скрипт работал
end

function tosterCallBack(params)
    sampAddChatMessage("Дзынь!", -1)
end
Теперь при вводе команды "/toster" мы увидим в чате сообщение. Успех? Но как например вывести свой текст в чат? Легко!
Lua:
sampAddChatMessage(params, -1)
Теперь мы выводим весь текст после команды "/toster" в чат. Например: /toster Привет жалкий мирок!

Помните я говорил что нельзя использовать wait() внутри callback-функций, это всё еще так, но есть тут одна хитрость!
Lua:
function tosterCallBack()
    sampAddChatMessage("Дзынь!", -1)
    lua_thread.create(function() -- Создаем новый поток
        wait(5000) -- Ждём 5 секунд
        sampAddChatMessage("Тоже дзынь, но на 5 секунд позже!", -1) -- Выводим текст в чат
    end) -- Тут наш поток умирает :(
end
К списку вопросов

c184o.png

На сегодня всё, теперь вы чертовы волшебники, поняв как всё работает, можно приступать к изучению примеров Lua скриптов!

Тема будет дополняться по мере изучения популярных вопросов по Lua скриптингу.

Я понимаю что вы невъебенные мастера луа скриптинга, но это тема не для вас
 
Последнее редактирование: