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:28:51 +10:00
|
|
|
#include <datReader/DatCategories/bg/pcb.h>
|
|
|
|
#include <datReader/DatCategories/bg/lgb.h>
|
|
|
|
#include <datReader/DatCategories/bg/sgb.h>
|
2019-04-11 19:06:27 +10:00
|
|
|
|
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() );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-04-11 22:18:18 +10:00
|
|
|
const std::string getTypeString( uint32_t type )
|
|
|
|
{
|
|
|
|
switch( type )
|
|
|
|
{
|
|
|
|
case 1: return "BgParts";
|
|
|
|
case 3: return "Light";
|
|
|
|
case 4: return "Vfx";
|
|
|
|
case 5: return "PositionMarker";
|
|
|
|
case 6: return "Gimmick/SharedGroup6";
|
|
|
|
case 7: return "Sound";
|
|
|
|
case 8: return "EventNpc";
|
|
|
|
case 9: return "BattleNpc";
|
|
|
|
case 12: return "Aetheryte";
|
|
|
|
case 13: return "EnvSpace";
|
|
|
|
case 14: return "Gathering";
|
|
|
|
case 15: return "SharedGroup15";
|
|
|
|
case 16: return "Treasure";
|
|
|
|
case 39: return "Weapon";
|
|
|
|
case 40: return "PopRange";
|
|
|
|
case 41: return "ExitRange";
|
|
|
|
case 43: return "MapRange";
|
|
|
|
case 44: return "NaviMeshRange";
|
|
|
|
case 45: return "EventObject";
|
|
|
|
case 47: return "EnvLocation";
|
|
|
|
case 49: return "EventRange";
|
|
|
|
case 51: return "QuestMarker";
|
|
|
|
case 57: return "CollisionBox";
|
|
|
|
case 58: return "DoorRange";
|
|
|
|
case 59: return "LineVfx";
|
|
|
|
case 65: return "ClientPath";
|
|
|
|
case 66: return "ServerPath";
|
|
|
|
case 67: return "GimmickRange";
|
|
|
|
case 68: return "TargetMarker";
|
|
|
|
case 69: return "ChairMarker";
|
|
|
|
case 70: return "ClickableRange";
|
|
|
|
case 71: return "PrefetchRange";
|
|
|
|
case 72: return "FateRange";
|
|
|
|
case 75: return "SphereCastRange";
|
|
|
|
|
|
|
|
default: return "";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-04-11 19:06:27 +10:00
|
|
|
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;
|
2019-04-11 19:28:51 +10:00
|
|
|
|
2019-04-11 19:06:27 +10:00
|
|
|
std::vector< uint32_t > lgbGroupIds;
|
|
|
|
std::vector< DupeResult > lgbGroupDupes;
|
2019-04-11 22:18:18 +10:00
|
|
|
std::vector< uint32_t > foundTypes;
|
2019-04-11 19:06:27 +10:00
|
|
|
|
|
|
|
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 )
|
|
|
|
{
|
2019-04-11 22:18:18 +10:00
|
|
|
std::vector< uint32_t > types;
|
|
|
|
|
|
|
|
for( const auto& entry : group.entries )
|
|
|
|
{
|
|
|
|
types.emplace_back( static_cast< uint32_t >( entry->getType() ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string typeStr;
|
|
|
|
|
|
|
|
std::sort( types.begin(), types.end() );
|
|
|
|
auto end = std::unique( types.begin(), types.end() );
|
|
|
|
types.erase( end, types.end() );
|
2019-04-11 19:06:27 +10:00
|
|
|
|
2019-04-11 22:18:18 +10:00
|
|
|
foundTypes.insert( foundTypes.end(), types.begin(), types.end() );
|
|
|
|
|
|
|
|
for( auto type : types )
|
|
|
|
{
|
|
|
|
typeStr.append( " " + std::to_string( type ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
Logger::info( " - {:<7} {:<25} groups: {:<3} types:{}",
|
|
|
|
group.header.id, group.name, group.header.entryCount, typeStr );
|
|
|
|
|
|
|
|
if( std::find( lgbGroupIds.begin(), lgbGroupIds.end(), group.header.id ) == lgbGroupIds.end() )
|
2019-04-11 19:06:27 +10:00
|
|
|
{
|
2019-04-11 22:18:18 +10:00
|
|
|
lgbGroupIds.emplace_back( group.header.id );
|
2019-04-11 19:06:27 +10:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2019-04-11 22:18:18 +10:00
|
|
|
lgbGroupDupes.push_back( { group.name, filePath, group.header.id } );
|
2019-04-11 19:06:27 +10:00
|
|
|
}
|
|
|
|
}
|
|
|
|
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 )
|
|
|
|
{
|
2019-04-11 22:18:18 +10:00
|
|
|
Logger::info( " - id: {:<7} group: {:<30} file: {} ", result.id, result.groupName, result.lgb );
|
2019-04-11 19:06:27 +10:00
|
|
|
}
|
|
|
|
}
|
2018-08-29 21:40:59 +02:00
|
|
|
|
2019-04-11 22:18:18 +10:00
|
|
|
Logger::info( "Found LGB entry types:" );
|
|
|
|
|
|
|
|
std::sort( foundTypes.begin(), foundTypes.end() );
|
|
|
|
auto end = std::unique( foundTypes.begin(), foundTypes.end() );
|
|
|
|
foundTypes.erase( end, foundTypes.end() );
|
|
|
|
|
|
|
|
for( auto type : foundTypes )
|
|
|
|
{
|
|
|
|
Logger::info( " - {:<3} {}", type, getTypeString( type ) );
|
|
|
|
}
|
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
return 0;
|
2017-10-12 09:02:28 +02:00
|
|
|
}
|