papermario/tools/splat_ext/PaperMarioMapFS.py
Ethan Roseman eac31e27ab
All map data + rodata disasm (#218)
* Misc early code decomp

* Make expected script

* fix m2ctx

* gOverrideFlags & set/unset macros

* update symbol addrs

* Cleanup and PR comments

* oops

* UnkNpcAIFunc16

* UnkNpcAIFunc17

* UnkNpcAIFunc18

* symbol_addrs

* area_mac data/rodata disassembly

* 16C8E0 segment rodata migration

* delete_actor

* 16F740 funcs

* symbol_addrs

* depend on s files: optional

* UnkNpcAIFunc19

* UnkNpcAIFunc20

* UnkNpcAIFunc21

* UnkNpcAIFunc22

* .

* removing unnecessary lines from splat yaml

* all map rodata disassembled

* all map data disasm

* 2 undefined syms

* fix stuff

* Update splat extensions

* .

* git subrepo pull (merge) tools/splat

subrepo:
  subdir:   "tools/splat"
  merged:   "d93689f269"
upstream:
  origin:   "https://github.com/ethteck/splat.git"
  branch:   "master"
  commit:   "d93689f269"
git-subrepo:
  version:  "0.4.3"
  origin:   "https://github.com/ingydotnet/git-subrepo"
  commit:   "2f68596"

* git subrepo pull (merge) tools/splat

subrepo:
  subdir:   "tools/splat"
  merged:   "a1db6e1200"
upstream:
  origin:   "https://github.com/ethteck/splat.git"
  branch:   "master"
  commit:   "a1db6e1200"
git-subrepo:
  version:  "0.4.3"
  origin:   "https://github.com/ingydotnet/git-subrepo"
  commit:   "2f68596"

* git subrepo pull tools/splat

subrepo:
  subdir:   "tools/splat"
  merged:   "45f167b5fd"
upstream:
  origin:   "https://github.com/ethteck/splat.git"
  branch:   "master"
  commit:   "45f167b5fd"
git-subrepo:
  version:  "0.4.3"
  origin:   "https://github.com/ingydotnet/git-subrepo"
  commit:   "2f68596"

* git subrepo pull --force tools/splat

subrepo:
  subdir:   "tools/splat"
  merged:   "8d3af099e7"
upstream:
  origin:   "https://github.com/ethteck/splat.git"
  branch:   "master"
  commit:   "8d3af099e7"
git-subrepo:
  version:  "0.4.3"
  origin:   "https://github.com/ingydotnet/git-subrepo"
  commit:   "2f68596"

* git subrepo pull tools/splat

subrepo:
  subdir:   "tools/splat"
  merged:   "e904556c0c"
upstream:
  origin:   "https://github.com/ethteck/splat.git"
  branch:   "master"
  commit:   "e904556c0c"
git-subrepo:
  version:  "0.4.3"
  origin:   "https://github.com/ingydotnet/git-subrepo"
  commit:   "2f68596"

* git subrepo pull tools/splat

subrepo:
  subdir:   "tools/splat"
  merged:   "795df1f226"
upstream:
  origin:   "https://github.com/ethteck/splat.git"
  branch:   "master"
  commit:   "795df1f226"
git-subrepo:
  version:  "0.4.3"
  origin:   "https://github.com/ingydotnet/git-subrepo"
  commit:   "2f68596"

* git subrepo pull tools/splat

subrepo:
  subdir:   "tools/splat"
  merged:   "90787f49bd"
upstream:
  origin:   "https://github.com/ethteck/splat.git"
  branch:   "master"
  commit:   "90787f49bd"
git-subrepo:
  version:  "0.4.3"
  origin:   "https://github.com/ingydotnet/git-subrepo"
  commit:   "2f68596"

* git subrepo pull tools/splat

subrepo:
  subdir:   "tools/splat"
  merged:   "8f4395956b"
upstream:
  origin:   "https://github.com/ethteck/splat.git"
  branch:   "master"
  commit:   "8f4395956b"
git-subrepo:
  version:  "0.4.3"
  origin:   "https://github.com/ingydotnet/git-subrepo"
  commit:   "2f68596"

* Updated splat, fixed alignment stuff, woo

* File split
2021-03-22 22:29:47 -04:00

121 lines
4.4 KiB
Python

import os
from segtypes.n64.segment import N64Segment
from pathlib import Path
from util.n64 import Yay0decompress
from util.color import unpack_color
from util.iter import iter_in_groups
from util import options
import png
def decode_null_terminated_ascii(data):
length = 0
for byte in data:
if byte == 0:
break
length += 1
return data[:length].decode('ascii')
def parse_palette(data):
palette = []
for a, b in iter_in_groups(data, 2):
palette.append(unpack_color([a, b]))
return palette
class N64SegPaperMarioMapFS(N64Segment):
def __init__(self, segment, next_segment):
super().__init__(segment, next_segment)
def split(self, rom_bytes, base_path):
bin_dir = self.create_split_dir(base_path, options.get("assets_dir", "bin"))
img_party_dir = self.create_split_dir(base_path, options.get("assets_dir", "img") + "/party")
data = rom_bytes[self.rom_start: self.rom_end]
asset_idx = 0
while True:
asset_data = data[0x20 + asset_idx * 0x1C:]
name = decode_null_terminated_ascii(asset_data[0:])
offset = int.from_bytes(asset_data[0x10:0x14], byteorder="big")
size = int.from_bytes(asset_data[0x14:0x18], byteorder="big")
decompressed_size = int.from_bytes(
asset_data[0x18:0x1C], byteorder="big")
is_compressed = size != decompressed_size
if offset == 0:
path = None
elif name.startswith("party_"):
path = os.path.join(img_party_dir, "{}.png".format(name))
elif name.endswith("_hit") or name.endswith("_shape"):
map_dir = self.create_split_dir(base_path, options.get("assets_dir", "bin") + f"/map")
path = os.path.join(map_dir, "{}.bin".format(name))
elif name.endswith("_tex"):
map_dir = self.create_split_dir(base_path, options.get("assets_dir", "bin") + f"/map")
path = os.path.join(map_dir, "{}.bin".format(name))
elif name.endswith("_bg"):
map_dir = self.create_split_dir(base_path, options.get("assets_dir", "bin") + f"/map")
path = os.path.join(map_dir, "{}.png".format(name))
else:
path = os.path.join(bin_dir, "{}.bin".format(name))
if name == "end_data":
break
bytes = rom_bytes[self.rom_start + 0x20 +
offset: self.rom_start + 0x20 + offset + size]
Path(path).parent.mkdir(parents=True, exist_ok=True)
if is_compressed:
self.log(f"Decompressing {name}...")
bytes = Yay0decompress.decompress_yay0(bytes)
if name.startswith("party_"):
with open(path, "wb") as f:
# CI-8
w = png.Writer(150, 105, palette=parse_palette(bytes[:0x200]))
w.write_array(f, bytes[0x200:])
elif name.endswith("_bg"):
def write_bg_png(bytes, path, header_offset=0):
header = bytes[header_offset:header_offset+0x10]
raster_offset = int.from_bytes(header[0:4], byteorder="big") - 0x80200000
palette_offset = int.from_bytes(header[4:8], byteorder="big") - 0x80200000
assert int.from_bytes(header[8:12], byteorder="big") == 0x000C0014 # draw pos
width = int.from_bytes(header[12:14], byteorder="big")
height = int.from_bytes(header[14:16], byteorder="big")
with open(path, "wb") as f:
# CI-8
w = png.Writer(width, height, palette=parse_palette(bytes[palette_offset:palette_offset+512]))
w.write_array(f, bytes[raster_offset:])
write_bg_png(bytes, path)
# sbk_bg has an alternative palette
if name == "sbk_bg":
write_bg_png(bytes, path.split(".")[0] + ".alt.png", header_offset=0x10)
else:
with open(path, "wb") as f:
f.write(bytes)
self.log(f"Wrote {name} to {Path(bin_dir, path)}")
asset_idx += 1
def get_ld_files(self):
return [(options.get("assets_dir", "bin"), self.name, ".data", self.rom_start)]
@staticmethod
def get_default_name(addr):
return "assets"