Разработка и ромхакинг > Инструменты
[DC][PS1][PS2][GC] Плагин к 7-zip для распаковки CHD, RVZ и AFS
(1/1)
cptPauer:
Я доделал наконец свой плагин к 7-zip.
https://github.com/Conkwer/tres7z/releases/tag/v2.3.0
Распаковка CHD, AFS, RVZ.
В чём суть?
Он распаковывает CHD (Dreamcast, PSX, PS2) и RVZ (GameCube).
Плагин обычно ложится в c:\Program Files\7-Zip\Formats\ (64 бит)
Бывает такое, берешь образ GameCube, а он в RVZ и что делать? Качаешь Долфин, распаковываешь.
Очень бесячая тема.
Та же ерунда с CHD v5 и особенно которые с ZSTD компрессией, новые.
У меня все образы PlayStation1 в нём для Анберника.
Тут бывает надо ISO достать и поиграть на старом ePSXe, тут начинается гемморой, впоминай как, качай МАМЕ, опять бери chdman и извлекай.
Ну и для Dreamcast так же. Хочешь закинуть игру на GD-emu, а она в CHD.
С плагином же вообще удобно. Просто как обычный архив открываешь, по-человечески наконец.
Всё равно 7-Zip уже установлен для 7z.
В смысле, из CHD можно достать ISO или GDI. Из RVZ -> ISO. Из AFS что угодно.
Без потерь в качестве, как было запаковано так и достанется. Запаковку не делал обратно в CHD, только распаковка.
Плагин сложно было сделать, цените. У 7-zip система сборки упоротая, не говоря про плагины. Там даже с нейронкой его собрать, можно быстрее состарится.
Наверное, поэтому никто и не делает такие плагины. Я тоже бы не делал, просто научился их делать раньше, для CDI.
Плагин поддерживает еще CDI, да. Но не полноценно, CDDA надо доделывать. Зато он показывает IP.BIN как bootsector.bin.
Вообще, для 7-zip существовал плагин iso7z. Вот мой с ним конфликтует, кстати.
В том плагине нету нормальной поддержки CHD v5 ZSTD, он только четвертой открывает. И там есть поддержка CDI, но не показывает бутсектор.
Еще мой плагин открывает MTF для Darkstone (с компрессией!) и несколько других форматов, но это не актуально на эмуленде.
Что актуально, это то что он открывает AFS! Те, которые повсеместно на Dreamcast. С поддержкой запаковки. Вообще, сложности распаковать/запаковать AFS небыло никогда, но это было всегда неудобно. И Puyo Puyo Tools багованная.
А тут можно сделать нормальный индекс и вынести это в комментарии, у 7-zip есть такая фича.
И автоопределение ADX музыки в таких архивах, как у AFS Explorer. Поддержка AFS подогнана как у AFS Explorer.
Это должно быть лучше Puyo Puyo Tools и AFS Explorer. Но, только для архивов первой версии, которые на Dreamcast. Более новые (которые встречаются на PS2 и GC) меня не интересовали, я их не добавлял.
Код, понятно что, не с нуля написан. Собрал из готового. Все кудосы соответствующим проектам и спекам: MAME, Долфину и т.п.
Времязатраты: 2 дня на каждый формат, кроме RVZ. Где можно было ускорится нейронкой и готовым кодом, ускорялся (я же не садомазохист). Там и так гемморно, что бы ещё кодить всё лично.
Roosya:
--- Цитата: cptPauer от 01 Сентября 2026, 03:09:04 ---из CHD можно достать ISO или GDI. Из RVZ -> ISO. Из AFS что угодно.
--- Конец цитаты ---
Хорошее дело, а то для пс1 держал в chd только из-за многофайловой структуры куебин. А для пс2 мог бы и в исо. А тут поголовно куча форматов ужато в этот новый. Старые эмули с ним не работают. Хотя вот epsxe читал вроде обновили. но в анберниках и ретроидах его нет.
e2e41:
This plugin can be used for Magic the Gathering DC???
там вреде deflate, хз не работает вроде
cptPauer:
--- Цитата: e2e41 от 01 Сентября 2026, 16:51:44 ---This plugin can be used for Magic the Gathering DC???
там вреде deflate, хз не работает вроде
--- Конец цитаты ---
Да. Почему не работает? Fully supported, блин.
На распаковку и запаковку. Хорошо работает. Что нужно делать, что бы оно не работало?
Открываю pac, извлекает и запаковывает. Можно вообще любые файлы паковать в pac.
Автоматически показывает pvr текстуры и str музыку в этих pac по заголовкам.
Кстати, если кто-то хочет помочь это перевести на русский, то помогайте. Я сам не осилю это доперевести. Больше чем два года прошло.
Ситуация такая: в игре есть английский язык для описания карт, но он не активен. Можно переключить японский на английский, все описания карт станут на английском. Менюшки все на японском, английского перевода небыло для них.
Статут проекта: я сделал русскую озвучку Яндексом. Как по мне, то достаточно нормально перевелось. Lin нарисовал пробный шрифт, но шрифт кривоватый, доделывать шрифт некому.
Есть проект для Круптара. Лично мне в Круптаре неудобно, но Круптар пересчитывает поинтеры и можно текст любого размера писать. Весь текст можно редактировать свободно, тот который не текстурами.
Туторы я перевёл (обучающие ролики), но озвучки для них не делал на русский. На английский есть..
Сейчас вроде бы перевели игру на английский, но я не смотрел что там, этот перевод был начат раньше и с японского могу перевести сам. Я переводил без нейронок, для этого я сделал на английский eTypist OCR и им распознавал текстуры.
Патч с переводом для eTypist я выкладывал. eTypist забытая, но очень мощная японская OCR. Изначатально интерфейс там на японском полностью. Часто распознаёт лучше нейронок, но они уже близко подобрались.
-----
Можно попробовать натравить нейронку перевести на русский текст. Но, это тоже не так просто как кажется и не бесплатно. Я бы даже сказал, что описания карт полюбому нужно переводить нейронкой, их там вроде около 300. Но делать вычитку и меню надёжнее переводить вручную.
-----
Я делал на два языка. На английский там относительно просто, потому что описания карт уже есть на английском (не активно), ролики есть на английском (но субтитры к ним японские, на английском голосом, но сабы я сделал), шрифт английский уже есть. Там только меню на японском, текстуры (магазин). В целом, тоже достаточно много текстур. Картинки карт на японском, но они продублированы текстом и на таком разрешении их всё равно толком не видно. Там не рассчитано, что с карт будут читать текст.
Игра планировалась на два языка, наверное. Там английский есть, но не до конца.
Да, Deflate без заголовка. Я оговорился, наверное. Алгоритм не мой, я просто портировал c Python тот скрипт, с которым со мной поделились.
--- Код: ---import sys
import zlib
from pathlib import Path
from struct import unpack, pack
import argparse
import json
def read_u32le(f):
return unpack("<I", f.read(4))[0]
def pack_u32le(u32):
return pack("<I", u32)
def ceil4(n):
return ((n + 3) // 4) * 4
def unpack_pac(input_file, output_dir):
p_in = Path(input_file).resolve()
if output_dir:
p_out = Path(output_dir).resolve() / p_in.stem
else:
p_out = p_in.parent / p_in.stem
p_out.mkdir(parents=True, exist_ok=True)
file_info = []
with open(p_in, "rb") as f:
magic = f.read(4)
if magic != b"PAC\x00":
print("magic != PAC\x00")
sys.exit(1)
file_count = read_u32le(f)
for i in range(file_count):
off = 8 + i * 4
f.seek(off)
file_off = read_u32le(f)
file_off_end = read_u32le(f)
file_size = file_off_end - file_off
f.seek(file_off)
data = f.read(file_size)
file_entry = {"index": i, "size": file_size}
file_name = f"{i:08d}"
if data[:4] == b"NZIP":
try:
u = zlib.decompress(data[8:], wbits=-15)
if u[:4] == b"GBIX":
p = p_out / (file_name + ".pvr")
p.write_bytes(u)
file_entry["type"] = "pvr"
elif u[:4] == b"SDCP":
p = p_out / (file_name + ".sdcp")
p.write_bytes(u)
file_entry["type"] = "sdcp"
else:
p = p_out / (file_name + ".bin")
p.write_bytes(u)
file_entry["type"] = "bin"
except zlib.error:
p = p_out / (file_name + ".nzip")
p.write_bytes(data)
file_entry["type"] = "nzip"
elif data[:4] == b"SDCP":
p = p_out / (file_name + ".sdcp")
p.write_bytes(data)
file_entry["type"] = "sdcp"
else:
p = p_out / (file_name + ".bin")
p.write_bytes(data)
file_entry["type"] = "bin"
file_info.append(file_entry)
info_json_path = p_out / "info.json"
with info_json_path.open("w") as info_json_file:
json.dump(file_info, info_json_file, indent=4)
def pack_pac(input_folder, output_file):
input_folder = Path(input_folder)
output_file = Path(output_file)
info_json_path = input_folder / "info.json"
if info_json_path.exists():
with info_json_path.open("r") as info_json_file:
file_info = json.load(info_json_file)
else:
print("No info.json found. Processing files as usual.")
file_info = None
files = []
if file_info:
for entry in file_info:
file_path = input_folder / f"{entry['index']:08d}.{entry['type']}"
if file_path.exists():
data = file_path.read_bytes()
if entry['type'] == 'pvr':
c = zlib.compress(data, level=9, wbits=-15)
c = b"NZIP" + pack_u32le(len(data)) + c
files.append(c)
elif entry['type'] == 'nzip':
u = file_path.read_bytes()
c = zlib.compress(u, level=9, wbits=-15)
c = b"NZIP" + pack_u32le(len(u)) + c
files.append(c)
else:
files.append(data)
else:
print(f"File {file_path} not found. Skipping.")
else:
file_paths = sorted(input_folder.glob('*'))
for file_path in file_paths:
if file_path.suffix in ['.pvr', '.nzip', '.bin', '.sdcp']:
data = file_path.read_bytes()
if file_path.suffix == '.pvr':
c = zlib.compress(data, level=9, wbits=-15)
c = b"NZIP" + pack_u32le(len(data)) + c
files.append(c)
elif file_path.suffix == '.nzip':
u = file_path.read_bytes()
c = zlib.compress(u, level=9, wbits=-15)
c = b"NZIP" + pack_u32le(len(u)) + c
files.append(c)
else:
files.append(data)
else:
print(f"Skipping {file_path.name}")
with open(output_file, "wb") as f:
f.write(b"PAC\x00")
f.write(pack_u32le(len(files)))
off = 8 + len(files) * 4 + 4
for i in range(len(files)):
f.write(pack_u32le(off))
off += ceil4(len(files[i]))
f.write(pack_u32le(off))
for i in range(len(files)):
padded = files[i].ljust(ceil4(len(files[i])), b"\x00")
f.write(padded)
def main():
parser = argparse.ArgumentParser(
description="Unpack or pack a PAC file.",
epilog="Examples:\n"
" python script.py unpack example.pac -d ./uncompressed\n"
" python script.py unpack example.pac\n"
" python script.py pack ./uncompressed/example example.new.pac",
formatter_class=argparse.RawTextHelpFormatter
)
subparsers = parser.add_subparsers(dest="command", required=True)
unpack_parser = subparsers.add_parser("unpack", help="Unpack a PAC file.")
unpack_parser.add_argument("input_file", type=str, help="The input PAC file to unpack.")
unpack_parser.add_argument("-d", "--directory", type=str, default=None, help="The output directory for unpacked files.")
pack_parser = subparsers.add_parser("pack", help="Pack files into a PAC file.")
pack_parser.add_argument("input_folder", type=str, help="The input folder containing files to pack.")
pack_parser.add_argument("output_file", type=str, help="The output PAC file.")
args = parser.parse_args()
if args.command == "unpack":
unpack_pac(args.input_file, args.directory)
elif args.command == "pack":
pack_pac(args.input_folder, args.output_file)
if __name__ == "__main__":
main()
--- Конец кода ---
Автор один из местных, но я не уверен кто.
Сделано было до нейронок, несколько лет назад.
Это MTF был в LZSS. Просто MTF запарил меня, теперь оговариваюсь. Там тоже запаковка поддерживается. И инфы как сделать правильно небыло, данные смещались и игра крашилась.
Поэтому LZSS застрял у меня в голове, оговариваюсь, моральная травма)). А в Магике был Deflate.
Я проверял на игре, работало. Но, если какие-то косяки, то скрипт на Python тогда наверняка работает, проверено.
--- Цитата: Roosya от 01 Сентября 2026, 08:54:41 ---Хорошее дело, а то для пс1 держал в chd только из-за многофайловой структуры куебин. А для пс2 мог бы и в исо. А тут поголовно куча форматов ужато в этот новый. Старые эмули с ним не работают. Хотя вот epsxe читал вроде обновили. но в анберниках и ретроидах его нет.
--- Конец цитаты ---
Кстати, можно было сделать для PS1, что бы из CHD обратно получался многобин. Но, сейчас там извлекается одним файлом + cue.
Поэтому, если игру PS1 из Редампа запаковать в CHD, а этим плагином извлечь, то она из многобина редампа превратится в однобин. Сама игра останется точно такой же, но формат изменится.
--- Цитата ---Хотя вот epsxe читал вроде обновили. но в анберниках и ретроидах его нет.
--- Конец цитаты ---
Кстати, в epsxe наверное без zstd, не уверен.
Раньше же был просто пятой версии chd, хотя часто встречались четвёртой для первой соньки.
А теперь переходят на zstd компрессию и такие вообще мало где открываются, эмуляторы не поддерживают.
Redream не поддерживает, например.
e2e41:
шрифт разве не в DPFONT? если там то кирилица уже вшита должна быть, жалко что все заглохло...
в текущих реалиях текст перевести не состовляет труда
7zG.exe не работает
7zFM.exe работает
cptPauer:
--- Цитата: e2e41 от Вчера в 17:02:28 ---видимо я что то делаю не так просто закинул плагин в корень с 7zip...
--- Конец цитаты ---
Плагины ложатся не в корень! У тебя не подключен, открывает как без плагина.
Ложится в подпапку "Formats" или "Сodecs".
Например: "c:\Program Files\7-Zip\Formats\tres7z.64.dll" (раньше dream7z.64.dll, название самой dll роли не играет).
Разрядность должна совпадать. Если у тебя 64-битная версия, то плагин должен быть 64-битный.
32-битного там пока нету.
Кроме того, там есть архив "всё включено". Архиватор вместе с плагином (7-Zip-Zstandard-x64.zip).
Старая версия не лучший вариант, но проверить работу плагина можно.
Плагин подходит как к официальному 7-zip (https://www.7-zip.org/) так и форкам (https://github.com/mcmilk/7-Zip-zstd) разных версий.
cl:
я не проверял абсолюно все форматы но это работает, я даже 1 звезду поставил
cptPauer:
А чего в отдельную тему перенесли из "Рус. переводы и ромхакинг игр на Dreamcast".
Обсуждалось как раз ромхакинг и переводы: а) перевод Magic the Gathering (Dreamcast) на русский язык. Ромхакинг чистой воды, скрины с Круптара, алгоритмы компрессии и разное.
б) распаковка pac (это формат архивов с кастомным заголовком) это ромхакинг, пример распаковки на Python.
в) распаковка AFS это близко к ромхакингу, половина игр на Dreamcast использует AFS v1. Раньше для этого использовали AFS Exporer и Puyo Puyo Tools.
И я даже не успел проги остальные выложить. Там еще плеер был yamaha apdcm, который удобнее vgmstream.
Небыло оффтопа. Всё про ромхакинг и касается переводов. Для Dreamcast в основном было сделано. И плагин позволяет из CDI доставать IP.BIN. Это часто нужно для правильной пересборки образа.
CDI, CHD, AFS v1, PAC = Dreamcast
Сонька 1-2 просто тоже использует CHD, так исторически сложилось, но на Dreamcast раньше начали. RVZ просто бонус.
Теперь чёрта с два найдешь, так всё в одном месте было. И где проги и переводы теперь обсуждать?
e2e41:
Просто линк оставить в профильной на эту тему, откровенно плагин удобный для некоторых моментов.
Навигация
Перейти к полной версии