Разработка и ромхакинг > Ромхакинг и программирование
Urban Strike hack project
(1/1)
Arkadij:
Всем привет! Я решил вернуться к проекту, который был в коме более 5 лет, а именно хаку Urban Strike. Я уже когда-то создал Jungle Strike Enemy Hack, где заменил врагов из Jungle Strike на врагов из Desert Strike, а в Urban Strike решил заняться переделом самих уровней - миссий, карты, картинки, расположения объектов и т.д. Единственный момент, который меня интересует, форумчане, существует ли еще распаковщик/упаковщик графики для этой игры (формат LZSS) или уже утрачен? Или может быть кто-то подскажет, как можно вытащить оттуда графику и отредактировать? Ибо у меня был большой перерыв и я потихоньку собираю обратно все знания.
SeregaZ:
Красная Площадь и Ми-28Н будут? :)
Arkadij:
Возможно  :lol:
Sharpnull:

--- Цитата: Arkadij от 26 Июнь 2020, 15:42:52 ---существует ли еще распаковщик/упаковщик графики для этой игры (формат LZSS) или уже утрачен?
--- Конец цитаты ---
У Guyver были наработки давно (есть на emu-land, можно его спросить).

Я разобрал алгоритм с помощью GHIDRA и загрузчика от DrMefistO. Сначала в эмуляторе в окне памяти предположил, где лежат несжатые данные (RAM: 0xFF26F2 - здесь "окно" алгоритма, 0xFF2EF2 - два байта, которые копируются в VRAM), перехватил запись в коде (ROM: границы функции с 0x762A по 0x76E2 включительно), открыл в GHIDRA ром и проанализировал функцию (изначально она была неопределенна, почему-то), разобрал выданный код на C.

Действительно, там обычный LZSS, но с двумя отличиями: размер окна 2048, а не 4096, начальное положение окна 0x7EE, а не 0. Обычный, потому что код практически такой, что видел в одной игре.
Прикладываю свой код и сборку на C, который только декодирует. Он принимает аргументы:

--- Код: ---StrikeLZSS.exe "Urban Strike (UE) [!].gen" out.bin 0x1CA8F4
--- Конец кода ---
Входной, выходной файлы и необязательная позиция в файле (можно hex или десятичное). В начале данных должен быть размер несжатых данных (4 байта Big-Endian), так они лежат в роме. В данном примере позиция на шрифт.
Чтобы узнать положение графики я ставил breakpoint на PC: 762A - начало функции, в регистре A2 уже хранится положение в роме, с размером в начале.
Не делал много проверок, поэтому программа может падать при неправильных данных. Выделение памяти зависит от размера файла, умножается на 9 (макс. сжатие), в выходном файле размер правильный.

Я думаю, что можно изменить первый попавшийся алгоритм LZSS. Например, https://github.com/MichaelDipperstein/lzss.
Размер окна, заменить:

--- Код: ---#define WINDOW_SIZE     (1 << OFFSET_BITS)
на
#define WINDOW_SIZE     0x800
--- Конец кода ---
Положение при декодировании:

--- Код: ---nextChar = 0;
на
nextChar = 0x7EE;
--- Конец кода ---
Положение при кодировании:

--- Код: ---windowHead = 0;
на
windowHead = 0x7EE;
--- Конец кода ---
Не проверял и не знаю как хорошо сжимает. Если не справитесь или если кто-то не предоставит готовые программы, позже посмотрю. С хакингом игры не помогу, не разбираюсь.
--------
UPD: Я ошибся с размером в начале данных, он указывает на размер несжатых данных. Это на результат программы не влияет, но там получается ошибка в описании и лишнее выделении памяти. Возможно поправлю позже. Вообще, можно было сделать с указанием размера сжатых данных, выход был бы при другом условии.
Guyver(X.B.M.):
Я, скорее всего, не помогу. С 2010 года у меня сменилась куча ноутов и где теперь искать эти файлы - я не знаю... :neznayu: Если только у Марата осталось. Но у него, как помню, полетел ноут с жёстким и куча всего пропала...
Sharpnull:
Я сейчас ещё проверил http://www.hacking-cult.org/download/tsdc-v2.2-rc3-win32.rar (отсюда, тема Jungle Strike), оказалось она работает. Нужно выбрать Saxman и размер сжатых данных при декодировании. Обратно не пробовал.
--------
Хотя, в теме Urban Strike Марат писал, что Saxman сжимает не так.
Там ещё защита/CRC, нужно найти исправление.
Arkadij:

--- Цитата: Sharpnull от 27 Июнь 2020, 04:31:40 ---Я сейчас ещё проверил http://www.hacking-cult.org/download/tsdc-v2.2-rc3-win32.rar (отсюда, тема Jungle Strike), оказалось она работает. Нужно выбрать Saxman и размер сжатых данных при декодировании. Обратно не пробовал.
--------
Хотя, в теме Urban Strike Марат писал, что Saxman сжимает не так.
Там ещё защита/CRC, нужно найти исправление.

--- Конец цитаты ---

Распаковка графики на Saxman работает, но когда сжимаю обратно остаются разводы на экране. В целом интересно, попробую что-нибудь наколдовать
--- Цитата: Sharpnull от 27 Июнь 2020, 03:10:35 ---У Guyver были наработки давно (есть на emu-land, можно его спросить).

Я разобрал алгоритм с помощью GHIDRA и загрузчика от DrMefistO. Сначала в эмуляторе в окне памяти предположил, где лежат несжатые данные (RAM: 0xFF26F2 - здесь "окно" алгоритма, 0xFF2EF2 - два байта, которые копируются в VRAM), перехватил запись в коде (ROM: границы функции с 0x762A по 0x76E2 включительно), открыл в GHIDRA ром и проанализировал функцию (изначально она была неопределенна, почему-то), разобрал выданный код на C.

Действительно, там обычный LZSS, но с двумя отличиями: размер окна 2048, а не 4096, начальное положение окна 0x7EE, а не 0. Обычный, потому что код практически такой, что видел в одной игре.
Прикладываю свой код и сборку на C, который только декодирует. Он принимает аргументы:

--- Код: ---StrikeLZSS.exe "Urban Strike (UE) [!].gen" out.bin 0x1CA8F4
--- Конец кода ---
Входной, выходной файлы и необязательная позиция в файле (можно hex или десятичное). В начале данных должен быть размер несжатых данных (4 байта Big-Endian), так они лежат в роме. В данном примере позиция на шрифт.
Чтобы узнать положение графики я ставил breakpoint на PC: 762A - начало функции, в регистре A2 уже хранится положение в роме, с размером в начале.
Не делал много проверок, поэтому программа может падать при неправильных данных. Выделение памяти зависит от размера файла, умножается на 9 (макс. сжатие), в выходном файле размер правильный.

Я думаю, что можно изменить первый попавшийся алгоритм LZSS. Например, https://github.com/MichaelDipperstein/lzss.
Размер окна, заменить:

--- Код: ---#define WINDOW_SIZE     (1 << OFFSET_BITS)
на
#define WINDOW_SIZE     0x800
--- Конец кода ---
Положение при декодировании:

--- Код: ---nextChar = 0;
на
nextChar = 0x7EE;
--- Конец кода ---
Положение при кодировании:

--- Код: ---windowHead = 0;
на
windowHead = 0x7EE;
--- Конец кода ---
Не проверял и не знаю как хорошо сжимает. Если не справитесь или если кто-то не предоставит готовые программы, позже посмотрю. С хакингом игры не помогу, не разбираюсь.
--------
UPD: Я ошибся с размером в начале данных, он указывает на размер несжатых данных. Это на результат программы не влияет, но там получается ошибка в описании и лишнее выделении памяти. Возможно поправлю позже. Вообще, можно было сделать с указанием размера сжатых данных, выход был бы при другом условии.

--- Конец цитаты ---

Я не понял, как этим StrikeLZSS пользоваться?
Sharpnull:

--- Цитата: Arkadij от 27 Июнь 2020, 10:25:23 ---Я не понял, как этим StrikeLZSS пользоваться?
--- Конец цитаты ---
Через команду строку, я же описал. 1-й аргумент - файл со сжатой графикой, можно ром. 2-й - имя выходного файла. 3-й - смещение графики в файле, должен указывать на размер несжатых данных.

--- Код: ---StrikeLZSS.exe "Urban Strike (UE) [!].gen" out.bin 0x1CA8F4
--- Конец кода ---
В out.bin будет несжатый шрифт.
Не нужно цитировать так много текста, места занимает.
Arkadij:

--- Цитата: Sharpnull от 27 Июнь 2020, 18:53:27 ---Через команду строку, я же описал. 1-й аргумент - файл со сжатой графикой, можно ром. 2-й - имя выходного файла. 3-й - смещение графики в файле, должен указывать на размер несжатых данных.

--- Код: ---StrikeLZSS.exe "Urban Strike (UE) [!].gen" out.bin 0x1CA8F4
--- Конец кода ---
В out.bin будет несжатый шрифт.
Не нужно цитировать так много текста, места занимает.

--- Конец цитаты ---

Хорошо, попробую, уже в процессе работы :)
Sharpnull:
Написал сжатие. Прикладываю, на github попробую добавить позже.
Использование
Распаковка:

--- Код: ---StrikeLZSS -d "Urban Strike.gen" out.bin -p 0x1CA8F4
--- Конец кода ---
-d - декомпрессия, -p ЧИСЛО - позиция в файле.
Сжатие:

--- Код: ---StrikeLZSS input.bin compressed.bin
--- Конец кода ---
Можно указать -c (компрессия) и позицию во входном файле (-p). Сжатый файл имеет в начале размер как и во входном для распаковки.
Положение -d/-c и -p ЧИСЛО может быть в любом месте, порядок входного и выходного файлов важен.
О программе
Теперь выводится размер несжатых и сжатых данных без учёта 4 байтов размера у сжатых, это поможет определить, влезет ли графика назад.
Сжатие должно выдавать по размеру не больше, чем у оригинальной графики. У одних данных даже получилось на 5 байтов меньше, почему-то.
Код сжатия написал на основе моего сжатия PZZ у игры Jojo no Kimyou na Bouken - Ougon no Kaze (Japan). Оказалось, можно использовать простой алгоритм с поиском повторений у ранее записанных байтов и контрольного байта (биты указывающие на несжатый байт или на смещение + длина), отличие только в записи смещения относительно "окна" у LZSS.
Можно было написать сразу вставку в ром по смещению, указание размера вместо чтения из файла и т. п., но особо смысла нет.
Замечания
То, что я говорил про https://github.com/MichaelDipperstein/lzss, не сработало, похоже там используется другая реализация LZSS.
Сравнил код распаковки Desert Strike, Jungle Strike и Urban Strike, он одинаковый. Вы могли бы использовать те же утилиты, что использовали раньше.
Попробовал вставку графики, вроде правильно. Для отключения проверки CRC использовал Master Code - https://gamehacking.org/game/16162 - 1FF0D4:4E75.
Arkadij:

--- Цитата: Sharpnull от 28 Июнь 2020, 07:18:01 ---Написал сжатие. Прикладываю, на github попробую добавить позже.
Использование
Распаковка:

--- Код: ---StrikeLZSS -d "Urban Strike.gen" out.bin -p 0x1CA8F4
--- Конец кода ---
-d - декомпрессия, -p ЧИСЛО - позиция в файле.
Сжатие:

--- Код: ---StrikeLZSS input.bin compressed.bin
--- Конец кода ---
Можно указать -c (компрессия) и позицию во входном файле (-p). Сжатый файл имеет в начале размер как и во входном для распаковки.
Положение -d/-c и -p ЧИСЛО может быть в любом месте, порядок входного и выходного файлов важен.
О программе
Теперь выводится размер несжатых и сжатых данных без учёта 4 байтов размера у сжатых, это поможет определить, влезет ли графика назад.
Сжатие должно выдавать по размеру не больше, чем у оригинальной графики. У одних данных даже получилось на 5 байтов меньше, почему-то.
Код сжатия написал на основе моего сжатия PZZ у игры Jojo no Kimyou na Bouken - Ougon no Kaze (Japan). Оказалось, можно использовать простой алгоритм с поиском повторений у ранее записанных байтов и контрольного байта (биты указывающие на несжатый байт или на смещение + длина), отличие только в записи смещения относительно "окна" у LZSS.
Можно было написать сразу вставку в ром по смещению, указание размера вместо чтения из файла и т. п., но особо смысла нет.
Замечания
То, что я говорил про https://github.com/MichaelDipperstein/lzss, не сработало, похоже там используется другая реализация LZSS.
Сравнил код распаковки Desert Strike, Jungle Strike и Urban Strike, он одинаковый. Вы могли бы использовать те же утилиты, что использовали раньше.
Попробовал вставку графики, вроде правильно. Для отключения проверки CRC использовал Master Code - https://gamehacking.org/game/16162 - 1FF0D4:4E75.

--- Конец цитаты ---

Класс :) Спасибо :)
Sharpnull:
Новая версия 1.2.0, выложил https://github.com/infval/StrikeLZSS, сборка программы. По этому поводу больше не буду ничего делать, если будут проблемы, пишите, лучше в ЛС.
Изменения
* Добавлено улучшенное сжатие по умолчанию. Отключается опцией -nu (not ultra :)).
* Если размер в начале сжатого файла был 0x00000000, происходил вылет. Пустые файлы допускаются.
* Добавлена проверка на выход за пределы данных при распаковке. Происходит с неверными файлами.
* Точная проверка аргументов командной строки, раньше допускалось писать что угодно после первого символа, например -d и -d123 считалось одинаково.
* Если позиция при распаковке была между [0xFFFFFFFC, 0xFFFFFFFF], из-за переполнения допускалось выполнение дальше. Макс. размер входного файла всё равно меньше 2GB.
* Убрано ограничение на 16МБ распакованного файла, добавлял на случай ошибочных данных, так как для этих игр нет смысла в данных >= 65536 байт из-за ограничений памяти Mega Drive. Теперь если ОЗУ не хватит, то будет ошибка выделения памяти (malloc()).
* И по мелочи, связанное с кодом в основном.
Компиляция
Не стал добавлять проект Visual Studio 2019, потому что можно просто создать новый пустой консольный C/C++ проект и добавить файл main.c. Я также: убирал добавление отладочной информации в Release сборки, чтобы не было абсолютного пути до проекта; делал статическую линковку, чтобы не было зависимости от DLL, но лучше так не делать и ставить Microsoft Visual C++ 2019 Redistributable Package.
Добавил простой Makefile, можно скомпилировать с помощью MinGW, если через MinGW-консоль ввести команду make.
Улучшенное сжатие
Я говорил, что моё сжатие не должно быть хуже оригинала, но всё-таки у некоторых данных из Strike игр было хуже на 1 байт, но в остальных также или лучше.
С улучшенным сжатием хуже не должно быть, а сжатие улучшено где-то на 2%. Но это точно не лучший алгоритм, потому что повторное применение алгоритма давало результат на 1 байт меньше в двух местах, не стал так делать из-за мизерной пользы.
Обычное сжатие, в котором ищется всегда макс. последовательность - не лучший, иногда взятие меньше даёт улучшение. Я заметил, когда имеет смысл брать меньше, но не знаю почему это работает. Можно было изучить информацию по сжатию, но так не интересно.
Алгоритм Saxman
Та программа по случайности распаковывала шрифт, но дефис (48-й тайл) там был неправильный. После сжатия Saxman'ом, узнал, что размер "окна" 4096 (у нас 2048), а начальное смещение 0x0FDC (у нас 0x07EE). Из-за смещения близкого к концу "окна" шрифт получался почти правильно, но после распаковки больше 2048 байтов всё равно было бы неверно. В Saxman алгоритме предполагается, что "окно" уже заполнено нулями, экономии не так много и требует очищения памяти. И он может поставить в начале файла 2 байта (Little-Endian) - размер сжатых данных.
ElectrixX:
Sharpnull, ты походу писарь крутой, не хочешь присоединиться к какому нибудь проекту? или чем то уже занимаешься? просто спросил))
Sharpnull:
ElectrixX, такое стоит спрашивать в ЛС. Не крутой, посредственный. Ни с кем над ретро не работаю. Идей и незаконченного много, но вряд ли что-то получится.
Навигация
Главная страница сообщений

Перейти к полной версии