2017-12-17 10:37:29 +00:00
# include <cstdint>
# include <fstream>
2017-08-08 13:53:47 +02:00
# include <iostream>
2017-12-17 10:37:29 +00:00
# include <locale>
2017-08-08 13:53:47 +02:00
# include <set>
2017-12-17 10:37:29 +00:00
# include <string>
2017-12-16 13:13:49 +00:00
# include <boost/algorithm/string.hpp>
# include <boost/filesystem.hpp>
2017-08-08 13:53:47 +02:00
2017-12-17 10:37:29 +00:00
# include <Exd.h>
# include <ExdCat.h>
# include <ExdData.h>
# include <File.h>
# include <GameData.h>
# include <DatCat.h>
# include <src/servers/Server_Common/Exd/ExdData.h>
# include <src/servers/Server_Common/Logging/Logger.h>
2017-08-08 13:53:47 +02:00
Core : : Logger g_log ;
Core : : Data : : ExdData g_exdData ;
2017-12-16 13:13:49 +00:00
const std : : string onTalkStr (
2017-12-17 10:37:29 +00:00
" void onTalk( uint32_t eventId, Entity::Player& player, uint64_t actorId ) override \n "
2017-12-16 13:13:49 +00:00
" { \n "
" auto actor = Core::Event::mapEventActorToRealActor( actorId ); \n "
" } \n \n "
) ;
const std : : string onWithinRangeStr (
2017-12-17 10:37:29 +00:00
" void onWithinRange( uint32_t eventId, Entity::Player& player, uint64_t eRangeId, float x, float y, float z ) override \n "
2017-12-16 13:13:49 +00:00
" { \n "
" } \n \n "
) ;
const std : : string onEmoteStr (
2017-12-17 10:37:29 +00:00
" void onEmote( uint32_t eventId, Entity::Player& player, uint64_t actorId, uint32_t emoteId ) override \n "
2017-12-16 13:13:49 +00:00
" { \n "
" } \n \n "
) ;
std : : string titleCase ( const std : : string & str )
{
if ( str . empty ( ) )
return str ;
std : : string retStr ( str ) ;
std : : transform ( str . begin ( ) , str . end ( ) , retStr . begin ( ) , : : tolower ) ;
std : : locale loc ;
retStr [ 0 ] = std : : toupper ( str [ 0 ] , loc ) ;
for ( size_t i = 1 ; i < str . size ( ) ; + + i )
{
if ( str [ i - 1 ] = = ' ' | | str [ i - 1 ] = = ' _ ' | | ( std : : isdigit ( str [ i - 1 ] , loc ) & & ! std : : isdigit ( str [ i ] , loc ) ) )
retStr [ i ] = std : : toupper ( str [ i ] , loc ) ;
}
return retStr ;
}
2017-08-08 13:53:47 +02:00
2017-12-16 13:13:49 +00:00
void createScript ( boost : : shared_ptr < Core : : Data : : QuestInfo > & pQuestData , std : : set < std : : string > & additionalList )
2017-08-08 13:53:47 +02:00
{
std : : string header (
2017-12-16 13:13:49 +00:00
" // This is an automatically generated C++ script template \n "
2017-08-08 13:53:47 +02:00
" // Content needs to be added by hand to make it function \n "
2017-12-16 13:13:49 +00:00
" // In order for this script to be loaded, change its extension to .cpp \n "
" // and move it to the correct folder in <root>/scripts/native/ \n "
2017-08-08 13:53:47 +02:00
" \n "
2017-12-16 13:13:49 +00:00
" #include <ScriptObject.h> \n \n "
2017-08-08 13:53:47 +02:00
) ;
2017-12-16 13:13:49 +00:00
std : : size_t splitPos ( pQuestData - > name_intern . find ( " _ " ) ) ;
std : : string className ( pQuestData - > name_intern . substr ( 0 , splitPos ) ) ;
//className = "Quest" + className;
std : : string sceneStr ( " ////////////////////////////////////////////////////////////////////// \n // Available Scenes in this quest, not necessarly all are used \n " ) ;
std : : string seqStr ;
seqStr . reserve ( 0xFFF ) ;
seqStr + = ( " // Steps in this quest ( 0 is before accepting, \n // 1 is first, 255 means ready for turning it in \n " ) ;
std : : string questVarStr ( " // Quest vars / flags used \n " ) ;
2017-08-08 13:53:47 +02:00
2017-12-16 13:13:49 +00:00
seqStr + = " enum Sequence : uint8_t \n { \n " ;
2017-08-08 13:53:47 +02:00
for ( auto & entry : additionalList )
{
if ( entry . find ( " OnScene " ) ! = std : : string : : npos )
{
std : : string sceneName = entry . substr ( 2 ) ;
std : : string sceneId = entry . substr ( 7 ) ;
std : : size_t numOff = sceneId . find_first_not_of ( " 0 " ) ;
sceneId = numOff ! = std : : string : : npos ? sceneId . substr ( numOff ) : " 0 " ;
2017-12-16 13:13:49 +00:00
sceneStr + = std : : string (
" void " +
sceneName +
" ( Entity::Player& player ) \n "
" { \n "
" player.eventPlay( this->getId(), " +
sceneId +
" , 0, \n "
" [&]( Entity::Player& player, uint32_t eventId, uint16_t param1, uint16_t param2, uint16_t param3 ) \n "
" { \n "
" }); \n "
" } \n \n "
) ;
2017-08-08 13:53:47 +02:00
}
else if ( entry . find ( " Flag " ) ! = std : : string : : npos | |
entry . find ( " QuestUI " ) ! = std : : string : : npos )
{
2017-12-16 13:13:49 +00:00
questVarStr + = " // " + entry + " \n " ;
2017-08-08 13:53:47 +02:00
}
else if ( entry . find ( " SEQ " ) ! = std : : string : : npos )
{
if ( entry . find ( " SEQ_FINISH " ) ! = std : : string : : npos )
{
2017-12-16 13:13:49 +00:00
seqStr + = " SeqFinish = 255, \n " ;
2017-08-08 13:53:47 +02:00
}
else if ( entry . find ( " SEQ_OFFER " ) ! = std : : string : : npos )
{
}
else
{
2017-12-16 13:13:49 +00:00
std : : string seqName = titleCase ( entry ) ;
boost : : replace_all ( seqName , " _ " , " " ) ;
2017-08-08 13:53:47 +02:00
std : : string seqId = entry . substr ( 4 ) ;
2017-12-16 13:13:49 +00:00
seqStr + = " " + seqName + " = " + seqId + " , \n " ;
2017-08-08 13:53:47 +02:00
}
}
}
2017-12-16 13:13:49 +00:00
seqStr + = " }; \n " ;
std : : string rewards ;
rewards . reserve ( 0xFFF ) ;
rewards + = " // Quest rewards \n " ;
rewards + = ( pQuestData - > reward_exp_factor ! = 0 ) ? " static constexpr auto RewardExpFactor = " + std : : to_string ( pQuestData - > reward_exp_factor ) + " ; \n " : " " ;
rewards + = ( pQuestData - > reward_gil ! = 0 ) ? " static constexpr auto RewardGil = " + std : : to_string ( pQuestData - > reward_gil ) + " ; \n " : " " ;
rewards + = ( pQuestData - > reward_emote ! = 0 ) ? " static constexpr auto RewardEmote = " + std : : to_string ( pQuestData - > reward_emote ) + " ; \n " : " " ;
rewards + = ( pQuestData - > reward_action ! = 0 ) ? " static constexpr auto RewardAction = " + std : : to_string ( pQuestData - > reward_action ) + " ; \n " : " " ;
rewards + = ( pQuestData - > reward_action_general1 ! = 0 ) ? " static constexpr auto RewardGeneralAction1 = " + std : : to_string ( pQuestData - > reward_action_general1 ) + " ; \n " : " " ;
rewards + = ( pQuestData - > reward_action_general2 ! = 0 ) ? " static constexpr auto RewardGeneralAction2 = " + std : : to_string ( pQuestData - > reward_action_general2 ) + " ; \n " : " " ;
rewards + = ( pQuestData - > reward_gc_seals ! = 0 ) ? " static constexpr auto RewardGCSeals = " + std : : to_string ( pQuestData - > reward_gc_seals ) + " ; \n " : " " ;
rewards + = ( pQuestData - > reward_other ! = 0 ) ? " static constexpr auto RewardOther = " + std : : to_string ( pQuestData - > reward_other ) + " ; \n " : " " ;
rewards + = ( pQuestData - > reward_reputation ! = 0 ) ? " static constexpr auto RewardReputation = " + std : : to_string ( pQuestData - > reward_reputation ) + " ; \n " : " " ;
rewards + = ( pQuestData - > reward_tome_type ! = 0 ) ? " static constexpr auto RewardTomeType = " + std : : to_string ( pQuestData - > reward_tome_type ) + " ; \n " : " " ;
rewards + = ( pQuestData - > reward_tome_count ! = 0 ) ? " static constexpr auto RewardTomeCount = " + std : : to_string ( pQuestData - > reward_tome_count ) + " ; \n " : " " ;
rewards + = ( pQuestData - > instanced_content_unlock ! = 0 ) ? " static constexpr auto InstancedContentUnlock = " + std : : to_string ( pQuestData - > instanced_content_unlock ) + " ; \n " : " " ;
2017-08-08 13:53:47 +02:00
if ( pQuestData - > reward_item . size ( ) > 0 )
{
2017-12-16 13:13:49 +00:00
rewards + = " static constexpr auto RewardItem[] = { " ;
2017-10-19 07:12:09 -07:00
for ( size_t ca = 0 ; ca < pQuestData - > reward_item . size ( ) ; ca + + )
2017-08-08 13:53:47 +02:00
{
rewards + = std : : to_string ( pQuestData - > reward_item . at ( ca ) ) ;
if ( ca ! = pQuestData - > reward_item . size ( ) - 1 )
{
rewards + = " , " ;
}
}
2017-12-16 13:13:49 +00:00
rewards + = " }; \n " ;
2017-08-08 13:53:47 +02:00
}
if ( pQuestData - > reward_item . size ( ) > 0 )
{
2017-12-16 13:13:49 +00:00
rewards + = " static constexpr auto RewardItemCount[] = { " ;
2017-10-19 07:12:09 -07:00
for ( size_t ca = 0 ; ca < pQuestData - > reward_item_count . size ( ) ; ca + + )
2017-08-08 13:53:47 +02:00
{
rewards + = std : : to_string ( pQuestData - > reward_item_count . at ( ca ) ) ;
if ( ca ! = pQuestData - > reward_item_count . size ( ) - 1 )
{
rewards + = " , " ;
}
}
2017-12-16 13:13:49 +00:00
rewards + = " }; \n " ;
2017-08-08 13:53:47 +02:00
}
if ( pQuestData - > reward_item_optional . size ( ) > 0 )
{
2017-12-16 13:13:49 +00:00
rewards + = " static constexpr auto RewardItemOptional[] = { " ;
2017-10-19 07:12:09 -07:00
for ( size_t ca = 0 ; ca < pQuestData - > reward_item_optional . size ( ) ; ca + + )
2017-08-08 13:53:47 +02:00
{
rewards + = std : : to_string ( pQuestData - > reward_item_optional . at ( ca ) ) ;
if ( ca ! = pQuestData - > reward_item_optional . size ( ) - 1 )
{
rewards + = " , " ;
}
}
2017-12-16 13:13:49 +00:00
rewards + = " }; \n " ;
2017-08-08 13:53:47 +02:00
}
if ( pQuestData - > reward_item_optional_count . size ( ) > 0 )
{
2017-12-16 13:13:49 +00:00
rewards + = " static constexpr auto RewardItemOptionalCount[] = { " ;
2017-10-19 07:12:09 -07:00
for ( size_t ca = 0 ; ca < pQuestData - > reward_item_optional_count . size ( ) ; ca + + )
2017-08-08 13:53:47 +02:00
{
rewards + = std : : to_string ( pQuestData - > reward_item_optional_count . at ( ca ) ) ;
if ( ca ! = pQuestData - > reward_item_optional_count . size ( ) - 1 )
{
rewards + = " , " ;
}
}
2017-12-16 13:13:49 +00:00
rewards + = " }; \n " ;
2017-08-08 13:53:47 +02:00
}
bool hasERange = false ;
bool hasEmote = false ;
bool hasEnemies = false ;
std : : vector < uint32_t > enemy_ids ;
std : : vector < std : : string > script_entities ;
2017-12-16 13:13:49 +00:00
std : : string sentities = " // Entities found in the script data of the quest \n " ;
2017-10-19 07:12:09 -07:00
for ( size_t ca = 0 ; ca < pQuestData - > script_entity . size ( ) ; ca + + )
2017-08-08 13:53:47 +02:00
{
if ( ( pQuestData - > script_entity . at ( ca ) . find ( " HOWTO " ) ! = std : : string : : npos ) | | ( pQuestData - > script_entity . at ( ca ) . find ( " HOW_TO " ) ! = std : : string : : npos ) )
continue ;
2017-12-16 13:13:49 +00:00
if ( ( pQuestData - > script_entity . at ( ca ) . find ( " EMOTENO " ) ! = std : : string : : npos ) | | ( pQuestData - > script_entity . at ( ca ) . find ( " EMOTEOK " ) ! = std : : string : : npos ) )
2017-08-08 13:53:47 +02:00
hasEmote = true ;
2017-12-16 13:13:49 +00:00
if ( pQuestData - > script_entity . at ( ca ) . find ( " ENEMY " ) ! = std : : string : : npos )
2017-08-08 13:53:47 +02:00
{
hasEnemies = true ;
2017-12-16 13:13:49 +00:00
enemy_ids . push_back ( pQuestData - > script_value . at ( ca ) ) ;
2017-08-08 13:53:47 +02:00
}
2017-12-16 13:13:49 +00:00
script_entities . push_back ( pQuestData - > script_entity . at ( ca ) + " = " + std : : to_string ( pQuestData - > script_value . at ( ca ) ) ) ;
2017-08-08 13:53:47 +02:00
}
std : : sort ( script_entities . begin ( ) , script_entities . end ( ) ) ;
for ( auto & entity : script_entities )
{
2017-12-16 13:13:49 +00:00
auto name = titleCase ( entity ) ;
boost : : replace_all ( name , " _ " , " " ) ;
sentities + = " static constexpr auto " + name + " ; \n " ;
2017-08-08 13:53:47 +02:00
}
std : : string additional = " // Quest Script: " + pQuestData - > name_intern + " \n " ;
additional + = " // Quest Name: " + pQuestData - > name + " \n " ;
additional + = " // Quest ID: " + std : : to_string ( pQuestData - > id ) + " \n " ;
additional + = " // Start NPC: " + std : : to_string ( pQuestData - > enpc_resident_start ) + " \n " ;
additional + = " // End NPC: " + std : : to_string ( pQuestData - > enpc_resident_end ) + " \n \n " ;
2017-12-16 13:13:49 +00:00
std : : string scriptEntry ;
scriptEntry . reserve ( 0xFFFF ) ;
scriptEntry + = " ////////////////////////////////////////////////////////////////////// \n // Event Handlers \n " ;
scriptEntry + = onTalkStr ;
2017-08-08 13:53:47 +02:00
if ( hasERange )
{
2017-12-17 10:37:29 +00:00
scriptEntry + = onWithinRangeStr ;
2017-08-08 13:53:47 +02:00
}
2017-12-16 13:13:49 +00:00
2017-08-08 13:53:47 +02:00
if ( hasEmote )
{
2017-12-17 10:37:29 +00:00
scriptEntry + = onEmoteStr ;
2017-08-08 13:53:47 +02:00
}
for ( auto enemy : enemy_ids )
{
2017-12-16 13:13:49 +00:00
scriptEntry + = std : : string (
" void onMobKill_ " + std : : to_string ( enemy ) + " ( Entity::Player& player ) \n "
" { \n "
" } \n \n "
) ;
2017-08-08 13:53:47 +02:00
}
2017-12-16 13:13:49 +00:00
2017-08-08 13:53:47 +02:00
std : : string constructor ;
2017-12-16 13:13:49 +00:00
constructor + = std : : string (
" private: \n "
" // Basic quest information \n " ) ;
2017-08-08 13:53:47 +02:00
constructor + = questVarStr + " \n " ;
constructor + = seqStr + " \n " ;
constructor + = rewards + " \n " ;
constructor + = sentities + " \n " ;
2017-12-16 13:13:49 +00:00
constructor + = " public: \n " ;
constructor + = " " + className + " () : EventScript " + " ( \" " + pQuestData - > name + " \" , " + std : : to_string ( pQuestData - > id ) + " ){}; \n " ;
constructor + = " ~ " + className + " (){}; \n " ;
2017-08-08 13:53:47 +02:00
std : : string classString (
2017-12-16 13:13:49 +00:00
" class " + className + " : public EventScript \n "
" { \n " +
constructor +
" \n " +
2017-08-08 13:53:47 +02:00
scriptEntry +
2017-12-17 10:37:29 +00:00
" private: \n " +
sceneStr +
2017-08-08 13:53:47 +02:00
" }; \n \n "
) ;
2017-12-16 13:13:49 +00:00
std : : string initObj ( " EXPORT_SCRIPTOBJECT( " + className + " ); " ) ;
2017-08-08 13:53:47 +02:00
std : : ofstream outputFile ;
2017-12-16 13:13:49 +00:00
outputFile . open ( " generated/ " + className + " .cpp_generated " ) ;
2017-08-08 13:53:47 +02:00
outputFile < < header < < additional < < classString < < initObj ;
outputFile . close ( ) ;
}
2017-12-16 13:13:49 +00:00
int main ( int argc , char * * argv )
2017-08-08 13:53:47 +02:00
{
g_log . init ( ) ;
2017-12-16 13:13:49 +00:00
bool unluac = false ;
2017-08-08 13:53:47 +02:00
// std::string datLocation( "/opt/sapphire_3_15_0/bin/sqpack" );
2017-12-16 13:13:49 +00:00
std : : string datLocation ( " C:/Program Files (x86)/SquareEnix/FINAL FANTASY XIV - A Realm Reborn/game/sqpack/ffxiv " ) ;
if ( argc > 1 )
datLocation = std : : string ( argv [ 1 ] ) ;
if ( argc > 2 )
unluac = ( bool ) atoi ( argv [ 2 ] ) ;
2017-08-08 13:53:47 +02:00
g_log . info ( " Setting up EXD data " ) ;
if ( ! g_exdData . init ( datLocation ) )
{
2017-12-16 13:13:49 +00:00
std : : cout < < datLocation < < " \n " ;
2017-08-08 13:53:47 +02:00
g_log . fatal ( " Error setting up EXD data " ) ;
2017-12-16 13:13:49 +00:00
std : : cout < < " Usage: quest_parser \" path/to/ffxiv/game/sqpack \" <1/0 unluac export toggle> \n " ;
2017-08-08 13:53:47 +02:00
return 0 ;
}
xiv : : dat : : GameData data ( datLocation ) ;
xiv : : exd : : ExdData eData ( data ) ;
auto QuestDat = g_exdData . setupDatAccess ( " Quest " , xiv : : exd : : Language : : en ) ;
auto rows = QuestDat . get_rows ( ) ;
2017-12-16 13:13:49 +00:00
if ( ! boost : : filesystem : : exists ( " ./generated " ) )
boost : : filesystem : : create_directory ( " ./generated " ) ;
std : : cout < < " Export in progress " ;
uint32_t updateInterval = rows . size ( ) / 20 ;
uint32_t i = 0 ;
for ( const auto & row : rows )
2017-08-08 13:53:47 +02:00
{
auto questInfo = g_exdData . getQuestInfo ( row . first ) ;
if ( questInfo - > name . empty ( ) | | questInfo - > name_intern . empty ( ) )
{
continue ;
}
size_t pos_seperator = questInfo - > name_intern . find_first_of ( " _ " ) ;
std : : string folder ;
if ( pos_seperator ! = std : : string : : npos )
{
folder = questInfo - > name_intern . substr ( pos_seperator + 1 , 3 ) ;
}
else
{
return 0 ;
}
const xiv : : dat : : Cat & test = data . get_category ( " game_script " ) ;
const std : : string questPath = " game_script/quest/ " + folder + " / " + questInfo - > name_intern + " .luab " ;
const auto & test_file = data . get_file ( questPath ) ;
auto & section = test_file - > access_data_sections ( ) . at ( 0 ) ;
int32_t size = * ( uint32_t * ) & section [ 4 ] ;
std : : set < std : : string > stringList ;
uint32_t offset = 0 ;
std : : ofstream outputFile1 ;
2017-12-16 13:13:49 +00:00
outputFile1 . open ( " generated/ " + questInfo - > name_intern + " .luab " , std : : ios : : binary ) ;
outputFile1 . write ( & section [ 0 ] , section . size ( ) ) ;
2017-08-08 13:53:47 +02:00
outputFile1 . close ( ) ;
2017-12-16 13:13:49 +00:00
if ( unluac )
2017-11-01 22:24:50 -07:00
{
2017-12-16 13:13:49 +00:00
std : : string command = std : : string ( " java -jar unluac_2015_06_13.jar " ) + " generated/ " + questInfo - > name_intern + " .luab " + " >> " + " generated/ " + questInfo - > name_intern + " .lua " ;
if ( system ( command . c_str ( ) ) = = - 1 )
{
g_log . error ( " Error executing java command: \n " + command + " \n errno: " + std : : strerror ( errno ) ) ;
return errno ;
}
2017-11-01 22:24:50 -07:00
}
2017-08-08 13:53:47 +02:00
for ( ; ; )
{
2017-12-16 13:13:49 +00:00
2017-08-08 13:53:47 +02:00
std : : string entry ( & section [ offset ] ) ;
offset + = entry . size ( ) + 1 ;
2017-12-16 13:13:49 +00:00
if ( entry . size ( ) > 3
& & entry . find_first_not_of ( " abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890_- " ) = = std : : string : : npos )
2017-08-08 13:53:47 +02:00
{
if ( entry . find ( " SEQ " ) ! = std : : string : : npos
| | entry . find ( " QuestUI " ) ! = std : : string : : npos
| | entry . find ( " OnScene " ) ! = std : : string : : npos
| | entry . find ( " Flag " ) ! = std : : string : : npos
| | entry . find ( " ACTOR " ) ! = std : : string : : npos
& & entry . find ( " _ACTOR " ) = = std : : string : : npos )
if ( entry . find ( " HOWTO " ) = = std : : string : : npos )
stringList . insert ( entry ) ;
}
if ( offset > = section . size ( ) )
break ;
}
createScript ( questInfo , stringList ) ;
2017-12-16 13:13:49 +00:00
+ + i ;
if ( i % updateInterval = = 0 )
std : : cout < < " . " ;
2017-08-08 13:53:47 +02:00
//break;
}
2017-12-16 13:13:49 +00:00
std : : cout < < " \n Done! " ;
2017-08-08 13:53:47 +02:00
return 0 ;
}