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

Revavi

Участник
101
24
Можно как-то узнать количество пикселей в тексте или у определённого символа? в ширину пикселей
использую trebucbd.ttf, размер 35.0
 
Последнее редактирование:

chapo

tg/inst: @moujeek
Всефорумный модератор
9,204
12,528
Можно как-то узнать количество пикселей в тексте или у определённого символа? в ширину пикселей
использую trebucbd.ttf, размер 35.0
float length = renderGetFontDrawTextLength(DxFont font, zstring text [, bool ignoreColorTags=false])
 

Revavi

Участник
101
24
первый параметр - переменная в которую записан шрифт
второй параметр - текст
на третий параметр похуй
как-то очень странно работает, выдаёт неправильное число. приходится для каждого текста отдельно подгонять. может я что-то не то сделал?
local font = renderCreateFont("Trebucbd", 35)
local text = 'текст текст текст'
local length = renderGetFontDrawTextLength(font, text)
(там ещё в начале прописано, что imgui использует этот текст)
 
Последнее редактирование:

chapo

tg/inst: @moujeek
Всефорумный модератор
9,204
12,528
как-то очень странно работает, выдаёт неправильное число. приходится для каждого текста отдельно подгонять. может я что-то не то сделал?
local font = renderCreateFont("Trebucbd", 35)
local text = 'текст текст текст'
local length = renderGetFontDrawTextLength(font, text)
(там ещё в начале прописано, что imgui использует этот текст)
если тебе нужно в имгуи, то используй imgui.CalcTextSize(text)
 

Insanity

Известный
247
20
Как эмулировать нажатие клавиши?
К примеру в чате появилась строка "нажмите ALT"
И нужно что бы нажималась клавиша альт
 

chapo

tg/inst: @moujeek
Всефорумный модератор
9,204
12,528
Как эмулировать нажатие клавиши?
К примеру в чате появилась строка "нажмите ALT"
И нужно что бы нажималась клавиша альт
Lua:
local sampev = require 'lib.samp.events'
function sampev.onServerMessage(color, text)
    if text:find('Нажми ALT') then
        local data = samp_create_sync_data('player')
        data.keysData = data.keysData + 1024
        data.send()
        print('alt sended')
    end
end

function 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
 
  • Нравится
Реакции: Insanity

Insanity

Известный
247
20
Lua:
local sampev = require 'lib.samp.events'
function sampev.onServerMessage(color, text)
    if text:find('Нажми ALT') then
        local data = samp_create_sync_data('player')
        data.keysData = data.keysData + 1024
        data.send()
        print('alt sended')
    end
end

function 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
Охренеть, а почему такой большой код :D?

Я вот попробовал этот, он отдельно работает, но если его куда-то вставить в другой скрипт, он не робит

Lua:
function sampev.onServerMessage(color, text)
        lua_thread.create(function()
   if text:find("Упакуйте ресурсы") then
            setVirtualKeyDown(18, true)
            wait(400)
            setVirtualKeyDown(18, false)
        end
    end)
end
 

YarikVL

Известный
Проверенный
4,721
1,807
Охренеть, а почему такой большой код :D?

Я вот попробовал этот, он отдельно работает, но если его куда-то вставить в другой скрипт, он не робит

Lua:
function sampev.onServerMessage(color, text)
        lua_thread.create(function()
   if text:find("Упакуйте ресурсы") then
            setVirtualKeyDown(18, true)
            wait(400)
            setVirtualKeyDown(18, false)
        end
    end)
end
может ты поток потерял в другом скрипте, или библиотека под другой "переменной" подключил.
Ещё кстати можно юзать setGameKeyState
У чапо функция которая передает значение самой игре о нажатии клавиши ( синхру передает если не ошибаюсь ), а твой метод просто делает нажатие клавиши с твоей клавиатуры
 

chapo

tg/inst: @moujeek
Всефорумный модератор
9,204
12,528
Охренеть, а почему такой большой код :D?

Я вот попробовал этот, он отдельно работает, но если его куда-то вставить в другой скрипт, он не робит

Lua:
function sampev.onServerMessage(color, text)
        lua_thread.create(function()
   if text:find("Упакуйте ресурсы") then
            setVirtualKeyDown(18, true)
            wait(400)
            setVirtualKeyDown(18, false)
        end
    end)
end
моя функция отпрвляет серверу информацию о том что ты нажал на альт, setVirtualKeyDown в этом случае говно, так как если прожать быстро, то может не сработать, да и клавиша грубо говоря нажимается на клаве, то есть если после сообщения в течении 400 мс ты нажмешь на таб, то игра свернется (так как сработает альт + таб), а setGameKeyState хуйня потому что нажатие просто может "не успеть" отправится
 
  • Нравится
  • Влюблен
Реакции: YarikVL, Insanity и ARMOR

Revavi

Участник
101
24
Lua:
local sampev = require 'lib.samp.events'
function sampev.onServerMessage(color, text)
    if text:find('Нажми ALT') then
        local data = samp_create_sync_data('player')
        data.keysData = data.keysData + 1024
        data.send()
        print('alt sended')
    end
end

function 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
а как тут отправить, например tab? откуда брать коды клавиш и что нужно изменить?
 
  • Злость
Реакции: qdIbp

F0RQU1N and

Известный
1,297
500
откуда брать коды клавиш и что нужно изменить?
нажатие на игрока в табе, или открыть таб? когда ты таб открываешь инфа об этом не отправляется на сервер, только при нажатии на игрока. тем более не через клавишу таба
 

Revavi

Участник
101
24

нажатие на игрока в табе, или открыть таб? когда ты таб открываешь инфа об этом не отправляется на сервер, только при нажатии на игрока. тем более не через клавишу таба
А как это сделать тогда? просто нужно чтобы обновляло инфу в scoreboard. Знаю, что она сама обновляется, но у меня почему-то баги