XGM Forum
Сайт - Статьи - Проекты - Ресурсы - Блоги

Форуме в режиме ТОЛЬКО ЧТЕНИЕ. Вы можете задать вопросы в Q/A на сайте, либо создать свой проект или ресурс.
Вернуться   XGM Forum > Warcraft> Барахолка
Ник
Пароль
Войти через VK в один клик
Сайт использует только имя.

Ответ
 
prog

offline
Опыт: 32,498
Активность:
Кодинг Редактора Объектов - доступ из jass, код в полях РО и многое другое

Вступление

Первоначальная идея

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

Что получилось в итоге

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

Спецификация

Использование шаблонов

Шаблоны поддерживаются для файлов war3map.wts и war3map.j и обрабатываются до передачи кода другим препроцессорам.

Разновидности шаблонов

Поддерживается две разновидности шаблонов - это операции с данными и директивы.
Операции с данными выглядят так:
${код}
В составе кода могут быть использованы любые арифметические операции, шаблонные переменные и обращения к данным по объектам.
Директивы выглядят так:
<имя директивы и параметры>

</имя директивы>

Обращение к данным объектов

В общем виде доступ к данным конкретного объекта осуществляется с помощью конструкции ${XXXX.YYYYzz}, где XXXX это равкод объекта, YYYY равкод поля, к которому идет обращение, а zz - уровень способности или вариация декорации и не указывается для других типов объектов.
К сожалению, на данный момент доступны только нестандартные значения полей, но это будет исправлено со временем.

Использование директив

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

Директива if

<if условие>

</if>
Содержимое директивы "выполняется" только если выполняется условие директивы.

Директива list

<list collection as variable>
	
</list>
Содержимое директивы "выполняется" для каждого элемента коллекции.
В качестве collection на данный момент может быть использована одна из следующих коллекций объектов:
units - все юниты
ability - все способности
items - все предметы
Позже будут добавлены коллекции для всех остальных типов объектов.
Что касается variable, то это локальная шаблонная переменная, которую можно обозвать как угодно и которая доступна только в области видимости директивы list. Для объектных коллекций обращение к этой переменной аналогично обращению к объекту по его равкоду.
Также эта конструкция может быть применена для обхода всех уровней способности. Для этого вместо collection нужно использовать конструкцию вида A000.levels или, любой другой способ обратиться к полю levels какой-либо способности.

Равкоды полей

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

Примеры


<list units as u>
	юнит: ${u} скорость: ${u.umvs} стоимость: {u.ugol}
</list>
Выдаст после компиляции список всех юнитов, их скорость и стоимость в золоте
<list units as u>
	<if u.ugol \gt 100 >
		юнит: ${u} стоимость: {u.ugol}
	</if>
</list>
Выдаст после компиляции список равкодов и стоимостей всех юнитов, стоимость которых больше или равна 100
	${hgyr.ubld}
Выдаст время строительства вертолета (стандартный юнит альянса), если это значение отличается от стандартного.
	${ 2 * 2 + 5 }
Думаю вы догадываетесь что получится в результате)
<list A000.levels as L>
	${L} ${L.Data}
</>
выведет номер каждого уровня способности A000 и значение поля Data на этом уровне

Бета версия

В ближайшее время здесь будет выложена бета-версия для тестирования. Желающим пораньше посмотреть что это за зверь просьба писать в личку - бета уже есть.
Установка бета-версии достаточно проста.
Для начала необходимо установить седьмую джаву, затем извлечь архив бета-версии в папку с экспериментальным JNGP, предварительно сделав бекап файла wehack.lua.
тут будет ссылка на скачивание

Для любопытных

» как это работает
Для начала из карты извлекаются файлы с данными по объектам (w3u,w3a,w3t и так далее), файлы строк и код карты.
Затем данные разбираются утилитой и формируется модель данных.
После чего модель данных, файл строк и код карты передаются библиотеке FreeMarker в качестве шаблонов для компиляции.
Для уменьшения веса утилиты используется версия FreeMarker 2.03.
Также файл строк очищается от пустых строк, которые там возникают в процессе импорта/экспорта.

В разработке

К сожалению, утилита пока далека от совершенства и многое только предстоит доделать.
Например, на данный момент, если сохранить и закрыть карту, использующую шаблоны, а затем открыть ее, то все шаблоны будут утеряны, кроме тех что находятся в триггерах.
Второй серьезной проблемой является способ хранения строк описаний объектов - они вынесены в файл war3map.wts и утилита на данный момент еще не ассоциирует их с конкретными объектами. Как результат, при попытке подставить значение одного текстового поля в другое, получим надпись TRIGSTR_ вместо фактического значения. Также параллельно с решением этой проблемы планируется добавить локальную переменную, видимую только в описаниях объектов, указывающую на объект, которому принадлежит данное описание. Это позволит использовать ${this.равкод поля} вместо ${равкод конкретного объекта.равкод поля} при обращении к полям данного объекта.
И таких примеров еще множество и они будут добавляться сюда по мере того как я буду о них вспоминать.

Дополнительные ссылки


Отредактировано prog, 28.02.2012 в 18:51.
Старый 20.02.2012, 22:53
Hanabishi
COOL STATUS
offline
Опыт: отключен
Старый 21.02.2012, 11:55
prog

offline
Опыт: 32,498
Активность:
Hanabishi, спасибо, конечно, но по моей ссылке информации намного больше. В частности там приведен подробный формат большинства файлов из архива, а не только их описание. Этого достаточно для решения моей задачи, вопрос в том есть ли еще что-то, например готовые утилиты? Или, может, кому-то уже доводилось заниматься этим и он может поделиться опытом.
Старый 21.02.2012, 13:16
ScorpioT1000
Crazy Architecture
offline
Опыт: отключен
продублирую рандом идея =)
ScorpioT1000:
можно же cjass заюзать, только дефайны оттуда. вобще это все круто было бы замутить с сижассом, например сначала мы парсим весь ро и делаем дейфинишны типа
#define OE_UNIT_H001_MODEL = "тут путь к модели" // означает РО - юнит - "H001" - файл модели
#define OE_UNIT_H001_HERONAME_0 = "имя1" // РО - юнит - "H001" - имена героев - первое
#define OE_UNIT_H001_HERONAME_1 = "имя2"

#define OE_DESTR_D001_DESCRIPTION = "описание" // РО - разрушаемые - "D001" - текст-описание (ну или вроде того)
т.е. всё строго структурировано
Потом в полях, в которых есть спецсимволы, мы их превращаем в функции, типа
OE_DESTR_D001_DESCRIPTION
изменили это поле на значение OE_UNIT_H001_MODEL + "раз два три"
то это уже транслируется не в простой дефинишн
#define OE_DESTR_D001_DESCRIPTION = "описание"
а в целую функцию
string OE_DESTR_D001_DESCRIPTION () {
	return OE_UNIT_H001_MODEL + "раз два три"
}
тоесть если в описании заюзаны любые спецсимволы, кроме знаков препинания, мы втупую делаем их как функцию, в итоге результат будет в кастом коде карту:
#define OE_UNIT_H001_MODEL = "тут путь к модели"
#define OE_UNIT_H001_HERONAME_0 = "имя1"
#define OE_UNIT_H001_HERONAME_1 = "имя2"

string OE_DESTR_D001_DESCRIPTION () {
	return OE_UNIT_H001_MODEL + "раз два три"
}
это сделать как нехрен делать, если у тебя есть возможность норм брать поля РО и вставлять в war3map.j
Потом идет магия сижасса ! если макрос ни разу не был заюзан, он просто стирается, тем самым нету затрат на константы, т.е. ты парсишь весь ро, вписываешь около тыщи дифайнов, а он все удаляет, если не надо =)

Пример применения:

  1. описание спелла:
"уровень 1 - " + OE_ABILITY_A001_START_DAMAGE + " урона\n" + \
"уровень 5 - " + R2S( S2R(OE_ABILITY_A001_START_DAMAGE) * \
S2R(OE_ABILITY_A001_DAMAGE_MULTIPLIER) * 5.0 ) + " урона"
  1. добавляется в war3map.j как:
string OE_ABILITY_A001_DESCRIPTION () {
	return "уровень 1 - " + OE_ABILITY_A001_START_DAMAGE + " урона\n" + \
"уровень 5 - " + R2S( S2R(OE_ABILITY_A001_START_DAMAGE) * \
S2R(OE_ABILITY_A001_DAMAGE_MULTIPLIER) * 5.0 ) + " урона"
}
  1. после трансляции cjass:
function OE_ABILITY_A001_DESCRIPTION takes nothing returns string
	return "уровень 1 - " + "5" + " урона\n" + "уровень 5 - " + R2S( S2R(5.0) * S2R(1.144) * 5.0 ) + " урона"
endfunction
  1. после оптимизации cjass:
function OE_ABILITY_A001_DESCRIPTION takes nothing returns string
	return "уровень 1 - 5 урона\nуровень 5 - " + R2S( S2R(5.0) * S2R(1.144) * 5.0 ) + " урона"
endfunction
  1. ну и в игре что-то типа
уровень 1 - 5 урона
уровень 5 - 28.6 урона

Отредактировано ScorpioT1000, 21.02.2012 в 13:51.
Старый 21.02.2012, 13:35
Alex_Hell
Mapmaker 'N' Programmer
offline
Опыт: 6,885
Активность:
На счет извлечения данных - думаю справишся.
А вот способ использования: хотелось бы прямо в игре иметь возможность обратиться к любому юниту и получить из него все его параметры.
Например:
local unit u = GetTriggerUnit()
local UnitInfo info1 = UnitInfo.create(u)
local string name = info1.Name
local string description = info1.Description
local SkillInfo info2 = SkillInfo.create(GetSpellAbilityId())
local string skill_name = info2.Name
local string skill_description = info2.Description
local string skill_mana = info2.ManaCost
local string skill_coldown = info2.Cooldown
Т.е. задача проги - сгенерировать классы UnitInfo, SkillInfo (впринципе написать их руками можно сейчас), и забить контектом базы данных, т.е. в реализации метода UnitInfo.create(unit) идет обращение к БД, заполненной прогой. Такие виды классов сделать для всех объектов: unit, item, destructable, skill, buff.
В качестве БД - hashtable.
Способ заполнения - обычный dictionary между путем в файле вара и ключем в БД (Description, Name). Реализация свойства Description, Name - обращение к БД с ключем Description, Name и типом юнита или типом скила.
________________
стохастическое программирование:
#define true ((rnd() % 2) == 0)

Отредактировано Alex_Hell, 21.02.2012 в 14:39.
Старый 21.02.2012, 14:24
ScorpioT1000
Crazy Architecture
offline
Опыт: отключен
опятьже продублирую, тут проблема очевидная =)
В коде будет получаться нормальная строка со всеми операциями, а если мы заюзаем это поле в игре, допустим то же описание - его никто не исполнит, т.е. придется сначала както прогонять это через обработчик, так что то, что я предложил, не подходит.. а в cjass нету вложенности дифайнов (так то можно было бы ему давать файл, который нам нужен и обрабатывать результат).
Хмм, если попробовать через луа пропускать это дело ... т.е. мы даем луа набор полей, она там считает все вещи типа
"описание спелла = "урон " + урон спелла * силу юнита * 5"
и дает назад обработанный код "описание спелла = урон 26.8", который мы суем снова в описание...
Старый 21.02.2012, 14:27
prog

offline
Опыт: 32,498
Активность:
Alex_Hell, поскольку я не поклонник vjass - оставлю эту задачу кому-нибудь другому. Ну или если совсем уж нечего делать будет.
ScorpioT1000, меня куда больше волнуют перспективы потери данных и их неотображения в РО без перезапуска.
По поводу препроцессинга описаний - свой препроцессор написать не проблема. В крайнем случае припахать того-же адольфа, если у меня не получится. Положить эти описания обратно в w3u файл - не проблема. Положить файл обратно в карту - ты показал как.
Проблема может быть с потерей данных при неправильном обращении с утилитой, но это частично решается введением переключателя dev/релиз. В режиме dev описания только переносятся в код, без обратновго вкладывания в карту, в режиме релиз карта сохраняется в двух экземплярах (если это возможно) первый аналогичен dev, а ко второму применяется какая-нибудь оптимизация и препроцессинг описаний.
Старый 21.02.2012, 14:42
ScorpioT1000
Crazy Architecture
offline
Опыт: отключен
что мешает перед какойто хитроумной обработкой сделать нескомпиленный бекап?
Старый 21.02.2012, 14:58
prog

offline
Опыт: 32,498
Активность:
ScorpioT1000, вот потому и нужен переключатель, отключающий впихивание в карту скомпиленную версию описаний. А лучше еще и автобекап перед сохранением скомпиленной версии - на случай кривых рук или недосыпания.
Старый 21.02.2012, 15:01
ScorpioT1000
Crazy Architecture
offline
Опыт: отключен
да зачем плодить карты ? давай разберемся, у нас есть 2 проблемы:
  1. нужно обезопаситься от сбоев
для этого мы перед всяческой компиляцией создаем файл backup_mapname, после компиляции мы его убиваем. но это вроде уже жнгп делает, причем много раз и не убивает, просто проверить, точно ли он до всех наших действий это делает и всё, проблема решена - если потеряем конечную карту, у нас еще есть ~16 бекапов последних сейвов, осталось открыть один и перекомпилить
  1. нужно, чтобы в игре был конечный файл РО, а в редакторе - исходный
нам просто надо ввести копию файла ро (или файлов), и также импортить его в карту. Перед запуском ве мы меняем их местами (прямо в карте! архиватором т.е.), после компиляции, сохраняем исходный как копию, а конечный, как нормальный объектный файл
Старый 21.02.2012, 15:09
Alex_Hell
Mapmaker 'N' Programmer
offline
Опыт: 6,885
Активность:
Ребят, я не совсем понял о чем вы пишете, что касается изменения данных и возврата изменений в РО. Есть рутиная задача - карта по diablo. Так вот есть например 6 видов драгоценных камней, и у каждого предмета 1 сокет - куда вставить можно камень. Вручную сделать - скопировать каждый предмет 6 раз, в каждом подменить описание вида "сокет: аметист" , "сокет: череп". Эффекты от сокетов будут одинаковые так что можно тут же добавить способность предмету (1 из 6) или возложить на jass - запихать в БД, т.к. БД все равно нужна будет чтобы сопоставить скилл улучшения (вставки сокета, 6 скилов) и полученный предмет. Так вот с помощью этой проги можно будет легко такой механизм реализоать? Вы хотите решать задачи такого плана?
prog:
Alex_Hell, поскольку я не поклонник vjass - оставлю эту задачу кому-нибудь другому. Ну или если совсем уж нечего делать будет.
Ты же мне именно об этом писал в ЛС, когда писал о способе восстановления маны за скилл без ручного написания БД. Это во мних случаях может пригодиться. Как прога будет почти готова, могу добавить такой функционал - генерации vJass структур (там статичный код будет для всех карт) и заполнении БД (это будет зависеть от содержимого карты).
________________
стохастическое программирование:
#define true ((rnd() % 2) == 0)
Старый 21.02.2012, 16:17
prog

offline
Опыт: 32,498
Активность:
Alex_Hell, изначально эти данные будут складываться в виде cJass дефайнов, примерно так как предложил ScorpioT1000
Если дружишь с джавой - посмотрим. По поводу БД я сам пока думаю как реализовать. Скорее всего это будет внешний конфигурационный файл для каждой карты, определяющий что туда ложить, а что нет.
Старый 21.02.2012, 16:32
ScorpioT1000
Crazy Architecture
offline
Опыт: отключен
Ну я кароче тогда так предлагаю: написать несложный анализатор, в котором можно будет объявить простенькие макросы доступа, математики и работы со строками, тот же луа бы мог сойти.
Базовый функционал:
  1. обращаться из одних полей РО в другие, по всей области РО
  2. изменять из одних областей РО те, которые были уже занесены (распарсены до них), тоесть тот же инкремент - мы запомнили какоето число, в следующих объектах оно увеличивается на 1 например или дописывается строка
  3. простая математика с полями РО (используя средства в п. 1), из этого следует:
  • хотябы временные переменные - можно будет круто задавать дамаги
  • глобальные переменные - нужны ли ? или сойдет. п.1 и п.2 ?
  1. после компиляции РО, скопировать все поля в war3map.j - пока как cJass дифайны
Предложение Alex_Hell насчет структур было бы удобнее, НО ! cJass оптимизирует и удаляет ненужные дифайны, а представь будет 1000 полей у структур ?
также необязательно, но неплохо было бы сделать простые операции подстроки и сложения строк.
смотрите, мы используя пункт 1, можем объявить один главный предмет, а у остальных ссылаться на первый, кроме какихто определенных полей, тем самым, можно менять 1 предмет не опасаясь за остальные
используя пункт 2 можно задать какойто предмет например "полный сет", который требует итемы при этом не задавать явно в нём что он требует, а дописывать его требования в отдельных новых итемах ! можно даже статы одного итема дописывать или убирать в других итемах
так же с юнитами и декором, т.е. это откроет офигенные возможности =)
это будет новый, динамический подход к статическим объектам в варкрафте)
ScorpioT1000 добавил:
Скорее всего это будет внешний конфигурационный файл для каждой карты, определяющий что туда ложить, а что нет.
я бы предложил таки запихивать всё в карту, не думаю что 20 килобайт сильно мешать будут. Даже есть 200 килобайт кода, мпку отлично его сжимает

Отредактировано ScorpioT1000, 21.02.2012 в 17:18.
Старый 21.02.2012, 17:24
prog

offline
Опыт: 32,498
Активность:
ScorpioT1000:
я бы предложил таки запихивать всё в карту, не думаю что 20 килобайт сильно мешать будут. Даже есть 200 килобайт кода, мпку отлично его сжимает
Речь идет не о дефайнах - они будут все ложиться, а о БД на массивах или хештаблице. Там уже надо отслеживать что должно сохраняться, а что - нет.
Старый 21.02.2012, 17:31
ScorpioT1000
Crazy Architecture
offline
Опыт: отключен
prog, ты имеешь ввиду парсинг варовского архива, типа чтобы потом оттуда цеплять те данные, которые запрошены в юзерских полях ? могу посоветовать Sqlite - база данных без демонов ! x) удобно и практично, всего одна библиотечка
Старый 21.02.2012, 17:33
prog

offline
Опыт: 32,498
Активность:
ScorpioT1000, нет имеется ввиду БД на jass, чтобы можно было спросить, зная Id, например, что написано в поле стоимость заклинания. При этом Id становится известен только на этапе выполнения - дефайны не катят.
Решается эта задача примерно так:
  • каким-либо образом отмечаются заклинания, которые надо спарсить в БД (например в поле описание редактора)
  • в память утилиты парсятся и подгружаются данные по обьектам
  • препроцессор делает свое грязное дело
  • на сцену выходит генератор БД
  • все поля, отмеченные для формирования БД записываются в виде jass-кода
  • результирующий файл инжектится через cjass
  • при запуске карты код выполняется и мы получаем БД с нужной нам информацией
обычно такие БД собирают вручную, что представляет собой страшный геморрой
Старый 21.02.2012, 17:55
ScorpioT1000
Crazy Architecture
offline
Опыт: отключен
ты имеешь ввиду, чтобы можно было делать например обход или пикать юнита и по его типу что-то находить ? ну я тоже так думал, это вполне реализуемо, если касается нестандартных вещей, а вот если на основе стандарта - начинается веселье =) да наверно так и есть - придется отметить явно объекты, которые надо будет подгружать. но я бы предложил пока сделать хотябы по нестандартной части. Действительно, дифайны тут не катят.
Про описание карты - както не шарит, хм. А что если сделать так - проверить, есть ли изменения в указанном объекте (ну помните они другим цветом выделяются, и это еще лежит в файлах карты), и их заливать в бд ? а юзерам скажем, типа если хотите по ним делать выборку - измените в них чето-то, поставьте пробел )
ScorpioT1000 добавил:
результирующий файл инжектится через cjass
вот это лишнее, имхо. можно же в вар3мап закинуть всё
и да, базу тогда предлагаю делать типа XAT - большой одномерный массив, работающий как хештейбл. Можно найти оффсет и писать его в константу внутри, по нему + равкоду и находить ячейку.
Старый 21.02.2012, 18:15
prog

offline
Опыт: 32,498
Активность:
ScorpioT1000, объясняю зачем инжектить через cjass - это проще чем выковыривать .j файл, и дописывать в него.
По поводу объектов, которые надо подгружать. У меня в картах бывает до нескольких сотен способностей. Все нестандартные, естественно. Из них данные мне нужны, скажем, по двум десяткам. Забивать в базу все способности не вариант - это лишняя нагрузка и затраты памяти.
Второе - поля. У объектов достаточно много полей, не все из которых могут быть нужны во время игры - лишние тоже было бы неплохо убрать из БД.
Решение первой проблемы - какой-нибудь индикатор для препроцессора, указывающий что данные по этому объекту должны быть сложены в БД. (в одном из существующих полей или путем добавления полей в РО для нужд препроцессора)
Решение второй проблемы чуть сложнее - на ум приходит только создание конфигурационного файла со списком полей, которые должны быть подгружены в БД для данной карты.
Теперь по стандартной части - эти данные не так уж и сложно выдрать. Для их хранения вполне подойдет файл того-же формата что и для нестандартных, надо только скомпоновать данные из slk-таблиц
Старый 21.02.2012, 18:36
ScorpioT1000
Crazy Architecture
offline
Опыт: отключен
prog, тогда смысл программы отпадает автоматически =) т.к. вся фича в автоматике была.
Я бы тогда предложил парсить конечный .j файл на наличие обращений к полям (может задать команду cjass, которая заменяет вызовы какойнить штуки вроде OELOAD(RAW,TYPE) на хорошо узнаваемую последовательность символов) и задавать для всех требуемых объектов только те поля, к которым были обращения.
Вынуть war3map.j не так уж сложно, если хочешь, я тебе даже прогу напишу, которая из файла .j собирает все обращения по какомуто keyword(rawcode,arg1,arg2,...) и складывает их в файл типа
rawcode|arg1|arg2|...\n
я бы даже сделал умнее, и это будет наверно еще круче, кароче:
  • мы ищем по кейворду как было выше сказано, в конечном war3map.j
  • если хоть один равкод не похож на равкод (значит там заюзали цикл или переменную), то ставим галку добавлять в базу все нестандартные (и "тронутые") объекты, т.е. уже для частных случаев фикс. хотя редко кто равкоды вставляет в чистом виде, НО cjass и оптимизатор векса какраз ДЕЛАЕТ ЭТО! =)
  • далее ищем уже по аргументам, я точно не знаю структуру, ну допустим будет TYPE - тип поля, собираем множество всех типов полей, к которым обращались (вот тут вот надо юзера ограничить - сказать, чтобы его явно указывал в коде)
  • потом ссылаясь на эти 2 множества, а также то что мы говорили про явно добавленные равкоды, заполняем бд
Старый 21.02.2012, 18:54
prog

offline
Опыт: 32,498
Активность:
да ладно, необходимость прописать один include со стадартным именем файла убивает на корню всю автоматику)
Или ты про конфиг с полями? так он делается один раз для каждого вида ресурсов и дальше просто используется.
Да, конфиг вынести в .j файл идея хорошая. Но парсить код на предмет обращения к полям это уже слишком, как мне кажется. Тем более что моя утилита рассчитана на работу перед cJass. Для начала сделаю в виде специального комментария - он будет легко парситься и удалится на этапе оптимизации карты любым оптимизатором. А там видно будет - может и это доделаю.
Старый 21.02.2012, 18:56
Ответ

Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск

Ваши права в разделе
Вы не можете создавать темы
Вы не можете отвечать на сообщения
Вы не можете прикреплять файлы
Вы можете скачивать файлы

BB-коды Вкл.
[IMG] код Вкл.
HTML код Выкл.
Быстрый переход



Часовой пояс GMT +3, время: 05:45.