diff --git a/Makefile b/Makefile index 789aa32..c7d6f5e 100644 --- a/Makefile +++ b/Makefile @@ -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) diff --git a/tools/extract_assets.sh b/tools/extract_assets.sh new file mode 100755 index 0000000..057e316 --- /dev/null +++ b/tools/extract_assets.sh @@ -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 diff --git a/tools/unpack_asset.py b/tools/unpack_asset.py new file mode 100755 index 0000000..f1b71b4 --- /dev/null +++ b/tools/unpack_asset.py @@ -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