Это популярное сообщение. KD87 718 Опубликовано 16 Сентября 2011 Это популярное сообщение. Поделиться Опубликовано 16 Сентября 2011 Как некоторым, может быть, известно, на X-Ray Engine Toolset идет развитие утилит, доставшихся нам вместе с исходниками от выдающихся программистов коммьюнити (прежде всего, конечно, bardak'a). В силу своих скудных навыков по программированию я занимаюсь прежде всего perl-скриптами - ACDC, game.graph recompiler и т.д. В этой теме я прошу тех мододелов, кто часто работает с perl-скриптами, помочь с отловом багов. Прежде всего интересует Universal ACDC - спавны каких модов не распаковывает, какие фичи не работают, все, что найдете. Здравые мысли по развитию скриптов также приветствуются. Надеюсь на вашу помощь. ----------------------------------------------------------- --S.T.A.L.K.E.R. *.spawn compiler/decompiler-- ----------------------------------------------------------- Версия: 1.38 Дата последних правок: 21.05.2014 Данный acdc предназначен для распаковки и запаковки all.spawn/level.spawn от любого билда, начиная с 1265. Основные фичи: -распаковка оригинальных спавнов ТЧ, ЧН, ЗП и билдов ТЧ, начиная с xrCore build 1265. -распаковка спавнов от модов (требуется папка конфигов от мода) -конвертация спавна в любую другую версию. -массовая замена гейм-вертексов в распакованном спавне. -разбивка all.spawn на level.spawn'ы и level.game'ы -сравнение файлов распакованного спавна -обновление вертексов согласно координат объектов Что нужно для работы: -собственно, сам спавн (all.spawn, level.spawn) -game.graph (только если распаковываете all.spawn). Если all.spawn от билда 3120, ЧН или ЗП - game.graph не нужен (он вшит в спавн). -папка configs (если распаковываете мод и acdc жалуется на unknown section) Для корректной работы используйте с папкой stkutils строго последней версии. Использование: Кладете all.spawn (или level.spawn) и game.graph в папку с программой, делаете батник (команды ниже), запускаете батник, радуетесь жизни. Пояснение по дальнейшему тексту: в угловых скобочках (<>) указано значение опции. Это путь до спавна, папка для распаковки и т.п., то есть то, что нужно вписывать вам. В квадратных скобочках ([]) указаны необязательные опции. Опции без скобочек - обязательны. Режим предназначен для распаковки файлов all.spawn и level.spawn Команда: universal_acdc.pl -d <spawn_file> [common_options] -d <spawn_file> - путь до спавна. common_options - общие опции. Читайте про них ниже. При распаковке спавнов от модов может возникнуть ошибка "unknown section". Это означает, что в моде используются нестандартные секции предметов/мобов. Для распаковки такого спавна необходимо использовать ключ -scan, указав ему в качестве параметра путь до папки config/configs. Пример смотрите в батнике acdc_decompile_scan. Режим предназначен для запаковки распакованных текстовых файлов спавна в all.spawn или level.spawn Команда: universal_acdc.pl -compile <dir> [-idx <index_file>] [-f <flag1,flag2,...>] [common_options] -compile <dir> - папка, в которой лежит распакованный спавн. Если работаете в текущей папке, <dir> не нужно. common_options - общие опции. Читайте про них ниже. -idx <index_file> - с этим ключом скрипт сформирует ltx конфиг с секциями вида: [13_box_wood_01_0021] ;формат - "индекс_локации"_"имя_объекта" id = 2907 ;id объекта story_id = -1 ;story_id объекта Такие записи создадутся для ВСЕХ объектов из спавна. Если указать ключ -idx без пути до конфига, он появится в папке с acdc (spawn_ids). Зачем это нужно? В игре вы сможете открыть этот файл из скриптов и найти нужный вам объект. Если раньше для нахождения нужного id объекта по имени требовалось перебрать все объекты в игре, теперь это можно сделать, просто считав id из нужной секции конфига. Также есть кое-какие дополнительные фичи: - при компиляции для правильной работы необязательно проставлять всем секциям в спавне параметры version и script_version. Достаточно поставить их в секции актора, ацдц далее будет использовать их. Полезно, когда спавн "сборный". - при компиляции контролируется уникальность параметров story_id, чтобы не мучиться потом с вылетами игры. Режим позволяет конвертировать спавны ТЧ, ЧН, ЗП между собой. Команда: universal_acdc.pl -convert <file> -version <new_version> [common_options] -convert <file> - файл, который нужно сконвертировать. Можно указывать как запакованный (*.spawn) спавн, так и распакованный (alife_***.ltx). Внимание! Так как граф и кросс-таблицы в ЧН и ЗП вшиты в спавн, для конвертирования ЗАПАКОВАННЫХ спавнов ТЧ в эти форматы вам потребуется положить в папку с acdc папку levels из игры. Необязательно копировать все файлы, достаточно оставить в папке с каждой локацией файл level.gct. -version <new_version> - новая версия спавна. Подобрать версию вы сможете, посмотрев файл spawn_versions.txt common_options - общие опции. Читайте про них ниже. Также поддерживается тонкая настройка конвертации через файл convert.ini. В файле есть две секции: [exclude] и [change]. В секции exclude можно прописать те секции, которые надо удалить из спавна при конвертации. Пример: [exclude] sections = m_trader, m_car, flesh_weak В секции change прописываются имена тех секций, в которых нужно что-то поменять или дополнить. Пример: [change] sections = inventory_box Далее заполняете файл записями для тех секций, которые вы прописали в change. Пример: [inventory_box] //section_name нужной секции add:custom_data = PREVED //префикс add используется для тех параметров, в которые нужно добавить add:game_vertex_id = 10000 //необходимое значение (если число - складывается, если строка - добавляется в конец) rep:level_vertex_id = 0 //префикс rep используется для параметров, которые необходимо заменить на что-то Общий пример. Следующий конфиг приведет к тому, что у всех сталкеров прибавится 500 к гейм-вертексу и визуал сменится на визуал вояки в противогазе: [exclude] [change] sections = stalker [stalker] add:game_vertex_id = 500 rep:visual_name = actors/soldier/soldier_antigas.ogf При подключении новых локаций без перекомпиляции графа возникает необходимость одновременного сдвига всех гейм-вертексов спавна новых локаций на какое-то определенное значение. Это можно сделать в этом режиме. Команда: acdc -parse <file> -old <old_gvid0> -new <new_gvid0> [-way] [common_options] -parse <file> - имя ltx, в котором находится спавн. -old <old_gvid0> - старый начальный game_vertex_id локации. -new <new_gvid0> - новый начальный game_vertex_id локации. -way - обрабатывает также файл way_***.ltx для этой же локации. Пример: acdc -parse alife_l01_escape.ltx -old 0 -new 934 Разбивка all.spawn на level.spawn может быть полезна при одновременной правке спавна в СДК и с помощью ACDC. Команда: acdc -split <file> [-use_graph] [-way] [common_options] -split <file> - разбиваемый спавн. Для восстановления граф-поинтов необходимы level.spawn для всех локаций, находящихся в графе. Их следует поместить в папку levels согласно их положению в геймдате сталкера - по папкам, соответствующим локациям. Папка levels должна быть в папке с acdc (или путь до нее можно задать ключом - читайте далее). -use_graph - использование game.graph для восстановления граф-поинтов. Плюс - не нужны level.spawn, минус - не восстанавливаются имена граф-поинтов (за исключением граф-поинтов переходов). -way - также из спавна генерируются level.game В этом режиме сравниваются два текстовых файла спавна. Итоговый файл формируется на основе первого файла. Все секции, которых нет во втором файле, но есть в первом, удаляются, а те секции, которые есть во втором, но нет в первом, переносятся в итоговый файл. Параметры секций не меняются. Режим позволяет сэкономить время в случае, если надо совместить два файла, причем секции там идут вразнобой. Команда: acdc -compare <file1,file2> [common_options] -compare <file1,file2> - файлы для сравнения Зачем нужно: при изменении аи-сетки у объектов изменяются game_vertex_id и level_vertex_id. Это влечет за собой необходимость повторного снятия данных параметров в игре. Данный режим позволяет автоматически обновить вертексы у всех секций спавна. Команда: universal_acdc -update <spawn_name> [common_options] -update <spawn_name> - all.spawn, для которого надо обновить вертексы. Режим update требует дополнительной настройки. В папке с acdc есть файл fs_vertex.ltx В этот файл необходимо вписать путь до локаций с ОБНОВЛЕННОЙ аи-сеткой. Обязательно должны присутствовать файлы level.ai, level.gct для всех локаций из спавна. ВНИМАНИЕ! Для нормальной отработки режима геймграф должен быть СТАРЫЙ, использовавшийся до перекомпиляции. После нормальной отработки режима спавн можно распаковывать уже с НОВЫМ геймграфом. -out <file> - путь до файла/папки с результатом. Имеет разный смысл для разных опций: для decompile, parse - папка с результатом для compile, convert - результрующий файл. для split - папка levels, куда сохранять level.spawn. -scan <scan_dir> - путь до папки с конфигами. Используется в случае спавнов от модов. -g <graph_dir> - путь до папки с game.graph. Бесполезен для compile и parse, а также, если работаете со спавном ЧН, ЗП, build 3120. -level - обрабатывать спавн как level.spawn. -af - также распаковываются\запаковываются места спавна артефактов в аномалиях (section2.bin). -nofatal - отключает вылет при фатальной ошибке, заменяя ее предупреждением. Если acdc генерирует ошибку 'unknown clsid ... for section...', это означает, что в данном моде добавлены новые пары клиентский/серверный класс в class_registrator.script. Дабы не усложнять работу с acdc, такие пары не определяются автоматически. Лучше всего сообщить об этом мне, однако, если вы понимаете, что находится внутри class_registrator.script, можете добавить новые сеты в clsids.ini сами. Сеты добавляются в таком формате: clsid = соответствующий_серверный_класс Пример: ZS_ELECT = se_zone_anom ================================= Любые имена опций можно сокращать. К примеру, необязательно использовать именно -use_graph, скрипт поймет также и -use, и -u. Однако ряд опций при сокращении их имени могут конфликтовать друг с другом. -compile нельзя сократить до -c, поскольку в таком случае скрипту неясно, что имеется ввиду: -compile или -convert. В таком случае наиболее короткое имя для compile будет таким: -com 1.38: [!] добавлена поддержка релизного спавна Lost Alpha [!] исправлена конвертация и конвертация 1.37: [+] добавлена распаковка и запаковка спавна билда Lost Alpha [!] все не распознанные пути при сплите теперь сваливаются в unrecognized_ways.game 1.36: [!] исправлена разбивка спавна на level.spawn и level.game [!] исправлено сканирование конфигов 1.35: [!] исправлено автоназначение версии при отсутствии этого параметра в секции [!] убрано чтение game.graph при компиляции 1.34: [!] исправлено обновление вертексов [+] добавлено обновление параметра distance при обновлении вертексов [+] добавлен контроль уникальности story_id при компиляции 1.33: [!] исправлена распаковка спавнов некоторых билдов [+] добавлен режим обновления вертексов [+] добавлен "умный" разбор way-объектов по локациям для режима split 1.322: [+] добавлено сравнение распакованных файлов 1.321: [!] исправлена распаковка спавнов ЗП 1.32: [!] guids.ltx больше не нужен без ключа -idx [+] реализована сортировка way-объектов по алфавиту [+] реализовано определение принадлежности way-секции к локации по gvid и префиксу [+] реализована сортировка alife-объектов 1.31: [!] изменен алгоритм сканирования конфигов [!] изменен приоритет запросов из clsids.ini, теперь данные из него перекрывают внутренние таблицы [!] скрипт адаптирован под новую систему отладочных сообщений [f] поправлена логика работы с пакетом актора в ЧН [+] добавлена возможность вынесения лога в файл [+] добавлена возможность вынесения сетов в отдельный конфиг-файл 1.30: [f] теперь новая версия обработчика ошибок по-прежнему обрабатывает спавн Народной солянки [f] исправлены проблемы распаковки level.spawn некоторых билдов 1.29: [f] исправлена ошибка распаковки level.spawn билдов [f] исправлена ошибка распаковки спавна ЧН [f] всякие мелкие правки 1.28: [f] исправлено игнорирование парсером ключа -way в режиме split. [f] исправлена ошибка сканирования конфигов при компиляции. [f] исправлена ошибка чтения секций некоторых se-классов. [f] исправлена ошибка разбивки спавна, из-за которой генерировались левел спавны неправильного формата. [+] добавлен контроль дубликатов актора при компиляции. 1.27: [f] исправлена ошибка парсера, в некоторых случаях приводившая к порче логики. [f] исправлено создание папок при сохранении результата. [+] добавлена переинициализация параметров секции после смены класса при конвертации. Это расширяет диапазон версий, доступных для конвертирования. [+] добавлена поддержка масок при конвертации. [+] добавлен ключ -ini в режиме конвертации 1.26: [f] поправлена распаковка спавнов ЧН. [+] добавлено автоматическое заполнение версии спавна из первой секции (если актора в спавне нет). [+] что-то еще по мелочи, не помню. 1.25: [f] отключен вывод пустого параметра spawned_obj при распаковке. [+] реализовано автоматическое заполнение параметров version и script_version при запаковке спавнов с секциями из разных версий игры. Версия берется из конфига актора. 1.24: [f] исправлена распаковка/запаковка спавна билда 2571. [f] исправлена запись guids.ltx [f] мелкие правки 1.23b: [+] убрано предупреждение "state data left" при распаковке спавнов ЗП, запакованных ранее с помощью acdccop. [f] исправлены ошибки split, из-за которых могли получаться кривые level.spawn [f] переделана логика чтения/записи пакетов se_stalker/se_monster [f] мелкие изменения 1.22b: [+] добавлен ключ -nofatal 1.21b: [f] исправлены небольшие опечатки в коде. [f] парсер теперь корректно читает значения с комментариями. 1.2b: [f] небольшие правки по конвертации. [+] добавленные в модах соответствия clsid -> серверный класс теперь редактируются в отдельном конфиге (clsids.ini). [+] ошибка при встрече незнакомого clsid теперь выдается при распаковки секции спавна с таким clsid, а не при сканировании конфигов, как раньше. 1.1b: [+] проверена распаковка билд-спавнов, решена проблема декомпиляции спавнов билдов 25хх. [+] добавлен контроль наличия параметра version в секциях распакованного спавна. [f] исправлено исключение файла со spawn_id объектов при сканировании конфигов. 1.0b: [+] основательно переработан код, часть скрипта вынесена в отдельные модули. [f] исправлены все не работавшие функции. [+] увеличена скорость выполнения кода, уменьшены требования по памяти. ACDC для ТЧ - bardak, для ЗП - bardak, @Kolmogor. Все остальное - @KD87 Используйте/выкладывайте где и как хотите, с указанием авторов. Новичкам в редактировании спавна поможет краткая инструкция: Чтобы не плодить сторонних папок и все было под рукой для работы и игры - будем работать прямо в рабочей папке с игрой/модом. Устанавливаем и настраиваем комплект ACDC: 1. Открываем папку 'gamedata\spawns' и в ней создаем папку 'acdc'. 2. В эту папку (acdc) копируем (распаковываем) весь комплект файлов из архива 'Universal ACDC.7z', т.е. в папке должны лежать: - universal_acdc.pl - перл-скрипт утилиты; - acdc_decompile.bat - командный файл для распаковки; - acdc_compile.bat - командный файл для запаковки; - stkutils - папка со служебными библиотеками утилиты; ... - необязательные или технологические файлы (universal_acdc_readme.txt и т.п.). 4. Выходим опять в папку 'gamedata\spawns' и создаем в ней папку 'unpack' - в этой папке будут находиться файлы распакованного спавна. 5. Открываем командный файл (батник) 'acdc_decompile.bat' и изменяем в нем строку на эту: universal_acdc.pl -d ../all.spawn -o ../unpack -g ../../ -scan ../../config/ 6. Открываем командный файл (батник) 'acdc_compile.bat' и изменяем в нем строку на эту: universal_acdc.pl -c ../unpack -o ../all.spawn 7. Проверьте, есть ли в папке 'gamedata' файл 'game.graph'. Если его нет - распакуйте его из пак-файлов (gamedata.db*) оригинальной игры и скопируйте в папку 'gamedata' мода. 8. Важно! Для вашей безопасности скопируйте файл 'all.spawn' в удобное вам место (зарезервируйте) для возможности восстановления исходного файла спавна после возможных ваших ошибок при редактировании. Все, ваш комплект готов для работы с 'all/spawn'-ом на лету, т.е. вы можете запускать игру и играть, можете распаковывать, редактировать и запаковывать файл спавна. - Распаковка - запускаете 'acdc_decompile.bat' (см. по пути '\gamedata\spawns\acdc'); - Редактируете в папке 'unpack' (см. по пути '\gamedata\spawns\unpack'); - Запаковка - запускаете 'acdc_compile.bat' (см. по пути '\gamedata\spawns\acdc'); - ... проверяете в игре. Примечание: Если у вас стоит ОС Windows 7 - возможно потребуется в начало командных строк добавить вызов 'perl': perl universal_acdc.pl -d ../all.spawn -o ../unpack -g ../../ -scan ../../config/ perl universal_acdc.pl -c ../unpack -o ../all.spawn Успехов в модмейкерстве! :-) Для удобства выкладываю ссылку на ACDC отдельно (папка stkutils - ставить обязательно!) Версия 1.38 Для работы необходим Active Perl (брать с официального сайта) - LA (билд) - АМК v.1.4.1 - Z.E.N.O.B.I.A.N mod - NLC 2-6 - SIMBION - OGSM v.2.3.1 Final - Народная солянка 2010 от 19.04 (с ключом -nofatal) - R.M.A. v.1.1 - Oblivion_Lost - SRP - Тайные тропы 2 - Lost World - Requital - Lost World - Trops of Doom - OGSM v.1.7 (для распаковки исправьте в w_vintorez.ltx class = WP_VINT на class = WP_AK74 либо используйте ключ -nofatal) - Difficult Zone Mod v.1.0 (аналогично OGSM) - SolinX v.1.1.3 - SolinX v.2.0 (без сканирования) - Full Realism Mod v.1.0 - Shoker Mod v.1.2 (без сканирования) - SGM v.1.7 - SGM v.2.0 - Slayer mod beta 0.17 - ARS v.0.5.2 (без сканирования) - AMK ЗП v.0.4 Priboi Story не распаковывается из-за xrSpawner. Кому надо, вот распакованный спавн. Постите результаты распаковки спавнов, полученные вами. Внимание! Для повторного сканирования конфигов необходимо удалить файл sections.ini. Или воспользоваться батником acdc_decompile_scan (распаковка). Собрал большинство перл-скриптов в кучу и адаптировал их под единую библиотеку модулей stkutils. Написал пару новых скриптов. Итак: gamemtl.xr (поддерживается полная распаковка)lanims.xr (поддерживается полная распаковка)particles.xr (поддерживается только распаковка на бинарные файлы)shaders.xr (поддерживается полная распаковка)shaders_xrlc.xr (поддерживается полная распаковка)senvironment.xr (поддерживается полная распаковка) levellevel.snd_staticlevel.ps_static Распаковщик спавнов universal acdc 1.35 Распаковщик сохранений save unpacker 0.4 Сборщик/разборщик файлов RIFF-формата: chunk parser Скрипт для массовой замены строк файлах формата ini сталкера: data repclacement ini Скрипт для массовой замены строк в произвольных текстовых файлах: data repclacement text Скрипт для изменения высоты травы: details height changer Скрипт для копирования ресурсов разрабатываемой локации из СДК: resource copier Распакованную библиотеку модулей (папка stkutils) нужно положить в папку со скриптом или (советую) в C:\Perl\lib (или аналогичную папку, если вы установили ActivePerl в другую папку). Во втором случае stkutils будет работать для всех скриптов сразу независимо от расположения. Universal ACDC.exe от @PSI - версия утилиты, собранная в виде единого .exe файла и не требующая установки дополнительного софта.Репозиторий проектаСсылки на скачивание Universal ACDC v1.40 от @abramcumner - добавлено чтение секций из system.ltx - исправлены переносы строк при разбиении all.spawnРепозиторий проектаСcылки на скачивание 6 9 8 Ссылка на комментарий
Pluto 0 Опубликовано 23 Мая 2016 Поделиться Опубликовано 23 Мая 2016 Была у кого подобная проблема? Ссылка на комментарий
PTB 8 Опубликовано 24 Мая 2016 Поделиться Опубликовано 24 Мая 2016 Ребят, нужна помощи! Немогу разобрать спавн AMK 1.4.1 + Народная Солянка от 19.04.10. FATAL ERROR! Function: stkutils::file::entity::error Line: 247 Description: stkutils::file::entity::read_m_update 129 $packet->resid() == 0 update data left [1] in entity kat_wpn_ak74_m1 В жизни много плохих моментов. Пытайся избавляться от них ! Ссылка на комментарий
nasar75 3 868 Опубликовано 24 Мая 2016 Поделиться Опубликовано 24 Мая 2016 Description: stkutils::file::entity::read_m_update 129 $packet->resid() == 0 update data left [1] in entity kat_wpn_ak74_m1 допиши в батник -nofatal AMD Athlon II X2 250, NVIDIA GTS 450, RAM 8.0 GB, WIN 7/64 правки Золотой Шар Ссылка на комментарий
PTB 8 Опубликовано 24 Мая 2016 Поделиться Опубликовано 24 Мая 2016 @nasar75, Не помогает.Ещё вопрос:Вылетает ggrcВот сам файл data_packet.pm # Module for packing and unpacking data# Update history:# 26/08/2012 - fix for new fail() syntax######################################################package stkutils::data_packet;use strict;use IO::File;use stkutils::debug qw(fail);use stkutils::ini_file;use stkutils::math;use POSIX;use constant FL_IS_25XX => 0x08;use constant FL_HANDLED => 0x20;use constant SUCCESS_HANDLE => 2;use constant template_len => {'V' => 4,'v' => 2,'C' => 1,'l' => 4,'f' => 4,'vf' => 6,'v4' => 8,'a[16]' => 16,'C8' => 8,'C4' => 4,'f2' => 8,'f3' => 12,'f4' => 16,'l3' => 12,'l4' => 16,'V2' => 8,'V3' => 12,'V4' => 16,'a[12]' => 12,'a[8]' => 8,'a[169]' => 169,'a[157]' => 157,'a[153]' => 153,};use constant template_for_scalar => {h8 => 'C',h16 => 'v',h32 => 'V',u8 => 'C',u16 => 'v',u32 => 'V',s8 => 'C',s16 => 'v',s32 => 'l',q8 => 'C',q16 => 'v',q16_old => 'v',sz => 'Z*',f32 => 'f',guid => 'a[16]',ha1 => 'a[12]',ha2 => 'a[8]',dumb_1 => 'a[169]',dumb_2 => 'a[157]',dumb_3 => 'a[153]',};use constant template_for_vector => {l8u8v => 'C/C',l8u16v => 'C/v',l8u32v => 'C/V',l8szv => 'C/(Z*)',l8szbv => 'C/(Z*C)',l8szu16v => 'C/(Z*v)',l8u16u8v => 'C/(v*C)',l8u16u16v => 'C/(v*v)',l16u16v => 'v/v',l32u8v => 'V/C',l32u16v => 'V/v',l32u32v => 'V/V',l32szv => 'V/(Z*)',u8v3 => 'C3',u8v4 => 'C4',u8v8 => 'C8',u32v2 => 'V2',u16v4 => 'v4',f32v2 => 'f2',f32v3 => 'f3',f32v4 => 'f4',s32v3 => 'l3',s32v4 => 'l4',h32v3 => 'V3',h32v4 => 'V4',q8v3 => 'C3',q8v4 => 'C4',sdir => 'vf',};#function refsuse constant sub_hash => {'convert_q8' => \&convert_q8,'convert_q16' => \&convert_q16,'convert_q16_old' => \&convert_q16_old,'convert_u8' => \&convert_u8,'convert_u16' => \&convert_u16,'convert_u16_old' => \&convert_u16_old,};#constructorsub new {my $class = shift;my $data = shift;my $self = {};$self->{data} = '';$self->{data} = $$data if defined $data;$self->{init_length} = CORE::length($self->{data});$self->{pos} = 0;bless($self, $class);return $self;}sub DESTROY {undef $_[0]->{data};}#unpacksub unpack {# my $self = shift;# my $template = shift;my $fl = 0;$fl = 1 if ($_[1] =~ /f/ and $_[1] !~ /Z/);fail("packet is not defined") if !(defined $_[0]);fail("there is no data in packet") if !(defined $_[0]->{data});fail("template is not defined") if !(defined $_[1]);my @values;if (!defined $_[2]) {@values = CORE::unpack($_[1].'a*', substr($_[0]->{data}, $_[0]->{pos}));fail("cannot unpack requested data") if $#values == -1;$_[0]->{pos} = length($_[0]->{data}) - length(pop(@values));} else {my $resid = length($_[0]->{data}) - $_[0]->{pos};fail ("data [$resid] is shorter than template [$_[2]]") if $_[2] > $resid;@values = CORE::unpack($_[1], substr($_[0]->{data}, $_[0]->{pos}, $_[2]));$_[0]->{pos} += $_[2];}fail("data container is empty") if !(defined $_[0]->{data});#print "@values\n";if ($fl == 1) {foreach my $val (@values) {$val = 0 if (isinf($val) || isnan($val));}$fl = 0;}return @values;}sub unpack_properties {my $self = shift;my $container = shift;foreach my $p (@_) {#print "$p->{name} = "; my $template = template_for_scalar->{$p->{type}};($p->{type} eq 'sz') && do {$self->_unpack_string($container, $p); next;};defined $template && do {$self->_unpack_scalar($template, $container, $p); last if is_handled($container); next;};($p->{type} eq 'u24') && do {$self->_unpack_u24($container, $p); next;};($p->{type} eq 'shape') && do {$self->_unpack_shape($container, $p); next;};($p->{type} eq 'skeleton') && do {$self->_unpack_skeleton($container, $p); next;};($p->{type} eq 'supplies') && do {$self->_unpack_supplies($container, $p); next;};($p->{type} =~ /afspawns/) && do {$self->_unpack_artefact_spawns($container, $p); next;};($p->{type} eq 'ordaf') && do {$self->_unpack_ordered_artefacts($container, $p); next;};($p->{type} eq 'CTime') && do {$container->{$p->{name}} = $self->unpack_ctime(); next;};($p->{type} eq 'complex_time') && do {$container->{$p->{name}} = $self->_unpack_complex_time($container, $p); last if is_handled($container); next;};($p->{type} eq 'npc_info') && do {$self->_unpack_npc_info($container, $p); next;};($p->{type} eq 'sdir') && do {$self->_unpack_sdir($container, $p); last if is_handled($container); next;};#SOC($p->{type} eq 'jobs') && do {$self->_unpack_jobs($container, $p); next;};#CS($p->{type} eq 'covers') && do {$self->_unpack_covers($container, $p); next;};($p->{type} eq 'squads') && do {$self->_unpack_squads($container, $p); next;};($p->{type} eq 'sim_squads') && do {$self->_unpack_sim_squads($container, $p); next;};($p->{type} eq 'inited_tasks') && do {$self->_unpack_inited_tasks($container, $p); next;};($p->{type} eq 'inited_find_upgrade_tasks') && do {$self->_unpack_inited_find_upgrade_tasks($container, $p); next;};($p->{type} eq 'rewards') && do {$self->_unpack_rewards($container, $p); next;};($p->{type} eq 'minigames') && do {$self->_unpack_minigames($container, $p); next;};#COP($p->{type} eq 'times') && do {$self->_unpack_times($container, $p); next;};$self->_unpack_vector($container, $p);last if is_handled($container);}}sub _unpack_scalar {my ($self, $template, $container, $p) = @_;$self->error_handler($container, $template) if (CORE::length($self->data()) == $self->pos() || (defined template_len->{$template} && $self->resid() < template_len->{$template}));return if is_handled($container);($container->{$p->{name}}) = $self->unpack($template, template_len->{$template});if ($p->{type} =~ /q/) {my $func = "convert_".$p->{type};$container->{$p->{name}} = sub_hash->{$func}($container->{$p->{name}}, -1, 1);}}sub _unpack_u24 {my ($self, $container, $p) = @_;($container->{$p->{name}}) = CORE::unpack('V', CORE::pack('CCCC', $self->unpack('C3', 3), 0));}sub _unpack_string {my ($self, $container, $p) = @_;($container->{$p->{name}}) = $self->unpack('Z*');chomp $container->{$p->{name}};$container->{$p->{name}} =~ s/\r//g;}sub _unpack_vector {my ($self, $container, $p) = @_;my $template = template_for_vector->{$p->{type}};$self->error_handler($container, $template) if (CORE::length($self->data()) == $self->pos() || (defined template_len->{$template} && $self->resid() < template_len->{$template}));return if is_handled($container);@{$container->{$p->{name}}} = $self->unpack($template, template_len->{$template});if ($p->{type} =~ /(q\d+)/) {my $func = "convert_".$1;foreach (@{$container->{$p->{name}}}) {$_ = sub_hash->{$func}($_, -1, 1);}}}sub _unpack_sdir {my ($self, $container, $p) = @_;$self->error_handler($container, 'vf') if (CORE::length($self->data()) == $self->pos() || $self->resid() < 6);return if is_handled($container);$self->_unpack_dir($container, $p);my ($s) = $self->unpack('f', 4);$container->{$p->{name}}[0] *= $s;$container->{$p->{name}}[1] *= $s;$container->{$p->{name}}[2] *= $s;}sub _unpack_dir {my ($self, $container, $p) = @_;my ($t) = $self->unpack('v', 2);my ($i, $u, $v);my ($x, $y, $z);$u = ($t >> 7) & 0x3f;$v = $t & 0x7f;if ($u + $v >= 0x7f) {$u = 0x7f - $u;$v = 0x7f - $v;}$i = $t & 0x1fff;$self->_prepare_uv_adjustment();$x = $self->{uv_adjustment}[$i] * $u;$y = $self->{uv_adjustment}[$i] * $v;my $j = 126-$u-$v;if ($j == 0) {$z = 0.0000000000001;} else {$z = $self->{uv_adjustment}[$i] * $j;}$x *= -1 if $t & 0x8000;$y *= -1 if $t & 0x4000;$z *= -1 if $t & 0x2000;@{$container->{$p->{name}}} = ($x, $y, $z);}sub _prepare_uv_adjustment {my ($i, $u, $v);for (my $i = 0; $i < 0x2000; $i++) {$u = $i >> 7;$v = $i & 0x7f;if ($u + $v >= 0x7f) {$u = 0x7f - $u;$v = 0x7f - $v;}$_[0]->{uv_adjustment}[$i] = 1.0/sqrt($u*$u + $v*$v + (126-$u-$v)*(126-$u-$v));}}sub _unpack_shape {my ($self, $container, $p) = @_;my ($count) = $self->unpack('C', 1);while ($count--) {my %shape;($shape{type}) = $self->unpack('C', 1);if ($shape{type} == 0) {@{$shape{sphere}} = $self->unpack('f4', 16);} elsif ($shape{type} == 1) {@{$shape{box}} = $self->unpack('f12', 48);} else {fail("shape has undefined type ($shape{type})");}push @{$container->{$p->{name}}}, \%shape;}}sub _unpack_skeleton {my ($self, $container, $p) = @_;@{$container->{bones_mask}} = $self->unpack('C8', 8);($container->{root_bone}) = $self->unpack('v', 2);@{$container->{bbox_min}} = $self->unpack('f3', 12);@{$container->{bbox_max}} = $self->unpack('f3', 12);my ($count) = $self->unpack('v', 2);while ($count--) {my %bone;@{$bone{ph_position}} = $self->unpack('C3', 3);my $i = 0;foreach (@{$bone{ph_position}}) {$_ = convert_q8($_, $container->{bbox_min}[$i], $container->{bbox_max}[$i]);$i++;}@{$bone{ph_rotation}} = $self->unpack('C4', 4);foreach (@{$bone{ph_rotation}}) {$_ = convert_q8($_, -1, 1);}($bone{enabled}) = $self->unpack('C', 1);push @{$container->{bones}}, \%bone;}}sub _unpack_supplies {my ($self, $container, $p) = @_;my ($count) = $self->unpack('V', 4);while ($count--) {my $obj = {};($obj->{section_name}) = $self->unpack('Z*');($obj->{item_count}, $obj->{min_factor}, $obj->{max_factor}) = $self->unpack('Vff', 12);push @{$container->{$p->{name}}}, $obj;}}sub _unpack_artefact_spawns {my ($self, $container, $p) = @_;my ($count) = $self->unpack('v', 2);while ($count--) {my $obj = {};($obj->{section_name}) = $self->unpack('Z*');if ($p->{type} eq 'afspawns') {($obj->{weight}) = $self->unpack('f', 4);} else {($obj->{weight}) = $self->unpack('V', 4);}push @{$container->{$p->{name}}}, $obj;}}sub _unpack_ordered_artefacts {my ($self, $container, $p) = @_;my ($count) = $self->unpack('V', 4);while ($count--) {my $obj = {};($obj->{unknown_string}) = $self->unpack('Z*');($obj->{unknown_number}) = $self->unpack('V', 4);my ($inner_count) = $self->unpack('V', 4);while ($inner_count--) {my $afs = {};($afs->{artefact_name}) = $self->unpack('Z*');($afs->{number_1},$afs->{number_2}) = $self->unpack('VV', 8);push @{$obj->{af_sects}}, $afs;}push @{$container->{$p->{name}}}, $obj;}}sub unpack_ctime {my ($self) = @_;my $time = stkutils::math->create('CTime');my ($year) = $self->unpack('C', 1);if ($year != 0 && $year != 255) {$time->set($year, $self->unpack('C5v', 7))} else {$time->set($year);}return $time;}sub _unpack_complex_time {my ($self, $container, $p) = @_;$self->error_handler($container, 'C') if (CORE::length($self->data()) == $self->pos() || ($self->resid() < 1));return if is_handled($container);my ($flag) = $self->unpack('C', 1);if ($flag != 0) {return $self->unpack_ctime()} else {return 0;}}sub _unpack_jobs {my ($self, $container, $p) = @_;my ($count) = $self->unpack('C', 1);while($count--) {my $job = {};($job->{job_begin},$job->{job_fill_idle},$job->{job_idle_after_death_end}) = $self->unpack('VVV', 12);push @{$container->{$p->{name}}}, $job;}}sub _unpack_npc_info {my $self = shift;if ($_[0]->{version} >= 122) {$self->_unpack_npc_info_cop(@_);} elsif ($_[0]->{version} >= 117) {$self->_unpack_npc_info_soc(@_);} else {$self->_unpack_npc_info_old(@_);}}sub _unpack_npc_info_old {my ($self, $container, $p) = @_;my ($count) = $self->unpack('C', 1);while($count--) {my %info;($info{o_id},$info{group},$info{squad},$info{move_offline},$info{switch_offline}) = $self->unpack('vCCCC', 6);$info{stay_end} = $self->unpack_ctime();($info{jobN}) = $self->unpack('C', 1) if $container->{script_version} >= 1 && $container->{gulagN} != 0;push @{$container->{$p->{name}}}, \%info;}}sub _unpack_npc_info_soc {my ($self, $container, $p) = @_;my ($count) = $self->unpack('C', 1);while($count--) {my %info;($info{o_id},$info{o_group},$info{o_squad},$info{exclusive}) = $self->unpack('vCCC', 5);$info{stay_end} = $self->unpack_ctime();($info{Object_begin_job}) = $self->unpack('C', 1);($info{Object_didnt_begin_job}) = $self->unpack('C', 1) if $container->{script_version} > 4;($info{jobN}) = $self->unpack('C', 1);push @{$container->{$p->{name}}}, \%info;}}sub _unpack_npc_info_cop {my ($self, $container, $p) = @_;my ($count) = $self->unpack('C', 1);while($count--) {my %info;($info{id},$info{job_prior},$info{job_id},$info{begin_job},$info{need_job}) = $self->unpack('vCCCZ*');push @{$container->{$p->{name}}}, \%info;}}sub _unpack_covers {my ($self, $container, $p) = @_;my ($count) = $self->unpack('C', 1);while($count--) {my %cover;($cover{npc_id},$cover{cover_vertex_id}) = $self->unpack('vV', 6);@{$cover{cover_position}} = $self->unpack('f3', 12);@{$cover{look_pos}} = $self->unpack('f3', 12);($cover{is_smart_cover}) = $self->unpack('C', 1);push @{$container->{$p->{name}}}, \%cover;}}sub _unpack_squads {my ($self, $container, $p) = @_;my ($count) = $self->unpack('C', 1);while($count--) {my %squad;($squad{squad_name},$squad{squad_stage},$squad{squad_prepare_shouted},$squad{squad_attack_shouted},$squad{squad_attack_squad}) = $self->unpack('Z*Z*CCC');$squad{squad_inited_defend_time} = $self->_unpack_complex_time();$squad{squad_start_attack_wait} = $self->_unpack_complex_time();$squad{squad_last_defence_kill_time} = $self->_unpack_complex_time();($squad{squad_power}) = $self->unpack('f', 4);push @{$container->{$p->{name}}}, \%squad;}}sub _unpack_sim_squads {my ($self, $container, $p) = @_;my ($count) = $self->unpack('v', 2);while($count--) {my $squad = {};($squad->{squad_id},$squad->{settings_id},$squad->{is_scripted}) = $self->unpack('Z*Z*C');$self->_unpack_sim_squad_generic($container, $squad);if ($squad->{is_scripted} == 1) {$self->set_save_marker($container, 'load', 0, 'sim_squad_scripted');($squad->{next_target},$squad->{need_free_update},$squad->{relationship},$squad->{sympathy}) = $self->unpack('CCCC', 4);$self->set_save_marker($container, 'load', 1, 'sim_squad_scripted');}push @{$container->{$p->{name}}}, $squad;}}sub _unpack_sim_squad_generic {my ($self, $container, $squad) = @_;$self->set_save_marker($container, 'load', 0, 'sim_squad_generic');($squad->{smart_id},$squad->{assigned_target_smart_id},$squad->{sim_combat_id},$squad->{delayed_attack_task}) = $self->unpack('vvvv', 8);@{$squad->{random_tasks}} = $self->unpack('C/(vv)');($squad->{npc_count},$squad->{squad_power},$squad->{commander_id}) = $self->unpack('Cfv', 7);@{$squad->{squad_npc}} = $self->unpack('C/v');($squad->{spoted_shouted}) = $self->unpack('C', 1);$squad->{last_action_timer} = $self->unpack_ctime();($squad->{squad_attack_power}) = $self->unpack('v', 2);my ($flag) = $self->unpack('C', 1);if ($flag == 1) {($squad->{class}) = $self->unpack('C', 1);if ($squad->{class} == 1) {#sim_attack_point($squad->{dest_smrt_id}) = $self->unpack('v', 2);$self->set_save_marker($container, 'load', 0, 'sim_attack_point');($squad->{major},$squad->{target_power_value}) = $self->unpack('Cv', 3);$self->set_save_marker($container, 'load', 1, 'sim_attack_point');} else {#sim_stay_point$self->set_save_marker($container, 'load', 0, 'sim_stay_point');($squad->{stay_defended},$squad->{next_point_id}) = $self->unpack('Cv', 3);$squad->{begin_time} = $self->_unpack_complex_time();$self->set_save_marker($container, 'load', 1, 'sim_stay_point');}}($squad->{items_spawned}) = $self->unpack('C', 1);$squad->{bring_item_inited_time} = $self->unpack_ctime();$squad->{recover_item_inited_time} = $self->unpack_ctime();$self->set_save_marker($container, 'load', 1, 'sim_squad_generic');}sub _unpack_times {my ($self, $container, $p) = @_;my ($count) = $self->unpack('C', 1);while($count--) {my $time = $self->_unpack_complex_time();push @{$container->{$p->{name}}}, $time;}}sub _unpack_inited_find_upgrade_tasks {my ($self, $container, $p) = @_;my ($count) = $self->unpack('v', 2);while($count--) {my $task = {};($task->{k}) = $self->unpack('v', 2);my ($num) = $self->unpack('v', 2);while($num--) {my $subtask = {};($subtask->{kk},$subtask->{entity_id}) = $self->unpack('Z*v');push @{$task->{subtasks}}, $subtask;}push @{$container->{$p->{name}}}, $task;}}sub _unpack_rewards {my ($self, $container, $p) = @_;my ($count) = $self->unpack('C', 1);while($count--) {my $comm = {};($comm->{community}) = $self->unpack('Z*');my ($num) = $self->unpack('C', 1);while($num--) {my $reward = {};($reward->{is_money}) = $self->unpack('C', 1);if ($reward->{is_money} == 1) {($reward->{amount}) = $self->unpack('v', 2);} else {($reward->{item_name}) = $self->unpack('Z*');}push @{$comm->{rewards}}, $reward;}push @{$container->{$p->{name}}}, $comm;}}sub _unpack_CGeneralTask {my ($self, $task, $container) = @_;$self->set_save_marker($container, 'load', 0, 'CGeneralTask');($task->{entity_id},$task->{prior},$task->{status},$task->{actor_helped},$task->{community},$task->{actor_come},$task->{actor_ignore}) = $self->unpack('vCCCZ*CC');$task->{inited_time} = $self->unpack_ctime();$self->set_save_marker($container, 'load', 1, 'CGeneralTask');}sub _unpack_CStorylineTask {my ($self, $task, $container) = @_;$self->set_save_marker($container, 'load', 0, 'CStorylineTask');$self->_unpack_CGeneralTask($task, $container);($task->{target}) = $self->unpack('V', 4);$self->set_save_marker($container, 'load', 1, 'CStorylineTask');}sub _unpack_CEliminateSmartTask {my ($self, $task, $container) = @_;$self->set_save_marker($container, 'load', 0, 'CEliminateSmartTask');$self->_unpack_CGeneralTask($task, $container);($task->{target},$task->{src_obj},$task->{faction}) = $self->unpack('vZ*Z*');$self->set_save_marker($container, 'load', 1, 'CEliminateSmartTask');}sub _unpack_CCaptureSmartTask {my ($self, $task, $container) = @_;$self->set_save_marker($container, 'load', 0, 'CCaptureSmartTask');$self->_unpack_CGeneralTask($task, $container);($task->{target},$task->{state},$task->{counter_attack_community},$task->{counter_squad},$task->{src_obj},$task->{faction}) = $self->unpack('vZ*Z*Z*Z*Z*');$self->set_save_marker($container, 'load', 1, 'CCaptureSmartTask');}sub _unpack_CDefendSmartTask {my ($self, $task, $container) = @_;$self->set_save_marker($container, 'load', 0, 'CDefendSmartTask');$self->_unpack_CGeneralTask($task, $container);($task->{target}) = $self->unpack('v');$task->{last_called_time} = $self->unpack_ctime();$self->set_save_marker($container, 'load', 1, 'CDefendSmartTask');}sub _unpack_CBringItemTask {my ($self, $task, $container) = @_;$self->set_save_marker($container, 'load', 0, 'CBringItemTask');$self->_unpack_CGeneralTask($task, $container);($task->{state},$task->{ri_counter},$task->{target},$task->{squad_id}) = $self->unpack('Z*CvZ*');my ($num) = $self->unpack('C', 1);while ($num--) {my $requested_item = {};($requested_item->{id}) = $self->unpack('Z*');@{$requested_item->{items}} = $self->unpack('v/C');push @{$task->{requested_items}}, $requested_item;}$self->set_save_marker($container, 'load', 1, 'CBringItemTask');}sub _unpack_CRecoverItemTask {my ($self, $task, $container) = @_;$self->set_save_marker($container, 'load', 0, 'CRecoverItemTask');$self->_unpack_CGeneralTask($task, $container);($task->{state},$task->{squad_id},$task->{target_obj_id},$task->{presence_requested_item},$task->{requested_item}) = $self->unpack('CZ*vCZ*');$self->set_save_marker($container, 'load', 1, 'CRecoverItemTask');}sub _unpack_CFindUpgradeTask {my ($self, $task, $container) = @_;$self->set_save_marker($container, 'load', 0, 'CFindUpgradeTask');$self->_unpack_CGeneralTask($task, $container);($task->{state},$task->{presence_requested_item},$task->{requested_item}) = $self->unpack('Z*CZ*');$self->set_save_marker($container, 'load', 1, 'CFindUpgradeTask');}sub _unpack_CHideFromSurgeTask {my ($self, $task, $container) = @_;$self->set_save_marker($container, 'load', 0, 'CHideFromSurgeTask');$self->_unpack_CGeneralTask($task, $container);($task->{target},$task->{wait_time},$task->{effector_started_time}) = $self->unpack('vvv', 12);$self->set_save_marker($container, 'load', 1, 'CHideFromSurgeTask');}sub _unpack_CEliminateSquadTask {my ($self, $task, $container) = @_;$self->set_save_marker($container, 'load', 0, 'CEliminateSquadTask');$self->_unpack_CGeneralTask($task, $container);($task->{target},$task->{src_obj}) = $self->unpack('vZ*');$self->set_save_marker($container, 'load', 1, 'CEliminateSquadTask');}sub _unpack_inited_tasks {my ($self, $container, $p) = @_;my ($count) = $self->unpack('v', 2);while($count--) {my $task = {};($task->{base_id},$task->{id},$task->{type}) = $self->unpack('Z*Z*v');SWITCH: {($task->{type} == 0 || $task->{type} == 5) && do {$self->_unpack_CStorylineTask($task, $container);last SWITCH;};$task->{type} == 1 && do {$self->_unpack_CEliminateSmartTask($task, $container);last SWITCH;};$task->{type} == 2 && do {$self->_unpack_CCaptureSmartTask($task, $container);last SWITCH;};($task->{type} == 3 || $task->{type} == 4) && do {$self->_unpack_CDefendSmartTask($task, $container);last SWITCH;};$task->{type} == 6 && do {$self->_unpack_CBringItemTask($task, $container);last SWITCH;};$task->{type} == 7 && do {$self->_unpack_CRecoverItemTask($task, $container);last SWITCH;};$task->{type} == 8 && do {$self->_unpack_CFindUpgradeTask($task, $container);last SWITCH;};$task->{type} == 9 && do {$self->_unpack_CHideFromSurgeTask($task, $container);last SWITCH;};$task->{type} == 10 && do {$self->_unpack_CEliminateSquadTask($task, $container);last SWITCH;};}push @{$container->{$p->{name}}}, $task;}}sub _unpack_minigames {my ($self, $container, $p) = @_;my ($count) = $self->unpack('v', 2);while($count--) {my $minigame = {};($minigame->{key},$minigame->{profile},$minigame->{state}) = $self->unpack('Z*Z*Z*');if ($minigame->{profile} eq 'CMGCrowKiller') {$self->set_save_marker($container, 'load', 0, 'CMGCrowKiller');($minigame->{param_highscore},$minigame->{param_timer},$minigame->{param_win}) = $self->unpack('CvC', 4);@{$minigame->{param_crows_to_kill}} = $self->unpack('C/C');($minigame->{param_money_multiplier},$minigame->{param_champion_multiplier},$minigame->{param_selected},$minigame->{param_game_type},$minigame->{high_score},$minigame->{timer},$minigame->{time_out},$minigame->{killed_counter},$minigame->{win}) = $self->unpack('vvCZ*CvvCC');$self->set_save_marker($container, 'load', 1, 'CMGCrowKiller');} elsif ($minigame->{profile} eq 'CMGShooting') {$self->set_save_marker($container, 'load', 0, 'CMGShooting');($minigame->{param_game_type},$minigame->{param_wpn_type},$minigame->{param_stand_way},$minigame->{param_look_way},$minigame->{param_stand_way_back},$minigame->{param_look_way_back},$minigame->{param_obj_name}) = $self->unpack('Z*Z*Z*Z*Z*Z*Z*');($minigame->{param_is_u16}) = $self->unpack('C', 1);if ($minigame->{param_is_u16} == 0) {($minigame->{param_win}) = $self->unpack('C', 1);} else {($minigame->{param_win}) = $self->unpack('v', 2);}($minigame->{param_distance},$minigame->{param_ammo}) = $self->unpack('CC', 2);my ($count) = $self->unpack('C', 1);while($count--) {my @target = $self->unpack('C/(Z*)');push @{$minigame->{targets}}, \@target;}($minigame->{param_target_counter}) = $self->unpack('C', 1);@{$minigame->{inventory_items}} = $self->unpack('C/v');($minigame->{prev_time},$minigame->{type}) = $self->unpack('VZ*');if ($minigame->{type} eq 'training' ||$minigame->{type} eq 'points') {$self->set_save_marker($container, 'load', 0, $minigame->{type});($minigame->{win},$minigame->{ammo},$minigame->{cur_target},$minigame->{points},$minigame->{ammo_counter}) = $self->unpack('vvZ*vC');$self->set_save_marker($container, 'load', 1, $minigame->{type});} elsif ($minigame->{type} eq 'count') {$self->set_save_marker($container, 'load', 0, $minigame->{type});($minigame->{wpn_type},$minigame->{win},$minigame->{ammo}) = $self->unpack('Z*CC');my ($count) = $self->unpack('C', 1);while($count--) {my @target = $self->unpack('C/(Z*)');push @{$minigame->{targets}}, \@target;}($minigame->{distance},$minigame->{cur_target},$minigame->{points},$minigame->{scored},$minigame->{ammo_counter}) = $self->unpack('CZ*CCC');$self->set_save_marker($container, 'load', 1, $minigame->{type});} elsif ($minigame->{type} eq 'three_hit_training') {$self->set_save_marker($container, 'load', 0, $minigame->{type});($minigame->{wpn_type},$minigame->{win},$minigame->{ammo}) = $self->unpack('Z*vC');my ($count) = $self->unpack('C', 1);while($count--) {my @target = $self->unpack('C/(Z*)');push @{$minigame->{targets}}, \@target;}($minigame->{distance},$minigame->{cur_target},$minigame->{points},$minigame->{scored},$minigame->{ammo_counter},$minigame->{target_counter},$minigame->{target_hit}) = $self->unpack('CZ*vCCCC');$self->set_save_marker($container, 'load', 1, $minigame->{type});} elsif ($minigame->{type} eq 'all_targets') {$self->set_save_marker($container, 'load', 0, $minigame->{type});($minigame->{wpn_type},$minigame->{win},$minigame->{ammo}) = $self->unpack('Z*vC');my ($count) = $self->unpack('C', 1);while($count--) {push @{$minigame->{targets}}, \$self->unpack('C/(Z*)');push @{$minigame->{hitted_targets}}, \$self->unpack('C/(CZ*)');}($minigame->{ammo_counter},$minigame->{time},$minigame->{target_counter},$minigame->{prev_time},$minigame->{more_targets},$minigame->{last_target}) = $self->unpack('CvCVCZ*');$self->set_save_marker($container, 'load', 1, $minigame->{type});} elsif ($minigame->{type} eq 'count_on_time') {$self->set_save_marker($container, 'load', 0, $minigame->{type});($minigame->{wpn_type},$minigame->{win},$minigame->{ammo}) = $self->unpack('Z*CC');my ($count) = $self->unpack('C', 1);while($count--) {push @{$minigame->{targets}}, \$self->unpack('C/(Z*)');}($minigame->{distance},$minigame->{cur_target},$minigame->{points},$minigame->{scored},$minigame->{ammo_counter},$minigame->{time},$minigame->{prev_time}) = $self->unpack('CZ*CCCCV');$self->set_save_marker($container, 'load', 1, $minigame->{type});} elsif ($minigame->{type} eq 'ten_targets') {$self->set_save_marker($container, 'load', 0, $minigame->{type});($minigame->{wpn_type},$minigame->{win},$minigame->{ammo}) = $self->unpack('Z*CC');my ($count) = $self->unpack('C', 1);while($count--) {push @{$minigame->{targets}}, \$self->unpack('C/(Z*)');}($minigame->{distance},$minigame->{cur_target},$minigame->{points},$minigame->{scored},$minigame->{ammo_counter},$minigame->{time},$minigame->{prev_time}) = $self->unpack('CZ*CCCvV');$self->set_save_marker($container, 'load', 1, $minigame->{type});} elsif ($minigame->{type} eq 'two_seconds_standing') {$self->set_save_marker($container, 'load', 0, $minigame->{type});($minigame->{wpn_type},$minigame->{win},$minigame->{ammo}) = $self->unpack('Z*CC');my ($count) = $self->unpack('C', 1);while($count--) {push @{$minigame->{targets}}, \$self->unpack('C/(Z*)');}($minigame->{distance},$minigame->{cur_target},$minigame->{points},$minigame->{ammo_counter},$minigame->{time},$minigame->{prev_time}) = $self->unpack('CZ*CCCV');$self->set_save_marker($container, 'load', 1, $minigame->{type});}$self->set_save_marker($container, 'load', 1, 'CMGShooting');}push @{$container->{$p->{name}}}, $minigame;}}#packsub pack {my $self = shift;my $template = shift;fail("template is not defined") if !(defined $template);fail("data is not defined") if !(@_);fail("packet is not defined") unless defined $self;# print "@_\n";$self->{data} .= CORE::pack($template, @_);}sub pack_properties {my $self = shift;my $container = shift; foreach my $p (@_) {#print "$p->{name} = ";my $template = template_for_scalar->{$p->{type}};defined $template && do {$self->_pack_scalar($template, $container, $p); next;};($p->{type} eq 'u24') && do {$self->_pack_u24($container, $p); next;};($p->{type} =~ /^l/) && do {$self->_pack_complex($container, $p); next;};($p->{type} eq 'shape') && do {$self->_pack_shape($container, $p); next;};($p->{type} eq 'skeleton') && do {$self->_pack_skeleton($container, $p); next;};($p->{type} eq 'supplies') && do {$self->_pack_supplies($container, $p); next;};($p->{type} =~ /afspawns/) && do {$self->_pack_artefact_spawns($container, $p); next;};($p->{type} eq 'ordaf') && do {$self->_pack_ordered_artefacts($container, $p); next;};($p->{type} eq 'CTime') && do {$self->_pack_ctime($container->{$p->{name}}); next;};($p->{type} eq 'complex_time') && do {$self->_pack_complex_time($container->{$p->{name}}); next;};($p->{type} eq 'npc_info') && do {$self->_pack_npc_info($container, $p); next;};($p->{type} eq 'sdir') && do {$self->_pack_sdir($container, $p); next;};#SOC($p->{type} eq 'jobs') && do {$self->_pack_jobs($container, $p); next;};#CS($p->{type} eq 'covers') && do {$self->_pack_covers($container, $p); next;};($p->{type} eq 'squads') && do {$self->_pack_squads($container, $p); next;};($p->{type} eq 'sim_squads') && do {$self->_pack_sim_squads($container, $p); next;};($p->{type} eq 'inited_tasks') && do {$self->_pack_inited_tasks($container, $p); next;};($p->{type} eq 'inited_find_upgrade_tasks') && do {$self->_pack_inited_find_upgrade_tasks($container, $p); next;};($p->{type} eq 'rewards') && do {$self->_pack_rewards($container, $p); next;};($p->{type} eq 'minigames') && do {$self->_pack_minigames($container, $p); next;};#COP($p->{type} eq 'times') && do {$self->_pack_times($container, $p); next;};$self->_pack_vector($container, $p);}}sub _pack_scalar {my ($self, $template, $container, $p) = @_;if ($p->{type} =~ /q(.*)/) {my $func = "convert_u".$1;$container->{$p->{name}} = sub_hash->{$func}($container->{$p->{name}}, -1, 1);}$self->pack($template, $container->{$p->{name}});}sub _pack_u24 {my ($self, $container, $p) = @_;$self->pack('CCC', CORE::unpack('CCCC', CORE::pack('V', $container->{$p->{name}})));}sub _pack_complex {my ($self, $container, $p) = @_;my $n = $#{$container->{$p->{name}}} + 1;if ($p->{type} eq 'l8u8v') {$self->pack("CC$n", $n, @{$container->{$p->{name}}});} elsif ($p->{type} eq 'l8u16v') {$self->pack("Cv$n", $n, @{$container->{$p->{name}}});} elsif ($p->{type} eq 'l8u32v') {$self->pack("CV$n", $n, @{$container->{$p->{name}}});} elsif ($p->{type} eq 'l8szv') {$self->pack("C(Z*)$n", $n, @{$container->{$p->{name}}});} elsif ($p->{type} eq 'l8szbv') {$n = $n/2;$self->pack("C(Z*C)$n", $n, @{$container->{$p->{name}}});} elsif ($p->{type} eq 'l8szu16v') {$n = $n/2;$self->pack("C(Z*v)$n", $n, @{$container->{$p->{name}}});} elsif ($p->{type} eq 'l8u16u8v') {$n = $n/2;$self->pack("C(v*C)$n", $n, @{$container->{$p->{name}}});} elsif ($p->{type} eq 'l8u16u16v') {$n = $n/2;$self->pack("C(v*v)$n", $n, @{$container->{$p->{name}}});} elsif ($p->{type} eq 'l16u16v') {$self->pack("vv$n", $n, @{$container->{$p->{name}}});} elsif ($p->{type} eq 'l32u8v') {$self->pack("VC$n", $n, @{$container->{$p->{name}}});} elsif ($p->{type} eq 'l32u16v') {$self->pack("Vv$n", $n, @{$container->{$p->{name}}});} elsif ($p->{type} eq 'l32u32v') {$self->pack("VV$n", $n, @{$container->{$p->{name}}});} elsif ($p->{type} eq 'l32szv') {$self->pack("V(Z*)$n", $n, @{$container->{$p->{name}}});}}sub _pack_vector {my ($self, $container, $p) = @_;if ($p->{type} =~ /q(\d+)/) {my $func = "convert_u".$1;foreach (@{$container->{$p->{name}}}) {$_ = sub_hash->{$func}($_, -1, 1);}}$self->pack(template_for_vector->{$p->{type}}, @{$container->{$p->{name}}});}sub _pack_sdir {my ($self, $container, $p) = @_;my ($x, $y, $z) = @{$container->{$p->{name}}};my ($s) = sqrt($x*$x + $y*$y + $z*$z);if ($s > 0.0000001) {$container->{$p->{name}}[0] /= $s;$container->{$p->{name}}[1] /= $s;$container->{$p->{name}}[2] /= $s;$self->_pack_dir($container, $p);} else {$s = 0.0;$container->{$p->{name}}[0] = 0;$container->{$p->{name}}[1] = 0;$container->{$p->{name}}[2] = 0;$self->pack('v', 0);}$self->pack('f', $s);}sub _pack_dir {my ($self, $container, $p) = @_;my ($x, $y, $z) = @{$container->{$p->{name}}};my ($i, $u, $v);my $t = 0;if ($x < 0) {$t = 0x8000;$x = -$x;}if ($y < 0) {$t |= 0x4000;$y = -$y;}if ($z < 0) {$t |= 0x2000;$z = -$z;}$i = ($x + $y + $z)/126;$u = round($x / $i);$v = round($y / $i);if ($u >= 64) {$v = 127 - $v;$u = 127 - $u;}$t |= $v;$t |= ($u << 7);$self->pack('v', $t);}sub _pack_shape {my ($self, $container, $p) = @_;$self->pack('C', $#{$container->{$p->{name}}} + 1);foreach my $shape (@{$container->{$p->{name}}}) {$self->pack('C', $$shape{type});if ($$shape{type} == 0) {$self->pack('f4', @{$$shape{sphere}});} elsif ($$shape{type} == 1) {$self->pack('f12', @{$$shape{box}});}}}sub _pack_skeleton {my ($self, $container, $p) = @_;$self->pack('C8vf3f3v', @{$container->{bones_mask}}, $container->{root_bone}, @{$container->{bbox_min}}, @{$container->{bbox_max}}, $#{$container->{bones}} + 1);foreach my $bone (@{$container->{bones}}) {my $i = 0;foreach (@{$$bone{ph_position}}) {$_ = convert_u8($_, $container->{bbox_min}[$i], $container->{bbox_max}[$i]);$i++;}$self->pack('C3', @{$$bone{ph_position}});foreach (@{$$bone{ph_rotation}}) {$_ = convert_u8($_, -1, 1);}$self->pack('C4', @{$$bone{ph_rotation}});$self->pack('C', $$bone{enabled});}}sub _pack_supplies {my ($self, $container, $p) = @_;$self->pack('V', $#{$container->{$p->{name}}} + 1);foreach my $sect (@{$container->{$p->{name}}}) {$self->pack('Z*Vff', $$sect{section_name}, $$sect{item_count}, $$sect{min_factor}, $$sect{max_factor});}}sub _pack_artefact_spawns {my ($self, $container, $p) = @_;$self->pack('v', $#{$container->{$p->{name}}} + 1);if ($p->{type} eq 'afspawns') {foreach my $sect (@{$container->{$p->{name}}}) {$self->pack('Z*f', $$sect{section_name}, $$sect{weight});}} else {foreach my $sect (@{$container->{$p->{name}}}) {$self->pack('Z*V', $$sect{section_name}, $$sect{weight});}}}sub _pack_ordered_artefacts {my ($self, $container, $p) = @_;$self->pack('V', $#{$container->{$p->{name}}} + 1);foreach my $sect (@{$container->{$p->{name}}}) {$self->pack('Z*VV', $$sect{unknown_string}, $$sect{unknown_number}, $#{$sect->{af_sects}} + 1);foreach my $obj (@{$sect->{af_sects}}) {$self->pack('Z*VV', $$obj{artefact_name}, $$obj{number_1}, $$obj{number_2});}}}sub _pack_ctime {my ($self, $time) = @_;my @date;if ($time != 0) {@date = $time->get_all();} else {$date[0] = 2000;}$date[0] -= 2000;if ($date[0] == 0 || $date[0] == 255) {$self->pack('C', $date[0]);} else {$self->pack('C6v', @date);}}sub _pack_complex_time {my ($self, $time) = @_;my $flag = 0;$flag = 1 if $time != 0;$self->pack('C', $flag);$self->_pack_ctime($time) if $flag == 1;}sub _pack_jobs {my ($self, $container, $p) = @_;$self->pack('C', $#{$container->{$p->{name}}} + 1);foreach my $job (@{$container->{$p->{name}}}) {$self->pack('VVV', $job->{job_begin}, $job->{job_fill_idle}, $job->{job_idle_after_death_end});}}sub _pack_npc_info {my $self = shift;if ($_[0]->{version} >= 122) {$self->_pack_npc_info_cop(@_);} elsif ($_[0]->{version} >= 117) {$self->_pack_npc_info_soc(@_);} else {$self->_pack_npc_info_old(@_);}}sub _pack_npc_info_old {my ($self, $container, $p) = @_;$self->pack('C', $#{$container->{$p->{name}}} + 1);foreach my $info (@{$container->{$p->{name}}}) {$self->pack('vCCCC', $info->{o_id}, $info->{group}, $info->{squad}, $info->{move_offline}, $info->{switch_offline});$self->_pack_ctime($info->{stay_end});$self->pack('C', $info->{jobN}) if $container->{script_version} >= 1 && $container->{gulagN} != 0;}}sub _pack_npc_info_soc {my ($self, $container, $p) = @_;$self->pack('C', $#{$container->{$p->{name}}} + 1);foreach my $info (@{$container->{$p->{name}}}) {$self->pack('vCCC', $info->{o_id}, $info->{o_group}, $info->{o_squad}, $info->{exclusive});$self->_pack_ctime($info->{stay_end});$self->pack('C', $info->{Object_begin_job});$self->pack('C', $info->{Object_didnt_begin_job}) if $container->{script_version} > 4;$self->pack('C', $info->{jobN});}}sub _pack_npc_info_cop {my ($self, $container, $p) = @_;$self->pack('C', $#{$container->{$p->{name}}} + 1);foreach my $info (@{$container->{$p->{name}}}) {$self->pack('vCCCZ*', $info->{id}, $info->{job_prior}, $info->{job_id}, $info->{begin_job}, $info->{need_job});}}sub _pack_covers {my ($self, $container, $p) = @_;$self->pack('C', $#{$container->{$p->{name}}} + 1);foreach my $cover (@{$container->{$p->{name}}}) {$self->pack('vVf3f3C', $cover->{npc_id}, $cover->{cover_vertex_id}, @{$cover->{cover_position}}, @{$cover->{look_pos}}, $cover->{is_smart_cover});}}sub _pack_squads {my ($self, $container, $p) = @_;$self->pack('C', $#{$container->{$p->{name}}} + 1);foreach my $squad (@{$container->{$p->{name}}}) {$self->pack('Z*Z*CCC', $squad->{squad_name}, $squad->{squad_stage}, $squad->{squad_prepare_shouted}, $squad->{squad_attack_shouted}, $squad->{squad_attack_squad});$self->_pack_complex_time($squad->{squad_inited_defend_time});$self->_pack_complex_time($squad->{squad_start_attack_wait});$self->_pack_complex_time($squad->{squad_last_defence_kill_time});$self->pack('f', $squad->{squad_power});}}sub _pack_sim_squads {my ($self, $container, $p) = @_;$self->pack('v', $#{$container->{$p->{name}}} + 1);foreach my $squad (@{$container->{$p->{name}}}) {$self->pack('Z*Z*C', $squad->{squad_id}, $squad->{settings_id}, $squad->{is_scripted});$self->_pack_sim_squad_generic($container, $squad);if ($squad->{is_scripted} == 1) {$self->set_save_marker($container, 'save', 0, 'sim_squad_scripted');$self->pack('CCCC', $squad->{next_target}, $squad->{need_free_update}, $squad->{relationship}, $squad->{sympathy});$self->set_save_marker($container, 'save', 1, 'sim_squad_scripted');}}}sub _pack_sim_squad_generic {my ($self, $container, $squad) = @_;$self->set_save_marker($container, 'save', 0, 'sim_squad_generic');$self->pack('vvvv', $squad->{smart_id}, $squad->{assigned_target_smart_id}, $squad->{sim_combat_id}, $squad->{delayed_attack_task});my $n = $#{$squad->{random_tasks}} + 1;$n = $n/2;$self->pack("C(vv)$n", $n, @{$squad->{random_tasks}});$self->pack('Cfv', $squad->{npc_count}, $squad->{squad_power}, $squad->{commander_id});$n = $#{$squad->{squad_npc}} + 1;$self->pack("C(v)$n", $n, @{$squad->{squad_npc}});$self->pack('C', $squad->{spoted_shouted});$self->_pack_ctime($squad->{last_action_timer});$self->pack('v', $squad->{squad_attack_power});if (defined $squad->{class}) {$self->pack('C', 1);$self->pack('C', $squad->{class});if ($squad->{class} == 1) {#sim_attack_point$self->pack('v', $squad->{dest_smrt_id});$self->set_save_marker($container, 'save', 0, 'sim_attack_point');$self->pack('Cv', $squad->{major}, $squad->{target_power_value});$self->set_save_marker($container, 'save', 1, 'sim_attack_point');} else {$self->set_save_marker($container, 'save', 0, 'sim_stay_point');$self->pack('Cv', $squad->{stay_defended}, $squad->{next_point_id});$self->_pack_complex_time($squad->{begin_time});$self->set_save_marker($container, 'save', 1, 'sim_stay_point');}} else {$self->pack('C', 0);}$self->pack('C', $squad->{items_spawned});$self->_pack_ctime($squad->{bring_item_inited_time});$self->_pack_ctime($squad->{recover_item_inited_time});$self->set_save_marker($container, 'save', 1, 'sim_squad_generic');}sub _pack_times {my ($self, $container, $p) = @_;$self->pack('C', $#{$container->{$p->{name}}} + 1);foreach (@{$container->{$p->{name}}}) {$self->_pack_complex_time($_);}}sub _pack_inited_find_upgrade_tasks {my ($self, $container, $p) = @_;$self->pack('v', $#{$container->{$p->{name}}} + 1);foreach (@{$container->{$p->{name}}}) {$self->unpack('vv', $_->{k}, $#{$_->{subtasks}} + 1);foreach my $subtask (@{$_->{subtasks}}) {$self->unpack('Z*v', $subtask->{kk}, $subtask->{entity_id});}}}sub _pack_rewards {my ($self, $container, $p) = @_;$self->pack('C', $#{$container->{$p->{name}}} + 1);foreach (@{$container->{$p->{name}}}) {$self->pack('Z*C', $_->{community}, $#{$_->{rewards}} + 1);foreach my $reward (@{$_->{rewards}}) {$self->pack('C', $reward->{is_money});if ($reward->{is_money} == 1) {$self->pack('v', $reward->{amount});} else {$self->pack('Z*', $reward->{item_name});}}}}sub _pack_CGeneralTask {my ($self, $task, $container) = @_;$self->set_save_marker($container, 'save', 0, 'CGeneralTask');$self->pack('vCCCZ*CC', $task->{entity_id}, $task->{prior}, $task->{status}, $task->{actor_helped}, $task->{community}, $task->{actor_come}, $task->{actor_ignore});$self->_pack_ctime($task->{inited_time});$self->set_save_marker($container, 'save', 1, 'CGeneralTask');}sub _pack_CStorylineTask {my ($self, $task, $container) = @_;$self->set_save_marker($container, 'save', 0, 'CStorylineTask');$self->_pack_CGeneralTask($task, $container);$self->pack('V', $task->{target});$self->set_save_marker($container, 'save', 1, 'CStorylineTask');}sub _pack_CEliminateSmartTask {my ($self, $task, $container) = @_;$self->set_save_marker($container, 'save', 0, 'CEliminateSmartTask');$self->_pack_CGeneralTask($task, $container);$self->pack('vZ*Z*', $task->{target}, $task->{src_obj}, $task->{faction});$self->set_save_marker($container, 'save', 1, 'CEliminateSmartTask');}sub _pack_CCaptureSmartTask {my ($self, $task, $container) = @_;$self->set_save_marker($container, 'save', 0, 'CCaptureSmartTask');$self->_pack_CGeneralTask($task, $container);$self->pack('vZ*Z*Z*Z*Z*', $task->{target}, $task->{state}, $task->{counter_attack_community}, $task->{counter_squad}, $task->{src_obj}, $task->{faction});$self->set_save_marker($container, 'save', 1, 'CCaptureSmartTask');}sub _pack_CDefendSmartTask {my ($self, $task, $container) = @_;$self->set_save_marker($container, 'save', 0, 'CDefendSmartTask');$self->_pack_CGeneralTask($task, $container);$self->pack('v', $task->{target});$self->pack_ctime($task->{last_called_time});$self->set_save_marker($container, 'save', 1, 'CDefendSmartTask');}sub _pack_CBringItemTask {my ($self, $task, $container) = @_;$self->set_save_marker($container, 'save', 0, 'CBringItemTask');$self->_pack_CGeneralTask($task, $container);$self->pack('Z*CvZ*C', $task->{state}, $task->{ri_counter}, $task->{target}, $task->{squad_id}, $#{$task->{requested_items}} + 1);foreach (@{$task->{requested_items}}) {$self->pack('Z*', $_->{id});my $n = $#{$_->{items}} + 1;$self->pack("v©$n", @{$_->{items}});}$self->set_save_marker($container, 'save', 1, 'CBringItemTask');}sub _pack_CRecoverItemTask {my ($self, $task, $container) = @_;$self->set_save_marker($container, 'save', 0, 'CRecoverItemTask');$self->_pack_CGeneralTask($task, $container);$self->pack('CZ*vCZ*', $task->{state}, $task->{squad_id}, $task->{target_obj_id}, $task->{presence_requested_item}, $task->{requested_item});$self->set_save_marker($container, 'save', 1, 'CRecoverItemTask');}sub _pack_CFindUpgradeTask {my ($self, $task, $container) = @_;$self->set_save_marker($container, 'save', 0, 'CFindUpgradeTask');$self->_pack_CGeneralTask($task, $container);$self->pack('Z*CZ*', $task->{state}, $task->{presence_requested_item}, $task->{requested_item});$self->set_save_marker($container, 'save', 1, 'CFindUpgradeTask');}sub _pack_CHideFromSurgeTask {my ($self, $task, $container) = @_;$self->set_save_marker($container, 'save', 0, 'CHideFromSurgeTask');$self->_pack_CGeneralTask($task, $container);$self->pack('vvv', $task->{target}, $task->{wait_time}, $task->{effector_started_time});$self->set_save_marker($container, 'save', 1, 'CHideFromSurgeTask');}sub _pack_CEliminateSquadTask {my ($self, $task, $container) = @_;$self->set_save_marker($container, 'save', 0, 'CEliminateSquadTask');$self->_pack_CGeneralTask($task, $container);$self->pack('vZ*', $task->{target}, $task->{src_obj});$self->set_save_marker($container, 'save', 1, 'CEliminateSquadTask');}sub _pack_inited_tasks {my ($self, $container, $p) = @_;my ($count) = $self->pack('v', $#{$container->{$p->{name}}} + 1);foreach (@{$container->{$p->{name}}}) {$self->pack('Z*Z*v', $_->{base_id}, $_->{id}, $_->{type});SWITCH: {($_->{type} == 0 || $_->{type} == 5) && do {$self->_pack_CStorylineTask($_, $container);last SWITCH;};$_->{type} == 1 && do {$self->_pack_CEliminateSmartTask($_, $container);last SWITCH;};$_->{type} == 2 && do {$self->_pack_CCaptureSmartTask($_, $container);last SWITCH;};($_->{type} == 3 || $_->{type} == 4) && do {$self->_pack_CDefendSmartTask($_, $container);last SWITCH;};$_->{type} == 6 && do {$self->_pack_CBringItemTask($_, $container);last SWITCH;};$_->{type} == 7 && do {$self->_pack_CRecoverItemTask($_, $container);last SWITCH;};$_->{type} == 8 && do {$self->_pack_CFindUpgradeTask($_, $container);last SWITCH;};$_->{type} == 9 && do {$self->_pack_CHideFromSurgeTask($_, $container);last SWITCH;};$_->{type} == 10 && do {$self->_pack_CEliminateSquadTask($_, $container);last SWITCH;};}}}sub _pack_minigames {my ($self, $container, $p) = @_;$self->pack('v', $#{$container->{$p->{name}}} + 1);foreach (@{$container->{$p->{name}}}) {$self->pack('Z*Z*Z*', $_->{key}, $_->{profile}, $_->{state});if ($_->{profile} eq 'CMGCrowKiller') {$self->set_save_marker($container, 'save', 0, 'CMGCrowKiller');$self->pack('CvC', $_->{param_highscore}, $_->{param_timer}, $_->{param_win});my $n = $#{$_->{param_crows_to_kill}} + 1;$self->pack("C©$n", $n, @{$_->{param_crows_to_kill}});$self->pack('vvCZ*CvvCC', $_->{param_money_multiplier}, $_->{param_champion_multiplier}, $_->{param_selected}, $_->{param_game_type}, $_->{high_score}, $_->{timer}, $_->{time_out}, $_->{killed_counter}, $_->{win});$self->set_save_marker($container, 'save', 1, 'CMGCrowKiller');} elsif ($_->{profile} eq 'CMGShooting') {$self->set_save_marker($container, 'save', 0, 'CMGShooting');$self->pack('Z*Z*Z*Z*Z*Z*Z*', $_->{param_game_type}, $_->{param_wpn_type}, $_->{param_stand_way}, $_->{param_look_way}, $_->{param_stand_way_back}, $_->{param_look_way_back}, $_->{param_obj_name});$self->pack('C', $_->{param_is_u16});if ($_->{param_is_u16} == 0) {$self->pack('C', $_->{param_win});} else {$self->pack('v', $_->{param_win});}$self->pack('CCC', $_->{param_distance}, $_->{param_ammo}, $#{$_->{targets}} + 1);foreach my $target (@{$_->{targets}}) {my $n = $#{$target} + 1;$self->pack("C(Z*)$n", $n, @$target);}$self->pack('C', $_->{param_target_counter});my $n = $#{$_->{inventory_items}} + 1;$self->pack("C(v)$n", $n, @{$_->{inventory_items}});$self->pack('VZ*', $_->{prev_time}, $_->{type});if ($_->{type} eq 'training' || $_->{type} eq 'points') {$self->set_save_marker($container, 'save', 0, $_->{type});$self->pack('vvZ*vC', $_->{win}, $_->{ammo}, $_->{cur_target}, $_->{points}, $_->{ammo_counter});$self->set_save_marker($container, 'save', 1, $_->{type});} elsif ($_->{type} eq 'count') {$self->set_save_marker($container, 'save', 0, $_->{type});$self->pack('Z*CCC', $_->{wpn_type}, $_->{win}, $_->{ammo}, $#{$_->{targets}} + 1);foreach my $target (@{$_->{targets}}) {my $n = $#{$target} + 1;$self->pack("C(Z*)$n", $n, @$target);}$self->pack('CZ*CCC', $_->{distance}, $_->{cur_target}, $_->{points}, $_->{scored}, $_->{ammo_counter});$self->set_save_marker($container, 'save', 1, $_->{type});} elsif ($_->{type} eq 'three_hit_training') {$self->set_save_marker($container, 'save', 0, $_->{type});$self->pack('Z*vCC', $_->{wpn_type}, $_->{win}, $_->{ammo}, $#{$_->{targets}} + 1);foreach my $target (@{$_->{targets}}) {my $n = $#{$target} + 1;$self->pack("C(Z*)$n", $n, @$target);}$self->pack('CZ*vCCCC', $_->{distance}, $_->{cur_target}, $_->{points}, $_->{scored}, $_->{ammo_counter}, $_->{target_counter}, $_->{target_hit});$self->set_save_marker($container, 'save', 1, $_->{type});} elsif ($_->{type} eq 'all_targets') {$self->set_save_marker($container, 'save', 0, $_->{type});$self->pack('Z*vCC', $_->{wpn_type}, $_->{win}, $_->{ammo}, $#{$_->{targets}} + 1);foreach my $target (@{$_->{targets}}) {my $n = $#{$target} + 1;$self->pack("C(Z*)$n", $n, @$target);}foreach my $hitted_target (@{$_->{hitted_targets}}) {my $n = $#{$hitted_target} + 1;$self->pack("C(Z*)$n", $n, @$hitted_target);}$self->pack('CvCVCZ*', $_->{ammo_counter}, $_->{time}, $_->{target_counter}, $_->{prev_time}, $_->{more_targets}, $_->{last_target});$self->set_save_marker($container, 'save', 1, $_->{type});} elsif ($_->{type} eq 'count_on_time') {$self->set_save_marker($container, 'save', 0, $_->{type});$self->pack('Z*vCC', $_->{wpn_type}, $_->{win}, $_->{ammo}, $#{$_->{targets}} + 1);foreach my $target (@{$_->{targets}}) {my $n = $#{$target} + 1;$self->pack("C(Z*)$n", $n, @$target);}$self->pack('CZ*CCCCV', $_->{distance}, $_->{cur_target}, $_->{points}, $_->{scored}, $_->{ammo_counter}, $_->{time}, $_->{prev_time});$self->set_save_marker($container, 'save', 1, $_->{type});} elsif ($_->{type} eq 'ten_targets') {$self->set_save_marker($container, 'save', 0, $_->{type});$self->pack('Z*vCC', $_->{wpn_type}, $_->{win}, $_->{ammo}, $#{$_->{targets}} + 1);foreach my $target (@{$_->{targets}}) {my $n = $#{$target} + 1;$self->pack("C(Z*)$n", $n, @$target);}$self->pack('CZ*CCCvV', $_->{distance}, $_->{cur_target}, $_->{points}, $_->{scored}, $_->{ammo_counter}, $_->{time}, $_->{prev_time});$self->set_save_marker($container, 'save', 1, $_->{type});} elsif ($_->{type} eq 'two_seconds_standing') {$self->set_save_marker($container, 'save', 0, $_->{type});$self->pack('Z*vCC', $_->{wpn_type}, $_->{win}, $_->{ammo}, $#{$_->{targets}} + 1);foreach my $target (@{$_->{targets}}) {my $n = $#{$target} + 1;$self->pack("C(Z*)$n", $n, @$target);}$self->pack('CZ*CCCV', $_->{distance}, $_->{cur_target}, $_->{points}, $_->{ammo_counter}, $_->{time}, $_->{prev_time});$self->set_save_marker($container, 'save', 1, $_->{type});}$self->set_save_marker($container, 'save', 1, 'CMGShooting');}}}#varioussub length {return CORE::length($_[0]->{data})}sub resid {return CORE::length($_[0]->{data}) - $_[0]->{pos}}sub r_tell {return $_[0]->{init_length} - $_[0]->resid()}sub w_tell {return CORE::length($_[0]->{data})}sub raw {if ($#_ == 1) {my $out = substr($_[0]->{data}, $_[0]->{pos}, $_[1]);$_[0]->{pos} += $_[1];return $out;} elsif ($#_ == 2) {substr($_[0]->{data}, $_[0]->{pos}, $_[1], $_[2]);}}sub data {return $_[0]->{data} if $#_ == 0;$_[0]->{data} = $_[1];}sub pos {return $_[0]->{pos} if $#_ == 0;$_[0]->{pos} = $_[1];}sub isinf {if ($_[0] == 9**9**9 || $_[0] == -9**9**9) {return 1;}return 0;}sub isnan {if (! defined($_[0] <=> 9**9**9)) {return 1;}return 0;}sub set_save_marker {my $packet = shift;my $object = shift;my $mode = shift;my $check = shift;my $name = shift;if ($check) {die unless defined($object->{markers}{$name});if ($mode eq 'save') {my $diff = $packet->w_tell() - $object->{markers}{$name};die unless $diff > 0;$packet->pack('v', $diff);} else {my $diff = $packet->r_tell() - $object->{markers}{$name};die unless $diff > 0;my ($diff1) = $packet->unpack('v', 2);die unless $diff == $diff1;}} else {if ($mode eq 'save') {$object->{markers}{$name} = $packet->w_tell();} else {$object->{markers}{$name} = $packet->r_tell();}}}sub convert_q8 {my ($u, $min, $max) = @_;my $q = $u / 255.0 * ($max - $min) + $min;return $q;}sub convert_u8 {my ($q, $min, $max) = @_;my $u = ($q - $min) * 255.0 / ($max - $min);return $u;}sub convert_q16 {my ($u) = @_;my $q = (($u / 43.69) - 500.0);return $q;}sub convert_u16 {my ($q) = @_;my $u = round((($q + 500.0) * 43.69));return $u;}sub convert_q16_old {my ($u) = @_;my $q = (($u / 32.77) - 1000.0);return $q;}sub convert_u16_old {my ($q) = @_;my $u = round((($q + 1000.0) * 32.77));return $u;}sub error_handler {my $self = shift;my ($container, $template) = @_;print "handling error with $container->{section_name}, template $template\n";SWITCH: {# Nar Sol fix($template eq 'C') && (ref($container) eq 'se_zone_anom') && $container->{version} == 118 && $container->{script_version} == 6 && do {print "unpacking spawn of Narodnaya Solyanka, huh? OK...\n";bless $container, 'cse_alife_anomalous_zone';$container->{ini}->{sections_hash}{'sections'}{"'$container->{section_name}'"} = 'cse_alife_anomalous_zone' if defined $container->{ini};$container->{flags} |= FL_HANDLED;last;};# future fix($template eq 'C') && (ref($container) eq 'se_zone_visual') && $container->{version} == 118 && $container->{script_version} == 6 && do {print "unpacking spawn of some mod, huh? OK...\n";bless $container, 'cse_alife_zone_visual';$container->{ini}->{sections_hash}{'sections'}{"'$container->{section_name}'"} = 'cse_alife_zone_visual' if defined $container->{ini};$container->{flags} |= FL_HANDLED;last;};($template eq 'f') && (ref($container) eq 'cse_alife_anomalous_zone') && $container->{version} == 118 && $container->{script_version} == 6 && do {print "unpacking spawn of some mod, huh? OK...\n";bless $container, 'cse_alife_custom_zone';$container->{ini}->{sections_hash}{'sections'}{"'$container->{section_name}'"} = 'cse_alife_custom_zone' if defined $container->{ini};$container->{flags} |= FL_HANDLED;last;};# builds 25xx fix(ref($container) =~ /cse_alife_item_weapon_/) && $container->{version} == 118 && $container->{script_version} == 5 && do {if (ref($container) eq 'cse_alife_item_weapon_shotgun') {bless $container, 'cse_alife_item_weapon_magazined';} else {bless $container, 'cse_alife_item_weapon';}fix_25xx($self, $container);last;};(ref($container) =~ /stalker|monster|actor/) && $container->{version} == 118 && $container->{script_version} == 5 && do {fix_25xx($self, $container);last;};fail("unhandled exception\n");}}sub round {my $temp = sprintf("%.2f", $_[0]);my $int = int($temp);if (($temp - $int) > 0.5000) {return ceil($temp);} else {return floor($temp);}}sub fix_25xx {$_[1]->{flags} |= FL_IS_25XX;$_[0]->{pos} = 2;$_[1]->update_read($_[0]);$_[1]->{flags} |= FL_HANDLED;$_[0]->{pos} = 42 if ref($_[1]) =~ /stalker|monster/;foreach my $section (keys %{$_[1]->{ini}->{sections_hash}{'sections'}}) {if ($_[1]->{ini}->{sections_hash}{'sections'}{$section} =~ /cse_alife_item_weapon_magazined/) {$_[1]->{ini}->{sections_hash}{'sections'}{$section} = 'cse_alife_item_weapon';} elsif ($_[1]->{ini}->{sections_hash}{'sections'}{$section} eq 'cse_alife_item_weapon_shotgun') {$_[1]->{ini}->{sections_hash}{'sections'}{$section} = 'cse_alife_item_weapon_magazined';}}}sub is_handled {return (UNIVERSAL::can($_[0], 'is_handled') && $_[0]->is_handled())}1; Скачал другой ggrc теперь другая ошибка: В жизни много плохих моментов. Пытайся избавляться от них ! Ссылка на комментарий
PTB 8 Опубликовано 25 Мая 2016 Поделиться Опубликовано 25 Мая 2016 Насчёт этого поста http://www.amk-team.ru/forum/topic/11568-universal-acdc-i-drugie-perl-skripty/?p=1013757 all.spawn распаковал xrSpawner'ом Вопрос: есть способ в ltx файлы это перенести? В жизни много плохих моментов. Пытайся избавляться от них ! Ссылка на комментарий
Kinsiinoo 0 Опубликовано 11 Июня 2016 Поделиться Опубликовано 11 Июня 2016 Universal ACDC v.1.38 checking version of all.spawn... This is a spawn of S.T.A.L.K.E.R. Call Of Pripyat (any patch) opening all.spawn... reading header... reading alife objects... handling error with wpn_kar98k, template C/C FATAL ERROR! Function: stkutils::data_packet::error_handler Line: 1548 Description: unhandled exception Can anybody help me? Please Ссылка на комментарий
Kober(BRUC) 99 Опубликовано 12 Июня 2016 Поделиться Опубликовано 12 Июня 2016 Can anybody help me? Please Hi. Copy the configs folder from a game directory in the folder from ACDC. Ссылка на комментарий
Kinsiinoo 0 Опубликовано 12 Июня 2016 Поделиться Опубликовано 12 Июня 2016 Már megtettem ezt, és azután írtam, hogy ez a fórum ... Tehát bármilyen más módszerrel megoldani ezt a problémát? : / (Az én szörnyű angol) Добавлено Black Hawk, 12 Июня 2016 ГУГЛ-перевод с венгерского языка: "Я уже сделал это, и тогда я писал, что этот форум ... Таким образом, любой другой способ, чтобы решить эту проблему? : / (В моем ужасном английском языке)" Ссылка на комментарий
Kinsiinoo 0 Опубликовано 12 Июня 2016 Поделиться Опубликовано 12 Июня 2016 No success with anything :/ Always the same error: Universal ACDC v.1.38checking version of all.spawn...This is a spawn of S.T.A.L.K.E.R. Call Of Pripyat (any patch)opening all.spawn...reading header...reading alife objects...handling error with wpn_kar98k, template C/CFATAL ERROR!Function: stkutils::data_packet::error_handlerLine: 1548Description: unhandled exception KD87 can you tell me any solution? I wrote you a pm. Ссылка на комментарий
KD87 718 Опубликовано 14 Июня 2016 Автор Поделиться Опубликовано 14 Июня 2016 @Kinsiinoo, that's not a full log. Obviously, configs aren't scanned. Delete sections.ini from your un_acdc folder and try to decompile with -scan key. Ссылка на комментарий
sneik 341 Опубликовано 14 Июня 2016 Поделиться Опубликовано 14 Июня 2016 Кто может помочь с этой утилитой? https://yadi.sk/d/rk7OUmQvsV2QLОна меняет названия текстур ТЧ на ЗП, раньше я ей пользовался, она работала, теперь забыл как ее использовать. Ссылка на комментарий
PTB 8 Опубликовано 15 Июня 2016 Поделиться Опубликовано 15 Июня 2016 (изменено) @sneik, По-моему ссылка битая. Изменено 15 Июня 2016 пользователем BFG В жизни много плохих моментов. Пытайся избавляться от них ! Ссылка на комментарий
sneik 341 Опубликовано 15 Июня 2016 Поделиться Опубликовано 15 Июня 2016 @PTB, Уже разобрался, неправильно был записан массив текстур для замены в файле config.ini. Напутал что то автор утилиты. По-моему ссылка битая. Ссылка есть в шапке темы http://yadi.sk/d/RfLlAAau1w5_a 1 Ссылка на комментарий
Воробей_Свобода 0 Опубликовано 23 Июня 2016 Поделиться Опубликовано 23 Июня 2016 (изменено) Как сделать чтоб ACDC работал на виндовс 8.1? Изменено 24 Июня 2016 пользователем HellRatz Ссылка на комментарий
aka_sektor 1 476 Опубликовано 23 Июня 2016 Поделиться Опубликовано 23 Июня 2016 @Воробей_Свобода, на десятке без проблем работает. Недавно спавн ТЧ пересобирал, да и мода фотограф. В чем конкретно проблема? Discord-сервер modfaq.ru: https://discord.gg/9j42BXwB Ссылка на комментарий
PTB 8 Опубликовано 24 Июня 2016 Поделиться Опубликовано 24 Июня 2016 @Воробей_Свобода, Опишите проблему, что делали, какие батники писали, и т.п. МБ что-нибудь не так сделали. В жизни много плохих моментов. Пытайся избавляться от них ! Ссылка на комментарий
Alexa74 0 Опубликовано 25 Июня 2016 Поделиться Опубликовано 25 Июня 2016 ACDC выдаёт ошибку FATAL ERROR! Function: stkutils::file::entity::error Line: 247 Description: stkutils::file::entity::read_m_update 129 $packet->resid() == 0 update data left [1] in entity kat_wpn_ak74_m1 Ссылка на комментарий
aka_sektor 1 476 Опубликовано 25 Июня 2016 Поделиться Опубликовано 25 Июня 2016 (изменено) @Alexa74, поподробнее давай: какая версия игры? С модом или без? Какой батник? Изменено 25 Июня 2016 пользователем aka_sektor Discord-сервер modfaq.ru: https://discord.gg/9j42BXwB Ссылка на комментарий
Alexa74 0 Опубликовано 25 Июня 2016 Поделиться Опубликовано 25 Июня 2016 (изменено) НС ОП2 Патч 9.2Батник: universal_acdc.pl -d all.spawn -scan config\pause ACDC выдаёт ошибкуFATAL ERROR!Function: stkutils::file::entity::errorLine: 247Description: stkutils::file::entity::read_m_update 129 $packet->resid() == 0 update data left [1] in entity kat_wpn_ak74_m1 Подскажите пожалуйста!!! ...BFG спасибо за помощь, времени мало а успеть надо много!!! Ну впрочем как всегда. Ещё раз спасибо!!! Изменено 29 Июня 2016 пользователем Eugen81 Ссылка на комментарий
BFG 7 582 Опубликовано 25 Июня 2016 Поделиться Опубликовано 25 Июня 2016 @Alexa74, Слишком долго объяснять что надо делать, а читать тему ты не хочешь. Вот тебе папка с последним АСДС, и файлами ОП2 патч 9.2. - http://rgho.st/8Xwd8YgBF Ничо там не трогай, просто скопируй её в корень диска Цэ. Надеюсь Perl у тебя установлен ? Если да, то жми на батник "декомпиляция" и получишь в папке spawn распакованный all.spawn. Всё работает, проверено. 1 "Кругом зомби.....у меня кончаются патроны...." Ссылка на комментарий
Рекомендуемые сообщения
Создайте аккаунт или авторизуйтесь, чтобы оставить комментарий
Комментарии могут оставлять только зарегистрированные пользователи
Создать аккаунт
Зарегистрировать новый аккаунт в нашем сообществе. Это несложно!
Зарегистрировать новый аккаунтВойти
Есть аккаунт? Войти.
Войти