diff --git a/src/Compression.cc b/src/Compression.cc index a7eeda70..91a23ab9 100644 --- a/src/Compression.cc +++ b/src/Compression.cc @@ -96,10 +96,11 @@ struct prs_compress_ctx { } }; -string prs_compress(const string& data) { +string prs_compress(const void* vdata, size_t size) { + const uint8_t* data = reinterpret_cast(vdata); prs_compress_ctx pc; - ssize_t data_ssize = static_cast(data.size()); + ssize_t data_ssize = static_cast(size); ssize_t read_offset = 0; while (read_offset < data_ssize) { @@ -117,8 +118,8 @@ string prs_compress(const string& data) { while ((this_size < 0x100) && // max copy size is 255 bytes ((this_offset + this_size) < 0) && // don't copy past the read offset (this_size <= data_ssize - read_offset) && // don't copy past the end - !memcmp(data.data() + read_offset + this_offset, - data.data() + read_offset, this_size)) { + !memcmp(data + read_offset + this_offset, data + read_offset, + this_size)) { this_size++; } this_size--; @@ -143,6 +144,10 @@ string prs_compress(const string& data) { return pc.finish(); } +string prs_compress(const string& data) { + return prs_compress(data.data(), data.size()); +} + static int16_t get_u8_or_eof(StringReader& r) { diff --git a/src/Compression.hh b/src/Compression.hh index 7b59bcf1..726600bc 100644 --- a/src/Compression.hh +++ b/src/Compression.hh @@ -6,6 +6,8 @@ +std::string prs_compress(const void* vdata, size_t size); std::string prs_compress(const std::string& data); + std::string prs_decompress(const std::string& data, size_t max_size = 0); size_t prs_decompress_size(const std::string& data, size_t max_size = 0); diff --git a/src/Episode3.cc b/src/Episode3.cc index 7508a904..d1d26754 100644 --- a/src/Episode3.cc +++ b/src/Episode3.cc @@ -774,36 +774,51 @@ Ep3DataIndex::Ep3DataIndex(const string& directory) { } for (const auto& filename : list_directory(directory)) { - if (ends_with(filename, ".mnm")) { - try { - string compressed_data = load_file(directory + "/" + filename); - // There's a small header (Ep3CompressedMapHeader) before the compressed - // data, which we ignore - string data_to_decompress = compressed_data.substr(8); - string data = prs_decompress(data_to_decompress); - if (data.size() != sizeof(Ep3Map)) { - throw runtime_error(string_printf( - "decompressed data size is incorrect (expected %zu bytes, read %zu bytes)", - sizeof(Ep3Map), data.size())); - } + try { + shared_ptr entry; - shared_ptr entry(new MapEntry( - {*reinterpret_cast(data.data()), move(compressed_data)})); + if (ends_with(filename, ".mnmd")) { + entry.reset(new MapEntry(load_object_file(directory + "/" + filename))); + } else if (ends_with(filename, ".mnm")) { + entry.reset(new MapEntry(load_file(directory + "/" + filename))); + } + + if (entry.get()) { if (!this->maps.emplace(entry->map.map_number, entry).second) { throw runtime_error("duplicate map number"); } string name = entry->map.name; log(INFO, "Indexed Episode 3 map %s (%08" PRIX32 "; %s)", filename.c_str(), entry->map.map_number.load(), name.c_str()); - - } catch (const exception& e) { - log(WARNING, "Failed to index Episode 3 map %s: %s", - filename.c_str(), e.what()); } + + } catch (const exception& e) { + log(WARNING, "Failed to index Episode 3 map %s: %s", + filename.c_str(), e.what()); } } } +Ep3DataIndex::MapEntry::MapEntry(const Ep3Map& map) : map(map) { } + +Ep3DataIndex::MapEntry::MapEntry(const string& compressed) + : compressed_data(compressed) { + string decompressed = prs_decompress(this->compressed_data); + if (decompressed.size() != sizeof(Ep3Map)) { + throw runtime_error(string_printf( + "decompressed data size is incorrect (expected %zu bytes, read %zu bytes)", + sizeof(Ep3Map), decompressed.size())); + } + this->map = *reinterpret_cast(decompressed.data()); +} + +string Ep3DataIndex::MapEntry::compressed() const { + if (this->compressed_data.empty()) { + this->compressed_data = prs_compress(&this->map, sizeof(this->map)); + } + return this->compressed_data; +} + const string& Ep3DataIndex::get_compressed_card_definitions() const { if (this->compressed_card_definitions.empty()) { throw runtime_error("card definitions are not available"); diff --git a/src/Episode3.hh b/src/Episode3.hh index f05d00a7..db8e2639 100644 --- a/src/Episode3.hh +++ b/src/Episode3.hh @@ -295,7 +295,7 @@ struct Ep3Map { // .mnm format (after decompressing and discarding the header) ptext name; parray unknown_a3; } __attribute__((packed)); - /* 20F0 */ parray npc_chars; // Unused if name[0] == 0 + /* 20F0 */ NPCCharacter npc_chars[3]; // Unused if name[0] == 0 /* 242C */ parray unknown_a8; // Always FF? /* 2440 */ ptext before_message; /* 25D0 */ ptext after_message; @@ -305,7 +305,7 @@ struct Ep3Map { // .mnm format (after decompressing and discarding the header) be_uint16_t unknown_a2; // Always 0x0064 if valid, 0xFFFF if unused? ptext strings[4]; } __attribute__((packed)); // Total size: 0x104 bytes - /* 28F0 */ parray dialogue_sets[3]; // Up to 0x10 per valid NPC + /* 28F0 */ DialogueSet dialogue_sets[3][0x10]; // Up to 0x10 per valid NPC /* 59B0 */ be_uint16_t reward_card_id; // TODO: This could be an array. The only examples I've seen have only one here /* 59B2 */ parray unknown_a9; /* 5A18 */ @@ -320,9 +320,17 @@ public: std::vector text; }; - struct MapEntry { + class MapEntry { + public: Ep3Map map; - std::string compressed_data; + + MapEntry(const Ep3Map& map); + MapEntry(const std::string& compressed_data); + + std::string compressed() const; + + private: + mutable std::string compressed_data; }; const std::string& get_compressed_card_definitions() const; diff --git a/src/ProxyCommands.cc b/src/ProxyCommands.cc index 891031b6..aeee7540 100644 --- a/src/ProxyCommands.cc +++ b/src/ProxyCommands.cc @@ -26,6 +26,7 @@ #include #endif +#include "Compression.hh" #include "PSOProtocol.hh" #include "SendCommands.hh" #include "ReceiveCommands.hh" @@ -637,11 +638,11 @@ static bool process_server_60_62_6C_6D_C9_CB(shared_ptr, if ((session.version == GameVersion::GC) && (data.size() >= 0x14)) { PSOSubcommand* subs = &check_size_t(data, 0x14, 0xFFFF); if (subs[0].dword == 0x000000B6 && subs[2].dword == 0x00000041) { - string filename = string_printf("map%08" PRIX32 ".%" PRIu64 ".mnm", + string filename = string_printf("map%08" PRIX32 ".%" PRIu64 ".mnmd", subs[3].dword.load(), now()); - string file_data = data.substr(0x0C); - save_file(filename, file_data); - session.log(INFO, "Wrote %zu bytes to %s", file_data.size(), filename.c_str()); + string map_data = prs_decompress(data.substr(0x14)); + save_file(filename, map_data); + session.log(INFO, "Wrote %zu bytes to %s", map_data.size(), filename.c_str()); } } } diff --git a/src/SendCommands.cc b/src/SendCommands.cc index 3357665d..5e7b9ab8 100644 --- a/src/SendCommands.cc +++ b/src/SendCommands.cc @@ -1399,13 +1399,19 @@ void send_ep3_map_list(shared_ptr s, shared_ptr l) { // sends the map data for the chosen map to all players in the game void send_ep3_map_data(shared_ptr s, shared_ptr l, uint32_t map_id) { auto entry = s->ep3_data_index->get_map(map_id); + const auto& compressed = entry->compressed(); - string data(12, '\0'); + string data(0x14, '\0'); PSOSubcommand* subs = reinterpret_cast(data.data()); subs[0].dword = 0x000000B6; - subs[1].dword = (19 + entry->compressed_data.size()) & 0xFFFFFFFC; + subs[1].dword = (19 + compressed.size()) & 0xFFFFFFFC; subs[2].dword = 0x00000041; - data += entry->compressed_data; + subs[3].dword = entry->map.map_number.load(); + subs[4].dword = compressed.size(); + data += compressed; + while (data.size() & 3) { + data.push_back('\0'); + } send_command(l, 0x6C, 0x00, data); } diff --git a/system/ep3/map00000230.mnm b/system/ep3/map00000230.mnm deleted file mode 100644 index 17364c2d..00000000 Binary files a/system/ep3/map00000230.mnm and /dev/null differ diff --git a/system/ep3/map00000230.mnmd b/system/ep3/map00000230.mnmd new file mode 100644 index 00000000..c178eb22 Binary files /dev/null and b/system/ep3/map00000230.mnmd differ diff --git a/system/ep3/map00000244.mnm b/system/ep3/map00000244.mnm deleted file mode 100644 index fe3c4cfb..00000000 Binary files a/system/ep3/map00000244.mnm and /dev/null differ diff --git a/system/ep3/map00000244.mnmd b/system/ep3/map00000244.mnmd new file mode 100644 index 00000000..9e3a7b40 Binary files /dev/null and b/system/ep3/map00000244.mnmd differ diff --git a/system/ep3/map00000258.mnm b/system/ep3/map00000258.mnm deleted file mode 100644 index 05c58fd0..00000000 Binary files a/system/ep3/map00000258.mnm and /dev/null differ diff --git a/system/ep3/map00000258.mnmd b/system/ep3/map00000258.mnmd new file mode 100644 index 00000000..579af62f Binary files /dev/null and b/system/ep3/map00000258.mnmd differ diff --git a/system/ep3/map0000026C.mnm b/system/ep3/map0000026C.mnm deleted file mode 100644 index 3eb267af..00000000 Binary files a/system/ep3/map0000026C.mnm and /dev/null differ diff --git a/system/ep3/map0000026C.mnmd b/system/ep3/map0000026C.mnmd new file mode 100644 index 00000000..5d2a2f81 Binary files /dev/null and b/system/ep3/map0000026C.mnmd differ diff --git a/system/ep3/map00000280.mnm b/system/ep3/map00000280.mnm deleted file mode 100644 index 318de8bc..00000000 Binary files a/system/ep3/map00000280.mnm and /dev/null differ diff --git a/system/ep3/map00000280.mnmd b/system/ep3/map00000280.mnmd new file mode 100644 index 00000000..b08d26d8 Binary files /dev/null and b/system/ep3/map00000280.mnmd differ diff --git a/system/ep3/map00000294.mnm b/system/ep3/map00000294.mnm deleted file mode 100644 index 44556451..00000000 Binary files a/system/ep3/map00000294.mnm and /dev/null differ diff --git a/system/ep3/map00000294.mnmd b/system/ep3/map00000294.mnmd new file mode 100644 index 00000000..3fa2652a Binary files /dev/null and b/system/ep3/map00000294.mnmd differ diff --git a/system/ep3/map000002A8.mnm b/system/ep3/map000002A8.mnm deleted file mode 100644 index 52e241d8..00000000 Binary files a/system/ep3/map000002A8.mnm and /dev/null differ diff --git a/system/ep3/map000002A8.mnmd b/system/ep3/map000002A8.mnmd new file mode 100644 index 00000000..1de4ec5e Binary files /dev/null and b/system/ep3/map000002A8.mnmd differ diff --git a/system/ep3/map000002BC.mnm b/system/ep3/map000002BC.mnm deleted file mode 100644 index 5e81eeec..00000000 Binary files a/system/ep3/map000002BC.mnm and /dev/null differ diff --git a/system/ep3/map000002BC.mnmd b/system/ep3/map000002BC.mnmd new file mode 100644 index 00000000..98543e6b Binary files /dev/null and b/system/ep3/map000002BC.mnmd differ diff --git a/system/ep3/map000002BD.mnm b/system/ep3/map000002BD.mnm deleted file mode 100644 index 3efc895c..00000000 Binary files a/system/ep3/map000002BD.mnm and /dev/null differ diff --git a/system/ep3/map000002BD.mnmd b/system/ep3/map000002BD.mnmd new file mode 100644 index 00000000..c71aee78 Binary files /dev/null and b/system/ep3/map000002BD.mnmd differ diff --git a/system/ep3/map000002E4.mnm b/system/ep3/map000002E4.mnm deleted file mode 100644 index 85d367d0..00000000 Binary files a/system/ep3/map000002E4.mnm and /dev/null differ diff --git a/system/ep3/map000002E4.mnmd b/system/ep3/map000002E4.mnmd new file mode 100644 index 00000000..da7b58ca Binary files /dev/null and b/system/ep3/map000002E4.mnmd differ diff --git a/system/ep3/map000002F8.mnm b/system/ep3/map000002F8.mnm deleted file mode 100644 index c7e73b4d..00000000 Binary files a/system/ep3/map000002F8.mnm and /dev/null differ diff --git a/system/ep3/map000002F8.mnmd b/system/ep3/map000002F8.mnmd new file mode 100644 index 00000000..a897211a Binary files /dev/null and b/system/ep3/map000002F8.mnmd differ diff --git a/system/ep3/map000002F9.mnm b/system/ep3/map000002F9.mnm deleted file mode 100644 index 8ddd6110..00000000 Binary files a/system/ep3/map000002F9.mnm and /dev/null differ diff --git a/system/ep3/map000002F9.mnmd b/system/ep3/map000002F9.mnmd new file mode 100644 index 00000000..f86607c5 Binary files /dev/null and b/system/ep3/map000002F9.mnmd differ diff --git a/system/ep3/map00000320.mnm b/system/ep3/map00000320.mnm deleted file mode 100644 index 5868c1a2..00000000 Binary files a/system/ep3/map00000320.mnm and /dev/null differ diff --git a/system/ep3/map00000320.mnmd b/system/ep3/map00000320.mnmd new file mode 100644 index 00000000..e3cfa333 Binary files /dev/null and b/system/ep3/map00000320.mnmd differ diff --git a/system/ep3/map00000334.mnm b/system/ep3/map00000334.mnm deleted file mode 100644 index 206c0c51..00000000 Binary files a/system/ep3/map00000334.mnm and /dev/null differ diff --git a/system/ep3/map00000334.mnmd b/system/ep3/map00000334.mnmd new file mode 100644 index 00000000..79642fce Binary files /dev/null and b/system/ep3/map00000334.mnmd differ