diff --git a/examples/mods/aim1_community_fix/my_mod.cpp b/examples/mods/aim1_community_fix/my_mod.cpp index acbfea3..704a10e 100644 --- a/examples/mods/aim1_community_fix/my_mod.cpp +++ b/examples/mods/aim1_community_fix/my_mod.cpp @@ -87,14 +87,14 @@ int main(int argc, char *argv[]) { mod.add_map_good("location6.mmo", "B_L6_IK_FINDER", "GL_S3_PS_FINDER1", R"( 47 4c 5f 53 33 5f 50 53 5f 46 49 4e 44 45 52 32 00 d2 e2 77 42 04 06 00 35 01 00 00 76 0c 01 30 -00 5f 4c 36 5f 49 4b 5f 46 32 2e 43 4f 4d 50 4c +54 5f 4c 36 5f 49 4b 5f 46 32 2e 43 4f 4d 50 4c 45 54 45 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -)"_bin); // 54 +)"_bin); //mod.add_resource("MOD_GL_S3_PS_FINDER1"); //mod.add_resource("TEX_GL_S3_PS_FINDER1_MASK.TM"); // patch note: add Finder-2 model and textures from aim2 game (lz) @@ -128,31 +128,36 @@ int main(int argc, char *argv[]) { // patch note: Database Changes // patch note: DB + auto db = mod.db().open(); // patch note: set glider GL_S3_PS_FINDER2 model to MOD_GL_S3_PS_FINDER2 (lz) - mod.db().edit_value(u8"Глайдеры", "GL_S3_PS_FINDER2", "MODEL", "MOD_GL_S3_PS_FINDER2"); + db(u8"Глайдеры", "GL_S3_PS_FINDER2", "MODEL") = "MOD_GL_S3_PS_FINDER2"; // patch note: change MOD_GL_S3_PS_FINDER2 model radius to MOD_GL_S3_PS_FINDER1 radius (lz) - mod.db().edit_value(u8"Модели", "MOD_GL_S3_PS_FINDER2", "RADIUS", 4.012578f); + db(u8"Модели", "MOD_GL_S3_PS_FINDER2", "RADIUS") = 4.768386f; // from finder1 - 4.012578f; // patch note: double gun for config CFG_NARGOON (double electro discharge) (lz) - mod.db().edit_value(u8"Конфигурации", "CFG_NARGOON", "HEAVYGUN1", "GUN_ELECTRO_DISCHARGER"); + auto tblcfg = db(u8"Конфигурации"); + tblcfg("CFG_NARGOON", "HEAVYGUN1") = "GUN_ELECTRO_DISCHARGER"; // patch note: double gun for config CFG_NARGOON1 (double two-barreled atomic gun) (lz) - mod.db().edit_value(u8"Конфигурации", "CFG_NARGOON1", "HEAVYGUN1", "GUN_DOUBLE_BARRELED_ATOMIC_GUN"); + tblcfg("CFG_NARGOON1", "HEAVYGUN1") = "GUN_DOUBLE_BARRELED_ATOMIC_GUN"; // patch note: double gun for config CFG_BASE_NARG - Nargoon (double two-barreled atomic gun) (lz) - mod.db().edit_value(u8"Конфигурации", "CFG_BASE_NARG", "HEAVYGUN1", "GUN_DOUBLE_BARRELED_ATOMIC_GUN"); + tblcfg("CFG_BASE_NARG", "HEAVYGUN1") = "GUN_DOUBLE_BARRELED_ATOMIC_GUN"; // patch note: double gun for config CFG_STNAR-97 - Nargoon (double GUN_INFRAATOMIC_PLASMA_GUN) (lz) - mod.db().edit_value(u8"Конфигурации", "CFG_STNAR-97", "HEAVYGUN1", "GUN_INFRAATOMIC_PLASMA_GUN"); + tblcfg("CFG_STNAR-97", "HEAVYGUN1") = "GUN_INFRAATOMIC_PLASMA_GUN"; // patch note: double gun for config CFG_FINDER_1 (std.3): from GUN_MICROWAVE_OSCILLATOR (std.4) and GUN_CHAOS_GENERATOR (std.4) to double GUN_FOUR_BARRELED_IMP_GAZER (std.3) (lz) - mod.db().edit_value(u8"Конфигурации", "CFG_FINDER_1", "LIGHTGUN1", "GUN_FOUR_BARRELED_IMP_GAZER"); - mod.db().edit_value(u8"Конфигурации", "CFG_FINDER_1", "HEAVYGUN1", "GUN_FOUR_BARRELED_IMP_GAZER"); + auto finder1 = tblcfg("CFG_FINDER_1"); + finder1("LIGHTGUN1") = "GUN_FOUR_BARRELED_IMP_GAZER"; + finder1("HEAVYGUN1") = "GUN_FOUR_BARRELED_IMP_GAZER"; // patch note: double gun for config CFG_FINDER_2: from GUN_FOUR_BARRELED_IMP_GAZER (std.3) + GUN_POZITRON_EMITTER (std.4) to double GUN_TACHYON_HEATER (std.3) (lz) - mod.db().edit_value(u8"Конфигурации", "CFG_FINDER_2", "LIGHTGUN1", "GUN_TACHYON_HEATER"); - mod.db().edit_value(u8"Конфигурации", "CFG_FINDER_2", "HEAVYGUN1", "GUN_TACHYON_HEATER"); + auto finder2 = tblcfg("CFG_FINDER_2"); + finder2("LIGHTGUN1") = "GUN_TACHYON_HEATER"; + finder2("HEAVYGUN1") = "GUN_TACHYON_HEATER"; // patch note: double gun for config CFG_EYEDSTONE_1: from GUN_FAST_ELECTROMAGNETIC_BEAM to double GUN_FAST_ELECTROMAGNETIC_BEAM (lz) - mod.db().edit_value(u8"Конфигурации", "CFG_EYEDSTONE_1", "LIGHTGUN1", "GUN_FAST_ELECTROMAGNETIC_BEAM"); + tblcfg("CFG_EYEDSTONE_1", "LIGHTGUN1") = "GUN_FAST_ELECTROMAGNETIC_BEAM"; // patch note: double gun for config CFG_EYEDSTONE_2: from GUN_FAST_ELECTROMAGNETIC_BEAM to double GUN_FAST_ELECTROMAGNETIC_BEAM (lz) - mod.db().edit_value(u8"Конфигурации", "CFG_EYEDSTONE_2", "LIGHTGUN1", "GUN_FAST_ELECTROMAGNETIC_BEAM"); + tblcfg("CFG_EYEDSTONE_2", "LIGHTGUN1") = "GUN_FAST_ELECTROMAGNETIC_BEAM"; // patch note: INFORMATION + auto quest = mod.quest().open(); // patch note: add name for SINIGR armor, it was unnamed before (lz) - mod.quest().add_value("INFORMATION", "EQP_ZERO_ARMOR_S_SIN", "NAME", u8"Особая нуль-броня"); + quest("INFORMATION", "EQP_ZERO_ARMOR_S_SIN", "NAME") = u8"Особая нуль-броня"; // patch note: // patch note: Game Changes @@ -174,6 +179,11 @@ int main(int argc, char *argv[]) { // patch note dev: Developer Mode!!! // patch note dev: enabled developer mode (free camera - F3 key, time shift - N key) (lz, Solant) mod.enable_free_camera(); + // patch note dev: make initial reactor (EQP_GLUON_REACTOR_S1) and drive (EQP_ION_DRIVE_S1) more powerful + db(u8"Оборудование", "EQP_GLUON_REACTOR_S1", "VALUE1") = 9'000'000.f; + db(u8"Оборудование", "EQP_ION_DRIVE_S1", "VALUE1") = 4158000.f; + // patch note dev: make EQP_VACUUM_DRIVE_S4 more powerful + db(u8"Оборудование", "EQP_VACUUM_DRIVE_S4", "VALUE1") = 4158000.f; // patch note dev: start money, rating, glider and sector access mod.replace("Script/bin/B_L1_BASE1.scr", "_ADDBALANCE(300)", R"( _ADDBALANCE(300 ) @@ -223,6 +233,8 @@ int main(int argc, char *argv[]) { // patch note: lz // patch note: // patch note: Have fun! + db.~files(); + quest.~files(); mod.apply(); // patch note: diff --git a/src/aim1_mod_maker/aim1_mod_maker.h b/src/aim1_mod_maker/aim1_mod_maker.h index 3967998..dd061dc 100644 --- a/src/aim1_mod_maker/aim1_mod_maker.h +++ b/src/aim1_mod_maker/aim1_mod_maker.h @@ -186,30 +186,12 @@ struct mod_maker { c.push_back("a"); c.push_back(ar); // we use zip as more common for (auto &&f : files_to_distribute) { - c.push_back(f); + c.push_back(f.is_absolute() ? f.lexically_relative(game_dir) : f); } for (auto &&f : code_files_to_distribute) { - c.push_back(f); + c.push_back(f.is_absolute() ? f.lexically_relative(game_dir) : f); } run_command(c); - - auto rename = [&](auto &&from, auto &&to) { - primitives::Command c; - c.working_directory = game_dir; - c.push_back("7z"); - c.push_back("rn"); - c.push_back(ar); - c.push_back(from); - c.push_back(to); - run_command(c); - }; - for (auto &&f : code_files_to_distribute) { - if (f.filename() == path{loc.file_name()}.filename()) { - rename(f.filename(), path{"data"} / "mods" / get_full_mod_name() / get_full_mod_name() += ".cpp"); - } else { - rename(f.filename(), path{"data"} / "mods" / get_full_mod_name() / f.filename()); - } - } } } @@ -314,8 +296,13 @@ struct mod_maker { ENABLE_DISABLE_FUNC(win_key, 0x00, 0x10) #undef ENABLE_DISABLE_FUNC - void add_code_file_for_archive(const path &fn) { - code_files_to_distribute.insert(path{loc.file_name()}.parent_path() / fn); + void add_code_file_for_archive(path fn) { + if (!fn.is_absolute()) { + fn = path{loc.file_name()}.parent_path() / fn.filename(); + } + auto dst_fn = get_mod_dir() / fn.filename(); + fs::copy_file(fn, dst_fn, fs::copy_options::overwrite_existing); + code_files_to_distribute.insert(dst_fn); } void add_resource(path fn) { fn = find_real_filename(fn); @@ -330,16 +317,21 @@ struct mod_maker { } private: - void make_bak_file(const path &fn) { + path make_bak_file(const path &fn) { auto backup = path{fn} += ".bak"; if (!fs::exists(backup)) { fs::copy_file(fn, backup); } + return backup; } auto open_db(auto &&name) { auto d = db2{get_data_dir() / name, db_codepage}; - for (auto &&f : d.open().get_files()) { - make_bak_file(f); + auto files = d.open().get_files(); + for (auto &&f : files) { + auto bak = make_bak_file(f); + if (fs::exists(bak)) { + fs::copy_file(bak, f, fs::copy_options::overwrite_existing); + } files_to_distribute.insert(f); } return d; @@ -363,9 +355,17 @@ private: void init(const path &dir) { read_name(); detect_game_dir(dir); +#ifdef NDEBUG + if (fs::exists(get_mod_dir())) { + fs::remove_all(get_mod_dir()); + } +#endif fs::create_directories(get_mod_dir()); - code_files_to_distribute.insert(loc.file_name()); + auto src_fn = get_mod_dir() / get_full_mod_name() += ".cpp"; + fs::copy_file(loc.file_name(), src_fn, fs::copy_options::overwrite_existing); + code_files_to_distribute.insert(src_fn); detect_tools(); + create_backup_exe_file(); prepare_injections(); #ifndef NDEBUG enable_win_key(); @@ -482,7 +482,6 @@ private: ::memcpy(p + off, to.data(), to.size()); } void prepare_injections() { - create_backup_exe_file(); #ifdef NDEBUG make_injected_dll(); #endif @@ -592,16 +591,17 @@ FF D7 ; call edi } // from https://github.com/Solant/aim-patches void free_camera(uint8_t val) { - create_backup_exe_file(); patch(aim_exe, 0x1F805, val); } void win_key(uint8_t val) { - create_backup_exe_file(); patch(aim_exe, 0x4A40D, val); } void create_backup_exe_file() { auto fn = find_real_filename(aim_exe); - make_bak_file(fn); + auto bak = make_bak_file(fn); + if (fs::exists(bak)) { + fs::copy_file(bak, fn, fs::copy_options::overwrite_existing); + } } template void patch_raw(path fn, uint32_t offset, T val) const { diff --git a/src/common/db2.h b/src/common/db2.h index 41b3224..c6dc430 100644 --- a/src/common/db2.h +++ b/src/common/db2.h @@ -100,6 +100,14 @@ struct db2 { }; // actual db struct files { + template + struct setter { + T field; + V value; + void operator=(auto &&v) { + value.set_field(field, v); + } + }; struct table { files &f; db2::tab::table t; @@ -149,6 +157,17 @@ struct db2 { } return value{*this,*itv}; } + auto operator()(auto &&name) { + return find_value(name); + } + auto operator()(auto &&vname, auto &&fname) { + auto value = find_value(vname); + if constexpr (std::is_convertible_v) { + return setter{fname, value}; + } else { + return setter{fname, value}; + } + } }; struct value { table t; @@ -166,6 +185,9 @@ struct db2 { void set_field(auto &&name, auto &&v) { using T = std::decay_t; auto f = t.find_field(name, field_type(v)); + if (f.type != field_type(v)) { + throw std::runtime_error{"field type mismatch: "s + t.f.db.utf8_to_dbstr(name)}; + } dat::field_value_base newfield{f.id}; if constexpr (std::same_as, int> || std::same_as, float>) { @@ -215,13 +237,12 @@ struct db2 { this->v.offset = t.f.dat_.f.sz; memcpy(t.f.dat_.f.alloc_raw(t.f.dat_.f.sz + reallen), data.data(), reallen); } - }; - template - struct setter { - T field; - value value; - void operator=(auto &&v) { - value.set_field(field, v); + auto operator()(auto &&name) { + if constexpr (std::is_convertible_v) { + return setter{name, *this}; + } else { + return setter{name, *this}; + } } }; @@ -258,13 +279,16 @@ struct db2 { } // [] not in msvc yet + auto operator()(auto &&tname) { + return find_table(tname); + } auto operator()(auto &&tname, auto &&vname, auto &&fname) { auto tbl = find_table(tname); auto value = tbl.find_value(vname); if constexpr (std::is_convertible_v) { - return setter{fname, value}; + return setter{fname, value}; } else { - return setter{fname, value}; + return setter{fname, value}; } } }; @@ -272,174 +296,6 @@ struct db2 { auto open() { return files{*this,fn}; } - void add_value(auto &&table, auto &&value, auto && ... fields1) { - auto f = open(); - auto tbl = f.tab_.data->tables(); - auto fields = f.tab_.data->fields(); - auto values = f.ind_.data->values(); - - auto table_db_cp = utf8_to_dbstr(table); - auto value_db_cp = utf8_to_dbstr(value); - - auto calc_fields_size = [&](this auto &&f, auto &&field_name, auto &&n, auto &&v, auto &&...fields) { - if (field_name == n) { - if constexpr (std::same_as, int>) { - return sizeof(db2::dat::field_value_base) + sizeof(int); - } else if constexpr (std::same_as, float>) { - return sizeof(db2::dat::field_value_base) + sizeof(float); - } else { - auto s = utf8_to_dbstr(v); - return sizeof(db2::dat::field_value_base) + s.size() + 1; - } - } - if constexpr (sizeof...(fields)) { - return f(field_name, fields...); - } - if constexpr (std::same_as, int>) { - return sizeof(db2::dat::field_value_base) + sizeof(int); - } else if constexpr (std::same_as, float>) { - return sizeof(db2::dat::field_value_base) + sizeof(float); - } else { - return sizeof(db2::dat::field_value_base) + 1; - } - }; - auto write_fields = [&](this auto &&f, auto &&p, auto &&field, auto &&field_name, auto &&n, auto &&v, auto &&...fields) { - if (field_name == n) { - if constexpr (std::same_as, int>) { - if (field.type != db2::field_type::integer) { - throw std::runtime_error{"field type mismatch"}; - } - (*(db2::dat::field_value_base*)p).field_id = field.id; - (*(db2::dat::field_value_base*)p).size = sizeof(int); - p += sizeof(db2::dat::field_value_base); - *(int*)p = v; - p += sizeof(int); - return; - } else if constexpr (std::same_as, float>) { - if (field.type != db2::field_type::float_) { - throw std::runtime_error{"field type mismatch"}; - } - (*(db2::dat::field_value_base *)p).field_id = field.id; - (*(db2::dat::field_value_base *)p).size = sizeof(float); - p += sizeof(db2::dat::field_value_base); - *(float *)p = v; - p += sizeof(float); - return; - } else { - if (field.type != db2::field_type::string) { - throw std::runtime_error{"field type mismatch"}; - } - auto s = utf8_to_dbstr(v); - (*(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); - memcpy(p, s.data(), s.size()); - p[s.size()] = 0; - p += s.size() + 1; - return; - } - } - if constexpr (sizeof...(fields)) { - return f(p, field, field_name, fields...); - } - if constexpr (std::same_as, int>) { - (*(db2::dat::field_value_base *)p).field_id = field.id; - (*(db2::dat::field_value_base *)p).size = 0; - p += sizeof(db2::dat::field_value_base); - return; - } else if constexpr (std::same_as, float>) { - (*(db2::dat::field_value_base *)p).field_id = field.id; - (*(db2::dat::field_value_base *)p).size = 0; - p += sizeof(db2::dat::field_value_base); - return; - } else { - (*(db2::dat::field_value_base *)p).field_id = field.id; - (*(db2::dat::field_value_base *)p).size = 1; - p += sizeof(db2::dat::field_value_base); - p[1] = 0; - p += 1; - return; - } - }; - - auto it = std::ranges::find_if(tbl, [&](auto &v){return v.name == table_db_cp;}); - if (it == tbl.end()) { - throw std::runtime_error{"no such table: "s + table_db_cp}; - } - auto &t = *it; - auto itv = std::ranges::find_if(values, [&](auto &v){return v.table_id == t.id && value_db_cp == v.name;}); - if (itv == values.end()) { - db2::ind::value i{}; - i.table_id = t.id; - memcpy(i.name, value_db_cp.data(), value_db_cp.size()); - i.offset = f.dat_.f.sz; - for (auto &&f : fields) { - if (f.table_id != t.id) { - continue; - } - std::string_view fn = f.name; - i.size += calc_fields_size(fn, fields1...); - } - - ++f.ind_.data->n_values; - auto p = f.ind_.f.alloc_raw(f.ind_.f.sz + sizeof(i)); - memcpy(p, &i, sizeof(i)); - - p = f.dat_.f.alloc_raw(f.dat_.f.sz + i.size); - for (auto &&f : fields) { - if (f.table_id != t.id) { - continue; - } - std::string_view fn = f.name; - write_fields(p, f, fn, fields1...); - } - } - } - template - void edit_value(auto &&table, auto &&value, auto &&field, const T &field_value) { - auto f = open(); - auto fields = f.tab_.data->fields(); - auto values = f.ind_.data->values(); - - auto value_db_cp = utf8_to_dbstr(value); - auto field_db_cp = utf8_to_dbstr(field); - - /*auto t = f.find_table(table); - auto itv = std::ranges::find_if(values, [&](auto &v) { - return v.table_id == t.id && value_db_cp == v.name; - }); - if (itv == values.end()) { - throw std::runtime_error{"no such value: "s + value_db_cp}; - } - auto itf = std::ranges::find_if(fields, [&](auto &v) { - return v.table_id == t.id && field_db_cp == v.name; - }); - if (itf == fields.end()) { - throw std::runtime_error{"no such field: "s + field_db_cp}; - } - - auto p = f.dat_.f.p + itv->offset; - while (p < f.dat_.f.p + itv->offset + itv->size) { - auto &header = *(dat::field_value_base*)p; - p += sizeof(header); - if (header.field_id == itf->id) { - if constexpr (std::same_as, int>) { - *(int*)p = field_value; - } else if constexpr (std::same_as, float>) { - *(float *)p = field_value; - } else { - auto s = utf8_to_dbstr(field_value); - if (s.size() + 1 != header.size) { - throw std::runtime_error{"not implemented yet"}; // maybe just assign new value into the end of db - } - memcpy(p, s.data(), s.size()); - } - return; - } - p += header.size; - }*/ - throw std::runtime_error{"no such field"}; - } private: std::string utf8_to_dbstr(const char *s) const {