Files
ss/tools/custom/apply_state_mgr_fns.py
T
robojumper 3b5a959d1b Cursor chaos (#71)
* dCsBase_c mostly done

* dCsGame_c state funcs

* More labels

* Idk anymore

* label ctor

* Move some code

* Add offsets, fix EffectsStruct misconception
2024-10-20 10:01:00 -04:00

159 lines
5.1 KiB
Python

"""
Appropriately names state manager weak functions, given a .s file with
correctly named vtables.
Call with:
python ./tools/custom/apply_state_mgr_fns.py PATH_TO_S_FILE PATH_TO_SYMBOLS_FILE
"""
from dataclasses import dataclass
import pathlib
import re
import sys
from typing import Callable, List
@dataclass
class Vtable:
# A vtable pattern with a match named class_name
vtable_pat: re.Pattern
# A factory for function names
functions: Callable[[str], List[str | None]]
def L(items):
"""Join items and add a length prefix"""
s = None
if isinstance(items, list):
s = "".join(items)
else:
s = items
return str(len(s)) + s
sFStateMgr_c = Vtable(
re.compile("__vt__[0-9]+sFStateMgr_c<(?P<class_name>[A-Za-z0-9_]+),20sStateMethodUsr_FI_c>"),
lambda name: [
None,
None,
"__dt__" + L(["sFStateMgr_c<", name, ",20sStateMethodUsr_FI_c>"]) + "Fv",
"initializeState__" + L(["sStateMgr_c<", name, ",20sStateMethodUsr_FI_c,12sFStateFct_c,13sStateIDChk_c>"]) + "Fv",
"executeState__" + L(["sStateMgr_c<", name, ",20sStateMethodUsr_FI_c,12sFStateFct_c,13sStateIDChk_c>"]) + "Fv",
"finalizeState__" + L(["sStateMgr_c<", name, ",20sStateMethodUsr_FI_c,12sFStateFct_c,13sStateIDChk_c>"]) + "Fv",
"changeState__" + L(["sStateMgr_c<", name, ",20sStateMethodUsr_FI_c,12sFStateFct_c,13sStateIDChk_c>"]) + "FRC12sStateIDIf_c",
"refreshState__" + L(["sStateMgr_c<", name, ",20sStateMethodUsr_FI_c,12sFStateFct_c,13sStateIDChk_c>"]) + "Fv",
"getState__" + L(["sStateMgr_c<", name, ",20sStateMethodUsr_FI_c,12sFStateFct_c,13sStateIDChk_c>"]) + "CFv",
"getNewStateID__" + L(["sStateMgr_c<", name, ",20sStateMethodUsr_FI_c,12sFStateFct_c,13sStateIDChk_c>"]) + "CFv",
"getStateID__" + L(["sStateMgr_c<", name, ",20sStateMethodUsr_FI_c,12sFStateFct_c,13sStateIDChk_c>"]) + "CFv",
"getOldStateID__" + L(["sStateMgr_c<", name, ",20sStateMethodUsr_FI_c,12sFStateFct_c,13sStateIDChk_c>"]) + "CFv",
]
)
sStateMgr_c = Vtable(
re.compile("__vt__[0-9]+sStateMgr_c<(?P<class_name>[A-Za-z0-9_]+),20sStateMethodUsr_FI_c,12sFStateFct_c,13sStateIDChk_c>"),
lambda name: [
None,
None,
"__dt__" + L(["sStateMgr_c<", name, ",20sStateMethodUsr_FI_c,12sFStateFct_c,13sStateIDChk_c>"]) + "Fv",
# the rest are dupes
]
)
sFStateFct_c = Vtable(
re.compile("__vt__[0-9]+sFStateFct_c<(?P<class_name>[A-Za-z0-9_]+)>"),
lambda name: [
None,
None,
"__dt__" + L(["sFStateFct_c<", name, ">"]) + "Fv",
"build__" + L(["sFStateFct_c<", name, ">"]) + "FRC12sStateIDIf_c",
"dispose__" + L(["sFStateFct_c<", name, ">"]) + "FRP10sStateIf_c",
]
)
sFState_c = Vtable(
re.compile("__vt__[0-9]+sFState_c<(?P<class_name>[A-Za-z0-9_]+)>"),
lambda name: [
None,
None,
"__dt__" + L(["sFState_c<", name, ">"]) + "Fv",
"initialize__" + L(["sFState_c<", name, ">"]) + "Fv",
"execute__" + L(["sFState_c<", name, ">"]) + "Fv",
"finalize__" + L(["sFState_c<", name, ">"]) + "Fv",
]
)
sFStateID_c = Vtable(
re.compile("__vt__[0-9]+sFStateID_c<(?P<class_name>[A-Za-z0-9_]+)>"),
lambda name: [
None,
None,
"__dt__" + L(["sFStateID_c<", name, ">"]) + "Fv",
None,
None,
None,
None,
"isSameName__" + L(["sFStateID_c<", name, ">"]) + "CFPCc",
None,
None,
"initializeState__" + L(["sFStateID_c<", name, ">"]) + "CFR" + name,
"executeState__" + L(["sFStateID_c<", name, ">"]) + "CFR" + name,
"finalizeState__" + L(["sFStateID_c<", name, ">"]) + "CFR" + name,
]
)
vtables = [
sFStateMgr_c,
sStateMgr_c,
sFStateFct_c,
sFState_c,
sFStateID_c,
]
def parse_data(file):
renames = []
lines: List[str] = file.splitlines()
i = 0
while i < len(lines):
if lines[i].startswith(".obj"):
obj_name = lines[i].rsplit(",", maxsplit=1)[0][5:]
if obj_name.startswith('"') and obj_name.endswith('"'):
obj_name = obj_name[1:-1]
for tab in vtables:
if (match := tab.vtable_pat.match(obj_name)):
class_name = match.group("class_name")
fns = tab.functions(class_name)
for new_name in fns:
i += 1
if new_name is not None:
old_name = lines[i].split(" ")[-1]
if old_name.startswith('"') and old_name.endswith('"'):
old_name = old_name[1:-1]
renames.append((old_name, new_name))
break
i += 1
return renames
def main():
s_file = sys.argv[1]
sym_file = sys.argv[2]
s_text = pathlib.Path(s_file).read_text()
renames = parse_data(s_text)
sym_text = pathlib.Path(sym_file).read_text()
for (old, new) in renames:
if old != new:
sym_text = sym_text.replace(old + " = .text", new + " = .text")
pathlib.Path(sym_file).write_text(sym_text)
if __name__ == "__main__":
main()