Initial mmo_extractor2.

This commit is contained in:
lzwdgc 2024-02-13 21:48:32 +03:00
parent 8f8a49791a
commit 074c91d7c4
4 changed files with 186 additions and 4 deletions

View file

@ -86,6 +86,7 @@ struct db2 {
tab *tab_{};
ind *ind_{};
dat *dat_{};
int codepage{1251};
db2() = default;
db2(const path &fn) : fn{fn} {
@ -117,14 +118,14 @@ struct db2 {
auto fields = tab_->fields();
auto values = ind_->values();
auto calc_fields_size = [](this auto &&f, std::string_view field_name, auto &&n, auto &&v, auto &&...fields) {
auto calc_fields_size = [&](this auto &&f, std::string_view field_name, auto &&n, auto &&v, auto &&...fields) {
if (field_name == n) {
if constexpr (std::same_as<std::decay_t<decltype(v)>, int>) {
return sizeof(db2::dat::field_value_base) + sizeof(int);
} else if constexpr (std::same_as<std::decay_t<decltype(v)>, float>) {
return sizeof(db2::dat::field_value_base) + sizeof(float);
} else {
auto s = str2str(v, CP_UTF8, 1251);
auto s = str2str(v, CP_UTF8, codepage);
return sizeof(db2::dat::field_value_base) + s.size() + 1;
}
}
@ -139,7 +140,7 @@ struct db2 {
return sizeof(db2::dat::field_value_base) + 1;
}
};
auto write_fields = [](this auto &&f, auto &&p, auto &&field, std::string_view field_name, auto &&n, auto &&v, auto &&...fields) {
auto write_fields = [&](this auto &&f, auto &&p, auto &&field, std::string_view field_name, auto &&n, auto &&v, auto &&...fields) {
if (field_name == n) {
if constexpr (std::same_as<std::decay_t<decltype(v)>, int>) {
if (field.type != db2::field_type::integer) {
@ -165,7 +166,7 @@ struct db2 {
if (field.type != db2::field_type::string) {
throw std::runtime_error{"field type mismatch"};
}
auto s = str2str(v, CP_UTF8, 1251);
auto s = str2str(v, CP_UTF8, codepage);
(*(db2::dat::field_value_base *)p).field_id = field.id;
(*(db2::dat::field_value_base *)p).size = s.size() + 1;
p += sizeof(db2::dat::field_value_base);

View file

@ -24,6 +24,11 @@ struct stream {
memcpy(p, (uint8_t*)&v, sizeof(v));
p += sizeof(v);
}
template <typename T>
void read(std::vector<T> &v) {
memcpy(v.data(), p, sizeof(T) * v.size());
p += sizeof(T) * v.size();
}
void skip(size_t len) {
p += len;
}

124
src/common/mmo2.h Normal file
View file

@ -0,0 +1,124 @@
#pragma once
#include "mmap.h"
struct mmo_storage2 {
struct object {
uint32_t type;
uint32_t size;
uint32_t n_objects;
};
struct mech_group {
char name[0x20];
char org[0x20];
// probably state
// alive
// dead
// in the base
// in the other mech cargo
uint32_t type;
uint32_t n_mechs;
char org_ru[0x70];
};
struct map_good {
char name[0x20];
char cond[0x40];
float buy_price;
float sell_price;
float unk[8];
uint32_t unk1;
};
// our own data
struct section {
uint32_t offset;
};
struct {
section objects;
section mech_groups;
section map_goods;
section music_and_sounds;
} sections;
struct map_building {
uint32_t offset;
std::map<std::string, uint32_t> building_goods;
};
std::map<std::string, map_building> map_building_goods;
void load(auto &&fn) {
primitives::templates2::mmap_file<uint8_t> f{fn};
stream s{f};
// objects
{
sections.objects.offset = s.p - f.p;
uint32_t n_segments = s;
while (n_segments--) {
object o = s;
s.skip(o.size);
}
}
// mech_groups
{
sections.mech_groups.offset = s.p - f.p;
uint32_t n_mechs = s;
s.skip(0x30);
while (n_mechs--) {
mech_group o = s;
switch (o.type) {
case 0:
case 1: {
uint32_t unk0 = s; // road id?
float unk1 = s; // height?
} break;
case 2: {
std::vector<uint32_t> t; // current path?
uint32_t len = s;
t.resize(len);
s.read(t);
} break;
case 3: // 3 = free mechanoids only?
case 4: {
uint32_t t = s; // other mech id?
} break;
default:
assert(false);
}
while (o.n_mechs--) {
struct mech {
char name[0x20];
};
mech m = s;
}
bool hidden = s;
}
}
// map goods
{
sections.map_goods.offset = s.p - f.p;
uint32_t size = s;
uint32_t unk2 = s;
float unk3 = s;
uint32_t n_buildings = s;
while (n_buildings--) {
struct bld {
char name[0x20];
};
bld b = s;
map_building_goods[b.name].offset = s.p - f.p;
uint32_t n_goods = s;
while (n_goods--) {
map_good g = s;
map_building_goods[b.name].building_goods[g.name] = s.p - f.p;
}
}
}
// music & sounds section
{
sections.music_and_sounds.offset = s.p - f.p;
uint32_t size = s;
s.skip(size);
}
}
};

View file

@ -0,0 +1,52 @@
/*
* AIM mmo_extractor2 (only for aim1)
* Copyright (C) 2024 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 "mmo2.h"
#include "objects.h"
#include <primitives/sw/main.h>
#include <primitives/sw/cl.h>
void read_mmo(const path &fn)
{
mmo_storage2 s;
s.load(fn);
}
int main(int argc, char *argv[])
{
cl::opt<path> p(cl::Positional, cl::desc("<.mmo file or directory with .mmo files>"), cl::value_desc("file or directory"), cl::Required);
cl::ParseCommandLineOptions(argc, argv);
if (fs::is_regular_file(p))
read_mmo(p);
else if (fs::is_directory(p))
{
auto files = enumerate_files_like(p, ".*\\.[Mm][Mm][Oo]", false);
for (auto &file : files)
{
std::cerr << "processing: " << file << "\n";
read_mmo(file);
}
}
else
throw std::runtime_error("Bad fs object");
return 0;
}