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

chromiusj

модерирую шмодерирую
Модератор
5,970
4,295
описание: копирует все содержимое либо что-то одно на выбор по указанному пути, и копирует в указанный путь
код:
Lua:
function copyPath(src, dst)
    local function norm(p)
        return p:gsub("/", "\\"):gsub("\\+", "\\"):gsub("\\+$", ""):lower()
    end
    local nsrc, ndst = norm(src), norm(dst)
    if nsrc == ndst then
        return nil, "source and destination paths are the same"
    end
    if doesDirectoryExist(src) and ndst:sub(1, #nsrc+1) == nsrc.."\\" then
        return nil, "destination is inside source"
    end
    if doesFileExist(src) then
        local name = src:match("[^\\]+$")
        if doesDirectoryExist(dst) then
            dst = dst .. "\\" .. name
        elseif not doesFileExist(dst) then
            local last = dst:match("[^\\]+$") or ""
            if dst:sub(-1) == "\\" or not last:find("%.") then
                if not doesDirectoryExist(dst) and not createDirectory(dst) then
                    return nil, "cannot create destination directory"
                end
                dst = dst .. "\\" .. name
            end
        end
        local r, err = io.open(src, "rb"); if not r then return nil, "cannot open source: " .. tostring(err) end
        local data = r:read("*a"); r:close()
        local w; w, err = io.open(dst, "wb"); if not w then return nil, "cannot write destination: " .. tostring(err) end
        w:write(data); w:close()
        return true
    end
    if doesDirectoryExist(src) then
        if doesFileExist(dst) then
            return nil, "cannot copy directory into existing file"
        end
        if not doesDirectoryExist(dst) and not createDirectory(dst) then
            return nil, "cannot create destination directory"
        end
        local h, f = findFirstFile(src.."\\*")
        while f do
            if f ~= "." and f ~= ".." then
                local ok, err = copyPath(src.."\\"..f, dst.."\\"..f)
                if not ok then
                    findClose(h)
                    return nil, err
                end
            end
            f = findNextFile(h)
        end
        findClose(h)
        return true
    end
    return nil, "source not found"
end
пример использования:
Lua:
function main()
    while not isSampAvailable() do wait(0) end
    -- создаст backup\\EVSP.ini
    local ok, err = copyPath(getWorkingDirectory().."\\config\\EVSP.ini", getWorkingDirectory().."\\backup\\")
    print(ok and "OK (файл - папка)" or "Ошибка: "..err)
    -- создаст backup\\copy.ini
    ok, err = copyPath(getWorkingDirectory().."\\config\\EVSP.ini", getWorkingDirectory().."\\backup\\copy.ini")
    print(ok and "OK (файл - файл)" or "Ошибка: "..err)
    -- создаст backup\\nested\\EVSP.ini
    ok, err = copyPath(getWorkingDirectory().."\\config\\EVSP.ini", getWorkingDirectory().."\\backup\\nested\\")
    print(ok and "OK (файл - новая папка)" or "Ошибка: "..err)
    -- создаст backup_config\\(содержимое config)
    ok, err = copyPath(getWorkingDirectory().."\\config", getWorkingDirectory().."\\backup_config")
    print(ok and "OK (папка - папка)" or "Ошибка: "..err)
    -- создаст backup\\config\\(содержимое config)
    ok, err = copyPath(getWorkingDirectory().."\\config", getWorkingDirectory().."\\backup\\")
    print(ok and "OK (папка - внутрь папки)" or "Ошибка: "..err)
    wait(-1)
end
 
Последнее редактирование:

fsrxvdd

Активный
286
71
Описание: Функция для показа аризоновских уведомлений внизу экрана.
1759822472840.png

Пример использования:
Lua:
function main()
    while not isSampAvailable() do wait(0) end
    sampRegisterChatCommand('not', function() notif('success', 'Привет', 'Здравствуй', 3000) end)
    while true do
        wait(0)
    end
end
Код:
Lua:
---@param type string success, error, info, halloween
---@param title string any
---@param text string any
---@param time number ms
function notif(type, title, text, time)
    type = type or 'info'
    title = title or 'Заголовок'
    text = text or 'Текст'
    time = time or 2000
    local json = string.format('[%q,%q,%q,%d]', type, title, text, time)
    local code = "window.executeEvent('event.notify.initialize', `" .. json .. "`);"
    local bs = raknetNewBitStream()
    raknetBitStreamWriteInt8(bs, 17)
    raknetBitStreamWriteInt32(bs, 0)
    raknetBitStreamWriteInt16(bs, #code)
    raknetBitStreamWriteInt8(bs, 0)
    raknetBitStreamWriteString(bs, code)
    raknetEmulPacketReceiveBitStream(220, bs)
    raknetDeleteBitStream(bs)
end

за идею взял эту тему, потому что у меня не работало, поэтому и решил переписать сам
 

SigmaProHacker228Amogus

Участник
27
2
Описание: простенькая функция которая отталкивает вашего персонажа от стен, думаю может кому то пригодится где нибудь, уверен есть где улучшить можно
Пример использования:
Использование:
lua_thread.create(function ()
    AIwalk(true/false) -- укажите true чтобы включить, false - выключить
end)

Код:
Lua:
local antidirections = {
    forward = 83,
    left = 68,
    right = 65
}
local directions = {
    forward = false,
    left = false,
    right = false,
}

function AIwalk(state)
        while state do
            if state then
            wait(0) -- если хотите сделать так чтобы персонаж не был дерганный как в конвульсиях, то просто прибавьте задержки на ваше усмотрение
            local x,y,z = getCharCoordinates(PLAYER_PED)
           
            local tx,ty,tz = getOffsetFromCharInWorldCoords(PLAYER_PED, 0, 3, 0)
            local mx,my,mz = getOffsetFromCharInWorldCoords(PLAYER_PED, 3,0,0)
            local qx,qy,qz = getOffsetFromCharInWorldCoords(PLAYER_PED, -3, 0, 0)

            directions.forward = isLineOfSightClear(x,y,z,tx,ty,tz,true,true,false,true,false)
            directions.left = isLineOfSightClear(x,y,z,qx,qy,qz,true,true,false,true,false)
            directions.right = isLineOfSightClear(x,y,z, mx,my,mz, true, true, false, true,false)
           
            local walk = false
            for key, value in pairs(directions) do
                for k, v in pairs(antidirections) do
                    if value then
                        walk = false
                    end
                    if not value then
                        walk = true
                    end
                    setVirtualKeyDown(antidirections[key], walk)
                end
            end
        end
    end
end
 
Последнее редактирование:

kin4stat

mq-team · kin4@naebalovo.team
Всефорумный модератор
2,762
4,891
Описание: Функция для проверки валидности email адреса. Проверяет формат, длину, наличие доменной зоны, корректность символов и отсекает зарезервированные имена.
Код:
Lua:
function isValidEmail(email)
    if not email or type(email) ~= "string" then
        return false
    end

    email = email:gsub("^%s+", ""):gsub("%s+$", "")

    if #email > 254 then
        return false
    end

    local at_count = 0
    for i = 1, #email do
        if email:sub(i, i) == "@" then
            at_count = at_count + 1
        end
    end
    if at_count ~= 1 then
        return false
    end

    local local_part, domain = email:match("^([^@]+)@(.+)$")
    if not local_part or not domain then
        return false
    end

    if #local_part > 64 then
        return false
    end
    if not local_part:match("^[a-zA-Z0-9.!#$%%&'*+/=?^_`{|}~-]+$") then
        return false
    end
    if local_part:match("^%.") or local_part:match("%.$") then
        return false
    end
    if local_part:match("%.%.") then
        return false
    end

    if #domain > 253 then
        return false
    end
    if not domain:match("^[a-zA-Z0-9.-]+$") then
        return false
    end
    if domain:match("^%-") or domain:match("%-$") then
        return false
    end
    if domain:match("%-%-") then
        return false
    end
    if domain:match("%.%.") then
        return false
    end

    if not domain:match("%.") then
        return false
    end

    local tld = domain:match("%.([a-zA-Z0-9-]+)$")
    if not tld then
        return false
    end
    if #tld < 2 then
        return false
    end
    if tld:match("%d") then
        return false
    end

    local reserved = {
        "admin", "administrator", "postmaster", "hostmaster", "webmaster",
        "root", "null", "undefined", "test", "example", "invalid"
    }
    for _, name in ipairs(reserved) do
        if local_part:lower() == name then
            return false
        end
    end

    if email:match("nigerian") or email:match("viagra") or email:match("casino") then
        return false
    end

    local rfc_pattern = "^[a-zA-Z0-9.!#$%%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:%.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$"
  
    return email:match(rfc_pattern) ~= nil
end
Пример использования:
Lua:
print(isValidEmail("test@example.com")) -- true
print(isValidEmail("user.name@domain.co.uk")) -- true
print(isValidEmail("invalid@domain")) -- false
print(isValidEmail("user@.com")) -- false
print(isValidEmail("admin@company.com")) -- false
Не работает:


Lua:
print(isValidEmail("👉@👈")) -- false
print(isValidEmail("\"@\"@[@]")) -- false
print(isValidEmail("\"'()'\"(\"''\")@example.com")) -- false
print(isValidEmail("c̷̨̈́i̵̮̅l̶̠̐͊͝ȁ̷̠̗̆̍̍n̷͖̘̯̍̈͒̅t̶͍͂͋ř̵̞͈̓ȯ̷̯̠-̸͚̖̟͋s̴͉̦̭̔̆̃͒û̵̥̪͆̒̕c̸̨̨̧̺̎k̵̼͗̀s̸̖̜͍̲̈́͋̂͠@example.com")) -- false
Да, совет на будущее: если хотите проверять имейлы - не пытайтесь в регулярки, проиграете.
 
  • Эм
Реакции: The Spark

moreveal

Известный
974
704
Не работает:


Lua:
print(isValidEmail("👉@👈")) -- false
print(isValidEmail("\"@\"@[@]")) -- false
print(isValidEmail("\"'()'\"(\"''\")@example.com")) -- false
print(isValidEmail("c̷̨̈́i̵̮̅l̶̠̐͊͝ȁ̷̠̗̆̍̍n̷͖̘̯̍̈͒̅t̶͍͂͋ř̵̞͈̓ȯ̷̯̠-̸͚̖̟͋s̴͉̦̭̔̆̃͒û̵̥̪͆̒̕c̸̨̨̧̺̎k̵̼͗̀s̸̖̜͍̲̈́͋̂͠@example.com")) -- false
Да, совет на будущее: если хотите проверять имейлы - не пытайтесь в регулярки, проиграете.
и че не так в выводе, не догоняю
 

moreveal

Известный
974
704
Это валидные имейлы
ну вообще, если на практике встречаются долбоебские емайлы, а мы это отвергаем регуляркой (в каждом из юкзейсов которых емайл приводится чуть ли не как hello-world, потому что выигрыш от традиционных алгоритмов нагляднее) — это проблема экзотических клиентов, которые тянут тонны рудимента за собой, а не современного приложения которое отклонит какой-нибудь "👉@👈" бредовый

вообще, это первый стейж, очевидно что в своём сервисе не стоит доверять указанному ящику, пока чел не введёт код с него или тип того
 

kin4stat

mq-team · kin4@naebalovo.team
Всефорумный модератор
2,762
4,891
ну вообще, если на практике встречаются долбоебские емайлы, а мы это отвергаем регуляркой (в каждом из юкзейсов которых емайл приводится чуть ли не как hello-world, потому что выигрыш от традиционных алгоритмов нагляднее) — это проблема экзотических клиентов, которые тянут тонны рудимента за собой, а не современного приложения которое отклонит какой-нибудь "👉@👈" бредовый

вообще, это первый стейж, очевидно что в своём сервисе не стоит доверять указанному ящику, пока чел не введёт код с него или тип того
Я все еще не вижу применения этой хуйне в луа, поэтому это просто одна из причин доебаться была, да
 
  • Влюблен
  • Клоун
Реакции: sep и moreveal

moreveal

Известный
974
704
Я все еще не вижу применения этой хуйне в луа, поэтому это просто одна из причин доебаться была, да
в луа нельзя найти применение 90% 100% тому, что публикует этот человечек, поэтому это во внимание ваще не бралось, очень интересно что он там такого пишет, скоро сурсы машины времени на луа увидим
 
  • Нравится
Реакции: Corenale

SigmaProHacker228Amogus

Участник
27
2
Описание: функция которая позволяет плавно передвигать камеру на опеделённое кол-во градусов. Сохраняет нынешний угол так что подходить будет для скриптов в которых пользователь не двигает камеру самостоятельно.
Использование:
Код:
smoothCamera(angle) -- angle это параметр на сколько градусов надо повернуть нашу камеру

Код:
Lua:
local rad = {}

function smoothCamera(angle)
    
    lua_thread.create(function()
        
        local angle_rad = math.rad(angle)
        
        if #rad == 0 then
            local startX, startZ = 0, 0
            local targetZ = startZ + angle_rad
            
            steps = angle_rad > 10 and 80 or 40
            local step = angle_rad / steps
            local current = startZ
            
            while current < targetZ do
                wait(0)
                current = current + step
                
                local progress = current / angle_rad
                local xCurrent = -0.3 + progress * (-0.3)
                
                setCameraPositionUnfixed(xCurrent, current)
            end
            
            setCameraPositionUnfixed(-0.6, targetZ)
            table.insert(rad, targetZ)
            table.insert(rad, -0.6)
            
        else
            local startX, startZ = rad[2], rad[1]
            local targetZ = startZ + angle_rad
            
            steps = angle_rad > 8 and 120 or 30
            local step = angle_rad / steps
            local current = startZ
            
            while current < targetZ do
                wait(0)
                current = current + step
                
                local progress = (current - startZ) / angle_rad
                local xCurrent = -0.6 + progress * (0.3)
                
                setCameraPositionUnfixed(xCurrent, current)
            end
            
            setCameraPositionUnfixed(-0.3, targetZ)
            table.remove(rad, 2)
            table.remove(rad, 1)
            table.insert(rad, targetZ)
            table.insert(rad, -0.3)
        end
        
    end)
end
 
  • Эм
Реакции: Corenale

chromiusj

модерирую шмодерирую
Модератор
5,970
4,295
Описание: Простой прыжок кролика как в CS:GO
Код:
Lua:
require("moonloader")
local memory = require("memory")

function applyMovement(speed, height)
    local CPed = memory.getint32(0xB7CD98)
    if CPed == 0 or CPed == nil then return end

    if isKeyDown(VK_SPACE) then
        memory.setuint8(CPed + 0x42C, 0)
        memory.setuint8(CPed + 0x46A, 0)
        memory.setuint8(CPed + 0x46C, 0)

        local velocityZ = memory.getfloat(CPed + 0x4C)
        if velocityZ == 0.0 then
            memory.setfloat(CPed + 0x4C, height)
            memory.setint32(CPed + 0x15A, CPed)
        end

        local cameraAngle = memory.getfloat(0xB6F258) + math.pi / 2
        memory.setfloat(CPed + 0x44, -math.sin(cameraAngle) * speed)
        memory.setfloat(CPed + 0x48, math.cos(cameraAngle) * speed)
    end
end
Пример использования:
Lua:
local state = false

function main()
    while not isSampAvailable() do wait(0) end
    sampRegisterChatCommand("corenale", function()
        state = not state
        sampAddChatMessage(string.format("%s", state and "enabled! use the SPACE key" or "disabled"), -1)
    end)
    while true do wait(0)
        if state and not sampIsChatInputActive() and not sampIsDialogActive() and not sampIsCursorActive() and sampIsLocalPlayerSpawned() then
            applyMovement(0.4, 0.2)
        end
    end
end
 

chapo

tg/inst: @moujeek
Всефорумный модератор
9,203
12,535
Описание: Диаграмма в виде полосочки
Пример использования:
1761736992925.png

Lua:
local players = {};
local colorsNames = {
    [-1] = u8'Неизвестно',
    [368966908] = u8'Без организации',
    [2566951719] = u8'Grove Street',
    [2580667164] = u8'Los Santos Vagos',
    [2580283596] = u8'East Side Ballas',
    [2566979554] = u8'Varrios Los Aztecas',
    [2573625087] = u8'The Rifa',
    [2157523814] = u8'La Cosa Nostra',
    [2159694877] = u8'Warlock MC',
    [23486046] = u8'Night Wolves',
    [2150852249] = u8'Russian Mafia',
    [2157314562] = u8'Yakuza',
    [2160918272] = u8'Правительство',
    [2152104628] = u8'Страховая компания',
    [2150206647] = u8'Банк',
    [2164221491] = u8'Инструктор',
    [2164227710] = u8'Больница',
    [2157536819] = u8'Армия/ТСР',
    [2164228096] = u8'TV студия',
    [2164212992] = u8'Пожарный',
    [2147502591] = u8'Полиция'
};

local function getPlayersColorsStatistics()
    local function explodeArgb(argb)
        local a = bit.band(bit.rshift(argb, 24), 0xFF)
        local r = bit.band(bit.rshift(argb, 16), 0xFF)
        local g = bit.band(bit.rshift(argb, 8), 0xFF)
        local b = bit.band(argb, 0xFF)
        return a, r, g, b
    end
    local result, colors, totalPlayers = {}, {}, 0;
    for id = 0, 1003 do
        if (sampIsPlayerConnected(id)) then
            totalPlayers = totalPlayers + 1;
            local playerColor = sampGetPlayerColor(id);
            local key = colorsNames[playerColor] and playerColor or -1;
            colors[key] = (colors[key] or 0) + 1;
        end
    end
    for color, playersCount in pairs(colors) do
        local a, r, g, b = explodeArgb(color);
        table.insert(result, {
            label = colorsNames[color] or u8'Неизвестно',
            color = imgui.ImVec4(r / 255, g / 255, b / 255, 1),
            precent = (playersCount / totalPlayers) * 100
        });
    end
    return result;
end

-- Frame
imgui.Text(u8'Игроки в организциях');
imgui.PushStyleColor(imgui.Col.ChildBg, imgui.ImVec4(1, 1, 1, 0.1));
imgui.DiagramBar(
    imgui.GetWindowWidth() - 20,
    10,
    players,
    true
);
imgui.PopStyleColor();
if (imgui.Button('Update')) then
    players = getPlayersColorsStatistics();
end
Код:
Lua:
---@param width number
---@param barHeight number
---@param bars {label: string, precent: number, color: ImVec4}[]
---@param drawLabels boolean
function imgui.DiagramBar(width, barHeight, bars, drawLabels)
    local style = imgui.GetStyle();
    local dl = imgui.GetWindowDrawList();
    local barPos = imgui.GetCursorScreenPos();
    local barSize = imgui.ImVec2(width, barHeight);

    imgui.Dummy(barSize);
    dl:AddRectFilled(barPos, barPos + barSize, imgui.GetColorU32(imgui.Col.FrameBg), style.FrameRounding);

    local currentPrecent, onePrecentSize = 0, width / 100;
    for index, bar in ipairs(bars) do
        local startPos = barPos + imgui.ImVec2(currentPrecent * onePrecentSize, 0);
        local endPos = barPos + imgui.ImVec2((currentPrecent + bar.precent) * onePrecentSize, barHeight);
        local roundingCorners = currentPrecent == 0 and 1 + 4 or (currentPrecent + bar.precent >= 100 and 2 + 8 or 0);
        dl:AddRectFilled(
            startPos,
            endPos,
            imgui.GetColorU32Vec4(bar.color),
            style.FrameRounding,
            roundingCorners
        );
        if (not imgui.IsAnyItemHovered() and imgui.IsMouseHoveringRect(startPos, endPos)) then
            dl:AddRect(startPos, endPos, imgui.GetColorU32(imgui.Col.Border), style.FrameRounding, roundingCorners, 2);
            imgui.BeginTooltip();
            imgui.TextColored(bar.color, ('%s - %d%%%%'):format(bar.label, bar.precent));
            imgui.EndTooltip();
        end
        if (drawLabels) then
            imgui.PushStyleColor(imgui.Col.Text, bar.color);
            imgui.Bullet();
            imgui.PopStyleColor();
            imgui.SameLine();
            local x = imgui.GetCursorPosX() + imgui.CalcTextSize(bar.label).x;
            imgui.Text(bar.label);

            local nextBar = bars[index + 1];
            if (nextBar) then
                local nextLabelSize = imgui.CalcTextSize(nextBar.label).x + 5 + style.ItemSpacing.x * 2;
                if (x + nextLabelSize < imgui.GetContentRegionMax().x - style.WindowPadding.x) then
                    imgui.SameLine();
                end
            end
        end
        currentPrecent = currentPrecent + bar.precent;
    end
end
 

pathtohell

Участник
14
57
Описание: Голографический радар для отображения игроков в радиусе с анимированным сканированием и подсветкой ближайших целей.
Код:
Lua:
local imgui = require("mimgui")

local radarState = {
    currentTime = os.clock(),
    lastUpdateTime = os.clock(),
    rotationAngle = 0,
    sweepProgress = 0
}

local function createColor(red, green, blue, alpha)
    return imgui.ColorConvertFloat4ToU32(imgui.ImVec4(red, green, blue, alpha or 1.0))
end

local function worldToRadarCoordinates(centerX, centerY, radarSize, deltaX, deltaY, maximumRange, rotation)
    local angle = math.atan2(deltaY, deltaX) - rotation
    local normalizedDistance = math.sqrt(deltaX * deltaX + deltaY * deltaY) / maximumRange
    local radarDistance = normalizedDistance * (radarSize * 0.5)
    
    local positionX = centerX + math.cos(angle) * radarDistance
    local positionY = centerY + math.sin(angle) * radarDistance
    
    return positionX, positionY
end

local function drawSoftGlow(drawList, centerX, centerY, baseRadius, red, green, blue, alpha)
    for layer = 0, 2 do
        local currentRadius = baseRadius + layer * 1.5
        local layerAlpha = alpha * (0.6 - layer * 0.2)
        drawList:AddCircleFilled(
            imgui.ImVec2(centerX, centerY),
            currentRadius,
            createColor(red, green, blue, layerAlpha),
            32
        )
    end
end

---@param size number Размер радара в пикселях
---@param players table[] Список игроков {id, name, deltaX, deltaY, distance}
---@param range number Дальность сканирования в метрах
---@param opacity number Прозрачность от 0.0 до 1.0
---@param scale number Масштаб радара
function imgui.HolographicRadar(size, players, range, opacity, scale)
    local io = imgui.GetIO()
    local screenWidth = io.DisplaySize.x
    local screenHeight = io.DisplaySize.y

    local currentTime = os.clock()
    local deltaTime = currentTime - radarState.lastUpdateTime
    radarState.lastUpdateTime = currentTime
    
    radarState.rotationAngle = (radarState.rotationAngle + deltaTime * 0.35) % (math.pi * 2)
    radarState.sweepProgress = (radarState.sweepProgress + deltaTime * 0.85) % 1.0

    local drawList = imgui.GetBackgroundDrawList()
    local radarSize = size * (scale or 1.0)
    local radarCenterX = screenWidth - radarSize / 2 - 40
    local radarCenterY = screenHeight - radarSize / 2 - 40
    local currentOpacity = opacity or 0.95

    drawList:AddCircleFilled(
        imgui.ImVec2(radarCenterX, radarCenterY),
        radarSize / 2 + 12,
        createColor(0.02, 0.03, 0.05, 0.85 * currentOpacity),
        90
    )

    for ringIndex = 1, 3 do
        local ringRadius = (radarSize / 2) * (ringIndex / 3)
        local ringAlpha = 0.08 + (ringIndex * 0.03)
        drawList:AddCircle(
            imgui.ImVec2(radarCenterX, radarCenterY),
            ringRadius,
            createColor(0.1, 0.8, 1.0, ringAlpha * currentOpacity),
            90,
            1.6
        )
    end

    local currentAngle = radarState.rotationAngle
    for beamIndex = 0, 20 do
        local beamAngle = currentAngle + (beamIndex / 20) * 0.8
        local beamEndX = radarCenterX + math.cos(beamAngle) * (radarSize / 2)
        local beamEndY = radarCenterY + math.sin(beamAngle) * (radarSize / 2)
        local beamAlpha = 0.35 - (beamIndex * 0.015)
        
        drawList:AddLine(
            imgui.ImVec2(radarCenterX, radarCenterY),
            imgui.ImVec2(beamEndX, beamEndY),
            createColor(0.1, 0.9, 1.0, beamAlpha * currentOpacity),
            1.4
        )
    end

    local pulseRadius = (radarSize / 2) * radarState.sweepProgress
    local pulseAlpha = 0.25 * (1 - radarState.sweepProgress)
    drawList:AddCircle(
        imgui.ImVec2(radarCenterX, radarCenterY),
        pulseRadius,
        createColor(0.2, 0.9, 1.0, pulseAlpha * currentOpacity),
        80,
        2.5
    )

    local centerPulse = 0.8 + 0.2 * math.sin(currentTime * 3)
    drawList:AddCircleFilled(
        imgui.ImVec2(radarCenterX, radarCenterY),
        4 * centerPulse,
        createColor(0.9, 1.0, 1.0, 0.9 * currentOpacity),
        16
    )
    
    drawList:AddCircle(
        imgui.ImVec2(radarCenterX, radarCenterY),
        6 * centerPulse,
        createColor(0.1, 0.9, 1.0, 0.6 * currentOpacity),
        16,
        1.5
    )

    local nearestPlayerId = players[1] and players[1].id

    for _, player in ipairs(players) do
        local playerX, playerY = worldToRadarCoordinates(
            radarCenterX, radarCenterY, radarSize,
            player.deltaX, player.deltaY,
            range, radarState.rotationAngle
        )

        local glowIntensity = (player.id == nearestPlayerId) and 1.2 or 1.0
        drawSoftGlow(drawList, playerX, playerY, 3 * glowIntensity, 0.2, 0.9, 1.0, 0.7 * currentOpacity)

        drawList:AddCircleFilled(
            imgui.ImVec2(playerX, playerY),
            2.2 * glowIntensity,
            createColor(0.9, 1.0, 1.0, 1.0 * currentOpacity),
            22
        )

        local playerInfo = player.name .. " (" .. math.floor(player.distance) .. "m)"
        drawList:AddText(
            imgui.ImVec2(playerX + 6, playerY - 6),
            createColor(0.9, 1.0, 1.0, 0.95 * currentOpacity),
            playerInfo
        )
    end
end
Пример использования:
Lua:
local radarConfig = {
    isEnabled = imgui.new.bool(true),
    detectionRange = imgui.new.float(180.0),
    interfaceOpacity = imgui.new.float(0.95),
    displayScale = imgui.new.float(1.32)
}

local function getNearbyPlayers(range)
    local players = {}
    local playerX, playerY = getCharCoordinates(PLAYER_PED)
    
    for id = 0, sampGetMaxPlayerId(true) do
        local streamed, ped = sampGetCharHandleBySampPlayerId(id)
        if streamed and not sampIsPlayerPaused(id) and not isCharDead(ped) then
            local targetX, targetY = getCharCoordinates(ped)
            local deltaX = targetX - playerX
            local deltaY = targetY - playerY
            local distance = math.sqrt(deltaX * deltaX + deltaY * deltaY)
            
            if distance <= range then
                table.insert(players, {
                    id = id,
                    name = sampGetPlayerNickname(id),
                    deltaX = deltaX,
                    deltaY = deltaY,
                    distance = distance
                })
            end
        end
    end
    
    table.sort(players, function(a, b)
        return a.distance < b.distance
    end)
    
    return players
end

imgui.OnFrame(function() return radarConfig.isEnabled[0] end, function()
    local players = getNearbyPlayers(radarConfig.detectionRange[0])
    imgui.HolographicRadar(250, players, radarConfig.detectionRange[0], radarConfig.interfaceOpacity[0], radarConfig.displayScale[0])
end)
Как выглядит:
radar_demo.gif
 

kyrtion

Известный
1,339
508
for id = 0, sampGetMaxPlayerId(true) do
local streamed, ped = sampGetCharHandleBySampPlayerId(id)
if streamed and not sampIsPlayerPaused(id) and not isCharDead(ped) then
local targetX, targetY = getCharCoordinates(ped)
local deltaX = targetX - playerX
local deltaY = targetY - playerY
local distance = math.sqrt(deltaX * deltaX + deltaY * deltaY)

if distance <= range then
table.insert(players, {
id = id,
name = sampGetPlayerNickname(id),
deltaX = deltaX,
deltaY = deltaY,
distance = distance
})
end
end
end

table.sort(players, function(a, b)
return a.distance < b.distance
end
Сразу замечу. Для оптимизации достаточно проследить на получение синхронизация и вход/выход в стрим через SAMP.Lua