Jump to content
Alloder.pro  about Allods with love 😱
Search In
  • More options...
Find results that contain...
Find results in...

Servers monitoring and the Addons Editor

We present you two legends. All dreams come true.

Servers monitoring The Addons Editor

Digest April

We talk about what was done and updated in the past month. We help keep abreast of events.

Read more

Game tooltips

Tooltips provide a way for 3rd party fansites and extensions to display detailed information on mouseover.

Read more

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


 Share

Recommended Posts

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

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

Что сделано:

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

Link to comment
Share on other sites

  • Replies 60
  • Created
  • Last Reply

Top Posters In This Topic

Guest Valltron

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

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

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

Link to comment
Share on other sites

Шас заканчиваю обновление. Прикрутил там работу с 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 голова хорошо, а гидра рулит *))))

Link to comment
Share on other sites

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

Link to comment
Share on other sites

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

Link to comment
Share on other sites

Инициатива похвальная, круто. Но только исполнение пока излишне большое, дырявое и тем самым малоэффективное. Без обид, ты сам попросил поучаствовать. Нарожать оберток можно вагон, но их потом менеджить запаришься, да и не нужны они по-хорошему. В 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++).

Link to comment
Share on other sites

Guest Valltron

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

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

Link to comment
Share on other sites

Guest Valltron

посидел поизучал код... тоже неасилил. 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 про аддоны, но всетаки рекомендую поизучать лутинфо, может найдешь полезного чтонить для оптимизации и реализации.

Link to comment
Share on other sites

Guest Demens

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

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

Link to comment
Share on other sites

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

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

Link to comment
Share on other sites

Guest Demens

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

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

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

Link to comment
Share on other sites

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

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

Link to comment
Share on other sites

Guest Cyberserge

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

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

if "условие" then

RegisterEventHandlers( onEvent )

end

Link to comment
Share on other sites

Guest Demens

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

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

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 ) причем усложнит существенно...

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

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

Link to comment
Share on other sites

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

Link to comment
Share on other sites

Guest Demens

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

Link to comment
Share on other sites

Guest Cyberserge

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

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

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

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

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

Link to comment
Share on other sites

Guest Valltron

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

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

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 

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

Link to comment
Share on other sites

Guest Demens

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

З.Ы. ИМХО

to wait:

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

Link to comment
Share on other sites

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

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

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

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. К слову, сам уже не пользуюсь ни одним из этих "подходов" и не вижу в них никакой сакральной ценности. Просто "промышленный" ОЧЕВИДНО проще в работе.

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

Link to comment
Share on other sites

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

 Share


×
×
  • Create New...

Important Information

By using our site you agree to the Terms of Use