From b8a12cca3e4514cf9982f2c6b1b0837c7f7b08ea Mon Sep 17 00:00:00 2001 From: Aleos Date: Wed, 20 Nov 2019 08:15:54 -0500 Subject: [PATCH] Updated the CSV2YAML tool to utilize YAML Emitter (#4448) * Processing performance increases by an order of magnitudes. * Generalized the path vector names to be used for future conversion functions. * Fixed new lines. * Added header templates. Thanks to @Lemongrass3110! --- .gitattributes | 2 +- doc/yaml/db/guild_skill_tree.yml | 15 ++ doc/yaml/db/license.yml | 17 +++ doc/yaml/db/pet_db.yml | 34 +++++ src/tool/csv2yaml.cpp | 236 ++++++++++++++++--------------- 5 files changed, 192 insertions(+), 112 deletions(-) create mode 100644 doc/yaml/db/guild_skill_tree.yml create mode 100644 doc/yaml/db/license.yml create mode 100644 doc/yaml/db/pet_db.yml diff --git a/.gitattributes b/.gitattributes index cd05f7536c..cae443c670 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,6 +1,6 @@ * text=auto *.cpp diff=cpp -*.yml diff +*.yml diff text eol=lf *.sln merge=union *.vcproj merge=union *.vcxproj merge=union diff --git a/doc/yaml/db/guild_skill_tree.yml b/doc/yaml/db/guild_skill_tree.yml new file mode 100644 index 0000000000..78539f5036 --- /dev/null +++ b/doc/yaml/db/guild_skill_tree.yml @@ -0,0 +1,15 @@ +########################################################################### +# Guild Skill Database +########################################################################### +# +# Guild Skill Settings +# +########################################################################### +# Id - Skill ID of the guild skill. +########################################################################### +# MaxLevel - Maximum level of the guild skill. +########################################################################### +# Required - A list of required skills for the skill to become available. +# Id: Skill ID of the required guild skill. +# Level: Level of the required guild skill. +########################################################################### diff --git a/doc/yaml/db/license.yml b/doc/yaml/db/license.yml new file mode 100644 index 0000000000..e39ee5e624 --- /dev/null +++ b/doc/yaml/db/license.yml @@ -0,0 +1,17 @@ +# This file is a part of rAthena. +# Copyright(C) 2019 rAthena Development Team +# https://rathena.org - https://github.com/rathena +# +# 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 . +# diff --git a/doc/yaml/db/pet_db.yml b/doc/yaml/db/pet_db.yml new file mode 100644 index 0000000000..bfe36d2f6f --- /dev/null +++ b/doc/yaml/db/pet_db.yml @@ -0,0 +1,34 @@ +########################################################################### +# Pet Database +########################################################################### +# +# Pet Settings +# +########################################################################### +# - Mob Monster that can be used as pet +# TameItem Pet Tame Item. +# EggItem Pet Egg Item. +# EquipItem Pet Accessory Item. (Default: 0) +# FoodItem Pet Food Item. (Default: 0) +# Fullness The amount of hunger is decreased every [HungryDelay] seconds. +# HungryDelay The amount of time in seconds it takes for hunger to decrease after feeding. (Default: 60) +# HungerIncrease The amount of hunger that is increased every time the pet is fed (Default: 20) +# IntimacyStart Amount of Intimacy the pet starts with. (Default: 250) +# IntimacyFed Amount of Intimacy that is increased when fed. (Default: 50) +# IntimacyOverfed Amount of Intimacy that is increased when over-fed. (Default: -100) +# IntimacyHungry Amount of Intimacy that is increased when the pet is hungry. (Default: -5) +# IntimacyOwnerDie Amount of Intimacy that is increased when the pet owner dies. (Default: -20) +# CaptureRate Capture success rate. (10000 = 100%) +# SpecialPerformance If a pet has a Special Performance. (Default: true) +# AttackRate Rate of which the pet will attack [requires at least pet_support_min_friendly intimacy]. (10000 = 100%) +# RetaliateRate Rate of which the pet will retaliate when master is being attacked [requires at least pet_support_min_friendly intimacy]. (10000 = 100%) +# ChangeTargetRate Rate of which the pet will change its attack target. (10000 = 100%) +# AllowAutoFeed Allows turning automatic pet feeding on. (Default: false) +# Script Bonus script to execute when the pet is alive. (Default: null) +# SupportScript Bonus script to execute when pet_status_support is enabled. (Default: null) +# Evolution: Pet evolution settings. (Optional) (Default: null) +# - Target Mob this pet can evolve to. +# ItemRequirements: Item requirements for evolving this pet. +# - Item Self-explanatory +# Amount +########################################################################### diff --git a/src/tool/csv2yaml.cpp b/src/tool/csv2yaml.cpp index 7ecdeffa5c..c7f8e7b7cc 100644 --- a/src/tool/csv2yaml.cpp +++ b/src/tool/csv2yaml.cpp @@ -1,11 +1,12 @@ // Copyright (c) rAthena Dev Teams - Licensed under GNU GPL // For more information, see LICENCE in the main folder -#include #include #include -#include +#include +#include #include +#include #ifdef WIN32 #include @@ -81,12 +82,9 @@ static bool parse_mob_constants( char* split[], int columns, int current ); static bool parse_skill_constants( char* split[], int columns, int current ); bool fileExists( const std::string& path ); -bool writeToFile( const YAML::Node& node, const std::string& path ); -void prepareHeader( YAML::Node& node, const std::string& type, uint32 version ); bool askConfirmation( const char* fmt, ... ); -YAML::Node body; -size_t counter; +YAML::Emitter body; // Implement the function instead of including the original version by linking void script_set_constant_( const char* name, int value, const char* constant_name, bool isparameter, bool deprecated ){ @@ -106,6 +104,54 @@ const char* constant_lookup( int32 value, const char* prefix ){ return nullptr; } +void copyFileIfExists( std::ofstream& file,const std::string& name, bool newLine ){ + std::string path = "doc/yaml/db/" + name + ".yml"; + + if( fileExists( path ) ){ + std::ifstream source( path, std::ios::binary ); + + std::istreambuf_iterator begin_source( source ); + std::istreambuf_iterator end_source; + std::ostreambuf_iterator begin_dest( file ); + copy( begin_source, end_source, begin_dest ); + + source.close(); + + if( newLine ){ + file << "\n"; + } + } +} + +void prepareHeader(std::ofstream &file, const std::string& type, uint32 version, const std::string& name) { + copyFileIfExists( file, "license", false ); + copyFileIfExists( file, name, true ); + + YAML::Emitter header(file); + + header << YAML::BeginMap; + header << YAML::Key << "Header"; + header << YAML::BeginMap; + header << YAML::Key << "Type" << YAML::Value << type; + header << YAML::Key << "Version" << YAML::Value << version; + header << YAML::EndMap; + header << YAML::EndMap; + + file << "\n"; + file << "\n"; +} + +void prepareBody(void) { + body << YAML::BeginMap; + body << YAML::Key << "Body"; + body << YAML::BeginSeq; +} + +void finalizeBody(void) { + body << YAML::EndSeq; + body << YAML::EndMap; +} + template bool process( const std::string& type, uint32 version, const std::vector& paths, const std::string& name, Func lambda ){ for( const std::string& path : paths ){ @@ -117,30 +163,35 @@ bool process( const std::string& type, uint32 version, const std::vector guild_skill_tree_paths = { + std::vector root_paths = { path_db, + path_db_mode, path_db_import }; - if( !process( "GUILD_SKILL_TREE_DB", 1, guild_skill_tree_paths, "guild_skill_tree", []( const std::string& path, const std::string& name_ext ) -> bool { + if( !process( "GUILD_SKILL_TREE_DB", 1, root_paths, "guild_skill_tree", []( const std::string& path, const std::string& name_ext ) -> bool { return sv_readdb( path.c_str(), name_ext.c_str(), ',', 2 + MAX_GUILD_SKILL_REQUIRE * 2, 2 + MAX_GUILD_SKILL_REQUIRE * 2, -1, &guild_read_guildskill_tree_db, false ); } ) ){ return 0; } - std::vector pet_paths = { - path_db_mode, - path_db_import - }; - - if( !process( "PET_DB", 1, pet_paths, "pet_db", []( const std::string& path, const std::string& name_ext ) -> bool { + if( !process( "PET_DB", 1, root_paths, "pet_db", []( const std::string& path, const std::string& name_ext ) -> bool { return pet_read_db( ( path + name_ext ).c_str() ); } ) ){ return 0; @@ -209,39 +256,6 @@ bool fileExists( const std::string& path ){ } } -bool writeToFile( const YAML::Node& node, const std::string& path ){ - std::ofstream out; - - out.open( path ); - - if( !out.is_open() ){ - ShowError( "Can not open file \"%s\" for writing.\n", path.c_str() ); - return false; - } - - out << node; - - // Make sure there is an empty line at the end of the file for git -#ifdef WIN32 - out << "\r\n"; -#else - out << "\n"; -#endif - - out.close(); - - return true; -} - -void prepareHeader( YAML::Node& node, const std::string& type, uint32 version ){ - YAML::Node header; - - header["Type"] = type; - header["Version"] = version; - - node["Header"] = header; -} - bool askConfirmation( const char* fmt, ... ){ va_list ap; @@ -410,10 +424,7 @@ static bool parse_skill_constants( char* split[], int columns, int current ){ // Copied and adjusted from guild.cpp // ,,,,,,,,,,, static bool guild_read_guildskill_tree_db( char* split[], int columns, int current ){ - YAML::Node node; - uint16 skill_id = (uint16)atoi(split[0]); - std::string* name = util::umap_find( aegis_skillnames, skill_id ); if( name == nullptr ){ @@ -421,33 +432,39 @@ static bool guild_read_guildskill_tree_db( char* split[], int columns, int curre return false; } - node["Id"] = *name; - node["MaxLevel"] = (uint16)atoi(split[1]); + body << YAML::BeginMap; + body << YAML::Key << "Id" << YAML::Value << *name; + body << YAML::Key << "MaxLevel" << YAML::Value << atoi(split[1]); - for( int i = 0, j = 0; i < MAX_GUILD_SKILL_REQUIRE; i++ ){ - uint16 required_skill_id = atoi( split[i * 2 + 2] ); - uint16 required_skill_level = atoi( split[i * 2 + 3] ); + if (atoi(split[2]) > 0) { + body << YAML::Key << "Required"; + body << YAML::BeginSeq; - if( required_skill_id == 0 || required_skill_level == 0 ){ - continue; + for (int i = 0, j = 0; i < MAX_GUILD_SKILL_REQUIRE; i++) { + uint16 required_skill_id = atoi(split[i * 2 + 2]); + uint16 required_skill_level = atoi(split[i * 2 + 3]); + + if (required_skill_id == 0 || required_skill_level == 0) { + continue; + } + + std::string* required_name = util::umap_find(aegis_skillnames, required_skill_id); + + if (required_name == nullptr) { + ShowError("Skill name for required skill id %hu is not known.\n", required_skill_id); + return false; + } + + body << YAML::BeginMap; + body << YAML::Key << "Id" << YAML::Value << *required_name; + body << YAML::Key << "Level" << YAML::Value << required_skill_level; + body << YAML::EndMap; } - std::string* required_name = util::umap_find( aegis_skillnames, required_skill_id ); - - if( required_name == nullptr ){ - ShowError( "Skill name for required skill id %hu is not known.\n", required_skill_id ); - return false; - } - - YAML::Node req; - - req["Id"] = *required_name; - req["Level"] = required_skill_level; - - node["Required"][j++] = req; + body << YAML::EndSeq; } - body[counter++] = node; + body << YAML::EndMap; return true; } @@ -531,9 +548,8 @@ static size_t pet_read_db( const char* file ){ continue; } - YAML::Node node; - - node["Mob"] = *mob_name; + body << YAML::BeginMap; + body << YAML::Key << "Mob" << YAML::Value << *mob_name; uint16 tame_item_id = (uint16)atoi( str[3] ); @@ -545,11 +561,10 @@ static size_t pet_read_db( const char* file ){ return false; } - node["TameItem"] = *tame_item_name; + body << YAML::Key << "TameItem" << YAML::Value << *tame_item_name; } uint16 egg_item_id = (uint16)atoi( str[4] ); - std::string* egg_item_name = util::umap_find( aegis_itemnames, egg_item_id ); if( egg_item_name == nullptr ){ @@ -557,7 +572,7 @@ static size_t pet_read_db( const char* file ){ return false; } - node["EggItem"] = *egg_item_name; + body << YAML::Key << "EggItem" << YAML::Value << *egg_item_name; uint16 equip_item_id = (uint16)atoi( str[5] ); @@ -569,7 +584,7 @@ static size_t pet_read_db( const char* file ){ return false; } - node["EquipItem"] = *equip_item_name; + body << YAML::Key << "EquipItem" << YAML::Value << *equip_item_name; } uint16 food_item_id = (uint16)atoi( str[6] ); @@ -582,48 +597,47 @@ static size_t pet_read_db( const char* file ){ return false; } - node["FoodItem"] = *food_item_name; + body << YAML::Key << "FoodItem" << YAML::Value << *food_item_name; } - node["Fullness"] = atoi( str[7] ); + body << YAML::Key << "Fullness" << YAML::Value << atoi(str[7]); // Default: 60 if( atoi( str[8] ) != 60 ){ - node["HungryDelay"] = atoi( str[8] ); + body << YAML::Key << "HungryDelay" << YAML::Value << atoi(str[8]); } // Default: 250 if( atoi( str[11] ) != 250 ){ - node["IntimacyStart"] = atoi( str[11] ); + body << YAML::Key << "IntimacyStart" << YAML::Value << atoi(str[11]); } - node["IntimacyFed"] = atoi( str[9] ); + body << YAML::Key << "IntimacyFed" << YAML::Value << atoi(str[9]); // Default: -100 if( atoi( str[10] ) != 100 ){ - node["IntimacyOverfed"] = -atoi( str[10] ); + body << YAML::Key << "IntimacyOverfed" << YAML::Value << -atoi(str[10]); } // pet_hungry_friendly_decrease battle_conf - //node["IntimacyHungry"] = -5; + //body << YAML::Key << "IntimacyHungry" << YAML::Value << -5; // Default: -20 if( atoi( str[12] ) != 20 ){ - node["IntimacyOwnerDie"] = -atoi( str[12] ); + body << YAML::Key << "IntimacyOwnerDie" << YAML::Value << -atoi(str[12]); } - node["CaptureRate"] = atoi( str[13] ); + body << YAML::Key << "CaptureRate" << YAML::Value << atoi(str[13]); // Default: true if( atoi( str[15] ) == 0 ){ - node["SpecialPerformance"] = false; + body << YAML::Key << "SpecialPerformance" << YAML::Value << "false"; } - node["AttackRate"] = atoi( str[17] ); - node["RetaliateRate"] = atoi( str[18] ); - node["ChangeTargetRate"] = atoi( str[19] ); + body << YAML::Key << "AttackRate" << YAML::Value << atoi(str[17]); + body << YAML::Key << "RetaliateRate" << YAML::Value << atoi(str[18]); + body << YAML::Key << "ChangeTargetRate" << YAML::Value << atoi(str[19]); if( *str[21] ){ - node["Script"] = str[21]; + body << YAML::Key << "Script" << YAML::Value << YAML::Literal << str[21]; } if( *str[20] ){ - node["SupportScript"] = str[20]; + body << YAML::Key << "SupportScript" << YAML::Value << YAML::Literal << str[20]; } - body[counter++] = node; - + body << YAML::EndMap; entries++; }