Разработка и ромхакинг > Ромхакинг
Заказ хака за оплату
Caesar007:
Задача - разработать методику конвертации формата трассы NFS3HP PS1 в формат трассы NFSHS PS1
8000 Р
Sharpnull:
--- Цитата: SaintAspid от 30 Мая 2023, 13:22:46 ---перевод игры Dino Crisis 2 на PS1 от известного переводчика под ником VIT
--- Конец цитаты ---
Выкладываю изменённые файлы для самостоятельной вставки русской паузы на всякий случай (можно через CDmage), а также программу сжатия и написал что разобрал для перевода меню паузы.
Текстура с меню паузы и координатами хранятся в \PSX\DATA\CORE.DAT, также в SLUS_012.79 изменил координаты относительно экрана и адрес начала информации о символах. Информацию по структуре файла и сжатию нашёл здесь: https://www.tapatalk.com/groups/residentevil123/dino-crisis-2-t2236.html (код разжатия также в https://code.google.com/archive/p/dinoclasher/downloads). Подробности:
# Структура .DAT
В начале заголовки отдельных записей (т. е. части файла) по 32 байта:
00, 4 байта (LE): тип записи, 08 - сжатая LZSS текстура с перестановкой (swizzle), 07 - просто сжатые LZSS данные.
04, 4 байта (LE): реальный размер записи, нужно потому что всё выровнено до 2048 байт, для сжатых данных он может указываться больше.
08, Остальные байты: зависит от типа, для типа 08 - u16 x, y, w, h - координаты и размеры в framebuffer (его 1 пиксель == 4 байта), для типа 07 - 4 байта (LE) - адрес загрузки в RAM (например, 0x80181500).
Здесь нет позиции записи в файле, она высчитывается как сумма размеров предыдущих записей выровненных до 2048 байт.
# Текстура с меню паузы
Хранится в CORE.DAT 0x26000-0x267FF в сжатом виде. Заголовок с 0x1C0, я указывал новый размер записи с 0x1C4, т. к. сжатая текстура стала больше, но не превысила выровненный размер, поэтому всё в порядке.
Моим компрессором разжать через командную строку:
LZSS.exe -d CORE.DAT core26000.bin -p 0x26000
Сжать после обработки:
LZSS.exe -c core26000.bin core26000_comp.bin
Потом вставить в CORE.DAT с 0x26000 и после вставленных данных выставить нули до 0x267FF чтобы затереть остатки и изменить размер в 0x1C4, можно указать без учёта двух нулей, которые добавляет моя программа, они нужны для остановки, указание размера чуть больше не проблема.
Для разжатого файла можно сделать перестановку туда и обратно (unswizzle и swizzle), но в данном случае и так нормально. Открыть в CrystalTile2: View > Tile Viewer, Tile form: GBA 4bpp, width 128, height 32, в Palette загрузить палитру (Import, я приложил palette_gray.pal) с прозрачным цветом и оттенками серого от чёрного к белому, для прозрачного у меня magenta. В 1-м куске целое слово PAUSE, во 2-м куске отдельные буквы для OPTION EXIT. Правый клик мыши по кускам и Export/Import для сохранения/вставки изображения. Я использовал Photoshop и сохранял как PNG, при импорте кол-во цветов само уменьшалось (лучше это делать вручную). Слово "ПАУЗА" расположил как и оригинал, а буквы "ОПЦИНАЗД" каждые 16 пикселей по всей длине (слева было свободно - прозрачный цвет, но место не должно использоваться игрой), по высоте чуть больше.
Для просмотра результата можно запустить игру в pcsx-redux, выбрать Debug > VRAM viewers > Show main VRAM viewer, в этом окне View > View VRAM in 4 bits и Enable greyscale, движение мышью с зажатой средней кнопкой - перемещение, колёсико меняет масштаб, наверху коориданты, по которым найдёте текстуру в 576:224, они указаны в CORE.DAT с 0x1C8.
# Координаты текста меню паузы
Основные данные в CORE.DAT 0x27000-0x297FF в сжатом виде. Заголовок с 0x200, я не изменял размер, т. к. в сжатом виде получилось меньше, но вообще стоит указать размер новой сжатой записи и также добавить нули после вставленного, если остались прошлые данные. В разжатом виде с 0x4850 до конца идут данные (оригинал):
--- Код: ---00 E0 78 10 00 00 01 01 # Целый PAUSE
A8 E0 10 10 10 00 06 00 98 E0 10 10 00 00 06 00 # Для OPTION, не по порядку
B8 E0 10 10 1F 00 06 00 D0 E0 10 10 44 00 06 00 # ...
98 E0 10 10 34 00 06 00 C8 E0 08 10 2E 00 06 01 # ...
B8 E0 10 10 22 00 04 00 C8 E0 08 10 1C 00 04 00 # Для EXIT, не по порядку
F0 E0 10 10 0D 00 04 00 E0 E0 10 10 00 00 04 01 # ...
--- Конец кода ---
Во время игры копируются в RAM 0x80185D50 (в заголовке CORE.DAT 0x208 указано 0x80181500, поэтому 0x80181500 + 0x4850 == 0x80185D50), для расстановки и теста можно менять в эмуляторе. Структура из записей по 8 байтов описывают часть текстуры, по 1 байту:
00: координата X относительно текстуры в пикселях текстуры (т. е. для 4bpp по 4 бита, не нужно пересчитывать).
01: координата Y относительно framebuffer.
02 и 03: ширина и высота вырезаемой области из текстуры в пикселях.
04 и 05: координаты X, Y на экране относительно координаты слова (задаётся в SLUS_012.79).
06: кол-во записей, считая эту запись, но учитывается только значение 1-й записи, у остальных просто указано столько же.
07: == 01 в последней записи и == 00 в остальных. Не знаю зачем.
В моём переводе получилось:
--- Код: ---00 E0 78 10 00 00 01 01 # ПАУЗА
80 E0 10 10 00 00 05 00 90 E0 10 10 0F 00 05 00 # ОПЦИИ
A0 E0 10 10 1E 00 05 00 B0 E0 10 10 2F 00 05 00 # ...
B0 E0 10 10 3F 00 05 01
C0 E0 10 10 00 00 05 00 D0 E0 10 10 0F 00 05 00 # НАЗАД
E0 E0 10 10 1E 00 05 00 D0 E0 10 10 2B 00 05 00 # ...
F0 E0 10 10 3B 00 05 01
--- Конец кода ---
Слово НАЗАД вышло длиннее и кол-во букв разное, поэтому нужно отредактировать SLUS_012.79.
В отладчике с 80031AA4 код вызывающий 3 раза функцию 800317FC для отображения каждого слова. Перед вызовом задаются регистры: $a0 адрес на данные, которые меняли выше, и координаты X, Y начала слова на экране в $a1, $a2. Из-за сдвига слова "НАЗАД", нужно изменить адрес данных в инструкции "80031AE4: li $a0, 0x80185D88" на 0x80185D80, а для координаты X ниже в "80031AEC: move $a1, 0x008A" поставить 0x007A. В итоге в файле SLUS_012.79 найти 88 5d 84 34 8a 00 05 24 и заменить на 80 5d 84 34 7a 00 05 24.
# Сжатие LZSS
Оно простое, если вы видели LZSS сжатие. Я изменил свой компрессор для Clock Tower 2. Компилировал через MinGW64 из MSYS2, но можно легко добавить в пустой консольный проект Visual Studio. Алгоритм сжатия простой, поэтому размер сжатого примерно как в оригинальной игре, но у VIT сжатие лучше.
Как я понял, если указать размер сжатых данных в заголовке больше, чем их есть, но при это дальше нули до указанного размера, то за пределами разжатых данных не будет испорченных данных, но будет перезапись байтов с таким же значением, т. к. 00 00 распознаются как копировать 2 байта с текущей позиции.
Mr2:
--- Цитата: Sharpnull от 05 Июня 2023, 00:22:45 ---Моим компрессором разжать через командную строку
--- Конец цитаты ---
Ну ты даёшь, даже компрессор забабахал. :) Я думал ты в курсе что он уже давно есть в открытом доступе. :wall:
Sharpnull:
--- Цитата: Mr2 от 05 Июня 2023, 07:23:54 ---Ну ты даёшь, даже компрессор забабахал. :) Я думал ты в курсе что он уже давно есть в открытом доступе. :wall:
--- Конец цитаты ---
Я использовал код, который у меня был, немного изменил. У вас исходника нет и работает в точности как мой, т. е. примитивное сжатие, у ViT заметно лучше сжимает. У меня быстрее сжатие, dcarc.exe сжимает себя же - 525КБ за 2.5 секунды, у меня - мгновенно и пробовал 11МБ - меньше секунды. Только я указал размер окна 0xFFE в LZSS.c (оставлял на всякий случай), если изменить на #define WINDOW_SIZE_8 0xFFF, то будет также сжимать, сейчас чуть хуже в редких случаях. Ещё у меня добавляются нули в конце для остановки алгоритма и поэтому не будет разжатия, если сжато вашей программой (нужно добавить нули в конце).
Mr2:
--- Цитата: Sharpnull от 05 Июня 2023, 17:32:31 ---Я использовал код, который у меня был, немного изменил. У вас исходника нет и работает в точности как мой, т. е. примитивное сжатие,
--- Конец цитаты ---
Не, мой лучше жмёт в некоторых случаях.)
--- Цитата: Sharpnull от 05 Июня 2023, 17:32:31 ---у ViT заметно лучше сжимает.
--- Конец цитаты ---
Ага, он говорил что где-то исходник или алгоритм сжатия нашёл.
--- Цитата: Sharpnull от 05 Июня 2023, 17:32:31 ---У меня быстрее сжатие, dcarc.exe сжимает себя же - 525КБ за 2.5 секунды, у меня - мгновенно и пробовал 11МБ - меньше секунды.
--- Конец цитаты ---
О скорости в курсе, это из-за того что вывод прогресса не оптимизирован. ;) Так как игровые файлы небольшие, это не критично.
Sharpnull:
--- Цитата: Mr2 от 05 Июня 2023, 20:59:35 ---Не, мой лучше жмёт в некоторых случаях.) Тут сжатый тремя разными компрессорами *.bmp скриншот.
--- Конец цитаты ---
Одинаково с моим, я же написал: "Только я указал размер окна 0xFFE в LZSS.c (оставлял на всякий случай), если изменить на #define WINDOW_SIZE_8 0xFFF, то будет также сжимать, сейчас чуть хуже в редких случаях". Это касается и вашего теста. Сейчас адаптировал мой старый медленный алгоритм, но с хорошим сжатием (вроде не предел), получилось 533 448 байт против 535 034 от ViT, что-то недожал. Позже выложу обновлённое сжатие, если доделаю, скорее всего в другой теме, много оффтопа. Я знаю что можно найти макс. сжатие, но хочется самому подумать.
--- Цитата: Mr2 от 05 Июня 2023, 20:59:35 ---О скорости в курсе, это из-за того что вывод прогресса не оптимизирован. ;) Так как игровые файлы небольшие, это не критично.
--- Конец цитаты ---
Я говорил об ускорении алгоритма сжатия, есть быстрый и медленный, я думал у вас медленный (без исходника не ясно), но оказалось у меня оба работают неразличимо быстро на небольших данных. Разница, например, с быстрым - 600МБ за 25 секунд, а с обычным перестал ждать на 5 минутах. Это важно, когда сжимаешь много файлов сразу. Ваш можно ускорить в 2 раза, если убрать вывод, добавив на конце > nul 2>&1, но видимо вызов функции вывода долгий всё равно.
Из забавно, можно немного улучшить сжатие, если не сжимать последовательность из 2 байт, сжимает только на 1 бит и чаще мешает. У меня для этого поменять константу на #define MIN_SEQ_8 3.
Mr2:
--- Цитата: Sharpnull от 07 Июня 2023, 04:56:13 ---Одинаково с моим, я же написал
--- Конец цитаты ---
Я тестил оригинал, не менял ничего в исходниках. ;)
--- Цитата: Sharpnull от 07 Июня 2023, 04:56:13 ---получилось 533 448 байт против 535 034 от ViT, что-то недожал.
--- Конец цитаты ---
Получается что пережал лучше чем у ViT'a. 533 448 < 535 034
--- Цитата: Sharpnull от 07 Июня 2023, 04:56:13 ---я думал у вас медленный
--- Конец цитаты ---
Да, убрал вывод прогресса, скорость осталась прежней. :-\
Марат:
--- Цитата: Sharpnull от 07 Июня 2023, 04:56:13 ---Сейчас адаптировал мой старый медленный алгоритм, но с хорошим сжатием (вроде не предел), получилось 533 448 байт
--- Конец цитаты ---
Хм-м, адаптировал один из своих пакеров под стандарты Дино Кризис. В нём у меня используется оптимальный разбор строки, который я вычитал то ли в какой-то книжке, то ли в методичке.
И получился абсолютно такой же результат.
Добавлено позже:
PS:У меня то сначала результат получился хуже и я, было, уже подумал, что Sharpnull нашёл какой-то более оптимальный код разбора словаря, а так как я уже давно считал, что нашёл самый оптимальный разбор словаря, то стало интересно. Но оказалось, что просто у меня в поиске закралась ошибка, из-за которой функция поиска не находила максимально длинную фразу.
ViToTiV:
--- Цитата: Mr2 от 05 Июня 2023, 20:59:35 ---Ага, он говорил что где-то исходник или алгоритм сжатия нашёл.
--- Конец цитаты ---
я использовал модуль для Delphi, где взял не помню, где-то в нете, но очень давно.
--- Код: ---unit LZss;
interface
uses
Windows, Classes;
Procedure LZSSCompress(LZss_Ms: TStream);
procedure LZSSDecompress(LZss_Ms: TStream);
Type
chunk_t = record
code, bitcount: byte;
end;
lz_t = record
length, offset, distance: Word;
end;
const
Window_Size = 4095;
Max_Match_Length = 17;
Min_Match_Length = 2;
implementation
Procedure search_lz(pos: integer; Buffer: Array of byte; inputsize: integer;
var lz: lz_t);
var
lz_off, lz_len: integer;
match: byte;
win: integer;
begin
lz_off := 0;
lz_len := 0;
match := 0;
win := pos - Window_Size;
if win < 0 then
win := 0;
while (win < pos) and (win + Max_Match_Length < pos + Max_Match_Length) do
begin
if Buffer[win] = Buffer[pos] then
begin
match := 1;
while (Buffer[win + match] = Buffer[pos + match]) and
(pos + match < inputsize) do
begin
if match >= Max_Match_Length then
Break;
inc(match);
end;
if match > lz_len then
begin
lz_len := match;
lz_off := win;
end;
end;
if match > Max_Match_Length then
begin
lz_len := Max_Match_Length;
Break;
end;
inc(win);
end;
lz.length := lz_len;
lz.offset := lz_off;
lz.distance := pos - lz_off;
end;
Procedure write_lz(var read_pos: integer; var write_buf: Array of byte;
var write_pos: integer; var lz: lz_t; var chunk: chunk_t);
var
lz1, lz2: byte;
lz_dist, lz_len: Word;
lz_d1, lz_d2: Word;
begin
lz_dist := lz.distance;
lz_len := (lz.length - Min_Match_Length) and $0F;
lz_len := (lz_len shl 4) and $F0;
lz_d1 := (lz_dist and $0F00) shr 8;
lz_d2 := lz_dist and $FF;
lz1 := lz_d2;
lz2 := lz_d1 or lz_len;
write_buf[write_pos] := lz1;
inc(write_pos);
write_buf[write_pos] := lz2;
inc(write_pos);
read_pos := read_pos + lz.length;
chunk.code := chunk.code shr 1;
chunk.code := chunk.code or $00;
inc(chunk.bitcount);
end;
Procedure write_lit(var read_pos: integer; var read_buf: Array of byte;
var write_pos: integer; var write_buf: Array of byte; var chunk: chunk_t);
begin
write_buf[write_pos] := read_buf[read_pos];
inc(write_pos);
inc(read_pos);
chunk.code := chunk.code shr 1;
chunk.code := chunk.code or $80;
inc(chunk.bitcount);
end;
Procedure LZSSCompress(LZss_Ms: TStream);
var
input, output: Array of byte;
inputposition, outputposition, headerposition: integer;
inputsize: integer;
lz, lz_alt: lz_t;
chunk: chunk_t;
bit_shift: byte;
begin
chunk.code := 0;
chunk.bitcount := 0;
headerposition := 0;
inputposition := 0;
outputposition := 1;
inputsize := LZss_Ms.Size;
SetLength(input, inputsize);
SetLength(output, inputsize);
LZss_Ms.Read(input[0], inputsize);
LZss_Ms.Size := 0;
LZss_Ms.Position := 0;
write_lit(inputposition, input, outputposition, output, chunk);
while inputposition < inputsize do
begin
search_lz(inputposition, input, inputsize, lz);
search_lz(inputposition + 1, input, inputsize, lz_alt);
if (lz_alt.length > lz.length) and (lz_alt.length >= Min_Match_Length) then
write_lit(inputposition, input, outputposition, output, chunk)
else
begin
if lz.length < Min_Match_Length then
write_lit(inputposition, input, outputposition, output, chunk)
else
write_lz(inputposition, output, outputposition, lz, chunk);
end;
if chunk.bitcount = 8 then
begin
output[headerposition] := chunk.code;
chunk.code := $00;
chunk.bitcount := 0;
headerposition := outputposition;
inc(outputposition)
end;
end;
if (chunk.bitcount < 8) and (chunk.bitcount <> 0) then
begin
bit_shift := 8 - chunk.bitcount;
chunk.code := chunk.code shr bit_shift;
output[headerposition] := chunk.code;
end;
SetLength(output, outputposition);
LZss_Ms.WriteBuffer(output[0], outputposition);
LZss_Ms.Position := 0;
end;
procedure LZSSDecompress(LZss_Ms: TStream);
var
Temp_Ms: Tmemorystream;
ch, Temp_, Temp: byte;
i, jump, Size, flag: integer;
b: array [0 .. 16] of byte;
Temp_Offset, Last_Offset: DWORD;
begin
flag := 1;
LZss_Ms.Position := 0;
Temp_Ms := Tmemorystream.Create;
while LZss_Ms.Position < LZss_Ms.Size do
begin
if flag = 1 then
begin
LZss_Ms.Read(Temp, 1);
flag := Temp or $100;
end;
LZss_Ms.Read(ch, 1);
if Bool(flag and 1) then
Temp_Ms.Write(ch, 1)
else
begin
LZss_Ms.Read(Temp_, 1);
jump := ((Temp_ and $F) shl 8) or ch;
Size := (Temp_ shr 4) + 2;
Temp_Offset := Temp_Ms.Position;
Temp_Ms.Position := Temp_Ms.Position - jump;
Last_Offset := Temp_Ms.Position;
for i := 0 to Size - 1 do
begin
Temp_Ms.Read(b[i], 1);
if Temp_Ms.Position >= Temp_Ms.Size then
Temp_Ms.Position := Last_Offset;
end;
Temp_Ms.Position := Temp_Offset;
Temp_Ms.Write(b, Size);
end;
flag := flag shr 1;
end;
LZss_Ms.Size := 0;
Temp_Ms.Position := 0;
LZss_Ms.CopyFrom(Temp_Ms, Temp_Ms.Size);
LZss_Ms.Position := 0;
Temp_Ms.Free;
end;
end.
--- Конец кода ---
Марат:
--- Цитата: Марат от 07 Июня 2023, 18:48:13 ---В нём у меня используется оптимальный разбор строки, который я вычитал то ли в какой-то книжке, то ли в методичке.
И получился абсолютно такой же результат.
--- Конец цитаты ---
Вспомнил автора: Кадач А.В. и это была не методичка, а диссертация под названием "Эффективные алгоритмы неискажающего сжатия текстовой информации" из его диссертации следует,
--- Цитата ---Как показали эмпирические испытания, ограничения на расход памяти М = 128
более чем достаточно для практического применения, т. к. во всех испытаниях m ни разу
не достигло этого значения (следовательно, порядок кодирования был оптимальным).
--- Конец цитаты ---
Т.е. тот алгоритм, который он реализовал даёт оптимальный разбор, если M не достигает 128. А у меня он и не достиг 128 при сжатии картинки MK. Но если, кто сможет сжать ещё лучше, то это будет интересно.
Беларус:
Опять сжимаете, шакалы? Не хотите в отдельную тему идти мериться своими размерами? :)
Phil:
Здравствуйте! Кто может (оплата и сроки в личку) сделать:
- либо конверсию Черепах 3 (U) с маппера (ММС3 на VRC4d);
- либо перевод-локализацию на английский Японских Черепах2 (VRC4d) чтобы получились как бы Американские Черепахи3 (VRC4d).
Первый способ сложный.
Второй... и проще и быстрее (тоже устраивает).
https://tcrf.net/Teenage_Mutant_Ninja_Turtles_III:_The_Manhattan_Project&cc_key=
тем более, что там есть Region Switch
Т.е. просто нужно, чтобы Японка как бы казалась американкой
понятно, что богут быть небольшие отличия... Но, чтобы казалось, что это Американка, но на VRC4d
Sharpnull:
--- Цитата: Phil от 16 Июня 2023, 19:23:12 ---Второй... и проще и быстрее (тоже устраивает).
--- Конец цитаты ---
Скинул с Region Switch и заменой заставки, ничего сложного.
Я делал конверсию на VRC4d для Phil и сильно затянул с этим, мой косяк, может доделаю.
--- Цитата: ViToTiV от 08 Июня 2023, 10:23:23 ---я использовал модуль для Delphi, где взял не помню, где-то в нете, но очень давно.
--- Конец цитаты ---
Я вроде понял в чём проблема, когда-то похожее делал, там проверяется стоит ли вставить обычный байт, если будет больше последовательность сжатия со следующего байта, но не проверяется будет ли общее сжатие лучше.
Я сделал относительно быстро для сжатия Dino Crisis, убрав лишнее из моего медленного алгоритма где перебирал варианты бездумно. Позже выложу в другой теме, если кому-то нужно.
ww:
Эмуль: Gens Rerecording 11b
Доработать, чтобы запускал все (или почти все) игры с сега СД. Большинство просто виснут после надписи Сега (или в начале ролика), особенно японского региона (образы рабочие, на Fusion все идет). Для примера запустить игру Cliffhanger, Anett Futatabi или Keio Flying Squadron.
Цена: в личку
Guyver(X.B.M.):
--- Цитата ---и назначаете оплату
--- Конец цитаты ---
Vincent7:
STALKER Lost Alpha DC
В старой версии игры элитный детектор аномалий отображал все аномалии в виде коричневых кружков на мини карте. После обновления бинарников это убрали и теперь от него никакого толку. Нужно вернуть детектору эту функцию! Путем переброски файлов выяснилось что изменения правились в xrGame.dll
Выкладываю старую и новую версию. За подробности а также по цене пишите в ЛС :)
ryuukenger:
Игра: Battletoads & Double Dragon
Платформа: Super Nintendo
Хотелось обсудить возможность переделать игру под японский регион:
- замена лого издателя Tradewest на Masaya (это издатель японской версии Battlemaniacs, наверно можно будет оттуда и взять);
- замена текста сюжета и диалогов на японскую хирагану (наверно можно из той же японской Battlemaniacs взять шрифты, переводом займусь я сам);
- увеличить количество жизней на старте до 5-ти сердечек (Учитывая то, что 2 жизни по пути встретится, можно попробовать как-то иначе упростить игру как обычно бывает для японских релизов).
Цена: 500р.
Sharpnull:
--- Цитата: ryuukenger от 31 Августа 2023, 18:11:23 ---Хотелось обсудить возможность переделать игру под японский регион:
- замена лого издателя Tradewest на Masaya (это издатель японской версии Battlemaniacs, наверно можно будет оттуда и взять);
- замена текста сюжета и диалогов на японскую хирагану (наверно можно из той же японской Battlemaniacs взять шрифты, переводом займусь я сам);
- увеличить количество жизней на старте до 5-ти сердечек (Учитывая то, что 2 жизни по пути встретится, можно попробовать как-то иначе упростить игру как обычно бывает для японских релизов).
--- Конец цитаты ---
Перенесу логотип Masaya из Battlemaniacs и увеличу жизни за 500р, я уже посмотрел и почти сделал. Ром придётся расширить. С текстом возиться больше, нужно проверить что везде хватит VRAM. Пишите в ЛС. UPD: Ещё бесконечные continue могу сделать с убиранием текста.
Kotix:
Хотелось бы уже наконец-то хак WWF Wrestlemania Arcade (Sega) с режимом 2 на 2. Не знаю насколько там это технически сложно реализуемо, но с радостью готов внести свои кровные деньги на это.
Maksim86:
Paprium (GEN) бы задампили, заплатил бы с удовольствием.. :)
Навигация
Перейти к полной версии