mirror of
https://github.com/SapphireServer/Sapphire.git
synced 2025-05-23 10:17:44 +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 )
|
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 "${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()
|
else()
|
||||||
add_definitions( -D_WIN32_WINNT=0x601 )
|
add_definitions( -D_WIN32_WINNT=0x601 )
|
||||||
add_definitions( -D_CRT_SECURE_NO_WARNINGS )
|
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:
|
default:
|
||||||
throw std::runtime_error(
|
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;
|
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 );
|
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 );
|
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();
|
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
|
// 32000 in compressed_size means it is not compressed so take uncompressed_size
|
||||||
if( block_header.compressed_size == 32000 )
|
if( block_header.compressed_size == 32000 )
|
||||||
{
|
{
|
||||||
m_handle.read( o_data.data() + data_size, block_header.uncompressed_size );
|
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
|
else
|
||||||
{
|
{
|
||||||
// If it is compressed use zlib
|
// If it is compressed use zlib
|
||||||
// Read the data to be decompressed
|
// Read the data to be decompressed
|
||||||
std::vector< char > temp_buffer( block_header.compressed_size );
|
auto temp_buffer = std::make_unique< char[] >( block_header.compressed_size );
|
||||||
m_handle.read( temp_buffer.data(), 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() ),
|
if( !m_handle.good() )
|
||||||
temp_buffer.size(),
|
{
|
||||||
|
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 ),
|
reinterpret_cast< uint8_t* >( o_data.data() + data_size ),
|
||||||
static_cast< size_t >( block_header.uncompressed_size ) );
|
static_cast< size_t >( block_header.uncompressed_size ) );
|
||||||
}
|
}
|
||||||
|
|
18
deps/datReader/DatCat.cpp
vendored
18
deps/datReader/DatCat.cpp
vendored
|
@ -5,21 +5,21 @@
|
||||||
#include "GameData.h"
|
#include "GameData.h"
|
||||||
#include "Index.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 ),
|
Cat::Cat( const std::filesystem::path& basePath, uint32_t catNum, const std::string& name ) : m_name( name ),
|
||||||
m_catNum( catNum ),
|
m_catNum( catNum ),
|
||||||
m_chunk( -1 )
|
m_chunk( -1 )
|
||||||
{
|
{
|
||||||
|
// Format the category number as a two-digit hex string
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
ss << std::setw( 2 ) << std::setfill( '0' ) << std::hex << catNum;
|
ss << std::setw( 2 ) << std::setfill( '0' ) << std::hex << catNum;
|
||||||
std::string prefix = ss.str() + "0000.win32";
|
std::string prefix = ss.str() + "0000.win32";
|
||||||
|
|
||||||
|
// Create an Index object using the formatted category number and basePath
|
||||||
m_index = std::make_unique< Index >( basePath / "ffxiv" / ( prefix + ".index" ) );
|
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 )
|
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 ) );
|
||||||
|
@ -30,17 +30,17 @@ namespace xiv
|
||||||
m_catNum( catNum ),
|
m_catNum( catNum ),
|
||||||
m_chunk( chunk )
|
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" ) );
|
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 )
|
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
|
const Index& Cat::getIndex() const
|
||||||
{
|
{
|
||||||
|
@ -72,6 +72,4 @@ namespace xiv
|
||||||
{
|
{
|
||||||
return m_catNum;
|
return m_catNum;
|
||||||
}
|
}
|
||||||
|
}// namespace xiv::dat
|
||||||
}// namespace dat
|
|
||||||
}// namespace xiv
|
|
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
|
// Retrieve a file from the category given its hashes
|
||||||
std::unique_ptr< File > getFile( uint32_t dir_hash, uint32_t filename_hash ) const;
|
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;
|
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;
|
bool doesDirExist( uint32_t dir_hash ) const;
|
||||||
|
|
||||||
|
// Returns the name of the Cat object
|
||||||
// Returns thename of the category
|
|
||||||
const std::string& getName() const;
|
const std::string& getName() const;
|
||||||
|
|
||||||
// Returns the number of the category
|
// Returns the category number of the Cat object
|
||||||
uint32_t getCatNum() const;
|
uint32_t getCatNum() const;
|
||||||
|
|
||||||
protected:
|
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:
|
public:
|
||||||
ENpcData data;
|
ENpcData data;
|
||||||
std::string_view name;
|
std::string_view name;
|
||||||
|
@ -94,7 +95,8 @@ public:
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
struct LGB_EOBJ_ENTRY : public LgbEntry {
|
struct LGB_EOBJ_ENTRY : public LgbEntry
|
||||||
|
{
|
||||||
public:
|
public:
|
||||||
EObjData data;
|
EObjData data;
|
||||||
std::string_view name;
|
std::string_view name;
|
||||||
|
@ -106,7 +108,8 @@ public:
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
struct LGB_MAP_RANGE_ENTRY : public LgbEntry {
|
struct LGB_MAP_RANGE_ENTRY : public LgbEntry
|
||||||
|
{
|
||||||
public:
|
public:
|
||||||
MapRangeData data;
|
MapRangeData data;
|
||||||
std::string_view name;
|
std::string_view name;
|
||||||
|
@ -118,7 +121,8 @@ public:
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
struct LGB_EXIT_RANGE_ENTRY : public LgbEntry {
|
struct LGB_EXIT_RANGE_ENTRY : public LgbEntry
|
||||||
|
{
|
||||||
public:
|
public:
|
||||||
ExitRangeData data;
|
ExitRangeData data;
|
||||||
std::string_view name;
|
std::string_view name;
|
||||||
|
@ -130,7 +134,8 @@ public:
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
struct LGB_POP_RANGE_ENTRY : public LgbEntry {
|
struct LGB_POP_RANGE_ENTRY : public LgbEntry
|
||||||
|
{
|
||||||
public:
|
public:
|
||||||
PopRangeData data;
|
PopRangeData data;
|
||||||
|
|
||||||
|
@ -140,7 +145,8 @@ public:
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
struct LGB_EVENT_RANGE_ENTRY : public LgbEntry {
|
struct LGB_EVENT_RANGE_ENTRY : public LgbEntry
|
||||||
|
{
|
||||||
public:
|
public:
|
||||||
EventRangeData data;
|
EventRangeData data;
|
||||||
|
|
||||||
|
@ -198,7 +204,7 @@ struct LGB_GROUP
|
||||||
LGB_FILE* parent;
|
LGB_FILE* parent;
|
||||||
LGB_GROUP_HEADER header;
|
LGB_GROUP_HEADER header;
|
||||||
LayerSetReferencedList layerSetReferencedList;
|
LayerSetReferencedList layerSetReferencedList;
|
||||||
std::string name;
|
std::string_view name;
|
||||||
std::vector< std::shared_ptr< LgbEntry > > entries;
|
std::vector< std::shared_ptr< LgbEntry > > entries;
|
||||||
std::vector< LayerSetReferenced > refs;
|
std::vector< LayerSetReferenced > refs;
|
||||||
|
|
||||||
|
@ -206,19 +212,32 @@ struct LGB_GROUP
|
||||||
{
|
{
|
||||||
parent = parentStruct;
|
parent = parentStruct;
|
||||||
header = *reinterpret_cast< LGB_GROUP_HEADER* >( buf + offset );
|
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 );
|
layerSetReferencedList = *reinterpret_cast< LayerSetReferencedList* >( buf + offset + header.LayerSetRef );
|
||||||
|
|
||||||
|
// Check if there are any layer set references to initialize
|
||||||
if( layerSetReferencedList.LayerSetCount > 0 )
|
if( layerSetReferencedList.LayerSetCount > 0 )
|
||||||
{
|
{
|
||||||
refs.resize( layerSetReferencedList.LayerSetCount );
|
// Reserve memory for layer set references
|
||||||
std::memcpy( refs.data(), buf + offset + header.LayerSetRef + layerSetReferencedList.LayerSets, layerSetReferencedList.LayerSetCount * sizeof( LayerSetReferenced ) );
|
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 );
|
entries.reserve( header.entryCount );
|
||||||
|
|
||||||
|
// Calculate the offset for entries
|
||||||
const auto entriesOffset = offset + header.entriesOffset;
|
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 )
|
for( auto i = 0; i < header.entryCount; ++i )
|
||||||
{
|
{
|
||||||
const auto entryOffset = entriesOffset + *reinterpret_cast< int32_t* >( buf + ( entriesOffset + i * 4 ) );
|
const auto entryOffset = entriesOffset + *reinterpret_cast< int32_t* >( buf + ( entriesOffset + i * 4 ) );
|
||||||
|
@ -277,7 +296,7 @@ struct LGB_GROUP
|
||||||
}
|
}
|
||||||
catch( std::exception& e )
|
catch( std::exception& e )
|
||||||
{
|
{
|
||||||
std::cout << name << " " << e.what() << std::endl;
|
throw e;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -296,63 +315,38 @@ struct LGB_FILE_HEADER
|
||||||
int32_t groupCount;
|
int32_t groupCount;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct LGB_FILE {
|
struct LGB_FILE
|
||||||
|
{
|
||||||
LGB_FILE_HEADER header;
|
LGB_FILE_HEADER header;
|
||||||
std::vector< LGB_GROUP > groups;
|
std::vector< LGB_GROUP > groups;
|
||||||
std::string m_name;
|
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 )
|
LGB_FILE( char* buf, const std::string& name ) : LGB_FILE( buf )
|
||||||
{
|
{
|
||||||
m_name = name;
|
m_name = name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Constructor that initializes an LGB_FILE object from a buffer
|
||||||
LGB_FILE( char* buf )
|
LGB_FILE( char* buf )
|
||||||
{
|
{
|
||||||
|
// Reinterpret the buffer as an LGB_FILE_HEADER pointer and dereference it
|
||||||
header = *reinterpret_cast< LGB_FILE_HEADER* >( buf );
|
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 )
|
if( strncmp( &header.magic[ 0 ], "LGB1", 4 ) != 0 || strncmp( &header.magic2[ 0 ], "LGP1", 4 ) != 0 )
|
||||||
|
{
|
||||||
throw std::runtime_error( "Invalid LGB file!" );
|
throw std::runtime_error( "Invalid LGB file!" );
|
||||||
|
}
|
||||||
|
|
||||||
constexpr auto baseOffset = sizeof( header );
|
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 )
|
for( size_t i = 0; i < header.groupCount; ++i )
|
||||||
{
|
{
|
||||||
const auto groupOffset = baseOffset + *reinterpret_cast< int32_t* >( buf + ( baseOffset + i * 4 ) );
|
const auto groupOffset = baseOffset + *reinterpret_cast< int32_t* >( buf + ( baseOffset + i * 4 ) );
|
||||||
groups.emplace_back( buf, this, groupOffset );
|
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;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Multiplies two 4x4 matrices and returns the result
|
||||||
matrix4 operator*( const matrix4& rhs ) const
|
matrix4 operator*( const matrix4& rhs ) const
|
||||||
{
|
{
|
||||||
matrix4 ret;
|
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 ) =
|
// Iterate through each column of the resulting matrix
|
||||||
( *this )( i, 0 ) * rhs( 0, 0 ) + ( *this )( i, 1 ) * rhs( 1, 0 ) + ( *this )( i, 2 ) * rhs( 2, 0 ) +
|
for( unsigned int col = 0; col < 4; col++ )
|
||||||
( *this )( i, 3 ) * rhs( 3, 0 );
|
{
|
||||||
ret( i, 1 ) =
|
// Calculate the value for the current cell by summing the product of the corresponding row and column elements
|
||||||
( *this )( i, 0 ) * rhs( 0, 1 ) + ( *this )( i, 1 ) * rhs( 1, 1 ) + ( *this )( i, 2 ) * rhs( 2, 1 ) +
|
float value = 0;
|
||||||
( *this )( i, 3 ) * rhs( 3, 1 );
|
for( unsigned int k = 0; k < 4; k++ )
|
||||||
ret( i, 2 ) =
|
{
|
||||||
( *this )( i, 0 ) * rhs( 0, 2 ) + ( *this )( i, 1 ) * rhs( 1, 2 ) + ( *this )( i, 2 ) * rhs( 2, 2 ) +
|
value += ( *this )( row, k ) * rhs( k, col );
|
||||||
( *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 );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Assign the calculated value to the corresponding cell of the resulting matrix
|
||||||
|
ret( row, col ) = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
53
deps/datReader/DatCategories/bg/sgb.h
vendored
53
deps/datReader/DatCategories/bg/sgb.h
vendored
|
@ -1,5 +1,4 @@
|
||||||
#ifndef _SGB_H
|
#pragma once
|
||||||
#define _SGB_H
|
|
||||||
|
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
@ -132,24 +131,24 @@ struct SGB_MODEL_ENTRY : public SGB_GROUP_ENTRY
|
||||||
{
|
{
|
||||||
SGB_MODEL_HEADER header;
|
SGB_MODEL_HEADER header;
|
||||||
SgbGroupEntryType type;
|
SgbGroupEntryType type;
|
||||||
std::string name;
|
std::string_view name;
|
||||||
std::string modelFileName;
|
std::string_view modelFileName;
|
||||||
std::string collisionFileName;
|
std::string_view collisionFileName;
|
||||||
|
|
||||||
SGB_MODEL_ENTRY( char* buf, size_t offset, SgbGroupEntryType type )
|
SGB_MODEL_ENTRY( char* buf, size_t offset, SgbGroupEntryType type )
|
||||||
{
|
{
|
||||||
this->type = type;
|
this->type = type;
|
||||||
header = *reinterpret_cast< SGB_MODEL_HEADER* >( buf + offset );
|
header = *reinterpret_cast< SGB_MODEL_HEADER* >( buf + offset );
|
||||||
name = std::string( buf + offset + header.nameOffset );
|
name = std::string_view( buf + offset + header.nameOffset );
|
||||||
modelFileName = std::string( buf + offset + header.modelFileOffset );
|
modelFileName = std::string_view( buf + offset + header.modelFileOffset );
|
||||||
collisionFileName = std::string( buf + offset + header.collisionFileOffset );
|
collisionFileName = std::string_view( buf + offset + header.collisionFileOffset );
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SGB_GROUP
|
struct SGB_GROUP
|
||||||
{
|
{
|
||||||
SGB_GROUP_HEADER header;
|
SGB_GROUP_HEADER header;
|
||||||
std::string name;
|
std::string_view name;
|
||||||
SGB_FILE* parent;
|
SGB_FILE* parent;
|
||||||
std::vector< std::shared_ptr< SGB_GROUP_ENTRY > > entries;
|
std::vector< std::shared_ptr< SGB_GROUP_ENTRY > > entries;
|
||||||
|
|
||||||
|
@ -157,23 +156,32 @@ struct SGB_GROUP
|
||||||
{
|
{
|
||||||
parent = file;
|
parent = file;
|
||||||
header = *reinterpret_cast< SGB_GROUP_HEADER* >( buf + offset );
|
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 );
|
auto entriesOffset = offset + sizeof( header );
|
||||||
|
|
||||||
|
entries.reserve( header.entryCount );
|
||||||
|
|
||||||
for( auto i = 0; i < header.entryCount; ++i )
|
for( auto i = 0; i < header.entryCount; ++i )
|
||||||
{
|
{
|
||||||
auto entryOffset = entriesOffset + *reinterpret_cast< uint32_t* >( buf + ( entriesOffset + ( i * 4 ) ) );
|
auto entryOffset = entriesOffset + *reinterpret_cast< uint32_t* >( buf + ( entriesOffset + ( i * 4 ) ) );
|
||||||
if( entryOffset > fileSize )
|
if( entryOffset > fileSize )
|
||||||
throw std::runtime_error( "SGB_GROUP entry offset was larger than SGB file size!" );
|
throw std::runtime_error( "SGB_GROUP entry offset was larger than SGB file size!" );
|
||||||
|
|
||||||
auto type = *reinterpret_cast< uint32_t* >( buf + entryOffset );
|
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 ) );
|
case SgbGroupEntryType::Model:
|
||||||
|
case SgbGroupEntryType::Gimmick:
|
||||||
|
{
|
||||||
|
entries.emplace_back( std::make_shared< SGB_MODEL_ENTRY >( buf, entryOffset, ( SgbGroupEntryType ) type ) );
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
else
|
default:
|
||||||
{
|
{
|
||||||
// std::cout << "\t\tUnknown SGB entry! Group: " << name << " type: " << type << " index: " << i << " entryOffset: " << entryOffset << "\n";
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -268,27 +276,28 @@ struct SGB_FILE
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
entries.reserve( 2 );
|
||||||
|
|
||||||
auto group = SGB_GROUP( buf, this, header.fileSize, baseOffset + header.sharedOffset );
|
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 );
|
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 );
|
uint32_t stateCount = *reinterpret_cast< uint32_t* >( buf + baseOffset + header.statesOffset + 4 );
|
||||||
if( stateCount > 0 )
|
if( stateCount > 0 )
|
||||||
{
|
{
|
||||||
stateCount = stateCount;
|
stateEntries.reserve( stateCount );
|
||||||
|
|
||||||
for( size_t i = 0; i < stateCount; ++i )
|
for( size_t i = 0; i < stateCount; ++i )
|
||||||
{
|
{
|
||||||
auto state = SGB_STATE_ENTRY( buf + baseOffset + header.statesOffset + 8 + i * sizeof( SGB_STATE_HEADER ) );
|
auto state = SGB_STATE_ENTRY( buf + baseOffset + header.statesOffset + 8 + i * sizeof( SGB_STATE_HEADER ) );
|
||||||
stateEntries.push_back( state );
|
stateEntries.emplace_back( state );
|
||||||
std::cout << state.name << "\n";
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch( std::exception& e )
|
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
|
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;
|
_exh = i_exh;
|
||||||
_files = i_files;
|
_files = i_files;
|
||||||
|
|
||||||
|
|
||||||
// Iterates over all the files
|
// 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 )
|
for( auto& file_ptr : _files )
|
||||||
|
@ -29,8 +28,6 @@ namespace xiv::exd
|
||||||
|
|
||||||
// Preallocate and extract the record_indices
|
// Preallocate and extract the record_indices
|
||||||
const uint32_t record_count = exd_header.index_size / sizeof( ExdRecordIndexData );
|
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 )
|
for( uint32_t i = 0; i < record_count; ++i )
|
||||||
{
|
{
|
||||||
auto recordIndex = extract< ExdRecordIndexData >( iss );
|
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 )
|
||||||
{
|
{
|
||||||
}
|
// Check if id is in the cache
|
||||||
|
|
||||||
const std::vector< Field > Exd::get_row( uint32_t id, uint32_t subRow )
|
|
||||||
{
|
|
||||||
|
|
||||||
auto cacheEntryIt = _idCache.find( id );
|
auto cacheEntryIt = _idCache.find( id );
|
||||||
if( cacheEntryIt == _idCache.end() )
|
if( cacheEntryIt == _idCache.end() )
|
||||||
throw std::runtime_error( "Id not found: " + std::to_string( id ) );
|
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() );
|
const uint32_t member_count = static_cast< uint32_t >( _exh->get_members().size() );
|
||||||
auto& file_ptr = cacheEntryIt->second.file;
|
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::vector< char > dataCpy = file_ptr->get_data_sections().front();
|
||||||
std::istringstream iss( std::string( dataCpy.begin(), dataCpy.end() ) );
|
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 ];
|
auto fields = _data[ id ];
|
||||||
fields.reserve( member_count );
|
fields.reserve( member_count );
|
||||||
iss.seekg( cacheEntryIt->second.offset + 6 );
|
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 ) );
|
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() )
|
for( auto& member_entry : _exh->get_exh_members() )
|
||||||
{
|
{
|
||||||
// Seek to the position of the member to extract.
|
// Seek to the position of the member to extract
|
||||||
// 6 is because we have uint32_t/uint16_t at the start of each record
|
|
||||||
iss.seekg( offset + member_entry.offset );
|
iss.seekg( offset + member_entry.offset );
|
||||||
|
|
||||||
// Switch depending on the type to extract
|
// Switch depending on the type to extract
|
||||||
|
|
29
deps/datReader/Exd.h
vendored
29
deps/datReader/Exd.h
vendored
|
@ -1,18 +1,18 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <memory>
|
|
||||||
#include <map>
|
#include <map>
|
||||||
|
#include <memory>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
|
||||||
#include <variant>
|
#include <variant>
|
||||||
|
|
||||||
#include "File.h"
|
|
||||||
#include "Exd/Common.h"
|
#include "Exd/Common.h"
|
||||||
#include "Exd/Structs.h"
|
#include "Exd/Structs.h"
|
||||||
|
#include "Exh.h"
|
||||||
|
#include "File.h"
|
||||||
|
#include "bparse.h"
|
||||||
#include "stream.h"
|
#include "stream.h"
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include "Exh.h"
|
|
||||||
#include "bparse.h"
|
|
||||||
|
|
||||||
namespace xiv::exd
|
namespace xiv::exd
|
||||||
{
|
{
|
||||||
|
@ -27,7 +27,7 @@ namespace xiv::exd
|
||||||
uint32_t id;
|
uint32_t id;
|
||||||
uint32_t offset;
|
uint32_t offset;
|
||||||
};
|
};
|
||||||
}
|
}// namespace xiv::exd
|
||||||
|
|
||||||
namespace xiv::utils::bparse
|
namespace xiv::utils::bparse
|
||||||
{
|
{
|
||||||
|
@ -86,13 +86,11 @@ namespace xiv::exd
|
||||||
public:
|
public:
|
||||||
// i_exh: the header
|
// i_exh: the header
|
||||||
// i_files: the multiple exd files
|
// 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
|
// Get a row by its id
|
||||||
const std::vector< Field > get_row( uint32_t id );
|
const std::vector< Field > get_row( uint32_t id );
|
||||||
|
@ -107,8 +105,7 @@ namespace xiv::exd
|
||||||
|
|
||||||
if( sizeof( T ) != _exh->get_header().data_offset )
|
if( sizeof( T ) != _exh->get_header().data_offset )
|
||||||
{
|
{
|
||||||
throw std::runtime_error(
|
throw std::runtime_error( "the struct size (" + std::to_string( sizeof( T ) ) + ") doesn't match the size in the header (" +
|
||||||
"the struct size (" + std::to_string( sizeof( T ) ) + ") doesn't match the size in the header (" +
|
|
||||||
std::to_string( _exh->get_header().data_offset ) + ")!" );
|
std::to_string( _exh->get_header().data_offset ) + ")!" );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -126,7 +123,7 @@ namespace xiv::exd
|
||||||
fields.reserve( member_count );
|
fields.reserve( member_count );
|
||||||
iss.seekg( cacheEntryIt->second.offset + 6 );
|
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;
|
int stringCount = 0;
|
||||||
for( auto& member_entry : _exh->get_exh_members() )
|
for( auto& member_entry : _exh->get_exh_members() )
|
||||||
|
@ -221,7 +218,6 @@ namespace xiv::exd
|
||||||
}
|
}
|
||||||
|
|
||||||
return pSheet;
|
return pSheet;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get a row by its id and sub-row
|
// Get a row by its id and sub-row
|
||||||
|
@ -270,7 +266,7 @@ namespace xiv::exd
|
||||||
fields.reserve( member_count );
|
fields.reserve( member_count );
|
||||||
iss.seekg( cacheEntryIt->second.offset + 6 );
|
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;
|
int stringCount = 0;
|
||||||
for( auto& member_entry : _exh->get_exh_members() )
|
for( auto& member_entry : _exh->get_exh_members() )
|
||||||
|
@ -379,5 +375,4 @@ namespace xiv::exd
|
||||||
std::map< uint32_t, ExdCacheEntry > _idCache;
|
std::map< uint32_t, ExdCacheEntry > _idCache;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}// namespace xiv::exd
|
||||||
|
|
42
deps/datReader/ExdCat.cpp
vendored
42
deps/datReader/ExdCat.cpp
vendored
|
@ -4,44 +4,39 @@
|
||||||
|
|
||||||
#include "GameData.h"
|
#include "GameData.h"
|
||||||
|
|
||||||
#include "Exh.h"
|
|
||||||
#include "Exd.h"
|
#include "Exd.h"
|
||||||
|
#include "Exh.h"
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
// Suffix of the filenames given a language
|
// 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::none, "" },
|
||||||
{xiv::exd::Language::ja, "_ja"},
|
{ xiv::exd::Language::ja, "_ja" },
|
||||||
{xiv::exd::Language::en, "_en"},
|
{ xiv::exd::Language::en, "_en" },
|
||||||
{xiv::exd::Language::de, "_de"},
|
{ xiv::exd::Language::de, "_de" },
|
||||||
{xiv::exd::Language::fr, "_fr"},
|
{ xiv::exd::Language::fr, "_fr" },
|
||||||
{xiv::exd::Language::chs, "_chs"}
|
{ xiv::exd::Language::chs, "_chs" }
|
||||||
};
|
};
|
||||||
}
|
}// namespace
|
||||||
|
|
||||||
namespace xiv::exd
|
namespace xiv::exd
|
||||||
{
|
{
|
||||||
Cat::Cat( dat::GameData& i_game_data, const std::string& i_name ) :
|
Cat::Cat( dat::GameData& i_game_data, const std::string& i_name ) : _name( i_name )
|
||||||
_name( i_name )
|
|
||||||
{
|
{
|
||||||
//XIV_INFO(xiv_exd_logger, "Initializing Cat with name: " << i_name);
|
|
||||||
// creates the header .exh
|
// creates the header .exh
|
||||||
{
|
|
||||||
auto header_file = i_game_data.getFile( "exd/" + i_name + ".exh" );
|
auto header_file = i_game_data.getFile( "exd/" + i_name + ".exh" );
|
||||||
_header = std::shared_ptr< Exh >( new Exh( *header_file ) );
|
_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
|
// chs not yet in data files
|
||||||
if( language == Language::en || language == Language::none )
|
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)
|
// 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;
|
std::vector< std::shared_ptr< dat::File > > files;
|
||||||
for( auto& exd_def: _header->get_exd_defs() )
|
for( auto& exd_def : _header->get_exd_defs() )
|
||||||
{
|
{
|
||||||
files.emplace_back( i_game_data.getFile(
|
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" ) );
|
||||||
|
@ -52,10 +47,7 @@ namespace xiv::exd
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Cat::~Cat()
|
Cat::~Cat() = default;
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::string& Cat::get_name() const
|
const std::string& Cat::get_name() const
|
||||||
{
|
{
|
||||||
|
@ -72,7 +64,7 @@ namespace xiv::exd
|
||||||
auto ln_it = _data.find( i_language );
|
auto ln_it = _data.find( i_language );
|
||||||
if( ln_it == _data.end() )
|
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 );
|
return *( ln_it->second );
|
||||||
|
@ -89,4 +81,4 @@ namespace xiv::exd
|
||||||
return *( ln_it->second );
|
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;
|
std::map<Language, std::unique_ptr<Exd>> _data;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}// namespace exd
|
||||||
}
|
}// namespace xiv
|
||||||
|
|
62
deps/datReader/ExdData.cpp
vendored
62
deps/datReader/ExdData.cpp
vendored
|
@ -7,26 +7,23 @@
|
||||||
|
|
||||||
#include "ExdCat.h"
|
#include "ExdCat.h"
|
||||||
|
|
||||||
namespace xiv::exd {
|
namespace xiv::exd
|
||||||
|
|
||||||
ExdData::ExdData( dat::GameData& i_game_data ) try :
|
|
||||||
_game_data( i_game_data )
|
|
||||||
{
|
{
|
||||||
//XIV_INFO(xiv_exd_logger, "Initializing ExdData");
|
ExdData::ExdData( dat::GameData& i_game_data )
|
||||||
|
try : _game_data( i_game_data )
|
||||||
|
{
|
||||||
// Fetch the root.exl and get a stream from it
|
// Fetch the root.exl and get a stream from it
|
||||||
auto root_exl = i_game_data.getFile( "exd/root.exl" );
|
auto root_exl = i_game_data.getFile( "exd/root.exl" );
|
||||||
std::vector< char > dataCpy = root_exl->get_data_sections().front();
|
std::vector< char > dataCpy = root_exl->get_data_sections().front();
|
||||||
xiv::utils::stream::vectorwrapbuf< char > databuf( dataCpy );
|
xiv::utils::stream::vectorwrapbuf< char > databuf( dataCpy );
|
||||||
std::istream stream( &databuf );
|
std::istream stream( &databuf );
|
||||||
|
|
||||||
// Iterates over the lines while skipping the first one
|
// Skip the first line (EXLT,2)
|
||||||
std::string line;
|
std::string line;
|
||||||
std::getline( stream, line ); // extract first line EXLT,2
|
|
||||||
std::getline( stream, line );
|
std::getline( stream, line );
|
||||||
|
|
||||||
// Until the EOF
|
// Read the remaining lines
|
||||||
while( !line.empty() )
|
while( std::getline( stream, line ) && !line.empty() )
|
||||||
{
|
{
|
||||||
// Format is cat_name,XX
|
// Format is cat_name,XX
|
||||||
// XX being an internal identifier
|
// XX being an internal identifier
|
||||||
|
@ -34,34 +31,26 @@ ExdData::ExdData( dat::GameData& i_game_data ) try :
|
||||||
auto sep = line.find( ',' );
|
auto sep = line.find( ',' );
|
||||||
auto category = line.substr( 0, sep );
|
auto category = line.substr( 0, sep );
|
||||||
|
|
||||||
// Add to the list of category name
|
// Add to the list of category names
|
||||||
// creates the empty category in the cats map
|
// Create the empty category in the cats map
|
||||||
// instantiate the creation mutex for this category
|
// Instantiate the creation mutex for this category
|
||||||
_cat_names.push_back( category );
|
_cat_names.emplace_back( category );
|
||||||
_cats[ category ] = std::unique_ptr< Cat >();
|
_cats[ category ] = nullptr;
|
||||||
_cat_creation_mutexes[ category ] = std::make_unique< std::mutex >();
|
_cat_creation_mutexes[ category ] = std::make_unique< std::mutex >();
|
||||||
|
|
||||||
std::getline( stream, line );
|
|
||||||
}
|
}
|
||||||
}
|
} catch( std::exception& e )
|
||||||
catch( std::exception& e )
|
{
|
||||||
{
|
|
||||||
// In case of failure here, client is supposed to catch the exception because it is not recoverable on our side
|
// 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() ) );
|
throw std::runtime_error( "ExdData initialization failed: " + std::string( e.what() ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
ExdData::~ExdData()
|
const std::vector< std::string >& ExdData::get_cat_names() const
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::vector< std::string >& ExdData::get_cat_names() const
|
|
||||||
{
|
|
||||||
return _cat_names;
|
return _cat_names;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Cat& ExdData::get_category( const std::string& i_cat_name )
|
const Cat& ExdData::get_category( const std::string& i_cat_name )
|
||||||
{
|
{
|
||||||
// Get the category from its name
|
// Get the category from its name
|
||||||
auto cat_it = _cats.find( i_cat_name );
|
auto cat_it = _cats.find( i_cat_name );
|
||||||
if( cat_it == _cats.end() )
|
if( cat_it == _cats.end() )
|
||||||
|
@ -80,10 +69,10 @@ const Cat& ExdData::get_category( const std::string& i_cat_name )
|
||||||
create_category( i_cat_name );
|
create_category( i_cat_name );
|
||||||
return *( _cats[ i_cat_name ] );
|
return *( _cats[ i_cat_name ] );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ExdData::create_category( const std::string& i_cat_name )
|
void ExdData::create_category( const std::string& i_cat_name )
|
||||||
{
|
{
|
||||||
// Lock mutex in this scope
|
// Lock mutex in this scope
|
||||||
std::lock_guard< std::mutex > lock( *( _cat_creation_mutexes[ i_cat_name ] ) );
|
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)
|
// Maybe after unlocking it has already been created, so check (most likely if it blocked)
|
||||||
|
@ -91,6 +80,5 @@ void ExdData::create_category( const std::string& i_cat_name )
|
||||||
{
|
{
|
||||||
_cats[ i_cat_name ] = std::make_unique< Cat >( _game_data, 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:
|
public:
|
||||||
// Need an initialized dat::GameData to retrieve the files from the dat
|
// Need an initialized dat::GameData to retrieve the files from the dat
|
||||||
ExdData(dat::GameData& i_game_data);
|
ExdData( dat::GameData& i_game_data );
|
||||||
~ExdData();
|
~ExdData() = default;
|
||||||
|
|
||||||
// Get the list of thenames of the categories
|
// 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
|
// 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
|
// 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:
|
protected:
|
||||||
// Lazy instantiation of category
|
// 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
|
// Reference to the game_data object
|
||||||
dat::GameData& _game_data;
|
dat::GameData& _game_data;
|
||||||
|
|
||||||
// Categories, indexed by their name
|
// 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()
|
// 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
|
// 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
|
namespace xiv::exd
|
||||||
{
|
{
|
||||||
|
|
||||||
Exh::Exh( const dat::File& i_file )
|
Exh::Exh( const dat::File& i_file )
|
||||||
{
|
{
|
||||||
// Get a stream from the file
|
// Get a stream from the file
|
||||||
std::vector< char > dataCpy = i_file.get_data_sections().front();
|
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
|
// Extract header and skip to member definitions
|
||||||
_header = extract< ExhHeader >( iss );
|
_header = extract< ExhHeader >( iss );
|
||||||
|
@ -43,10 +43,6 @@ namespace xiv::exd
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Exh::~Exh()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
const ExhHeader& Exh::get_header() const
|
const ExhHeader& Exh::get_header() const
|
||||||
{
|
{
|
||||||
return _header;
|
return _header;
|
||||||
|
|
41
deps/datReader/Exh.h
vendored
41
deps/datReader/Exh.h
vendored
|
@ -44,12 +44,13 @@ namespace xiv::exd
|
||||||
uint32_t start_id;
|
uint32_t start_id;
|
||||||
uint32_t count_id;
|
uint32_t count_id;
|
||||||
};
|
};
|
||||||
};
|
};// namespace xiv::exd
|
||||||
|
|
||||||
namespace xiv::utils::bparse {
|
namespace xiv::utils::bparse
|
||||||
template<>
|
|
||||||
inline void reorder< xiv::exd::ExhHeader >( xiv::exd::ExhHeader& i_struct )
|
|
||||||
{
|
{
|
||||||
|
template<>
|
||||||
|
inline void reorder< xiv::exd::ExhHeader >( xiv::exd::ExhHeader& i_struct )
|
||||||
|
{
|
||||||
for( int32_t i = 0; i < 0x4; ++i )
|
for( int32_t i = 0; i < 0x4; ++i )
|
||||||
{
|
{
|
||||||
xiv::utils::bparse::reorder( i_struct.magic[ i ] );
|
xiv::utils::bparse::reorder( i_struct.magic[ i ] );
|
||||||
|
@ -64,26 +65,26 @@ inline void reorder< xiv::exd::ExhHeader >( xiv::exd::ExhHeader& i_struct )
|
||||||
xiv::utils::bparse::reorder( i_struct.exd_count );
|
xiv::utils::bparse::reorder( i_struct.exd_count );
|
||||||
i_struct.language_count = xiv::utils::bparse::byteswap( i_struct.language_count );
|
i_struct.language_count = xiv::utils::bparse::byteswap( i_struct.language_count );
|
||||||
xiv::utils::bparse::reorder( i_struct.language_count );
|
xiv::utils::bparse::reorder( i_struct.language_count );
|
||||||
}
|
}
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
inline void reorder< xiv::exd::ExhMember >( xiv::exd::ExhMember& i_struct )
|
inline void reorder< xiv::exd::ExhMember >( xiv::exd::ExhMember& i_struct )
|
||||||
{
|
{
|
||||||
i_struct.type = xiv::utils::bparse::byteswap( i_struct.type );
|
i_struct.type = xiv::utils::bparse::byteswap( i_struct.type );
|
||||||
xiv::utils::bparse::reorder( i_struct.type );
|
xiv::utils::bparse::reorder( i_struct.type );
|
||||||
i_struct.offset = xiv::utils::bparse::byteswap( i_struct.offset );
|
i_struct.offset = xiv::utils::bparse::byteswap( i_struct.offset );
|
||||||
xiv::utils::bparse::reorder( i_struct.offset );
|
xiv::utils::bparse::reorder( i_struct.offset );
|
||||||
}
|
}
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
inline void reorder< xiv::exd::ExhExdDef >( xiv::exd::ExhExdDef& i_struct )
|
inline void reorder< xiv::exd::ExhExdDef >( xiv::exd::ExhExdDef& i_struct )
|
||||||
{
|
{
|
||||||
i_struct.start_id = xiv::utils::bparse::byteswap( i_struct.start_id );
|
i_struct.start_id = xiv::utils::bparse::byteswap( i_struct.start_id );
|
||||||
xiv::utils::bparse::reorder( i_struct.start_id );
|
xiv::utils::bparse::reorder( i_struct.start_id );
|
||||||
i_struct.count_id = xiv::utils::bparse::byteswap( i_struct.count_id );
|
i_struct.count_id = xiv::utils::bparse::byteswap( i_struct.count_id );
|
||||||
xiv::utils::bparse::reorder( i_struct.count_id );
|
xiv::utils::bparse::reorder( i_struct.count_id );
|
||||||
}
|
}
|
||||||
};
|
};// namespace xiv::utils::bparse
|
||||||
|
|
||||||
namespace xiv
|
namespace xiv
|
||||||
{
|
{
|
||||||
|
@ -105,16 +106,21 @@ namespace xiv
|
||||||
// The header file
|
// The header file
|
||||||
Exh( const dat::File& i_file );
|
Exh( const dat::File& i_file );
|
||||||
|
|
||||||
~Exh();
|
~Exh() = default;
|
||||||
|
|
||||||
|
// Returns a const reference to the ExhHeader object
|
||||||
const ExhHeader& get_header() const;
|
const ExhHeader& get_header() const;
|
||||||
|
|
||||||
|
// Returns a const reference to a vector of ExhExdDef objects
|
||||||
const std::vector< ExhExdDef >& get_exd_defs() const;
|
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;
|
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;
|
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;
|
const std::vector< ExhMember >& get_exh_members() const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
@ -126,6 +132,5 @@ namespace xiv
|
||||||
std::vector< Language > _languages;
|
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
|
FileType File::get_type() const
|
||||||
{
|
{
|
||||||
return _type;
|
return _type;
|
||||||
|
@ -31,12 +27,20 @@ namespace xiv::dat
|
||||||
|
|
||||||
void File::exportToFile( const std::filesystem::path& i_path ) const
|
void File::exportToFile( const std::filesystem::path& i_path ) const
|
||||||
{
|
{
|
||||||
std::ofstream ofs( i_path.string(), std::ios_base::binary | std::ios_base::out );
|
std::ofstream ofs( i_path, std::ios::binary | std::ios::out );
|
||||||
for( auto& data_section : _data_sections )
|
|
||||||
|
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:
|
public:
|
||||||
File();
|
File();
|
||||||
|
|
||||||
~File();
|
~File() = default;
|
||||||
|
|
||||||
|
// Returns the file type of the File object
|
||||||
FileType get_type() const;
|
FileType get_type() const;
|
||||||
|
|
||||||
// Getters functions for the data in the file
|
// Returns a const reference to the data sections in the File object
|
||||||
const std::vector< std::vector< char>>& get_data_sections() const;
|
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;
|
void exportToFile( const std::filesystem::path& i_path ) const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
// Stores the file type of the File object
|
||||||
FileType _type;
|
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;
|
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
|
#pragma once
|
||||||
#define XIV_DAT_INDEX_H
|
|
||||||
|
|
||||||
#include "SqPack.h"
|
#include "SqPack.h"
|
||||||
|
|
||||||
|
@ -58,6 +57,4 @@ namespace xiv::dat
|
||||||
HashTable m_hashTable;
|
HashTable m_hashTable;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}// namespace xiv::dat
|
||||||
|
|
||||||
#endif // XIV_DAT_INDEX_H
|
|
||||||
|
|
11
deps/datReader/SqPack.h
vendored
11
deps/datReader/SqPack.h
vendored
|
@ -1,5 +1,4 @@
|
||||||
#ifndef XIV_DAT_SQPACK_H
|
#pragma once
|
||||||
#define XIV_DAT_SQPACK_H
|
|
||||||
|
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
|
||||||
|
@ -15,7 +14,7 @@ namespace xiv::dat
|
||||||
uint8_t hash[0x14];
|
uint8_t hash[0x14];
|
||||||
uint32_t padding[0xB];
|
uint32_t padding[0xB];
|
||||||
};
|
};
|
||||||
}
|
}// namespace xiv::dat
|
||||||
|
|
||||||
namespace xiv::utils::bparse
|
namespace xiv::utils::bparse
|
||||||
{
|
{
|
||||||
|
@ -31,7 +30,7 @@ namespace xiv::utils::bparse
|
||||||
xiv::utils::bparse::reorder( i_struct.padding[ i ] );
|
xiv::utils::bparse::reorder( i_struct.padding[ i ] );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};// namespace xiv::utils::bparse
|
||||||
|
|
||||||
namespace xiv::dat
|
namespace xiv::dat
|
||||||
{
|
{
|
||||||
|
@ -53,6 +52,4 @@ namespace xiv::dat
|
||||||
std::ifstream m_handle;
|
std::ifstream m_handle;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}// namespace xiv::dat
|
||||||
|
|
||||||
#endif // XIV_DAT_SQPACK_H
|
|
||||||
|
|
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 xiv::utils::bparse::extract_cstring( std::istream& i_stream, const std::string& i_name )
|
||||||
{
|
{
|
||||||
std::string temp_str;
|
// Using a stringstream and reading character by character avoids this issue and ensures all input is processed correctly.
|
||||||
std::getline( i_stream, temp_str, '\0' );
|
std::stringstream ss;
|
||||||
return temp_str;
|
char c;
|
||||||
|
while( i_stream.get( c ) && c != '\0' )
|
||||||
|
{
|
||||||
|
ss << c;
|
||||||
|
}
|
||||||
|
return ss.str();
|
||||||
}
|
}
|
57
deps/datReader/bparse.h
vendored
57
deps/datReader/bparse.h
vendored
|
@ -7,15 +7,63 @@
|
||||||
namespace xiv::utils::bparse
|
namespace xiv::utils::bparse
|
||||||
{
|
{
|
||||||
|
|
||||||
// Internal macro for byteswapping
|
// Helper struct for compile-time unrolling of byteswap
|
||||||
template< int N >
|
template< int N, bool Unroll >
|
||||||
void byteswap_impl( char (& bytes)[N] )
|
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 )
|
||||||
|
{
|
||||||
|
// 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 );
|
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)
|
// byteswapping any type (no pointers to array)
|
||||||
template< typename T >
|
template< typename T >
|
||||||
|
@ -91,7 +139,6 @@ namespace xiv::utils::bparse
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// For cstrings
|
|
||||||
std::string extract_cstring( std::istream& i_stream, const std::string& i_name );
|
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 "conv.h"
|
||||||
#include <cstring>// for memcpy
|
#include <cstring>
|
||||||
|
|
||||||
namespace xiv::utils::conv
|
namespace xiv::utils::conv
|
||||||
{
|
{
|
||||||
|
@ -23,7 +23,7 @@ namespace xiv::utils::conv
|
||||||
t1 |= t2; // Re-insert sign bit
|
t1 |= t2; // Re-insert sign bit
|
||||||
|
|
||||||
float result;
|
float result;
|
||||||
memcpy( &result, &t1, sizeof( float ) );// Convert uint32_t to float using memcpy
|
memcpy( &result, &t1, sizeof( float ) );
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
11
deps/datReader/stream.h
vendored
11
deps/datReader/stream.h
vendored
|
@ -1,5 +1,4 @@
|
||||||
#ifndef XIV_UTILS_STREAM_H
|
#pragma once
|
||||||
#define XIV_UTILS_STREAM_H
|
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
@ -8,14 +7,12 @@
|
||||||
namespace xiv::utils::stream
|
namespace xiv::utils::stream
|
||||||
{
|
{
|
||||||
template< typename CharT, typename TraitsT = std::char_traits< CharT > >
|
template< typename CharT, typename TraitsT = std::char_traits< CharT > >
|
||||||
class vectorwrapbuf :
|
class vectorwrapbuf : public std::basic_streambuf< CharT, TraitsT >
|
||||||
public std::basic_streambuf< CharT, TraitsT >
|
|
||||||
{
|
{
|
||||||
public:
|
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() );
|
this->setg( vec.data(), vec.data(), vec.data() + vec.size() );
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}// namespace xiv::utils::stream
|
||||||
#endif // XIV_UTILS_STREAM_H
|
|
||||||
|
|
7
deps/datReader/zlib.h
vendored
7
deps/datReader/zlib.h
vendored
|
@ -1,5 +1,4 @@
|
||||||
#ifndef XIV_UTILS_ZLIB_H
|
#pragma once
|
||||||
#define XIV_UTILS_ZLIB_H
|
|
||||||
|
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <cstdint>
|
#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 );
|
void no_header_decompress( const uint8_t* in, size_t in_size, uint8_t* out, size_t out_size );
|
||||||
|
|
||||||
}
|
} // namespace xiv::utils::zlib
|
||||||
|
|
||||||
#endif // XIV_UTILS_ZLIB_H
|
|
||||||
|
|
8
deps/watchdog/Watchdog.h
vendored
8
deps/watchdog/Watchdog.h
vendored
|
@ -32,14 +32,10 @@
|
||||||
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
|
||||||
// fucking filesystem
|
|
||||||
#if _MSC_VER >= 1925
|
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
namespace ci { namespace fs = std::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
|
//! Exception for when Watchdog can't locate a file or parse the wildcard
|
||||||
class WatchedFileSystemExc : public std::exception {
|
class WatchedFileSystemExc : public std::exception {
|
||||||
|
|
|
@ -31,15 +31,8 @@
|
||||||
#include <Util/CrashHandler.h>
|
#include <Util/CrashHandler.h>
|
||||||
|
|
||||||
|
|
||||||
// fucking filesystem
|
|
||||||
#if _MSC_VER >= 1925
|
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
namespace fs = std::filesystem;
|
namespace fs = std::filesystem;
|
||||||
#else
|
|
||||||
#include <experimental/filesystem>
|
|
||||||
namespace fs = std::experimental::filesystem;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
Sapphire::Common::Util::CrashHandler crashHandler;
|
Sapphire::Common::Util::CrashHandler crashHandler;
|
||||||
|
|
||||||
|
|
|
@ -2,13 +2,8 @@
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
|
||||||
#if _MSC_VER >= 1925
|
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
namespace fs = std::filesystem;
|
namespace fs = std::filesystem;
|
||||||
#else
|
|
||||||
#include <experimental/filesystem>
|
|
||||||
namespace fs = std::experimental::filesystem;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
using namespace Sapphire;
|
using namespace Sapphire;
|
||||||
using namespace Sapphire::Common;
|
using namespace Sapphire::Common;
|
||||||
|
|
|
@ -7,30 +7,23 @@
|
||||||
#include <spdlog/sinks/stdout_color_sinks.h>
|
#include <spdlog/sinks/stdout_color_sinks.h>
|
||||||
#include <spdlog/sinks/daily_file_sink.h>
|
#include <spdlog/sinks/daily_file_sink.h>
|
||||||
|
|
||||||
// #include <iostream>
|
|
||||||
#if _MSC_VER >= 1925
|
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
namespace fs = std::filesystem;
|
namespace fs = std::filesystem;
|
||||||
#else
|
|
||||||
#include <experimental/filesystem>
|
|
||||||
namespace fs = std::experimental::filesystem;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
void Sapphire::Logger::init( const std::string& logPath )
|
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(log_directory);
|
||||||
fs::create_directories( realPath );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
spdlog::init_thread_pool( 8192, 1 );
|
spdlog::init_thread_pool( 8192, 1 );
|
||||||
|
|
||||||
auto stdout_sink = std::make_shared< spdlog::sinks::stdout_color_sink_mt >();
|
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 };
|
std::vector< spdlog::sink_ptr > sinks { stdout_sink, daily_sink };
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,10 @@
|
||||||
#include "Hive.h"
|
|
||||||
#include "Acceptor.h"
|
#include "Acceptor.h"
|
||||||
#include "Connection.h"
|
#include "Connection.h"
|
||||||
|
#include "Hive.h"
|
||||||
|
|
||||||
using namespace Sapphire;
|
using namespace Sapphire;
|
||||||
|
|
||||||
Network::Acceptor::Acceptor( HivePtr hive ) :
|
Network::Acceptor::Acceptor( HivePtr hive ) : m_hive( hive ),
|
||||||
m_hive( hive ),
|
|
||||||
m_acceptor( hive->getService() ),
|
m_acceptor( hive->getService() ),
|
||||||
m_io_strand( hive->getService() ),
|
m_io_strand( hive->getService() ),
|
||||||
m_error_state( 0 )
|
m_error_state( 0 )
|
||||||
|
@ -77,7 +75,10 @@ void Network::Acceptor::handleAccept( const asio::error_code& error, ConnectionP
|
||||||
|
|
||||||
void Network::Acceptor::stop()
|
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 )
|
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.set_option( asio::ip::tcp::acceptor::reuse_address( false ) );
|
||||||
m_acceptor.bind( endpoint );
|
m_acceptor.bind( endpoint );
|
||||||
m_acceptor.listen( asio::socket_base::max_connections );
|
m_acceptor.listen( asio::socket_base::max_connections );
|
||||||
}
|
} catch( const asio::system_error& ex )
|
||||||
catch( ... )
|
|
||||||
{
|
{
|
||||||
// this should not happen
|
// Call the onError function to handle the error
|
||||||
assert( true );
|
onError( ex.code() );
|
||||||
|
} catch( ... )
|
||||||
|
{
|
||||||
|
// Call the onError function with a generic error code
|
||||||
|
onError( asio::error::operation_aborted );
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Network::HivePtr Network::Acceptor::getHive()
|
Network::HivePtr Network::Acceptor::getHive()
|
||||||
|
@ -116,6 +119,11 @@ asio::ip::tcp::acceptor& Network::Acceptor::getAcceptor()
|
||||||
return m_acceptor;
|
return m_acceptor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
asio::strand& Network::Acceptor::getStrand()
|
||||||
|
{
|
||||||
|
return m_io_strand;
|
||||||
|
}
|
||||||
|
|
||||||
bool Network::Acceptor::hasError()
|
bool Network::Acceptor::hasError()
|
||||||
{
|
{
|
||||||
uint32_t v1 = 1;
|
uint32_t v1 = 1;
|
||||||
|
|
|
@ -148,9 +148,9 @@ namespace Sapphire::Network
|
||||||
acceptor->accept( connection );
|
acceptor->accept( connection );
|
||||||
return 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
|
#pragma once
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <thread>
|
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <queue>
|
#include <queue>
|
||||||
#include <algorithm>
|
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
namespace Sapphire::Common::Util
|
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 >
|
template< class T >
|
||||||
class LockedQueue
|
class LockedQueue
|
||||||
{
|
{
|
||||||
public:
|
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();
|
T pop();
|
||||||
|
|
||||||
//we can pass this in by reference, instead of copying
|
// Adds an object to the end of the queue, using a const reference.
|
||||||
void push( const T object );
|
// The object is copied into the queue in a thread-safe manner.
|
||||||
|
// Locks the mutex before accessing the queue and unlocks it after
|
||||||
//we can pass this in by reference
|
// the operation is complete.
|
||||||
//this will push it onto the queue, and swap the object
|
void push( const T& 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 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:
|
protected:
|
||||||
std::queue< T > m_queue;
|
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 >
|
template< class T >
|
||||||
LockedQueue< T >::LockedQueue()
|
std::size_t LockedQueue< T >::size() const
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
template< class T >
|
|
||||||
std::size_t LockedQueue< T >::size()
|
|
||||||
{
|
{
|
||||||
std::lock_guard< std::mutex > lock( m_mutex );
|
std::lock_guard< std::mutex > lock( m_mutex );
|
||||||
return m_queue.size();
|
return m_queue.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
template< class T >
|
|
||||||
LockedQueue< T >::~LockedQueue()
|
|
||||||
{
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
template< class T >
|
template< class T >
|
||||||
T LockedQueue< T >::pop()
|
T LockedQueue< T >::pop()
|
||||||
{
|
{
|
||||||
|
@ -72,58 +63,24 @@ namespace Sapphire::Common::Util
|
||||||
return T();
|
return T();
|
||||||
}
|
}
|
||||||
|
|
||||||
T result = m_queue.front();
|
T result = std::move( m_queue.front() );
|
||||||
|
|
||||||
m_queue.pop();
|
m_queue.pop();
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
template< class T >
|
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 );
|
std::lock_guard< std::mutex > lock( m_mutex );
|
||||||
m_queue.push( object );
|
m_queue.push( object );
|
||||||
}
|
}
|
||||||
|
|
||||||
template< class T >
|
template< class T >
|
||||||
void LockedQueue< T >::push_swap( T& object )
|
void LockedQueue< T >::push( T&& object )
|
||||||
{
|
{
|
||||||
std::lock_guard< std::mutex > lock( m_mutex );
|
std::lock_guard< std::mutex > lock( m_mutex );
|
||||||
|
m_queue.emplace( std::forward< T >( object ) );
|
||||||
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.
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template< class T >
|
}// namespace Sapphire::Common::Util
|
||||||
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.
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,16 +1,18 @@
|
||||||
#ifndef _LOCKED_WAIT_H
|
#pragma once
|
||||||
#define _LOCKED_WAIT_H
|
|
||||||
|
|
||||||
|
#include <atomic>
|
||||||
#include <condition_variable>
|
#include <condition_variable>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <queue>
|
#include <queue>
|
||||||
#include <atomic>
|
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
namespace Sapphire::Common::Util
|
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 >
|
template< typename T >
|
||||||
class LockedWaitQueue
|
class LockedWaitQueue
|
||||||
{
|
{
|
||||||
|
@ -21,20 +23,25 @@ namespace Sapphire::Common::Util
|
||||||
std::atomic< bool > m_shutdown;
|
std::atomic< bool > m_shutdown;
|
||||||
|
|
||||||
public:
|
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 );
|
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();
|
m_condition.notify_one();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Returns true if the queue is empty, false otherwise. The queue is locked
|
||||||
|
// during the check.
|
||||||
bool empty()
|
bool empty()
|
||||||
{
|
{
|
||||||
std::lock_guard< std::mutex > lock( m_queueLock );
|
std::lock_guard< std::mutex > lock( m_queueLock );
|
||||||
|
@ -42,6 +49,10 @@ namespace Sapphire::Common::Util
|
||||||
return m_queue.empty();
|
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 )
|
bool pop( T& value )
|
||||||
{
|
{
|
||||||
std::lock_guard< std::mutex > lock( m_queueLock );
|
std::lock_guard< std::mutex > lock( m_queueLock );
|
||||||
|
@ -49,13 +60,17 @@ namespace Sapphire::Common::Util
|
||||||
if( m_queue.empty() || m_shutdown )
|
if( m_queue.empty() || m_shutdown )
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
value = m_queue.front();
|
value = std::move( m_queue.front() );
|
||||||
|
|
||||||
m_queue.pop();
|
m_queue.pop();
|
||||||
|
|
||||||
return true;
|
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 )
|
void waitAndPop( T& value )
|
||||||
{
|
{
|
||||||
std::unique_lock< std::mutex > lock( m_queueLock );
|
std::unique_lock< std::mutex > lock( m_queueLock );
|
||||||
|
@ -66,11 +81,15 @@ namespace Sapphire::Common::Util
|
||||||
if( m_queue.empty() || m_shutdown )
|
if( m_queue.empty() || m_shutdown )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
value = m_queue.front();
|
value = std::move( m_queue.front() );
|
||||||
|
|
||||||
m_queue.pop();
|
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()
|
void cancel()
|
||||||
{
|
{
|
||||||
std::unique_lock< std::mutex > lock( m_queueLock );
|
std::unique_lock< std::mutex > lock( m_queueLock );
|
||||||
|
@ -90,6 +109,8 @@ namespace Sapphire::Common::Util
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
// Helper functions for deleting queued objects depending on whether T is
|
||||||
|
// a pointer type or not.
|
||||||
template< typename E = T >
|
template< typename E = T >
|
||||||
typename std::enable_if< std::is_pointer< E >::value >::type deleteQueuedObject( E& obj )
|
typename std::enable_if< std::is_pointer< E >::value >::type deleteQueuedObject( E& obj )
|
||||||
{
|
{
|
||||||
|
@ -101,7 +122,4 @@ namespace Sapphire::Common::Util
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}// namespace Sapphire::Common::Util
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
#ifndef SAPPHIRE_SPAWNINDEXALLOCATOR_H
|
#pragma once
|
||||||
#define SAPPHIRE_SPAWNINDEXALLOCATOR_H
|
|
||||||
|
|
||||||
#include <queue>
|
|
||||||
#include <unordered_map>
|
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
|
#include <unordered_set>
|
||||||
|
|
||||||
namespace Sapphire::Common::Util
|
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 >
|
template< typename T, typename ActorIdType = uint32_t >
|
||||||
class SpawnIndexAllocator
|
class SpawnIndexAllocator
|
||||||
{
|
{
|
||||||
|
@ -16,92 +16,109 @@ namespace Sapphire::Common::Util
|
||||||
std::is_same< T, uint32_t >::value || std::is_same< T, uint64_t >::value,
|
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" );
|
"T must be uint8_t, uint16_t, uint32_t, uint64_t" );
|
||||||
|
|
||||||
SpawnIndexAllocator() :
|
// Constructor for the SpawnIndexAllocator, initializing internal variables
|
||||||
m_maxSlotId( 0 ),
|
// such as maximum slot ID, reserve first slot flag, and allocation failure ID.
|
||||||
m_reserveFirstSlot( false )
|
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 )
|
void init( T maxSlotId, bool reserveFirstSlot = false )
|
||||||
{
|
{
|
||||||
m_maxSlotId = maxSlotId;
|
m_maxSlotId = maxSlotId;
|
||||||
m_reserveFirstSlot = reserveFirstSlot;
|
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 )
|
T freeUsedSpawnIndex( ActorIdType actorId )
|
||||||
{
|
{
|
||||||
auto it = m_actorIdToAllocatedMap.find( actorId );
|
auto it = m_usedIndexes.find( actorId );
|
||||||
if( it == m_actorIdToAllocatedMap.end() )
|
if( it == m_usedIndexes.end() )
|
||||||
return getAllocFailId();
|
return m_allocFailId;
|
||||||
|
|
||||||
auto index = it->second;
|
auto index = *it;
|
||||||
m_availableIds.push( index );
|
m_usedIndexes.erase( it );
|
||||||
m_actorIdToAllocatedMap.erase( it );
|
m_freeIndexes.insert( index );
|
||||||
|
|
||||||
return 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 )
|
T getNextFreeSpawnIndex( ActorIdType actorId )
|
||||||
{
|
{
|
||||||
assert( m_maxSlotId != 0 );
|
assert( m_maxSlotId != 0 );
|
||||||
|
|
||||||
if( m_availableIds.empty() )
|
if( m_freeIndexes.empty() )
|
||||||
return getAllocFailId();
|
return m_allocFailId;
|
||||||
|
|
||||||
auto nextId = m_availableIds.front();
|
auto nextId = *m_freeIndexes.begin();
|
||||||
m_availableIds.pop();
|
m_freeIndexes.erase( m_freeIndexes.begin() );
|
||||||
|
m_usedIndexes.insert( nextId );
|
||||||
m_actorIdToAllocatedMap[ actorId ] = nextId;
|
|
||||||
|
|
||||||
return nextId;
|
return nextId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Frees all used spawn indices and clears the used set. Resets the free
|
||||||
|
// set to contain all possible indices.
|
||||||
void freeAllSpawnIndexes()
|
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 )
|
bool isSpawnIndexValid( T spawnIndex )
|
||||||
{
|
{
|
||||||
return spawnIndex != getAllocFailId();
|
return spawnIndex != m_allocFailId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Returns the allocation failure ID.
|
||||||
constexpr T getAllocFailId() const
|
constexpr T getAllocFailId() const
|
||||||
{
|
{
|
||||||
return static_cast< T >( -1 );
|
return m_allocFailId;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
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 );
|
assert( m_maxSlotId != 0 );
|
||||||
|
|
||||||
while( !m_availableIds.empty() )
|
m_freeIndexes.clear();
|
||||||
m_availableIds.pop();
|
|
||||||
|
|
||||||
uint32_t start = 0;
|
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
|
// will be used by another actor and despawn the local player
|
||||||
if( m_reserveFirstSlot )
|
if( m_reserveFirstSlot )
|
||||||
start = 1;
|
start = 1;
|
||||||
|
|
||||||
for( uint32_t i = start; i < m_maxSlotId; i++ )
|
for( uint32_t i = start; i < m_maxSlotId; i++ )
|
||||||
m_availableIds.push( i );
|
m_freeIndexes.insert( i );
|
||||||
}
|
}
|
||||||
|
|
||||||
std::queue< T > m_availableIds;
|
std::unordered_set< T > m_freeIndexes;
|
||||||
std::unordered_map< ActorIdType, T > m_actorIdToAllocatedMap;
|
std::unordered_set< T > m_usedIndexes;
|
||||||
|
|
||||||
T m_maxSlotId;
|
T m_maxSlotId;
|
||||||
bool m_reserveFirstSlot;
|
bool m_reserveFirstSlot;
|
||||||
|
const T m_allocFailId;
|
||||||
};
|
};
|
||||||
}
|
}// namespace Sapphire::Common::Util
|
||||||
|
|
||||||
#endif //SAPPHIRE_SPAWNINDEXALLOCATOR_H
|
|
|
@ -122,15 +122,14 @@ std::string Util::binaryToHexDump( uint8_t* pBinData, uint16_t size )
|
||||||
|
|
||||||
uint64_t Util::getTimeMs()
|
uint64_t Util::getTimeMs()
|
||||||
{
|
{
|
||||||
std::chrono::milliseconds epoch = std::chrono::duration_cast< std::chrono::milliseconds >
|
const auto epoch = std::chrono::duration_cast< std::chrono::milliseconds >( std::chrono::steady_clock::now().time_since_epoch() );
|
||||||
( std::chrono::system_clock::now().time_since_epoch() );
|
|
||||||
return epoch.count();
|
return epoch.count();
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t Util::getTimeSeconds()
|
uint32_t Util::getTimeSeconds()
|
||||||
{
|
{
|
||||||
auto currClock = std::chrono::system_clock::now();
|
const auto currClock = std::chrono::steady_clock::now();
|
||||||
return static_cast< uint32_t >( std::chrono::time_point_cast< std::chrono::seconds >( currClock ).time_since_epoch().count() );
|
return static_cast< uint32_t >( std::chrono::duration_cast< std::chrono::seconds >( currClock.time_since_epoch() ).count() );
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t Util::getEorzeanTimeStamp()
|
uint64_t Util::getEorzeanTimeStamp()
|
||||||
|
@ -140,18 +139,17 @@ uint64_t Util::getEorzeanTimeStamp()
|
||||||
|
|
||||||
void Util::valueToFlagByteIndexValue( uint32_t inVal, uint8_t& outVal, uint16_t& outIndex )
|
void Util::valueToFlagByteIndexValue( uint32_t inVal, uint8_t& outVal, uint16_t& outIndex )
|
||||||
{
|
{
|
||||||
uint32_t id = inVal;
|
const uint32_t id = inVal;
|
||||||
outIndex = id / 8;
|
outIndex = id / 8;
|
||||||
uint8_t bitIndex = id % 8;
|
const uint8_t bitIndex = id % 8;
|
||||||
|
|
||||||
outVal = 1 << bitIndex;
|
outVal = 1 << bitIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
std::string Util::fmtUtcTime( const std::string& fmt )
|
std::string Util::fmtUtcTime( const std::string& fmt )
|
||||||
{
|
{
|
||||||
auto t = std::time( nullptr );
|
const auto t = std::time( nullptr );
|
||||||
auto tm = std::gmtime( &t );
|
const auto tm = std::gmtime( &t );
|
||||||
|
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
|
|
||||||
|
|
|
@ -8,33 +8,44 @@
|
||||||
|
|
||||||
namespace Sapphire::Common::Util
|
namespace Sapphire::Common::Util
|
||||||
{
|
{
|
||||||
|
// Retrieves the operation code from a raw network packet
|
||||||
uint16_t getOpCode( Network::Packets::FFXIVARR_PACKET_RAW& raw );
|
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 );
|
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 );
|
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 );
|
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 );
|
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 );
|
void eraseAllIn( std::string& inOutStr, std::string& remove );
|
||||||
|
|
||||||
|
// Returns a lowercase copy of the input string
|
||||||
std::string toLowerCopy( const std::string& inStr );
|
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 );
|
std::string fmtUtcTime( const std::string& fmt );
|
||||||
|
|
||||||
|
// Gets the current time in milliseconds
|
||||||
uint64_t getTimeMs();
|
uint64_t getTimeMs();
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
* Gets the current time in seconds
|
||||||
* @brief Get a POSIX epoch representation of the current time
|
* @brief Get a POSIX epoch representation of the current time
|
||||||
* @return 32-bit unsigned integer
|
* @return 32-bit unsigned integer
|
||||||
*/
|
*/
|
||||||
|
|
||||||
uint32_t getTimeSeconds();
|
uint32_t getTimeSeconds();
|
||||||
|
|
||||||
|
// Gets the current Eorzean timestamp (used in the game world)
|
||||||
uint64_t getEorzeanTimeStamp();
|
uint64_t getEorzeanTimeStamp();
|
||||||
|
|
||||||
|
// Converts a value to a flag byte index value pair
|
||||||
void valueToFlagByteIndexValue( uint32_t inVal, uint8_t& outVal, uint16_t& outIndex );
|
void valueToFlagByteIndexValue( uint32_t inVal, uint8_t& outVal, uint16_t& outIndex );
|
||||||
|
|
||||||
template< class T >
|
template< class T >
|
||||||
|
|
|
@ -7,28 +7,40 @@
|
||||||
|
|
||||||
namespace Sapphire::Common::Util
|
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 );
|
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 );
|
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 );
|
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 );
|
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 );
|
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 );
|
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 );
|
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 );
|
float trunc( float value, uint8_t digitsToRemain );
|
||||||
|
|
||||||
|
// Converts a float to a uint16_t
|
||||||
uint16_t floatToUInt16( float val );
|
uint16_t floatToUInt16( float val );
|
||||||
|
|
||||||
|
// Converts a float to a uint16_t representing a rotation angle
|
||||||
uint16_t floatToUInt16Rot( float val );
|
uint16_t floatToUInt16Rot( float val );
|
||||||
|
|
||||||
|
// Converts a float to a uint8_t representing a rotation angle
|
||||||
uint8_t floatToUInt8Rot( float val );
|
uint8_t floatToUInt8Rot( float val );
|
||||||
|
|
||||||
|
// Clamps a value between a minimum and maximum value
|
||||||
template < typename T >
|
template < typename T >
|
||||||
T clamp( T val, T minimum, T maximum )
|
T clamp( T val, T minimum, T maximum )
|
||||||
{
|
{
|
||||||
|
@ -41,8 +53,10 @@ namespace Sapphire::Common::Util
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Transforms a 3D position vector using a 3x3 matrix
|
||||||
FFXIVARR_POSITION3 transform( const FFXIVARR_POSITION3& vector, const Matrix33& 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 );
|
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
|
#pragma once
|
||||||
|
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
namespace Sapphire::Common
|
namespace Sapphire::Common
|
||||||
{
|
{
|
||||||
struct FFXIVARR_POSITION3
|
struct FFXIVARR_POSITION3
|
||||||
|
@ -7,7 +9,24 @@ namespace Sapphire::Common
|
||||||
float x;
|
float x;
|
||||||
float y;
|
float y;
|
||||||
float z;
|
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
|
struct Vector3
|
||||||
|
@ -16,11 +35,59 @@ namespace Sapphire::Common
|
||||||
float y;
|
float y;
|
||||||
float z;
|
float z;
|
||||||
float reserve;
|
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
|
struct Matrix33
|
||||||
{
|
{
|
||||||
float m[ 3 ][ 3 ];
|
float m[ 3 ][ 3 ];
|
||||||
};
|
};
|
||||||
}
|
}// namespace Sapphire::Common
|
|
@ -6,19 +6,13 @@
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <Logging/Logger.h>
|
#include <Logging/Logger.h>
|
||||||
|
|
||||||
#include <common/Util/Util.h>
|
#include <Util/Util.h>
|
||||||
|
|
||||||
using namespace Sapphire;
|
using namespace Sapphire;
|
||||||
using namespace Sapphire::Common;
|
using namespace Sapphire::Common;
|
||||||
|
|
||||||
// fucking filesystem
|
|
||||||
#if _MSC_VER >= 1925
|
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
namespace fs = std::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 ) :
|
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 <iostream>
|
||||||
#include <cctype>
|
#include <cctype>
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <common/Logging/Logger.h>
|
#include <Logging/Logger.h>
|
||||||
#include <MySqlConnector.h>
|
#include <MySqlConnector.h>
|
||||||
#include <common/Util/CrashHandler.h>
|
#include <Util/CrashHandler.h>
|
||||||
#include <common/Config/ConfigMgr.h>
|
#include <Config/ConfigMgr.h>
|
||||||
|
|
||||||
Sapphire::Common::Util::CrashHandler crashHandler;
|
Sapphire::Common::Util::CrashHandler crashHandler;
|
||||||
|
|
||||||
// fucking filesystem
|
|
||||||
#if _MSC_VER >= 1925
|
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
namespace filesys = std::filesystem;
|
namespace fs = std::filesystem;
|
||||||
#else
|
|
||||||
#include <experimental/filesystem>
|
|
||||||
namespace filesys = std::experimental::filesystem;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <streambuf>
|
#include <streambuf>
|
||||||
|
@ -36,19 +31,19 @@ std::vector< std::string > getAllFilesInDir( const std::string& dirPath,
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// Check if given path exists and points to a directory
|
// 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
|
// 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.
|
// Create a Recursive Directory Iterator object pointing to end.
|
||||||
filesys::recursive_directory_iterator end;
|
fs::recursive_directory_iterator end;
|
||||||
|
|
||||||
// Iterate till end
|
// Iterate till end
|
||||||
while( iter != end )
|
while( iter != end )
|
||||||
{
|
{
|
||||||
// Check if current entry is a directory and if exists in skip list
|
// 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() ) )
|
( std::find( dirSkipList.begin(), dirSkipList.end(), iter->path().filename() ) != dirSkipList.end() ) )
|
||||||
{
|
{
|
||||||
// Skip the iteration of current directory pointed by iterator
|
// Skip the iteration of current directory pointed by iterator
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
#include <Common.h>
|
#include <Common.h>
|
||||||
#include <Vector3.cpp>
|
#include <Vector3.h>
|
||||||
#include <Network/CommonNetwork.h>
|
#include <Network/CommonNetwork.h>
|
||||||
#include <Network/GamePacket.h>
|
#include <Network/GamePacket.h>
|
||||||
#include <Network/CommonActorControl.h>
|
#include <Network/CommonActorControl.h>
|
||||||
|
|
|
@ -56,7 +56,8 @@ bool Sapphire::Scripting::ScriptMgr::init()
|
||||||
std::set< std::string > files;
|
std::set< std::string > files;
|
||||||
auto& server = Common::Service< World::WorldServer >::ref();
|
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 )
|
if( !status )
|
||||||
{
|
{
|
||||||
|
@ -67,13 +68,13 @@ bool Sapphire::Scripting::ScriptMgr::init()
|
||||||
uint32_t scriptsFound = 0;
|
uint32_t scriptsFound = 0;
|
||||||
uint32_t scriptsLoaded = 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++;
|
scriptsFound++;
|
||||||
|
|
||||||
if( m_nativeScriptMgr->loadScript( path ) )
|
if( m_nativeScriptMgr->loadScript( file_path.string() ) )
|
||||||
scriptsLoaded++;
|
scriptsLoaded++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -180,15 +180,29 @@ void WorldServer::run( int32_t argc, char* argv[] )
|
||||||
auto verString = readFileToString( verPath );
|
auto verString = readFileToString( verPath );
|
||||||
if( verString != m_config.global.general.dataVersion )
|
if( verString != m_config.global.general.dataVersion )
|
||||||
{
|
{
|
||||||
Logger::fatal( "Sqpack version {} does not match expected version {}!", verString, m_config.global.general.dataVersion );
|
Logger::warn( "Sqpack version {} does not match expected version {}!", verString, m_config.global.general.dataVersion );
|
||||||
return;
|
|
||||||
}
|
std::string response;
|
||||||
}
|
do
|
||||||
catch ( const std::exception& e )
|
{
|
||||||
|
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" )
|
||||||
{
|
{
|
||||||
Logger::fatal( e.what() );
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch( const std::exception& e )
|
||||||
|
{
|
||||||
|
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 ) )
|
if( !pExdData->init( dataPath ) )
|
||||||
{
|
{
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <set>
|
#include <set>
|
||||||
|
#include <thread>
|
||||||
#include "ForwardsZone.h"
|
#include "ForwardsZone.h"
|
||||||
#include <Config/ConfigDef.h>
|
#include <Config/ConfigDef.h>
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue