Update mmo, mmp.

This commit is contained in:
lzwdgc 2018-01-27 03:40:30 +03:00
parent 539c5dde83
commit aad50f9160
11 changed files with 202 additions and 108 deletions

View file

@ -5,3 +5,4 @@ local_settings:
- pvt.egorpugin.primitives.filesystem: master - pvt.egorpugin.primitives.filesystem: master
- pvt.egorpugin.primitives.executor: master - pvt.egorpugin.primitives.executor: master
- pvt.cppan.demo.unicode.icu.i18n: "*" - pvt.cppan.demo.unicode.icu.i18n: "*"
- pvt.cppan.demo.taywee.args: "*"

View file

@ -35,6 +35,7 @@ add_executable(mmo_extractor ${mmo_extractor_src})
target_link_libraries(mmo_extractor target_link_libraries(mmo_extractor
common common
pvt.lzwdgc.polygon4.data_manager.data_manager pvt.lzwdgc.polygon4.data_manager.data_manager
pvt.cppan.demo.taywee.args
) )
file(GLOB mmp_extractor_src "mmp_extractor/*") file(GLOB mmp_extractor_src "mmp_extractor/*")

View file

@ -65,8 +65,8 @@ Segment *Segment::create_segment(const buffer &b)
case ObjectType::unk0: case ObjectType::unk0:
segment = new SegmentObjects<unk0>; segment = new SegmentObjects<unk0>;
break; break;
case ObjectType::unk1: case ObjectType::TANK:
segment = new SegmentObjects<unk1>; segment = new SegmentObjects<Tank>;
break; break;
default: default:
assert(false); assert(false);

View file

@ -59,7 +59,7 @@ enum class ObjectType : uint32_t
BOUNDARY = 23, BOUNDARY = 23,
SOUND_ZONE = 24, SOUND_ZONE = 24,
unk1 = 27, TANK = 27,
}; };
struct Segment struct Segment
@ -160,12 +160,12 @@ KNOWN_OBJECT(Image);
KNOWN_OBJECT(Anomaly); KNOWN_OBJECT(Anomaly);
KNOWN_OBJECT(Tower); KNOWN_OBJECT(Tower);
KNOWN_OBJECT(SoundZone); KNOWN_OBJECT(SoundZone);
KNOWN_OBJECT(Tank);
#define UNKNOWN_OBJECT(name) \ #define UNKNOWN_OBJECT(name) \
struct name : public MapObject { void load(const buffer &b){ int pos = b.index(); assert(false); } } struct name : public MapObject { void load(const buffer &b){ int pos = b.index(); assert(false); } }
UNKNOWN_OBJECT(unk0); UNKNOWN_OBJECT(unk0);
UNKNOWN_OBJECT(unk1);
struct Objects struct Objects
{ {

View file

@ -33,6 +33,7 @@
#include <Polygon4/DataManager/Storage.h> #include <Polygon4/DataManager/Storage.h>
#include <Polygon4/DataManager/Types.h> #include <Polygon4/DataManager/Types.h>
#include <primitives/filesystem.h> #include <primitives/filesystem.h>
#include <args.hxx>
#include <buffer.h> #include <buffer.h>
#include <types.h> #include <types.h>
@ -52,7 +53,6 @@ struct mmo_storage
Objects objects; Objects objects;
MechGroups mechGroups; MechGroups mechGroups;
MapGoods mapGoods; MapGoods mapGoods;
uint32_t unk0 = 0;
MapMusic mapMusic; MapMusic mapMusic;
MapSounds mapSounds; MapSounds mapSounds;
// aim2 // aim2
@ -60,6 +60,8 @@ struct mmo_storage
OrganizationBases orgsBases; OrganizationBases orgsBases;
Prices prices; Prices prices;
uint32_t unk0 = 0;
void load(const buffer &b) void load(const buffer &b)
{ {
objects.load(b); objects.load(b);
@ -268,39 +270,62 @@ void write_mmo(Storage *storage, const mmo_storage &s)
int main(int argc, char *argv[]) int main(int argc, char *argv[])
try try
{ {
if (argc != 4) args::ArgumentParser parser("mmo extractor");
{ args::HelpFlag help(parser, "help", "Display this help menu", { 'h', "help" });
std::cout << "Usage:\n" << argv[0] << " db.sqlite {file.mmo,mmo_dir} prefix" << "\n"; args::Flag m2(parser, "m2", "m2 .mmo file", { "m2" });
return 1; args::Flag print_mechanoids(parser, "print_mechanoids", "Print mechanoids", { "print_mechanoids" });
} args::ValueFlag<std::string> db_path(parser, "db_path", "Database file", {'d', "db"});
prefix = argv[3]; args::Positional<std::string> file_path(parser, "file or directory", ".mmo file or directory with .mmo files");
if (prefix == "m1") parser.Prog(argv[0]);
gameType = GameType::Aim1;
else if (prefix == "m2")
gameType = GameType::Aim2;
else
throw std::runtime_error("unknown prefix (game type)");
auto storage = initStorage(argv[1]); parser.ParseCLI(argc, argv);
storage->load();
path p = argv[2]; const path p = file_path.Get();
if (fs::is_regular_file(p)) gameType = m2 ? GameType::Aim2 : GameType::Aim1;
write_mmo(storage.get(), read_mmo(p));
else if (fs::is_directory(p)) /*{
std::cerr << parser;
}*/
auto action = [&p](auto f)
{ {
auto files = enumerate_files_like(p, ".*\\.mmo", false); if (fs::is_regular_file(p))
for (auto &f : files) f(p, read_mmo(p));
else if (fs::is_directory(p))
{ {
std::cout << "processing: " << f << "\n"; auto files = enumerate_files_like(p, ".*\\.[Mm][Mm][Oo]", false);
write_mmo(storage.get(), read_mmo(f)); 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 else
throw std::runtime_error("Bad fs object"); {
auto storage = initStorage(db_path.Get());
if (inserted_all) storage->load();
storage->save(); action([&storage](const path &, const auto &m) {write_mmo(storage.get(), m); });
if (inserted_all)
storage->save();
}
return 0; return 0;
} }

View file

@ -27,63 +27,86 @@
#include <buffer.h> #include <buffer.h>
#include <types.h> #include <types.h>
#include <variant>
struct MechGroup struct MechGroup
{ {
std::string name; std::string name;
std::string org; std::string org;
uint32_t type1 = 0; std::vector<std::string> mechanoids;
uint32_t len1 = 0;
char name1[0x70]; // used only in m1.loc1 and for sinigr
//{3,4 // probably an old field
uint32_t unk30 = 0; std::string org_ru;
//}
//{2 struct unk_type01
uint32_t len = 0; {
std::vector<uint32_t> unk11; uint32_t unk0 = 0;
//} float unk1 = 0;
//{1,0 };
uint32_t unk20 = 0;
uint32_t unk21 = 0; std::variant<unk_type01, std::vector<uint32_t>, uint32_t> type_data;
//}
std::vector<std::string> configs; bool hidden;
char unk100;
void load(const buffer &b) void load(const buffer &b)
{ {
READ_STRING(b, name); READ_STRING(b, name);
READ_STRING(b, org); READ_STRING(b, org);
READ(b, type1); uint32_t type = 0;
READ(b, len1); READ(b, type);
READ(b, name1); uint32_t number_of_mechanoids = 0;
if (type1 == 3 || type1 == 4) 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<uint32_t> t;
uint32_t len = 0;
READ(b, len); READ(b, len);
unk11.resize(len); t.resize(len);
for (int i = 0; i < len; i++) 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); uint32_t t;
READ(b, unk21); READ(b, t);
type_data = t;
} }
else break;
default:
assert(false); assert(false);
configs.resize(len1, std::string(0x20, 0)); }
for (int i = 0; i < len1; i++)
READ_N(b, configs[i][0], 0x20); for (int i = 0; i < number_of_mechanoids; i++)
READ(b, unk100); {
std::string t;
READ_STRING_N(b, t, 0x20);
mechanoids.push_back(t);
}
READ(b, hidden);
} }
}; };
struct MechGroups struct MechGroups
{ {
char prefix[0x30];
std::vector<MechGroup> mechGroups; std::vector<MechGroup> mechGroups;
char unk0[0x30]; // prefix?
void load(const buffer &b) void load(const buffer &b)
{ {
@ -94,7 +117,7 @@ struct MechGroups
} }
uint32_t n = 0; uint32_t n = 0;
READ(b, n); READ(b, n);
READ(b, prefix); READ(b, unk0);
for (int s = 0; s < n; s++) for (int s = 0; s < n; s++)
{ {

View file

@ -84,10 +84,14 @@ void header::load(const buffer &b)
void segment::load(const buffer &b) void segment::load(const buffer &b)
{ {
uint32_t offset;
READ(b, offset);
READ(b, desc); READ(b, desc);
buffer b2(b); buffer b2(b);
b2.seek(desc.offset); b2.seek(offset);
READ(b2, d); READ(b2, d);
b2.seek(offset);
READ(b2, d2);
} }
void mmp::load(const buffer &b) void mmp::load(const buffer &b)
@ -107,7 +111,7 @@ void mmp::load(const buffer &b)
// check whether all segments were read // check whether all segments were read
if (segments.size()) 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()) if (len != b.size())
throw std::logic_error("Some segments were not read"); throw std::logic_error("Some segments were not read");
} }
@ -167,6 +171,7 @@ void mmp::process()
// merge // merge
heightmap = decltype(heightmap)(h.width, h.length); heightmap = decltype(heightmap)(h.width, h.length);
//heightmap_segmented = decltype(heightmap)(segment::len, h.length);
texmap = decltype(texmap)(h.width, h.length); texmap = decltype(texmap)(h.width, h.length);
texmap_colored = decltype(texmap_colored)(h.width, h.length); texmap_colored = decltype(texmap_colored)(h.width, h.length);
colormap = decltype(colormap)(h.width, h.length); colormap = decltype(colormap)(h.width, h.length);
@ -213,11 +218,12 @@ void mmp::process()
alpha_maps.erase(0); alpha_maps.erase(0);
scale16 = 0xffff / (h_max - h_min); scale16 = 0xffff / (h_max - h_min);
const int unreal_koef = 51200; const int unreal_koef = 51300;
const int aim_koef = 10; const int aim_koef = 10;
const double diff = h_max - h_min; 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) for (auto &s : segments)
{ {
int y1 = s.desc.min.y / 10; int y1 = s.desc.min.y / 10;
@ -281,7 +287,7 @@ void mmp::writeTexturesList()
void mmp::writeHeightMap() void mmp::writeHeightMap()
{ {
auto fn = filename + ".heightmap16.raw"; auto fn = filename + ".heightmap16.r16";
FILE *f = fopen(fn.c_str(), "wb"); FILE *f = fopen(fn.c_str(), "wb");
if (f == nullptr) if (f == nullptr)
return; return;
@ -289,6 +295,16 @@ void mmp::writeHeightMap()
fclose(f); 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() void mmp::writeTextureMap()
{ {
auto fn = filename + ".texmap.bmp"; auto fn = filename + ".texmap.bmp";

View file

@ -81,49 +81,52 @@ struct segment
static const int len = 65; static const int len = 65;
static const int size = len * len; static const int size = len * len;
static const int mini_len = 33;
static const int mini_size = mini_len * mini_len;
struct description struct description
{ {
uint32_t offset;
vector3 min; vector3 min;
vector3 max; vector3 max;
float unk0[5]; float unk0[5];
uint32_t unk1[7]; 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 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; uint32_t MagicNumber;
mini_lod mlod; mini_lod mlod;
Height Heightmap[size]; Height Heightmap[size];
@ -133,8 +136,28 @@ struct segment
normal Normalmap[size]; 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; description desc;
data d; data d;
data2 d2;
void load(const buffer &b); void load(const buffer &b);
}; };
@ -158,6 +181,7 @@ struct mmp
double scale16 = 0; double scale16 = 0;
double scale = 0; double scale = 0;
mat<uint16_t> heightmap; mat<uint16_t> heightmap;
//mat<uint16_t> heightmap_segmented;
mat<uint32_t> texmap; mat<uint32_t> texmap;
mat<uint32_t> texmap_colored; mat<uint32_t> texmap_colored;
mat<uint32_t> colormap; mat<uint32_t> colormap;
@ -171,6 +195,7 @@ struct mmp
void writeFileInfo(); void writeFileInfo();
void writeTexturesList(); void writeTexturesList();
void writeHeightMap(); void writeHeightMap();
void writeHeightMapSegmented();
void writeTextureMap(); void writeTextureMap();
void writeTextureAlphaMaps(); void writeTextureAlphaMaps();
void writeTextureMapColored(); void writeTextureMapColored();

View file

@ -45,12 +45,13 @@ try
m.load(p.string()); m.load(p.string());
m.process(); m.process();
m.writeFileInfo(); m.writeFileInfo();
m.writeTexturesList(); //m.writeTexturesList();
m.writeHeightMap(); m.writeHeightMap();
m.writeTextureMap(); //m.writeHeightMapSegmented();
/*m.writeTextureMap();
m.writeTextureAlphaMaps(); m.writeTextureAlphaMaps();
m.writeTextureMapColored(); m.writeTextureMapColored();
m.writeColorMap(); m.writeColorMap();*/
}; };
path p = argv[1]; path p = argv[1];

View file

@ -256,6 +256,8 @@ bool CreateScene(model &model, const std::string &name, FbxManager* pSdkManager,
int fx_id = 0; int fx_id = 0;
for (auto &b : model.blocks) for (auto &b : model.blocks)
{ {
// b.h.name == "SHAPE" - collision object
// //
if (b.isEngineFx()) if (b.isEngineFx())
{ {

View file

@ -306,4 +306,4 @@ int decode_f4(char *input, int size, char *output, int segment_offset)
goto LABEL_9; goto LABEL_9;
} }
return result; return result;
} }