площадь текстдрава

chromiusj

модерирую шмодерирую
Автор темы
Модератор
5,986
4,298
Версия MoonLoader
.026-beta
Привет, имеется рабочей слепок подобного функционала, но имеются вопросы к нему насчет погрешности:
1. Можно ли её уменьшить? (если таковая конечно имеется, в целом все выглядит нормально)
2. Есть ли более простое решение, о котором, я возможно не догадываюсь? (желательно без использования хуков, и прочего взаимодействия с памятью, либо же использовать внутренний функционал)
Примерно говорю об этом: https://sampforum.blast.hk/showthread.php?tid=618883
Оно разумеется работает, и даже хорошо:
Lua:
local BASE_HEIGHT = 13.5

local charWidths = {
    0,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
    15,9,17,27,20,34,23,12,12,12,21,20,12,14,12,15,23,15,21,21,21,21,21,21,20,21,12,12,24,24,24,19,
    10,22,19,19,22,16,19,24,22,11,16,21,15,28,24,27,20,25,19,19,18,23,23,31,23,19,21,21,13,35,11,21,
    10,19,20,14,20,19,13,20,19,9,9,19,9,29,19,21,19,19,15,15,14,18,19,27,20,20,17,21,17,20,15,15,
    22,22,22,22,29,19,16,16,16,16,11,11,11,11,27,27,27,27,23,23,23,23,20,19,19,19,19,30,14,19,19,19,
    19,9,9,9,9,21,21,21,21,18,18,18,18,24,19,19,20,18,19,19,21,19,19,19,19,19,16,19,19,19,20,19,
    16,19,19,9,19,20,14,29,19,19,19,19,19,19,21,19,20,32,21,19,19,19,19,19,19,29,19,19,19,19,19,9,
    9,9,9,19,19,19,19,19,19,19,19,19,21,19,10,9,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20
}

function colorize(id)
    local h = (id * 137.508) % 360
    local c = 0.8 * 0.7
    local x = c * (1 - math.abs((h/60)%2 - 1))
    local m = 0.8 - c
    local r,g,b=0,0,0
    if h<60 then r,g,b=c,x,0 elseif h<120 then r,g,b=x,c,0 elseif h<180 then r,g,b=0,c,x
    elseif h<240 then r,g,b=0,x,c elseif h<300 then r,g,b=x,0,c else r,g,b=c,0,x end
    r,g,b=(r+m)*255,(g+m)*255,(b+m)*255
    return bit.bor(0xFF000000, bit.lshift(r,16), bit.lshift(g,8), b)
end

function measureText(text, prop, letX, letY)
    local t = text:gsub("{......}", "")
    local lines = select(2, t:gsub("n","")) + 1
    local w = 0
    if prop == 0 then
        local longest = 0
        for s in t:gmatch("[^\n]+") do
            longest = math.max(longest, #s * 20)
        end
        w = longest
    else
        local longest = 0
        for s in t:gmatch("[^\n]+") do
            local lw = 0
            for i = 1, #s do
                lw = lw + (charWidths[s:byte(i)+1] or 20)
            end
            longest = math.max(longest, lw)
        end
        w = longest
    end
    local h = (lines == 1) and (letY * BASE_HEIGHT) or (lines * letY * BASE_HEIGHT * 1.35)
    return w, h, lines
end

function main()
    if not isSampLoaded() or not isSampfuncsLoaded() then return end
    while not isSampAvailable() do wait(100) end
    while true do
        wait(0)
        for id = 0, 2304 do
            if sampTextdrawIsExists(id) then
                local text = sampTextdrawGetString(id)
                local font = sampTextdrawGetStyle(id)
                local x, y = sampTextdrawGetPos(id)
                local letX, letY = sampTextdrawGetLetterSizeAndColor(id)
                local align = sampTextdrawGetAlign(id)
                local box, _, sizeX, sizeY = sampTextdrawGetBoxEnabledColorAndSize(id)
                local outline = sampTextdrawGetOutlineColor(id)
                local prop = sampTextdrawGetProportional(id)
                local w, h = 0, 0
                local fx, fy = x, y
                if font == 4 or font == 5 then
                    w, h = sizeX, sizeY
                    if align == 2 then fx = x - w/2 elseif align == 3 then fx = x - w end
                else
                    local tw, th = measureText(text, prop, letX, letY)
                    h = th
                    if box == 1 then
                        if align == 1 then w = sizeX - x end
                        if align == 2 then w = tw * letX + outline end
                        if align == 3 then w = x - sizeX; fx = sizeX end
                        if w <= 1 then w = tw * letX + outline end
                    else
                        w = tw * letX + outline
                        if align == 2 then fx = x - w/2 elseif align == 3 then fx = x - w end
                    end
                end
                if w > 0.5 and h > 0.5 and w < 2000 then
                    local sx1, sy1 = convertGameScreenCoordsToWindowScreenCoords(fx, fy)
                    local sx2, sy2 = convertGameScreenCoordsToWindowScreenCoords(fx+w, fy+h)
                    local sw, sh = sx2 - sx1, sy2 - sy1
                    local col = colorize(id)
                    renderDrawBox(sx1, sy1, sw, 1, col)
                    renderDrawBox(sx1, sy1+sh-1, sw, 1, col)
                    renderDrawBox(sx1, sy1, 1, sh, col)
                    renderDrawBox(sx1+sw-1, sy1, 1, sh, col)
                    renderDrawBox(sx1, sy1, sw, sh, bit.band(col,0x40FFFFFF))
                end
            end
        end
    end
end
1763929324843.png
 
Последнее редактирование:
  • Нравится
  • Злость
Реакции: #Northn и Vespan

Tema05

Известный
1,634
545
Это конечно всё хорошо, но ты используешь lua. Думаю многие сталкивались с тем, что если через print вывести координаты текстдравов, а потом вставляешь это число в код хука для проверки и координаты не сходятся. Я так понимаю тебя беспокоит именно такая погрешность. lua язык высокого уровня и точность float значений им ограничена. Если ты хочешь прям идеально точно всё рассчитывать без заморочек в ffi, а скорее всего без dll модуля тебе не обойтись.

По поводу конкретно шрифтов, там столько подводных камней, что кашмар. Я когда для imgui пытался идеально вплоть до сотых пикселей выровнять текст просто забил хуй и заревёрсил все муновские функции, функции самой игры и библиотек, посмотрел досконально как там что высчитывается, вынес всю логику вычислений в dllку откуда ещё дополнительно дёргаю оригинальные функции и только после этого всё встало идеально вплоть до полупрозрачности теней. (это надо было для реализации динамического изменения размера шрифтов без округления)
 
Последнее редактирование:

chromiusj

модерирую шмодерирую
Автор темы
Модератор
5,986
4,298
Это конечно всё хорошо, но ты используешь lua. Думаю многие сталкивались с тем, что если через print вывести координаты текстдравов, а потом вставляешь это число в код хука для проверки и координаты не сходятся. Я так понимаю тебя беспокоит именно такая погрешность. lua язык высокого уровня и точность float значений им ограничена. Если ты хочешь прям идеально точно всё рассчитывать без заморочек в ffi, а скорее всего без dll модуля тебе не обойтись.

По поводу конкретно шрифтов, там столько подводных камней, что кашмар. Я когда для imgui пытался идеально вплоть до сотых пикселей выровнять текст просто забил хуй и вынес всю логику вычислений в dllку откуда ещё дополнительно дёргаю оригинальные функции
я уже попробовал вычислять значения через CFont(SetScale,Justify, etc), но не особо хочется с этим возиться, учитывая что адреса и так на руках, в целом, немного перебрав операции, понял, что вычисляю длину уже более менее нормально, но с высотой хотелось бы сделать еще лучше
1763994073896.png

1763991646389.png


Lua:
local charWidths = {
    0,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
    15,9,17,27,20,34,23,12,12,12,21,20,12,14,12,15,23,15,21,21,21,21,21,21,20,21,12,12,24,24,24,19,
    10,22,19,19,22,16,19,24,22,11,16,21,15,28,24,27,20,25,19,19,18,23,23,31,23,19,21,21,13,35,11,21,
    10,19,20,14,20,19,13,20,19,9,9,19,9,29,19,21,19,19,15,15,14,18,19,27,20,20,17,21,17,20,15,15,
    22,22,22,22,29,19,16,16,16,16,11,11,11,11,27,27,27,27,23,23,23,23,20,19,19,19,19,30,14,19,19,19,
    19,9,9,9,9,21,21,21,21,18,18,18,18,24,19,19,20,18,19,19,21,19,19,19,19,19,16,19,19,19,20,19,
    16,19,19,9,19,20,14,29,19,19,19,19,19,19,21,19,20,32,21,19,19,19,19,19,19,29,19,19,19,19,19,9,
    9,9,9,19,19,19,19,19,19,19,19,19,21,19,10,9,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20
}

local BASE_HEIGHT = 12.75

local function colorize(id)
    local h = (id * 137.508) % 360
    local c = 0.8 * 0.7
    local x = c * (1 - math.abs((h/60)%2 - 1))
    local m = 0.8 - c
    local r,g,b=0,0,0
    if h<60 then r,g,b=c,x,0 elseif h<120 then r,g,b=x,c,0 elseif h<180 then r,g,b=0,c,x
    elseif h<240 then r,g,b=0,x,c elseif h<300 then r,g,b=x,0,c else r,g,b=c,0,x end
    r,g,b=(r+m)*255,(g+m)*255,(b+m)*255
    return bit.bor(0xFF000000, bit.lshift(r,16), bit.lshift(g,8), b)
end

local function getLines(text)
    text = text:gsub("{%x%x%x%x%x%x}", "")
    text = text:gsub("~n~", "\n")
    local t = {}
    for line in text:gmatch("[^\n]+") do
        t[#t+1] = line
    end
    return (#t > 0) and t or { " " }
end

local function calcTextSize(text, prop, letX, letY, outline, shadow)
    local lines = getLines(text)
    local maxWidth = 0
    if prop == 0 then
        for _, line in ipairs(lines) do
            local w = #line * 20
            if w > maxWidth then maxWidth = w end
        end
    else
        for _, line in ipairs(lines) do
            local w = 0
            for i = 1, #line do
                w = w + (charWidths[line:byte(i)+1] or 20)
            end
            if w > maxWidth then maxWidth = w end
        end
    end
    local lineCount = #lines
    local lineHeight = BASE_HEIGHT * letY
    local height = (lineCount == 1) and lineHeight or (lineCount * lineHeight)
    local os = 0
    if outline > 0 then os = os + outline end
    if shadow  > 0 then os = os + shadow  end
    return maxWidth * letX + os * 2, height - 1
end

local function computeTextdrawRect(id)
    local text  = sampTextdrawGetString(id)
    local font  = sampTextdrawGetStyle(id)
    local x, y  = sampTextdrawGetPos(id)
    local letX, letY = sampTextdrawGetLetterSizeAndColor(id)
    local align = sampTextdrawGetAlign(id)
    local box, _, boxX, boxY = sampTextdrawGetBoxEnabledColorAndSize(id)
    local outline,_ = sampTextdrawGetOutlineColor(id)
    local shadow,_  = sampTextdrawGetShadowColor(id)
    local prop = sampTextdrawGetProportional(id)
    if font == 4 or font == 5 then
        local w = (boxX > 1) and boxX or 1
        local h = (boxY > 1) and boxY or 1
        if align == 2 then x = x - w / 2
        elseif align == 3 then x = x - w end
        return x, y, w, h
    end
    local w, h = calcTextSize(text, prop, letX, letY, outline, shadow)
    if box == 1 then
        if boxY > 1 then h = boxY end
        if align == 1 then
            w = boxX - x
        elseif align == 2 then
            w = boxX
            x = x - w / 2
        elseif align == 3 then
            w = x - boxX
            x = boxX
        end
    else
        if align == 2 then x = x - w / 2
        elseif align == 3 then x = x - w  end
    end
    return x, y, w, h
end

function main()
    if not isSampLoaded() or not isSampfuncsLoaded() then return end
    while not isSampAvailable() do wait(100) end
    while true do
        wait(0)
        for id = 0, 2304 do
            if sampTextdrawIsExists(id) then
                local fx, fy, w, h = computeTextdrawRect(id)
                if w > 0.5 and h > 0.5 and w < 4000 then
                    local sx1, sy1 = convertGameScreenCoordsToWindowScreenCoords(fx, fy)
                    local sx2, sy2 = convertGameScreenCoordsToWindowScreenCoords(fx + w, fy + h)
                    local sw, sh = sx2 - sx1, sy2 - sy1
                    local col = colorize(id)
                    renderDrawBox(sx1, sy1, sw, 1, col)
                    renderDrawBox(sx1, sy1 + sh - 1, sw, 1, col)
                    renderDrawBox(sx1, sy1, 1, sh, col)
                    renderDrawBox(sx1 + sw - 1, sy1, 1, sh, col)
                    renderDrawBox(sx1, sy1, sw, sh, bit.band(col, 0x40FFFFFF))
                end
            end
        end
    end
end