1
Fork 0
mirror of https://github.com/SapphireServer/Sapphire.git synced 2025-04-29 07:37:45 +00:00

pcb_reader

- added eobj parsing (doesnt seem to work?)
- readded ghetto commandline recastdemo export (windows only)
- fixed threadpool legit this time
This commit is contained in:
Tahir Akhlaq 2019-01-22 19:43:12 +00:00
parent 4bad458849
commit 2f02b5c850
6 changed files with 231 additions and 53 deletions

View file

@ -83,7 +83,7 @@ private:
m_lgbCache.clear();
m_sgbCache.clear();
m_pcbCache.clear();
std::cout << "Purged PCB/SGB/PCB cache \n";
std::cout << "Purged PCB/SGB/LGB cache \n";
m_totalFiles = 1;
}

View file

@ -40,6 +40,7 @@ uint32_t zoneId;
std::set< std::string > zoneDumpList;
std::shared_ptr< Cache > pCache;
std::map< uint32_t, uint16_t > eobjSgbPaths;
xiv::dat::GameData* data1 = nullptr;
xiv::exd::ExdData* eData = nullptr;
@ -61,6 +62,49 @@ void initExd( const std::string& gamePath )
pCache = std::make_shared< Cache >( data1 );
}
void replaceAll( std::string& str, const std::string& from, const std::string& to ) {
if( from.empty() )
return;
size_t start_pos = 0;
while( ( start_pos = str.find( from, start_pos ) ) != std::string::npos ) {
str.replace( start_pos, from.length(), to );
start_pos += to.length(); // In case 'to' contains 'from', like replacing 'x' with 'yx'
}
}
std::string getEobjSgbPath( uint32_t eobjId )
{
static std::map< uint16_t, std::string > exportedSgMap;
if( !exportedSgMap.empty() )
return exportedSgMap[ eobjSgbPaths[ eobjId ] ];
auto& eobjCat = eData->get_category( "EObj" );
auto eObjExd = static_cast< xiv::exd::Exd >( eobjCat.get_data_ln( xiv::exd::Language::none ) );
auto& exportedSgCat = eData->get_category( "ExportedSG" );
auto exportedSgExd = static_cast< xiv::exd::Exd >( exportedSgCat.get_data_ln( xiv::exd::Language::none ) );
for( auto& row : exportedSgExd.get_rows() )
{
auto id = row.first;
auto& fields = row.second;
auto path = std::get< std::string >( fields.at( 0 ) );
exportedSgMap[id] = path;
}
uint16_t exportedSgId{0};
for( auto& row : eObjExd.get_rows() )
{
auto id = row.first;
auto& fields = row.second;
eobjSgbPaths[id] = std::get< uint16_t >( fields.at( 11 ) );
}
return exportedSgMap[exportedSgId];
}
std::string zoneNameToPath( const std::string& name )
{
@ -116,7 +160,10 @@ int main( int argc, char* argv[] )
{ return arg == "--dump-all"; } ) != argVec.end();
bool generateNavmesh = std::remove_if( argVec.begin(), argVec.end(), []( auto arg )
{ return arg == "--navmesh"; } ) != argVec.end();
bool splitByGroup = std::remove_if( argVec.begin(), argVec.end(), []( auto arg )
{ return arg == "--split-by-group"; }) != argVec.end();
bool splitByZone = std::remove_if( argVec.begin(), argVec.end(), []( auto arg )
{ return arg == "--split-by-zone"; }) != argVec.end();
int exportFileType = 0;
if( !noObj )
exportFileType |= ExportFileType::WavefrontObj;
@ -137,6 +184,7 @@ int main( int argc, char* argv[] )
try
{
initExd( gamePath );
getEobjSgbPath( 0 );
}
catch( std::exception& e )
{
@ -324,7 +372,7 @@ int main( int argc, char* argv[] )
if( auto pPcbFile = pCache->getPcbFile( fileName ) )
buildModelEntry( pPcbFile, exportedTerrainGroup, fileName, zoneName );
}
exportMgr.exportGroup( zoneName, exportedTerrainGroup, ( ExportFileType )exportFileType );
exportedZone.groups.emplace( exportedTerrainGroup.name, exportedTerrainGroup );
for( const auto& lgb : lgbList )
{
@ -351,12 +399,51 @@ int main( int argc, char* argv[] )
}
return true;
};
auto exportSgbModel = [&]( const std::string& sgbFilePath, LGB_ENTRY* pGimmick, bool isEobj = false )
{
if( auto pSgbFile = pCache->getSgbFile( sgbFilePath ) )
{
const auto& sgbFile = *pSgbFile;
for( const auto& group : sgbFile.entries )
{
for( const auto& pSgbEntry : group.entries )
{
auto pModel = dynamic_cast< SGB_MODEL_ENTRY* >( pSgbEntry.get() );
fileName = pModel->collisionFileName;
if( pModel->type == SgbGroupEntryType::Gimmick )
{
if( auto pSubSgbFile = pCache->getSgbFile( pModel->modelFileName ) )
{
for( const auto& subGroup : pSubSgbFile->entries )
{
for( const auto& pSubEntry : subGroup.entries )
{
auto pSubModel = dynamic_cast< SGB_MODEL_ENTRY* >( pSubEntry.get() );
std::string subModelFile = pSubModel->modelFileName;
//"bg/ex1/02_dra_d2/alx/common/bgparts/d2a0_a7_btog2.mdl"
//"bg/ex1/02_dra_d2/alx/common/collision/d2a0_a1_twl01.pcb"
replaceAll( subModelFile, "/bgparts/", "/collision/" );
replaceAll( subModelFile, ".mdl", ".pcb ");
if( pSubModel && pSubModel->type == SgbGroupEntryType::Model )
pcbTransformModel( subModelFile, &pGimmick->header.scale, &pGimmick->header.rotation,
&pGimmick->header.translation, pSubModel );
}
}
}
}
pcbTransformModel( fileName, &pGimmick->header.scale, &pGimmick->header.rotation,
&pGimmick->header.translation, pModel );
}
}
}
};
switch( pEntry->getType() )
{
case LgbEntryType::BgParts:
{
auto pBgParts = static_cast<LGB_BGPARTS_ENTRY*>(pEntry.get());
auto pBgParts = static_cast< LGB_BGPARTS_ENTRY* >( pEntry.get() );
fileName = pBgParts->collisionFileName;
pcbTransformModel( fileName, &pBgParts->header.scale, &pBgParts->header.rotation,
&pBgParts->header.translation );
@ -366,37 +453,41 @@ int main( int argc, char* argv[] )
// gimmick entry
case LgbEntryType::Gimmick:
{
auto pGimmick = static_cast<LGB_GIMMICK_ENTRY*>( pEntry.get() );
if( auto pSgbFile = pCache->getSgbFile( pGimmick->gimmickFileName ) )
{
const auto& sgbFile = *pSgbFile;
for( const auto& group : sgbFile.entries )
{
for( const auto& pEntry : group.entries )
{
auto pModel = dynamic_cast< SGB_MODEL_ENTRY* >( pEntry.get() );
fileName = pModel->collisionFileName;
pcbTransformModel( fileName, &pGimmick->header.scale, &pGimmick->header.rotation,
&pGimmick->header.translation, pModel );
}
}
}
auto pGimmick = static_cast< LGB_GIMMICK_ENTRY* >( pEntry.get() );
exportSgbModel( pGimmick->gimmickFileName, pGimmick );
}
break;
case LgbEntryType::EventObject:
{
auto pEobj = static_cast< LGB_EOBJ_ENTRY* >( pEntry.get() );
pcbTransformModel( fileName, &pEntry->header.scale, &pEntry->header.rotation, &pEntry->header.translation );
auto sgbPath = getEobjSgbPath( pEobj->header.eobjId );
if ( !sgbPath.empty() )
{
exportSgbModel( sgbPath, pEobj, true );
if( auto pGimmick = pCache->getSgbFile( sgbPath ) )
{
for( const auto& offset1cFile : pGimmick->offset1cObjects )
exportSgbModel( offset1cFile, pEobj, true );
}
}
}
break;
default:
break;
}
}
exportMgr.exportGroup( zoneName, exportedGroup, ( ExportFileType )exportFileType );
//exportedZone.groups.emplace( group.name, exportedGroup );
if( splitByGroup )
exportMgr.exportGroup( zoneName, exportedGroup, ( ExportFileType )exportFileType );
exportedZone.groups.emplace( group.name, exportedGroup );
}
}
//exportMgr.exportZone( exportedZone, ( ExportFileType )exportFileType );
exportMgr.exportZone( exportedZone, ExportFileType::Navmesh );
printf( "Exported %s in %u seconds \n",

View file

@ -9,6 +9,8 @@
#include <chrono>
#include "exporter.h"
#include "obj_exporter.h"
/*
#include <recastnavigation/Recast/Include/Recast.h>
#include <recastnavigation/Recast/Include/RecastAlloc.h>
@ -23,11 +25,14 @@
class NavmeshExporter
{
public:
static void exportZone( const ExportedZone& zone )
static void exportZone( const ExportedZone& zone, bool deleteObj = false )
{
static std::string currPath = std::experimental::filesystem::current_path().string();
auto start = std::chrono::high_resolution_clock::now();
auto fileName = zone.name + ".obj";
auto fileName = currPath + "/" + zone.name + "/" + zone.name + ".nav";
exportZoneCommandline( zone, deleteObj );
auto end = std::chrono::high_resolution_clock::now();
printf( "[Navmesh] Finished exporting %s in %u ms\n",
@ -35,19 +40,50 @@ public:
std::chrono::duration_cast< std::chrono::milliseconds >( end - start ).count() );
}
static void exportGroup( const std::string& zoneName, const ExportedGroup& group )
static void exportGroup( const std::string& zoneName, const ExportedGroup& group, bool deleteObj = false )
{
static std::string currPath = std::experimental::filesystem::current_path().string();
auto start = std::chrono::high_resolution_clock::now();
auto fileName = zoneName + "_" + group.name + ".obj";
auto fileName = currPath + "/" + zoneName + "/" + zoneName + "_" + group.name + ".obj";
exportGroupCommandline( zoneName, group );
auto end = std::chrono::high_resolution_clock::now();
printf( "[Navmesh] Finished exporting %s in %u ms\n",
fileName.c_str(),
std::chrono::duration_cast< std::chrono::milliseconds >( end - start ).count() );
}
private:
static void exportZoneCommandline( const ExportedZone& zone, bool deleteObj = false )
{
static std::string currPath = "\"\"" + std::experimental::filesystem::current_path().string();
auto fileName = ObjExporter::exportZone( zone );
if( fileName.empty() )
{
printf( "Unable to export navmesh for %s", zone.name.c_str() );
return;
}
static std::string recastDemoLaunch = std::string( "RecastDemo.exe --type tileMesh --obj ");
std::string actualStr( recastDemoLaunch + "\"" + fileName + "\"" );
system( actualStr.c_str() );
}
static void exportGroupCommandline( const std::string& zoneName, const ExportedGroup& group, bool deleteObj = false )
{
static std::string currPath = "\"\"" + std::experimental::filesystem::current_path().string();
auto fileName = ObjExporter::exportGroup( zoneName, group );
if( fileName.empty() )
{
printf( "Unable to export navmesh for %s", zoneName.c_str() );
return;
}
static std::string recastDemoLaunch = std::string( "RecastDemo.exe --type tileMesh --obj ");
std::string actualStr( recastDemoLaunch + "\"" + fileName + "\"" );
system( actualStr.c_str() );
}
/*/
static unsigned char* buildTileMesh( const ExportedGroup& group, int tx, int ty )
{

View file

@ -14,7 +14,7 @@
class ObjExporter
{
public:
static void exportZone( const ExportedZone& zone )
static std::string exportZone( const ExportedZone& zone )
{
static std::string currPath = std::experimental::filesystem::current_path().string();
@ -30,7 +30,7 @@ public:
if( !std::experimental::filesystem::create_directory( dir, e ) )
{
printf( "Unable to create directory '%s'", ( dir ).c_str() );
return;
return "";
}
}
std::ofstream of( fileName, std::ios::trunc );
@ -53,9 +53,10 @@ public:
printf( "[Obj] Finished exporting %s in %u ms\n",
fileName.c_str(),
std::chrono::duration_cast< std::chrono::milliseconds >( end - start ).count() );
return fileName;
}
static void exportGroup( const std::string& zoneName, const ExportedGroup& group )
static std::string exportGroup( const std::string& zoneName, const ExportedGroup& group )
{
static std::string currPath = std::experimental::filesystem::current_path().string();
@ -70,7 +71,7 @@ public:
if( !std::experimental::filesystem::create_directory( dir, e ) )
{
printf( "Unable to create directory '%s'", ( dir ).c_str() );
return;
return "";
}
}
std::ofstream of( fileName, std::ios::trunc );
@ -90,6 +91,7 @@ public:
printf( "[Obj] Finished exporting %s in %u ms\n",
fileName.c_str(),
std::chrono::duration_cast< std::chrono::milliseconds >( end - start ).count() );
return fileName;
}
private:
static void exportGroup( const ExportedGroup& group, std::ofstream& of, int& indicesOffset, int& modelCount )

View file

@ -36,6 +36,7 @@ enum SgbGroupEntryType :
uint32_t
{
Model = 0x01,
Gimmick = 0x06,
};
struct SGB_GROUP_HEADER
@ -64,6 +65,35 @@ struct SGB_GROUP_HEADER
uint32_t unknown44;
};
struct SGB_GROUP1C_HEADER
{
SgbDataType type;
int32_t nameOffset;
uint32_t unknown08;
int32_t entryCount;
uint32_t unknown14;
int32_t modelFileOffset;
vec3 unknownFloat3;
vec3 unknownFloat3_2;
int32_t stateOffset;
int32_t modelFileOffset2;
uint32_t unknown3;
float unknown4;
int32_t nameOffset2;
vec3 unknownFloat3_3;
};
struct SGB_GROUP1C_ENTRY
{
uint32_t unk;
uint32_t unk2;
int32_t nameOffset;
uint32_t index;
uint32_t unk3;
int32_t modelFileOffset;
};
struct SGB_GROUP_ENTRY
{
public:
@ -113,8 +143,9 @@ struct SGB_MODEL_ENTRY :
std::string modelFileName;
std::string collisionFileName;
SGB_MODEL_ENTRY( char* buf, uint32_t offset )
SGB_MODEL_ENTRY( char* buf, uint32_t offset, SgbGroupEntryType type )
{
this->type = type;
header = *reinterpret_cast< SGB_MODEL_HEADER* >( buf + offset );
name = std::string( buf + offset + header.nameOffset );
modelFileName = std::string( buf + offset + header.modelFileOffset );
@ -129,23 +160,45 @@ struct SGB_GROUP
SGB_FILE* parent;
std::vector< std::shared_ptr< SGB_GROUP_ENTRY > > entries;
SGB_GROUP( char* buf, SGB_FILE* file, uint32_t fileSize, uint32_t offset )
SGB_GROUP( char* buf, SGB_FILE* file, std::set< std::string >* offset1cObjects, uint32_t fileSize, uint32_t offset, bool isOffset1C = false )
{
parent = file;
if( isOffset1C )
{
auto header1c = *reinterpret_cast< SGB_GROUP1C_HEADER* >( buf + offset );
auto entriesOffset = offset + sizeof( header1c );
auto entryCount = header1c.entryCount;
for( auto i = 0; i < entryCount; ++i )
{
auto entryOffset = entriesOffset + ( i * 24 );
auto entry = *reinterpret_cast< SGB_GROUP1C_ENTRY* >( buf + entryOffset );
std::string entryModelFile( buf + entryOffset + entry.modelFileOffset + 9 );
if( entryModelFile.find( ".sgb" ) != std::string::npos )
{
offset1cObjects->emplace( entryModelFile );
}
}
return;
}
auto entriesOffset = offset + sizeof( header );
header = *reinterpret_cast< SGB_GROUP_HEADER* >( buf + offset );
name = std::string( buf + offset + header.nameOffset );
auto entriesOffset = offset + sizeof( header );
for( auto i = 0; i < header.entryCount; ++i )
{
auto entryOffset = entriesOffset + *reinterpret_cast< uint32_t* >( buf + ( entriesOffset + ( i * 4 ) ) );
if( entryOffset > fileSize )
throw std::runtime_error( "SGB_GROUP entry offset was larger than SGB file size!" );
auto type = *reinterpret_cast< uint32_t* >( buf + entryOffset );
if( type == SgbGroupEntryType::Model )
if( type == SgbGroupEntryType::Model || type == SgbGroupEntryType::Gimmick )
{
entries.push_back( std::make_shared< SGB_MODEL_ENTRY >( buf, entryOffset ) );
entries.push_back( std::make_shared< SGB_MODEL_ENTRY >( buf, entryOffset, ( SgbGroupEntryType )type ) );
}
else
{
@ -190,6 +243,7 @@ struct SGB_FILE
{
SGB_HEADER header;
std::vector< SGB_GROUP > entries;
std::set< std::string > offset1cObjects;
SGB_FILE()
{
@ -206,9 +260,9 @@ struct SGB_FILE
try
{
auto group = SGB_GROUP( buf, this, header.fileSize, baseOffset + header.sharedOffset );
auto group = SGB_GROUP( buf, this, &offset1cObjects, header.fileSize, baseOffset + header.sharedOffset );
entries.push_back( group );
auto group2 = SGB_GROUP( buf, this, header.fileSize, baseOffset + header.offset1C );
auto group2 = SGB_GROUP( buf, this, &offset1cObjects, header.fileSize, baseOffset+ header.offset1C, true );
entries.push_back( group2 );
}
catch( std::exception& e )

View file

@ -10,6 +10,9 @@
#include <mutex>
#include <thread>
// credit to
// https://riptutorial.com/cplusplus/example/15806/create-a-simple-thread-pool
class ThreadPool
{
public:
@ -55,23 +58,20 @@ public:
{
std::unique_lock lock( m_mutex );
m_pendingJobs.clear();
for( auto&& worker : m_workers )
{
m_pendingJobs.emplace( {} );
}
}
m_cv.notify_all();
m_workers.clear();
complete();
}
bool complete()
{
m_cv.notify_all();
{
std::unique_lock lock( m_mutex );
m_runFlag = false;
m_cv.wait( lock, [&]{ return m_pendingJobs.empty(); } );
for( auto&& worker : m_workers )
{
m_pendingJobs.push_back( {} );
}
}
m_cv.notify_all();
m_workers.clear();
return true;
}
@ -85,11 +85,6 @@ private:
std::unique_lock lock( m_mutex );
if( m_pendingJobs.empty() )
{
if( !m_runFlag )
{
m_cv.notify_all();
return;
}
m_cv.wait( lock, [&](){ return !m_pendingJobs.empty(); } );
}
func = std::move( m_pendingJobs.front() );