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

abnomegd

Активный
347
37
Advance?


Если да, то 0 измени на 65535. У OpenMP какая-то фигня с input диалогами.
да адванс, хотя без опенмп так-же было, работает спасибо

При сканировании сообщения из /id скрываются из чата чтобы не засорять чат. Мне нужно чтобы при сканировании номеров и ников, информациия из /id анализировалась и сканировалась, сохранялась в конфиг прежде чем сообщение из /id будет скрыто, хоть это и моментально это возможно сделать?
вот сам код

code:
script_name("CollectorNumberAndNick")
script_version("version 1")
script_authors("collectSms")

require "lib.moonloader"
local inicfg = require "inicfg"
local sampev = require 'lib.samp.events'
local samputils = require 'lib.sampfuncs'

local config_path = getWorkingDirectory() .. "\\config\\sms_config.ini"
if not doesDirectoryExist(getWorkingDirectory() .. "\\config") then
    createDirectory(getWorkingDirectory() .. "\\config")
end

local config = inicfg.load({ sms = { list = "", players = "" } }, config_path)

-- Переменные для сбора SMS
local existingNumbers = {}
local existingPlayers = {}
local collecting = false
local scanning = false

-- Таблица для отслеживания отправленных ID
local sentIds = {}

local function loadExistingData()
    existingNumbers = {}
    existingPlayers = {}
 
    if config.sms.list ~= nil and config.sms.list ~= "" then
        for num in string.gmatch(config.sms.list, "[^,]+") do
            existingNumbers[num] = true
        end
    end
 
    if config.sms.players ~= nil and config.sms.players ~= "" then
        for pair in string.gmatch(config.sms.players, "[^,]+") do
            local number, name = pair:match("([^=]+)=(.+)")
            if number and name then
                existingPlayers[number] = name
            end
        end
    end
end

local function saveData()
    local allNumbers = {}
    for num in pairs(existingNumbers) do
        table.insert(allNumbers, num)
    end
    config.sms.list = table.concat(allNumbers, ",")
 
    local allPlayers = {}
    for num, name in pairs(existingPlayers) do
        table.insert(allPlayers, num .. "=" .. name)
    end
    config.sms.players = table.concat(allPlayers, ",")
 
    inicfg.save(config, config_path)
end

local function addPlayer(number, name)
    if existingNumbers[number] then
        print("[SMS Collector] Номер уже в конфиге: " .. number)
        return false
    else
        existingNumbers[number] = true
        existingPlayers[number] = name
        saveData()
        print("[SMS Collector] Добавлен: " .. number .. " (" .. name .. ")")
        return true
    end
end

local function removeColorCodes(text)
    return text:gsub("{[%x]+}", "")
end

local function extractNickFromAd(text)
    local senderNick = text:match("Отправил%s+([%w_]+)")
    if senderNick then
        return senderNick
    end
 
    senderNick = text:match("от%s+([%w_]+)")
    if senderNick then
        return senderNick
    end
 
    local nick = text:match("^([%w_]+)")
    if nick then
        return nick
    end
 
    return "Объявление"
end

-- Функция для обработки ответов на /id
local function processAndAddPlayer(cleanText)
    -- Паттерны для разных форматов ответов
    local patterns = {
        {pattern = "(.+) id (%d+) %- тел%. (%d+)",
         extract = function(p, id, num) return p, num end},
        {pattern = "(.+) id (%d+) %- ren%. (%d+)",
         extract = function(p, id, num) return p, num end},
        {pattern = "(.+) id (%d+) %(.-%) %- тел%. (%d+)",
         extract = function(p, id, num) return p, num end},
        {pattern = "(.+) id (%d+) %(.-%) %- ren%. (%d+)",
         extract = function(p, id, num) return p, num end},
        {pattern = "(.+) id (%d+)",
         extract = function(p, id) return p, nil end}
    }
 
    for _, p in ipairs(patterns) do
        local playerName, id, number = cleanText:match(p.pattern)
        if playerName then
            playerName, number = p.extract(playerName, id, number)
            playerName = playerName:gsub("%s+$", ""):gsub("^%s+", "")
         
            if number then
                if addPlayer(number, playerName) then
                    print("[Сканирование] Добавлено: ID "..id.." | "..number.." | "..playerName)
                end
                return true
            else
                print("[Сканирование] Найден ID "..id..": "..playerName.." (номер не обнаружен)")
                return true
            end
        end
    end
 
    return false
end

-- Блокировка отображения команд /id в чате
function sampev.onSendCommand(cmd)
    if scanning then
        local id = cmd:match("^/id%s+(%d+)")
        if id then
            return false -- Блокируем вывод команды
        end
    end
end

-- Обработка серверных сообщений
function sampev.onServerMessage(color, text)
    local cleanText = removeColorCodes(text)
 
    if scanning then
        -- Обработка ответов на /id
        if processAndAddPlayer(cleanText) then
            return true -- Скрываем сообщение
        end
    end
 
    if collecting then
        -- Обработка объявлений
        local found = false
        for number in cleanText:gmatch("тел%.%s*(%d+)") or cleanText:gmatch("ren%.%s*(%d+)") do
            found = true
            local playerName = extractNickFromAd(cleanText)
            addPlayer(number, playerName)
        end
     
        if found then
            print("[SMS Collector] Найдено в объявлении: " .. cleanText)
        end
    end
end

-- Обработка сообщений чата
function sampev.onChatMessage(color, text, playerId)
    local cleanText = removeColorCodes(text)
 
    if scanning then
        -- Обработка ответов на /id
        if processAndAddPlayer(cleanText) then
            return false -- Скрываем сообщение
        end
    end
 
    if collecting then
        local playerName = sampGetPlayerNickname(playerId) or "Неизвестно"
        local found = false
     
        for number in cleanText:gmatch("тел%.%s*(%d+)") or cleanText:gmatch("ren%.%s*(%d+)") do
            found = true
            addPlayer(number, playerName)
        end
     
        if found then
            print("[SMS Collector] Найдено в чате: " .. cleanText)
        end
    end
 
    return true
end

-- Функция сканирования ID
local function scanIDs()
    if scanning then
        print("[SMS Collector] Сканирование уже запущено!")
        return
    end

    scanning = true
    sentIds = {}
 
    print("[SMS Collector] Начинаем сканирование ID 0-1000...")
    print("Все найденные номера будут мгновенно сохраняться")

    lua_thread.create(function()
        for i = 0, 1000 do
            if not scanning then break end
            if sampIsPlayerConnected(i) then
                table.insert(sentIds, i)
                sampSendChat("/id " .. i)
                wait(100)
            end
        end
     
        -- Ждем завершения обработки
        wait(3000)
        scanning = false
        sampAddChatMessage("Сканирование завершено.", 0x00FF00)
        print("[SMS Collector] Сканирование завершено")
    end)
end

function main()
    while not isSampAvailable() do wait(100) end

    loadExistingData()
    sampAddChatMessage("SMS Collector Pro v21 загружен. Команды:", 0x00FFAA)
    sampAddChatMessage("/collectsms - начать сбор", 0x00FFAA)
    sampAddChatMessage("/collectstop - остановить сбор", 0x00FFAA)

    sampRegisterChatCommand("collectsms", function()
        if collecting then
            sampAddChatMessage("Сбор уже активен.", 0xFFFF00)
            return
        end
        collecting = true
        sampAddChatMessage("Сбор номеров и ников активирован!", 0x00FF00)
        print("[SMS Collector] Запущено сканирование ID")
        scanIDs()
    end)

    sampRegisterChatCommand("collectstop", function()
        if not collecting then
            sampAddChatMessage("Сбор не активен.", 0xFFFF00)
            return
        end
        collecting = false
        scanning = false
        sampAddChatMessage("Сбор остановлен.", 0xFF9900)
        print("[SMS Collector] Сканирование остановлено")
    end)

    wait(-1)
end
 
Последнее редактирование:

k1lla

Известный
4
0
всем здарова. мучу фейк афк для своих нужд. не могу понять че можно занопить чтобы уйти в афк с пассажирского места.
для водительского работает function sampev.onSendVehicleSync(data) но на пассажирском это нихуя не дает
 

dmitry.karle

Известный
366
102
всем здарова. мучу фейк афк для своих нужд. не могу понять че можно занопить чтобы уйти в афк с пассажирского места.
для водительского работает function sampev.onSendVehicleSync(data) но на пассажирском это нихуя не дает
Lua:
require('lib.samp.events').onSendPlayerSync = function(data)
    if isCharInAnyCar(PLAYER_PED) then
        return false
    end
end
банальщина, но попробуй, но может кикнуть с пассажирки
 
Последнее редактирование:
  • Нравится
Реакции: k1lla

Ciske

Новичок
25
7
Народ, как узнать скорость персонажа? Функция getCharSpeed(PLAYER_PED) возвращает что-то не то. Например, при езде на авто на скорости 100+ км в час она выдаёт около 30. Даже бег показывает не выше 13, хотя если ехать на авто примерно с такой скоростью будет 30+. В чём тут нюанс? Другие единицы? Но не мили же.

Мне нужно именно персонажа, не скорость авто. (например, если персонаж летит на джетпаке)
 
Последнее редактирование:

Winstаl

Известный
902
358
Народ, как узнать скорость персонажа? Функция getCharSpeed(PLAYER_PED) возвращает что-то не то. Например, при езде на авто на скорости 100+ км в час она выдаёт около 30. Даже бег показывает не выше 13, хотя если ехать на авто примерно с такой скоростью будет 30+. В чём тут нюанс? Другие единицы? Но не мили же.

Мне нужно именно персонажа, не скорость авто. (например, если персонаж летит на джетпаке)
А с чем ты сравниваешь?
 

abnomegd

Активный
347
37

При сканировании сообщения из /id скрываются из чата чтобы не засорять чат. Мне нужно чтобы при сканировании номеров и ников, информациия из /id анализировалась и сканировалась, сохранялась в конфиг прежде чем сообщение из /id будет скрыто, хоть это и моментально это возможно сделать?
вот сам код

code:
require "lib.moonloader"
local inicfg = require "inicfg"
local sampev = require 'lib.samp.events'
local samputils = require 'lib.sampfuncs'

local config_path = getWorkingDirectory() .. "\\config\\sms_config.ini"
if not doesDirectoryExist(getWorkingDirectory() .. "\\config") then
    createDirectory(getWorkingDirectory() .. "\\config")
end

local config = inicfg.load({ sms = { list = "", players = "" } }, config_path)

-- Переменные для сбора SMS
local existingNumbers = {}
local existingPlayers = {}
local collecting = false
local scanning = false

-- Таблица для отслеживания отправленных ID
local sentIds = {}

local function loadExistingData()
    existingNumbers = {}
    existingPlayers = {}
 
    if config.sms.list ~= nil and config.sms.list ~= "" then
        for num in string.gmatch(config.sms.list, "[^,]+") do
            existingNumbers[num] = true
        end
    end
 
    if config.sms.players ~= nil and config.sms.players ~= "" then
        for pair in string.gmatch(config.sms.players, "[^,]+") do
            local number, name = pair:match("([^=]+)=(.+)")
            if number and name then
                existingPlayers[number] = name
            end
        end
    end
end

local function saveData()
    local allNumbers = {}
    for num in pairs(existingNumbers) do
        table.insert(allNumbers, num)
    end
    config.sms.list = table.concat(allNumbers, ",")
 
    local allPlayers = {}
    for num, name in pairs(existingPlayers) do
        table.insert(allPlayers, num .. "=" .. name)
    end
    config.sms.players = table.concat(allPlayers, ",")
 
    inicfg.save(config, config_path)
end

local function addPlayer(number, name)
    if existingNumbers[number] then
        print("[SMS Collector] Номер уже в конфиге: " .. number)
        return false
    else
        existingNumbers[number] = true
        existingPlayers[number] = name
        saveData()
        print("[SMS Collector] Добавлен: " .. number .. " (" .. name .. ")")
        return true
    end
end

local function removeColorCodes(text)
    return text:gsub("{[%x]+}", "")
end

local function extractNickFromAd(text)
    local senderNick = text:match("Отправил%s+([%w_]+)")
    if senderNick then
        return senderNick
    end
 
    senderNick = text:match("от%s+([%w_]+)")
    if senderNick then
        return senderNick
    end
 
    local nick = text:match("^([%w_]+)")
    if nick then
        return nick
    end
 
    return "Объявление"
end

-- Функция для обработки ответов на /id
local function processAndAddPlayer(cleanText)
    -- Паттерны для разных форматов ответов
    local patterns = {
        {pattern = "(.+) id (%d+) %- тел%. (%d+)",
         extract = function(p, id, num) return p, num end},
        {pattern = "(.+) id (%d+) %- ren%. (%d+)",
         extract = function(p, id, num) return p, num end},
        {pattern = "(.+) id (%d+) %(.-%) %- тел%. (%d+)",
         extract = function(p, id, num) return p, num end},
        {pattern = "(.+) id (%d+) %(.-%) %- ren%. (%d+)",
         extract = function(p, id, num) return p, num end},
        {pattern = "(.+) id (%d+)",
         extract = function(p, id) return p, nil end}
    }
 
    for _, p in ipairs(patterns) do
        local playerName, id, number = cleanText:match(p.pattern)
        if playerName then
            playerName, number = p.extract(playerName, id, number)
            playerName = playerName:gsub("%s+$", ""):gsub("^%s+", "")
       
            if number then
                if addPlayer(number, playerName) then
                    print("[Сканирование] Добавлено: ID "..id.." | "..number.." | "..playerName)
                end
                return true
            else
                print("[Сканирование] Найден ID "..id..": "..playerName.." (номер не обнаружен)")
                return true
            end
        end
    end
 
    return false
end

-- Блокировка отображения команд /id в чате
function sampev.onSendCommand(cmd)
    if scanning then
        local id = cmd:match("^/id%s+(%d+)")
        if id then
            return false -- Блокируем вывод команды
        end
    end
end

-- Обработка серверных сообщений
function sampev.onServerMessage(color, text)
    local cleanText = removeColorCodes(text)
 
    if scanning then
        -- Обработка ответов на /id
        if processAndAddPlayer(cleanText) then
            return true -- Скрываем сообщение
        end
    end
 
    if collecting then
        -- Обработка объявлений
        local found = false
        for number in cleanText:gmatch("тел%.%s*(%d+)") or cleanText:gmatch("ren%.%s*(%d+)") do
            found = true
            local playerName = extractNickFromAd(cleanText)
            addPlayer(number, playerName)
        end
   
        if found then
            print("[SMS Collector] Найдено в объявлении: " .. cleanText)
        end
    end
end

-- Обработка сообщений чата
function sampev.onChatMessage(color, text, playerId)
    local cleanText = removeColorCodes(text)
 
    if scanning then
        -- Обработка ответов на /id
        if processAndAddPlayer(cleanText) then
            return false -- Скрываем сообщение
        end
    end
 
    if collecting then
        local playerName = sampGetPlayerNickname(playerId) or "Неизвестно"
        local found = false
   
        for number in cleanText:gmatch("тел%.%s*(%d+)") or cleanText:gmatch("ren%.%s*(%d+)") do
            found = true
            addPlayer(number, playerName)
        end
   
        if found then
            print("[SMS Collector] Найдено в чате: " .. cleanText)
        end
    end
 
    return true
end

-- Функция сканирования ID
local function scanIDs()
    if scanning then
        print("[SMS Collector] Сканирование уже запущено!")
        return
    end

    scanning = true
    sentIds = {}
 
    print("[SMS Collector] Начинаем сканирование ID 0-1000...")
    print("Все найденные номера будут мгновенно сохраняться")

    lua_thread.create(function()
        for i = 0, 1000 do
            if not scanning then break end
            if sampIsPlayerConnected(i) then
                table.insert(sentIds, i)
                sampSendChat("/id " .. i)
                wait(100)
            end
        end
   
        -- Ждем завершения обработки
        wait(3000)
        scanning = false
        sampAddChatMessage("Сканирование завершено.", 0x00FF00)
        print("[SMS Collector] Сканирование завершено")
    end)
end

function main()
    while not isSampAvailable() do wait(100) end

    loadExistingData()
    sampAddChatMessage("SMS Collector Pro v21 загружен. Команды:", 0x00FFAA)
    sampAddChatMessage("/collectsms - начать сбор", 0x00FFAA)
    sampAddChatMessage("/collectstop - остановить сбор", 0x00FFAA)

    sampRegisterChatCommand("collectsms", function()
        if collecting then
            sampAddChatMessage("Сбор уже активен.", 0xFFFF00)
            return
        end
        collecting = true
        sampAddChatMessage("Сбор номеров и ников активирован!", 0x00FF00)
        print("[SMS Collector] Запущено сканирование ID")
        scanIDs()
    end)

    sampRegisterChatCommand("collectstop", function()
        if not collecting then
            sampAddChatMessage("Сбор не активен.", 0xFFFF00)
            return
        end
        collecting = false
        scanning = false
        sampAddChatMessage("Сбор остановлен.", 0xFF9900)
        print("[SMS Collector] Сканирование остановлено")
    end)

    wait(-1)
end
up
 

Ciske

Новичок
25
7
Верно. 3.4-3.6, примерно такой коэффициент.
Спасибо! Методом замера (/limit 100 на спидометре и делим результат потом) получил 3.5897.
Если он для всех авто одинаковый конечно. Было бы логично влепить топ-донатным авто немного фейковый спидометр:) Пусть радуются циферкам.
 
  • Нравится
Реакции: Winstаl

Oki_Bern

Участник
290
7
При нажатии на текст окно закрывается, но при следующим открытии окна оно прилипает к курсору, т.к. imgui.IsItemClicked проверяет на нажатие, а не отжатие клавиши, как это можно исправить

Lua:
    imgui.Text((' '):rep(3) .. icon)
    if imgui.IsItemClicked(0) then Window[0] = false end
 

SiarCis

Новичок
11
0
Подскажите. Я правильно понимаю, что нет возможности легко получить список всех видимых текстдравов? Что их надо записывать в таблицу при появлении в событии onShowTextDraw?

И второй вопрос… как так получается, что у в текстдравах лавок Аризоны некоторые modelId одинаковые у разных предметов? Например, у бронзовой, золотой и платиновой рулетки в слоте текстдрава лежит моделька 1649. Более того! Сморим дальше… у Монеты Основания тоже 1649. Это как?
 
Последнее редактирование:

Naito

Активный
165
36
The welcome text looks blurry. How can I make it sharper? So it looks good.


code:
local imgui = require('mimgui')

local showAnimation = false
local animationStartTime = 0
local animationDuration = 4.0
local fadeInDuration = 1.0
local holdDuration = 2.0
local fadeOutDuration = 1.0
local playerSpawned = false

local function calculateAlpha(currentTime)
    local elapsed = currentTime - animationStartTime
    
    if elapsed < fadeInDuration then
        return elapsed / fadeInDuration
    elseif elapsed < fadeInDuration + holdDuration then
        return 1.0
    elseif elapsed < animationDuration then
        local fadeOutStart = fadeInDuration + holdDuration
        local fadeOutElapsed = elapsed - fadeOutStart
        return 1.0 - (fadeOutElapsed / fadeOutDuration)
    else
        return 0.0
    end
end

local function startAnimation()
    showAnimation = true
    animationStartTime = os.clock()
end

local function renderTextWithShadow(text, posX, posY, mainColor, shadowColor, shadowOffset)
    imgui.SetCursorPos(imgui.ImVec2(posX + shadowOffset, posY + shadowOffset))
    imgui.PushStyleColor(imgui.Col.Text, shadowColor)
    imgui.Text(text)
    imgui.PopStyleColor()

    imgui.SetCursorPos(imgui.ImVec2(posX, posY))
    imgui.PushStyleColor(imgui.Col.Text, mainColor)
    imgui.Text(text)
    imgui.PopStyleColor()
end

local function renderSharpText(text, posX, posY, color, alpha)
    local offsets = {
        {0, 0},
        {0.5, 0},
        {0, 0.5},
        {0.5, 0.5}
    }
    
    for _, offset in ipairs(offsets) do
        imgui.SetCursorPos(imgui.ImVec2(posX + offset[1], posY + offset[2]))
        imgui.PushStyleColor(imgui.Col.Text, imgui.ImVec4(color.x, color.y, color.z, alpha * 0.25))
        imgui.Text(text)
        imgui.PopStyleColor()
    end
end

imgui.OnFrame(
    function() return showAnimation end,
    function(self)
        self.HideCursor = true
        
        local currentTime = os.clock()
        local alpha = calculateAlpha(currentTime)
        
        if currentTime - animationStartTime >= animationDuration then
            showAnimation = false
            return
        end
        
        local resX, resY = getScreenResolution()
        
        imgui.SetNextWindowPos(imgui.ImVec2(0, 0))
        imgui.SetNextWindowSize(imgui.ImVec2(resX, resY))
        
        imgui.PushStyleColor(imgui.Col.WindowBg, imgui.ImVec4(0, 0, 0, alpha))
        imgui.PushStyleColor(imgui.Col.Border, imgui.ImVec4(0, 0, 0, 0))
        imgui.PushStyleVarFloat(imgui.StyleVar.WindowRounding, 0)
        imgui.PushStyleVarFloat(imgui.StyleVar.WindowBorderSize, 0)
        
        imgui.Begin('welcome', nil,
            imgui.WindowFlags.NoTitleBar +
            imgui.WindowFlags.NoResize +
            imgui.WindowFlags.NoMove +
            imgui.WindowFlags.NoScrollbar +
            imgui.WindowFlags.NoScrollWithMouse +
            imgui.WindowFlags.NoCollapse +
            imgui.WindowFlags.NoNav +
            imgui.WindowFlags.NoBringToFrontOnFocus
        )
        
        local text = "test"
        
        imgui.SetWindowFontScale(6.0)
        
        local textSize = imgui.CalcTextSize(text)
        local textPosX = (resX - textSize.x) / 2
        local textPosY = (resY - textSize.y) / 2
        
        local purpleColor = imgui.ImVec4(0.7, 0.3, 1.0, alpha)
        local shadowColor = imgui.ImVec4(0.0, 0.0, 0.0, alpha * 0.5)
        local glowColor = imgui.ImVec4(0.8, 0.4, 1.0, alpha * 0.3)
        
        local microOffsets = {
            {0, 0}, {0.25, 0}, {0.5, 0}, {0.75, 0},
            {0, 0.25}, {0.25, 0.25}, {0.5, 0.25}, {0.75, 0.25},
            {0, 0.5}, {0.25, 0.5}, {0.5, 0.5}, {0.75, 0.5},
            {0, 0.75}, {0.25, 0.75}, {0.5, 0.75}, {0.75, 0.75}
        }
        
        imgui.SetCursorPos(imgui.ImVec2(textPosX + 8, textPosY + 8))
        imgui.PushStyleColor(imgui.Col.Text, shadowColor)
        imgui.Text(text)
        imgui.PopStyleColor()
        
        for i = 1, 4 do
            local glowOffset = i * 2
            imgui.SetCursorPos(imgui.ImVec2(textPosX - glowOffset, textPosY - glowOffset))
            imgui.PushStyleColor(imgui.Col.Text, imgui.ImVec4(glowColor.x, glowColor.y, glowColor.z, glowColor.w * 0.2))
            imgui.Text(text)
            imgui.PopStyleColor()
            
            imgui.SetCursorPos(imgui.ImVec2(textPosX + glowOffset, textPosY - glowOffset))
            imgui.PushStyleColor(imgui.Col.Text, imgui.ImVec4(glowColor.x, glowColor.y, glowColor.z, glowColor.w * 0.2))
            imgui.Text(text)
            imgui.PopStyleColor()
            
            imgui.SetCursorPos(imgui.ImVec2(textPosX - glowOffset, textPosY + glowOffset))
            imgui.PushStyleColor(imgui.Col.Text, imgui.ImVec4(glowColor.x, glowColor.y, glowColor.z, glowColor.w * 0.2))
            imgui.Text(text)
            imgui.PopStyleColor()
            
            imgui.SetCursorPos(imgui.ImVec2(textPosX + glowOffset, textPosY + glowOffset))
            imgui.PushStyleColor(imgui.Col.Text, imgui.ImVec4(glowColor.x, glowColor.y, glowColor.z, glowColor.w * 0.2))
            imgui.Text(text)
            imgui.PopStyleColor()
        end
        
        for _, offset in ipairs(microOffsets) do
            imgui.SetCursorPos(imgui.ImVec2(textPosX + offset[1], textPosY + offset[2]))
            imgui.PushStyleColor(imgui.Col.Text, imgui.ImVec4(purpleColor.x, purpleColor.y, purpleColor.z, purpleColor.w * 0.0625)) -- 1/16 de opacidad por cada renderizado
            imgui.Text(text)
            imgui.PopStyleColor()
        end
        
        imgui.SetCursorPos(imgui.ImVec2(textPosX, textPosY))
        imgui.PushStyleColor(imgui.Col.Text, purpleColor)
        imgui.Text(text)
        imgui.PopStyleColor()
        
        imgui.SetWindowFontScale(1.0)
        imgui.End()
        
        imgui.PopStyleVar(2)
        imgui.PopStyleColor(2)
    end
)

function main()
    while not isSampAvailable() or not sampIsLocalPlayerSpawned() do
        wait(200)
    end
    
    while sampGetCurrentServerName() == "SA-MP" do
        wait(200)
    end
    
    wait(1000)
    
    startAnimation()

    while true do
        wait(1000)
    end
end
 

abnomegd

Активный
347
37

При сканировании сообщения из /id скрываются из чата чтобы не засорять чат. Мне нужно чтобы при сканировании номеров и ников, информациия из /id анализировалась и сканировалась, сохранялась в конфиг прежде чем сообщение из /id будет скрыто, хоть это и моментально это возможно сделать?
вот сам код

code:
require "lib.moonloader"
local inicfg = require "inicfg"
local sampev = require 'lib.samp.events'
local samputils = require 'lib.sampfuncs'

local config_path = getWorkingDirectory() .. "\\config\\sms_config.ini"
if not doesDirectoryExist(getWorkingDirectory() .. "\\config") then
    createDirectory(getWorkingDirectory() .. "\\config")
end

local config = inicfg.load({ sms = { list = "", players = "" } }, config_path)

-- Переменные для сбора SMS
local existingNumbers = {}
local existingPlayers = {}
local collecting = false
local scanning = false

-- Таблица для отслеживания отправленных ID
local sentIds = {}

local function loadExistingData()
    existingNumbers = {}
    existingPlayers = {}
 
    if config.sms.list ~= nil and config.sms.list ~= "" then
        for num in string.gmatch(config.sms.list, "[^,]+") do
            existingNumbers[num] = true
        end
    end
 
    if config.sms.players ~= nil and config.sms.players ~= "" then
        for pair in string.gmatch(config.sms.players, "[^,]+") do
            local number, name = pair:match("([^=]+)=(.+)")
            if number and name then
                existingPlayers[number] = name
            end
        end
    end
end

local function saveData()
    local allNumbers = {}
    for num in pairs(existingNumbers) do
        table.insert(allNumbers, num)
    end
    config.sms.list = table.concat(allNumbers, ",")
 
    local allPlayers = {}
    for num, name in pairs(existingPlayers) do
        table.insert(allPlayers, num .. "=" .. name)
    end
    config.sms.players = table.concat(allPlayers, ",")
 
    inicfg.save(config, config_path)
end

local function addPlayer(number, name)
    if existingNumbers[number] then
        print("[SMS Collector] Номер уже в конфиге: " .. number)
        return false
    else
        existingNumbers[number] = true
        existingPlayers[number] = name
        saveData()
        print("[SMS Collector] Добавлен: " .. number .. " (" .. name .. ")")
        return true
    end
end

local function removeColorCodes(text)
    return text:gsub("{[%x]+}", "")
end

local function extractNickFromAd(text)
    local senderNick = text:match("Отправил%s+([%w_]+)")
    if senderNick then
        return senderNick
    end
 
    senderNick = text:match("от%s+([%w_]+)")
    if senderNick then
        return senderNick
    end
 
    local nick = text:match("^([%w_]+)")
    if nick then
        return nick
    end
 
    return "Объявление"
end

-- Функция для обработки ответов на /id
local function processAndAddPlayer(cleanText)
    -- Паттерны для разных форматов ответов
    local patterns = {
        {pattern = "(.+) id (%d+) %- тел%. (%d+)",
         extract = function(p, id, num) return p, num end},
        {pattern = "(.+) id (%d+) %- ren%. (%d+)",
         extract = function(p, id, num) return p, num end},
        {pattern = "(.+) id (%d+) %(.-%) %- тел%. (%d+)",
         extract = function(p, id, num) return p, num end},
        {pattern = "(.+) id (%d+) %(.-%) %- ren%. (%d+)",
         extract = function(p, id, num) return p, num end},
        {pattern = "(.+) id (%d+)",
         extract = function(p, id) return p, nil end}
    }
 
    for _, p in ipairs(patterns) do
        local playerName, id, number = cleanText:match(p.pattern)
        if playerName then
            playerName, number = p.extract(playerName, id, number)
            playerName = playerName:gsub("%s+$", ""):gsub("^%s+", "")
      
            if number then
                if addPlayer(number, playerName) then
                    print("[Сканирование] Добавлено: ID "..id.." | "..number.." | "..playerName)
                end
                return true
            else
                print("[Сканирование] Найден ID "..id..": "..playerName.." (номер не обнаружен)")
                return true
            end
        end
    end
 
    return false
end

-- Блокировка отображения команд /id в чате
function sampev.onSendCommand(cmd)
    if scanning then
        local id = cmd:match("^/id%s+(%d+)")
        if id then
            return false -- Блокируем вывод команды
        end
    end
end

-- Обработка серверных сообщений
function sampev.onServerMessage(color, text)
    local cleanText = removeColorCodes(text)
 
    if scanning then
        -- Обработка ответов на /id
        if processAndAddPlayer(cleanText) then
            return true -- Скрываем сообщение
        end
    end
 
    if collecting then
        -- Обработка объявлений
        local found = false
        for number in cleanText:gmatch("тел%.%s*(%d+)") or cleanText:gmatch("ren%.%s*(%d+)") do
            found = true
            local playerName = extractNickFromAd(cleanText)
            addPlayer(number, playerName)
        end
  
        if found then
            print("[SMS Collector] Найдено в объявлении: " .. cleanText)
        end
    end
end

-- Обработка сообщений чата
function sampev.onChatMessage(color, text, playerId)
    local cleanText = removeColorCodes(text)
 
    if scanning then
        -- Обработка ответов на /id
        if processAndAddPlayer(cleanText) then
            return false -- Скрываем сообщение
        end
    end
 
    if collecting then
        local playerName = sampGetPlayerNickname(playerId) or "Неизвестно"
        local found = false
  
        for number in cleanText:gmatch("тел%.%s*(%d+)") or cleanText:gmatch("ren%.%s*(%d+)") do
            found = true
            addPlayer(number, playerName)
        end
  
        if found then
            print("[SMS Collector] Найдено в чате: " .. cleanText)
        end
    end
 
    return true
end

-- Функция сканирования ID
local function scanIDs()
    if scanning then
        print("[SMS Collector] Сканирование уже запущено!")
        return
    end

    scanning = true
    sentIds = {}
 
    print("[SMS Collector] Начинаем сканирование ID 0-1000...")
    print("Все найденные номера будут мгновенно сохраняться")

    lua_thread.create(function()
        for i = 0, 1000 do
            if not scanning then break end
            if sampIsPlayerConnected(i) then
                table.insert(sentIds, i)
                sampSendChat("/id " .. i)
                wait(100)
            end
        end
  
        -- Ждем завершения обработки
        wait(3000)
        scanning = false
        sampAddChatMessage("Сканирование завершено.", 0x00FF00)
        print("[SMS Collector] Сканирование завершено")
    end)
end

function main()
    while not isSampAvailable() do wait(100) end

    loadExistingData()
    sampAddChatMessage("SMS Collector Pro v21 загружен. Команды:", 0x00FFAA)
    sampAddChatMessage("/collectsms - начать сбор", 0x00FFAA)
    sampAddChatMessage("/collectstop - остановить сбор", 0x00FFAA)

    sampRegisterChatCommand("collectsms", function()
        if collecting then
            sampAddChatMessage("Сбор уже активен.", 0xFFFF00)
            return
        end
        collecting = true
        sampAddChatMessage("Сбор номеров и ников активирован!", 0x00FF00)
        print("[SMS Collector] Запущено сканирование ID")
        scanIDs()
    end)

    sampRegisterChatCommand("collectstop", function()
        if not collecting then
            sampAddChatMessage("Сбор не активен.", 0xFFFF00)
            return
        end
        collecting = false
        scanning = false
        sampAddChatMessage("Сбор остановлен.", 0xFF9900)
        print("[SMS Collector] Сканирование остановлено")
    end)

    wait(-1)
end
up
 

veXOR

Новичок
2
0
РЎРєСЂРёРїС‚ загружен. КоманРПостоянно как я свои скрипты загружаю подобная проблема, с чужими ворк
 

paulohardy

вы еще постите говно? тогда я иду к вам
Всефорумный модератор
1,982
1,322