[decompiler] jak 2 cutscene file support (#2390)

fixes #2332 

also fills out the japanese character set
This commit is contained in:
ManDude
2023-03-22 21:31:13 +00:00
committed by GitHub
parent b18198e655
commit 217a979048
26 changed files with 1285 additions and 64 deletions
@@ -276,6 +276,10 @@ std::string LinkedObjectFile::print_words() {
auto& word = words_by_seg[seg][i];
append_word_to_string(result, word);
if (word.kind() == LinkedWord::TYPE_PTR && word.symbol_name() == "string") {
result += "; " + get_goal_string(seg, i) + "\n";
}
}
}
+74 -16
View File
@@ -29,6 +29,7 @@
#include "decompiler/data/StrFileReader.h"
#include "decompiler/data/dir_tpages.h"
#include "decompiler/data/game_count.h"
#include "decompiler/data/game_subs.h"
#include "decompiler/data/game_text.h"
#include "decompiler/data/tpage.h"
@@ -204,18 +205,20 @@ ObjectFileDB::ObjectFileDB(const std::vector<fs::path>& _dgos,
add_obj_from_dgo(name, name, data.data(), data.size(), "NO-XGO", config);
}
lg::info("-Loading {} streaming object files...", str_files.size());
for (auto& obj : str_files) {
StrFileReader reader(obj);
// name from the file name
std::string base_name = obj_filename_to_name(obj.string());
// name from inside the file (this does a lot of sanity checking)
auto obj_name = reader.get_full_name(base_name + ".STR");
for (int i = 0; i < reader.chunk_count(); i++) {
// append the chunk ID to the full name
std::string name = obj_name + fmt::format("+{}", i);
auto& data = reader.get_chunk(i);
add_obj_from_dgo(name, name, data.data(), data.size(), "NO-XGO", config);
if (config.read_spools) {
lg::info("-Loading {} streaming object files...", str_files.size());
for (auto& obj : str_files) {
StrFileReader reader(obj, version());
// name from the file name
std::string base_name = obj_filename_to_name(obj.string());
// name from inside the file (this does a lot of sanity checking)
auto obj_name = reader.get_full_name(base_name + ".STR");
for (int i = 0; i < reader.chunk_count(); i++) {
// append the chunk ID to the full name
std::string name = obj_name + fmt::format("+{}", i);
auto& data = reader.get_chunk(i);
add_obj_from_dgo(name, name, data.data(), data.size(), "ALLSPOOL", config, obj_name);
}
}
}
@@ -369,7 +372,8 @@ void ObjectFileDB::add_obj_from_dgo(const std::string& obj_name,
const uint8_t* obj_data,
uint32_t obj_size,
const std::string& dgo_name,
const Config& config) {
const Config& config,
const std::string& cut_name) {
if (config.banned_objects.find(obj_name) != config.banned_objects.end()) {
return;
}
@@ -415,6 +419,7 @@ void ObjectFileDB::add_obj_from_dgo(const std::string& obj_name,
// if this is the first time we've seen this object file name, add it in the order.
obj_file_order.push_back(obj_name);
}
data.base_name_from_chunk = cut_name;
data.record.version = obj_files_by_name[obj_name].size();
data.name_in_dgo = name_in_dgo;
data.obj_version = version;
@@ -489,9 +494,10 @@ std::string ObjectFileDB::generate_obj_listing(const std::unordered_set<std::str
for (auto& obj_file : obj_file_order) {
for (auto& x : obj_files_by_name.at(obj_file)) {
std::string dgos = "[";
for (auto& y : x.dgo_names) {
ASSERT(y.length() >= 5);
std::string new_str = y == "NO-XGO" ? y : y.substr(0, y.length() - 4);
for (auto& name : x.dgo_names) {
ASSERT(name.length() >= 5);
std::string new_str =
(name == "NO-XGO" || name == "ALLSPOOL") ? name : name.substr(0, name.length() - 4);
dgos += "\"" + new_str + "\", ";
}
dgos.pop_back();
@@ -725,6 +731,58 @@ std::string ObjectFileDB::process_tpages(TextureDB& tex_db, const fs::path& outp
return result;
}
std::string ObjectFileDB::process_all_spool_subtitles(const Config& cfg,
const fs::path& image_out) {
try {
lg::info("- Finding spool subtitles...");
Timer timer;
int obj_count = 0;
int string_count = 0;
int image_count = 0;
int subs_count = 0;
std::unordered_map<std::string, std::vector<SpoolSubtitleRange>> all_subs;
for_each_obj_in_dgo("ALLSPOOL", [&](ObjectFileData& data) {
int this_string_count = 0;
int this_image_count = 0;
obj_count++;
auto this_spool_subs = process_spool_subtitles(data, cfg.text_version);
if (!this_spool_subs.empty()) {
for (auto& s : this_spool_subs) {
subs_count++;
for (int i = 0; i < 8; ++i) {
if (s.message[i].kind == SpoolSubtitleMessage::Kind::IMAGE) {
this_image_count++;
} else if (s.message[i].kind == SpoolSubtitleMessage::Kind::STRING) {
this_string_count++;
}
}
}
auto& spool_subs = all_subs[data.base_name_from_chunk];
for (auto& x : this_spool_subs) {
bool skip = false;
for (auto& other : spool_subs) {
skip |= other == x;
}
if (!skip) {
all_subs[data.base_name_from_chunk].push_back(x);
image_count += this_image_count;
string_count += this_string_count;
}
}
}
});
lg::info("Processed {} subtitles in {} spool objects ({} strings, {} images) in {:.2f} ms",
subs_count, obj_count, string_count, image_count, timer.getMs());
return write_spool_subtitles(cfg.text_version, image_out, all_subs);
} catch (std::runtime_error& e) {
lg::warn("Error when extracting spool subtitles: {}", e.what());
return {};
}
}
std::string ObjectFileDB::process_game_text_files(const Config& cfg) {
try {
lg::info("- Finding game text...");
+18 -3
View File
@@ -47,6 +47,7 @@ struct ObjectFileData {
std::string name_in_dgo;
std::string name_from_map;
std::string to_unique_name() const;
std::string base_name_from_chunk;
uint32_t reference_count = 0; // number of times its used.
std::string full_output;
@@ -246,6 +247,7 @@ class ObjectFileDB {
std::string process_tpages(TextureDB& tex_db, const fs::path& output_path);
std::string process_game_count_file();
std::string process_game_text_files(const Config& cfg);
std::string process_all_spool_subtitles(const Config& cfg, const fs::path& image_out);
const ObjectFileData& lookup_record(const ObjectFileRecord& rec) const;
DecompilerTypeSystem dts;
@@ -255,7 +257,6 @@ class ObjectFileDB {
const Config& config,
TypeSpec* result);
public:
void load_map_file(const std::string& map_data);
void get_objs_from_dgo(const fs::path& filename, const Config& config);
void add_obj_from_dgo(const std::string& obj_name,
@@ -263,7 +264,8 @@ class ObjectFileDB {
const uint8_t* obj_data,
uint32_t obj_size,
const std::string& dgo_name,
const Config& config);
const Config& config,
const std::string& cut_name = "");
/*!
* Apply f to all ObjectFileData's. Does it in the right order.
@@ -273,7 +275,20 @@ class ObjectFileDB {
ASSERT(obj_files_by_name.size() == obj_file_order.size());
for (const auto& name : obj_file_order) {
for (auto& obj : obj_files_by_name.at(name)) {
// lg::info("{}...", name);
f(obj);
}
}
}
/*!
* Apply f to all ObjectFileData's in a specific DGO. Does it in the right order.
*/
template <typename Func>
void for_each_obj_in_dgo(const std::string& dgo_name, Func f) {
ASSERT(obj_files_by_name.size() == obj_file_order.size());
const auto& dgo_objs = obj_files_by_dgo.at(dgo_name);
for (const auto& rec : dgo_objs) {
for (auto& obj : obj_files_by_name.at(rec.name)) {
f(obj);
}
}