papermario/diff_evt.py
Alex Bates d22bd18f98
Disassemble Star Power scripts (#584)
* fix diff_evt.py

* document UW/UF based on @SeekyCt's advice

* fix star_rod_idx_to_c.py

* migrate battle/star/focus data

* use N() where possible

* rm data.s

* update symbol_addrs

* refresh

* lullaby

* star storm

* chill out

* fix float problems (sad)

* smooch

* time out

* up and away

* star beam

* peach beam

* peach focus

* peach dash

* rm old data

* Assorted Decomp Across The Galaxy (#574)

* popup_menu_update & other

* a bunch of 190B20

* starting load_player_actor

* load_player_actor

* blorp

* load_partner_actor

* fx_11_main

* fx_11 done

* cleanup

* fx_12

* 3 encounter_api funcs

* encounter_api done

* some 20ec0 funcs

* clean

* PR comments, warnings

* name btl_actorHomePositions

* PR comments

* merge

* Introduce SPRITE_PIXEL_SCALE (#580)

* fix func_80273444 warns

* make end of data explicit in splat.yaml

* lol

Co-authored-by: Ethan Roseman <ethteck@gmail.com>
Co-authored-by: Alexander Faßbender <31699028+Brotenko@users.noreply.github.com>
2021-12-29 02:11:07 +09:00

169 lines
4.5 KiB
Python
Executable File

#!/usr/bin/env python3
import argparse
import queue
import time
import subprocess
import sys
from diff import Display, debounced_fs_watch
from colorama import Fore, Back, Style
sys.path.append("tools")
from tools.update_evts import parse_symbol_addrs
from tools.disasm_script import ScriptDisassembler, get_constants
parser = argparse.ArgumentParser(
description="Diff EVT macros."
)
parser.add_argument(
"start",
help="Symbol name or ROM address to start diffing from.",
)
parser.add_argument(
"-w",
"--watch",
action="store_true",
help="Watch for file changes and update the diff automatically."
)
parser.add_argument(
"-m",
"--make",
action="store_true",
help="Run ninja automatically."
)
parser.add_argument(
"-o",
action="store_true",
help="Ignored for compatibility with diff.py."
)
class EvtDisplay(Display):
def __init__(self, start):
self.config = None
self.base_lines = None
self.mydump = None
self.emsg = None
self.last_refresh_key = None
self.last_diff_output = None
self.start = start
def run_diff(self):
if self.emsg is not None:
return (self.emsg, self.emsg)
symbols = parse_symbol_addrs()
if self.start in symbols:
start = symbols[self.start].rom_addr
else:
try:
start = int(self.start, base=0)
except ValueError:
print("Start symbol name is not known or is an invalid address.")
exit(2)
with open("ver/current/build/papermario.z64", "rb") as f:
f.seek(start)
current = ScriptDisassembler(f, romstart=start, prelude=False).disassemble()
with open("ver/current/baserom.z64", "rb") as f:
f.seek(start)
target = ScriptDisassembler(f, romstart=start, prelude=False).disassemble()
current = current.splitlines()
target = target.splitlines()
score = 0
output = ""
for i in range(max(len(current), len(target))):
if i >= len(current):
current.append("")
if i >= len(target):
target.append("")
current_line = current[i][4:]
target_line = target[i][4:]
output += Style.RESET_ALL
if current_line != target_line:
output += Fore.RED
score += 10
else:
output += Style.DIM
output += f"{target_line:<60} {current_line:<60}\n"
output = f"{'TARGET':<60} {f'CURRENT ({score})':<60}\n" + output
refresh_key = (current, target)
return (output, refresh_key)
class FakeConfig():
def __init__(self, args):
self.make = args.make
self.source_extensions = ["c", "h"]
def run_ninja():
return subprocess.run(
["ninja", "ver/current/build/papermario.z64"],
stderr=subprocess.PIPE,
stdout=subprocess.PIPE,
)
def main():
args = parser.parse_args()
get_constants()
display = EvtDisplay(args.start)
if args.watch:
if not args.make:
yn = input(
"Warning: watch-mode (-w) enabled without auto-ninja (-m). "
"You will have to run ninja manually. Ok? (Y/n) "
)
if yn.lower() == "n":
return
if args.make:
watch_sources = ["src", "include"]
else:
watch_sources = ["ver/current/build/papermario.z64"]
q = queue.Queue()
debounced_fs_watch(watch_sources, q, FakeConfig(args), FakeConfig(args))
display.run_async(q)
last_build = 0.0
try:
while True:
t = q.get()
if t is None:
break
if t < last_build:
continue
last_build = time.time()
if args.make:
display.progress("Building...")
ret = run_ninja()
if ret.returncode != 0:
display.update(
ret.stderr.decode("utf-8-sig", "replace")
or ret.stdout.decode("utf-8-sig", "replace"),
error=True,
)
continue
display.update(last_build, error=False)
except KeyboardInterrupt:
display.terminate()
else:
display.run_sync()
if __name__ == "__main__":
main()