[decompiler] setup before making IR2 type inspector (#1423)

This commit is contained in:
water111
2022-06-06 17:58:49 -04:00
committed by GitHub
parent 4c28794d23
commit aff2f2e10c
34 changed files with 402 additions and 5875 deletions
+1
View File
@@ -6,6 +6,7 @@ cmake-build-debug/*
.idea/*
build/*
decompiler_out/*
decompiler_out2/*
logs/*
# wsl apparently builds to here?
+28
View File
@@ -211,6 +211,34 @@ void TypeSystem::forward_declare_type_method_count(const std::string& name, int
m_forward_declared_method_counts[name] = num_methods;
}
/*!
* forward declare, but allow the method count to be too large by up to 3 because jak2 stores
* method counts in v2/v4's like n*4 + 3.
*/
void TypeSystem::forward_declare_type_method_count_multiple_of_4(const std::string& name,
int num_methods) {
auto existing_fwd = m_forward_declared_method_counts.find(name);
if (existing_fwd != m_forward_declared_method_counts.end() &&
existing_fwd->second + 3 < num_methods) {
throw_typesystem_error(
"Type {} was originally forward declared with {} methods and is now being forward declared "
"with {} methods",
name, existing_fwd->second, num_methods);
}
auto existing_type = m_types.find(name);
if (existing_type != m_types.end()) {
int existing_count = get_next_method_id(existing_type->second.get());
if (existing_count + 3 < num_methods) {
throw_typesystem_error(
"Type {} was defined with {} methods and is now being forward declared with {} methods",
name, existing_count, num_methods);
}
}
m_forward_declared_method_counts[name] = num_methods;
}
int TypeSystem::get_type_method_count(const std::string& name) const {
auto result = try_get_type_method_count(name);
if (result) {
+2
View File
@@ -128,6 +128,8 @@ class TypeSystem {
void forward_declare_type_as_type(const std::string& name);
void forward_declare_type_as(const std::string& new_type, const std::string& parent_type);
void forward_declare_type_method_count(const std::string& name, int num_methods);
void forward_declare_type_method_count_multiple_of_4(const std::string& name, int num_methods);
int get_type_method_count(const std::string& name) const;
std::optional<int> try_get_type_method_count(const std::string& name) const;
std::string get_runtime_type(const TypeSpec& ts);
+23 -21
View File
@@ -19,33 +19,35 @@ 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) {
const std::string art_group_text =
fmt::format("/src/next/data/art-group{}/",
versions::ART_FILE_VERSION); // todo, this may change in other games
const std::string art_group_text_strings[] = {
fmt::format("/src/next/data/art-group{}/", versions::jak1::ART_FILE_VERSION),
fmt::format("/src/jak2/final/art-group{}/", versions::jak2::ART_FILE_VERSION)};
const std::string suffix = "-ag.go";
int len = int(art_group_text.length());
for (int start = 0; start < size; start++) {
bool failed = false;
for (int i = 0; i < len; i++) {
if (start + i >= size || data[start + i] != art_group_text[i]) {
failed = true;
break;
}
}
if (!failed) {
for (int i = 0; i < int(original_name.length()); i++) {
if (start + len + i >= size || data[start + len + i] != original_name[i]) {
ASSERT(false);
for (auto& art_group_text : art_group_text_strings) {
int len = int(art_group_text.length());
for (int start = 0; start < size; start++) {
bool failed = false;
for (int i = 0; i < len; i++) {
if (start + i >= size || data[start + i] != art_group_text[i]) {
failed = true;
break;
}
}
ASSERT(int(suffix.length()) + start + len + int(original_name.length()) < size);
ASSERT(
!memcmp(data + start + len + original_name.length(), suffix.data(), suffix.length() + 1));
if (!failed) {
for (int i = 0; i < int(original_name.length()); i++) {
if (start + len + i >= size || data[start + len + i] != original_name[i]) {
ASSERT(false);
}
}
return original_name + "-ag";
ASSERT(int(suffix.length()) + start + len + int(original_name.length()) < size);
ASSERT(!memcmp(data + start + len + original_name.length(), suffix.data(),
suffix.length() + 1));
return original_name + "-ag";
}
}
}
+1
View File
@@ -2,6 +2,7 @@
#include <string>
#include "common/common_types.h"
#include "common/versions.h"
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);
+10 -1
View File
@@ -14,12 +14,19 @@ constexpr s32 GOAL_VERSION_MINOR = 9;
constexpr int DECOMPILER_VERSION = 4;
namespace jak1 {
// these versions are from the game
constexpr u32 ART_FILE_VERSION = 6;
constexpr u32 LEVEL_FILE_VERSION = 30;
constexpr u32 DGO_FILE_VERSION = 1;
constexpr u32 RES_FILE_VERSION = 1;
constexpr u32 TX_PAGE_VERSION = 7;
} // namespace jak1
namespace jak2 {
constexpr u32 ART_FILE_VERSION = 7;
}
} // namespace versions
// GOAL kernel version (OpenGOAL changes this version from the game's version)
@@ -28,4 +35,6 @@ constexpr int KERNEL_VERSION_MINOR = 0;
// OVERLORD version returned by an RPC
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 };
+46 -2
View File
@@ -4,6 +4,7 @@
* This is the part of the disassembler that decodes MIPS instructions.
*/
#include "third-party/fmt/core.h"
#include "InstructionDecode.h"
#include "decompiler/ObjectFile/LinkedObjectFile.h"
#include "common/util/Assert.h"
@@ -93,6 +94,7 @@ static InstructionKind decode_cop2(OpcodeFields fields) {
return IK::CTC2;
default:
ASSERT(false);
return IK::UNKNOWN;
}
break;
@@ -149,6 +151,10 @@ static InstructionKind decode_cop2(OpcodeFields fields) {
ASSERT(fields.data & (1 << 25));
return IK::VFTOI12;
case 0b00101111111:
ASSERT(fields.data & (1 << 25));
return IK::VFTOI15;
case 0b00100111100:
ASSERT(fields.data & (1 << 25));
return IK::VITOF0;
@@ -197,10 +203,16 @@ static InstructionKind decode_cop2(OpcodeFields fields) {
ASSERT(fields.data & (1 << 25));
return IK::VOPMULA;
case 0b01011111101:
return IK::VMSUBA;
case 0b01100111100:
ASSERT(fields.data & (1 << 25));
return IK::VMOVE;
case 0b01100111101:
return IK::VMR32;
case 0b01110111100:
ASSERT(fields.data & (1 << 25));
return IK::VDIV;
@@ -343,6 +355,7 @@ static InstructionKind decode_cop2(OpcodeFields fields) {
ASSERT(fields.dest() == 0b0);
return IK::VCALLMS;
default:
ASSERT_MSG(false, fmt::format("unknown cop2 lower11 case 0b{:b}\n", fields.lower11()));
return IK::UNKNOWN;
}
}
@@ -355,6 +368,7 @@ static InstructionKind decode_W(OpcodeFields fields) {
ASSERT(fields.ft() == 0);
return IK::CVTSW;
default:
ASSERT(false);
return IK::UNKNOWN;
}
}
@@ -416,6 +430,7 @@ static InstructionKind decode_S(OpcodeFields fields) {
ASSERT(fields.fd() == 0);
return IK::CLES;
default:
ASSERT(false);
return IK::UNKNOWN;
}
}
@@ -432,6 +447,7 @@ static InstructionKind decode_BC1(OpcodeFields fields) {
case 0b00011:
return IK::BC1TL;
default:
ASSERT(false);
return IK::UNKNOWN;
}
}
@@ -454,6 +470,7 @@ static InstructionKind decode_cop1(OpcodeFields fields) {
case 0b10100:
return decode_W(fields);
default:
ASSERT(false);
return IK::UNKNOWN;
}
}
@@ -467,6 +484,7 @@ static InstructionKind decode_c0(OpcodeFields fields) {
ASSERT(fields.sa() == 0 && fields.rd() == 0 && fields.rt() == 0);
return IK::EI;
default:
ASSERT(false);
return IK::UNKNOWN;
}
}
@@ -486,6 +504,7 @@ static InstructionKind decode_mt0(OpcodeFields fields) {
if (fields.rd() == 0b11001 && fields.sa() == 0 && (fields.data & 1) == 1) {
return IK::MTPC;
} else {
ASSERT(false);
return IK::UNKNOWN;
}
}
@@ -500,6 +519,7 @@ static InstructionKind decode_mf0(OpcodeFields fields) {
if (fields.rd() == 0b11001 && fields.sa() == 0 && (fields.data & 1) == 1) {
return IK::MFPC;
} else {
ASSERT(false);
return IK::UNKNOWN;
}
}
@@ -514,6 +534,7 @@ static InstructionKind decode_cop0(OpcodeFields fields) {
case 0b10000:
return decode_c0(fields);
default:
ASSERT(false);
return InstructionKind::UNKNOWN;
}
}
@@ -533,6 +554,7 @@ static InstructionKind decode_mmi3(OpcodeFields fields) {
ASSERT(fields.rs() == 0);
return IK::PCPYH;
default:
ASSERT(false);
return IK::UNKNOWN;
}
}
@@ -546,6 +568,8 @@ static InstructionKind decode_mmi2(OpcodeFields fields) {
return IK::PMADDH;
case 0b10010:
return IK::PAND;
case 0b10011:
return IK::PXOR;
case 0b11100:
return IK::PMULTH;
case 0b11110:
@@ -553,6 +577,7 @@ static InstructionKind decode_mmi2(OpcodeFields fields) {
case 0b11111:
return IK::PROT3W;
default:
ASSERT_MSG(false, fmt::format("unknown mmi2: 0b{:b}\n", fields.MMI_func()));
return IK::UNKNOWN;
}
}
@@ -576,7 +601,10 @@ static InstructionKind decode_mmi1(OpcodeFields fields) {
return IK::PEXTUH;
case 0b11010:
return IK::PEXTUB;
case 0b11011:
return IK::QFSRV;
default:
ASSERT_MSG(false, fmt::format("unknown mmi1: 0b{:b}\n", fields.MMI_func()));
return IK::UNKNOWN;
}
}
@@ -594,8 +622,14 @@ static InstructionKind decode_mmi0(OpcodeFields fields) {
return IK::PMAXW;
case 0b00100:
return IK::PADDH;
case 0b00101:
return IK::PSUBH;
case 0b00111:
return IK::PMAXH;
case 0b01000:
return IK::PADDB;
case 0b01010:
return IK::PCGTB;
case 0b10010:
return IK::PEXTLW;
case 0b10011:
@@ -609,6 +643,7 @@ static InstructionKind decode_mmi0(OpcodeFields fields) {
case 0b11011:
return IK::PPACB;
default:
ASSERT_MSG(false, fmt::format("unknown mmi0: 0b{:b}\n", fields.MMI_func()));
return IK::UNKNOWN;
}
}
@@ -631,6 +666,7 @@ static InstructionKind decode_pmfhl(OpcodeFields fields) {
ASSERT(fields.rt() == 0);
return IK::PMFHL_LH;
default:
ASSERT(false);
return IK::UNKNOWN;
}
}
@@ -675,13 +711,14 @@ static InstructionKind decode_mmi(OpcodeFields fields) {
case 0b111111:
return IK::PSRAW;
default:
ASSERT(false);
return IK::UNKNOWN;
}
}
static InstructionKind decode_regimm(OpcodeFields files) {
static InstructionKind decode_regimm(OpcodeFields fields) {
typedef InstructionKind IK;
switch (files.rt()) {
switch (fields.rt()) {
case 0b00000:
return IK::BLTZ;
case 0b00001:
@@ -692,7 +729,10 @@ static InstructionKind decode_regimm(OpcodeFields files) {
return IK::BGEZL;
case 0b10001:
return IK::BGEZAL;
case 0b11000:
return IK::MTSAB;
default:
ASSERT_MSG(false, fmt::format("unknown regimm: 0b{:b}\n", fields.rt()));
return IK::UNKNOWN;
}
}
@@ -710,6 +750,7 @@ static InstructionKind decode_sync(OpcodeFields fields) {
} else if (stype == 0b10000) {
return IK::SYNCP;
} else {
ASSERT(false);
return IK::UNKNOWN;
}
}
@@ -855,6 +896,7 @@ static InstructionKind decode_special(OpcodeFields fields) {
ASSERT(fields.rs() == 0);
return IK::DSRA32;
default:
ASSERT(false);
return IK::UNKNOWN;
}
}
@@ -867,6 +909,7 @@ static InstructionKind decode_cache(OpcodeFields fields) {
case 0b10100:
return IK::CACHE_DXWBIN;
default:
ASSERT(false);
return IK::UNKNOWN;
}
}
@@ -988,6 +1031,7 @@ static InstructionKind decode_opcode(uint32_t code) {
case 0b111111:
return IK::SD;
default:
ASSERT(false);
return IK::UNKNOWN;
break;
}
-5
View File
@@ -5,10 +5,6 @@
* The Instruction Decoder - converts a LinkedWord into a Instruction.
* This is the part of the disassembler that decodes MIPS instructions.
*/
#ifndef NEXT_INSTRUCTIONDECODE_H
#define NEXT_INSTRUCTIONDECODE_H
#include "Instruction.h"
namespace decompiler {
@@ -17,4 +13,3 @@ class LinkedObjectFile;
Instruction decode_instruction(LinkedWord& word, LinkedObjectFile& file, int seg_id, int word_id);
} // namespace decompiler
#endif // NEXT_INSTRUCTIONDECODE_H
+11
View File
@@ -278,12 +278,18 @@ void init_opcode_info() {
def(IK::SYNCL, "sync.l"); // Synchronize Shared Memory (Load)
def(IK::ERET, "eret"); // Exception Return
def(IK::EI, "ei"); // Enable Interrupt
def(IK::MTSAB, "mtsab")
.src_gpr(FT::RS)
.src(FT::ZIMM16, DT::IMM); // Move Byte Count to Shift Amount Register
drd_srs_srt(def(IK::QFSRV, "qfsrv")).gpr128(); // Quadword Funnel Shift Right Variable
drd_srs_srt(def(IK::PPACB, "ppacb").gpr128()); // Parallel Pack to Byte
drd_srs_srt(def(IK::PPACH, "ppach").gpr128()); // Parallel Pack to Halfword
drd_srs_srt(def(IK::PPACW, "ppacw").gpr128()); // Parallel Pack to Word
drd_srs_srt(def(IK::PADDB, "paddb").gpr128()); // Parallel Add Byte
drd_srs_srt(def(IK::PADDH, "paddh").gpr128()); // Parallel Add Halfword
drd_srs_srt(def(IK::PADDW, "paddw").gpr128()); // Parallel Add Word
drd_srs_srt(def(IK::PSUBH, "psubh").gpr128()); // Parallel Subtract Halfword
drd_srs_srt(def(IK::PSUBW, "psubw").gpr128()); // Parallel Subtract Word
drd_srs_srt(def(IK::PMINH, "pminh").gpr128()); // Parallel Minimize Halfword
drd_srs_srt(def(IK::PMINW, "pminw").gpr128()); // Parallel Minimize Word
@@ -293,6 +299,7 @@ void init_opcode_info() {
drd_srs_srt(def(IK::PEXTLH, "pextlh").gpr128()); // Parallel Extend Lower from Halfword
drd_srs_srt(def(IK::PEXTLW, "pextlw").gpr128()); // Parallel Extend Lower from Word
drd_srs_srt(def(IK::PCGTW, "pcgtw").gpr128()); // Parallel Compare for Greater Than Word
drd_srs_srt(def(IK::PCGTB, "pcgtb").gpr128()); // Parallel Compare for Greater Than Byte
drd_srs_srt(def(IK::PCEQB, "pceqb").gpr128()); // Parallel Compare for Equal Byte
drd_srs_srt(def(IK::PCEQW, "pceqw").gpr128()); // Parallel Compare for Equal Word
drd_srs_srt(def(IK::PEXTUB, "pextub").gpr128()); // Parallel Extend Upper from Byte
@@ -306,6 +313,7 @@ void init_opcode_info() {
drd_srs_srt(def(IK::PAND, "pand").gpr128()); // Parallel And
drd_srs_srt(def(IK::POR, "por").gpr128()); // Parallel Or
drd_srs_srt(def(IK::PNOR, "pnor").gpr128()); // Parallel Not Or
drd_srs_srt(def(IK::PXOR, "pxor").gpr128()); // Parallel Exclusive Or
def(IK::PEXEW, "pexew").gpr128().dst_gpr(FT::RD).src_gpr(FT::RT); // Parallel Exchange Even Word
@@ -372,6 +380,7 @@ void init_opcode_info() {
cd_dvft_svfs(def(IK::VFTOI0, "vftoi0")); // Conversion to Fixed Point
cd_dvft_svfs(def(IK::VFTOI4, "vftoi4")); // Conversion to Fixed Point
cd_dvft_svfs(def(IK::VFTOI12, "vftoi12")); // Conversion to Fixed Point
cd_dvft_svfs(def(IK::VFTOI15, "vftoi15")); // Conversion to Fixed Point
cd_dvft_svfs(def(IK::VITOF0, "vitof0")); // Conversion to Floating Point Number
cd_dvft_svfs(def(IK::VITOF12, "vitof12")); // Conversion to Floating Point Number
cd_dvft_svfs(def(IK::VITOF15, "vitof15")); // Conversion to Floating Point Number
@@ -407,6 +416,7 @@ void init_opcode_info() {
cd_dacc_svfs_svft(def(IK::VMULA, "vmula"));
cd_dacc_svfs_svft(def(IK::VADDA, "vadda"));
cd_dacc_svfs_svft(def(IK::VMADDA, "vmadda"));
cd_dacc_svfs_svft(def(IK::VMSUBA, "vmsuba"));
cd_dacc_svfs_svft(def(IK::VOPMULA, "vopmula"));
@@ -431,6 +441,7 @@ void init_opcode_info() {
.src(FT::ZERO, DT::VU_Q);
def(IK::VRGET, "vrget").src(FT::DEST, DT::DEST).dst_vf(FT::FT);
def(IK::VMR32, "vmr32").src(FT::DEST, DT::DEST).src_vf(FT::FT).dst_vf(FT::FS);
// integer
def(IK::VMTIR, "vmtir").dst(FT::RT, DT::VI).src_vf(FT::FS).src(FT::BC, DT::BC);
+9 -4
View File
@@ -5,9 +5,6 @@
* Decoding info for each opcode.
*/
#ifndef NEXT_OPCODEINFO_H
#define NEXT_OPCODEINFO_H
#include <string>
namespace decompiler {
@@ -128,6 +125,8 @@ enum class InstructionKind {
EI,
CACHE_DXWBIN,
PREF,
MTSAB,
QFSRV,
// MMI unsorted
PSLLW,
@@ -144,6 +143,7 @@ enum class InstructionKind {
PEXTLW,
PPACH,
PSUBW,
PCGTB,
PCGTW,
PEXTLH,
PEXTLB,
@@ -153,6 +153,8 @@ enum class InstructionKind {
PADDH,
PMAXW,
PPACW,
PSUBH,
PADDB,
// MMI 1
PCEQW,
@@ -171,6 +173,7 @@ enum class InstructionKind {
PMADDH,
PMULTH,
PEXEW,
PXOR,
// MMI 3
POR,
@@ -212,6 +215,7 @@ enum class InstructionKind {
VFTOI0,
VFTOI4,
VFTOI12,
VFTOI15,
VITOF0,
VITOF12,
VITOF15,
@@ -247,6 +251,7 @@ enum class InstructionKind {
VMULA,
VADDA,
VMADDA,
VMSUBA,
VOPMULA,
VDIV,
@@ -268,6 +273,7 @@ enum class InstructionKind {
VRNEXT,
VNOP,
VWAITQ,
VMR32,
VCALLMS, // last cop2 macro instruction
EE_OP_MAX
@@ -361,4 +367,3 @@ extern OpcodeInfo gOpcodeInfo[(uint32_t)InstructionKind::EE_OP_MAX];
void init_opcode_info();
} // namespace decompiler
#endif // NEXT_OPCODEINFO_H
@@ -444,6 +444,8 @@ void LinkedObjectFile::disassemble_functions() {
decode_instruction(words_by_seg.at(seg).at(word), *this, seg, word));
if (function.instructions.back().is_valid()) {
stats.decoded_ops++;
} else {
lg::error("Failed to decode op: 0x{:08x}", words_by_seg.at(seg).at(word).data);
}
}
}
@@ -582,6 +584,9 @@ std::string LinkedObjectFile::print_function_disassembly(Function& func,
result += " ;;";
auto& word = words_by_seg[seg].at(func.start_word + i);
append_word_to_string(result, word);
} else {
result += line;
result += '\n';
}
if (in_delay_slot) {
@@ -219,7 +219,8 @@ static uint32_t c_symlink3(LinkedObjectFile& f,
static void link_v2_or_v4(LinkedObjectFile& f,
const std::vector<uint8_t>& data,
const std::string& name,
DecompilerTypeSystem& dts) {
DecompilerTypeSystem& dts,
GameVersion version) {
const auto* header = (const LinkHeaderV4*)&data.at(0);
ASSERT(header->version == 4 || header->version == 2);
@@ -251,6 +252,13 @@ static void link_v2_or_v4(LinkedObjectFile& f,
const uint8_t* code_start = &data.at(code_offset);
const uint8_t* code_end =
&data.at(code_offset + code_size - 1) + 1; // get the pointer to one past the end.
if (version == GameVersion::Jak2) {
while (((code_end - code_start) % 4)) {
code_end++;
}
}
ASSERT(((code_end - code_start) % 4) == 0);
f.set_segment_count(1);
for (auto x = code_start; x < code_end; x += 4) {
@@ -605,7 +613,7 @@ static void link_v3(LinkedObjectFile& f,
const std::vector<uint8_t>& data,
const std::string& name,
DecompilerTypeSystem& dts,
int game_version) {
GameVersion game_version) {
auto header = (const LinkHeaderV3*)(&data.at(0));
ASSERT(name == header->name);
ASSERT(header->segments == 3);
@@ -652,11 +660,11 @@ static void link_v3(LinkedObjectFile& f,
// HACK!
// why is this a thing?
// HACK!
if (game_version == 1 && name == "level-h" && seg_id == 0) {
if (game_version == GameVersion::Jak1 && name == "level-h" && seg_id == 0) {
segment_size++;
}
if (game_version == 2) {
if (game_version == GameVersion::Jak2) {
bool adjusted = false;
while (segment_size % 4) {
segment_size++;
@@ -756,7 +764,16 @@ static void link_v3(LinkedObjectFile& f,
s_name = (const char*)(&data.at(link_ptr));
} else {
s_name = (const char*)(&data.at(link_ptr));
dts.ts.forward_declare_type_method_count(s_name, reloc & 0x7f);
switch (game_version) {
case GameVersion::Jak1:
dts.ts.forward_declare_type_method_count(s_name, (reloc & 0x7f));
break;
case GameVersion::Jak2:
dts.ts.forward_declare_type_method_count_multiple_of_4(s_name, (reloc & 0x7f) * 4 + 3);
break;
default:
ASSERT(false);
}
kind = SymbolLinkKind::TYPE;
}
@@ -795,7 +812,7 @@ static void link_v3(LinkedObjectFile& f,
LinkedObjectFile to_linked_object_file(const std::vector<uint8_t>& data,
const std::string& name,
DecompilerTypeSystem& dts,
int game_version) {
GameVersion game_version) {
LinkedObjectFile result;
const auto* header = (const LinkHeaderCommon*)&data.at(0);
@@ -805,7 +822,7 @@ LinkedObjectFile to_linked_object_file(const std::vector<uint8_t>& data,
link_v3(result, data, name, dts, game_version);
} else if (header->version == 4 || header->version == 2) {
ASSERT(header->type_tag == 0xffffffff);
link_v2_or_v4(result, data, name, dts);
link_v2_or_v4(result, data, name, dts, game_version);
} else if (header->version == 5) {
link_v5(result, data, name, dts);
} else {
@@ -13,5 +13,5 @@ class DecompilerTypeSystem;
LinkedObjectFile to_linked_object_file(const std::vector<uint8_t>& data,
const std::string& name,
DecompilerTypeSystem& dts,
int game_version);
GameVersion game_version);
} // namespace decompiler
+5 -3
View File
@@ -115,7 +115,7 @@ ObjectFileDB::ObjectFileDB(const std::vector<std::string>& _dgos,
Timer timer;
lg::info("-Loading types...");
dts.parse_type_defs({"decompiler", "config", "all-types.gc"});
dts.parse_type_defs({config.all_types_file});
if (!obj_file_name_map_file.empty()) {
lg::info("-Loading obj name map file...");
@@ -407,7 +407,9 @@ std::string ObjectFileDB::generate_obj_listing(const std::unordered_set<std::str
// this check is extremely important. It makes sure we don't have any repeat names. This could
// be caused by two files with the same name, in the same DGOs, but different data.
if (int(all_unique_names.size()) != unique_count) {
lg::error("Object files are not named properly, data will be lost!");
lg::error(
"Object files are not named properly, data will be lost! Got {} objs, but only {} names\n",
unique_count, all_unique_names.size());
}
if (unique_count > 0) {
@@ -530,7 +532,7 @@ void ObjectFileDB::find_code(const Config& config) {
obj.linked_data.find_functions();
obj.linked_data.disassemble_functions();
if (config.game_version == 1 || obj.to_unique_name() != "effect-control-v0") {
if (config.game_version == GameVersion::Jak1 || obj.to_unique_name() != "effect-control-v0") {
obj.linked_data.process_fp_relative_links();
} else {
lg::warn("Skipping process_fp_relative_links in {}", obj.to_unique_name().c_str());
+4 -1
View File
@@ -34,12 +34,15 @@ Config read_config_file(const std::string& path_to_config_file,
cfg[key] = val;
}
config.game_version = cfg.at("game_version").get<int>();
int version_int = cfg.at("game_version").get<int>();
ASSERT(version_int == 1 || version_int == 2);
config.game_version = (GameVersion)version_int;
config.text_version = cfg.at("text_version").get<GameTextVersion>();
config.game_name = cfg.at("game_name").get<std::string>();
if (cfg.contains("expected_elf_name")) {
config.expected_elf_name = cfg.at("expected_elf_name").get<std::string>();
}
config.all_types_file = cfg.at("all_types_file").get<std::string>();
auto inputs_json = read_json_file_from_config(cfg, "inputs_file");
config.dgo_names = inputs_json.at("dgo_names").get<std::vector<std::string>>();
+3 -1
View File
@@ -7,6 +7,7 @@
#include <optional>
#include "decompiler/Disasm/Register.h"
#include "decompiler/data/game_text.h"
#include "common/versions.h"
namespace decompiler {
struct RegisterTypeCast {
@@ -82,7 +83,7 @@ struct DecompileHacks {
};
struct Config {
int game_version = -1;
GameVersion game_version = GameVersion::Jak1;
std::vector<std::string> dgo_names;
std::vector<std::string> object_file_names;
std::vector<std::string> str_file_names;
@@ -91,6 +92,7 @@ struct Config {
std::vector<std::string> streamed_audio_file_names;
std::string obj_file_name_map_file;
std::string all_types_file;
bool disassemble_code = false;
bool decompile_code = false;
View File
@@ -78,6 +78,7 @@
"inputs_file": "decompiler/config/jak1_ntsc_black_label/inputs.jsonc",
"art_info_file": "decompiler/config/jak1_ntsc_black_label/art_info.jsonc",
"import_deps_file": "decompiler/config/jak1_ntsc_black_label/import_deps.jsonc",
"all_types_file": "decompiler/config/all-types.gc",
// optional: a predetermined object file name map from a file.
// this will make decompilation naming consistent even if you only run on some objects.
@@ -1,10 +1,3 @@
{
"gkernel":[
[16, "(function process symbol)"],
[22, "(function process symbol)"],
[25, "(function process symbol)"],
[28, "(function process symbol)"],
[30, "(function process symbol)"],
[32, "(function process symbol)"]
]
}
+4
View File
@@ -0,0 +1,4 @@
{
"files":{},
"functions":{}
}
+20 -486
View File
@@ -4,10 +4,7 @@
////////////////////////////
"types_with_bad_inspect_methods": [
"engine",
"bsp-header",
"joint-anim-matrix",
"part-tracker"
],
"no_type_analysis_functions_by_name": [],
@@ -16,368 +13,27 @@
// 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.
"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
// you can add the function name to this list and it will more aggressively reject this rewrite.
"aggressively_reject_cond_to_value_rewrite": [
"(method 10 res-lump)",
"(method 11 res-lump)",
"(method 12 res-lump)",
"(method 7 texture-page)"
],
// 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.
"hint_inline_assembly_functions": ["matrix-transpose!"],
"hint_inline_assembly_functions": [],
"asm_functions_by_name": [
// gcommon
"quad-copy!",
// gkernel
"(method 11 cpu-thread)",
"throw",
"return-from-thread",
"return-from-thread-dead",
"reset-and-call",
"(method 10 cpu-thread)",
"(method 0 catch-frame)",
"throw-dispatch",
"set-to-run-bootstrap",
"run-function-in-process", // not asm, but it uses the stack.
// pskernel
"return-from-exception", // F: eret
"kernel-read-function", // F: delay slot tricks
"kernel-write-function", // F: delay slot tricks
"kernel-copy-function",
"kernel-check-hardwired-addresses",
// math
"rand-uint31-gen",
// bounding box
"(method 9 bounding-box)", // F: asm branching
"(method 14 bounding-box)",
// matrix
"(method 9 matrix)", // F: asm branching
"matrix-axis-sin-cos!", // F: asm branching
"matrix-axis-sin-cos-vu!",
// geometry
"circle-circle-xz-intersect", // F: asm branching
// trigonometry
"exp", // BUG: cfg is wrong.
"atan0", // P: manual use of stack
"sincos!", // P: manual use of stack
"sincos-rad!",
// dma-h
"dma-count-until-done", // F: asm branching
"dma-sync-with-count", // F: asm branching
"dma-send-no-scratch", // F: asm branching
"dma-sync-fast",
// dma
"symlink3", // F: asm branching
"symlink2", // F: asm branching
"dma-sync-hang",
// display
"vblank-handler", // F: weird asm for interrupt handler
"vif1-handler", // F: weird asm for interrupt handler
"vif1-handler-debug",
// vector
"vector=", // asm branching
// collide-mesh-h
"(method 11 collide-mesh-cache)",
// collide-func
"moving-sphere-triangle-intersect", // P: weird branching
"collide-do-primitives", // P: asm branching
// joint
"calc-animation-from-spr", // F: asm branching
"decompress-frame-data-pair-to-accumulator", // P: asm calling
"decompress-frame-data-to-accumulator", // P: asm calling
"decompress-fixed-data-to-accumulator", // P: asm calling
"normalize-frame-quaternions", // F: asm branching, return
"clear-frame-accumulator", // F: asm branching
"cspace<-parented-transformq-joint!",
// sprite
// merc-blend-shape
"setup-blerc-chains-for-one-fragment", // F: asm branching
"merc-dma-chain-to-spr", // F: asm branching
"blerc-a-fragment",
// ripple
"ripple-matrix-scale",
"ripple-apply-wave-table",
"ripple-create-wave-table",
"ripple-execute-init",
// bones
"draw-bones-hud",
"draw-bones",
"draw-bones-check-longest-edge-asm",
"draw-bones-merc",
"bones-mtx-calc-execute",
"bones-mtx-calc",
"texscroll-execute",
// generic-effect
"generic-debug-light-proc",
"generic-none-dma-wait",
"generic-copy-vtx-dclr-dtex",
"generic-light",
"generic-envmap-only-proc",
"generic-no-light",
"generic-no-light+envmap",
"generic-no-light-dproc",
"generic-no-light-dproc-only",
"generic-no-light-proc",
"generic-interp-dproc",
"generic-envmap-dproc",
"generic-prepare-dma-single",
"generic-prepare-dma-double",
"generic-envmap-proc",
"generic-light-proc",
"generic-dma-from-spr",
"upload-vu0-program",
// generic-merc
"generic-merc-execute-all",
"generic-merc-execute-asm", // CFG
"high-speed-reject",
"mercneric-convert",
"mercneric-bittable-asm",
"mercneric-shader-asm",
"mercneric-matrix-asm",
"generic-merc-init-asm",
// generic-tie
"generic-tie-convert",
"generic-tie-convert-proc",
"generic-tie-upload-next",
"generic-tie-decompress",
"generic-tie-dma-to-spad-sync",
// shadow-cpu
"shadow-execute",
"shadow-add-double-edges",
"shadow-add-double-tris",
"shadow-add-single-edges",
"shadow-add-facing-single-tris",
"shadow-add-verts",
"shadow-find-double-edges",
"shadow-find-facing-double-tris",
"shadow-find-single-edges",
"shadow-find-facing-single-tris",
"shadow-scissor-top",
"shadow-scissor-edges",
"shadow-calc-dual-verts",
// background
"background-upload-vu0",
// draw-node
"draw-node-cull",
// shrubbery
"test-func",
"draw-inline-array-instance-shrub",
// tfrag
"stats-tfrag-asm",
"draw-inline-array-tfrag-near",
"draw-inline-array-tfrag",
// tie-methods
"draw-inline-array-prototype-tie-near-asm",
"draw-inline-array-prototype-tie-asm",
"draw-inline-array-prototype-tie-generic-asm",
"draw-inline-array-instance-tie",
// sparticle-launcher
"sp-init-fields!",
// sparticle
"memcpy",
"sp-process-block-3d",
"sp-process-block-2d",
"sp-launch-particles-var",
"particle-adgif",
"sp-init-fields!",
// time-of-day
"time-of-day-interp-colors-scratch",
"time-of-day-interp-colors",
// sky-tng
"clip-polygon-against-negative-hyperplane",
"clip-polygon-against-positive-hyperplane",
"draw-large-polygon",
// load-boundary
"render-boundary-tri",
"render-boundary-quad",
"draw-boundary-polygon",
// collide-probe
"collide-probe-instance-tie", // CFG
"collide-probe-node", // CFG
// collide-edge-grab
"(method 13 collide-edge-work)", // CFG
"(method 17 collide-edge-work)", // CFG
"(method 15 collide-edge-work)", // CFG
"(method 16 collide-edge-work)", // CFG
"(method 9 edge-grab-info)", // CFG
"(method 18 collide-edge-work)", // CFG
"(method 10 collide-edge-hold-list)", // CFG
// collide-shape
"(method 15 collide-shape-prim-mesh)", // CFG
"(method 15 collide-shape-prim-sphere)", // CFG
"(method 16 collide-shape-prim)", // CFG
"(method 15 collide-shape-prim-group)", // CFG
"(method 18 collide-shape-prim-sphere)",
"(method 23 collide-shape-prim-sphere)", // CFG
"(method 23 collide-shape-prim-mesh)", // BUG - crash in variable pass
"(method 24 collide-shape-prim)", // CFG
"(method 23 collide-shape-prim-group)", // CFG
"(method 42 collide-shape)", // CFG
// process-drawable BUG
"cspace-inspect-tree",
"(method 19 process-drawable)",
// ambient
"ambient-inspect",
// target BUG
"target-falling-anim-trans", // CFG resolution
// target2 BUG
"look-for-points-of-interest", // Failed to split nested sc - looks like dead code to me
// drawable-tree
"(method 16 drawable-tree)",
// collide-cache
"(method 10 collide-puss-work)", // CFG
"(method 9 collide-puss-work)", // decompiler crash
"(method 19 collide-cache)", // decompiler crash
"(method 10 collide-cache-prim)", // CFG
"(method 9 collide-cache-prim)", // CFG
"(method 30 collide-cache)", // unsupported asm - c.le.s
"(method 13 collide-shape-prim-group)", // CFG
"(method 13 collide-shape-prim-mesh)", // CFG
"(method 14 collide-shape-prim-group)", // CFG
"(method 14 collide-shape-prim-mesh)", // CFG
"(method 12 collide-shape-prim-group)", // CFG
"(method 12 collide-shape-prim-mesh)", // CFG
"(method 27 collide-cache)", // CFG
"(method 14 collide-cache)", // CFG
"(method 28 collide-cache)", // CFG
"(method 26 collide-cache)", // CFG
"(method 21 collide-cache)", // CFG
"(method 32 collide-cache)", // CFG
// memory-usage BUG
//"(method 14 level)",
// navigate BUG
"(method 32 nav-control)",
// ocean
"draw-large-polygon-ocean", // CFG
// ocean-vu0
"ocean-generate-verts", // crash
"ocean-interp-wave",
// ropebridge BUG
"(method 27 ropebridge)",
// all unchecked and in level DGO code
"(anon-function 21 plant-boss)", // CFG
// "(anon-function 10 ice-cube)",
// "(anon-function 15 ice-cube)",
"mistycannon-find-best-solution",
"target-flut-falling-anim-trans", // CFG failure
"kermit-check-to-hit-player?",
"(anon-function 36 mistycannon)",
"(anon-function 2 target-tube)",
"(anon-function 5 orbit-plat)",
"(anon-function 2 ogreboss)"
],
// these functions use pairs and the decompiler
// will be less picky about types related to pairs.
"pair_functions_by_name": [
"ref",
"last",
"member",
"nmember",
"assoc",
"assoce",
"append!",
"delete!",
"delete-car!",
"insert-cons!",
"sort",
"unload-package",
"(method 4 pair)",
"nassoc",
"nassoce",
"lookup-level-info",
"(method 21 level-group)",
"(method 12 level)",
"update-sound-banks",
"(method 16 level-group)",
"bg",
"(method 18 game-info)",
"debug-menu-context-default-selection",
"debug-menu-rebuild",
"debug-menu-func-decode",
"debug-menu-make-from-template",
"debug-menu-render",
"debug-menu-context-select-next-or-prev-item",
"debug-menu-context-select-new-item",
"debug-menu-send-msg",
"debug-menu-find-from-template",
"build-continue-menu",
"(method 8 process-tree)",
"(method 16 load-state)",
"(method 15 load-state)",
"build-continue-menu",
"entity-remap-names",
"(method 21 swamp-rat-nest-dummy-a)",
"(method 21 swamp-rat-nest-dummy-b)",
"(method 21 swamp-rat-nest-dummy-c)",
"(method 27 battlecontroller)",
"load-boundary-from-template",
"command-get-time",
"command-get-param",
"command-get-quoted-param",
"command-get-trans",
"command-get-camera",
"(method 14 camera-tracker)",
"(enter billy-playing)",
"(code target-continue)",
"next-level"
],
// If format is used with the wrong number of arguments,
@@ -385,108 +41,11 @@
// that they used the correct number. This will override the decompiler's
// automatic detection.
"bad_format_strings": {
"ERROR: dma tag has data in reserved bits ~X~%": 0,
"#<surface f0:~m f1:~f tf+:~f tf-:~f sf:~f tvv:~m": 5,
"ERROR<GMJ>: value of symbol ~A in task-controls is not a task-control~%": 0,
"~0K~10,'-S--~5,'-DK-of-~5,'-DK--~5,'-DK-of-~5,'-DK--": 5,
" bsp ~192H~5DK ~280Hdebug~456H~5DK~%": 2,
" bsp-leaf-vis-iop ~192H~5DK~%": 1,
" bsp-leaf-vis-adj ~192H~5DK~%": 1,
" level-code ~192H~5DK~%": 1,
" 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-near~456H~5DK~%": 2,
" shrub-instance ~192H~5DK ~280Hshrubbery~456H~5DK~%": 2,
" collision ~192H~5DK ~280Htie-generic~456H~5DK~%": 2,
" pris-geo ~192H~5DK ~280Hpris-fragment~456H~5DK~%": 2,
" pris-anim ~192H~5DK ~280Hpris-generic~456H~5DK~%": 2,
" textures ~192H~5DK ~280Htextures~456H~5DK~%": 2,
" entity ~192H~5DK~%": 1,
" misc ~192H~5DK ~280Hsprite~456H~5DK~%": 2,
"ERROR: <asg> ~A in spool anim loop for ~A ~D, but not loaded.~": 3,
"~0k~5d/~d ~6d/~d ~6d/~d ": 6,
"~0k~s~%": 1,
"money ~A was killed in pickup~%": 0
},
"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
],
"find-knot-span": [0, 1, 2, 3, 5, 6, 7, 8, 9],
"curve-evaluate!": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
"(method 9 texture-page-dir)": [4, 5],
"adgif-shader<-texture-with-update!": [0, 1],
"display-loop": [44, 49, 66, 96],
"load-game-text-info": [12, 13, 14, 16, 17, 18],
"real-main-draw-hook": [75, 77],
"(method 12 perf-stat)": [0],
"(method 11 perf-stat)": [0],
"raw-ray-sphere-intersect": [0, 1, 2, 3, 4, 5],
"ray-cylinder-intersect": [0, 1, 2, 3, 4, 5],
"ray-triangle-intersect": [0, 1, 2, 3, 4],
"bsp-camera-asm": [1, 2, 3],
"level-remap-texture": [2, 3, 4, 5, 6],
"start-perf-stat-collection": [26],
"end-perf-stat-collection": [0],
"sprite-draw-distorters": [4, 5],
"draw-string": [
1, 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, 33, 34, 35, 36, 37, 38, 39,
40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57,
58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75,
76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93,
94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109,
110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124,
125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139,
140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154,
155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169,
170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184,
185, 186, 187, 188, 189
],
"get-string-length": [
0, 1, 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, 33, 34, 35, 36, 37, 38,
39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50
],
"unpack-comp-rle": [1, 3, 5, 6],
"(method 16 level)": [1, 5, 13, 14, 15, 19, 26, 53],
"unpack-comp-huf": [2, 4, 5, 6, 7, 8, 9],
"blerc-execute": [
0, 1, 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, 33
],
"(method 11 fact-info-target)": [42],
"(anon-function 9 game-save)": [3, 4, 5, 6, 7, 8, 10],
//"(anon-function 9 game-save)":[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14],
"particle-adgif": [0, 1, 2, 3, 4, 5, 7],
"sp-launch-particles-var": [
0, 1, 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, 33, 34, 35, 36, 37, 38,
39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56,
57, 58, 59, 60, 61, 62, 63, 64, 65, 66
],
"(method 11 sparticle-launch-control)": [27, 28, 35, 46, 48, 49, 77],
"upload-vis-bits": [0, 1, 2, 3, 4, 5, 6],
"draw-drawable-tree-tfrag": [6, 8, 13, 15],
"draw-drawable-tree-trans-tfrag": [6, 8, 13, 15],
"draw-drawable-tree-dirt-tfrag": [6, 8, 13, 15],
"draw-drawable-tree-ice-tfrag": [6, 8, 13, 15],
"birth-pickup-at-point": [0]
},
// Sometimes the game might use format strings that are fetched dynamically,
@@ -495,51 +54,26 @@
// e.g. "function-name":[[op, argc], [op, argc], ...]
// where "op" is the op number for the call to format.
"dynamic_format_arg_counts": {
"(method 35 progress)": [
[44, 1],
[92, 1]
],
"(method 49 progress)": [[35, 1]],
"(method 37 progress)": [[41, 1]],
"(method 38 progress)": [[106, 1]],
"(method 39 progress)": [[41, 1]],
"(method 41 progress)": [[73, 1]],
"(method 42 progress)": [[41, 1]],
"(method 43 progress)": [
[51, 1],
[94, 1]
],
"": []
},
"mips2c_functions_by_name": [
"sp-init-fields!",
"particle-adgif",
"sp-launch-particles-var",
"sp-process-block-2d",
"sp-process-block-3d",
"draw-large-polygon",
"clip-polygon-against-positive-hyperplane",
"clip-polygon-against-negative-hyperplane",
"render-sky-quad",
"render-sky-tri",
"init-sky-regs",
"set-tex-offset",
"adgif-shader<-texture-with-update!",
"init-boundary-regs",
"draw-boundary-polygon",
"render-boundary-quad",
"render-boundary-tri",
"draw-inline-array-tfrag",
"stats-tfrag-asm",
"time-of-day-interp-colors-scratch"
],
"mips2c_jump_table_functions": {
},
// there are some missing textures. I don't know what the game actually does here.
// the format for entries is [level, tpage, index]
"missing_textures": [
["finalboss", 1419, 3]
"missing_textures": [],
// 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.
// this just suppresses a message.
"expected_merged_objs": [
]
}
+3
View File
@@ -0,0 +1,3 @@
{
}
+160 -158
View File
@@ -7,163 +7,163 @@
// most objects are part of CGO/DGO files (both go in dgo_names). This includes levels and the engine
// the DGOs will be processed in this order. Usually it's best to have KERNEL, ENGINE, then the levels when
// you want to run on the entire game.
"dgo_names": [/*
"CGO/ART.CGO",
"CGO/KERNEL.CGO",
"CGO/ENGINE.CGO",
"CGO/GAME.CGO",
"CGO/COMMON.CGO",
"DGO/LWIDEB.DGO",
"DGO/LMEETBRT.DGO",
"DGO/CTA.DGO",
"DGO/PALOUT.DGO",
"DGO/STD.DGO",
"DGO/FOR.DGO",
"DGO/CASEXT.DGO",
"DGO/HIDEOUT.DGO",
"DGO/LWIDESTA.DGO",
"DGO/LRACELIT.DGO",
"DGO/CTB.DGO",
"DGO/KIOSK.DGO",
"DGO/DG1.DGO",
"DGO/FEB.DGO",
"DGO/DMI.DGO",
"DGO/ORACLE.DGO",
"DGO/LERLTESS.DGO",
"DGO/DRI.DGO",
"DGO/LBRNERMK.DGO",
"DGO/LRACECF.DGO",
"DGO/CTC.DGO",
"DGO/LTHRNOUT.DGO",
"DGO/FRA.DGO",
"DGO/LGARCSTA.DGO",
"DGO/MTN.DGO",
"DGO/INTROCST.DGO",
"DGO/DRB.DGO",
"DGO/ATE.DGO",
"DGO/LERROL.DGO",
"DGO/LTRNYSAM.DGO",
"DGO/LOUTCSTB.DGO",
"DGO/LASHTHRN.DGO",
"DGO/TOC.DGO",
"DGO/CFB.DGO",
"DGO/CAB.DGO",
"DGO/STC.DGO",
"DGO/STR.DGO",
"DGO/ATO.DGO",
"DGO/SEB.DGO",
"DGO/LPRSNCST.DGO",
"DGO/SWB.DGO",
"DGO/LPOWER.DGO",
"DGO/FOB.DGO",
"DGO/CIB.DGO",
"DGO/LSHUTTLE.DGO",
"DGO/LJAKDAX.DGO",
"DGO/FORDUMPC.DGO",
"DGO/LTRNTESS.DGO",
"DGO/TBO.DGO",
"DGO/THR.DGO",
"DGO/PRI.DGO",
"DGO/LKIDDOGE.DGO",
"DGO/NESTT.DGO",
"DGO/LWIDEC.DGO",
"DGO/SAG.DGO",
"DGO/NEB.DGO",
"DGO/COB.DGO",
"DGO/LBOMBBOT.DGO",
"DGO/DEMO.DGO",
"DGO/LRACEDF.DGO",
"DGO/LERLCHAL.DGO",
"DGO/LHIPOUT.DGO",
"DGO/OUTROCST.DGO",
"DGO/NES.DGO",
"DGO/PAR.DGO",
"DGO/LERBRNGD.DGO",
"DGO/MTX.DGO",
"DGO/FDA.DGO",
"DGO/LKEIRIFT.DGO",
"DGO/LWHACK.DGO",
"DGO/LJKDXASH.DGO",
"DGO/CAS.DGO",
"DGO/COA.DGO",
"DGO/LTESS.DGO",
"DGO/CFA.DGO",
"DGO/TOMBEXT.DGO",
"DGO/LCGUARD.DGO",
"DGO/TOE.DGO",
"DGO/PALBOSS.DGO",
"DGO/FRB.DGO",
"DGO/PAE.DGO",
"DGO/TITLE.DGO",
"DGO/FORDUMPD.DGO",
"DGO/D3A.DGO",
"DGO/DRILLMTN.DGO",
"DGO/PAC.DGO",
"DGO/LTENTOB.DGO",
"DGO/LRACEBF.DGO",
"DGO/LPROTECT.DGO",
"DGO/FEA.DGO",
"DGO/ONINTENT.DGO",
"DGO/STA.DGO",
"DGO/CGC.DGO",
"DGO/CMA.DGO",
"DGO/FDB.DGO",
"DGO/SKA.DGO",
"DGO/LTRNKRKD.DGO",
"DGO/CIA.DGO",
"DGO/TOB.DGO",
"DGO/LRACEDB.DGO",
"DGO/LDJAKBRN.DGO",
"DGO/TOA.DGO",
"DGO/STADBLMP.DGO",
"DGO/UND.DGO",
"DGO/LYSKDCD.DGO",
"DGO/HALFPIPE.DGO",
"DGO/LSAMERGD.DGO",
"DGO/PAS.DGO",
"DGO/LBBUSH.DGO",
"DGO/LPACKAGE.DGO",
"DGO/LINTCSTB.DGO",
"DGO/LPORTRUN.DGO",
"DGO/LASHGRD.DGO",
"DGO/CGB.DGO",
"DGO/D3B.DGO",
"DGO/STB.DGO",
"DGO/GARAGE.DGO",
"DGO/PORTWALL.DGO",
"DGO/LHELLDOG.DGO",
"DGO/SWE.DGO",
"DGO/LRACECB.DGO",
"DGO/GGA.DGO",
"DGO/TOD.DGO",
"DGO/MCN.DGO",
"DGO/SEW.DGO",
"DGO/VIN.DGO",
"DGO/CGA.DGO",
"DGO/CMB.DGO",
"DGO/LGUARD.DGO",
"DGO/CPA.DGO",
"DGO/LCITYLOW.DGO",
"DGO/LTENTOUT.DGO",
"DGO/UNB.DGO",
"DGO/CPO.DGO",
"DGO/CAP.DGO",
"DGO/CWI.DGO",
"DGO/CTYKORA.DGO",
"DGO/RUI.DGO",
"DGO/LSACK.DGO",
"DGO/CTYASHA.DGO",
"DGO/LPRTRACE.DGO",
"DGO/LWIDEA.DGO",
"DGO/HIPHOG.DGO",
"DGO/LSMYSBRT.DGO",
"DGO/LRACEBB.DGO",
"DGO/CASCITY.DGO",
"DGO/LYSAMSAM.DGO",
"DGO/VI1.DGO"*/
],
"dgo_names": [
"./CGO/ART.CGO",
"./CGO/KERNEL.CGO",
"./CGO/ENGINE.CGO",
"./CGO/GAME.CGO",
"./CGO/COMMON.CGO",
"./DGO/LWIDEB.DGO",
"./DGO/LMEETBRT.DGO",
"./DGO/CTA.DGO",
"./DGO/PALOUT.DGO",
"./DGO/STD.DGO",
"./DGO/FOR.DGO",
"./DGO/CASEXT.DGO",
"./DGO/HIDEOUT.DGO",
"./DGO/LWIDESTA.DGO",
"./DGO/LRACELIT.DGO",
"./DGO/CTB.DGO",
"./DGO/KIOSK.DGO",
"./DGO/DG1.DGO",
"./DGO/FEB.DGO",
"./DGO/DMI.DGO",
"./DGO/ORACLE.DGO",
"./DGO/LERLTESS.DGO",
"./DGO/DRI.DGO",
"./DGO/LBRNERMK.DGO",
"./DGO/LRACECF.DGO",
"./DGO/CTC.DGO",
"./DGO/LTHRNOUT.DGO",
"./DGO/FRA.DGO",
"./DGO/LGARCSTA.DGO",
"./DGO/MTN.DGO",
"./DGO/INTROCST.DGO",
"./DGO/DRB.DGO",
"./DGO/ATE.DGO",
"./DGO/LERROL.DGO",
"./DGO/LTRNYSAM.DGO",
"./DGO/LOUTCSTB.DGO",
"./DGO/LASHTHRN.DGO",
"./DGO/TOC.DGO",
"./DGO/CFB.DGO",
"./DGO/CAB.DGO",
"./DGO/STC.DGO",
"./DGO/STR.DGO",
"./DGO/ATO.DGO",
"./DGO/SEB.DGO",
"./DGO/LPRSNCST.DGO",
"./DGO/SWB.DGO",
"./DGO/LPOWER.DGO",
"./DGO/FOB.DGO",
"./DGO/CIB.DGO",
"./DGO/LSHUTTLE.DGO",
"./DGO/LJAKDAX.DGO",
"./DGO/FORDUMPC.DGO",
"./DGO/LTRNTESS.DGO",
"./DGO/TBO.DGO",
"./DGO/THR.DGO",
"./DGO/PRI.DGO",
"./DGO/LKIDDOGE.DGO",
"./DGO/NESTT.DGO",
"./DGO/LWIDEC.DGO",
"./DGO/SAG.DGO",
"./DGO/NEB.DGO",
"./DGO/COB.DGO",
"./DGO/LBOMBBOT.DGO",
"./DGO/DEMO.DGO",
"./DGO/LRACEDF.DGO",
"./DGO/LERLCHAL.DGO",
"./DGO/LHIPOUT.DGO",
"./DGO/OUTROCST.DGO",
"./DGO/NES.DGO",
"./DGO/PAR.DGO",
"./DGO/LERBRNGD.DGO",
"./DGO/MTX.DGO",
"./DGO/FDA.DGO",
"./DGO/LKEIRIFT.DGO",
"./DGO/LWHACK.DGO",
"./DGO/LJKDXASH.DGO",
"./DGO/CAS.DGO",
"./DGO/COA.DGO",
"./DGO/LTESS.DGO",
"./DGO/CFA.DGO",
"./DGO/TOMBEXT.DGO",
"./DGO/LCGUARD.DGO",
"./DGO/TOE.DGO",
"./DGO/PALBOSS.DGO",
"./DGO/FRB.DGO",
"./DGO/PAE.DGO",
"./DGO/TITLE.DGO",
"./DGO/FORDUMPD.DGO",
"./DGO/D3A.DGO",
"./DGO/DRILLMTN.DGO",
"./DGO/PAC.DGO",
"./DGO/LTENTOB.DGO",
"./DGO/LRACEBF.DGO",
"./DGO/LPROTECT.DGO",
"./DGO/FEA.DGO",
"./DGO/ONINTENT.DGO",
"./DGO/STA.DGO",
"./DGO/CGC.DGO",
"./DGO/CMA.DGO",
"./DGO/FDB.DGO",
"./DGO/SKA.DGO",
"./DGO/LTRNKRKD.DGO",
"./DGO/CIA.DGO",
"./DGO/TOB.DGO",
"./DGO/LRACEDB.DGO",
"./DGO/LDJAKBRN.DGO",
"./DGO/TOA.DGO",
"./DGO/STADBLMP.DGO",
"./DGO/UND.DGO",
"./DGO/LYSKDCD.DGO",
"./DGO/HALFPIPE.DGO",
"./DGO/LSAMERGD.DGO",
"./DGO/PAS.DGO",
"./DGO/LBBUSH.DGO",
"./DGO/LPACKAGE.DGO",
"./DGO/LINTCSTB.DGO",
"./DGO/LPORTRUN.DGO",
"./DGO/LASHGRD.DGO",
"./DGO/CGB.DGO",
"./DGO/D3B.DGO",
"./DGO/STB.DGO",
"./DGO/GARAGE.DGO",
"./DGO/PORTWALL.DGO",
"./DGO/LHELLDOG.DGO",
"./DGO/SWE.DGO",
"./DGO/LRACECB.DGO",
"./DGO/GGA.DGO",
"./DGO/TOD.DGO",
"./DGO/MCN.DGO",
"./DGO/SEW.DGO",
"./DGO/VIN.DGO",
"./DGO/CGA.DGO",
"./DGO/CMB.DGO",
"./DGO/LGUARD.DGO",
"./DGO/CPA.DGO",
"./DGO/LCITYLOW.DGO",
"./DGO/LTENTOUT.DGO",
"./DGO/UNB.DGO",
"./DGO/CPO.DGO",
"./DGO/CAP.DGO",
"./DGO/CWI.DGO",
"./DGO/CTYKORA.DGO",
"./DGO/RUI.DGO",
"./DGO/LSACK.DGO",
"./DGO/CTYASHA.DGO",
"./DGO/LPRTRACE.DGO",
"./DGO/LWIDEA.DGO",
"./DGO/HIPHOG.DGO",
"./DGO/LSMYSBRT.DGO",
"./DGO/LRACEBB.DGO",
"./DGO/CASCITY.DGO",
"./DGO/LYSAMSAM.DGO",
"./DGO/VI1.DGO"
],
// some objects are part of STR files (streaming data). In Jak 1 this is just animations
// some objects are part of STR files (streaming data).
"str_file_names": [
],
@@ -177,11 +177,13 @@
"TEXT/5COMMON.TXT",
"TEXT/6COMMON.TXT",
"TEXT/7COMMON.TXT"
],
],
// uncomment the next line to extract audio to wave files.
//"audio_dir_file_name": "jak1/VAG",
"audio_dir_file_name": "",
"streamed_audio_file_names": ["VAGWAD.ENG", "VAGWAD.JAP"]
"streamed_audio_file_names": [],
"levels_to_extract": []
}
File diff suppressed because it is too large Load Diff
-110
View File
@@ -1,114 +1,4 @@
{
"(method 2 array)":[
[23, "gp", "(array int32)"],
[43, "gp", "(array uint32)"],
[63, "gp", "(array int64)"],
[83, "gp", "(array uint64)"],
[102, "gp", "(array int8)"],
[121, "gp", "(array uint8)"],
[141, "gp", "(array int16)"],
[161, "gp", "(array uint16)"],
[185, "gp", "(array uint128)"],
[203, "gp", "(array int32)"],
[222, "gp", "(array float)"],
[231, "gp", "(array float)"],
[248, "gp", "(array basic)"],
[257, "gp", "(array basic)"]
],
"(method 3 array)":[
[44, "gp", "(array int32)"],
[62, "gp", "(array uint32)"],
[80, "gp", "(array int64)"],
[98, "gp", "(array uint64)"],
[115, "gp", "(array int8)"],
[132, "gp", "(array int8)"], // bug in game
[150, "gp", "(array int16)"],
[168, "gp", "(array uint16)"],
[190, "gp", "(array uint128)"],
[203, "gp", "(array int32)"],
[225, "gp", "(array float)"],
[242, "gp", "(array basic)"]
],
"(method 2 handle)":[
[10, "a3", "process"],
[11, "v1", "int"],
[15, "gp", "int"]
],
"(method 3 handle)":[
[10, "gp", "int"]
],
"(method 0 cpu-thread)":[
[13, "v0", "cpu-thread"]
],
"(method 0 dead-pool-heap)":[
[60, "v0", "int"], // a lie, actually the 115 is an align16 constant propagated on addr of heap start.
[61, "v0", "dead-pool-heap"]
],
"(method 21 dead-pool-heap)":[
[5, "v1", "pointer"],
[13, "a0", "pointer"],
[25, "v1", "pointer"]
],
"(method 5 dead-pool-heap)":[
[3, "v1", "int"],
[3, "a0", "int"]
],
"remove-exit":[
[0, "s6", "process"]
],
"(method 0 process)":[
[12, "a0", "int"],
[13, "v0", "process"]
],
"inspect-process-heap":[
[4, "s5", "basic"],
[17, "s5", "int"]
],
"return-from-thread-dead":[
[0, "s6", "process"]
],
"(method 14 dead-pool)":[
[23, "v1", "process"], // bad visit order with #f?
[28, "s4", "(pointer process-tree)"] // bug in real game, see gkernel.gc
],
"throw":[
[20, "s4", "protect-frame"] // type case
],
"(method 0 protect-frame)":[
[0, "a0", "int"],
[1, "v0", "protect-frame"]
],
"(method 9 process)":[
[43, "s5", "process"]
],
"(method 10 process)":[
[24, "s4", "protect-frame"]
],
"enter-state":[
[67, "s0", "protect-frame"]
],
"name=":[
[24, "a1", "symbol"],
[39, "a0", "symbol"]
],
"placeholder-do-not-add-below": []
}
+19 -8
View File
@@ -2,6 +2,9 @@
"game_version": 2,
"text_version": 20,
"game_name": "jak2",
"expected_elf_name": "SCUS_972.65",
// if you want to filter to only some object names.
// it will make the decompiler much faster.
"allowed_objects": [],
@@ -13,7 +16,7 @@
// set to true to generate plain .asm files with MIPS disassembly, with no fancy decompilation.
// this is fast and should succeed 100% of the time.
"disassemble_code": false,
"disassemble_code": true,
// Run the decompiler
"decompile_code": false,
@@ -32,7 +35,9 @@
// unpack game text to assets folder
"process_game_text": true,
// unpack game count to assets folder
"process_game_count": false,
"process_game_count": true,
// write goal imports for art groups
"process_art_groups": true,
///////////////////////////
// WEIRD OPTIONS
@@ -40,9 +45,6 @@
// these options are used rarely and should usually be left at false
// output a file type_defs.gc which is used for the types part of all-types.gc
"regenerate_all_types": false,
// generate the symbol_map.json file.
// this is a guess at where each symbol is first defined/used.
"generate_symbol_definition_map": false,
@@ -75,15 +77,24 @@
"stack_structures_file": "decompiler/config/jak2/stack_structures.jsonc",
"hacks_file": "decompiler/config/jak2/hacks.jsonc",
"inputs_file": "decompiler/config/jak2/inputs.jsonc",
"art_info_file": "decompiler/config/jak2/art_info.jsonc",
"import_deps_file": "decompiler/config/jak2/import_deps.jsonc",
"all_types_file": "decompiler/config/all-types2.gc",
// optional: a predetermined object file name map from a file.
// this will make decompilation naming consistent even if you only run on some objects.
"obj_file_name_map_file": "",//"goal_src/build/all_objs.json",
// "obj_file_name_map_file": "goal_src2/build/all_objs.json",
////////////////////////////
// LEVEL EXTRACTION
////////////////////////////
"levels_to_extract":[
]
// turn this on to extract level background graphics data
"levels_extract": false,
// turn this on if you want extracted levels to be saved out as .obj files
"levels_convert_to_obj": false,
// should we extract collision meshes?
// these can be displayed in game, but makes the .fr3 files slightly larger
"extract_collision": true
}
+1 -1
View File
@@ -338,7 +338,7 @@ TexturePage read_texture_page(ObjectFileData& data,
tpage.info_label = get_label(data, words.at(offset));
tpage.info = read_file_info(data, words, label_to_word_offset(tpage.info_label, true));
ASSERT(tpage.info.file_type == "texture-page");
ASSERT(tpage.info.major_version == versions::TX_PAGE_VERSION);
ASSERT(tpage.info.major_version == versions::jak1::TX_PAGE_VERSION);
ASSERT(tpage.info.minor_version == 0);
ASSERT(tpage.info.maya_file_name == "Unknown");
ASSERT(tpage.info.mdb_file_name == 0);
+1 -1
View File
@@ -278,7 +278,7 @@ char* DecodeFileName(const char* name) {
* PC PORT NOTE : Changed some paths so that they work for us (namely, got rid of 'host')
*/
char* MakeFileName(int type, const char* name, int new_string) {
using namespace versions;
using namespace versions::jak1;
// start with network filesystem
// kstrcpy(buffer_633, "host:");
kstrcpy(buffer_633, "");
+1 -1
View File
@@ -138,7 +138,7 @@
(string 80)
(array 81)
(sprite 82)
;;
;;
(debug-dma 84) ;; maybe
(sky-dma 85) ;; maybe
;;
+3 -4
View File
@@ -14,7 +14,7 @@
;; Some example uses:
;; - a "foreground-engine" has connections to all foreground objects that need to be drawn on each frame.
;; - when a process wants to change a game setting, it opens a connection to the settings engine to request a change.
;; when the process is killed, the setting change is reverted.
;; when the process is killed (or it stops requesting the change), the setting change is reverted.
;; A "connection" is really just a function that gets called when the engine runs, or a set of parameters that the engine can iterate through.
@@ -53,9 +53,8 @@
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; this is the actual data for the connection.
;; it may be used in multiple ways, but it appears like
;; the first param0 is a function that receives
;; the three other params as arguments, plus the engine it is connect to as a 4th.
;; it may be used in multiple ways, but the most common is to use param0 as a function
;; it receives param1, param2, param3, and the engine as the arugmetns.
;; in some cases, the return value is checked for 'dead.
(declare-type engine basic)
+1 -1
View File
@@ -45,7 +45,7 @@
(light-yellow 32)
(red-orange 33)
(another-orange-red 34)
(red 3)
(red2 4)
(yellow 5)
+9 -8
View File
@@ -17,7 +17,7 @@
(defun get-current-time ()
"Get the in game time. This advances when the game is unpaused.
This increase at the same rate for PAL/NTSC and if the game is lagging."
This increases at the same rate for PAL/NTSC and if the game is lagging."
(-> *display* base-frame-counter)
)
@@ -32,12 +32,12 @@
(defmethod set-time-ratios display ((obj display) (slowdown float))
"Set the time ratios for the current game speed. For example, set slowdown = 1.0 if the game
is running at full speed or slowdown = 2.0 if the game is running at half speed."
;; don't allow slowdowns of more than 4x. This prevents the dt's in the physics
;; calculations from getting huge.
(let ((ratio (fmin 4.0 slowdown)))
(set! (-> obj time-ratio) ratio)
(case (get-video-mode)
(case (get-video-mode)
(('pal)
(set! (-> obj time-adjust-ratio) (* 1.2 ratio))
(set! (-> obj seconds-per-frame) (* 0.02 ratio))
@@ -76,7 +76,7 @@
fpb: the framebuffer."
;; these will eventually be consumed by a sony function. I think it just sets GS registers.
;; set these to the mode that makes the GS actually work. Basically every game uses exactly this.
(set! (-> env pmode)
(new 'static 'gs-pmode :en1 #x1 :mmod #x1 :slbg #x1 :alp #xff)
@@ -243,7 +243,8 @@
(set! (-> disp integral-frame-counter) (seconds 1000))
(set! (-> disp real-integral-frame-counter) (seconds 1000))
;; and the "old" version, which I think was their value on the last... frame?
;; and fake the "old" versions. These are normally set to the value on the previous frame
;; (which may jump due to saving/loading or lag)
(set! (-> disp old-base-frame-counter) (+ (-> disp base-frame-counter) -1))
(set! (-> disp old-game-frame-counter) (+ (-> disp game-frame-counter) -1))
(set! (-> disp old-real-frame-counter) (+ (-> disp real-frame-counter) -1))
@@ -458,7 +459,7 @@
(defun draw-sprite2d-xy ((buf dma-buffer) (x int) (y int) (w int) (h int) (color rgba))
"Draw a sprite primitive with the given color and dimensions."
;; create context and clip dimensions.
(let* ((context (new 'stack 'draw-context x y w h color))
(draw-x (max 1792 (min 2304 (+ (-> context orgx) 1792))))
@@ -473,14 +474,14 @@
;; remember the address of the first dma-tag
)
(with-cnt-vif-block (buf)
(dma-buffer-add-gif-tag buf (new 'static 'gif-tag64 :nloop 1 :eop 1 :flg (gif-flag reg-list) :nreg 4)
(gs-reg-list prim rgbaq xyzf2 xyzf2)
)
(dma-buffer-add-uint64 buf (new 'static 'gs-prim :prim (gs-prim-type sprite) :abe 1)
(-> context color 0)
(new 'static 'gs-xyzf :x (* draw-x 16) :y (* draw-y 16) :z #x3fffff)
(new 'static 'gs-xyzf :x (* (minmax (+ draw-x draw-w) 1792 2304) 16)
(new 'static 'gs-xyzf :x (* (minmax (+ draw-x draw-w) 1792 2304) 16)
:y (* (minmax (+ draw-y draw-h) (-> *video-parms* screen-miny) (-> *video-parms* screen-maxy)) 16) :z #x3fffff)
)
)
+1 -1
View File
@@ -146,7 +146,7 @@
(beach-level-name #x221)
(jungle-level-name #x222)
(misty-level-name #x223)
(jungleb-level-name #x225)
(beach-seagull-get #x22e)
+4 -1
View File
@@ -9,6 +9,8 @@
#include "common/util/Assert.h"
constexpr GameVersion kGameVersion = GameVersion::Jak1;
/*!
* Get the level data from a DGO File.
* Will ignore all the other things in the level DGO and just return the bsp file.
@@ -28,7 +30,8 @@ decompiler::LinkedObjectFile load_bsp_from_dgo(const std::string& file_name,
fmt::print("Using level file: {}, size {} kB\n", level_file.internal_name,
level_file.data.size() / 1024);
return decompiler::to_linked_object_file(level_file.data, level_file.internal_name, dts, 1);
return decompiler::to_linked_object_file(level_file.data, level_file.internal_name, dts,
kGameVersion);
}
bool is_valid_bsp(const decompiler::LinkedObjectFile& file) {