mirror of
https://github.com/SapphireServer/Sapphire.git
synced 2025-05-21 17:47:45 +00:00
Cleanup, Improvements
- Refactored datReader and several other files for code cleanliness - Enhanced runtime performance by optimizing select functions, utilizing std::string_view in place of std::string where appropriate - Removed deprecated filesystem implementation - Introduced Link Time Optimization (LTO) support for Linux builds - Enabled parallel builds for GCC/Clang compilers - Expanded and improved comments for various functions - Replaced version check failure with warning, allowing for continued use with a cautionary message Tested on MSVC/Windows and Clang/Ubuntu
This commit is contained in:
parent
4256d55d23
commit
8dd40b1378
46 changed files with 825 additions and 701 deletions
|
@ -1,7 +1,24 @@
|
|||
|
||||
if( UNIX )
|
||||
# override policy CMP0069 to NEW
|
||||
set( CMAKE_POLICY_DEFAULT_CMP0069 NEW )
|
||||
cmake_policy( SET CMP0069 NEW )
|
||||
|
||||
set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17 -fPIC" )
|
||||
set( CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS} -O3")
|
||||
set( CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS} -O3" )
|
||||
|
||||
# enable parallel builds for GCC/Clang with Make
|
||||
if(${CMAKE_GENERATOR} MATCHES "Make")
|
||||
set( CMAKE_MAKE_PROGRAM "${CMAKE_MAKE_PROGRAM} -j$(nproc)" )
|
||||
endif()
|
||||
|
||||
# enable Link Time Optimization (LTO)
|
||||
include( CheckIPOSupported )
|
||||
check_ipo_supported( RESULT result )
|
||||
if( result )
|
||||
set( CMAKE_INTERPROCEDURAL_OPTIMIZATION TRUE )
|
||||
else()
|
||||
message( WARNING "IPO is not supported on this platform." )
|
||||
endif()
|
||||
else()
|
||||
add_definitions( -D_WIN32_WINNT=0x601 )
|
||||
add_definitions( -D_CRT_SECURE_NO_WARNINGS )
|
||||
|
|
40
deps/datReader/Dat.cpp
vendored
40
deps/datReader/Dat.cpp
vendored
|
@ -276,37 +276,61 @@ namespace xiv::dat
|
|||
|
||||
default:
|
||||
throw std::runtime_error(
|
||||
"Invalid entry_type: " + std::to_string( static_cast<uint32_t>(file_header.entry_type) ) );
|
||||
"Invalid entry_type: " + std::to_string( static_cast< uint32_t >( file_header.entry_type ) ) );
|
||||
}
|
||||
}
|
||||
|
||||
return outputFile;
|
||||
}
|
||||
|
||||
void Dat::extractBlock( uint32_t i_offset, std::vector< char >& o_data )
|
||||
void Dat::extractBlock( uint32_t i_offset, std::vector< char >& o_data )
|
||||
{
|
||||
m_handle.seekg( i_offset );
|
||||
|
||||
if( !m_handle.good() )
|
||||
{
|
||||
throw std::runtime_error( "Failed to set stream position." );
|
||||
}
|
||||
|
||||
auto block_header = extract< DatBlockHeader >( m_handle );
|
||||
|
||||
// Resizing the vector to write directly into it
|
||||
if( !m_handle.good() )
|
||||
{
|
||||
throw std::runtime_error( "Failed to read block header." );
|
||||
}
|
||||
|
||||
// Reserving space in the output vector to avoid reallocations
|
||||
const auto data_size = o_data.size();
|
||||
o_data.resize( data_size + block_header.uncompressed_size );
|
||||
o_data.reserve( data_size + block_header.uncompressed_size );
|
||||
|
||||
// 32000 in compressed_size means it is not compressed so take uncompressed_size
|
||||
if( block_header.compressed_size == 32000 )
|
||||
{
|
||||
m_handle.read( o_data.data() + data_size, block_header.uncompressed_size );
|
||||
|
||||
if( !m_handle.good() )
|
||||
{
|
||||
throw std::runtime_error( "Failed to read uncompressed data." );
|
||||
}
|
||||
|
||||
o_data.resize( data_size + block_header.uncompressed_size );
|
||||
}
|
||||
else
|
||||
{
|
||||
// If it is compressed use zlib
|
||||
// Read the data to be decompressed
|
||||
std::vector< char > temp_buffer( block_header.compressed_size );
|
||||
m_handle.read( temp_buffer.data(), block_header.compressed_size );
|
||||
auto temp_buffer = std::make_unique< char[] >( block_header.compressed_size );
|
||||
m_handle.read( temp_buffer.get(), block_header.compressed_size );
|
||||
|
||||
utils::zlib::no_header_decompress( reinterpret_cast< uint8_t* >( temp_buffer.data() ),
|
||||
temp_buffer.size(),
|
||||
if( !m_handle.good() )
|
||||
{
|
||||
throw std::runtime_error( "Failed to read compressed data." );
|
||||
}
|
||||
|
||||
o_data.resize( data_size + block_header.uncompressed_size );
|
||||
|
||||
utils::zlib::no_header_decompress( reinterpret_cast< uint8_t* >( temp_buffer.get() ),
|
||||
block_header.compressed_size,
|
||||
reinterpret_cast< uint8_t* >( o_data.data() + data_size ),
|
||||
static_cast< size_t >( block_header.uncompressed_size ) );
|
||||
}
|
||||
|
|
108
deps/datReader/DatCat.cpp
vendored
108
deps/datReader/DatCat.cpp
vendored
|
@ -5,73 +5,71 @@
|
|||
#include "GameData.h"
|
||||
#include "Index.h"
|
||||
|
||||
namespace xiv
|
||||
namespace xiv::dat
|
||||
{
|
||||
namespace dat
|
||||
Cat::Cat( const std::filesystem::path& basePath, uint32_t catNum, const std::string& name ) : m_name( name ),
|
||||
m_catNum( catNum ),
|
||||
m_chunk( -1 )
|
||||
{
|
||||
// Format the category number as a two-digit hex string
|
||||
std::stringstream ss;
|
||||
ss << std::setw( 2 ) << std::setfill( '0' ) << std::hex << catNum;
|
||||
std::string prefix = ss.str() + "0000.win32";
|
||||
|
||||
Cat::Cat( const std::filesystem::path& basePath, uint32_t catNum, const std::string& name ) : m_name( name ),
|
||||
m_catNum( catNum ),
|
||||
m_chunk( -1 )
|
||||
// Create an Index object using the formatted category number and basePath
|
||||
m_index = std::make_unique< Index >( basePath / "ffxiv" / ( prefix + ".index" ) );
|
||||
|
||||
// Create Dat objects for each entry in the index
|
||||
for( uint32_t i = 0; i < getIndex().getDatCount(); ++i )
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << std::setw( 2 ) << std::setfill( '0' ) << std::hex << catNum;
|
||||
std::string prefix = ss.str() + "0000.win32";
|
||||
|
||||
m_index = std::make_unique< Index >( basePath / "ffxiv" / ( prefix + ".index" ) );
|
||||
|
||||
for( uint32_t i = 0; i < getIndex().getDatCount(); ++i )
|
||||
{
|
||||
m_dats.emplace_back( std::make_unique< Dat >( basePath / "ffxiv" / ( prefix + ".dat" + std::to_string( i ) ), i ) );
|
||||
}
|
||||
m_dats.emplace_back( std::make_unique< Dat >( basePath / "ffxiv" / ( prefix + ".dat" + std::to_string( i ) ), i ) );
|
||||
}
|
||||
}
|
||||
|
||||
Cat::Cat( const std::filesystem::path& basePath, uint32_t catNum, const std::string& name, uint32_t exNum, uint32_t chunk ) : m_name( name ),
|
||||
m_catNum( catNum ),
|
||||
m_chunk( chunk )
|
||||
Cat::Cat( const std::filesystem::path& basePath, uint32_t catNum, const std::string& name, uint32_t exNum, uint32_t chunk ) : m_name( name ),
|
||||
m_catNum( catNum ),
|
||||
m_chunk( chunk )
|
||||
{
|
||||
// Create an Index object using the basePath and formatted information
|
||||
m_index = std::make_unique< Index >( basePath / GameData::buildDatStr( "ex" + std::to_string( exNum ), catNum, exNum, chunk, "win32", "index" ) );
|
||||
|
||||
// Create Dat objects for each entry in the index
|
||||
for( uint32_t i = 0; i < getIndex().getDatCount(); ++i )
|
||||
{
|
||||
m_index = std::make_unique< Index >( basePath / GameData::buildDatStr( "ex" + std::to_string( exNum ), catNum, exNum, chunk, "win32", "index" ) );
|
||||
|
||||
for( uint32_t i = 0; i < getIndex().getDatCount(); ++i )
|
||||
{
|
||||
m_dats.emplace_back( std::make_unique< Dat >( basePath / GameData::buildDatStr( "ex" + std::to_string( exNum ), catNum, exNum, chunk, "win32", "dat" + std::to_string( i ) ), i ) );
|
||||
}
|
||||
m_dats.emplace_back( std::make_unique< Dat >( basePath / GameData::buildDatStr( "ex" + std::to_string( exNum ), catNum, exNum, chunk, "win32", "dat" + std::to_string( i ) ), i ) );
|
||||
}
|
||||
}
|
||||
|
||||
Cat::~Cat()
|
||||
{
|
||||
}
|
||||
Cat::~Cat() = default;
|
||||
|
||||
const Index& Cat::getIndex() const
|
||||
{
|
||||
return *m_index;
|
||||
}
|
||||
const Index& Cat::getIndex() const
|
||||
{
|
||||
return *m_index;
|
||||
}
|
||||
|
||||
std::unique_ptr< File > Cat::getFile( uint32_t dir_hash, uint32_t filename_hash ) const
|
||||
{
|
||||
auto& hash_table_entry = getIndex().getHashTableEntry( dir_hash, filename_hash );
|
||||
return m_dats[ hash_table_entry.datNum ]->getFile( hash_table_entry.datOffset );
|
||||
}
|
||||
std::unique_ptr< File > Cat::getFile( uint32_t dir_hash, uint32_t filename_hash ) const
|
||||
{
|
||||
auto& hash_table_entry = getIndex().getHashTableEntry( dir_hash, filename_hash );
|
||||
return m_dats[ hash_table_entry.datNum ]->getFile( hash_table_entry.datOffset );
|
||||
}
|
||||
|
||||
bool Cat::doesFileExist( uint32_t dir_hash, uint32_t filename_hash ) const
|
||||
{
|
||||
return getIndex().doesFileExist( dir_hash, filename_hash );
|
||||
}
|
||||
bool Cat::doesFileExist( uint32_t dir_hash, uint32_t filename_hash ) const
|
||||
{
|
||||
return getIndex().doesFileExist( dir_hash, filename_hash );
|
||||
}
|
||||
|
||||
bool Cat::doesDirExist( uint32_t dir_hash ) const
|
||||
{
|
||||
return getIndex().doesDirExist( dir_hash );
|
||||
}
|
||||
bool Cat::doesDirExist( uint32_t dir_hash ) const
|
||||
{
|
||||
return getIndex().doesDirExist( dir_hash );
|
||||
}
|
||||
|
||||
const std::string& Cat::getName() const
|
||||
{
|
||||
return m_name;
|
||||
}
|
||||
const std::string& Cat::getName() const
|
||||
{
|
||||
return m_name;
|
||||
}
|
||||
|
||||
uint32_t Cat::getCatNum() const
|
||||
{
|
||||
return m_catNum;
|
||||
}
|
||||
|
||||
}// namespace dat
|
||||
}// namespace xiv
|
||||
uint32_t Cat::getCatNum() const
|
||||
{
|
||||
return m_catNum;
|
||||
}
|
||||
}// namespace xiv::dat
|
8
deps/datReader/DatCat.h
vendored
8
deps/datReader/DatCat.h
vendored
|
@ -38,16 +38,16 @@ namespace xiv::dat
|
|||
// Retrieve a file from the category given its hashes
|
||||
std::unique_ptr< File > getFile( uint32_t dir_hash, uint32_t filename_hash ) const;
|
||||
|
||||
|
||||
// Returns whether a file exists in the Cat based on the given directory and filename hashes
|
||||
bool doesFileExist( uint32_t dir_hash, uint32_t filename_hash ) const;
|
||||
|
||||
// Returns whether a directory exists in the Cat based on the given directory hash
|
||||
bool doesDirExist( uint32_t dir_hash ) const;
|
||||
|
||||
|
||||
// Returns thename of the category
|
||||
// Returns the name of the Cat object
|
||||
const std::string& getName() const;
|
||||
|
||||
// Returns the number of the category
|
||||
// Returns the category number of the Cat object
|
||||
uint32_t getCatNum() const;
|
||||
|
||||
protected:
|
||||
|
|
92
deps/datReader/DatCategories/bg/lgb.h
vendored
92
deps/datReader/DatCategories/bg/lgb.h
vendored
|
@ -82,7 +82,8 @@ public:
|
|||
};
|
||||
};
|
||||
|
||||
struct LGB_ENPC_ENTRY : public LgbEntry {
|
||||
struct LGB_ENPC_ENTRY : public LgbEntry
|
||||
{
|
||||
public:
|
||||
ENpcData data;
|
||||
std::string_view name;
|
||||
|
@ -94,7 +95,8 @@ public:
|
|||
};
|
||||
};
|
||||
|
||||
struct LGB_EOBJ_ENTRY : public LgbEntry {
|
||||
struct LGB_EOBJ_ENTRY : public LgbEntry
|
||||
{
|
||||
public:
|
||||
EObjData data;
|
||||
std::string_view name;
|
||||
|
@ -106,7 +108,8 @@ public:
|
|||
};
|
||||
};
|
||||
|
||||
struct LGB_MAP_RANGE_ENTRY : public LgbEntry {
|
||||
struct LGB_MAP_RANGE_ENTRY : public LgbEntry
|
||||
{
|
||||
public:
|
||||
MapRangeData data;
|
||||
std::string_view name;
|
||||
|
@ -118,7 +121,8 @@ public:
|
|||
};
|
||||
};
|
||||
|
||||
struct LGB_EXIT_RANGE_ENTRY : public LgbEntry {
|
||||
struct LGB_EXIT_RANGE_ENTRY : public LgbEntry
|
||||
{
|
||||
public:
|
||||
ExitRangeData data;
|
||||
std::string_view name;
|
||||
|
@ -130,7 +134,8 @@ public:
|
|||
};
|
||||
};
|
||||
|
||||
struct LGB_POP_RANGE_ENTRY : public LgbEntry {
|
||||
struct LGB_POP_RANGE_ENTRY : public LgbEntry
|
||||
{
|
||||
public:
|
||||
PopRangeData data;
|
||||
|
||||
|
@ -140,7 +145,8 @@ public:
|
|||
};
|
||||
};
|
||||
|
||||
struct LGB_EVENT_RANGE_ENTRY : public LgbEntry {
|
||||
struct LGB_EVENT_RANGE_ENTRY : public LgbEntry
|
||||
{
|
||||
public:
|
||||
EventRangeData data;
|
||||
|
||||
|
@ -198,7 +204,7 @@ struct LGB_GROUP
|
|||
LGB_FILE* parent;
|
||||
LGB_GROUP_HEADER header;
|
||||
LayerSetReferencedList layerSetReferencedList;
|
||||
std::string name;
|
||||
std::string_view name;
|
||||
std::vector< std::shared_ptr< LgbEntry > > entries;
|
||||
std::vector< LayerSetReferenced > refs;
|
||||
|
||||
|
@ -206,19 +212,32 @@ struct LGB_GROUP
|
|||
{
|
||||
parent = parentStruct;
|
||||
header = *reinterpret_cast< LGB_GROUP_HEADER* >( buf + offset );
|
||||
name = std::string( buf + offset + header.groupNameOffset );
|
||||
name = std::string_view( buf + offset + header.groupNameOffset );
|
||||
|
||||
// Initialize the layerSetReferencedList from the buffer and offset
|
||||
layerSetReferencedList = *reinterpret_cast< LayerSetReferencedList* >( buf + offset + header.LayerSetRef );
|
||||
|
||||
// Check if there are any layer set references to initialize
|
||||
if( layerSetReferencedList.LayerSetCount > 0 )
|
||||
{
|
||||
refs.resize( layerSetReferencedList.LayerSetCount );
|
||||
std::memcpy( refs.data(), buf + offset + header.LayerSetRef + layerSetReferencedList.LayerSets, layerSetReferencedList.LayerSetCount * sizeof( LayerSetReferenced ) );
|
||||
// Reserve memory for layer set references
|
||||
refs.reserve( layerSetReferencedList.LayerSetCount );
|
||||
|
||||
// Iterate through each layer set reference and construct LayerSetReferenced objects from the buffer
|
||||
for( size_t i = 0; i < layerSetReferencedList.LayerSetCount; ++i )
|
||||
{
|
||||
LayerSetReferenced ref = *reinterpret_cast< LayerSetReferenced* >( buf + offset + header.LayerSetRef + layerSetReferencedList.LayerSets + i * sizeof( LayerSetReferenced ) );
|
||||
refs.emplace_back( ref );
|
||||
}
|
||||
}
|
||||
|
||||
// Reserve memory for entries
|
||||
entries.reserve( header.entryCount );
|
||||
|
||||
// Calculate the offset for entries
|
||||
const auto entriesOffset = offset + header.entriesOffset;
|
||||
|
||||
// Iterate through each entry and construct the appropriate objects (not shown in the code snippet)
|
||||
for( auto i = 0; i < header.entryCount; ++i )
|
||||
{
|
||||
const auto entryOffset = entriesOffset + *reinterpret_cast< int32_t* >( buf + ( entriesOffset + i * 4 ) );
|
||||
|
@ -277,7 +296,7 @@ struct LGB_GROUP
|
|||
}
|
||||
catch( std::exception& e )
|
||||
{
|
||||
std::cout << name << " " << e.what() << std::endl;
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -296,63 +315,38 @@ struct LGB_FILE_HEADER
|
|||
int32_t groupCount;
|
||||
};
|
||||
|
||||
struct LGB_FILE {
|
||||
struct LGB_FILE
|
||||
{
|
||||
LGB_FILE_HEADER header;
|
||||
std::vector< LGB_GROUP > groups;
|
||||
std::string m_name;
|
||||
|
||||
// Constructor that initializes an LGB_FILE object from a buffer and a name
|
||||
LGB_FILE( char* buf, const std::string& name ) : LGB_FILE( buf )
|
||||
{
|
||||
m_name = name;
|
||||
}
|
||||
|
||||
// Constructor that initializes an LGB_FILE object from a buffer
|
||||
LGB_FILE( char* buf )
|
||||
{
|
||||
// Reinterpret the buffer as an LGB_FILE_HEADER pointer and dereference it
|
||||
header = *reinterpret_cast< LGB_FILE_HEADER* >( buf );
|
||||
|
||||
// Check for a valid file header
|
||||
if( strncmp( &header.magic[ 0 ], "LGB1", 4 ) != 0 || strncmp( &header.magic2[ 0 ], "LGP1", 4 ) != 0 )
|
||||
{
|
||||
throw std::runtime_error( "Invalid LGB file!" );
|
||||
}
|
||||
|
||||
constexpr auto baseOffset = sizeof( header );
|
||||
groups.reserve( header.groupCount );
|
||||
groups.reserve( header.groupCount );// Reserve memory for the groups
|
||||
|
||||
// Iterate through each group and construct LGB_GROUP objects from the buffer
|
||||
for( size_t i = 0; i < header.groupCount; ++i )
|
||||
{
|
||||
const auto groupOffset = baseOffset + *reinterpret_cast< int32_t* >( buf + ( baseOffset + i * 4 ) );
|
||||
groups.emplace_back( buf, this, groupOffset );
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
#if __cplusplus >= 201703L
|
||||
#include <experimental/filesystem>
|
||||
std::map<std::string, LGB_FILE> getLgbFiles( const std::string& dir )
|
||||
{
|
||||
namespace fs = std::experimental::filesystem;
|
||||
std::map<std::string, LGB_FILE> fileMap;
|
||||
for( const auto& path : fs::recursive_directory_iterator( dir ) )
|
||||
{
|
||||
if( path.path().extension() == ".lgb" )
|
||||
{
|
||||
const auto& strPath = path.path().string();
|
||||
auto f = fopen( strPath.c_str(), "rb" );
|
||||
fseek( f, 0, SEEK_END );
|
||||
const auto size = ftell( f );
|
||||
std::vector<char> bytes( size );
|
||||
rewind( f );
|
||||
fread( bytes.data(), 1, size, f );
|
||||
fclose( f );
|
||||
try
|
||||
{
|
||||
LGB_FILE lgbFile( bytes.data() );
|
||||
fileMap.insert( std::make_pair( strPath, lgbFile ) );
|
||||
}
|
||||
catch( std::exception& e )
|
||||
{
|
||||
std::cout << "Unable to load " << strPath << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
return fileMap;
|
||||
}
|
||||
#endif
|
||||
*/
|
31
deps/datReader/DatCategories/bg/matrix4.h
vendored
31
deps/datReader/DatCategories/bg/matrix4.h
vendored
|
@ -86,24 +86,29 @@ struct matrix4
|
|||
return ret;
|
||||
}
|
||||
|
||||
// Multiplies two 4x4 matrices and returns the result
|
||||
matrix4 operator*( const matrix4& rhs ) const
|
||||
{
|
||||
matrix4 ret;
|
||||
for( unsigned int i = 0; i < 4; i++ )
|
||||
|
||||
// Iterate through each row of the resulting matrix
|
||||
for( unsigned int row = 0; row < 4; row++ )
|
||||
{
|
||||
ret( i, 0 ) =
|
||||
( *this )( i, 0 ) * rhs( 0, 0 ) + ( *this )( i, 1 ) * rhs( 1, 0 ) + ( *this )( i, 2 ) * rhs( 2, 0 ) +
|
||||
( *this )( i, 3 ) * rhs( 3, 0 );
|
||||
ret( i, 1 ) =
|
||||
( *this )( i, 0 ) * rhs( 0, 1 ) + ( *this )( i, 1 ) * rhs( 1, 1 ) + ( *this )( i, 2 ) * rhs( 2, 1 ) +
|
||||
( *this )( i, 3 ) * rhs( 3, 1 );
|
||||
ret( i, 2 ) =
|
||||
( *this )( i, 0 ) * rhs( 0, 2 ) + ( *this )( i, 1 ) * rhs( 1, 2 ) + ( *this )( i, 2 ) * rhs( 2, 2 ) +
|
||||
( *this )( i, 3 ) * rhs( 3, 2 );
|
||||
ret( i, 3 ) =
|
||||
( *this )( i, 0 ) * rhs( 0, 3 ) + ( *this )( i, 1 ) * rhs( 1, 3 ) + ( *this )( i, 2 ) * rhs( 2, 3 ) +
|
||||
( *this )( i, 3 ) * rhs( 3, 3 );
|
||||
// Iterate through each column of the resulting matrix
|
||||
for( unsigned int col = 0; col < 4; col++ )
|
||||
{
|
||||
// Calculate the value for the current cell by summing the product of the corresponding row and column elements
|
||||
float value = 0;
|
||||
for( unsigned int k = 0; k < 4; k++ )
|
||||
{
|
||||
value += ( *this )( row, k ) * rhs( k, col );
|
||||
}
|
||||
|
||||
// Assign the calculated value to the corresponding cell of the resulting matrix
|
||||
ret( row, col ) = value;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
|
|
59
deps/datReader/DatCategories/bg/sgb.h
vendored
59
deps/datReader/DatCategories/bg/sgb.h
vendored
|
@ -1,5 +1,4 @@
|
|||
#ifndef _SGB_H
|
||||
#define _SGB_H
|
||||
#pragma once
|
||||
|
||||
#include <cstring>
|
||||
#include <memory>
|
||||
|
@ -132,24 +131,24 @@ struct SGB_MODEL_ENTRY : public SGB_GROUP_ENTRY
|
|||
{
|
||||
SGB_MODEL_HEADER header;
|
||||
SgbGroupEntryType type;
|
||||
std::string name;
|
||||
std::string modelFileName;
|
||||
std::string collisionFileName;
|
||||
std::string_view name;
|
||||
std::string_view modelFileName;
|
||||
std::string_view collisionFileName;
|
||||
|
||||
SGB_MODEL_ENTRY( char* buf, size_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 );
|
||||
collisionFileName = std::string( buf + offset + header.collisionFileOffset );
|
||||
name = std::string_view( buf + offset + header.nameOffset );
|
||||
modelFileName = std::string_view( buf + offset + header.modelFileOffset );
|
||||
collisionFileName = std::string_view( buf + offset + header.collisionFileOffset );
|
||||
}
|
||||
};
|
||||
|
||||
struct SGB_GROUP
|
||||
{
|
||||
SGB_GROUP_HEADER header;
|
||||
std::string name;
|
||||
std::string_view name;
|
||||
SGB_FILE* parent;
|
||||
std::vector< std::shared_ptr< SGB_GROUP_ENTRY > > entries;
|
||||
|
||||
|
@ -157,23 +156,32 @@ struct SGB_GROUP
|
|||
{
|
||||
parent = file;
|
||||
header = *reinterpret_cast< SGB_GROUP_HEADER* >( buf + offset );
|
||||
name = std::string( buf + offset + header.nameOffset );
|
||||
name = std::string_view( buf + offset + header.nameOffset );
|
||||
|
||||
auto entriesOffset = offset + sizeof( header );
|
||||
|
||||
entries.reserve( header.entryCount );
|
||||
|
||||
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 || type == SgbGroupEntryType::Gimmick )
|
||||
|
||||
switch( type )
|
||||
{
|
||||
entries.push_back( std::make_shared< SGB_MODEL_ENTRY >( buf, entryOffset, ( SgbGroupEntryType )type ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
// std::cout << "\t\tUnknown SGB entry! Group: " << name << " type: " << type << " index: " << i << " entryOffset: " << entryOffset << "\n";
|
||||
case SgbGroupEntryType::Model:
|
||||
case SgbGroupEntryType::Gimmick:
|
||||
{
|
||||
entries.emplace_back( std::make_shared< SGB_MODEL_ENTRY >( buf, entryOffset, ( SgbGroupEntryType ) type ) );
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -268,27 +276,28 @@ struct SGB_FILE
|
|||
|
||||
try
|
||||
{
|
||||
entries.reserve( 2 );
|
||||
|
||||
auto group = SGB_GROUP( buf, this, header.fileSize, baseOffset + header.sharedOffset );
|
||||
entries.push_back( group );
|
||||
entries.emplace_back( group );
|
||||
auto group2 = SGB_GROUP( buf, this, header.fileSize, baseOffset + header.offset1C );
|
||||
entries.push_back( group2 );
|
||||
entries.emplace_back( group2 );
|
||||
|
||||
uint32_t stateCount = *reinterpret_cast< uint32_t* >( buf + baseOffset + header.statesOffset + 4 );
|
||||
if( stateCount > 0 )
|
||||
{
|
||||
stateCount = stateCount;
|
||||
stateEntries.reserve( stateCount );
|
||||
|
||||
for( size_t i = 0; i < stateCount; ++i )
|
||||
{
|
||||
auto state = SGB_STATE_ENTRY( buf + baseOffset + header.statesOffset + 8 + i * sizeof( SGB_STATE_HEADER ) );
|
||||
stateEntries.push_back( state );
|
||||
std::cout << state.name << "\n";
|
||||
stateEntries.emplace_back( state );
|
||||
}
|
||||
}
|
||||
}
|
||||
catch( std::exception& e )
|
||||
{
|
||||
std::cout << e.what() << "\n";
|
||||
throw std::runtime_error( std::string( "Failed to load SGB file: " ) + e.what() );
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
#endif // !_SGB_H
|
||||
};
|
22
deps/datReader/Exd.cpp
vendored
22
deps/datReader/Exd.cpp
vendored
|
@ -9,12 +9,11 @@ using xiv::utils::bparse::extract;
|
|||
|
||||
namespace xiv::exd
|
||||
{
|
||||
Exd::Exd( std::shared_ptr< Exh > i_exh, const std::vector< std::shared_ptr< dat::File>>& i_files )
|
||||
Exd::Exd( std::shared_ptr< Exh > i_exh, const std::vector< std::shared_ptr< dat::File > >& i_files )
|
||||
{
|
||||
_exh = i_exh;
|
||||
_files = i_files;
|
||||
|
||||
|
||||
// Iterates over all the files
|
||||
const uint32_t member_count = static_cast< uint32_t >( _exh->get_members().size() );
|
||||
for( auto& file_ptr : _files )
|
||||
|
@ -29,8 +28,6 @@ namespace xiv::exd
|
|||
|
||||
// Preallocate and extract the record_indices
|
||||
const uint32_t record_count = exd_header.index_size / sizeof( ExdRecordIndexData );
|
||||
std::vector< ExdRecordIndexData > record_indices;
|
||||
record_indices.reserve( record_count );
|
||||
for( uint32_t i = 0; i < record_count; ++i )
|
||||
{
|
||||
auto recordIndex = extract< ExdRecordIndexData >( iss );
|
||||
|
@ -39,25 +36,22 @@ namespace xiv::exd
|
|||
}
|
||||
}
|
||||
|
||||
Exd::~Exd()
|
||||
const std::vector< Field > Exd::get_row( uint32_t id, uint32_t subRow )
|
||||
{
|
||||
}
|
||||
|
||||
const std::vector< Field > Exd::get_row( uint32_t id, uint32_t subRow )
|
||||
{
|
||||
|
||||
// Check if id is in the cache
|
||||
auto cacheEntryIt = _idCache.find( id );
|
||||
if( cacheEntryIt == _idCache.end() )
|
||||
throw std::runtime_error( "Id not found: " + std::to_string( id ) );
|
||||
|
||||
// Iterates over all the files
|
||||
// Retrieve the corresponding file
|
||||
const uint32_t member_count = static_cast< uint32_t >( _exh->get_members().size() );
|
||||
auto& file_ptr = cacheEntryIt->second.file;
|
||||
|
||||
// Create a string from the data section and use it to initialize an input string stream
|
||||
std::vector< char > dataCpy = file_ptr->get_data_sections().front();
|
||||
std::istringstream iss( std::string( dataCpy.begin(), dataCpy.end() ) );
|
||||
|
||||
// Get the vector fields for the given record and preallocate it
|
||||
// Retrieve the vector fields for the given record and preallocate it
|
||||
auto fields = _data[ id ];
|
||||
fields.reserve( member_count );
|
||||
iss.seekg( cacheEntryIt->second.offset + 6 );
|
||||
|
@ -69,10 +63,10 @@ namespace xiv::exd
|
|||
|
||||
int offset = cacheEntryIt->second.offset + 6 + ( subRow * _exh->get_header().data_offset + 2 * ( subRow + 1 ) );
|
||||
|
||||
// Iterate over the member entries and extract the corresponding data
|
||||
for( auto& member_entry : _exh->get_exh_members() )
|
||||
{
|
||||
// Seek to the position of the member to extract.
|
||||
// 6 is because we have uint32_t/uint16_t at the start of each record
|
||||
// Seek to the position of the member to extract
|
||||
iss.seekg( offset + member_entry.offset );
|
||||
|
||||
// Switch depending on the type to extract
|
||||
|
|
177
deps/datReader/Exd.h
vendored
177
deps/datReader/Exd.h
vendored
|
@ -1,18 +1,18 @@
|
|||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
|
||||
#include <variant>
|
||||
|
||||
#include "File.h"
|
||||
#include "Exd/Common.h"
|
||||
#include "Exd/Structs.h"
|
||||
#include "Exh.h"
|
||||
#include "File.h"
|
||||
#include "bparse.h"
|
||||
#include "stream.h"
|
||||
#include <fstream>
|
||||
#include "Exh.h"
|
||||
#include "bparse.h"
|
||||
|
||||
namespace xiv::exd
|
||||
{
|
||||
|
@ -27,7 +27,7 @@ namespace xiv::exd
|
|||
uint32_t id;
|
||||
uint32_t offset;
|
||||
};
|
||||
}
|
||||
}// namespace xiv::exd
|
||||
|
||||
namespace xiv::utils::bparse
|
||||
{
|
||||
|
@ -63,16 +63,16 @@ namespace xiv::exd
|
|||
|
||||
// Field type containing all the possible types in the data files
|
||||
using Field = std::variant<
|
||||
std::string,
|
||||
bool,
|
||||
int8_t,
|
||||
uint8_t,
|
||||
int16_t,
|
||||
uint16_t,
|
||||
int32_t,
|
||||
uint32_t,
|
||||
float,
|
||||
uint64_t >;
|
||||
std::string,
|
||||
bool,
|
||||
int8_t,
|
||||
uint8_t,
|
||||
int16_t,
|
||||
uint16_t,
|
||||
int32_t,
|
||||
uint32_t,
|
||||
float,
|
||||
uint64_t >;
|
||||
|
||||
struct ExdCacheEntry
|
||||
{
|
||||
|
@ -86,13 +86,11 @@ namespace xiv::exd
|
|||
public:
|
||||
// i_exh: the header
|
||||
// i_files: the multiple exd files
|
||||
Exd()
|
||||
{
|
||||
}
|
||||
Exd() = default;
|
||||
|
||||
Exd( std::shared_ptr< Exh > i_exh, const std::vector< std::shared_ptr< dat::File>>& i_files );
|
||||
Exd( std::shared_ptr< Exh > i_exh, const std::vector< std::shared_ptr< dat::File > >& i_files );
|
||||
|
||||
~Exd();
|
||||
~Exd() = default;
|
||||
|
||||
// Get a row by its id
|
||||
const std::vector< Field > get_row( uint32_t id );
|
||||
|
@ -107,9 +105,8 @@ namespace xiv::exd
|
|||
|
||||
if( sizeof( T ) != _exh->get_header().data_offset )
|
||||
{
|
||||
throw std::runtime_error(
|
||||
"the struct size (" + std::to_string( sizeof( T ) ) + ") doesn't match the size in the header (" +
|
||||
std::to_string( _exh->get_header().data_offset ) + ")!" );
|
||||
throw std::runtime_error( "the struct size (" + std::to_string( sizeof( T ) ) + ") doesn't match the size in the header (" +
|
||||
std::to_string( _exh->get_header().data_offset ) + ")!" );
|
||||
}
|
||||
|
||||
// Iterates over all the files
|
||||
|
@ -126,7 +123,7 @@ namespace xiv::exd
|
|||
fields.reserve( member_count );
|
||||
iss.seekg( cacheEntryIt->second.offset + 6 );
|
||||
|
||||
iss.read( reinterpret_cast<char*>( &pSheet.get()->_data ), sizeof( T ) );
|
||||
iss.read( reinterpret_cast< char* >( &pSheet.get()->_data ), sizeof( T ) );
|
||||
|
||||
int stringCount = 0;
|
||||
for( auto& member_entry : _exh->get_exh_members() )
|
||||
|
@ -148,7 +145,7 @@ namespace xiv::exd
|
|||
std::string value = utils::bparse::extract_cstring( iss, "string" );
|
||||
auto it = pSheet->_strings.insert( pSheet->_strings.end(), value );
|
||||
*reinterpret_cast< uint32_t* >( pSheet->ptr() + member_entry.offset ) =
|
||||
static_cast< uint32_t >( std::distance( pSheet->_strings.begin(), it ) );
|
||||
static_cast< uint32_t >( std::distance( pSheet->_strings.begin(), it ) );
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -166,46 +163,46 @@ namespace xiv::exd
|
|||
|
||||
|
||||
case DataType::int16:
|
||||
{
|
||||
int16_t value = bparse::extract< int16_t >( iss, "int16_t", false );
|
||||
*reinterpret_cast< int16_t* >( pSheet->ptr() + member_entry.offset ) = value;
|
||||
}
|
||||
break;
|
||||
{
|
||||
int16_t value = bparse::extract< int16_t >( iss, "int16_t", false );
|
||||
*reinterpret_cast< int16_t* >( pSheet->ptr() + member_entry.offset ) = value;
|
||||
}
|
||||
break;
|
||||
|
||||
case DataType::uint16:
|
||||
{
|
||||
uint16_t value = bparse::extract< uint16_t >( iss, "uint16_t", false );
|
||||
*reinterpret_cast< uint16_t* >( pSheet->ptr() + member_entry.offset ) = value;
|
||||
}
|
||||
break;
|
||||
{
|
||||
uint16_t value = bparse::extract< uint16_t >( iss, "uint16_t", false );
|
||||
*reinterpret_cast< uint16_t* >( pSheet->ptr() + member_entry.offset ) = value;
|
||||
}
|
||||
break;
|
||||
|
||||
case DataType::int32:
|
||||
{
|
||||
int32_t value = bparse::extract< int32_t >( iss, "int32_t", false );
|
||||
*reinterpret_cast< int32_t* >( pSheet->ptr() + member_entry.offset ) = value;
|
||||
}
|
||||
break;
|
||||
{
|
||||
int32_t value = bparse::extract< int32_t >( iss, "int32_t", false );
|
||||
*reinterpret_cast< int32_t* >( pSheet->ptr() + member_entry.offset ) = value;
|
||||
}
|
||||
break;
|
||||
|
||||
case DataType::uint32:
|
||||
{
|
||||
uint32_t value = bparse::extract< uint32_t >( iss, "uint32_t", false );
|
||||
*reinterpret_cast< uint32_t* >( pSheet->ptr() + member_entry.offset ) = value;
|
||||
}
|
||||
break;
|
||||
{
|
||||
uint32_t value = bparse::extract< uint32_t >( iss, "uint32_t", false );
|
||||
*reinterpret_cast< uint32_t* >( pSheet->ptr() + member_entry.offset ) = value;
|
||||
}
|
||||
break;
|
||||
|
||||
case DataType::float32:
|
||||
{
|
||||
float value = bparse::extract< float >( iss, "float", false );
|
||||
*reinterpret_cast< float* >( pSheet->ptr() + member_entry.offset ) = value;
|
||||
}
|
||||
break;
|
||||
{
|
||||
float value = bparse::extract< float >( iss, "float", false );
|
||||
*reinterpret_cast< float* >( pSheet->ptr() + member_entry.offset ) = value;
|
||||
}
|
||||
break;
|
||||
|
||||
case DataType::uint64:
|
||||
{
|
||||
uint64_t value = bparse::extract< uint64_t >( iss, "uint64_t", false );
|
||||
*reinterpret_cast< uint64_t* >( pSheet->ptr() + member_entry.offset ) = value;
|
||||
}
|
||||
break;
|
||||
{
|
||||
uint64_t value = bparse::extract< uint64_t >( iss, "uint64_t", false );
|
||||
*reinterpret_cast< uint64_t* >( pSheet->ptr() + member_entry.offset ) = value;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
auto type = static_cast< uint16_t >( member_entry.type );
|
||||
|
@ -221,7 +218,6 @@ namespace xiv::exd
|
|||
}
|
||||
|
||||
return pSheet;
|
||||
|
||||
}
|
||||
|
||||
// Get a row by its id and sub-row
|
||||
|
@ -237,7 +233,7 @@ namespace xiv::exd
|
|||
std::unordered_map< uint32_t, std::shared_ptr< Excel::ExcelStruct< T > > > sheets;
|
||||
|
||||
// Iterates over all the files
|
||||
const uint32_t member_count = static_cast< uint32_t >( _exh->get_members().size() );
|
||||
const uint32_t member_count = static_cast< uint32_t >( _exh->get_members().size() );
|
||||
for( auto& file_ptr : _files )
|
||||
{
|
||||
// Get a stream
|
||||
|
@ -270,7 +266,7 @@ namespace xiv::exd
|
|||
fields.reserve( member_count );
|
||||
iss.seekg( cacheEntryIt->second.offset + 6 );
|
||||
|
||||
iss.read( reinterpret_cast<char*>( &pSheet.get()->_data ), sizeof( T ) );
|
||||
iss.read( reinterpret_cast< char* >( &pSheet.get()->_data ), sizeof( T ) );
|
||||
|
||||
int stringCount = 0;
|
||||
for( auto& member_entry : _exh->get_exh_members() )
|
||||
|
@ -292,7 +288,7 @@ namespace xiv::exd
|
|||
std::string value = xiv::utils::bparse::extract_cstring( iss, "string" );
|
||||
auto it = pSheet->_strings.insert( pSheet->_strings.end(), value );
|
||||
*reinterpret_cast< uint32_t* >( pSheet->ptr() + member_entry.offset ) =
|
||||
static_cast< uint32_t >( std::distance( pSheet->_strings.begin(), it ) );
|
||||
static_cast< uint32_t >( std::distance( pSheet->_strings.begin(), it ) );
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -310,46 +306,46 @@ namespace xiv::exd
|
|||
|
||||
|
||||
case DataType::int16:
|
||||
{
|
||||
int16_t value = xiv::utils::bparse::extract< int16_t >( iss, "int16_t", false );
|
||||
*reinterpret_cast< int16_t* >( pSheet->ptr() + member_entry.offset ) = value;
|
||||
}
|
||||
break;
|
||||
{
|
||||
int16_t value = xiv::utils::bparse::extract< int16_t >( iss, "int16_t", false );
|
||||
*reinterpret_cast< int16_t* >( pSheet->ptr() + member_entry.offset ) = value;
|
||||
}
|
||||
break;
|
||||
|
||||
case DataType::uint16:
|
||||
{
|
||||
uint16_t value = xiv::utils::bparse::extract< uint16_t >( iss, "uint16_t", false );
|
||||
*reinterpret_cast< uint16_t* >( pSheet->ptr() + member_entry.offset ) = value;
|
||||
}
|
||||
break;
|
||||
{
|
||||
uint16_t value = xiv::utils::bparse::extract< uint16_t >( iss, "uint16_t", false );
|
||||
*reinterpret_cast< uint16_t* >( pSheet->ptr() + member_entry.offset ) = value;
|
||||
}
|
||||
break;
|
||||
|
||||
case DataType::int32:
|
||||
{
|
||||
int32_t value = xiv::utils::bparse::extract< int32_t >( iss, "int32_t", false );
|
||||
*reinterpret_cast< int32_t* >( pSheet->ptr() + member_entry.offset ) = value;
|
||||
}
|
||||
break;
|
||||
{
|
||||
int32_t value = xiv::utils::bparse::extract< int32_t >( iss, "int32_t", false );
|
||||
*reinterpret_cast< int32_t* >( pSheet->ptr() + member_entry.offset ) = value;
|
||||
}
|
||||
break;
|
||||
|
||||
case DataType::uint32:
|
||||
{
|
||||
uint32_t value = xiv::utils::bparse::extract< uint32_t >( iss, "uint32_t", false );
|
||||
*reinterpret_cast< uint32_t* >( pSheet->ptr() + member_entry.offset ) = value;
|
||||
}
|
||||
break;
|
||||
{
|
||||
uint32_t value = xiv::utils::bparse::extract< uint32_t >( iss, "uint32_t", false );
|
||||
*reinterpret_cast< uint32_t* >( pSheet->ptr() + member_entry.offset ) = value;
|
||||
}
|
||||
break;
|
||||
|
||||
case DataType::float32:
|
||||
{
|
||||
float value = xiv::utils::bparse::extract< float >( iss, "float", false );
|
||||
*reinterpret_cast< float* >( pSheet->ptr() + member_entry.offset ) = value;
|
||||
}
|
||||
break;
|
||||
{
|
||||
float value = xiv::utils::bparse::extract< float >( iss, "float", false );
|
||||
*reinterpret_cast< float* >( pSheet->ptr() + member_entry.offset ) = value;
|
||||
}
|
||||
break;
|
||||
|
||||
case DataType::uint64:
|
||||
{
|
||||
uint64_t value = xiv::utils::bparse::extract< uint64_t >( iss, "uint64_t", false );
|
||||
*reinterpret_cast< uint64_t* >( pSheet->ptr() + member_entry.offset ) = value;
|
||||
}
|
||||
break;
|
||||
{
|
||||
uint64_t value = xiv::utils::bparse::extract< uint64_t >( iss, "uint64_t", false );
|
||||
*reinterpret_cast< uint64_t* >( pSheet->ptr() + member_entry.offset ) = value;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
auto type = static_cast< uint16_t >( member_entry.type );
|
||||
|
@ -379,5 +375,4 @@ namespace xiv::exd
|
|||
std::map< uint32_t, ExdCacheEntry > _idCache;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
}// namespace xiv::exd
|
46
deps/datReader/ExdCat.cpp
vendored
46
deps/datReader/ExdCat.cpp
vendored
|
@ -4,47 +4,42 @@
|
|||
|
||||
#include "GameData.h"
|
||||
|
||||
#include "Exh.h"
|
||||
#include "Exd.h"
|
||||
#include "Exh.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
// Suffix of the filenames given a language
|
||||
std::map<xiv::exd::Language, std::string> language_map =
|
||||
const std::map< xiv::exd::Language, std::string > language_map =
|
||||
{
|
||||
{xiv::exd::Language::none, ""},
|
||||
{xiv::exd::Language::ja, "_ja"},
|
||||
{xiv::exd::Language::en, "_en"},
|
||||
{xiv::exd::Language::de, "_de"},
|
||||
{xiv::exd::Language::fr, "_fr"},
|
||||
{xiv::exd::Language::chs, "_chs"}
|
||||
{ xiv::exd::Language::none, "" },
|
||||
{ xiv::exd::Language::ja, "_ja" },
|
||||
{ xiv::exd::Language::en, "_en" },
|
||||
{ xiv::exd::Language::de, "_de" },
|
||||
{ xiv::exd::Language::fr, "_fr" },
|
||||
{ xiv::exd::Language::chs, "_chs" }
|
||||
};
|
||||
}
|
||||
}// namespace
|
||||
|
||||
namespace xiv::exd
|
||||
{
|
||||
Cat::Cat( dat::GameData& i_game_data, const std::string& i_name ) :
|
||||
_name( i_name )
|
||||
Cat::Cat( dat::GameData& i_game_data, const std::string& i_name ) : _name( i_name )
|
||||
{
|
||||
//XIV_INFO(xiv_exd_logger, "Initializing Cat with name: " << i_name);
|
||||
// creates the header .exh
|
||||
{
|
||||
auto header_file = i_game_data.getFile( "exd/" + i_name + ".exh" );
|
||||
_header = std::shared_ptr< Exh >( new Exh( *header_file ) );
|
||||
auto header_file = i_game_data.getFile( "exd/" + i_name + ".exh" );
|
||||
_header = std::make_shared< Exh >( *header_file );
|
||||
|
||||
}
|
||||
|
||||
for( auto language: _header->get_languages() )
|
||||
for( auto language : _header->get_languages() )
|
||||
{
|
||||
// chs not yet in data files
|
||||
if( language == Language::en || language == Language::none )
|
||||
{
|
||||
// Get all the files for a given category/language, in case of multiple range of IDs in separate files (like Quest)
|
||||
std::vector< std::shared_ptr< dat::File>> files;
|
||||
for( auto& exd_def: _header->get_exd_defs() )
|
||||
std::vector< std::shared_ptr< dat::File > > files;
|
||||
for( auto& exd_def : _header->get_exd_defs() )
|
||||
{
|
||||
files.emplace_back( i_game_data.getFile(
|
||||
"exd/" + i_name + "_" + std::to_string( exd_def.start_id ) + language_map.at( language ) + ".exd" ) );
|
||||
"exd/" + i_name + "_" + std::to_string( exd_def.start_id ) + language_map.at( language ) + ".exd" ) );
|
||||
}
|
||||
// Instantiate the data for this language
|
||||
_data[ language ] = std::make_unique< Exd >( _header, files );
|
||||
|
@ -52,10 +47,7 @@ namespace xiv::exd
|
|||
}
|
||||
}
|
||||
|
||||
Cat::~Cat()
|
||||
{
|
||||
|
||||
}
|
||||
Cat::~Cat() = default;
|
||||
|
||||
const std::string& Cat::get_name() const
|
||||
{
|
||||
|
@ -72,7 +64,7 @@ namespace xiv::exd
|
|||
auto ln_it = _data.find( i_language );
|
||||
if( ln_it == _data.end() )
|
||||
{
|
||||
throw std::runtime_error( "No data for language: " + std::to_string( uint16_t( i_language ) ) );
|
||||
throw std::runtime_error( "No data for language: " + std::to_string( static_cast< uint16_t >( i_language ) ) );
|
||||
}
|
||||
|
||||
return *( ln_it->second );
|
||||
|
@ -89,4 +81,4 @@ namespace xiv::exd
|
|||
return *( ln_it->second );
|
||||
}
|
||||
|
||||
}
|
||||
}// namespace xiv::exd
|
4
deps/datReader/ExdCat.h
vendored
4
deps/datReader/ExdCat.h
vendored
|
@ -61,5 +61,5 @@ namespace xiv
|
|||
std::map<Language, std::unique_ptr<Exd>> _data;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
}// namespace exd
|
||||
}// namespace xiv
|
||||
|
|
134
deps/datReader/ExdData.cpp
vendored
134
deps/datReader/ExdData.cpp
vendored
|
@ -7,90 +7,78 @@
|
|||
|
||||
#include "ExdCat.h"
|
||||
|
||||
namespace xiv::exd {
|
||||
|
||||
ExdData::ExdData( dat::GameData& i_game_data ) try :
|
||||
_game_data( i_game_data )
|
||||
namespace xiv::exd
|
||||
{
|
||||
//XIV_INFO(xiv_exd_logger, "Initializing ExdData");
|
||||
|
||||
// Fetch the root.exl and get a stream from it
|
||||
auto root_exl = i_game_data.getFile( "exd/root.exl" );
|
||||
std::vector< char > dataCpy = root_exl->get_data_sections().front();
|
||||
xiv::utils::stream::vectorwrapbuf< char > databuf( dataCpy );
|
||||
std::istream stream( &databuf );
|
||||
|
||||
// Iterates over the lines while skipping the first one
|
||||
std::string line;
|
||||
std::getline( stream, line ); // extract first line EXLT,2
|
||||
std::getline( stream, line );
|
||||
|
||||
// Until the EOF
|
||||
while( !line.empty() )
|
||||
ExdData::ExdData( dat::GameData& i_game_data )
|
||||
try : _game_data( i_game_data )
|
||||
{
|
||||
// Format is cat_name,XX
|
||||
// XX being an internal identifier
|
||||
// Get only the cat_name
|
||||
auto sep = line.find( ',' );
|
||||
auto category = line.substr( 0, sep );
|
||||
|
||||
// Add to the list of category name
|
||||
// creates the empty category in the cats map
|
||||
// instantiate the creation mutex for this category
|
||||
_cat_names.push_back( category );
|
||||
_cats[ category ] = std::unique_ptr< Cat >();
|
||||
_cat_creation_mutexes[ category ] = std::make_unique< std::mutex >();
|
||||
// Fetch the root.exl and get a stream from it
|
||||
auto root_exl = i_game_data.getFile( "exd/root.exl" );
|
||||
std::vector< char > dataCpy = root_exl->get_data_sections().front();
|
||||
xiv::utils::stream::vectorwrapbuf< char > databuf( dataCpy );
|
||||
std::istream stream( &databuf );
|
||||
|
||||
// Skip the first line (EXLT,2)
|
||||
std::string line;
|
||||
std::getline( stream, line );
|
||||
}
|
||||
}
|
||||
catch( std::exception& e )
|
||||
{
|
||||
// In case of failure here, client is supposed to catch the exception because it is not recoverable on our side
|
||||
throw std::runtime_error( "ExdData initialization failed: " + std::string( e.what() ) );
|
||||
}
|
||||
|
||||
ExdData::~ExdData()
|
||||
{
|
||||
// Read the remaining lines
|
||||
while( std::getline( stream, line ) && !line.empty() )
|
||||
{
|
||||
// Format is cat_name,XX
|
||||
// XX being an internal identifier
|
||||
// Get only the cat_name
|
||||
auto sep = line.find( ',' );
|
||||
auto category = line.substr( 0, sep );
|
||||
|
||||
}
|
||||
|
||||
const std::vector< std::string >& ExdData::get_cat_names() const
|
||||
{
|
||||
return _cat_names;
|
||||
}
|
||||
|
||||
const Cat& ExdData::get_category( const std::string& i_cat_name )
|
||||
{
|
||||
// Get the category from its name
|
||||
auto cat_it = _cats.find( i_cat_name );
|
||||
if( cat_it == _cats.end() )
|
||||
// Add to the list of category names
|
||||
// Create the empty category in the cats map
|
||||
// Instantiate the creation mutex for this category
|
||||
_cat_names.emplace_back( category );
|
||||
_cats[ category ] = nullptr;
|
||||
_cat_creation_mutexes[ category ] = std::make_unique< std::mutex >();
|
||||
}
|
||||
} catch( std::exception& e )
|
||||
{
|
||||
throw std::runtime_error( "Category not found: " + i_cat_name );
|
||||
// In case of failure here, client is supposed to catch the exception because it is not recoverable on our side
|
||||
throw std::runtime_error( "ExdData initialization failed: " + std::string( e.what() ) );
|
||||
}
|
||||
|
||||
if( cat_it->second )
|
||||
const std::vector< std::string >& ExdData::get_cat_names() const
|
||||
{
|
||||
// If valid return it
|
||||
return *( cat_it->second );
|
||||
return _cat_names;
|
||||
}
|
||||
else
|
||||
{
|
||||
// If not, create it and return it
|
||||
create_category( i_cat_name );
|
||||
return *( _cats[ i_cat_name ] );
|
||||
}
|
||||
}
|
||||
|
||||
void ExdData::create_category( const std::string& i_cat_name )
|
||||
{
|
||||
// Lock mutex in this scope
|
||||
std::lock_guard< std::mutex > lock( *( _cat_creation_mutexes[ i_cat_name ] ) );
|
||||
// Maybe after unlocking it has already been created, so check (most likely if it blocked)
|
||||
if( !_cats[ i_cat_name ] )
|
||||
const Cat& ExdData::get_category( const std::string& i_cat_name )
|
||||
{
|
||||
_cats[ i_cat_name ] = std::make_unique< Cat >( _game_data, i_cat_name );
|
||||
}
|
||||
}
|
||||
// Get the category from its name
|
||||
auto cat_it = _cats.find( i_cat_name );
|
||||
if( cat_it == _cats.end() )
|
||||
{
|
||||
throw std::runtime_error( "Category not found: " + i_cat_name );
|
||||
}
|
||||
|
||||
}
|
||||
if( cat_it->second )
|
||||
{
|
||||
// If valid return it
|
||||
return *( cat_it->second );
|
||||
}
|
||||
else
|
||||
{
|
||||
// If not, create it and return it
|
||||
create_category( i_cat_name );
|
||||
return *( _cats[ i_cat_name ] );
|
||||
}
|
||||
}
|
||||
|
||||
void ExdData::create_category( const std::string& i_cat_name )
|
||||
{
|
||||
// Lock mutex in this scope
|
||||
std::lock_guard< std::mutex > lock( *( _cat_creation_mutexes[ i_cat_name ] ) );
|
||||
// Maybe after unlocking it has already been created, so check (most likely if it blocked)
|
||||
if( !_cats[ i_cat_name ] )
|
||||
{
|
||||
_cats[ i_cat_name ] = std::make_unique< Cat >( _game_data, i_cat_name );
|
||||
}
|
||||
}
|
||||
}// namespace xiv::exd
|
22
deps/datReader/ExdData.h
vendored
22
deps/datReader/ExdData.h
vendored
|
@ -25,32 +25,32 @@ namespace xiv
|
|||
{
|
||||
public:
|
||||
// Need an initialized dat::GameData to retrieve the files from the dat
|
||||
ExdData(dat::GameData& i_game_data);
|
||||
~ExdData();
|
||||
ExdData( dat::GameData& i_game_data );
|
||||
~ExdData() = default;
|
||||
|
||||
// Get the list of thenames of the categories
|
||||
const std::vector<std::string>& get_cat_names() const;
|
||||
const std::vector< std::string >& get_cat_names() const;
|
||||
|
||||
// Get a category by its name
|
||||
const Cat& get_category(const std::string& i_cat_name);
|
||||
const Cat& get_category( const std::string& i_cat_name );
|
||||
|
||||
// Export in csv in base flder i_ouput_path
|
||||
void export_as_csvs(const std::filesystem::path& i_output_path);
|
||||
void export_as_csvs( const std::filesystem::path& i_output_path );
|
||||
|
||||
protected:
|
||||
// Lazy instantiation of category
|
||||
void create_category(const std::string& i_cat_name);
|
||||
void create_category( const std::string& i_cat_name );
|
||||
|
||||
// Reference to the game_data object
|
||||
dat::GameData& _game_data;
|
||||
|
||||
// Categories, indexed by their name
|
||||
std::unordered_map<std::string, std::unique_ptr<Cat>> _cats;
|
||||
std::unordered_map< std::string, std::unique_ptr< Cat > > _cats;
|
||||
// List of category names = m_cats.keys()
|
||||
std::vector<std::string> _cat_names;
|
||||
std::vector< std::string > _cat_names;
|
||||
// Mutexes used to avoid race condition when lazy instantiating a category
|
||||
std::unordered_map<std::string, std::unique_ptr<std::mutex>> _cat_creation_mutexes;
|
||||
std::unordered_map< std::string, std::unique_ptr< std::mutex > > _cat_creation_mutexes;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
}// namespace exd
|
||||
}// namespace xiv
|
||||
|
|
8
deps/datReader/Exh.cpp
vendored
8
deps/datReader/Exh.cpp
vendored
|
@ -9,12 +9,12 @@ using xiv::utils::bparse::extract;
|
|||
|
||||
namespace xiv::exd
|
||||
{
|
||||
|
||||
Exh::Exh( const dat::File& i_file )
|
||||
{
|
||||
// Get a stream from the file
|
||||
std::vector< char > dataCpy = i_file.get_data_sections().front();
|
||||
std::istringstream iss( std::string( dataCpy.begin(), dataCpy.end() ) );
|
||||
std::string dataStr( dataCpy.begin(), dataCpy.end() );
|
||||
std::istringstream iss( std::move( dataStr ) );
|
||||
|
||||
// Extract header and skip to member definitions
|
||||
_header = extract< ExhHeader >( iss );
|
||||
|
@ -43,10 +43,6 @@ namespace xiv::exd
|
|||
}
|
||||
}
|
||||
|
||||
Exh::~Exh()
|
||||
{
|
||||
}
|
||||
|
||||
const ExhHeader& Exh::get_header() const
|
||||
{
|
||||
return _header;
|
||||
|
|
81
deps/datReader/Exh.h
vendored
81
deps/datReader/Exh.h
vendored
|
@ -44,46 +44,47 @@ namespace xiv::exd
|
|||
uint32_t start_id;
|
||||
uint32_t count_id;
|
||||
};
|
||||
};
|
||||
};// namespace xiv::exd
|
||||
|
||||
namespace xiv::utils::bparse {
|
||||
template<>
|
||||
inline void reorder< xiv::exd::ExhHeader >( xiv::exd::ExhHeader& i_struct )
|
||||
namespace xiv::utils::bparse
|
||||
{
|
||||
for( int32_t i = 0; i < 0x4; ++i )
|
||||
template<>
|
||||
inline void reorder< xiv::exd::ExhHeader >( xiv::exd::ExhHeader& i_struct )
|
||||
{
|
||||
xiv::utils::bparse::reorder( i_struct.magic[ i ] );
|
||||
for( int32_t i = 0; i < 0x4; ++i )
|
||||
{
|
||||
xiv::utils::bparse::reorder( i_struct.magic[ i ] );
|
||||
}
|
||||
i_struct.unknown = xiv::utils::bparse::byteswap( i_struct.unknown );
|
||||
xiv::utils::bparse::reorder( i_struct.unknown );
|
||||
i_struct.data_offset = xiv::utils::bparse::byteswap( i_struct.data_offset );
|
||||
xiv::utils::bparse::reorder( i_struct.data_offset );
|
||||
i_struct.field_count = xiv::utils::bparse::byteswap( i_struct.field_count );
|
||||
xiv::utils::bparse::reorder( i_struct.field_count );
|
||||
i_struct.exd_count = xiv::utils::bparse::byteswap( i_struct.exd_count );
|
||||
xiv::utils::bparse::reorder( i_struct.exd_count );
|
||||
i_struct.language_count = xiv::utils::bparse::byteswap( i_struct.language_count );
|
||||
xiv::utils::bparse::reorder( i_struct.language_count );
|
||||
}
|
||||
i_struct.unknown = xiv::utils::bparse::byteswap( i_struct.unknown );
|
||||
xiv::utils::bparse::reorder( i_struct.unknown );
|
||||
i_struct.data_offset = xiv::utils::bparse::byteswap( i_struct.data_offset );
|
||||
xiv::utils::bparse::reorder( i_struct.data_offset );
|
||||
i_struct.field_count = xiv::utils::bparse::byteswap( i_struct.field_count );
|
||||
xiv::utils::bparse::reorder( i_struct.field_count );
|
||||
i_struct.exd_count = xiv::utils::bparse::byteswap( i_struct.exd_count );
|
||||
xiv::utils::bparse::reorder( i_struct.exd_count );
|
||||
i_struct.language_count = xiv::utils::bparse::byteswap( i_struct.language_count );
|
||||
xiv::utils::bparse::reorder( i_struct.language_count );
|
||||
}
|
||||
|
||||
template<>
|
||||
inline void reorder< xiv::exd::ExhMember >( xiv::exd::ExhMember& i_struct )
|
||||
{
|
||||
i_struct.type = xiv::utils::bparse::byteswap( i_struct.type );
|
||||
xiv::utils::bparse::reorder( i_struct.type );
|
||||
i_struct.offset = xiv::utils::bparse::byteswap( i_struct.offset );
|
||||
xiv::utils::bparse::reorder( i_struct.offset );
|
||||
}
|
||||
template<>
|
||||
inline void reorder< xiv::exd::ExhMember >( xiv::exd::ExhMember& i_struct )
|
||||
{
|
||||
i_struct.type = xiv::utils::bparse::byteswap( i_struct.type );
|
||||
xiv::utils::bparse::reorder( i_struct.type );
|
||||
i_struct.offset = xiv::utils::bparse::byteswap( i_struct.offset );
|
||||
xiv::utils::bparse::reorder( i_struct.offset );
|
||||
}
|
||||
|
||||
template<>
|
||||
inline void reorder< xiv::exd::ExhExdDef >( xiv::exd::ExhExdDef& i_struct )
|
||||
{
|
||||
i_struct.start_id = xiv::utils::bparse::byteswap( i_struct.start_id );
|
||||
xiv::utils::bparse::reorder( i_struct.start_id );
|
||||
i_struct.count_id = xiv::utils::bparse::byteswap( i_struct.count_id );
|
||||
xiv::utils::bparse::reorder( i_struct.count_id );
|
||||
}
|
||||
};
|
||||
template<>
|
||||
inline void reorder< xiv::exd::ExhExdDef >( xiv::exd::ExhExdDef& i_struct )
|
||||
{
|
||||
i_struct.start_id = xiv::utils::bparse::byteswap( i_struct.start_id );
|
||||
xiv::utils::bparse::reorder( i_struct.start_id );
|
||||
i_struct.count_id = xiv::utils::bparse::byteswap( i_struct.count_id );
|
||||
xiv::utils::bparse::reorder( i_struct.count_id );
|
||||
}
|
||||
};// namespace xiv::utils::bparse
|
||||
|
||||
namespace xiv
|
||||
{
|
||||
|
@ -105,16 +106,21 @@ namespace xiv
|
|||
// The header file
|
||||
Exh( const dat::File& i_file );
|
||||
|
||||
~Exh();
|
||||
~Exh() = default;
|
||||
|
||||
// Returns a const reference to the ExhHeader object
|
||||
const ExhHeader& get_header() const;
|
||||
|
||||
// Returns a const reference to a vector of ExhExdDef objects
|
||||
const std::vector< ExhExdDef >& get_exd_defs() const;
|
||||
|
||||
// Returns a const reference to a vector of Language enums
|
||||
const std::vector< Language >& get_languages() const;
|
||||
|
||||
// Returns a const reference to a map of ExhMember objects, indexed by their offset
|
||||
const std::map< uint32_t, ExhMember >& get_members() const;
|
||||
|
||||
// Returns a const reference to a vector of ExhMember objects
|
||||
const std::vector< ExhMember >& get_exh_members() const;
|
||||
|
||||
protected:
|
||||
|
@ -126,6 +132,5 @@ namespace xiv
|
|||
std::vector< Language > _languages;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}// namespace exd
|
||||
}// namespace xiv::exd
|
20
deps/datReader/File.cpp
vendored
20
deps/datReader/File.cpp
vendored
|
@ -10,10 +10,6 @@ namespace xiv::dat
|
|||
{
|
||||
}
|
||||
|
||||
File::~File()
|
||||
{
|
||||
}
|
||||
|
||||
FileType File::get_type() const
|
||||
{
|
||||
return _type;
|
||||
|
@ -31,12 +27,20 @@ namespace xiv::dat
|
|||
|
||||
void File::exportToFile( const std::filesystem::path& i_path ) const
|
||||
{
|
||||
std::ofstream ofs( i_path.string(), std::ios_base::binary | std::ios_base::out );
|
||||
for( auto& data_section : _data_sections )
|
||||
std::ofstream ofs( i_path, std::ios::binary | std::ios::out );
|
||||
|
||||
if( !ofs )
|
||||
{
|
||||
ofs.write( data_section.data(), data_section.size() );
|
||||
throw std::runtime_error( "Failed to open the output file: " + i_path.string() );
|
||||
}
|
||||
ofs.close();
|
||||
|
||||
for( const auto& data_section : _data_sections )
|
||||
{
|
||||
ofs.write( reinterpret_cast< const char* >( data_section.data() ), static_cast< std::streamsize >( data_section.size() ) );
|
||||
}
|
||||
|
||||
// The file stream will be closed automatically when the ofstream object goes out of scope
|
||||
// ofs.close();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
20
deps/datReader/File.h
vendored
20
deps/datReader/File.h
vendored
|
@ -27,20 +27,26 @@ namespace xiv::dat
|
|||
public:
|
||||
File();
|
||||
|
||||
~File();
|
||||
~File() = default;
|
||||
|
||||
// Returns the file type of the File object
|
||||
FileType get_type() const;
|
||||
|
||||
// Getters functions for the data in the file
|
||||
const std::vector< std::vector< char>>& get_data_sections() const;
|
||||
// Returns a const reference to the data sections in the File object
|
||||
const std::vector< std::vector< char > >& get_data_sections() const;
|
||||
|
||||
std::vector< std::vector< char>>& access_data_sections();
|
||||
// Returns a reference to the data sections in the File object
|
||||
std::vector< std::vector< char > >& access_data_sections();
|
||||
|
||||
// Exports the content of the File object to a file on disk at the given path
|
||||
void exportToFile( const std::filesystem::path& i_path ) const;
|
||||
|
||||
protected:
|
||||
// Stores the file type of the File object
|
||||
FileType _type;
|
||||
std::vector< std::vector< char>> _data_sections;
|
||||
};
|
||||
}
|
||||
|
||||
// Stores the data sections of the File object as a vector of vectors of chars
|
||||
std::vector< std::vector< char > > _data_sections;
|
||||
};
|
||||
}// namespace xiv::dat
|
||||
|
||||
|
|
3
deps/datReader/GameData.h
vendored
3
deps/datReader/GameData.h
vendored
|
@ -89,5 +89,4 @@ namespace xiv::dat
|
|||
std::unordered_map< uint32_t, std::unique_ptr< std::mutex>> m_catCreationMutexes;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
}// namespace xiv::dat
|
7
deps/datReader/Index.h
vendored
7
deps/datReader/Index.h
vendored
|
@ -1,5 +1,4 @@
|
|||
#ifndef XIV_DAT_INDEX_H
|
||||
#define XIV_DAT_INDEX_H
|
||||
#pragma once
|
||||
|
||||
#include "SqPack.h"
|
||||
|
||||
|
@ -58,6 +57,4 @@ namespace xiv::dat
|
|||
HashTable m_hashTable;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // XIV_DAT_INDEX_H
|
||||
}// namespace xiv::dat
|
||||
|
|
11
deps/datReader/SqPack.h
vendored
11
deps/datReader/SqPack.h
vendored
|
@ -1,5 +1,4 @@
|
|||
#ifndef XIV_DAT_SQPACK_H
|
||||
#define XIV_DAT_SQPACK_H
|
||||
#pragma once
|
||||
|
||||
#include <fstream>
|
||||
|
||||
|
@ -15,7 +14,7 @@ namespace xiv::dat
|
|||
uint8_t hash[0x14];
|
||||
uint32_t padding[0xB];
|
||||
};
|
||||
}
|
||||
}// namespace xiv::dat
|
||||
|
||||
namespace xiv::utils::bparse
|
||||
{
|
||||
|
@ -31,7 +30,7 @@ namespace xiv::utils::bparse
|
|||
xiv::utils::bparse::reorder( i_struct.padding[ i ] );
|
||||
}
|
||||
}
|
||||
};
|
||||
};// namespace xiv::utils::bparse
|
||||
|
||||
namespace xiv::dat
|
||||
{
|
||||
|
@ -53,6 +52,4 @@ namespace xiv::dat
|
|||
std::ifstream m_handle;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // XIV_DAT_SQPACK_H
|
||||
}// namespace xiv::dat
|
||||
|
|
11
deps/datReader/bparse.cpp
vendored
11
deps/datReader/bparse.cpp
vendored
|
@ -2,7 +2,12 @@
|
|||
|
||||
std::string xiv::utils::bparse::extract_cstring( std::istream& i_stream, const std::string& i_name )
|
||||
{
|
||||
std::string temp_str;
|
||||
std::getline( i_stream, temp_str, '\0' );
|
||||
return temp_str;
|
||||
// Using a stringstream and reading character by character avoids this issue and ensures all input is processed correctly.
|
||||
std::stringstream ss;
|
||||
char c;
|
||||
while( i_stream.get( c ) && c != '\0' )
|
||||
{
|
||||
ss << c;
|
||||
}
|
||||
return ss.str();
|
||||
}
|
59
deps/datReader/bparse.h
vendored
59
deps/datReader/bparse.h
vendored
|
@ -7,14 +7,62 @@
|
|||
namespace xiv::utils::bparse
|
||||
{
|
||||
|
||||
// Internal macro for byteswapping
|
||||
template< int N >
|
||||
void byteswap_impl( char (& bytes)[N] )
|
||||
// Helper struct for compile-time unrolling of byteswap
|
||||
template< int N, bool Unroll >
|
||||
struct byteswap_impl_helper
|
||||
{
|
||||
for( auto p = std::begin( bytes ), end = std::end( bytes ) - 1; p < end; ++p, --end )
|
||||
static void swap( char ( &bytes )[ N ], int start )
|
||||
{
|
||||
std::swap( *p, *end );
|
||||
// Intentionally left empty. This specialization should never be used.
|
||||
}
|
||||
};
|
||||
|
||||
// Specialization of byteswap_impl_helper for compile-time unrolling (true)
|
||||
template< int N >
|
||||
struct byteswap_impl_helper< N, true >
|
||||
{
|
||||
static void swap( char ( &bytes )[ N ], int start )
|
||||
{
|
||||
// Swap pairs of bytes recursively, unrolling the loop at compile-time
|
||||
if constexpr( N >= 2 )
|
||||
{
|
||||
std::swap( bytes[ start ], bytes[ N - start - 1 ] );
|
||||
if constexpr( N >= 4 )
|
||||
{
|
||||
std::swap( bytes[ start + 1 ], bytes[ N - start - 2 ] );
|
||||
if constexpr( N >= 6 )
|
||||
{
|
||||
std::swap( bytes[ start + 2 ], bytes[ N - start - 3 ] );
|
||||
if constexpr( N >= 8 )
|
||||
{
|
||||
std::swap( bytes[ start + 3 ], bytes[ N - start - 4 ] );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template< int N >
|
||||
struct byteswap_impl_helper< N, false >
|
||||
{
|
||||
static void swap( char ( &bytes )[ N ], int start )
|
||||
{
|
||||
// Swap pairs of bytes using a loop
|
||||
for( auto p = std::begin( bytes ), end = std::end( bytes ) - 1; p < end;
|
||||
++p, --end )
|
||||
{
|
||||
std::swap( *p, *end );
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template< int N >
|
||||
void byteswap_impl( char ( &bytes )[ N ] )
|
||||
{
|
||||
// Decide whether to use compile-time unrolling or loop-based swapping
|
||||
constexpr bool Unroll = N <= 8;
|
||||
byteswap_impl_helper< N, Unroll >::swap( bytes, 0 );
|
||||
}
|
||||
|
||||
// byteswapping any type (no pointers to array)
|
||||
|
@ -91,7 +139,6 @@ namespace xiv::utils::bparse
|
|||
}
|
||||
}
|
||||
|
||||
// For cstrings
|
||||
std::string extract_cstring( std::istream& i_stream, const std::string& i_name );
|
||||
|
||||
}
|
||||
|
|
4
deps/datReader/conv.cpp
vendored
4
deps/datReader/conv.cpp
vendored
|
@ -1,5 +1,5 @@
|
|||
#include "conv.h"
|
||||
#include <cstring>// for memcpy
|
||||
#include <cstring>
|
||||
|
||||
namespace xiv::utils::conv
|
||||
{
|
||||
|
@ -23,7 +23,7 @@ namespace xiv::utils::conv
|
|||
t1 |= t2; // Re-insert sign bit
|
||||
|
||||
float result;
|
||||
memcpy( &result, &t1, sizeof( float ) );// Convert uint32_t to float using memcpy
|
||||
memcpy( &result, &t1, sizeof( float ) );
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
11
deps/datReader/stream.h
vendored
11
deps/datReader/stream.h
vendored
|
@ -1,5 +1,4 @@
|
|||
#ifndef XIV_UTILS_STREAM_H
|
||||
#define XIV_UTILS_STREAM_H
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <iostream>
|
||||
|
@ -8,14 +7,12 @@
|
|||
namespace xiv::utils::stream
|
||||
{
|
||||
template< typename CharT, typename TraitsT = std::char_traits< CharT > >
|
||||
class vectorwrapbuf :
|
||||
public std::basic_streambuf< CharT, TraitsT >
|
||||
class vectorwrapbuf : public std::basic_streambuf< CharT, TraitsT >
|
||||
{
|
||||
public:
|
||||
vectorwrapbuf( std::vector< CharT >& vec )
|
||||
vectorwrapbuf( std::vector< CharT >& vec ) : std::basic_streambuf< CharT, TraitsT >()
|
||||
{
|
||||
this->setg( vec.data(), vec.data(), vec.data() + vec.size() );
|
||||
}
|
||||
};
|
||||
}
|
||||
#endif // XIV_UTILS_STREAM_H
|
||||
}// namespace xiv::utils::stream
|
||||
|
|
7
deps/datReader/zlib.h
vendored
7
deps/datReader/zlib.h
vendored
|
@ -1,5 +1,4 @@
|
|||
#ifndef XIV_UTILS_ZLIB_H
|
||||
#define XIV_UTILS_ZLIB_H
|
||||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
|
@ -12,6 +11,4 @@ namespace xiv::utils::zlib
|
|||
|
||||
void no_header_decompress( const uint8_t* in, size_t in_size, uint8_t* out, size_t out_size );
|
||||
|
||||
}
|
||||
|
||||
#endif // XIV_UTILS_ZLIB_H
|
||||
} // namespace xiv::utils::zlib
|
||||
|
|
8
deps/watchdog/Watchdog.h
vendored
8
deps/watchdog/Watchdog.h
vendored
|
@ -32,14 +32,10 @@
|
|||
|
||||
#include <functional>
|
||||
|
||||
// fucking filesystem
|
||||
#if _MSC_VER >= 1925
|
||||
|
||||
#include <filesystem>
|
||||
namespace ci { namespace fs = std::filesystem; }
|
||||
#else
|
||||
#include <experimental/filesystem>
|
||||
namespace ci { namespace fs = std::experimental::filesystem; }
|
||||
#endif
|
||||
|
||||
|
||||
//! Exception for when Watchdog can't locate a file or parse the wildcard
|
||||
class WatchedFileSystemExc : public std::exception {
|
||||
|
|
|
@ -31,15 +31,8 @@
|
|||
#include <Util/CrashHandler.h>
|
||||
|
||||
|
||||
// fucking filesystem
|
||||
#if _MSC_VER >= 1925
|
||||
#include <filesystem>
|
||||
namespace fs = std::filesystem;
|
||||
#else
|
||||
#include <experimental/filesystem>
|
||||
namespace fs = std::experimental::filesystem;
|
||||
#endif
|
||||
|
||||
|
||||
Sapphire::Common::Util::CrashHandler crashHandler;
|
||||
|
||||
|
|
|
@ -434,7 +434,7 @@ namespace Sapphire::Common
|
|||
Currency = 2000,
|
||||
Crystal = 2001,
|
||||
//UNKNOWN_0 = 2003,
|
||||
KeyItem = 2004,
|
||||
KeyItem = 2004,
|
||||
HandIn = 2005,
|
||||
DamagedGear = 2007,
|
||||
//UNKNOWN_1 = 2008,
|
||||
|
|
|
@ -2,13 +2,8 @@
|
|||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
||||
#if _MSC_VER >= 1925
|
||||
#include <filesystem>
|
||||
namespace fs = std::filesystem;
|
||||
#else
|
||||
#include <experimental/filesystem>
|
||||
namespace fs = std::experimental::filesystem;
|
||||
#endif
|
||||
|
||||
using namespace Sapphire;
|
||||
using namespace Sapphire::Common;
|
||||
|
|
|
@ -7,30 +7,23 @@
|
|||
#include <spdlog/sinks/stdout_color_sinks.h>
|
||||
#include <spdlog/sinks/daily_file_sink.h>
|
||||
|
||||
// #include <iostream>
|
||||
#if _MSC_VER >= 1925
|
||||
#include <filesystem>
|
||||
namespace fs = std::filesystem;
|
||||
#else
|
||||
#include <experimental/filesystem>
|
||||
namespace fs = std::experimental::filesystem;
|
||||
#endif
|
||||
|
||||
|
||||
void Sapphire::Logger::init( const std::string& logPath )
|
||||
{
|
||||
auto pos = logPath.find_last_of( fs::path::preferred_separator );
|
||||
fs::path log_file_path(logPath);
|
||||
fs::path log_directory = log_file_path.parent_path();
|
||||
|
||||
if( pos != std::string::npos )
|
||||
if( !log_directory.empty() )
|
||||
{
|
||||
std::string realPath = logPath.substr( 0, pos );
|
||||
fs::create_directories( realPath );
|
||||
fs::create_directories(log_directory);
|
||||
}
|
||||
|
||||
spdlog::init_thread_pool( 8192, 1 );
|
||||
|
||||
auto stdout_sink = std::make_shared< spdlog::sinks::stdout_color_sink_mt >();
|
||||
auto daily_sink = std::make_shared< spdlog::sinks::daily_file_sink_mt >( logPath + ".log", 0, 0 );
|
||||
auto daily_sink = std::make_shared< spdlog::sinks::daily_file_sink_mt >( log_file_path.string() + ".log", 0, 0 );
|
||||
|
||||
std::vector< spdlog::sink_ptr > sinks { stdout_sink, daily_sink };
|
||||
|
||||
|
|
|
@ -1,15 +1,13 @@
|
|||
#include "Hive.h"
|
||||
#include "Acceptor.h"
|
||||
#include "Connection.h"
|
||||
|
||||
#include "Hive.h"
|
||||
|
||||
using namespace Sapphire;
|
||||
|
||||
Network::Acceptor::Acceptor( HivePtr hive ) :
|
||||
m_hive( hive ),
|
||||
m_acceptor( hive->getService() ),
|
||||
m_io_strand( hive->getService() ),
|
||||
m_error_state( 0 )
|
||||
Network::Acceptor::Acceptor( HivePtr hive ) : m_hive( hive ),
|
||||
m_acceptor( hive->getService() ),
|
||||
m_io_strand( hive->getService() ),
|
||||
m_error_state( 0 )
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -77,7 +75,10 @@ void Network::Acceptor::handleAccept( const asio::error_code& error, ConnectionP
|
|||
|
||||
void Network::Acceptor::stop()
|
||||
{
|
||||
|
||||
// Cancel all operations and close the acceptor
|
||||
asio::error_code ec;
|
||||
m_acceptor.cancel( ec );
|
||||
m_acceptor.close( ec );
|
||||
}
|
||||
|
||||
void Network::Acceptor::accept( ConnectionPtr connection )
|
||||
|
@ -97,13 +98,15 @@ void Network::Acceptor::listen( const std::string& host, const uint16_t& port )
|
|||
m_acceptor.set_option( asio::ip::tcp::acceptor::reuse_address( false ) );
|
||||
m_acceptor.bind( endpoint );
|
||||
m_acceptor.listen( asio::socket_base::max_connections );
|
||||
}
|
||||
catch( ... )
|
||||
} catch( const asio::system_error& ex )
|
||||
{
|
||||
// this should not happen
|
||||
assert( true );
|
||||
// Call the onError function to handle the error
|
||||
onError( ex.code() );
|
||||
} catch( ... )
|
||||
{
|
||||
// Call the onError function with a generic error code
|
||||
onError( asio::error::operation_aborted );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Network::HivePtr Network::Acceptor::getHive()
|
||||
|
@ -116,6 +119,11 @@ asio::ip::tcp::acceptor& Network::Acceptor::getAcceptor()
|
|||
return m_acceptor;
|
||||
}
|
||||
|
||||
asio::strand& Network::Acceptor::getStrand()
|
||||
{
|
||||
return m_io_strand;
|
||||
}
|
||||
|
||||
bool Network::Acceptor::hasError()
|
||||
{
|
||||
uint32_t v1 = 1;
|
||||
|
|
|
@ -148,9 +148,9 @@ namespace Sapphire::Network
|
|||
acceptor->accept( connection );
|
||||
return connection;
|
||||
}
|
||||
catch( std::runtime_error e )
|
||||
catch( ... )
|
||||
{
|
||||
throw;
|
||||
throw std::runtime_error( "Failed to add server to hive" );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,67 +1,58 @@
|
|||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <thread>
|
||||
#include <mutex>
|
||||
#include <queue>
|
||||
#include <algorithm>
|
||||
#include <utility>
|
||||
|
||||
namespace Sapphire::Common::Util
|
||||
{
|
||||
|
||||
// The LockedQueue class template is a thread-safe wrapper around std::queue.
|
||||
// It ensures that only one thread can access the underlying queue at a time
|
||||
// by using a std::mutex for synchronization.
|
||||
template< class T >
|
||||
class LockedQueue
|
||||
{
|
||||
public:
|
||||
LockedQueue();
|
||||
LockedQueue() = default;
|
||||
~LockedQueue() = default;
|
||||
|
||||
~LockedQueue();
|
||||
// Returns the size of the queue in a thread-safe manner.
|
||||
// Locks the mutex before accessing the queue and unlocks it after
|
||||
// the operation is complete.
|
||||
std::size_t size() const;
|
||||
|
||||
// Removes the front element from the queue and returns it
|
||||
// in a thread-safe manner. If the queue is empty, it returns
|
||||
// a default-constructed object of type T.
|
||||
// Locks the mutex before accessing the queue and unlocks it after
|
||||
// the operation is complete.
|
||||
T pop();
|
||||
|
||||
//we can pass this in by reference, instead of copying
|
||||
void push( const T object );
|
||||
|
||||
//we can pass this in by reference
|
||||
//this will push it onto the queue, and swap the object
|
||||
// with a default-constructed T at the same time.
|
||||
void push_swap( T& object );
|
||||
|
||||
void push_reset( T& object );
|
||||
|
||||
|
||||
std::size_t size();
|
||||
// Adds an object to the end of the queue, using a const reference.
|
||||
// The object is copied into the queue in a thread-safe manner.
|
||||
// Locks the mutex before accessing the queue and unlocks it after
|
||||
// the operation is complete.
|
||||
void push( const T& object );
|
||||
|
||||
// Adds an object to the end of the queue, using an rvalue reference.
|
||||
// The object is moved into the queue in a thread-safe manner.
|
||||
// Locks the mutex before accessing the queue and unlocks it after
|
||||
// the operation is complete.
|
||||
void push( T&& object );
|
||||
|
||||
protected:
|
||||
std::queue< T > m_queue;
|
||||
std::mutex m_mutex;
|
||||
|
||||
mutable std::mutex m_mutex;// Make mutex mutable to be used in const member functions
|
||||
};
|
||||
|
||||
template< class T >
|
||||
LockedQueue< T >::LockedQueue()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
template< class T >
|
||||
std::size_t LockedQueue< T >::size()
|
||||
std::size_t LockedQueue< T >::size() const
|
||||
{
|
||||
std::lock_guard< std::mutex > lock( m_mutex );
|
||||
return m_queue.size();
|
||||
}
|
||||
|
||||
|
||||
template< class T >
|
||||
LockedQueue< T >::~LockedQueue()
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
template< class T >
|
||||
T LockedQueue< T >::pop()
|
||||
{
|
||||
|
@ -72,58 +63,24 @@ namespace Sapphire::Common::Util
|
|||
return T();
|
||||
}
|
||||
|
||||
T result = m_queue.front();
|
||||
|
||||
T result = std::move( m_queue.front() );
|
||||
m_queue.pop();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
template< class T >
|
||||
void LockedQueue< T >::push( const T object )
|
||||
void LockedQueue< T >::push( const T& object )
|
||||
{
|
||||
std::lock_guard< std::mutex > lock( m_mutex );
|
||||
m_queue.push( object );
|
||||
}
|
||||
|
||||
template< class T >
|
||||
void LockedQueue< T >::push_swap( T& object )
|
||||
void LockedQueue< T >::push( T&& object )
|
||||
{
|
||||
std::lock_guard< std::mutex > lock( m_mutex );
|
||||
|
||||
m_queue.push( object );
|
||||
|
||||
T default_ctored_object = T();
|
||||
//this is a special swap that will do a legit naive swap normally,
|
||||
// except if there exists a function called T::swap(), which is
|
||||
// specialized and possibly faster.
|
||||
std::swap( object, default_ctored_object );
|
||||
|
||||
|
||||
|
||||
//default_ctored_object is now the value of object, and it will go out
|
||||
// of scope here. In the case that T is a shared_ptr of some kind,
|
||||
// this will allow that the object on the queue is the *last* shared_ptr
|
||||
// in existance by the time this function returns.
|
||||
|
||||
m_queue.emplace( std::forward< T >( object ) );
|
||||
}
|
||||
|
||||
template< class T >
|
||||
void LockedQueue< T >::push_reset( T& object )
|
||||
{
|
||||
std::lock_guard< std::mutex > lock( m_mutex );
|
||||
|
||||
m_queue.push( object );
|
||||
|
||||
T default_ctored_object = T();
|
||||
|
||||
object.reset();
|
||||
|
||||
//default_ctored_object is now the value of object, and it will go out
|
||||
// of scope here. In the case that T is a shared_ptr of some kind,
|
||||
// this will allow that the object on the queue is the *last* shared_ptr
|
||||
// in existance by the time this function returns.
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}// namespace Sapphire::Common::Util
|
|
@ -1,16 +1,18 @@
|
|||
#ifndef _LOCKED_WAIT_H
|
||||
#define _LOCKED_WAIT_H
|
||||
#pragma once
|
||||
|
||||
#include <atomic>
|
||||
#include <condition_variable>
|
||||
#include <mutex>
|
||||
#include <queue>
|
||||
#include <atomic>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
namespace Sapphire::Common::Util
|
||||
{
|
||||
|
||||
// The LockedWaitQueue class template is a thread-safe wrapper around std::queue
|
||||
// that provides blocking and non-blocking operations for concurrent access.
|
||||
// It uses a combination of a std::mutex and a std::condition_variable to
|
||||
// synchronize access to the queue and allow waiting for new elements to arrive.
|
||||
template< typename T >
|
||||
class LockedWaitQueue
|
||||
{
|
||||
|
@ -21,20 +23,25 @@ namespace Sapphire::Common::Util
|
|||
std::atomic< bool > m_shutdown;
|
||||
|
||||
public:
|
||||
|
||||
LockedWaitQueue< T >() :
|
||||
m_shutdown( false )
|
||||
LockedWaitQueue< T >() : m_shutdown( false )
|
||||
{
|
||||
}
|
||||
|
||||
void push( const T& value )
|
||||
// Adds an element to the end of the queue. The element can be passed as an
|
||||
// lvalue or rvalue reference, and it will be either copied or moved into
|
||||
// the queue as appropriate. The queue is locked during the push operation,
|
||||
// and a waiting thread is notified using the condition variable.
|
||||
template< typename U >
|
||||
void push( U&& value )
|
||||
{
|
||||
std::lock_guard< std::mutex > lock( m_queueLock );
|
||||
m_queue.push( std::move( value ) );
|
||||
m_queue.push( std::forward< U >( value ) );
|
||||
|
||||
m_condition.notify_one();
|
||||
}
|
||||
|
||||
// Returns true if the queue is empty, false otherwise. The queue is locked
|
||||
// during the check.
|
||||
bool empty()
|
||||
{
|
||||
std::lock_guard< std::mutex > lock( m_queueLock );
|
||||
|
@ -42,6 +49,10 @@ namespace Sapphire::Common::Util
|
|||
return m_queue.empty();
|
||||
}
|
||||
|
||||
// Tries to remove the front element from the queue and move it into the
|
||||
// provided reference. Returns true if an element was successfully popped,
|
||||
// or false if the queue was empty or the wait queue was in shutdown state.
|
||||
// The queue is locked during the pop operation.
|
||||
bool pop( T& value )
|
||||
{
|
||||
std::lock_guard< std::mutex > lock( m_queueLock );
|
||||
|
@ -49,13 +60,17 @@ namespace Sapphire::Common::Util
|
|||
if( m_queue.empty() || m_shutdown )
|
||||
return false;
|
||||
|
||||
value = m_queue.front();
|
||||
value = std::move( m_queue.front() );
|
||||
|
||||
m_queue.pop();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Waits for an element to become available in the queue and then removes
|
||||
// it and moves it into the provided reference. If the queue is empty and
|
||||
// not in shutdown state, the thread will block until an element is added
|
||||
// or the wait queue is shut down. The queue is locked during the operation.
|
||||
void waitAndPop( T& value )
|
||||
{
|
||||
std::unique_lock< std::mutex > lock( m_queueLock );
|
||||
|
@ -66,11 +81,15 @@ namespace Sapphire::Common::Util
|
|||
if( m_queue.empty() || m_shutdown )
|
||||
return;
|
||||
|
||||
value = m_queue.front();
|
||||
value = std::move( m_queue.front() );
|
||||
|
||||
m_queue.pop();
|
||||
}
|
||||
|
||||
// Shuts down the wait queue, deleting all elements currently in the queue
|
||||
// (if T is a pointer type) and notifying all waiting threads. Any future
|
||||
// calls to pop() or waitAndPop() will return immediately with false or
|
||||
// without modifying the provided reference, respectively.
|
||||
void cancel()
|
||||
{
|
||||
std::unique_lock< std::mutex > lock( m_queueLock );
|
||||
|
@ -90,6 +109,8 @@ namespace Sapphire::Common::Util
|
|||
}
|
||||
|
||||
private:
|
||||
// Helper functions for deleting queued objects depending on whether T is
|
||||
// a pointer type or not.
|
||||
template< typename E = T >
|
||||
typename std::enable_if< std::is_pointer< E >::value >::type deleteQueuedObject( E& obj )
|
||||
{
|
||||
|
@ -101,7 +122,4 @@ namespace Sapphire::Common::Util
|
|||
{
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
}// namespace Sapphire::Common::Util
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
#ifndef SAPPHIRE_SPAWNINDEXALLOCATOR_H
|
||||
#define SAPPHIRE_SPAWNINDEXALLOCATOR_H
|
||||
#pragma once
|
||||
|
||||
#include <queue>
|
||||
#include <unordered_map>
|
||||
#include <type_traits>
|
||||
#include <unordered_set>
|
||||
|
||||
namespace Sapphire::Common::Util
|
||||
{
|
||||
|
||||
// The SpawnIndexAllocator class template is a utility class that allocates
|
||||
// unique indices for spawned objects in the game world. It is parameterized
|
||||
// by the index type T and an optional actor ID type.
|
||||
template< typename T, typename ActorIdType = uint32_t >
|
||||
class SpawnIndexAllocator
|
||||
{
|
||||
|
@ -16,92 +16,109 @@ namespace Sapphire::Common::Util
|
|||
std::is_same< T, uint32_t >::value || std::is_same< T, uint64_t >::value,
|
||||
"T must be uint8_t, uint16_t, uint32_t, uint64_t" );
|
||||
|
||||
SpawnIndexAllocator() :
|
||||
m_maxSlotId( 0 ),
|
||||
m_reserveFirstSlot( false )
|
||||
// Constructor for the SpawnIndexAllocator, initializing internal variables
|
||||
// such as maximum slot ID, reserve first slot flag, and allocation failure ID.
|
||||
SpawnIndexAllocator() : m_maxSlotId( 0 ),
|
||||
m_reserveFirstSlot( false ),
|
||||
m_allocFailId( static_cast< T >( -1 ) )
|
||||
{
|
||||
}
|
||||
|
||||
// Initializes the SpawnIndexAllocator by setting the maximum slot ID and
|
||||
// whether to reserve the first slot. Sets up the free and used index sets.
|
||||
void init( T maxSlotId, bool reserveFirstSlot = false )
|
||||
{
|
||||
m_maxSlotId = maxSlotId;
|
||||
m_reserveFirstSlot = reserveFirstSlot;
|
||||
|
||||
setupQueue();
|
||||
setupSet();
|
||||
|
||||
// todo: reserve max slot id in map to prevent any runtime reshashing
|
||||
// reserve max slot id in set to prevent any runtime rehashing
|
||||
m_freeIndexes.reserve( m_maxSlotId );
|
||||
m_usedIndexes.reserve( m_maxSlotId );
|
||||
}
|
||||
|
||||
// Frees a used spawn index, given an actor ID. Removes the index from the
|
||||
// used set and adds it back to the free set. Returns the freed index or
|
||||
// the allocation failure ID if the actor ID is not found.
|
||||
T freeUsedSpawnIndex( ActorIdType actorId )
|
||||
{
|
||||
auto it = m_actorIdToAllocatedMap.find( actorId );
|
||||
if( it == m_actorIdToAllocatedMap.end() )
|
||||
return getAllocFailId();
|
||||
auto it = m_usedIndexes.find( actorId );
|
||||
if( it == m_usedIndexes.end() )
|
||||
return m_allocFailId;
|
||||
|
||||
auto index = it->second;
|
||||
m_availableIds.push( index );
|
||||
m_actorIdToAllocatedMap.erase( it );
|
||||
auto index = *it;
|
||||
m_usedIndexes.erase( it );
|
||||
m_freeIndexes.insert( index );
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
// Allocates the next free spawn index and associates it with the given
|
||||
// actor ID. Removes the index from the free set and adds it to the used set.
|
||||
// Returns the allocated index or the allocation failure ID if there are no
|
||||
// free indices.
|
||||
T getNextFreeSpawnIndex( ActorIdType actorId )
|
||||
{
|
||||
assert( m_maxSlotId != 0 );
|
||||
|
||||
if( m_availableIds.empty() )
|
||||
return getAllocFailId();
|
||||
if( m_freeIndexes.empty() )
|
||||
return m_allocFailId;
|
||||
|
||||
auto nextId = m_availableIds.front();
|
||||
m_availableIds.pop();
|
||||
|
||||
m_actorIdToAllocatedMap[ actorId ] = nextId;
|
||||
auto nextId = *m_freeIndexes.begin();
|
||||
m_freeIndexes.erase( m_freeIndexes.begin() );
|
||||
m_usedIndexes.insert( nextId );
|
||||
|
||||
return nextId;
|
||||
}
|
||||
|
||||
// Frees all used spawn indices and clears the used set. Resets the free
|
||||
// set to contain all possible indices.
|
||||
void freeAllSpawnIndexes()
|
||||
{
|
||||
setupQueue();
|
||||
setupSet();
|
||||
|
||||
m_actorIdToAllocatedMap.clear();
|
||||
m_usedIndexes.clear();
|
||||
}
|
||||
|
||||
// Returns true if the given spawn index is valid (i.e., not equal to the
|
||||
// allocation failure ID), false otherwise.
|
||||
bool isSpawnIndexValid( T spawnIndex )
|
||||
{
|
||||
return spawnIndex != getAllocFailId();
|
||||
return spawnIndex != m_allocFailId;
|
||||
}
|
||||
|
||||
// Returns the allocation failure ID.
|
||||
constexpr T getAllocFailId() const
|
||||
{
|
||||
return static_cast< T >( -1 );
|
||||
return m_allocFailId;
|
||||
}
|
||||
|
||||
protected:
|
||||
void setupQueue()
|
||||
// Sets up the free index set by inserting all possible spawn indices
|
||||
// into the set, optionally reserving the first slot.
|
||||
void setupSet()
|
||||
{
|
||||
assert( m_maxSlotId != 0 );
|
||||
|
||||
while( !m_availableIds.empty() )
|
||||
m_availableIds.pop();
|
||||
m_freeIndexes.clear();
|
||||
|
||||
uint32_t start = 0;
|
||||
|
||||
// slot 0 is reserved when used for spawning actors/players otherwise the local player actor spawnIndex
|
||||
// slot is reserved when used for spawning actors/players otherwise the local player actor spawnIndex
|
||||
// will be used by another actor and despawn the local player
|
||||
if( m_reserveFirstSlot )
|
||||
start = 1;
|
||||
|
||||
for( uint32_t i = start; i < m_maxSlotId; i++ )
|
||||
m_availableIds.push( i );
|
||||
m_freeIndexes.insert( i );
|
||||
}
|
||||
|
||||
std::queue< T > m_availableIds;
|
||||
std::unordered_map< ActorIdType, T > m_actorIdToAllocatedMap;
|
||||
std::unordered_set< T > m_freeIndexes;
|
||||
std::unordered_set< T > m_usedIndexes;
|
||||
|
||||
T m_maxSlotId;
|
||||
bool m_reserveFirstSlot;
|
||||
const T m_allocFailId;
|
||||
};
|
||||
}
|
||||
|
||||
#endif //SAPPHIRE_SPAWNINDEXALLOCATOR_H
|
||||
}// namespace Sapphire::Common::Util
|
|
@ -122,15 +122,14 @@ std::string Util::binaryToHexDump( uint8_t* pBinData, uint16_t size )
|
|||
|
||||
uint64_t Util::getTimeMs()
|
||||
{
|
||||
std::chrono::milliseconds epoch = std::chrono::duration_cast< std::chrono::milliseconds >
|
||||
( std::chrono::system_clock::now().time_since_epoch() );
|
||||
const auto epoch = std::chrono::duration_cast< std::chrono::milliseconds >( std::chrono::steady_clock::now().time_since_epoch() );
|
||||
return epoch.count();
|
||||
}
|
||||
|
||||
uint32_t Util::getTimeSeconds()
|
||||
{
|
||||
auto currClock = std::chrono::system_clock::now();
|
||||
return static_cast< uint32_t >( std::chrono::time_point_cast< std::chrono::seconds >( currClock ).time_since_epoch().count() );
|
||||
const auto currClock = std::chrono::steady_clock::now();
|
||||
return static_cast< uint32_t >( std::chrono::duration_cast< std::chrono::seconds >( currClock.time_since_epoch() ).count() );
|
||||
}
|
||||
|
||||
uint64_t Util::getEorzeanTimeStamp()
|
||||
|
@ -140,18 +139,17 @@ uint64_t Util::getEorzeanTimeStamp()
|
|||
|
||||
void Util::valueToFlagByteIndexValue( uint32_t inVal, uint8_t& outVal, uint16_t& outIndex )
|
||||
{
|
||||
uint32_t id = inVal;
|
||||
const uint32_t id = inVal;
|
||||
outIndex = id / 8;
|
||||
uint8_t bitIndex = id % 8;
|
||||
const uint8_t bitIndex = id % 8;
|
||||
|
||||
outVal = 1 << bitIndex;
|
||||
}
|
||||
|
||||
|
||||
std::string Util::fmtUtcTime( const std::string& fmt )
|
||||
{
|
||||
auto t = std::time( nullptr );
|
||||
auto tm = std::gmtime( &t );
|
||||
const auto t = std::time( nullptr );
|
||||
const auto tm = std::gmtime( &t );
|
||||
|
||||
std::stringstream ss;
|
||||
|
||||
|
|
|
@ -8,33 +8,44 @@
|
|||
|
||||
namespace Sapphire::Common::Util
|
||||
{
|
||||
|
||||
// Retrieves the operation code from a raw network packet
|
||||
uint16_t getOpCode( Network::Packets::FFXIVARR_PACKET_RAW& raw );
|
||||
|
||||
// Converts binary data to a hexadecimal string representation
|
||||
std::string binaryToHexString( uint8_t* pBinData, uint16_t size );
|
||||
|
||||
// Converts binary data to a formatted hexadecimal dump
|
||||
std::string binaryToHexDump( uint8_t* pBinData, uint16_t size );
|
||||
|
||||
// Converts an integer value to a hexadecimal string representation with the specified width
|
||||
std::string intToHexString( uint64_t intValue, uint8_t width = 2 );
|
||||
|
||||
// Erases all occurrences of the specified character from the input/output string
|
||||
void eraseAll( std::string& inOutStr, char remove );
|
||||
|
||||
// Erases all occurrences of any character in the remove string from the input/output string
|
||||
void eraseAllIn( std::string& inOutStr, std::string& remove );
|
||||
|
||||
// Returns a lowercase copy of the input string
|
||||
std::string toLowerCopy( const std::string& inStr );
|
||||
|
||||
// Formats the current UTC time according to the given format string
|
||||
std::string fmtUtcTime( const std::string& fmt );
|
||||
|
||||
// Gets the current time in milliseconds
|
||||
uint64_t getTimeMs();
|
||||
|
||||
/*!
|
||||
* Gets the current time in seconds
|
||||
* @brief Get a POSIX epoch representation of the current time
|
||||
* @return 32-bit unsigned integer
|
||||
*/
|
||||
|
||||
uint32_t getTimeSeconds();
|
||||
|
||||
// Gets the current Eorzean timestamp (used in the game world)
|
||||
uint64_t getEorzeanTimeStamp();
|
||||
|
||||
// Converts a value to a flag byte index value pair
|
||||
void valueToFlagByteIndexValue( uint32_t inVal, uint8_t& outVal, uint16_t& outIndex );
|
||||
|
||||
template< class T >
|
||||
|
|
|
@ -7,28 +7,40 @@
|
|||
|
||||
namespace Sapphire::Common::Util
|
||||
{
|
||||
|
||||
// Computes the squared distance between two 3D points (x, y, z) and (x1, y1, z1)
|
||||
float distanceSq( float x, float y, float z, float x1, float y1, float z1 );
|
||||
|
||||
// Computes the distance between two 3D points (x, y, z) and (x1, y1, z1)
|
||||
float distance( float x, float y, float z, float x1, float y1, float z1 );
|
||||
|
||||
// Computes the distance between two 3D positions using FFXIVARR_POSITION3 structures
|
||||
float distance( const Common::FFXIVARR_POSITION3& pos1, const Common::FFXIVARR_POSITION3& pos2 );
|
||||
|
||||
// Computes the squared distance between two 2D points (x, y) and (x1, y1)
|
||||
float distance2DSq( float x, float y, float x1, float y1 );
|
||||
|
||||
// Computes the distance between two 2D points (x, y) and (x1, y1)
|
||||
float distance2D( float x, float y, float x1, float y1 );
|
||||
|
||||
// Calculates the angle (in radians) to a point (x1, y1) from a point (x, y)
|
||||
float calcAngTo( float x, float y, float x1, float y1 );
|
||||
|
||||
// Calculates the angle (in radians) from a point (x1, y1) to a point (x, y)
|
||||
float calcAngFrom( float x, float y, float x1, float y1 );
|
||||
|
||||
// Truncates a floating-point value to a specified number of digits
|
||||
float trunc( float value, uint8_t digitsToRemain );
|
||||
|
||||
// Converts a float to a uint16_t
|
||||
uint16_t floatToUInt16( float val );
|
||||
|
||||
// Converts a float to a uint16_t representing a rotation angle
|
||||
uint16_t floatToUInt16Rot( float val );
|
||||
|
||||
// Converts a float to a uint8_t representing a rotation angle
|
||||
uint8_t floatToUInt8Rot( float val );
|
||||
|
||||
// Clamps a value between a minimum and maximum value
|
||||
template < typename T >
|
||||
T clamp( T val, T minimum, T maximum )
|
||||
{
|
||||
|
@ -41,8 +53,10 @@ namespace Sapphire::Common::Util
|
|||
return val;
|
||||
}
|
||||
|
||||
// Transforms a 3D position vector using a 3x3 matrix
|
||||
FFXIVARR_POSITION3 transform( const FFXIVARR_POSITION3& vector, const Matrix33& matrix );
|
||||
|
||||
// Converts a 3D position representing Euler angles to a direction
|
||||
float eulerToDirection( const FFXIVARR_POSITION3& euler );
|
||||
}
|
||||
|
||||
|
|
|
@ -1,14 +0,0 @@
|
|||
#include "Vector3.h"
|
||||
|
||||
using namespace Sapphire::Common;
|
||||
|
||||
inline bool FFXIVARR_POSITION3::operator == ( const FFXIVARR_POSITION3& target ) const
|
||||
{
|
||||
return x == target.x && y == target.y && z == target.z;
|
||||
}
|
||||
|
||||
|
||||
inline bool Vector3::operator == ( const Vector3& target ) const
|
||||
{
|
||||
return x == target.x && y == target.y && z == target.z && reserve == target.reserve;
|
||||
}
|
|
@ -1,5 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <cmath>
|
||||
|
||||
namespace Sapphire::Common
|
||||
{
|
||||
struct FFXIVARR_POSITION3
|
||||
|
@ -7,7 +9,24 @@ namespace Sapphire::Common
|
|||
float x;
|
||||
float y;
|
||||
float z;
|
||||
inline bool operator == ( const FFXIVARR_POSITION3& target ) const;
|
||||
|
||||
// Checks for equality between two FFXIVARR_POSITION3 objects
|
||||
inline bool operator==( const FFXIVARR_POSITION3& target ) const
|
||||
{
|
||||
return x == target.x && y == target.y && z == target.z;
|
||||
}
|
||||
|
||||
// Adds two FFXIVARR_POSITION3 objects
|
||||
inline FFXIVARR_POSITION3 operator+( const FFXIVARR_POSITION3& target ) const
|
||||
{
|
||||
return { x + target.x, y + target.y, z + target.z };
|
||||
}
|
||||
|
||||
// Subtracts two FFXIVARR_POSITION3 objects
|
||||
inline FFXIVARR_POSITION3 operator-( const FFXIVARR_POSITION3& target ) const
|
||||
{
|
||||
return { x - target.x, y - target.y, z - target.z };
|
||||
}
|
||||
};
|
||||
|
||||
struct Vector3
|
||||
|
@ -16,11 +35,59 @@ namespace Sapphire::Common
|
|||
float y;
|
||||
float z;
|
||||
float reserve;
|
||||
inline bool operator == ( const Vector3& target ) const;
|
||||
|
||||
// Checks for equality between two Vector3 objects
|
||||
inline bool operator==( const Vector3& target ) const
|
||||
{
|
||||
return x == target.x && y == target.y && z == target.z;
|
||||
}
|
||||
|
||||
// Adds two Vector3 objects
|
||||
inline Vector3 operator+( const Vector3& target ) const
|
||||
{
|
||||
return { x + target.x, y + target.y, z + target.z, reserve };
|
||||
}
|
||||
|
||||
// Subtracts two Vector3 objects
|
||||
inline Vector3 operator-( const Vector3& target ) const
|
||||
{
|
||||
return { x - target.x, y - target.y, z - target.z, reserve };
|
||||
}
|
||||
|
||||
// Scales a Vector3 object by a scalar value
|
||||
inline Vector3 operator*( float scalar ) const
|
||||
{
|
||||
return { x * scalar, y * scalar, z * scalar, reserve };
|
||||
}
|
||||
|
||||
// Computes the dot product of two Vector3 objects
|
||||
inline float dot( const Vector3& target ) const
|
||||
{
|
||||
return x * target.x + y * target.y + z * target.z;
|
||||
}
|
||||
|
||||
// Computes the cross product of two Vector3 objects
|
||||
inline Vector3 cross( const Vector3& target ) const
|
||||
{
|
||||
return { y * target.z - z * target.y, z * target.x - x * target.z, x * target.y - y * target.x, reserve };
|
||||
}
|
||||
|
||||
// Computes the length (magnitude) of a Vector3 object
|
||||
inline float length() const
|
||||
{
|
||||
return std::sqrt( x * x + y * y + z * z );
|
||||
}
|
||||
|
||||
// Normalizes a Vector3 object
|
||||
inline Vector3 normalize() const
|
||||
{
|
||||
float len = length();
|
||||
return { x / len, y / len, z / len, reserve };
|
||||
}
|
||||
};
|
||||
|
||||
struct Matrix33
|
||||
{
|
||||
float m[ 3 ][ 3 ];
|
||||
};
|
||||
}
|
||||
}// namespace Sapphire::Common
|
|
@ -6,19 +6,13 @@
|
|||
#include <sstream>
|
||||
#include <Logging/Logger.h>
|
||||
|
||||
#include <common/Util/Util.h>
|
||||
#include <Util/Util.h>
|
||||
|
||||
using namespace Sapphire;
|
||||
using namespace Sapphire::Common;
|
||||
|
||||
// fucking filesystem
|
||||
#if _MSC_VER >= 1925
|
||||
#include <filesystem>
|
||||
namespace fs = std::filesystem;
|
||||
#else
|
||||
#include <experimental/filesystem>
|
||||
namespace fs = std::experimental::filesystem;
|
||||
#endif
|
||||
|
||||
|
||||
DbManager::DbManager( const std::string& host, const std::string& database, const std::string& user, const std::string& pw, uint16_t port ) :
|
||||
|
|
|
@ -2,21 +2,16 @@
|
|||
#include <iostream>
|
||||
#include <cctype>
|
||||
#include <set>
|
||||
#include <common/Logging/Logger.h>
|
||||
#include <Logging/Logger.h>
|
||||
#include <MySqlConnector.h>
|
||||
#include <common/Util/CrashHandler.h>
|
||||
#include <common/Config/ConfigMgr.h>
|
||||
#include <Util/CrashHandler.h>
|
||||
#include <Config/ConfigMgr.h>
|
||||
|
||||
Sapphire::Common::Util::CrashHandler crashHandler;
|
||||
|
||||
// fucking filesystem
|
||||
#if _MSC_VER >= 1925
|
||||
|
||||
#include <filesystem>
|
||||
namespace filesys = std::filesystem;
|
||||
#else
|
||||
#include <experimental/filesystem>
|
||||
namespace filesys = std::experimental::filesystem;
|
||||
#endif
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
#include <fstream>
|
||||
#include <streambuf>
|
||||
|
@ -36,19 +31,19 @@ std::vector< std::string > getAllFilesInDir( const std::string& dirPath,
|
|||
try
|
||||
{
|
||||
// Check if given path exists and points to a directory
|
||||
if( filesys::exists( dirPath ) && filesys::is_directory( dirPath ) )
|
||||
if( fs::exists( dirPath ) && fs::is_directory( dirPath ) )
|
||||
{
|
||||
// Create a Recursive Directory Iterator object and points to the starting of directory
|
||||
filesys::recursive_directory_iterator iter( dirPath );
|
||||
fs::recursive_directory_iterator iter( dirPath );
|
||||
|
||||
// Create a Recursive Directory Iterator object pointing to end.
|
||||
filesys::recursive_directory_iterator end;
|
||||
fs::recursive_directory_iterator end;
|
||||
|
||||
// Iterate till end
|
||||
while( iter != end )
|
||||
{
|
||||
// Check if current entry is a directory and if exists in skip list
|
||||
if( filesys::is_directory( iter->path() ) &&
|
||||
if( fs::is_directory( iter->path() ) &&
|
||||
( std::find( dirSkipList.begin(), dirSkipList.end(), iter->path().filename() ) != dirSkipList.end() ) )
|
||||
{
|
||||
// Skip the iteration of current directory pointed by iterator
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#include <Common.h>
|
||||
#include <Vector3.cpp>
|
||||
#include <Vector3.h>
|
||||
#include <Network/CommonNetwork.h>
|
||||
#include <Network/GamePacket.h>
|
||||
#include <Network/CommonActorControl.h>
|
||||
|
|
|
@ -56,7 +56,8 @@ bool Sapphire::Scripting::ScriptMgr::init()
|
|||
std::set< std::string > files;
|
||||
auto& server = Common::Service< World::WorldServer >::ref();
|
||||
|
||||
auto status = loadDir( server.getConfig().scripts.path, files, m_nativeScriptMgr->getModuleExtension() );
|
||||
fs::path script_path( server.getConfig().scripts.path );
|
||||
auto status = loadDir( script_path.string(), files, m_nativeScriptMgr->getModuleExtension() );
|
||||
|
||||
if( !status )
|
||||
{
|
||||
|
@ -67,13 +68,13 @@ bool Sapphire::Scripting::ScriptMgr::init()
|
|||
uint32_t scriptsFound = 0;
|
||||
uint32_t scriptsLoaded = 0;
|
||||
|
||||
for( auto itr = files.begin(); itr != files.end(); ++itr )
|
||||
for( const auto& file_path_str : files )
|
||||
{
|
||||
auto& path = *itr;
|
||||
fs::path file_path( file_path_str );
|
||||
|
||||
scriptsFound++;
|
||||
|
||||
if( m_nativeScriptMgr->loadScript( path ) )
|
||||
if( m_nativeScriptMgr->loadScript( file_path.string() ) )
|
||||
scriptsLoaded++;
|
||||
}
|
||||
|
||||
|
|
|
@ -180,14 +180,28 @@ void WorldServer::run( int32_t argc, char* argv[] )
|
|||
auto verString = readFileToString( verPath );
|
||||
if( verString != m_config.global.general.dataVersion )
|
||||
{
|
||||
Logger::fatal( "Sqpack version {} does not match expected version {}!", verString, m_config.global.general.dataVersion );
|
||||
return;
|
||||
Logger::warn( "Sqpack version {} does not match expected version {}!", verString, m_config.global.general.dataVersion );
|
||||
|
||||
std::string response;
|
||||
do
|
||||
{
|
||||
Logger::warn( "Continuing with mismatched versions may cause unexpected behavior, and you will not receive support. Continue at your own risk." );
|
||||
Logger::warn( "Do you wish to continue? (yes/no): " );
|
||||
std::cin >> response;
|
||||
std::transform( response.begin(), response.end(), response.begin(), ::tolower );
|
||||
} while( response != "yes" && response != "no" );
|
||||
|
||||
if( response == "no" )
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch ( const std::exception& e )
|
||||
catch( const std::exception& e )
|
||||
{
|
||||
Logger::fatal( e.what() );
|
||||
return;
|
||||
Logger::warn( "Failed to retrieve the server's SqPack version. Supported server version is: {}", m_config.global.general.dataVersion );
|
||||
Logger::warn( "Ensure the server data version is configured correctly before seeking help or creating an issue." );
|
||||
Logger::warn( "Reason: {}", e.what() );
|
||||
}
|
||||
|
||||
if( !pExdData->init( dataPath ) )
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include <mutex>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <thread>
|
||||
#include "ForwardsZone.h"
|
||||
#include <Config/ConfigDef.h>
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue