From f0b888a4a3bd99b57b44df8375a3935af3b8aaef Mon Sep 17 00:00:00 2001 From: Tahir Akhlaq Date: Wed, 24 Jan 2018 15:34:01 +0000 Subject: [PATCH] added planmap loading to pcb_reader --- src/tools/pcb_reader/lgb.h | 37 +++---- src/tools/pcb_reader/main.cpp | 182 +++++++++++++++++++--------------- src/tools/pcb_reader/sgb.h | 10 +- 3 files changed, 125 insertions(+), 104 deletions(-) diff --git a/src/tools/pcb_reader/lgb.h b/src/tools/pcb_reader/lgb.h index 4354ca55..94fbfa20 100644 --- a/src/tools/pcb_reader/lgb.h +++ b/src/tools/pcb_reader/lgb.h @@ -60,6 +60,16 @@ enum class LgbEntryType : uint32_t SphereCastRange = 75, }; +struct LGB_ENTRY_HEADER +{ + LgbEntryType type; + uint32_t unknown; + uint32_t nameOffset; + vec3 translation; + vec3 rotation; + vec3 scale; +}; + class LGB_MODEL_ENTRY { public: @@ -80,14 +90,8 @@ public: }; -struct LGB_BGPARTS_HEADER +struct LGB_BGPARTS_HEADER : public LGB_ENTRY_HEADER { - LgbEntryType type; - uint32_t unknown2; - uint32_t nameOffset; - vec3 translation; - vec3 rotation; - vec3 scale; uint32_t modelFileOffset; uint32_t collisionFileOffset; uint32_t unknown4; @@ -112,22 +116,9 @@ public: name = std::string( buf + offset + header.nameOffset ); modelFileName = std::string( buf + offset + header.modelFileOffset ); collisionFileName = std::string( buf + offset + header.collisionFileOffset ); - //std::cout << "BGPARTS_ENTRY " << name << "\n"; - //std::cout << " " << modelFileName << "\n"; - //std::cout << " " << collisionFileName << "\n"; }; }; -struct LGB_ENTRY_HEADER -{ - LgbEntryType type; - uint32_t unknown; - uint32_t nameOffset; - vec3 translation; - vec3 rotation; - vec3 scale; -}; - struct LGB_GIMMICK_HEADER : public LGB_ENTRY_HEADER { uint32_t gimmickFileOffset; @@ -146,6 +137,7 @@ public: header = *reinterpret_cast( buf + offset ); name = std::string( buf + offset + header.nameOffset ); gimmickFileName = std::string( buf + offset + header.gimmickFileOffset ); + //std::cout << "\t " << gimmickFileName << " unknown: " << header.unknown << "\n"; }; }; @@ -165,6 +157,7 @@ public: { header = *reinterpret_cast< LGB_ENPC_HEADER* >( buf + offset ); name = std::string( buf + offset + header.nameOffset ); + //std::cout << "\t ENpc " << header.enpcId << " " << name << "\n"; }; }; @@ -183,7 +176,7 @@ public: LGB_EOBJ_ENTRY( char* buf, uint32_t offset ) { header = *reinterpret_cast< LGB_EOBJ_HEADER* >( buf + offset ); - std::cout << header.eobjId << std::endl; + //std::cout << "\t " << header.eobjId << " " << name << " unknown: " << header.unknown << "\n"; name = std::string( buf + offset + header.nameOffset ); }; }; @@ -218,7 +211,7 @@ struct LGB_GROUP header = *reinterpret_cast< LGB_GROUP_HEADER* >( buf + offset ); name = std::string( buf + offset + header.groupNameOffset ); //entries.resize( header.entryCount ); - std::cout << name << std::endl; + //std::cout << name << "\n\t unknown: " << header.unknown << "\n"; const auto entriesOffset = offset + header.entriesOffset; for( auto i = 0; i < header.entryCount; ++i ) { diff --git a/src/tools/pcb_reader/main.cpp b/src/tools/pcb_reader/main.cpp index 7448da38..2a5d5c61 100644 --- a/src/tools/pcb_reader/main.cpp +++ b/src/tools/pcb_reader/main.cpp @@ -23,6 +23,8 @@ std::string gamePath("C:\\Program Files (x86)\\SquareEnix\\FINAL FANTASY XIV - A Realm Reborn\\game\\sqpack\\ffxiv"); std::unordered_map< uint32_t, std::string > eobjNameMap; +xiv::dat::GameData* data1 = nullptr; +xiv::exd::ExdData* eData = nullptr; enum class TerritoryTypeExdIndexes : size_t { @@ -37,6 +39,12 @@ struct face int32_t f1, f2, f3; }; +void initExd( const std::string& gamePath ) +{ + data1 = data1 ? data1 : new xiv::dat::GameData( gamePath ); + eData = eData ? eData : new xiv::exd::ExdData( *data1 ); +} + int parseBlockEntry( char* data, std::vector& entries, int gOff ) { int offset = 0; @@ -95,14 +103,12 @@ int parseBlockEntry( char* data, std::vector& entries, int gOff void dumpLevelExdEntries( uint32_t zoneId, const std::string& name = std::string() ) { - xiv::dat::GameData dat( gamePath ); - xiv::exd::ExdData eData( dat ); - auto& cat = eData.get_category( "Level" ); + auto& cat = eData->get_category( "Level" ); auto exd = static_cast< xiv::exd::Exd >( cat.get_data_ln( xiv::exd::Language::none ) ); std::string fileName( name + "_" + std::to_string( zoneId ) + "_Level" + ".csv" ); std::ofstream outfile( fileName, std::ios::trunc ); - + std::cout << "[Info] Writing level.exd entries to " << fileName << "\n"; if( outfile.good() ) { outfile.close(); @@ -198,9 +204,7 @@ std::string zoneNameToPath( const std::string& name ) void loadEobjNames() { - xiv::dat::GameData dat( gamePath ); - xiv::exd::ExdData eData( dat ); - auto& cat = eData.get_category( "EObjName" ); + auto& cat = eData->get_category( "EObjName" ); auto exd = static_cast< xiv::exd::Exd >( cat.get_data_ln( xiv::exd::Language::en ) ); for( auto& row : exd.get_rows() ) { @@ -244,7 +248,6 @@ int main( int argc, char* argv[] ) // todo: support expansions std::string zoneName = "r1f1"; - if( argc > 1 ) { zoneName = argv[1]; @@ -254,24 +257,28 @@ int main( int argc, char* argv[] ) } } + initExd( gamePath ); try { const auto& zonePath = zoneNameToPath( zoneName ); std::string listPcbPath( zonePath + "/collision/list.pcb" ); - std::string bgLgbPath( zonePath + "/level/planmap.lgb" ); + std::string bgLgbPath( zonePath + "/level/bg.lgb" ); + std::string planmapLgbPath( zonePath + "/level/planmap.lgb" ); std::string collisionFilePath( zonePath + "/collision/" ); std::vector< char > section; std::vector< char > section1; + std::vector< char > section2; #ifndef STANDALONE - xiv::dat::GameData data1( gamePath ); - xiv::exd::ExdData eData( data1 ); - const xiv::dat::Cat& test = data1.get_category( "bg" ); + const xiv::dat::Cat& test = data1->get_category( "bg" ); - auto test_file = data1.get_file( bgLgbPath ); + auto test_file = data1->get_file( bgLgbPath ); section = test_file->access_data_sections().at( 0 ); - auto test_file1 = data1.get_file( listPcbPath ); + auto planmap_file = data1->get_file( planmapLgbPath ); + section2 = planmap_file->access_data_sections().at( 0 ); + + auto test_file1 = data1->get_file( listPcbPath ); section1 = test_file1->access_data_sections().at( 0 ); #else { @@ -280,9 +287,6 @@ int main( int argc, char* argv[] ) } #endif - int32_t list_offset = *( uint32_t* )§ion[0x18]; - int32_t size = *( uint32_t* )§ion[4]; - std::vector< std::string > stringList; uint32_t offset1 = 0x20; @@ -314,6 +318,9 @@ int main( int argc, char* argv[] ) } LGB_FILE bgLgb( §ion[0] ); + LGB_FILE planmapLgb( §ion2[0] ); + + std::vector< LGB_FILE > lgbList { bgLgb, planmapLgb }; uint32_t max_index = 0; // dont bother if we cant write to a file @@ -342,10 +349,15 @@ int main( int argc, char* argv[] ) { try { + if( fileName.find( '.' ) == std::string::npos ) + return false; + else if( fileName.substr(fileName.find_last_of('.')) != ".pcb" ) + throw std::runtime_error( "Not a PCB file." ); + char* dataSection = nullptr; //std::cout << fileName << " "; #ifndef STANDALONE - auto file = data1.get_file( fileName ); + auto file = data1->get_file( fileName ); auto sections = file->get_data_sections(); dataSection = §ions.at( 0 )[0]; #else @@ -397,7 +409,7 @@ int main( int argc, char* argv[] ) char* dataSection = nullptr; //std::cout << fileName << " "; #ifndef STANDALONE - auto file = data1.get_file( fileName ); + auto file = data1->get_file( fileName ); auto sections = file->get_data_sections(); dataSection = §ions.at( 0 )[0]; #else @@ -508,80 +520,83 @@ int main( int argc, char* argv[] ) std::cout << "[Info] " << bgLgb.groups.size() << " groups " << "\n"; uint32_t totalGroups = 0; uint32_t totalGroupEntries = 0; - for( const auto& group : bgLgb.groups ) + + for( const auto& lgb : lgbList ) { - //std::cout << "\t" << group.name << " Size " << group.header.entryCount << "\n"; - totalGroups++; - for( const auto& pEntry : group.entries ) + for( const auto& group : bgLgb.groups ) { - auto pGimmick = dynamic_cast< LGB_GIMMICK_ENTRY* >( pEntry.get() ); - auto pBgParts = dynamic_cast< LGB_BGPARTS_ENTRY* >( pEntry.get() ); - auto pEventObj = dynamic_cast< LGB_EOBJ_ENTRY* >( pEntry.get() ); - - std::string fileName( "" ); - fileName.resize( 256 ); - totalGroupEntries++; - - // write files - auto writeOutput = [&]( const std::string& fileName, const vec3* scale, const vec3* rotation, const vec3* translation, const SGB_MODEL_ENTRY* pModel = nullptr) -> bool + //std::cout << "\t" << group.name << " Size " << group.header.entryCount << "\n"; + totalGroups++; + for( const auto& pEntry : group.entries ) { - { - const auto& it = pcbFiles.find( fileName ); - if( it == pcbFiles.end() ) - { - if( fileName.empty() || !loadPcbFile( fileName ) ) - return false; - //std::cout << "\t\tLoaded PCB File " << pBgParts->collisionFileName << "\n"; - } - } - const auto& it = pcbFiles.find( fileName ); - if( it != pcbFiles.end() ) - { - const auto& pcb_file = it->second; - pushVerts( pcb_file, fileName, scale, rotation, translation, pModel ); - } - return true; - }; + auto pGimmick = dynamic_cast< LGB_GIMMICK_ENTRY* >( pEntry.get() ); + auto pBgParts = dynamic_cast< LGB_BGPARTS_ENTRY* >( pEntry.get() ); + auto pEventObj = dynamic_cast< LGB_EOBJ_ENTRY* >( pEntry.get() ); - if( pBgParts ) - { - fileName = pBgParts->collisionFileName; - writeOutput( fileName, &pBgParts->header.scale, &pBgParts->header.rotation, &pBgParts->header.translation ); - } + std::string fileName( "" ); + fileName.resize( 256 ); + totalGroupEntries++; - // gimmick entry - if( pGimmick ) - { + // write files + auto writeOutput = [&]( const std::string& fileName, const vec3* scale, const vec3* rotation, const vec3* translation, const SGB_MODEL_ENTRY* pModel = nullptr) -> bool { - const auto& it = sgbFiles.find( pGimmick->gimmickFileName ); - if( it == sgbFiles.end() ) { - //std::cout << "\tGIMMICK:\n\t\t" << pGimmick->name << " " << pGimmick->gimmickFileName << "\n"; - loadSgbFile( pGimmick->gimmickFileName ); - } - } - const auto& it = sgbFiles.find( pGimmick->gimmickFileName ); - if( it != sgbFiles.end() ) - { - const auto& sgbFile = it->second; - - for( const auto& group : sgbFile.entries ) - { - for( const auto& pEntry : group.entries ) + const auto& it = pcbFiles.find( fileName ); + if( it == pcbFiles.end() ) { - auto pModel = dynamic_cast< SGB_MODEL_ENTRY* >( pEntry.get() ); - fileName = pModel->collisionFileName; - writeOutput( fileName, &pGimmick->header.scale, &pGimmick->header.rotation, &pGimmick->header.translation, pModel ); + if( fileName.empty() || !loadPcbFile( fileName ) ) + return false; + //std::cout << "\t\tLoaded PCB File " << pBgParts->collisionFileName << "\n"; + } + } + const auto& it = pcbFiles.find( fileName ); + if( it != pcbFiles.end() ) + { + const auto& pcb_file = it->second; + pushVerts( pcb_file, fileName, scale, rotation, translation, pModel ); + } + return true; + }; + + if( pBgParts ) + { + fileName = pBgParts->collisionFileName; + writeOutput( fileName, &pBgParts->header.scale, &pBgParts->header.rotation, &pBgParts->header.translation ); + } + + // gimmick entry + if( pGimmick ) + { + { + const auto& it = sgbFiles.find( pGimmick->gimmickFileName ); + if( it == sgbFiles.end() ) + { + // std::cout << "\tGIMMICK:\n\t\t" << pGimmick->gimmickFileName << "\n"; + loadSgbFile( pGimmick->gimmickFileName ); + } + } + const auto& it = sgbFiles.find( pGimmick->gimmickFileName ); + if( it != sgbFiles.end() ) + { + const auto& sgbFile = it->second; + for( const auto& group : sgbFile.entries ) + { + for( const auto& pEntry : group.entries ) + { + auto pModel = dynamic_cast< SGB_MODEL_ENTRY* >( pEntry.get() ); + fileName = pModel->collisionFileName; + writeOutput( fileName, &pGimmick->header.scale, &pGimmick->header.rotation, &pGimmick->header.translation, pModel ); + } } } } - } - if( pEventObj ) - { - fileName = pEventObj->name.empty() ? eobjNameMap[pEventObj->header.eobjId] : pEventObj->name; - writeEobjEntry( eobjOut, pEventObj, fileName ); - writeOutput( fileName, &pEventObj->header.scale, &pEventObj->header.rotation, &pEventObj->header.translation ); + if( pEventObj ) + { + fileName = pEventObj->name.empty() ? eobjNameMap[pEventObj->header.eobjId] : pEventObj->name; + writeEobjEntry( eobjOut, pEventObj, fileName ); + //writeOutput( fileName, &pEventObj->header.scale, &pEventObj->header.rotation, &pEventObj->header.translation ); + } } } } @@ -598,5 +613,10 @@ int main( int argc, char* argv[] ) std::cout << std::endl; std::cout << "[Info] " << "Usage: pcb_reader2 territory \"path/to/game/sqpack/ffxiv\" " << std::endl; } + + if( eData ) + delete eData; + if( data1 ) + delete data1; return 0; } diff --git a/src/tools/pcb_reader/sgb.h b/src/tools/pcb_reader/sgb.h index d989acab..edd6899a 100644 --- a/src/tools/pcb_reader/sgb.h +++ b/src/tools/pcb_reader/sgb.h @@ -78,7 +78,7 @@ public: virtual ~SGB_GROUP_ENTRY() {}; }; -struct SGB_MODEL_HEADER +struct SGB_ENTRY_HEADER { SgbGroupEntryType type; uint32_t unknown2; @@ -86,6 +86,10 @@ struct SGB_MODEL_HEADER vec3 translation; vec3 rotation; vec3 scale; +}; + +struct SGB_MODEL_HEADER : public SGB_ENTRY_HEADER +{ int32_t modelFileOffset; int32_t collisionFileOffset; }; @@ -132,6 +136,10 @@ struct SGB_GROUP { entries.push_back( std::make_shared< SGB_MODEL_ENTRY >( buf, entryOffset ) ); } + else + { + // std::cout << "\t\tUnknown SGB entry! Group: " << name << " type: " << type << " index: " << i << " entryOffset: " << entryOffset << "\n"; + } } } };