mirror of
https://github.com/aimrebirth/tools.git
synced 2026-04-15 01:43:25 +00:00
Take languages from json files on github. Overhaul work with databases.
This commit is contained in:
parent
3d7970df53
commit
ace9535747
4 changed files with 124 additions and 85 deletions
|
|
@ -143,7 +143,7 @@ int main(int argc, char *argv[]) {
|
||||||
|
|
||||||
// patch note: Database Changes
|
// patch note: Database Changes
|
||||||
// patch note: DB
|
// patch note: DB
|
||||||
auto db = mod.db();
|
auto &db = mod.db();
|
||||||
// patch note: set glider GL_S3_PS_FINDER2 model to MOD_GL_S3_PS_FINDER2 (lz)
|
// patch note: set glider GL_S3_PS_FINDER2 model to MOD_GL_S3_PS_FINDER2 (lz)
|
||||||
db["Глайдеры"]["GL_S3_PS_FINDER2"]["MODEL"] = "MOD_GL_S3_PS_FINDER2";
|
db["Глайдеры"]["GL_S3_PS_FINDER2"]["MODEL"] = "MOD_GL_S3_PS_FINDER2";
|
||||||
// patch note: copy MOD_GL_S3_PS_FINDER2 model from aim2 (lz)
|
// patch note: copy MOD_GL_S3_PS_FINDER2 model from aim2 (lz)
|
||||||
|
|
@ -170,24 +170,12 @@ int main(int argc, char *argv[]) {
|
||||||
// patch note: double gun for config CFG_EYEDSTONE_2: from GUN_FAST_ELECTROMAGNETIC_BEAM to double GUN_FAST_ELECTROMAGNETIC_BEAM (lz)
|
// patch note: double gun for config CFG_EYEDSTONE_2: from GUN_FAST_ELECTROMAGNETIC_BEAM to double GUN_FAST_ELECTROMAGNETIC_BEAM (lz)
|
||||||
tblcfg["CFG_EYEDSTONE_2"]["LIGHTGUN1"] = "GUN_FAST_ELECTROMAGNETIC_BEAM";
|
tblcfg["CFG_EYEDSTONE_2"]["LIGHTGUN1"] = "GUN_FAST_ELECTROMAGNETIC_BEAM";
|
||||||
// end of db changes
|
// end of db changes
|
||||||
#ifdef NDEBUG
|
|
||||||
db.write();
|
|
||||||
#endif
|
|
||||||
// patch note: INFORMATION
|
// patch note: INFORMATION
|
||||||
{
|
auto &quest = mod.quest();
|
||||||
auto quest = mod.quest("ru_RU");
|
// patch note: add name for SINIGR armor, it was unnamed before (lz)
|
||||||
// patch note: add name for SINIGR armor, it was unnamed before (lz)
|
quest["ru_RU"]["INFORMATION"]["EQP_ZERO_ARMOR_S_SIN"]["NAME"] = "Особая нуль-броня";
|
||||||
quest["INFORMATION"]["EQP_ZERO_ARMOR_S_SIN"]["NAME"] = "Особая нуль-броня";
|
quest["en_US"]["INFORMATION"]["EQP_ZERO_ARMOR_S_SIN"]["NAME"] = "Special zero armor";
|
||||||
}
|
|
||||||
{
|
|
||||||
auto quest = mod.quest("en_US");
|
|
||||||
quest["INFORMATION"]["EQP_ZERO_ARMOR_S_SIN"]["NAME"] = "Special zero armor";
|
|
||||||
}
|
|
||||||
// more known langs: cs_CZ, de_DE, et_EE, fr_FR
|
|
||||||
// you can find vanilla dbs here (not sure if it is 1.00 or 1.03, probably 1.00):
|
|
||||||
// Supercluster discord
|
|
||||||
// https://discord.gg/CFFKpTwYZD
|
|
||||||
// https://discord.com/channels/463656710666584064/516316063747538945/615934366593581067
|
|
||||||
// patch note:
|
// patch note:
|
||||||
|
|
||||||
// patch note: Game Changes
|
// patch note: Game Changes
|
||||||
|
|
@ -217,13 +205,12 @@ int main(int argc, char *argv[]) {
|
||||||
// patch note dev: make EQP_VACUUM_DRIVE_S4 more powerful
|
// patch note dev: make EQP_VACUUM_DRIVE_S4 more powerful
|
||||||
db["Оборудование"]["EQP_VACUUM_DRIVE_S4"]["VALUE1"] = 4158000.f;
|
db["Оборудование"]["EQP_VACUUM_DRIVE_S4"]["VALUE1"] = 4158000.f;
|
||||||
// end of db changes in dev mode
|
// end of db changes in dev mode
|
||||||
auto m2_gliders = mod.open_aim2_db()["Глайдеры"];
|
auto m2_gliders = mod.open_aim2_db().at("Глайдеры");
|
||||||
for (auto &&[n,_] : db["Глайдеры"]) {
|
for (auto &&[n,_] : db["Глайдеры"]) {
|
||||||
m2_gliders.erase(n);
|
m2_gliders.erase(n);
|
||||||
}
|
}
|
||||||
m2_gliders.erase("GL_BOT");
|
m2_gliders.erase("GL_BOT");
|
||||||
m2_gliders.erase("GL_RACE1");
|
m2_gliders.erase("GL_RACE1");
|
||||||
db.write();
|
|
||||||
// patch note dev: copy gliders from m2: GL_M4_C_MASTODON, GL_M4_S_FLASH, GL_M4_A_FORWARD, GL_M4_A_FORWARD_BLACK
|
// patch note dev: copy gliders from m2: GL_M4_C_MASTODON, GL_M4_S_FLASH, GL_M4_A_FORWARD, GL_M4_A_FORWARD_BLACK
|
||||||
auto add_glider = [&, after = "GL_M1_A_ATTACKER"s](auto &&name) mutable {
|
auto add_glider = [&, after = "GL_M1_A_ATTACKER"s](auto &&name) mutable {
|
||||||
mod.copy_glider_from_aim2(name);
|
mod.copy_glider_from_aim2(name);
|
||||||
|
|
|
||||||
|
|
@ -74,7 +74,7 @@ struct aim_exe_v1_06_constants {
|
||||||
struct mod_maker {
|
struct mod_maker {
|
||||||
struct db_wrapper {
|
struct db_wrapper {
|
||||||
db2::files::db2_internal m;
|
db2::files::db2_internal m;
|
||||||
db2::files::db2_internal *m2_{};
|
db2::files::db2_internal m2;
|
||||||
path fn;
|
path fn;
|
||||||
int codepage{1251};
|
int codepage{1251};
|
||||||
bool written{};
|
bool written{};
|
||||||
|
|
@ -88,33 +88,56 @@ struct mod_maker {
|
||||||
m.save(fn, codepage);
|
m.save(fn, codepage);
|
||||||
written = true;
|
written = true;
|
||||||
}
|
}
|
||||||
|
auto write(const path &fn) {
|
||||||
|
auto files = m.save(fn, codepage);
|
||||||
|
written = true;
|
||||||
|
return files;
|
||||||
|
}
|
||||||
auto &operator[](this auto &&d, const std::string &s) {
|
auto &operator[](this auto &&d, const std::string &s) {
|
||||||
return d.m[s];
|
return d.m[s];
|
||||||
}
|
}
|
||||||
auto &m2() {
|
|
||||||
return *m2_;
|
|
||||||
}
|
|
||||||
void copy_from_aim2(auto &&table_name, auto &&value_name, auto &&field_name) {
|
void copy_from_aim2(auto &&table_name, auto &&value_name, auto &&field_name) {
|
||||||
auto check_val = [](auto &&m, const std::string &key, auto &&err) {
|
if (m2.empty()) {
|
||||||
if (auto it = m.find(key); it == m.end()) {
|
return;
|
||||||
throw std::runtime_error{err};
|
}
|
||||||
}
|
m[table_name][value_name][field_name] = m2.at(table_name).at(value_name).at(field_name);
|
||||||
};
|
|
||||||
check_val(m2().m, (const char *)table_name, "aim2: no such table");
|
|
||||||
check_val(m2()[table_name], value_name, "aim2: no such value");
|
|
||||||
check_val(m2()[table_name][value_name], field_name, "aim2: no such field");
|
|
||||||
m[table_name][value_name][field_name] = m2()[table_name][value_name][field_name];
|
|
||||||
}
|
}
|
||||||
void copy_from_aim2(auto &&table_name, auto &&value_name) {
|
void copy_from_aim2(auto &&table_name, auto &&value_name) {
|
||||||
auto check_val = [](auto &&m, const std::string &key, auto &&err) {
|
if (m2.empty()) {
|
||||||
if (auto it = m.find(key); it == m.end()) {
|
return;
|
||||||
throw std::runtime_error{err};
|
}
|
||||||
}
|
m[table_name][value_name] = m2.at(table_name).at(value_name);
|
||||||
};
|
|
||||||
check_val(m2().m, (const char *)table_name, "aim2: no such table");
|
|
||||||
check_val(m2()[table_name], value_name, "aim2: no such value");
|
|
||||||
m[table_name][value_name] = m2()[table_name][value_name];
|
|
||||||
}
|
}
|
||||||
|
bool empty() const { return m.empty(); }
|
||||||
|
};
|
||||||
|
struct quest_wrapper {
|
||||||
|
std::map<std::string, db_wrapper> m;
|
||||||
|
bool written{};
|
||||||
|
|
||||||
|
quest_wrapper() = default;
|
||||||
|
quest_wrapper(const quest_wrapper &) = delete;
|
||||||
|
auto write(const path &datadir) {
|
||||||
|
std::set<path> files;
|
||||||
|
for (auto &&[fn,v] : m) {
|
||||||
|
files.merge(v.write(datadir / ("quest_" + fn)));
|
||||||
|
}
|
||||||
|
written = true;
|
||||||
|
return files;
|
||||||
|
}
|
||||||
|
auto &operator[](this auto &&d, const std::string &s) {
|
||||||
|
return d.m[s];
|
||||||
|
}
|
||||||
|
void copy_from_aim2(auto &&table_name, auto &&value_name, auto &&field_name) {
|
||||||
|
for (auto &&[_, v] : m) {
|
||||||
|
v.copy_from_aim2(table_name, value_name, field_name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void copy_from_aim2(auto &&table_name, auto &&value_name) {
|
||||||
|
for (auto &&[_, v] : m) {
|
||||||
|
v.copy_from_aim2(table_name, value_name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bool empty() const { return m.empty(); }
|
||||||
};
|
};
|
||||||
enum class file_type {
|
enum class file_type {
|
||||||
unknown,
|
unknown,
|
||||||
|
|
@ -138,6 +161,8 @@ struct mod_maker {
|
||||||
std::set<path> restored_files;
|
std::set<path> restored_files;
|
||||||
std::set<path> copied_files;
|
std::set<path> copied_files;
|
||||||
std::source_location loc;
|
std::source_location loc;
|
||||||
|
db_wrapper dw;
|
||||||
|
quest_wrapper qw;
|
||||||
|
|
||||||
mod_maker(std::source_location loc = std::source_location::current()) : loc{loc} {
|
mod_maker(std::source_location loc = std::source_location::current()) : loc{loc} {
|
||||||
init(fs::current_path());
|
init(fs::current_path());
|
||||||
|
|
@ -171,6 +196,10 @@ struct mod_maker {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void apply() {
|
void apply() {
|
||||||
|
dw.write();
|
||||||
|
auto quest_dbs = qw.write(get_data_dir());
|
||||||
|
files_to_distribute.merge(quest_dbs);
|
||||||
|
|
||||||
std::vector<std::string> files;
|
std::vector<std::string> files;
|
||||||
for (auto &&p : files_to_pak) {
|
for (auto &&p : files_to_pak) {
|
||||||
if (p.filename() == aim_exe) {
|
if (p.filename() == aim_exe) {
|
||||||
|
|
@ -398,9 +427,8 @@ struct mod_maker {
|
||||||
add_resource(copied_fn);
|
add_resource(copied_fn);
|
||||||
db().copy_from_aim2("Модели", path{object}.stem().string());
|
db().copy_from_aim2("Модели", path{object}.stem().string());
|
||||||
auto textures = read_lines(path{copied_fn} += ".textures.txt");
|
auto textures = read_lines(path{copied_fn} += ".textures.txt");
|
||||||
auto &m2 = open_aim2_db();
|
|
||||||
for (auto &&t : textures) {
|
for (auto &&t : textures) {
|
||||||
path fn = std::get<std::string>(m2["Текстуры"][t]["FILENAME"]);
|
path fn = std::get<std::string>(db().m2.at("Текстуры").at(t).at("FILENAME"));
|
||||||
if (fn.empty()) {
|
if (fn.empty()) {
|
||||||
throw std::runtime_error{"Can't find texture: "s + t};
|
throw std::runtime_error{"Can't find texture: "s + t};
|
||||||
}
|
}
|
||||||
|
|
@ -437,44 +465,65 @@ struct mod_maker {
|
||||||
|
|
||||||
copy_from_aim2("MOD_"s + object);
|
copy_from_aim2("MOD_"s + object);
|
||||||
db().copy_from_aim2("Глайдеры", path{object}.stem().string());
|
db().copy_from_aim2("Глайдеры", path{object}.stem().string());
|
||||||
// may be absent - try..catch?
|
quest().copy_from_aim2("INFORMATION", path{object}.stem().string());
|
||||||
quest("ru_RU").copy_from_aim2("INFORMATION", path{object}.stem().string());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto db() {
|
auto &db() {
|
||||||
auto w = open_db("db", 1251); // always 1251 probably
|
if (dw.empty()) {
|
||||||
if (aim2_available()) {
|
auto cp = 1251; // always 1251 or 0 probably for db
|
||||||
w.m2_ = &open_aim2_db();
|
dw = open_db("db", cp);
|
||||||
}
|
|
||||||
return w;
|
|
||||||
}
|
|
||||||
auto quest(const std::string &language = {}) {
|
|
||||||
// TODO: check if it's possible to use utf8/16 in aim game
|
|
||||||
// set codepages here until we fix or implement unicode
|
|
||||||
int db_codepage = 1251;
|
|
||||||
if (language == "fr_fr") {
|
|
||||||
// change cp. Also for other langs
|
|
||||||
}
|
|
||||||
if (language.empty()) {
|
|
||||||
auto w = open_db("quest", db_codepage);
|
|
||||||
if (aim2_available()) {
|
if (aim2_available()) {
|
||||||
w.m2_ = &open_aim2_quest();
|
dw.m2 = db2{aim2_game_dir / "data" / "db"}.open().to_map(cp);
|
||||||
}
|
}
|
||||||
return w;
|
|
||||||
} else {
|
|
||||||
auto w = open_db("quest_" + language, db_codepage);
|
|
||||||
if (aim2_available()) {
|
|
||||||
w.m2_ = &open_aim2_quest();
|
|
||||||
}
|
|
||||||
return w;
|
|
||||||
}
|
}
|
||||||
|
return dw;
|
||||||
}
|
}
|
||||||
db2::files::db2_internal &open_aim2_db() {
|
auto &quest() {
|
||||||
|
// check if it's possible to use utf8/16 in aim game
|
||||||
|
// | set codepages here until we fix or implement unicode
|
||||||
|
// probably not possible, so use default codepages
|
||||||
|
if (qw.empty()) {
|
||||||
|
// TODO: maybe add vanilla db into translations repository as well?
|
||||||
|
prepare_languages();
|
||||||
|
}
|
||||||
|
return qw;
|
||||||
|
}
|
||||||
|
const auto &open_aim2_db() {
|
||||||
if (!aim2_available()) {
|
if (!aim2_available()) {
|
||||||
throw std::runtime_error{"aim2 is not available, setup it first"};
|
throw std::runtime_error{"aim2 is not available, setup it first"};
|
||||||
}
|
}
|
||||||
static auto m2 = db2{aim2_game_dir / "data" / "db"}.open().to_map(1251);
|
return db().m2;
|
||||||
return m2;
|
}
|
||||||
|
void prepare_languages() {
|
||||||
|
auto trdirname = "translations";
|
||||||
|
auto trdir = get_mod_dir().parent_path() / trdirname;
|
||||||
|
primitives::Command c;
|
||||||
|
c.push_back("git");
|
||||||
|
if (!fs::exists(trdir)) {
|
||||||
|
c.working_directory = get_mod_dir().parent_path();
|
||||||
|
c.push_back("clone");
|
||||||
|
c.push_back("https://github.com/aimrebirth/translations");
|
||||||
|
c.push_back(trdirname);
|
||||||
|
} else {
|
||||||
|
c.working_directory = trdir;
|
||||||
|
c.push_back("pull");
|
||||||
|
c.push_back("origin");
|
||||||
|
c.push_back("master");
|
||||||
|
}
|
||||||
|
run_command(c);
|
||||||
|
for (auto &&p : fs::directory_iterator{trdir / "aim1"}) {
|
||||||
|
if (!fs::is_regular_file(p) || p.path().extension() != ".json") {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
auto s = split_string(p.path().stem().string(), "_");
|
||||||
|
auto lang = std::format("{}_{}", s.at(1), s.at(2));
|
||||||
|
qw[lang].m.load_from_json(p);
|
||||||
|
qw[lang].codepage = code_pages.at(s.at(1));
|
||||||
|
auto m2fn = trdir / "aim2" / p.path().filename();
|
||||||
|
if (fs::exists(m2fn)) {
|
||||||
|
qw[lang].m2.load_from_json(m2fn);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
@ -483,13 +532,6 @@ private:
|
||||||
fs::copy_file(from, to, fs::copy_options::overwrite_existing);
|
fs::copy_file(from, to, fs::copy_options::overwrite_existing);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
db2::files::db2_internal &open_aim2_quest() {
|
|
||||||
if (!aim2_available()) {
|
|
||||||
throw std::runtime_error{"aim2 is not available, setup it first"};
|
|
||||||
}
|
|
||||||
static auto m2 = db2{aim2_game_dir / "data" / "quest"}.open().to_map(1251);
|
|
||||||
return m2;
|
|
||||||
}
|
|
||||||
bool aim2_available() const {
|
bool aim2_available() const {
|
||||||
return !aim2_game_dir.empty();
|
return !aim2_game_dir.empty();
|
||||||
}
|
}
|
||||||
|
|
@ -871,7 +913,8 @@ FF D7 ; call edi
|
||||||
game_dir = fs::absolute(game_dir).lexically_normal();
|
game_dir = fs::absolute(game_dir).lexically_normal();
|
||||||
}
|
}
|
||||||
void detect_tools() {
|
void detect_tools() {
|
||||||
//check_in_path("git");
|
// for languages/translations support
|
||||||
|
check_in_path("git");
|
||||||
// also --self-upgrade?
|
// also --self-upgrade?
|
||||||
check_in_path("sw");
|
check_in_path("sw");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,7 @@ static const std::map<std::string, int> code_pages
|
||||||
{ "en", 0 },
|
{ "en", 0 },
|
||||||
{ "cz", 1250 },
|
{ "cz", 1250 },
|
||||||
{ "ru", 1251 },
|
{ "ru", 1251 },
|
||||||
{ "ge", 1252 },
|
{ "de", 1252 },
|
||||||
{ "fr", 1252 },
|
{ "fr", 1252 },
|
||||||
{ "et", 1257 },
|
{ "et", 1257 },
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -186,6 +186,9 @@ struct db2 {
|
||||||
auto &operator[](this auto &&d, const std::string &s) {
|
auto &operator[](this auto &&d, const std::string &s) {
|
||||||
return d.m[s];
|
return d.m[s];
|
||||||
}
|
}
|
||||||
|
auto &at(this auto &&d, const std::string &s) {
|
||||||
|
return d.m.at(s);
|
||||||
|
}
|
||||||
auto to_json() const {
|
auto to_json() const {
|
||||||
nlohmann::json ja;
|
nlohmann::json ja;
|
||||||
for (auto &&[tn,t] : m) {
|
for (auto &&[tn,t] : m) {
|
||||||
|
|
@ -222,7 +225,7 @@ struct db2 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void save(const path &fn, int codepage) {
|
auto save(const path &fn, int codepage) {
|
||||||
auto s_to_char20 = [&](char20 &dst, const std::string &in, int codepage) {
|
auto s_to_char20 = [&](char20 &dst, const std::string &in, int codepage) {
|
||||||
auto s = utf8_to_dbstr(in, codepage);
|
auto s = utf8_to_dbstr(in, codepage);
|
||||||
if (s.size() + 1 > sizeof(char20)) {
|
if (s.size() + 1 > sizeof(char20)) {
|
||||||
|
|
@ -291,9 +294,15 @@ struct db2 {
|
||||||
++table_id;
|
++table_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
write_file(path{fn} += ".tab", tabv.d);
|
std::set<path> files;
|
||||||
write_file(path{fn} += ".ind", indv.d);
|
auto f = [&](auto &&fn, auto &&d) {
|
||||||
write_file(path{fn} += ".dat", datv.d);
|
write_file(fn, d);
|
||||||
|
files.insert(fn);
|
||||||
|
};
|
||||||
|
f(path{fn} += ".tab", tabv.d);
|
||||||
|
f(path{fn} += ".ind", indv.d);
|
||||||
|
f(path{fn} += ".dat", datv.d);
|
||||||
|
return files;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue