mirror of
https://github.com/aimrebirth/tools.git
synced 2026-04-14 17:33:25 +00:00
Extract all information from MMP files.
This commit is contained in:
parent
93850b0864
commit
7f214ed2ec
16 changed files with 445 additions and 87 deletions
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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})
|
||||
|
|
|
|||
29
src/mmm_extractor/mmm.cpp
Normal file
29
src/mmm_extractor/mmm.cpp
Normal file
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#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);
|
||||
}
|
||||
39
src/mmm_extractor/mmm.h
Normal file
39
src/mmm_extractor/mmm.h
Normal file
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <common.h>
|
||||
|
||||
struct dxt5_record
|
||||
{
|
||||
char unk[0x10];
|
||||
};
|
||||
|
||||
struct mmm
|
||||
{
|
||||
uint32_t unk1;
|
||||
uint32_t unk2;
|
||||
uint32_t width;
|
||||
uint32_t height;
|
||||
std::vector<dxt5_record> data;
|
||||
|
||||
void load(buffer &b);
|
||||
};
|
||||
67
src/mmm_extractor/mmm_extractor.cpp
Normal file
67
src/mmm_extractor/mmm_extractor.cpp
Normal file
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include <stdint.h>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
|
||||
#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;
|
||||
}
|
||||
|
|
@ -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
|
||||
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
|
||||
|
|
@ -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__':
|
||||
|
|
@ -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<segment>(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);
|
||||
}
|
||||
|
|
@ -16,45 +16,158 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
using namespace std;
|
||||
#include <common.h>
|
||||
|
||||
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<unk_segment1_1> 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<unk_segment2_1> 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<header_segment*> 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<segment> 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<segment> segments;
|
||||
|
||||
void load(FILE *f);
|
||||
void load(buffer &b);
|
||||
};
|
||||
2
src/mmp_extractor/mmp_extractor.bat
Normal file
2
src/mmp_extractor/mmp_extractor.bat
Normal file
|
|
@ -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"
|
||||
|
|
@ -16,14 +16,10 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <algorithm>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
|
||||
#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;
|
||||
}
|
||||
25
src/mmp_extractor/mmp_extractor.py
Normal file
25
src/mmp_extractor/mmp_extractor.py
Normal file
|
|
@ -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()
|
||||
Loading…
Reference in a new issue