Unpack/post process asset bins into simple file structure

This commit is contained in:
ProjectRevoTPP 2024-10-11 19:22:50 -04:00
parent cbf102782e
commit b0a1dddf50
3 changed files with 123 additions and 0 deletions

View File

@ -156,6 +156,7 @@ SPLAT := $(PYTHON) -m splat split
SPLAT_YAML := $(TARGET)-$(VERSION).yaml
ENCRYPT_LIBLEO := $(PYTHON) tools/encrypt_libleo.py
EXTRACT_ASSETS := tools/extract_assets.sh
IINC := -Iinclude -Isrc -Isrc/libnaudio -Iassets/$(VERSION) -I. -I$(BUILD_DIR)
IINC += -Ilib/ultralib/include -Ilib/ultralib/include/PR -Ilib/ultralib/include/ido
@ -342,6 +343,7 @@ extract:
$(V)$(RM) -r asm/$(VERSION) assets/$(VERSION)
$(V)$(CAT) yamls/$(VERSION)/header.yaml yamls/$(VERSION)/rom.yaml > $(SPLAT_YAML)
$(V)$(SPLAT) $(SPLAT_FLAGS) $(SPLAT_YAML)
$(V)$(EXTRACT_ASSETS)
lib: $(ULTRALIB_LIB)

54
tools/extract_assets.sh Executable file
View File

@ -0,0 +1,54 @@
#!/usr/bin/env bash
# Unpack assets from ROM extraction.
# TODO: The packed bins do not depend on their extracted contents yet so modifying these files will do nothing. Add dependencies
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
tools/unpack_asset.py assets/us/battle_headers.bin
tools/unpack_asset.py assets/us/common_menu0_ui.bin
tools/unpack_asset.py assets/us/common_menu1_ui.bin
tools/unpack_asset.py assets/us/common_menu2_ui.bin
tools/unpack_asset.py assets/us/area_select_ui.bin
tools/unpack_asset.py assets/us/menu_select_ui.bin
tools/unpack_asset.py assets/us/stadium_select_ui.bin
tools/unpack_asset.py assets/us/title_ui.bin
tools/unpack_asset.py assets/us/52F6D0.bin # unused UI
tools/unpack_asset.py assets/us/battle_portraits.bin
tools/unpack_asset.py assets/us/stadium_models.bin
tools/unpack_asset.py assets/us/5C7A70.bin # unk FRAGMENT
tools/unpack_asset.py assets/us/pokedex_area_model.bin
tools/unpack_asset.py assets/us/sushi_go_round.bin
tools/unpack_asset.py assets/us/order_select_ui.bin
tools/unpack_asset.py assets/us/cup_ball_select_ui.bin
tools/unpack_asset.py assets/us/trade_select_ui.bin
tools/unpack_asset.py assets/us/kids_club_select_ui.bin
tools/unpack_asset.py assets/us/gym_leader_castle_clear_gfx.bin
tools/unpack_asset.py assets/us/rental_rules_ui.bin
tools/unpack_asset.py assets/us/sushi_go_round_sprites.bin
tools/unpack_asset.py assets/us/kids_club_game_ui.bin
tools/unpack_asset.py assets/us/gallery_ui.bin
tools/unpack_asset.py assets/us/album_ui.bin
tools/unpack_asset.py assets/us/6A9750.bin # print UI
tools/unpack_asset.py assets/us/snap_select_ui.bin
tools/unpack_asset.py assets/us/cup_clear_ui.bin
tools/unpack_asset.py assets/us/gb_pak_select_ui.bin
tools/unpack_asset.py assets/us/victory_palace_plate_text.bin
tools/unpack_asset.py assets/us/run_rattata_run_flag_gfx.bin
tools/unpack_asset.py assets/us/kanto_gb_map.bin
tools/unpack_asset.py assets/us/6CA730.bin # unused 15 type BGs
tools/unpack_asset.py assets/us/6E2F90.bin # blank file
tools/unpack_asset.py assets/us/battle_ui.bin
tools/unpack_asset.py assets/us/transfer_pak_error_ui.bin
tools/unpack_asset.py assets/us/6EB340.bin
tools/unpack_asset.py assets/us/6EC4D0.bin
tools/unpack_asset.py assets/us/badge_ui.bin
tools/unpack_asset.py assets/us/gym_leader_castle_ui.bin
# 70D3A0 needs special processing. not a normal asset bin
# 7820E0 isnt a normal asset bin either
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

67
tools/unpack_asset.py Executable file
View File

@ -0,0 +1,67 @@
#!/usr/bin/env python3
import sys
import re
import os
from pathlib import Path
import crunch64
# Asset unpacker v0.1 (WIP)
# 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])
# --------------------------
# Main program
# --------------------------
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(0x10))
#print("[DEBUG] File path:", filepath)
#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"
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')
f.write(fin.read())
sys.exit(0)
# Otherwise, process as multi.
bin_size = read_32_be_value(file_header, 8)
file_count = read_32_be_value(file_header, 12)
#print("[DEBUG] Size:", hex(bin_size))
#print("[DEBUG] File count:", file_count)
# Reallocate the file based on the bin size. First seek back to the start, then reallocate.
file.seek(0, os.SEEK_SET)
file_bytes = bytearray(file.read(bin_size))
file_num = 0
while file_num < file_count:
#print("[DEBUG] Processing File #:", file_num)
# Get bin offset and bin size for the # file being processed.
bin_offset = read_32_be_value(file_bytes, 0x10 + (file_num * 0x10) + 0)
bin_size = read_32_be_value(file_bytes, 0x10 + (file_num * 0x10) + 4)
#print("[DEBUG] File Offset:", hex(bin_offset))
#print("[DEBUG] File Size:", hex(bin_size))
# 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"
#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')
file_to_write.write(sub_file_bytes)
file_num = file_num + 1