decompiler: some hacks to allow running decompiler on jak 3 v5 code files, improve all-types generation (#2526)

Co-authored-by: water <awaterford111445@gmail.com>
This commit is contained in:
Hat Kid 2023-10-07 22:14:12 +02:00 committed by GitHub
parent 5f8415320b
commit bf961a36f4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
23 changed files with 4954 additions and 412 deletions

View File

@ -68,6 +68,8 @@ constexpr s32 max_symbols(GameVersion version) {
return jak1::GOAL_MAX_SYMBOLS; return jak1::GOAL_MAX_SYMBOLS;
case GameVersion::Jak2: case GameVersion::Jak2:
return jak2::GOAL_MAX_SYMBOLS; return jak2::GOAL_MAX_SYMBOLS;
case GameVersion::Jak3:
return jak2::GOAL_MAX_SYMBOLS;
} }
} }

View File

@ -159,6 +159,7 @@ constexpr int true_symbol_offset(GameVersion version) {
case GameVersion::Jak1: case GameVersion::Jak1:
return jak1_symbols::FIX_SYM_TRUE; return jak1_symbols::FIX_SYM_TRUE;
case GameVersion::Jak2: case GameVersion::Jak2:
case GameVersion::Jak3:
return jak2_symbols::FIX_SYM_TRUE; return jak2_symbols::FIX_SYM_TRUE;
} }
} }
@ -168,6 +169,7 @@ constexpr int empty_pair_offset_from_s7(GameVersion version) {
case GameVersion::Jak1: case GameVersion::Jak1:
return jak1_symbols::FIX_SYM_EMPTY_PAIR; return jak1_symbols::FIX_SYM_EMPTY_PAIR;
case GameVersion::Jak2: case GameVersion::Jak2:
case GameVersion::Jak3:
// minus 1 for the symbol table pointer's offset. // minus 1 for the symbol table pointer's offset.
return jak2_symbols::S7_OFF_FIX_SYM_EMPTY_PAIR; return jak2_symbols::S7_OFF_FIX_SYM_EMPTY_PAIR;
} }

View File

@ -238,6 +238,9 @@ class Field {
int offset() const { return m_offset; } int offset() const { return m_offset; }
bool skip_in_decomp() const { return m_skip_in_static_decomp; } bool skip_in_decomp() const { return m_skip_in_static_decomp; }
bool user_placed() const { return m_placed_by_user; } bool user_placed() const { return m_placed_by_user; }
void set_comment(const std::string& comment) { m_comment = comment; }
const std::string& comment() const { return m_comment; }
bool has_comment() const { return !m_comment.empty(); }
bool operator==(const Field& other) const; bool operator==(const Field& other) const;
bool operator!=(const Field& other) const { return !((*this) == other); } bool operator!=(const Field& other) const { return !((*this) == other); }
std::string diff(const Field& other) const; std::string diff(const Field& other) const;
@ -274,6 +277,7 @@ class Field {
int m_alignment = -1; int m_alignment = -1;
bool m_skip_in_static_decomp = false; bool m_skip_in_static_decomp = false;
bool m_placed_by_user = false; // was this field placed manually by the user? bool m_placed_by_user = false; // was this field placed manually by the user?
std::string m_comment; // optional comment placed next to the field
double m_field_score = 0.; double m_field_score = 0.;

View File

@ -1027,6 +1027,7 @@ void TypeSystem::add_builtin_types(GameVersion version) {
symbol_type = add_builtin_basic("basic", "symbol"); symbol_type = add_builtin_basic("basic", "symbol");
break; break;
case GameVersion::Jak2: case GameVersion::Jak2:
case GameVersion::Jak3:
symbol_type = add_builtin_structure("object", "symbol", true); symbol_type = add_builtin_structure("object", "symbol", true);
symbol_type->override_offset(1); symbol_type->override_offset(1);
break; break;

View File

@ -24,7 +24,8 @@ void assert_string_empty_after(const char* str, int size) {
std::string get_object_file_name(const std::string& original_name, u8* data, int size) { std::string get_object_file_name(const std::string& original_name, u8* data, int size) {
const std::string art_group_text_strings[] = { const std::string art_group_text_strings[] = {
fmt::format("/src/next/data/art-group{}/", versions::jak1::ART_FILE_VERSION), fmt::format("/src/next/data/art-group{}/", versions::jak1::ART_FILE_VERSION),
fmt::format("/src/jak2/final/art-group{}/", versions::jak2::ART_FILE_VERSION)}; fmt::format("/src/jak2/final/art-group{}/", versions::jak2::ART_FILE_VERSION),
fmt::format("/src/jak3/final/art-group{}/", versions::jak3::ART_FILE_VERSION)};
const std::string suffix = "-ag.go"; const std::string suffix = "-ag.go";
for (auto& art_group_text : art_group_text_strings) { for (auto& art_group_text : art_group_text_strings) {

View File

@ -29,9 +29,12 @@ constexpr u32 ART_FILE_VERSION = 7;
constexpr u32 LEVEL_FILE_VERSION = 36; constexpr u32 LEVEL_FILE_VERSION = 36;
constexpr u32 DGO_FILE_VERSION = 1; constexpr u32 DGO_FILE_VERSION = 1;
constexpr u32 TX_PAGE_VERSION = 8; constexpr u32 TX_PAGE_VERSION = 8;
} // namespace jak2 } // namespace jak2
namespace jak3 {
constexpr u32 ART_FILE_VERSION = 8;
}
} // namespace versions } // namespace versions
// GOAL kernel version (OpenGOAL changes this version from the game's version) // GOAL kernel version (OpenGOAL changes this version from the game's version)
@ -42,7 +45,7 @@ constexpr int KERNEL_VERSION_MINOR = 0;
constexpr int IRX_VERSION_MAJOR = 2; constexpr int IRX_VERSION_MAJOR = 2;
constexpr int IRX_VERSION_MINOR = 0; constexpr int IRX_VERSION_MINOR = 0;
enum class GameVersion { Jak1 = 1, Jak2 = 2 }; enum class GameVersion { Jak1 = 1, Jak2 = 2, Jak3 = 3 };
template <typename T> template <typename T>
struct PerGameVersion { struct PerGameVersion {

View File

@ -584,6 +584,13 @@ void Function::find_type_defs(LinkedObjectFile& file, DecompilerTypeSystem& dts)
int label_idx = -1; int label_idx = -1;
for (const auto& instr : instructions) { for (const auto& instr : instructions) {
// far labels
if (label_idx != -1 && state == 5 &&
!(instr.kind == InstructionKind::JALR && instr.get_dst(0).get_reg() == make_gpr(Reg::RA) &&
instr.get_src(0).get_reg() == make_gpr(Reg::T9))) {
continue;
}
// look for lw xx, type(s7) // look for lw xx, type(s7)
if (instr.kind == InstructionKind::LW && instr.get_src(0).is_sym() && if (instr.kind == InstructionKind::LW && instr.get_src(0).is_sym() &&
instr.get_src(0).get_sym() == "type" && instr.get_src(1).get_reg() == make_gpr(Reg::S7)) { instr.get_src(0).get_sym() == "type" && instr.get_src(1).get_reg() == make_gpr(Reg::S7)) {
@ -630,8 +637,14 @@ void Function::find_type_defs(LinkedObjectFile& file, DecompilerTypeSystem& dts)
if (state == 4) { if (state == 4) {
// look for ld a2, LXX(fp) // look for ld a2, LXX(fp)
if (instr.kind == InstructionKind::LD && instr.get_dst(0).get_reg() == make_gpr(Reg::A2) && if ((instr.kind == InstructionKind::LD && instr.get_dst(0).get_reg() == make_gpr(Reg::A2) &&
instr.get_src(0).is_label() && instr.get_src(1).get_reg() == make_gpr(Reg::FP)) { instr.get_src(0).is_label() && instr.get_src(1).get_reg() == make_gpr(Reg::FP))) {
state = 5;
label_idx = instr.get_src(0).get_label();
continue;
} else if ((instr.kind == InstructionKind::LUI &&
instr.get_dst(0).get_reg() == make_gpr(Reg::V1) && instr.get_src(0).is_label())) {
// far labels
state = 5; state = 5;
label_idx = instr.get_src(0).get_label(); label_idx = instr.get_src(0).get_label();
continue; continue;

View File

@ -624,7 +624,9 @@ void ObjectFileDB::write_disassembly(const fs::path& output_dir,
std::string asm_functions; std::string asm_functions;
for_each_obj([&](ObjectFileData& obj) { for_each_obj([&](ObjectFileData& obj) {
if ((obj.obj_version == 3 && disassemble_code) || (obj.obj_version != 3 && disassemble_data)) { if (((obj.obj_version == 3 || (obj.obj_version == 5 && obj.linked_data.has_any_functions())) &&
disassemble_code) ||
(obj.obj_version != 3 && disassemble_data)) {
auto file_text = obj.linked_data.print_disassembly(print_hex); auto file_text = obj.linked_data.print_disassembly(print_hex);
asm_functions += obj.linked_data.print_asm_function_disassembly(obj.to_unique_name()); asm_functions += obj.linked_data.print_asm_function_disassembly(obj.to_unique_name());
auto file_name = output_dir / (obj.to_unique_name() + ".asm"); auto file_name = output_dir / (obj.to_unique_name() + ".asm");

View File

@ -321,7 +321,7 @@ void ObjectFileDB::ir2_analyze_all_types(const fs::path& output_file,
const std::unordered_set<std::string>& bad_types) { const std::unordered_set<std::string>& bad_types) {
std::vector<PerObjectAllTypeInfo> per_object; std::vector<PerObjectAllTypeInfo> per_object;
DecompilerTypeSystem previous_game_ts(GameVersion::Jak1); // version here doesn't matter. DecompilerTypeSystem previous_game_ts(GameVersion::Jak2); // version here doesn't matter.
if (previous_game_types) { if (previous_game_types) {
previous_game_ts.parse_type_defs({*previous_game_types}); previous_game_ts.parse_type_defs({*previous_game_types});
} }
@ -329,44 +329,43 @@ void ObjectFileDB::ir2_analyze_all_types(const fs::path& output_file,
TypeInspectorCache ti_cache; TypeInspectorCache ti_cache;
for_each_obj([&](ObjectFileData& data) { for_each_obj([&](ObjectFileData& data) {
if (data.obj_version != 3) { if (data.obj_version == 3 || (data.obj_version == 5 && data.linked_data.has_any_functions())) {
return; auto& object_result = per_object.emplace_back();
} object_result.object_name = data.to_unique_name();
auto& object_result = per_object.emplace_back(); // Go through the top-level segment first to identify the type names associated with each
object_result.object_name = data.to_unique_name(); // symbol def
for_each_function_in_seg_in_obj(TOP_LEVEL_SEGMENT, data, [&](Function& f) {
inspect_top_level_for_metadata(f, data.linked_data, dts, previous_game_ts, object_result);
});
// Go through the top-level segment first to identify the type names associated with each symbol // Handle the top level last, which is fine as all symbol_defs are always written after
// def // typedefs
for_each_function_in_seg_in_obj(TOP_LEVEL_SEGMENT, data, [&](Function& f) { for_each_function_def_order_in_obj(data, [&](Function& f, int seg) {
inspect_top_level_for_metadata(f, data.linked_data, dts, previous_game_ts, object_result); if (seg != TOP_LEVEL_SEGMENT) {
}); if (f.is_inspect_method && bad_types.find(f.guessed_name.type_name) == bad_types.end()) {
auto deftype_from_inspect =
// Handle the top level last, which is fine as all symbol_defs are always written after typedefs inspect_inspect_method(f, f.guessed_name.type_name, dts, data.linked_data,
for_each_function_def_order_in_obj(data, [&](Function& f, int seg) { previous_game_ts, ti_cache, object_result);
if (seg != TOP_LEVEL_SEGMENT) { bool already_seen = object_result.type_info.count(f.guessed_name.type_name) > 0;
if (f.is_inspect_method && bad_types.find(f.guessed_name.type_name) == bad_types.end()) { if (!already_seen) {
auto deftype_from_inspect = object_result.type_names_in_order.push_back(f.guessed_name.type_name);
inspect_inspect_method(f, f.guessed_name.type_name, dts, data.linked_data, }
previous_game_ts, ti_cache, object_result); auto& info = object_result.type_info[f.guessed_name.type_name];
bool already_seen = object_result.type_info.count(f.guessed_name.type_name) > 0; info.from_inspect_method = true;
if (!already_seen) { info.type_definition = deftype_from_inspect;
object_result.type_names_in_order.push_back(f.guessed_name.type_name); } else {
// no inspect methods
// - can we solve custom print methods in a generic way? ie `entity-links`
} }
auto& info = object_result.type_info[f.guessed_name.type_name];
info.from_inspect_method = true;
info.type_definition = deftype_from_inspect;
} else {
// no inspect methods
// - can we solve custom print methods in a generic way? ie `entity-links`
} }
} });
});
for_each_function_in_seg_in_obj(TOP_LEVEL_SEGMENT, data, [&](Function& f) { for_each_function_in_seg_in_obj(TOP_LEVEL_SEGMENT, data, [&](Function& f) {
object_result.symbol_defs += inspect_top_level_symbol_defines( object_result.symbol_defs += inspect_top_level_symbol_defines(
f, data.linked_data, dts, previous_game_ts, object_result); f, data.linked_data, dts, previous_game_ts, object_result);
}); });
}
}); });
std::string result; std::string result;
@ -1180,7 +1179,7 @@ bool ObjectFileDB::lookup_function_type(const FunctionName& name,
std::string ObjectFileDB::ir2_final_out(ObjectFileData& data, std::string ObjectFileDB::ir2_final_out(ObjectFileData& data,
const std::vector<std::string>& imports, const std::vector<std::string>& imports,
const std::unordered_set<std::string>& skip_functions) { const std::unordered_set<std::string>& skip_functions) {
if (data.obj_version == 3) { if (data.obj_version == 3 || (data.obj_version == 5 && data.linked_data.has_any_functions())) {
std::string result; std::string result;
result += ";;-*-Lisp-*-\n"; result += ";;-*-Lisp-*-\n";
result += "(in-package goal)\n\n"; result += "(in-package goal)\n\n";

View File

@ -5,6 +5,11 @@
namespace decompiler { namespace decompiler {
// types with duplicate inspects
static const std::vector<std::string> g_duplicate_inspects_jak3 = {
"sky-vertex", "shadow-edge", "hfrag-poly4", "hfrag-poly9",
"hfrag-poly25", "hfrag-mip-packet", "sprite-aux-list", "game-save"};
bool is_set_reg_to_int(AtomicOp* op, Register dst, s64 value) { bool is_set_reg_to_int(AtomicOp* op, Register dst, s64 value) {
// should be a set reg to int math 2 ir // should be a set reg to int math 2 ir
auto set = dynamic_cast<SetVarOp*>(op); auto set = dynamic_cast<SetVarOp*>(op);
@ -186,33 +191,63 @@ std::optional<u64> get_set_reg_to_u64_load(AtomicOp* op,
const LinkedObjectFile& file) { const LinkedObjectFile& file) {
auto lvo = dynamic_cast<LoadVarOp*>(op); auto lvo = dynamic_cast<LoadVarOp*>(op);
if (!lvo) { if (!lvo) {
return false; return std::nullopt;
} }
// destination should be a register // destination should be a register
auto dest = lvo->get_set_destination(); auto dest = lvo->get_set_destination();
if (dst != dest.reg()) { if (dst != dest.reg()) {
return false; return std::nullopt;
} }
if (lvo->src().kind() != SimpleExpression::Kind::IDENTITY) { if (lvo->src().kind() != SimpleExpression::Kind::IDENTITY) {
return false; return std::nullopt;
} }
if (lvo->size() != 8) { if (lvo->size() != 8) {
return false; return std::nullopt;
} }
const auto& s = lvo->src().get_arg(0); const auto& s = lvo->src().get_arg(0);
if (!s.is_label()) { if (!s.is_label()) {
return false; return std::nullopt;
} }
auto lab = file.labels.at(s.label()); auto lab = file.labels.at(s.label());
auto& low = file.words_by_seg.at(lab.target_segment).at(lab.offset / 4); auto& low = file.words_by_seg.at(lab.target_segment).at(lab.offset / 4);
auto& hi = file.words_by_seg.at(lab.target_segment).at((lab.offset / 4) + 1); auto& hi = file.words_by_seg.at(lab.target_segment).at((lab.offset / 4) + 1);
if (low.kind() != LinkedWord::PLAIN_DATA || hi.kind() != LinkedWord::PLAIN_DATA) { if (low.kind() != LinkedWord::PLAIN_DATA || hi.kind() != LinkedWord::PLAIN_DATA) {
return false; return std::nullopt;
}
return ((u64)low.data) | (((u64)hi.data) << 32);
}
std::optional<u64> get_set_reg_to_lui(AtomicOp* op, Register dst, const LinkedObjectFile& file) {
auto lvo = dynamic_cast<SetVarOp*>(op);
if (!lvo) {
return std::nullopt;
}
// destination should be a register
auto dest = lvo->get_set_destination();
if (dst != dest.reg()) {
return std::nullopt;
}
if (lvo->src().kind() != SimpleExpression::Kind::IDENTITY) {
return std::nullopt;
}
const auto& s = lvo->src().get_arg(0);
if (!s.is_label()) {
return std::nullopt;
}
auto lab = file.labels.at(s.label());
auto& low = file.words_by_seg.at(lab.target_segment).at(lab.offset / 4);
auto& hi = file.words_by_seg.at(lab.target_segment).at((lab.offset / 4) + 1);
if (low.kind() != LinkedWord::PLAIN_DATA || hi.kind() != LinkedWord::PLAIN_DATA) {
return std::nullopt;
} }
return ((u64)low.data) | (((u64)hi.data) << 32); return ((u64)low.data) | (((u64)hi.data) << 32);
} }
@ -246,13 +281,23 @@ std::optional<std::string> get_string_loaded_to_reg(AtomicOp* op,
} }
struct FieldPrint { struct FieldPrint {
static constexpr int NO_ARR = -1;
static constexpr int DYNAMIC_ARRAY = -2;
static constexpr int UNKNOWN_ARR_SIZE = -3;
char format = '\0'; char format = '\0';
std::string field_name; std::string field_name;
std::string field_type_name; std::string field_type_name;
bool has_array = false; bool has_array = false;
int array_size = -1; int array_size = NO_ARR;
}; };
// if a field has a weird inspect, just return the FieldPrint instead of asserting,
// there's too many edge cases in custom prints to account for all of them
FieldPrint handle_custom_prints(FieldPrint& fp, const std::string& str) {
return fp;
}
FieldPrint get_field_print(const std::string& str) { FieldPrint get_field_print(const std::string& str) {
int idx = 0; int idx = 0;
auto next = [&]() { return str.at(idx++); }; auto next = [&]() { return str.at(idx++); };
@ -272,7 +317,10 @@ FieldPrint get_field_print(const std::string& str) {
// next the name: // next the name:
char name_char = next(); char name_char = next();
while (name_char != ':' && name_char != '[') { if (name_char == '~') {
return handle_custom_prints(field_print, str);
}
while (name_char != ':' && name_char != '[' && name_char != ' ') {
field_print.field_name.push_back(name_char); field_print.field_name.push_back(name_char);
name_char = next(); name_char = next();
} }
@ -281,6 +329,18 @@ FieldPrint get_field_print(const std::string& str) {
if (name_char == '[') { if (name_char == '[') {
int size = 0; int size = 0;
char num_char = next(); char num_char = next();
// dynamic array using a ~D print
// (format "~Tstack[~D] @ #x~X~%" (-> obj allocated-length) (-> obj stack))
if (num_char == '~') {
num_char = next();
ASSERT(num_char == 'D');
num_char = next();
ASSERT(num_char == ']');
// distinguish from dynamic arrays that are set to size 0
field_print.array_size = size = FieldPrint::DYNAMIC_ARRAY;
}
while (num_char >= '0' && num_char <= '9') { while (num_char >= '0' && num_char <= '9') {
size = size * 10 + (num_char - '0'); size = size * 10 + (num_char - '0');
num_char = next(); num_char = next();
@ -290,30 +350,68 @@ FieldPrint get_field_print(const std::string& str) {
ASSERT(num_char == ']'); ASSERT(num_char == ']');
char c = next(); char c = next();
ASSERT(c == ' '); // (method 3 array) and some others have a colon instead of a space here
if (c == ':') {
c = next();
}
if (c != ' ') {
return handle_custom_prints(field_print, str);
}
c = next(); c = next();
ASSERT(c == '@'); if (c != '@') {
return handle_custom_prints(field_print, str);
}
c = next(); c = next();
ASSERT(c == ' '); if (c != ' ') {
return handle_custom_prints(field_print, str);
}
c = next(); c = next();
ASSERT(c == '#'); if (c != '#') {
return handle_custom_prints(field_print, str);
}
c = next(); c = next();
ASSERT(c == 'x'); if (c != 'x') {
return handle_custom_prints(field_print, str);
}
} else { } else {
// next a space // next a space
char space_char = next(); char space_char = next();
ASSERT(space_char == ' '); if (space_char != ' ') {
return handle_custom_prints(field_print, str);
}
} }
// next the format // next the format
char fmt1 = next(); char fmt1 = next();
// if there are extra spaces
if (fmt1 == ' ') {
while (fmt1 == ' ') {
fmt1 = next();
}
}
if (fmt1 == '~' && peek(0) != '`') { // normal ~_~% if (fmt1 == '~' && peek(0) != '`') { // normal ~_~%
char fmt_code = next(); char fmt_code = next();
field_print.format = fmt_code; field_print.format = fmt_code;
char end1 = next(); char end1 = next();
ASSERT(end1 == '~'); if (end1 != '~') {
return handle_custom_prints(field_print, str);
}
char end2 = next(); char end2 = next();
ASSERT(end2 == '%'); if (end2 != '%') {
return handle_custom_prints(field_print, str);
}
ASSERT(idx == (int)str.size());
} else if (fmt1 == '~' && (peek(0) == 'g' || peek(0) == 'G')) { // ~g~%
char fmt_code = next();
field_print.format = fmt_code;
char end1 = next();
if (end1 != '~') {
return handle_custom_prints(field_print, str);
}
char end2 = next();
if (end2 != '%') {
return handle_custom_prints(field_print, str);
}
ASSERT(idx == (int)str.size()); ASSERT(idx == (int)str.size());
} else if (fmt1 == '#' && peek(0) == '<') { // struct #<my-struct @ #x~X>~% } else if (fmt1 == '#' && peek(0) == '<') { // struct #<my-struct @ #x~X>~%
next(); next();
@ -331,6 +429,30 @@ FieldPrint get_field_print(const std::string& str) {
field_print.format = 'X'; field_print.format = 'X';
ASSERT(idx == (int)str.size()); ASSERT(idx == (int)str.size());
} else if (fmt1 == '#' && peek(4) == ':') { // #x~X : (enum-name
// OR
// #x~X : ~S~%
if (peek(6) != '(' && peek(7) == 'S') {
next();
std::string expect_end = "~X : ~S~%";
for (char i : expect_end) {
char c = next();
ASSERT(i == c);
}
field_print.format = 'X';
} else {
// skip to paren
for (int i = 0; i < 7; i++) {
next();
}
auto name = str.substr(idx);
// some of these don't have the enum name
if (!name.empty()) {
name.pop_back();
field_print.field_type_name = name;
}
field_print.format = 'X';
}
} else if (fmt1 == '#' && peek(0) == 'x') { // #x~X~% } else if (fmt1 == '#' && peek(0) == 'x') { // #x~X~%
next(); next();
std::string expect_end = "~X~%"; std::string expect_end = "~X~%";
@ -364,17 +486,31 @@ FieldPrint get_field_print(const std::string& str) {
} }
else { else {
throw std::runtime_error("other format nyi in get_field_print " + str.substr(idx)); // throw std::runtime_error("other format nyi in get_field_print " + str.substr(idx));
lg::print("other format nyi in get_field_print {}\n", str.substr(idx));
} }
return field_print; return field_print;
} }
int get_start_idx_process(Function& function, const std::string& parent_type, Env& env) { int get_start_idx_process(Function& function,
const std::string& parent_type,
Env& env,
TypeInspectorResult* result) {
// hack
if (function.name() == "(method 3 process-tree)" || function.name() == "(method 3 process)") {
result->is_basic = true;
return 7;
}
if (parent_type == "process-focusable") {
result->is_basic = true;
}
if (function.basic_blocks.size() != 5) { if (function.basic_blocks.size() != 5) {
lg::print("[iim] inspect {} had {} basic blocks, expected 5\n", function.name(), lg::print("[iim] inspect {} had {} basic blocks, expected 5\n", function.name(),
function.basic_blocks.size()); function.basic_blocks.size());
return -1; return 1;
} }
if (!function.ir2.atomic_ops) { if (!function.ir2.atomic_ops) {
@ -475,12 +611,27 @@ L2:
} }
op_idx++; op_idx++;
if (!is_set_reg_to_symbol_value(aos.ops.at(op_idx).get(), Register(Reg::GPR, Reg::V1), // try to determine parent type for far labels
parent_type)) { if (parent_type == "UNKNOWN") {
lg::print("[iim] op5 bad in {}: {} (bad set parent type)\n", aos.ops.at(op_idx)->to_string(env), auto parent_op_str = aos.ops.at(op_idx)->to_string(env);
function.name()); auto parent_type_str = parent_op_str.substr(9);
return -1; parent_type_str.pop_back();
result->parent_type_name = parent_type_str;
} else {
if (!is_set_reg_to_symbol_value(aos.ops.at(op_idx).get(), Register(Reg::GPR, Reg::V1),
parent_type)) {
lg::print("[iim] op5 bad in {}: {} (bad set parent type)\n",
aos.ops.at(op_idx)->to_string(env), function.name());
return -1;
}
} }
// TODO check if this catches all cases or if there are false positives
// hack to get correct field offsets for children of process
if (result->parent_type_name != "structure") {
result->is_basic = true;
}
op_idx++; op_idx++;
if (aos.ops.at(op_idx).get()->to_string(env) != "(set! t9 (l.wu (+ v1 28)))") { if (aos.ops.at(op_idx).get()->to_string(env) != "(set! t9 (l.wu (+ v1 28)))") {
@ -536,12 +687,15 @@ L3:
int get_start_idx(Function& function, int get_start_idx(Function& function,
LinkedObjectFile& file, LinkedObjectFile& file,
TypeInspectorResult* result, TypeInspectorResult* result,
const std::string& /*parent_type*/, const std::string& parent_type,
const std::string& type_name, const std::string& type_name,
Env& env) { Env& env) {
if (function.basic_blocks.size() != 5) { if (function.basic_blocks.size() != 5) {
lg::print("[iim] inspect {} had {} basic blocks, expected 5\n", function.name(), lg::print("[iim] inspect {} had {} basic blocks, expected 5\n", function.name(),
function.basic_blocks.size()); function.basic_blocks.size());
if (parent_type == "basic") {
result->is_basic = true;
}
return -1; return -1;
} }
@ -673,7 +827,9 @@ int get_start_idx(Function& function,
if (is_set_reg_to_symbol_ptr(aos.ops.at(op_idx).get(), Register(Reg::GPR, Reg::A3), type_name)) { if (is_set_reg_to_symbol_ptr(aos.ops.at(op_idx).get(), Register(Reg::GPR, Reg::A3), type_name)) {
result->is_basic = false; result->is_basic = false;
} else if (aos.ops.at(op_idx)->to_string(env) == "(set! a3 (l.wu (+ gp -4)))") { } else if (aos.ops.at(op_idx)->to_string(env) == "(set! a3 (l.wu (+ gp -4)))" ||
aos.ops.at(op_idx)->to_string(env) == "(set! a3-0 (l.wu (+ a0-0 -4)))" ||
aos.ops.at(op_idx)->to_string(env) == "(set! a3-0 (l.wu (+ obj -4)))") {
result->is_basic = true; result->is_basic = true;
} else { } else {
lg::print("[iim] op 9 bad in {}: {}\n", aos.ops.at(op_idx)->to_string(env), function.name()); lg::print("[iim] op 9 bad in {}: {}\n", aos.ops.at(op_idx)->to_string(env), function.name());
@ -877,9 +1033,24 @@ int identify_array_field(int idx,
Function& function, Function& function,
TypeInspectorResult* result, TypeInspectorResult* result,
FieldPrint& print_info) { FieldPrint& print_info) {
auto& get_op = function.ir2.atomic_ops->ops.at(idx++); AtomicOp* get_op;
// dynamic array with ~D inspect print
if (print_info.array_size == FieldPrint::DYNAMIC_ARRAY) {
idx++;
get_op = function.ir2.atomic_ops->ops.at(idx).get();
} else {
get_op = function.ir2.atomic_ops->ops.at(idx++).get();
}
int offset = 0; int offset = 0;
if (!get_ptr_offset(get_op.get(), make_gpr(Reg::A2), make_gpr(Reg::GP), &offset)) {
bool ptr;
if (print_info.array_size == FieldPrint::DYNAMIC_ARRAY) {
ptr = get_ptr_offset(get_op, make_gpr(Reg::A3), make_gpr(Reg::GP), &offset);
} else {
ptr = get_ptr_offset(get_op, make_gpr(Reg::A2), make_gpr(Reg::GP), &offset);
}
if (!ptr) {
printf("bad get ptr offset %s\n", get_op->to_string(function.ir2.env).c_str()); printf("bad get ptr offset %s\n", get_op->to_string(function.ir2.env).c_str());
ASSERT(false); ASSERT(false);
} }
@ -888,7 +1059,7 @@ int identify_array_field(int idx,
} }
Field field(print_info.field_name, TypeSpec("UNKNOWN"), offset); Field field(print_info.field_name, TypeSpec("UNKNOWN"), offset);
if (print_info.array_size) { if (print_info.array_size > 0) {
field.set_array(print_info.array_size); field.set_array(print_info.array_size);
} else { } else {
field.set_dynamic(); field.set_dynamic();
@ -904,7 +1075,7 @@ int identify_struct_not_inline_field(int idx,
auto load_info = get_load_info_from_set(function.ir2.atomic_ops->ops.at(idx++).get()); auto load_info = get_load_info_from_set(function.ir2.atomic_ops->ops.at(idx++).get());
if (!(load_info.size == 4 && load_info.kind == LoadVarOp::Kind::UNSIGNED)) { if (!(load_info.size == 4 && load_info.kind == LoadVarOp::Kind::UNSIGNED)) {
result->warnings += "field " + print_info.field_type_name + " is likely a value type"; result->warnings += "field " + print_info.field_type_name + " is likely a value type. ";
} }
int offset = load_info.offset; int offset = load_info.offset;
if (result->is_basic) { if (result->is_basic) {
@ -924,7 +1095,7 @@ int identify_struct_inline_field(int idx,
int offset = 0; int offset = 0;
if (!get_ptr_offset(get_op.get(), make_gpr(Reg::A2), make_gpr(Reg::GP), &offset)) { if (!get_ptr_offset(get_op.get(), make_gpr(Reg::A2), make_gpr(Reg::GP), &offset)) {
printf("bad get ptr offset %s\n", get_op->to_string(function.ir2.env).c_str()); printf("bad get ptr offset %s\n", get_op->to_string(function.ir2.env).c_str());
ASSERT(false); // ASSERT(false);
} }
if (result->is_basic) { if (result->is_basic) {
offset += BASIC_OFFSET; offset += BASIC_OFFSET;
@ -946,12 +1117,12 @@ int identify_basic_field(int idx,
ASSERT(load_info.kind == LoadVarOp::Kind::UNSIGNED || load_info.kind == LoadVarOp::Kind::SIGNED); ASSERT(load_info.kind == LoadVarOp::Kind::UNSIGNED || load_info.kind == LoadVarOp::Kind::SIGNED);
TypeSpec field_type("basic"); TypeSpec field_type("basic");
if (load_info.size == 8) { if (load_info.size == 8) {
result->warnings += "field " + print_info.field_name + " uses ~A with a 64-bit load "; result->warnings += "field " + print_info.field_name + " uses ~A with a 64-bit load. ";
field_type = TypeSpec("uint64"); field_type = TypeSpec("uint64");
} else if (load_info.size == 4) { } else if (load_info.size == 4) {
// I wonder if this actually "object", or some other type? It seems to be // I wonder if this actually "object", or some other type? It seems to be
if (load_info.kind == LoadVarOp::Kind::SIGNED) { if (load_info.kind == LoadVarOp::Kind::SIGNED) {
result->warnings += "field " + print_info.field_name + " uses ~A with a signed load "; result->warnings += "field " + print_info.field_name + " uses ~A with a signed load. ";
} }
} else { } else {
ASSERT(false); ASSERT(false);
@ -967,9 +1138,79 @@ int identify_basic_field(int idx,
return idx; return idx;
} }
int identify_string_field(int idx,
Function& function,
LinkedObjectFile& file,
TypeInspectorResult* result,
FieldPrint& print_info) {
(void)file;
auto load_info = get_load_info_from_set(function.ir2.atomic_ops->ops.at(idx++).get());
ASSERT(load_info.kind == LoadVarOp::Kind::UNSIGNED || load_info.kind == LoadVarOp::Kind::SIGNED);
TypeSpec field_type("string");
if (load_info.size == 8) {
result->warnings += "field " + print_info.field_name + " uses ~S with a 64-bit load. ";
field_type = TypeSpec("uint64");
} else if (load_info.size == 4) {
// I wonder if this actually "object", or some other type? It seems to be
if (load_info.kind == LoadVarOp::Kind::SIGNED) {
result->warnings += "field " + print_info.field_name + " uses ~S with a signed load. ";
}
} else {
ASSERT(false);
}
int offset = load_info.offset;
if (result->is_basic) {
offset += BASIC_OFFSET;
}
Field field(print_info.field_name, field_type, offset);
result->fields_of_type.push_back(field);
return idx;
}
int identify_cstring_field(int idx,
Function& function,
LinkedObjectFile& file,
TypeInspectorResult* result,
FieldPrint& print_info) {
(void)file;
auto& get_op = function.ir2.atomic_ops->ops.at(idx++);
// assuming unknown array size at first
int size = FieldPrint::UNKNOWN_ARR_SIZE;
int offset = 0;
std::string comment;
// usually either a daddiu or lq
if (!get_ptr_offset(get_op.get(), make_gpr(Reg::A2), make_gpr(Reg::GP), &offset)) {
// daddiu failed, try lq
auto load_info = get_load_info_from_set(get_op.get());
if (load_info.size == 16) {
size = 16;
offset = load_info.offset;
comment = "field uses ~g print with a quadword load!";
} else {
printf("bad get ptr offset %s\n", get_op->to_string(function.ir2.env).c_str());
ASSERT(false);
}
}
if (result->is_basic) {
offset += BASIC_OFFSET;
}
Field field(print_info.field_name, TypeSpec("uint8"), offset);
field.set_array(size);
if (!comment.empty()) {
field.set_comment(comment);
}
result->fields_of_type.push_back(field);
return idx;
}
int detect(int idx, Function& function, LinkedObjectFile& file, TypeInspectorResult* result) { int detect(int idx, Function& function, LinkedObjectFile& file, TypeInspectorResult* result) {
auto& get_format_op = function.ir2.atomic_ops->ops.at(idx++); auto& get_format_op = function.ir2.atomic_ops->ops.at(idx++);
if (!is_set_reg_to_symbol_value(get_format_op.get(), make_gpr(Reg::T9), "format")) { if (!is_set_reg_to_symbol_value(get_format_op.get(), make_gpr(Reg::T9), "format")) {
return idx;
ASSERT_MSG(false, ASSERT_MSG(false,
fmt::format("bad get format: {}\n", get_format_op->to_string(function.ir2.env))); fmt::format("bad get format: {}\n", get_format_op->to_string(function.ir2.env)));
} }
@ -985,13 +1226,35 @@ int detect(int idx, Function& function, LinkedObjectFile& file, TypeInspectorRes
ASSERT_MSG(false, "bad sstr"); ASSERT_MSG(false, "bad sstr");
} }
// hack to ignore format print from enum->string and other unexpected stuff
if (sstr->substr(0, 1) != "~" || sstr == "~T [~D]~2Tactor-group: ~`actor-group`P~%" ||
sstr == "~T [~D]~2Tbuffer: ~A~%") {
return idx;
}
auto info = get_field_print(*sstr); auto info = get_field_print(*sstr);
auto& first_get_op = function.ir2.atomic_ops->ops.at(idx); auto& first_get_op = function.ir2.atomic_ops->ops.at(idx);
if (is_get_load(first_get_op.get(), make_gpr(Reg::A2), make_gpr(Reg::GP)) && // v1 load (process pointer):
(info.format == 'D' || info.format == 'X' || info.format == 'e') && !info.has_array && // lw t9, format(s7)
info.field_type_name.empty()) { // daddiu a0, s7, #t
// daddiu a1, fp, L389
// lwu v1, 12(gp)
// beq s7, v1, L281
// or a2, s7, r0
// B1:
// lwu v1, 0(v1)
// lwu a2, 28(v1)
// B2:
// L281:
// jalr ra, t9
auto load_a2_gp = is_get_load(first_get_op.get(), make_gpr(Reg::A2), make_gpr(Reg::GP));
auto load_v1_gp = is_get_load(first_get_op.get(), make_gpr(Reg::V1), make_gpr(Reg::GP));
if ((load_a2_gp || load_v1_gp) &&
(info.format == 'D' || info.format == 'd' || info.format == 'X' || info.format == 'e') &&
!info.has_array && info.field_type_name.empty()) {
idx = identify_int_field(idx, function, result, info); idx = identify_int_field(idx, function, result, info);
// it's a load! // it's a load!
} else if (is_get_load(first_get_op.get(), make_fpr(0), make_gpr(Reg::GP)) && } else if (is_get_load(first_get_op.get(), make_fpr(0), make_gpr(Reg::GP)) &&
@ -999,11 +1262,17 @@ int detect(int idx, Function& function, LinkedObjectFile& file, TypeInspectorRes
info.format == 'X') && info.format == 'X') &&
!info.has_array && info.field_type_name.empty()) { !info.has_array && info.field_type_name.empty()) {
idx = identify_float_field(idx, function, result, info); idx = identify_float_field(idx, function, result, info);
} else if (is_get_load(first_get_op.get(), make_gpr(Reg::A2), make_gpr(Reg::GP)) && } else if ((load_a2_gp || load_v1_gp) && info.format == 'A' && !info.has_array &&
info.format == 'A' && !info.has_array && info.field_type_name.empty()) { info.field_type_name.empty()) {
idx = identify_basic_field(idx, function, file, result, info); idx = identify_basic_field(idx, function, file, result, info);
} else if (is_get_load(first_get_op.get(), make_gpr(Reg::A2), make_gpr(Reg::GP)) && } else if ((load_a2_gp || load_v1_gp) && info.format == 'S' && !info.has_array &&
info.format == 'X' && !info.has_array && info.field_type_name.empty()) { info.field_type_name.empty()) {
idx = identify_string_field(idx, function, file, result, info);
} else if ((load_a2_gp || load_v1_gp) && (info.format == 'G' || info.format == 'g') &&
!info.has_array && info.field_type_name.empty()) {
idx = identify_cstring_field(idx, function, file, result, info);
} else if ((load_a2_gp || load_v1_gp) && info.format == 'X' && !info.has_array &&
info.field_type_name.empty()) {
idx = identify_pointer_field(idx, function, result, info); idx = identify_pointer_field(idx, function, result, info);
} else if (info.has_array && (info.format == 'X' || info.format == 'P') && } else if (info.has_array && (info.format == 'X' || info.format == 'P') &&
info.field_type_name.empty()) { info.field_type_name.empty()) {
@ -1020,14 +1289,51 @@ int detect(int idx, Function& function, LinkedObjectFile& file, TypeInspectorRes
} }
else { else {
printf("couldn't do %s, %s\n", sstr->c_str(), printf("couldn't do %s, %s, adding unknown field\n", sstr->c_str(),
first_get_op->to_string(function.ir2.env).c_str()); first_get_op->to_string(function.ir2.env).c_str());
return -1; // if all else fails, create an unknown field so the rest of the inspect can pass.
Field unknown("UNKNOWN", TypeSpec("UNKNOWN"), -1);
unknown.set_comment("field could not be read.");
result->fields_of_type.push_back(unknown);
return idx;
} }
if (!dynamic_cast<CallOp*>(function.ir2.atomic_ops->ops.at(idx++).get())) { CallOp* call_op;
if (load_v1_gp) {
call_op = dynamic_cast<CallOp*>(function.ir2.atomic_ops->ops.at(idx = idx + 3).get());
} else {
// dynamic array with ~D inspect print
if (info.array_size == FieldPrint::DYNAMIC_ARRAY) {
idx++;
call_op = dynamic_cast<CallOp*>(function.ir2.atomic_ops->ops.at(idx++).get());
} else {
call_op = dynamic_cast<CallOp*>(function.ir2.atomic_ops->ops.at(idx++).get());
}
}
// inspect strings like "#x~X : ~S~%" load the field twice, once into a2, then into v1,
// then have a bunch of string branches, so we just skip this, since we already have the field.
//
// lw t9, format(s7) ;; [218] (set! t9 format)
// daddiu a0, s7, #t ;; [219] (set! a0 #t)
// daddiu a1, fp, L503 ;; [220] (set! a1 L503) "~1Tclass: #x~X : ~S~%"
// lhu a2, 26(gp) ;; [221] (set! a2 (l.hu (+ gp 26)))
// lhu v1, 26(gp) ;; [222] (set! v1 (l.hu (+ gp 26)))
// addiu a3, r0, 149 ;; [223] (set! a3 149)
// bne v1, a3, L70 ;; [224] (b! (!= v1 a3) L70 (nop!))
// sll r0, r0, 0
if (load_a2_gp) {
auto load_v1_gp_again = is_get_load(function.ir2.atomic_ops->ops.at(idx - 1).get(),
make_gpr(Reg::V1), make_gpr(Reg::GP));
if (load_v1_gp_again) {
return idx;
}
}
if (!call_op) {
printf("bad call\n"); printf("bad call\n");
ASSERT(false); // ASSERT(false);
return -1; return -1;
} }
@ -1053,6 +1359,13 @@ std::string inspect_inspect_method(Function& inspect_method,
result.type_size = flags.size; result.type_size = flags.size;
result.type_method_count = flags.methods; result.type_method_count = flags.methods;
// ignore duplicate inspects
if (ti_cache.previous_results.find(type_name) != ti_cache.previous_results.end() &&
!(std::find(g_duplicate_inspects_jak3.begin(), g_duplicate_inspects_jak3.end(), type_name) !=
g_duplicate_inspects_jak3.end())) {
return fmt::format(";; {} is already defined!\n", type_name);
}
// Only set heap-base if it's different from the automatic one // Only set heap-base if it's different from the automatic one
// A child (or child of a child) of process ALWAYS has heap-base set. // A child (or child of a child) of process ALWAYS has heap-base set.
if (flags.heap_base > 0) { if (flags.heap_base > 0) {
@ -1081,7 +1394,8 @@ std::string inspect_inspect_method(Function& inspect_method,
inspect_method.ir2.env); inspect_method.ir2.env);
if (idx < 0) { if (idx < 0) {
idx = get_start_idx_process(inspect_method, result.parent_type_name, inspect_method.ir2.env); idx = get_start_idx_process(inspect_method, result.parent_type_name, inspect_method.ir2.env,
&result);
} }
StructureType* old_game_type = nullptr; StructureType* old_game_type = nullptr;
if (previous_game_ts.ts.fully_defined_type_exists(type_name)) { if (previous_game_ts.ts.fully_defined_type_exists(type_name)) {
@ -1096,6 +1410,12 @@ std::string inspect_inspect_method(Function& inspect_method,
object_file_meta); object_file_meta);
} }
while (idx < int(inspect_method.ir2.atomic_ops->ops.size()) - 2 && idx != -1) { while (idx < int(inspect_method.ir2.atomic_ops->ops.size()) - 2 && idx != -1) {
// skip over non-format calls in inspects
auto sstr = inspect_method.ir2.atomic_ops->ops.at(idx)->to_string(inspect_method.ir2.env);
if (sstr.substr(sstr.size() - 7) != "format)") {
idx++;
continue;
}
idx = detect(idx, inspect_method, file, &result); idx = detect(idx, inspect_method, file, &result);
} }
@ -1158,7 +1478,7 @@ bool allow_guess(const Field& field) {
std::string TypeInspectorResult::print_as_deftype( std::string TypeInspectorResult::print_as_deftype(
StructureType* old_game_type, StructureType* old_game_type,
std::unordered_map<std::string, TypeInspectorResult>& previous_results, std::unordered_map<std::string, TypeInspectorResult>& previous_results,
DecompilerTypeSystem& /*previous_game_ts*/, DecompilerTypeSystem& previous_game_ts,
ObjectFileDB::PerObjectAllTypeInfo& object_file_meta) { ObjectFileDB::PerObjectAllTypeInfo& object_file_meta) {
std::string result; std::string result;
@ -1216,7 +1536,12 @@ std::string TypeInspectorResult::print_as_deftype(
int mods = 0; int mods = 0;
// mods are array size, :inline, :dynamic // mods are array size, :inline, :dynamic
if (field.is_array() && !field.is_dynamic()) { if (field.is_array() && !field.is_dynamic()) {
mods += std::to_string(field.array_size()).size(); // "??" for unknown array size
if (field.array_size() == FieldPrint::UNKNOWN_ARR_SIZE) {
mods += 2;
} else {
mods += std::to_string(field.array_size()).size();
}
} }
if (field.is_inline()) { if (field.is_inline()) {
@ -1248,8 +1573,13 @@ std::string TypeInspectorResult::print_as_deftype(
std::string mods; std::string mods;
if (field.is_array() && !field.is_dynamic()) { if (field.is_array() && !field.is_dynamic()) {
mods += std::to_string(field.array_size()); if (field.array_size() == FieldPrint::UNKNOWN_ARR_SIZE) {
mods += " "; mods += "??";
mods += " ";
} else {
mods += std::to_string(field.array_size());
mods += " ";
}
} }
if (field.is_inline()) { if (field.is_inline()) {
@ -1284,6 +1614,9 @@ std::string TypeInspectorResult::print_as_deftype(
} }
} }
} }
if (field.has_comment()) {
result += fmt::format(" ;; {}", field.comment());
}
if (was_guess[field_idx]) { if (was_guess[field_idx]) {
result += " ;; guessed by decompiler"; result += " ;; guessed by decompiler";
@ -1337,21 +1670,21 @@ std::string TypeInspectorResult::print_as_deftype(
// Print out states if we have em // Print out states if we have em
// - Could probably assume the process name comes first and associate it with the right type // - Could probably assume the process name comes first and associate it with the right type
// but that may or may not be risky so, edit the types yourself... // but that may or may not be risky so, edit the types yourself...
// if (method_states.size() > 0) { if (method_states.size() > 0) {
// result.append("(:states\n "); result.append("(:states\n ");
// for (const auto& [id, name] : method_states) { for (const auto& [id, name] : method_states) {
// result.append(name); result.append(name);
// // Append old symbol def if we have it // Append old symbol def if we have it
// auto it = previous_game_ts.symbol_types.find(name); auto it = previous_game_ts.symbol_types.find(name);
// if (it != previous_game_ts.symbol_types.end()) { if (it != previous_game_ts.symbol_types.end()) {
// result.append(fmt::format(" ;; {}", it->second.print())); result.append(fmt::format(" ;; {}", it->second.print()));
// } }
// // Add symbol name to `already_seen_symbols` // Add symbol name to `already_seen_symbols`
// object_file_meta.already_seen_symbols.insert(name); object_file_meta.already_seen_symbols.insert(name);
// result.append("\n "); result.append("\n ");
// } }
// result.append(")\n "); result.append(")\n ");
//} }
result.append(")\n"); result.append(")\n");
result += "|#\n"; result += "|#\n";
@ -1359,7 +1692,7 @@ std::string TypeInspectorResult::print_as_deftype(
return result; return result;
} }
std::string get_regex_match(std::string form, std::regex regex) { std::string get_regex_match(const std::string& form, const std::regex& regex) {
std::smatch matches; std::smatch matches;
if (std::regex_search(form, matches, regex)) { if (std::regex_search(form, matches, regex)) {
if (matches.size() == 2) { if (matches.size() == 2) {
@ -1369,7 +1702,7 @@ std::string get_regex_match(std::string form, std::regex regex) {
return ""; return "";
} }
std::string get_state_symbol_name(LinkedObjectFile& file, std::string label_name) { std::string get_state_symbol_name(LinkedObjectFile& file, const std::string& label_name) {
try { try {
auto& label = file.get_label_by_name(label_name); auto& label = file.get_label_by_name(label_name);
auto& label_words = file.words_by_seg.at(label.target_segment); auto& label_words = file.words_by_seg.at(label.target_segment);
@ -1391,7 +1724,7 @@ std::string get_state_symbol_name(LinkedObjectFile& file, std::string label_name
} }
} }
std::string get_label_type_name(LinkedObjectFile& file, std::string label_name) { std::string get_label_type_name(LinkedObjectFile& file, const std::string& label_name) {
try { try {
auto& label = file.get_label_by_name(label_name); auto& label = file.get_label_by_name(label_name);
auto& label_words = file.words_by_seg.at(label.target_segment); auto& label_words = file.words_by_seg.at(label.target_segment);
@ -1433,7 +1766,7 @@ void inspect_top_level_for_metadata(Function& top_level,
} }
// Check for non-method states // Check for non-method states
std::string last_seen_label = ""; std::string last_seen_label;
// TODO - safely increment op number // TODO - safely increment op number
for (int i = 0; i < (int)top_level.ir2.atomic_ops->ops.size(); i++) { for (int i = 0; i < (int)top_level.ir2.atomic_ops->ops.size(); i++) {
const auto& aop = top_level.ir2.atomic_ops->ops.at(i); const auto& aop = top_level.ir2.atomic_ops->ops.at(i);
@ -1521,13 +1854,25 @@ void inspect_top_level_for_metadata(Function& top_level,
const auto& aop_4 = top_level.ir2.atomic_ops->ops.at(i + 4); const auto& aop_4 = top_level.ir2.atomic_ops->ops.at(i + 4);
auto flags = get_set_reg_to_u64_load(aop_4.get(), Register(Reg::GPR, Reg::A2), file); auto flags = get_set_reg_to_u64_load(aop_4.get(), Register(Reg::GPR, Reg::A2), file);
if (!flags) { if (!flags) {
continue; // far label load
// lui v1, L1352 ;; [ 24] (set! v1-10 L1352)
// ori v1, v1, L1352
// addu v1, fp, v1
// ld a2, 0(v1) ;; [ 25] (set! a2-0 (l.d v1-10))
flags = get_set_reg_to_lui(aop_4.get(), Register(Reg::GPR, Reg::V1), file);
if (!flags) {
continue;
}
} }
// jalr ra, t9 ;; [ 25] (call! a0-0 a1-0 a2-0) // jalr ra, t9 ;; [ 25] (call! a0-0 a1-0 a2-0)
const auto& aop_5 = top_level.ir2.atomic_ops->ops.at(i + 5); const auto& aop_5 = top_level.ir2.atomic_ops->ops.at(i + 5);
if (!dynamic_cast<CallOp*>(aop_5.get())) { if (!dynamic_cast<CallOp*>(aop_5.get())) {
continue; // far labels
const auto& aop_6 = top_level.ir2.atomic_ops->ops.at(i + 6);
if (!dynamic_cast<CallOp*>(aop_6.get())) {
continue;
}
} }
if (objectFile.type_info.count(*type_name) == 0) { if (objectFile.type_info.count(*type_name) == 0) {

View File

@ -1795,6 +1795,7 @@ std::unique_ptr<AtomicOp> convert_5(const Instruction& i0,
process_offset = 44; process_offset = 44;
break; break;
case GameVersion::Jak2: case GameVersion::Jak2:
case GameVersion::Jak3:
process_offset = 48; process_offset = 48;
break; break;
default: default:

View File

@ -1569,6 +1569,7 @@ Form* try_sc_as_type_of(FormPool& pool, Function& f, const ShortCircuit* vtx, Ga
case GameVersion::Jak1: case GameVersion::Jak1:
return try_sc_as_type_of_jak1(pool, f, vtx); return try_sc_as_type_of_jak1(pool, f, vtx);
case GameVersion::Jak2: case GameVersion::Jak2:
case GameVersion::Jak3:
return try_sc_as_type_of_jak2(pool, f, vtx); return try_sc_as_type_of_jak2(pool, f, vtx);
default: default:
ASSERT(false); ASSERT(false);

View File

@ -25,7 +25,7 @@ nlohmann::json read_json_file_from_config(const nlohmann::json& json, const std:
Config make_config_via_json(nlohmann::json& json) { Config make_config_via_json(nlohmann::json& json) {
Config config; Config config;
int version_int = json.at("game_version").get<int>(); int version_int = json.at("game_version").get<int>();
ASSERT(version_int == 1 || version_int == 2); ASSERT(version_int == 1 || version_int == 2 || version_int == 3);
config.game_version = (GameVersion)version_int; config.game_version = (GameVersion)version_int;
config.text_version = json.at("text_version").get<GameTextVersion>(); config.text_version = json.at("text_version").get<GameTextVersion>();
config.game_name = json.at("game_name").get<std::string>(); config.game_name = json.at("game_name").get<std::string>();

View File

@ -26,5 +26,671 @@
(define-extern stack-frame type) (define-extern stack-frame type)
(define-extern global kheap) (define-extern global kheap)
(define-extern kheap type) (define-extern kheap type)
(define-extern pointer type)
(define-extern #t symbol) (define-extern #t symbol)
(define-extern #f symbol)
;; some types we need.
(declare-type sparticle-launch-group basic)
(declare-type lightning-spec basic)
(declare-type sparticle-launcher basic)
(declare-type state basic)
(declare-type res-lump basic)
;; kernel types
(defenum link-flag
:bitfield #t
:type int32
(output-load-msg 0)
(output-load-true-msg 1)
(execute-login 2)
(print-login 3)
(force-debug 4)
(fast-link 5)
)
(defenum language-enum
:type int64
(english)
(french)
(german)
(spanish)
(italian)
(japanese)
(korean)
(uk-english)
)
(define-extern *debug-segment* symbol)
(define-extern nothing (function none))
(define-extern _format (function _varargs_ object))
(define-extern method-set! (function type int object none)) ;; may actually return function.
(define-extern malloc (function symbol int pointer))
(define-extern kmemopen (function kheap string none))
(define-extern kmemclose (function none))
(define-extern dgo-load (function string kheap link-flag int none))
(define-extern *listener-function* (function object))
(define-extern *enable-method-set* int)
(declare-type cpad-info basic)
(declare-type mouse-info basic)
(define-extern cpad-open (function cpad-info int cpad-info))
(define-extern cpad-get-data (function cpad-info cpad-info))
(define-extern scf-get-territory (function int)) ;; not actually a scf function...
(define-extern mouse-get-data (function mouse-info none))
(define-extern file-stream-open (function file-stream string symbol file-stream))
(define-extern file-stream-close (function file-stream file-stream))
(define-extern file-stream-length (function file-stream int))
(define-extern file-stream-seek (function file-stream int int int))
(define-extern file-stream-read (function file-stream pointer int int))
(define-extern file-stream-write (function file-stream pointer uint uint))
(define-extern reset-path (function none))
(define-extern flush-cache (function int none))
(define-extern gs-store-image (function object object object))
(define-extern sync-path (function int int int))
(define-extern file-stream-write (function file-stream pointer uint uint))
(define-extern file-stream-close (function file-stream file-stream))
(define-extern new-dynamic-structure (function symbol type int structure))
(define-extern kernel-shutdown (function none))
(define-extern scf-get-timeout (function int))
(define-extern scf-get-inactive-timeout (function int))
(define-extern syncv (function int int))
(define-extern string->symbol (function string symbol))
(define-extern link-begin (function pointer (pointer uint8) int kheap link-flag int))
(define-extern link-resume (function int))
(define-extern link-reset (function none))
(define-extern kset-language (function language-enum int))
(define-extern reset-graph (function int int int int none))
(declare-type sql-result basic)
(define-extern sql-query (function string sql-result))
(define-extern loading-level kheap)
(define-extern dma-sync (function pointer int int int))
(define-extern unload (function string none))
(defenum kmalloc-flags
:bitfield #t
(align-16 4)
(align-64 6)
(align-256 8)
(memset 12)
(top 13)
)
(define-extern kmalloc (function kheap int kmalloc-flags string pointer))
(define-extern *kernel-boot-message* symbol)
(define-extern *kernel-boot-art-group* string)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; gcommon ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(deftype vec4s (uint128)
((x float :offset 0)
(y float :offset 32)
(z float :offset 64)
(w float :offset 96))
:method-count-assert 9
:size-assert #x10
:flag-assert #x900000010
)
(deftype vector (structure)
((data float 4 :score -1 :offset-assert 0)
(x float :offset 0)
(y float :offset 4)
(z float :offset 8)
(w float :offset 12)
(quad uint128 :offset 0 :score -1)
)
:method-count-assert 9
:size-assert #x10
:flag-assert #x900000010
)
(deftype bfloat (basic)
((data float :offset-assert 4)
)
:method-count-assert 9
:size-assert #x8
:flag-assert #x900000008
)
(deftype inline-array-class (basic)
((length int32 :offset-assert 4)
(allocated-length int32 :offset-assert 8)
;; this is 16-byte aligned.
;; children of inline-array-class should define their own data which overlays this one.
(_data uint8 :score -50 :dynamic :offset 16)
)
(:methods
(new (symbol type int) _type_ 0))
:method-count-assert 9
:size-assert #x10
:flag-assert #x900000010
)
(define-extern identity (function object object))
(define-extern 1/ (function float float))
(define-extern + (function int int int))
(define-extern - (function int int int))
(define-extern * (function int int int))
(define-extern / (function int int int))
(define-extern ash (function int int int))
(define-extern mod (function int int int))
(define-extern rem (function int int int))
(define-extern abs (function int int))
(define-extern min (function int int int))
(define-extern max (function int int int))
(define-extern logior (function int int int))
(define-extern logand (function int int int))
(define-extern lognor (function int int int))
(define-extern logxor (function int int int))
(define-extern lognot (function int int))
(define-extern false-func (function symbol))
(define-extern true-func (function symbol))
(define-extern format (function _varargs_ object))
(define-extern basic-type? (function basic type symbol))
(define-extern type-type? (function type type symbol))
(define-extern type? (function object type symbol))
(define-extern find-parent-method (function type int function))
(define-extern ref (function object int object))
(define-extern last (function object object))
(define-extern member (function object object object))
(define-extern nmember (function basic object object))
(define-extern assoc (function object object object))
(define-extern assoce (function object object object))
(define-extern nassoc (function string object object))
(define-extern nassoce (function string object object))
(define-extern append! (function object object object))
(define-extern delete! (function object object pair))
(define-extern delete-car! (function object object object))
(define-extern insert-cons! (function object object pair))
(define-extern sort (function pair (function object object object) pair))
(define-extern mem-copy! (function pointer pointer int pointer))
(define-extern qmem-copy<-! (function pointer pointer int pointer))
(define-extern qmem-copy->! (function pointer pointer int pointer))
(define-extern mem-set32! (function pointer int int pointer))
(define-extern mem-or! (function pointer pointer int pointer))
(define-extern quad-copy! (function pointer pointer int none))
(define-extern fact (function int int))
(define-extern *print-column* binteger)
(define-extern print (function object object))
(define-extern printl (function object object))
(define-extern inspect (function object object))
(define-extern mem-print (function (pointer uint32) int symbol))
(define-extern *trace-list* pair)
(define-extern print-tree-bitmask (function int int symbol))
(define-extern breakpoint-range-set! (function uint uint uint int))
(define-extern valid? (function object type string symbol object symbol))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; gstring-h ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; gkernel-h ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(declare-type process-tree basic)
(declare-type process process-tree)
(declare-type thread basic)
(declare-type cpu-thread thread)
(declare-type clock basic)
(declare-type res-lump basic)
(declare-type entity res-lump)
(declare-type entity-actor entity)
(declare-type event-message-block structure)
(declare-type level basic)
(defenum process-mask
:type uint32
:bitfield #t
(execute 0)
(freeze 1)
(pause 2)
(menu 3)
(progress 4)
(actor-pause 5)
(sleep 6)
(sleep-code 7)
(process-tree 8)
(heap-shrunk 9)
(going 10)
(kernel-run 11)
(no-kill 12)
(movie 13)
(dark-effect 14)
(target 15)
(sidekick 16)
(crate 17)
(bit18 18) ;; unused?
(enemy 19)
(camera 20)
(platform 21)
(ambient 22)
(entity 23)
(projectile 24)
(bot 25)
(collectable 26)
(death 27)
(no-track 28)
(guard 29)
(vehicle 30)
(civilian 31)
)
(deftype process-tree (basic)
((name string :offset-assert 4)
(mask process-mask :offset-assert 8)
(clock clock :offset-assert 12)
(parent (pointer process-tree) :offset-assert 16)
(brother (pointer process-tree) :offset-assert 20)
(child (pointer process-tree) :offset-assert 24)
(ppointer (pointer process) :offset-assert 28)
(self process-tree :offset-assert 32)
)
(:methods
(new (symbol type string) _type_ 0)
(activate (_type_ process-tree basic pointer) process-tree 9)
(deactivate (_type_) none 10)
(init-from-entity!
"Typically the method that does the initial setup on the process, potentially using the [[entity-actor]] provided as part of that.
This commonly includes things such as:
- stack size
- collision information
- loading the skeleton group / bones
- sounds"
(_type_ entity-actor) none 11)
(run-logic? (_type_) symbol 12)
(process-tree-method-13 () none 13)
)
:size-assert #x24
:method-count-assert 14
:no-runtime-type
)
(deftype kernel-context (basic)
((prevent-from-run process-mask :offset-assert 4) ;; guessed by decompiler
(require-for-run process-mask :offset-assert 8) ;; guessed by decompiler
(allow-to-run process-mask :offset-assert 12) ;; guessed by decompiler
(next-pid int32 :offset-assert 16)
(fast-stack-top pointer :offset-assert 20) ;; guessed by decompiler
(current-process process :offset-assert 24) ;; guessed by decompiler
(relocating-process basic :offset-assert 28)
(relocating-min int32 :offset-assert 32)
(relocating-max int32 :offset-assert 36)
(relocating-offset int32 :offset-assert 40)
(relocating-level level :offset-assert 44) ;; guessing here
(low-memory-message symbol :offset-assert 48) ;; guessed by decompiler
(login-object basic :offset-assert 52)
)
:method-count-assert 9
:size-assert #x38
:flag-assert #x900000038
;; field relocating-level uses ~A with a signed load
)
(deftype time-frame (int64)
()
:flag-assert #x900000008
)
(deftype clock (basic)
((index int32 :offset-assert 4) ;; which clock we are, in *display*
(mask process-mask :offset-assert 8) ;; mask for ticking
(clock-ratio float :offset-assert 12) ;; how fast to run. 1.0 = realtime.
(accum float :offset-assert 16) ;; fractional time for frame-counter (time-frame units)
(integral-accum float :offset-assert 20) ;; fractional time for integral (time-frame untis)
(frame-counter time-frame :offset-assert 24) ;; how much time has gone by since reset (time-frame units)
(old-frame-counter time-frame :offset-assert 32) ;; the frame-counter on the last engine iteration
(integral-frame-counter uint64 :offset-assert 40) ;; how many vsyncs have gone by since reset
(old-integral-frame-counter uint64 :offset-assert 48) ;; the integral-frame-counter on the last engine iteration
(sparticle-data vector :inline :offset-assert 64) ;; sparticle timescale info
(seconds-per-frame float :offset-assert 80) ;; how many seconds (not time-frames) should go by in 1 vsync
(frames-per-second float :offset-assert 84) ;; inverse of above
(time-adjust-ratio float :offset-assert 88) ;; 1, if the game runs at 60fps NTSC with clock-ratio = 1.
)
:method-count-assert 15
:size-assert #x5c
:flag-assert #xf0000005c
(:methods
(new (symbol type int) _type_ 0)
(update-rates! (_type_ float) float 9)
(advance-by! (_type_ float) clock 10)
(tick! (_type_) clock 11)
(save! (_type_ (pointer uint64)) int 12)
(load! (_type_ (pointer uint64)) int 13)
(reset! (_type_) none 14)
)
)
(deftype thread (basic)
((name symbol :offset-assert 4)
(process process :offset-assert 8) ;; guessed by decompiler
(previous thread :offset-assert 12) ;; guessed by decompiler
(suspend-hook (function cpu-thread none) :offset-assert 16) ;; guessed by decompiler
(resume-hook (function cpu-thread none) :offset-assert 20) ;; guessed by decompiler
(pc pointer :offset-assert 24) ;; guessed by decompiler
(sp pointer :offset-assert 28) ;; guessed by decompiler
(stack-top pointer :offset-assert 32) ;; guessed by decompiler
(stack-size int32 :offset-assert 36)
)
:method-count-assert 12
:size-assert #x28
:flag-assert #xc00000028
(:methods
(stack-size-set! (_type_ int) none 9)
(thread-suspend (_type_) none 10)
(thread-resume (_type_) none 11)
)
)
;; modified for x86.
(deftype cpu-thread (thread)
((rreg uint64 7 :offset-assert 40)
(freg float 8)
;; old values:
;; (rreg uint64 8 :offset-assert 40) ;; guessed by decompiler
;; (freg float 6 :offset-assert 104) ;; guessed by decompiler
(stack uint8 :dynamic :offset-assert 128) ;; guessed by decompiler
)
:method-count-assert 12
:size-assert #x80
:flag-assert #xc00000080
(:methods
(new (symbol type process symbol int pointer) _type_ 0)
)
)
(deftype dead-pool (process-tree)
()
:method-count-assert 16
:size-assert #x24
:flag-assert #x1000000024
;; Failed to read fields.
(:methods
(new (symbol type int int string) _type_ 0)
(get-process (_type_ type int) process 14)
(return-process (_type_ process) none 15)
)
)
(deftype dead-pool-heap-rec (structure)
((process process :offset-assert 0) ;; guessed by decompiler
(prev dead-pool-heap-rec :offset-assert 4)
(next dead-pool-heap-rec :offset-assert 8)
)
:pack-me
:method-count-assert 9
:size-assert #xc
:flag-assert #x90000000c
)
(deftype dead-pool-heap (dead-pool)
((allocated-length int32 :offset-assert 36)
(compact-time uint32 :offset-assert 40)
(compact-count-targ uint32 :offset-assert 44)
(compact-count uint32 :offset-assert 48)
(fill-percent float :offset-assert 52)
(first-gap dead-pool-heap-rec :offset-assert 56)
(first-shrink dead-pool-heap-rec :offset-assert 60)
(heap kheap :inline :offset-assert 64)
(alive-list dead-pool-heap-rec :inline :offset-assert 80)
(last dead-pool-heap-rec :offset #x54 :offset-assert 84)
(dead-list dead-pool-heap-rec :inline :offset-assert 92)
(process-list dead-pool-heap-rec :inline :dynamic :offset-assert 104)
)
:method-count-assert 28
:size-assert #x68
:flag-assert #x1c00000068
;; Failed to read fields.
(:methods
(new (symbol type string int int) _type_ 0)
(init (_type_ symbol int) none 16)
(compact (dead-pool-heap int) none 17)
(shrink-heap (dead-pool-heap process) dead-pool-heap 18)
(churn (dead-pool-heap int) none 19)
(memory-used (_type_) int 20)
(memory-total (_type_) int 21)
(memory-free (dead-pool-heap) int 22)
(compact-time (dead-pool-heap) uint 23)
(gap-size (dead-pool-heap dead-pool-heap-rec) int 24)
(gap-location (dead-pool-heap dead-pool-heap-rec) pointer 25)
(find-gap (dead-pool-heap dead-pool-heap-rec) dead-pool-heap-rec 26)
(find-gap-by-size (dead-pool-heap int) dead-pool-heap-rec 27)
)
)
(deftype stack-frame (basic)
((name symbol :offset 4)
(next stack-frame :offset 8) ;; which way does this point?
)
:size-assert #xc
:method-count-assert 9
:flag-assert #x90000000c
)
;; a "catch" frame is a frame that can be "thrown" to.
;; the "throw" is a nonlocal control flow back to the state before the "catch" block.
(deftype catch-frame (stack-frame)
((sp int32 :offset-assert 12)
(ra int32 :offset-assert 16)
; (freg float 6 :offset-assert 20)
; (rreg uint128 8 :offset-assert 48)
;; In OpenGOAL, we swap a rreg for 4 more fregs.
(freg float 10 :offset-assert 20) ;; only use 8
(rreg uint128 7) ;; only use 5
)
:method-count-assert 9
:size-assert #xb0
:flag-assert #x9000000b0
(:methods
(new (symbol type symbol function (pointer uint64)) object 0)
)
)
(deftype protect-frame (stack-frame)
((exit (function none) :offset-assert 12) ;; guessed by decompiler
)
(:methods
(new (symbol type (function none)) protect-frame)
)
:method-count-assert 9
:size-assert #x10
:flag-assert #x900000010
)
(deftype handle (uint64)
((process (pointer process) :offset 0)
(pid int32 :offset 32)
(u64 uint64 :offset 0)
)
:flag-assert #x900000008
)
(deftype state (protect-frame)
((code function :offset-assert 16) ;; guessed by decompiler
(trans (function none) :offset-assert 20) ;; guessed by decompiler
(post function :offset-assert 24) ;; guessed by decompiler
(enter function :offset-assert 28) ;; guessed by decompiler
(event (function process int symbol event-message-block object) :offset-assert 32) ;; guessed by decompiler
)
(:methods
(new (symbol type symbol function
(function none)
function
(function none)
(function process int symbol event-message-block object)) _type_ 0)
)
:method-count-assert 9
:size-assert #x24
:flag-assert #x900000024
)
(deftype event-message-block (structure)
((to-handle handle)
(to (pointer process) :offset 0) ;; overlays process field of handle
(form-handle handle :offset-assert 8)
(from (pointer process) :offset 8)
(param uint64 6)
(message symbol)
(num-params int32)
)
:method-count-assert 9
:size-assert #x48
:flag-assert #x900000048
;; Failed to read fields.
)
(deftype event-message-block-array (inline-array-class)
((data event-message-block :inline :dynamic :offset-assert 16)
)
:method-count-assert 10
:size-assert #x10
:flag-assert #xa00000010
(:methods
(send-all! (_type_) none 9)
)
)
(deftype process (process-tree)
((pool dead-pool)
(status symbol :offset-assert 40)
(pid int32)
(main-thread cpu-thread :offset-assert 48)
(top-thread cpu-thread :offset-assert 52)
(entity entity-actor :offset-assert 56)
(level level :offset-assert 60)
(state state :offset-assert 64)
(next-state state :offset-assert 68)
(trans-hook function :offset-assert 72)
(post-hook function :offset-assert 76)
(event-hook (function process int symbol event-message-block object) :offset-assert 80)
(allocated-length int32 :offset-assert 84)
(pad-unknown-0 uint32 2) ;; had to rename this unfortunately, there is a type that uses this same name "vehicle"
(heap-base pointer :offset-assert 96)
(heap-top pointer :offset-assert 100)
(heap-cur pointer :offset-assert 104)
(stack-frame-top stack-frame :offset-assert 108)
(connection-list connectable :inline :offset-assert 112)
(stack uint8 :dynamic :offset-assert 128 :score -1)
)
(:methods
(new (symbol type string int) _type_ 0)
)
(:states
dead-state
empty-state)
:size-assert #x80
:method-count-assert 14
:no-runtime-type ;; already defined by kscheme. Don't do it again.
)
(deftype sql-result (basic)
((len int32 :offset-assert 4)
(allocated-length uint32 :offset-assert 8)
(error symbol :offset-assert 12)
(data string :dynamic :offset-assert 16) ;; are these actually symbols, or are they strings (in the GOAL code they are treated as strings atleast)
)
(:methods (new (symbol type uint) _type_ 0))
:method-count-assert 9
:size-assert #x10
)
(define-extern *sql-result* sql-result)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; gkernel ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define-extern *kernel-version* binteger)
(define-extern *irx-version* binteger)
(define-extern *kernel-boot-mode* symbol)
(define-extern *kernel-boot-level* symbol)
(define-extern *deci-count* int)
(define-extern *last-loado-length* int)
(define-extern *last-loado-global-usage* int)
(define-extern *last-loado-debug-usage* int)
(define-extern *kernel-packages* pair)
(define-extern load-package (function string kheap pair))
(define-extern unload-package (function string pair))
(define-extern *kernel-context* kernel-context)
(define-extern *dram-stack* (pointer uint8))
(define-extern *null-kernel-context* kernel-context)
(define-extern remove-exit (function none :behavior process))
(define-extern stream<-process-mask (function object process-mask process-mask))
(define-extern *master-mode* symbol)
(define-extern *pause-lock* symbol)
(define-extern inspect-process-heap (function process symbol))
(define-extern return-from-thread (function none))
(define-extern return-from-thread-dead (function none))
(define-extern reset-and-call (function thread function object))
(define-extern method-state (function type basic state))
(define-extern *global-search-name* basic)
(define-extern *global-search-count* int)
(define-extern process-by-name (function string process-tree process))
(define-extern process-not-name (function string process-tree process))
(define-extern process-count (function process-tree int))
(define-extern kill-by-name (function string process-tree symbol))
(define-extern kill-by-type (function type process-tree symbol))
(define-extern kill-not-name (function string process-tree symbol))
(define-extern kill-not-type (function type process-tree symbol))
(define-extern iterate-process-tree (function process-tree (function object object) kernel-context object))
(define-extern execute-process-tree (function process-tree (function object object) kernel-context object))
(define-extern search-process-tree (function process-tree (function process-tree object) process-tree))
(define-extern kernel-dispatcher (function object))
(define-extern sync-dispatcher (function object))
(define-extern inspect-process-tree (function process-tree int int symbol process-tree))
(define-extern throw-dispatch (function catch-frame object none))
(define-extern throw (function symbol object int))
(define-extern previous-brother (function process-tree object))
(define-extern change-parent (function process-tree process-tree process-tree))
(define-extern change-brother (function process-tree process-tree object))
(define-extern change-to-last-brother (function process-tree process-tree))
(define-extern run-function-in-process (function process function object object object object object object object))
(define-extern set-to-run-bootstrap (function none))
(define-extern set-to-run (function cpu-thread function object object object object object object pointer))
(define-extern entity-deactivate-handler (function process entity-actor none))
(define-extern *listener-process* process)
(define-extern *null-process* process)
(define-extern *vis-boot* symbol)
(define-extern *kernel-clock* clock)
(define-extern *16k-dead-pool* dead-pool)
(define-extern *8k-dead-pool* dead-pool)
(define-extern *4k-dead-pool* dead-pool)
(define-extern *target-dead-pool* dead-pool)
(define-extern *camera-dead-pool* dead-pool)
(define-extern *camera-master-dead-pool* dead-pool)
(define-extern *debug-dead-pool* dead-pool-heap)
(define-extern *nk-dead-pool* dead-pool-heap)
(define-extern *default-dead-pool* dead-pool)
(define-extern *pickup-dead-pool* dead-pool)
(define-extern *city-dead-pool* dead-pool-heap)
(define-extern *dead-pool-list* pair)
(define-extern *active-pool* process-tree)
(define-extern *display-pool* process-tree) ;; process-tree
(define-extern *camera-pool* process-tree) ;; process-tree
(define-extern *target-pool* process-tree) ;; process-tree
(define-extern *entity-pool* process-tree) ;; process-tree
(define-extern *mid-pool* process-tree)
(define-extern *pusher-pool* process-tree)
(define-extern *bg-pool* process-tree)
(define-extern *default-pool* process-tree) ;; process-tree

View File

@ -8,7 +8,7 @@
// if you want to filter to only some object names. // if you want to filter to only some object names.
// it will make the decompiler much faster. // it will make the decompiler much faster.
"allowed_objects": [], "allowed_objects": [],
"banned_objects": [], "banned_objects": ["script", "ragdoll-edit", "gun-states", "manipulator", "hfrag", "hfrag-vu1", "ff-squad-control"],
//////////////////////////// ////////////////////////////
// CODE ANALYSIS OPTIONS // CODE ANALYSIS OPTIONS
@ -19,9 +19,9 @@
"disassemble_code": true, "disassemble_code": true,
// Run the decompiler // Run the decompiler
"decompile_code": false, "decompile_code": true,
"find_functions": false, "find_functions": true,
//////////////////////////// ////////////////////////////
// DATA ANALYSIS OPTIONS // DATA ANALYSIS OPTIONS
@ -39,9 +39,11 @@
// unpack game count to assets folder // unpack game count to assets folder
"process_game_count": false, "process_game_count": false,
// write goal imports for art groups // write goal imports for art groups
"process_art_groups": false, "process_art_groups": true,
// write out a json file containing the art info mapping, run this with all objects allowed // write out a json file containing the art info mapping, run this with all objects allowed
"dump_art_group_info": false, "dump_art_group_info": true,
// write out a json file containing the joint node mapping, run this with all objects allowed
"dump_joint_geo_info": false,
/////////////////////////// ///////////////////////////
// WEIRD OPTIONS // WEIRD OPTIONS
@ -79,16 +81,18 @@
// CONFIG FILES // CONFIG FILES
//////////////////////////// ////////////////////////////
"type_casts_file": "decompiler/config/jak3/type_casts.jsonc", "type_casts_file": "decompiler/config/jak3/ntsc_v1/type_casts.jsonc",
"anonymous_function_types_file": "decompiler/config/jak3/anonymous_function_types.jsonc", "anonymous_function_types_file": "decompiler/config/jak3/ntsc_v1/anonymous_function_types.jsonc",
"var_names_file": "decompiler/config/jak3/var_names.jsonc", "var_names_file": "decompiler/config/jak3/ntsc_v1/var_names.jsonc",
"label_types_file": "decompiler/config/jak3/label_types.jsonc", "label_types_file": "decompiler/config/jak3/ntsc_v1/label_types.jsonc",
"stack_structures_file": "decompiler/config/jak3/stack_structures.jsonc", "stack_structures_file": "decompiler/config/jak3/ntsc_v1/stack_structures.jsonc",
"hacks_file": "decompiler/config/jak3/hacks.jsonc", "hacks_file": "decompiler/config/jak3/ntsc_v1/hacks.jsonc",
"inputs_file": "decompiler/config/jak3/inputs.jsonc", "inputs_file": "decompiler/config/jak3/ntsc_v1/inputs.jsonc",
"art_info_file": "decompiler/config/jak3/art_info.jsonc", "art_info_file": "decompiler/config/jak3/ntsc_v1/art_info.jsonc",
"import_deps_file": "decompiler/config/jak3/import_deps.jsonc", "import_deps_file": "decompiler/config/jak3/ntsc_v1/import_deps.jsonc",
"all_types_file": "decompiler/config/jak3/all-types.gc", "all_types_file": "decompiler/config/jak3/all-types.gc",
"art_group_dump_file": "decompiler/config/jak3/ntsc_v1/art-group-info.min.json",
"joint_node_dump_file": "decompiler/config/jak3/ntsc_v1/joint-node-info.min.json",
// optional: a predetermined object file name map from a file. // optional: a predetermined object file name map from a file.
// this will make decompilation naming consistent even if you only run on some objects. // this will make decompilation naming consistent even if you only run on some objects.

View File

@ -0,0 +1 @@
{}

View File

@ -1,4 +1,6 @@
{ {
"files": {}, "files": {},
"functions": {} "functions": {},
"type_remap": {},
"joint_node_hacks": {}
} }

View File

@ -3,51 +3,761 @@
// HACKS and ASM FUNCTIONS // HACKS and ASM FUNCTIONS
//////////////////////////// ////////////////////////////
"types_with_bad_inspect_methods": [], "types_with_bad_inspect_methods": [
"game-task-event",
"game-task-control",
"predator-edge",
"manipy"
],
"no_type_analysis_functions_by_name": [], "no_type_analysis_functions_by_name": [],
// this limits the number of cases in a cond. The first argument is the name of the function. // this limits the number of cases in a cond. The first argument is the name of the function.
// the second argument is the name of the first condition in the cond. Use print_cfg to find it out. // the second argument is the name of the first condition in the cond. Use print_cfg to find it out.
// The third argument is the number of cases. If you set it too small it may fail to build the CFG. // The third argument is the number of cases. If you set it too small it may fail to build the CFG.
"cond_with_else_max_lengths": [], "cond_with_else_max_lengths": [
["(method 20 res-lump)", "b0", 2],
["(method 11 res-lump)", "b0", 1],
["(method 12 res-lump)", "b0", 1]
],
// if a cond with an else case is being used a value in a place where it looks wrong // if a cond with an else case is being used a value in a place where it looks wrong
// you can add the function name to this list and it will more aggressively reject this rewrite. // you can add the function name to this list and it will more aggressively reject this rewrite.
"aggressively_reject_cond_to_value_rewrite": [], "aggressively_reject_cond_to_value_rewrite": [
"(method 10 res-lump)",
"(method 11 res-lump)",
"(method 12 res-lump)"
],
// this provides a hint to the decompiler that these functions will have a lot of inline assembly. // this provides a hint to the decompiler that these functions will have a lot of inline assembly.
// currently it just leaves pcpyld as an asm op. // currently it just leaves pcpyld as an asm op.
"hint_inline_assembly_functions": [], "hint_inline_assembly_functions": [],
"asm_functions_by_name": [], "asm_functions_by_name": [
// checking boxed type is different now - these make the cfg stuff sad
"name=",
"(method 77 grenadier)",
// until loop without nop:
"target-history-print",
"display-list-control",
"anim-test-anim-list-handler",
"anim-test-sequence-list-handler",
"anim-tester-get-playing-item",
"start-pilot-recorder",
"(anon-function 10 pilot-recorder)",
"(anon-function 10 sig-recorder)",
// actual asm
"quad-copy!",
"return-from-thread",
"return-from-thread-dead",
"reset-and-call",
"(method 10 cpu-thread)",
"(method 11 cpu-thread)",
"(method 0 catch-frame)",
"throw-dispatch",
"throw",
"run-function-in-process",
"set-to-run-bootstrap",
"return-from-exception",
"exp",
"(method 17 bounding-box)",
"(method 9 bounding-box)",
"(method 9 matrix)",
"quaternion->matrix-2",
"sin-rad",
"cos-rad",
"atan-series-rad",
"sign-float",
"dma-count-until-done",
"(method 11 collide-mesh-cache)",
"cpu-delay",
"qword-read-time",
"dma-test-func",
"move-test-func",
"symlink2",
"blerc-a-fragment",
"blerc-execute",
"foreground-check-longest-edge-asm",
"generic-light-proc",
"shadow-add-single-edges",
"shadow-add-facing-single-tris",
"shadow-add-double-tris",
"shadow-add-double-edges",
"(method 17 collide-edge-work)",
"(method 10 collide-cache-prim)",
"(method 17 collide-cache)",
"(method 16 ocean)",
// unknown instructions
"debug-line-clip?",
// logand with #f arg
"bugfix?",
// CFG failed
"draw-inline-array-instance-shrub",
"(method 9 editable-region)", // condition branch assert hit
"test-to-from-spr",
"test-from-spr",
"test-to-spr",
"test-seq-read",
"test-worst-read",
"test-seq-write",
"test-worst-write",
// texture
"adgif-shader<-texture!",
// jak 3
"borrow-city-expansion",
"(method 26 level-group)",
"(anon-function 65 temple-obs)",
"(method 33 task-manager-nest-cocoons)",
"(method 33 rub-tower)",
"(method 261 crimson-guard)",
"(anon-function 25 volcanox-obs)"
],
// these functions use pairs and the decompiler // these functions use pairs and the decompiler
// will be less picky about types related to pairs. // will be less picky about types related to pairs.
"pair_functions_by_name": [], "pair_functions_by_name": [
"ref",
"(method 4 pair)",
"last",
"member",
"nmember",
"assoc",
"assoce",
"nassoc",
"nassoce",
"append!",
"delete!",
"delete-car!",
"insert-cons!",
"sort",
"unload-package",
"display-loop-main",
"lookup-level-info",
"(method 24 level-group)",
"(method 19 level-group)",
// script
"command-get-time",
"command-get-param",
"command-get-quoted-param",
"command-get-entity",
"(method 9 script-context)",
"(anon-function 6 script)",
"(anon-function 49 script)",
"(anon-function 52 script)",
"(anon-function 72 script)",
"(anon-function 73 script)",
"(anon-function 74 script)",
"(anon-function 75 script)",
"(anon-function 76 script)",
"(anon-function 80 script)",
"(method 11 script-context)",
"(method 10 script-context)",
"command-get-trans",
"key-assoc",
"(anon-function 0 script)",
// default-menu
"dm-scene-load-pick-func",
"debug-menu-make-continue-sub-menu",
"debug-menu-make-from-template",
"debug-menu-context-make-default-menus",
"debug-menu-make-task-menu",
"(method 19 gui-control)",
// menu
"debug-menu-rebuild",
"debug-menu-find-from-template",
"debug-menu-render",
"debug-menu-context-select-next-or-prev-item",
"debug-menu-context-select-new-item",
"debug-menu-send-msg",
// airlock
"(method 24 com-airlock)",
"(method 19 gui-control)",
"(method 28 editable)",
"execute-select",
"(method 29 editable)",
"(method 25 editable)",
// game-info
"(method 20 game-info)",
"print-continues",
// task-control
"(anon-function 55 task-control)",
"(method 17 load-state)",
"(method 12 level)",
"bg",
"update-sound-banks",
"entity-remap-names",
"(method 8 process-tree)",
"(post play-anim scene-player)",
"(method 25 scene-player)",
"(method 25 scene-player)",
"scene-player-init",
"next-continue",
"(method 25 warp-gate)",
"(code use warp-gate)",
"cspace-inspect-tree",
"(method 11 mtn-step-plat-rocks-a)",
"(method 11 mtn-step-plat-rocks-b)",
"(method 11 mtn-step-plat-rocks-c)",
"(method 22 fort-floor-spike-b)",
"prototypes-game-visible-set!",
"(method 22 fort-floor-spike-a)",
"(method 22 fort-floor-spike-b)",
"(method 22 fort-floor-spike-c)",
"(method 11 sew-catwalk)",
"(method 11 mtn-aval-rocks)",
"(method 11 gar-curtain)"
],
// If format is used with the wrong number of arguments, // If format is used with the wrong number of arguments,
// it will often mess up the decompilation, as the decompiler assumes // it will often mess up the decompilation, as the decompiler assumes
// that they used the correct number. This will override the decompiler's // that they used the correct number. This will override the decompiler's
// automatic detection. // automatic detection.
"bad_format_strings": {}, "bad_format_strings": {
"~170h~5d~220h~5d~280h~5,,2f": 3,
"~338h~5d~388h~5d~448h~5,,2f": 3,
"~30Htf: ~8D~134Hpr: ~8D~252Hsh: ~8D~370Hhd: ~8D~%": 4,
"~30Hal: ~8D~131Hwa: ~8D~252Hsp: ~8D~370Hwp: ~8D~%": 4,
"ERROR: <asg> ~A in spool anim loop for ~A ~D, but not loaded.~": 3,
// TODO - these should be automatic
" tfrag ~192H~5DK ~280Htfragment~456H~5DK~%": 2,
" tie-proto ~192H~5DK ~280Hsky~456H~5DK~%": 2,
" tie-instance ~192H~5DK ~280Htie-fragment~456H~5DK~%": 2,
" shrub-proto ~192H~5DK ~280Htie-scissor~456H~5DK~%": 2,
" shrub-instance ~192H~5DK ~280Hshrubbery~456H~5DK~%": 2,
" collision ~192H~5DK ~280Htie-generic~456H~5DK~%": 2,
" pris-anim ~192H~5DK ~280Hpris-generic~456H~5DK~%": 2,
" textures ~192H~5DK ~280Htextures~456H~5DK~%": 2,
" misc ~192H~5DK ~280Hsprite~456H~5DK~%": 2,
" entity ~192H~5DK~%": 1,
" pris-geo ~192H~5DK ~280Hpris-fragment~456H~5DK~%": 2,
"~33L~S~32L ~S": 2,
"~32L~S ~33L~S~1L": 2,
"~35L~S~33L ~S": 2,
"~1L~S~35L ~S": 2,
"~35L~S ~1L~S~1L": 2,
"~33L~S~35L ~S": 2,
"~33L~C~34L~S~33L~C": 3,
"~35L~S ~33L~S~1L": 2,
"~33L~S ~35L~S~1L": 2,
"~33L~C": 1
},
"blocks_ending_in_asm_branch": {}, "blocks_ending_in_asm_branch": {
"closest-pt-in-triangle": [17],
// this one is all asm branches
"circle-circle-xz-intersect": [
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14
],
"load-game-text-info": [15, 16, 17, 19, 20, 21],
"find-knot-span": [0, 1, 2, 3, 5, 6, 7, 8, 9],
"curve-evaluate!": [0, 2, 5, 6, 7, 8, 9],
"display-loop-main": [127, 130, 133, 136],
"real-main-draw-hook": [114, 115, 116, 118],
"sprite-draw-distorters": [4, 5],
"draw-drawable-tree-instance-shrub": [5, 7, 9, 11],
"add-debug-box-with-transform": [0, 3],
"add-debug-line-sphere": [0],
"(method 12 perf-stat)": [0],
"(method 11 perf-stat)": [0],
"bsp-camera-asm": [1, 2, 3, 4, 6, 7],
"(method 9 texture-page-dir)": [5, 6],
"level-remap-texture": [2, 3, 4, 5, 6],
"(method 27 nav-mesh)": [1, 2],
"(method 31 nav-mesh)": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11],
"(method 46 nav-mesh)": [2, 3],
"(method 32 nav-mesh)": [1, 2],
"(method 33 nav-mesh)": [1, 2],
"(method 42 nav-mesh)": [1, 2, 3, 7],
"point-poly-distance-min": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12],
"(method 34 nav-mesh)": [1, 2, 3, 7],
"(method 35 nav-mesh)": [2, 4],
"draw-actor-marks": [8],
"find-nearest-entity": [7, 9, 10, 11, 12, 13, 14],
"start-perf-stat-collection": [26],
"end-perf-stat-collection": [0],
"upload-vis-bits": [2, 6, 3, 0],
"set-background-regs!": [4, 3],
"draw-drawable-tree-instance-tie": [21, 23, 31, 33],
"command-get-process": [43],
"unpack-comp-rle": [1, 3, 5, 6],
"(method 16 level)": [0, 1, 5, 13, 14, 15],
"unpack-comp-huf": [2, 4, 5, 6, 7, 8, 9],
"unpack-comp-lzo": [
0,
1,
4,
5,
6,
7,
15,
16,
17,
18,
19,
20,
21,
22,
23,
24,
25,
26,
27,
28,
29,
30,
31,
32,
33,
34,
35, // branch fwd 39
39, // branch fwd no delay
43, // goto 18
45 // goto 6
],
"(method 27 conveyor)": [5, 14, 22],
"(method 44 nav-graph)": [
0, 1, 2, 3, 4, 5, 6, 7, 8, 14, 15, 16, 17, 18, 22, 24, 25, 26, 27, 30, 31,
32, 33, 34, 35, 36
],
"(method 11 sparticle-launch-control)": [
18, 24, 25, 28, 29, 32, 33, 34, 36, 41, 55, 58, 93, 95
],
"(method 22 gui-control)": [
10, // goto L63 (B39)
16, // goto L58 (B27)
26, // goto L62 (B)
27, // goto L62
28, // goto L61
35, // goto L62
36, // goto L62
38, // goto L99
42, // goto L89
50, // goto L84
108, // goto L86
110, // goto L86
116, // goto L99
117, // goto L91
120
],
"(anon-function 11 game-save)": [0, 3, 4, 5],
"update-actor-hash": [0, 2, 4],
"(code target-death)": [111, 140],
"(method 13 collide-cache)": [7, 9],
"(method 11 collide-mesh)": [2, 4],
"(method 12 collide-mesh-cache)": [0, 1, 2, 3, 4, 5],
"(method 10 collide-mesh)": [2],
"(method 42 collide-shape)": [0, 1, 2, 3, 4, 7],
"(method 18 collide-shape-prim-mesh)": [2, 3, 4, 5, 6, 7],
"(method 18 collide-shape-prim-sphere)": [2, 3, 4],
"(method 15 collide-shape-prim-sphere)": [1, 2, 3, 4, 5, 6],
"(method 16 collide-shape-prim-sphere)": [0, 1, 2, 3, 4],
"(method 36 collide-shape)": [8, 9],
"(method 45 collide-shape)": [33],
"(method 40 collide-shape)": [
0, 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
],
"(method 12 collide-shape-prim-group)": [1, 2, 3, 4, 5, 6],
"(method 13 collide-shape-prim)": [1, 2, 3, 4, 5, 6],
"(method 12 collide-shape-prim-sphere)": [
1, 2, 3, 4, 5, 8, 10, 11, 13, 14, 15
],
"(method 12 collide-shape-prim-mesh)": [
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 14, 15, 16
],
"(method 24 grid-hash)": [39, 35, 22, 15],
"(method 12 flow-control)": [11, 12, 13, 14, 15, 18, 20, 22, 29],
"(method 19 process-drawable)": [0, 2, 3, 7, 10, 11, 30],
"find-offending-process-focusable": [16, 19],
"target-standard-event-handler": [
5, // fwd L31/7
6, // to 152
7, // fwd L38
20, // to 152
21, // fwd L39
22, // to 152
23, // to L40
24, // to 152
25, // to L45
43, // to l152
44, // to 46
45, // to l152
46, // to l114
190, // to l152
191, // to 121
210,
211,
212,
213,
214,
224,
225,
226,
227,
232,
233,
234,
235,
236,
237,
238,
239,
240,
241,
242,
255,
256,
269,
270,
285,
286,
287,
288,
289,
290
],
"bones-mtx-calc-execute": [19, 7],
"foreground-draw": [0, 1, 126],
"dma-add-process-drawable": [0, 136],
"(anon-function 3 ruins-obs)": [14, 22],
"(anon-function 0 target-death)": [
50, // goto 52
51, // goto L65
63, // goto L47
73, // goto L25
78, // goto L46
84, // goto L42
95, // goto next
96, // goto L36
115, // goto L55
121,
131
],
"(anon-function 4 gun-states)": [94, 96, 98],
"target-board-handler": [13, 14, 18],
"find-closest-circle-ray-intersection": [0, 4, 15, 16, 17, 18],
"(method 18 nav-control)": [
11, // L283
12, // L300
19, // L295
20, // L293
31, // weird jump back
34 // weird jump no delay slot
],
"(method 19 nav-control)": [9, 10],
"(method 19 nav-mesh)": [7],
"(method 18 nav-mesh)": [9],
"(method 40 nav-state)": [1, 2],
"(method 45 nav-mesh)": [5, 6],
"(method 43 nav-mesh)": [0, 1, 2, 12, 13, 14, 15, 16, 17, 18, 19, 20],
"(anon-function 45 gungame-obs)": [0, 1, 6, 9, 14, 18, 21, 22, 30], // TODO - probably not the best
"(method 142 grenadier)": [0, 1, 3],
"(anon-function 34 predator)": [24],
"(anon-function 57 crimson-guard-level)": [22],
"(method 48 rigid-body-object)": [0, 1, 2, 3, 4, 5],
"(method 15 rigid-body)": [0, 1, 2, 5],
"(method 63 collide-shape-moving)": [
0, 1, 2, 3, 4, 5, 6, 10, 12, 13, 14, 28, 38, 39, 40, 44
],
"string-word-wrap": [1, 2, 6],
"(method 37 vehicle)": [0, 1, 10, 11, 12, 13, 15, 16],
"(method 123 vehicle)": [
0, 1, 2, 3, 4, 7, 8, 9, 10, 17, 19, 20, 23, 26, 30, 31, 32, 33, 34
],
"(method 122 vehicle)": [0, 1, 10, 11, 17, 18, 19, 20, 21, 22, 24, 25],
"(method 48 vehicle)": [
0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 16, 17, 23, 24, 29, 30, 31
],
"(method 11 vehicle-hud-requests)": [0, 6, 7, 10, 11, 12],
"(method 17 traffic-manager)": [
0, 4, 7, 17, 23, 25, 26, 27, 28, 39, 42, 43, 44
],
"(anon-function 12 vehicle-states)": [0, 1, 2, 3],
"(method 45 traffic-engine)": [5, 8],
"(method 15 city-level-info)": [0, 1, 2, 6, 7, 9, 11, 13],
"(method 59 traffic-engine)": [5, 6, 7, 8, 9, 10],
"(method 10 traffic-suppressor)": [0, 1, 2, 4],
"(method 18 traffic-tracker)": [2, 3, 5, 6, 7, 8],
"(method 181 gator)": [
2, 3, 7, 10, 11, 14, 15, 16, 17, 18, 19, 20, 21, 22, 25, 26, 30
],
"(method 10 simple-sprite-system)": [0],
"target-pilot-post": [0, 2, 4, 13, 16, 22, 27, 41],
"(anon-function 0 ruins-obs)": [
0, 5, 7, 12, 13, 15, 17, 23, 24, 33, 42, 45, 46, 53, 58
],
"(anon-function 1 ruins-obs)": [
1, 2, 4, 6, 7, 14, 17, 19, 22, 24, 26, 27, 29, 31, 33, 35
],
"(anon-function 2 ruins-obs)": [7, 28, 37, 50, 51, 61, 62, 71],
"(anon-function 62 sig0-course)": [0, 1, 5, 6],
"(method 67 collide-shape-moving)": [0, 1, 2, 3, 11, 12, 13],
"(anon-function 12 juicer)": [29, 30],
"(anon-function 0 atoll-obs)": [11, 19, 20],
"(method 74 spydroid)": [12], // stack spill delay slot
"(anon-function 16 kid-states)": [4, 5],
"(anon-function 23 kid-states)": [4, 5],
"(anon-function 16 kor-states)": [4, 5],
"(anon-function 23 kor-states)": [4, 5],
"(method 18 mysql-nav-graph)": [0, 1, 2, 3, 4, 7, 8, 9, 14, 16],
"(anon-function 2 rigid-body-queue)": [0, 1, 2, 3],
"(method 15 rigid-body-queue)": [5, 6, 7, 8, 9, 10, 11],
"(method 13 rigid-body-queue)": [5, 6, 7, 8, 9, 10, 11],
"(method 11 rigid-body-queue)": [0, 5, 6, 7, 8, 9, 10, 11, 17, 18, 25],
"(method 10 rigid-body-queue)": [0, 9, 10, 16, 24, 25, 26, 35, 36, 48],
"(method 18 vehicle-controller)": [0, 1, 74, 75],
"(method 15 vehicle-controller)": [0, 3, 5, 6, 7, 10],
"(anon-function 41 guard)": [9],
"(anon-function 10 metalhead-predator)": [24, 25],
"(anon-function 10 errol-chal)": [6],
"choose-next-branch-no-exit-level": [0, 6, 8, 12, 13, 16, 18, 26],
"(anon-function 39 kidesc-states)": [4, 5],
"(anon-function 56 hal2-course)": [4, 5],
"(anon-function 58 hal2-course)": [74],
"(method 142 gun-buoy)": [0, 2],
"generic-merc-execute-all": [7, 15]
},
// Sometimes the game might use format strings that are fetched dynamically, // Sometimes the game might use format strings that are fetched dynamically,
// for example using the game text lookup method // for example using the game text lookup method
// Add information about those format instructions here. // Add information about those format instructions here.
// e.g. "function-name":[[op, argc], [op, argc], ...] // e.g. "function-name":[[op, argc], [op, argc], ...]
// where "op" is the op number for the call to format. // where "op" is the op number for the call to format.
"dynamic_format_arg_counts": {}, "dynamic_format_arg_counts": {
"(method 10 menu-loading-option)": [[118, 1]],
"(method 10 menu-insufficient-space-option)": [
[63, 1],
[103, 1]
],
"(method 10 menu-secrets-insufficient-space-option)": [[55, 1]],
"(method 10 menu-card-removed-option)": [[48, 1]],
"(method 10 menu-format-card-option)": [[49, 1]],
"(method 10 menu-create-game-option)": [[49, 1]],
"(method 10 menu-error-auto-saving-option)": [[72, 1]],
"(method 10 menu-error-loading-option)": [
[64, 1],
[99, 1]
],
"(method 10 menu-insert-card-option)": [[48, 1]],
"(method 16 fail-mission)": [
[68, 1],
[101, 1],
[130, 1]
],
"auto-save-post": [[158, 1]],
"(method 30 training-manager)": [[53, 0]],
"(trans course training-manager)": [
[54, 0],
[89, 0],
[124, 0],
[155, 0],
[195, 0],
[230, 0],
[261, 0],
[307, 0],
[338, 0],
[374, 0],
[409, 0],
[444, 0],
[479, 0],
[510, 0]
],
"(method 17 hud-goal)": [[71, 0]],
"(method 15 hud-miss)": [[44, 0]],
"(method 28 hoverboard-training-manager)": [[53, 0]],
"(method 29 hoverboard-training-manager)": [
[48, 0],
[83, 0],
[118, 0],
[153, 0],
[184, 0],
[224, 0],
[259, 0],
[294, 0],
[325, 0],
[365, 0],
[400, 0],
[431, 0],
[477, 0],
[508, 0]
],
"(trans menu burning-bush)": [
[294, 0],
[378, 0],
[406, 0],
[434, 0],
[462, 0],
[490, 0],
[518, 0],
[350, 0]
],
"(trans idle burning-bush)": [[171, 0]],
"(anon-function 11 oracle-training)": [[79, 0]],
"(anon-function 4 oracle-training)": [[79, 0]],
"(anon-function 0 oracle-training)": [[79, 0]],
"(anon-function 7 oracle-training)": [[79, 0]],
"(method 27 sig-recorder)": [[93, 0]],
"(method 15 hud-race-final-stats)": [[158, 1]],
"(method 24 race-manager)": [[67, 1]],
"(method 25 race-manager)": [
[67, 1],
[96, 1]
]
},
"mips2c_functions_by_name": [], "mips2c_functions_by_name": [
"collide-do-primitives",
"moving-sphere-triangle-intersect",
"calc-animation-from-spr",
"draw-string-asm",
"draw-string",
"get-string-length",
"adgif-shader<-texture-with-update!",
"init-boundary-regs",
"draw-boundary-polygon",
"render-boundary-quad",
"render-boundary-tri",
"clip-polygon-against-negative-hyperplane",
"clip-polygon-against-positive-hyperplane",
"sp-init-fields!",
"particle-adgif",
"sp-launch-particles-var",
"sparticle-motion-blur",
"sp-process-block-2d",
"sp-process-block-3d",
"set-tex-offset",
"draw-large-polygon",
"render-sky-quad",
"render-sky-tri",
"(method 16 sky-work)",
"(method 17 sky-work)",
"(method 32 sky-work)",
"(method 33 sky-work)",
// "(method 28 sky-work)",
"(method 29 sky-work)",
"(method 30 sky-work)",
"(method 11 collide-hash)",
"(method 12 collide-hash)",
"fill-bg-using-box-new",
"fill-bg-using-line-sphere-new",
"(method 12 collide-mesh)",
"(method 11 collide-mesh)",
"(method 14 collide-mesh)",
"(method 15 collide-mesh)",
"(method 10 collide-edge-hold-list)",
"(method 19 collide-edge-work)",
"(method 9 edge-grab-info)",
"(method 16 collide-edge-work)",
"(method 17 collide-edge-work)",
"(method 18 collide-edge-work)",
"draw-large-polygon-ocean",
"render-ocean-quad",
"init-ocean-far-regs",
"(method 14 ocean)",
"(method 15 ocean)",
"(method 16 ocean)",
"(method 18 grid-hash)",
"(method 19 grid-hash)",
"(method 20 grid-hash)",
"(method 22 grid-hash)",
"(method 28 sphere-hash)",
"(method 33 sphere-hash)",
"(method 29 sphere-hash)",
"(method 30 sphere-hash)",
"(method 31 sphere-hash)",
"(method 32 sphere-hash)",
"(method 33 spatial-hash)",
"(method 39 spatial-hash)",
"(method 36 spatial-hash)",
"(method 37 spatial-hash)",
"(method 35 spatial-hash)",
"(method 10 collide-shape-prim-mesh)",
"(method 10 collide-shape-prim-sphere)",
"(method 10 collide-shape-prim-group)",
"(method 11 collide-shape-prim-mesh)",
"(method 11 collide-shape-prim-sphere)",
"(method 11 collide-shape-prim-group)",
"(method 9 collide-cache-prim)",
"(method 10 collide-cache-prim)",
"(method 17 collide-cache)",
"(method 9 collide-puss-work)",
"(method 10 collide-puss-work)",
"bones-mtx-calc",
"foreground-check-longest-edge-asm",
"foreground-merc",
"add-light-sphere-to-light-group",
"light-hash-add-items",
"light-hash-count-items",
"light-hash-get-bucket-index",
// nav-mesh / nav-control related
// TODO - it would be nice to eventually figure out the asm blocks for the majority of these
"nav-state-patch-pointers",
"(method 20 nav-engine)",
// "find-closest-circle-ray-intersection",
// "(method 18 nav-control)",
"nav-dma-send-to-spr-no-flush",
"nav-dma-send-from-spr-no-flush",
"(method 17 nav-engine)",
"(method 18 nav-engine)",
"(method 21 nav-engine)",
"(method 39 nav-state)",
"setup-blerc-chains-for-one-fragment",
"blerc-execute",
"ripple-create-wave-table",
"ripple-execute-init",
"ripple-apply-wave-table",
"ripple-matrix-scale",
"(method 53 squid)",
"init-vortex-regs",
"render-vortex-quad",
"draw-large-polygon-vortex",
"foreground-generic-merc",
"generic-merc-init-asm",
"mercneric-convert",
"high-speed-reject",
"generic-translucent",
"generic-merc-query",
"generic-merc-death",
"generic-merc-execute-asm",
"generic-merc-do-chain",
"generic-light-proc",
"generic-envmap-proc",
"generic-prepare-dma-double",
"generic-prepare-dma-single",
"generic-warp-source-proc",
"generic-warp-dest-proc",
"generic-warp-dest",
"generic-warp-envmap-dest",
"generic-no-light-proc"
],
"mips2c_jump_table_functions": {}, "mips2c_jump_table_functions": {},
// there are some missing textures. I don't know what the game actually does here. // there are some missing textures. I don't know what the game actually does here.
// the format for entries is [level, tpage, index] // the format for entries is [level, tpage, index]
"missing_textures": [], "missing_textures": [["vinroom", 0, 0]],
// some object files have garbage pad data at the end which makes the decompiler // some object files have garbage pad data at the end which makes the decompiler
// assume they must be different files, such as the art group for orb-cache-top. // assume they must be different files, such as the art group for orb-cache-top.

View File

@ -10,281 +10,281 @@
"dgo_names":[ "dgo_names":[
//"CGO/ART.CGO", //"CGO/ART.CGO",
"CGO/KERNEL.CGO", "CGO/KERNEL.CGO",
"CGO/ENGINE.CGO", // "CGO/ENGINE.CGO",
"CGO/GAME.CGO", "CGO/GAME.CGO",
"CGO/COMMON.CGO" // "CGO/COMMON.CGO",
//"DGO/LJKDMPK.DGO", "DGO/LJKDMPK.DGO",
//"DGO/LBBSDRP1.DGO", "DGO/LBBSDRP1.DGO",
//"DGO/LTNJXHIP.DGO", "DGO/LTNJXHIP.DGO",
//"DGO/MIC.DGO", "DGO/MIC.DGO",
//"DGO/OASISCST.DGO", "DGO/OASISCST.DGO",
//"DGO/CTYPEPA.DGO", "DGO/CTYPEPA.DGO",
//"DGO/LPRENME.DGO", "DGO/LPRENME.DGO",
//"DGO/LFREEOUT.DGO", "DGO/LFREEOUT.DGO",
//"DGO/LGUNNORM.DGO", "DGO/LGUNNORM.DGO",
//"DGO/LTOWA.DGO", "DGO/LTOWA.DGO",
//"DGO/TEMA.DGO", "DGO/TEMA.DGO",
//"DGO/CTA.DGO", "DGO/CTA.DGO",
//"DGO/LPRECC.DGO", "DGO/LPRECC.DGO",
//"DGO/LJKDXVIN.DGO", "DGO/LJKDXVIN.DGO",
//"DGO/CTYPEPC.DGO", "DGO/CTYPEPC.DGO",
//"DGO/SEA.DGO", "DGO/SEA.DGO",
//"DGO/COMBE.DGO", "DGO/COMBE.DGO",
//"DGO/CTYPESA.DGO", "DGO/CTYPESA.DGO",
//"DGO/LBLOWCST.DGO", "DGO/LBLOWCST.DGO",
//"DGO/WSD.DGO", "DGO/WSD.DGO",
//"DGO/LBBRING3.DGO", "DGO/LBBRING3.DGO",
//"DGO/LCTYPATK.DGO", "DGO/LCTYPATK.DGO",
//"DGO/WCB.DGO", "DGO/WCB.DGO",
//"DGO/DESRESC.DGO", "DGO/DESRESC.DGO",
//"DGO/LBBRING4.DGO", "DGO/LBBRING4.DGO",
//"DGO/GRIDCST.DGO", "DGO/GRIDCST.DGO",
//"DGO/RAILX.DGO", "DGO/RAILX.DGO",
//"DGO/SEJ.DGO", "DGO/SEJ.DGO",
//"DGO/LJAKC.DGO", "DGO/LJAKC.DGO",
//"DGO/CTB.DGO", "DGO/CTB.DGO",
//"DGO/CTYCARC.DGO", "DGO/CTYCARC.DGO",
//"DGO/LMECH.DGO", "DGO/LMECH.DGO",
//"DGO/LBBSDRP2.DGO", "DGO/LBBSDRP2.DGO",
//"DGO/NSA.DGO", "DGO/NSA.DGO",
//"DGO/LBBTCHA3.DGO", "DGO/LBBTCHA3.DGO",
//"DGO/GUNGAME2.DGO", "DGO/GUNGAME2.DGO",
//"DGO/CTC.DGO", "DGO/CTC.DGO",
//"DGO/LVINCST.DGO", "DGO/LVINCST.DGO",
//"DGO/COMBX.DGO", "DGO/COMBX.DGO",
//"DGO/DESH.DGO", "DGO/DESH.DGO",
//"DGO/DESRACE2.DGO", "DGO/DESRACE2.DGO",
//"DGO/RAILD.DGO", "DGO/RAILD.DGO",
//"DGO/FACC.DGO", "DGO/FACC.DGO",
//"DGO/CTYPESC.DGO", "DGO/CTYPESC.DGO",
//"DGO/LWASBBV.DGO", "DGO/LWASBBV.DGO",
//"DGO/TOWB.DGO", "DGO/TOWB.DGO",
//"DGO/HGA.DGO", "DGO/HGA.DGO",
//"DGO/SEH.DGO", "DGO/SEH.DGO",
//"DGO/MHCTYCST.DGO", "DGO/MHCTYCST.DGO",
//"DGO/GUNGAME1.DGO", "DGO/GUNGAME1.DGO",
//"DGO/INTROCST.DGO", "DGO/INTROCST.DGO",
//"DGO/DESJUMP.DGO", "DGO/DESJUMP.DGO",
//"DGO/SEM.DGO", "DGO/SEM.DGO",
//"DGO/SEI.DGO", "DGO/SEI.DGO",
//"DGO/DESG.DGO", "DGO/DESG.DGO",
//"DGO/DESW.DGO", "DGO/DESW.DGO",
//"DGO/LOUTRO3.DGO", "DGO/LOUTRO3.DGO",
//"DGO/LDAMKLEV.DGO", "DGO/LDAMKLEV.DGO",
//"DGO/DESERROL.DGO", "DGO/DESERROL.DGO",
//"DGO/RAILB2.DGO", "DGO/RAILB2.DGO",
//"DGO/LERROL.DGO", "DGO/LERROL.DGO",
//"DGO/IPF.DGO", "DGO/IPF.DGO",
//"DGO/RAILB.DGO", "DGO/RAILB.DGO",
//"DGO/LCTYHIJK.DGO", "DGO/LCTYHIJK.DGO",
//"DGO/CTYPEPB.DGO", "DGO/CTYPEPB.DGO",
//"DGO/PRECB.DGO", "DGO/PRECB.DGO",
//"DGO/LFORM.DGO", "DGO/LFORM.DGO",
//"DGO/WASLEAPR.DGO", "DGO/WASLEAPR.DGO",
//"DGO/LKEIRA.DGO", "DGO/LKEIRA.DGO",
//"DGO/LJAK.DGO", "DGO/LJAK.DGO",
//"DGO/SLUMBSET.DGO", "DGO/SLUMBSET.DGO",
//"DGO/FACD.DGO", "DGO/FACD.DGO",
//"DGO/LWASSIG.DGO", "DGO/LWASSIG.DGO",
//"DGO/LBIPED.DGO", "DGO/LBIPED.DGO",
//"DGO/DESD.DGO", "DGO/DESD.DGO",
//"DGO/CFB.DGO", "DGO/CFB.DGO",
//"DGO/FREECAST.DGO", "DGO/FREECAST.DGO",
//"DGO/SEG.DGO", "DGO/SEG.DGO",
//"DGO/FACTORYA.DGO", "DGO/FACTORYA.DGO",
//"DGO/LPATK.DGO", "DGO/LPATK.DGO",
//"DGO/FRSTX.DGO", "DGO/FRSTX.DGO",
//"DGO/SEB.DGO", "DGO/SEB.DGO",
//"DGO/DESBCST.DGO", "DGO/DESBCST.DGO",
//"DGO/DESE.DGO", "DGO/DESE.DGO",
//"DGO/DESOASIS.DGO", "DGO/DESOASIS.DGO",
//"DGO/CTYCARA.DGO", "DGO/CTYCARA.DGO",
//"DGO/LSIGKLV.DGO", "DGO/LSIGKLV.DGO",
//"DGO/CIB.DGO", "DGO/CIB.DGO",
//"DGO/LBBRING2.DGO", "DGO/LBBRING2.DGO",
//"DGO/LTNFXHIP.DGO", "DGO/LTNFXHIP.DGO",
//"DGO/MIA.DGO", "DGO/MIA.DGO",
//"DGO/MHCB.DGO", "DGO/MHCB.DGO",
//"DGO/LNSTOBC.DGO", "DGO/LNSTOBC.DGO",
//"DGO/COMBD.DGO", "DGO/COMBD.DGO",
//"DGO/RBCT.DGO", "DGO/RBCT.DGO",
//"DGO/LTORNJNX.DGO", "DGO/LTORNJNX.DGO",
//"DGO/DESBATTL.DGO", "DGO/DESBATTL.DGO",
//"DGO/SEK.DGO", "DGO/SEK.DGO",
//"DGO/LSNKWHLS.DGO", "DGO/LSNKWHLS.DGO",
//"DGO/LMHCB.DGO", "DGO/LMHCB.DGO",
//"DGO/LBOMBBOT.DGO", "DGO/LBOMBBOT.DGO",
//"DGO/OUTCAST3.DGO", "DGO/OUTCAST3.DGO",
//"DGO/LBLOWTMH.DGO", "DGO/LBLOWTMH.DGO",
//"DGO/TEMD.DGO", "DGO/TEMD.DGO",
//"DGO/LTOWCITY.DGO", "DGO/LTOWCITY.DGO",
//"DGO/OUTROCST.DGO", "DGO/OUTROCST.DGO",
//"DGO/WASCAST.DGO", "DGO/WASCAST.DGO",
//"DGO/LFACRM2.DGO", "DGO/LFACRM2.DGO",
//"DGO/WASPGAME.DGO", "DGO/WASPGAME.DGO",
//"DGO/RAILE.DGO", "DGO/RAILE.DGO",
//"DGO/CTYPESB.DGO", "DGO/CTYPESB.DGO",
//"DGO/DESBOSS1.DGO", "DGO/DESBOSS1.DGO",
//"DGO/FREEHQ.DGO", "DGO/FREEHQ.DGO",
//"DGO/LTORN.DGO", "DGO/LTORN.DGO",
//"DGO/TOWERA.DGO", "DGO/TOWERA.DGO",
//"DGO/LSAMOS.DGO", "DGO/LSAMOS.DGO",
//"DGO/LFORP.DGO", "DGO/LFORP.DGO",
//"DGO/CFA.DGO", "DGO/CFA.DGO",
//"DGO/LJINX.DGO", "DGO/LJINX.DGO",
//"DGO/SEO.DGO", "DGO/SEO.DGO",
//"DGO/PRECA.DGO", "DGO/PRECA.DGO",
//"DGO/TOWERC.DGO", "DGO/TOWERC.DGO",
//"DGO/WCA.DGO", "DGO/WCA.DGO",
//"DGO/SEC.DGO", "DGO/SEC.DGO",
//"DGO/DESF.DGO", "DGO/DESF.DGO",
//"DGO/SEL.DGO", "DGO/SEL.DGO",
//"DGO/LCTYDEST.DGO", "DGO/LCTYDEST.DGO",
//"DGO/LTORNSAM.DGO", "DGO/LTORNSAM.DGO",
//"DGO/MUSEUM3B.DGO", "DGO/MUSEUM3B.DGO",
//"DGO/SEE.DGO", "DGO/SEE.DGO",
//"DGO/DESHUNT.DGO", "DGO/DESHUNT.DGO",
//"DGO/RAILA.DGO", "DGO/RAILA.DGO",
//"DGO/TITLE.DGO", "DGO/TITLE.DGO",
//"DGO/RUBC.DGO", "DGO/RUBC.DGO",
//"DGO/DESB.DGO", "DGO/DESB.DGO",
//"DGO/LFACCAR.DGO", "DGO/LFACCAR.DGO",
//"DGO/LNSTOA.DGO", "DGO/LNSTOA.DGO",
//"DGO/MUSEUM3.DGO", "DGO/MUSEUM3.DGO",
//"DGO/ONINTENT.DGO", "DGO/ONINTENT.DGO",
//"DGO/STA.DGO", "DGO/STA.DGO",
//"DGO/WASSTADA.DGO", "DGO/WASSTADA.DGO",
//"DGO/POWERGD.DGO", "DGO/POWERGD.DGO",
//"DGO/LKLEEVER.DGO", "DGO/LKLEEVER.DGO",
//"DGO/FACB.DGO", "DGO/FACB.DGO",
//"DGO/LCTYASS.DGO", "DGO/LCTYASS.DGO",
//"DGO/MHCA.DGO", "DGO/MHCA.DGO",
//"DGO/LTOWB.DGO", "DGO/LTOWB.DGO",
//"DGO/LNSTCST.DGO", "DGO/LNSTCST.DGO",
//"DGO/DESRESCG.DGO", "DGO/DESRESCG.DGO",
//"DGO/INTPALRF.DGO", "DGO/INTPALRF.DGO",
//"DGO/LMHCA.DGO", "DGO/LMHCA.DGO",
//"DGO/TOWERCST.DGO", "DGO/TOWERCST.DGO",
//"DGO/RAILF.DGO", "DGO/RAILF.DGO",
//"DGO/CIA.DGO", "DGO/CIA.DGO",
//"DGO/CTYCARKG.DGO", "DGO/CTYCARKG.DGO",
//"DGO/WASCHASE.DGO", "DGO/WASCHASE.DGO",
//"DGO/LFACO.DGO", "DGO/LFACO.DGO",
//"DGO/WIN.DGO", "DGO/WIN.DGO",
//"DGO/TEMPLEE.DGO", "DGO/TEMPLEE.DGO",
//"DGO/LBBSPIRT.DGO", "DGO/LBBSPIRT.DGO",
//"DGO/MUSEUM2.DGO", "DGO/MUSEUM2.DGO",
//"DGO/INTTITLE.DGO", "DGO/INTTITLE.DGO",
//"DGO/STAA.DGO", "DGO/STAA.DGO",
//"DGO/MUSEUM4B.DGO", "DGO/MUSEUM4B.DGO",
//"DGO/PRECD.DGO", "DGO/PRECD.DGO",
//"DGO/SEF.DGO", "DGO/SEF.DGO",
//"DGO/CTYCARB.DGO", "DGO/CTYCARB.DGO",
//"DGO/WASDEFEN.DGO", "DGO/WASDEFEN.DGO",
//"DGO/LBLOWTKG.DGO", "DGO/LBLOWTKG.DGO",
//"DGO/DESA.DGO", "DGO/DESA.DGO",
//"DGO/COMBB.DGO", "DGO/COMBB.DGO",
//"DGO/WASSTADC.DGO", "DGO/WASSTADC.DGO",
//"DGO/DESC.DGO", "DGO/DESC.DGO",
//"DGO/LDAMPECK.DGO", "DGO/LDAMPECK.DGO",
//"DGO/LJAKSIG.DGO", "DGO/LJAKSIG.DGO",
//"DGO/HALFPIPE.DGO", "DGO/HALFPIPE.DGO",
//"DGO/DESRACE1.DGO", "DGO/DESRACE1.DGO",
//"DGO/SEN.DGO", "DGO/SEN.DGO",
//"DGO/TEMP.DGO", "DGO/TEMP.DGO",
//"DGO/SED.DGO", "DGO/SED.DGO",
//"DGO/LFACB.DGO", "DGO/LFACB.DGO",
//"DGO/LCTYSNPR.DGO", "DGO/LCTYSNPR.DGO",
//"DGO/LBBSPID.DGO", "DGO/LBBSPID.DGO",
//"DGO/FRSTA.DGO", "DGO/FRSTA.DGO",
//"DGO/LBBRING5.DGO", "DGO/LBBRING5.DGO",
//"DGO/LBBSPRT3.DGO", "DGO/LBBSPRT3.DGO",
//"DGO/HHG.DGO", "DGO/HHG.DGO",
//"DGO/LBBSPRT2.DGO", "DGO/LBBSPRT2.DGO",
//"DGO/CGB.DGO", "DGO/CGB.DGO",
//"DGO/LDMPCKGN.DGO", "DGO/LDMPCKGN.DGO",
//"DGO/LSEEMWCA.DGO", "DGO/LSEEMWCA.DGO",
//"DGO/HGB.DGO", "DGO/HGB.DGO",
//"DGO/LONINSIM.DGO", "DGO/LONINSIM.DGO",
//"DGO/RUBA.DGO", "DGO/RUBA.DGO",
//"DGO/DESRALLY.DGO", "DGO/DESRALLY.DGO",
//"DGO/WWD.DGO", "DGO/WWD.DGO",
//"DGO/STB.DGO", "DGO/STB.DGO",
//"DGO/MIB.DGO", "DGO/MIB.DGO",
//"DGO/LCTYBLOW.DGO", "DGO/LCTYBLOW.DGO",
//"DGO/LWSTDPCK.DGO", "DGO/LWSTDPCK.DGO",
//"DGO/MUSEUM.DGO", "DGO/MUSEUM.DGO",
//"DGO/LJAKCKLV.DGO", "DGO/LJAKCKLV.DGO",
//"DGO/LBBRING1.DGO", "DGO/LBBRING1.DGO",
//"DGO/MUSEUM4.DGO", "DGO/MUSEUM4.DGO",
//"DGO/LFACRM1.DGO", "DGO/LFACRM1.DGO",
//"DGO/LJKCDMKL.DGO", "DGO/LJKCDMKL.DGO",
//"DGO/LDAMSIG.DGO", "DGO/LDAMSIG.DGO",
//"DGO/DESTRACK.DGO", "DGO/DESTRACK.DGO",
//"DGO/GGA.DGO", "DGO/GGA.DGO",
//"DGO/RAILC.DGO", "DGO/RAILC.DGO",
//"DGO/LBBTCHA2.DGO", "DGO/LBBTCHA2.DGO",
//"DGO/DESINTER.DGO", "DGO/DESINTER.DGO",
//"DGO/NSB.DGO", "DGO/NSB.DGO",
//"DGO/LOUTRO.DGO", "DGO/LOUTRO.DGO",
//"DGO/VIN.DGO", "DGO/VIN.DGO",
//"DGO/LDESGCST.DGO", "DGO/LDESGCST.DGO",
//"DGO/WARPCAST.DGO", "DGO/WARPCAST.DGO",
//"DGO/LBBRING6.DGO", "DGO/LBBRING6.DGO",
//"DGO/FRSTB.DGO", "DGO/FRSTB.DGO",
//"DGO/TEMC.DGO", "DGO/TEMC.DGO",
//"DGO/COMBC.DGO", "DGO/COMBC.DGO",
//"DGO/LTRTWHLS.DGO", "DGO/LTRTWHLS.DGO",
//"DGO/PRECC.DGO", "DGO/PRECC.DGO",
//"DGO/DESCHASE.DGO", "DGO/DESCHASE.DGO",
//"DGO/CITYCAST.DGO", "DGO/CITYCAST.DGO",
//"DGO/CPO.DGO", "DGO/CPO.DGO",
//"DGO/LFACCITY.DGO", "DGO/LFACCITY.DGO",
//"DGO/RAILCST.DGO", "DGO/RAILCST.DGO",
//"DGO/LJNDKLEV.DGO", "DGO/LJNDKLEV.DGO",
//"DGO/CWI.DGO", "DGO/CWI.DGO",
//"DGO/MINEE.DGO", "DGO/MINEE.DGO",
//"DGO/LFORRING.DGO", "DGO/LFORRING.DGO",
//"DGO/LASHELIN.DGO", "DGO/LASHELIN.DGO",
//"DGO/LJAKKLEV.DGO", "DGO/LJAKKLEV.DGO",
//"DGO/LCTYPALT.DGO", "DGO/LCTYPALT.DGO",
//"DGO/LNSTOBB.DGO", "DGO/LNSTOBB.DGO",
//"DGO/LJKFEET.DGO", "DGO/LJKFEET.DGO",
//"DGO/DST.DGO", "DGO/DST.DGO",
//"DGO/LBBTCHA1.DGO", "DGO/LBBTCHA1.DGO",
//"DGO/LGUNRNC.DGO", "DGO/LGUNRNC.DGO",
//"DGO/COMBN.DGO", "DGO/COMBN.DGO",
//"DGO/DESRESCC.DGO", "DGO/DESRESCC.DGO",
//"DGO/LSIGJAKC.DGO", "DGO/LSIGJAKC.DGO",
//"DGO/DESLIZ.DGO", "DGO/DESLIZ.DGO",
//"DGO/WASPALA.DGO", "DGO/WASPALA.DGO",
//"DGO/LJAKNDAX.DGO", "DGO/LJAKNDAX.DGO",
//"DGO/WASSEEM.DGO", "DGO/WASSEEM.DGO",
//"DGO/WASALL.DGO", "DGO/WASALL.DGO",
//"DGO/WCASEEM.DGO", "DGO/WCASEEM.DGO",
//"DGO/LSIG.DGO", "DGO/LSIG.DGO",
//"DGO/LFACTORY.DGO", "DGO/LFACTORY.DGO",
//"DGO/LWLANDM.DGO", "DGO/LWLANDM.DGO",
//"DGO/LPTRL.DGO", "DGO/LPTRL.DGO",
//"DGO/MINED.DGO", "DGO/MINED.DGO",
//"DGO/LDAMPKSM.DGO", "DGO/LDAMPKSM.DGO",
//"DGO/RUBB.DGO", "DGO/RUBB.DGO",
//"DGO/LCITYSML.DGO", "DGO/LCITYSML.DGO",
//"DGO/RUBA2.DGO", "DGO/RUBA2.DGO",
//"DGO/LOUTRO2.DGO", "DGO/LOUTRO2.DGO",
//"DGO/VOCX.DGO", "DGO/VOCX.DGO",
//"DGO/TEMX.DGO", "DGO/TEMX.DGO",
//"DGO/ARENACST.DGO", "DGO/ARENACST.DGO",
//"DGO/TEMB.DGO", "DGO/TEMB.DGO",
//"DGO/COMBA.DGO", "DGO/COMBA.DGO",
//"DGO/LBBSDRP3.DGO", "DGO/LBBSDRP3.DGO",
//"DGO/LPATKCS.DGO", "DGO/LPATKCS.DGO",
//"DGO/VOCA.DGO", "DGO/VOCA.DGO",
//"DGO/WASSTADB.DGO", "DGO/WASSTADB.DGO",
//"DGO/LDAX.DGO", "DGO/LDAX.DGO",
//"DGO/LCTYPROT.DGO", "DGO/LCTYPROT.DGO",
//"DGO/DESHOVER.DGO", "DGO/DESHOVER.DGO",
//"DGO/DESBOSS2.DGO" "DGO/DESBOSS2.DGO"
], ],
// some objects are part of STR files (streaming data). // some objects are part of STR files (streaming data).

View File

@ -0,0 +1 @@
{}

View File

@ -160,6 +160,11 @@ void DecompilerTypeSystem::add_type_parent(const std::string& child, const std::
} }
std::string DecompilerTypeSystem::lookup_parent_from_inspects(const std::string& child) const { std::string DecompilerTypeSystem::lookup_parent_from_inspects(const std::string& child) const {
if (child == "process-tree")
return "basic";
if (child == "process")
return "process-tree";
auto kv_tp = type_parents.find(child); auto kv_tp = type_parents.find(child);
if (kv_tp != type_parents.end()) { if (kv_tp != type_parents.end()) {
return kv_tp->second; return kv_tp->second;
@ -169,6 +174,15 @@ std::string DecompilerTypeSystem::lookup_parent_from_inspects(const std::string&
} }
bool DecompilerTypeSystem::lookup_flags(const std::string& type, u64* dest) const { bool DecompilerTypeSystem::lookup_flags(const std::string& type, u64* dest) const {
if (type == "process-tree") {
*dest = ((u64)0xe << 32) + (0 << 16) + 0x24;
return true;
}
if (type == "process") {
*dest = ((u64)0xe << 32) + (0 << 16) + 0x80;
return true;
}
auto kv = type_flags.find(type); auto kv = type_flags.find(type);
if (kv != type_flags.end()) { if (kv != type_flags.end()) {
*dest = kv->second; *dest = kv->second;

File diff suppressed because it is too large Load Diff

6
scripts/shell/decomp3.sh Executable file
View File

@ -0,0 +1,6 @@
#!/usr/bin/env bash
# Directory of this script
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
"${DIR}"/../../build/decompiler/decompiler "${DIR}"/../../decompiler/config/jak3/jak3_config.jsonc "${DIR}"/../../iso_data/ "${DIR}"/../../decompiler_out --version ntsc_v1