From aad50f916024d83d53290bd5c43e1f0eaf24251d Mon Sep 17 00:00:00 2001 From: lzwdgc Date: Sat, 27 Jan 2018 03:40:30 +0300 Subject: [PATCH] Update mmo, mmp. --- cppan.yml | 1 + src/CMakeLists.txt | 1 + src/common/objects.cpp | 4 +- src/common/objects.h | 4 +- src/mmo_extractor/mmo_extractor.cpp | 79 +++++++++++++++--------- src/mmo_extractor/other.h | 91 +++++++++++++++++----------- src/mmp_extractor/mmp.cpp | 26 ++++++-- src/mmp_extractor/mmp.h | 93 ++++++++++++++++++----------- src/mmp_extractor/mmp_extractor.cpp | 7 ++- src/mod_converter/fbx.cpp | 2 + src/unpaker/decode.h | 2 +- 11 files changed, 202 insertions(+), 108 deletions(-) diff --git a/cppan.yml b/cppan.yml index 2208beb..d6000d1 100644 --- a/cppan.yml +++ b/cppan.yml @@ -5,3 +5,4 @@ local_settings: - pvt.egorpugin.primitives.filesystem: master - pvt.egorpugin.primitives.executor: master - pvt.cppan.demo.unicode.icu.i18n: "*" + - pvt.cppan.demo.taywee.args: "*" diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 84f3783..7f590f4 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -35,6 +35,7 @@ add_executable(mmo_extractor ${mmo_extractor_src}) target_link_libraries(mmo_extractor common pvt.lzwdgc.polygon4.data_manager.data_manager + pvt.cppan.demo.taywee.args ) file(GLOB mmp_extractor_src "mmp_extractor/*") diff --git a/src/common/objects.cpp b/src/common/objects.cpp index 48b6022..69e8c11 100644 --- a/src/common/objects.cpp +++ b/src/common/objects.cpp @@ -65,8 +65,8 @@ Segment *Segment::create_segment(const buffer &b) case ObjectType::unk0: segment = new SegmentObjects; break; - case ObjectType::unk1: - segment = new SegmentObjects; + case ObjectType::TANK: + segment = new SegmentObjects; break; default: assert(false); diff --git a/src/common/objects.h b/src/common/objects.h index e4e6910..13cddd0 100644 --- a/src/common/objects.h +++ b/src/common/objects.h @@ -59,7 +59,7 @@ enum class ObjectType : uint32_t BOUNDARY = 23, SOUND_ZONE = 24, - unk1 = 27, + TANK = 27, }; struct Segment @@ -160,12 +160,12 @@ KNOWN_OBJECT(Image); KNOWN_OBJECT(Anomaly); KNOWN_OBJECT(Tower); KNOWN_OBJECT(SoundZone); +KNOWN_OBJECT(Tank); #define UNKNOWN_OBJECT(name) \ struct name : public MapObject { void load(const buffer &b){ int pos = b.index(); assert(false); } } UNKNOWN_OBJECT(unk0); -UNKNOWN_OBJECT(unk1); struct Objects { diff --git a/src/mmo_extractor/mmo_extractor.cpp b/src/mmo_extractor/mmo_extractor.cpp index f243870..8a40dfa 100644 --- a/src/mmo_extractor/mmo_extractor.cpp +++ b/src/mmo_extractor/mmo_extractor.cpp @@ -33,6 +33,7 @@ #include #include #include +#include #include #include @@ -52,7 +53,6 @@ struct mmo_storage Objects objects; MechGroups mechGroups; MapGoods mapGoods; - uint32_t unk0 = 0; MapMusic mapMusic; MapSounds mapSounds; // aim2 @@ -60,6 +60,8 @@ struct mmo_storage OrganizationBases orgsBases; Prices prices; + uint32_t unk0 = 0; + void load(const buffer &b) { objects.load(b); @@ -268,39 +270,62 @@ void write_mmo(Storage *storage, const mmo_storage &s) int main(int argc, char *argv[]) try { - if (argc != 4) - { - std::cout << "Usage:\n" << argv[0] << " db.sqlite {file.mmo,mmo_dir} prefix" << "\n"; - return 1; - } - prefix = argv[3]; - if (prefix == "m1") - gameType = GameType::Aim1; - else if (prefix == "m2") - gameType = GameType::Aim2; - else - throw std::runtime_error("unknown prefix (game type)"); + args::ArgumentParser parser("mmo extractor"); + args::HelpFlag help(parser, "help", "Display this help menu", { 'h', "help" }); + args::Flag m2(parser, "m2", "m2 .mmo file", { "m2" }); + args::Flag print_mechanoids(parser, "print_mechanoids", "Print mechanoids", { "print_mechanoids" }); + args::ValueFlag db_path(parser, "db_path", "Database file", {'d', "db"}); + args::Positional file_path(parser, "file or directory", ".mmo file or directory with .mmo files"); + parser.Prog(argv[0]); - auto storage = initStorage(argv[1]); - storage->load(); + parser.ParseCLI(argc, argv); - path p = argv[2]; - if (fs::is_regular_file(p)) - write_mmo(storage.get(), read_mmo(p)); - else if (fs::is_directory(p)) + const path p = file_path.Get(); + gameType = m2 ? GameType::Aim2 : GameType::Aim1; + + /*{ + std::cerr << parser; + }*/ + + auto action = [&p](auto f) { - auto files = enumerate_files_like(p, ".*\\.mmo", false); - for (auto &f : files) + if (fs::is_regular_file(p)) + f(p, read_mmo(p)); + else if (fs::is_directory(p)) { - std::cout << "processing: " << f << "\n"; - write_mmo(storage.get(), read_mmo(f)); + auto files = enumerate_files_like(p, ".*\\.[Mm][Mm][Oo]", false); + for (auto &file : files) + { + std::cerr << "processing: " << file << "\n"; + f(file, read_mmo(file)); + } } + else + throw std::runtime_error("Bad fs object"); + }; + + if (print_mechanoids) + { + action([](const path &file, const mmo_storage &m) + { + for (auto &mg : m.mechGroups.mechGroups) + { + std::cout << mg.name; + std::cout << " " << mg.org; + std::cout << " " << mg.mechanoids.size(); + std::cout << " " << file.filename().stem().string(); + std::cout << "\n"; + } + }); } else - throw std::runtime_error("Bad fs object"); - - if (inserted_all) - storage->save(); + { + auto storage = initStorage(db_path.Get()); + storage->load(); + action([&storage](const path &, const auto &m) {write_mmo(storage.get(), m); }); + if (inserted_all) + storage->save(); + } return 0; } diff --git a/src/mmo_extractor/other.h b/src/mmo_extractor/other.h index b00da4f..e770c4e 100644 --- a/src/mmo_extractor/other.h +++ b/src/mmo_extractor/other.h @@ -27,63 +27,86 @@ #include #include +#include + struct MechGroup { std::string name; std::string org; - uint32_t type1 = 0; - uint32_t len1 = 0; - char name1[0x70]; - //{3,4 - uint32_t unk30 = 0; - //} - //{2 - uint32_t len = 0; - std::vector unk11; - //} - //{1,0 - uint32_t unk20 = 0; - uint32_t unk21 = 0; - //} - std::vector configs; - char unk100; + std::vector mechanoids; + + // used only in m1.loc1 and for sinigr + // probably an old field + std::string org_ru; + + struct unk_type01 + { + uint32_t unk0 = 0; + float unk1 = 0; + }; + + std::variant, uint32_t> type_data; + + bool hidden; void load(const buffer &b) { READ_STRING(b, name); READ_STRING(b, org); - READ(b, type1); - READ(b, len1); - READ(b, name1); - if (type1 == 3 || type1 == 4) + uint32_t type = 0; + READ(b, type); + uint32_t number_of_mechanoids = 0; + READ(b, number_of_mechanoids); + READ_STRING_N(b, org_ru, 0x70); + + switch (type) { - READ(b, unk30); + case 0: + case 1: + { + unk_type01 t; + READ(b, t.unk0); + READ(b, t.unk1); + type_data = t; } - else if (type1 == 2) + break; + case 2: { + std::vector t; + uint32_t len = 0; READ(b, len); - unk11.resize(len); + t.resize(len); for (int i = 0; i < len; i++) - READ(b, unk11[i]); + READ(b, t[i]); + type_data = t; } - else if (type1 == 1 || type1 == 0) + break; + case 3: // 3 = free mechanoids only? + case 4: { - READ(b, unk20); - READ(b, unk21); + uint32_t t; + READ(b, t); + type_data = t; } - else + break; + default: assert(false); - configs.resize(len1, std::string(0x20, 0)); - for (int i = 0; i < len1; i++) - READ_N(b, configs[i][0], 0x20); - READ(b, unk100); + } + + for (int i = 0; i < number_of_mechanoids; i++) + { + std::string t; + READ_STRING_N(b, t, 0x20); + mechanoids.push_back(t); + } + READ(b, hidden); } }; struct MechGroups { - char prefix[0x30]; std::vector mechGroups; + char unk0[0x30]; // prefix? void load(const buffer &b) { @@ -94,7 +117,7 @@ struct MechGroups } uint32_t n = 0; READ(b, n); - READ(b, prefix); + READ(b, unk0); for (int s = 0; s < n; s++) { diff --git a/src/mmp_extractor/mmp.cpp b/src/mmp_extractor/mmp.cpp index 0523899..52a6c52 100644 --- a/src/mmp_extractor/mmp.cpp +++ b/src/mmp_extractor/mmp.cpp @@ -84,10 +84,14 @@ void header::load(const buffer &b) void segment::load(const buffer &b) { + uint32_t offset; + READ(b, offset); READ(b, desc); buffer b2(b); - b2.seek(desc.offset); + b2.seek(offset); READ(b2, d); + b2.seek(offset); + READ(b2, d2); } void mmp::load(const buffer &b) @@ -107,7 +111,7 @@ void mmp::load(const buffer &b) // check whether all segments were read if (segments.size()) { - auto len = segments[0].desc.offset + segments.size() * sizeof(segment::data); + auto len = b.index() + segments.size() * sizeof(segment::data); if (len != b.size()) throw std::logic_error("Some segments were not read"); } @@ -167,6 +171,7 @@ void mmp::process() // merge heightmap = decltype(heightmap)(h.width, h.length); + //heightmap_segmented = decltype(heightmap)(segment::len, h.length); texmap = decltype(texmap)(h.width, h.length); texmap_colored = decltype(texmap_colored)(h.width, h.length); colormap = decltype(colormap)(h.width, h.length); @@ -213,11 +218,12 @@ void mmp::process() alpha_maps.erase(0); scale16 = 0xffff / (h_max - h_min); - const int unreal_koef = 51200; + const int unreal_koef = 51300; const int aim_koef = 10; const double diff = h_max - h_min; - scale = aim_koef / (unreal_koef / diff); + scale = aim_koef * diff / unreal_koef; + // make heightmap for (auto &s : segments) { int y1 = s.desc.min.y / 10; @@ -281,7 +287,7 @@ void mmp::writeTexturesList() void mmp::writeHeightMap() { - auto fn = filename + ".heightmap16.raw"; + auto fn = filename + ".heightmap16.r16"; FILE *f = fopen(fn.c_str(), "wb"); if (f == nullptr) return; @@ -289,6 +295,16 @@ void mmp::writeHeightMap() fclose(f); } +void mmp::writeHeightMapSegmented() +{ + /*auto fn = filename + ".heightmap.r16s"; + FILE *f = fopen(fn.c_str(), "wb"); + if (f == nullptr) + return; + fwrite(&heightmap_segmented(0, 0), heightmap_segmented.size() * sizeof(decltype(heightmap_segmented)::type), 1, f); + fclose(f);*/ +} + void mmp::writeTextureMap() { auto fn = filename + ".texmap.bmp"; diff --git a/src/mmp_extractor/mmp.h b/src/mmp_extractor/mmp.h index 92839a9..47f0bf6 100644 --- a/src/mmp_extractor/mmp.h +++ b/src/mmp_extractor/mmp.h @@ -81,49 +81,52 @@ struct segment static const int len = 65; static const int size = len * len; + static const int mini_len = 33; + static const int mini_size = mini_len * mini_len; + struct description { - uint32_t offset; vector3 min; vector3 max; float unk0[5]; uint32_t unk1[7]; }; + + struct info + { + uint16_t render_flags; + uint16_t texture_index; + + uint16_t getTexture() const { return texture_index & 0x0fff; } // first 4 bits are unk (flags?) + }; + + struct shadow + { + uint8_t unk[4]; + }; + + struct normal + { + int16_t x; + int16_t y; + }; + + struct flagged_heightmap + { + uint16_t height; + uint16_t flag; + }; + + struct mini_lod + { + flagged_heightmap Heightmap[mini_size]; + color Colormap[mini_size]; + uint32_t unk0[mini_size]; // shadowmap? + normal unk1[mini_size]; // normals? + }; + struct data { - struct info - { - uint16_t render_flags; - uint16_t texture_index; - - uint16_t getTexture() const { return texture_index & 0x0fff; } // first 4 bits are unk (flags?) - }; - struct shadow - { - uint8_t unk[4]; - }; - struct normal - { - int16_t x; - int16_t y; - }; - struct mini_lod - { - static const int len = 33; - static const int size = len * len; - - struct flagged_heightmap - { - uint16_t height; - uint16_t flag; - }; - - flagged_heightmap Heightmap[size]; - color Colormap[size]; - uint32_t unk0[size]; // shadowmap? - normal unk1[size]; // normals? - }; - uint32_t MagicNumber; mini_lod mlod; Height Heightmap[size]; @@ -133,8 +136,28 @@ struct segment normal Normalmap[size]; }; + struct mini_lod2 + { + flagged_heightmap Heightmap[mini_len][mini_len]; + color Colormap[mini_len][mini_len]; + uint32_t unk0[mini_len][mini_len]; // shadowmap? + normal unk1[mini_len][mini_len]; // normals? + }; + + struct data2 + { + uint32_t MagicNumber; + mini_lod2 mlod; + Height Heightmap[len][len]; + info Infomap[len][len]; + color Colormap[len][len]; + shadow Shadowmap[len][len]; + normal Normalmap[len][len]; + }; + description desc; data d; + data2 d2; void load(const buffer &b); }; @@ -158,6 +181,7 @@ struct mmp double scale16 = 0; double scale = 0; mat heightmap; + //mat heightmap_segmented; mat texmap; mat texmap_colored; mat colormap; @@ -171,6 +195,7 @@ struct mmp void writeFileInfo(); void writeTexturesList(); void writeHeightMap(); + void writeHeightMapSegmented(); void writeTextureMap(); void writeTextureAlphaMaps(); void writeTextureMapColored(); diff --git a/src/mmp_extractor/mmp_extractor.cpp b/src/mmp_extractor/mmp_extractor.cpp index 25198cf..b4cc3fa 100644 --- a/src/mmp_extractor/mmp_extractor.cpp +++ b/src/mmp_extractor/mmp_extractor.cpp @@ -45,12 +45,13 @@ try m.load(p.string()); m.process(); m.writeFileInfo(); - m.writeTexturesList(); + //m.writeTexturesList(); m.writeHeightMap(); - m.writeTextureMap(); + //m.writeHeightMapSegmented(); + /*m.writeTextureMap(); m.writeTextureAlphaMaps(); m.writeTextureMapColored(); - m.writeColorMap(); + m.writeColorMap();*/ }; path p = argv[1]; diff --git a/src/mod_converter/fbx.cpp b/src/mod_converter/fbx.cpp index c378761..a2f6774 100644 --- a/src/mod_converter/fbx.cpp +++ b/src/mod_converter/fbx.cpp @@ -256,6 +256,8 @@ bool CreateScene(model &model, const std::string &name, FbxManager* pSdkManager, int fx_id = 0; for (auto &b : model.blocks) { + // b.h.name == "SHAPE" - collision object + // if (b.isEngineFx()) { diff --git a/src/unpaker/decode.h b/src/unpaker/decode.h index 6a54470..2127423 100644 --- a/src/unpaker/decode.h +++ b/src/unpaker/decode.h @@ -306,4 +306,4 @@ int decode_f4(char *input, int size, char *output, int segment_offset) goto LABEL_9; } return result; -} \ No newline at end of file +}