From a093ae986475fb10ac4ba804b59ec39c3123eb42 Mon Sep 17 00:00:00 2001 From: Alice Ogeda Date: Sat, 4 Feb 2023 22:58:00 -0300 Subject: [PATCH] add wiki_parser; --- src/tools/CMakeLists.txt | 1 + src/tools/wiki_parse/CMakeLists.txt | 14 + src/tools/wiki_parse/main.cpp | 448 ++++++++++++++++++ .../Network/Handlers/GMCommandHandlers.cpp | 2 +- 4 files changed, 464 insertions(+), 1 deletion(-) create mode 100644 src/tools/wiki_parse/CMakeLists.txt create mode 100644 src/tools/wiki_parse/main.cpp diff --git a/src/tools/CMakeLists.txt b/src/tools/CMakeLists.txt index c4441dd2..7929cb4b 100644 --- a/src/tools/CMakeLists.txt +++ b/src/tools/CMakeLists.txt @@ -28,4 +28,5 @@ add_subdirectory( "nav_export" ) #add_subdirectory( "BattleNpcParserPs3" ) add_subdirectory( "event_object_parser" ) add_subdirectory( "action_parse" ) +add_subdirectory( "wiki_parse" ) #add_subdirectory( "questbattle_bruteforce" ) \ No newline at end of file diff --git a/src/tools/wiki_parse/CMakeLists.txt b/src/tools/wiki_parse/CMakeLists.txt new file mode 100644 index 00000000..b24dffef --- /dev/null +++ b/src/tools/wiki_parse/CMakeLists.txt @@ -0,0 +1,14 @@ +cmake_minimum_required( VERSION 3.0.2 ) +cmake_policy(SET CMP0015 NEW) +project(Tool_WikiParse) + +file(GLOB SERVER_PUBLIC_INCLUDE_FILES "${CMAKE_CURRENT_SOURCE_DIR}/*") +file(GLOB SERVER_SOURCE_FILES "${CMAKE_CURRENT_SOURCE_DIR}*.c*") + +add_executable( wiki_parse ${SERVER_PUBLIC_INCLUDE_FILES} ${SERVER_SOURCE_FILES}) + +if (UNIX) + target_link_libraries( wiki_parse common xivdat pthread mysql dl z stdc++fs ) +else() + target_link_libraries( wiki_parse common xivdat mysql zlib) +endif() diff --git a/src/tools/wiki_parse/main.cpp b/src/tools/wiki_parse/main.cpp new file mode 100644 index 00000000..914e7983 --- /dev/null +++ b/src/tools/wiki_parse/main.cpp @@ -0,0 +1,448 @@ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +namespace fs = std::filesystem; + +using namespace Sapphire; +Sapphire::Data::ExdData g_exdDataGen; + +//std::string datLocation( "F:\\client3.0\\game\\sqpack" ); +std::string datLocation( "C:\\Data\\Dev\\ffxiv3.35\\game\\sqpack" ); +//const std::string datLocation( "/mnt/c/Program Files (x86)/Steam/steamapps/common/FINAL FANTASY XIV Online/game/sqpack" ); + +bool invalidChar( char c ) +{ + return !( c >= 0 && c < 128 ); +} + +void stripUnicode( std::string& str ) +{ + str.erase( std::remove_if( str.begin(), str.end(), invalidChar ), str.end() ); + str.erase( std::remove_if( str.begin(), str.end(), + []( char c ) + { + return !std::isalpha( c ) && !std::isdigit( c ) && !std::isspace( c ) && + !std::ispunct( c ); + } ), + str.end() ); +} + +uint32_t stripNonNumerics( std::string& str ) +{ + str.erase( std::remove_if( str.begin(), str.end(), + []( char c ) + { + return !std::isdigit( c ); + }), str.end() ); + + return std::atoi( str.c_str() ); +} + +template< typename T > +std::string stringVec( const std::vector< T >& vec ) +{ + if( vec.empty() ) + return ""; + + std::ostringstream oss; + std::copy( vec.begin(), vec.end() - 1, std::ostream_iterator< T >( oss, ", " ) ); + oss << vec.back(); + + return oss.str(); +} + +int main( int argc, char* argv[] ) +{ + Logger::init( "wiki_parse" ); + + if( argc == 2 ) + { + datLocation = std::string( argv[ 1 ] ); + } + + Logger::info( "Setting up EXD data" ); + if( !g_exdDataGen.init( datLocation ) ) + { + Logger::fatal( "Error setting up EXD data " ); + return 0; + } + + // CFC list + { + + auto idList = g_exdDataGen.getIdList< Excel::ContentFinderCondition >(); + + std::stringstream cfcOutputStream; + + auto total = idList.size(); + int cursor = 0; + + std::map< uint8_t, std::string > instanceContentTypeMap; + instanceContentTypeMap[ 0 ] = ""; + instanceContentTypeMap[ 1 ] = "Raid"; + instanceContentTypeMap[ 2 ] = "Dungeon"; + instanceContentTypeMap[ 3 ] = "Guildhest"; + instanceContentTypeMap[ 4 ] = "Trial"; + instanceContentTypeMap[ 5 ] = "PvP (The Feast)"; + instanceContentTypeMap[ 6 ] = "PvP"; + instanceContentTypeMap[ 7 ] = "Quest Battle"; + instanceContentTypeMap[ 8 ] = "Hall of the Novice"; + instanceContentTypeMap[ 9 ] = "Deep Dungeon"; + instanceContentTypeMap[ 10 ] = "Treasure Hunt"; + instanceContentTypeMap[ 11 ] = "Event"; + instanceContentTypeMap[ 12 ] = "PvP (Rival Wings)"; + instanceContentTypeMap[ 13 ] = "Masked Carnivale"; + instanceContentTypeMap[ 14 ] = "Goldsaucer (Mahjong)"; + instanceContentTypeMap[ 15 ] = "Goldsaucer"; + + + cfcOutputStream << "| ID | Instance | Territory | Name | Type |" << std::endl + << "| --- | --- | --- | --- | --- |" << std::endl; + + for( auto id : idList ) + { + auto done = ( cursor++ / static_cast< float >( total ) ) * 100.f; + if( cursor % 50 == 0 && cursor > 0 ) + Logger::info( "Processing {} CFCs of {} ({:.2f}%)", cursor, total, done ); + + if( id == 0 ) + continue; + + auto cfc = g_exdDataGen.getRow< Excel::ContentFinderCondition >( id ); + + if( cfc ) + { + auto& cfcData = cfc->data(); + + auto pInstanceContent = g_exdDataGen.getRow< Excel::InstanceContent >( cfcData.InstanceContentId ); + if( !pInstanceContent ) + continue; + + auto name = pInstanceContent->getString( pInstanceContent->data().Text.Name ); + + // cfc ID + cfcOutputStream << "| " << std::to_string( id ) << " | "; + + // instance ID + cfcOutputStream << std::to_string( cfcData.InstanceContentId ) << " | "; + + // territory type + cfcOutputStream << std::to_string( pInstanceContent->data().TerritoryType ) << " | "; + + // instance name + cfcOutputStream << name << " | "; + + // instance type + cfcOutputStream << instanceContentTypeMap[ pInstanceContent->data().Type ] << " |" << std::endl; + } + } + + Logger::info( cfcOutputStream.str() ); + std::ofstream outH( "generated/cfc.txt" ); + outH << cfcOutputStream.str() << std::endl; + outH.close(); + } + + // territory type list + { + + enum TerritoryIntendedUse : uint8_t + { + Town = 0, + OpenWorld = 1, + Inn = 2, + Dungeon = 3, + JailArea = 5, + OpeningArea = 6, + BeforeTrialDung = 7, + AllianceRaid = 8, + OpenWorldInstanceBattle = 9, + Trial = 10, + HousingArea = 13, + HousingPrivateArea = 14, + MSQPrivateArea = 15, + Raids = 16, + RaidFights = 17, + ChocoboSquare = 19, + ChocoboTutorial = 21, + Wedding = 22, + GoldSaucer = 23, + DiademV1 = 26, + BeginnerTutorial = 27, + PvPTheFeast = 28, + MSQEventArea = 29, + FreeCompanyGarrison = 30, + PalaceOfTheDead = 31, + TreasureMapInstance = 33, + EventTrial = 36, + TheFeastArea = 37, + PrivateEventArea = 40, + //Eureka = 41, // wat + }; + + std::map< uint8_t, std::string > teriTypeIntendedUseMap; + for( int i = 0; i < 255; ++i ) + { + teriTypeIntendedUseMap[ i ] = "Unknown"; + } + teriTypeIntendedUseMap[ Town ] = "Town"; + teriTypeIntendedUseMap[ OpenWorld ] = "OpenWorld"; + teriTypeIntendedUseMap[ Inn ] = "Inn"; + teriTypeIntendedUseMap[ Dungeon ] = "Dungeon"; + teriTypeIntendedUseMap[ JailArea ] = "JailArea"; + teriTypeIntendedUseMap[ OpeningArea ] = "OpeningArea"; + teriTypeIntendedUseMap[ BeforeTrialDung ] = "BeforeTrialDung"; + teriTypeIntendedUseMap[ AllianceRaid ] = "AllianceRaid"; + teriTypeIntendedUseMap[ OpenWorldInstanceBattle ] = "OpenWorldInstanceBattle"; + teriTypeIntendedUseMap[ Trial ] = "Trial"; + teriTypeIntendedUseMap[ HousingArea ] = "HousingArea"; + teriTypeIntendedUseMap[ HousingPrivateArea ] = "HousingPrivateArea"; + teriTypeIntendedUseMap[ MSQPrivateArea ] = "MSQPrivateArea"; + teriTypeIntendedUseMap[ Raids ] = "Raids"; + teriTypeIntendedUseMap[ RaidFights ] = "RaidFights"; + teriTypeIntendedUseMap[ ChocoboSquare ] = "ChocoboSquare"; + teriTypeIntendedUseMap[ ChocoboTutorial ] = "ChocoboTutorial"; + teriTypeIntendedUseMap[ Wedding ] = "Wedding"; + teriTypeIntendedUseMap[ GoldSaucer ] = "GoldSaucer"; + teriTypeIntendedUseMap[ DiademV1 ] = "DiademV1"; + teriTypeIntendedUseMap[ BeginnerTutorial ] = "BeginnerTutorial"; + teriTypeIntendedUseMap[ PvPTheFeast ] = "PvPTheFeast"; + teriTypeIntendedUseMap[ MSQEventArea ] = "MSQEventArea"; + teriTypeIntendedUseMap[ FreeCompanyGarrison ] = "FreeCompanyGarrison"; + teriTypeIntendedUseMap[ PalaceOfTheDead ] = "PalaceOfTheDead"; + teriTypeIntendedUseMap[ TreasureMapInstance ] = "TreasureMapInstance"; + teriTypeIntendedUseMap[ EventTrial ] = "EventTrial"; + teriTypeIntendedUseMap[ TheFeastArea ] = "TheFeastArea"; + teriTypeIntendedUseMap[ PrivateEventArea ] = "PrivateEventArea"; + + auto idList = g_exdDataGen.getIdList< Excel::TerritoryType >(); + + std::stringstream teritypeOutputStream; + + teritypeOutputStream << "| ID | Place Name | Name | Intended Use |" << std::endl + << "| --- | --- | --- | --- |" << std::endl; + + auto total = idList.size(); + int cursor = 0; + + for( auto id : idList ) + { + auto done = ( cursor++ / static_cast< float >( total ) ) * 100.f; + if( cursor % 50 == 0 && cursor > 0 ) + Logger::info( "Processing {} teritypes of {} ({:.2f}%)", cursor, total, done ); + + auto teriType = g_exdDataGen.getRow< Excel::TerritoryType >( id ); + + if( teriType ) + { + auto& teriTypeData = teriType->data(); + + auto name = teriType->getString( teriTypeData.Name ); + std::string placeName = ""; + + auto pPlaceName = g_exdDataGen.getRow< Excel::PlaceName >( teriTypeData.Area ); + if( pPlaceName ) + { + placeName = pPlaceName->getString( pPlaceName->data().Text.SGL ); + } + + if( placeName == "" ) + placeName = "[empty]"; + + // teritype ID + teritypeOutputStream << "| " << std::to_string( id ) << " | "; + + // aetheryte placename + teritypeOutputStream << placeName << " | "; + + // name + teritypeOutputStream << name << " | "; + + // territory intended use + teritypeOutputStream << teriTypeIntendedUseMap[ teriTypeData.IntendedUse ] << " |" << std::endl; + + } + } + + Logger::info( teritypeOutputStream.str() ); + std::ofstream outH( "generated/teritype.txt" ); + outH << teritypeOutputStream.str() << std::endl; + outH.close(); + } + + // class/job list + { + auto idList = g_exdDataGen.getIdList< Excel::ClassJob >(); + + std::stringstream classjobOutputStream; + + classjobOutputStream << "| ID | Name | Short | Main Class |" << std::endl + << "| --- | --- | --- | --- |" << std::endl; + + auto total = idList.size(); + int cursor = 0; + + for( auto id : idList ) + { + auto done = ( cursor++ / static_cast< float >( total ) ) * 100.f; + if( cursor % 50 == 0 && cursor > 0 ) + Logger::info( "Processing {} classjobs of {} ({:.2f}%)", cursor, total, done ); + + auto classJob = g_exdDataGen.getRow< Excel::ClassJob >( id ); + + if( classJob ) + { + auto& classJobData = classJob->data(); + + auto name = classJob->getString( classJobData.Text.Name ); + auto shortName = classJob->getString( classJobData.Text.Abbreviation ); + + // ID + classjobOutputStream << "| " << std::to_string( id ) << " | "; + + // name + classjobOutputStream << name << " | "; + + // short name + classjobOutputStream << shortName << " | "; + + // main class + classjobOutputStream << std::to_string( classJobData.MainClass ) << " |" << std::endl; + } + } + + Logger::info( classjobOutputStream.str() ); + std::ofstream outH( "generated/classjob.txt" ); + outH << classjobOutputStream.str() << std::endl; + outH.close(); + } + + // achievement list + { + auto idList = g_exdDataGen.getIdList< Excel::Achievement >(); + + enum class Type : uint8_t + { + None, + General, + LinkedAchievement, + Classjob, + Unknown_4,// Materia related? id 304 + Unknown_5,// Hunt related? id 1259 + Quest, // Quests that need all required args met + Unknown_7, + Unknown_8,// Map discovery related + QuestAny, // Quests that need any required args met + ChocoboRank, + PvPRank, + WolvesDenMatches, + WolvesDenWins, + InstanceContent, + BeastTribeReputation, + Unknown_16, + FrontlineMatches, + FrontlineWinsGC, + FrontlineWinsAll, + AetherCurrent, + }; + + std::map< Common::Achievement::Type, std::string > achievementTypeMap; + + achievementTypeMap[ Common::Achievement::Type::None ] = "None"; + achievementTypeMap[ Common::Achievement::Type::General ] = "General"; + achievementTypeMap[ Common::Achievement::Type::LinkedAchievement ] = "LinkedAchievement"; + achievementTypeMap[ Common::Achievement::Type::Classjob ] = "Classjob"; + achievementTypeMap[ Common::Achievement::Type::Unknown_4 ] = "Unknown_4"; + achievementTypeMap[ Common::Achievement::Type::Unknown_5 ] = "Unknown_5"; + achievementTypeMap[ Common::Achievement::Type::Quest ] = "Quest"; + achievementTypeMap[ Common::Achievement::Type::Unknown_7 ] = "Unknown_7"; + achievementTypeMap[ Common::Achievement::Type::Unknown_8 ] = "Unknown_8"; + achievementTypeMap[ Common::Achievement::Type::QuestAny ] = "QuestAny"; + achievementTypeMap[ Common::Achievement::Type::ChocoboRank ] = "ChocoboRank"; + achievementTypeMap[ Common::Achievement::Type::PvPRank ] = "PvPRank"; + achievementTypeMap[ Common::Achievement::Type::WolvesDenMatches ] = "WolvesDenMatches"; + achievementTypeMap[ Common::Achievement::Type::WolvesDenWins ] = "WolvesDenWins"; + achievementTypeMap[ Common::Achievement::Type::InstanceContent ] = "InstanceContent"; + achievementTypeMap[ Common::Achievement::Type::BeastTribeReputation ] = "BeastTribeReputation"; + achievementTypeMap[ Common::Achievement::Type::Unknown_16 ] = "Unknown_16"; + achievementTypeMap[ Common::Achievement::Type::FrontlineMatches ] = "FrontlineMatches"; + achievementTypeMap[ Common::Achievement::Type::FrontlineWinsGC ] = "FrontlineWinsGC"; + achievementTypeMap[ Common::Achievement::Type::FrontlineWinsAll ] = "FrontlineWinsAll"; + achievementTypeMap[ Common::Achievement::Type::AetherCurrent ] = "AetherCurrent"; + + std::stringstream achvOutputStream; + + achvOutputStream << "| ID | Name | Type (Subtype) | Description |" << std::endl + << "| --- | --- | --- | --- |" << std::endl; + + auto total = idList.size(); + int cursor = 0; + + for( auto id : idList ) + { + auto done = ( cursor++ / static_cast< float >( total ) ) * 100.f; + if( cursor % 50 == 0 && cursor > 0 ) + Logger::info( "Processing {} achievements of {} ({:.2f}%)", cursor, total, done ); + + auto pAchv = g_exdDataGen.getRow< Excel::Achievement >( id ); + + if( pAchv ) + { + auto& achvData = pAchv->data(); + + auto achvType = static_cast< Common::Achievement::Type >( achvData.ConditionType ); + std::string type = std::to_string( achvData.ConditionType ); + + // verify if achievement type has already been added + if( achvType == Common::Achievement::Type::General || + achvType == Common::Achievement::Type::Classjob || + achvType == Common::Achievement::Type::InstanceContent ) + { + type = std::to_string( achvData.ConditionType ) + ", " + std::to_string( achvData.ConditionArg[ 0 ] ); + } + + auto name = pAchv->getString( achvData.Text.Name ); + auto desc = pAchv->getString( achvData.Text.Help ); + + // ID + achvOutputStream << "| " << std::to_string( id ) << " | "; + + // name + achvOutputStream << name << " | "; + + // type (+subtype) + achvOutputStream << achievementTypeMap[ achvType ] << " (" << type << ") | "; + + // desc + achvOutputStream << desc << " |" << std::endl; + } + } + + Logger::info( achvOutputStream.str() ); + std::ofstream outH( "generated/achievement.txt" ); + outH << achvOutputStream.str() << std::endl; + outH.close(); + } + + + return 0; +} diff --git a/src/world/Network/Handlers/GMCommandHandlers.cpp b/src/world/Network/Handlers/GMCommandHandlers.cpp index 33bb292f..ea7bcf27 100644 --- a/src/world/Network/Handlers/GMCommandHandlers.cpp +++ b/src/world/Network/Handlers/GMCommandHandlers.cpp @@ -471,7 +471,7 @@ void Sapphire::Network::GameConnection::gmCommandHandler( const Packets::FFXIVAR { server.queueForPlayer( player.getCharacterId(), std::make_shared< ActorControlSelfPacket >( player.getId(), ActorControlType::ToggleWireframeRendering ) ); - PlayerMgr::sendServerNotice( player, "Wireframe Rendering for {0} was toggled", player.getName()); + PlayerMgr::sendServerNotice( player, "Wireframe Rendering for {0} was toggled", player.getName() ); break; } case GmCommand::Teri: