Перейти к содержанию

Дайджесты за январь-февраль

Обновления гайдов и аддонов

Январь Февраль

Мониторинг серверов и редактор аддонов

Представляем вам две легенды. То, о чем можно было только мечтать, стало реальностью.

Мониторинг серверов Редактор аддонов

Подсказки из игры на вашем сайте

Теперь вы можете отображать сведения о внутриигровых элементах простым наведением курсора мыши.

Подробнее

Апдейтер аддонов

Представляем вам программу для автообновления аддонов и делимся подробностями.

Подробнее Скачать

AOClassLibrary.lua - бибилотека классов.


Рекомендуемые сообщения

Привествую комрады....

Я думаю сделать билбиотеку классов. Это упростит разработку и повысит читабильность кода. Суть в том чтобы создать набор классов для работы с компонентами, удобную и понятную обертку над Ниваловским АПИ, а так же обизательно реализовать там систему проверок и логирования ошибок, что значительно упростит дебаг. Эту библиотеку каждый сможет скачать и использовать. Планирую обновлять тему и при вашем содействии расширять функционал данной библиотеки.

Что сделано:

1. WidgetsContainerClass - это класс для управления виджетами. Включает в себя - создание, виджетов 2мя способами и общие для всех виджетов фукции управления. Описание:

1.1 CreateWidgetsContainer() - создает экземпляр класса.

1.2 Init() - инициализирует переменные класса

1.3 AddWidgetByName( wtFrom, Name, WidgetName ) - добавляет в контейнер виджет по имени, используеться для создания "статически" виджетов. Где: wtFrom - носитель виджета, Name - имя в .xdb файле, WidgetName - имя в контейнере.

1.4 AddWidgetByDesc( wtFrom, wtFromPrototype, WidgetName ) - добавляет в контейнер виджет по "образу" существуюшего виджета. Где: wtFrom - носитель виджета, wtFromPrototype - виджет по образу которого требуеться создать виджет, WidgetName - имя в контейнере.

1.4 Далее в библиотеки функции работы с виджетами. Изменения размеро, установка позиции, перемешение и т.д.

Пример использования:

Code:

Global( "WidgetsContainer1", {} )

Global( "WidgetsContainer2", {} )

.

.

.

WidgetsContainer1 = CreateWidgetsContainer()

WidgetsContainer1:Init()

WidgetsContainer1:AddWidgetByName( mainForm, "TestBtn1", "FirstTestBtn" )

WidgetsContainer1:SetPosition(  500, 200,  "FirstTestBtn" )

WidgetsContainer1:SetWidth(  100,  "FirstTestBtn" )

for i = 1, 5 do

local wtName = "TestBtn" .. i

WidgetsContainer1:AddWidgetByDesc( mainForm, WidgetsContainer1.Widgets [ "FirstTestBtn" ] ,  wtName )

WidgetsContainer1:SetPosition( 500, 200 + i * 32, wtName )

end

WidgetsContainer1:AddWidgetByName( mainForm, "TestBtn2", "SeccondTestBtn" )

WidgetsContainer1:SetPosition(  500, 400,  "SeccondTestBtn" )

WidgetsContainer1:SetWidth(  100,  "SeccondTestBtn" )

WidgetsContainer1:AddWidgetByName( mainForm, "TestBtn1", "FirstTestBtn" ) -- попытка добавить уже обьект с уже сушествующим имененм - в Лог    выведеться сообшение, Добавление не будет сделлано.

WidgetsContainer1:AddWidgetByName( wtBBB, "GGGG", "GGGG" ) -- попытка добавить обьект от несушествующего виджета wtBBB = nil, выведет ошибку в Лог.

WidgetsContainer2 = CreateWidgetsContainer()

WidgetsContainer2:Init()

WidgetsContainer2:AddWidgetByName( mainForm, "SuperBtn", "SuperBtn1" )

WidgetsContainer2:MoveWidget(  10, 30,  "SuperBtn1" )

WidgetsContainer2:SetWidth(  100,  "SuperBtn1" )

Просто, читабельно, безопасно ( проверки внутри функций, вывод в лог ошибок ), удобно. Как видно из премера можно создавать кучу кантейнеров - напрмиер для разных типов виджетов или создать 1 контейнер. 2 я привел для примера. Ктому же это пример как делать "классы" в LUA - для тех кто этого еше не умеет.

Можно придумать много таких полезных классов оберток. Это вопрос времени и фантазии. *))))

Вот сам файл: AOClassLibrary.lua

Ссылка на комментарий
Поделиться на другие сайты

  • Ответов 60
  • Создана
  • Последний ответ

Топ авторов темы

Топ авторов темы

теперь еще АПИ писать к библиотеке надо :)

не смотрел пока еще либу, не знаю на сколько там практично реализовано. но на заметку:

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

Ссылка на комментарий
Поделиться на другие сайты

Шас заканчиваю обновление. Прикрутил там работу с Childs. Но еше не все оттестил. Рабоатет пока что примерно так - по мимо методов относящихся к виджету не посредственно ( SetWidht, SetPosition, и т.д. ), добавли набор методов- Get\SetChild...( WidgetName, ChildName ). На практике очень удобно получаеться. Например:

У меня есть панелька - на ней еше одна панелька( прогресс бар), кнопка, 3 текствью. Вот иреархия:

Code:

PlayerInfoPanel

PlayerInfoBar

PlayerInfoButton

PlayerInfoTextViewName

PlayerInfoTextViewDamage

PlayerInfoTextViewPercentage

Классическим способом я должен завести 6 переменных в глобальной области и пригрузить туда все это, а если таких панелек N то N*6 *))))) Ну или массив, но подгрузка все равно напрягает. А через класс все просто и красиво и минимум кода :

Code:

PrototypeWidgetsContainer = CreateWidgetsContainer()

PrototypeWidgetsContainer:Init()

PrototypeWidgetsContainer:AddWidgetByName( mainForm, "PlayerInfoPanel", "PlayerInfoPanel" )

PrototypeWidgetsContainer:HideAllWidgets()

PlayerDPSInfoList  = CreateWidgetsContainer()

PlayerDPSInfoList:Init()

for i = 0, 5 do

local wtName = "PlayerInfoPanel" .. i

PlayerDPSInfoList:AddWidgetByDesc( wtMainPanel, PrototypeWidgetsContainer.Widgets [ "PlayerInfoPanel" ] ,  wtName )

PlayerDPSInfoList:SetPosition( 20, 47+ i * 24, wtName )

local newW = 242 * (  (100 - i*10) / 100  )

PlayerDPSInfoList:SetChildWidth( newW, wtName, "PlayerInfoBar" )

PlayerDPSInfoList:SetChildColor( ClassColors [ "MAGE" ] , wtName, "PlayerInfoBar" )

local wtNameTextView = PlayerDPSInfoList:GetWidgetChildByName( wtName, "PlayerInfoTextViewName" )

wtNameTextView:SetVal( "Index", common.FormatFloat( i+1 , "%d" ) )

end

Обратите внимание на PlayerDPSInfoList:SetChildWidth( newW, wtName, "PlayerInfoBar" ), я не где его не подгружаю *))) Я просто обращаюсь к нему через родительский Виджет - и меняю его *)))) Или вот еше PlayerDPSInfoList:GetWidgetChildByName( wtName, "PlayerInfoTextViewName" ), тут я беру дочерний виджет, моего виджета по его имени и дальше работаю с ним.

Но пока что мой класс поддерживает вложенность 2 порядка, то есть "дети" виджета доступны через методы Get\SetChild...(...), и это не решате проблеммы когда у меня сложная структура виджетов с 3йным или Nым уровнем вложенности. Но я уже придумал как это решить - осталось тока сделать и протетстить. Я буду каждый виджет в WidgetsContainerClass описывать собствено переменой виджета и переменой WidgetsContainer, которая изначально убдет пуста - при создании виджета и наличии у него детей, я буду создавать "под контейнер" для этого виджета, который в свою очередь будет делать тоже самое, таким образом, при создании главного виджета - создадуться все виджеты-дети, при чем если у них тоже есть дети, то создадуться и они. Вот такая идея.

А практичность.... по начало может показаться - сложно, но когда вникаешь в структуру класса - становиться удобно. Да вообще активнее участвуем, а то 1 голова хорошо, а гидра рулит *))))

Ссылка на комментарий
Поделиться на другие сайты

ммм а чего ен осилил то ? Букав много ? или не понял ? Если первое то, зря, если второе - спроси, обьясню.

Ссылка на комментарий
Поделиться на другие сайты

прочитал все... понял все что Ты хотел сказать, а вот не переварил и все..... надо попить чаю и еще раз прочитать.. =) (я сказал попить)

Ссылка на комментарий
Поделиться на другие сайты

Да ты просто попробуй - сделай простой аддончик с 1 кнопкой - загрузи ее стандартным образом, потом создай Контейнер и подобавляй в его новых кнопок - много методом CreateWidgetByDesc, потом поуправляй этими кнопками методами контейнера - и все поймешь.... Потом глянь как нечно похожее делаеться в других аддонах где много обьектов GuildGui и т.д. и сравни *)))) И снова поймешь

Ссылка на комментарий
Поделиться на другие сайты

Инициатива похвальная, круто. Но только исполнение пока излишне большое, дырявое и тем самым малоэффективное. Без обид, ты сам попросил поучаствовать. Нарожать оберток можно вагон, но их потом менеджить запаришься, да и не нужны они по-хорошему. В Lua вообще приветствуется подход "меньше кода = меньше ошибок". Так что, не очень понял цель этого скрипта. Группировать виджеты? А почему бы просто в таблицу не сложить? Вывод в лог ошибок? А как ловить ошибки в самой обертке? И так и не вкурил, причем здесь слово "класс".

Про дыры:

У любых созданных динамически виджетов родитель всегда mainForm, так что добавление в "контейнер" byDesc выглядит странно. Репликацию объектов через клонирование таблиц делать не рекомендуется, можно легко самому себе жизнь испортить, и никакая диагностика не спасет. Кстати, подумай, что будет при клонировании, если таблица ссылается хотя бы сама на себя, или на одну из своих частей, опыт сильно пригодится. Попробуй клонировать _G ради прикола. Хранить детей в специальной таблице "дети" и соорудить кучу оберточных методов для работы с ними - изощренный мазохизм, из которого проистекает в частности "вложенность 2 порядка". В Lua есть механизм доступа к элементам таблиц на любой глубине через точку, почему бы не использовать готовое и отлаженное? Будешь тогда писать что-то типа:

Code:
local Checkbox = mainForm.wtMainPanel.wtChilds [ 5 ] .wtEntry.wtCheckbox

Checkbox.__widget:Show( true )

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

Про ООП в Lua - вот библейские основы: http://www.lua.org/pil

Конкретно нужны главы 11, 13, 16 и 17, там подробно и с примерами написано, что именно предусмотрено в Lua для объектно-ориентированного скриптования. Остальное по желанию, но вообще если уж пишешь серьезно на Lua, то неплохо бы ознакомиться хотя бы с руководством, написанным создателем Lua (одним из), благо оно небольшое и все по делу. Побаловаться с чистым Lua можно, подключив к Notepad++ lua.exe нужной версии в стандартную плагу NppExec (идет в комплекте с Notepad++).

Ссылка на комментарий
Поделиться на другие сайты

Вообще в доках описан метод DestroyWidget. /LuaApi/FunctionWidgetDestroyWidget.html Так что, наверное, все-таки можно.

Ссылка на комментарий
Поделиться на другие сайты

Знаю что есть, но Удаление виджета еще не значит высвобождение памяти. Я писал про память их АПИ, не цитата, конечно, но смысл сохранен. Видать у них с этим какието проблемы возникли, вот и установили скриптокодерам такие ограничения.

поищу может завтра где я это видел.

Ссылка на комментарий
Поделиться на другие сайты

посидел поизучал код... тоже неасилил. Ramirez по большому счету прав. У меня тоже 10 кнопок в лутинфо, но проблем с реализацией, доступом и кодом не испытываю.

Не туда немного понесло тебя, собсно то о чем я и говорил - "lua внутри lua". То что уже реализовано в языке - можно не трогать, нужно улучшать то, что действительно приходится делать часто и по многу.

Для начала регистрация перетаскивания и прятания виджетов одной функцией.

Также можно функцию регистрации ивентов и реакций. смотреть все там же в лутинфо. две функции находятся в самом низу.

И подключение новых событий выполняется очень просто - добавлением новой функции в таблицу, с именем ивента.

чувствую опять непонятно объяснил нефига, в общем вот смотрим, функции для регистрации ивентов и реакций:

Code:
function RegisterEventHandlers( handlers )

for event, handler in handlers do

common.RegisterEventHandler( handler, event )

end

end

function RegisterReactionHandlers( handlers )

for event, handler in handlers do

common.RegisterReactionHandler( handler, event )

end

end

в init() прописываем

Code:
RegisterEventHandlers( onEvent )

не забываем про

Code:
Global( "onEvent", {} )

и дальше пишем

Code:
onEvent [ "EVENT_..." ]  = function( params )

  --здесь пишем код

end

И ненужно для каждого ивента будет писать снова регистрацию, сразу добавлять новую функцию и она подцепится.

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

ЗЫЖ не претендую на гениальность, т.к. луа изучать начал собсно с Аллодов, когда увидел тему на ЗБТ2 про аддоны, но всетаки рекомендую поизучать лутинфо, может найдешь полезного чтонить для оптимизации и реализации.

Ссылка на комментарий
Поделиться на другие сайты

вещь не плохая хоть и снижает читаемость, немного неудобно смотреть зарегистрированные события и реакции на которые подписан если редактор не умеет сворачивать код блоками ;-), но это не критично а лиш "на вкус и цвет", вопрос в другом:

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

Ссылка на комментарий
Поделиться на другие сайты

А кто мешает объявить несколько таблиц, и одну из них регистрировать по условию? Это ничего не усложняет. Подход хороший, позволяет группировать ивент-хэндлеры и оперировать не отдельными хэндлерами, а сразу группами. И не надо идиотскую копипаст-простыню регистраций писать, сам факт наличия хэндлера гарантирует, что он пойдет в дело. Хотя все равно, даже погруппированная свалка кучи хэндлеров, по которым тонким слоем размазана логика разных частей аддона - остается свалкой, и ориентироваться в ней можно только пока скрипт небольшой.

Хочется сказать: люди! =) Больше пользуйтесь таблицами, в них скрыта главная Луашная сила, это ж без пяти минут динамические объекты. Ну и поменьше глобальных переменных - они бессмысленны, только путаются где не положено и нэймспейс засоряют. =)

Ссылка на комментарий
Поделиться на другие сайты

Так и представляю себе как получилось у меня 3 таблицы, 1я - свалка всего что не по условиям, 2я - 2 события и 1 реакция по условию и 3я - 1 событие по другому условию... а всего событий юзается 15, реализация каждого 10 строк, + с 10 вспомогательных функций по 5 строк... и я сижу значит и чтобы увидеть логику аддона через 2 недели после написания либо мучаю скрол на мыше пытаясь запомнить что где к чиму..., либо выписываю на листочек все события по таблицам :-))))

З.Ы. ИМХО(я попробовал мне не понравилось, ничего против не имею, всё выше лиш рассуждения в слух) "оптимизация ради оптимизации". Ну или познание языка, но лиш чтобы уяснить и запомнить его возможности...

З.Ы.Ы. Тогда вы, уважаемый, можете и заголовочные файлы в С и С++ назвать "копипаст-простынёй обьявлений"

Ссылка на комментарий
Поделиться на другие сайты

Я верю практическому опыту; с досужими рассуждениями - в сад, это просто потеря времени. "2 события и 1 реакция по условию, +10 вспомогательных функций..." - дикие глупости.

P.S. Про объявления речи не было, читайте внимательней и не пишите ерунды.

Ссылка на комментарий
Поделиться на другие сайты

"при таком подходе у меня не получилось повесить подписку на события по условиям"

А чем тебе не нравится вот такая запись?

if "условие" then

RegisterEventHandlers( onEvent )

end

Ссылка на комментарий
Поделиться на другие сайты

чтобы не быть голословным...

что даст ваше предложение

Code:

--- globals

Global( "onEvent", {} )

--- helps

function RegisterEventHandlers( handlers )

for event, handler in handlers do

common.RegisterEventHandler( handler, event )

end

end

--- handlers

onEvent  [ "EVENT_1" ]   = function( params )

  -- тело обработчика события

end

-- только этот обработчик нужен по условию!!!

onEvent  [ "EVENT_2" ]   = function( params )

  -- тело обработчика события

end

--- init

function init()

    if "условие" then

        RegisterEventHandlers( onEvent )

    end

end

--- body

init()

, вариант с дополнительным полем под условие в таблице я рассматривал, но он тоже изрядно увеличивает сложность решения...

Code:

--- globals

Global( "onEvent", {} )

--- helps

function RegisterEventHandlers( handlers )

for event, handler in handlers do

    if handler.condition then

                 common.RegisterEventHandler( handler.body, event )

             end

end

end

--- handlers

onEvent  [ "EVENT_1" ] .body  = function( params )

  onEvent  [ "EVENT_1" ] .condition = true

  -- тело обработчика события

end

-- только этот обработчик нужен по условию!!!

onEvent  [ "EVENT_2" ] .body  = function( params )

    onEvent  [ "EVENT_2" ] .condition = function() 

                                         return condition1 and condition2 or condition3

                                       end

  -- тело обработчика события

end

--- init

function init()

     RegisterEventHandlers( onEvent )

end

--- body

init()

вариант при отдельной таблице событий на условие усложнит function RegisterEventHandlers( handlers ) причем усложнит существенно...

всегда остаётся вариант делать полвину по одному, половину по другому, но это мягко говоря не самое желательное в кодовстве :-)

З.Ы. повтрюсь: ИМХО, лиш то как я привык писать и вести код на работе и как мне удобно... ни на чем не настаиваю, никого от пользования подобным решением не отговариваю...

Ссылка на комментарий
Поделиться на другие сайты

Тот подход, который предложил Valltron (функции реакции на события в виде массива) используют сами разработчики игры. Нам же, в примерах кода (SampleAddons), они дали другой, более простой "НЕпромышленный" :) способ подписки функций на события. Конечно, использовать можно любой из них, или оба сразу. Те события, на которые аддон должен реагировать всегда, если их очень много, можно сделать массивом. А те, подписка которых зависит от каких-то условий - тем простым способом, который показан в примерах аддонов.

Ссылка на комментарий
Поделиться на другие сайты

+1, то что я и хотел сказать но показав возможные неудобства "промышленного" варианта, но у меня както слонее получилось выразить :-)))

Ссылка на комментарий
Поделиться на другие сайты

Можно использовать два массива:

Code:
Global( "onBaseEvent", {} ) -- массив для всех событий

Global( "onAdvancedEvent", {} ) -- массив для событий по условию

И еще хотел задать вопрос, а что за события ты хочешь регистрировать по условию?

Мой поинт такой: открыл окно аддона - зарегистрировал общие события, закрыл окно - отписался от этих событий. А отдельные события можно запихнуть в другой массив и регистрировать/отписываться от них по условию.

Ссылка на комментарий
Поделиться на другие сайты

Даже исходя из моих скудных познаний луа...

Вариант один:

Code:
Global( "onEvent", {} )

Global( OnBase, {} )

function RegisterEventHandlers( handlers )

for event, handler in handlers do

common.RegisterEventHandler( handler, event )

end

end

onEvent   [ "EVENT_1" ]    = function( params )

  -- тело обработчика события

end

onBase   [ "EVENT_2" ]    = function( params )

  -- тело обработчика события

end

function init()

    RegisterEventHandlers( onEvent )

    if "условие" then

        RegisterEventHandlers( OnBase )

    end

end 

Вариант два:

Code:
Global( "onEvent", {} )

function RegisterEventHandlers( handlers )

for event, handler in handlers do

common.RegisterEventHandler( handler, event )

end

end

onEvent.allways   [ "EVENT_1" ]    = function( params )

  -- тело обработчика события

end

onEvent.ext   [ "EVENT_2" ]    = function( params )

  -- тело обработчика события

end

function init()

    RegisterEventHandlers( onEvent.allways )

    if "условие" then

        RegisterEventHandlers( onEvent.ext )

    end

end 

Сильно громозко? или трудно реализуемо/читаемо?

Ссылка на комментарий
Поделиться на другие сайты

увеличивается количество того что надо держать в голове, + некоторая оторванность кусков реализации (чтобы глянуть чтоже за события вызываются по условию придется перелопатить половину кода)

З.Ы. ИМХО

to wait:

Да вы просто помешаны на таблицах в lua как на универсальных хранилищах данных, не к добру это, ой не к добру :-D

Ссылка на комментарий
Поделиться на другие сайты

я помешан на packed record в дельфи, а в луа просто нашел близкое по духу :)

Ссылка на комментарий
Поделиться на другие сайты

Эх, раз все ж пошла такая пьянка, держите меня семеро... =)

Так вот, чтобы не быть, блин, ГОЛОСЛОВНЫМИ, проведем-ка подробный анализ обоих "подходов" (готовьтесь много и с чувством читать).

Итак, "простой" метод разработчиков:

Code:
--------------------------------------------------------------------------------

function OnEventСложноеИмяЭвентаНомерРаз( params )

--...

-- тело хэндлера

--...

end

--------------------------------------------------------------------------------

function OnEventИмяЭвентаЕщеСложнееНомерДва( params )

--...

-- тело хэндлера

--...

end

--------------------------------------------------------------------------------

function OnEventСовсемНечитаемоеИмяЭвентаНомерТри( params )

--...

-- тело хэндлера

--...

end

--------------------------------------------------------------------------------

function OnEventНеИмяАКакаяТоДракулаНомерЧетыре( params )

--...

-- тело хэндлера

--...

end

--------------------------------------------------------------------------------

--...

--... еще ДВАДЦАТЬ ШЕСТЬ таких определений функций

--...

--------------------------------------------------------------------------------

function OnEventЯУжеОпухЭтоПисатьНомерТридцатьОдин( params )

--...

-- тело хэндлера

--...

end

--------------------------------------------------------------------------------

-- теперь пытаемся с этим всем взлететь

--------------------------------------------------------------------------------

function ShowAddon( visible ) -- пример регистрации по условию

addonPanel:Show( visible )

--... какая-то часть функции

--...

if visible then

common.RegisterEventHandler( OnEventСложноеИмяЭвентаНомерРаз, "EVENT_СЛОЖНОЕ_ИМЯ_ЭВЕНТА_НОМЕР_РАЗ" )

common.RegisterEventHandler( OnEventИмяЭвентаЕщеСложнееНомерДва, "EVENT_ИМЯ_ЭВЕНТА_ЕЩЕ_СЛОЖНЕЕ_НОМЕР_ДВА" )

common.RegisterEventHandler( OnEventСовсемНечитаемоеИмяЭвентаНомерТри, "EVENT_СОВСЕМ_НЕЧИТАЕМОЕ_ИМЯ_ЭВЕНТА_НОМЕР_ТРИ" )

common.RegisterEventHandler( OnEventНеИмяАКакаяТоДракулаНомерЧетыре, "EVENT_НЕ_ИМЯ_А_КАКАЯ_ТО_ДРАКУЛА_НОМЕР_ЧЕТЫРЕ" )

common.RegisterEventHandler( OnEvent..., "..._НОМЕР_ПЯТЬ" )

common.RegisterEventHandler( OnEvent..., "..._НОМЕР_ШЕСТЬ" )

common.RegisterEventHandler( OnEvent..., "..._НОМЕР_СЕМЬ" )

--...

--... ЕЩЕ ДЕВЯТЬ ТАКИХ ЖЕ РЕГИСТРАЦИЙ ХЭНДЛЕРОВ

--...

common.RegisterEventHandler( OnEvent..., "..._НОМЕР_СЕМНАДЦАТЬ" )

else

common.UnRegisterEventHandler( OnEventСложноеИмяЭвентаНомерРаз, "EVENT_СЛОЖНОЕ_ИМЯ_ЭВЕНТА_НОМЕР_РАЗ" )

common.UnRegisterEventHandler( OnEventИмяЭвентаЕщеСложнееНомерДва, "EVENT_ИМЯ_ЭВЕНТА_ЕЩЕ_СЛОЖНЕЕ_НОМЕР_ДВА" )

common.UnRegisterEventHandler( OnEventСовсемНечитаемоеИмяЭвентаНомерТри, "EVENT_СОВСЕМ_НЕЧИТАЕМОЕ_ИМЯ_ЭВЕНТА_НОМЕР_ТРИ" )

common.UnRegisterEventHandler( OnEventНеИмяАКакаяТоДракулаНомерЧетыре, "EVENT_НЕ_ИМЯ_А_КАКАЯ_ТО_ДРАКУЛА_НОМЕР_ЧЕТЫРЕ" )

common.UnRegisterEventHandler( OnEvent..., "..._НОМЕР_ПЯТЬ" )

common.UnRegisterEventHandler( OnEvent..., "..._НОМЕР_ШЕСТЬ" )

common.UnRegisterEventHandler( OnEvent..., "..._НОМЕР_СЕМЬ" )

--...

--... ЕЩЕ ДЕВЯТЬ ТАКИХ ЖЕ АНРЕГИСТРАЦИЙ ХЭНДЛЕРОВ

--...

common.RegisterEventHandler( OnEvent..., "..._НОМЕР_СЕМНАДЦАТЬ" )

end

--...

--... остальная часть функции

end -- неплохих размеров простыня копипаста получилась, внимательно см.

--------------------------------------------------------------------------------

--...

--... Какой-то вспомогательный код, всегда есть

--...

--------------------------------------------------------------------------------

function Init()

--... какая-то часть функции Инита

--...

common.RegisterEventHandler( OnEvent..., "..._НОМЕР_ВОСЕМНАДЦАТЬ" )

common.RegisterEventHandler( OnEvent..., "..._НОМЕР_ДЕВЯТНАДЦАТЬ" )

common.RegisterEventHandler( OnEvent..., "..._НОМЕР_ДВАДЦАТЬ" )

common.RegisterEventHandler( OnEvent..., "..._НОМЕР_ДВАДЦАТЬ_ОДИН" )

common.RegisterEventHandler( OnEvent..., "..._НОМЕР_ДВАДЦАТЬ_ДВА" )

--...

--... ЕЩЕ ВОСЕМЬ ТАКИХ ЖЕ РЕГИСТРАЦИЙ ХЭНДЛЕРОВ

--...

common.RegisterEventHandler( OnEventЯУжеОпухЭтоПисатьНомерТридцатьОдин, "EVENT_Я_УЖЕ_ОПУХ_ЭТО_ПИСАТЬ_НОМЕР_ТРИДЦАТЬ_ОДИН" )

--...

--... остальная часть Инита

end -- еще одна простыня поменьше

--------------------------------------------------------------------------------

Init() -- Наконец-то!

--------------------------------------------------------------------------------

Теперь считаем пальцем, сколько всего нужно помнить, чтоб добавить сюда еще один ивент-хэндлер:

  • Надо ПРИДУМАТЬ а потом помнить имена хэндлеров(код-стандарт обязывает):

OnEventСложноеИмяЭвентаНомерРазOnEventИмяЭвентаЕщеСложнееНомерДваOnEventСовсемНечитаемоеИмяЭвентаНомерТриOnEventНеИмяАКакаяТоДракулаНомерЧетыре...еще 26 подобных имен...OnEventЯУжеОпухЭтоПисатьНомерТридцатьОдин

Надо помнить, где регистрировали каждый из них. После определения нового хэндлера добро пожаловать "скроллить весь код"( в два разных места ) чтоб скопипастить регистрацию и для него тоже; и ОЧЕНЬ легко забыть это сделать. А потом мучительно охреневать, почему свеженаписанное не работает.

Итого помнить: 33 пункта + легкий общий геморрой.

Теперь "промышленный" метод разработчиков:

Code:
--------------------------------------------------------------------------------

Global( "baseEvents", {} )

Global( "eventsOnDemand", {} )

--------------------------------------------------------------------------------

function baseEvents.СКОПИРОВАННОЕ_ИЗ_АПИ_РЕФЕРЕНСА_ИМЯ_ЕВЕНТА_НОМЕР_ОДИН( params )

--...

-- тело хэндлера

--...

end

--------------------------------------------------------------------------------

function baseEvents.СКОПИРОВАННОЕ_ИЗ_АПИ_РЕФЕРЕНСА_ИМЯ_ЕВЕНТА_НОМЕР_ДВА( params )

--...

-- тело хэндлера

--...

end

--------------------------------------------------------------------------------

--...

--... Еще пятнадцать таких же определений

--...

--------------------------------------------------------------------------------

function eventsOnDemand.СКОПИРОВАННОЕ_ИЗ_АПИ_РЕФЕРЕНСА_ИМЯ_ЕВЕНТА_НОМЕР_ВОСЕМНАДЦАТЬ( params )

--...

-- тело хэндлера

--...

end

--------------------------------------------------------------------------------

function eventsOnDemand.СКОПИРОВАННОЕ_ИЗ_АПИ_РЕФЕРЕНСА_ИМЯ_ЕВЕНТА_НОМЕР_ДЕВЯТНАДЦАТЬ( params )

--...

-- тело хэндлера

--...

end

--------------------------------------------------------------------------------

--...

--... Еще одиннадцать таких же определений

--...

--------------------------------------------------------------------------------

function eventsOnDemand.СКОПИРОВАННОЕ_ИЗ_АПИ_РЕФЕРЕНСА_ИМЯ_ЕВЕНТА_НОМЕР_ТРИДЦАТЬ_ОДИН( params )

--...

-- тело хэндлера

--...

end

--------------------------------------------------------------------------------

-- теперь активация аддона

--------------------------------------------------------------------------------

function ShowAddon( visible ) -- пример регистрации по условию

addonPanel:Show( visible )

--... какая-то часть функции

--...

if visible then

RegisterEventHandlers( eventsOnDemand )

else

UnRegisterEventHandlers( eventsOnDemand )

end

--...

--... остальная часть функции

end

--------------------------------------------------------------------------------

--...

--... Какой-то вспомогательный код, который всегда есть

--... Среди него затерялось ОДНАЖДЫ ОБЪЯВЛЕННОЕ вот это

--------------------------------------------------------------------------------

function RegisterEventHandlers( handlers )

for event, handler in handlers do

common.RegisterEventHandler( handler, event )

end

end

--------------------------------------------------------------------------------

function UnRegisterEventHandlers( handlers )

for event, handler in handlers do

common.UnRegisterEventHandler( handler, event )

end

end

--------------------------------------------------------------------------------

--...

--------------------------------------------------------------------------------

function Init() -- Теперь инициализация

--... какая-то часть функции Инита

--...

RegisterEventHandlers( baseEvents )

--...

--... остальная часть Инита

end

--------------------------------------------------------------------------------

Init()

--------------------------------------------------------------------------------

Опять считаем пальцем, сколько нужно помнить:

  • Именовать хэндлеры не нужно, именами им служат САМИ ИМЕНА ИВЕНТОВ, скопированные из предоставленного разрабами МАНУАЛА. Нужно помнить только имена таблиц
  • baseEvents
  • eventsOnDemand

    дабы их использовать при добавлении новых хэндлеров. При этом И ЕЖУ понятно, что "регистрация по условию" - это про eventsOnDemand, а постоянно работают - baseEvents. Пожалуй, это момент стоит тоже запомнить - +1.

  • Где регистрировали, помнить не надо, там никогда ничего не меняется. После определения нового хэндлера "скроллить" к регистрации не нужно, FOR..EACH-цикл( который никто никогда и не видел ) все сделает сам.

Итого помнить: 3 пункта. ТРИ! И принцип действия, как у ракет с тепловым наведением - объявил и забыл.

Результаты партии: 3 против 33. "Помнить" надо в 11 раз МЕНЬШЕ. Это еще без намеренно не упомянутых реакций виджетов. Вот уж, воистину, "оптимизация ради оптимизации". Об "оторванных кусках реализации" можно смело забыть, что Вы там менять-то собрались так часто, и зачем?

А теперь сарказм ( я предупреждал, держите меня ):

Специально для детей, которым обязательно нужно лопатить код, чтоб посмотреть, что же там именно вызывается по условию, угрюмые бородатые дядьки придумали - внимание! - ИМЕНА ПЕРЕМЕННЫХ, прошу любить, жаловать и пользоваться. Помогает. А для детей, внезапно обнаруживших на своей мышке колесико, которое, о чудо! - можно крутить, не менее бородатые, но гораздо более лютые дядьки придумали быстрый поиск по коду, без которого ни один программер вообще не живет. А вот кручение колесика для него - ночной кошмар и предмет необоримой лени.

Можно попытаться еще что-то поговорить, но приведенный Вами выше "второй вариант" говорит сам за себя очень отчетливо. Он бессмысленный и беспощадный(с), как всякий ценный пушной зверь песец. Никакие "ЗЫИМХО" этого не скрывают. Вот уж точно - "не умеешь сам - научи другого!". Боже, сделай так, чтоб всякий тут пишущий хотя бы разбирался в предмете.

P.S. Таблицы в Lua - основной механизм полноценной жизни, и только в последнюю очередь "универсальные хранилища данных". НЕ ИМХО, учите матчасть.

P.P.S. К слову, сам уже не пользуюсь ни одним из этих "подходов" и не вижу в них никакой сакральной ценности. Просто "промышленный" ОЧЕВИДНО проще в работе.

Надеюсь, что приведенное подробное разъяснение уж закроет тему.

Ссылка на комментарий
Поделиться на другие сайты

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Восстановить форматирование

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.


×
×
  • Создать...

Важная информация

Пользуясь сайтом, вы принимаете Условия использования