1
Fork 0
mirror of https://github.com/SapphireServer/Sapphire.git synced 2025-04-27 14:57:44 +00:00

quest parser improvements

- add actor and item names as comments
- add actor positions as comments (bnpc/eobj teris may be inaccurate)
- sort script entities properly with shameless natural sort steal
This commit is contained in:
Tahir 2023-01-20 05:16:00 +00:00
parent cb5f8067d6
commit 446228cc0d

View file

@ -5,6 +5,7 @@
#include <set> #include <set>
#include <string> #include <string>
#include <cstring> #include <cstring>
#include <unordered_map>
#include <filesystem> #include <filesystem>
@ -24,8 +25,8 @@ Sapphire::Data::ExdData g_exdDataGen;
namespace fs = std::filesystem; namespace fs = std::filesystem;
using namespace Sapphire; using namespace Sapphire;
std::string javaPath( "\"C:\\Program Files (x86)\\Java\\jre1.8.0_301\\bin\\java.exe\"" ); std::string javaPath("java " );
std::string gamePath( "F:\\client3.0\\game\\sqpack" ); std::string gamePath( "H:\\Games\\ffxiv3.05\\game\\sqpack" );
const std::string onWithinRangeStr( const std::string onWithinRangeStr(
" void onWithinRange( World::Quest& quest, Entity::Player& player, uint64_t eRangeId, float x, float y, float z ) override\n" " void onWithinRange( World::Quest& quest, Entity::Player& player, uint64_t eRangeId, float x, float y, float z ) override\n"
@ -39,6 +40,38 @@ const std::string onEmoteStr(
" }\n\n" " }\n\n"
); );
// https://stackoverflow.com/a/9745132
bool compareNat(const std::string& a, const std::string& b)
{
if (a.empty())
return true;
if (b.empty())
return false;
if (std::isdigit(a[0]) && !std::isdigit(b[0]))
return true;
if (!std::isdigit(a[0]) && std::isdigit(b[0]))
return false;
if (!std::isdigit(a[0]) && !std::isdigit(b[0]))
{
if (std::toupper(a[0]) == std::toupper(b[0]))
return compareNat(a.substr(1), b.substr(1));
return (std::toupper(a[0]) < std::toupper(b[0]));
}
std::istringstream issa(a);
std::istringstream issb(b);
int ia, ib;
issa >> ia;
issb >> ib;
if (ia != ib)
return ia < ib;
std::string anew, bnew;
std::getline(issa, anew);
std::getline(issb, bnew);
return (compareNat(anew, bnew));
}
std::string titleCase( const std::string& str ) std::string titleCase( const std::string& str )
{ {
if( str.empty() ) if( str.empty() )
@ -99,6 +132,117 @@ Container& split(
return result; return result;
} }
const std::string& getItemNameFromExd( uint32_t id )
{
static std::unordered_map< uint32_t, std::string > itemNames;
static std::string invalid;
if( itemNames.empty() )
{
auto nameIdList = g_exdDataGen.getIdList< Excel::Item >();
for( auto id : nameIdList )
{
auto itemName = g_exdDataGen.getRow< Excel::Item >( id );
if( itemName && !itemName->getString( itemName->data().Text.SGL ).empty() )
itemNames[id] = itemName->getString( itemName->data().Text.SGL );
}
}
if( auto name = itemNames.find( id ); name != itemNames.end() )
return name->second;
return invalid;
}
const std::string& getActorPosFromLevelExd( uint32_t id )
{
static std::unordered_map< uint32_t, std::string > levelPositions;
static std::string invalid;
if( levelPositions.empty() )
{
auto levelIdList = g_exdDataGen.getIdList< Excel::Level >();
for( auto id : levelIdList )
{
auto levelRow = g_exdDataGen.getRow< Excel::Level >( id );
if( levelRow )
{
auto assetType = levelRow->data().eAssetType;
// enpc, bnpc, eobj
if( assetType != 8 && assetType != 9 && assetType != 45 )
continue;
std::string pos(" ( Pos: ");
pos +=
std::to_string( levelRow->data().TransX ) + " " +
std::to_string( levelRow->data().TransY ) + " " +
std::to_string( levelRow->data().TransZ ) + " " +
"Teri: " + std::to_string( levelRow->data().TerritoryType ) + " )";
levelPositions.emplace( levelRow->data().BaseId, pos );
}
}
}
if( auto pos = levelPositions.find( id ); pos != levelPositions.end() )
return pos->second;
return invalid;
}
const std::string& getActorNameFromExd( uint32_t id )
{
static std::unordered_map< uint32_t, std::string > bnpcNames, enpcNames, eobjNames;
static std::string invalid;
// bnpc
if( id < 1000000 )
{
if( bnpcNames.empty() )
{
auto nameIdList = g_exdDataGen.getIdList< Excel::BNpcName >();
for( auto id : nameIdList )
{
auto BNpcName = g_exdDataGen.getRow< Excel::BNpcName >( id );
if( BNpcName && !BNpcName->getString( BNpcName->data().Text.SGL ).empty() )
bnpcNames[id] = BNpcName->getString( BNpcName->data().Text.SGL );
}
}
if( auto name = bnpcNames.find( id ); name != bnpcNames.end() )
return name->second;
}
// enpcresident
else if( id < 2000000 )
{
if( enpcNames.empty() )
{
auto nameIdList = g_exdDataGen.getIdList< Excel::ENpcResident >();
for( auto id : nameIdList )
{
auto eNpcName = g_exdDataGen.getRow< Excel::ENpcResident >( id );
if( eNpcName && !eNpcName->getString( eNpcName->data().Text.SGL ).empty() )
enpcNames[id] = eNpcName->getString( eNpcName->data().Text.SGL );
}
}
if( auto name = enpcNames.find( id ); name != enpcNames.end() )
return name->second;
}
// eobj
else
{
if( eobjNames.empty() )
{
auto nameIdList = g_exdDataGen.getIdList< Excel::EObj >();
for( auto id : nameIdList )
{
auto eObjName = g_exdDataGen.getRow< Excel::EObj >( id );
if( eObjName && !eObjName->getString( eObjName->data().Text.SGL ).empty() )
eobjNames[id] = eObjName->getString( eObjName->data().Text.SGL );
}
}
if( auto name = eobjNames.find( id ); name != eobjNames.end() )
return name->second;
}
return invalid;
}
void void
createScript( std::shared_ptr< Excel::ExcelStruct< Excel::Quest > >& pQuestData, std::set< std::string >& additionalList, int questId, std::vector< std::string >& functions ) createScript( std::shared_ptr< Excel::ExcelStruct< Excel::Quest > >& pQuestData, std::set< std::string >& additionalList, int questId, std::vector< std::string >& functions )
{ {
@ -152,11 +296,6 @@ createScript( std::shared_ptr< Excel::ExcelStruct< Excel::Quest > >& pQuestData,
std::size_t splitPos( pQuestData->getString( pQuestData->data().Script ).find( '_' ) ); std::size_t splitPos( pQuestData->getString( pQuestData->data().Script ).find( '_' ) );
std::string className( pQuestData->getString( pQuestData->data().Script ).substr( 0, splitPos ) ); std::string className( pQuestData->getString( pQuestData->data().Script ).substr( 0, splitPos ) );
if( className == "SubFst033" )
{
className = className;
}
std::string todoInfo; std::string todoInfo;
for( int i = 0; i < 23; ++i ) for( int i = 0; i < 23; ++i )
{ {
@ -181,8 +320,8 @@ createScript( std::shared_ptr< Excel::ExcelStruct< Excel::Quest > >& pQuestData,
std::string rewardString( std::string rewardString(
" if( result.getResult( 0 ) == 1 )\n" " if( result.getResult( 0 ) == 1 )\n"
" {\n" " {\n"
" if( player.giveQuestRewards( getId(), 0 ) )\n" " if( player.giveQuestRewards( getId(), 0, result.getResult( 1 ) )\n"
" player.finishQuest( getId() );\n" " player.finishQuest( getId(), result.getResult( 1 ) );\n"
" }\n" " }\n"
); );
@ -319,29 +458,43 @@ createScript( std::shared_ptr< Excel::ExcelStruct< Excel::Quest > >& pQuestData,
if( !name.empty() ) if( !name.empty() )
{ {
if( titleCaseNoUnderscores(name).substr( 0, 5 ) == "Actor" ) auto nameStripped = titleCaseNoUnderscores( name );
{ if( nameStripped.substr( 0, 5 ) == "Actor" )
actorList.push_back( titleCaseNoUnderscores( name ) ); actorList.push_back( titleCaseNoUnderscores( name ) );
std::transform( nameStripped.begin(), nameStripped.end(), nameStripped.begin(), ::tolower);
// comment actor names and positions if possible
if( nameStripped.find( "acto" ) != std::string::npos || nameStripped.find( "enemy" ) != std::string::npos
|| nameStripped.find( "eobj" ) != std::string::npos || nameStripped.find( "npc" ) != std::string::npos )
{
script_entities.push_back( name + " = " + std::to_string( pQuestData->data().Define[ ca ].Value ) + "; // " +
getActorNameFromExd( pQuestData->data().Define[ca].Value ) + getActorPosFromLevelExd( pQuestData->data().Define[ca].Value ) );
} }
script_entities.push_back( // comment item names
name + " = " + std::to_string( pQuestData->data().Define[ ca ].Value ) ); else if( nameStripped.find( "ritem" ) != std::string::npos )
{
script_entities.push_back( name + " = " + std::to_string( pQuestData->data().Define[ ca ].Value ) + "; // " + getItemNameFromExd( pQuestData->data().Define[ca].Value ) );
}
else
script_entities.push_back(
name + " = " + std::to_string( pQuestData->data().Define[ ca ].Value ) + ";");
} }
} }
std::sort( script_entities.begin(), script_entities.end() ); std::sort( script_entities.begin(), script_entities.end(), compareNat );
for( auto& entity : script_entities ) for( auto& entity : script_entities )
{ {
auto name = titleCaseNoUnderscores( entity ); auto name = titleCaseNoUnderscores( entity );
sentities += " static constexpr auto " + name + ";\n"; sentities += " static constexpr auto " + name + "\n";
} }
std::string additional = "// Quest Script: " + pQuestData->getString( pQuestData->data().Script ) + "\n"; std::string additional = "// Quest Script: " + pQuestData->getString( pQuestData->data().Script ) + "\n";
additional += "// Quest Name: " + pQuestData->getString( pQuestData->data().Text.Name ) + "\n"; additional += "// Quest Name: " + pQuestData->getString( pQuestData->data().Text.Name ) + "\n";
additional += "// Quest ID: " + std::to_string( questId ) + "\n"; additional += "// Quest ID: " + std::to_string( questId ) + "\n";
additional += "// Start NPC: " + std::to_string( pQuestData->data().Client ) + "\n"; additional += "// Start NPC: " + std::to_string( pQuestData->data().Client ) + " (" + getActorNameFromExd( pQuestData->data().Client ) + ")\n";
additional += "// End NPC: " + std::to_string( pQuestData->data().Finish ) + "\n\n"; additional += "// End NPC: " + std::to_string( pQuestData->data().Finish ) + " (" + getActorNameFromExd( pQuestData->data().Finish ) + ")\n\n";
additional += "using namespace Sapphire;\n\n"; additional += "using namespace Sapphire;\n\n";
@ -598,7 +751,7 @@ int main( int argc, char** argv )
offset += static_cast< uint32_t >( entry.size() + 1 ); offset += static_cast< uint32_t >( entry.size() + 1 );
if( entry.size() > 3 if( entry.size() > 3
&& entry.find_first_not_of( "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890_-" ) == && entry.find_first_not_of( "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-" ) ==
std::string::npos ) std::string::npos )
{ {
if( entry.find( "SEQ" ) != std::string::npos if( entry.find( "SEQ" ) != std::string::npos