2018-02-26 23:50:50 +01:00
# include <stdio.h>
# include <cstdint>
# include <string>
# include <iostream>
# include <chrono>
# include <fstream>
# include <regex>
# include <map>
# include <vector>
# include <set>
2018-10-27 22:51:16 +02:00
# include <variant>
# include <Util/Util.h>
2018-02-26 23:50:50 +01:00
# include "pcb.h"
# include "lgb.h"
# include "sgb.h"
2019-04-09 14:55:07 +02:00
# include <Exd/ExdDataGenerated.h>
# include <Logging/Logger.h>
2018-08-29 21:40:59 +02:00
2018-02-26 23:50:50 +01:00
# include <GameData.h>
# include <File.h>
# include <DatCat.h>
# include <ExdData.h>
# include <ExdCat.h>
# include <Exd.h>
2018-08-29 21:40:59 +02:00
2018-10-25 13:38:06 +11:00
# include <experimental/filesystem>
2019-04-09 14:55:07 +02:00
# include <Util/CrashHandler.h>
Sapphire : : Common : : Util : : CrashHandler crashHandler ;
Sapphire : : Data : : ExdDataGenerated g_exdData ;
using namespace Sapphire ;
2018-10-25 13:38:06 +11:00
namespace fs = std : : experimental : : filesystem ;
2018-02-26 23:50:50 +01:00
// garbage to ignore models
bool ignoreModels = false ;
2019-04-09 14:55:07 +02:00
std : : string gamePath ( " /home/mordred/sqpack " ) ;
//std::string gamePath( "C:\\SquareEnix\\FINAL FANTASY XIV - A Realm Reborn\\game\\sqpack" );
2018-02-26 23:50:50 +01:00
std : : unordered_map < uint32_t , std : : string > eobjNameMap ;
std : : unordered_map < uint16_t , std : : vector < std : : pair < uint16_t , std : : string > > > zoneInstanceMap ;
uint32_t zoneId ;
struct instanceContent
{
2018-08-29 21:40:59 +02:00
uint32_t id ;
std : : string name ;
std : : string zoneName ;
uint8_t type ;
2018-02-26 23:50:50 +01:00
} ;
std : : vector < instanceContent > contentList ;
std : : set < std : : string > zoneDumpList ;
xiv : : dat : : GameData * data1 = nullptr ;
using namespace std : : chrono_literals ;
void initExd ( const std : : string & gamePath )
{
2018-08-29 21:40:59 +02:00
data1 = data1 ? data1 : new xiv : : dat : : GameData ( gamePath ) ;
2018-02-26 23:50:50 +01:00
}
2018-08-29 21:40:59 +02:00
int parseBlockEntry ( char * data , std : : vector < PCB_BLOCK_ENTRY > & entries , int gOff )
2018-02-26 23:50:50 +01:00
{
2018-08-29 21:40:59 +02:00
int offset = 0 ;
bool isgroup = true ;
while ( isgroup )
{
PCB_BLOCK_ENTRY block_entry ;
memcpy ( & block_entry . header , data + offset , sizeof ( block_entry . header ) ) ;
isgroup = block_entry . header . type = = 0x30 ;
//printf( " BLOCKHEADER_%X: type: %i, group_size: %i\n", gOff + offset, block_entry.header.type, block_entry.header.group_size );
if ( isgroup )
{
parseBlockEntry ( data + offset + 0x30 , entries , gOff + offset ) ;
offset + = block_entry . header . group_size ;
}
else
{
/* printf( "\tnum_v16: %i, num_indices: %i, num_vertices: %i\n\n",
block_entry . header . num_v16 , block_entry . header . num_indices , block_entry . header . num_vertices ) ; */
int doffset = sizeof ( block_entry . header ) + offset ;
uint16_t block_size = sizeof ( block_entry . header ) +
block_entry . header . num_vertices * 3 * 4 +
block_entry . header . num_v16 * 6 +
block_entry . header . num_indices * 6 ;
if ( block_entry . header . num_vertices ! = 0 )
{
block_entry . data . vertices . resize ( block_entry . header . num_vertices ) ;
2018-02-26 23:50:50 +01:00
2018-08-29 21:40:59 +02:00
int32_t size_vertexbuffer = block_entry . header . num_vertices * 3 ;
memcpy ( & block_entry . data . vertices [ 0 ] , data + doffset , size_vertexbuffer * 4 ) ;
doffset + = size_vertexbuffer * 4 ;
}
if ( block_entry . header . num_v16 ! = 0 )
2018-02-26 23:50:50 +01:00
{
2018-08-29 21:40:59 +02:00
block_entry . data . vertices_i16 . resize ( block_entry . header . num_v16 ) ;
int32_t size_unknownbuffer = block_entry . header . num_v16 * 6 ;
memcpy ( & block_entry . data . vertices_i16 [ 0 ] , data + doffset , size_unknownbuffer ) ;
doffset + = block_entry . header . num_v16 * 6 ;
2018-02-26 23:50:50 +01:00
}
2018-08-29 21:40:59 +02:00
if ( block_entry . header . num_indices ! = 0 )
2018-02-26 23:50:50 +01:00
{
2018-08-29 21:40:59 +02:00
block_entry . data . indices . resize ( block_entry . header . num_indices ) ;
int32_t size_indexbuffer = block_entry . header . num_indices * 12 ;
memcpy ( & block_entry . data . indices [ 0 ] , data + doffset , size_indexbuffer ) ;
doffset + = size_indexbuffer ;
2018-02-26 23:50:50 +01:00
}
2018-08-29 21:40:59 +02:00
entries . push_back ( block_entry ) ;
}
}
2018-02-26 23:50:50 +01:00
2018-08-29 21:40:59 +02:00
return 0 ;
2018-02-26 23:50:50 +01:00
}
2019-04-11 13:23:01 +02:00
std : : unordered_map < std : : string , std : : string > g_nameMap ;
2018-02-26 23:50:50 +01:00
std : : string zoneNameToPath ( const std : : string & name )
{
2018-08-29 21:40:59 +02:00
std : : string path ;
bool found = false ;
2018-02-26 23:50:50 +01:00
2019-04-11 13:23:01 +02:00
auto it = g_nameMap . find ( Sapphire : : Util : : toLowerCopy ( name ) ) ;
if ( it ! = g_nameMap . end ( ) )
return it - > second ;
2019-04-09 14:55:07 +02:00
auto teriIdList = g_exdData . getTerritoryTypeIdList ( ) ;
for ( auto teriId : teriIdList )
2018-08-29 21:40:59 +02:00
{
2019-04-09 14:55:07 +02:00
auto teri = g_exdData . get < Sapphire : : Data : : TerritoryType > ( teriId ) ;
if ( ! teri )
continue ;
auto teriName = teri - > name ;
auto teriPath = teri - > bg ;
2018-08-29 21:40:59 +02:00
if ( teriName . empty ( ) )
continue ;
2019-04-09 14:55:07 +02:00
if ( Sapphire : : Util : : toLowerCopy ( name ) = = Sapphire : : Util : : toLowerCopy ( teriName ) )
2018-08-29 21:40:59 +02:00
{
path = teriPath ;
found = true ;
2019-04-09 14:55:07 +02:00
break ;
2018-08-29 21:40:59 +02:00
}
}
2018-02-26 23:50:50 +01:00
2018-08-29 21:40:59 +02:00
if ( found )
{
path = std : : string ( " bg/ " ) + path . substr ( 0 , path . find ( " /level/ " ) ) ;
2019-04-09 14:55:07 +02:00
Logger : : debug ( " Found path for {0}: {1} " , name , path ) ;
2019-04-11 13:23:01 +02:00
g_nameMap [ Sapphire : : Util : : toLowerCopy ( name ) ] = path ;
2018-08-29 21:40:59 +02:00
}
else
{
2019-04-09 14:55:07 +02:00
throw std : : runtime_error ( " Unable to find path for " + name ) ;
2018-08-29 21:40:59 +02:00
}
return path ;
2018-02-26 23:50:50 +01:00
}
void loadEobjNames ( )
{
2019-04-11 13:23:01 +02:00
auto nameIdList = g_exdData . getEObjNameIdList ( ) ;
for ( auto id : nameIdList )
2018-08-29 21:40:59 +02:00
{
2019-04-11 13:23:01 +02:00
auto eObjName = g_exdData . get < Sapphire : : Data : : EObjName > ( id ) ;
if ( ! eObjName )
continue ;
2018-08-29 21:40:59 +02:00
2019-04-11 13:23:01 +02:00
if ( ! eObjName - > singular . empty ( ) )
eobjNameMap [ id ] = eObjName - > singular ;
2018-08-29 21:40:59 +02:00
}
2018-02-26 23:50:50 +01:00
}
void writeEobjEntry ( std : : ofstream & out , LGB_ENTRY * pObj )
{
2018-08-29 21:40:59 +02:00
static std : : string mapRangeStr ( " \" MapRange \" , " ) ;
static std : : string eobjStr ( " \" EObj \" , " ) ;
uint32_t id ;
uint32_t unknown = 0 , unknown2 = 0 ;
std : : string name ;
std : : string typeStr ;
uint32_t eobjlevelHierachyId = 0 ;
if ( pObj - > getType ( ) = = LgbEntryType : : EventObject )
{
auto pEobj = reinterpret_cast < LGB_EOBJ_ENTRY * > ( pObj ) ;
id = pEobj - > header . eobjId ;
unknown = pEobj - > header . unknown ;
name = eobjNameMap [ id ] ;
typeStr = eobjStr ;
eobjlevelHierachyId = pEobj - > header . levelHierachyId ;
}
else if ( pObj - > getType ( ) = = LgbEntryType : : MapRange )
{
auto pMapRange = reinterpret_cast < LGB_MAPRANGE_ENTRY * > ( pObj ) ;
id = pMapRange - > header . unknown ;
unknown = pMapRange - > header . unknown2 ;
unknown2 = pMapRange - > header . unknown3 ;
typeStr = mapRangeStr ;
}
std : : string outStr (
std : : to_string ( id ) + " , " + typeStr + " \" " + name + " \" , " +
std : : to_string ( pObj - > header . translation . x ) + " , " + std : : to_string ( pObj - > header . translation . y ) + " , " +
std : : to_string ( pObj - > header . translation . z ) +
" , " + std : : to_string ( eobjlevelHierachyId ) + " \n "
) ;
out . write ( outStr . c_str ( ) , outStr . size ( ) ) ;
2018-02-26 23:50:50 +01:00
}
void loadAllInstanceContentEntries ( )
{
2019-04-09 14:55:07 +02:00
auto cfcIdList = g_exdData . getContentFinderConditionIdList ( ) ;
for ( auto cfcId : cfcIdList )
2018-08-29 21:40:59 +02:00
{
2019-04-09 14:55:07 +02:00
auto cfc = g_exdData . get < Sapphire : : Data : : ContentFinderCondition > ( cfcId ) ;
if ( ! cfc )
continue ;
uint16_t teriId = cfc - > territoryType ;
auto tt = g_exdData . get < Sapphire : : Data : : TerritoryType > ( teriId ) ;
if ( ! tt )
continue ;
uint16_t contentId = cfc - > content ;
uint8_t type ;
2019-02-20 19:54:15 +11:00
std : : string name ;
2019-04-09 14:55:07 +02:00
if ( cfc - > contentLinkType = = 1 )
2019-02-20 19:54:15 +11:00
{
2019-04-09 14:55:07 +02:00
auto ic = g_exdData . get < Sapphire : : Data : : InstanceContent > ( cfc - > content ) ;
if ( ! ic )
continue ;
type = ic - > instanceContentType ;
name = ic - > name ;
2019-03-31 01:39:49 +01:00
}
2019-04-09 14:55:07 +02:00
else if ( cfc - > contentLinkType = = 5 )
{
auto qb = g_exdData . get < Sapphire : : Data : : QuestBattle > ( cfc - > content ) ;
if ( ! qb )
continue ;
auto q = g_exdData . get < Sapphire : : Data : : Quest > ( qb - > quest ) ;
if ( ! q )
2019-03-31 01:39:49 +01:00
continue ;
type = 7 ;
2019-04-09 14:55:07 +02:00
name = q - > name ;
2019-02-20 19:54:15 +11:00
}
else
continue ;
2019-04-09 14:55:07 +02:00
2018-08-29 21:40:59 +02:00
if ( name . empty ( ) )
continue ;
2019-04-09 14:55:07 +02:00
2018-08-29 21:40:59 +02:00
auto i = 0 ;
while ( ( i = name . find ( ' ' ) ) ! = std : : string : : npos )
name = name . replace ( name . begin ( ) + i , name . begin ( ) + i + 1 , { ' _ ' } ) ;
2019-04-09 14:55:07 +02:00
zoneDumpList . emplace ( tt - > name ) ;
2018-08-29 21:40:59 +02:00
2019-03-31 13:48:09 +02:00
std : : string remove = " ,★_ '()[]- \xae \x1a \ x1 \ x2 \x1f \ x1 \ x3.: " ;
2018-11-29 16:55:48 +01:00
Sapphire : : Util : : eraseAllIn ( name , remove ) ;
2018-08-29 21:40:59 +02:00
name [ 0 ] = toupper ( name [ 0 ] ) ;
2019-04-09 14:55:07 +02:00
contentList . push_back ( { contentId , name , tt - > name , type } ) ;
2018-08-29 21:40:59 +02:00
}
2018-02-26 23:50:50 +01:00
}
int main ( int argc , char * argv [ ] )
{
2018-08-29 21:40:59 +02:00
auto startTime = std : : chrono : : system_clock : : now ( ) ;
auto entryStartTime = std : : chrono : : system_clock : : now ( ) ;
2019-04-09 14:55:07 +02:00
Logger : : init ( " Event Object Parser " ) ;
Logger : : info ( " Setting up EXD data " ) ;
if ( ! g_exdData . init ( gamePath ) )
{
Logger : : fatal ( " Error setting up EXD data " ) ;
return 0 ;
}
2018-08-29 21:40:59 +02:00
std : : vector < std : : string > argVec ( argv + 1 , argv + argc ) ;
// todo: support expansions
std : : string zoneName = " r2t2 " ;
ignoreModels = true ;
if ( argc > 1 )
{
zoneName = argv [ 1 ] ;
if ( argc > 2 )
{
std : : string tmpPath ( argv [ 2 ] ) ;
if ( ! tmpPath . empty ( ) )
gamePath = argv [ 2 ] ;
}
}
2019-02-20 19:54:15 +11:00
std : : map < uint8_t , std : : string > instanceContentTypeMap ;
instanceContentTypeMap [ 0 ] = " " ;
instanceContentTypeMap [ 1 ] = " raids " ;
instanceContentTypeMap [ 2 ] = " dungeons " ;
instanceContentTypeMap [ 3 ] = " guildhests " ;
instanceContentTypeMap [ 4 ] = " trials " ;
instanceContentTypeMap [ 5 ] = " pvp/thefeast " ;
instanceContentTypeMap [ 6 ] = " pvp " ;
instanceContentTypeMap [ 7 ] = " questbattles " ;
instanceContentTypeMap [ 8 ] = " hallofthenovice " ;
instanceContentTypeMap [ 9 ] = " deepdungeon " ;
instanceContentTypeMap [ 10 ] = " treasurehunt " ;
instanceContentTypeMap [ 11 ] = " events " ;
instanceContentTypeMap [ 12 ] = " pvp/rivalwings " ;
instanceContentTypeMap [ 13 ] = " maskedcarnivale " ; // todo: better name?
instanceContentTypeMap [ 14 ] = " goldsaucer/mahjong " ;
instanceContentTypeMap [ 15 ] = " goldsaucer " ;
2018-08-29 21:40:59 +02:00
2018-10-25 13:38:06 +11:00
if ( ! fs : : exists ( " instance.tmpl " ) )
2018-08-29 21:40:59 +02:00
throw std : : runtime_error ( " instance.tmpl is missing in working directory " ) ;
2019-03-31 01:39:49 +01:00
try
{
initExd ( gamePath ) ;
}
catch ( std : : runtime_error error )
{
std : : cout < < error . what ( ) ;
}
2019-04-09 15:11:05 +02:00
2019-04-09 14:55:07 +02:00
loadAllInstanceContentEntries ( ) ;
2019-04-11 13:23:01 +02:00
loadEobjNames ( ) ;
2019-03-31 13:06:37 +02:00
2018-08-29 21:40:59 +02:00
for ( auto entry : contentList )
{
std : : string eobjects = " " ;
entryStartTime = std : : chrono : : system_clock : : now ( ) ;
zoneName = entry . zoneName ;
try
{
const auto & zonePath = zoneNameToPath ( zoneName ) ;
std : : string listPcbPath ( zonePath + " /collision/list.pcb " ) ;
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 ;
2018-02-26 23:50:50 +01:00
2018-08-29 21:40:59 +02:00
const xiv : : dat : : Cat & test = data1 - > getCategory ( " bg " ) ;
2018-02-26 23:50:50 +01:00
2018-08-29 21:40:59 +02:00
auto test_file = data1 - > getFile ( bgLgbPath ) ;
section = test_file - > access_data_sections ( ) . at ( 0 ) ;
2018-02-26 23:50:50 +01:00
2018-08-29 21:40:59 +02:00
auto planmap_file = data1 - > getFile ( planmapLgbPath ) ;
section2 = planmap_file - > access_data_sections ( ) . at ( 0 ) ;
2018-02-26 23:50:50 +01:00
2018-08-29 21:40:59 +02:00
std : : vector < std : : string > stringList ;
2018-02-26 23:50:50 +01:00
2018-08-29 21:40:59 +02:00
uint32_t offset1 = 0x20 ;
2018-02-26 23:50:50 +01:00
2018-08-29 21:40:59 +02:00
LGB_FILE bgLgb ( & section [ 0 ] , " bg " ) ;
LGB_FILE planmapLgb ( & section2 [ 0 ] , " planmap " ) ;
2018-02-26 23:50:50 +01:00
2018-08-29 21:40:59 +02:00
std : : vector < LGB_FILE > lgbList { bgLgb , planmapLgb } ;
uint32_t max_index = 0 ;
2018-02-26 23:50:50 +01:00
2018-08-29 21:40:59 +02:00
//if( ignoreModels )
{
std : : map < std : : string , SGB_FILE > sgbFiles ;
auto loadSgbFile = [ & ] ( const std : : string & fileName ) - > bool
{
SGB_FILE sgbFile ;
try
{
char * dataSection = nullptr ;
//std::cout << fileName << " ";
auto file = data1 - > getFile ( fileName ) ;
auto sections = file - > get_data_sections ( ) ;
dataSection = & sections . at ( 0 ) [ 0 ] ;
sgbFile = SGB_FILE ( & dataSection [ 0 ] ) ;
sgbFiles . insert ( std : : make_pair ( fileName , sgbFile ) ) ;
return true ;
}
catch ( std : : exception & e )
{
std : : cout < < " [Error] " < < " Unable to load SGB " < < fileName < < " \n \t Error: \n \t " < < e . what ( ) < < " \n " ;
sgbFiles . insert ( std : : make_pair ( fileName , sgbFile ) ) ;
}
return false ;
} ;
std : : cout < < " [Info] " < < ( ignoreModels ? " Dumping MapRange and EObj " : " Writing obj file " ) < < " \n " ;
uint32_t totalGroups = 0 ;
uint32_t totalGroupEntries = 0 ;
2019-04-09 14:55:07 +02:00
std : : cout < < zoneName < < " \n " ;
2018-08-29 21:40:59 +02:00
uint32_t count = 0 ;
for ( const auto & lgb : lgbList )
{
std : : map < std : : string , uint32_t > nameMap ;
for ( const auto & group : lgb . groups )
{
//std::cout << "\t" << group.name << " Size " << group.header.entryCount << "\n";
totalGroups + + ;
for ( const auto & pEntry : group . entries )
2018-02-26 23:50:50 +01:00
{
2018-08-29 21:40:59 +02:00
auto pGimmick = dynamic_cast < LGB_GIMMICK_ENTRY * > ( pEntry . get ( ) ) ;
auto pBgParts = dynamic_cast < LGB_BGPARTS_ENTRY * > ( pEntry . get ( ) ) ;
std : : string fileName ( " " ) ;
fileName . resize ( 256 ) ;
totalGroupEntries + + ;
if ( pEntry - > getType ( ) = = LgbEntryType : : EventObject )
{
auto pObj = pEntry . get ( ) ;
static std : : string eobjStr ( " \" EObj \" , " ) ;
uint32_t id ;
uint32_t unknown = 0 , unknown2 = 0 ;
std : : string name ;
std : : string typeStr ;
uint32_t eobjlevelHierachyId = 0 ;
auto pEobj = reinterpret_cast < LGB_EOBJ_ENTRY * > ( pObj ) ;
id = pEobj - > header . eobjId ;
unknown = pEobj - > header . unknown ;
typeStr = eobjStr ;
eobjlevelHierachyId = pEobj - > header . levelHierachyId ;
std : : string states = " " ;
std : : string gimmickName = " " ;
for ( const auto & pEntry1 : group . entries )
{
auto pGObj = pEntry1 . get ( ) ;
if ( pGObj - > getType ( ) = = LgbEntryType : : Gimmick )
2018-02-26 23:50:50 +01:00
{
2018-08-29 21:40:59 +02:00
if ( pGObj - > header . unknown = = pEobj - > header . levelHierachyId )
{
auto pGObjR = reinterpret_cast < LGB_GIMMICK_ENTRY * > ( pGObj ) ;
char * dataSection = nullptr ;
//std::cout << fileName << " ";
auto file = data1 - > getFile ( pGObjR - > gimmickFileName ) ;
auto sections = file - > get_data_sections ( ) ;
dataSection = & sections . at ( 0 ) [ 0 ] ;
auto sgbFile = SGB_FILE ( & dataSection [ 0 ] ) ;
auto pos = pGObjR - > gimmickFileName . find_last_of ( " / " ) ;
if ( pos ! = std : : string : : npos )
{
name = pGObjR - > gimmickFileName . substr ( pos + 1 ) ;
name = name . substr ( 0 , name . length ( ) - 4 ) ;
gimmickName = name ;
}
if ( sgbFile . stateEntries . size ( ) > 0 )
{
2019-02-20 19:58:57 +11:00
states = " // States -> " ;
2018-08-29 21:40:59 +02:00
for ( auto entries1 : sgbFile . stateEntries )
2018-02-26 23:50:50 +01:00
{
2019-02-20 19:54:15 +11:00
states + = entries1 . name + " (id: " + std : : to_string ( entries1 . header . id ) + " ) " ;
2018-02-26 23:50:50 +01:00
}
2018-08-29 21:40:59 +02:00
states + = " \n " ;
}
2018-02-26 23:50:50 +01:00
2018-08-29 21:40:59 +02:00
break ;
2018-03-04 00:16:44 +01:00
2018-08-29 21:40:59 +02:00
}
2018-02-26 23:50:50 +01:00
}
2018-08-29 21:40:59 +02:00
}
int state = 4 ;
if ( eobjNameMap . find ( id ) ! = eobjNameMap . end ( ) )
{
name = eobjNameMap [ id ] ;
2019-03-31 13:48:09 +02:00
std : : string remove = " ,★_ '()[]- \xae \x1a \ x1 \ x2 \x1f \ x1 \ x3.: " ;
2018-11-29 16:55:48 +01:00
Sapphire : : Util : : eraseAllIn ( name , remove ) ;
2018-10-27 22:51:16 +02:00
2018-08-29 21:40:59 +02:00
name [ 0 ] = toupper ( name [ 0 ] ) ;
}
if ( name . empty ( ) )
name = " unknown_ " + std : : to_string ( count + + ) ;
if ( id = = 2000182 | | gimmickName = = " sgvf_w_lvd_b0095 " )
{
state = 5 ;
name = " Entrance " ;
}
auto count1 = 0 ;
if ( nameMap . find ( name ) = = nameMap . end ( ) )
{
nameMap [ name ] = 0 ;
}
else
{
nameMap [ name ] = + + nameMap [ name ] ;
count1 = nameMap [ name ] ;
}
if ( count1 > 0 )
name = name + " _ " + std : : to_string ( count1 ) ;
2019-02-20 19:54:15 +11:00
eobjects + = " instance.registerEObj( \" " + name + " \" , " + std : : to_string ( id ) +
2018-08-29 21:40:59 +02:00
" , " + std : : to_string ( eobjlevelHierachyId ) + " , " + std : : to_string ( state ) +
" , " +
" { " + std : : to_string ( pObj - > header . translation . x ) + " f, "
+ std : : to_string ( pObj - > header . translation . y ) + " f, "
+ std : : to_string ( pObj - > header . translation . z ) + " f }, " +
std : : to_string ( pObj - > header . scale . x ) + " f, " +
// for whatever reason, the rotation inside the sgbs is the inverse of what the game uses
std : : to_string ( pObj - > header . rotation . y * - 1.f ) + " f ); \n " + states ;
std : : string outStr (
std : : to_string ( id ) + " , " + typeStr + " \" " + name + " \" , " +
std : : to_string ( pObj - > header . translation . x ) + " , " +
std : : to_string ( pObj - > header . translation . y ) + " , " +
std : : to_string ( pObj - > header . translation . z ) + " , " +
std : : to_string ( eobjlevelHierachyId ) + " \n "
) ;
//eobjOut.write( outStr.c_str(), outStr.size() );
}
2018-02-26 23:50:50 +01:00
}
2018-08-29 21:40:59 +02:00
}
}
std : : cout < < " [Info] " < < " Total Groups " < < totalGroups < < " Total entries " < < totalGroupEntries < < " \n " ;
2018-02-26 23:50:50 +01:00
}
2018-08-29 21:40:59 +02:00
std : : cout < < " [Success] " < < " Exported " < < zoneName < < " in " < <
std : : chrono : : duration_cast < std : : chrono : : seconds > (
std : : chrono : : system_clock : : now ( ) - entryStartTime ) . count ( ) < < " seconds \n " ;
}
catch ( std : : exception & e )
{
std : : cout < < " [Error] " < < e . what ( ) < < std : : endl ;
std : : cout < < " [Error] "
< < " Unable to extract collision data. \n \t If using standalone ensure your working directory folder layout is \n \t bg/[ffxiv|ex1|ex2]/teri/type/zone/[level|collision] "
< < std : : endl ;
std : : cout < < std : : endl ;
std : : cout < < " [Info] " < < " Usage: pcb_reader2 territory \" path/to/game/sqpack/ffxiv \" " < < std : : endl ;
}
std : : cout < < " \n \n \n " ;
2019-03-31 13:06:37 +02:00
std : : ifstream t ;
if ( entry . type = = 7 )
{
t = std : : ifstream ( " questbattle.tmpl " ) ;
}
else
t = std : : ifstream ( " instance.tmpl " ) ;
2018-08-29 21:40:59 +02:00
std : : string instanceTpl ( ( std : : istreambuf_iterator < char > ( t ) ) ,
std : : istreambuf_iterator < char > ( ) ) ;
2018-02-26 23:50:50 +01:00
2018-08-29 21:40:59 +02:00
auto result = std : : regex_replace ( instanceTpl , std : : regex ( " \\ INSTANCE_NAME " ) , entry . name ) ;
result = std : : regex_replace ( result , std : : regex ( " \\ INSTANCE_ID " ) , std : : to_string ( entry . id ) ) ;
result = std : : regex_replace ( result , std : : regex ( " \\ EOBJ_INIT " ) , eobjects ) ;
2018-02-26 23:50:50 +01:00
2019-03-31 13:06:37 +02:00
if ( entry . type = = 7 )
{
if ( entry . id > 200 )
continue ;
2019-04-11 13:23:01 +02:00
auto qb = g_exdData . get < Sapphire : : Data : : QuestBattle > ( entry . id ) ;
if ( ! qb )
continue ;
2019-03-31 13:06:37 +02:00
std : : string instruction ;
for ( int i = 0 ; i < 149 ; + + i )
{
2019-04-11 13:23:01 +02:00
if ( qb - > scriptInstruction [ i ] . empty ( ) )
2019-03-31 13:06:37 +02:00
continue ;
2019-04-11 13:23:01 +02:00
instruction + = " static constexpr auto " + qb - > scriptInstruction [ i ] + " = " +
std : : to_string ( qb - > scriptValue [ i ] ) + " ; \n " ;
2019-03-31 13:06:37 +02:00
}
result = std : : regex_replace ( result , std : : regex ( " \\ SCRIPT_INSTRUCTIONS " ) , instruction ) ;
}
2018-02-26 23:50:50 +01:00
2018-08-29 21:40:59 +02:00
std : : string subdir = " " ;
2018-03-04 17:49:18 +11:00
2019-02-20 19:54:15 +11:00
auto subdirIt = instanceContentTypeMap . find ( entry . type ) ;
if ( subdirIt ! = instanceContentTypeMap . end ( ) )
2018-08-29 21:40:59 +02:00
subdir = subdirIt - > second + " / " ;
2018-03-04 17:49:18 +11:00
2018-10-25 13:38:06 +11:00
fs : : path outDir ( " instances/ " + subdir ) ;
fs : : create_directories ( outDir ) ;
2018-03-04 17:49:18 +11:00
2018-08-29 21:40:59 +02:00
std : : ofstream outH ( outDir . string ( ) + entry . name + " .cpp " ) ;
outH < < result ;
outH . close ( ) ;
2018-03-04 17:49:18 +11:00
2018-08-29 21:40:59 +02:00
}
2018-02-26 23:50:50 +01:00
2018-08-29 21:40:59 +02:00
std : : cout < < " \n \n \n [Success] Finished all tasks in " < <
std : : chrono : : duration_cast < std : : chrono : : seconds > ( std : : chrono : : system_clock : : now ( ) - startTime ) . count ( )
< < " seconds \n " ;
2018-02-26 23:50:50 +01:00
2019-02-20 19:54:15 +11:00
// getchar();
2018-02-26 23:50:50 +01:00
2018-08-29 21:40:59 +02:00
if ( data1 )
delete data1 ;
return 0 ;
2018-02-26 23:50:50 +01:00
}