mirror of
https://github.com/zeldaret/oot.git
synced 2024-11-14 05:19:36 +00:00
Delete old bootstrap tools (#1590)
* Delete old bootstrap tools * Restore find_unused_asm.sh
This commit is contained in:
parent
0ed57f61b7
commit
b2f596faca
14 changed files with 0 additions and 1872 deletions
|
@ -1,69 +0,0 @@
|
|||
import os
|
||||
|
||||
class FileEntry:
|
||||
def __init__(self, nFuncName):
|
||||
self.funcName = nFuncName
|
||||
self.lines = list()
|
||||
|
||||
def ReadAllLines(filename):
|
||||
with open(filename) as f:
|
||||
lines = f.read().splitlines()
|
||||
|
||||
return lines;
|
||||
|
||||
def WriteAllLines(filename, lines):
|
||||
with open(filename, 'w') as f:
|
||||
for item in lines:
|
||||
f.write("%s\n" % item)
|
||||
|
||||
return lines;
|
||||
|
||||
if not os.path.exists("asm"):
|
||||
os.makedirs("asm")
|
||||
|
||||
if not os.path.exists("c"):
|
||||
os.makedirs("c")
|
||||
|
||||
dirs = os.listdir("asm")
|
||||
|
||||
for directory in dirs:
|
||||
if (os.path.isdir("asm//" + directory)):
|
||||
continue
|
||||
|
||||
print("Processing asm//" + directory)
|
||||
|
||||
folderName = os.path.splitext(directory)[0]
|
||||
lines = ReadAllLines("asm//" + directory)
|
||||
functions = list()
|
||||
currentFunction = None
|
||||
|
||||
for line in lines:
|
||||
if (line.startswith("glabel")):
|
||||
if (currentFunction != None):
|
||||
functions.insert(len(functions), currentFunction)
|
||||
|
||||
currentFunction = FileEntry(line.split("glabel ")[1])
|
||||
|
||||
if (currentFunction != None):
|
||||
currentFunction.lines.insert(len(currentFunction.lines), line)
|
||||
|
||||
if (currentFunction != None):
|
||||
functions.insert(len(functions), currentFunction)
|
||||
|
||||
if not os.path.exists("asm//" + folderName):
|
||||
os.makedirs("asm//" + folderName)
|
||||
|
||||
for func in functions:
|
||||
WriteAllLines("asm//" + folderName + "//" + func.funcName + ".s", func.lines)
|
||||
|
||||
cLines = list()
|
||||
|
||||
cLines.insert(len(cLines), "#include <ultra64.h>")
|
||||
cLines.insert(len(cLines), "#include <global.h>\n")
|
||||
|
||||
for func in functions:
|
||||
cLines.insert(len(cLines), "#pragma GLOBAL_ASM(\"asm/non_matchings/code/" + folderName + "/" + func.funcName + ".s\")\n")
|
||||
|
||||
WriteAllLines("c//" + folderName + ".c", cLines)
|
||||
|
||||
print("Done!")
|
|
@ -1,218 +0,0 @@
|
|||
#!/usr/bin/python3
|
||||
|
||||
import os
|
||||
import sys
|
||||
import re
|
||||
from disassemble import get_z_name
|
||||
|
||||
script_dir = os.path.dirname(os.path.realpath(__file__))
|
||||
root_dir = script_dir + "/../"
|
||||
data_dir = root_dir + "data/overlays/actors"
|
||||
asm_dir = root_dir + "asm/non_matchings/overlays/actors"
|
||||
src_dir = root_dir + "src/overlays/actors"
|
||||
include_dir = root_dir + "include"
|
||||
indent = " "
|
||||
|
||||
to_rename = []
|
||||
|
||||
with open(os.path.join(include_dir, "z64actor.h")) as f:
|
||||
z64actor_text = f.read()
|
||||
|
||||
with open(os.path.join(include_dir, "z64object.h")) as f:
|
||||
z64object_text = f.read()
|
||||
|
||||
|
||||
def get_actor_id_name(actor_id):
|
||||
matches = re.findall(actor_id + " .*\n", z64actor_text)
|
||||
if len(matches) == 0:
|
||||
return "0x" + actor_id
|
||||
match = matches[-1]
|
||||
match = match.replace(",", "").strip().split(" ")[-1]
|
||||
return match
|
||||
|
||||
|
||||
def get_actor_type_name(actor_type):
|
||||
matches = re.findall(actor_type + " .*\n", z64actor_text)
|
||||
for m in matches:
|
||||
if "ACTORCAT" in m:
|
||||
match = m.replace(",", "").strip().split(" ")[-1]
|
||||
return match
|
||||
return "0x" + actor_type
|
||||
|
||||
|
||||
def get_object_id_name(object_id):
|
||||
matches = re.findall(object_id + " .*\n", z64object_text)
|
||||
if len(matches) == 0:
|
||||
return "0x" + object_id
|
||||
match = matches[-1]
|
||||
match = match.replace(",", "").strip().split(" ")[-1]
|
||||
return match
|
||||
|
||||
|
||||
def create_struct(name, size):
|
||||
ret = "typedef struct\n{\n" + indent + "/* 0x0000 */ Actor actor;\n"
|
||||
leftover = int(size, 16) - int("0x14C", 16)
|
||||
if leftover > 0:
|
||||
ret += indent + "/* 0x014C */ char unk_14C[0x" + hex(leftover).upper()[2:] + "];\n"
|
||||
ret += "} " + name + "; // size = 0x" + size + "\n"
|
||||
return ret
|
||||
|
||||
|
||||
def rename():
|
||||
# Filenames first
|
||||
for root, dirs, files in os.walk(root_dir):
|
||||
for file in files:
|
||||
for elem in to_rename:
|
||||
if elem[0] in file:
|
||||
new_file = file.replace(elem[0], elem[1])
|
||||
file_path = os.path.join(root, file)
|
||||
new_file_path = os.path.join(root, new_file)
|
||||
os.rename(file_path, new_file_path)
|
||||
|
||||
# File contents
|
||||
for root, dirs, files in os.walk(root_dir):
|
||||
for file in files:
|
||||
if file.endswith(".c") or file.endswith(".s"):
|
||||
file_path = os.path.join(root, file)
|
||||
with open(file_path) as f:
|
||||
file_text = f.read()
|
||||
new_file_text = file_text
|
||||
for elem in to_rename:
|
||||
# if "func_" in elem[0]:
|
||||
# new_file_text = new_file_text.replace("glabel " + elem[0], elem[1] + ":")
|
||||
new_file_text = new_file_text.replace(elem[0], elem[1])
|
||||
if new_file_text != file_text:
|
||||
with open(file_path, "w", newline="\n") as f:
|
||||
f.write(new_file_text)
|
||||
|
||||
|
||||
def bootstrap(ovl_path, ovl_text):
|
||||
path_split = ovl_path.split(os.path.sep)
|
||||
z_name = path_split[-1][:-2]
|
||||
ovl_name = path_split[-2]
|
||||
init_vars_name = ovl_name[4:] + "_InitVars"
|
||||
|
||||
with open(os.path.join(data_dir, z_name + ".data.s")) as f:
|
||||
data_text = f.read()
|
||||
|
||||
pattern = re.compile("glabel D_........\n .word 0x........, 0x........, 0x........, 0x........\n(\.word func_........\n|\.word 0x00000000\n|\.word Actor_Noop\n){4}")
|
||||
init_data = pattern.search(data_text)
|
||||
if init_data is None or len(init_data.regs) == 0:
|
||||
return ""
|
||||
init_data = data_text[init_data.regs[0][0]:init_data.regs[0][1]]
|
||||
|
||||
lines = init_data.split("\n")
|
||||
|
||||
init_var_label = lines[0][7:]
|
||||
init_func = lines[2][6:]
|
||||
destroy_func = lines[3][6:]
|
||||
update_func = lines[4][6:]
|
||||
draw_func = lines[5][6:]
|
||||
|
||||
ovl_shortened = ovl_name.replace("ovl", "").replace("_", "")
|
||||
init_func_name = ovl_shortened + "_Init"
|
||||
destroy_func_name = ovl_shortened + "_Destroy"
|
||||
update_func_name = ovl_shortened + "_Update"
|
||||
draw_func_name = ovl_shortened + "_Draw"
|
||||
|
||||
to_rename.append((init_var_label, init_vars_name))
|
||||
if init_func != "0x00000000" and init_func != "Actor_Noop":
|
||||
to_rename.append((init_func, init_func_name))
|
||||
if destroy_func != "0x00000000" and destroy_func != "Actor_Noop":
|
||||
to_rename.append((destroy_func, destroy_func_name))
|
||||
if update_func != "0x00000000" and update_func != "Actor_Noop":
|
||||
to_rename.append((update_func, update_func_name))
|
||||
if draw_func != "0x00000000" and draw_func != "Actor_Noop":
|
||||
to_rename.append((draw_func, draw_func_name))
|
||||
|
||||
init_var_data = lines[1]
|
||||
init_data = init_var_data[7:53].replace("0x", "").split(", ")
|
||||
actor_id = init_data[0][0:4]
|
||||
actor_type = init_data[0][4:6]
|
||||
room = init_data[0][6:8]
|
||||
flags = init_data[1]
|
||||
object_id = init_data[2][0:4]
|
||||
struct_size = init_data[3][4:8]
|
||||
|
||||
actor_id_name = get_actor_id_name(actor_id)
|
||||
actor_type_name = get_actor_type_name(actor_type)
|
||||
object_id_name = get_object_id_name(object_id)
|
||||
|
||||
struct_name = ovl_shortened
|
||||
|
||||
struct_text = create_struct(struct_name, struct_size)
|
||||
|
||||
defines = "#define ROOM 0x" + room + "\n#define FLAGS 0x" + flags + "\n"
|
||||
|
||||
decs = ""
|
||||
if init_func != "0x00000000" and init_func != "Actor_Noop":
|
||||
decs += "void " + init_func_name + "(" + struct_name + "* this, PlayState* play);\n"
|
||||
if destroy_func != "0x00000000" and destroy_func != "Actor_Noop":
|
||||
decs += "void " + destroy_func_name + "(" + struct_name + "* this, PlayState* play);\n"
|
||||
if update_func != "0x00000000" and update_func != "Actor_Noop":
|
||||
decs += "void " + update_func_name + "(" + struct_name + "* this, PlayState* play);\n"
|
||||
if draw_func != "0x00000000" and draw_func != "Actor_Noop":
|
||||
decs += "void " + draw_func_name + "(" + struct_name + "* this, PlayState* play);\n"
|
||||
|
||||
init_vars = "ActorInit " + init_vars_name + " =\n{\n"
|
||||
init_vars += indent + actor_id_name + ",\n"
|
||||
init_vars += indent + actor_type_name + ",\n"
|
||||
init_vars += indent + "ROOM,\n" + indent + "FLAGS,\n"
|
||||
init_vars += indent + object_id_name + ",\n"
|
||||
init_vars += indent + "sizeof(" + struct_name + "),\n"
|
||||
|
||||
if init_func == "0x00000000":
|
||||
init_vars += indent + "NULL,\n"
|
||||
elif init_func == "Actor_Noop":
|
||||
init_vars += indent + "(ActorFunc)Actor_Noop,\n"
|
||||
else:
|
||||
init_vars += indent + "(ActorFunc)" + init_func_name + ",\n"
|
||||
|
||||
if destroy_func == "0x00000000":
|
||||
init_vars += indent + "NULL,\n"
|
||||
elif destroy_func == "Actor_Noop":
|
||||
init_vars += indent + "(ActorFunc)Actor_Noop,\n"
|
||||
else:
|
||||
init_vars += indent + "(ActorFunc)" + destroy_func_name + ",\n"
|
||||
|
||||
if update_func == "0x00000000":
|
||||
init_vars += indent + "NULL,\n"
|
||||
elif update_func == "Actor_Noop":
|
||||
init_vars += indent + "(ActorFunc)Actor_Noop,\n"
|
||||
else:
|
||||
init_vars += indent + "(ActorFunc)" + update_func_name + ",\n"
|
||||
|
||||
if draw_func == "0x00000000":
|
||||
init_vars += indent + "NULL,\n"
|
||||
elif draw_func == "Actor_Noop":
|
||||
init_vars += indent + "(ActorFunc)Actor_Noop,\n"
|
||||
else:
|
||||
init_vars += indent + "(ActorFunc)" + draw_func_name + ",\n"
|
||||
|
||||
init_vars += "};\n"
|
||||
|
||||
return struct_text + "\n" + defines + "\n" + decs + "\n/*\n" + init_vars + "*/"
|
||||
|
||||
|
||||
def main():
|
||||
for root, dirs, files in os.walk(src_dir):
|
||||
for file in files:
|
||||
if file.endswith(".c"):
|
||||
file_path = os.path.join(root, file)
|
||||
with open(file_path) as f:
|
||||
file_text = f.read()
|
||||
brace_count = file_text.count("{")
|
||||
if brace_count == 0:
|
||||
bootstrap_text = bootstrap(file_path, file_text)
|
||||
if bootstrap_text != "":
|
||||
newline_spot = file_text.find("\n\n") + 1
|
||||
newfile_text = file_text[:newline_spot] + "\n" + bootstrap_text + file_text[newline_spot:]
|
||||
newfile_text = newfile_text.replace("\n\n\n\n\n", "\n")
|
||||
|
||||
with open(file_path, "w", newline="\n") as f:
|
||||
f.write(newfile_text)
|
||||
else:
|
||||
dog = 5
|
||||
rename()
|
||||
|
||||
main()
|
|
@ -1,196 +0,0 @@
|
|||
#!/usr/bin/python3
|
||||
|
||||
import os
|
||||
import sys
|
||||
import re
|
||||
|
||||
script_dir = os.path.dirname(os.path.realpath(__file__))
|
||||
root_dir = script_dir + "/../"
|
||||
data_dir = root_dir + "data/overlays/effects"
|
||||
asm_dir = root_dir + "asm/non_matchings/overlays/effects"
|
||||
src_dir = root_dir + "src/overlays/effects"
|
||||
include_dir = root_dir + "include"
|
||||
indent = " "
|
||||
|
||||
effect_enum = [
|
||||
"EFFECT_SS_DUST",
|
||||
"EFFECT_SS_KIRAKIRA",
|
||||
"EFFECT_SS_BOMB",
|
||||
"EFFECT_SS_BOMB2",
|
||||
"EFFECT_SS_BLAST",
|
||||
"EFFECT_SS_G_SPK",
|
||||
"EFFECT_SS_D_FIRE",
|
||||
"EFFECT_SS_BUBBLE",
|
||||
"EFFECT_SS_UNSET",
|
||||
"EFFECT_SS_G_RIPPLE",
|
||||
"EFFECT_SS_G_SPLASH",
|
||||
"EFFECT_SS_G_MAGMA",
|
||||
"EFFECT_SS_G_FIRE",
|
||||
"EFFECT_SS_LIGHTNING",
|
||||
"EFFECT_SS_DT_BUBBLE",
|
||||
"EFFECT_SS_HAHEN",
|
||||
"EFFECT_SS_STICK",
|
||||
"EFFECT_SS_SIBUKI",
|
||||
"EFFECT_SS_SIBUKI2",
|
||||
"EFFECT_SS_G_MAGMA2",
|
||||
"EFFECT_SS_STONE1",
|
||||
"EFFECT_SS_HITMARK",
|
||||
"EFFECT_SS_FHG_FLASH",
|
||||
"EFFECT_SS_K_FIRE",
|
||||
"EFFECT_SS_SOLDER_SRCH_BALL",
|
||||
"EFFECT_SS_KAKERA",
|
||||
"EFFECT_SS_ICE_PIECE",
|
||||
"EFFECT_SS_EN_ICE",
|
||||
"EFFECT_SS_FIRE_TAIL",
|
||||
"EFFECT_SS_EN_FIRE",
|
||||
"EFFECT_SS_EXTRA",
|
||||
"EFFECT_SS_FCIRCLE",
|
||||
"EFFECT_SS_DEAD_DB",
|
||||
"EFFECT_SS_DEAD_DD",
|
||||
"EFFECT_SS_DEAD_DS",
|
||||
"EFFECT_SS_DEAD_SOUND",
|
||||
"EFFECT_SS_ICE_SMOKE",
|
||||
]
|
||||
|
||||
to_rename = []
|
||||
|
||||
|
||||
def get_regs_enum(short_name):
|
||||
upper_name = short_name.upper()
|
||||
return \
|
||||
"typedef enum {\n" + \
|
||||
indent + "/* 0x00 */ SS_" + upper_name + "_0,\n" + \
|
||||
indent + "/* 0x01 */ SS_" + upper_name + "_1,\n" + \
|
||||
indent + "/* 0x02 */ SS_" + upper_name + "_2,\n" + \
|
||||
indent + "/* 0x03 */ SS_" + upper_name + "_3,\n" + \
|
||||
indent + "/* 0x04 */ SS_" + upper_name + "_4,\n" + \
|
||||
indent + "/* 0x05 */ SS_" + upper_name + "_5,\n" + \
|
||||
indent + "/* 0x06 */ SS_" + upper_name + "_6,\n" + \
|
||||
indent + "/* 0x07 */ SS_" + upper_name + "_7,\n" + \
|
||||
indent + "/* 0x08 */ SS_" + upper_name + "_8,\n" + \
|
||||
indent + "/* 0x09 */ SS_" + upper_name + "_9,\n" + \
|
||||
indent + "/* 0x0A */ SS_" + upper_name + "_A,\n" + \
|
||||
indent + "/* 0x0B */ SS_" + upper_name + "_B,\n" + \
|
||||
indent + "/* 0x0C */ SS_" + upper_name + "_C,\n" + \
|
||||
"} " + "EffectSs" + short_name + "Regs;\n"
|
||||
|
||||
def bootstrap(ovl_path, ovl_text):
|
||||
path_split = ovl_path.split(os.path.sep)
|
||||
z_name = path_split[-1][:-2]
|
||||
ovl_name = path_split[-2]
|
||||
short_name = ovl_name[14:]
|
||||
init_vars_name = ovl_name[4:] + "_InitVars"
|
||||
|
||||
top_comment = "/*\n * File: " + z_name + ".c" \
|
||||
"\n * Overlay: " + ovl_name + "\n * Description:\n */\n"
|
||||
header_include = "#include \"" + z_name + ".h\"\n"
|
||||
regs_enum = get_regs_enum(short_name)
|
||||
|
||||
with open(os.path.join(data_dir, z_name + ".data.s")) as f:
|
||||
data_text = f.read()
|
||||
|
||||
pattern = re.compile("glabel " + init_vars_name +
|
||||
"\n.word 0x........\n\.word func_........\n")
|
||||
init_data = pattern.search(data_text)
|
||||
if init_data is None or len(init_data.regs) == 0:
|
||||
return ""
|
||||
init_data = data_text[init_data.regs[0][0]:init_data.regs[0][1]]
|
||||
|
||||
lines = init_data.split("\n")
|
||||
|
||||
effect_id = int(lines[1][6:], 16)
|
||||
init_func = lines[2][6:]
|
||||
|
||||
ovl_shortened = ovl_name.replace("ovl", "").replace("_", "")
|
||||
init_func_name = ovl_shortened + "_Init"
|
||||
|
||||
ovl_text = ovl_text.replace(init_func, init_func_name)
|
||||
to_rename.append((init_func, init_func_name))
|
||||
|
||||
effect_id_name = effect_enum[effect_id]
|
||||
|
||||
struct_text = "/*\nEffectSsInit " + init_vars_name + \
|
||||
" = {\n" + indent + effect_id_name + \
|
||||
",\n" + indent + init_func_name + ",\n};\n*/"
|
||||
|
||||
decs = "u32 " + init_func_name + \
|
||||
"(PlayState* play, u32 index, EffectSs* this, void* initParamsx);\n"
|
||||
decs += "void " + \
|
||||
init_func_name[:-4] + \
|
||||
"Draw(PlayState* play, u32 index, EffectSs* this);\n"
|
||||
decs += "void " + \
|
||||
init_func_name[:-4] + \
|
||||
"Update(PlayState* play, u32 index, EffectSs* this);\n"
|
||||
|
||||
insert_pos = ovl_text.find("global.h>\n")
|
||||
|
||||
return top_comment + "\n" + header_include + "\n" + regs_enum + "\n" + decs + "\n" + struct_text + "\n" + ovl_text[insert_pos + 10:]
|
||||
|
||||
|
||||
def get_header(header_path):
|
||||
path_split = header_path.split(os.path.sep)
|
||||
ovl_name = path_split[-2]
|
||||
short_name = ovl_name[14:]
|
||||
init_vars_name = "".join(ovl_name[4:].split("_")) + "InitParams"
|
||||
|
||||
ifndef = "#ifndef _Z_EFF_SS_" + short_name.upper() + "_H_\n" + \
|
||||
"#define _Z_EFF_SS_" + short_name.upper() + "_H_\n\n"
|
||||
|
||||
includes = "#include <ultra64.h>\n#include <global.h>\n\n"
|
||||
|
||||
struct = "typedef struct {\n" + \
|
||||
indent + "/* 0x00 */ Vec3f pos;\n" + \
|
||||
indent + "/* 0x0C */ Vec3f velocity;\n" + \
|
||||
indent + "/* 0x18 */ Vec3f accel;\n" + \
|
||||
"} " + init_vars_name + "; // size = 0x\n\n#endif\n"
|
||||
|
||||
return ifndef + includes + struct
|
||||
|
||||
def rename():
|
||||
# Filenames first
|
||||
for root, dirs, files in os.walk(root_dir):
|
||||
for file in files:
|
||||
for elem in to_rename:
|
||||
if elem[0] in file:
|
||||
new_file = file.replace(elem[0], elem[1])
|
||||
file_path = os.path.join(root, file)
|
||||
new_file_path = os.path.join(root, new_file)
|
||||
os.rename(file_path, new_file_path)
|
||||
|
||||
# File contents
|
||||
for root, dirs, files in os.walk(root_dir):
|
||||
for file in files:
|
||||
if file.endswith(".c") or file.endswith(".s"):
|
||||
file_path = os.path.join(root, file)
|
||||
with open(file_path) as f:
|
||||
file_text = f.read()
|
||||
new_file_text = file_text
|
||||
for elem in to_rename:
|
||||
# if "func_" in elem[0]:
|
||||
# new_file_text = new_file_text.replace("glabel " + elem[0], elem[1] + ":")
|
||||
new_file_text = new_file_text.replace(elem[0], elem[1])
|
||||
if new_file_text != file_text:
|
||||
with open(file_path, "w", newline="\n") as f:
|
||||
f.write(new_file_text)
|
||||
|
||||
def main():
|
||||
for root, dirs, files in os.walk(src_dir):
|
||||
for file in files:
|
||||
if file.endswith(".c"):
|
||||
file_path = os.path.join(root, file)
|
||||
with open(file_path) as f:
|
||||
file_text = f.read()
|
||||
brace_count = file_text.count("{")
|
||||
if brace_count == 0:
|
||||
if "dead" in file_path:
|
||||
dog = 5
|
||||
header_path = file_path[:-1] + "h"
|
||||
c_text = bootstrap(file_path, file_text)
|
||||
header_text = get_header(header_path)
|
||||
with open(file_path, "w", newline="\n") as f:
|
||||
f.write(c_text)
|
||||
with open(header_path, "w", newline="\n") as f:
|
||||
f.write(header_text)
|
||||
rename()
|
||||
|
||||
main()
|
|
@ -1,114 +0,0 @@
|
|||
#!/usr/bin/python3
|
||||
|
||||
import re
|
||||
import os
|
||||
from disassemble import get_ovl_dir, get_z_name
|
||||
|
||||
script_dir = os.path.dirname(os.path.realpath(__file__))
|
||||
root_dir = script_dir + "/../"
|
||||
src_dir = root_dir + "src/overlays/"
|
||||
asm_dir = root_dir + "asm/non_matchings/overlays/"
|
||||
|
||||
|
||||
def get_overlays_to_bootstrap():
|
||||
non_decomped_ovls = []
|
||||
|
||||
# traverse root directory, and list directories as dirs and files as files
|
||||
for root, dirs, files in os.walk(asm_dir):
|
||||
for ovl_name in dirs:
|
||||
if ovl_name.startswith("ovl_"):
|
||||
non_decomped_ovls.append(ovl_name)
|
||||
|
||||
for root, dirs, files in os.walk(src_dir):
|
||||
for ovl_name in dirs:
|
||||
if ovl_name in non_decomped_ovls:
|
||||
non_decomped_ovls.remove(ovl_name)
|
||||
|
||||
return non_decomped_ovls
|
||||
|
||||
|
||||
def create_source_dir(overlay):
|
||||
overlay_dir = get_ovl_dir(overlay)
|
||||
full_dir = src_dir + overlay_dir
|
||||
os.mkdir(full_dir)
|
||||
c_name = get_z_name(overlay) + ".c"
|
||||
s_name = get_z_name(overlay) + ".s"
|
||||
|
||||
with open(full_dir + c_name, "w", newline="\n") as c_file:
|
||||
pragma_line = "#pragma GLOBAL_ASM(\"asm/non_matchings/overlays/" + get_ovl_dir(overlay) + s_name + "\")\n"
|
||||
c_file.write("#include <ultra64.h>\n#include <global.h>\n\n")
|
||||
c_file.write(pragma_line)
|
||||
|
||||
with open(full_dir + "overlay.cfg", "w", newline="\n") as cfg_file:
|
||||
cfg_file.write(overlay + "\n" + c_name)
|
||||
|
||||
|
||||
def strip_header_from_s(overlay):
|
||||
s_file_path = asm_dir + get_ovl_dir(overlay) + get_z_name(overlay) + ".s"
|
||||
beginning_line = -1
|
||||
with open(s_file_path, "r") as s_file:
|
||||
s_lines = s_file.readlines()
|
||||
|
||||
for i in range(len(s_lines)):
|
||||
if s_lines[i].startswith("glabel") or s_lines[i].startswith("func_"):
|
||||
beginning_line = i
|
||||
break
|
||||
|
||||
if beginning_line > -1:
|
||||
if beginning_line > 10:
|
||||
for i in range(0, beginning_line):
|
||||
if s_lines[i].startswith("/*"):
|
||||
func_name = s_lines[i].split(" ")[2]
|
||||
func_line = "glabel func_" + func_name + "\n"
|
||||
s_lines.insert(i, func_line)
|
||||
beginning_line = i
|
||||
|
||||
for i in range(len(s_lines)):
|
||||
if s_lines[i].startswith("func"):
|
||||
s_lines[i] = "glabel " + s_lines[i]
|
||||
s_lines[i] = s_lines[i].replace(":", "")
|
||||
|
||||
with open(s_file_path, "w", newline="\n") as s_file:
|
||||
s_file.writelines(s_lines[beginning_line:])
|
||||
|
||||
|
||||
def manage_overlays_mk(overlay):
|
||||
with open(root_dir + "overlays.mk", "a", newline="\n") as overlays_file:
|
||||
overlays_file.write(" src/overlays/" + get_ovl_dir(overlay) + " \\\n")
|
||||
|
||||
with open(root_dir + "overlays_asm.mk", "r") as overlays_asm_file:
|
||||
lines = overlays_asm_file.readlines()
|
||||
to_remove = " asm/non_matchings/overlays/" + get_ovl_dir(overlay)[:-1] + " \\\n"
|
||||
lines.remove(to_remove)
|
||||
|
||||
with open(root_dir + "overlays_asm.mk", "w", newline="\n") as overlays_asm_file:
|
||||
overlays_asm_file.writelines(lines)
|
||||
|
||||
|
||||
def manage_spec(overlay):
|
||||
with open(root_dir + "spec", "r") as spec_file:
|
||||
spec_text = spec_file.read()
|
||||
spec_text = spec_text.replace("asm/non_matchings/overlays/" + get_ovl_dir(overlay), "src/overlays/"
|
||||
+ get_ovl_dir(overlay))
|
||||
|
||||
with open(root_dir + "spec", "w", newline="\n") as spec_file:
|
||||
spec_file.write(spec_text)
|
||||
|
||||
|
||||
def main():
|
||||
num = 100
|
||||
i = 0
|
||||
overlays = get_overlays_to_bootstrap()
|
||||
|
||||
for overlay in overlays:
|
||||
print("Setting up " + overlay)
|
||||
create_source_dir(overlay)
|
||||
strip_header_from_s(overlay)
|
||||
#manage_overlays_mk(overlay)
|
||||
#manage_spec(overlay)
|
||||
i += 1
|
||||
if i >= num:
|
||||
break
|
||||
|
||||
|
||||
main()
|
|
@ -1,71 +0,0 @@
|
|||
#!/usr/bin/python3
|
||||
|
||||
import os
|
||||
import sys
|
||||
import re
|
||||
from disassemble import get_z_name
|
||||
|
||||
script_dir = os.path.dirname(os.path.realpath(__file__))
|
||||
root_dir = script_dir + "/../"
|
||||
asm_dir = root_dir + "asm/non_matchings/overlays/actors"
|
||||
src_dir = root_dir + "src/overlays/actors"
|
||||
include_dir = root_dir + "include"
|
||||
indent = " "
|
||||
|
||||
includes = "#include <ultra64.h>\n#include <global.h>\n\n"
|
||||
|
||||
|
||||
def remove_struct(root, filename):
|
||||
with open(os.path.join(root, filename)) as f:
|
||||
c_text = f.read()
|
||||
|
||||
struct_start = c_text.find("typedef")
|
||||
struct_end = c_text.find("#define")
|
||||
|
||||
struct = c_text[struct_start:struct_end]
|
||||
|
||||
newfile_text = "#include \"" + filename[:-2] + ".h\"" + "\n\n" + c_text[struct_end:]
|
||||
with open(os.path.join(root, filename), "w", newline="\n") as f:
|
||||
f.write(newfile_text)
|
||||
return struct
|
||||
|
||||
|
||||
def handle_file(root, filename):
|
||||
guard_name = "_" + filename[:-2].upper() + "_H_"
|
||||
top_guard = "#ifndef " + guard_name + "\n#define " + guard_name + "\n\n"
|
||||
header_text = top_guard
|
||||
header_text += includes
|
||||
|
||||
struct = remove_struct(root, filename)
|
||||
header_text += struct
|
||||
|
||||
u_split = filename[:-2].split("_")
|
||||
init_vars_name = ""
|
||||
for part in u_split[1:]:
|
||||
init_vars_name += part[0].upper()
|
||||
if len(part) > 1:
|
||||
init_vars_name += part[1:]
|
||||
init_vars_name += "_"
|
||||
init_vars_name += "InitVars"
|
||||
|
||||
header_text += "extern ActorInit " + init_vars_name + ";\n\n"
|
||||
|
||||
header_text += "#endif\n"
|
||||
|
||||
with open(os.path.join(root, filename[:-2] + ".h"), "w", newline="\n") as f:
|
||||
f.write(header_text)
|
||||
|
||||
|
||||
def main():
|
||||
for root, dirs, files in os.walk(src_dir):
|
||||
for filename in files:
|
||||
if filename.endswith(".c"):
|
||||
file_path = os.path.join(root, filename)
|
||||
with open(file_path) as f:
|
||||
file_text = f.read()
|
||||
brace_count = file_text.count("{")
|
||||
if brace_count == 2:
|
||||
handle_file(root, filename)
|
||||
dog = 5
|
||||
|
||||
main()
|
|
@ -1,136 +0,0 @@
|
|||
#!/usr/bin/python3
|
||||
|
||||
import os
|
||||
import re
|
||||
import shutil
|
||||
import subprocess
|
||||
|
||||
atom_path = "/mnt/c/Users/Ethan/Documents/GitHub/MasterOcarina/Atom/bin/Release/netcoreapp3.0"
|
||||
atom_cmd = "Atom df oot DBGMQ baserom.z64 --mips-to-c -f"
|
||||
script_dir = os.path.dirname(os.path.realpath(__file__))
|
||||
|
||||
|
||||
def load_symbols():
|
||||
ret = {}
|
||||
with open(script_dir + "/overlayhelpers/batchdisasm/symbols.txt") as f:
|
||||
symbol_text = f.readlines()
|
||||
for line in symbol_text:
|
||||
if len(line.strip()) > 0:
|
||||
line_split = line.split(" ")
|
||||
ret[line_split[0]] = line_split[1]
|
||||
return ret
|
||||
|
||||
|
||||
symbols = load_symbols()
|
||||
|
||||
|
||||
def get_overlays_to_disassemble():
|
||||
all_overlays = {}
|
||||
|
||||
# traverse root directory, and list directories as dirs and files as files
|
||||
for root, dirs, files in os.walk("baserom"):
|
||||
for file in files:
|
||||
if file.startswith("ovl_"):
|
||||
all_overlays[file] = os.path.getsize(os.path.join(root, file))
|
||||
|
||||
non_disassembled_ovls = all_overlays.copy()
|
||||
|
||||
for root, dirs, files in os.walk("asm/overlays"):
|
||||
for ovl_name in dirs:
|
||||
if ovl_name in non_disassembled_ovls:
|
||||
non_disassembled_ovls.pop(ovl_name)
|
||||
|
||||
for root, dirs, files in os.walk("src/overlays"):
|
||||
for ovl_name in dirs:
|
||||
if ovl_name in non_disassembled_ovls:
|
||||
non_disassembled_ovls.pop(ovl_name)
|
||||
|
||||
print("Found " + str(len(non_disassembled_ovls)) + " non-disassembled overlays out of " + str(len(all_overlays))
|
||||
+ " total")
|
||||
|
||||
return {k: v for k, v in sorted(non_disassembled_ovls.items(), key=lambda item: item[1])}
|
||||
|
||||
|
||||
def disassemble(overlay):
|
||||
args = atom_cmd.split(" ")
|
||||
args.append(overlay)
|
||||
# subprocess.run(args, cwd=atom_path, shell=True)
|
||||
|
||||
with open(atom_path + "/O/DBGMQ/" + overlay + ".txt") as f:
|
||||
return f.read()
|
||||
|
||||
|
||||
def fix_symbols(assembly):
|
||||
for symbol in symbols:
|
||||
assembly = assembly.replace(symbol, symbols[symbol])
|
||||
return assembly
|
||||
|
||||
|
||||
def get_ovl_dir(overlay):
|
||||
actors_overrides = ['ovl_player_actor']
|
||||
|
||||
ovl_part = "/" + overlay + "/"
|
||||
category = "actors"
|
||||
|
||||
if overlay.startswith("ovl_Effect"):
|
||||
category = "effects"
|
||||
|
||||
if overlay[4:5].islower():
|
||||
category = "gamestates"
|
||||
|
||||
if 'data' in overlay:
|
||||
category = "data"
|
||||
|
||||
if overlay in actors_overrides:
|
||||
category = "actors"
|
||||
|
||||
return category + ovl_part
|
||||
|
||||
|
||||
def create_asm_dir(overlay, assembly):
|
||||
asm_dir = "asm/non_matchings/overlays/" + get_ovl_dir(overlay)
|
||||
shutil.rmtree(asm_dir)
|
||||
os.mkdir(asm_dir)
|
||||
with open(asm_dir + get_z_name(overlay) + ".s", "w", newline="\n") as f:
|
||||
f.write(assembly)
|
||||
|
||||
|
||||
def get_z_name(overlay):
|
||||
# Annoying edge case
|
||||
if overlay == 'ovl_Effect_Ss_Solder_Srch_Ball':
|
||||
return 'z_eff_ss_solder_srch_ball'
|
||||
if overlay == "ovl_player_actor":
|
||||
return "z_player"
|
||||
|
||||
ret = overlay.lower()
|
||||
ret = "z_" + ret[4:]
|
||||
return ret
|
||||
|
||||
|
||||
def patch_spec(overlay):
|
||||
with open("spec", "r+", newline="\n") as f:
|
||||
spec = f.read()
|
||||
spec = re.sub("build/baserom/" + overlay + ".o",
|
||||
"build/asm/overlays/" + get_ovl_dir(overlay) + get_z_name(overlay) + ".o",
|
||||
spec)
|
||||
f.seek(0)
|
||||
f.write(spec)
|
||||
f.truncate()
|
||||
|
||||
|
||||
def patch_overlays_asm_mk(overlay):
|
||||
with open("overlays_asm.mk", "a", newline="\n") as f:
|
||||
f.write(" asm/overlays/" + get_ovl_dir(overlay)[:-1] + " \\\n")
|
||||
|
||||
|
||||
def main():
|
||||
print("Beginning disassembly in the order of filesize, ascending")
|
||||
overlays = get_overlays_to_disassemble()
|
||||
|
||||
for overlay in overlays:
|
||||
print("\t" + overlay)
|
||||
assembly = disassemble(overlay)
|
||||
assembly = fix_symbols(assembly)
|
||||
create_asm_dir(overlay, assembly)
|
||||
patch_spec(overlay)
|
||||
patch_overlays_asm_mk(overlay)
|
|
@ -1,53 +0,0 @@
|
|||
#!/usr/bin/python3
|
||||
|
||||
import os
|
||||
import sys
|
||||
import re
|
||||
from disassemble import get_z_name
|
||||
|
||||
script_dir = os.path.dirname(os.path.realpath(__file__))
|
||||
root_dir = script_dir + "/../"
|
||||
src_dir = root_dir + "src/overlays/"
|
||||
asm_dir = root_dir + "asm/non_matchings/overlays/"
|
||||
|
||||
|
||||
def handle_actor_line(match):
|
||||
match = match.group()
|
||||
base_portion = match[23:-4]
|
||||
base_portion_split = base_portion.split("/")
|
||||
if len(base_portion_split) < 3:
|
||||
return match
|
||||
|
||||
ret = match
|
||||
base_name = "build/data/overlays/" + base_portion_split[1] + "/" + base_portion_split[3]
|
||||
data_path = base_name + ".data.o"
|
||||
rodata_path = base_name + ".rodata.o"
|
||||
bss_path = base_name + ".bss.o"
|
||||
reloc_path = base_name + ".reloc.o"
|
||||
|
||||
if os.path.exists(root_dir + data_path):
|
||||
ret += " include \"" + data_path + "\"\n"
|
||||
|
||||
if os.path.exists(root_dir + rodata_path):
|
||||
ret += " include \"" + rodata_path + "\"\n"
|
||||
|
||||
if os.path.exists(root_dir + bss_path):
|
||||
ret += " include \"" + bss_path + "\"\n"
|
||||
|
||||
if os.path.exists(root_dir + reloc_path):
|
||||
ret += " include \"" + reloc_path + "\"\n"
|
||||
|
||||
return ret
|
||||
|
||||
|
||||
def main():
|
||||
with open(root_dir + "spec") as spec_file:
|
||||
spec_text = spec_file.read()
|
||||
|
||||
spec_text_replaced = re.sub(".*ovl_.*\.o.*\n", handle_actor_line, spec_text)
|
||||
|
||||
with open(root_dir + "spec", "w", newline="\n") as spec_file:
|
||||
spec_file.write(spec_text_replaced)
|
||||
|
||||
|
||||
main()
|
|
@ -1,86 +0,0 @@
|
|||
#!/usr/bin/python3
|
||||
|
||||
import os
|
||||
import sys
|
||||
import re
|
||||
from disassemble import get_z_name
|
||||
|
||||
script_dir = os.path.dirname(os.path.realpath(__file__))
|
||||
root_dir = script_dir + "/../"
|
||||
src_dir = root_dir + "src/overlays/"
|
||||
asm_dir = root_dir + "asm/non_matchings/overlays/"
|
||||
|
||||
|
||||
def remove_empty_lines_after_glabel(file_text):
|
||||
file_lines = file_text.splitlines()
|
||||
last_glabel = False
|
||||
to_remove = []
|
||||
for i, line in enumerate(file_lines):
|
||||
if "glabel" in line:
|
||||
last_glabel = True
|
||||
continue
|
||||
if last_glabel and not line.strip():
|
||||
to_remove.append(i)
|
||||
last_glabel = False
|
||||
if len(to_remove) > 0:
|
||||
for line_num in reversed(to_remove):
|
||||
del file_lines[line_num]
|
||||
file_text = "\n".join(file_lines)
|
||||
return file_text
|
||||
|
||||
def remove_balign_after_float(file_text):
|
||||
file_lines = file_text.splitlines()
|
||||
last_float = False
|
||||
to_remove = []
|
||||
for i, line in enumerate(file_lines):
|
||||
if ".float" in line:
|
||||
last_float = True
|
||||
continue
|
||||
if last_float and line == " .balign 4":
|
||||
to_remove.append(i)
|
||||
last_float = False
|
||||
if len(to_remove) > 0:
|
||||
for line_num in reversed(to_remove):
|
||||
del file_lines[line_num]
|
||||
file_text = "\n".join(file_lines)
|
||||
return file_text
|
||||
|
||||
|
||||
def format_file(file_path):
|
||||
with open(file_path) as f:
|
||||
orig_file_text = f.read()
|
||||
|
||||
file_text = orig_file_text
|
||||
|
||||
# Condense 2+ empty lines to 1
|
||||
file_text = file_text.replace("\n\n\n+", "\n\n")
|
||||
|
||||
# Remove empty lines after section declarations
|
||||
file_text = file_text.replace(".rdata\n\n", ".rdata\n")
|
||||
file_text = file_text.replace(".late_rodata\n\n", ".late_rodata\n")
|
||||
file_text = file_text.replace(".text\n\n", ".text\n")
|
||||
|
||||
# Remove dumb empty lines after glabel
|
||||
file_text = remove_empty_lines_after_glabel(file_text)
|
||||
|
||||
# Remove dumb balign 4 lines after float
|
||||
file_text = remove_balign_after_float(file_text)
|
||||
|
||||
# Make sure there's only one empty line at the end
|
||||
file_text = file_text.rstrip("\n") + "\n"
|
||||
|
||||
if file_text != orig_file_text:
|
||||
with open(file_path, "w", newline="\n") as f:
|
||||
f.write(file_text)
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def main():
|
||||
for root, dirs, files in os.walk(asm_dir):
|
||||
for f in files:
|
||||
if f.endswith(".s"):
|
||||
format_file(os.path.join(root, f))
|
||||
|
||||
|
||||
main()
|
|
@ -1,203 +0,0 @@
|
|||
#!/usr/bin/python3
|
||||
|
||||
import os
|
||||
#import pprint
|
||||
import re
|
||||
import argparse
|
||||
import math
|
||||
|
||||
script_dir = os.path.dirname(os.path.realpath(__file__))
|
||||
root_dir = script_dir + "/../"
|
||||
asm_dir = root_dir + "asm/non_matchings/overlays/actors"
|
||||
build_dir = root_dir + "build/src/overlays/actors"
|
||||
|
||||
|
||||
def get_num_instructions(f_path):
|
||||
with open(f_path) as f:
|
||||
f_lines = f.readlines()
|
||||
sum = 0
|
||||
for line in f_lines:
|
||||
if line.startswith("/* "):
|
||||
sum += 1
|
||||
return sum
|
||||
|
||||
|
||||
def count_non_matching():
|
||||
overlays = {}
|
||||
|
||||
for root, dirs, _ in os.walk(asm_dir):
|
||||
for actor_dir in dirs:
|
||||
total_size = 0
|
||||
max_size = -1
|
||||
ovl_path = os.path.join(root, actor_dir)
|
||||
num_files = 0
|
||||
|
||||
actor_funcs = {}
|
||||
|
||||
for f_name in os.listdir(ovl_path):
|
||||
file_path = os.path.join(ovl_path, f_name)
|
||||
file_size = get_num_instructions(file_path)
|
||||
|
||||
num_files += 1
|
||||
total_size += file_size
|
||||
if file_size > max_size:
|
||||
max_size = file_size
|
||||
actor_funcs[f_name] = file_size
|
||||
|
||||
overlays[actor_dir] = {
|
||||
"summary": (num_files, max_size, total_size,
|
||||
total_size / num_files),
|
||||
"funcs": actor_funcs
|
||||
}
|
||||
|
||||
return overlays
|
||||
|
||||
|
||||
pattern_function = re.compile("^[0-9a-fA-F]+ <(.+)>:")
|
||||
pattern_switchcase = re.compile("L[0-9a-fA-F]{8}")
|
||||
|
||||
def count_builded_funcs_and_instructions(f_path):
|
||||
f_lines = ""
|
||||
with open(f_path) as f:
|
||||
f_lines = f.readlines()
|
||||
|
||||
current = ""
|
||||
funcs = {}
|
||||
for line in f_lines:
|
||||
if line.strip() == "":
|
||||
continue
|
||||
match_function = pattern_function.match(line)
|
||||
if match_function:
|
||||
func_name = match_function.group(1)
|
||||
if pattern_switchcase.match(func_name):
|
||||
# this is not a real function tag.
|
||||
# probably a case from a switch
|
||||
# for example: <L80979A80>
|
||||
continue
|
||||
current = func_name
|
||||
funcs[current] = 0
|
||||
elif current != "":
|
||||
funcs[current] += 1
|
||||
return funcs
|
||||
|
||||
|
||||
def count_build():
|
||||
overlays = {}
|
||||
|
||||
for root, dirs, _ in os.walk(build_dir):
|
||||
for actor_dir in dirs:
|
||||
total_size = 0
|
||||
max_size = -1
|
||||
ovl_path = os.path.join(root, actor_dir)
|
||||
num_files = 0
|
||||
|
||||
actor_funcs = {}
|
||||
|
||||
for f_name in os.listdir(ovl_path):
|
||||
if not f_name.endswith(".s"):
|
||||
continue
|
||||
if f_name.endswith("_reloc.s"):
|
||||
continue
|
||||
|
||||
file_path = os.path.join(ovl_path, f_name)
|
||||
funcs = count_builded_funcs_and_instructions(file_path)
|
||||
|
||||
if len(funcs) > 0:
|
||||
num_files += len(funcs)
|
||||
# round up the file size to a multiple of four.
|
||||
total_size += math.ceil(sum(funcs.values())/4)*4
|
||||
max_size = max(max_size, max(funcs.values()))
|
||||
# merges both dictionaries
|
||||
actor_funcs = {**actor_funcs, **funcs}
|
||||
|
||||
overlays[actor_dir] = {
|
||||
"summary": (num_files, max_size, total_size,
|
||||
total_size / num_files),
|
||||
"funcs": actor_funcs
|
||||
}
|
||||
|
||||
return overlays
|
||||
|
||||
|
||||
def get_list_from_file(filename):
|
||||
actor_list = []
|
||||
if filename is not None:
|
||||
with open(filename) as f:
|
||||
actor_list = list(map(lambda x: x.strip().split(",")[0], f.readlines()))
|
||||
return actor_list
|
||||
|
||||
|
||||
def print_csv(overlays, ignored, include_only):
|
||||
sorted_actors = [(k, v["summary"]) for k, v in overlays.items()]
|
||||
sorted_actors.sort()
|
||||
|
||||
row = "{},{},{},{},{}"
|
||||
print(row.format("Overlay", "Num files", "Max size", "Total size", "Average size"))
|
||||
|
||||
for actor_data in sorted_actors:
|
||||
name = actor_data[0]
|
||||
other = actor_data[1]
|
||||
if name in ignored:
|
||||
continue
|
||||
if include_only and name not in include_only:
|
||||
continue
|
||||
print(row.format(name, *other))
|
||||
|
||||
|
||||
def print_function_lines(overlays, ignored, include_only):
|
||||
sorted_actors = []
|
||||
for k, v in overlays.items():
|
||||
func_data = []
|
||||
for func_name, lines in v["funcs"].items():
|
||||
func_data.append((func_name, lines))
|
||||
#func_data.sort(key=lambda x: x[1], reverse=True)
|
||||
sorted_actors.append((k, func_data))
|
||||
sorted_actors.sort()
|
||||
|
||||
row = "{},{},{}"
|
||||
print(row.format("actor_name", "function_name", "lines"))
|
||||
|
||||
for actor_data in sorted_actors:
|
||||
name = actor_data[0]
|
||||
func_data = actor_data[1]
|
||||
if name in ignored:
|
||||
continue
|
||||
if include_only and name not in include_only:
|
||||
continue
|
||||
for func_name, lines in func_data:
|
||||
print(row.format(name, func_name, lines))
|
||||
|
||||
|
||||
def main():
|
||||
description = "Collects actor's functions sizes, and print them in csv format."
|
||||
|
||||
epilog = """\
|
||||
To make a .csv with the data, simply redirect the output. For example:
|
||||
./tools/get_actor_sizes.py > results.csv
|
||||
|
||||
Flags can be mixed to produce a customized result:
|
||||
./tools/get_actor_sizes.py --function-lines --non-matching > status.csv
|
||||
./tools/get_actor_sizes.py --non-matching --ignore pull_request.csv > non_matching.csv
|
||||
./tools/get_actor_sizes.py --non-matching --function-lines --include-only my_reserved.csv > my_status.csv
|
||||
"""
|
||||
parser = argparse.ArgumentParser(description=description, epilog=epilog, formatter_class=argparse.RawTextHelpFormatter)
|
||||
parser.add_argument("--non-matching", help="Collect data of the non-matching actors instead.", action="store_true")
|
||||
parser.add_argument("--function-lines", help="Prints the size of every function instead of a summary.", action="store_true")
|
||||
parser.add_argument("--ignore", help="Path to a file containing actor's names. The data of actors in this list will be ignored.")
|
||||
parser.add_argument("--include-only", help="Path to a file containing actor's names. Only data of actors in this list will be printed.")
|
||||
args = parser.parse_args()
|
||||
|
||||
if args.non_matching:
|
||||
overlays = count_non_matching()
|
||||
else:
|
||||
overlays = count_build()
|
||||
|
||||
ignored = get_list_from_file(args.ignore)
|
||||
include_only = get_list_from_file(args.include_only)
|
||||
|
||||
if args.function_lines:
|
||||
print_function_lines(overlays, ignored, include_only)
|
||||
else:
|
||||
print_csv(overlays, ignored, include_only)
|
||||
|
||||
main()
|
|
@ -1,296 +0,0 @@
|
|||
"""
|
||||
Given a code file name (excluding the file extension, e.g. z_view) this script
|
||||
will attempt to build rodata and late_rodata sections for all of its functions.
|
||||
|
||||
Supports overlays and other files as long as the rodata file is formatted
|
||||
correctly(see files in code for examples of properly formatted rodata sections)
|
||||
|
||||
This supports automatically commenting or deleting the rodata file from the
|
||||
spec and automatic deletion of the rodata file itself (only use if you are sure
|
||||
it will build afterwards)
|
||||
|
||||
Has trouble with rodata that goes unused, and .incbin placement
|
||||
"""
|
||||
|
||||
import re
|
||||
import os
|
||||
from os import system, listdir, remove, walk
|
||||
from os.path import exists, isdir, sep
|
||||
|
||||
# FUNCTIONS -----------------------------------------------------------------
|
||||
|
||||
"""
|
||||
Extracts rodata symbols from asm
|
||||
"""
|
||||
def asm_syms(asm):
|
||||
split = re.split("jtbl_|D_",asm)
|
||||
return [s.partition(")")[0] for s in split[1:len(split)]]
|
||||
|
||||
"""
|
||||
Extracts rodata symbols from rodata
|
||||
"""
|
||||
def rodata_syms(rodata):
|
||||
split = re.split("glabel jtbl_|glabel D_",rodata)
|
||||
return [s.partition("\n")[0] for s in split[1:len(split)]]
|
||||
|
||||
"""
|
||||
Extracts the symbol from a single rodata block
|
||||
"""
|
||||
def rodata_sym(rodata_block):
|
||||
return (re.split("glabel jtbl_|glabel D_",rodata_block)[1]).split("\n")[0]
|
||||
|
||||
"""
|
||||
Splits rodata into blocks
|
||||
"""
|
||||
def rodata_blocks(rodata):
|
||||
split = rodata.split("glabel")
|
||||
return ["glabel" + b for b in split[1:len(split)]]
|
||||
|
||||
"""
|
||||
Gets the block size
|
||||
"""
|
||||
def rodata_block_size(rodata):
|
||||
split = rodata.split(" .")
|
||||
elements = split[1:len(split)]
|
||||
size = 0
|
||||
for e in elements:
|
||||
element_type = e.split(" ")[0]
|
||||
if element_type == "double":
|
||||
size += 8
|
||||
if element_type == "float":
|
||||
size += 4
|
||||
if element_type == "word":
|
||||
size += 4
|
||||
if element_type == "incbin":
|
||||
size += int(e.rpartition(", ")[2].split("\n")[0],16)
|
||||
if element_type == "ascii":
|
||||
size += len(e.split("\"")[1].split("\"")[0])
|
||||
if element_type == "asciz":
|
||||
size += len(e.split("\"")[1].split("\"")[0])
|
||||
if element_type == "balign":
|
||||
size += size % int(e.split(" ")[1])
|
||||
return size
|
||||
|
||||
"""
|
||||
Gets the text size
|
||||
"""
|
||||
def text_size(asm):
|
||||
instructions = [l for l in asm.split("\n") if l.startswith("/* ")]
|
||||
return 4*(len(instructions)-1)
|
||||
|
||||
"""
|
||||
Gets the rodata-to-text ratio
|
||||
"""
|
||||
def late_rodata_ratio(asm,late_rodata_blocks):
|
||||
total_rodata_size = 0
|
||||
for b in late_rodata_blocks:
|
||||
total_rodata_size += rodata_block_size(b)
|
||||
return total_rodata_size/text_size(asm)
|
||||
|
||||
"""
|
||||
Accepts a single block of rodata and extracts the type
|
||||
"""
|
||||
def rodata_type(rodata_block):
|
||||
first_split = re.split("\s+\.", rodata_block)
|
||||
return first_split[1].split(" ")[0]
|
||||
|
||||
"""
|
||||
Checks if a block should go in .rdata or .late_rodata
|
||||
"""
|
||||
def is_rodata(r):
|
||||
return (rodata_type(r)=="asciz" or rodata_type=="ascii")
|
||||
|
||||
"""
|
||||
For given asm and rodata files, build a rodata section for the asm file
|
||||
"""
|
||||
def build_rodata(asm, rodata):
|
||||
contained_syms = [s for s in asm_syms(asm) if s in rodata_syms(rodata)]
|
||||
contained_blocks = [b for b in rodata_blocks(rodata) if rodata_sym(b) in contained_syms]
|
||||
# TODO include arrays in rodata_list
|
||||
rodata_list = [r for r in contained_blocks if is_rodata(r)]
|
||||
return_str = ""
|
||||
if (len(rodata_list)!=0):
|
||||
return_str += ".rdata\n"
|
||||
for r in rodata_list:
|
||||
return_str += r
|
||||
late_rodata_list = [r for r in contained_blocks if r not in rodata_list]
|
||||
if (len(late_rodata_list)!=0):
|
||||
if late_rodata_ratio(asm,late_rodata_list) > (1/3):
|
||||
top_sym = rodata_sym(late_rodata_list[0])
|
||||
if top_sym.endswith("0") or top_sym.endswith("8"):
|
||||
return_str += ".late_rodata\n.late_rodata_alignment 8\n"
|
||||
elif top_sym.endswith("4") or top_sym.endswith("C"):
|
||||
return_str += ".late_rodata\n.late_rodata_alignment 4\n"
|
||||
else:
|
||||
return_str += ".late_rodata\n"
|
||||
for r in late_rodata_list:
|
||||
return_str += r
|
||||
return None if return_str=="" else return_str + ("" if return_str.endswith("\n\n") else "\n") + ".text\n"
|
||||
|
||||
"""
|
||||
Gets all file paths contained in a given folder, does not enter subfolders
|
||||
"""
|
||||
def get_file_paths(folder_path):
|
||||
return next(walk(folder_path),(None,None,[]))[2]
|
||||
|
||||
"""
|
||||
Given a path, reads the asm .s file into a single string
|
||||
"""
|
||||
def file_read(path):
|
||||
with open(path, 'r', encoding="utf-8") as infile:
|
||||
return infile.read()
|
||||
|
||||
"""
|
||||
Writes the rodata section to the start of the file specified by path
|
||||
"""
|
||||
def rodata_write(path, section):
|
||||
with open(path, 'r+', encoding="utf-8", newline="\n") as outfile:
|
||||
original = outfile.read()
|
||||
outfile.seek(0,0)
|
||||
outfile.write(str(section) + original)
|
||||
|
||||
"""
|
||||
Comments out the line in spec associated with the given filenames
|
||||
"""
|
||||
def modify_spec(filenames, identifier, delete):
|
||||
lines = ""
|
||||
with open("spec", 'r+', encoding="utf-8", newline="\n") as spec:
|
||||
lines = spec.read().split("\n")
|
||||
changed = False
|
||||
files = filenames.split(",")
|
||||
for filename in files:
|
||||
eff_filename = filename.lower().replace("effect_", "eff_")
|
||||
if identifier == "code" and " include \"build/data/" + filename + ".rodata.o\"" in lines:
|
||||
e = lines.index(" include \"build/data/" + filename + ".rodata.o\"")
|
||||
if delete:
|
||||
del lines[e]
|
||||
else:
|
||||
lines[e] = " //include \"build/data/" + filename + ".rodata.o\""
|
||||
changed = True
|
||||
elif " include \"build/data/overlays/" + identifier + "/z_" + eff_filename + ".rodata.o\"" in lines:
|
||||
e = lines.index(" include \"build/data/overlays/" + identifier + "/z_" + eff_filename + ".rodata.o\"")
|
||||
if delete:
|
||||
del lines[e]
|
||||
else:
|
||||
lines[e] = " //include \"build/data/overlays/" + identifier + "/z_" + eff_filename + ".rodata.o\""
|
||||
changed = True
|
||||
if changed:
|
||||
modified = "\n".join(lines)
|
||||
with open("spec", 'w', encoding="utf-8", newline="\n") as spec:
|
||||
#spec.seek(0,0)
|
||||
spec.write(modified)
|
||||
|
||||
"""
|
||||
Processes each individual file
|
||||
asm\non_matchings\overlays\<identifier>
|
||||
data\overlays\<identifier>
|
||||
asm\non_matchings\code\
|
||||
data\code\
|
||||
"""
|
||||
def process_file(filename, identifier, delete_rodata):
|
||||
folder_path = "asm" + sep + "non_matchings" + sep + ("code" + sep if identifier=="code" else "overlays" + sep + identifier.lower() + sep + "ovl_") + filename + sep
|
||||
rodata_path = "data" + sep + (sep if identifier=="code" else "overlays" + sep + identifier.lower() + sep + "z_") + filename.lower() + ".rodata.s"
|
||||
if filename == "player":
|
||||
folder_path = "asm" + sep + "non_matchings" + sep + "overlays" + sep + "actors" + sep + "ovl_player_actor" + sep
|
||||
rodata_path = rodata_path.replace("effect_", "eff_")
|
||||
print("ASM at: " + folder_path)
|
||||
print("Data at: " + rodata_path)
|
||||
if not exists(folder_path):
|
||||
print("Aborting: ASM does not exist")
|
||||
return
|
||||
if not exists(rodata_path):
|
||||
print("Aborting: Data does not exist")
|
||||
return
|
||||
files = [folder_path + f for f in get_file_paths(folder_path)]
|
||||
for asm_file in files:
|
||||
asm = file_read(asm_file)
|
||||
print("Found asm file " + asm_file)
|
||||
if ".rdata" in asm:
|
||||
print("Skipping: it already has a rodata section")
|
||||
continue
|
||||
print("Processing asm file " + asm_file)
|
||||
section = build_rodata(asm, file_read(rodata_path))
|
||||
if section is not None:
|
||||
print("Writing asm file " + asm_file)
|
||||
rodata_write(asm_file, section)
|
||||
else: print("Skipping: no rodata to write")
|
||||
print("Built rodata sections for " + identifier + " file " + filename)
|
||||
if delete_rodata:
|
||||
remove(rodata_path)
|
||||
print("Deleted rodata at " + rodata_path)
|
||||
|
||||
"""
|
||||
Allows files to be provided as comma-separated filenames for batch migration
|
||||
"""
|
||||
def process_files(filenames, identifier, spechandle, delete_rodata):
|
||||
if "," in filenames:
|
||||
files = filenames.split(",")
|
||||
for f in files:
|
||||
process_file(f, identifier, delete_rodata)
|
||||
else:
|
||||
process_file(filenames, identifier, delete_rodata)
|
||||
if spechandle.lower() == "delete":
|
||||
modify_spec(filenames, identifier, True)
|
||||
print("Deleted rodata for files in spec")
|
||||
elif spechandle.lower() == "comment":
|
||||
result = modify_spec(filenames, identifier, False)
|
||||
if result:
|
||||
print("Commented out rodata for files in spec")
|
||||
|
||||
"""
|
||||
Asks what to do about spec and rodata, converts 'all' to comma-separated filenames
|
||||
"""
|
||||
def check_spec_rodata(filenames, identifier):
|
||||
spechandle = input("Delete, Comment or Leave spec? ")
|
||||
delete_rodata = input("Delete rodata file(s)? (Y/N) ")
|
||||
if filenames == "all" or "all|" in filenames:
|
||||
to_remove_list = []
|
||||
if "all|" in filenames:
|
||||
print("all| in filenames")
|
||||
to_remove_list = filenames.split("|")[1]
|
||||
basedir = "asm" + sep + "non_matchings" + sep + ("code" if identifier=="code" else "overlays" + sep + identifier.lower()) + sep
|
||||
folder_names = [name.replace("ovl_","") for name in listdir(basedir) if isdir(basedir + name) and name not in to_remove_list]
|
||||
filenames = ",".join(map(str, folder_names))
|
||||
print(filenames)
|
||||
process_files(filenames, identifier, spechandle, delete_rodata == "Y")
|
||||
|
||||
"""
|
||||
Main execution
|
||||
"""
|
||||
def run(show_help):
|
||||
if(show_help):
|
||||
print("""Usage: Enter 'Code' or 'Overlay' and follow the instructions.
|
||||
Batch migrate files by entering comma-separated filenames instead of a single filename.
|
||||
Migrate all files by entering 'all' for filenames. Exclude files from all with all| followed by comma-separated filenames Use at your own risk.
|
||||
Enter 'q' to the code or overlay question to quit.""")
|
||||
code_or_overlay = input("Code or Overlay? ")
|
||||
if(code_or_overlay == "q"):
|
||||
return
|
||||
if(code_or_overlay == "Code"):
|
||||
filename = input("Enter the code file name(s) (excluding .c) or all: ")
|
||||
check_spec_rodata(filename, "code")
|
||||
elif(code_or_overlay == "Overlay"):
|
||||
overlay_type = input("Actor, Effect or Gamestate? ")
|
||||
if(overlay_type == "Actor"):
|
||||
filename = input("Enter the actor name(s) (excluding ovl_ or z_, ex. obj_bombiwa) or all: ")
|
||||
check_spec_rodata(filename, "actors")
|
||||
elif(overlay_type == "Effect"):
|
||||
filename = input("Enter the effect name(s) (excluding ovl_ or z_, ex. effect_ss_bomb) or all: ")
|
||||
check_spec_rodata(filename, "effects")
|
||||
elif(overlay_type == "Gamestate"):
|
||||
filename = input("Enter the gamestate name(s) (excluding ovl_ or z_, ex. kaleido_scope) or all: ")
|
||||
check_spec_rodata(filename, "gamestates")
|
||||
run(True)
|
||||
|
||||
# PROGRAM -------------------------------------------------------------------
|
||||
|
||||
run(False)
|
||||
#bigs = ["Boss_Ganon", "Boss_Ganondrof","En_Wf", "Door_Warp1",]
|
||||
#ovls = ["En_Elf"]
|
||||
#effects = [x[0] for x in os.walk("src/overlays/effects")][1:]
|
||||
|
||||
#for i, ovl in enumerate(effects):
|
||||
# process_files(ovl.split("/")[-1][4:], "effects", "Delete", True)
|
||||
# command = "echo >> src/overlays/effects/ovl_" + effects[i] + "/z_" + effects[i].lower() + ".c"
|
||||
# os.system(command) # purpose of this is to "modify" each C file in order to prevent undefined symbol errors.
|
||||
# # the new line will be removed by format.sh
|
|
@ -1,84 +0,0 @@
|
|||
#!/usr/bin/python3
|
||||
|
||||
import os
|
||||
import sys
|
||||
import re
|
||||
from disassemble import get_z_name
|
||||
|
||||
script_dir = os.path.dirname(os.path.realpath(__file__))
|
||||
root_dir = script_dir + "/../"
|
||||
data_dir = root_dir + "data/overlays"
|
||||
asm_dir = root_dir + "asm/non_matchings/overlays"
|
||||
|
||||
|
||||
def rename(old_name, new_name):
|
||||
for root, dirs, files in os.walk(asm_dir):
|
||||
for file in files:
|
||||
file_path = os.path.join(root, file)
|
||||
with open(file_path) as f:
|
||||
file_text = f.read()
|
||||
new_file_text = file_text.replace(old_name, new_name)
|
||||
if file_text != new_file_text:
|
||||
with open(file_path, "w", newline="\n") as f:
|
||||
f.write(new_file_text)
|
||||
|
||||
|
||||
def rename_l(old_name, new_name):
|
||||
for root, dirs, files in os.walk(asm_dir):
|
||||
for file in files:
|
||||
file_path = os.path.join(root, file)
|
||||
with open(file_path) as f:
|
||||
file_text = f.read()
|
||||
new_file_text = file_text.replace(old_name + ":", "glabel " + new_name)
|
||||
new_file_text = new_file_text.replace(old_name, new_name)
|
||||
if file_text != new_file_text:
|
||||
with open(file_path, "w", newline="\n") as f:
|
||||
f.write(new_file_text)
|
||||
|
||||
|
||||
def handle_jtbl(match):
|
||||
match = match.group()
|
||||
split = match.replace(":", "").split(" ")
|
||||
lbl_name = split[0]
|
||||
new_lbl_name = "jtbl_" + lbl_name[2:]
|
||||
rename(lbl_name, new_lbl_name)
|
||||
ret = "glabel " + new_lbl_name + "\n.word .L"
|
||||
return ret
|
||||
|
||||
|
||||
def handle_data_line(match):
|
||||
match = match.group()
|
||||
ret = "glabel " + match[:-1] + "\n"
|
||||
return ret
|
||||
|
||||
|
||||
def handle_word_l(match):
|
||||
match = match.group()
|
||||
split = match.split(" ")
|
||||
lbl_name = split[1]
|
||||
new_lbl_name = split[1][1:]
|
||||
rename_l(lbl_name, new_lbl_name)
|
||||
ret = ".word " + new_lbl_name
|
||||
return ret
|
||||
|
||||
|
||||
def main():
|
||||
preamble = ".include \"macro.inc\"\n\n # assembler directives\n .set noat # allow manual use of $at\n .set noreorder # don't insert nops after branches\n .set gp=64 # allow use of 64-bit general purpose registers\n\n"
|
||||
|
||||
for root, dirs, files in os.walk(data_dir):
|
||||
for file in files:
|
||||
file_path = os.path.join(root, file)
|
||||
with open(file_path) as f:
|
||||
file_text = f.read()
|
||||
|
||||
file_text = preamble + file_text
|
||||
file_text = re.sub("D_.*: .word .L", handle_jtbl, file_text)
|
||||
file_text = re.sub("D_.*:", handle_data_line, file_text)
|
||||
file_text = re.sub(".word .L........", handle_word_l, file_text)
|
||||
file_text = re.sub("\n\n ", "\n ", file_text)
|
||||
|
||||
with open(file_path, "w", newline="\n") as f:
|
||||
f.write(file_text)
|
||||
|
||||
|
||||
main()
|
|
@ -1,55 +0,0 @@
|
|||
import os
|
||||
import sys
|
||||
|
||||
specFile = open("spec", "r");
|
||||
specText = specFile.read();
|
||||
specFile.close()
|
||||
specLines = specText.split("\n");
|
||||
|
||||
# TODO: CLEAN THIS UP!
|
||||
for i in range(0, len(specLines)):
|
||||
line = specLines[i]
|
||||
if (line.startswith("INCLUDE_SEG_SCENE")):
|
||||
params = line.split("(")[1].split(")")[0].split(",")
|
||||
for j in range(0, len(params)):
|
||||
while (params[j].startswith(" ")):
|
||||
params[j] = params[j][1 : len(params[j])]
|
||||
|
||||
line = "beginseg\r\n";
|
||||
line += "\tname " + params[0] + "\r\n";
|
||||
line += "\tromalign 0x1000\r\n";
|
||||
line += "\tinclude " + params[1] + "\r\n";
|
||||
line += "\taddress SEGMENT_SCENE\r\n";
|
||||
line += "endseg\r\n";
|
||||
elif (line.startswith("INCLUDE_SEG_ROOM")):
|
||||
params = line.split("(")[1].split(")")[0].split(",")
|
||||
for j in range(0, len(params)):
|
||||
while (params[j].startswith(" ")):
|
||||
params[j] = params[j][1 : len(params[j])]
|
||||
|
||||
line = "beginseg\r\n";
|
||||
line += "\tname " + params[0] + "\r\n";
|
||||
line += "\tromalign 0x1000\r\n";
|
||||
line += "\tinclude " + params[1] + "\r\n";
|
||||
line += "\taddress SEGMENT_ROOM\r\n";
|
||||
line += "endseg\r\n";
|
||||
elif (line.startswith("INCLUDE_SEG_OBJECT")):
|
||||
params = line.split("(")[1].split(")")[0].split(",")
|
||||
for j in range(0, len(params)):
|
||||
while (params[j].startswith(" ")):
|
||||
params[j] = params[j][1 : len(params[j])]
|
||||
|
||||
line = "beginseg\r\n";
|
||||
line += "\tname " + params[0] + "\r\n";
|
||||
line += "\tromalign 0x1000\r\n";
|
||||
line += "\tinclude " + params[1] + "\r\n";
|
||||
line += "\taddress SEGMENT_OBJECT\r\n";
|
||||
line += "endseg\r\n";
|
||||
|
||||
|
||||
line += "\r\n";
|
||||
specLines[i] = line;
|
||||
|
||||
specOut = open("build/spec_preproc", "w");
|
||||
specOut.writelines(specLines);
|
||||
specOut.close();
|
|
@ -1,78 +0,0 @@
|
|||
#!/usr/bin/python3
|
||||
|
||||
import os
|
||||
import sys
|
||||
import re
|
||||
from disassemble import get_z_name
|
||||
|
||||
script_dir = os.path.dirname(os.path.realpath(__file__))
|
||||
root_dir = script_dir + "/../"
|
||||
src_dir = root_dir + "src/overlays/"
|
||||
asm_dir = root_dir + "asm/non_matchings/overlays/"
|
||||
|
||||
|
||||
def get_c_file_path(file):
|
||||
c_file = get_z_name(file) + ".c"
|
||||
for root, dirs, files in os.walk(src_dir):
|
||||
if c_file in files:
|
||||
return os.path.join(root, c_file)
|
||||
return None
|
||||
|
||||
|
||||
def handle_file(asm_root, asm_file, c_file_path):
|
||||
file_path = os.path.join(asm_root, asm_file)
|
||||
with open(file_path) as f:
|
||||
file_lines = f.readlines()
|
||||
|
||||
new_files = []
|
||||
num_rodata = 0
|
||||
for i, line in enumerate(file_lines):
|
||||
asm_basename = asm_file.split(".")[0]
|
||||
if line.startswith("glabel func"):
|
||||
new_files.append((i, line.split(" ")[1].strip() + ".s", "func"))
|
||||
elif line.startswith(".section .data"):
|
||||
new_files.append((i, asm_basename + ".data.s", "data"))
|
||||
elif line.startswith(".section .rodata"):
|
||||
type = "rodata"
|
||||
ext = ".rodata.s"
|
||||
if num_rodata > 0:
|
||||
type = "reloc"
|
||||
ext = ".reloc.s"
|
||||
num_rodata += 1
|
||||
|
||||
new_files.append((i, asm_basename + ext, type))
|
||||
elif line.startswith(".bss"):
|
||||
new_files.append((i, asm_basename + ".bss.s", "bss"))
|
||||
|
||||
if len(new_files) == 1:
|
||||
return
|
||||
|
||||
os.remove(file_path)
|
||||
for i, new_file in enumerate(new_files):
|
||||
if i < len(new_files) - 1:
|
||||
new_file_lines = file_lines[new_file[0]:new_files[i+1][0]]
|
||||
else:
|
||||
new_file_lines = file_lines[new_file[0]:]
|
||||
|
||||
with open(os.path.join(asm_root, new_file[1]), mode="w", newline="\n") as out_file:
|
||||
out_file.writelines(new_file_lines)
|
||||
|
||||
os.remove(c_file_path)
|
||||
|
||||
pragma_begin = "#pragma GLOBAL_ASM(\"" + asm_root.split("../")[1] + "/"
|
||||
pragma_end = "\")"
|
||||
with open(c_file_path, mode="w", newline="\n") as c_file:
|
||||
for new_file in new_files:
|
||||
c_file.write(pragma_begin + new_file[1] + pragma_end + "\n\n")
|
||||
|
||||
|
||||
def main():
|
||||
for root, dirs, files in os.walk(asm_dir):
|
||||
for file in files:
|
||||
if file.startswith("z_"):
|
||||
c_file_path = get_c_file_path(root.split("/")[-1])
|
||||
if c_file_path is not None:
|
||||
handle_file(root, file, c_file_path)
|
||||
|
||||
|
||||
main()
|
|
@ -1,213 +0,0 @@
|
|||
#!/usr/bin/python3
|
||||
import os
|
||||
import argparse
|
||||
|
||||
offsets = set()
|
||||
replacements = {}
|
||||
global_name = ''
|
||||
|
||||
name_fmt = 'g{0}{1}_{2}'
|
||||
spec_fmt = ' include "build/assets/objects/{0}/{0}.o"\n number 6\n'
|
||||
|
||||
dlist_xml = '<DList Name="{0}" Offset="0x{1}"/>'
|
||||
collision_xml = '<Collision Name="{0}" Offset="0x{1}"/>'
|
||||
animation_xml = '<Animation Name="{0}" Offset="0x{1}"/>'
|
||||
skeleton_xml = '<Skeleton Name="{0}" Type="{2}" LimbType="{3}" Offset="0x{1}"/>'
|
||||
unknown_xml = '<!-- <{2} Name="{0}" Offset="0x{1}"/> -->'
|
||||
|
||||
def set_globals(new_name):
|
||||
global offsets
|
||||
global global_name
|
||||
global replacements
|
||||
|
||||
offsets = set()
|
||||
replacements = {}
|
||||
global_name = new_name
|
||||
return 0
|
||||
|
||||
|
||||
def dlist_to_xml(var_name,offset):
|
||||
|
||||
return dlist_xml.format(var_name,offset.lstrip('0'))
|
||||
|
||||
def collision_to_xml(var_name,offset):
|
||||
|
||||
return collision_xml.format(var_name,offset.lstrip('0'))
|
||||
|
||||
def animation_to_xml(var_name,offset):
|
||||
|
||||
return animation_xml.format(var_name,offset.lstrip('0'))
|
||||
|
||||
def skeleton_to_xml(var_name,offset, type):
|
||||
skel_type = "Flex" if "Flex" in type else "Normal"
|
||||
limb_type = "Standard"
|
||||
|
||||
return skeleton_xml.format(var_name, offset.lstrip('0'), skel_type, limb_type)
|
||||
|
||||
def unknown_to_xml(var_name,offset, type):
|
||||
|
||||
return unknown_xml.format(var_name,offset.lstrip('0'),type)
|
||||
|
||||
def make_xml_line(offset, type):
|
||||
if 'Gfx' in type:
|
||||
var_name = name_fmt.format(global_name,'DL',offset)
|
||||
xml_line = dlist_to_xml(var_name, offset)
|
||||
elif 'Col' in type:
|
||||
var_name = name_fmt.format(global_name,'Col',offset)
|
||||
xml_line = collision_to_xml(var_name, offset)
|
||||
elif 'Animation' in type:
|
||||
var_name = name_fmt.format(global_name,'Anim',offset)
|
||||
xml_line = animation_to_xml(var_name, offset)
|
||||
elif 'Skeleton' in type:
|
||||
var_name = name_fmt.format(global_name,'Skel',offset)
|
||||
xml_line = skeleton_to_xml(var_name, offset, type)
|
||||
else:
|
||||
var_name = name_fmt.format(global_name,'Unknown',offset)
|
||||
xml_line = unknown_to_xml(var_name, offset, type)
|
||||
print('Unknown type at offset', offset)
|
||||
replacements['06'+offset] = var_name
|
||||
return xml_line
|
||||
|
||||
def extern_to_xml(line):
|
||||
global offsets
|
||||
|
||||
type = line.split()[1]
|
||||
sym = line.split()[2]
|
||||
offset = sym[4:10]
|
||||
if(offset in offsets):
|
||||
return ''
|
||||
else:
|
||||
offsets.add(offset)
|
||||
|
||||
xml_line = ' ' * 8
|
||||
xml_line += make_xml_line(offset, type)
|
||||
# make_replace(offset, type)
|
||||
|
||||
return xml_line + '\n'
|
||||
|
||||
def find_type(srcdata, i):
|
||||
j = i
|
||||
while(j >= 0 and ' = {' not in srcdata[j]):
|
||||
j -= 1
|
||||
if(j < 0):
|
||||
return 'UNKNOWN'
|
||||
else:
|
||||
return srcdata[j].split(' = {')[0].split()[-2]
|
||||
|
||||
def other_to_xml(srcdata, i):
|
||||
xml_data = ''
|
||||
line = srcdata[i]
|
||||
|
||||
index = line.find('0x060')
|
||||
while(index < len(line) and '0x060' in line[index:]):
|
||||
offset = line[index+4:index+10]
|
||||
type = find_type(srcdata, i)
|
||||
if(offset not in offsets):
|
||||
offsets.add(offset)
|
||||
xml_data += ' ' * 8 + make_xml_line(offset, type) + '\n'
|
||||
# make_replace(offset, type)
|
||||
index += line[index+10:].find('0x060') + 10
|
||||
return xml_data
|
||||
|
||||
def find_object(src):
|
||||
with open(src,'r',encoding='utf-8') as srcfile:
|
||||
srcdata = srcfile.readlines()
|
||||
for i, line in enumerate(srcdata):
|
||||
if 'OBJECT_' in line and ' FLAGS,' in srcdata[i-1]:
|
||||
object = line.strip().strip(',')
|
||||
return object.lower()
|
||||
|
||||
print('Object not found in', src)
|
||||
object = ''
|
||||
return object
|
||||
|
||||
def create_xml(src, name):
|
||||
set_globals(name)
|
||||
with open(src,'r',encoding='utf-8') as srcfile:
|
||||
srcdata = srcfile.readlines()
|
||||
object = find_object(src)
|
||||
xml = '<Root>\n <File Name="' + object + '" Segment="6">\n'
|
||||
symbols = {}
|
||||
for i, line in enumerate(srcdata):
|
||||
if '0x060' in line or 'D_060' in line:
|
||||
if 'extern' in line:
|
||||
xml += extern_to_xml(line)
|
||||
elif '0x060' in line:
|
||||
xml += other_to_xml(srcdata, i)
|
||||
xml += ' </File>\n</Root>\n'
|
||||
return xml
|
||||
|
||||
def add_header(src):
|
||||
object = find_object(src)
|
||||
if(object == ''):
|
||||
return 0
|
||||
with open(src,'r', encoding='utf-8') as srcfile:
|
||||
srcdata = srcfile.readlines()
|
||||
for i, line in enumerate(srcdata):
|
||||
if('#include' in line):
|
||||
break
|
||||
srcdata = srcdata[0:i+1] + ['#include "objects/' + object + '/' + object + '.h"\n'] + srcdata[i+1:]
|
||||
with open(src,'w',encoding='utf-8', newline = '\n') as outfile:
|
||||
outfile.writelines(srcdata)
|
||||
return 1
|
||||
|
||||
def replace_src(src):
|
||||
global replacements
|
||||
global global_name
|
||||
|
||||
add_header(src)
|
||||
with open(src,'r', encoding='utf-8') as srcfile:
|
||||
srcdata = srcfile.read()
|
||||
for key in list(replacements.keys()):
|
||||
srcdata = srcdata.replace(key, replacements.get(key))
|
||||
srcdata = srcdata.replace('D_g' + global_name, 'g' + global_name)
|
||||
if('Gfx' in replacements.get(key)):
|
||||
srcdata = srcdata.replace('0xg' + global_name, 'g' + global_name)
|
||||
else:
|
||||
srcdata = srcdata.replace('0xg' + global_name, '&g' + global_name)
|
||||
with open(src,'w',encoding='utf-8', newline = '\n') as outfile:
|
||||
outfile.write(srcdata)
|
||||
return 1
|
||||
|
||||
def fix_spec(src, spec):
|
||||
object = find_object(src)
|
||||
fix = False
|
||||
old = False
|
||||
with open(spec, 'r') as specfile:
|
||||
specdata = specfile.readlines()
|
||||
for i, line in enumerate(specdata):
|
||||
if ('"' + object + '"') in line:
|
||||
if 'number' in specdata[i+3]:
|
||||
old = True
|
||||
else:
|
||||
specdata[i+2] = spec_fmt.format(object)
|
||||
fix = True
|
||||
break
|
||||
if old:
|
||||
print('Already fixed', object, 'in', spec)
|
||||
return 0
|
||||
if not fix:
|
||||
print('Could not find',object,'in', spec)
|
||||
return -1
|
||||
with open(spec, 'w', newline='\n') as outfile:
|
||||
outfile.writelines(specdata)
|
||||
return 1
|
||||
|
||||
parser = argparse.ArgumentParser(description="Generate an xml object file from a source file")
|
||||
parser.add_argument('file', help="overlay file to generate xml from")
|
||||
parser.add_argument('name', help='name to use for xml variables')
|
||||
parser.add_argument('-r',action='store_true', help="replace variables in overlay with the new names")
|
||||
parser.add_argument('-s',metavar = 'spec', dest = 'spec', help="spec file to update", default=None)
|
||||
parser.add_argument('-o', metavar = 'outfile', dest = 'outfile', help = 'file to write xml to', default = None)
|
||||
|
||||
if __name__ == "__main__":
|
||||
args = parser.parse_args()
|
||||
if args.outfile is None:
|
||||
print(create_xml(args.file, args.name))
|
||||
else:
|
||||
with open(args.outfile, 'w', encoding='utf-8',newline='\n') as outfile:
|
||||
outfile.write(create_xml(args.file, args.name))
|
||||
if(args.r):
|
||||
replace_src(args.file)
|
||||
if(args.spec is not None):
|
||||
fix_spec(args.file, args.spec)
|
Loading…
Reference in a new issue