yamlupgrade.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327
  1. // Copyright (c) rAthena Dev Teams - Licensed under GNU GPL
  2. // For more information, see LICENCE in the main folder
  3. #include "yamlupgrade.hpp"
  4. using namespace rathena::tool_yamlupgrade;
  5. static bool upgrade_achievement_db(std::string file, const uint32 source_version);
  6. static bool upgrade_item_db(std::string file, const uint32 source_version);
  7. static bool upgrade_job_stats(std::string file, const uint32 source_version);
  8. static bool upgrade_status_db(std::string file, const uint32 source_version);
  9. template<typename Func>
  10. bool process(const std::string &type, uint32 version, const std::vector<std::string> &paths, const std::string &name, Func lambda) {
  11. for (const std::string &path : paths) {
  12. const std::string name_ext = name + ".yml";
  13. const std::string from = path + "/" + name_ext;
  14. const std::string to = path + "/" + name + "-upgrade.yml";
  15. inNode.reset();
  16. if (fileExists(from)) {
  17. inNode = YAML::LoadFile(from);
  18. uint32 source_version = getHeaderVersion(inNode);
  19. if (source_version >= version) {
  20. continue;
  21. }
  22. if (!askConfirmation("Found the file \"%s\", which requires an upgrade.\nDo you want to convert it now? (Y/N)\n", from.c_str())) {
  23. continue;
  24. }
  25. if (fileExists(to)) {
  26. if (!askConfirmation("The file \"%s\" already exists.\nDo you want to replace it? (Y/N)\n", to.c_str())) {
  27. continue;
  28. }
  29. }
  30. ShowNotice("Upgrade process has begun.\n");
  31. std::ofstream outFile;
  32. body.~Emitter();
  33. new (&body) YAML::Emitter();
  34. outFile.open(to);
  35. if (!outFile.is_open()) {
  36. ShowError("Can not open file \"%s\" for writing.\n", to.c_str());
  37. return false;
  38. }
  39. prepareHeader(outFile, type, version, name);
  40. if (inNode["Body"].IsDefined()) {
  41. prepareBody();
  42. if (!lambda(path, name_ext, source_version)) {
  43. outFile.close();
  44. return false;
  45. }
  46. finalizeBody();
  47. outFile << body.c_str();
  48. }
  49. prepareFooter(outFile);
  50. // Make sure there is an empty line at the end of the file for git
  51. outFile << "\n";
  52. outFile.close();
  53. }
  54. }
  55. return true;
  56. }
  57. bool YamlUpgradeTool::initialize( int argc, char* argv[] ){
  58. const std::string path_db = std::string(db_path);
  59. const std::string path_db_mode = path_db + "/" + DBPATH;
  60. const std::string path_db_import = path_db + "/" + DBIMPORT;
  61. // Loads required conversion constants
  62. if (fileExists(item_db.getDefaultLocation())) {
  63. item_db.load();
  64. } else {
  65. parse_item_constants_txt((path_db_mode + "item_db.txt").c_str());
  66. parse_item_constants_txt((path_db_import + "item_db.txt").c_str());
  67. }
  68. if (fileExists(mob_db.getDefaultLocation())) {
  69. mob_db.load();
  70. } else {
  71. sv_readdb(path_db_mode.c_str(), "mob_db.txt", ',', 31 + 2 * MAX_MVP_DROP + 2 * MAX_MOB_DROP, 31 + 2 * MAX_MVP_DROP + 2 * MAX_MOB_DROP, -1, &parse_mob_constants_txt, false);
  72. sv_readdb(path_db_import.c_str(), "mob_db.txt", ',', 31 + 2 * MAX_MVP_DROP + 2 * MAX_MOB_DROP, 31 + 2 * MAX_MVP_DROP + 2 * MAX_MOB_DROP, -1, &parse_mob_constants_txt, false);
  73. }
  74. if (fileExists(skill_db.getDefaultLocation())) {
  75. skill_db.load();
  76. } else {
  77. sv_readdb(path_db_mode.c_str(), "skill_db.txt", ',', 18, 18, -1, parse_skill_constants_txt, false);
  78. sv_readdb(path_db_import.c_str(), "skill_db.txt", ',', 18, 18, -1, parse_skill_constants_txt, false);
  79. }
  80. // Load constants
  81. #define export_constant_npc(a) export_constant(a)
  82. #include <map/script_constants.hpp>
  83. std::vector<std::string> root_paths = {
  84. path_db,
  85. path_db_mode,
  86. path_db_import
  87. };
  88. if (!process("ACHIEVEMENT_DB", 2, root_paths, "achievement_db", [](const std::string &path, const std::string &name_ext, uint32 source_version) -> bool {
  89. return upgrade_achievement_db(path + name_ext, source_version);
  90. })) {
  91. return false;
  92. }
  93. if (!process("ITEM_DB", 3, root_paths, "item_db", [](const std::string& path, const std::string& name_ext, uint32 source_version) -> bool {
  94. return upgrade_item_db(path + name_ext, source_version);
  95. })) {
  96. return false;
  97. }
  98. if (!process("JOB_STATS", 2, root_paths, "job_stats", [](const std::string& path, const std::string& name_ext, uint32 source_version) -> bool {
  99. return upgrade_job_stats(path + name_ext, source_version);
  100. })) {
  101. return false;
  102. }
  103. if (!process("STATUS_DB", 3, root_paths, "status", [](const std::string& path, const std::string& name_ext, uint32 source_version) -> bool {
  104. return upgrade_status_db(path + name_ext, source_version);
  105. })) {
  106. return 0;
  107. }
  108. return true;
  109. }
  110. // Implementation of the upgrade functions
  111. static bool upgrade_achievement_db(std::string file, const uint32 source_version) {
  112. size_t entries = 0;
  113. for (const auto &input : inNode["Body"]) {
  114. body << YAML::BeginMap;
  115. body << YAML::Key << "Id" << YAML::Value << input["ID"];
  116. std::string constant = input["Group"].as<std::string>();
  117. constant.erase(0, 3); // Remove "AG_"
  118. if (constant.compare("Chat") == 0) // Chat -> Chatting
  119. constant.insert(4, "ting");
  120. else if (constant.compare("Hear") == 0 || constant.compare("See") == 0)
  121. constant = "Chatting"; // Aegis treats these as general "Talk to NPC" achievements.
  122. else if (constant.compare("Refine") == 0) { // Refine -> Enchant
  123. constant.erase(0, 6);
  124. constant = "Enchant" + constant;
  125. }
  126. body << YAML::Key << "Group" << YAML::Value << name2Upper(constant);
  127. body << YAML::Key << "Name" << YAML::Value << input["Name"];
  128. if (input["Target"].IsDefined()) {
  129. body << YAML::Key << "Targets";
  130. body << YAML::BeginSeq;
  131. for (const auto &it : input["Target"]) {
  132. body << YAML::BeginMap;
  133. body << YAML::Key << "Id" << YAML::Value << it["Id"];
  134. if (it["MobID"].IsDefined()) {
  135. uint16 mob_id = it["MobID"].as<uint16>();
  136. std::string *mob_name = util::umap_find(aegis_mobnames, mob_id);
  137. if (mob_name == nullptr) {
  138. ShowWarning("mob_avail reading: Invalid mob-class %hu, Mob not read.\n", mob_id);
  139. return false;
  140. }
  141. body << YAML::Key << "Mob" << YAML::Value << *mob_name;
  142. }
  143. if (it["Count"].IsDefined() && it["Count"].as<int32>() > 1)
  144. body << YAML::Key << "Count" << YAML::Value << it["Count"];
  145. body << YAML::EndMap;
  146. }
  147. body << YAML::EndSeq;
  148. }
  149. if (input["Condition"].IsDefined())
  150. body << YAML::Key << "Condition" << YAML::Value << input["Condition"];
  151. if (input["Map"].IsDefined())
  152. body << YAML::Key << "Map" << YAML::Value << input["Map"];
  153. if (input["Dependent"].IsDefined()) {
  154. body << YAML::Key << "Dependents";
  155. body << YAML::BeginMap;
  156. for (const auto &it : input["Dependent"]) {
  157. body << YAML::Key << it["Id"] << YAML::Value << true;
  158. }
  159. body << YAML::EndMap;
  160. }
  161. /**
  162. * Example usage for adding label at specific version.
  163. if (source_version < ?) {
  164. body << YAML::Key << "CustomLabel" << YAML::Value << "Unique";
  165. }
  166. */
  167. if (input["Reward"].IsDefined()) {
  168. body << YAML::Key << "Rewards";
  169. body << YAML::BeginMap;
  170. if (input["Reward"]["ItemID"].IsDefined()) {
  171. t_itemid item_id = input["Reward"]["ItemID"].as<t_itemid>();
  172. std::string *item_name = util::umap_find(aegis_itemnames, item_id);
  173. if (item_name == nullptr) {
  174. ShowError("Reward item name for item ID %u is not known.\n", item_id);
  175. return false;
  176. }
  177. body << YAML::Key << "Item" << YAML::Value << *item_name;
  178. }
  179. if (input["Reward"]["Amount"].IsDefined() && input["Reward"]["Amount"].as<uint16>() > 1)
  180. body << YAML::Key << "Amount" << YAML::Value << input["Reward"]["Amount"];
  181. if (input["Reward"]["Script"].IsDefined())
  182. body << YAML::Key << "Script" << YAML::Value << input["Reward"]["Script"];
  183. if (input["Reward"]["TitleID"].IsDefined())
  184. body << YAML::Key << "TitleId" << YAML::Value << input["Reward"]["TitleID"];
  185. body << YAML::EndMap;
  186. }
  187. body << YAML::Key << "Score" << YAML::Value << input["Score"];
  188. body << YAML::EndMap;
  189. entries++;
  190. }
  191. ShowStatus("Done converting/upgrading '" CL_WHITE "%zu" CL_RESET "' achievements in '" CL_WHITE "%s" CL_RESET "'.\n", entries, file.c_str());
  192. return true;
  193. }
  194. static bool upgrade_item_db(std::string file, const uint32 source_version) {
  195. size_t entries = 0;
  196. for( auto input : inNode["Body"] ){
  197. // If under version 2
  198. if( source_version < 2 ){
  199. // Add armor level to all equipments
  200. if( input["Type"].IsDefined() && input["Type"].as<std::string>() == "Armor" ){
  201. input["ArmorLevel"] = 1;
  202. }
  203. }
  204. // TODO: this currently converts all scripts using Literal syntax to normal double quote strings
  205. body << input;
  206. entries++;
  207. }
  208. ShowStatus("Done converting/upgrading '" CL_WHITE "%zu" CL_RESET "' items in '" CL_WHITE "%s" CL_RESET "'.\n", entries, file.c_str());
  209. return true;
  210. }
  211. static bool upgrade_job_stats(std::string file, const uint32 source_version) {
  212. size_t entries = 0;
  213. for (auto input : inNode["Body"]) {
  214. // If under version 2
  215. if (source_version < 2) {
  216. // Field name changes
  217. if (input["HPFactor"].IsDefined()) {
  218. input["HpFactor"] = input["HPFactor"].as<uint32>();
  219. input.remove("HPFactor");
  220. }
  221. if (input["HpMultiplicator"].IsDefined()) {
  222. input["HpIncrease"] = input["HpMultiplicator"].as<uint32>();
  223. input.remove("HpMultiplicator");
  224. }
  225. if (input["HPMultiplicator"].IsDefined()) {
  226. input["HpIncrease"] = input["HPMultiplicator"].as<uint32>();
  227. input.remove("HPMultiplicator");
  228. }
  229. if (input["SpFactor"].IsDefined()) {
  230. input["SpIncrease"] = input["SpFactor"].as<uint32>();
  231. input.remove("SpFactor");
  232. }
  233. if (input["SPFactor"].IsDefined()) {
  234. input["SpIncrease"] = input["SPFactor"].as<uint32>();
  235. input.remove("SPFactor");
  236. }
  237. }
  238. body << input;
  239. entries++;
  240. }
  241. ShowStatus("Done converting/upgrading '" CL_WHITE "%zu" CL_RESET "' job stats in '" CL_WHITE "%s" CL_RESET "'.\n", entries, file.c_str());
  242. return true;
  243. }
  244. static bool upgrade_status_db(std::string file, const uint32 source_version) {
  245. size_t entries = 0;
  246. for (auto input : inNode["Body"]) {
  247. // If under version 3
  248. if (source_version < 3) {
  249. // Rename End to EndOnStart
  250. if (input["End"].IsDefined()) {
  251. input["EndOnStart"] = input["End"];
  252. input.remove("End");
  253. }
  254. }
  255. body << input;
  256. entries++;
  257. }
  258. ShowStatus("Done converting/upgrading '" CL_WHITE "%zu" CL_RESET "' statuses in '" CL_WHITE "%s" CL_RESET "'.\n", entries, file.c_str());
  259. return true;
  260. }
  261. int main( int argc, char *argv[] ){
  262. return main_core<YamlUpgradeTool>( argc, argv );
  263. }