mirror of
https://github.com/open-goal/jak-project.git
synced 2024-11-24 06:39:51 +00:00
45318be063
* decomp: mostly finish `cam-master` * decomp/scripts: lots of work in cam-states * stash * Merge remote-tracking branch 'water111/master' into decomp/camera-master Updated submodule third-party/googletest * decompiler: Add support for non power of 2 offsets for inline arr access * decomp: mostly finish `cam-states` need to fix a macro issue * blocked: `cam-master` decompiler crash when adding casts * decomp: finish `cam-states-dbg` * decomp: mostly finish `pov-camera` with the exception of joint-related code * decomp: `cam-debug` finished decompiling, no way does this compile yet though * decomp: considerable work done in `cam-layout` * decomp: `cam-layout` almost done! * decomp: `pov-camera` finished, TC tests will fail for now * decomp: working on resolving issues * decomp: cam-layout decompiling * fixing more issues in cam-master...one event handler remains * skip problematic function in `cam-master` for now * gsrc: update res macros * decomp: finish `cam-states` * decomp: giving up on `cam-debug` * tests: allow skipping state handlers in ref tests * decomp: working through cam-layout bugs * decomp: allow for shifting non-integers * decomp: finalize `cam-layout` and `cam-master` * decomp: finalize `cam-states` * cleanup: bi-annual formatting of the casting files * formatting * address feedback - leave the float labels alone for now * address feedback * linting/formatting * update gsrc and ref tests Co-authored-by: ManDude <7569514+ManDude@users.noreply.github.com>
189 lines
7.3 KiB
Python
189 lines
7.3 KiB
Python
from prompt_toolkit import PromptSession
|
|
from prompt_toolkit.history import FileHistory
|
|
from jsmin import jsmin
|
|
import shlex
|
|
import json
|
|
import collections
|
|
|
|
stack_cast_file_path = "./decompiler/config/jak1_ntsc_black_label/stack_structures.jsonc"
|
|
type_cast_file_path = "./decompiler/config/jak1_ntsc_black_label/type_casts.jsonc"
|
|
lambda_cast_file_path = "./decompiler/config/jak1_ntsc_black_label/anonymous_function_types.jsonc"
|
|
|
|
global_file_name = ""
|
|
global_func_name = ""
|
|
|
|
def ordered_dict_insert(ordered_dict, index, key, value):
|
|
if key in ordered_dict:
|
|
raise KeyError("Key already exists")
|
|
if index < 0 or index > len(ordered_dict):
|
|
raise IndexError("Index out of range")
|
|
|
|
keys = list(ordered_dict.keys())[index:]
|
|
ordered_dict[key] = value
|
|
for k in keys:
|
|
ordered_dict.move_to_end(k)
|
|
|
|
# TODO - optional size
|
|
def stack_cast(function_name, type_name, offset):
|
|
with open(stack_cast_file_path, "r+") as config_file:
|
|
minified = jsmin(config_file.read())
|
|
json_data = json.JSONDecoder(object_pairs_hook=collections.OrderedDict).decode(minified)
|
|
# Check if the function name has already been added
|
|
if function_name not in json_data:
|
|
ordered_dict_insert(json_data, len(json_data)-1, function_name, [])
|
|
# Check if there already exists a cast with the same offset, if so replace it
|
|
casts = json_data[function_name]
|
|
for cast in casts:
|
|
if cast[0] == offset:
|
|
print("Found cast with the same offset, replacing!")
|
|
cast[1] = type_name
|
|
config_file.seek(0)
|
|
json.dump(json_data, config_file, indent=2)
|
|
config_file.truncate()
|
|
return
|
|
json_data[function_name].append([offset, type_name])
|
|
config_file.seek(0)
|
|
json.dump(json_data, config_file, indent=2)
|
|
config_file.truncate()
|
|
print("Stack Cast Applied!")
|
|
|
|
def type_cast(function_name, register, type_cast, cast_range):
|
|
with open(type_cast_file_path, "r+") as config_file:
|
|
minified = jsmin(config_file.read())
|
|
json_data = json.JSONDecoder(object_pairs_hook=collections.OrderedDict).decode(minified)
|
|
# Check if the function name has already been added
|
|
if function_name not in json_data:
|
|
ordered_dict_insert(json_data, len(json_data)-1, function_name, [])
|
|
|
|
range_start = -1
|
|
range_end = -1
|
|
if "-" in cast_range:
|
|
range_start = int(cast_range.split("-")[0])
|
|
range_end = int(cast_range.split("-")[1])
|
|
else:
|
|
range_start = int(cast_range)
|
|
|
|
# Check if there already exists a cast with the same offset, if so replace it
|
|
casts = json_data[function_name]
|
|
new_casts = []
|
|
for cast in casts:
|
|
cast_range_start = -1
|
|
cast_range_end = -1
|
|
if isinstance(cast[0], list):
|
|
cast_range_start = cast[0][0]
|
|
cast_range_end = cast[0][1]
|
|
else:
|
|
cast_range_start = cast[0]
|
|
cast_register = cast[1]
|
|
|
|
if range_end == -1 and cast_range_end == -1 and range_start == cast_range_start and register == cast_register:
|
|
print("Found cast with the same range, replacing!")
|
|
continue
|
|
elif range_end == -1:
|
|
if range_start >= cast_range_start and range_start <= cast_range_end and register == cast_register:
|
|
print("Found cast with the same range, replacing!")
|
|
continue
|
|
elif cast_range_end == -1:
|
|
if cast_range_start >= range_start and cast_range_start <= range_end and register == cast_register:
|
|
print("Found cast with the same range, replacing!")
|
|
continue
|
|
new_casts.append(cast)
|
|
|
|
json_data[function_name] = new_casts
|
|
if range_end == -1:
|
|
json_data[function_name].append([range_start, register, type_cast])
|
|
else:
|
|
json_data[function_name].append([[range_start, range_end], register, type_cast])
|
|
config_file.seek(0)
|
|
json.dump(json_data, config_file, indent=2)
|
|
config_file.truncate()
|
|
print("Type Cast Applied!")
|
|
|
|
def lambda_cast(file_name, func_sig, func_id):
|
|
with open(lambda_cast_file_path, "r+") as config_file:
|
|
minified = jsmin(config_file.read())
|
|
json_data = json.JSONDecoder(object_pairs_hook=collections.OrderedDict).decode(minified)
|
|
# Check if the function name has already been added
|
|
if file_name not in json_data:
|
|
ordered_dict_insert(json_data, len(json_data)-1, file_name, [])
|
|
# Check if there already exists a cast with the same offset, if so replace it
|
|
functions = json_data[file_name]
|
|
for func in functions:
|
|
if func[0] == func_id:
|
|
print("Found lambda with the same id, replacing!")
|
|
func[1] = func_sig
|
|
config_file.seek(0)
|
|
json.dump(json_data, config_file, indent=2)
|
|
config_file.truncate()
|
|
return
|
|
json_data[file_name].append([func_id, func_sig])
|
|
config_file.seek(0)
|
|
json.dump(json_data, config_file, indent=2)
|
|
config_file.truncate()
|
|
print("Lambda Cast Applied!")
|
|
|
|
def main():
|
|
global global_file_name
|
|
global global_func_name
|
|
|
|
from pathlib import Path
|
|
home = str(Path.home())
|
|
session = PromptSession(history=FileHistory('{}/.castReplHistory'.format(home)))
|
|
|
|
# LOOP
|
|
while True:
|
|
# READ
|
|
try:
|
|
prompt_string = "castREPL> "
|
|
if global_file_name and global_func_name:
|
|
prompt_string = "castREPL-{}-{}> ".format(global_file_name, global_func_name)
|
|
elif global_file_name:
|
|
prompt_string = "castREPL-{}> ".format(global_file_name)
|
|
elif global_func_name:
|
|
prompt_string = "castREPL-{}> ".format(global_func_name)
|
|
text = session.prompt(prompt_string)
|
|
except KeyboardInterrupt:
|
|
continue
|
|
except EOFError:
|
|
break
|
|
|
|
# TODO - help command
|
|
# TODO - command to list current casts
|
|
# TODO - command to delete casts
|
|
# TODO - command to lookup function signature in all-types
|
|
# TODO - command to tie into the C++ program I'll right to narrow down an unknown type
|
|
# TODO - command to define function signature in all-types
|
|
|
|
# EVAL / CAST / PRINT
|
|
tokens = shlex.split(text)
|
|
if len(tokens) < 1:
|
|
continue
|
|
# PROCESS COMMANDS
|
|
command = tokens[0]
|
|
# Allows you to persist a file name -- cutting down on command args (useful if working on a big file)
|
|
if command == "enter-file" and len(tokens) == 2:
|
|
global_file_name = tokens[1]
|
|
elif command == "exit-file":
|
|
global_file_name = ""
|
|
# Allows you to persist a function name -- cutting down on command args (useful if working on a big function)
|
|
elif command == "enter-func" and len(tokens) == 2:
|
|
global_func_name = tokens[1]
|
|
elif command == "exit-func":
|
|
global_func_name = ""
|
|
elif command == "stack" and len(tokens) == 4:
|
|
# Stack casts are in the following format stack <func> <type> <offset>
|
|
stack_cast(tokens[1], tokens[2], int(tokens[3]))
|
|
elif command == "lambda" and len(tokens) == 4:
|
|
# Stack casts are in the following format lambda <file_name> <id> <func_sig>
|
|
lambda_cast(tokens[1], tokens[2], int(tokens[3]))
|
|
elif command == "type" and len(tokens) == 5:
|
|
# Stack casts are in the following format type <func> <register> <type_cast> <range = X | X-Y>
|
|
type_cast(tokens[1], tokens[2], tokens[3], tokens[4])
|
|
else:
|
|
print("Invalid Cast Command!")
|
|
# Exit
|
|
print('GoodBye!')
|
|
|
|
if __name__ == '__main__':
|
|
main()
|