2017-10-12 09:02:28 +02:00
|
|
|
|
|
|
|
#include <GameData.h>
|
|
|
|
#include <File.h>
|
|
|
|
#include <DatCat.h>
|
|
|
|
#include <ExdData.h>
|
|
|
|
#include <ExdCat.h>
|
|
|
|
#include <Exd.h>
|
|
|
|
#include <Exh.h>
|
|
|
|
#include <iostream>
|
|
|
|
#include <cctype>
|
|
|
|
#include <set>
|
2018-03-06 22:22:19 +01:00
|
|
|
#include <Exd/ExdDataGenerated.h>
|
|
|
|
#include <Logging/Logger.h>
|
2017-10-12 09:02:28 +02:00
|
|
|
|
|
|
|
#include <fstream>
|
|
|
|
#include <streambuf>
|
|
|
|
#include <regex>
|
|
|
|
|
2019-04-11 19:06:27 +10:00
|
|
|
#include <Exd/StructureDef/pcb.h>
|
|
|
|
#include <Exd/StructureDef/lgb.h>
|
|
|
|
#include <Exd/StructureDef/sgb.h>
|
|
|
|
|
2019-03-26 23:09:07 +11:00
|
|
|
#include <Util/CrashHandler.h>
|
|
|
|
|
2019-04-11 19:06:27 +10:00
|
|
|
#include <experimental/filesystem>
|
|
|
|
|
2019-03-26 23:09:07 +11:00
|
|
|
Sapphire::Common::Util::CrashHandler crashHandler;
|
|
|
|
|
2018-11-29 16:55:48 +01:00
|
|
|
Sapphire::Data::ExdDataGenerated g_exdData;
|
2019-04-11 19:06:27 +10:00
|
|
|
xiv::dat::GameData* gameData = nullptr;
|
2017-10-12 09:02:28 +02:00
|
|
|
|
2018-12-23 03:53:08 +01:00
|
|
|
using namespace Sapphire;
|
2017-10-12 09:02:28 +02:00
|
|
|
|
2019-04-11 19:06:27 +10:00
|
|
|
namespace fs = std::experimental::filesystem;
|
|
|
|
|
2018-11-24 01:35:25 +01:00
|
|
|
//const std::string datLocation( "/opt/sapphire_3_15_0/bin/sqpack" );
|
2019-01-08 18:08:51 +11:00
|
|
|
const std::string datLocation( "/mnt/c/Program Files (x86)/Steam/steamapps/common/FINAL FANTASY XIV Online/game/sqpack" );
|
2017-10-12 09:02:28 +02:00
|
|
|
|
2019-04-11 19:06:27 +10:00
|
|
|
void exportFile( const std::string& path )
|
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
|
|
|
auto file = gameData->getFile( path );
|
|
|
|
|
|
|
|
if( !file )
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
auto p = fs::path( path );
|
|
|
|
fs::create_directories( p.parent_path() );
|
|
|
|
file->exportToFile( p );
|
|
|
|
}
|
|
|
|
catch( const std::exception& ex )
|
|
|
|
{
|
|
|
|
Logger::error( "Failed to export file {0}, error: {1}", path, ex.what() );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
struct DupeResult
|
|
|
|
{
|
|
|
|
std::string groupName;
|
|
|
|
std::string lgb;
|
|
|
|
uint32_t id;
|
|
|
|
};
|
|
|
|
|
|
|
|
int main( int argc, char* argv[] )
|
2017-10-12 09:02:28 +02:00
|
|
|
{
|
|
|
|
|
2018-12-23 03:53:08 +01:00
|
|
|
Logger::init( "struct_test" );
|
2017-10-12 09:02:28 +02:00
|
|
|
|
2018-12-23 03:53:08 +01:00
|
|
|
Logger::info( "Setting up EXD data" );
|
2018-08-29 21:40:59 +02:00
|
|
|
if( !g_exdData.init( datLocation ) )
|
|
|
|
{
|
2018-12-23 03:53:08 +01:00
|
|
|
Logger::fatal( "Error setting up EXD data " );
|
2018-08-29 21:40:59 +02:00
|
|
|
return 0;
|
|
|
|
}
|
2017-10-12 09:02:28 +02:00
|
|
|
|
2019-04-11 19:06:27 +10:00
|
|
|
gameData = new xiv::dat::GameData( datLocation );
|
|
|
|
|
|
|
|
if( argc > 1 )
|
|
|
|
{
|
|
|
|
while( argc-- > 1 )
|
|
|
|
{
|
|
|
|
Logger::info( "Exporting file: {}", argv[ argc ] );
|
|
|
|
exportFile( argv[ argc ] );
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::vector< std::string > levelNames;
|
|
|
|
std::vector< std::string > paths;
|
|
|
|
|
|
|
|
std::vector< uint32_t > lgbGroupIds;
|
|
|
|
std::vector< DupeResult > lgbGroupDupes;
|
|
|
|
|
|
|
|
paths.emplace_back( "level/bg.lgb" );
|
|
|
|
paths.emplace_back( "level/planmap.lgb" );
|
|
|
|
paths.emplace_back( "level/planevent.lgb" );
|
|
|
|
paths.emplace_back( "level/planlive.lgb" );
|
|
|
|
paths.emplace_back( "level/sound.lgb" );
|
|
|
|
paths.emplace_back( "level/planner.lgb" );
|
|
|
|
|
|
|
|
auto ids = g_exdData.getTerritoryTypeIdList();
|
|
|
|
|
|
|
|
for( auto id : ids )
|
2018-08-29 21:40:59 +02:00
|
|
|
{
|
2019-04-11 19:06:27 +10:00
|
|
|
auto territoryType = g_exdData.get< Data::TerritoryType >( id );
|
|
|
|
if( !territoryType )
|
|
|
|
continue;
|
|
|
|
|
|
|
|
auto bg = territoryType->bg;
|
|
|
|
bg = bg.substr( 0, bg.find( "/level/" ) );
|
|
|
|
|
|
|
|
if( bg.empty() )
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if( std::find( levelNames.begin(), levelNames.end(), bg ) != levelNames.end() )
|
|
|
|
continue;
|
|
|
|
|
|
|
|
levelNames.push_back( bg );
|
|
|
|
|
|
|
|
Logger::info( "LGB groups for: {}", bg );
|
|
|
|
|
|
|
|
for( const auto& path : paths )
|
|
|
|
{
|
|
|
|
auto filePath = fmt::format( "bg/{}/{}", bg, path );
|
|
|
|
|
|
|
|
try
|
|
|
|
{
|
|
|
|
auto file = gameData->getFile( filePath );
|
|
|
|
auto data = file->access_data_sections().at( 0 );
|
|
|
|
|
|
|
|
LGB_FILE lgb( &data[ 0 ], "wtf" );
|
|
|
|
|
|
|
|
Logger::info(" {} groups: {}", path, lgb.header.groupCount );
|
|
|
|
|
|
|
|
for( const auto& group : lgb.groups )
|
|
|
|
{
|
|
|
|
Logger::info( " - {:<7} {:<25} children: {}", group.header.unknown, group.name, group.header.entryCount );
|
|
|
|
|
|
|
|
if( std::find( lgbGroupIds.begin(), lgbGroupIds.end(), group.header.unknown ) == lgbGroupIds.end() )
|
|
|
|
{
|
|
|
|
lgbGroupIds.emplace_back( group.header.unknown );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
lgbGroupDupes.push_back( { group.name, filePath, group.header.unknown } );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Logger::info( "" );
|
|
|
|
}
|
|
|
|
catch( const std::exception& ex )
|
|
|
|
{
|
|
|
|
Logger::warn( "Failed on file {}, error: {}", path, ex.what() );
|
|
|
|
}
|
|
|
|
}
|
2018-08-29 21:40:59 +02:00
|
|
|
}
|
2019-01-08 18:08:51 +11:00
|
|
|
|
2019-04-11 19:06:27 +10:00
|
|
|
if( !lgbGroupDupes.empty() )
|
|
|
|
{
|
|
|
|
Logger::info( "Found duplicate LGB group ids: " );
|
|
|
|
|
|
|
|
for( const auto& result : lgbGroupDupes )
|
|
|
|
{
|
|
|
|
Logger::info( " - file: {:<50} group: {:<30} id: {}", result.lgb, result.groupName, result.id );
|
|
|
|
}
|
|
|
|
}
|
2018-08-29 21:40:59 +02:00
|
|
|
|
|
|
|
return 0;
|
2017-10-12 09:02:28 +02:00
|
|
|
}
|