Добавлен , опубликован
Алгоритмы, Наработки и Способности
Способ реализации:
Lua
Тип:
Наработка
Версия Warcraft:
1.26+

Предыстория

В те далёкие времена, когда динозавры ходили по планете и изучали gui, внезапно оказалось, что спустя некоторое время карты начинали жутко тормозить. Коллективным разумом были найдены странные зверьки - утечки.
Вариант борьбы с ними был прост - обнулять локальные переменные с типом handle. Только вот узнать на сколько протёк код и стоит ли бежать и полностью его переписывать можно было по косвенным причинам. Пока не изобрели...

Handle Counter

Идея была проста - необходимо посчитать все handle. Но игра напрямую не предоставляла эту возможность, но у handle была интересная особенность - GetHandleId возвращала номер handle который отличался от предыдущего на единицу, а удалённые handle переиспользовались. Посему если создать в игре достаточное количество handle, чтоб перекрыть дырки в последовательности номеров, то вызвав GetHandleId и использовав нехитрую математику, можно узнать их количество.
И все начали дружно считать handle.
Выглядело это примерно так:
library HandleCounter

globals
    private constant integer safety = 50
endglobals

function CountHandles takes nothing returns integer
    local integer i = 0
    local integer i2 = 0
    local integer space = 0
    local integer space2 = 0
    local integer count = 0
    local location array loc
    local integer hid = 0
    local integer hid2
    loop
        set loc[i] = Location(0., 0.)
        set hid2 = GetHandleId(loc[i]) - 0x100000
        if hid2 == hid + 1 or hid == 0 then
            set space = space + 1
            set space2 = space2 + 1
        else
            set space2 = 0
        endif
        set hid = hid2
        set i = i + 1
        set count = hid
        exitwhen space2 == safety
    endloop
    loop
        exitwhen i2 > i
        call RemoveLocation(loc[i2])
        set loc[i2] = null
        set i2 = i2 + 1
    endloop
    return count - space - safety - 1
endfunction

endlibrary
Вы наверно часто встречали такую табличку в публикациях способностей. Но была одна проблема - точность оставляла желать лучшего и позволял понять происходящее только в первом приближении. Да и в карте мог использоваться Leaderboard, что затрудняло тестирование. Пока не изобрели...

UjAPI

Идея была ещё проще предыдущей - создать свой лаунчер и дописать недостающие функции. И одной из первых была реализована GetHandleCount, которая брала значение напрямую из движка игры исключая любые неточности. Что позволило более эффективно тестировать свои карты, чтоб исключить дискомфорт игроков на поздней стадии игры.
Оставалась только одна проблема - JNGP, запущенный без лаунчера, отказывался сохранять карты с активной функцией GetHandleCount, а каждый раз копировать код в карту накладною. Мы ценим ваше время.
Тут на помощь пришёл Warcraft III - Lua и картина сразу сложилась - для его работы в корне карты должен быть файл war3map.lua, который игра без лаунчера просто проигнорирует.
Поэтому просто импортируем в корень карты war3map.lua, удаляем war3mapImported\ из пути и наслаждаемся красивым и аккуратным фреймом:
Слева у него количество handle, а справа количество секунд, прошедших с начала игры.
Если же вы захотите использовать UjAPI + Warcraft III - Lua на постоянной основе, то можете воспользоваться инструкцией, а потом добавить код файла куда вашей душеньке мятежной будет угодно.
war3map.lua
TimerStart(CreateTimer(), 0, false, function()
    DestroyTimer(GetExpiredTimer())

    local gameUi = GetOriginFrame(ORIGIN_FRAME_GAME_UI, 0)
    local menu = CreateFrame('LoadingPlayerSlot', gameUi, 0, 0)
    SetFrameSize(menu, .16, .03)
    FRAMEPOINT_BOTTOM = ConvertFramePointType(7);
    SetFrameRelativePoint(menu, FRAMEPOINT_BOTTOM, gameUi, FRAMEPOINT_BOTTOM, 0, 0.16)

    local left = GetFrameByName('LoadingPlayerSlotName', 0)
    local right = GetFrameByName('LoadingPlayerSlotRace', 0)
    
    local seconds = 0
    local period = .25

    TimerStart(CreateTimer(), period, true, function()
        seconds = seconds + period;
        SetFrameText(left, tostring(GetHandleCount()))
        SetFrameText(right, tostring(math.floor(seconds)))
    end)
end)

Послесловие

Проекты активно разрабатываются силами всего лишь нескольких человек и они не всегда успевают вовремя вносить в них правки. Так что не стесняйтесь поддерживать авторов рублём и писать комментарии.
Ваша поддержка очень важна!
`
ОЖИДАНИЕ РЕКЛАМЫ...