Приветствуем вас на форуме проекта WoW Circle. Если вы читаете это, значит не зарегистрировались у нас. Для того, чтобы получить доступ к расширенным возможностям нашего форума нажмите сюда и пройди регистрацию, которая не займет у вас много времени. После регистрации будут доступны новые, более расширенные, возможности.
Создание фреймворка для модульно сборки.

Упомянутые в теме пользователи:

Показано с 1 по 2 из 2

Комбинированный просмотр

Предыдущее сообщение Предыдущее сообщение   Следующее сообщение Следующее сообщение
  1. #1
    Инопланетянин
    Регистрация
    20.03.2012
    Сообщений
    4,208
    Поблагодарил(а)
    362
    Получено благодарностей: 1,441 (сообщений: 840).
    Репутация: 2401

    Создание фреймворка для модульно сборки.

    Для начала , что же такое фреймврок и нужен ли он? Постараюсь без заумных фраз. Сразу скажу - можно и без него, но толку писать модульную сборку без него нет смысла.

    Что же это такое?
    -- Если кто то начинал что то писать наверное сталкивался с такой ситуацией , когда одни и те же действие нужно выполнять по нескольку раз в разных местах, будь то вывод формата времени, обработка событий, создание какой то графики, иконок и тд. Так вот, это набор функций, которые используются по нескольку раз в разных местах. Например зачем создавать для каждого модуля обработчик событий , когда можно создать один обработчик событий с обратным вызовом и получить тот же результат. Или зачем создавать кучу различных кнопок содержащих одинаковый код. Для этого и нужен фрейворк.

    Итак начнем. Все что будет далее - создание так называемого фреймворка
    Состоять он будет из нескольких частей:

    1) Функция для создание модулей.
    2) Списки очереди загрузки для наших модулей. Луа элементы массива сортирует как ему угодно и если мы захотим загружать какой то из модулей , который использует элементы созданные другим модулем , а эти элементы загрузятся после нашего модуля , то будем ловить ошибки.
    3) Обработчик обратных вызовов - регистрация событий для наших будущих модулей.
    4) Функции, которые часто используются в разных частях разных модулей. Думаю можно назвать это API.

    Начнем:

    PHP код:
    -- Получаем текущее окружение , в котором выполняется наш аддон
    -- первый аргумент возвращается название аддона в строчном формате
    -- второй аргумент возвращает пространство ивент (массив)
    local addon, ns = ...

    -- 
    простенький обработчик ошибок
    local error 
    = function(...) print("|cffff0000Error:|r "..string.format(...)) end

    -- будущий обработчик обратных вызовов
    local frame 
    = CreateFrame"frame"

    -- создаем прототип нашего будущего модуля и массив в котором будем хранить ссылки на модули
    local Modules
    , module = {}, {__index = {}}

    -- 
    сократим время жизни некоторых переменных которые ниже не понадобятся
    do
        -- 
    небольшая перегрузка, вызывается, когда луа запускает функцию.
        
    local events, event_meta = {}, {
            
    __call = function(funcs, self, ...)
                for 
    _, func in next, funcs do
                    
    func(self, ...)
                
    end
            end
    ,
        }
        
        -- 
    нужен небольшой перехват и переопределение функции регистрации событий
        local RegisterEvent 
    = frame.RegisterEvent
        
        
    -- переопределяем метод RegisterEvent для обьекта frame
        
    function frame:RegisterEvent(event, module, func)
        
            -- 
    небольшое исключение для методов модуля
            
    if(type(func) == 'string' and type(module[event]) == 'function') then
                func 
    = module[func]
            
    end
            
            
    -- создаем массив обратных вызовов вызовов для регистрируемого события, если его нет
            
    if not events[event] then events[event] = {} end

            local curev 
    = module[event]
            
            -- 
    в случае если для этого события необходимо обработать несколько функций делаем перегрузку
            
    if(curev and func) then
                
    -- если таблица уже существует нет смысла создавать ее заново, просто регистрируем событие
                
    if type(curev)=="table" and not self:IsEventRegistered(event) then
                    RegisterEvent
    (self, event)
                else
                    -- 
    в противпном случае делаем перегрузку
                    
    if(type(curev) == 'function') then
                        module
    [event] = setmetatable({curev, func}, event_meta)
                    else
                        for 
    _, infunc in next, curev do
                            if(
    infunc == func) then return end
                        end
                        
    -- заносим функцию в массив обратных вызовов
                        table
    .insert(curev, func)
                    
    end
                end
            
    else
                -- 
    если функция всего одна , перегрузка не нужна, добавляем ее в массив обратных вызовов и регистрируем событие
                
    if(func) then
                    module
    [event] = func
                    table
    .insert(events[event], module)
                elseif(
    not module[event]) then
                    
    return error("Обработчик событий [%s] не существует.", event)
                
    end
                RegisterEvent
    (self, event)
            
    end
            
        end
        
        
    -- метод для регистрации события для прототипа модуля
        
    function module.__index:RegisterEvent(event, func)
            return 
    frame:RegisterEvent(event, self, func)
        
    end
        
        local UnregisterEvent 
    = frame.UnregisterEvent
        
    function frame:UnregisterEvent(event, module, func)
            
    local curev = module[event]
            if(
    type(curev) == 'table' and func) then
                
    for k, infunc in next, curev do
                    if(
    infunc == func) then
                        curev
    [k] = nil

                        
    if(#curev == 0) then
                            
    table.remove(curev, k)
                            
    events[event] = nil
                            UnregisterEvent
    (self, event)
                        
    end

                        
    break
                    
    end
                end
            
    else
                
    module[event] = nil
                events
    [event] = nil
                UnregisterEvent
    (self, event)
            
    end
        end
        
        
    --метод для удаления ивента и обратных вызовов для него с модуля
        
    function module.__index:UnregisterEvent(event, func)
            return 
    frame:UnregisterEvent(event, self, func)
        
    end
        
        
    -- рукурсивная обработка массива обратных вызовов
        local 
    function burst(i, modules, event, ...)
            
    local module = modules[i]
            if 
    module then
                module
    [event](module, event, ...)
                return 
    burst(i+1, modules, event, ...)
            
    end
        end
        
        
    -- обработка событий
        frame
    :SetScript("OnEvent", function(self, event, ...)
            return 
    burst(1, events[event], event, ...)
        
    end)
    end

    -- создаем API при вызове которого будет создан модуль с обработчик событий и тд
    function ns:NewModule(name, dependency)

        -- 
    если модуль существует, возвращаем ошибку
        
    if Modules[name] then
            
    return error("Модуль с именем [%s] уже существует.", name)
        
    end
        
        
    -- наследуем мету из прототипа модуля
        local Module 
    = setmetatable({}, module)
        
        -- 
    создаем очередь загрузки
        Module
    .Queue = {}

        
    Modules[name] = Module
        
        
    if dependency then
            local Parent 
    = Modules[dependency]
            
            if 
    Parent then
                Parent
    .Queue[name] = Module
                Module
    .HasDependency = true
            end
        end
        
        
    return Module
    end

    -- получаем ссылку на наш модуль по имени модуля
    function ns:GetModule(name)
        
        if 
    Modules[name] then
            
    return Modules[name]
        else
            return 
    error("Модуль с именем [%s] не существует.", name)
        
    end
    end

    -- "Инициализация" наших модулей
    -- Ивент PLAYER_LOGIN необходим, иначе наши модули будут созданы позже, чем будет выполнена их загрузка
    local f 
    = CreateFrame"frame"
    f:RegisterEvent("PLAYER_LOGIN")
    f:SetScript("OnEvent", function()
        -- 
    загрузка
        
    for _, Module in pairs(Modules) do
            -- 
    инициализация для модулей без очереди загрузки
            
    if (Module.Init and not Module.HasDependency) then
                Module
    :Init()
            
    end
            
            
    -- инициализация очереди загрузки
            
    for _, ChildModule in pairs(Module.Queue) do
                if 
    ChildModule.Init then
                    ChildModule
    :Init()
                
    end
            end
        end
    end
    ) 
    Вот собственно и все.
    Последний раз редактировалось DreamlØlz; 16.05.2016 в 14:26.

  2. 1 пользователь сказал cпасибо DreamlØlz за это полезное сообщение:

    Arena_noTdie (02.07.2019)

  3. #2
    Инопланетянин
    Регистрация
    20.03.2012
    Сообщений
    4,208
    Поблагодарил(а)
    362
    Получено благодарностей: 1,441 (сообщений: 840).
    Репутация: 2401
    Небольшой набор функций для формата времени и хуки для анимации кулдауна с последующим выводом текста (похожий внешний вид имеет omnicc и аналоги). Именно эти функции и будут использованы мной далее. Возможно пополнение.

    PHP код:
    local addon, ns = ...

    ns.FormatValue = function(value)
        if (
    value >= 1e6) then
            
    return format('%.1f', value/1e6)..'m'
        
    elseif (value >= 1e3) then
            
    return format('%.1f', value/1e3)..'k'
        
    else
            return 
    value
        end
    end

    local FormatTime
    do
        
    FormatTime = function(s)
        
    local day, hour, minute = 86400, 3600, 60
        local ceil
    , format = ceil, format
            
    if s >= day then
                
    return format("%dd", ceil(s / hour))
            elseif 
    s >= hour then
                
    return format("%dh", ceil(s / hour))
            elseif 
    s >= minute then
                
    return format("%dm", ceil(s / minute))
            elseif 
    s >= minute / 12 then
                
    return floor(s)
            
    end
            
    return format("%.1f", s)
        
    end
        ns
    .FormatTime = FormatTime
    end

    local HandleCD
    do
        
    local OnUpdate = function(self)
            
    local endTime = self.timeLeft - GetTime()
            -- print(
    endTime)
            if 
    endTime > 0 then
                
    -- print(endTime)
                
    local Remaining = self.Remaining
                
    if endTime > 2 then
                    Remaining
    :SetTextColor(1,1,1)
                else
                    
    Remaining:SetTextColor(1,0,0)
                
    end
                Remaining
    :SetText(FormatTime(endTime))
            else
                
    self.Remaining:Hide()
            
    end
        end
        
        local OnSetCooldown 
    = function(self, start, duration)
            
    self.timeLeft = start + duration
            self
    .duration = duration
            
    if duration > 0 then
                self
    .Remaining:Show()
            
    end
            
    return self.__SetCooldown(self, start, duration)
        
    end
        
        local OnSetCooldownMin 
    = function(self, start, duration)
            
    self.timeLeft = start + duration
            self
    .duration = duration
            
    if duration > 2 then
                self
    .Remaining:Show()
            
    end
            
    return self.__SetCooldown(self, start, duration)
        
    end
        
        HandleCD 
    = function(cd, size, minduration)
            
    local Remaining = cd:CreateFontString(nil, 'ARTWORK')
            
    Remaining:SetFont("Fonts/FRIZQT__.ttf", size, 'OUTLINE')
            
    Remaining:Hide()
            
    Remaining:SetJustifyH("CENTER")
            
    Remaining:SetShadowOffset(0, 0)
            
    Remaining:SetPoint('CENTER', cd, 0, 0)
            
    cd.Remaining = Remaining
            cd
    .__SetCooldown = cd.SetCooldown
            
    if minduration then
                cd
    .SetCooldown = OnSetCooldownMin
            
    else
                
    cd.SetCooldown = OnSetCooldown
            end
            cd
    :SetScript("OnUpdate", OnUpdate)
        
    end
        
        ns
    .HandleCD = HandleCD
    end 

  4. 2 пользователей сказали cпасибо DreamlØlz за это полезное сообщение:

    Arena_noTdie (02.07.2019),Blacken (18.10.2016)

Похожие темы

  1. За что может забанить античит [обязательно к прочтению]
    от EvTech в разделе Новости проекта WoW Circle
    Ответов: 6
    Последнее сообщение: 30.09.2018, 17:02
  2. Ответов: 1
    Последнее сообщение: 29.10.2012, 15:59

Ваши права

  • Вы не можете создавать новые темы
  • Вы не можете отвечать в темах
  • Вы не можете прикреплять вложения
  • Вы не можете редактировать свои сообщения
  •