papermario/tools/build/msg/combine.py
Ethan Roseman 3315d6010f
Splat refactor (#257)
* all non-world rodata migrated

* data disasm

* kinda working

* updated yaml

* bloop

* linker header

* configure 2.0

* bin

* mass rename to remove code_

* pause rename

* battle partner stuff

* whew

* more renames

* more renames

* more renaming

* it builds!

* updates

* remove main prefix

* one more thing

* crc, yay0

* .data, .rodata, .bss

* img

* dead_atan2

* it buildsgit add -A

* split battle/partner/6FAD10

* rm &s on sleepy_sheep syms

* sha1sum ninja rule description

* OK but commented out PaperMarioMapFS and PaperMarioNpcSprites

* uncomment

* fix mapfs

* match func_8003CFB4

* .

* clean up and name npc_iter_no_op

* npc.c

* enable cc warnings

* name npc_find_near

* use singular options.asset_path

* smores

* cc_dsl only when needed

* kinda fix configure for splat refactor2

* ok!

* new msg format

* remove old msg format docs

* slight bug fixes, splat adjustment

* git subrepo pull (merge) --force tools/splat

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

* git subrepo pull (merge) --force tools/splat

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

* Update symbol addrs

* git subrepo pull tools/splat

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

Co-authored-by: Alex Bates <hi@imalex.xyz>
2021-04-13 16:47:52 +09:00

121 lines
3.9 KiB
Python
Executable File

#! /usr/bin/python3
from sys import argv
from collections import OrderedDict
import re
import msgpack
import os
class Message:
def __init__(self, d: dict, header_file_index: int):
self.section = d.get("section")
self.index = d.get("index")
self.name = d.get("name")
self.bytes = d["bytes"]
self.header_file_index = header_file_index
if __name__ == "__main__":
if len(argv) < 3:
print("usage: combine.py [out.bin] [out.h] [compiled...]")
exit(1)
_, outfile, header_file, *infiles = argv
messages = []
#header_files = []
for i, infile in enumerate(infiles):
# if infile == "--headers":
# header_files = infiles[i+1:]
# break
with open(infile, "rb") as f:
messages.extend(Message(msg, i) for msg in msgpack.unpack(f))
with open(outfile, "wb") as f:
# sectioned+indexed, followed by just sectioned, followed by just indexed, followed by named (unsectioned & unindexed)
#messages.sort(key=lambda msg: bool(msg.section)<<2 + bool(msg.index))
names = set()
sections = []
#messages_by_file = {}
for message in messages:
if message.section is None:
# allocate a section
for section_idx, section in enumerate(sections):
if len(section) < 0xFFF:
break
message.section = section_idx
else:
section_idx = message.section
while len(sections) <= section_idx:
sections.append({})
section = sections[section_idx]
if message.index is None:
message.index = len(section)
# if message.name:
# if message.name in names:
# print(f"error: multiple messages with name '{message.name}'")
# exit(1)
# else:
# names.add(message.name)
# if message.header_file_index in messages_by_file:
# messages_by_file[message.header_file_index].add(message)
# else:
# messages_by_file[message.header_file_index] = set([message])
if message.index in section:
print(f"warning: multiple messages allocated to id {section_idx:02X}:{message.index:03X}")
if section[message.index].name and message.name:
print(f"warning: message '{section[message.index].name}' and '{message.name}' conflict")
section[message.index] = message
f.seek((len(sections) + 1) * 4) # skip past table of contents
section_offsets = []
for section in sections:
# convert dict into sorted list
section = [msg for idx, msg in sorted(section.items(), key=lambda ele: ele[0])]
message_offsets = []
for message in section:
message_offsets.append(f.tell())
f.write(message.bytes)
section_offset = f.tell()
section_offsets.append(section_offset)
for offset in message_offsets:
f.write(offset.to_bytes(4, byteorder="big"))
f.write(section_offset.to_bytes(4, byteorder="big"))
# padding
while f.tell() % 0x10 != 0:
f.write(b'\0\0\0\0')
f.seek(0)
for offset in section_offsets:
f.write(offset.to_bytes(4, byteorder="big"))
f.write(b'\0\0\0\0')
with open(header_file, "w") as f:
f.write(
f"#ifndef _MESSAGE_IDS_H_\n"
f"#define _MESSAGE_IDS_H_\n"
"\n"
'#include "messages.h"\n'
"\n"
)
for message in messages:
if message.name:
f.write(f"#define MSG_{message.name} MESSAGE_ID(0x{message.section:02X}, 0x{message.index:03X})\n")
f.write("\n#endif\n")