Перейти к содержимому


кликабельные WeakAuras


  • Закрытая тема Тема закрыта
Сообщений в теме: 2

#1 Анаджин

Анаджин

    Ветеран

  • Пользователи
  • PipPip
  • 12 сообщений

  • Эльф крови Анаджинн Паладин


    Эльф крови Паладин
    • Уровень: 120 (iLvl: 413/415)
    • Достижения: побед 18465

Отправлено 04 Август 2018 - 02:21

Всем привет!
Я вернулся и, как водится, сразу приступаю к гайдописанию =)

Этот гайд будет посвящен, как уже было заявлено, кликабельным викаурам. Данный вопрос не освящен в интернете от слова вообще, поэтому гайд является единственным в своем роде. Но не стоит думать, что это узкая тема. Если вникнуть в написанное здесь, можно весьма широко приоткрыть для себя дверь в мир написания аддонов. В общем, поехали.

Предыстория вопроса такова. В легионе я поставил себе аддон, создающий интерфейс в стиле дьябло. Со сферками и статуями. Как водится, при переходе к БФА, все аддоны поломались, и этот в том числе. Но он был глючный и так, а надеятся на своевременное обновление не приходилось, и я решил попробовать переписать его своими силами.

Изображение

Выбор в первую очередь пал на известный всем аддон Weakauras2. Здесь, как ни странно, стоит уточнить, чем на самом деле является этот аддон. Рядовой пользователь просто тырит непонятные строчки с wago, на таких мы сразу поставим крест, и этот гайд вряд ли для вас. Продвинутый [все еще] пользователь использует стандартный инструментарий для создания значков, текстовых полей, анимированных текстур прогресса для отслеживания состояния игрового мира. И наконец те, кого стоит уже назвать "разработчиками" в состоянии дополнить эти шаблоны скриптами на lua с использованием WoW API, что позволяет выходить далеко за рамки базовых инструментов как в плане функциональности, так и в плане дизайна. На самом деле возможности разработки за счет интерфейса скриптовых функций так велики, что можно смело назвать Weakauras ФРЕЙМВОРКОМ для разработки аддонов: как фреймворк аддон инкапсулирует механизмы создания фреймов для аур, их распределения по экрану, загрузку ресурсов и проч, по сути избавляя нас от писанины.

Разберем с этой точки зрения то, что было сделано для эмуляции интерфейса в стиле дьябло:
1) Вставка статического арта. Для этого нам более чем достаточно стандартного, хоть и неплохо закопанного триггера. Картинка загружается с диска просто по пути в папке вов. Но это тривиально.
Изображение
2) Сферки как текстуры прогресса и текст для них. это достаточно стандартные вещи.
3) Затем я решил, что я хочу повторить в своем аддоне значки отслеживания боя, отдыха и пвп. Для этого достаточно опять же триггера Статус > Условие
4) Более интересным оказался значок лидера и значок номера группы. Здесь стандартных триггеров уже нет, и потребовалось написать собственный код ака кастомный триггер
Для проверки на лидера достаточно выставить триггер Самостоятельно > Статус, затем можно проверку каждый кадр, но я оптимизировал событиями GROUP_ROSTER_UPDATE, PARTY_LEADER_CHANGED, которых более чем достаточно для отслеживания любых изменений в группе. Далее собственно следует код "Свой триггер", он же условие, которое будет возвращать, показывать или не показывать ауру, по этим событиям.
function(...)
return UnitIsGroupLeader("player")
end
Проверка простая, и больше ничего от нас на самом деле не требуется.
Для проверки номера группы (ну уже, право, надоело спрашивать в войсе "А В КАКОЙ Я ГРУППЕ О_О") нужно сделать дополниельный шаг.
Во-первых, проверим, что мы вообще в группе, иначе зачем нам вообще ее номер. Пишем кастомный триггер:
function()
-- Следует заметить, что здесь используется чуть другая форма записи, несколько более безопасная в рамках не строготипизированного языка lua
return IsInRaid() and true
end
Дальше напишем кастомный отображаемый текст, у текстового поля для этого надо вписать %c, и сразу появится поле для скрипта:
function ()
-- Проверим всех членов группы
for i=1,GetNumGroupMembers() do
-- У них узнаем имя n и номер группы g
local n,_,g=GetRaidRosterInfo(i)
if n==UnitName("player") then
-- Если имя совпадает с именем игрока, немедленно возвращаем номер группы и завершаем выполнение
return g
end
end
-- Не нашли, не пишем ничего. Нужно скорее для очистки совести. ибо триггер с этим справился заранее.
return ""
end

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

И тут Остапа понесло. Раз мы уже запилили целый фрейм игрока, зачем нам стандартный? СКРЫТЬ!
Берем наш фрейм сферки хп, просто потому что он нам очень нравится и во вкладке Действия > При инициализации пишем:
-- Hiding blizzard frame
PlayerFrame:Hide()
Как к этому решению прийти... Спросить у гугла, как "WoW API lua hide player frame", и мы найдем ровно ту функцию Hide, которая применена выше. Остается запустить ее при загрузке интерфейса. Есть сайт, который позволяет СОЗДАТЬ, чтоб его, АДДОН, который вызовет на своей загрузке наш код. А оно нам надо? Воспользуемся нашей викаурой для запуска кода на загрузке. Это уже нетривиальное использование: по сути в этот момент мы полностью ушли от аур и статусов, в общем, от назначения аддона к его функциям как фреймворка.

Ладно, это мы сделали. Но теперь мы не можем (если мы не в группе) сделать две важные вещи: не можем вызвать контекстное меню игрока без выделения и не можем выделить себя мышью. Естественно, макросы с маусовером нам тоже делать некуда. И вот здесь мы приходим неожиданно к задаче о кликабельных викаурах.

С этой задачей сталкивались многие, кто копался в этом аддоне: викауры не реагируют на клики мышью. Да, вообще. В интернетах максимум что можно найти - это как Вася99 на своем ютьюб канальчике серьезным тоном вещает, как подложить панельки Bartender под викауру. издевательство. Нас такое не устраивает.

А теперь подумаем. Аддон говорит, нельзя. При этом мы можем писать в нем скрипты. В этих скриптах мы можем достучаться до объектов фреймов наших викаур, то есть знаем о них все. Но при этом другие аддоны реализуют свои фреймы игрока аналогично стандартному, а значит это возможно. Так и что нам, черт возьми, тогда мешает сделать то, что мы хотим? ... Ничего. Но мы опять же не обязаны писать свой аддон с нуля: нас устраивает то, что есть в викаурас.

Итак, гуглим и выясняем, что чтобы обработать клик, нам нужен некий кликабельный объект, которым фрейм викауры не является. Ну так в чем проблема? создадим его там же, где мы скрыли фрейм игрока, на загрузке:
-- Creating button
local captor = CreateFrame("Button", "PlayerOrbButton", aura_env.region, "SecureUnitButtonTemplate")
-- Setting position
point, relativeTo, relativePoint, xOfs, yOfs = aura_env.region:GetPoint()
captor:SetPoint(point, mainframe, relativePoint, xOfs, yOfs)
captor:SetWidth(aura_env.region:GetWidth())
captor:SetHeight(aura_env.region:GetHeight())
Во-первых мы создали объект типа Кнопка. Естественно, кнопка кликабельна. Мы дали ей название "PlayerOrbButton", чтобы можно было потом к ней стуачаться, затем родительский объект, к которому она будет привязана... Последний пораметр нам пока не нужен.
Затем из aura_env.rect, который и является фреймом викауры, копируем его положение и размеры.
Итак, теперь мы имеем кнопку, которая получает из системы сообщения onmousedown, и теперь мы можем задать скрипт, который будет выполняться по этому сообщению:
Player dropdown for right click
captor:SetScript("onmousedown", function(self, button)
if button == "RightButton" then
-- Результат короткого гугления: функция контекста игрока
ToggleDropDownMenu(1, nil, PlayerFrameDropDown, "PlayerOrbButton", 0, 0)
end		
end)
Ура. Перезагрузим интерфейс /reload, и у нас по клику правой кнопкой мыши вылезает контекстное меню. Получается, мы только что решили задачу, над которой уже по меньшей мере 6 лет бьются Васи99? На самом деле пока еще нет. У нас осталось еще две задачи, маусовер и выделение, и тут мы получаем веселую загвоздку.

Логичным образом дополним наш код выделением игрока:
Player dropdown for right click
captor:SetScript("onmousedown", function(self, button)
if button == "RightButton" then
ToggleDropDownMenu(1, nil, PlayerFrameDropDown, "PlayerOrbButton", 0, 0)
elseif button == "LeftButton" then
TargetUnit("player")
end
end)
Мы ожидаем, что теперь по ЛКМ у нас будет выдеяться игрок... А мы получаем ошибку: модификация якобы выполнила действие, доступное только интерфейсу близзард. Многие видели такие ошибки у аддонов, но в чем же дело у нас?

Дело в том, что в вов есть три интерпретатора lua. Но сначала взглянем на знакомые всем макросы. Допустим, когда-то давно в макросах можно было задавать /castsequence с задержками времени, творить большую магию... но потом это понерфили, чтобы игроки не злоупотребляли. При этом в макросах же мы встречаем первый интерпретатор lua - /script, где может быть записан луа-код. Вот только если разрешить там делать все, что угодно, то зачем было нерфить макросы? Поэтому /script может использовать только ПУБЛИЧНЫЕ функции интерфейса, функции выделения цели и использования скиллов такими не являются, и доступны они в макросах только через оболочки /use и /target, которые подчиняются упомянутым выше жестким ограничениям.
А теперь еще два интерпретатора: аддоны и интерфейс близзард. Для интерфейса близзард есть приватные функции, которые может использовать только он, но их СОВСЕМ мало, остальные же функции являются ЗАЩИЩЕННЫМИ, и нам нужно найти способ их вызывать.

Выясняется, что для этого объект, исполняющий защищенный код должен быть объектом из следующего списка:
https://wowwiki.wiki...SecureTemplates.
Логично, что среди них нас интересует SecureUnitButtonTemplate - кнопка юнита. Начинаем разбираться.

Во-первых, выясняется как его создать, но этим мы уже воспользовались выше 4ым параметром.
Во-вторых, такому фрейму можно задать юнита, которого он представляет, а это именно то, что нам надо для маусовера.
Теперь мы на самом деле можем вызывать функции в лоб, но мы воспользуемся специально формой записи для этого типа:
SecureUnitButton_onload(captor, "player", function() end)
Все. Теперь наш фрейм поддерживает еще и выделение игрока с маусовером. Задача выполнена. Еще раз приведем полностью код нашего микроаддона:
-- Hiding blizzard frame
PlayerFrame:Hide()

-- Creating button
local captor = CreateFrame("Button", "PlayerOrbButton", aura_env.region, "SecureUnitButtonTemplate")

-- Setting position
point, relativeTo, relativePoint, xOfs, yOfs = aura_env.region:GetPoint()
captor:SetPoint(point, relativeTo, relativePoint, xOfs, yOfs)
captor:SetWidth(aura_env.region:GetWidth())
captor:SetHeight(aura_env.region:GetHeight())

SecureUnitButton_onload(captor, "player", function() end)
captor:SetScript("onmousedown", function(self, button)
if button == "RightButton" then
ToggleDropDownMenu(1, nil, PlayerFrameDropDown, "PlayerOrbButton", 0, 0)
end		
end)
Как видно, ничего сложного тут нет. А что самое хорошее, на этом примере можно выстроить вообще все что угодно с минимальным использованием гугла.

Остается последний вопрос, который я пока не затронул: а как нам использовать из такого самопала скиллы?
Ответ: нам требуется SecureActionButtonTemplate, который работает благодаря ровно тем же принципам, что и SecureUnitButtonTemplate.
До достижения результата достаточно прочитать инструкцию по ссылке выше, но я приведу пример викауры со скиллом, где по нажатию применяется эльфийский волшебный поток.
-- Creating button
local captor = CreateFrame("Button", nil, aura_env.region, "SecureActionButtonTemplate")

-- Setting position
point, relativeTo, relativePoint, xOfs, yOfs = aura_env.region:GetPoint()
captor:SetPoint(point, relativeTo, relativePoint, xOfs, yOfs)
captor:SetWidth(aura_env.region:GetWidth())
captor:SetHeight(aura_env.region:GetHeight())

--Отладочная текстура для проверки, где получается кнопка
--captor:SetNormalTexture("Interface\SPELLBOOK\UI-Spellbook-SpellBackground")

captor:SetAttribute("type", "spell");
captor:SetAttribute("spell", "Волшебный поток");

Также для примера приведу строку для импорта этой викауры. Следует заметить, что в ней я использую простейший триггер и даже не делаю в ней иконку. Это связано лишь с тем, что в контексте уже существующих у меня викаур эта является заглушкой, выполняющей только функции клика, в то время как реальные триггеры для визуализации вынесены отдельно. Мне так было нужно :)

Все, на основании написанного читатель сможет создавать свои собственные кликабельные панели скиллов. Да и вообще, с использованием приведенных трюков возможности разработчика викаур становятся практически безграничными.

#2 Анаджин

Анаджин

    Ветеран

  • Пользователи
  • PipPip
  • 12 сообщений

  • Эльф крови Анаджинн Паладин


    Эльф крови Паладин
    • Уровень: 120 (iLvl: 413/415)
    • Достижения: побед 18465

Отправлено 05 Август 2018 - 14:50

Обновил на предмет аур со скиллами

#3 Керыч

Керыч

    Зам ГМ

  • Лидеры гильдии
  • PipPipPip
  • 2 155 сообщений

  • Таурен Керыч Друид


    Таурен Друид
    • Акт.спека:
    • Уровень: 60
    • Достижения: побед 19565
    • 1-й Легион Немезис [мт] - главный танк

Отправлено 27 Сентябрь 2018 - 20:15

А ведь работает! Ты гуру)




Количество пользователей, читающих эту тему: 0

0 пользователей, 0 гостей, 0 скрытых пользователей