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

Andrinall

Известный
678
531
Хз насчет нормальных функций. Есть только идея кинуть луч (https://wiki.blast.hk/ru/moonloader/lua/processLineOfSight) прямо из камеры в точку прицела.

Как рассчитать все это тоже хз, возможно кто-нибудь мозговитый поможет. Глянь PACKET_AIM_SYNC 203, может быть там есть полезное для тебя, но тогда вне сампа не получится. Еще на крайний случай https://wiki.blast.hk/ru/moonloader/lua/getDebugCameraPointAt


Функция возвращает таблицу, где можно искать если table.entityType == 'ped', парсить getAllChars() и искать равные getCharPointer из парсинга и table.entity.
Lua:
local result, colPoint = processLineOfSight(
    originX, originY, originZ,
    targetX, targetY, targetZ,
    true, false, true --[[ искать только ped ]], false
)

if result and colPoint.entityType == "ped" then
    for _, handle in ipairs(getAllChars()) do
        if getCharPointer(handle) == colPoint.entity then
            print(getCharHealth(handle)) -- хп нашей цели
            break
        end
    end
end
Во-первых, entityType имеет тип int, никак не string
Во-вторых, зачем перебирать всех педов если можно
local ped = getCharPointerHandle(colPoint.entity)
if doesCharExist(ped) then
 
  • Нравится
Реакции: savvin

savvin

Известный
409
142
Во-первых, entityType имеет тип int, никак не string
Во-вторых, зачем перебирать всех педов если можно
local ped = getCharPointerHandle(colPoint.entity)
if doesCharExist(ped) then

В остальном да, тупанул.
 

Andrinall

Известный
678
531
Есть ли способ узнать, держит ли игрок (я) снайперский прицел на ком-то на расстоянии? Это не работает через getCharPlayerIsTargeting(playerHandle).

Да, костыльно, но работает)
Lua:
-- main
while true do wait(0)
	local result, handle = testSniperTarget()
	if result and not targetted then
		targetted = true
		sampAddChatMessage("Ты навёлся на скин", -1)
		marker = addBlipForChar(handle)
		changeBlipColour(marker, 0xFFFC78D5)
	elseif not result and targetted then
		targetted = false
		sampAddChatMessage("Ты увёл прицел с скина", -1)
		removeBlip(marker)
	end
end


function testSniperTarget()
	if isPauseMenuActive() or isCharDead(PLAYER_PED) or (getCharWeaponInSlot(PLAYER_PED, 7) < 33 or getCharWeaponInSlot(PLAYER_PED, 7) > 34) then return false, -1 end
	if not isCharPlayingAnim(PLAYER_PED, "GUN_STAND") then return false, -1 end
	local sw, sh = getScreenResolution()
	local activeCoords = { getActiveCameraCoordinates() }
	local pointAt = { convertScreenCoordsToWorld3D(sw / 2, sh / 2, 350.0) }
	local res, point = processLineOfSight(activeCoords[1], activeCoords[2], activeCoords[3] + 0.1, pointAt[1], pointAt[2], pointAt[3], false, false, true, false, false, false, false)
	if not res or point.entity == 0 then return false, -1 end
	local ped = getCharPointerHandle(point.entity)
	if ped == PLAYER_PED or not doesCharExist(ped) then return false, -1 end
	return true, ped
end
 

SyLvy

Активный
231
25
Да, костыльно, но работает)
Lua:
-- main
while true do wait(0)
    local result, handle = testSniperTarget()
    if result and not targetted then
        targetted = true
        sampAddChatMessage("Ты навёлся на скин", -1)
        marker = addBlipForChar(handle)
        changeBlipColour(marker, 0xFFFC78D5)
    elseif not result and targetted then
        targetted = false
        sampAddChatMessage("Ты увёл прицел с скина", -1)
        removeBlip(marker)
    end
end


function testSniperTarget()
    if isPauseMenuActive() or isCharDead(PLAYER_PED) or (getCharWeaponInSlot(PLAYER_PED, 7) < 33 or getCharWeaponInSlot(PLAYER_PED, 7) > 34) then return false, -1 end
    if not isCharPlayingAnim(PLAYER_PED, "GUN_STAND") then return false, -1 end
    local sw, sh = getScreenResolution()
    local activeCoords = { getActiveCameraCoordinates() }
    local pointAt = { convertScreenCoordsToWorld3D(sw / 2, sh / 2, 350.0) }
    local res, point = processLineOfSight(activeCoords[1], activeCoords[2], activeCoords[3] + 0.1, pointAt[1], pointAt[2], pointAt[3], false, false, true, false, false, false, false)
    if not res or point.entity == 0 then return false, -1 end
    local ped = getCharPointerHandle(point.entity)
    if ped == PLAYER_PED or not doesCharExist(ped) then return false, -1 end
    return true, ped
end
Я попытался преобразовать ваш фрагмент скрипта в свой, чтобы, когда прицел был на проигрывателе, на экране был виден рендерфонтдраутекст, но он отображался только на миллисекунду, как я могу сделать так, чтобы он оставался, пока я не уберу его с цели ?

Помогите мне реализовать это в моем скрипте, если вы хотите:
Lua:
local samp = require 'samp.events'
local se = require 'lib.samp.events'
local imgui = require 'mimgui'
local sampev = require("lib.samp.events")
require "lib.moonloader"
local inicfg = require "inicfg"
local mainIni = inicfg.load({
    config = {
        dist = 160,
        autofind = true
    }
}, "hitmen.ini")
inicfg.save(mainIni, "hitmen.ini")

--
local active = imgui.new.bool(false)
local checkbox = imgui.new.bool(false)
local playerId = nil
local my_font = renderCreateFont('Arial', 20, 13)
local dist_font = renderCreateFont('Arial', 30, 13)
local font = renderCreateFont("Arial", 13, 5) -- Font name, font size, font flag.

function main()
    while not isSampAvailable() do wait(0) end
    sampAddChatMessage('{aa3333}[Hitmen Helper]{ffffff} Loaded. Made by {aa3333}SyLvy', -1)
    sampAddChatMessage('{aa3333}[Hitmen Helper]{ffffff} Help & features: {aa3333}/hah {ffffff}| Resolution: {aa3333}1920x1080', -1)
        sampRegisterChatCommand("hah", function() active[0] = not active[0] end)
        sampRegisterChatCommand('lgh', lgh)
    sampRegisterChatCommand('uc', uc)
    sampRegisterChatCommand('afvr', afvr)
    sampRegisterChatCommand('kc', kc)
    sampRegisterChatCommand('cf', cf)
    sampRegisterChatCommand('o1', o1)
    sampRegisterChatCommand('o2', o2)
    sampRegisterChatCommand('gu', gu)
    sampRegisterChatCommand('gh', gh)
    sampRegisterChatCommand('lh', lh)
    sampRegisterChatCommand('myc', myc)
    sampRegisterChatCommand('lg', lg)
    sampRegisterChatCommand('pt', pt)   
    sampRegisterChatCommand('ex', ex)
    sampRegisterChatCommand('rr', rr)
    sampRegisterChatCommand('en', en)
    sampRegisterChatCommand('track', function(arg)
        local id = tonumber(arg)
        if not id or not sampIsPlayerConnected(id) then
        sampAddChatMessage('{aa3333}[Hitmen Helper]{ffffff} Distance Tracker este {aa3333}dezactivat.', -1)
        sampAddChatMessage('{aa3333}[Hitmen Helper]{ffffff} Foloseste {aa3333}/track <ID>{ffffff} pentru a-l activa.', -1)
        end
        playerId = id
    end)
    while true do
        wait(0)
        renderFontDrawText(font, "{aa3333}Hitmen Helper {ffffff}v1.1", 1720, 1030, 0xFFFFFFFF)
        if mainIni.config.dist == 0 then
        renderFontDrawText(font, "{aa3333}  Protection distance:{ffffff}"..mainIni.config.dist.."m", 1655, 990, 0xFFFFFFFF)
        else
        renderFontDrawText(font, "{aa3333}Protection distance:{ffffff} "..mainIni.config.dist.."m", 1655, 990, 0xFFFFFFFF) end
            renderFontDrawText(font, mainIni.config.autofind and "{aa3333}Auto Find:{ffffff} ON" or "{aa3333}Auto Find:{ffffff}OFF", 1760, 1010, -1)
        if playerId then
            local result, ped = sampGetCharHandleBySampPlayerId(playerId)
            renderFontDrawText(font, "{aa3333}Distance Tracker:{ffffff} ON", 1695, 970, -1)
            if result then
                local x, y, z = getCharCoordinates(ped)
                local dist = getDistanceBetweenCoords3d(x, y, z, getCharCoordinates(playerPed))
                renderFontDrawText(my_font, string.format("{33aaaa}%s {ffffff}({ff3333}%s{ffffff}) is {33aaaa}%.2f meters {ffffff}away.", sampGetPlayerNickname(playerId), playerId, dist), 710, 850, -1)
                                if isKeyDown(VK_RBUTTON) then
                    weapon = getCurrentCharWeapon(playerPed)
                    if weapon == 34 then
                    renderFontDrawText(dist_font, string.format("{33aaaa}%.2fm", dist), 970, 625, -1)
                    end
                    end
                if dist < mainIni.config.dist then
                renderFontDrawText(my_font, string.format("{33aaaa}%s {ffffff}({ff3333}%s{ffffff}) is {ff0000}%.2f meters {ffffff}away.", sampGetPlayerNickname(playerId), playerId, dist), 710, 850, -1)
                if     isCurrentCharWeapon(PLAYER_PED, 34) then
                printStringNow('~r~TINTA ESTE PREA APROAPE, ~w~NU POTI ECHIPA SNIPERUL!', 3000)
                setCurrentCharWeapon(PLAYER_PED, 0)
                end
                end
            end
        end
    end
end



local mainFrame = imgui.OnFrame(function() return active[0] end, function(self)
local sw, sh = getScreenResolution()
    imgui.SetNextWindowSize(imgui.ImVec2(sw / 5.4, sh / 2.5), imgui.Cond.FirstUseEver)
    imgui.SetNextWindowPos(imgui.ImVec2(sw / 1.4, sh / 2), imgui.Cond.FirstUseEver, imgui.ImVec2(-0.3, 0.5))
    imgui.Begin('Hitmen Helper v1.1 - by SyLvy', active)
    imgui.Text('Acest mod are ca scop sa faca treaba membrilor Hitmen Agency mult mai usoara.')
    imgui.Text(' ')
    imgui.Text('Modul include si o functie numita Protection Distance, care va scoate sniperul cand aveti functia')
    imgui.Text('Distance Tracker (/track) activata, respectiv cand tinta este mai aproape de tinta impusa,')
    imgui.Text('pentru a evita anumite sanctiuni pentru contract sub 150 de metri.  (valoare default: 160)')
    imgui.Text('Puteti modifica aceasta distanta din moonloader/config/hitmen.ini, dar nu este recomandata.')
    imgui.Text('* pentru a dezactiva Protection Distance, inlocuiti valoarea din "dist" cu 0.')
    imgui.Text(' ')
    imgui.Text('Comenzi prescurtate:')
    imgui.Text('/pt - /portable')
    imgui.Text('/gh - gethit')
    imgui.Text('/lh - leavehit')
    imgui.Text('/myc - mycontract')
    imgui.Text('/uc - undercover')
    imgui.Text('/o1 - order 1 de 3 ori')
    imgui.Text('/o2 - order 2 de 3 ori')
    imgui.Text('/lg - logout')
    imgui.Text('/gu - gethit si undercover simultan')
    imgui.Text('/lgh - leavehit, gethit si undercover simultan')
    imgui.Text('/track (ID) - distanta reala a tintei la milisecunda (apare doar intre 0 si 350 metri, dupa caz)')
    imgui.Text('/track - opreste functia Distance Tracker.')
    imgui.Text('/autofind - activezi/dezactivezi Auto Find (atunci cand dai gethit)')
    imgui.Text(' ! s-ar putea sa nu mearga pe unele modpack-uri din cauza modificarilor facute fisierelor samp-ului')
    imgui.Text(' ')
    imgui.Text('/cf - cancel find')
    imgui.Text('/kc - /killcp')
    imgui.Text('/ex - /exit')
    imgui.Text('/en - /engine')
    imgui.Text('/rr - /repair&/refill (skill 5 Mechanic)')
        imgui.End()
end)

 sampRegisterChatCommand("autofind", function()
        mainIni.config.autofind = not mainIni.config.autofind
        inicfg.save(mainIni, "hitmen.ini")
         sampAddChatMessage("{aa3333}[Hitmen Helper]{FFFFFF} Auto Find a fost "..(mainIni.config.autofind and "{aa3333}activat{ffffff}." or "{aa3333}dezactivat{ffffff}."), -1)
    end)
    
    function sampev.onServerMessage(color, text)
    if mainIni.config.autofind then
    
    if text:find("Undercover OFF") then
        lua_thread.create(function() wait(50)
            printStyledString("~w~Undercover-ul a fost ~r~inlaturat", 5000, 5)
        end)
    end
    
    if text:find("Undercover DEZACTIVAT") then
        lua_thread.create(function() wait(50)
            printStyledString("~w~Undercover-ul a fost ~r~inlaturat", 5000, 5)
        end)
    end
    
    
    if text:find("%*.+ took the contract on%: .+ %((%d+)%)") then
        lua_thread.create(function() wait(50)
            local id = text:match("%*.+ took the contract on%: .+ %((%d+)%)")
            sampSendChat("/find "..id)
            sampProcessChatInput("/track "..id)
        end)
    end
end
    if text:find("%*.+ a pornit spre asasinarea lui%: .+ %((%d+)%)") then
        lua_thread.create(function() wait(50)
            local id = text:match("%*.+ a pornit spre asasinarea lui%: .+ %((%d+)%)")
            sampSendChat("/find "..id)
            sampProcessChatInput("/track "..id)
        end)
    end
end

function cf()
sampSendChat('/cancel find')
end
function kc()
sampSendChat('/killcp')
end
function gh()
sampSendChat('gethit')
end
function pt()
sampSendChat('/portable')
end
function lgh()
lua_thread.create(function()
sampSendChat('leavehit')
sampSendChat('gethit')
wait(676)
sampSendChat('undercover')
end)
end
function gu()
sampSendChat('gethit')
end
function uc()
sampSendChat('undercover')
end
function o1()
sampSendChat('order 1')
sampSendChat('order 1')
sampSendChat('order 1')
end
function o2()
sampSendChat('order 2')
sampSendChat('order 2')
sampSendChat('order 2')
end
function gu()
lua_thread.create(function()
sampSendChat('gethit')
wait(676)
sampSendChat('undercover')
end)
end
function lh()
sampSendChat('leavehit')
end
function myc()
sampSendChat('mycontract')
end
function lg()
sampSendChat('logout')
end
function ex()
sampSendChat('/exit')
end
function rr()
sampSendChat('/repair')
sampSendChat('/refill')
end
function en()
sampSendChat('/engine')
end

Как мне получить собственное имя игрока, чтобы использовать его в этой функции? Первым ".+" должно быть мое имя игрока.
Lua:
    if text:find("%*.+ took the contract on%: .+ %((%d+)%)") then
        lua_thread.create(function() wait(50)
            local id = text:match("%*.+ took the contract on%: .+ %((%d+)%)")
            sampSendChat("/find "..id)
            sampProcessChatInput("/track "..id)
        end)
    end
end
 
Последнее редактирование:

accord-

Потрачен
438
80
Обратите внимание, пользователь заблокирован на форуме. Не рекомендуется проводить сделки.
Как проверить txt файл на наличие текста "asd"
 

sep

Известный
672
76
как это пофиксить ?

[ML] (error) название файла: not enough memory
[ML] (error) название файла: not enough memory
[ML] (error) название файлаr: Script died due to an error. (0C0AA15C)

ошибка в 1 файле
 

bulba$h

Активный
335
92
как можно перехватывать килы?
допустим в килл листе Nick_Name убил с дигла Name_Nick, и в чат пишет "Nick_Name убил с дигла Name_Nick", код ниже при запуске просто крашит

Lua:
local sampev = require("samp.events")
local weap = require("game.weapons")

function sampev.onPlayerDeathNotification(killerID, killerID2, reason)
    local nick = sampGetPlayerNickname(killerID)
    local nick2 = sampGetPlayerNickname(killerID2)
    local gun = weap.get_name(reason)
    local format = string.format("{FFFFFF}%s >> {FFFFFF}%s << {FFFFFF}%s",nick, gun, nick2)
    sampAddChatMessage(format, 0xFFFFFFFF)
end
 
  • Эм
Реакции: percheklii

siwage

Активный
188
65
как можно перехватывать килы?
допустим в килл листе Nick_Name убил с дигла Name_Nick, и в чат пишет "Nick_Name убил с дигла Name_Nick", код ниже при запуске просто крашит

Lua:
local sampev = require("samp.events")
local weap = require("game.weapons")

function sampev.onPlayerDeathNotification(killerID, killerID2, reason)
    local nick = sampGetPlayerNickname(killerID)
    local nick2 = sampGetPlayerNickname(killerID2)
    local gun = weap.get_name(reason)
    local format = string.format("{FFFFFF}%s >> {FFFFFF}%s << {FFFFFF}%s",nick, gun, nick2)
    sampAddChatMessage(format, 0xFFFFFFFF)
end
Ошибка есть?
 

percheklii

Известный
703
256
как можно перехватывать килы?
допустим в килл листе Nick_Name убил с дигла Name_Nick, и в чат пишет "Nick_Name убил с дигла Name_Nick", код ниже при запуске просто крашит

Lua:
local sampev = require("samp.events")
local weap = require("game.weapons")

function sampev.onPlayerDeathNotification(killerID, killerID2, reason)
    local nick = sampGetPlayerNickname(killerID)
    local nick2 = sampGetPlayerNickname(killerID2)
    local gun = weap.get_name(reason)
    local format = string.format("{FFFFFF}%s >> {FFFFFF}%s << {FFFFFF}%s",nick, gun, nick2)
    sampAddChatMessage(format, 0xFFFFFFFF)
end
Попробуй еще так, я не знаю почему у тебя не работает то что я тебе кидал.
Если не работает, будет очень грустно(
Lua:
local sampev = require("samp.events")
local weap = require("game.weapons")

local hui = {}

function main()
    repeat wait(0) until isSampAvailable()

    local font = renderCreateFont("Arial", 10, 13)

    while true do wait(0)

        local x, y = 500, 500
        for i = 1, #hui do
            renderFontDrawText(font, hui[i], x, y, 0xFFFFFFFF)
            y = y + 20
        end
    end
end

function sampev.onPlayerDeathNotification(killer, victim, reason)
    local killernick = sampGetPlayerNickname(killer)
    local victimnick = sampGetPlayerNickname(victim)
    local gun = weap.get_name(reason)
    local format = string.format("Игрок: %s Убил: %s Оружие: %s", killernick, victimnick, gun)
    table.insert(hui, format)
    if #hui > 5 then
        table.remove(hui, 1)
    end
end

 
Последнее редактирование:

tyukapa

Активный
298
65
как это пофиксить ?

[ML] (error) название файла: not enough memory
[ML] (error) название файла: not enough memory
[ML] (error) название файлаr: Script died due to an error. (0C0AA15C)

ошибка в 1 файле
Покажи что пишет, а не "название файла", там строку кода с ошибкой покажет
 

sep

Известный
672
76
Покажи что пишет, а не "название файла", там строку кода с ошибкой покажет
сроку кода не пишет только это
если была бы ошибка в строке то былобы более понятнее

актуально
ошибка
[ML] (error) Binder: not enough memory
[ML] (error) Binder: Script died due to an error. (0BD310DC)
как фиксить ?
 
Последнее редактирование:
  • Грустно
Реакции: tyukapa

why ega

РП игрок
Модератор
2,537
2,217
сроку кода не пишет только это
если была бы ошибка в строке то былобы более понятнее

актуально
ошибка
[ML] (error) Binder: not enough memory
[ML] (error) Binder: Script died due to an error. (0BD310DC)
как фиксить ?
Недостаточно памяти. Предполагаю, что у тебя в каком-нибудь цикле течет память. Скинь код, чтобы точно понять, из-за чего это
 

Revavi

Участник
101
24
кто нибудь знает, возможно ли заменять сообщение, которые ты пишешь в чат? если да, то как?
например я пишу в чат "тест", а отправляется от моего имени серверу "норм"
я знаю как получить данные, которые пишу в чат(onSendChat) и как отправить сообщение(sampSendChat), но как отменить отправку из чата?
 

chapo

🫡 В армии с 17.10.2023. В ЛС НЕ ОТВЕЧАЮ
Друг
8,762
11,195
кто нибудь знает, возможно ли заменять сообщение, которые ты пишешь в чат? если да, то как?
например я пишу в чат "тест", а отправляется от моего имени серверу "норм"
я знаю как получить данные, которые пишу в чат(onSendChat) и как отправить сообщение(sampSendChat), но как отменить отправку из чата?
в ретурне можешь подменять текст
Lua:
local sampev = require('lib.samp.events')

function sampev.onSendChat(text)
    if text:find('привет') then
        return { 'маме привет, дуралей' }
    end
end
что бы "отменить" отправку ебашь return false