full ntsc-j mode + greatest hits support (#1525)

* remove str files from inputs

* removed unused verbose flag

* allow some kind of conditional game building for JP extras

* make `PrintBankInfo` do nothing

* clang

* Update gltf_mesh_extract.cpp

* fix `*jak1-full-game*` in extractor

* use json library to build json file

* screw it red label support as well
This commit is contained in:
ManDude
2022-06-23 23:44:02 +01:00
committed by GitHub
parent 9754688879
commit 85bef15364
21 changed files with 234 additions and 36 deletions
+53 -14
View File
@@ -1,7 +1,10 @@
#include <map>
#include <regex>
#include <unordered_map>
#include "common/log/log.h"
#include "common/util/FileUtil.h"
#include "common/util/json_util.h"
#include "common/util/read_iso_file.h"
#include "decompiler/Disasm/OpcodeInfo.h"
@@ -23,12 +26,18 @@ enum class ExtractorErrorCode {
DECOMPILATION_GENERIC_ERROR = 4030
};
enum GameIsoFlags { FLAG_JAK1_BLACK_LABEL = (1 << 0) };
static const std::unordered_map<std::string, GameIsoFlags> sGameIsoFlagNames = {
{"jak1-black-label", FLAG_JAK1_BLACK_LABEL}};
struct ISOMetadata {
std::string canonical_name;
std::string region;
int num_files;
xxh::hash64_t contents_hash;
std::string decomp_config;
GameIsoFlags flags = (GameIsoFlags)0;
};
// TODO - when we support jak2 and beyond, add which game it's for as well
@@ -39,11 +48,12 @@ static const std::map<std::string, std::map<xxh::hash64_t, ISOMetadata>> isoData
{"SCUS-97124",
{{7280758013604870207U,
{"Jak & Daxter™: The Precursor Legacy (Black Label)", "NTSC-U", 337, 11363853835861842434U,
"jak1_ntsc_black_label"}}}},
"jak1_ntsc_black_label", FLAG_JAK1_BLACK_LABEL}},
{744661860962747854,
{"Jak & Daxter™: The Precursor Legacy", "NTSC-U", 338, 8538304367812415885U, "jak1_jp"}}}},
{"SCES-50361",
{{12150718117852276522U,
{"Jak & Daxter™: The Precursor Legacy (PAL)", "PAL", 338, 16850370297611763875U,
"jak1_pal"}}}},
{"Jak & Daxter™: The Precursor Legacy", "PAL", 338, 16850370297611763875U, "jak1_pal"}}}},
{"SCPS-15021",
{{16909372048085114219U,
{"ジャックXダクスター  旧世界の遺産", "NTSC-J", 338, 1262350561338887717,
@@ -90,11 +100,12 @@ std::pair<std::optional<std::string>, std::optional<xxh::hash64_t>> findElfFile(
return {serial, elf_hash};
}
ExtractorErrorCode validate(const IsoFile& iso_file,
const std::filesystem::path& extracted_iso_path) {
std::pair<ExtractorErrorCode, std::optional<ISOMetadata>> validate(
const IsoFile& iso_file,
const std::filesystem::path& extracted_iso_path) {
if (!std::filesystem::exists(extracted_iso_path / "DGO")) {
fmt::print(stderr, "ERROR: input folder doesn't have a DGO folder. Is this the right input?\n");
return ExtractorErrorCode::VALIDATION_BAD_EXTRACTION;
return {ExtractorErrorCode::VALIDATION_BAD_EXTRACTION, std::nullopt};
}
std::optional<ExtractorErrorCode> error_code;
@@ -116,10 +127,11 @@ ExtractorErrorCode validate(const IsoFile& iso_file,
error_code = std::make_optional(ExtractorErrorCode::VALIDATION_CANT_LOCATE_ELF);
}
// No point in continuing here
return error_code.value();
return {*error_code, std::nullopt};
}
// Find the game in our tracking database
std::optional<ISOMetadata> meta_res = std::nullopt;
if (auto dbEntry = isoDatabase.find(serial.value()); dbEntry == isoDatabase.end()) {
fmt::print(stderr, "ERROR: Serial '{}' not found in the validation database\n", serial.value());
if (!error_code.has_value()) {
@@ -137,7 +149,8 @@ ExtractorErrorCode validate(const IsoFile& iso_file,
error_code = std::make_optional(ExtractorErrorCode::VALIDATION_ELF_MISSING_FROM_DB);
}
} else {
auto meta = meta_entry->second;
meta_res = std::make_optional<ISOMetadata>(meta_entry->second);
const auto& meta = *meta_res;
// Print out some information
fmt::print("Detected Game Metadata:\n");
fmt::print("\tDetected - {}\n", meta.canonical_name);
@@ -189,10 +202,10 @@ ExtractorErrorCode validate(const IsoFile& iso_file,
"Validation has failed to match with expected values, see the above errors for "
"specifics. This may be an error in the validation database!\n");
}
return error_code.value();
return {*error_code, std::nullopt};
}
return ExtractorErrorCode::SUCCESS;
return {ExtractorErrorCode::SUCCESS, meta_res};
}
std::optional<ISOMetadata> determineRelease(const std::filesystem::path& jak1_input_files) {
@@ -313,6 +326,17 @@ void compile(std::filesystem::path extracted_iso_path) {
compiler.make_system().set_constant("*iso-data*", absolute(extracted_iso_path).string());
compiler.make_system().set_constant("*use-iso-data-path*", true);
auto buildinfo_path = (extracted_iso_path / "buildinfo.json").string();
auto bi = parse_commented_json(file_util::read_text_file(buildinfo_path), buildinfo_path);
auto all_flags = bi.at("flags").get<std::vector<std::string>>();
int flags = 0;
for (const auto& n : all_flags) {
if (auto it = sGameIsoFlagNames.find(n); it != sGameIsoFlagNames.end()) {
flags |= it->second;
}
}
compiler.make_system().set_constant("*jak1-full-game*", !(flags & FLAG_JAK1_BLACK_LABEL));
compiler.make_system().load_project_file(
(file_util::get_jak_project_dir() / "goal_src" / "game.gp").string());
compiler.run_front_end_on_string("(mi)");
@@ -389,15 +413,17 @@ int main(int argc, char** argv) {
}
std::filesystem::create_directories(path_to_iso_files);
int flags = 0;
if (std::filesystem::is_regular_file(data_dir_path)) {
// it's a file, treat it as an ISO
auto iso_file = extract_files(data_dir_path, path_to_iso_files);
auto validation_res = validate(iso_file, path_to_iso_files);
if (validation_res == ExtractorErrorCode::VALIDATION_BAD_EXTRACTION) {
flags = validation_res.second->flags;
if (validation_res.first == ExtractorErrorCode::VALIDATION_BAD_EXTRACTION) {
// We fail here regardless of the flag
return static_cast<int>(validation_res);
} else if (flag_fail_on_validation && validation_res != ExtractorErrorCode::SUCCESS) {
return static_cast<int>(validation_res);
return static_cast<int>(validation_res.first);
} else if (flag_fail_on_validation && validation_res.first != ExtractorErrorCode::SUCCESS) {
return static_cast<int>(validation_res.first);
}
} else if (std::filesystem::is_directory(data_dir_path)) {
if (!flag_folder) {
@@ -407,6 +433,19 @@ int main(int argc, char** argv) {
}
path_to_iso_files = data_dir_path;
}
// write out a json file with some metadata for the game
nlohmann::json buildinfo_json;
auto flags_json = nlohmann::json::array();
for (const auto& [n, f] : sGameIsoFlagNames) {
if (flags & f) {
flags_json.push_back(n);
}
}
buildinfo_json["flags"] = flags_json;
// something tells me a ps2 game is unlikely to have a json file in root
file_util::write_text_file((path_to_iso_files / "buildinfo.json").string(),
buildinfo_json.dump(2));
}
if (flag_decompile) {