forked from pmret/papermario
-
Notifications
You must be signed in to change notification settings - Fork 0
/
diff_evt.py
executable file
·166 lines (136 loc) · 4.45 KB
/
diff_evt.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
#!/usr/bin/env python3
import argparse
import queue
import time
import subprocess
from diff import Display, debounced_fs_watch
from colorama import Fore, Back, Style
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()