From 7f214ed2ec3078486a5bce25a0bd5744b25963be Mon Sep 17 00:00:00 2001 From: lzwdgc Date: Wed, 5 Aug 2015 18:04:39 +0300 Subject: [PATCH] Extract all information from MMP files. --- CMakeLists.txt | 2 +- src/CMakeLists.txt | 13 +- src/mmm_extractor/mmm.cpp | 29 +++ src/mmm_extractor/mmm.h | 39 ++++ src/mmm_extractor/mmm_extractor.cpp | 67 +++++++ .../mmo_extractor.bat} | 4 +- .../mmo_extractor.cpp} | 0 .../mmo_extractor.py} | 2 +- .../objects.cpp | 0 .../objects.h | 0 src/{obj_extractor => mmo_extractor}/other.h | 0 src/mmp_extractor/mmp.cpp | 132 ++++++++++--- src/mmp_extractor/mmp.h | 179 ++++++++++++++---- src/mmp_extractor/mmp_extractor.bat | 2 + src/mmp_extractor/mmp_extractor.cpp | 38 ++-- src/mmp_extractor/mmp_extractor.py | 25 +++ 16 files changed, 445 insertions(+), 87 deletions(-) create mode 100644 src/mmm_extractor/mmm.cpp create mode 100644 src/mmm_extractor/mmm.h create mode 100644 src/mmm_extractor/mmm_extractor.cpp rename src/{obj_extractor/obj_extractor.bat => mmo_extractor/mmo_extractor.bat} (57%) rename src/{obj_extractor/obj_extractor.cpp => mmo_extractor/mmo_extractor.cpp} (100%) rename src/{obj_extractor/obj_extractor.py => mmo_extractor/mmo_extractor.py} (92%) rename src/{obj_extractor => mmo_extractor}/objects.cpp (100%) rename src/{obj_extractor => mmo_extractor}/objects.h (100%) rename src/{obj_extractor => mmo_extractor}/other.h (100%) create mode 100644 src/mmp_extractor/mmp_extractor.bat create mode 100644 src/mmp_extractor/mmp_extractor.py diff --git a/CMakeLists.txt b/CMakeLists.txt index b69c757..1cd4aea 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -18,7 +18,7 @@ if (MSVC) #set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /MTd") #set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MT") else() - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} --std=c++11") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} --std=c++14") endif(MSVC) if (NOT DATABASE_MANAGER_DIR) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 63ad19f..6d2f044 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -9,15 +9,20 @@ add_executable(db_extractor ${db_extractor_src}) target_link_libraries(db_extractor common) endif() -file(GLOB obj_extractor_src "obj_extractor/*") -add_executable(obj_extractor ${obj_extractor_src}) -target_link_libraries(obj_extractor DatabaseManager common) - file(GLOB script2txt_src "script2txt/*") add_executable(script2txt ${script2txt_src}) +file(GLOB mmm_extractor_src "mmm_extractor/*") +add_executable(mmm_extractor ${mmm_extractor_src}) +target_link_libraries(mmm_extractor DatabaseManager common) + +file(GLOB mmo_extractor_src "mmo_extractor/*") +add_executable(mmo_extractor ${mmo_extractor_src}) +target_link_libraries(mmo_extractor DatabaseManager common) + file(GLOB mmp_extractor_src "mmp_extractor/*") add_executable(mmp_extractor ${mmp_extractor_src}) +target_link_libraries(mmp_extractor common) file(GLOB mod_converter_src "mod_converter/*") add_executable(mod_converter ${mod_converter_src}) diff --git a/src/mmm_extractor/mmm.cpp b/src/mmm_extractor/mmm.cpp new file mode 100644 index 0000000..2222cc1 --- /dev/null +++ b/src/mmm_extractor/mmm.cpp @@ -0,0 +1,29 @@ +/* + * AIM mmm_extractor + * Copyright (C) 2015 lzwdgc + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "mmm.h" + +void mmm::load(buffer &b) +{ + READ(b, unk1); + READ(b, unk2); + READ(b, width); + READ(b, height); + data.resize(width * height / 16); + READ_N(b, data[0], data.size() * 16); +} \ No newline at end of file diff --git a/src/mmm_extractor/mmm.h b/src/mmm_extractor/mmm.h new file mode 100644 index 0000000..61a5914 --- /dev/null +++ b/src/mmm_extractor/mmm.h @@ -0,0 +1,39 @@ +/* + * AIM mmm_extractor + * Copyright (C) 2015 lzwdgc + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include + +#include + +struct dxt5_record +{ + char unk[0x10]; +}; + +struct mmm +{ + uint32_t unk1; + uint32_t unk2; + uint32_t width; + uint32_t height; + std::vector data; + + void load(buffer &b); +}; \ No newline at end of file diff --git a/src/mmm_extractor/mmm_extractor.cpp b/src/mmm_extractor/mmm_extractor.cpp new file mode 100644 index 0000000..7f91f1f --- /dev/null +++ b/src/mmm_extractor/mmm_extractor.cpp @@ -0,0 +1,67 @@ +/* + * AIM mmm_extractor + * Copyright (C) 2015 lzwdgc + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include + +#include "mmm.h" + +using namespace std; + +mmm read_mmm(string fn) +{ + buffer b(readFile(fn)); + mmm m; + m.load(b); + + if (!b.eof()) + { + stringstream ss; + ss << hex << b.index() << " != " << hex << b.size(); + throw std::logic_error(ss.str()); + } + return m; +} + +int main(int argc, char *argv[]) +try +{ +#ifdef NDEBUG + if (argc != 2) + { + cout << "Usage:\n" << argv[0] << " file.mmp" << "\n"; + return 1; + } + read_mmm(argv[1]); +#else + auto loc1 = read_mmm("h:\\Games\\AIM\\data\\minimaps.pak.dir\\location1.mmm"); +#endif + return 0; +} +catch (std::exception &e) +{ + printf("error: %s\n", e.what()); + return 1; +} +catch (...) +{ + printf("error: unknown exception\n"); + return 1; +} \ No newline at end of file diff --git a/src/obj_extractor/obj_extractor.bat b/src/mmo_extractor/mmo_extractor.bat similarity index 57% rename from src/obj_extractor/obj_extractor.bat rename to src/mmo_extractor/mmo_extractor.bat index 6f54f48..a04d0bf 100644 --- a/src/obj_extractor/obj_extractor.bat +++ b/src/mmo_extractor/mmo_extractor.bat @@ -1,2 +1,2 @@ -python obj_extractor.py --db "h:\Games\Epic Games\Projects\Polygon4\Mods\db.sqlite" --dir "h:\Games\AIM\data\maps.pak.dir" --prefix m1 -python obj_extractor.py --db "h:\Games\Epic Games\Projects\Polygon4\Mods\db.sqlite" --dir "h:\Games\Steam\steamapps\common\AIM2\Data\mmo.pak\DATA\LOCS" --prefix m2 \ No newline at end of file +python mmo_extractor.py --db "h:\Games\Epic Games\Projects\Polygon4\Mods\db.sqlite" --dir "h:\Games\AIM\data\maps.pak.dir" --prefix m1 +python mmo_extractor.py --db "h:\Games\Epic Games\Projects\Polygon4\Mods\db.sqlite" --dir "h:\Games\Steam\steamapps\common\AIM2\Data\mmo.pak\DATA\LOCS" --prefix m2 \ No newline at end of file diff --git a/src/obj_extractor/obj_extractor.cpp b/src/mmo_extractor/mmo_extractor.cpp similarity index 100% rename from src/obj_extractor/obj_extractor.cpp rename to src/mmo_extractor/mmo_extractor.cpp diff --git a/src/obj_extractor/obj_extractor.py b/src/mmo_extractor/mmo_extractor.py similarity index 92% rename from src/obj_extractor/obj_extractor.py rename to src/mmo_extractor/mmo_extractor.py index ff5444c..4672f16 100644 --- a/src/obj_extractor/obj_extractor.py +++ b/src/mmo_extractor/mmo_extractor.py @@ -23,7 +23,7 @@ def run(dir, db, prefix): if os.path.isdir(file) or os.path.splitext(file)[1].lower() != ".mmo": continue print('loading: ' + file) - p = subprocess.Popen(['obj_extractor.exe', db, dir + '/' + file, prefix]) + p = subprocess.Popen(['mmo_extractor.exe', db, dir + '/' + file, prefix]) p.communicate() if __name__ == '__main__': diff --git a/src/obj_extractor/objects.cpp b/src/mmo_extractor/objects.cpp similarity index 100% rename from src/obj_extractor/objects.cpp rename to src/mmo_extractor/objects.cpp diff --git a/src/obj_extractor/objects.h b/src/mmo_extractor/objects.h similarity index 100% rename from src/obj_extractor/objects.h rename to src/mmo_extractor/objects.h diff --git a/src/obj_extractor/other.h b/src/mmo_extractor/other.h similarity index 100% rename from src/obj_extractor/other.h rename to src/mmo_extractor/other.h diff --git a/src/mmp_extractor/mmp.cpp b/src/mmp_extractor/mmp.cpp index 4e74e84..a38febd 100644 --- a/src/mmp_extractor/mmp.cpp +++ b/src/mmp_extractor/mmp.cpp @@ -18,40 +18,114 @@ #include "mmp.h" -#define FREAD(var) fread(&var, 1, sizeof(var), f) -#define FREAD_N(var, n) fread(&var, 1, n, f) - -size_t file_size(FILE *f) +void unk_segment1::load(buffer &b) { - auto old = ftell(f); - fseek(f, 0, SEEK_END); - auto sz = ftell(f); - fseek(f, old, SEEK_SET); - return sz; + while (!b.eof()) + { + unk_segment1_1 s; + s.load(b); + segments.push_back(s); + } } -void mmp::load(FILE *f) +void unk_segment1_1::load(buffer &b) { - FREAD(unk1); - FREAD(unk2); - FREAD(width); - FREAD(height); - FREAD(unk3); - FREAD(unk4); - FREAD(unk5); - FREAD(unk6); - FREAD(unk7); - FREAD(unk8); + READ(b, unk0); + READ(b, name1); + READ(b, unk1); + READ(b, unk2); + READ(b, unk3); + READ(b, unk4); + READ(b, name2); + READ(b, unk5); +} - int n_seg = width / 64 * height / 64; - int sz = n_seg * sizeof(segment); - int fsz = file_size(f); - int off = fsz - sz; - fseek(f, off, SEEK_SET); +void unk_segment2::load(buffer &b) +{ + READ(b, n_segs); + segments.resize(n_segs); + READ(b, name); + for (auto &s : segments) + s.load(b); +} - segments = vector(n_seg); - for (int i = 0; i < n_seg; i++) - FREAD(segments[i]); +void unk_segment2_1::load(buffer &b) +{ + READ(b, name1); + READ(b, name2); + READ(b, name3); + READ(b, name4); + READ(b, name5); + READ(b, unk0); + READ(b, unk1); + READ(b, tex_name0); + READ(b, unk2); + READ(b, unk_name0); + READ(b, unk3); + READ(b, tex_name1); + READ(b, tex_name2); + READ(b, unk4); +} - assert(ftell(f) == fsz); +header_segment *header::create_segment(buffer &b) +{ + HeaderSegmentType type; + READ(b, type); + + header_segment *segment = 0; + switch (type) + { + case HeaderSegmentType::unk1: + segment = new unk_segment1; + break; + case HeaderSegmentType::unk2: + segment = new unk_segment2; + break; + default: + throw std::logic_error("unknown header segment type " + std::to_string((int)type)); + break; + } + if (segment) + { + segment->type = type; + READ(b, segment->unk0); + READ(b, segment->len); + } + return segment; +} + +void header::load(buffer &b) +{ + READ(b, unk0); + READ(b, name1); + READ(b, name2); + READ(b, width); + READ(b, height); + READ(b, n_segs); + segments.resize(n_segs); + READ(b, name); + for (auto &s : segments) + { + s = create_segment(b); + buffer b2(b, s->len); + if (!b2.eof()) + s->load(b2); + } +} + +void segment::load(buffer &b) +{ + READ(b, desc); + buffer b2(b); + b2.seek(desc.offset); + READ(b2, d); +} + +void mmp::load(buffer &b) +{ + h.load(b); + int n_segs = h.width / 64 * h.height / 64; + segments.resize(n_segs); + for (auto &s : segments) + s.load(b); } \ No newline at end of file diff --git a/src/mmp_extractor/mmp.h b/src/mmp_extractor/mmp.h index 4650a5f..e4d522a 100644 --- a/src/mmp_extractor/mmp.h +++ b/src/mmp_extractor/mmp.h @@ -16,45 +16,158 @@ * along with this program. If not, see . */ -#include -#include -#include #include -#include #include #include -using namespace std; +#include + +enum class HeaderSegmentType : uint32_t +{ + unk1 = 1, + unk2 = 2, +}; + +struct header_segment +{ + HeaderSegmentType type; + uint32_t unk0; + uint32_t len; + + virtual void load(buffer &b) = 0; +}; + +struct unk_segment1_1 +{ + float unk0[6]; + char name1[0x20]; + uint32_t unk1; + float unk2; + uint32_t unk3[16]; + float unk4; + char name2[0x20]; + uint32_t unk5[16]; + + void load(buffer &b); +}; + +struct unk_segment1 : public header_segment +{ + std::vector segments; + + virtual void load(buffer &b) override; +}; + +struct unk_segment2_1 +{ + char name1[0x20]; + char name2[0x20]; + char name3[0x20]; + char name4[0x20]; + char name5[0x20]; + float unk0[2]; + uint32_t unk1[6]; + char tex_name0[0x20]; + uint32_t unk2[3]; + char unk_name0[0x20]; + float unk3; + char tex_name1[0x20]; + char tex_name2[0x20]; + uint32_t unk4[23]; + + void load(buffer &b); +}; + +struct unk_segment2 : public header_segment +{ + uint32_t n_segs; + char name[0xA0]; + std::vector segments; + + virtual void load(buffer &b) override; +}; + +struct header +{ + uint32_t unk0; + wchar_t name1[0x20]; + wchar_t name2[0x20]; + uint32_t width; + uint32_t height; + uint32_t n_segs; + char name[0xA0]; + std::vector segments; + + void load(buffer &b); + +private: + header_segment *create_segment(buffer &b); +}; + +struct segment +{ + struct description + { + uint32_t offset; + float Xmin; + float Ymin; + float Zmin; + float Xmax; + float Ymax; + float Zmax; + float unk0[5]; + uint32_t unk1[7]; + }; + struct data + { + struct info + { + uint16_t render_flags; + uint16_t texture_index; + }; + struct color + { + uint8_t b; + uint8_t g; + uint8_t r; + uint8_t a; + }; + struct shadow + { + uint8_t unk[4]; + }; + struct normal + { + int16_t x; + int16_t y; + }; + struct old_data + { + uint16_t Heightmap[1089 * 2]; + color Colormap[1089]; + uint32_t unk0[1089]; + normal unk1[1089]; // normals? + }; + + uint32_t MagicNumber; + old_data old; + float Heightmap[4225]; + info Infomap[4225]; + color Colormap[4225]; + shadow Shadowmap[4225]; + normal Normalmap[4225]; + }; + + description desc; + data d; + + void load(buffer &b); +}; struct mmp { - struct segment - { - uint32_t MagicNumber; - uint32_t MiniLayer1[1089]; - uint32_t MiniLayer2[1089]; - uint32_t MiniLayer3[1089]; - uint32_t MiniLayer4[1089]; - float Heightmap[4225]; - uint32_t Infomap[4225]; - uint32_t Colormap[4225]; - uint32_t Shadowmap[4225]; - uint32_t Normalmap[4225]; - }; + header h; + std::vector segments; - uint32_t unk1; - char unk2[0x80]; - uint32_t width; - uint32_t height; - uint32_t unk3; - char unk4[0xA0]; - uint32_t unk5[7]; - char unk6[0xA0]; - char unk7[0x1AC]; - char unk8[0x1AC]; - uint32_t offset; // the beginning of segments - - vector segments; - - void load(FILE *f); + void load(buffer &b); }; \ No newline at end of file diff --git a/src/mmp_extractor/mmp_extractor.bat b/src/mmp_extractor/mmp_extractor.bat new file mode 100644 index 0000000..8d0d700 --- /dev/null +++ b/src/mmp_extractor/mmp_extractor.bat @@ -0,0 +1,2 @@ +python mmp_extractor.py --dir "h:\Games\AIM\data\maps.pak.dir" +python mmp_extractor.py --dir "h:\Games\Steam\steamapps\common\AIM2\Data\mmp.pak\DATA\LOCS" \ No newline at end of file diff --git a/src/mmp_extractor/mmp_extractor.cpp b/src/mmp_extractor/mmp_extractor.cpp index dd5fc67..cb68fee 100644 --- a/src/mmp_extractor/mmp_extractor.cpp +++ b/src/mmp_extractor/mmp_extractor.cpp @@ -16,14 +16,10 @@ * along with this program. If not, see . */ -#include -#include #include -#include -#include -#include #include #include +#include #include "mmp.h" @@ -31,27 +27,35 @@ using namespace std; mmp read_mmp(string fn) { + buffer b(readFile(fn)); mmp m; - FILE *f = fopen(fn.c_str(), "rb"); - if (!f) - return m; - m.load(f); - fclose(f); + m.load(b); return m; } -int main(int argc, char *argv[]) +void process_mmp(mmp &m, string fn) +{ +} + +int main(int argc, char *argv[]) +try { -#ifdef NDEBUG if (argc != 2) { cout << "Usage:\n" << argv[0] << " file.mmp" << "\n"; return 1; } - read_mmp(argv[1]); -#else - auto arena = read_mmp("h:\\Games\\AIM\\data\\maps.pak.dir\\arena.mmp"); - auto loc1 = read_mmp("h:\\Games\\AIM\\data\\maps.pak.dir\\location1.mmp"); -#endif + auto m = read_mmp(argv[1]); + process_mmp(m, argv[1]); return 0; +} +catch (std::exception &e) +{ + printf("error: %s\n", e.what()); + return 1; +} +catch (...) +{ + printf("error: unknown exception\n"); + return 1; } \ No newline at end of file diff --git a/src/mmp_extractor/mmp_extractor.py b/src/mmp_extractor/mmp_extractor.py new file mode 100644 index 0000000..b1b9e3b --- /dev/null +++ b/src/mmp_extractor/mmp_extractor.py @@ -0,0 +1,25 @@ +#!/usr/bin/python3 +# -*- coding: utf-8 -*- + +import argparse +import os +import subprocess + +def main(): + parser = argparse.ArgumentParser(description='Batch MMP extractor') + parser.add_argument('--dir', dest='dir', help='path to directory with maps') + pargs = parser.parse_args() + + if pargs.dir: + run(pargs.dir) + +def run(dir): + for file in sorted(os.listdir(dir)): + if os.path.isdir(file) or os.path.splitext(file)[1].lower() != ".mmp": + continue + print('processing: ' + file) + p = subprocess.Popen(['mmp_extractor.exe', dir + '/' + file]) + p.communicate() + +if __name__ == '__main__': + main()