Перейти к контенту

Язык Lua. Общие вопросы программирования


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

С чего начинать и где взять.

 

Установка Lua:
http://www.amk-team.ru/forum/index.php?showtopic=11584&p=629106

 

Руководство «Программирование на языке Lua», третье издание:
http://www.amk-team.ru/forum/index.php?showtopic=11584&p=905308

Изменено пользователем Kirgudu
Ссылка на комментарий
Неплохо бы все же добавть проверку на то, что передаваемые функции для регистрации в коллбэках проверялись бы на наличие.

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

 

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

Это тоже не запрещено. Использовать стандартное module.function

Все, кто стоит на моем пути: идите нахрен и там погибните! ©

Ссылка на комментарий

Сорри, это я уже ступил ... задумался о "своем" ... ;-(

 

Добавлено через 19 мин.:

xStream, хотел бы спросить:

А для чего функция 'trigger' вынесена из класса в отдельную локальную?

Ведь так более логично и оптимально

<код удален как ошибочный>

- заодно и events_in_process прямо перед циклом включается (иначе - порой в холостую будет сработывать)

+ не обнаружил сброс прерывания коллбэка (self.__break), т.е. в последующих циклах уже не будут обрабатываться события - добавил сброс.

Изменено пользователем Artos

"Но иногда найдется вдруг чудак, этот чудак все сделает не так ..."© Машина времени

Ссылка на комментарий

Gun12 почитай как в действительности хранятся, складываются, перемножаются числа в памяти компьютера различных типов - видно незнание этого.

 

Код

 

if (i==0.4)

 

может писаться только так

 

if abs(i - 0.4) < eps

 

где eps какое-то маленькое число, точность с которой ты сравниваешь числа. Например, если eps = 0.001 то сравнишь до третьего знака после запятой.

Изменено пользователем Whisper
Ссылка на комментарий
Ведь так более логично и оптимально:

Сделано по принципу "мухи отдельно, котлеты отдельно".

С точки зрения "плоского" кода - да, логичнее и оптимальнее. Но надо разделять две сущности - концентратор и событие. Поэтому я делегирую. Потери минимальны, так как передается объект по ссылке. С точки зрения ООП это гораздо правильнее, да и разгружается объект ивента.

 

+ не обнаружил сброс прерывания коллбэка (self.__break), т.е. в последующих циклах уже не будут обрабатываться события - добавил сброс.

Не поняла. Какой сброс? Куда, зачем? Отработанное событие исчезает. В следующий раз создается новое, девственно чистое. Батенька, это ООП :)

 

Добавлено через 13 мин.:

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

 

Добавлено через 15 мин.:

Поняла, почему ты так сделал :-D

Ты, походу, не въехал в принцип, на котором работает это все добро. Концентратор существует всегда, событие - с момента создания, потом "выстреливает", проходят все обработчики, после этого событие отправляется в сборщик мусора.

Когда наступает снова такое же событие, создается новый объект-ивент.

Изменено пользователем xStream

Все, кто стоит на моем пути: идите нахрен и там погибните! ©

Ссылка на комментарий

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

 

P.S. А насчет "мух и котлет" - все же ситуация более похожа на "котлеты и соус" ... Кто-то предпочитает макать в соус, а кто-то сразу полить котлету им. :-)

Изменено пользователем Artos

"Но иногда найдется вдруг чудак, этот чудак все сделает не так ..."© Машина времени

Ссылка на комментарий

Ты вот зачеркнул про сброс, а зачеркнуть надо бы и остальное :)

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

ИМХО, конечно. Но это действительно делает код аккуратнее.

 

В С++ есть даже негласное правило - если метод состоит из больше чем 20-ти строк, то надо переписывать, или стараться оптимизировать.

 

P.S. А насчет "мух и котлет" - все же ситуация более похожа на "котлеты и соус" ... Кто-то предпочитает макать в соус, а кто-то сразу полить котлету им. :-)

Глупая игра слов. Я архитектор приложений уже три года. Насмотрелась всякого.

Изменено пользователем xStream

Все, кто стоит на моем пути: идите нахрен и там погибните! ©

Ссылка на комментарий

xStream, оставил по двум причинам: а) как историю обсуждения/ошибок и б) все же толика разумного осталась, т.е. в кодах локальной функции перенести установку/сброс events_in_process ближе к циклу (после проверки callbacks_recipients[callback_name]):

-- event callbacks can trigger another events but they must have different type
local function trigger(evt)
  
  local callback_name = evt:name()
  if callback_name then
    if callbacks_recipients[callback_name] then
      -- hang debug
      events_in_process[callback_name] = evt
      
      for _,funct in ipairs(callbacks_recipients[callback_name]) do
        if evt.__break == true then
          break
        end
        funct(evt)
      end
    
      -- hang debug
      events_in_process[callback_name] = nil
    end
  end
    
  -- hang debug
  if #events_in_process>0 then
    for evt_name, lost_event in pairs(events_in_process) do
      local err = "sandbox error: event '" .. evt_name .. "' has hanged with fingerprint: " .. (lost_event.__dbg_fingerprint or 0)
      vis_log(err)
    end
    abort("Sandbox fatal error. See info above")
  end
  
end

т.к. с пустым именем и без регистрации события - нечего и обрабатывать ...

(ошибочный код удалил)

Изменено пользователем Artos

"Но иногда найдется вдруг чудак, этот чудак все сделает не так ..."© Машина времени

Ссылка на комментарий

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

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

Изменено пользователем xStream

Все, кто стоит на моем пути: идите нахрен и там погибните! ©

Ссылка на комментарий

xStream, не нужно так строго к словам отниситься.

1. Неудачно выразился, подразумечая под 'пустым' - отсутствие имени события.

2. Заносить в events_in_process процесс, который заведомо не будет обрабатываться, чтобы потом этот стек от него очищать - это имеет какую-либо цель? Ведь единственное где может теоретически зависнуть кроме как в цикле обработки - это при парсинге таблица входых параметров для триггера. А это отлавливается/отлаживается на начальной стадии. (ИМХО)

Изменено пользователем Artos

"Но иногда найдется вдруг чудак, этот чудак все сделает не так ..."© Машина времени

Ссылка на комментарий

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

Мы проверяем на наличие незавершившихся ивентов, а не текущего.

То есть я про то место, не где мы помещаем в этот стек, а проверяем, не пустой ли он.

Изменено пользователем xStream

Все, кто стоит на моем пути: идите нахрен и там погибните! ©

Ссылка на комментарий

xStream, понятно, мы просто о разном, хотя и об одно м и том же (каламбур получился).

Я о регистрации текущего события в массиве, а ты об уже проверке всего этого массива на этапе завершения ...

 

(проверку всего массива уже вернул)

Изменено пользователем Artos

"Но иногда найдется вдруг чудак, этот чудак все сделает не так ..."© Машина времени

Ссылка на комментарий

Про регистрацию я не спорю, все верно. Лишнее действие.

А вот проверку - надо вернуть как было, чтоб всегда проверялось

 

Добавлено через 3 мин.:

Мог бы и не пояснять, я как бы не глупая, все поняла по коду :)

Все, кто стоит на моем пути: идите нахрен и там погибните! ©

Ссылка на комментарий

xStream, кстати, ранее в подобном регистраторе от АМК была возможность подписываться на коллбэк со своим параметром (user_object вроде называлось). ИМХО удобно иногда. Если прикрутить к регистрации типа:

function event:register(funct, uo)

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

Простейший пример применения: Спавним некий объект в ящик, подписываемся на коллбэк на взятие из ящика с uo=ID, и обрабатываем коллбэки, дожидаясь своего, т.е. с нашим ID, после чего отрегистрируемся от коллбэка (вот где и отрегистрация востребована!). Не нужно создавать где-то свою запоминалку ...

(хотя ... еще подумав ... это уже опять из категории котлет и кетчупа, т.е. вкусов)

 

Все, заканчиваю флудить. Срастил оба варианта и начал на практике сравнивать, пока результаты отличные.

Изменено пользователем Artos

"Но иногда найдется вдруг чудак, этот чудак все сделает не так ..."© Машина времени

Ссылка на комментарий

То, что было в амк - зачаточная идея, ну совсем зачаточная.

Если прикрутить к регистрации типа: function event:register(funct, uo)

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

Внутри песочницы придется реализовывать код, который будет заниматься сравнением и по сути выполнять e:stop(). Это логика явно не ядра. Каждый должен разгребать свое дерьмо сам, извиняюсь за такую метафору :)

Пример: подписана куча колбеков. Срабатывает ивент, попадается нужный ящик, стопаем процессинг очереди колбеков. Все, та же механика получается.

 

Про отрегистрацию мне вообще непонятно. Зачем? Зачем вешать избыточные одноразовые колбеки? Вот это мне действительно не понятно. Сделать то ее не сложно - функции можно сравнивать в ЛУА оператором ==.

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

 

Добавлено через 16 мин.:

Хотя ты мне подкинул одну очень интересную мысль :)

Надо покумекать...

Мысль следующая: подавать то можно и безымянные функции, что в принципе и приведет к тому, что можно это считать твоим юзер-обжект. А в объект-ивент добавить event:removeThis() - будет приводить к тому, что только что вызванный колбек после выполнения будет удален (отрегистирован).

Вот при таком подходе польза несомненна.

Изменено пользователем xStream

Все, кто стоит на моем пути: идите нахрен и там погибните! ©

Ссылка на комментарий
xStream: Про отрегистрацию мне вообще непонятно. Зачем? Зачем вешать избыточные одноразовые колбеки?

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

Еще пример: Обработка пояса у меня построена на следующем алгоритме:

1. В ящик кладем фейк предмет. Регистрируем коллбэк на взятие предметов актором, потерю или открытие инвентаря.

2. Как только срабатывает коллбэк на взятие/потерю/открытие - трансферим фейк-предмет актору и регистрируем коллбэк апдейта актора.

3. За четыре такта апдейта обрабатываем 'поясной' алгоритм.

4. Отрегистрируем коллбэк апдейта актора и возвращаем фейк-предмет в ящик.

... и далее по факту нового взятия/...

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

И таких примеров иль иного характера немало.

 

А по 'uo' - регистрация на коллбэк 'таймер' могут выставляться одним и тем же модулем по нескольку раз. Имея метку какой-же сработал - достаточно просто идентифицировать и событие зарегистрировавшее этот коллбэк.

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

Изменено пользователем Artos

"Но иногда найдется вдруг чудак, этот чудак все сделает не так ..."© Машина времени

Ссылка на комментарий

Ты слишком узко мыслишь :)

Регистрацию колбеков, естественно, можно делать в любой момент, но не стоит забывать их заново биндить, если они еще нужны, на следующую загрузку.

То, что я описала выше, сделала. Получилось очень интересно, на мой взгляд.

Ссылка та же - http://dl.dropbox.com/u/46539648/xs_sandbox.script

Работает просто - неважно, как был зарегистрирован колбек, но можно после его выполнения его отрегистрировать, достаточно внутри него выполнить e:removeThisCallback()

 

Прогон "вхолостую", как ты выразился дает мизернейшие накладные расходы. Изучив природу ЛУА, я давно не занимаюсь такой дурацкой оптимизацией :)

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

 

И еще раз говорю - 'uo' не нужны. Пользуйтесь либо безымянными функциями, либо как то иначе организовывайте. НЕЛЬЗЯ ядро заставлять выполнять не свою работу.

 

Добавлено через 16 мин.:

Обновила сам архив, чтоб непоняток не было - http://dl.dropbox.com/u/46539648/xs_sandbox.rar

Изменено пользователем xStream

Все, кто стоит на моем пути: идите нахрен и там погибните! ©

Ссылка на комментарий

xStream, именно об этом (callbacks_recipients[callback_name][id] = nil) я и глаголил ... невнятно.

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

"Но иногда найдется вдруг чудак, этот чудак все сделает не так ..."© Машина времени

Ссылка на комментарий

Да я поняла, но произвольная отписка требует финтов ушами, а такая, как у меня - нет, она простая и семантичная.

Все, кто стоит на моем пути: идите нахрен и там погибните! ©

Ссылка на комментарий

Однако, простота и семантичность в одном, порой приводит кучерявости и сложностям в другом.

Вот например ситуации, когда простота приводит к плохим последствиям:

Вспомним о том, что не редко игра с модами рушится при загрузке, а чаще при сэйвах/выходах из игры.

Многие модмейкеры идут простым путем, ставя колбэки на тэйк/дроп в самые различные модули/скрипты. Причем кол-во таких модулей в модах возрастает. Но многие и не подозревают, что в моменты спавна актора и его дестроем (колбэки уже зарегистрированы! или взведены на постоянку) возникают лавинные вброс/выброс в игру в/из инветарь всего того барахла, который насобирал актор. Все это нередко приводит и к лагам на старте и выходе из игры, к коллизиям между обработчиками коллбэков и т.п.

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

 

ИМХО, все же подобный сэндбокс именно интегратор-коммутатор (концентратор), котороый и должен максимально взять на себя эту работу и не только тупо транслировать события действиям, а и иметь возможность разруливать в нужное время и в нужных ситуациях.

Да, от должен быть достаточно простым и понятным, надежным по максимуму. Но и не перекладывать с себя то, что ему то и следует делать.

Твоя позиция все же близка к тому, что вот этот кусок сделан очень хорошо и функционально - а дальше не мои проблему/заморочки, разгребайте мусор сами руками ... Моя же в том, чтобы все радотало в целом и 'мусор' разгребали все (узлы/модули в моде), и в первую очередь те, которые и предназначены для "уборки". У модулей в первую очередь их функционал, а связка их и взаимодействие - как раз на концентраторе. Перекладывать его работу на другие коды, дробить по несвязанным кускам и т.п. - как раз снижает эффективность и функциональность центральноо коммутатора.

Почти закончил перевод кода на вариант с ООП (классом) - чуть позже проверим на "вшивость" ... если учесть что на ~50 коллбэков более 400 подписчиков - то проверка неплохая получается.

 

"Но иногда найдется вдруг чудак, этот чудак все сделает не так ..."© Машина времени

Ссылка на комментарий

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

Изменено пользователем xStream

Все, кто стоит на моем пути: идите нахрен и там погибните! ©

Ссылка на комментарий

Создайте аккаунт или авторизуйтесь, чтобы оставить комментарий

Комментарии могут оставлять только зарегистрированные пользователи

Создать аккаунт

Зарегистрировать новый аккаунт в нашем сообществе. Это несложно!

Зарегистрировать новый аккаунт

Войти

Есть аккаунт? Войти.

Войти
  • Недавно просматривали   0 пользователей

    • Ни один зарегистрированный пользователь не просматривает эту страницу.
×
×
  • Создать...