TRX/tools/tr2/generate_funcs

193 lines
5.4 KiB
Text
Raw Normal View History

2024-10-02 10:19:36 +02:00
#!/usr/bin/env python3
import re
2024-10-02 10:23:23 +02:00
from pathlib import Path
2024-10-02 10:19:36 +02:00
from shared.ida_progress import Symbol, parse_progress_file
2024-10-02 10:23:23 +02:00
from shared.paths import TR2Paths
2024-10-02 10:19:36 +02:00
2024-10-02 10:23:23 +02:00
FUNCS_H_FILE = TR2Paths.src_dir / "global/funcs.h"
VARS_H_FILE = TR2Paths.src_dir / "global/vars_decomp.h"
TYPES_H_FILE = TR2Paths.src_dir / "global/types_decomp.h"
2024-10-02 10:19:36 +02:00
COMMON_HEADER = [
"// This file is autogenerated. To update it, run tools/generate_funcs.",
"",
"#pragma once",
"",
]
FUNC_PTR_RE = re.compile(
r"^"
r"(?P<ret_type>.+?)\s*"
r"\("
r"\s*\*(?P<call_type>.*?\s)\s*(?P<func_name>\w+)"
r"(?P<array_def>\[[^\]]*?\]+)?"
r"\)\s*"
r"\((?P<args>.+)\)"
r";?$"
)
VAR_RE = re.compile(
r"^"
r"(?P<ret_type>.+?)\s*"
r"(?P<var_name>\b\w+)\s*"
r"(?P<array_def>(?:\[[^\]]*?\])*)"
r"(\s*=\s*(?P<value_def>.*?))?"
r";?"
r"(\s*\/\/\s*(?P<comment>.*))?"
r"$"
)
2024-10-02 10:19:36 +02:00
def update_file(path: Path, new_content: str) -> None:
if path.read_text() != new_content:
path.write_text(new_content)
def make_func_pointer_define(function: Symbol) -> str:
if match := re.match(
r"(?P<ret_type>.+?\W)(?P<func_name>\b\w+)\s*\((?P<args>.+)\);?",
function.signature,
):
ret_type = match.group("ret_type").strip()
func_name = match.group("func_name").strip()
args = match.group("args").strip()
return f"#define {func_name} (({ret_type} (*)({args})){function.offset_str})"
return ""
def make_var_pointer_define(variable: Symbol) -> str:
if match := FUNC_PTR_RE.match(variable.signature):
ret_type = match.group("ret_type")
call_type = match.group("call_type")
array_def = match.group("array_def")
func_name = match.group("func_name")
args = match.group("args")
if array_def:
return f"#define {func_name} (*(({ret_type}({call_type} *(*){array_def})({args})){variable.offset_str}))"
else:
return f"#define {func_name} (*({ret_type}({call_type}**)({args})){variable.offset_str})"
if match := VAR_RE.match(variable.signature):
ret_type = match.group("ret_type")
var_name = match.group("var_name")
array_def = match.group("array_def")
value_def = match.group("value_def")
comment = match.group("comment")
if not array_def and not value_def and comment == "no-dereferencing":
return f"#define {var_name} (({ret_type}){variable.offset_str})"
if array_def:
return f"#define {var_name} (*({ret_type}(*){array_def}){variable.offset_str})"
elif value_def:
return f"#define {var_name} (*({ret_type}*){variable.offset_str}) // = {value_def}"
else:
return f"#define {var_name} (*({ret_type}*){variable.offset_str})"
print("warn: unrecognized signature", variable.signature)
return ""
def make_funcs_h(functions: list[Symbol]) -> None:
header = [
*COMMON_HEADER,
'#include "global/types.h"',
"",
"// clang-format off",
]
footer = ["// clang-format on"]
defines = []
for function in functions:
if not function.is_decompiled and (
2024-10-02 10:19:36 +02:00
define := make_func_pointer_define(function)
):
defines.append(define)
update_file(FUNCS_H_FILE, "\n".join([*header, *defines, *footer]) + "\n")
def make_vars_h(variables: list[Symbol]) -> None:
header = [
*COMMON_HEADER,
'#include "global/types.h"',
'#include "inject_util.h"',
"",
"// clang-format off",
]
footer = [
"",
"// clang-format on",
]
defines = []
for variable in sorted(variables, key=lambda symbol: symbol.offset):
if not variable.is_decompiled and (
2024-10-02 10:19:36 +02:00
define := make_var_pointer_define(variable)
):
defines.append(define)
update_file(VARS_H_FILE, "\n".join([*header, *defines, *footer]) + "\n")
def make_types_h(types: list[str]) -> None:
header = [
*COMMON_HEADER,
'#include "const.h"',
"",
"#include <libtrx/game/collision.h>",
"#include <libtrx/game/effects.h>",
"#include <libtrx/game/gameflow/types.h>",
"#include <libtrx/game/items.h>",
"#include <libtrx/game/lara/types.h>",
"#include <libtrx/game/lot.h>",
"#include <libtrx/game/math.h>",
"#include <libtrx/game/objects/common.h>",
"#include <libtrx/game/rooms/types.h>",
"#include <libtrx/game/text.h>",
2024-10-02 10:19:36 +02:00
"",
"#include <stdbool.h>",
"#include <stdint.h>",
"#include <windows.h>",
"",
"#pragma pack(push, 1)",
"",
"// clang-format off",
]
footer = [
"",
"// clang-format on",
"",
"#pragma pack(pop)",
2024-10-02 10:19:36 +02:00
]
update_file(
TYPES_H_FILE,
"\n".join(
[
*header,
2024-10-02 10:23:23 +02:00
"\n\n".join(
[
definition.strip()
for definition in types
if "// decompiled" not in definition.strip()
]
),
2024-10-02 10:19:36 +02:00
*footer,
]
)
+ "\n",
)
def main() -> None:
2024-10-02 10:23:23 +02:00
progress_file = parse_progress_file(TR2Paths.progress_file)
2024-10-02 10:19:36 +02:00
make_funcs_h(progress_file.functions)
make_vars_h(progress_file.variables)
make_types_h(progress_file.types)
if __name__ == "__main__":
main()