Skip to content

Commit

Permalink
decompress Yay0s and extract PRESJPEGs
Browse files Browse the repository at this point in the history
  • Loading branch information
RevoSucks committed Oct 12, 2024
1 parent f83ef11 commit 12d06db
Show file tree
Hide file tree
Showing 5 changed files with 259 additions and 5 deletions.
4 changes: 2 additions & 2 deletions src/3FB0.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ typedef struct PERSSZP {

typedef struct PRESJPEG {
/* 0x00 */ char magic[0x8]; // PRESJPEG
/* 0x08 */ u32 unk_08;
/* 0x0C */ u32 unk_0C;
/* 0x08 */ u32 unk_08; // header size? always 0x10
/* 0x0C */ u32 unk_0C;
} PRESJPEG; // size = 0x10

typedef struct Yay0 {
Expand Down
38 changes: 38 additions & 0 deletions tools/decompress_persszp.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
#!/usr/bin/env python3

import sys
import re
import os
from pathlib import Path
import crunch64

# PERS-SZP decompressor v0.1 (WIP)
# Usage: decompress_persszp.py [path to PERS-SZP file]

# Read a big endian 32-bit value from a bytearray file with a given offset.
def read_32_be_value(file_arr, i):
return (file_arr[i + 0] << 24) + (file_arr[i + 1] << 16) \
+ (file_arr[i + 2] << 8) + (file_arr[i + 3])

assets_path = "assets/us/"

filepath = Path(sys.argv[1])
filename = os.path.splitext(os.path.basename(filepath))[0]

file = open(filepath, 'rb')
file_header = bytearray(file.read(0xC)) # First, we need to fetch the header size. This is right after the magic part of the header.

# Check for 50 45 52 53 2D 53 5A 50, which is "PERS-SZP"
if file_header[0] != 0x50 or file_header[1] != 0x45 or file_header[2] != 0x52 or file_header[3] != 0x53 or file_header[4] != 0x2D or file_header[5] != 0x53 or file_header[6] != 0x5A or file_header[7] != 0x50:
print(filepath, "File magic is NOT 'PERS-SZP'. Please pass a valid file.")
sys.exit(1)

header_size = read_32_be_value(file_header, 8)
# Now that we have the header size, seek past the header.
file.seek(header_size, os.SEEK_SET)
yay0_file = file.read()

decompressed = crunch64.yay0.decompress(yay0_file)
file.close()
file = open(filepath, 'wb')
file.write(decompressed)
178 changes: 178 additions & 0 deletions tools/extract_assets.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

# TODO: The packed bins do not depend on their extracted contents yet so modifying these files will do nothing. Add dependencies

# Unpack/move any multi or single asset bins.
tools/unpack_asset.py assets/us/n64_logo_texture.bin
tools/unpack_asset.py assets/us/fonts.bin
tools/unpack_asset.py assets/us/backgrounds.bin
Expand Down Expand Up @@ -52,3 +53,180 @@ tools/unpack_asset.py assets/us/textdata.bin
tools/unpack_asset.py assets/us/798CD0.bin
tools/unpack_asset.py assets/us/snap_mode_ui.bin
tools/unpack_asset.py assets/us/copyright.bin

# Next, decompress all the PERS-SZP files with a Yay0. TODO: Roll these up
# into recursive calls. All of the files within an asset bin SHOULD be the
# same type, but it in theory it isnt guaranteed to be. Does the game ensure
# that? If so, we should be able to safely roll these up.
tools/decompress_persszp.py assets/us/n64_logo_texture/0/file.bin
tools/decompress_persszp.py assets/us/fonts/0/file.bin
tools/decompress_persszp.py assets/us/fonts/1/file.bin
tools/decompress_persszp.py assets/us/fonts/2/file.bin
tools/decompress_persszp.py assets/us/fonts/3/file.bin
tools/decompress_persszp.py assets/us/fonts/4/file.bin
tools/decompress_persszp.py assets/us/fonts/5/file.bin
tools/decompress_persszp.py assets/us/battle_headers/0/file.bin
tools/decompress_persszp.py assets/us/battle_headers/1/file.bin
tools/decompress_persszp.py assets/us/battle_headers/2/file.bin
tools/decompress_persszp.py assets/us/battle_headers/3/file.bin
tools/decompress_persszp.py assets/us/battle_headers/4/file.bin
tools/decompress_persszp.py assets/us/battle_headers/5/file.bin
tools/decompress_persszp.py assets/us/battle_headers/6/file.bin
tools/decompress_persszp.py assets/us/battle_headers/7/file.bin
tools/decompress_persszp.py assets/us/battle_headers/8/file.bin
tools/decompress_persszp.py assets/us/battle_headers/9/file.bin
tools/decompress_persszp.py assets/us/battle_headers/10/file.bin
tools/decompress_persszp.py assets/us/battle_headers/11/file.bin
tools/decompress_persszp.py assets/us/battle_headers/12/file.bin
tools/decompress_persszp.py assets/us/common_menu0_ui/0/file.bin
tools/decompress_persszp.py assets/us/common_menu1_ui/0/file.bin
tools/decompress_persszp.py assets/us/common_menu2_ui/0/file.bin
tools/decompress_persszp.py assets/us/area_select_ui/0/file.bin
tools/decompress_persszp.py assets/us/menu_select_ui/0/file.bin
tools/decompress_persszp.py assets/us/stadium_select_ui/0/file.bin
tools/decompress_persszp.py assets/us/title_ui/0/file.bin
tools/decompress_persszp.py assets/us/52F6D0/0/file.bin
tools/decompress_persszp.py assets/us/battle_portraits/0/file.bin
tools/decompress_persszp.py assets/us/battle_portraits/1/file.bin
tools/decompress_persszp.py assets/us/battle_portraits/2/file.bin
tools/decompress_persszp.py assets/us/battle_portraits/3/file.bin
tools/decompress_persszp.py assets/us/battle_portraits/4/file.bin
tools/decompress_persszp.py assets/us/battle_portraits/5/file.bin
tools/decompress_persszp.py assets/us/battle_portraits/6/file.bin
tools/decompress_persszp.py assets/us/battle_portraits/7/file.bin
tools/decompress_persszp.py assets/us/battle_portraits/8/file.bin
tools/decompress_persszp.py assets/us/battle_portraits/9/file.bin
tools/decompress_persszp.py assets/us/battle_portraits/10/file.bin
tools/decompress_persszp.py assets/us/battle_portraits/11/file.bin
tools/decompress_persszp.py assets/us/battle_portraits/12/file.bin
tools/decompress_persszp.py assets/us/battle_portraits/13/file.bin
tools/decompress_persszp.py assets/us/battle_portraits/14/file.bin
tools/decompress_persszp.py assets/us/battle_portraits/15/file.bin
tools/decompress_persszp.py assets/us/battle_portraits/16/file.bin
tools/decompress_persszp.py assets/us/battle_portraits/17/file.bin
tools/decompress_persszp.py assets/us/battle_portraits/18/file.bin
tools/decompress_persszp.py assets/us/battle_portraits/19/file.bin
tools/decompress_persszp.py assets/us/battle_portraits/20/file.bin
tools/decompress_persszp.py assets/us/battle_portraits/21/file.bin
tools/decompress_persszp.py assets/us/battle_portraits/22/file.bin
tools/decompress_persszp.py assets/us/battle_portraits/23/file.bin
tools/decompress_persszp.py assets/us/battle_portraits/24/file.bin
tools/decompress_persszp.py assets/us/battle_portraits/25/file.bin
tools/decompress_persszp.py assets/us/battle_portraits/26/file.bin
tools/decompress_persszp.py assets/us/battle_portraits/27/file.bin
tools/decompress_persszp.py assets/us/battle_portraits/28/file.bin
tools/decompress_persszp.py assets/us/battle_portraits/29/file.bin
tools/decompress_persszp.py assets/us/battle_portraits/30/file.bin
tools/decompress_persszp.py assets/us/battle_portraits/31/file.bin
tools/decompress_persszp.py assets/us/battle_portraits/32/file.bin
tools/decompress_persszp.py assets/us/battle_portraits/33/file.bin
tools/decompress_persszp.py assets/us/battle_portraits/34/file.bin
tools/decompress_persszp.py assets/us/battle_portraits/35/file.bin
tools/decompress_persszp.py assets/us/battle_portraits/36/file.bin
tools/decompress_persszp.py assets/us/battle_portraits/37/file.bin
tools/decompress_persszp.py assets/us/battle_portraits/38/file.bin
tools/decompress_persszp.py assets/us/battle_portraits/39/file.bin
tools/decompress_persszp.py assets/us/battle_portraits/40/file.bin
tools/decompress_persszp.py assets/us/battle_portraits/41/file.bin
tools/decompress_persszp.py assets/us/battle_portraits/42/file.bin
tools/decompress_persszp.py assets/us/battle_portraits/43/file.bin
tools/decompress_persszp.py assets/us/battle_portraits/44/file.bin
tools/decompress_persszp.py assets/us/battle_portraits/45/file.bin
tools/decompress_persszp.py assets/us/battle_portraits/46/file.bin
tools/decompress_persszp.py assets/us/battle_portraits/47/file.bin
tools/decompress_persszp.py assets/us/battle_portraits/48/file.bin
tools/decompress_persszp.py assets/us/battle_portraits/49/file.bin
tools/decompress_persszp.py assets/us/battle_portraits/50/file.bin
tools/decompress_persszp.py assets/us/battle_portraits/51/file.bin
tools/decompress_persszp.py assets/us/battle_portraits/52/file.bin
tools/decompress_persszp.py assets/us/battle_portraits/53/file.bin
tools/decompress_persszp.py assets/us/stadium_models/0/file.bin
tools/decompress_persszp.py assets/us/stadium_models/1/file.bin
tools/decompress_persszp.py assets/us/stadium_models/2/file.bin
tools/decompress_persszp.py assets/us/stadium_models/3/file.bin
tools/decompress_persszp.py assets/us/stadium_models/4/file.bin
tools/decompress_persszp.py assets/us/stadium_models/5/file.bin
tools/decompress_persszp.py assets/us/stadium_models/6/file.bin
tools/decompress_persszp.py assets/us/stadium_models/7/file.bin
tools/decompress_persszp.py assets/us/stadium_models/8/file.bin
tools/decompress_persszp.py assets/us/stadium_models/9/file.bin
tools/decompress_persszp.py assets/us/stadium_models/10/file.bin
tools/decompress_persszp.py assets/us/stadium_models/11/file.bin
tools/decompress_persszp.py assets/us/stadium_models/12/file.bin
tools/decompress_persszp.py assets/us/stadium_models/13/file.bin
tools/decompress_persszp.py assets/us/stadium_models/14/file.bin
tools/decompress_persszp.py assets/us/stadium_models/15/file.bin
tools/decompress_persszp.py assets/us/stadium_models/16/file.bin
tools/decompress_persszp.py assets/us/stadium_models/17/file.bin
tools/decompress_persszp.py assets/us/5C7A70/0/file.bin
tools/decompress_persszp.py assets/us/pokedex_area_model/0/file.bin
tools/decompress_persszp.py assets/us/sushi_go_round/0/file.bin
tools/decompress_persszp.py assets/us/order_select_ui/0/file.bin
tools/decompress_persszp.py assets/us/cup_ball_select_ui/0/file.bin
tools/decompress_persszp.py assets/us/trade_select_ui/0/file.bin
tools/decompress_persszp.py assets/us/kids_club_select_ui/0/file.bin
tools/decompress_persszp.py assets/us/gym_leader_castle_clear_gfx/0/file.bin
tools/decompress_persszp.py assets/us/rental_rules_ui/0/file.bin
tools/decompress_persszp.py assets/us/sushi_go_round_sprites/0/file.bin
tools/decompress_persszp.py assets/us/kids_club_game_ui/0/file.bin
tools/decompress_persszp.py assets/us/gallery_ui/0/file.bin
tools/decompress_persszp.py assets/us/album_ui/0/file.bin
tools/decompress_persszp.py assets/us/6A9750/0/file.bin
tools/decompress_persszp.py assets/us/snap_select_ui/0/file.bin
tools/decompress_persszp.py assets/us/cup_clear_ui/0/file.bin
tools/decompress_persszp.py assets/us/gb_pak_select_ui/0/file.bin
tools/decompress_persszp.py assets/us/victory_palace_plate_text/0/file.bin
tools/decompress_persszp.py assets/us/run_rattata_run_flag_gfx/0/file.bin
tools/decompress_persszp.py assets/us/kanto_gb_map/0/file.bin
tools/decompress_persszp.py assets/us/6E2F90/0/file.bin
tools/decompress_persszp.py assets/us/battle_ui/0/file.bin
tools/decompress_persszp.py assets/us/transfer_pak_error_ui/0/file.bin
tools/decompress_persszp.py assets/us/6EB340/0/file.bin
tools/decompress_persszp.py assets/us/6EB340/1/file.bin
tools/decompress_persszp.py assets/us/6EB340/2/file.bin
tools/decompress_persszp.py assets/us/6EB340/3/file.bin
tools/decompress_persszp.py assets/us/6EC4D0/0/file.bin
tools/decompress_persszp.py assets/us/badge_ui/0/file.bin
tools/decompress_persszp.py assets/us/gym_leader_castle_ui/0/file.bin
tools/decompress_persszp.py assets/us/798CD0/0/file.bin
tools/decompress_persszp.py assets/us/snap_mode_ui/0/file.bin
tools/decompress_persszp.py assets/us/copyright/0/file.bin

# Extract all PRESJPEG files.
tools/extract_presjpeg.py assets/us/backgrounds/0/file.bin
tools/extract_presjpeg.py assets/us/backgrounds/1/file.bin
tools/extract_presjpeg.py assets/us/backgrounds/2/file.bin
tools/extract_presjpeg.py assets/us/backgrounds/3/file.bin
tools/extract_presjpeg.py assets/us/backgrounds/4/file.bin
tools/extract_presjpeg.py assets/us/backgrounds/5/file.bin
tools/extract_presjpeg.py assets/us/backgrounds/6/file.bin
tools/extract_presjpeg.py assets/us/backgrounds/7/file.bin
tools/extract_presjpeg.py assets/us/backgrounds/8/file.bin
tools/extract_presjpeg.py assets/us/backgrounds/9/file.bin
tools/extract_presjpeg.py assets/us/backgrounds/10/file.bin
tools/extract_presjpeg.py assets/us/backgrounds/11/file.bin
tools/extract_presjpeg.py assets/us/backgrounds/12/file.bin
tools/extract_presjpeg.py assets/us/backgrounds/13/file.bin
tools/extract_presjpeg.py assets/us/backgrounds/14/file.bin
tools/extract_presjpeg.py assets/us/backgrounds/15/file.bin
tools/extract_presjpeg.py assets/us/backgrounds/16/file.bin
tools/extract_presjpeg.py assets/us/backgrounds/17/file.bin
tools/extract_presjpeg.py assets/us/backgrounds/18/file.bin
tools/extract_presjpeg.py assets/us/backgrounds/19/file.bin
tools/extract_presjpeg.py assets/us/backgrounds/20/file.bin
tools/extract_presjpeg.py assets/us/6CA730/0/file.bin
tools/extract_presjpeg.py assets/us/6CA730/1/file.bin
tools/extract_presjpeg.py assets/us/6CA730/2/file.bin
tools/extract_presjpeg.py assets/us/6CA730/3/file.bin
tools/extract_presjpeg.py assets/us/6CA730/4/file.bin
tools/extract_presjpeg.py assets/us/6CA730/5/file.bin
tools/extract_presjpeg.py assets/us/6CA730/6/file.bin
tools/extract_presjpeg.py assets/us/6CA730/7/file.bin
tools/extract_presjpeg.py assets/us/6CA730/8/file.bin
tools/extract_presjpeg.py assets/us/6CA730/9/file.bin
tools/extract_presjpeg.py assets/us/6CA730/10/file.bin
tools/extract_presjpeg.py assets/us/6CA730/11/file.bin
tools/extract_presjpeg.py assets/us/6CA730/12/file.bin
tools/extract_presjpeg.py assets/us/6CA730/13/file.bin
tools/extract_presjpeg.py assets/us/6CA730/14/file.bin
tools/extract_presjpeg.py assets/us/6CA730/15/file.bin
36 changes: 36 additions & 0 deletions tools/extract_presjpeg.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
#!/usr/bin/env python3

import sys
import re
import os
from pathlib import Path
import crunch64

# PRESJPEG extractor
# Usage: decompress_presjpeg.py [path to PRESJPEG file]

# Read a big endian 32-bit value from a bytearray file with a given offset.
def read_32_be_value(file_arr, i):
return (file_arr[i + 0] << 24) + (file_arr[i + 1] << 16) \
+ (file_arr[i + 2] << 8) + (file_arr[i + 3])

assets_path = "assets/us/"

filepath = Path(sys.argv[1])
filename = os.path.splitext(os.path.basename(filepath))[0]

file = open(filepath, 'rb')
file_header = bytearray(file.read(0xC)) # First, we need to fetch the header size. This is right after the magic part of the header.

# Check for 50 52 45 53 4A 50 45 47, which is "PRESJPEG"
if file_header[0] != 0x50 or file_header[1] != 0x52 or file_header[2] != 0x45 or file_header[3] != 0x53 or file_header[4] != 0x4A or file_header[5] != 0x50 or file_header[6] != 0x45 or file_header[7] != 0x47:
print(filepath, "File magic is NOT 'PRESJPEG'. Please pass a valid file.")
sys.exit(1)

header_size = read_32_be_value(file_header, 8)
file.seek(header_size, os.SEEK_SET)
jpeg_file = bytearray(file.read())
file.close()
file = open(filepath, 'wb')
file.write(jpeg_file)
filepath.rename(filepath.with_suffix('.jpeg'))
8 changes: 5 additions & 3 deletions tools/unpack_asset.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,10 @@ def read_32_be_value(file_arr, i):
#print("[DEBUG] File name:", filename)

# Magic check for multi asset bin. If no match, treat as a single asset bin, and just copy it to the expected folder.
if file_header[0] != 0x00 or file_header[1] != 0x00 or file_header[2] != 0x00 or file_header[3] != 0x00 or file_header[4] != 0x00 or file_header[5] != 0x00 or file_header[6] != 0x00 or file_header[7] != 0x00:
file_path_to_write = assets_path + filename + "/0/0.bin"
# For some reason, stadium_models.bin breaks this pattern and uses this for something. (HACK: Workaround by just not checking the 4th byte.)
# TODO: Properly handle this
if file_header[0] != 0x00 or file_header[1] != 0x00 or file_header[2] != 0x00 or file_header[4] != 0x00 or file_header[5] != 0x00 or file_header[6] != 0x00 or file_header[7] != 0x00:
file_path_to_write = assets_path + filename + "/0/file.bin"
os.makedirs(os.path.dirname(file_path_to_write), exist_ok=True)
with open(file_path_to_write, 'wb') as f:
fin = open(filepath, 'rb')
Expand Down Expand Up @@ -59,7 +61,7 @@ def read_32_be_value(file_arr, i):
# Seek to the file offset.
file.seek(bin_offset, os.SEEK_SET)
sub_file_bytes = bytearray(file.read(bin_size))
file_path_to_write = assets_path + filename + "/" + str(file_num) + "/" + str(file_num) + ".bin"
file_path_to_write = assets_path + filename + "/" + str(file_num) + "/file.bin"
#print("[DEBUG] Path to write:", file_path_to_write)
os.makedirs(os.path.dirname(file_path_to_write), exist_ok=True)
file_to_write = open(file_path_to_write, 'wb')
Expand Down

0 comments on commit 12d06db

Please sign in to comment.