www.mudconnector.su
https://forum.mudconnector.su/

Фреймворк для билдера
https://forum.mudconnector.su/viewtopic.php?f=15&t=126
Страница 1 из 4

Автор:  omlin [ Пт авг 28, 2009 2:03 pm ]
Заголовок сообщения:  Фреймворк для билдера

Вступление

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

Предыстория

KadVar писал(а):
Как бы это сказать. С++ конечно хороший язык, но причем тут триггера итп ?
Я видел то, что сделали в сфере, простите но мой вывод: "ниже плинтуса".
Продраться через это практически невозможно.
Проблема не в синтаксисе, хотя у С++ он АБСОЛЮТНО не подходит, проблема в библиотеках, которые вы должны создать для нормальной работы.

Код циркловых мадов, таких как былины и хьервард, а по большей части - и адамант, это native Си-код. Иными словами, куча структурок, процедурное программирование, широкое использование дефайнов.

Насчет сферы, это мад с новой кодовой базой. Там, слава богу, нормальный ООП.
И по сравнению с DG-скрипт, это шаг вперед.

Посудите сами, ведь гораздо проще и понятнее фрагмент:
Код:
foreach (Char ch in Room.Chars)  ch.damage(10);

, чем существующая конструкция в DG-скриптах, повторяющая убогость стековой системы циркла:
Код:
set ch %self.people%
while (%ch%)
  set next %ch.next_in_room%
  wdamage %ch.name% 10
  set ch %next%
end


При отсутствии фреймворка, и при наличии ООП в коде мада - я считаю даже вывод С++ - это очень разумный подход. Хотя, конечно, лучше, вывести мад-объекты на более дружественные новичкам скриптовые языки, такие как LUA(http://ru.wikipedia.org/wiki/Lua), python, и т.п.


KadVar писал(а):
Можно открыть все возможности, но как вы будете контролировать то, что понафигачит рядовой билдер ?

Возможностей в любом случае придется открывать немало. Поэтому контроль - это отдельная тема

KadVar писал(а):
Тут вопрос в том, что нужна непротиворечивая надстройка в виде набора необходимых функций. Причем надстройка удобная в работе. Это подразумевает совсем иной уровень, существенно выше того, который обеспечивает к примеру С++. В том числе и уровень контроля над ошибками. Понимаете... средство разработки зон должно быть ориентированно не на программистов вовсе. Это создание именно своего ЯЗЫКА... задача не такая простая, как кажется.

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


Фреймворк

Хочется немного конкретики и примеров. Каким он может быть, этот фреймворк?
Итак, сначала выясним, что же требуется делать билдеру чаще всего:
  • перечислять объекты (чаще всего персонажей, но также и предметы) по определенному фильтру (по комнате, по лидеру, по признаку моб/не моб, по наличию денег, по внумам и т.п. - по сути это может быть произвольный фильтр) и что-нибудь с ними делать
  • выдавать квесты пойди-принеси
  • выводить сообщения по типу act
В общем, это и есть те вещи, которые фреймворк должен максимально упростить.


Перечисления

Думаю, оптимально было бы ввести некую абстрактную конструкцию, например так:
Код:
foreach переменная_объекта in класс_объекта where фильтр
  ** действия над переменной_объекта
next

переменная_объекта - название произвольной переменной, которой будет присвоен "текущий" объект, с которым можно будет оперировать
класс_объекта - один из: персонажи, предметы, комнаты.
фильтр - условие, в котором можно использовать поля персонажей/предметов/комнат

Примеры:
Код:
foreach ch in chars where room=self.room and !is_npc and align>0
  ch.damage(10);
next

Код:
num_of_coins = 0
foreach obj in objects where owner=actor and vnum=8120
  num_of_coins += 2
  obj.purge
next
if num_of_coins>0
  say Отлично, я вижу ты принес то что я просил. Вот твоя награда!
  ** сгенерим монеты, на случай если у нас столько нет
  self.money += num_of_coins
  ** отдадим их тому кто сделал квест
  give actor num_of_coins монет
end

Оба примера предполагаются быть моб-триггерами (self - это моб).
Язык абстрактный, с закосом под адамантовский dg_script.
Первый пример дамажит всех светлых плееров в комнате с текущим мобом.
Второй пример ищет в инвентаре у игрока все предметы с определенным внумом, уничтожает эти предметы и выдает за них по 2 монеты.


Квесты принеси-подай
Это очень частые квесты, и я думаю очень было бы классно, если бы внутри триггеров они были МАКСИМАЛЬНО простыми.
Например, рассмотрим фрагмент:
Код:
register_quest
    init
      cur_time = get_time()
    end
    greet
      say Привет! Я потерял свою любимую запонку. Если найдешь ее - награжу!
      get_mob(1023).attach_death_obj(1020, 100%)
    end
    award
      say Отлично! А я уже и не надеялся ее найти! Вот твоя награда
      load obj 1040
      give obj_1040 actor
    end
    conditions
      if was_zone_reset_since(10, cur_time)
        reset_quest
      end
    end
end


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


Сообщения

Ну тут главное задокументировать как следует, и отказаться от мадовских $N $n $y $g $u $t ..... Я вот сколько лет уже билдю - до сих пор не запомнил. Тем более, что у разных мадов разные переменные... Так что первейшее дело - это переменные назвать, и конечно связать их с объектами. Пример:
Код:
act
  to_vict => "Вы содрогнулись от удара молнии, посланной " ch.tname
  to_not_vict => vict.name + "содрогнул" + vict.lingvo_sya + " от удара молнии, посланной " ch.tname
  to_char => vict.name + "содрогнул" + vict.lingvo_sya + " от удара молнии, посланной Вами!"
end



Вот примерно так. Дополнения приветствуются.

Автор:  KadVar [ Пт авг 28, 2009 2:46 pm ]
Заголовок сообщения:  Re: Фреймворк для билдера

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

Вы абсолютно зря вообще используете dg_scripts.
Задача превзойти язык созданный 10-15 лет назад в других условиях и под другие задачи довольно проста
и на мой взгляд не стоит...

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

Я готов выложить типовую "зону с заморочками" на растерзание. По-моему она выдавалась в паблик с
нашими редакторами. Если есть желающие (пусть даже 1 человек) я готов на ее примере обсосать
все тонкости и обдумать как на базе луа создать что-то более продвинутое. Отчасти потому, что это
все-равно мне понадобится, а взгляд со стороны несомненно лучше.

Думаю, также имеет смысл рассмотреть конкретные команды и сам фреймворк. Если есть желание.
Можно сделать это и в почте, могу сделать отдельный подфорум.

ЗЫ. Я несколько обеспокоен идеей шаблонов, не задавит ли мысль и идеи ?
Однако нужность очевидна.

Автор:  omlin [ Пт авг 28, 2009 3:17 pm ]
Заголовок сообщения:  Re: Фреймворк для билдера

отлично, я рад, что мои идеи возымели определенный успех :)
я полностью "за" обсуждение, почему бы и нет
насчет организации:
  • почтой - непублично. а значит могут быть упущены некоторые весомые мнения. мозговой штурм в данном случае важен, и особенно - мнение рядовых билдеров. кто знает, может они сюда захаживают :)
  • подфорум с топиками на каждую команду/функцию - громоздко. если во фреймворке окажется хотя бы штук 20 конструкций, то придется лазить между 20 разными топиками. да и вообще в форуме когда обсуждение доходит эдак страницы до 5й, то его нить для вновь вступающих в него - теряется.
предлагаю компромиссный вариант:
Обсуждение проводится где-нибудь здесь, в одном или нескольких топиках, а результаты можно выложить в отдельный раздел в Wiki, со ссылками на форум.

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

Автор:  KadVar [ Пт авг 28, 2009 3:25 pm ]
Заголовок сообщения:  Re: Фреймворк для билдера

Тут вопрос целей.
Если цель - создание удачных реализаций, то непонятно зачем все в одну кучу валить.
http://www.a-mud.ru/builder/builder/272.zip 46килобайт trg-файла
В идеале его порезать по числу триггеров или задач на топике и в каждом
уже искать лучший вариант.

Проблемы в том или ином виде видны невооруженным взглядом уже после чтения
первых 10-15 строк.

Это хорошо что у всех много своих приватных зон, я за всех рад.
Однако найти решения их проблемам я возможности не вижу :)

Автор:  Кошир [ Пт авг 28, 2009 4:01 pm ]
Заголовок сообщения:  Re: Фреймворк для билдера

Фреймворк должен позволять работать с событиями.
Например:
some_item.add_event(take, deal_damage_to_all)
some_weapon.add_event(deal_damage, deal_damage_to_owner)
some_room.add_event(enter, load_some_evil_mobs)
some_item.add_event(wear, add_ressurect_event)
some_character.add_event(die, ressurect_and_destroy_relic)
и т.п.

Автор:  omlin [ Пт авг 28, 2009 5:36 pm ]
Заголовок сообщения:  Re: Фреймворк для билдера

Прицепляемые переменные

Ну во-первых, амудовские get_var, set_var, set_var_reset - это чудовищные конструкции, жутко неудобные и сложные поначалу для запоминания.

Например LUA в хьервардовской реализации позволяет к любым своим объектам по определению цеплять любые поля, и это выглядит намного проще, например:
Код:
if (mob.quest_given == nil)
  mob.quest_given = 1
  mob.do_cmd("г Привет тебе, "..actor.name[0])
end

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

По сути, пока я писал, Кошир эту проблему уже решил. Это действительно проще сделать через некие слизанные откуда-нибудь эвентные модели.
Вот пример:
Код:
mob.add_event(event_reset_zone,function f
  self.quest_given = nil
end)

Здесь переменная монстра quest_given будет обнуляться при репопе зоны, к которой принадлежит монстр.

Еще отдельно по таймеру, аналог амудовского set_var_reset("var" "round" "%n%").
Эта фишка бывает полезной. Вот пример:
Код:
function hello
  self:do_cmd("г Привет!")
end
mob1:set_timer(5,hello)
mob2:set_timer(10,hello)
mob3:set_timer(15,hello)
mob4:set_timer(20,hello)

Монстры с 1го по 4й будут говорить "Привет!" через каждые 5 секунд, причем при этом в выполнении триггера задержки не будет, действия по таймеру выполняются асинхронно.

Автор:  KadVar [ Пт авг 28, 2009 6:35 pm ]
Заголовок сообщения:  Re: Фреймворк для билдера

omlin писал(а):
Прицепляемые переменные
Ну во-первых, амудовские get_var, set_var, set_var_reset - это чудовищные конструкции, жутко неудобные и сложные поначалу для запоминания.

Например LUA в хьервардовской реализации позволяет к любым своим объектам по определению цеплять любые поля, и это выглядит намного проще, например:
Код:
if (mob.quest_given == nil)
  mob.quest_given = 1
  mob.do_cmd("г Привет тебе, "..actor.name[0])
end

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

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


omlin писал(а):
По сути, пока я писал, Кошир эту проблему уже решил. Это действительно проще сделать через некие слизанные откуда-нибудь эвентные модели.
Вот пример:
Код:
mob.add_event(event_reset_zone,function f
  self.quest_given = nil
end)

Здесь переменная монстра quest_given будет обнуляться при репопе зоны, к которой принадлежит монстр.

По мне, так это - пример чудовищной конструкции. Эвенты ? Объясните что это такое
выпускнуку суриковского в 3х словах :).
Разница подхода в том, где и как вы задаете когда должна обнулиться переменная.
В практике - 9 из 10 в вашем случае просто забудут.

omlin писал(а):
Еще отдельно по таймеру, аналог амудовского set_var_reset("var" "round" "%n%").
Эта фишка бывает полезной. Вот пример:
Код:
function hello
  self:do_cmd("г Привет!")
end
mob1:set_timer(5,hello)
mob2:set_timer(10,hello)
mob3:set_timer(15,hello)
mob4:set_timer(20,hello)

Монстры с 1го по 4й будут говорить "Привет!" через каждые 5 секунд, причем при этом в выполнении триггера задержки не будет, действия по таймеру выполняются асинхронно.


Кстати очень небезопасная конструкция.
Как показывает практика делать что-то асинхронно не всегда хорошо (та самая set_var_reset тоже вполне асинхронна) - это с одной стороны.
С другой - обычно все надо сделать 1 раз. Где тут это указано :) ?

Что-то посмотрел еще раз... и эээ... совсем не понял. Они по 1 разу через Х секунд что-ли сработают ?

Автор:  omlin [ Пт авг 28, 2009 7:58 pm ]
Заголовок сообщения:  Re: Фреймворк для билдера

KadVar писал(а):
Разница подхода в том, где и как вы задаете когда должна обнулиться переменная.В практике - 9 из 10 в вашем случае просто забудут.

А где в адамантовских триггерах написано, что нужно вызвать set_var_reset ? :) Почему set_var_reset точно также не могут забыть? )

Нет, ну зерно истины конечно тут есть, не спорю. Создается, вроде как, дополнительная конструкция, необходимость которой для большинства билдеров интуитивно неясна с первого раза.
В принципе, единственная альтернатива которую я могу предложить здесь - это делать все локальные переменные обнуляемыми по умолчанию при ресете зоны. А чтобы сделать их перманентными, потребуется их, к примеру, зарегистрировать:
Код:
actor.new_local_var = 10
actor:make_permanent(new_local_var)


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

Автор:  omlin [ Сб авг 29, 2009 12:57 pm ]
Заголовок сообщения:  Re: Фреймворк для билдера

KadVar писал(а):
Что-то посмотрел еще раз... и эээ... совсем не понял. Они по 1 разу через Х секунд что-ли сработают?


Именно так.

......момент вызова set_timer в триггере......
прошло 5 секунд
моб1 сказал: "Привет!"
прошло еще 5 секунд
моб2 сказал: "Привет!"
прошло еще 5 секунд
моб3 сказал: "Привет!"
прошло еще 5 секунд
моб4 сказал: "Привет!"

Автор:  KadVar [ Пн авг 31, 2009 12:22 pm ]
Заголовок сообщения:  Re: Фреймворк для билдера

omlin писал(а):
KadVar писал(а):
Разница подхода в том, где и как вы задаете когда должна обнулиться переменная.В практике - 9 из 10 в вашем случае просто забудут.

А где в адамантовских триггерах написано, что нужно вызвать set_var_reset ? :) Почему set_var_reset точно также не могут забыть? )

Я еще раз могу только еще раз порадоваться, что лет 5 назад мне удалось создать маяк, на который ориентируются и поныне. Несмотря на то, что все было спроектировано так, чтобы было легче внедрить, а не пользоваться :).

Но меня очень огорчает то, что многие и поныне пытаются превзойти неудачные примеры реализаций созданные многие годы назад... на мой взгляд это КРАЙНЕ непродуктивно... надо делать нормальные реализации, а не радоваться тому, что у кого-то еще кривее чем у тебя...


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


omlin писал(а):
В принципе, единственная альтернатива которую я могу предложить здесь - это делать все локальные переменные обнуляемыми по умолчанию при ресете зоны. А чтобы сделать их перманентными, потребуется их, к примеру, зарегистрировать:
Код:
actor.new_local_var = 10
actor:make_permanent(new_local_var)


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

omlin писал(а):
А вообще, эвентная модель это стандарт де-факто в современном программировании, и все хоть немного программисты прекрасно понимают как работать с эвентами. К тому же, все очень просто... По сути дела, это то же самое, что аттач новых триггеров, тока эти триггеры написаны в виде подпрограмм (функций).

Вы меня простите, но причем тут программисты ?
К слову сказать аттач новых тригеров, детач старых итп - не очень хорошая практика применяемая
в некоторых проектах. Особенно там, где по репопу ничто не переаттачивается автоматом...
Лично я считаю, что вместо этого должно быть состояние зоны, которое так или иначе
описывается переменными.

Страница 1 из 4 Часовой пояс: UTC + 3 часа [ Летнее время ]
Powered by phpBB® Forum Software © phpBB Group
http://www.phpbb.com/