Artos 99 Опубликовано 20 Декабря 2011 (изменено) xStream, kamikazze Бессмысленно оффтопить на тему вкусов и предпочтений. Моя ответная реплика была обусловлена только категоричностью оценки того, что я считаю "не совсем дерьмом". И не более! Не собираюсь никого агитировать за венгерку или еще за что-либо (кроме конечно семантики в наименованиях!). xStream, а определение 'привычное' употребил в том смысле, что большУю часть времени провожу за чтением кодов как оригинала, так и различных модов, так что то, что и я плохо приемлю - стало именно привычным. Меня, например, бесят 'npc' иль 'obj' - что означает достаточно расплывчатое определение того, что же подразумевает автор кода ... но это именно уже привычное (но не приемлемое!). Так что чем махать шашками, стОит вчитаться именно в семантику фразы и принять во внимание НЕ тождественность понятий: 'привычное' и 'предпочтительное'. ;-) kamikazze: ... код нечитаем, так как постоянная смена регистра вызывает "рваное" восприятие имен А ты не находишь, что принятое употребление заглавных букв в именах собственных, начале предложений, аббревиатур и т.п. - тоже сродни рваному нечитаемому? А ведь это именно выделение регистром особенностей текста/слов. По аналогии в венгерке выделены особенности в наименованиях переменных ... Если следовать логике - то уже привычное многим НЕ употребление заглавных букв в простых текстах, знаков препинания и т.п. - верх "понятного и читабельного" текста (и глаза не скачат и только буковки одного размера). И зачем модераторы/кураторы за грамотность радеют? ;-) (это я малость ерничаю). Не буду далее спорить, но немало, в свое время пообщавшись и почитав в сетях FIDO - не такая "рвань" становится не только понятной, но и привычной, а смена регистра позволяет по сути из набора привычных буковок выстраивать новые конструкции, которые при умелом и привычном применении становятся даже очень востребованными и воспринимаемыми. Далее врядли стОит продолжать (<= O! как раз пример того, как выделить сменой регистра ударение в слове, не имея под рукою иного средства!) ... и хулить иль навязывать вкусы/предпочтения. Все же это не столь программирование, сколько форма воплощения алгоритма в читабельное воплощение. P.S. Кстати, пришло на ум: А почему ник xStream выбран той, кому такое написание (аля-венгерка) глаза режет? (это не поддевка, а только размышление на тему). @>-`-,--`,-- Добавлено через 31 мин.: alpet, ну тогда при отключаемом Luacap функциональнее типа так: logmsg = function() end --/ заглушка if ODS then --/ при активном Luacap logmsg = ODS (msg, flags) elseif log1 then --/ при наличии расширителя logmsg = log1(msg) else --/ обычный вывод в лог logmsg = printf(msg) end - дабы в лог выводить при любом раскладе ... Изменено 20 Декабря 2011 пользователем Artos "Но иногда найдется вдруг чудак, этот чудак все сделает не так ..."© Машина времени Поделиться этим сообщением Ссылка на сообщение
Artos 99 Опубликовано 20 Декабря 2011 (изменено) Andrey07071977, вероятнее всего где-то описАлся. У меня в моде основной файл (по сути коммутатор между модулями) построен на половину именно применением оператора '...' , и практически все коллбэки и пр. с аргуменами идут во все модули именно через этот оператор. --/------------------------------------------------------------------ --/ общий обработчик для коллбэков local function do_callback(tCallback,...) for _,o in ipairs(tCallback) do o.func(o.uo,...) end end --/------------------------------------------------------------------ function on_new_game(...) do_callback(tCallbacks.new_game,...) end function on_pda_load(...) do_callback(tCallbacks.pda_load,...) end --/------------------------------------------------------------------ function on_fakebox(...) do_callback(tCallbacks.fakebox,...) end --/------------------------------------------------------------------ function on_npc_update(...) do_callback(tCallbacks.npc_update,...) end function on_mob_update(...) do_callback(tCallbacks.mob_update,...) end --/------------------------------------------------------------------ function on_npc_load(...) do_callback(tCallbacks.npc_load,...) end function on_mob_load(...) do_callback(tCallbacks.mob_load,...) end --/------------------------------------------------------------------ function on_npc_save(...) do_callback(tCallbacks.npc_save,...) end function on_mob_save(...) do_callback(tCallbacks.mob_save,...) end --/------------------------------------------------------------------ function on_net_spawn(...) do_callback(tCallbacks.net_spawn,...) end function on_mob_net_spawn(...) do_callback(tCallbacks.mob_net_spawn,...) on_net_spawn(...) end function on_npc_net_spawn(...) do_callback(tCallbacks.npc_net_spawn,...) on_net_spawn(...) end --/------------------------------------------------------------------ function on_respawn(...) do_callback(tCallbacks.respawn,...) end --/------------------------------------------------------------------ function on_net_destroy(...) do_callback(tCallbacks.net_destroy,...) end function on_npc_net_destroy(...) do_callback(tCallbacks.npc_net_destroy,...) on_net_destroy(...) end function on_mob_net_destroy(...) do_callback(tCallbacks.mob_net_destroy,...) on_net_destroy(...) end --/------------------------------------------------------------------ function on_death(...) do_callback(tCallbacks.death,...) end function on_npc_death(...) do_callback(tCallbacks.npc_death,...) on_death(...) end function on_mob_death(...) do_callback(tCallbacks.mob_death,...) on_death(...) end function on_actor_death(...) do_callback(tCallbacks.actor_death,...) tCallbacks.item_drop = {} --/#?# TODO: уточнить: а нужно ли все чистить? end --/------------------------------------------------------------------ function on_offline_death(...) --/#?# TODO: уточнить do_callback(tCallbacks.offline_death,...) end --/------------------------------------------------------------------ function on_hear(...) do_callback(tCallbacks.hear,...) end function on_npc_hear(...) do_callback(tCallbacks.npc_hear,...) on_hear(...) end function on_mob_hear(...) --/#?# reserve do_callback(tCallbacks.mob_hear,...) on_hear(...) end --/------------------------------------------------------------------ function on_actor_hit(...) do_callback(tCallbacks.actor_hit,...) end function on_hit(...) do_callback(tCallbacks.hit,...) end function on_npc_hit(...) do_callback(tCallbacks.npc_hit,...) on_hit(...) end function on_mob_hit(...) do_callback(tCallbacks.mob_hit,...) on_hit(...) end --/------------------------------------------------------------------ function on_enemy_see_actor(...) do_callback(tCallbacks.enemy_see_actor,...) end function on_actor_see_enemy(...) do_callback(tCallbacks.actor_see_enemy,...) end --/------------------------------------------------------------------ function on_npc_shot_actor(...) do_callback(tCallbacks.npc_shot_actor,...) end --/------------------------------------------------------------------ function on_info(...) do_callback(tCallbacks.info,...) end --/------------------------------------------------------------------ function on_change_hud(...) do_callback(tCallbacks.change_hud,...) end --/------------------------------------------------------------------ function on_task(...) do_callback(tCallbacks.task,...) end --/------------------------------------------------------------------ function on_trade(...) do_callback(tCallbacks.trade,...) end --/------------------------------------------------------------------ function on_use(...) do_callback(tCallbacks.use,...) end function on_use_npc(...) do_callback(tCallbacks.use_npc,...) on_use(...) end function on_use_mob(...) do_callback(tCallbacks.use_mob,...) on_use(...) end --/------------------------------------------------------------------ function on_item_use(...) do_callback(tCallbacks.item_use,...) end --/------------------------------------------------------------------ function on_item_take(...) do_callback(tCallbacks.item_take,...) end --/------------------------------------------------------------------ function on_item_take_from_box(...) do_callback(tCallbacks.item_take_from_box,...) end --/------------------------------------------------------------------ function on_item_drop(...) do_callback(tCallbacks.item_drop,...) end --/------------------------------------------------------------------ За все время не было повода грешить на потерю/искажение передачи аргументов. И я бы не сказал, что "те же помидоры", хоть и малые, но ресурсы расходует (доп.линки и пр. требуют байтов в памяти и тактов). А вот с unpack в свое время так и не нашел ответа, столкнувшись в игре с ограничением буфера/таблицы в ~2048 байт (точно не помню). Для передачи аргументов это конечно не критично (за глаза хватит), но использовать уже стараюсь с опаскою ... Изменено 20 Декабря 2011 пользователем Artos "Но иногда найдется вдруг чудак, этот чудак все сделает не так ..."© Машина времени Поделиться этим сообщением Ссылка на сообщение
Artos 99 Опубликовано 21 Декабря 2011 (изменено) xStream, посмотрел коды сендбокса ... приятно удивлен. :-) Как уже упомянул, показалось знакомым и ... даже не на 50% а на почти 100%. Ведь это же продолжение развития того, что было заложено в АМК-моде, кастрировано в ЧН (xr_s.script) и чем собственно сам занимаюсь эти годы моддинга Сталкера. Т.е. это интегратор (каркас конструктора) на котором можно строить любой по функциональности мод. Только еще бы добавить функционала аля- подзабытый 'xrs_ai.script'. Собственно на эту тему могу говорить очень много, т.к. суть этого сэндбокса и SIMBION'ов - едины, и критиковать/хвалить то, чем занимаешься сложновато. ;-) Вообще-то хотел(хочу) открыть на новый год тему именно по созданию подобного конструктора модов (планировал на базе своего варианта мода) и можно будет отложить делальный 'разбор полетов' и/или продолжить развитие. Не буду сейчас много разглагольствовать в топике по Lua, т.к. суть уже скорее о конкретном алгоритме, а не о нюансах программирования. Пробегусь по основным моментам: Собственно почти(!) все в сэндбоксе так или иначе реализовано у меня в моде, но более кучеряво (в моем варианте). Это и плохо и хорошо. 'Плохо' - - это значит вариант этого сэндвокса более оптимизирован, а 'хорощо' - он менее функционален. По порядку: 1. О функции вывода в лог (vis_log) лучше промолчу ... еще во времена АМК-мода (1.3) это было первое, что я начал править и ... выкинул. В данной реализации еще и ошибка имеется, т.е. 'bufferedmessages' не объявлена таблицей и по сути половина кодов функции - баласт. Да и безопасность кодов на невысоком уровне, что при неумелом использовании 'извне' может обрушить игру. 2. О регистрации модулей: Я все же сторонник выносить из скриптов то, что может потребовать правке игроком или другим модмейкером в конфиг-файл. Неаккуратная запись/правка в скрипте - блокирует весь конфиг-скрипт (xs_sandbox_binds.script), а вот прочитать конфиг-файл (*.ltx) можно и безопасно и пропустить некорректности. Достоиство этого варианта - наличие возможности зависимой регистрации, хотя ее востребованность достаточно низкая (ИМХО) и, учитывая автономность модулей - принятие о (не)регистрации все же (ИМХО) должно быть за модулем (и в начале и в процессе игры), а не за общим конфигом. Ну а в целях отладки (дебаг-режим) в моей реализации все модули разбиты на категории и можно, например, не регистрировать все AI-модули, или все второстепенные (пользовательские). 3. О регистрации коллбэков (событий): Достоинство - сделано на классе, что дает достаточную оптимизацию относительно локальных функций. Однако (ИМХО) не хватает возможности отрегистрации (снять коллбэк) или проверить уже установленный коллбэк (дабы не дублировать). Также может быть востребовано в одном и том же модуле регистрировать многократные коллбэки со своими параметрами (data_table), что в данной реализации невозможно. 4. О работе сэндбокса (trigger): Очень удачно введена проверка на зависание модулей! Подспорье моддейкеру может дать немалое при отладке кодов. С Вашего позволения добавлю в свой вариант аналогичный функционал. Удачно реализована и остановка цепочки обработки одного события (у меня слишком кучеряво сделано). 5. Ну и о том, что бы я подправил: 5.1. В 'event:trigger' чуть хромает логика условий. Ну зачем при 'data_table == nil' пропускать до цикла и даже в него подставлять пустую таблицу, по которой все одно не будет перебора полей? Отсечь все это в самом начале: --/ triggers event function event:trigger(data_table) if type(data_table) == 'table' then for k,v in pairs(tData) do self[k] = v end elseif data_table ~= nil then vis_log("sandbox error: event's data should be a table or nil. " .. type(data_table) .. " is passed") end trigger(self) end - при отсутствии ошибок будет проверяться только одно условие вместо двух и будет исключен цикл при нилевых аргументах. 6. И последнее: все же это не сэндбокс (песочница/механизм для безопасного исполнения программ), а скорее центральный интегратор модулей и коммутатор-синхронизатор с элементами контроля сбоев. Хотя добавить тот же 'pcall' для funct(evt) в принципе не сложно. Пока закругляюсь, хотя на эту тему могу порассуждать очень много ... :-) xStream, осмелюсь все же спросить, а какова причина появления этого кода (сэндбокса)? Это из старых загашников или Вы вновь чуток пробуете кодить для Сталка? Готов в этом случае (для сэнд бокса) быть типа спаринг партнером (критиком) или просто партнером, дабы этот конструктор все же увидел свет (был реализован) в других модах ... Добавлено через 11 мин.: malandrinus, если это все для тех, кто начинает программировать - полностью соглашусь, но если это все же критика того, что, например, мною используется устаревшая рудиментарность - начну оббороняться ... ;-). Мне, например, наплевать, что модно стало пить обезжиренное молоко, есть бутербродное "масло", пить тоники, поменьше соли/сахара и т.п. ... Ел жирное, пил крепкое, солил по вкусу - и буду так делать далее несмотря на "немодность и устарелость". Ваши аргументы весомы, но вы забывете, что они бОльшей частью обусловлены для программирования в проекте/команде, а для одиночек - ХОРОШО то, что удобно именно одиночке! А в моддинге Сталкера по сути уже 95% - это именно одиночки. Корпоративные стандарты и т.п. - хороши на работе, а для хобби удобно то, что именно тебе удобно. Ходить в домашних тапочках по улице конечно же моветон, но дома - именно то, что востребовано. ИМХО. Вот если над подобным сэндбоксом работать вместе, дабы сделать его употребимым в более широком круге модов - то естественно писать коды на более общепринятом языке (нотации). Изменено 21 Декабря 2011 пользователем Artos "Но иногда найдется вдруг чудак, этот чудак все сделает не так ..."© Машина времени Поделиться этим сообщением Ссылка на сообщение
Artos 99 Опубликовано 21 Декабря 2011 (изменено) kamikazze, давай перестанем холиварить и обсуждать/навязывать вкусы других! (алаверды) Также не нужно аргументировать неудобство венгерки с читабельность кодов как чтение обычных текстов ... Так и хочется высказаться: "Не удобано - не читай ...". Коды, по крайней мере мною, пишутся НЕ для публичного прочтения и/или использования в качестве пособия по программированию. Мне так удобнее писать/читать и любые аргументы против этого не имеют никакого значения (для меня). (брек, иначе начну нападать ... ) Изменено 21 Декабря 2011 пользователем Artos "Но иногда найдется вдруг чудак, этот чудак все сделает не так ..."© Машина времени Поделиться этим сообщением Ссылка на сообщение
Artos 99 Опубликовано 21 Декабря 2011 (изменено) xStream: Я написала под действием ностальгии, рада, если кому-то пригодится. Не только пригодится, а будет использовано. Если честно, то давно хотел перевести свои кода аналогичного концентратора на коды класса, но ... и времени не было и достаточной для себя аргуменации. Огромное спасибо за то, что именно несколько положительных достоинств перевесили чашу и потрачу время на модернизацию кода. А двойку - это зря-я-я ... ИМХО, если присутствует подобная примочка, то должна а) минимизировать свое присутствие тратой ресурсов/тактов б) быть функциональной. Для готового продукта, конечноже подобное лучше выкинуть и концентратор сделать 'непробиваемам', но пока код в отладке - концентратор как раз очень удобен для отлова 'всего в купе'. Изменено 21 Декабря 2011 пользователем Artos "Но иногда найдется вдруг чудак, этот чудак все сделает не так ..."© Машина времени Поделиться этим сообщением Ссылка на сообщение
Artos 99 Опубликовано 21 Декабря 2011 (изменено) xStream: Включение/выключение модулей производится тупо удалением файлов или их переименованием Вот тут не соглашусь, порой модуль нужно отрегистрировать от концентратора (коммутатора), но он может иметь коды/функции/таблицы, которые востребованы в других местах. Т.о. удалять/переименовывать - не лучший выход. Изменено 21 Декабря 2011 пользователем Artos "Но иногда найдется вдруг чудак, этот чудак все сделает не так ..."© Машина времени Поделиться этим сообщением Ссылка на сообщение
Artos 99 Опубликовано 21 Декабря 2011 (изменено) kamikazze: Вот этого не стоит делать, сие вредно. Не стоит злоупотреблять контролируемым исполнением кода - расхолаживает ... Давайте все же стараться судить не со своей колокольни и не применительно к некоей, хотя может и досточно широкой, но все же частности. Иметь возможность поместить вызовы в песочницу, дабы хотя бы получить информацию по ошибками - при отладке кода очень востребована. Даже если песочница отлавливает только Lua ошибки - это уже большое подспорье, т.к. большинство ошибок, особенно у начинающих модмейкеров, именно такого характера. Ну а насчет расхолаживать, согласен полностью, но НЕ в ситуации при отладке кодов. У меня, например, сделано так, что при включении ручками дебаг режима включается при необходимости режим песочницы с обязательной трансляцией в лог информации. Это дает хотя бы то, что продвинутый игрок может дать мне уже не куций лог, а достаточно информативный для определения причин проблем. А вот когда песочница становится основой стабильности мода, замазывая огрехи программирования (ситуация в известном моде ;-) ) - это уже иная ситуация и тут с тобою совершенно согласен! Добавлено через 6 мин.: xStream, согласен что зависимостей должно быть по возможности минимум, но ... тут вскрываются противоречия между автономностью модулей и интеграцией всего мода. Писать в каждом модуле однотипные функции, получать однотипные данные и т.д. - это не самый лучший вариан для оптимизации. Автономность и взаимозависимость все же должны иметь некие границы, иначе страдает оптимальность. Как пример, можно привести новостной модуль от АМК и оффлайн-алайф из того же мода. Сканирование всей Зоны достаточно ресурсоемкая операция и делать это в обоих модулях - расточительно. А вот если в качестве базового использовать мастер-модуль, который даже может быть отключенным, но выполнять сканирование - как раз и позволяет не вставлять в коды достаточно большие куски дублирующих функций ... Изменено 21 Декабря 2011 пользователем Artos "Но иногда найдется вдруг чудак, этот чудак все сделает не так ..."© Машина времени Поделиться этим сообщением Ссылка на сообщение
Artos 99 Опубликовано 21 Декабря 2011 xStream, но я все же имею ввиду конечно не скрипт-файл в качестве модуля, а некий законченный фрагмент алгоритма для мода. Конечно же можно писать и в несколько файлов, но тогда начинают расти 'транспортные' расходы передачи информации между файлами оодного модуля ... Ну да это конечно же сильно зависит от контекста, но моя реплика востребованности отключать от регистратора, не удаляя сам файл - имеет мето быть (ИМХО). Хотел бы по багоустойчивости сэндбокса высказать мысль: Неплохо бы все же добавть проверку на то, что передаваемые функции для регистрации в коллбэках проверялись бы на наличие. Нередки ситуации, когда при разработке/отладке кода функции изымаются/переименовываются, а регистратор на коллбэк не подправляется ... т.е. проводят к ситуации вызова уже несуществующей функции. И по функциональности: Также не так редко, событие в одном модуле может потребовать регистрации в коллбэке некоей функции из другого модуля. Неплохо бы дать возможность регистрировать функции кросс-модульно. (Подобное реализовано у меня и попробую перенести в данное исполнение) "Но иногда найдется вдруг чудак, этот чудак все сделает не так ..."© Машина времени Поделиться этим сообщением Ссылка на сообщение
Artos 99 Опубликовано 21 Декабря 2011 (изменено) Сорри, это я уже ступил ... задумался о "своем" ... ;-( Добавлено через 19 мин.: xStream, хотел бы спросить: А для чего функция 'trigger' вынесена из класса в отдельную локальную? Ведь так более логично и оптимально <код удален как ошибочный> - заодно и events_in_process прямо перед циклом включается (иначе - порой в холостую будет сработывать) + не обнаружил сброс прерывания коллбэка (self.__break), т.е. в последующих циклах уже не будут обрабатываться события - добавил сброс. Изменено 21 Декабря 2011 пользователем Artos "Но иногда найдется вдруг чудак, этот чудак все сделает не так ..."© Машина времени Поделиться этим сообщением Ссылка на сообщение
Artos 99 Опубликовано 21 Декабря 2011 (изменено) xStream, нет, въехал, но ... сложновато переключаться между двумя реализациями аналогичных алгоритмов и ... пока голова все еще мыслит/сбивается на прежние категории. P.S. А насчет "мух и котлет" - все же ситуация более похожа на "котлеты и соус" ... Кто-то предпочитает макать в соус, а кто-то сразу полить котлету им. :-) Изменено 21 Декабря 2011 пользователем Artos "Но иногда найдется вдруг чудак, этот чудак все сделает не так ..."© Машина времени Поделиться этим сообщением Ссылка на сообщение
Artos 99 Опубликовано 21 Декабря 2011 (изменено) 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 т.к. с пустым именем и без регистрации события - нечего и обрабатывать ... (ошибочный код удалил) Изменено 21 Декабря 2011 пользователем Artos "Но иногда найдется вдруг чудак, этот чудак все сделает не так ..."© Машина времени Поделиться этим сообщением Ссылка на сообщение
Artos 99 Опубликовано 21 Декабря 2011 (изменено) xStream, не нужно так строго к словам отниситься. 1. Неудачно выразился, подразумечая под 'пустым' - отсутствие имени события. 2. Заносить в events_in_process процесс, который заведомо не будет обрабатываться, чтобы потом этот стек от него очищать - это имеет какую-либо цель? Ведь единственное где может теоретически зависнуть кроме как в цикле обработки - это при парсинге таблица входых параметров для триггера. А это отлавливается/отлаживается на начальной стадии. (ИМХО) Изменено 21 Декабря 2011 пользователем Artos "Но иногда найдется вдруг чудак, этот чудак все сделает не так ..."© Машина времени Поделиться этим сообщением Ссылка на сообщение
Artos 99 Опубликовано 21 Декабря 2011 (изменено) xStream, понятно, мы просто о разном, хотя и об одно м и том же (каламбур получился). Я о регистрации текущего события в массиве, а ты об уже проверке всего этого массива на этапе завершения ... (проверку всего массива уже вернул) Изменено 21 Декабря 2011 пользователем Artos "Но иногда найдется вдруг чудак, этот чудак все сделает не так ..."© Машина времени Поделиться этим сообщением Ссылка на сообщение
Artos 99 Опубликовано 21 Декабря 2011 (изменено) xStream, кстати, ранее в подобном регистраторе от АМК была возможность подписываться на коллбэк со своим параметром (user_object вроде называлось). ИМХО удобно иногда. Если прикрутить к регистрации типа: function event:register(funct, uo) то можно и отрабатывать этот параметр, хотя в регистраторе придется на табличку переделать (что не сложно и необременительно, вроде как). Простейший пример применения: Спавним некий объект в ящик, подписываемся на коллбэк на взятие из ящика с uo=ID, и обрабатываем коллбэки, дожидаясь своего, т.е. с нашим ID, после чего отрегистрируемся от коллбэка (вот где и отрегистрация востребована!). Не нужно создавать где-то свою запоминалку ... (хотя ... еще подумав ... это уже опять из категории котлет и кетчупа, т.е. вкусов) Все, заканчиваю флудить. Срастил оба варианта и начал на практике сравнивать, пока результаты отличные. Изменено 21 Декабря 2011 пользователем Artos "Но иногда найдется вдруг чудак, этот чудак все сделает не так ..."© Машина времени Поделиться этим сообщением Ссылка на сообщение
Artos 99 Опубликовано 21 Декабря 2011 (изменено) xStream: Про отрегистрацию мне вообще непонятно. Зачем? Зачем вешать избыточные одноразовые колбеки? Выше вроде пояснил примером. Для чего вешать при регистрации модуля на старте игры, если этот коллбэк нужен только в некоторые моменты? Можно конечно в самом модуле его не обрабатывать, но не проще ли просто НЕ устанавливать в начале, атолько тогда когда потребовалось. И снимать не по завершению игры, а когда в коллбэке отпала нужда. Еще пример: Обработка пояса у меня построена на следующем алгоритме: 1. В ящик кладем фейк предмет. Регистрируем коллбэк на взятие предметов актором, потерю или открытие инвентаря. 2. Как только срабатывает коллбэк на взятие/потерю/открытие - трансферим фейк-предмет актору и регистрируем коллбэк апдейта актора. 3. За четыре такта апдейта обрабатываем 'поясной' алгоритм. 4. Отрегистрируем коллбэк апдейта актора и возвращаем фейк-предмет в ящик. ... и далее по факту нового взятия/... Т.о. самый нагруженный коллбэк апдейта актора востребован и обрабатывается только по факту, а не висит постоянно. И таких примеров иль иного характера немало. А по 'uo' - регистрация на коллбэк 'таймер' могут выставляться одним и тем же модулем по нескольку раз. Имея метку какой-же сработал - достаточно просто идентифицировать и событие зарегистрировавшее этот коллбэк. И опять же, сработали все таймеры - и надобность регистрации модуля в подписке на коллбэк отпала. Зачем в холостую гонять циклы по всем модулям? Изменено 21 Декабря 2011 пользователем Artos "Но иногда найдется вдруг чудак, этот чудак все сделает не так ..."© Машина времени Поделиться этим сообщением Ссылка на сообщение
Artos 99 Опубликовано 21 Декабря 2011 xStream, именно об этом (callbacks_recipients[callback_name][id] = nil) я и глаголил ... невнятно. Разница в том, что ты сделала вариант с отпиской из текущего коллбэка, а я говорил о более расширенном варианте, чтобы модуль не дожидаясь конца очередного коллбэка мог бы отписываться от него. "Но иногда найдется вдруг чудак, этот чудак все сделает не так ..."© Машина времени Поделиться этим сообщением Ссылка на сообщение
Artos 99 Опубликовано 22 Декабря 2011 Однако, простота и семантичность в одном, порой приводит кучерявости и сложностям в другом. Вот например ситуации, когда простота приводит к плохим последствиям: Вспомним о том, что не редко игра с модами рушится при загрузке, а чаще при сэйвах/выходах из игры. Многие модмейкеры идут простым путем, ставя колбэки на тэйк/дроп в самые различные модули/скрипты. Причем кол-во таких модулей в модах возрастает. Но многие и не подозревают, что в моменты спавна актора и его дестроем (колбэки уже зарегистрированы! или взведены на постоянку) возникают лавинные вброс/выброс в игру в/из инветарь всего того барахла, который насобирал актор. Все это нередко приводит и к лагам на старте и выходе из игры, к коллизиям между обработчиками коллбэков и т.п. Конечно можно/нужно в каждом модуле озаботиться и с производительностью и багоустойчивостью и пр. Но(!) не проще ли это сделать в одном месте! Если дать возможность модулям подписываться на коолбэк не сразу, а позже (после появления экрана) - это снимет стартовый лаг/коллизии. Если же одним коллбэком по началу сэйва иль по деструктору актора останаливать/снимать коллбэк на дропы (а лучше подписки на него) - верятность в модах нарваться на вылеты и битые сэйвы резко снизится. ИМХО, все же подобный сэндбокс именно интегратор-коммутатор (концентратор), котороый и должен максимально взять на себя эту работу и не только тупо транслировать события действиям, а и иметь возможность разруливать в нужное время и в нужных ситуациях. Да, от должен быть достаточно простым и понятным, надежным по максимуму. Но и не перекладывать с себя то, что ему то и следует делать. Твоя позиция все же близка к тому, что вот этот кусок сделан очень хорошо и функционально - а дальше не мои проблему/заморочки, разгребайте мусор сами руками ... Моя же в том, чтобы все радотало в целом и 'мусор' разгребали все (узлы/модули в моде), и в первую очередь те, которые и предназначены для "уборки". У модулей в первую очередь их функционал, а связка их и взаимодействие - как раз на концентраторе. Перекладывать его работу на другие коды, дробить по несвязанным кускам и т.п. - как раз снижает эффективность и функциональность центральноо коммутатора. Почти закончил перевод кода на вариант с ООП (классом) - чуть позже проверим на "вшивость" ... если учесть что на ~50 коллбэков более 400 подписчиков - то проверка неплохая получается. "Но иногда найдется вдруг чудак, этот чудак все сделает не так ..."© Машина времени Поделиться этим сообщением Ссылка на сообщение
Artos 99 Опубликовано 23 Декабря 2011 (изменено) xStream, ну тогда сменим ракурс нашего обсуждения. Причиной нашего взаимного непонимания, по крайней мере с моей стороны, послужило то, что ты выложила свой вариант (см. #159) именно в связке с песочницей by Andrey07071977. Дополнтельно, довольно вольное определение 'песочница' с твоей стороны, также послужило причиной разговора о разных вещах. Все же общеупотребимое понятие: Песо́чница (англ. sandbox) — в компьютерной безопасности механизм для безопасного исполнения программ Песочница обычно предоставляет собой жёстко контролируемый набор ресурсов для исполнения гостевой программы — например, место на диске или в памяти. Доступ к сети, возможность сообщаться с главной операционной системой или считывать информацию с устройств ввода обычно либо частично эмулируют, либо сильно ограничивают. Песочницы представляют собой пример виртуализации. Повышенная безопасность исполнения кода в песочнице зачастую связана с большой нагрузкой на систему — именно поэтому некоторые виды песочниц используют только для неотлаженного или подозрительного кодаТ.о. хотя твой вариант и подразумевает создание некой выделенной среды для кросс-модульной коммутации событий, но никоим образом не имеет отношения к безопасному исполнению кодов ... хотя и дает возможность выявлять сбои в исполняемых кодах(!). Хорошо, давай говорить об именно концепте, а не уже практическом воплощении в играбельный вариант для 'кучерявого' мода ... ;-) Обнаружил довольно значительный недостаток в твоем варианте, корнями уходящий в идеологию линейного/плоского кода: В данной реализации невозможно выполнять события (driven-events), которые являются 'дочерними' (ведомыми) по отношению к основному (event), т.е. генерируются в цикле исполнения основного события. Если в цикле обработки события (event_parent) в подписанных на него модулях произойдет генерация другого события (event_driven) - то это новое сгенерированное событие (event_driven) и его цикл обрабоки приведет к тому, что в конце отработки этого нового сбытия (вложенного по времени в основное событие!) будет вызвана проверка наличия 'зависших' событий (#events_in_process>0) и еще не завершенное (не закончен цикл) родительское событие (event_parent) будет воспринято как зависшее(!). Т.о. произойдет вызов завершения приложения по якобы фатальной ошибке зависшего треда. Примером может являться например такая ситуация: При обработке события "получение актором инфопоршня" в каком-либо модуле может генерироваться дочернее событие, обрабатываемое другими модулями (хотя бы зависимыми от первого) и - сгенерированное новое событие прервет приложение из-за незавершенного пока еще события по инфопоршню. Это ограничение несложно обойти, введя в алгоритм sandbox'а возможность зависимым событиям выставлять некий флаг/признак, по которому игнорировать в 'зависших' незавершенные (а не зависшие) события. ИМХО, такое увеличение сложности все же именно повышает безопасность использования "песочницы" сторонними модулями. Ну или же ... идти по пути еще большей упрощенности, оставим коммутатору-концентратору (сэндбоксу) только транспортный функционал, убрав проверки на зависания и/или прерывание приложения по таким проверкам, что для конечного продукта (релиза мода) может быть и лучше ... P.S. Если будешь дорабатывать в сторону усложнения - хотелось бы увидеть этот доработанный вариант, дабы сравнить решение со своим. Изменено 23 Декабря 2011 пользователем Artos "Но иногда найдется вдруг чудак, этот чудак все сделает не так ..."© Машина времени Поделиться этим сообщением Ссылка на сообщение
Artos 99 Опубликовано 23 Декабря 2011 (изменено) Имел ввиду под усложнением не усложнение интерфейсов, а усложнение функционала, хотя конечно же последнее нередко приводит к первому. И, по-моему, универсальность как раз возрастает при возможности вызывать события из событий, хотя 'простота' чуток падает. У меня как раз обработчик зависших событий работает (хотя код аалогичен твоему). Именно им и обнаружил ограничение по вложенности при адаптации под свои нужды ... Ведь не зря же предлагал заменить '#events_in_process>0' => 'next(events_in_process)' ! ;-) И, если все же интересно, еще некоторый нюанс применения: У меня, например, имеется несколько мест, где одна и та же функция принимает как событие из коллбэка, так и вызов из обычной функции. Т.е. аргументами могут быть как аргументы события коллбэка, так и аргументы стороннего вызова (не события из коллбэка, а некоего иного). То, что в данной реализации в качестве аргумента коллбэка выступает юзердата (класса event) потребовало доп.ухищрений и проверок, дабы не получать коллизии по разным форматам данных. Это к тому, что простота в одном месте приводит к усложнению в другом(других) ... хотя в данном случае суммарный выигрыш по простоте все же за данным вариантом! Изменено 23 Декабря 2011 пользователем Artos "Но иногда найдется вдруг чудак, этот чудак все сделает не так ..."© Машина времени Поделиться этим сообщением Ссылка на сообщение
Artos 99 Опубликовано 23 Декабря 2011 (изменено) xStream, ну про проблемы аттавизмов при адаптации старых кодов - это конечно же понятно. Своей ремаркой хотел обратить внимание по сути на необходимость иметь пару типов коллбэков: тех, которые голобальны и тех, которые узкого применения. Но это уже конечно нюансы архитектуры модов, а не данного концепта. В дополнение кину еще одну косточку для размышлений (не по концепту, а для ... все же тему читают и вдумчивые): ИМХО, может быть (но не в данном концепте, а в его расширенной реализации) стОит предусмотреть четыре типа поведения на различных отрезках игры: - старт и инициализация модулей, среды окружения и игровых объектов (т.е. до появления игрового экрана или чуть позже); - 'штатный' режим игры; - создание сэйва; - завершение игры. Все же и транспортные связи и реакция на события у одних и тех же модулей/функций в этих режимах могут сильно отличаться: вплоть до полного игнорирования события ... Регистрация модулей и подписка только в самом начале игры (при инициализации модулей) все же довольно существенное ограничение (ИМХО). Добавлено через 3 мин.: Но не выстреливать, а просто создавать, заполнять и передавать - получится унифицированность. Жду (но НЕ тороплю!) доработанного варианта - сравним. Не предлагаю - дабы не навешивать шоры ... :-) Изменено 23 Декабря 2011 пользователем Artos "Но иногда найдется вдруг чудак, этот чудак все сделает не так ..."© Машина времени Поделиться этим сообщением Ссылка на сообщение