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

Nessel

Участник
120
25
Парни я шота разбирался, разбирался, но так и не понял, как сделать передвижение на координаты 3dText'a
Код:
script_dependencies("CLEO", "SAMP", "SAMPFUNCS")

---------------------------------------------------------------------------

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

---------------------------------------------------------------------------

function main()
    if not isSampfuncsLoaded() or not isSampLoaded() then return end
    sampRegisterChatCommand("mycmd", cmd)
    runToPoint(posX, posY)

    while true do wait(0) end
end

function cmd(param)
    if isPlayerPlaying(playerHandle) then
        local posX, posY, posZ = getCharCoordinates(playerPed)
        local res, text, color, x, y, z, distance, ignoreWalls, player, vehicle = Search3Dtext(posX, posY, posZ, 50.0, "")
        if res then
            sampAddChatMessage(string.format("Найден 3D текст \"%s\" в координатах %.2f %.2f %.2f, дистанция %.2f, id игрока %d, id транспорта %d", text, x, y, z, distance, player, vehicle), color)
        end
    end
end

function Search3Dtext(x, y, z, radius, patern)
    local text = ""
    local color = 0
    local posX = 0.0
    local posY = 0.0
    local posZ = 0.0
    local distance = 0.0
    local ignoreWalls = false
    local player = -1
    local vehicle = -1
    local result = false

    for id = 0, 2048 do
        if sampIs3dTextDefined(id) then
            local text2, color2, posX2, posY2, posZ2, distance2, ignoreWalls2, player2, vehicle2 = sampGet3dTextInfoById(id)
            if getDistanceBetweenCoords3d(x, y, z, posX2, posY2, posZ2) < radius then
                if string.len(patern) ~= 0 then
                    if string.match(text2, patern, 0) ~= nil then result = true end
                else
                    result = true
                end
                if result then
                    text = text2
                    color = color2
                    posX = posX2
                    posY = posY2
                    posZ = posZ2
                    distance = distance2
                    ignoreWalls = ignoreWalls2
                    player = player2
                    vehicle = vehicle2
                    radius = getDistanceBetweenCoords3d(x, y, z, posX, posY, posZ)
                end
            end
        end
    end

    return result, text, color, posX, posY, posZ, distance, ignoreWalls, player, vehicle
end

function runToPoint(tox, toy)
    local x, y, z = getCharCoordinates(PLAYER_PED)
    local angle = getHeadingFromVector2d(tox - x, toy - y)
    local xAngle = math.random(-50, 50)/100
    setCameraPositionUnfixed(xAngle, math.rad(angle - 90))
    stopRun = false
    while getDistanceBetweenCoords2d(x, y, tox, toy) > 0.8 do
        setGameKeyState(1, -255)
        wait(1)
        x, y, z = getCharCoordinates(PLAYER_PED)
        angle = getHeadingFromVector2d(tox - x, toy - y)
        setCameraPositionUnfixed(xAngle, math.rad(angle - 90))
        if stopRun then
            stopRun = false
            break
        end
    end
end
 
Последнее редактирование:

thedqrkway

Участник
247
11
можно ли как-то сделать так, чтобы текст писался в строку чата, но не отправлялся?
 

Morse

Потрачен
436
70
Обратите внимание, пользователь заблокирован на форуме. Не рекомендуется проводить сделки.
Кто может объяснить как работает Хук и что это такое?
 

Letovo

Известный
95
12
Кто может объяснить как работает Хук и что это такое?
Хук - крюк, штука которой что-то ловят.
В нашем случае хук - это функция, которая срабатывает ("ловит") на какое-нибудь событие.

Возьмём к примеру библиотеку events, которая нам позволяет делать эти самые хуки.

Lua:
local samp = require 'lib.samp.events'

function samp.onServerMessage(color, text)
    print(text, color)
end

Функция samp.onServerMessage - это и есть хук. Он сработает, когда сервер отправит нам какое-нибудь сообщение. Мы получим текст и цвет сообщения, с которым уже сможем делать всё, что захотим. (В примере мы просто выводим в консоль текст и цвет сообщения).
 
  • Нравится
Реакции: Morse

Сarlos777

Потрачен
3
3
Обратите внимание, пользователь заблокирован на форуме. Не рекомендуется проводить сделки.
Кто может объяснить как работает Хук и что это такое?
Lua:
--Либа такая подключают её так:

local hook = require 'lib.samp.events' -- вместо hook любое название это переменная.

--Дальше можно зайти в файлике по пути твоя гта/moonloader/lib/samp/events.lua
--И посмотреть все события/хуки и что они возвращают.
--Ты находишь строку примером: INCOMING_RPCS[RPC.CLIENTMESSAGE] = {'onServerMessage', {color = 'int32'}, {text = 'string32'}}
--Например рассмотрим хук onServerMessage, сработает тогда когда сервер отправит тебе сообщение.

function hook.onServerMessage(color, text) -- на месте hook твоя переменная которую ты указал когда подключал библиотеку к скрипту.
  print(text)
end

-- будет выводить любой текст когда сервер отправит сообщение
 
  • Нравится
Реакции: Morse

Morse

Потрачен
436
70
Обратите внимание, пользователь заблокирован на форуме. Не рекомендуется проводить сделки.
Хук - крюк, штука которой что-то ловят.
В нашем случае хук - это функция, которая срабатывает ("ловит") на какое-нибудь событие.

Возьмём к примеру библиотеку events, которая нам позволяет делать эти самые хуки.

Lua:
local samp = require 'lib.samp.events'

function samp.onServerMessage(color, text)
    print(text, color)
end

Функция samp.onServerMessage - это и есть хук. Он сработает, когда сервер отправит нам какое-нибудь сообщение. Мы получим текст и цвет сообщения, с которым уже сможем делать всё, что захотим. (В примере мы просто выводим в консоль текст и цвет сообщения).
Cпасибо, а с помощью хука можно сделать проверку на авторизацию\спавн? Что бы когда ты авторизирован писало команду которую я укажу
 

Letovo

Известный
95
12
Cпасибо, а с помощью хука можно сделать проверку на авторизацию\спавн? Что бы когда ты авторизирован писало команду которую я укажу
Если я тебя правильно понял, то в твоём случае хук не нужен. Ты можешь просто использовать функцию для проверки заспавнился ли наш игрок - sampIsLocalPlayerSpawned(). А для проверки на авторизацию придётся немного запариться, в зависимости от сервера зависит какой способ лучше взять.
 

Morse

Потрачен
436
70
Обратите внимание, пользователь заблокирован на форуме. Не рекомендуется проводить сделки.
Если я тебя правильно понял, то в твоём случае хук не нужен. Ты можешь просто использовать функцию для проверки заспавнился ли наш игрок - sampIsLocalPlayerSpawned(). А для проверки на авторизацию придётся немного запариться, в зависимости от сервера зависит какой способ лучше взять.
я делал изначально через sampIsLocalPlayerSpawned(), но мне сказали что нужно через хук
 

Сarlos777

Потрачен
3
3
Обратите внимание, пользователь заблокирован на форуме. Не рекомендуется проводить сделки.
  • Нравится
Реакции: riassems.
У

Удалённый пользователь 341712

Гость
я делал изначально через sampIsLocalPlayerSpawned(), но мне сказали что нужно через хук
ну такое, я помню делал для арз, тупо расскажу метод
Есть 2 функции, onShowDialog and onExitScript(booleanTrue), я проверял, если через диалог я авторизовался, то задавал в ини переменной true, дальше если я вышел под проверкой booleanTrue т.е. скрипт завершил свою работу с выходом из игры то false,
 

thedqrkway

Участник
247
11
можно ли сделать так, чтобы при определенном действии отправлялась клавиша?
 

thedqrkway

Участник
247
11
Когда будет на экране "Press Y" нажмет Y
Lua:
local hook = require 'lib.samp.events'

function hook.onDisplayGameText(style, timer, text)
  if text:find('Press: ~g~Y') then --  ~g~ это зеленый цвет
    lua_thread.create(function()
      wait(25)
      local data = samp_create_sync_data('player')
      data.weapon = data.weapon + 64 --64 ид клавиши
      data.send()
  end)
end

unction samp_create_sync_data(sync_type, copy_from_player)
    local ffi = require 'ffi'
    local sampfuncs = require 'sampfuncs'
    -- from SAMP.Lua
    local raknet = require 'samp.raknet'
    require 'samp.synchronization'

    copy_from_player = copy_from_player or true
    local sync_traits = {
        player = {'PlayerSyncData', raknet.PACKET.PLAYER_SYNC, sampStorePlayerOnfootData},
        vehicle = {'VehicleSyncData', raknet.PACKET.VEHICLE_SYNC, sampStorePlayerIncarData},
        passenger = {'PassengerSyncData', raknet.PACKET.PASSENGER_SYNC, sampStorePlayerPassengerData},
        aim = {'AimSyncData', raknet.PACKET.AIM_SYNC, sampStorePlayerAimData},
        trailer = {'TrailerSyncData', raknet.PACKET.TRAILER_SYNC, sampStorePlayerTrailerData},
        unoccupied = {'UnoccupiedSyncData', raknet.PACKET.UNOCCUPIED_SYNC, nil},
        bullet = {'BulletSyncData', raknet.PACKET.BULLET_SYNC, nil},
        spectator = {'SpectatorSyncData', raknet.PACKET.SPECTATOR_SYNC, nil}
    }
    local sync_info = sync_traits[sync_type]
    local data_type = 'struct ' .. sync_info[1]
    local data = ffi.new(data_type, {})
    local raw_data_ptr = tonumber(ffi.cast('uintptr_t', ffi.new(data_type .. '*', data)))
    -- copy player's sync data to the allocated memory
    if copy_from_player then
        local copy_func = sync_info[3]
        if copy_func then
            local _, player_id
            if copy_from_player == true then
                _, player_id = sampGetPlayerIdByCharHandle(PLAYER_PED)
            else
                player_id = tonumber(copy_from_player)
            end
            copy_func(player_id, raw_data_ptr)
        end
    end
    -- function to send packet
    local func_send = function()
        local bs = raknetNewBitStream()
        raknetBitStreamWriteInt8(bs, sync_info[2])
        raknetBitStreamWriteBuffer(bs, raw_data_ptr, ffi.sizeof(data))
        raknetSendBitStreamEx(bs, sampfuncs.HIGH_PRIORITY, sampfuncs.UNRELIABLE_SEQUENCED, 1)
        raknetDeleteBitStream(bs)
    end
    -- metatable to access sync data and 'send' function
    local mt = {
        __index = function(t, index)
            return data[index]
        end,
        __newindex = function(t, index, value)
            data[index] = value
        end
    }
    return setmetatable({send = func_send}, mt)
end
зачем мне весь код? мне нужна именно строчка, которая за это отвечает, тут ничего не понятно