Полезные сниппеты и функции

Cosmo

Известный
Друг
656
2,744
Описание:
Функция, которая ищет координаты ближайшей к вам дороги (проезжей части)
Lua:
function getNearestRoadCoordinates(radius)
    local A = { getCharCoordinates(PLAYER_PED) }
    local B = { getClosestStraightRoad(A[1], A[2], A[3], 0, radius or 600) }
    if B[1] ~= 0 and B[2] ~= 0 and B[3] ~= 0 then
        return true, B[1], B[2], B[3]
    end
    return false
end

Использование:
При нажатии на F4 вас телепортирует на ближайшую к вам дорогу
Lua:
function onWindowMessage(msg, wparam, lparam)
    if msg == 0x0100 and wparam == 0x73 then -- F4
        local result, x, y, z = getNearestRoadCoordinates()
        if result then
            local dist = getDistanceBetweenCoords3d(x, y, z, getCharCoordinates(PLAYER_PED))
            setCharCoordinates(PLAYER_PED, x, y, z + 1)
            sampAddChatMessage(("Вы телепортированны на ближайшую от Вас дорогу (%dm.)"):format(dist), 0xAAFFAA)
        else
            sampAddChatMessage("Не нашлось ни одной дороги поблизости", 0xFFAAAA)
        end
    end
end
 

Fott

Простреленный
3,461
2,378
Описание:
Функция, которая служит некому аналогу оператору принадлежности in с питона. Позволяет удобно проверять, является ли значение частью последовательности. Позволяет так же проверять элементы с одного массива в другом.
Функция принимает 3 аргумента.
Lua:
function iin(list, what_find, mode)
    if what_find and type(what_find) ~= 'table' then
        local set = {}
        for _, l in ipairs(list) do set[l] = true end
        return set[what_find] and true or false
    elseif type(what_find) == 'table' then
        if not mode or mode == false then
            local set = {}
            for _, l in ipairs(list) do set[l] = true end
            for _, l in ipairs(what_find) do if set[l] then return true end end
        elseif mode == true then
            local set = {}
            local res = nil
            for _, l in ipairs(list) do set[l] = true end
            for k,v in pairs(what_find) do if set[v] then res = true else res = false end end
            return res
        end
    end
end
АргументОписаниеВажностьТип данных который должен быть передан
listМассив в котором будет производится проверкаобязательный параметрtable
what_findЭлемент который будет искаться. В случае если будет передан массив - будет проверять все элементы.обязательный параметрstring/number/table
modeРежим точной проверки последовательности. Используется если во второй параметр передан массив. При false функция вернет положительный ответ если будет найдено хоть 1 совпадение. При true функция вернет положительный ответ если все элементы будут совпадать.необязательный параметр. Стандартно - falsebool

Пример использования:
Lua:
ids = {1, 2, 3, 5}
id = 4
if iin(ids, id) then print('true') else print('false') end -- false
Lua:
ids = {1, 2, 3, 5}
id = 5
if iin(ids, id) then print('true') else print('false') end -- true
Пример использования с массивом:
Lua:
ids = {1, 2, 3, 5}
id = {2,4,7}
if iin(ids, id) then print('true') else print('false') end -- true
Lua:
ids = {1, 2, 3, 5}
id = {2,4,7}
if iin(ids, id, true) then print('true') else print('false') end -- false , потому что включен режим точности (передан 3 аргумент true)
 

madrasso

Потрачен
883
325
Обратите внимание, пользователь заблокирован на форуме. Не рекомендуется проводить сделки.
Описание: Получает название окна по hwnd
Lua:
ffi.cdef [[
        typedef const char *LPSTR;
        typedef const char* LPCSTR;
        typedef unsigned long HANDLE;
        typedef HANDLE HWND;

        HWND GetActiveWindow(void);
        int GetWindowTextA(HWND hWnd, LPSTR lpString,int nMaxCount);
        int GetWindowTextLengthA(HWND hWnd);
]]

local function getWindowName(hwnd)
    local length = ffi.C.GetWindowTextLengthA(hwnd) + 1;
    local str = ffi.new("char[" .. length .. "]");
    ffi.C.GetWindowTextA(hwnd, str, length);
    return ffi.string(str);
end
Пример использования:
Lua:
ffi.cdef [[
        typedef const char *LPSTR;
        typedef const char* LPCSTR;
        typedef unsigned long HANDLE;
        typedef HANDLE HWND;
        HWND GetActiveWindow(void);
        int GetWindowTextA(HWND hWnd, LPSTR lpString,int nMaxCount);
        int GetWindowTextLengthA(HWND hWnd);
]]

local function getWindowName(hwnd)
    local length = ffi.C.GetWindowTextLengthA(hwnd) + 1;
    local str = ffi.new("char[" .. length .. "]");
    ffi.C.GetWindowTextA(hwnd, str, length);
    return ffi.string(str);
end

function main()
    hwnd = ffi.C.GetActiveWindow();
    repeat wait(0) until isSampAvailable();
  
    local name = getWindowName(hwnd);
    print("Window name: " .. name)
end
 

kizn

\ 0 _ 0 /
Всефорумный модератор
2,407
2,108
Описание: получает информацию о любом сервере SA:MP
Код:
Lua:
function urlencode(str)
    if (str) then
       str = string.gsub (str, "\n", "\r\n")
       str = string.gsub (str, "([^%w ])",
          function (c) return string.format ("%%%02X", string.byte(c)) end)
       str = string.gsub (str, " ", "+")
    end
    return str
end

function getServerInfo(address)
    if address:find('(.+):(.+)') then
        local requests = require 'requests'
        local ip, port = address:match('(.+):(.+)')
        local serverInfo = requests.get('http://ff004d.site/index.php?ip='..urlencode(ip, 'CP1251')..'&port='..urlencode(port, 'CP1251'))
        if serverInfo.status_code == 200 then
            local data = decodeJson(serverInfo.text)
            sampAddChatMessage('hostname: '..data['hostname'], -1)
            sampAddChatMessage('players: '..data['players'], -1)
            sampAddChatMessage('max_players: '..data['max_players'], -1)
            sampAddChatMessage('gamemode: '..data['gamemode'], -1)
            sampAddChatMessage('language: '..data['language'], -1)
        end
    end
end
Код:
Lua:
function main()
    while not isSampAvailable() do wait(0) end
    sampRegisterChatCommand('serverinfo', function(arg)
        getServerInfo(arg)
    end)
    wait(-1)
end

function urlencode(str)
    if (str) then
       str = string.gsub (str, "\n", "\r\n")
       str = string.gsub (str, "([^%w ])",
          function (c) return string.format ("%%%02X", string.byte(c)) end)
       str = string.gsub (str, " ", "+")
    end
    return str
end

function getServerInfo(address)
    if address:find('(.+):(.+)') then
        local requests = require 'requests'
        local ip, port = address:match('(.+):(.+)')
        local serverInfo = requests.get('http://ff004d.site/index.php?ip='..urlencode(ip, 'CP1251')..'&port='..urlencode(port, 'CP1251'))
        if serverInfo.status_code == 200 then
            local data = decodeJson(serverInfo.text)
            sampShowDialog(191, 'SampServerInfo', 'IP: '..address..'\nНазвание: '..data['hostname']..'\nИгроки: '..data['players']..'/'..data['max_players']..'\nРежим игры: '..data['gamemode']..'\nЯзык: '..data['language'], 'закрыть', nil, 0)
        else
            sampShowDialog(191, 'SampServerInfo', 'Ошибка, код '..serverInfo.status_code, nil, 'закрыть', 0)
        end
    end
end
Результат:
Посмотреть вложение 122317
и какова гарантия что ты будешь каждый год платить за этот домен? это не полезный сниппет, а херь какая-то, потому что зависит от стороннего сайта
 

MrBidloKoder

Известный
423
249
Описание: получает информацию о любом сервере SA:MP
Код:
Lua:
function urlencode(str)
    if (str) then
       str = string.gsub (str, "\n", "\r\n")
       str = string.gsub (str, "([^%w ])",
          function (c) return string.format ("%%%02X", string.byte(c)) end)
       str = string.gsub (str, " ", "+")
    end
    return str
end

function getServerInfo(address)
    if address:find('(.+):(.+)') then
        local requests = require 'requests'
        local ip, port = address:match('(.+):(.+)')
        local serverInfo = requests.get('http://ff004d.site/index.php?ip='..urlencode(ip, 'CP1251')..'&port='..urlencode(port, 'CP1251'))
        if serverInfo.status_code == 200 then
            local data = decodeJson(serverInfo.text)
            sampAddChatMessage('hostname: '..data['hostname'], -1)
            sampAddChatMessage('players: '..data['players'], -1)
            sampAddChatMessage('max_players: '..data['max_players'], -1)
            sampAddChatMessage('gamemode: '..data['gamemode'], -1)
            sampAddChatMessage('language: '..data['language'], -1)
        end
    end
end
Код:
Lua:
function main()
    while not isSampAvailable() do wait(0) end
    sampRegisterChatCommand('serverinfo', function(arg)
        getServerInfo(arg)
    end)
    wait(-1)
end

function urlencode(str)
    if (str) then
       str = string.gsub (str, "\n", "\r\n")
       str = string.gsub (str, "([^%w ])",
          function (c) return string.format ("%%%02X", string.byte(c)) end)
       str = string.gsub (str, " ", "+")
    end
    return str
end

function getServerInfo(address)
    if address:find('(.+):(.+)') then
        local requests = require 'requests'
        local ip, port = address:match('(.+):(.+)')
        local serverInfo = requests.get('http://ff004d.site/index.php?ip='..urlencode(ip, 'CP1251')..'&port='..urlencode(port, 'CP1251'))
        if serverInfo.status_code == 200 then
            local data = decodeJson(serverInfo.text)
            sampShowDialog(191, 'SampServerInfo', 'IP: '..address..'\nНазвание: '..data['hostname']..'\nИгроки: '..data['players']..'/'..data['max_players']..'\nРежим игры: '..data['gamemode']..'\nЯзык: '..data['language'], 'закрыть', nil, 0)
        else
            sampShowDialog(191, 'SampServerInfo', 'Ошибка, код '..serverInfo.status_code, nil, 'закрыть', 0)
        end
    end
end
Результат:
Посмотреть вложение 122317
мне кажется стоит опубликовать серверную часть иначе от этого сниппета толку ноль
 

meowprd

Тот самый Котовский
Проверенный
1,278
720
Описание: Минималистичные чекбоксы с минимальной анимацией для mimgui
Код:
Lua:
function imgui.CustomCheck(label, bool)
    local result = false
    local drawList = imgui.GetWindowDrawList()
    local draw = imgui.GetCursorScreenPos()
    local lineHeight = imgui.GetTextLineHeight()
    local itemSpacing = imgui.GetStyle().ItemSpacing
    local boxSize = math.floor(lineHeight * 0.95)
    local clearance = boxSize * 0.2
    local corner = draw + imgui.ImVec2(0, itemSpacing.y + math.floor(0.5 * (lineHeight - boxSize)))
    local color = imgui.GetStyle().Colors[imgui.Col.Text]
    local changedColor = imgui.ImVec4(color.x, color.y, color.z, 0.25)
    local colorMark = color
    local name = string.gsub(label, "##.*", "")
    local radius = boxSize * 0.2
    local conv = imgui.ColorConvertFloat4ToU32
    local ImVec2 = imgui.ImVec2

    if not cMarks then cMarks = {} end
    if not cMarks[label] then cMarks[label] = 0 end

    imgui.BeginGroup()
        imgui.InvisibleButton(label, ImVec2(boxSize, boxSize))
        if #name > 0 then
            imgui.SameLine()
            imgui.SetCursorPosY(imgui.GetCursorPosY() + 2.5)
            imgui.Text(name)
        end
    imgui.EndGroup()
    if imgui.IsItemClicked() then
        bool[0] = not bool[0]
        result = true
        if bool[0] then cMarks[label] = os.clock() end
    end

    changedColor.w = imgui.IsItemHovered() and 1.0 or 0.25
    drawList:AddRect(corner, corner + ImVec2(boxSize, boxSize), conv(changedColor), 0.0, 0, 1.0)

    if bool[0] then
        local pts = {
            corner + ImVec2(clearance, clearance + boxSize * 0.3),
            corner + ImVec2(boxSize * 0.5, boxSize - clearance),
            corner + ImVec2(boxSize - clearance, clearance)
        }
        drawList:AddLine(pts[1], pts[2], conv(colorMark), 1.0)
        drawList:AddLine(pts[2], pts[3], conv(colorMark), 1.0)
    end

    local timer = os.clock() - cMarks[label]
    if timer < 0.4 then
        local r = radius + timer*25
        if timer <= 0.2 then circColor = imgui.ImVec4(color.x, color.y, color.z, r/5)
        else circColor = imgui.ImVec4(color.x, color.y, color.z, r/75)
        end
        drawList:AddCircle(ImVec2(draw.x + boxSize/2, draw.y + boxSize - clearance), r, conv(circColor))
    end
    return result
end

Пример использования:
Lua:
local new = imgui.new
local window = new.bool(false)
local var1, var2 = new.bool(false), new.bool(false)

imgui.OnFrame(
    function() return window[0] end,
    function() end,
    function(self)
        imgui.Begin("Title", window)
            imgui.CustomCheck(u8"Любить котов##someHiddenLabel", var1)
            imgui.CustomCheck(u8"Задавать нелепые вопросы", var2)
        imgui.End()
    end
)

uTHjOnu.gif
 

RTD

Потужно
Модератор
399
470
Описание: Один из кусков хука d3d9, который когда-то применял в других играх
Выложу тут потому что могу и потому что у муна пресент вызывается самым последних, в итоге все рисуется даже поверх консоли сампфункса, снипет меняет это поведение
Либу hooks брать тут https://www.blast.hk/threads/55743/
Можете использовать вместе с https://www.blast.hk/threads/13380/post-650507
Lua:
local ffi = require("ffi")
local hook = require("hooks")
do
    local org_addEventHandler = addEventHandler
    local hkPresentQueueu = {}
    function hkPresent(pDevice, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion)
        for i, f in ipairs(hkPresentQueueu) do
            f()
        end
        return hkPresent(pDevice, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion)
    end
    local D3D9Device = hook.vmt.new(ffi.cast('intptr_t*', 0xC97C28)[0]) --эти строчки вынести в main или куда там хотите чтобы хукалось самым последним
    hkPresent = D3D9Device.hookMethod('long(__stdcall*)(void*, void*, void*, void*, void*)', hkPresent, 17) --эти строчки вынести чтобы хукалось самым последним
    function addEventHandler(event, func)
        if event == "onD3DPresent" then
            table.insert(hkPresentQueueu, func)
        else
            return org_addEventHandler(event, func)
        end
    end
end
Пример использования:
Это не готовый код, если просто Ctrl+C Ctrl+V, то вас крашнет либо не будет работать потому что sf, moon и другие перезаписывают хук, по этому сделайте так чтобы хукалось после всего
Lua:
local ffi = require("ffi")
local hook = require("hooks")
do
    local org_addEventHandler = addEventHandler
    local hkPresentQueueu = {}
    function hkPresent(pDevice, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion)
        for i, f in ipairs(hkPresentQueueu) do
            f()
        end
        return hkPresent(pDevice, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion)
    end
    local D3D9Device = hook.vmt.new(ffi.cast('intptr_t*', 0xC97C28)[0]) --эти строчки вынести в main или куда там хотите чтобы хукалось самым последним
    hkPresent = D3D9Device.hookMethod('long(__stdcall*)(void*, void*, void*, void*, void*)', hkPresent, 17) --эти строчки вынести чтобы хукалось самым последним
    function addEventHandler(event, func)
        if event == "onD3DPresent" then
            table.insert(hkPresentQueueu, func)
        else
            return org_addEventHandler(event, func)
        end
    end
end
local imgui = require("mimgui")
imgui.OnFrame(function() return true end, function()
    imgui.Text("1")   
end)
До:
1637158612435.png


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

meowprd

Тот самый Котовский
Проверенный
1,278
720
Описание: Получает псевдо обороты двигателя (которые взяты из головы и приближены к реальности).
К примеру Infernus крутит двигатель до ~7300 об/мин, а Huntley до ~5100 об/мин
Код:

Lua:
function getEngineRpm(veh)
    local rpm = 0
    if veh then
        if isCarEngineOn(veh) then
            local speed = getCarSpeed(veh)*2
            if getCarCurrentGear(veh) > 0 then
                rpm = math.floor(((speed/getCarCurrentGear(veh))*300) + 0.5)
            else
                rpm = math.floor((speed*180) + 0.5)
            end
            if rpm < 650 then rpm = math.random(700, 725)
            elseif rpm >= 7900 then rpm = math.random(7900, 7950)
            end
        end
    end
    return rpm
end
Пример использования:
Lua:
function main()
    -- other code
    while true do
        wait(0)
        if isCharInAnyCar(PLAYER_PED) and getDriverOfCar(storeCarCharIsInNoSave(PLAYER_PED)) == PLAYER_PED then
            local car = storeCarCharIsInNoSave(PLAYER_PED)
            local rpm = getEngineRpm(car)
            print(rpm)
        end
    end
end

Или вариант реализации тут:
 

invilso.

Известный
259
89
Описание:
Генерация imgui интерфейса с помощью таблицы. Удобно делать всякие настройки скриптам.
Код:
Функция:
function imguiGenerateGUI(params)
    local generated = {}
    local params_model = {
        table = 'table', -- Сюда таблицу совать надо
        use_in_key = 'boolean', -- Тут ты говоришь юзать ли key родительского элемента (над потыкать)
        in_key = 'string', -- Задаешь вручную key родительского элемента (над потыкать)
        use_childs = 'boolean', -- Юзать ли imgui.Child
    }
    
    getChildY = function(table)
        local size = 0
        for key, value in pairs(table) do
            if type(value) == 'userdata' then
                size = size + 30
            else
                if type(value) == 'string' then
                    if not value:find('imgui%..+%(') then
                        size = size + 15
                        --imgui.Text(u8(value))
                    else
                        size = size + 25
                    end
                end
            end
            if type(value) == 'table' then
                if key ~= 'handler' then
                    size = size + getChildY(value)
                end
            end
        end
        return size
    end
    local child_size = getChildY(params.table)
    local iin = function(list, what_find, mode)
        if what_find and type(what_find) ~= 'table' then
            local set = {}
            for _, l in ipairs(list) do set[l] = true end
            return set[what_find] and true or false
        elseif type(what_find) == 'table' then
            if not mode or mode == false then
                local set = {}
                for _, l in ipairs(list) do set[l] = true end
                for _, l in ipairs(what_find) do if set[l] then return true end end
            elseif mode == true then
                local set = {}
                local res = nil
                for _, l in ipairs(list) do set[l] = true end
                for k,v in pairs(what_find) do if set[v] then res = true else res = false end end
                return res
            end
        end
    end
    local get_handler = function(table, text, value)
        if table.handler then
            if #table.handler.use_for > 0 then
                if iin(table.handler.use_for, text) then
                    table.handler.func({name = text, value = value})
                end
            else
                table.handler.func({name = text, value = value})
            end
        end
    end
    if params.use_childs then
        if child_size > 30 then
            table.insert(generated, {gui = function() imgui.BeginChild(tostring(params.table), imgui.ImVec2(0, child_size), true) end, handler = false})
            --imgui.BeginChild(tostring(params.table), imgui.ImVec2(0, child_size), true)
        end
    end
    for key, value in pairs(params.table) do
        local text = key
        if params.use_in_key and params.in_key ~= '' and child_size < 30 then
            text = params.in_key
        end
        if type(value) == 'userdata' then
            if type(value.v) == 'boolean' then
                table.insert(generated, {gui = function() return imgui.Checkbox(u8(text), value) end, handler = function() get_handler(params.table, text, value) end})
            elseif type(value.v) == 'string' then
                table.insert(generated, {gui = function() return imgui.InputText(u8(text), value) end, handler = function() get_handler(params.table, text, value) end})
            elseif type(value.v) == 'number' then
                if tostring(value.v):find('%.') then
                    table.insert(generated, {gui = function() return imgui.InputFloat(u8(text), value) end, handler = function() get_handler(params.table, text, value) end})
                else
                    table.insert(generated, {gui = function() return imgui.InputInt(u8(text), value) end, handler = function() get_handler(params.table, text, value) end})
                end
            end
        else
            if type(value) == 'string' then
                if value:find('imgui%..+%(') then
                    table.insert(generated, {gui = load('return '..value), handler = function() get_handler(params.table, text, nil) end})
                else
                    table.insert(generated, {gui = function() imgui.Text(u8(value)) end, handler = false})
                end
            end
        end
        if type(value) == 'table' then
            if key ~= 'handler' then
                local tables = imguiGenerateGUI({table = value, in_key = key, use_in_key = params.use_in_key, use_childs = params.use_childs})
                for k, gen in ipairs(tables) do
                    table.insert(generated, gen)
                end
            end
        end
    end
    if params.use_childs then
        if child_size > 30 then
            table.insert(generated, {gui = function() imgui.EndChild() end, handler = false})
            --imgui.EndChild()
        end
    end
    return generated
end

Пример использования:
Демо:
imgui = require 'imgui' --нужно без local
local encoding = require 'encoding'
encoding.default = 'CP1251'
u8 = encoding.UTF8

local window = imgui.ImBool(false)

local imgui_model = {
    {
        ['Кнопочка 1'] = imgui.ImBool(false),
    },
    { --Тут чилд не создаётся
        sl = 'imgui.SameLine()', -- тут можно записывать любую имгуи функцию
    },
    {
        ["Кнопочка 2"] = imgui.ImBool(false), -- Тут создатся чекбокс
    },
    {
        pw = 'imgui.PushItemWidth(80)', -- ставится ширина след элемента на 80
    },
    {
        ["Число 3"] = imgui.ImInt(5), -- Тут создатся поле ввода текста
        handler = { --Создавать обработчик не обязательно
            func = function(args)
                sampAddChatMessage('Изменено: '..args.name..': '..tostring(args.value.v), -1) -- вот что возвращается обработчиком: name - название с которым выводится элемент на который нажали, value - его значение в userdata
            end,
            use_for = {} -- обработчик юзается только для всей родительской таблицы
        }
    },
    {
        pw = 'imgui.PushItemWidth(50)', -- ставится ширина след элемента на 50
    },
    {
        ["Текст 4"] = imgui.ImBuffer(24), -- Тут создатся текстовое поле
        handler = { --Создавать обработчик не обязательно
            func = function(args)
                sampAddChatMessage('Изменено: '..args.name..': '..tostring(args.value.v), -1) -- вот что возвращается обработчиком: name - название с которым выводится элемент на который нажали, value - его значение в userdata
            end,
            use_for = {} -- обработчик юзается только для всей родительской таблицы
        }
    },
    { -- Я думаю вам понятно что эти 2 элемента будут в рандомном порядке?
        ["Кнопочка 5"] = imgui.ImBool(false),
        ["Кнопочка 5 (1)"] = imgui.ImBool(false), --тут не будет обработчика
        handler = { --Создавать обработчик не обязательно
            func = function(args)
                sampAddChatMessage('Изменено: '..args.name..': '..tostring(args.value.v), -1) -- вот что возвращается обработчиком: name - название с которым выводится элемент на который нажали, value - его значение в userdata
            end,
            use_for = {"Кнопочка 5"} -- обработчик юзается только для элемента с таким названием, в родительской таблице
        }
    },
    {
        pw = 'imgui.PushItemWidth(50)', -- ставится ширина след элемента на 50
    },
    {
        ['qqq'] = 'imgui.Button("qqq")', -- рисуется кнопка с таким названием, желательно key делать таким же как и текст в кнопке
        handler = { --Для кнопок, колапсов, и так далее, поддерживается обработчик, но value возвращает nil
            func = function(args)
                sampAddChatMessage('Нажата кнопка: '..args.name, -1) -- вот что возвращается обработчиком: name - название с которым выводится элемент на который нажали, value - nil так как это кнопка
            end,
            use_for = {}
        }
    }
}

function imgui.OnDrawFrame()
    if window.v then
        imgui.SetNextWindowSize(imgui.ImVec2(500, 300), imgui.Cond.FirstUseEver)
        imgui.Begin('Demo', window)
        local generated = imguiGenerateGUI({table = imgui_model, in_key = '', use_in_key = false, use_childs = true}) -- Возвращается таблица, ниже есть описание параметров
        for k, v in ipairs(generated) do
            if v.gui() then --Это гуи элемент
                if v.handler ~= false then --иногда нету обработчика, и возвращается false
                    print('handle')
                    v.handler() --А это обработчик, его нужно запускать
                end
            end
        end
        imgui.End()
    end
end

function main()
    while not isSampAvailable() do wait(100) end
    sampRegisterChatCommand('dgui', function() window.v = not window.v end)
    sampRegisterChatCommand('active_elements', function() showActiveElemets(imgui_model) end)
    while true do
        wait(0)
        imgui.Process = window.v
    end
end


function showActiveElemets(table)
    for k, val in pairs(table) do
        if type(val) == 'userdata' then
            if type(val.v) == 'boolean' then
                if val.v then
                    sampAddChatMessage('Активировано: '..tostring(k)..': '..tostring(val.v), -1)
                end
            end
        end
        if type(val) == 'table' then
            if key ~= 'handler' then
                showActiveElemets(val)
            end
        end
    end
end

function imguiGenerateGUI(params)
    local generated = {}
    local params_model = {
        table = 'table', -- Сюда таблицу совать надо
        use_in_key = 'boolean', -- Тут ты говоришь юзать ли key родительского элемента (над потыкать)
        in_key = 'string', -- Задаешь вручную key родительского элемента (над потыкать)
        use_childs = 'boolean', -- Юзать ли автоматические imgui.Child
    }
    
    getChildY = function(table)
        local size = 0
        for key, value in pairs(table) do
            if type(value) == 'userdata' then
                size = size + 30
            else
                if type(value) == 'string' then
                    if not value:find('imgui%..+%(') then
                        size = size + 15
                        --imgui.Text(u8(value))
                    else
                        size = size + 25
                    end
                end
            end
            if type(value) == 'table' then
                if key ~= 'handler' then
                    size = size + getChildY(value)
                end
            end
        end
        return size
    end
    local child_size = getChildY(params.table)
    local iin = function(list, what_find, mode)
        if what_find and type(what_find) ~= 'table' then
            local set = {}
            for _, l in ipairs(list) do set[l] = true end
            return set[what_find] and true or false
        elseif type(what_find) == 'table' then
            if not mode or mode == false then
                local set = {}
                for _, l in ipairs(list) do set[l] = true end
                for _, l in ipairs(what_find) do if set[l] then return true end end
            elseif mode == true then
                local set = {}
                local res = nil
                for _, l in ipairs(list) do set[l] = true end
                for k,v in pairs(what_find) do if set[v] then res = true else res = false end end
                return res
            end
        end
    end
    local get_handler = function(table, text, value)
        if table.handler then
            if #table.handler.use_for > 0 then
                if iin(table.handler.use_for, text) then
                    table.handler.func({name = text, value = value})
                end
            else
                table.handler.func({name = text, value = value})
            end
        end
    end
    if params.use_childs then
        if child_size > 30 then
            table.insert(generated, {gui = function() imgui.BeginChild(tostring(params.table), imgui.ImVec2(0, child_size), true) end, handler = false})
            --imgui.BeginChild(tostring(params.table), imgui.ImVec2(0, child_size), true)
        end
    end
    for key, value in pairs(params.table) do
        local text = key
        if params.use_in_key and params.in_key ~= '' and child_size < 30 then
            text = params.in_key
        end
        if type(value) == 'userdata' then
            if type(value.v) == 'boolean' then
                table.insert(generated, {gui = function() return imgui.Checkbox(u8(text), value) end, handler = function() get_handler(params.table, text, value) end})
            elseif type(value.v) == 'string' then
                table.insert(generated, {gui = function() return imgui.InputText(u8(text), value) end, handler = function() get_handler(params.table, text, value) end})
            elseif type(value.v) == 'number' then
                if tostring(value.v):find('%.') then
                    table.insert(generated, {gui = function() return imgui.InputFloat(u8(text), value) end, handler = function() get_handler(params.table, text, value) end})
                else
                    table.insert(generated, {gui = function() return imgui.InputInt(u8(text), value) end, handler = function() get_handler(params.table, text, value) end})
                end
            end
        else
            if type(value) == 'string' then
                if value:find('imgui%..+%(') then
                    table.insert(generated, {gui = load('return '..value), handler = function() get_handler(params.table, text, nil) end})
                else
                    table.insert(generated, {gui = function() imgui.Text(u8(value)) end, handler = false})
                end
            end
        end
        if type(value) == 'table' then
            if key ~= 'handler' then
                local tables = imguiGenerateGUI({table = value, in_key = key, use_in_key = params.use_in_key, use_childs = params.use_childs})
                for k, gen in ipairs(tables) do
                    table.insert(generated, gen)
                end
            end
        end
    end
    if params.use_childs then
        if child_size > 30 then
            table.insert(generated, {gui = function() imgui.EndChild() end, handler = false})
            --imgui.EndChild()
        end
    end
    return generated
end
 

THERION

Известный
Проверенный
88
327
Описание: Рисует текст с обводкой как у текстдравов (реализация одна и та же)
Код:
Lua:
local function render_text(font, text, x, y, color, outline, outline_color, ignore_colortags)
    if outline > 0 then -- outline (clockwise)
        renderFontDrawText(font, text, x, y + outline, outline_color, ignore_colortags)
        renderFontDrawText(font, text, x + outline, y + outline, outline_color, ignore_colortags)
        renderFontDrawText(font, text, x + outline, y, outline_color, ignore_colortags)
        renderFontDrawText(font, text, x + outline, y - outline, outline_color, ignore_colortags)
        renderFontDrawText(font, text, x, y - outline, outline_color, ignore_colortags)
        renderFontDrawText(font, text, x - outline, y - outline, outline_color, ignore_colortags)
        renderFontDrawText(font, text, x - outline, y, outline_color, ignore_colortags)
        renderFontDrawText(font, text, x - outline, y + outline, outline_color, ignore_colortags)
    end
    renderFontDrawText(font, text, x, y, color, ignore_colortags)
end
Использование:
Lua:
local font = renderCreateFont("Pricedown Rus", 50, 0)

-- где-то в бесконечном цикле
render_text(font, "$00000322", 500, 500, 0xFF36662C, 6, 0xFF000000)
Результат:
vEUxwTH.png
 
Последнее редактирование:

lorgon

Известный
656
271
Описание: Получает координаты точек лежащих на окружности
Источник
Lua:
function getPointOnCircle(x, y, radius, n, i) --x,y - центр окружности, radius - её радиус, n - кол-во точек, i - номер точки
  local x = math.cos(2 * math.pi * i / n) * radius + x
  local y = math.sin(2 * math.pi * i / n) * radius + y
  return x, y
end
Пример использования:
Lua:
function round(num, numDecimalPlaces)
  return tonumber(string.format("%." .. (numDecimalPlaces or 0) .. "f", num)) --return  float
end
function getPointOnCircle(x, y, radius, n, i)
  local x = math.cos(2 * math.pi * i / n) * radius + x
  local y = math.sin(2 * math.pi * i / n) * radius + y
  return x, y
end

local x1, y1 = getPointOnCircle(0, 0, 3, 4, 1) -- 1 точка
local x2, y2 = getPointOnCircle(0, 0, 3, 4, 2) -- 2 точка
-- Полученные результаты желательно округлять
print(round(x1, 3)..' / '..round(y1, 3)) --B(0; 3)
print(round(x2, 3)..' / '..round(y2, 3)) --C(-3; 0)
1639302700484.png
 
Последнее редактирование:

meowprd

Тот самый Котовский
Проверенный
1,278
720
Описание: Ищет и возвращает ид строки listitem для отправки sampSendDialogResponse (если такое было ранее не бейте тапками, вижу что много таких вопросов переодически задают)
(если ранее такое было - удалю)
Код:
Lua:
function getListItemNumberByText(text)
    local dtext = sampGetDialogText()
    local arr = {}
    for str in string.gmatch(dtext, "([^\n]+)") do
        table.insert(arr, str)
    end

    for i=1, #arr do
        if arr[i]:find(text) then
            return i-1
        end
    end
    return false
end
Пример использования:
Lua:
local result = getListItemNumberByText("Работа")
if result then
    sampAddChatMessage(result, -1)
end
 

mzxer

Активный
83
119

Описание:

получает информацию о SAMP/CRMP сервере прямым запросом
необходимо наличие библиотеки socket
последним аргументом передается максимальное время ожидания ответа от сервера, выраженное в миллисекундах
если сервер не ответит за это количество времени - функция вернёт nil. иначе - таблицу с результатом (см. 52-61 строчки кода)
запрос полностью идентичен запросу лаунчера, из-за чего данные приходят от сервера нормально (отличие от rakbot и подобных)
вызывайте функцию из потока lua_thread или функции main, иначе процесс будет подлагивать

UPD от 17.12.2021: доработка функции QueryServerInfo. теперь корректно обрабатываются пустые строки, возвращаемые сервером (строки с нулевой длиной)

Lua:
local ffi = require("ffi")
local bit = require("bit")
local socket = require("socket")

function QueryServerInfo(ip, port, timeout)
    local ret, response_data, isThread
    local s = socket.udp()
    s:setpeername(ip, port)
    s:settimeout(0)

    local request_data = ffi.new("char[11]", "\x53\x41\x4D\x50\x00\x00\x00\x00\x00\x00\x69")
    local wPort = ffi.new("uint16_t", port)
    local byteIp = {ip:match("(%d+)%.(%d+)%.(%d+)%.(%d+)")}

    for i = 1, 4 do request_data[3+i] = tonumber(byteIp[i]) or 0 end
    request_data[8] = tonumber(wPort)
    request_data[9] = bit.rshift(tonumber(wPort), 8)
 
    s:send(ffi.string(request_data, 11))

    timeout = os.clock() + (((timeout ~= nil) and timeout or 3000) / 1000)
    isThread = pcall(wait, 0)
    while response_data == nil and os.clock() < timeout do
        if isThread then wait(0) end
        response_data = s:receive()
    end

    if response_data and response_data:len() > 11 and response_data:sub(1, 4) == "\x53\x41\x4D\x50" then
        local szData = ffi.new("char[?]", 1024, response_data)
        for i = response_data:len(), 1023 do szData[i] = 0 end

        local parse_data = function(offs, size)
            if size <= 0 then return ffi.new("char[1]", 0) end -- new
         
            local ret = ffi.new("char[?]", size, 0)
            for i = 0, tonumber(size) - 1 do
                ret[i] = szData[i + offs]
            end
            return ret
        end

        local bytePassword = ffi.new("uint8_t", szData[11])
        local wOnlinePlayers = ffi.cast("uint16_t*", parse_data(12, 2))[0]
        local wMaxPlayers = ffi.cast("uint16_t*", parse_data(14, 2))[0]
        local iHostNameLen = ffi.cast("uint32_t*", parse_data(16, 4))[0]
        local szHostName = parse_data(20, iHostNameLen)
        local iGameModeLen = ffi.cast("uint32_t*", parse_data(iHostNameLen + 20, 4))[0]
        local szGameMode = parse_data(iHostNameLen + 24, iGameModeLen)
        local iLanguageLen = ffi.cast("uint32_t*", parse_data(iHostNameLen + iGameModeLen + 24, 4))[0]
        local szLanguage = parse_data(iHostNameLen + iGameModeLen + 28, iLanguageLen)

        ret = {
            password = (bytePassword ~= 0),
            players = {
                online = tonumber(wOnlinePlayers),
                max = tonumber(wMaxPlayers)
            },
            hostname = ffi.string(szHostName, iHostNameLen),
            gamemode = ffi.string(szGameMode, iGameModeLen),
            language = ffi.string(szLanguage, iLanguageLen)
        }
    end

    s:close()
    return ret
end

Пример использования:

Lua:
local ffi = require("ffi")
local bit = require("bit")
local socket = require("socket")

function QueryServerInfo(ip, port, timeout)
    local ret, response_data, isThread
    local s = socket.udp()
    s:setpeername(ip, port)
    s:settimeout(0)

    local request_data = ffi.new("char[11]", "\x53\x41\x4D\x50\x00\x00\x00\x00\x00\x00\x69")
    local wPort = ffi.new("uint16_t", port)
    local byteIp = {ip:match("(%d+)%.(%d+)%.(%d+)%.(%d+)")}

    for i = 1, 4 do request_data[3+i] = tonumber(byteIp[i]) or 0 end
    request_data[8] = tonumber(wPort)
    request_data[9] = bit.rshift(tonumber(wPort), 8)
 
    s:send(ffi.string(request_data, 11))

    timeout = os.clock() + (((timeout ~= nil) and timeout or 3000) / 1000)
    isThread = pcall(wait, 0)
    while response_data == nil and os.clock() < timeout do
        if isThread then wait(0) end
        response_data = s:receive()
    end

    if response_data and response_data:len() > 11 and response_data:sub(1, 4) == "\x53\x41\x4D\x50" then
        local szData = ffi.new("char[?]", 1024, response_data)
        for i = response_data:len(), 1023 do szData[i] = 0 end

        local parse_data = function(offs, size)
            if size <= 0 then return ffi.new("char[1]", 0) end -- new
         
            local ret = ffi.new("char[?]", size, 0)
            for i = 0, tonumber(size) - 1 do
                ret[i] = szData[i + offs]
            end
            return ret
        end

        local bytePassword = ffi.new("uint8_t", szData[11])
        local wOnlinePlayers = ffi.cast("uint16_t*", parse_data(12, 2))[0]
        local wMaxPlayers = ffi.cast("uint16_t*", parse_data(14, 2))[0]
        local iHostNameLen = ffi.cast("uint32_t*", parse_data(16, 4))[0]
        local szHostName = parse_data(20, iHostNameLen)
        local iGameModeLen = ffi.cast("uint32_t*", parse_data(iHostNameLen + 20, 4))[0]
        local szGameMode = parse_data(iHostNameLen + 24, iGameModeLen)
        local iLanguageLen = ffi.cast("uint32_t*", parse_data(iHostNameLen + iGameModeLen + 24, 4))[0]
        local szLanguage = parse_data(iHostNameLen + iGameModeLen + 28, iLanguageLen)

        ret = {
            password = (bytePassword ~= 0),
            players = {
                online = tonumber(wOnlinePlayers),
                max = tonumber(wMaxPlayers)
            },
            hostname = ffi.string(szHostName, iHostNameLen),
            gamemode = ffi.string(szGameMode, iGameModeLen),
            language = ffi.string(szLanguage, iLanguageLen)
        }
    end

    s:close()
    return ret
end

-- в случае игнора от сервера в течение 1 секунды - повторит попытку ещё 4 раза
function PrintServerInfo(ip, port)
    local current_attempt = 1

    ::label_try::
    local result = QueryServerInfo(ip, port, 1000)
    if result then
        print("Info about " .. ip .. ":")
        print("Password: " .. (result.password and "true" or "false"))
        print("Players: " .. result.players.online .. '/' .. result.players.max)
        print("Hostname: " .. result.hostname)
        print("Mode: " .. result.gamemode)
        print("Language: " .. result.language)
    else
        if current_attempt <= 5 then
            current_attempt = current_attempt + 1
            goto label_try
        end

        print("Error: cannot get info about " .. ip)
    end

    print()
end

function main()
    if not isSampLoaded() then return end
    while not isSampAvailable() do wait(100) end

    -- вызываем из main, игру не будет фризить во время вызовов
    PrintServerInfo("37.230.137.174", 7778)
    PrintServerInfo("185.169.134.4", 7777)
    PrintServerInfo("51.83.207.240", 7777)

    wait(-1)
end
126795

и какова гарантия что ты будешь каждый год платить за этот домен?
да хотя б месяц смог его продержать челик 😁
PkZSM.png
 

Вложения

  • image_2021-12-16_00-24-15.png
    image_2021-12-16_00-24-15.png
    8.3 KB · Просмотры: 2,048
Последнее редактирование:

leekyrave

Известный
419
226
Описание:
Кастомная функция для получения игроков в указанном радиусе, функция из коробки findAllCharsInSphere костыльная и может иногда не работать.

Код:

Lua:
function sampGetCharsInSphere(radius)
    local inSphere = {}
    if not radius then return {} end
    local Mx, My, Mz = getCharCoordinates(PLAYER_PED)
    for k,v in pairs(getAllChars()) do
        local x, y, z = getCharCoordinates(v)

        if getDistanceBetweenCoords3d(Mx, My, Mz, x, y, z) <= tonumber(radius) and v ~= 1 then
            local result, id = sampGetPlayerIdByCharHandle(v)

            if result then
                inSphere[#inSphere + 1] = id
            end
        end
    end

    return inSphere
end

Использование:
Lua:
inSpherePlayers = sampGetCharsInSphere(number)

if #inSpherePlayers > 0 then
    addonWindows['rslap'].v = true
else
    addonWindows['rslap'].v = false
    sampAddChatMessage('{F6361C}[Ошибка]{FFFFFF} Не найдено игроков в указанном радиусе.',-1)
end
 
Последнее редактирование: