mirror of
https://github.com/aimrebirth/tools.git
synced 2026-04-14 17:33:25 +00:00
Update mmo, mmp.
This commit is contained in:
parent
539c5dde83
commit
aad50f9160
11 changed files with 202 additions and 108 deletions
|
|
@ -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: "*"
|
||||
|
|
|
|||
|
|
@ -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/*")
|
||||
|
|
|
|||
|
|
@ -65,8 +65,8 @@ Segment *Segment::create_segment(const buffer &b)
|
|||
case ObjectType::unk0:
|
||||
segment = new SegmentObjects<unk0>;
|
||||
break;
|
||||
case ObjectType::unk1:
|
||||
segment = new SegmentObjects<unk1>;
|
||||
case ObjectType::TANK:
|
||||
segment = new SegmentObjects<Tank>;
|
||||
break;
|
||||
default:
|
||||
assert(false);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
{
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@
|
|||
#include <Polygon4/DataManager/Storage.h>
|
||||
#include <Polygon4/DataManager/Types.h>
|
||||
#include <primitives/filesystem.h>
|
||||
#include <args.hxx>
|
||||
|
||||
#include <buffer.h>
|
||||
#include <types.h>
|
||||
|
|
@ -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)
|
||||
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<std::string> db_path(parser, "db_path", "Database file", {'d', "db"});
|
||||
args::Positional<std::string> file_path(parser, "file or directory", ".mmo file or directory with .mmo files");
|
||||
parser.Prog(argv[0]);
|
||||
|
||||
parser.ParseCLI(argc, argv);
|
||||
|
||||
const path p = file_path.Get();
|
||||
gameType = m2 ? GameType::Aim2 : GameType::Aim1;
|
||||
|
||||
/*{
|
||||
std::cerr << parser;
|
||||
}*/
|
||||
|
||||
auto action = [&p](auto f)
|
||||
{
|
||||
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)");
|
||||
|
||||
auto storage = initStorage(argv[1]);
|
||||
storage->load();
|
||||
|
||||
path p = argv[2];
|
||||
if (fs::is_regular_file(p))
|
||||
write_mmo(storage.get(), read_mmo(p));
|
||||
f(p, read_mmo(p));
|
||||
else if (fs::is_directory(p))
|
||||
{
|
||||
auto files = enumerate_files_like(p, ".*\\.mmo", false);
|
||||
for (auto &f : files)
|
||||
auto files = enumerate_files_like(p, ".*\\.[Mm][Mm][Oo]", false);
|
||||
for (auto &file : files)
|
||||
{
|
||||
std::cout << "processing: " << f << "\n";
|
||||
write_mmo(storage.get(), read_mmo(f));
|
||||
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
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,63 +27,86 @@
|
|||
#include <buffer.h>
|
||||
#include <types.h>
|
||||
|
||||
#include <variant>
|
||||
|
||||
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<uint32_t> unk11;
|
||||
//}
|
||||
//{1,0
|
||||
uint32_t unk20 = 0;
|
||||
uint32_t unk21 = 0;
|
||||
//}
|
||||
std::vector<std::string> configs;
|
||||
char unk100;
|
||||
std::vector<std::string> 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<unk_type01, std::vector<uint32_t>, 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<uint32_t> 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<MechGroup> 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++)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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";
|
||||
|
|
|
|||
|
|
@ -81,16 +81,17 @@ 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 data
|
||||
{
|
||||
|
||||
struct info
|
||||
{
|
||||
uint16_t render_flags;
|
||||
|
|
@ -98,19 +99,17 @@ struct segment
|
|||
|
||||
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
|
||||
{
|
||||
|
|
@ -118,12 +117,16 @@ struct segment
|
|||
uint16_t flag;
|
||||
};
|
||||
|
||||
flagged_heightmap Heightmap[size];
|
||||
color Colormap[size];
|
||||
uint32_t unk0[size]; // shadowmap?
|
||||
normal unk1[size]; // normals?
|
||||
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
|
||||
{
|
||||
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<uint16_t> heightmap;
|
||||
//mat<uint16_t> heightmap_segmented;
|
||||
mat<uint32_t> texmap;
|
||||
mat<uint32_t> texmap_colored;
|
||||
mat<uint32_t> colormap;
|
||||
|
|
@ -171,6 +195,7 @@ struct mmp
|
|||
void writeFileInfo();
|
||||
void writeTexturesList();
|
||||
void writeHeightMap();
|
||||
void writeHeightMapSegmented();
|
||||
void writeTextureMap();
|
||||
void writeTextureAlphaMaps();
|
||||
void writeTextureMapColored();
|
||||
|
|
|
|||
|
|
@ -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];
|
||||
|
|
|
|||
|
|
@ -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())
|
||||
{
|
||||
|
|
|
|||
Loading…
Reference in a new issue