1
Fork 0
mirror of https://github.com/SapphireServer/Sapphire.git synced 2025-04-27 14:57:44 +00:00

Merge remote-tracking branch 'SapphireServer/develop' into develop

This commit is contained in:
Jeido 2020-11-26 19:14:12 +01:00
commit a9e6c85a5e
371 changed files with 32780 additions and 21115 deletions

View file

@ -1,5 +1,5 @@
os: os:
- Visual Studio 2017 - Visual Studio 2019
configuration: configuration:
- Debug - Debug
@ -20,8 +20,8 @@ before_build:
- git submodule update --init - git submodule update --init
- mkdir build - mkdir build
- cd build - cd build
- cmake .. -G "Visual Studio 15 2017 Win64" - cmake .. -G "Visual Studio 16 2019" -A x64
- cmake --build . --target ALL_BUILD --config Release - cmake --build . --target ALL_BUILD --config RelWithDebInfo
build_script: build_script:
- cd bin - cd bin

3
.gitmodules vendored
View file

@ -7,3 +7,6 @@
[submodule "deps/recastnavigation"] [submodule "deps/recastnavigation"]
path = deps/recastnavigation path = deps/recastnavigation
url = https://github.com/SapphireServer/recastnavigation url = https://github.com/SapphireServer/recastnavigation
[submodule "deps/ffxiv-actions"]
path = deps/ffxiv-actions
url = https://github.com/SapphireServer/ffxiv-actions.git

View file

@ -14,9 +14,10 @@ matrix:
sources: sources:
- ubuntu-toolchain-r-test - ubuntu-toolchain-r-test
packages: packages:
- g++-7 - g++-8
env: env:
- MATRIX_EVAL="CC=gcc-7 && CXX=g++-7" - MATRIX_EVAL="CC=gcc-8 && CXX=g++-8"
- CXX=g++-8
# Setup cache # Setup cache
cache: cache:

View file

@ -13,7 +13,9 @@ add_custom_target( copy_runtime_files ALL
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/config ${CMAKE_BINARY_DIR}/bin/config COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/config ${CMAKE_BINARY_DIR}/bin/config
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/sql ${CMAKE_BINARY_DIR}/bin/sql COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/sql ${CMAKE_BINARY_DIR}/bin/sql
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/web ${CMAKE_BINARY_DIR}/bin/web COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/web ${CMAKE_BINARY_DIR}/bin/web
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_SOURCE_DIR}/sql_import.sh ${CMAKE_BINARY_DIR}/bin/sql_import.sh ) COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_SOURCE_DIR}/sql_import.sh ${CMAKE_BINARY_DIR}/bin/sql_import.sh
COMMAND ${CMAKE_COMMAND} -E remove_directory ${CMAKE_BINARY_DIR}/bin/data/actions
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/deps/ffxiv-actions/actions ${CMAKE_BINARY_DIR}/bin/data/actions )
###################################### ######################################
# Dependencies and compiler settings # # Dependencies and compiler settings #
@ -44,7 +46,6 @@ add_subdirectory( "deps/MySQL" )
add_subdirectory( "deps/datReader" ) add_subdirectory( "deps/datReader" )
add_subdirectory( "deps/mysqlConnector" ) add_subdirectory( "deps/mysqlConnector" )
add_subdirectory( "deps/recastnavigation" ) add_subdirectory( "deps/recastnavigation" )
add_subdirectory( "deps/stackwalker" )
############################## ##############################
# Main Sapphire Components # # Main Sapphire Components #

View file

@ -1,21 +1,32 @@
{ {
// See https://go.microsoft.com//fwlink//?linkid=834763 for more information about this file. // See https://go.microsoft.com//fwlink//?linkid=834763 for more information about this file.
"environments": [
{
"BuildDir": "${env.USERPROFILE}\\CMakeBuilds\\${workspaceHash}\\build"
}
],
"configurations": [ "configurations": [
{ {
"name": "x64-Debug", "name": "x64-Debug",
"generator": "Visual Studio 15 2017 Win64", "generator": "Visual Studio 16 2019 Win64",
"configurationType": "Debug", "configurationType": "Debug",
"buildRoot": "${env.USERPROFILE}\\CMakeBuild\\${workspaceHash}\\build\\${name}", "buildRoot": "${env.BuildDir}\\${name}",
"cmakeCommandArgs": "-DCMAKE_BUILD_TYPE=\"Debug\"", "cmakeCommandArgs": "-DCMAKE_BUILD_TYPE=\"Debug\"",
"buildCommandArgs": "-m -v:minimal" "buildCommandArgs": "-m -v:minimal",
"inheritEnvironments": [
"msvc_x64"
]
}, },
{ {
"name": "x64-Release", "name": "x64-Release",
"generator": "Visual Studio 15 2017 Win64", "generator": "Visual Studio 16 2019 Win64",
"configurationType": "Release", "configurationType": "Release",
"buildRoot": "${env.USERPROFILE}\\CMakeBuild\\${workspaceHash}\\build\\${name}", "buildRoot": "${env.BuildDir}\\${name}",
"cmakeCommandArgs": "", "cmakeCommandArgs": "-DCMAKE_BUILD_TYPE=\"RelWithDebInfo\"",
"buildCommandArgs": "-m -v:minimal" "buildCommandArgs": "-m -v:minimal",
"inheritEnvironments": [
"msvc_x64"
]
} }
] ]
} }

View file

@ -18,7 +18,7 @@ Sapphire requires the following software:
| *Name* | *Windows* | *Linux* | | *Name* | *Windows* | *Linux* |
| ------ | --------- | ------- | | ------ | --------- | ------- |
| CMake 3.0.2+ and C++17 capable compiler | [Visual Studio 2017](https://www.visualstudio.com/) | `gcc 7` and `g++ 7` or newer | | CMake 3.0.2+ and C++17 capable compiler | [Visual Studio 2019](https://www.visualstudio.com/) | `gcc 8` and `g++ 8` or newer, or equivalent `clang` version. |
| MySQL Server 5.7 | [Official Site](https://dev.mysql.com/downloads/mysql/) | MySQL server from your distribution's package manager | | MySQL Server 5.7 | [Official Site](https://dev.mysql.com/downloads/mysql/) | MySQL server from your distribution's package manager |
Please check the [wiki](https://github.com/SapphireMordred/Sapphire/wiki) for detailed installation/build instructions for your OS. Please check the [wiki](https://github.com/SapphireMordred/Sapphire/wiki) for detailed installation/build instructions for your OS.

View file

@ -60,6 +60,7 @@ if( UNIX )
else( MYSQL_CONFIG ) else( MYSQL_CONFIG )
set(MYSQL_ADD_LIBRARIES "") set(MYSQL_ADD_LIBRARIES "")
list(APPEND MYSQL_ADD_LIBRARIES "mysqlclient_r") list(APPEND MYSQL_ADD_LIBRARIES "mysqlclient_r")
list(APPEND MYSQL_ADD_LIBRARIES "mariadbclient")
endif( MYSQL_CONFIG ) endif( MYSQL_CONFIG )
endif( UNIX ) endif( UNIX )
@ -76,6 +77,7 @@ find_path(MYSQL_INCLUDE_DIR
PATHS PATHS
${MYSQL_ADD_INCLUDE_PATH} ${MYSQL_ADD_INCLUDE_PATH}
/usr/include /usr/include
/usr/include/mariadb
/usr/include/mysql /usr/include/mysql
/usr/local/include /usr/local/include
/usr/local/include/mysql /usr/local/include/mysql
@ -83,6 +85,8 @@ find_path(MYSQL_INCLUDE_DIR
"${PROGRAM_FILES_64}/MySQL/MySQL Server 5.7/include" "${PROGRAM_FILES_64}/MySQL/MySQL Server 5.7/include"
"${PROGRAM_FILES_64}/MySQL/include" "${PROGRAM_FILES_64}/MySQL/include"
"${PROGRAM_FILES_64}/MariaDB 10.3/include/mysql" "${PROGRAM_FILES_64}/MariaDB 10.3/include/mysql"
"${PROGRAM_FILES_64}/MariaDB 10.4/include/mysql"
"${PROGRAM_FILES_64}/MariaDB 10.5/include/mysql"
"C:/MySQL/include" "C:/MySQL/include"
"[HKEY_LOCAL_MACHINE\\SOFTWARE\\MySQL AB\\MySQL Server 5.7;Location]/include" "[HKEY_LOCAL_MACHINE\\SOFTWARE\\MySQL AB\\MySQL Server 5.7;Location]/include"
"$ENV{ProgramFiles}/MySQL/MySQL Server 5.7/include" "$ENV{ProgramFiles}/MySQL/MySQL Server 5.7/include"
@ -97,7 +101,7 @@ if( UNIX )
foreach(LIB ${MYSQL_ADD_LIBRARIES}) foreach(LIB ${MYSQL_ADD_LIBRARIES})
find_library( MYSQL_LIBRARY find_library( MYSQL_LIBRARY
NAMES NAMES
mysql libmysql ${LIB} mysql libmysql libmariadb ${LIB}
PATHS PATHS
${MYSQL_ADD_LIBRARIES_PATH} ${MYSQL_ADD_LIBRARIES_PATH}
/usr/lib /usr/lib
@ -105,6 +109,7 @@ if( UNIX )
/usr/local/lib /usr/local/lib
/usr/local/lib/mysql /usr/local/lib/mysql
/usr/local/mysql/lib /usr/local/mysql/lib
/usr/lib/x86_64-linux-gnu
DOC "Specify the location of the mysql library here." DOC "Specify the location of the mysql library here."
) )
endforeach(LIB ${MYSQL_ADD_LIBRARY}) endforeach(LIB ${MYSQL_ADD_LIBRARY})
@ -121,6 +126,8 @@ if( WIN32 )
"${PROGRAM_FILES_64}/MySQL/MySQL Server 5.7/lib/opt" "${PROGRAM_FILES_64}/MySQL/MySQL Server 5.7/lib/opt"
"${PROGRAM_FILES_64}/MySQL/lib" "${PROGRAM_FILES_64}/MySQL/lib"
"${PROGRAM_FILES_64}/MariaDB 10.3/lib" "${PROGRAM_FILES_64}/MariaDB 10.3/lib"
"${PROGRAM_FILES_64}/MariaDB 10.4/lib"
"${PROGRAM_FILES_64}/MariaDB 10.5/lib"
"C:/MySQL/lib/debug" "C:/MySQL/lib/debug"
"[HKEY_LOCAL_MACHINE\\SOFTWARE\\MySQL AB\\MySQL Server 5.7;Location]/lib" "[HKEY_LOCAL_MACHINE\\SOFTWARE\\MySQL AB\\MySQL Server 5.7;Location]/lib"
"[HKEY_LOCAL_MACHINE\\SOFTWARE\\MySQL AB\\MySQL Server 5.7;Location]/lib/opt" "[HKEY_LOCAL_MACHINE\\SOFTWARE\\MySQL AB\\MySQL Server 5.7;Location]/lib/opt"
@ -174,6 +181,8 @@ if( WIN32 )
"${PROGRAM_FILES_64}/MySQL/MySQL Server 5.7/bin/opt" "${PROGRAM_FILES_64}/MySQL/MySQL Server 5.7/bin/opt"
"${PROGRAM_FILES_64}/MySQL/bin" "${PROGRAM_FILES_64}/MySQL/bin"
"${PROGRAM_FILES_64}/MariaDB 10.3/bin" "${PROGRAM_FILES_64}/MariaDB 10.3/bin"
"${PROGRAM_FILES_64}/MariaDB 10.4/bin"
"${PROGRAM_FILES_64}/MariaDB 10.5/bin"
"C:/MySQL/bin/debug" "C:/MySQL/bin/debug"
"[HKEY_LOCAL_MACHINE\\SOFTWARE\\MySQL AB\\MySQL Server 5.7;Location]/bin" "[HKEY_LOCAL_MACHINE\\SOFTWARE\\MySQL AB\\MySQL Server 5.7;Location]/bin"
"[HKEY_LOCAL_MACHINE\\SOFTWARE\\MySQL AB\\MySQL Server 5.7;Location]/bin/opt" "[HKEY_LOCAL_MACHINE\\SOFTWARE\\MySQL AB\\MySQL Server 5.7;Location]/bin/opt"

View file

@ -13,3 +13,4 @@ endif()
# Create log folder # Create log folder
file( MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/bin/log ) file( MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/bin/log )
file( MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/bin/navi ) file( MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/bin/navi )
file( MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/bin/data )

509
deps/datReader/Dat.cpp vendored
View file

@ -4,308 +4,319 @@
#include "File.h" #include "File.h"
namespace namespace {
{ const uint32_t model_section_count = 0xB;
const uint32_t model_section_count = 0xB;
} }
namespace xiv namespace xiv::dat
{ {
namespace dat struct DatFileHeader
{ {
struct DatFileHeader uint32_t size;
{ FileType entry_type;
uint32_t size; uint32_t total_uncompressed_size;
FileType entry_type; uint32_t unknown[0x2];
uint32_t total_uncompressed_size; };
uint32_t unknown[0x2];
};
struct DatBlockRecord struct DatBlockRecord
{ {
uint32_t offset; uint32_t offset;
uint32_t size; uint32_t size;
uint32_t unknown[0x4]; uint32_t unknown[0x4];
SqPackBlockHash block_hash; SqPackBlockHash block_hash;
}; };
struct DatBlockHeader struct DatBlockHeader
{ {
uint32_t size; uint32_t size;
uint32_t unknown1; uint32_t unknown1;
uint32_t compressed_size; uint32_t compressed_size;
uint32_t uncompressed_size; uint32_t uncompressed_size;
}; };
struct DatStdFileBlockInfos struct DatStdFileBlockInfos
{ {
uint32_t offset; uint32_t offset;
uint16_t size; uint16_t size;
uint16_t uncompressed_size; uint16_t uncompressed_size;
}; };
struct DatMdlFileBlockInfos struct DatMdlFileBlockInfos
{ {
uint32_t unknown1; uint32_t unknown1;
uint32_t uncompressed_sizes[::model_section_count]; uint32_t uncompressed_sizes[::model_section_count];
uint32_t compressed_sizes[::model_section_count]; uint32_t compressed_sizes[::model_section_count];
uint32_t offsets[::model_section_count]; uint32_t offsets[::model_section_count];
uint16_t block_ids[::model_section_count]; uint16_t block_ids[::model_section_count];
uint16_t block_counts[::model_section_count]; uint16_t block_counts[::model_section_count];
uint32_t unknown2[0x2]; uint32_t unknown2[0x2];
}; };
struct DatTexFileBlockInfos struct DatTexFileBlockInfos
{ {
uint32_t offset; uint32_t offset;
uint32_t size; uint32_t size;
uint32_t uncompressed_size; uint32_t uncompressed_size;
uint32_t block_id; uint32_t block_id;
uint32_t block_count; uint32_t block_count;
}; };
} }
}
namespace xiv namespace xiv::utils::bparse
{ {
namespace utils template<>
{ inline void reorder< xiv::dat::DatFileHeader >( xiv::dat::DatFileHeader& i_struct )
namespace bparse {
{ xiv::utils::bparse::reorder( i_struct.size );
template <> xiv::utils::bparse::reorder( i_struct.entry_type );
inline void reorder<xiv::dat::DatFileHeader>(xiv::dat::DatFileHeader& i_struct) xiv::utils::bparse::reorder( i_struct.total_uncompressed_size );
{ for( int32_t i = 0; i < 0x2; ++i )
xiv::utils::bparse::reorder(i_struct.size); {
xiv::utils::bparse::reorder(i_struct.entry_type); xiv::utils::bparse::reorder( i_struct.unknown[ i ] );
xiv::utils::bparse::reorder(i_struct.total_uncompressed_size); }
for (int32_t i = 0; i < 0x2; ++i) { xiv::utils::bparse::reorder(i_struct.unknown[i]); } }
}
template <> template<>
inline void reorder<xiv::dat::DatBlockRecord>(xiv::dat::DatBlockRecord& i_struct) inline void reorder< xiv::dat::DatBlockRecord >( xiv::dat::DatBlockRecord& i_struct )
{ {
xiv::utils::bparse::reorder(i_struct.offset); xiv::utils::bparse::reorder( i_struct.offset );
xiv::utils::bparse::reorder(i_struct.size); xiv::utils::bparse::reorder( i_struct.size );
for (int32_t i = 0; i < 0x4; ++i) { xiv::utils::bparse::reorder(i_struct.unknown[i]); } for( int32_t i = 0; i < 0x4; ++i )
xiv::utils::bparse::reorder(i_struct.block_hash); {
} xiv::utils::bparse::reorder( i_struct.unknown[ i ] );
}
xiv::utils::bparse::reorder( i_struct.block_hash );
}
template <> template<>
inline void reorder<xiv::dat::DatBlockHeader>(xiv::dat::DatBlockHeader& i_struct) inline void reorder< xiv::dat::DatBlockHeader >( xiv::dat::DatBlockHeader& i_struct )
{ {
xiv::utils::bparse::reorder(i_struct.size); xiv::utils::bparse::reorder( i_struct.size );
xiv::utils::bparse::reorder(i_struct.unknown1); xiv::utils::bparse::reorder( i_struct.unknown1 );
xiv::utils::bparse::reorder(i_struct.compressed_size); xiv::utils::bparse::reorder( i_struct.compressed_size );
xiv::utils::bparse::reorder(i_struct.uncompressed_size); xiv::utils::bparse::reorder( i_struct.uncompressed_size );
} }
template <> template<>
inline void reorder<xiv::dat::DatStdFileBlockInfos>(xiv::dat::DatStdFileBlockInfos& i_struct) inline void reorder< xiv::dat::DatStdFileBlockInfos >( xiv::dat::DatStdFileBlockInfos& i_struct )
{ {
xiv::utils::bparse::reorder(i_struct.offset); xiv::utils::bparse::reorder( i_struct.offset );
xiv::utils::bparse::reorder(i_struct.size); xiv::utils::bparse::reorder( i_struct.size );
xiv::utils::bparse::reorder(i_struct.uncompressed_size); xiv::utils::bparse::reorder( i_struct.uncompressed_size );
} }
template <> template<>
inline void reorder<xiv::dat::DatMdlFileBlockInfos>(xiv::dat::DatMdlFileBlockInfos& i_struct) inline void reorder< xiv::dat::DatMdlFileBlockInfos >( xiv::dat::DatMdlFileBlockInfos& i_struct )
{ {
xiv::utils::bparse::reorder(i_struct.unknown1); xiv::utils::bparse::reorder( i_struct.unknown1 );
for (auto i = 0; i < ::model_section_count; ++i) { xiv::utils::bparse::reorder(i_struct.uncompressed_sizes[i]); } for( auto i = 0; i < ::model_section_count; ++i )
for (auto i = 0; i < ::model_section_count; ++i) { xiv::utils::bparse::reorder(i_struct.compressed_sizes[i]); } {
for (auto i = 0; i < ::model_section_count; ++i) { xiv::utils::bparse::reorder(i_struct.offsets[i]); } xiv::utils::bparse::reorder( i_struct.uncompressed_sizes[ i ] );
for (auto i = 0; i < ::model_section_count; ++i) { xiv::utils::bparse::reorder(i_struct.block_ids[i]); } }
for (auto i = 0; i < ::model_section_count; ++i) { xiv::utils::bparse::reorder(i_struct.block_counts[i]); } for( auto i = 0; i < ::model_section_count; ++i )
for (auto i = 0; i < 0x2; ++i) { xiv::utils::bparse::reorder(i_struct.unknown2[i]); } {
} xiv::utils::bparse::reorder( i_struct.compressed_sizes[ i ] );
}
for( auto i = 0; i < ::model_section_count; ++i )
{
xiv::utils::bparse::reorder( i_struct.offsets[ i ] );
}
for( auto i = 0; i < ::model_section_count; ++i )
{
xiv::utils::bparse::reorder( i_struct.block_ids[ i ] );
}
for( auto i = 0; i < ::model_section_count; ++i )
{
xiv::utils::bparse::reorder( i_struct.block_counts[ i ] );
}
for( auto i = 0; i < 0x2; ++i )
{
xiv::utils::bparse::reorder( i_struct.unknown2[ i ] );
}
}
template <> template<>
inline void reorder<xiv::dat::DatTexFileBlockInfos>(xiv::dat::DatTexFileBlockInfos& i_struct) inline void reorder< xiv::dat::DatTexFileBlockInfos >( xiv::dat::DatTexFileBlockInfos& i_struct )
{ {
xiv::utils::bparse::reorder(i_struct.offset); xiv::utils::bparse::reorder( i_struct.offset );
xiv::utils::bparse::reorder(i_struct.size); xiv::utils::bparse::reorder( i_struct.size );
xiv::utils::bparse::reorder(i_struct.uncompressed_size); xiv::utils::bparse::reorder( i_struct.uncompressed_size );
xiv::utils::bparse::reorder(i_struct.block_id); xiv::utils::bparse::reorder( i_struct.block_id );
xiv::utils::bparse::reorder(i_struct.block_count); xiv::utils::bparse::reorder( i_struct.block_count );
} }
} }
}
};
using xiv::utils::bparse::extract; using xiv::utils::bparse::extract;
namespace xiv namespace xiv::dat
{
namespace dat
{ {
Dat::Dat( const std::experimental::filesystem::path& i_path, uint32_t i_nb ) : Dat::Dat( const std::filesystem::path& i_path, uint32_t i_nb ) :
SqPack( i_path ), SqPack( i_path ),
m_num( i_nb ) m_num( i_nb )
{ {
auto block_record = extract<DatBlockRecord>(m_handle); auto block_record = extract< DatBlockRecord >( m_handle );
block_record.offset *= 0x80; block_record.offset *= 0x80;
isBlockValid(block_record.offset, block_record.size, block_record.block_hash); isBlockValid( block_record.offset, block_record.size, block_record.block_hash );
} }
Dat::~Dat() Dat::~Dat()
{ {
} }
std::unique_ptr<File> Dat::getFile( uint32_t i_offset ) std::unique_ptr< File > Dat::getFile( uint32_t i_offset )
{ {
std::unique_ptr<File> outputFile(new File()); std::unique_ptr< File > outputFile( new File() );
{ {
// Lock in this scope // Lock in this scope
std::lock_guard<std::mutex> lock(m_fileMutex); std::lock_guard< std::mutex > lock( m_fileMutex );
// Seek to the start of the header of the file record and extract it // Seek to the start of the header of the file record and extract it
m_handle.seekg(i_offset); m_handle.seekg( i_offset );
auto file_header = extract<DatFileHeader>(m_handle); auto file_header = extract< DatFileHeader >( m_handle );
switch (file_header.entry_type) switch( file_header.entry_type )
{ {
case FileType::empty: case FileType::empty:
throw std::runtime_error("File is empty"); throw std::runtime_error( "File is empty" );
case FileType::standard: case FileType::standard:
{ {
outputFile->_type = FileType::standard; outputFile->_type = FileType::standard;
uint32_t number_of_blocks = extract<uint32_t>(m_handle, "number_of_blocks"); uint32_t number_of_blocks = extract< uint32_t >( m_handle, "number_of_blocks" );
// Just extract offset infos for the blocks to extract // Just extract offset infos for the blocks to extract
std::vector<DatStdFileBlockInfos> std_file_block_infos; std::vector< DatStdFileBlockInfos > std_file_block_infos;
extract<DatStdFileBlockInfos>( m_handle, number_of_blocks, std_file_block_infos ); extract< DatStdFileBlockInfos >( m_handle, number_of_blocks, std_file_block_infos );
// Pre allocate data vector for the whole file // Pre allocate data vector for the whole file
outputFile->_data_sections.resize(1); outputFile->_data_sections.resize( 1 );
auto& data_section = outputFile->_data_sections.front(); auto& data_section = outputFile->_data_sections.front();
data_section.reserve(file_header.total_uncompressed_size); data_section.reserve( file_header.total_uncompressed_size );
// Extract each block // Extract each block
for (auto& file_block_info : std_file_block_infos) for( auto& file_block_info : std_file_block_infos )
{
extractBlock( i_offset + file_header.size + file_block_info.offset, data_section );
}
}
break;
case FileType::model:
{
outputFile->_type = FileType::model;
DatMdlFileBlockInfos mdlBlockInfo = extract< DatMdlFileBlockInfos >( m_handle );
// Getting the block number and read their sizes
const uint32_t block_count = mdlBlockInfo.block_ids[ ::model_section_count - 1 ] +
mdlBlockInfo.block_counts[ ::model_section_count - 1 ];
std::vector< uint16_t > block_sizes;
extract< uint16_t >( m_handle, "block_size", block_count, block_sizes );
// Preallocate sufficient space
outputFile->_data_sections.resize( ::model_section_count );
for( uint32_t i = 0; i < ::model_section_count; ++i )
{
// Preallocating for section
auto& data_section = outputFile->_data_sections[ i ];
data_section.reserve( mdlBlockInfo.uncompressed_sizes[ i ] );
uint32_t current_offset = i_offset + file_header.size + mdlBlockInfo.offsets[ i ];
for( uint32_t j = 0; j < mdlBlockInfo.block_counts[ i ]; ++j )
{ {
extractBlock(i_offset + file_header.size + file_block_info.offset, data_section); extractBlock( current_offset, data_section );
current_offset += block_sizes[ mdlBlockInfo.block_ids[ i ] + j ];
} }
} }
break; }
break;
case FileType::model: case FileType::texture:
{ {
outputFile->_type = FileType::model; outputFile->_type = FileType::texture;
DatMdlFileBlockInfos mdlBlockInfo = extract<DatMdlFileBlockInfos>(m_handle); // Extracts mipmap entries and the block sizes
uint32_t sectionCount = extract< uint32_t >( m_handle, "sections_count" );
// Getting the block number and read their sizes std::vector< DatTexFileBlockInfos > texBlockInfo;
const uint32_t block_count = mdlBlockInfo.block_ids[::model_section_count - 1] + extract< DatTexFileBlockInfos >( m_handle, sectionCount, texBlockInfo );
mdlBlockInfo.block_counts[::model_section_count - 1];
std::vector<uint16_t> block_sizes;
extract<uint16_t>(m_handle, "block_size", block_count, block_sizes);
// Preallocate sufficient space // Extracting block sizes
outputFile->_data_sections.resize(::model_section_count); uint32_t block_count = texBlockInfo.back().block_id + texBlockInfo.back().block_count;
std::vector< uint16_t > block_sizes;
extract< uint16_t >( m_handle, "block_size", block_count, block_sizes );
for (uint32_t i = 0; i < ::model_section_count; ++i) outputFile->_data_sections.resize( sectionCount + 1 );
// Extracting header in section 0
const uint32_t header_size = texBlockInfo.front().offset;
auto& header_section = outputFile->_data_sections[ 0 ];
header_section.resize( header_size );
m_handle.seekg( i_offset + file_header.size );
m_handle.read( header_section.data(), header_size );
// Extracting other sections
for( uint32_t i = 0; i < sectionCount; ++i )
{
auto& data_section = outputFile->_data_sections[ i + 1 ];
auto& section_infos = texBlockInfo[ i ];
data_section.reserve( section_infos.uncompressed_size );
uint32_t current_offset = i_offset + file_header.size + section_infos.offset;
for( uint32_t j = 0; j < section_infos.block_count; ++j )
{ {
// Preallocating for section extractBlock( current_offset, data_section );
auto& data_section = outputFile->_data_sections[i]; current_offset += block_sizes[ section_infos.block_id + j ];
data_section.reserve(mdlBlockInfo.uncompressed_sizes[i]);
uint32_t current_offset = i_offset + file_header.size + mdlBlockInfo.offsets[i];
for (uint32_t j = 0; j < mdlBlockInfo.block_counts[i]; ++j)
{
extractBlock(current_offset, data_section);
current_offset += block_sizes[mdlBlockInfo.block_ids[i] + j];
}
} }
} }
break; }
break;
case FileType::texture: default:
{ throw std::runtime_error(
outputFile->_type = FileType::texture; "Invalid entry_type: " + std::to_string( static_cast<uint32_t>(file_header.entry_type) ) );
// Extracts mipmap entries and the block sizes
uint32_t sectionCount = extract<uint32_t>(m_handle, "sections_count");
std::vector<DatTexFileBlockInfos> texBlockInfo;
extract<DatTexFileBlockInfos>(m_handle, sectionCount, texBlockInfo);
// Extracting block sizes
uint32_t block_count = texBlockInfo.back().block_id + texBlockInfo.back().block_count;
std::vector<uint16_t> block_sizes;
extract<uint16_t>(m_handle, "block_size", block_count, block_sizes);
outputFile->_data_sections.resize(sectionCount + 1);
// Extracting header in section 0
const uint32_t header_size = texBlockInfo.front().offset;
auto& header_section = outputFile->_data_sections[0];
header_section.resize(header_size);
m_handle.seekg(i_offset + file_header.size);
m_handle.read(header_section.data(), header_size);
// Extracting other sections
for (uint32_t i = 0; i < sectionCount; ++i)
{
auto& data_section = outputFile->_data_sections[i + 1];
auto& section_infos = texBlockInfo[i];
data_section.reserve(section_infos.uncompressed_size);
uint32_t current_offset = i_offset + file_header.size + section_infos.offset;
for (uint32_t j = 0; j < section_infos.block_count; ++j)
{
extractBlock(current_offset, data_section);
current_offset += block_sizes[section_infos.block_id + j];
}
}
}
break;
default:
throw std::runtime_error("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 );
DatBlockHeader block_header = extract<DatBlockHeader>(m_handle); DatBlockHeader block_header = extract< DatBlockHeader >( m_handle );
// Resizing the vector to write directly into it // Resizing the vector to write directly into it
const uint32_t data_size = o_data.size(); const uint32_t data_size = o_data.size();
o_data.resize(data_size + block_header.uncompressed_size); o_data.resize( 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 );
} }
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); std::vector< char > temp_buffer( block_header.compressed_size );
m_handle.read(temp_buffer.data(), block_header.compressed_size); m_handle.read( temp_buffer.data(), block_header.compressed_size );
utils::zlib::no_header_decompress(reinterpret_cast<uint8_t*>(temp_buffer.data()), utils::zlib::no_header_decompress( reinterpret_cast<uint8_t*>(temp_buffer.data()),
temp_buffer.size(), temp_buffer.size(),
reinterpret_cast<uint8_t*>(o_data.data() + data_size), reinterpret_cast<uint8_t*>(o_data.data() + data_size),
block_header.uncompressed_size); block_header.uncompressed_size );
} }
} }
uint32_t Dat::getNum() const uint32_t Dat::getNum() const
{ {
return m_num; return m_num;
} }
} }
}

47
deps/datReader/Dat.h vendored
View file

@ -5,41 +5,38 @@
#include <mutex> #include <mutex>
#include <experimental/filesystem> #include <filesystem>
namespace xiv namespace xiv::dat
{
namespace dat
{ {
class File; class File;
class Dat : public SqPack class Dat : public SqPack
{ {
public: public:
// Full path to the dat file // Full path to the dat file
Dat( const std::experimental::filesystem::path& i_path, uint32_t i_nb ); Dat( const std::filesystem::path& i_path, uint32_t i_nb );
virtual ~Dat(); virtual ~Dat();
// Retrieves a file given the offset in the dat file // Retrieves a file given the offset in the dat file
std::unique_ptr<File> getFile( uint32_t i_offset ); std::unique_ptr<File> getFile( uint32_t i_offset );
// Appends to the vector the data of this block, it is assumed to be preallocated // Appends to the vector the data of this block, it is assumed to be preallocated
// Is it also assumed that the m_fileMutex is currently locked by this thread before the call // Is it also assumed that the m_fileMutex is currently locked by this thread before the call
void extractBlock( uint32_t i_offset, std::vector<char>& o_data ); void extractBlock( uint32_t i_offset, std::vector<char>& o_data );
// Returns the dat number // Returns the dat number
uint32_t getNum() const; uint32_t getNum() const;
protected: protected:
// File reading mutex to have only one thread reading the file at a time // File reading mutex to have only one thread reading the file at a time
std::mutex m_fileMutex; std::mutex m_fileMutex;
// Dat nb // Dat nb
uint32_t m_num; uint32_t m_num;
}; };
}
} }
#endif // XIV_DAT_DAT_H #endif // XIV_DAT_DAT_H

View file

@ -10,7 +10,7 @@ namespace xiv
namespace dat namespace dat
{ {
Cat::Cat( const std::experimental::filesystem::path& basePath, uint32_t catNum, const std::string& name ) : Cat::Cat( const std::filesystem::path& basePath, uint32_t catNum, const std::string& name ) :
m_name( name ), m_name( name ),
m_catNum( catNum ), m_catNum( catNum ),
m_chunk( -1 ) m_chunk( -1 )
@ -21,27 +21,27 @@ Cat::Cat( const std::experimental::filesystem::path& basePath, uint32_t catNum,
std::string prefix = ss.str() + "0000.win32"; std::string prefix = ss.str() + "0000.win32";
// Creates the index: XX0000.win32.index // Creates the index: XX0000.win32.index
m_index = std::unique_ptr<Index>( new Index( basePath / "//ffxiv" / ( prefix + ".index" ) ) ); m_index = std::unique_ptr<Index>( new Index( basePath / "ffxiv" / ( prefix + ".index" ) ) );
// For all dat files linked to this index, create it: XX0000.win32.datX // For all dat files linked to this index, create it: XX0000.win32.datX
for( uint32_t i = 0; i < getIndex().getDatCount(); ++i ) for( uint32_t i = 0; i < getIndex().getDatCount(); ++i )
{ {
m_dats.emplace_back( std::unique_ptr<Dat>( new Dat( basePath / "//ffxiv" / ( prefix + ".dat" + std::to_string( i ) ), i ) ) ); m_dats.emplace_back( std::make_unique< Dat >(basePath / "ffxiv" / ( prefix + ".dat" + std::to_string( i ) ), i ) );
} }
} }
Cat::Cat( const std::experimental::filesystem::path& basePath, uint32_t catNum, const std::string& name, uint32_t exNum, uint32_t chunk ) : Cat::Cat( const std::filesystem::path& basePath, uint32_t catNum, const std::string& name, uint32_t exNum, uint32_t chunk ) :
m_name( name ), m_name( name ),
m_catNum( catNum ), m_catNum( catNum ),
m_chunk( chunk ) m_chunk( chunk )
{ {
// Creates the index: XX0000.win32.index // Creates the index: XX0000.win32.index
m_index = std::unique_ptr<Index>( new 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" ) );
// For all dat files linked to this index, create it: XX0000.win32.datX // For all dat files linked to this index, create it: XX0000.win32.datX
for( uint32_t i = 0; i < getIndex().getDatCount(); ++i ) for( uint32_t i = 0; i < getIndex().getDatCount(); ++i )
{ {
m_dats.emplace_back( std::unique_ptr<Dat>( new 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 ) );
} }
} }

View file

@ -3,62 +3,66 @@
#include <memory> #include <memory>
#include <vector> #include <vector>
#include <experimental/filesystem> #include <filesystem>
namespace xiv { namespace xiv::dat
namespace dat {
class Index;
class Dat;
class File;
// A category represents an .index and its associated .datX
class Cat
{ {
public:
// basePath: Path to the folder containingthe datfiles
// catNum: The number of the category
// name: The name of the category, empty if not known
Cat( const std::experimental::filesystem::path& basePath, uint32_t catNum, const std::string& name );
// basePath: Path to the folder containingthe datfiles class Index;
// catNum: The number of the category
// name: The name of the category, empty if not known
// exNum: The number of the expansion to load from
// chunk: The chunk to load from
Cat( const std::experimental::filesystem::path& basePath, uint32_t catNum, const std::string& name, uint32_t exNum, uint32_t chunk );
~Cat();
// Returns .index of the category class Dat;
const Index& getIndex() const;
// Retrieve a file from the category given its hashes class File;
std::unique_ptr<File> getFile( uint32_t dir_hash, uint32_t filename_hash ) const;
// A category represents an .index and its associated .datX
class Cat
{
public:
// basePath: Path to the folder containingthe datfiles
// catNum: The number of the category
// name: The name of the category, empty if not known
Cat( const std::filesystem::path& basePath, uint32_t catNum, const std::string& name );
// basePath: Path to the folder containingthe datfiles
// catNum: The number of the category
// name: The name of the category, empty if not known
// exNum: The number of the expansion to load from
// chunk: The chunk to load from
Cat( const std::filesystem::path& basePath, uint32_t catNum, const std::string& name, uint32_t exNum,
uint32_t chunk );
~Cat();
// Returns .index of the category
const Index& getIndex() const;
// Retrieve a file from the category given its hashes
std::unique_ptr< File > getFile( uint32_t dir_hash, uint32_t filename_hash ) const;
bool doesFileExist( uint32_t dir_hash, uint32_t filename_hash ) const; bool doesFileExist( uint32_t dir_hash, uint32_t filename_hash ) const;
bool doesDirExist( uint32_t dir_hash ) const;
bool doesDirExist( uint32_t dir_hash ) const;
// Returns thename of the category // Returns thename of the category
const std::string& getName() const; const std::string& getName() const;
// Returns the number of the category // Returns the number of the category
uint32_t getCatNum() const; uint32_t getCatNum() const;
protected: protected:
const std::string m_name; const std::string m_name;
const uint32_t m_catNum; const uint32_t m_catNum;
const uint32_t m_chunk; const uint32_t m_chunk;
// The .index // The .index
std::unique_ptr<Index> m_index; std::unique_ptr< Index > m_index;
// The .datXs such as dat nb X => m_dats[X] // The .datXs such as dat nb X => m_dats[X]
std::vector<std::unique_ptr<Dat>> m_dats; std::vector< std::unique_ptr< Dat>> m_dats;
}; };
}
} }
#endif // XIV_DAT_CAT_H #endif // XIV_DAT_CAT_H

View file

@ -0,0 +1,198 @@
#ifndef SAPPHIRE_LGBTYPES_H
#define SAPPHIRE_LGBTYPES_H
#include "vec3.h"
enum class LgbEntryType : uint32_t
{
BgParts = 1,
Attribute = 2,
Light = 3,
Vfx = 4,
PositionMarker = 5,
Gimmick = 6,
SharedGroup6 = 6,// secondary variable is set to 2
Sound = 7,
EventNpc = 8,
BattleNpc = 9,
RoutePath = 10,
Character = 11,
Aetheryte = 12,
EnvSpace = 13,
Gathering = 14,
SharedGroup15 = 15,// secondary variable is set to 13
Treasure = 16,
Player = 37,
Monster = 38,
Weapon = 39,
PopRange = 40,
ExitRange = 41,
LVB = 42,
MapRange = 43,
NaviMeshRange = 44,
EventObject = 45,
DemiHuman = 46,
EnvLocation = 47,
ControlPoint = 48,
EventRange = 49,
RestBonusRange = 50,
QuestMarker = 51,
TimeLine = 52,
ObjectBehaviorSet = 53,
Movie = 54,
ScenarioEXD = 55,
ScenarioText = 56,
CollisionBox = 57,
DoorRange = 58,
LineVfx = 59,
SoundEnvSet = 60,
CutActionTimeline = 61,
CharaScene = 62,
CutAction = 63,
EquipPreset = 64,
ClientPath = 65,
ServerPath = 66,
GimmickRange = 67,
TargetMarker = 68,
ChairMarker = 69,
ClickableRange = 70,
PrefetchRange = 71,
FateRange = 72,
PartyMember = 73,
KeepRange = 74,
SphereCastRange = 75,
IndoorObject = 76,
OutdoorObject = 77,
EditGroup = 78,
StableChocobo = 79
};
enum PopType : uint32_t
{
PopTypePC = 0x1,
PopTypeNPC = 0x2,
PopTypeBNPC = 0x2,
PopTypeContent = 0x3,
};
struct Transformation
{
vec3 translation;
vec3 rotation;
vec3 scale;
};
struct InstanceObject
{
LgbEntryType type;
uint32_t instanceId;
uint32_t nameOffset;
Transformation transform;
};
struct BgPartsData : public InstanceObject
{
uint32_t modelFileOffset;
uint32_t collisionFileOffset;
uint32_t unknown4;
uint32_t unknown5;
uint32_t unknown6;
uint32_t unknown7;
uint32_t unknown8;
uint32_t unknown9;
};
struct RelativePositions
{
int32_t Pos;
int32_t PosCount;
};
struct PopRangeData : public InstanceObject
{
PopType popType;
RelativePositions relativePositions;
float innerRadiusRatio;
uint8_t index;
uint8_t padding00[3];
uint32_t reserved;
};
struct GimmickData : public InstanceObject
{
uint32_t gimmickFileOffset;
char unknownBytes[100];
};
struct ENpcData : public InstanceObject
{
uint32_t enpcId;
uint8_t unknown1[0x24];
};
struct EObjData : public InstanceObject
{
uint32_t eobjId;
uint32_t levelHierachyId;
uint8_t unknown1[0xC];
};
enum TriggerBoxShape : uint32_t
{
TriggerBoxShapeBox = 0x1,
TriggerBoxShapeSphere = 0x2,
TriggerBoxShapeCylinder = 0x3,
TriggerBoxShapeBoard = 0x4,
TriggerBoxShapeMesh = 0x5,
TriggerBoxShapeBoardBothSides = 0x6,
};
struct TriggerBoxInstanceObject
{
TriggerBoxShape triggerBoxShape;
int16_t priority;
int8_t enabled;
uint8_t padding;
uint32_t reserved;
};
struct ExitRangeData : public InstanceObject
{
TriggerBoxInstanceObject triggerBoxType;
uint32_t exitType;
uint16_t zoneId;
uint16_t destTerritoryType;
int index;
uint32_t destInstanceObjectId;
uint32_t returnInstanceObjectId;
float direction;
uint32_t reserved;
};
struct MapRangeData : public InstanceObject
{
TriggerBoxInstanceObject triggerBoxType;
uint32_t mapId;
uint32_t placeNameBlock;
uint32_t placeNameSpot;
uint32_t bGM;
uint32_t weather;
uint32_t reserved;
uint32_t reserved2;
uint16_t reserved3;
uint8_t housingBlockId;
int8_t restBonusEffective;
uint8_t discoveryIndex;
int8_t mapEnabled;
int8_t placeNameEnabled;
int8_t discoveryEnabled;
int8_t bGMEnabled;
int8_t weatherEnabled;
int8_t restBonusEnabled;
int8_t bGMPlayZoneInOnly;
int8_t liftEnabled;
int8_t housingEnabled;
uint16_t padding;
};
#endif //SAPPHIRE_LGBTYPES_H

View file

@ -12,87 +12,33 @@
#include "matrix4.h" #include "matrix4.h"
#include "vec3.h" #include "vec3.h"
#include "sgb.h" #include "sgb.h"
#include "LgbTypes.h"
// garbage to skip model loading // based on https://github.com/ufx/SaintCoinach/blob/master/SaintCoinach/Graphics/Lgb/
extern bool ignoreModels;
// all credit to
// https://github.com/ufx/SaintCoinach/blob/master/SaintCoinach/Graphics/Lgb/
// this is simply their work ported to c++ since we dont c#
struct LGB_FILE; struct LGB_FILE;
struct LGB_FILE_HEADER; struct LGB_FILE_HEADER;
struct LGB_GROUP; struct LGB_GROUP;
struct LGB_GROUP_HEADER; struct LGB_GROUP_HEADER;
enum class LgbEntryType : class LgbEntry
uint32_t
{
BgParts = 1,
Light = 3,
Vfx = 4,
PositionMarker = 5,
Gimmick = 6,
SharedGroup6 = 6,// secondary variable is set to 2
Sound = 7,
EventNpc = 8,
BattleNpc = 9,
Aetheryte = 12,
EnvSpace = 13,
Gathering = 14,
SharedGroup15 = 15,// secondary variable is set to 13
Treasure = 16,
Weapon = 39,
PopRange = 40,
ExitRange = 41,
MapRange = 43,
NaviMeshRange = 44,
EventObject = 45,
EnvLocation = 47,
EventRange = 49,
QuestMarker = 51,
CollisionBox = 57,
DoorRange = 58,
LineVfx = 59,
ClientPath = 65,
ServerPath = 66,
GimmickRange = 67,
TargetMarker = 68,
ChairMarker = 69,
ClickableRange = 70,
PrefetchRange = 71,
FateRange = 72,
SphereCastRange = 75,
};
struct LGB_ENTRY_HEADER
{
LgbEntryType type;
uint32_t unknown;
uint32_t nameOffset;
vec3 translation;
vec3 rotation;
vec3 scale;
};
class LGB_ENTRY
{ {
public: public:
char* m_buf; char* m_buf;
uint32_t m_offset; uint32_t m_offset;
LGB_ENTRY_HEADER header; InstanceObject header;
LGB_ENTRY() LgbEntry()
{ {
m_buf = nullptr; m_buf = nullptr;
m_offset = 0; m_offset = 0;
memset( &header, 0, sizeof( header ) ); memset( &header, 0, sizeof( header ) );
}; };
LGB_ENTRY( char* buf, uint32_t offset ) LgbEntry( char* buf, uint32_t offset )
{ {
m_buf = buf; m_buf = buf;
m_offset = offset; m_offset = offset;
header = *reinterpret_cast< LGB_ENTRY_HEADER* >( buf + offset ); header = *reinterpret_cast< InstanceObject* >( buf + offset );
}; };
const LgbEntryType getType() const const LgbEntryType getType() const
@ -100,30 +46,16 @@ public:
return header.type; return header.type;
}; };
virtual ~LGB_ENTRY() virtual ~LgbEntry()
{ {
}; };
}; };
struct LGB_BGPARTS_HEADER : class LGB_BGPARTS_ENTRY : public LgbEntry
public LGB_ENTRY_HEADER
{
uint32_t modelFileOffset;
uint32_t collisionFileOffset;
uint32_t unknown4;
uint32_t unknown5;
uint32_t unknown6;
uint32_t unknown7;
uint32_t unknown8;
uint32_t unknown9;
};
class LGB_BGPARTS_ENTRY :
public LGB_ENTRY
{ {
public: public:
LGB_BGPARTS_HEADER header; BgPartsData data;
std::string name; std::string name;
std::string modelFileName; std::string modelFileName;
std::string collisionFileName; std::string collisionFileName;
@ -132,124 +64,94 @@ public:
{ {
}; };
LGB_BGPARTS_ENTRY( char* buf, uint32_t offset ) : LGB_BGPARTS_ENTRY( char* buf, uint32_t offset ) : LgbEntry( buf, offset )
LGB_ENTRY( buf, offset )
{ {
header = *reinterpret_cast<LGB_BGPARTS_HEADER*>( buf + offset ); data = *reinterpret_cast< BgPartsData* >( buf + offset );
name = std::string( buf + offset + header.nameOffset ); name = std::string( buf + offset + header.nameOffset );
modelFileName = std::string( buf + offset + header.modelFileOffset ); modelFileName = std::string( buf + offset + data.modelFileOffset );
collisionFileName = std::string( buf + offset + header.collisionFileOffset ); collisionFileName = std::string( buf + offset + data.collisionFileOffset );
}; };
}; };
struct LGB_GIMMICK_HEADER : class LGB_GIMMICK_ENTRY : public LgbEntry
public LGB_ENTRY_HEADER
{
uint32_t gimmickFileOffset;
char unknownBytes[100];
};
class LGB_GIMMICK_ENTRY :
public LGB_ENTRY
{ {
public: public:
LGB_GIMMICK_HEADER header; GimmickData data;
std::string name; std::string name;
std::string gimmickFileName; std::string gimmickFileName;
LGB_GIMMICK_ENTRY( char* buf, uint32_t offset ) : LGB_GIMMICK_ENTRY( char* buf, uint32_t offset ) : LgbEntry( buf, offset )
LGB_ENTRY( buf, offset )
{ {
header = *reinterpret_cast<LGB_GIMMICK_HEADER*>( buf + offset ); data = *reinterpret_cast< GimmickData* >( buf + offset );
name = std::string( buf + offset + header.nameOffset ); name = std::string( buf + offset + header.nameOffset );
gimmickFileName = std::string( buf + offset + header.gimmickFileOffset ); gimmickFileName = std::string( buf + offset + data.gimmickFileOffset );
//std::cout << "\t " << gimmickFileName << " unknown: " << header.unknown << "\n";
}; };
}; };
struct LGB_ENPC_HEADER : class LGB_ENPC_ENTRY : public LgbEntry
public LGB_ENTRY_HEADER
{
uint32_t enpcId;
uint8_t unknown1[0x24];
};
class LGB_ENPC_ENTRY :
public LGB_ENTRY
{ {
public: public:
LGB_ENPC_HEADER header; ENpcData data;
std::string name; std::string name;
LGB_ENPC_ENTRY( char* buf, uint32_t offset ) : LGB_ENPC_ENTRY( char* buf, uint32_t offset ) :
LGB_ENTRY( buf, offset ) LgbEntry( buf, offset )
{ {
header = *reinterpret_cast< LGB_ENPC_HEADER* >( buf + offset ); data = *reinterpret_cast< ENpcData* >( buf + offset );
name = std::string( buf + offset + header.nameOffset );
//std::cout << "\t ENpc " << header.enpcId << " " << name << "\n";
};
};
struct LGB_EOBJ_HEADER :
public LGB_ENTRY_HEADER
{
uint32_t eobjId;
uint32_t levelHierachyId;
uint8_t unknown1[0xC];
};
class LGB_EOBJ_ENTRY :
public LGB_ENTRY
{
public:
LGB_EOBJ_HEADER header;
std::string name;
LGB_EOBJ_ENTRY( char* buf, uint32_t offset ) :
LGB_ENTRY( buf, offset )
{
header = *reinterpret_cast< LGB_EOBJ_HEADER* >( buf + offset );
//std::cout << "\t " << header.eobjId << " " << name << " unknown: " << header.unknown << "\n";
name = std::string( buf + offset + header.nameOffset ); name = std::string( buf + offset + header.nameOffset );
}; };
}; };
struct LGB_MAPRANGE_HEADER : class LGB_EOBJ_ENTRY : public LgbEntry
public LGB_ENTRY_HEADER
{
uint32_t type;
uint8_t unknown2;
uint8_t unknown2_1;
uint16_t unknown3;
uint32_t unknown5;
uint32_t mapId;
uint32_t offsetX;
uint32_t offsetY;
uint32_t unkInts[4];
uint16_t unkShort;
uint8_t unkFlag;
uint8_t unkFlag2;
uint8_t discoveryIndex;
uint8_t unkFlag3;
uint8_t unkFlag4;
uint8_t unknown4[0x09];
};
struct LGB_MAPRANGE_ENTRY :
public LGB_ENTRY
{ {
public: public:
LGB_MAPRANGE_HEADER header; EObjData data;
std::string name; std::string name;
LGB_MAPRANGE_ENTRY( char* buf, uint32_t offset ) : LGB_EOBJ_ENTRY( char* buf, uint32_t offset ) : LgbEntry( buf, offset )
LGB_ENTRY( buf, offset )
{ {
header = *reinterpret_cast< LGB_MAPRANGE_HEADER* >( buf + offset ); data = *reinterpret_cast< EObjData* >( buf + offset );
name = std::string( buf + offset + header.nameOffset ); name = std::string( buf + offset + header.nameOffset );
}; };
}; };
struct LGB_MAP_RANGE_ENTRY : public LgbEntry
{
public:
MapRangeData data;
std::string name;
LGB_MAP_RANGE_ENTRY( char* buf, uint32_t offset ) : LgbEntry( buf, offset )
{
data = *reinterpret_cast< MapRangeData* >( buf + offset );
name = std::string( buf + offset + header.nameOffset );
};
};
struct LGB_EXIT_RANGE_ENTRY : public LgbEntry
{
public:
ExitRangeData data;
std::string name;
LGB_EXIT_RANGE_ENTRY( char* buf, uint32_t offset ) : LgbEntry( buf, offset )
{
data = *reinterpret_cast< ExitRangeData* >( buf + offset );
name = std::string( buf + offset + header.nameOffset );
};
};
struct LGB_POP_RANGE_ENTRY : public LgbEntry
{
public:
PopRangeData data;
LGB_POP_RANGE_ENTRY( char* buf, uint32_t offset ) : LgbEntry( buf, offset )
{
data = *reinterpret_cast< PopRangeData* >( buf + offset );
};
};
struct LGB_GROUP_HEADER struct LGB_GROUP_HEADER
{ {
uint32_t id; uint32_t id;
@ -272,15 +174,13 @@ struct LGB_GROUP
LGB_FILE* parent; LGB_FILE* parent;
LGB_GROUP_HEADER header; LGB_GROUP_HEADER header;
std::string name; std::string name;
std::vector< std::shared_ptr< LGB_ENTRY > > entries; std::vector< std::shared_ptr< LgbEntry > > entries;
LGB_GROUP( char* buf, LGB_FILE* parentStruct, uint32_t offset ) LGB_GROUP( char* buf, LGB_FILE* parentStruct, uint32_t offset )
{ {
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( buf + offset + header.groupNameOffset );
//entries.resize( header.entryCount );
//std::cout << name << "\n\t unknown: " << header.unknown << "\n";
const auto entriesOffset = offset + header.entriesOffset; const auto entriesOffset = offset + header.entriesOffset;
for( auto i = 0; i < header.entryCount; ++i ) for( auto i = 0; i < header.entryCount; ++i )
{ {
@ -288,8 +188,7 @@ struct LGB_GROUP
try try
{ {
const auto type = *reinterpret_cast<LgbEntryType*>( buf + entryOffset ); const auto type = *reinterpret_cast< LgbEntryType* >( buf + entryOffset );
// garbage to skip model loading
if( type == LgbEntryType::BgParts ) if( type == LgbEntryType::BgParts )
{ {
entries.push_back( std::make_shared< LGB_BGPARTS_ENTRY >( buf, entryOffset ) ); entries.push_back( std::make_shared< LGB_BGPARTS_ENTRY >( buf, entryOffset ) );
@ -306,16 +205,18 @@ struct LGB_GROUP
{ {
entries.push_back( std::make_shared< LGB_EOBJ_ENTRY >( buf, entryOffset ) ); entries.push_back( std::make_shared< LGB_EOBJ_ENTRY >( buf, entryOffset ) );
} }
else if( type == LgbEntryType::ExitRange )
{
entries.push_back( std::make_shared< LGB_EXIT_RANGE_ENTRY >( buf, entryOffset ) );
}
else if( type == LgbEntryType::MapRange ) else if( type == LgbEntryType::MapRange )
{ {
entries.push_back( std::make_shared< LGB_MAPRANGE_ENTRY >( buf, entryOffset ) ); entries.push_back( std::make_shared< LGB_MAP_RANGE_ENTRY >( buf, entryOffset ) );
} }
else else
{ {
entries.push_back( std::make_shared< LGB_ENTRY >( buf, entryOffset ) ); entries.push_back( std::make_shared< LgbEntry >( buf, entryOffset ) );
} }
} }
catch( std::exception& e ) catch( std::exception& e )
{ {
@ -344,8 +245,7 @@ struct LGB_FILE
std::vector< LGB_GROUP > groups; std::vector< LGB_GROUP > groups;
std::string m_name; std::string m_name;
LGB_FILE( char* buf, const std::string& name ) : LGB_FILE( char* buf, const std::string& name ) : LGB_FILE( buf )
LGB_FILE( buf )
{ {
m_name = name; m_name = name;
} }
@ -356,8 +256,6 @@ struct LGB_FILE
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!" );
//groups.resize(header.groupCount);
constexpr auto baseOffset = sizeof( header ); constexpr auto baseOffset = sizeof( header );
for( auto i = 0; i < header.groupCount; ++i ) for( auto i = 0; i < header.groupCount; ++i )
{ {

View file

@ -22,15 +22,13 @@ struct SGB_GROUP;
struct SGB_GROUP_HEADER; struct SGB_GROUP_HEADER;
enum SgbDataType : enum SgbDataType : uint32_t
uint32_t
{ {
Unknown0008 = 0x0008, Unknown0008 = 0x0008,
Group = 0x0100, Group = 0x0100,
}; };
enum SgbGroupEntryType : enum SgbGroupEntryType : uint32_t
uint32_t
{ {
Model = 0x01, Model = 0x01,
Gimmick = 0x06, Gimmick = 0x06,
@ -124,15 +122,13 @@ struct SGB_ENTRY_HEADER
vec3 scale; vec3 scale;
}; };
struct SGB_MODEL_HEADER : struct SGB_MODEL_HEADER : public SGB_ENTRY_HEADER
public SGB_ENTRY_HEADER
{ {
int32_t modelFileOffset; int32_t modelFileOffset;
int32_t collisionFileOffset; int32_t collisionFileOffset;
}; };
struct SGB_MODEL_ENTRY : struct SGB_MODEL_ENTRY : public SGB_GROUP_ENTRY
public SGB_GROUP_ENTRY
{ {
SGB_MODEL_HEADER header; SGB_MODEL_HEADER header;
SgbGroupEntryType type; SgbGroupEntryType type;

737
deps/datReader/Exd.cpp vendored
View file

@ -8,373 +8,378 @@
using xiv::utils::bparse::extract; using xiv::utils::bparse::extract;
namespace xiv namespace xiv::exd
{ {
namespace exd struct ExdHeader
{ {
char magic[0x4];
uint16_t unknown;
uint16_t unknown2;
uint32_t index_size;
};
struct ExdRecordIndex
{
uint32_t id;
uint32_t offset;
};
}
namespace xiv::utils::bparse {
template<>
inline void reorder< xiv::exd::ExdHeader >( xiv::exd::ExdHeader& i_struct )
{
for( int32_t i = 0; i < 0x4; ++i )
{
xiv::utils::bparse::reorder( i_struct.magic[ i ] );
}
i_struct.unknown = xiv::utils::bparse::byteswap( i_struct.unknown );
xiv::utils::bparse::reorder( i_struct.unknown );
i_struct.unknown2 = xiv::utils::bparse::byteswap( i_struct.unknown2 );
xiv::utils::bparse::reorder( i_struct.unknown2 );
i_struct.index_size = xiv::utils::bparse::byteswap( i_struct.index_size );
xiv::utils::bparse::reorder( i_struct.index_size );
}
template<>
inline void reorder< xiv::exd::ExdRecordIndex >( xiv::exd::ExdRecordIndex& i_struct )
{
i_struct.id = xiv::utils::bparse::byteswap( i_struct.id );
xiv::utils::bparse::reorder( i_struct.id );
i_struct.offset = xiv::utils::bparse::byteswap( i_struct.offset );
xiv::utils::bparse::reorder( i_struct.offset );
}
};
namespace xiv::exd
{
Exd::Exd( std::shared_ptr< Exh > i_exh, const std::vector< std::shared_ptr< dat::File>>& i_files )
{
_exh = i_exh;
_files = i_files;
// Iterates over all the files
const uint32_t member_count = _exh->get_members().size();
for( auto& file_ptr : _files )
{
// Get a stream
std::vector< char > dataCpy = file_ptr->get_data_sections().front();
std::istringstream iss( std::string( dataCpy.begin(), dataCpy.end() ) );
// Extract the header and skip to the record indices
auto exd_header = extract< ExdHeader >( iss );
iss.seekg( 0x20 );
// Preallocate and extract the record_indices
const uint32_t record_count = exd_header.index_size / sizeof( ExdRecordIndex );
std::vector< ExdRecordIndex > record_indices;
record_indices.reserve( record_count );
for( uint32_t i = 0; i < record_count; ++i )
{
auto recordIndex = extract< ExdRecordIndex >( iss );
_idCache[ recordIndex.id ] = ExdCacheEntry{ file_ptr, recordIndex.offset };
}
}
}
Exd::~Exd()
{
}
const std::vector< Field > Exd::get_row( uint32_t id, uint32_t subRow )
{
auto cacheEntryIt = _idCache.find( id );
if( cacheEntryIt == _idCache.end() )
throw std::runtime_error( "Id not found: " + std::to_string( id ) );
// Iterates over all the files
const uint32_t member_count = _exh->get_members().size();
auto& file_ptr = cacheEntryIt->second.file;
std::vector< char > dataCpy = file_ptr->get_data_sections().front();
std::istringstream iss( std::string( dataCpy.begin(), dataCpy.end() ) );
// Get the vector fields for the given record and preallocate it
auto fields = _data[ id ];
fields.reserve( member_count );
iss.seekg( cacheEntryIt->second.offset + 6 );
uint8_t subRows = *reinterpret_cast< uint8_t* >( &dataCpy[ cacheEntryIt->second.offset + 5 ] );
if( subRow >= subRows )
throw std::runtime_error( "Out of bounds sub-row!" );
int offset = cacheEntryIt->second.offset + 6 + ( subRow * _exh->get_header().data_offset + 2 * ( subRow + 1 ) );
for( auto& member_entry : _exh->get_exh_members() )
{
// Seek to the position of the member to extract.
// 6 is because we have uint32_t/uint16_t at the start of each record
iss.seekg( offset + member_entry.offset );
// Switch depending on the type to extract
switch( member_entry.type )
{
case DataType::string:
// Extract the offset to the actual string
// Seek to it then extract the actual string
{
throw std::runtime_error( "String not implemented for variant 2!" );
//auto string_offset = extract<uint32_t>( iss, "string_offset", false );
//iss.seekg( cacheEntryIt->second.offset + 6 + _exh->get_header().data_offset + string_offset );
//fields.emplace_back( utils::bparse::extract_cstring( iss, "string" ) );
}
break;
case DataType::boolean:
fields.emplace_back( extract< bool >( iss, "bool" ) );
break;
case DataType::int8:
fields.emplace_back( extract< int8_t >( iss, "int8_t" ) );
break;
case DataType::uint8:
fields.emplace_back( extract< uint8_t >( iss, "uint8_t" ) );
break;
case DataType::int16:
fields.emplace_back( extract< int16_t >( iss, "int16_t", false ) );
break;
case DataType::uint16:
fields.emplace_back( extract< uint16_t >( iss, "uint16_t", false ) );
break;
case DataType::int32:
fields.emplace_back( extract< int32_t >( iss, "int32_t", false ) );
break;
case DataType::uint32:
fields.emplace_back( extract< uint32_t >( iss, "uint32_t", false ) );
break;
case DataType::float32:
fields.emplace_back( extract< float >( iss, "float", false ) );
break;
case DataType::uint64:
fields.emplace_back( extract< uint64_t >( iss, "uint64_t", false ) );
break;
default:
auto type = static_cast< uint16_t >( member_entry.type );
if( type < 0x19 || type > 0x20 )
throw std::runtime_error( "Unknown DataType: " + std::to_string( type ) );
uint64_t val = extract< uint64_t >( iss, "bool" );
int32_t shift = type - 0x19;
int32_t i = 1 << shift;
val &= i;
fields.emplace_back( ( val & i ) == i );
break;
}
}
return fields;
}
const std::vector< Field > Exd::get_row( uint32_t id )
{
auto cacheEntryIt = _idCache.find( id );
if( cacheEntryIt == _idCache.end() )
throw std::runtime_error( "Id not found: " + std::to_string( id ) );
// Iterates over all the files
const uint32_t member_count = _exh->get_members().size();
auto& file_ptr = cacheEntryIt->second.file;
std::vector< char > dataCpy = file_ptr->get_data_sections().front();
std::istringstream iss( std::string( dataCpy.begin(), dataCpy.end() ) );
// Get the vector fields for the given record and preallocate it
auto fields = _data[ id ];
fields.reserve( member_count );
iss.seekg( cacheEntryIt->second.offset + 6 );
uint8_t subRows = *reinterpret_cast< uint8_t* >( &dataCpy[ cacheEntryIt->second.offset + 5 ] );
for( auto& member_entry : _exh->get_exh_members() )
{
// Seek to the position of the member to extract.
// 6 is because we have uint32_t/uint16_t at the start of each record
iss.seekg( cacheEntryIt->second.offset + 6 + member_entry.offset );
// Switch depending on the type to extract
switch( member_entry.type )
{
case DataType::string:
// Extract the offset to the actual string
// Seek to it then extract the actual string
{
auto string_offset = extract< uint32_t >( iss, "string_offset", false );
iss.seekg( cacheEntryIt->second.offset + 6 + _exh->get_header().data_offset + string_offset );
fields.emplace_back( utils::bparse::extract_cstring( iss, "string" ) );
}
break;
case DataType::boolean:
fields.emplace_back( extract< bool >( iss, "bool" ) );
break;
case DataType::int8:
fields.emplace_back( extract< int8_t >( iss, "int8_t" ) );
break;
case DataType::uint8:
fields.emplace_back( extract< uint8_t >( iss, "uint8_t" ) );
break;
case DataType::int16:
fields.emplace_back( extract< int16_t >( iss, "int16_t", false ) );
break;
case DataType::uint16:
fields.emplace_back( extract< uint16_t >( iss, "uint16_t", false ) );
break;
case DataType::int32:
fields.emplace_back( extract< int32_t >( iss, "int32_t", false ) );
break;
case DataType::uint32:
fields.emplace_back( extract< uint32_t >( iss, "uint32_t", false ) );
break;
case DataType::float32:
fields.emplace_back( extract< float >( iss, "float", false ) );
break;
case DataType::uint64:
fields.emplace_back( extract< uint64_t >( iss, "uint64_t", false ) );
break;
default:
auto type = static_cast< uint16_t >( member_entry.type );
if( type < 0x19 || type > 0x20 )
throw std::runtime_error( "Unknown DataType: " + std::to_string( type ) );
uint64_t val = extract< uint64_t >( iss, "bool" );
int32_t shift = type - 0x19;
int32_t i = 1 << shift;
val &= i;
fields.emplace_back( ( val & i ) == i );
break;
}
}
return fields;
}
// Get all rows
const std::map< uint32_t, std::vector< Field>>& Exd::get_rows()
{
// Iterates over all the files
const uint32_t member_count = _exh->get_members().size();
for( auto& file_ptr : _files )
{
// Get a stream
std::vector< char > dataCpy = file_ptr->get_data_sections().front();
std::istringstream iss( std::string( dataCpy.begin(), dataCpy.end() ) );
// Extract the header and skip to the record indices
auto exd_header = extract< ExdHeader >( iss );
iss.seekg( 0x20 );
// Preallocate and extract the record_indices
const uint32_t record_count = exd_header.index_size / sizeof( ExdRecordIndex );
std::vector< ExdRecordIndex > record_indices;
record_indices.reserve( record_count );
for( uint32_t i = 0; i < record_count; ++i )
{
record_indices.emplace_back( extract< ExdRecordIndex >( iss ) );
}
for( auto& record_index : record_indices )
{
// Get the vector fields for the given record and preallocate it
auto& fields = _data[ record_index.id ];
fields.reserve( member_count );
for( auto& member_entry : _exh->get_exh_members() )
//for( auto& member_entry : _exh->get_members() )
{
// Seek to the position of the member to extract.
// 6 is because we have uint32_t/uint16_t at the start of each record
iss.seekg( record_index.offset + 6 + member_entry.offset );
// Switch depending on the type to extract
switch( member_entry.type )
{
case DataType::string:
// Extract the offset to the actual string
// Seek to it then extract the actual string
{
auto string_offset = extract< uint32_t >( iss, "string_offset", false );
iss.seekg( record_index.offset + 6 + _exh->get_header().data_offset + string_offset );
fields.emplace_back( utils::bparse::extract_cstring( iss, "string" ) );
}
break;
case DataType::boolean:
fields.emplace_back( extract< bool >( iss, "bool" ) );
break;
case DataType::int8:
fields.emplace_back( extract< int8_t >( iss, "int8_t" ) );
break;
case DataType::uint8:
fields.emplace_back( extract< uint8_t >( iss, "uint8_t" ) );
break;
case DataType::int16:
fields.emplace_back( extract< int16_t >( iss, "int16_t", false ) );
break;
case DataType::uint16:
fields.emplace_back( extract< uint16_t >( iss, "uint16_t", false ) );
break;
case DataType::int32:
fields.emplace_back( extract< int32_t >( iss, "int32_t", false ) );
break;
case DataType::uint32:
fields.emplace_back( extract< uint32_t >( iss, "uint32_t", false ) );
break;
case DataType::float32:
fields.emplace_back( extract< float >( iss, "float", false ) );
break;
case DataType::uint64:
fields.emplace_back( extract< uint64_t >( iss, "uint64_t", false ) );
break;
default:
auto type = static_cast< uint16_t >( member_entry.type );
if( type < 0x19 || type > 0x20 )
throw std::runtime_error( "Unknown DataType: " + std::to_string( type ) );
uint64_t val = extract< uint64_t >( iss, "bool" );
int32_t shift = type - 0x19;
int32_t i = 1 << shift;
val &= i;
fields.emplace_back( ( val & i ) == i );
break;
}
}
}
}
return _data;
}
struct ExdHeader
{
char magic[0x4];
uint16_t unknown;
uint16_t unknown2;
uint32_t index_size;
};
struct ExdRecordIndex
{
uint32_t id;
uint32_t offset;
};
}
}
namespace xiv
{
namespace utils
{
namespace bparse
{
template <> inline void reorder<xiv::exd::ExdHeader>( xiv::exd::ExdHeader& i_struct ) { for( int32_t i = 0; i < 0x4; ++i ) { xiv::utils::bparse::reorder( i_struct.magic[i] ); } i_struct.unknown = xiv::utils::bparse::byteswap( i_struct.unknown ); xiv::utils::bparse::reorder( i_struct.unknown ); i_struct.unknown2 = xiv::utils::bparse::byteswap( i_struct.unknown2 ); xiv::utils::bparse::reorder( i_struct.unknown2 ); i_struct.index_size = xiv::utils::bparse::byteswap( i_struct.index_size ); xiv::utils::bparse::reorder( i_struct.index_size ); }
template <> inline void reorder<xiv::exd::ExdRecordIndex>( xiv::exd::ExdRecordIndex& i_struct ) { i_struct.id = xiv::utils::bparse::byteswap( i_struct.id ); xiv::utils::bparse::reorder( i_struct.id ); i_struct.offset = xiv::utils::bparse::byteswap( i_struct.offset ); xiv::utils::bparse::reorder( i_struct.offset ); }
}
}
};
namespace xiv
{
namespace exd
{
Exd::Exd( std::shared_ptr<Exh> i_exh, const std::vector<std::shared_ptr<dat::File>>& i_files )
{
_exh = i_exh;
_files = i_files;
// Iterates over all the files
const uint32_t member_count = _exh->get_members().size();
for ( auto &file_ptr : _files )
{
// Get a stream
std::vector< char > dataCpy = file_ptr->get_data_sections().front();
std::istringstream iss( std::string( dataCpy.begin(), dataCpy.end() ) );
// Extract the header and skip to the record indices
auto exd_header = extract< ExdHeader >( iss );
iss.seekg( 0x20 );
// Preallocate and extract the record_indices
const uint32_t record_count = exd_header.index_size / sizeof( ExdRecordIndex );
std::vector< ExdRecordIndex > record_indices;
record_indices.reserve( record_count );
for ( uint32_t i = 0; i < record_count; ++i )
{
auto recordIndex = extract< ExdRecordIndex >( iss );
_idCache[recordIndex.id] = ExdCacheEntry{file_ptr, recordIndex.offset};
}
}
}
Exd::~Exd()
{
}
const std::vector<Field> Exd::get_row( uint32_t id, uint32_t subRow )
{
auto cacheEntryIt = _idCache.find( id );
if( cacheEntryIt == _idCache.end() )
throw std::runtime_error( "Id not found: " + std::to_string( id ) );
// Iterates over all the files
const uint32_t member_count = _exh->get_members().size();
auto& file_ptr = cacheEntryIt->second.file;
std::vector< char > dataCpy = file_ptr->get_data_sections().front();
std::istringstream iss( std::string( dataCpy.begin(), dataCpy.end() ) );
// Get the vector fields for the given record and preallocate it
auto fields = _data[id];
fields.reserve( member_count );
iss.seekg( cacheEntryIt->second.offset + 6 );
uint8_t subRows = *reinterpret_cast< uint8_t* >( &dataCpy[ cacheEntryIt->second.offset + 5 ] );
if( subRow >= subRows )
throw std::runtime_error( "Out of bounds sub-row!" );
int offset = cacheEntryIt->second.offset + 6 + ( subRow * _exh->get_header().data_offset + 2 * ( subRow + 1 ) );
for( auto& member_entry : _exh->get_exh_members() )
{
// Seek to the position of the member to extract.
// 6 is because we have uint32_t/uint16_t at the start of each record
iss.seekg( offset + member_entry.offset );
// Switch depending on the type to extract
switch( member_entry.type )
{
case DataType::string:
// Extract the offset to the actual string
// Seek to it then extract the actual string
{
throw std::runtime_error( "String not implemented for variant 2!" );
//auto string_offset = extract<uint32_t>( iss, "string_offset", false );
//iss.seekg( cacheEntryIt->second.offset + 6 + _exh->get_header().data_offset + string_offset );
//fields.emplace_back( utils::bparse::extract_cstring( iss, "string" ) );
}
break;
case DataType::boolean:
fields.emplace_back( extract<bool>( iss, "bool" ) );
break;
case DataType::int8:
fields.emplace_back( extract<int8_t>( iss, "int8_t" ) );
break;
case DataType::uint8:
fields.emplace_back( extract<uint8_t>( iss, "uint8_t" ) );
break;
case DataType::int16:
fields.emplace_back( extract<int16_t>( iss, "int16_t", false ) );
break;
case DataType::uint16:
fields.emplace_back( extract<uint16_t>( iss, "uint16_t", false ) );
break;
case DataType::int32:
fields.emplace_back( extract<int32_t>( iss, "int32_t", false ) );
break;
case DataType::uint32:
fields.emplace_back( extract<uint32_t>( iss, "uint32_t", false ) );
break;
case DataType::float32:
fields.emplace_back( extract<float>( iss, "float", false ) );
break;
case DataType::uint64:
fields.emplace_back( extract<uint64_t>( iss, "uint64_t", false ) );
break;
default:
auto type = static_cast< uint16_t >( member_entry.type );
if( type < 0x19 || type > 0x20 )
throw std::runtime_error("Unknown DataType: " + std::to_string( type ));
uint64_t val = extract< uint64_t >( iss, "bool" );
int32_t shift = type - 0x19;
int32_t i = 1 << shift;
val &= i;
fields.emplace_back( ( val & i ) == i );
break;
}
}
return fields;
}
const std::vector<Field> Exd::get_row( uint32_t id )
{
auto cacheEntryIt = _idCache.find( id );
if( cacheEntryIt == _idCache.end() )
throw std::runtime_error( "Id not found: " + std::to_string( id ) );
// Iterates over all the files
const uint32_t member_count = _exh->get_members().size();
auto& file_ptr = cacheEntryIt->second.file;
std::vector< char > dataCpy = file_ptr->get_data_sections().front();
std::istringstream iss( std::string( dataCpy.begin(), dataCpy.end() ) );
// Get the vector fields for the given record and preallocate it
auto fields = _data[id];
fields.reserve( member_count );
iss.seekg( cacheEntryIt->second.offset + 6 );
uint8_t subRows = *reinterpret_cast< uint8_t* >( &dataCpy[ cacheEntryIt->second.offset + 5 ] );
for( auto& member_entry : _exh->get_exh_members() )
{
// Seek to the position of the member to extract.
// 6 is because we have uint32_t/uint16_t at the start of each record
iss.seekg( cacheEntryIt->second.offset + 6 + member_entry.offset );
// Switch depending on the type to extract
switch( member_entry.type )
{
case DataType::string:
// Extract the offset to the actual string
// Seek to it then extract the actual string
{
auto string_offset = extract<uint32_t>( iss, "string_offset", false );
iss.seekg( cacheEntryIt->second.offset + 6 + _exh->get_header().data_offset + string_offset );
fields.emplace_back( utils::bparse::extract_cstring( iss, "string" ) );
}
break;
case DataType::boolean:
fields.emplace_back( extract<bool>( iss, "bool" ) );
break;
case DataType::int8:
fields.emplace_back( extract<int8_t>( iss, "int8_t" ) );
break;
case DataType::uint8:
fields.emplace_back( extract<uint8_t>( iss, "uint8_t" ) );
break;
case DataType::int16:
fields.emplace_back( extract<int16_t>( iss, "int16_t", false ) );
break;
case DataType::uint16:
fields.emplace_back( extract<uint16_t>( iss, "uint16_t", false ) );
break;
case DataType::int32:
fields.emplace_back( extract<int32_t>( iss, "int32_t", false ) );
break;
case DataType::uint32:
fields.emplace_back( extract<uint32_t>( iss, "uint32_t", false ) );
break;
case DataType::float32:
fields.emplace_back( extract<float>( iss, "float", false ) );
break;
case DataType::uint64:
fields.emplace_back( extract<uint64_t>( iss, "uint64_t", false ) );
break;
default:
auto type = static_cast< uint16_t >( member_entry.type );
if( type < 0x19 || type > 0x20 )
throw std::runtime_error("Unknown DataType: " + std::to_string( type ));
uint64_t val = extract< uint64_t >( iss, "bool" );
int32_t shift = type - 0x19;
int32_t i = 1 << shift;
val &= i;
fields.emplace_back( ( val & i ) == i );
break;
}
}
return fields;
}
// Get all rows
const std::map<uint32_t, std::vector<Field>>& Exd::get_rows()
{
// Iterates over all the files
const uint32_t member_count = _exh->get_members().size();
for( auto& file_ptr : _files )
{
// Get a stream
std::vector< char > dataCpy = file_ptr->get_data_sections().front();
std::istringstream iss( std::string( dataCpy.begin(), dataCpy.end() ) );
// Extract the header and skip to the record indices
auto exd_header = extract<ExdHeader>( iss );
iss.seekg( 0x20 );
// Preallocate and extract the record_indices
const uint32_t record_count = exd_header.index_size / sizeof( ExdRecordIndex );
std::vector<ExdRecordIndex> record_indices;
record_indices.reserve( record_count );
for( uint32_t i = 0; i < record_count; ++i )
{
record_indices.emplace_back( extract<ExdRecordIndex>( iss ) );
}
for( auto& record_index : record_indices )
{
// Get the vector fields for the given record and preallocate it
auto& fields = _data[record_index.id];
fields.reserve( member_count );
for( auto& member_entry : _exh->get_exh_members() )
//for( auto& member_entry : _exh->get_members() )
{
// Seek to the position of the member to extract.
// 6 is because we have uint32_t/uint16_t at the start of each record
iss.seekg( record_index.offset + 6 + member_entry.offset );
// Switch depending on the type to extract
switch( member_entry.type )
{
case DataType::string:
// Extract the offset to the actual string
// Seek to it then extract the actual string
{
auto string_offset = extract<uint32_t>( iss, "string_offset", false );
iss.seekg( record_index.offset + 6 + _exh->get_header().data_offset + string_offset );
fields.emplace_back( utils::bparse::extract_cstring( iss, "string" ) );
}
break;
case DataType::boolean:
fields.emplace_back( extract<bool>( iss, "bool" ) );
break;
case DataType::int8:
fields.emplace_back( extract<int8_t>( iss, "int8_t" ) );
break;
case DataType::uint8:
fields.emplace_back( extract<uint8_t>( iss, "uint8_t" ) );
break;
case DataType::int16:
fields.emplace_back( extract<int16_t>( iss, "int16_t", false ) );
break;
case DataType::uint16:
fields.emplace_back( extract<uint16_t>( iss, "uint16_t", false ) );
break;
case DataType::int32:
fields.emplace_back( extract<int32_t>( iss, "int32_t", false ) );
break;
case DataType::uint32:
fields.emplace_back( extract<uint32_t>( iss, "uint32_t", false ) );
break;
case DataType::float32:
fields.emplace_back( extract<float>( iss, "float", false ) );
break;
case DataType::uint64:
fields.emplace_back( extract<uint64_t>( iss, "uint64_t", false ) );
break;
default:
auto type = static_cast< uint16_t >( member_entry.type );
if( type < 0x19 || type > 0x20 )
throw std::runtime_error("Unknown DataType: " + std::to_string( type ));
uint64_t val = extract< uint64_t >( iss, "bool" );
int32_t shift = type - 0x19;
int32_t i = 1 << shift;
val &= i;
fields.emplace_back( ( val & i ) == i );
break;
}
}
}
}
return _data;
}
}
} }

56
deps/datReader/Exd.h vendored
View file

@ -8,15 +8,13 @@
#include "File.h" #include "File.h"
namespace xiv namespace xiv::exd
{
namespace exd
{ {
class Exh; class Exh;
// Field type containing all the possible types in the data files // Field type containing all the possible types in the data files
using Field = std::variant< using Field = std::variant<
std::string, std::string,
bool, bool,
int8_t, int8_t,
@ -27,40 +25,44 @@ using Field = std::variant<
uint32_t, uint32_t,
float, float,
uint64_t >; uint64_t >;
struct ExdCacheEntry
{
std::shared_ptr<dat::File> file;
uint32_t offset;
};
// Data for a given language struct ExdCacheEntry
class Exd {
{ std::shared_ptr< dat::File > file;
public: uint32_t offset;
};
// Data for a given language
class Exd
{
public:
// i_exh: the header // i_exh: the header
// i_files: the multiple exd files // i_files: the multiple exd files
Exd() {} Exd()
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();
// 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 );
// Get a row by its id and sub-row // Get a row by its id and sub-row
const std::vector<Field> get_row(uint32_t id, uint32_t subRow); const std::vector< Field > get_row( uint32_t id, uint32_t subRow );
// Get all rows // Get all rows
const std::map<uint32_t, std::vector<Field>>& get_rows(); const std::map< uint32_t, std::vector< Field>>& get_rows();
protected: protected:
// Data indexed by the ID of the row, the vector is field with the same order as exh.members // Data indexed by the ID of the row, the vector is field with the same order as exh.members
std::map<uint32_t, std::vector<Field>> _data; std::map< uint32_t, std::vector< Field>> _data;
std::vector<std::shared_ptr<dat::File>> _files; std::vector< std::shared_ptr< dat::File>> _files;
std::shared_ptr<Exh> _exh; std::shared_ptr< Exh > _exh;
std::map< uint32_t, ExdCacheEntry > _idCache; std::map< uint32_t, ExdCacheEntry > _idCache;
}; };
}
} }
#endif // XIV_EXD_EXD_H #endif // XIV_EXD_EXD_H

View file

@ -9,74 +9,73 @@
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 = std::map<xiv::exd::Language, std::string> language_map =
{{xiv::exd::Language::none, ""}, {
{xiv::exd::Language::ja, "_ja"}, {xiv::exd::Language::none, ""},
{xiv::exd::Language::en, "_en"}, {xiv::exd::Language::ja, "_ja"},
{xiv::exd::Language::de, "_de"}, {xiv::exd::Language::en, "_en"},
{xiv::exd::Language::fr, "_fr"}, {xiv::exd::Language::de, "_de"},
{xiv::exd::Language::chs, "_chs"}}; {xiv::exd::Language::fr, "_fr"},
{xiv::exd::Language::chs, "_chs"}
};
} }
namespace xiv namespace xiv::exd
{ {
namespace exd Cat::Cat( dat::GameData& i_game_data, const std::string& i_name ) :
{ _name( i_name )
{
//XIV_INFO(xiv_exd_logger, "Initializing Cat with name: " << i_name);
// creates the header .exh
{
auto header_file = i_game_data.getFile( "exd/" + i_name + ".exh" );
_header = std::shared_ptr< Exh >( new Exh( *header_file ) );
Cat::Cat(dat::GameData& i_game_data, const std::string& i_name) : }
_name(i_name)
for( auto language: _header->get_languages() )
{
// chs not yet in data files
if( language == Language::en || language == Language::none )
{ {
//XIV_INFO(xiv_exd_logger, "Initializing Cat with name: " << i_name); // Get all the files for a given category/language, in case of multiple range of IDs in separate files (like Quest)
// creates the header .exh std::vector< std::shared_ptr< dat::File>> files;
{ for( auto& exd_def: _header->get_exd_defs() )
auto header_file = i_game_data.getFile("exd/" + i_name + ".exh"); {
_header = std::shared_ptr< Exh >( new Exh( *header_file ) ); files.emplace_back( i_game_data.getFile(
"exd/" + i_name + "_" + std::to_string( exd_def.start_id ) + language_map.at( language ) + ".exd" ) );
} }
// Instantiate the data for this language
for(auto language: _header->get_languages()) _data[ language ] = std::make_unique< Exd >( _header, files );
{
// chs not yet in data files
if (language == Language::en || language == Language::none)
{
// Get all the files for a given category/language, in case of multiple range of IDs in separate files (like Quest)
std::vector<std::shared_ptr<dat::File>> files;
for(auto& exd_def: _header->get_exd_defs())
{
files.emplace_back( i_game_data.getFile("exd/" + i_name + "_" + std::to_string(exd_def.start_id) + language_map.at(language) + ".exd") );
}
// Instantiate the data for this language
_data[language] = std::unique_ptr<Exd>(new Exd(_header, files));
}
}
} }
}
}
Cat::~Cat() Cat::~Cat()
{ {
} }
const std::string& Cat::get_name() const const std::string& Cat::get_name() const
{ {
return _name; return _name;
} }
const Exh& Cat::get_header() const const Exh& Cat::get_header() const
{ {
return *_header; return *_header;
} }
const Exd& Cat::get_data_ln(Language i_language) const const Exd& Cat::get_data_ln( Language i_language ) const
{ {
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( uint16_t( i_language ) ) );
} }
return *(ln_it->second); return *( ln_it->second );
} }
}
} }

View file

@ -4,7 +4,7 @@
#include <memory> #include <memory>
#include <map> #include <map>
#include <experimental/filesystem> #include <filesystem>
#include "bparse.h" #include "bparse.h"
#include "Exd.h" #include "Exd.h"

View file

@ -7,50 +7,47 @@
#include "ExdCat.h" #include "ExdCat.h"
namespace xiv namespace xiv::exd {
{
namespace 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 : // Fetch the root.exl and get a stream from it
_game_data(i_game_data) auto root_exl = i_game_data.getFile( "exd/root.exl" );
{ std::vector< char > dataCpy = root_exl->get_data_sections().front();
//XIV_INFO(xiv_exd_logger, "Initializing ExdData"); xiv::utils::stream::vectorwrapbuf< char > databuf( dataCpy );
std::istream stream( &databuf );
// Fetch the root.exl and get a stream from it // Iterates over the lines while skipping the first one
auto root_exl = i_game_data.getFile("exd/root.exl"); std::string line;
std::vector< char > dataCpy = root_exl->get_data_sections().front(); std::getline( stream, line ); // extract first line EXLT,2
xiv::utils::stream::vectorwrapbuf<char> databuf(dataCpy); std::getline( stream, line );
std::istream stream(&databuf);
// Iterates over the lines while skipping the first one // Until the EOF
std::string line; while( !line.empty() )
std::getline(stream, line); // extract first line EXLT,2 {
std::getline(stream, line); // Format is cat_name,XX
// XX being an internal identifier
// Get only the cat_name
auto sep = line.find( ',' );
auto category = line.substr( 0, sep );
// Until the EOF // Add to the list of category name
while (!line.empty()) // creates the empty category in the cats map
{ // instantiate the creation mutex for this category
// Format is cat_name,XX _cat_names.push_back( category );
// XX being an internal identifier _cats[ category ] = std::unique_ptr< Cat >();
// Get only the cat_name _cat_creation_mutexes[ category ] = std::make_unique< std::mutex >();
auto sep = line.find(',');
auto category = line.substr(0, sep);
// Add to the list of category name std::getline( stream, line );
// creates the empty category in the cats map }
// instantiate the creation mutex for this category
_cat_names.push_back(category);
_cats[category] = std::unique_ptr<Cat>();
_cat_creation_mutexes[category] = std::unique_ptr<std::mutex>(new 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() ExdData::~ExdData()
@ -58,43 +55,42 @@ 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() )
{ {
throw std::runtime_error("Category not found: " + i_cat_name); throw std::runtime_error( "Category not found: " + i_cat_name );
} }
if (cat_it->second) if( cat_it->second )
{ {
// If valid return it // If valid return it
return *(cat_it->second); return *( cat_it->second );
} }
else else
{ {
// If not, create it and return it // If not, create it and return it
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)
if (!_cats[i_cat_name]) if( !_cats[ i_cat_name ] )
{ {
_cats[i_cat_name] = std::unique_ptr<Cat>(new Cat(_game_data, i_cat_name)); _cats[ i_cat_name ] = std::make_unique< Cat >( _game_data, i_cat_name );
} }
} }
} }
}

View file

@ -5,7 +5,7 @@
#include <memory> #include <memory>
#include <mutex> #include <mutex>
#include <experimental/filesystem> #include <filesystem>
namespace xiv namespace xiv
{ {
@ -34,7 +34,7 @@ namespace xiv
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::experimental::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

View file

@ -7,71 +7,69 @@
using xiv::utils::bparse::extract; using xiv::utils::bparse::extract;
namespace xiv namespace xiv::exd
{
namespace 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::istringstream iss( std::string( dataCpy.begin(), dataCpy.end() ) );
// Extract header and skip to member definitions // Extract header and skip to member definitions
_header = extract<ExhHeader>(iss); _header = extract< ExhHeader >( iss );
iss.seekg(0x20); iss.seekg( 0x20 );
// Extract all the members and feed the _members map // Extract all the members and feed the _members map
for (auto i = 0; i < _header.field_count; ++i) for( auto i = 0; i < _header.field_count; ++i )
{ {
auto member = extract<ExhMember>(iss); auto member = extract< ExhMember >( iss );
_members[member.offset] = member; _members[ member.offset ] = member;
_exh_defs.push_back( member ); _exh_defs.push_back( member );
} }
// Extract all the exd_defs // Extract all the exd_defs
_exd_defs.reserve(_header.exd_count); _exd_defs.reserve( _header.exd_count );
for (auto i = 0; i < _header.exd_count; ++i) for( auto i = 0; i < _header.exd_count; ++i )
{ {
_exd_defs.emplace_back(extract<ExhExdDef>(iss)); _exd_defs.emplace_back( extract< ExhExdDef >( iss ) );
} }
// Extract all the languages // Extract all the languages
_languages.reserve(_header.language_count); _languages.reserve( _header.language_count );
for (auto i = 0; i < _header.language_count; ++i) for( auto i = 0; i < _header.language_count; ++i )
{ {
_languages.emplace_back(Language(extract<uint16_t>(iss, "language"))); _languages.emplace_back( Language( extract< uint16_t >( iss, "language" ) ) );
} }
} }
Exh::~Exh() Exh::~Exh()
{ {
} }
const ExhHeader& Exh::get_header() const const ExhHeader& Exh::get_header() const
{ {
return _header; return _header;
} }
const std::vector<ExhExdDef>& Exh::get_exd_defs() const const std::vector< ExhExdDef >& Exh::get_exd_defs() const
{ {
return _exd_defs; return _exd_defs;
} }
const std::vector<Language>& Exh::get_languages() const const std::vector< Language >& Exh::get_languages() const
{ {
return _languages; return _languages;
} }
const std::map<uint32_t, ExhMember>& Exh::get_members() const const std::map< uint32_t, ExhMember >& Exh::get_members() const
{ {
return _members; return _members;
} }
const std::vector<ExhMember>& Exh::get_exh_members() const const std::vector< ExhMember >& Exh::get_exh_members() const
{ {
return _exh_defs; return _exh_defs;
} }
} }
}

190
deps/datReader/Exh.h vendored
View file

@ -5,99 +5,131 @@
#include "bparse.h" #include "bparse.h"
namespace xiv namespace xiv::exd
{ {
namespace exd enum class DataType :
{ uint16_t
enum class DataType : uint16_t {
{ string = 0,
string = 0, boolean = 1,
boolean = 1, int8 = 2,
int8 = 2, uint8 = 3,
uint8 = 3, int16 = 4,
int16 = 4, uint16 = 5,
uint16 = 5, int32 = 6,
int32 = 6, uint32 = 7,
uint32 = 7, float32 = 9,
float32 = 9, uint64 = 11,
uint64 = 11, };
};
struct ExhHeader struct ExhHeader
{ {
char magic[0x4]; char magic[0x4];
uint16_t unknown; uint16_t unknown;
uint16_t data_offset; uint16_t data_offset;
uint16_t field_count; uint16_t field_count;
uint16_t exd_count; uint16_t exd_count;
uint16_t language_count; uint16_t language_count;
uint16_t unknown1; uint16_t unknown1;
uint8_t u2; uint8_t u2;
uint8_t variant; uint8_t variant;
}; };
struct ExhMember struct ExhMember
{ {
DataType type; DataType type;
uint16_t offset; uint16_t offset;
}; };
struct ExhExdDef struct ExhExdDef
{ {
uint32_t start_id; uint32_t start_id;
uint32_t count_id; uint32_t count_id;
}; };
} };
namespace xiv::utils::bparse {
template<>
inline void reorder< xiv::exd::ExhHeader >( xiv::exd::ExhHeader& i_struct )
{
for( int32_t i = 0; i < 0x4; ++i )
{
xiv::utils::bparse::reorder( i_struct.magic[ i ] );
}
i_struct.unknown = xiv::utils::bparse::byteswap( i_struct.unknown );
xiv::utils::bparse::reorder( i_struct.unknown );
i_struct.data_offset = xiv::utils::bparse::byteswap( i_struct.data_offset );
xiv::utils::bparse::reorder( i_struct.data_offset );
i_struct.field_count = xiv::utils::bparse::byteswap( i_struct.field_count );
xiv::utils::bparse::reorder( i_struct.field_count );
i_struct.exd_count = xiv::utils::bparse::byteswap( i_struct.exd_count );
xiv::utils::bparse::reorder( i_struct.exd_count );
i_struct.language_count = xiv::utils::bparse::byteswap( i_struct.language_count );
xiv::utils::bparse::reorder( i_struct.language_count );
}
template<>
inline void reorder< xiv::exd::ExhMember >( xiv::exd::ExhMember& i_struct )
{
i_struct.type = xiv::utils::bparse::byteswap( i_struct.type );
xiv::utils::bparse::reorder( i_struct.type );
i_struct.offset = xiv::utils::bparse::byteswap( i_struct.offset );
xiv::utils::bparse::reorder( i_struct.offset );
}
template<>
inline void reorder< xiv::exd::ExhExdDef >( xiv::exd::ExhExdDef& i_struct )
{
i_struct.start_id = xiv::utils::bparse::byteswap( i_struct.start_id );
xiv::utils::bparse::reorder( i_struct.start_id );
i_struct.count_id = xiv::utils::bparse::byteswap( i_struct.count_id );
xiv::utils::bparse::reorder( i_struct.count_id );
}
}; };
namespace xiv namespace xiv
{ {
namespace utils
{
namespace bparse
{
template <> inline void reorder<xiv::exd::ExhHeader>( xiv::exd::ExhHeader& i_struct ) { for( int32_t i = 0; i < 0x4; ++i ) { xiv::utils::bparse::reorder( i_struct.magic[i] ); } i_struct.unknown = xiv::utils::bparse::byteswap( i_struct.unknown ); xiv::utils::bparse::reorder( i_struct.unknown ); i_struct.data_offset = xiv::utils::bparse::byteswap( i_struct.data_offset ); xiv::utils::bparse::reorder( i_struct.data_offset ); i_struct.field_count = xiv::utils::bparse::byteswap( i_struct.field_count ); xiv::utils::bparse::reorder( i_struct.field_count ); i_struct.exd_count = xiv::utils::bparse::byteswap( i_struct.exd_count ); xiv::utils::bparse::reorder( i_struct.exd_count ); i_struct.language_count = xiv::utils::bparse::byteswap( i_struct.language_count ); xiv::utils::bparse::reorder( i_struct.language_count ); }
template <> inline void reorder<xiv::exd::ExhMember>( xiv::exd::ExhMember& i_struct ) { i_struct.type = xiv::utils::bparse::byteswap( i_struct.type ); xiv::utils::bparse::reorder( i_struct.type ); i_struct.offset = xiv::utils::bparse::byteswap( i_struct.offset ); xiv::utils::bparse::reorder( i_struct.offset ); }
template <> inline void reorder<xiv::exd::ExhExdDef>( xiv::exd::ExhExdDef& i_struct ) { i_struct.start_id = xiv::utils::bparse::byteswap( i_struct.start_id ); xiv::utils::bparse::reorder( i_struct.start_id ); i_struct.count_id = xiv::utils::bparse::byteswap( i_struct.count_id ); xiv::utils::bparse::reorder( i_struct.count_id ); }
}
}
};
namespace xiv namespace dat
{ {
namespace dat class File;
{ }
class File;
}
namespace exd
{
enum Language : uint16_t; namespace exd
{
// Header file for exd data enum Language :
class Exh uint16_t;
{
public:
// The header file
Exh( const dat::File& i_file );
~Exh();
const ExhHeader& get_header() const; // Header file for exd data
const std::vector<ExhExdDef>& get_exd_defs() const; class Exh
const std::vector<Language>& get_languages() const; {
const std::map<uint32_t, ExhMember>& get_members() const; public:
const std::vector<ExhMember>& get_exh_members() const; // The header file
Exh( const dat::File& i_file );
protected: ~Exh();
ExhHeader _header;
// Members of the datastruct ordered(indexed) by offset
std::map<uint32_t, ExhMember> _members;
std::vector<ExhMember> _exh_defs;
std::vector<ExhExdDef> _exd_defs;
std::vector<Language> _languages;
};
} const ExhHeader& get_header() const;
const std::vector< ExhExdDef >& get_exd_defs() const;
const std::vector< Language >& get_languages() const;
const std::map< uint32_t, ExhMember >& get_members() const;
const std::vector< ExhMember >& get_exh_members() const;
protected:
ExhHeader _header;
// Members of the datastruct ordered(indexed) by offset
std::map< uint32_t, ExhMember > _members;
std::vector< ExhMember > _exh_defs;
std::vector< ExhExdDef > _exd_defs;
std::vector< Language > _languages;
};
}
} }
#endif // XIV_EXD_EXH_H #endif // XIV_EXD_EXH_H

View file

@ -2,44 +2,41 @@
#include <fstream> #include <fstream>
namespace xiv namespace xiv::dat
{
namespace dat
{ {
File::File() : File::File() :
_type(FileType::empty) _type( FileType::empty )
{ {
} }
File::~File() File::~File()
{ {
} }
FileType File::get_type() const FileType File::get_type() const
{ {
return _type; return _type;
} }
const std::vector<std::vector<char>>& File::get_data_sections() const const std::vector< std::vector< char>>& File::get_data_sections() const
{ {
return _data_sections; return _data_sections;
} }
std::vector<std::vector<char>>& File::access_data_sections() std::vector< std::vector< char>>& File::access_data_sections()
{ {
return _data_sections; return _data_sections;
} }
void File::exportToFile(const std::experimental::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.string(), std::ios_base::binary | std::ios_base::out );
for( auto& data_section : _data_sections ) for( auto& data_section : _data_sections )
{ {
ofs.write( data_section.data(), data_section.size() ); ofs.write( data_section.data(), data_section.size() );
} }
ofs.close(); ofs.close();
} }
} }
}

64
deps/datReader/File.h vendored
View file

@ -3,54 +3,46 @@
#include <vector> #include <vector>
#include <experimental/filesystem> #include <filesystem>
#include <stdint.h> #include <stdint.h>
#include "bparse.h" #include "bparse.h"
namespace xiv::dat
namespace xiv
{ {
namespace dat enum class FileType :
{ uint32_t
enum class FileType : uint32_t {
{ empty = 1,
empty = 1, standard = 2,
standard = 2, model = 3,
model = 3, texture = 4,
texture = 4, };
};
}
};
namespace xiv class Dat;
{
namespace dat
{
class Dat; // Basic file from the dats
class File
{
friend class Dat;
// Basic file from the dats public:
class File File();
{
friend class Dat;
public:
File();
~File();
FileType get_type() const; ~File();
// Getters functions for the data in the file FileType get_type() const;
const std::vector<std::vector<char>>& get_data_sections() const;
std::vector<std::vector<char>>& access_data_sections();
void exportToFile( const std::experimental::filesystem::path& i_path ) const; // Getters functions for the data in the file
const std::vector< std::vector< char>>& get_data_sections() const;
protected: std::vector< std::vector< char>>& access_data_sections();
FileType _type;
std::vector<std::vector<char>> _data_sections;
};
} void exportToFile( const std::filesystem::path& i_path ) const;
protected:
FileType _type;
std::vector< std::vector< char>> _data_sections;
};
} }
#endif // XIV_DAT_FILE_H #endif // XIV_DAT_FILE_H

View file

@ -11,312 +11,315 @@
#include "DatCat.h" #include "DatCat.h"
#include "File.h" #include "File.h"
namespace namespace {
{ // Relation between category number and category name
// Relation between category number and category name // These names are taken straight from the exe, it helps resolve dispatching when getting files by path
// These names are taken straight from the exe, it helps resolve dispatching when getting files by path
std::unordered_map< std::string, uint32_t > categoryNameToIdMap = std::unordered_map< std::string, uint32_t > categoryNameToIdMap =
{{"common", 0x00}, { { "common", 0x00 },
{"bgcommon", 0x01}, { "bgcommon", 0x01 },
{"bg", 0x02}, { "bg", 0x02 },
{"cut", 0x03}, { "cut", 0x03 },
{"chara", 0x04}, { "chara", 0x04 },
{"shader", 0x05}, { "shader", 0x05 },
{"ui", 0x06}, { "ui", 0x06 },
{"sound", 0x07}, { "sound", 0x07 },
{"vfx", 0x08}, { "vfx", 0x08 },
{"ui_script", 0x09}, { "ui_script", 0x09 },
{"exd", 0x0A}, { "exd", 0x0A },
{"game_script", 0x0B}, { "game_script", 0x0B },
{"music", 0x0C} { "music", 0x0C }
}; };
std::unordered_map< uint32_t, std::string > categoryIdToNameMap = std::unordered_map< uint32_t, std::string > categoryIdToNameMap =
{{0x00, "common"}, { { 0x00, "common" },
{0x01, "bgcommon"}, { 0x01, "bgcommon" },
{0x02, "bg"}, { 0x02, "bg" },
{0x03, "cut"}, { 0x03, "cut" },
{0x04, "chara"}, { 0x04, "chara" },
{0x05, "shader"}, { 0x05, "shader" },
{0x06, "ui"}, { 0x06, "ui" },
{0x07, "sound"}, { 0x07, "sound" },
{0x08, "vfx"}, { 0x08, "vfx" },
{0x09, "ui_script"}, { 0x09, "ui_script" },
{0x0A, "exd"}, { 0x0A, "exd" },
{0x0B, "game_script"}, { 0x0B, "game_script" },
{0x0C, "music"}}; { 0x0C, "music" } };
} }
namespace xiv namespace xiv::dat
{
namespace dat
{ {
GameData::GameData( const std::filesystem::path& path ) try :
m_path( path )
{
int maxExLevel = 0;
GameData::GameData(const std::experimental::filesystem::path& path) try : // msvc has retarded stdlib implementation
m_path(path) #ifdef _WIN32
{ static constexpr auto sep = "\\";
int maxExLevel = 0; #else
static constexpr auto sep = std::filesystem::path::preferred_separator;
#endif
// msvc has retarded stdlib implementation // Determine which expansions are available
#ifdef _WIN32 while( std::filesystem::exists( std::filesystem::path(
static constexpr auto sep = "\\"; m_path.string() + sep + "ex" + std::to_string( maxExLevel + 1 ) + sep + "ex" + std::to_string( maxExLevel + 1 ) +
#else ".ver" ) ) )
static constexpr auto sep = std::experimental::filesystem::path::preferred_separator; {
#endif
// Determine which expansions are available
while( std::experimental::filesystem::exists( std::experimental::filesystem::path( m_path.string() + sep + "ex" + std::to_string( maxExLevel + 1 ) + sep + "ex" + std::to_string( maxExLevel + 1 ) + ".ver" ) ) )
{
maxExLevel++; maxExLevel++;
} }
// Iterate over the files in path
for( auto it = std::experimental::filesystem::directory_iterator( m_path.string() + "//ffxiv" ); it != std::experimental::filesystem::directory_iterator(); ++it ) // Iterate over the files in path
{ for( auto it = std::filesystem::directory_iterator( m_path.string() + "//ffxiv" );
it != std::filesystem::directory_iterator(); ++it )
{
// Get the filename of the current element // Get the filename of the current element
auto filename = it->path().filename().string(); auto filename = it->path().filename().string();
// If it contains ".win32.index" this is most likely a hit for a category // If it contains ".win32.index" this is most likely a hit for a category
if( filename.find( ".win32.index" ) != std::string::npos && filename.find( ".win32.index2" ) == std::string::npos ) if( filename.find( ".win32.index" ) != std::string::npos && filename.find( ".win32.index2" ) == std::string::npos )
{ {
// Format of indexes is XX0000.win32.index, so fetch the hex number for category number // Format of indexes is XX0000.win32.index, so fetch the hex number for category number
std::istringstream iss( filename.substr( 0, 2 ) ); std::istringstream iss( filename.substr( 0, 2 ) );
uint32_t cat_nb; uint32_t cat_nb;
iss >> std::hex >> cat_nb; iss >> std::hex >> cat_nb;
// Add to the list of category number // Add to the list of category number
// creates the empty category in the cats map // creates the empty category in the cats map
// instantiate the creation mutex for this category // instantiate the creation mutex for this category
m_catNums.push_back( cat_nb ); m_catNums.push_back( cat_nb );
m_cats[cat_nb] = std::unique_ptr<Cat>(); m_cats[ cat_nb ] = std::unique_ptr< Cat >();
m_catCreationMutexes[cat_nb] = std::unique_ptr<std::mutex>( new std::mutex() ); m_catCreationMutexes[ cat_nb ] = std::make_unique< std::mutex >();
// Check for expansion // Check for expansion
for( int exNum = 1; exNum <= maxExLevel; exNum++ ) for( int exNum = 1; exNum <= maxExLevel; exNum++ )
{ {
const std::string path = m_path.string() + sep + buildDatStr( "ex" + std::to_string( exNum ), cat_nb, exNum, 0, "win32", "index" ); const std::string path =
m_path.string() + sep + buildDatStr( "ex" + std::to_string( exNum ), cat_nb, exNum, 0, "win32", "index" );
if( std::experimental::filesystem::exists( std::experimental::filesystem::path( path ) ) ) if( std::filesystem::exists( std::filesystem::path( path ) ) )
{
int chunkCount = 0;
for( int chunkTest = 0; chunkTest < 256; chunkTest++ )
{ {
if( std::filesystem::exists( m_path.string() + sep +
int chunkCount = 0; buildDatStr( "ex" + std::to_string( exNum ), cat_nb, exNum, chunkTest, "win32",
"index" ) ) )
for(int chunkTest = 0; chunkTest < 256; chunkTest++ ) {
{ m_exCats[ cat_nb ].exNumToChunkMap[ exNum ].chunkToCatMap[ chunkTest ] = std::unique_ptr< Cat >();
if( std::experimental::filesystem::exists( m_path.string() + sep + buildDatStr( "ex" + std::to_string( exNum ), cat_nb, exNum, chunkTest, "win32", "index" ) ) ) chunkCount++;
{ }
m_exCats[cat_nb].exNumToChunkMap[exNum].chunkToCatMap[chunkTest] = std::unique_ptr<Cat>();
chunkCount++;
}
}
} }
}
}
}
} }
} }
} }
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( "GameData initialization failed: " + std::string( e.what() ) ); throw std::runtime_error( "GameData initialization failed: " + std::string( e.what() ) );
} }
GameData::~GameData() GameData::~GameData()
{ {
} }
const std::string GameData::buildDatStr( const std::string folder, const int cat, const int exNum, const int chunk, const std::string platform, const std::string type ) const std::string GameData::buildDatStr( const std::string folder, const int cat, const int exNum, const int chunk,
{ const std::string platform, const std::string type )
char dat[1024]; {
sprintf( dat, "%s/%02x%02x%02x.%s.%s", folder.c_str(), cat, exNum, chunk, platform.c_str(), type.c_str() ); char dat[1024];
return std::string( dat ); sprintf( dat, "%s/%02x%02x%02x.%s.%s", folder.c_str(), cat, exNum, chunk, platform.c_str(), type.c_str() );
} return std::string( dat );
}
const std::vector<uint32_t>& GameData::getCatNumbers() const const std::vector< uint32_t >& GameData::getCatNumbers() const
{ {
return m_catNums; return m_catNums;
} }
std::unique_ptr<File> GameData::getFile(const std::string& path) std::unique_ptr< File > GameData::getFile( const std::string& path )
{ {
// Get the hashes, the category from the path then call the getFile of the category // Get the hashes, the category from the path then call the getFile of the category
uint32_t dirHash; uint32_t dirHash;
uint32_t filenameHash; uint32_t filenameHash;
getHashes( path, dirHash, filenameHash ); getHashes( path, dirHash, filenameHash );
return getCategoryFromPath( path ).getFile( dirHash, filenameHash ); return getCategoryFromPath( path ).getFile( dirHash, filenameHash );
} }
bool GameData::doesFileExist(const std::string& path) bool GameData::doesFileExist( const std::string& path )
{ {
uint32_t dirHash; uint32_t dirHash;
uint32_t filenameHash; uint32_t filenameHash;
getHashes( path, dirHash, filenameHash ); getHashes( path, dirHash, filenameHash );
return getCategoryFromPath( path ).doesFileExist( dirHash, filenameHash ); return getCategoryFromPath( path ).doesFileExist( dirHash, filenameHash );
} }
bool GameData::doesDirExist(const std::string& i_path) bool GameData::doesDirExist( const std::string& i_path )
{ {
uint32_t dirHash; uint32_t dirHash;
uint32_t filenameHash; uint32_t filenameHash;
getHashes( i_path, dirHash, filenameHash ); getHashes( i_path, dirHash, filenameHash );
return getCategoryFromPath( i_path ).doesDirExist( dirHash ); return getCategoryFromPath( i_path ).doesDirExist( dirHash );
} }
const Cat& GameData::getCategory(uint32_t catNum) const Cat& GameData::getCategory( uint32_t catNum )
{ {
// Check that the category number exists // Check that the category number exists
auto catIt = m_cats.find( catNum ); auto catIt = m_cats.find( catNum );
if( catIt == m_cats.end() ) if( catIt == m_cats.end() )
{ {
throw std::runtime_error( "Category not found: " + std::to_string( catNum ) ); throw std::runtime_error( "Category not found: " + std::to_string( catNum ) );
} }
// If it exists and already instantiated return it // If it exists and already instantiated return it
if( catIt->second ) if( catIt->second )
{ {
return *( catIt->second ); return *( catIt->second );
} }
else else
{ {
// Else create it and return it // Else create it and return it
createCategory( catNum ); createCategory( catNum );
return *( m_cats[catNum] ); return *( m_cats[ catNum ] );
} }
} }
const Cat& GameData::getCategory(const std::string& catName) const Cat& GameData::getCategory( const std::string& catName )
{ {
// Find the category number from the name // Find the category number from the name
auto categoryNameToIdMapIt = ::categoryNameToIdMap.find( catName ); auto categoryNameToIdMapIt = ::categoryNameToIdMap.find( catName );
if( categoryNameToIdMapIt == ::categoryNameToIdMap.end() ) if( categoryNameToIdMapIt == ::categoryNameToIdMap.end() )
{ {
throw std::runtime_error( "Category not found: " + catName ); throw std::runtime_error( "Category not found: " + catName );
} }
// From the category number return the category // From the category number return the category
return getCategory( categoryNameToIdMapIt->second ); return getCategory( categoryNameToIdMapIt->second );
} }
const Cat& GameData::getExCategory( const std::string& catName, uint32_t exNum, const std::string& path ) const Cat& GameData::getExCategory( const std::string& catName, uint32_t exNum, const std::string& path )
{ {
// Find the category number from the name // Find the category number from the name
auto categoryMapIt = ::categoryNameToIdMap.find( catName ); auto categoryMapIt = ::categoryNameToIdMap.find( catName );
if( categoryMapIt == ::categoryNameToIdMap.end() ) if( categoryMapIt == ::categoryNameToIdMap.end() )
{ {
throw std::runtime_error( "Category not found: " + catName ); throw std::runtime_error( "Category not found: " + catName );
} }
uint32_t dirHash; uint32_t dirHash;
uint32_t filenameHash; uint32_t filenameHash;
getHashes( path, dirHash, filenameHash ); getHashes( path, dirHash, filenameHash );
for( auto const& chunk : m_exCats[categoryMapIt->second].exNumToChunkMap[exNum].chunkToCatMap ) for( auto const& chunk : m_exCats[ categoryMapIt->second ].exNumToChunkMap[ exNum ].chunkToCatMap )
{ {
if( !chunk.second ) if( !chunk.second )
createExCategory( categoryMapIt->second ); createExCategory( categoryMapIt->second );
if( chunk.second->doesFileExist( dirHash, filenameHash ) ) if( chunk.second->doesFileExist( dirHash, filenameHash ) )
{ {
return *( chunk.second ); return *( chunk.second );
} }
} }
throw std::runtime_error( "Chunk not found for path: " + path ); throw std::runtime_error( "Chunk not found for path: " + path );
} }
const Cat& GameData::getCategoryFromPath(const std::string& path) const Cat& GameData::getCategoryFromPath( const std::string& path )
{ {
// Find the first / in the string, paths are in the format CAT_NAME/..../.../../.... // Find the first / in the string, paths are in the format CAT_NAME/..../.../../....
auto firstSlashPos = path.find( '/' ); auto firstSlashPos = path.find( '/' );
if( firstSlashPos == std::string::npos ) if( firstSlashPos == std::string::npos )
{ {
throw std::runtime_error( "Path does not have a / char: " + path ); throw std::runtime_error( "Path does not have a / char: " + path );
} }
if( path.substr( firstSlashPos + 1, 2) == "ex" ) if( path.substr( firstSlashPos + 1, 2 ) == "ex" )
{ {
return getExCategory( path.substr( 0, firstSlashPos ), std::stoi( path.substr( firstSlashPos + 3, 1 ) ), path ); return getExCategory( path.substr( 0, firstSlashPos ), std::stoi( path.substr( firstSlashPos + 3, 1 ) ), path );
} }
else else
{ {
// From the sub string found beforethe first / get the category // From the sub string found beforethe first / get the category
return getCategory( path.substr( 0, firstSlashPos ) ); return getCategory( path.substr( 0, firstSlashPos ) );
} }
} }
void GameData::getHashes(const std::string& path, uint32_t& dirHash, uint32_t& filenameHash) const void GameData::getHashes( const std::string& path, uint32_t& dirHash, uint32_t& filenameHash ) const
{ {
// Convert the path to lowercase before getting the hashes // Convert the path to lowercase before getting the hashes
std::string pathLower; std::string pathLower;
pathLower.resize( path.size() ); pathLower.resize( path.size() );
std::transform( path.begin(), path.end(), pathLower.begin(), ::tolower ); std::transform( path.begin(), path.end(), pathLower.begin(), ::tolower );
// Find last / to separate dir from filename // Find last / to separate dir from filename
auto lastSlashPos = pathLower.rfind( '/' ); auto lastSlashPos = pathLower.rfind( '/' );
if( lastSlashPos == std::string::npos ) if( lastSlashPos == std::string::npos )
{ {
throw std::runtime_error( "Path does not have a / char: " + path ); throw std::runtime_error( "Path does not have a / char: " + path );
} }
std::string dirPart = pathLower.substr( 0, lastSlashPos ); std::string dirPart = pathLower.substr( 0, lastSlashPos );
std::string filenamePart = pathLower.substr( lastSlashPos + 1 ); std::string filenamePart = pathLower.substr( lastSlashPos + 1 );
// Get the crc32 values from zlib, to compensate the final XOR 0xFFFFFFFF that isnot done in the exe we just reXOR // Get the crc32 values from zlib, to compensate the final XOR 0xFFFFFFFF that isnot done in the exe we just reXOR
dirHash = crc32( 0, reinterpret_cast<const uint8_t*>( dirPart.data() ), dirPart.size() ) ^ 0xFFFFFFFF; dirHash = crc32( 0, reinterpret_cast<const uint8_t*>( dirPart.data() ), dirPart.size() ) ^ 0xFFFFFFFF;
filenameHash = crc32( 0, reinterpret_cast<const uint8_t*>( filenamePart.data() ), filenamePart.size() ) ^ 0xFFFFFFFF; filenameHash = crc32( 0, reinterpret_cast<const uint8_t*>( filenamePart.data() ), filenamePart.size() ) ^ 0xFFFFFFFF;
} }
void GameData::createCategory(uint32_t catNum) void GameData::createCategory( uint32_t catNum )
{ {
// Lock mutex in this scope // Lock mutex in this scope
std::lock_guard<std::mutex> lock( *( m_catCreationMutexes[catNum] ) ); std::lock_guard< std::mutex > lock( *( m_catCreationMutexes[ catNum ] ) );
// 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)
if( !m_cats[catNum] ) if( !m_cats[ catNum ] )
{ {
// Get the category name if we have it // Get the category name if we have it
std::string catName; std::string catName;
auto categoryMapIt = ::categoryIdToNameMap.find( catNum ); auto categoryMapIt = ::categoryIdToNameMap.find( catNum );
if( categoryMapIt != ::categoryIdToNameMap.end() ) if( categoryMapIt != ::categoryIdToNameMap.end() )
{ {
catName = categoryMapIt->second; catName = categoryMapIt->second;
} }
// Actually creates the category // Actually creates the category
m_cats[catNum] = std::unique_ptr<Cat>( new Cat( m_path, catNum, catName ) ); m_cats[ catNum ] = std::make_unique< Cat >( m_path, catNum, catName );
} }
} }
void GameData::createExCategory( uint32_t catNum ) void GameData::createExCategory( uint32_t catNum )
{ {
// 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)
if( !m_exCats[catNum].exNumToChunkMap[1].chunkToCatMap[0] ) if( !m_exCats[ catNum ].exNumToChunkMap[ 1 ].chunkToCatMap[ 0 ] )
{ {
// Get the category name if we have it // Get the category name if we have it
std::string catName; std::string catName;
auto categoryMapIt = ::categoryIdToNameMap.find( catNum ); auto categoryMapIt = ::categoryIdToNameMap.find( catNum );
if( categoryMapIt != ::categoryIdToNameMap.end() ) if( categoryMapIt != ::categoryIdToNameMap.end() )
{ {
catName = categoryMapIt->second; catName = categoryMapIt->second;
} }
for( auto const& ex : m_exCats[catNum].exNumToChunkMap ) for( auto const& ex : m_exCats[ catNum ].exNumToChunkMap )
{ {
for( auto const& chunk : m_exCats[catNum].exNumToChunkMap[ex.first].chunkToCatMap ) for( auto const& chunk : m_exCats[ catNum ].exNumToChunkMap[ ex.first ].chunkToCatMap )
{ {
// Actually creates the category // Actually creates the category
m_exCats[catNum].exNumToChunkMap[ex.first].chunkToCatMap[chunk.first] = std::unique_ptr<Cat>( new Cat( m_path, catNum, catName, ex.first, chunk.first ) ); m_exCats[ catNum ].exNumToChunkMap[ ex.first ].chunkToCatMap[ chunk.first ] = std::unique_ptr< Cat >(
} new Cat( m_path, catNum, catName, ex.first, chunk.first ) );
}
} }
} }
} }
} }
}

View file

@ -5,80 +5,88 @@
#include <unordered_map> #include <unordered_map>
#include <mutex> #include <mutex>
#include <experimental/filesystem> #include <filesystem>
namespace xiv namespace xiv::dat
{
namespace dat
{ {
class Cat; class Cat;
class File;
// Interface to all the datfiles - Main entry point class File;
// All the paths to files/dirs inside the dats are case-insensitive
class GameData
{
public:
// This should be the path in which the .index/.datX files are located
GameData( const std::experimental::filesystem::path& path );
~GameData();
static const std::string buildDatStr( const std::string folder, const int cat, const int exNum, const int chunk, const std::string platform, const std::string type ); // Interface to all the datfiles - Main entry point
// All the paths to files/dirs inside the dats are case-insensitive
class GameData
{
public:
// This should be the path in which the .index/.datX files are located
GameData( const std::filesystem::path& path );
// Returns all the scanned category number available in the path ~GameData();
const std::vector<uint32_t>& getCatNumbers() const;
// Return a specific category by its number (see getCatNumbers() for loops) static const std::string
const Cat& getCategory( uint32_t catNum ); buildDatStr( const std::string folder, const int cat, const int exNum, const int chunk, const std::string platform,
// Return a specific category by it's name (e.g.: "exd"/"game_script"/ etc...) const std::string type );
const Cat& getCategory( const std::string& catName );
const Cat& getExCategory( const std::string& catName, uint32_t exNum, const std::string& path ); // Returns all the scanned category number available in the path
const std::vector< uint32_t >& getCatNumbers() const;
// Retrieve a file from the dats given its filename // Return a specific category by its number (see getCatNumbers() for loops)
std::unique_ptr<File> getFile( const std::string& path ); const Cat& getCategory( uint32_t catNum );
// Checks that a file exists // Return a specific category by it's name (e.g.: "exd"/"game_script"/ etc...)
bool doesFileExist( const std::string& path ); const Cat& getCategory( const std::string& catName );
// Checks that a dir exists, there must be a trailing / in the path const Cat& getExCategory( const std::string& catName, uint32_t exNum, const std::string& path );
// Note that it won't work for dirs that don't contain any file
// e.g.: - "ui/icon/" will return False
// - "ui/icon/000000/" will return True
bool doesDirExist( const std::string& path );
protected: // Retrieve a file from the dats given its filename
// Return a specific category given a path (calls const Cat& getCategory(const std::string& catName)) std::unique_ptr< File > getFile( const std::string& path );
const Cat& getCategoryFromPath( const std::string& path );
// From a full path, returns the dirHash and the filenameHash // Checks that a file exists
void getHashes( const std::string& path, uint32_t& dirHash, uint32_t& filenameHash ) const; bool doesFileExist( const std::string& path );
// Lazy instantiation of category // Checks that a dir exists, there must be a trailing / in the path
void createCategory( uint32_t catNum ); // Note that it won't work for dirs that don't contain any file
// e.g.: - "ui/icon/" will return False
// - "ui/icon/000000/" will return True
bool doesDirExist( const std::string& path );
void createExCategory( uint32_t catNum ); protected:
// Return a specific category given a path (calls const Cat& getCategory(const std::string& catName))
const Cat& getCategoryFromPath( const std::string& path );
// Path given to constructor, pointing to the folder with the .index/.datX files // From a full path, returns the dirHash and the filenameHash
const std::experimental::filesystem::path m_path; void getHashes( const std::string& path, uint32_t& dirHash, uint32_t& filenameHash ) const;
// Stored categories, indexed by their number, categories are instantiated and parsed individually when they are needed // Lazy instantiation of category
std::unordered_map<uint32_t, std::unique_ptr<Cat>> m_cats; void createCategory( uint32_t catNum );
// List of all the categories numbers, is equal to m_cats.keys() void createExCategory( uint32_t catNum );
std::vector<uint32_t> m_catNums;
// Map of all EX categories and their chunks, "CatNum - (ExNum - (ChunkNum - Cat))" // Path given to constructor, pointing to the folder with the .index/.datX files
// Map of all EX categories and their chunks, "CatNum - (ExNum - (ChunkNum - Cat))" const std::filesystem::path m_path;
using ChunkToCatMap = struct { std::unordered_map< uint32_t, std::unique_ptr< Cat > > chunkToCatMap; };
using ExNumToChunkMap = struct { std::unordered_map< uint32_t, ChunkToCatMap > exNumToChunkMap; }; // Stored categories, indexed by their number, categories are instantiated and parsed individually when they are needed
using CatNumToExNumMap = std::unordered_map< uint32_t, ExNumToChunkMap >; std::unordered_map< uint32_t, std::unique_ptr< Cat>> m_cats;
CatNumToExNumMap m_exCats;
std::unordered_map<uint32_t, std::unique_ptr<std::mutex>> m_catCreationMutexes; // List of all the categories numbers, is equal to m_cats.keys()
}; std::vector< uint32_t > m_catNums;
// Map of all EX categories and their chunks, "CatNum - (ExNum - (ChunkNum - Cat))"
// Map of all EX categories and their chunks, "CatNum - (ExNum - (ChunkNum - Cat))"
using ChunkToCatMap = struct
{
std::unordered_map< uint32_t, std::unique_ptr< Cat > > chunkToCatMap;
};
using ExNumToChunkMap = struct
{
std::unordered_map< uint32_t, ChunkToCatMap > exNumToChunkMap;
};
using CatNumToExNumMap = std::unordered_map< uint32_t, ExNumToChunkMap >;
CatNumToExNumMap m_exCats;
std::unordered_map< uint32_t, std::unique_ptr< std::mutex>> m_catCreationMutexes;
};
}
} }
#endif // XIV_DAT_GAMEDATA_H #endif // XIV_DAT_GAMEDATA_H

View file

@ -2,166 +2,154 @@
#include "bparse.h" #include "bparse.h"
namespace xiv namespace xiv::dat
{ {
namespace dat struct IndexBlockRecord
{ {
struct IndexBlockRecord uint32_t offset;
{ uint32_t size;
uint32_t offset; SqPackBlockHash blockHash;
uint32_t size; };
SqPackBlockHash blockHash;
};
struct IndexHashTableEntry struct IndexHashTableEntry
{ {
uint32_t filenameHash; uint32_t filenameHash;
uint32_t dirHash; uint32_t dirHash;
uint32_t datOffset; uint32_t datOffset;
uint32_t padding; uint32_t padding;
}; };
}
} }
namespace xiv namespace xiv::utils::bparse
{ {
namespace utils template<>
{ inline void reorder< xiv::dat::IndexBlockRecord >( xiv::dat::IndexBlockRecord& i_struct )
namespace bparse {
{ xiv::utils::bparse::reorder( i_struct.offset );
template <> xiv::utils::bparse::reorder( i_struct.size );
inline void reorder<xiv::dat::IndexBlockRecord>(xiv::dat::IndexBlockRecord& i_struct) xiv::utils::bparse::reorder( i_struct.blockHash );
{ }
xiv::utils::bparse::reorder(i_struct.offset);
xiv::utils::bparse::reorder(i_struct.size);
xiv::utils::bparse::reorder(i_struct.blockHash);
}
template <> template<>
inline void reorder<xiv::dat::IndexHashTableEntry>(xiv::dat::IndexHashTableEntry& i_struct) inline void reorder< xiv::dat::IndexHashTableEntry >( xiv::dat::IndexHashTableEntry& i_struct )
{ {
xiv::utils::bparse::reorder(i_struct.filenameHash); xiv::utils::bparse::reorder( i_struct.filenameHash );
xiv::utils::bparse::reorder(i_struct.dirHash); xiv::utils::bparse::reorder( i_struct.dirHash );
xiv::utils::bparse::reorder(i_struct.datOffset); xiv::utils::bparse::reorder( i_struct.datOffset );
xiv::utils::bparse::reorder(i_struct.padding); xiv::utils::bparse::reorder( i_struct.padding );
} }
} }
}
};
using xiv::utils::bparse::extract; using xiv::utils::bparse::extract;
namespace xiv namespace xiv::dat
{
namespace dat
{ {
Index::Index(const std::experimental::filesystem::path& path) : Index::Index( const std::filesystem::path& path ) :
SqPack( path ) SqPack( path )
{ {
if( !m_handle ) if( !m_handle )
throw new std::runtime_error( "Failed to load Index at " + path.string() ); throw new std::runtime_error( "Failed to load Index at " + path.string() );
// Hash Table record // Hash Table record
auto hashTableBlockRecord = extract<IndexBlockRecord>( m_handle ); auto hashTableBlockRecord = extract< IndexBlockRecord >( m_handle );
isIndexBlockValid( hashTableBlockRecord ); isIndexBlockValid( hashTableBlockRecord );
// Save the posin the stream to go back to it later on // Save the posin the stream to go back to it later on
auto pos = m_handle.tellg(); auto pos = m_handle.tellg();
// Seek to the pos of the hash table in the file // Seek to the pos of the hash table in the file
m_handle.seekg( hashTableBlockRecord.offset ); m_handle.seekg( hashTableBlockRecord.offset );
// Preallocate and extract the index_hash_table_entries // Preallocate and extract the index_hash_table_entries
std::vector<IndexHashTableEntry> indexHashTableEntries; std::vector< IndexHashTableEntry > indexHashTableEntries;
extract<IndexHashTableEntry>( m_handle, hashTableBlockRecord.size / sizeof( IndexHashTableEntry ), extract< IndexHashTableEntry >( m_handle, hashTableBlockRecord.size / sizeof( IndexHashTableEntry ),
indexHashTableEntries ); indexHashTableEntries );
// Feed the correct entry in the HashTable for each index_hash_table_entry // Feed the correct entry in the HashTable for each index_hash_table_entry
for( auto& indexHashTableEntry : indexHashTableEntries ) for( auto& indexHashTableEntry : indexHashTableEntries )
{ {
auto& hashTableEntry = m_hashTable[indexHashTableEntry.dirHash][indexHashTableEntry.filenameHash]; auto& hashTableEntry = m_hashTable[ indexHashTableEntry.dirHash ][ indexHashTableEntry.filenameHash ];
// The dat number is found in the offset, last four bits // The dat number is found in the offset, last four bits
hashTableEntry.datNum = ( indexHashTableEntry.datOffset & 0xF ) / 0x2; hashTableEntry.datNum = ( indexHashTableEntry.datOffset & 0xF ) / 0x2;
// The offset in the dat file, needs to strip the dat number indicator // The offset in the dat file, needs to strip the dat number indicator
hashTableEntry.datOffset = ( indexHashTableEntry.datOffset & 0xFFFFFFF0 ) * 0x08; hashTableEntry.datOffset = ( indexHashTableEntry.datOffset - ( indexHashTableEntry.datOffset & 0x000F ) ) * 0x08;
hashTableEntry.dirHash = indexHashTableEntry.dirHash; hashTableEntry.dirHash = indexHashTableEntry.dirHash;
hashTableEntry.filenameHash = indexHashTableEntry.filenameHash; hashTableEntry.filenameHash = indexHashTableEntry.filenameHash;
} }
// Come back to where we were before reading the HashTable // Come back to where we were before reading the HashTable
m_handle.seekg( pos ); m_handle.seekg( pos );
// Dat Count // Dat Count
m_datCount = extract<uint32_t>( m_handle, "dat_count" ); m_datCount = extract< uint32_t >( m_handle, "dat_count" );
// Free List // Free List
isIndexBlockValid( extract<IndexBlockRecord>( m_handle ) ); isIndexBlockValid( extract< IndexBlockRecord >( m_handle ) );
// Dir Hash Table // Dir Hash Table
isIndexBlockValid( extract<IndexBlockRecord>( m_handle ) ); isIndexBlockValid( extract< IndexBlockRecord >( m_handle ) );
} }
Index::~Index() Index::~Index()
{ {
} }
uint32_t Index::getDatCount() const uint32_t Index::getDatCount() const
{ {
return m_datCount; return m_datCount;
} }
const Index::HashTable& Index::getHashTable() const const Index::HashTable& Index::getHashTable() const
{ {
return m_hashTable; return m_hashTable;
} }
bool Index::doesFileExist( uint32_t dir_hash, uint32_t filename_hash ) const bool Index::doesFileExist( uint32_t dir_hash, uint32_t filename_hash ) const
{ {
auto dir_it = getHashTable().find( dir_hash ); auto dir_it = getHashTable().find( dir_hash );
if( dir_it != getHashTable().end() ) if( dir_it != getHashTable().end() )
{ {
return ( dir_it->second.find( filename_hash ) != dir_it->second.end() ); return ( dir_it->second.find( filename_hash ) != dir_it->second.end() );
} }
return false; return false;
} }
bool Index::doesDirExist( uint32_t dir_hash ) const bool Index::doesDirExist( uint32_t dir_hash ) const
{ {
return ( getHashTable().find( dir_hash ) != getHashTable().end() ); return ( getHashTable().find( dir_hash ) != getHashTable().end() );
} }
const Index::DirHashTable& Index::getDirHashTable( uint32_t dir_hash ) const const Index::DirHashTable& Index::getDirHashTable( uint32_t dir_hash ) const
{ {
auto dir_it = getHashTable().find( dir_hash ); auto dir_it = getHashTable().find( dir_hash );
if( dir_it == getHashTable().end() ) if( dir_it == getHashTable().end() )
{ {
throw std::runtime_error( "dirHash not found" ); throw std::runtime_error( "dirHash not found" );
} }
else else
{ {
return dir_it->second; return dir_it->second;
} }
} }
const Index::HashTableEntry& Index::getHashTableEntry( uint32_t dir_hash, uint32_t filename_hash ) const const Index::HashTableEntry& Index::getHashTableEntry( uint32_t dir_hash, uint32_t filename_hash ) const
{ {
auto& dirHashTable = getDirHashTable( dir_hash ); auto& dirHashTable = getDirHashTable( dir_hash );
auto file_it = dirHashTable.find( filename_hash ); auto file_it = dirHashTable.find( filename_hash );
if( file_it == dirHashTable.end() ) if( file_it == dirHashTable.end() )
{ {
throw std::runtime_error( "filenameHash not found" ); throw std::runtime_error( "filenameHash not found" );
} }
else else
{ {
return file_it->second; return file_it->second;
} }
} }
void Index::isIndexBlockValid( const IndexBlockRecord& i_index_block_record ) void Index::isIndexBlockValid( const IndexBlockRecord& i_index_block_record )
{ {
isBlockValid( i_index_block_record.offset, i_index_block_record.size, i_index_block_record.blockHash ); isBlockValid( i_index_block_record.offset, i_index_block_record.size, i_index_block_record.blockHash );
} }
} }
}

View file

@ -5,55 +5,59 @@
#include <unordered_map> #include <unordered_map>
#include <experimental/filesystem> #include <filesystem>
namespace xiv { namespace xiv::dat
namespace dat {
struct IndexBlockRecord;
class Index : public SqPack
{ {
public:
// Full path to the index file
Index( const std::experimental::filesystem::path& i_path );
virtual ~Index();
// An entry in the hash table, representing a file in a given dat struct IndexBlockRecord;
struct HashTableEntry
{ class Index :
public SqPack
{
public:
// Full path to the index file
Index( const std::filesystem::path& i_path );
virtual ~Index();
// An entry in the hash table, representing a file in a given dat
struct HashTableEntry
{
uint32_t datNum; uint32_t datNum;
uint32_t dirHash; uint32_t dirHash;
uint32_t filenameHash; uint32_t filenameHash;
uint32_t datOffset; uint32_t datOffset;
}; };
// HashTable has dir hashes -> filename hashes -> HashTableEntry // HashTable has dir hashes -> filename hashes -> HashTableEntry
using DirHashTable = std::unordered_map< uint32_t, HashTableEntry >; using DirHashTable = std::unordered_map< uint32_t, HashTableEntry >;
using HashTable = std::unordered_map< uint32_t, DirHashTable >; using HashTable = std::unordered_map< uint32_t, DirHashTable >;
// Get the number of dat files the index is linked to // Get the number of dat files the index is linked to
uint32_t getDatCount() const; uint32_t getDatCount() const;
bool doesFileExist( uint32_t dir_hash, uint32_t filename_hash ) const; bool doesFileExist( uint32_t dir_hash, uint32_t filename_hash ) const;
bool doesDirExist( uint32_t dir_hash ) const;
// Returns the whole HashTable bool doesDirExist( uint32_t dir_hash ) const;
const HashTable& getHashTable() const;
// Returns the hash table for a specific dir
const DirHashTable& getDirHashTable( uint32_t dir_hash ) const;
// Returns the HashTableEntry for a given file given its hashes
const HashTableEntry& getHashTableEntry( uint32_t dir_hash, uint32_t filename_hash ) const;
protected: // Returns the whole HashTable
// Checks that the block is valid with regards to its hash const HashTable& getHashTable() const;
void isIndexBlockValid( const IndexBlockRecord& i_index_block_record );
uint32_t m_datCount; // Returns the hash table for a specific dir
HashTable m_hashTable; const DirHashTable& getDirHashTable( uint32_t dir_hash ) const;
};
// Returns the HashTableEntry for a given file given its hashes
const HashTableEntry& getHashTableEntry( uint32_t dir_hash, uint32_t filename_hash ) const;
protected:
// Checks that the block is valid with regards to its hash
void isIndexBlockValid( const IndexBlockRecord& i_index_block_record );
uint32_t m_datCount;
HashTable m_hashTable;
};
}
} }
#endif // XIV_DAT_INDEX_H #endif // XIV_DAT_INDEX_H

View file

@ -1,76 +1,78 @@
#include "SqPack.h" #include "SqPack.h"
namespace xiv { namespace xiv::dat {
namespace dat { enum PlatformId :
struct SqPackHeader uint8_t
{ {
char magic[0x8]; Win32,
uint32_t zero; PS3,
uint32_t size; PS4
uint32_t version; };
uint32_t type;
};
struct SqPackIndexHeader struct SqPackHeader
{ {
uint32_t size; char magic[0x8];
uint32_t type; PlatformId platformId;
}; uint8_t padding0[3];
} uint32_t size;
} uint32_t version;
namespace xiv { uint32_t type;
namespace utils { };
namespace bparse {
template <>
inline void reorder<xiv::dat::SqPackHeader>(xiv::dat::SqPackHeader& i_struct)
{
for (int32_t i = 0; i < 0x8; ++i)
{
xiv::utils::bparse::reorder(i_struct.magic[i]);
}
xiv::utils::bparse::reorder(i_struct.zero);
xiv::utils::bparse::reorder(i_struct.size);
xiv::utils::bparse::reorder(i_struct.version);
xiv::utils::bparse::reorder(i_struct.type);
}
template <> struct SqPackIndexHeader
inline void reorder<xiv::dat::SqPackIndexHeader>(xiv::dat::SqPackIndexHeader& i_struct) {
{ uint32_t size;
xiv::utils::bparse::reorder(i_struct.size); uint32_t type;
xiv::utils::bparse::reorder(i_struct.type); };
}
} }
namespace xiv::utils:: bparse
{
template<>
inline void reorder< xiv::dat::SqPackHeader >( xiv::dat::SqPackHeader& i_struct )
{
for( int32_t i = 0; i < 0x8; ++i )
{
xiv::utils::bparse::reorder( i_struct.magic[ i ] );
}
xiv::utils::bparse::reorder( i_struct.platformId );
xiv::utils::bparse::reorder( i_struct.size );
xiv::utils::bparse::reorder( i_struct.version );
xiv::utils::bparse::reorder( i_struct.type );
}
template<>
inline void reorder< xiv::dat::SqPackIndexHeader >( xiv::dat::SqPackIndexHeader& i_struct )
{
xiv::utils::bparse::reorder( i_struct.size );
xiv::utils::bparse::reorder( i_struct.type );
}
} }
};
using xiv::utils::bparse::extract; using xiv::utils::bparse::extract;
namespace xiv namespace xiv::dat
{
namespace dat
{ {
SqPack::SqPack( const std::experimental::filesystem::path& path ) : // Open the file
// Open the file SqPack::SqPack( const std::filesystem::path& path ) :
m_handle( path.string(), std::ios_base::in | std::ios_base::binary ) m_handle( path.string(), std::ios_base::in | std::ios_base::binary )
{ {
// Extract the header // Extract the header
extract<SqPackHeader>( m_handle ); extract< SqPackHeader >( m_handle );
// Skip until the IndexHeader the extract it // Skip until the IndexHeader the extract it
m_handle.seekg( 0x400 ); m_handle.seekg( 0x400 );
extract<SqPackIndexHeader>( m_handle ); extract< SqPackIndexHeader >( m_handle );
} }
SqPack::~SqPack() SqPack::~SqPack()
{ {
} }
void SqPack::isBlockValid( uint32_t i_offset, uint32_t i_size, const SqPackBlockHash& i_block_hash ) void SqPack::isBlockValid( uint32_t i_offset, uint32_t i_size, const SqPackBlockHash& i_block_hash )
{ {
// TODO // TODO
} }
} }
}

View file

@ -3,64 +3,56 @@
#include <fstream> #include <fstream>
#include <experimental/filesystem> #include <filesystem>
#include "bparse.h" #include "bparse.h"
namespace xiv namespace xiv::dat
{ {
namespace dat struct SqPackBlockHash
{ {
uint8_t hash[0x14];
struct SqPackBlockHash uint32_t padding[0xB];
{ };
uint8_t hash[0x14];
uint32_t padding[0xB];
};
}
} }
namespace xiv {
namespace utils { namespace xiv::utils::bparse
namespace bparse { {
template <> inline void reorder<xiv::dat::SqPackBlockHash>( xiv::dat::SqPackBlockHash& i_struct ) template<>
{ inline void reorder< xiv::dat::SqPackBlockHash >( xiv::dat::SqPackBlockHash& i_struct )
for( auto i = 0; i < 0x14; ++i ) {
{ for( auto i = 0; i < 0x14; ++i )
xiv::utils::bparse::reorder( i_struct.hash[i] ); {
} xiv::utils::bparse::reorder( i_struct.hash[ i ] );
for( auto i = 0; i < 0xB; ++i ) }
{ for( auto i = 0; i < 0xB; ++i )
xiv::utils::bparse::reorder( i_struct.padding[i] ); {
} xiv::utils::bparse::reorder( i_struct.padding[ i ] );
} }
} }
}
}; };
namespace xiv namespace xiv::dat
{
namespace dat
{ {
class SqPack class SqPack
{ {
public: public:
// Full path to the sqpack file // Full path to the sqpack file
SqPack( const std::experimental::filesystem::path& i_path ); SqPack( const std::filesystem::path& i_path );
virtual ~SqPack();
protected: virtual ~SqPack();
// Checks that a given block is valid iven its hash
void isBlockValid( uint32_t i_offset, uint32_t i_size, const SqPackBlockHash& i_block_hash );
// File handle protected:
std::ifstream m_handle; // Checks that a given block is valid iven its hash
}; void isBlockValid( uint32_t i_offset, uint32_t i_size, const SqPackBlockHash& i_block_hash );
// File handle
std::ifstream m_handle;
};
}
} }
#endif // XIV_DAT_SQPACK_H #endif // XIV_DAT_SQPACK_H

View file

@ -6,98 +6,96 @@
#include <sstream> #include <sstream>
#include <vector> #include <vector>
namespace xiv namespace xiv::utils::bparse
{
namespace utils
{
namespace bparse
{ {
// Internal macro for byteswapping // Internal macro for byteswapping
template <int N> template< int N >
void byteswap_impl(char (&bytes)[N]) void byteswap_impl( char (& bytes)[N] )
{ {
for( auto p = std::begin( bytes ), end = std::end( bytes ) - 1; p < end; ++p, --end ) for( auto p = std::begin( bytes ), end = std::end( bytes ) - 1; p < end; ++p, --end )
{ {
std::swap( *p, *end ); std::swap( *p, *end );
} }
} }
// byteswapping any type (no pointers to array) // byteswapping any type (no pointers to array)
template <typename T> template< typename T >
T byteswap(T value) T byteswap( T value )
{ {
byteswap_impl(*reinterpret_cast<char (*)[sizeof(T)]>(&value)); byteswap_impl( *reinterpret_cast<char ( * )[sizeof( T )]>(&value) );
return value; return value;
} }
// Read a struct from a stream // Read a struct from a stream
template <typename StructType> template< typename StructType >
void read(std::istream& i_stream, StructType& i_struct) void read( std::istream& i_stream, StructType& i_struct )
{ {
static_assert( std::is_pod<StructType>::value, "StructType must be a POD to be able to use read." ); static_assert( std::is_pod< StructType >::value, "StructType must be a POD to be able to use read." );
i_stream.read( reinterpret_cast<char*>( &i_struct ), sizeof( StructType ) ); i_stream.read( reinterpret_cast<char*>( &i_struct ), sizeof( StructType ) );
} }
// By default a type does not need reordering // By default a type does not need reordering
template <typename StructType> void reorder(StructType& i_struct) {} template< typename StructType >
void reorder( StructType& i_struct )
{
}
// "Overload" for passed struct as arg // "Overload" for passed struct as arg
template <typename StructType> template< typename StructType >
void extract(std::istream& i_stream, StructType& o_struct) void extract( std::istream& i_stream, StructType& o_struct )
{ {
read( i_stream, o_struct ); read( i_stream, o_struct );
reorder( o_struct ); reorder( o_struct );
} }
// This should not copy because of RVO // This should not copy because of RVO
// Extract a struct from a stream and log it // Extract a struct from a stream and log it
template <typename StructType> template< typename StructType >
StructType extract( std::istream& i_stream ) StructType extract( std::istream& i_stream )
{ {
StructType temp_struct; StructType temp_struct;
extract<StructType>( i_stream, temp_struct ); extract< StructType >( i_stream, temp_struct );
return temp_struct; return temp_struct;
} }
template <typename StructType> template< typename StructType >
void extract(std::istream& i_stream, uint32_t i_size, std::vector<StructType>& o_structs ) void extract( std::istream& i_stream, uint32_t i_size, std::vector< StructType >& o_structs )
{ {
o_structs.reserve( i_size ); o_structs.reserve( i_size );
for( uint32_t i = 0; i < i_size; ++i ) for( uint32_t i = 0; i < i_size; ++i )
{ {
o_structs.emplace_back( extract<StructType>( i_stream ) ); o_structs.emplace_back( extract< StructType >( i_stream ) );
} }
} }
// For simple (integral) types just provide name and endianness directly // For simple (integral) types just provide name and endianness directly
template <typename StructType> template< typename StructType >
StructType extract(std::istream& i_stream, const std::string& i_name, bool i_is_le = true) StructType extract( std::istream& i_stream, const std::string& i_name, bool i_is_le = true )
{ {
StructType temp_struct; StructType temp_struct;
read( i_stream, temp_struct ); read( i_stream, temp_struct );
if( !i_is_le ) if( !i_is_le )
{ {
temp_struct = byteswap( temp_struct ); temp_struct = byteswap( temp_struct );
} }
return temp_struct; return temp_struct;
} }
template <typename StructType> template< typename StructType >
void extract(std::istream& i_stream, const std::string& i_name, uint32_t i_size, std::vector<StructType>& o_structs, bool i_is_le = true) void extract( std::istream& i_stream, const std::string& i_name, uint32_t i_size, std::vector< StructType >& o_structs,
{ bool i_is_le = true )
o_structs.reserve( i_size ); {
for( uint32_t i = 0; i < i_size; ++i ) o_structs.reserve( i_size );
{ for( uint32_t i = 0; i < i_size; ++i )
o_structs.emplace_back( extract<StructType>( i_stream, i_name ) ); {
} o_structs.emplace_back( extract< StructType >( i_stream, i_name ) );
} }
}
// For cstrings // 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 );
}
}
} }
#endif // XIV_UTILS_BPARSE_H #endif // XIV_UTILS_BPARSE_H

View file

@ -1,8 +1,8 @@
#include "conv.h" #include "conv.h"
namespace xiv { namespace xiv::utils::conv
namespace utils { {
namespace conv {
float half2float( const uint16_t i_value ) float half2float( const uint16_t i_value )
{ {
uint32_t t1; uint32_t t1;
@ -30,6 +30,4 @@ namespace conv {
} }
} }
}
}

View file

@ -5,13 +5,11 @@
#include <vector> #include <vector>
#include <ostream> #include <ostream>
namespace xiv { namespace xiv::utils::conv
namespace utils { {
namespace conv {
float half2float( const uint16_t i_value ); float half2float( const uint16_t i_value );
float ubyte2float( const uint8_t i_value ); float ubyte2float( const uint8_t i_value );
} }
}
}
#endif // XIV_UTILS_CONV_H #endif // XIV_UTILS_CONV_H

View file

@ -65,116 +65,111 @@ namespace internal
} }
} }
namespace xiv namespace xiv::utils::crc32
{
namespace utils
{
namespace crc32
{ {
uint32_t compute(const std::string& i_input, uint32_t init_crc) uint32_t compute( const std::string& i_input, uint32_t init_crc )
{ {
// Classical crc stuff // Classical crc stuff
auto& crc_table = internal::get_crc_table(); auto& crc_table = internal::get_crc_table();
auto crc = init_crc; auto crc = init_crc;
for(std::size_t i = 0; i < i_input.size(); ++i) for( std::size_t i = 0; i < i_input.size(); ++i )
{ {
crc = crc_table[(crc ^ i_input[i]) & 0xFF] ^ (crc >> 8); crc = crc_table[ ( crc ^ i_input[ i ] ) & 0xFF ] ^ ( crc >> 8 );
} }
return crc; return crc;
} }
uint32_t rev_compute(const std::string& i_input, uint32_t init_crc) uint32_t rev_compute( const std::string& i_input, uint32_t init_crc )
{ {
auto& rev_crc_table = internal::get_rev_crc_table(); auto& rev_crc_table = internal::get_rev_crc_table();
auto crc = init_crc; auto crc = init_crc;
const auto input_size = i_input.size(); const auto input_size = i_input.size();
// Reverse crc // Reverse crc
for(auto i = input_size; i > 0; --i) for( auto i = input_size; i > 0; --i )
{ {
crc = rev_crc_table[crc >> 24] ^ ((crc << 8) & 0xFFFFFF00) ^ i_input[input_size - i - 1]; crc = rev_crc_table[ crc >> 24 ] ^ ( ( crc << 8 ) & 0xFFFFFF00 ) ^ i_input[ input_size - i - 1 ];
} }
// Compute the 4 bytes needed for this init_crc // Compute the 4 bytes needed for this init_crc
for (auto i = 0; i < 4; ++i) for( auto i = 0; i < 4; ++i )
{ {
crc = rev_crc_table[crc >> 24] ^ ((crc << 8) & 0xFFFFFF00); crc = rev_crc_table[ crc >> 24 ] ^ ( ( crc << 8 ) & 0xFFFFFF00 );
} }
return crc; return crc;
} }
void generate_hashes_1(std::string& i_format, const uint32_t i_first_index, std::vector<uint32_t>& o_hashes) void generate_hashes_1( std::string& i_format, const uint32_t i_first_index, std::vector< uint32_t >& o_hashes )
{ {
char* str = const_cast<char*>(i_format.data()); char* str = const_cast<char*>(i_format.data());
const uint32_t str_size = i_format.size(); const uint32_t str_size = i_format.size();
o_hashes.resize(10000); o_hashes.resize( 10000 );
uint32_t i = 0; uint32_t i = 0;
for (char a = '0'; a <= '9'; ++a) for( char a = '0'; a <= '9'; ++a )
{ {
str[i_first_index] = a; str[ i_first_index ] = a;
for (char b = '0'; b <= '9'; ++b) for( char b = '0'; b <= '9'; ++b )
{ {
str[i_first_index + 1] = b; str[ i_first_index + 1 ] = b;
for (char c = '0'; c <= '9'; ++c) for( char c = '0'; c <= '9'; ++c )
{ {
str[i_first_index + 2] = c; str[ i_first_index + 2 ] = c;
for (char d = '0'; d <= '9'; ++d) for( char d = '0'; d <= '9'; ++d )
{ {
str[i_first_index + 3] = d; str[ i_first_index + 3 ] = d;
o_hashes[i] = ::crc32(0, reinterpret_cast<uint8_t*>(&(str[0])), str_size) ^ 0xFFFFFFFF; o_hashes[ i ] = ::crc32( 0, reinterpret_cast<uint8_t*>(&( str[ 0 ] )), str_size ) ^ 0xFFFFFFFF;
++i; ++i;
} }
} }
} }
} }
} }
void generate_hashes_2(std::string& i_format, const uint32_t i_first_index, const uint32_t i_second_index, std::vector<uint32_t>& o_hashes) void generate_hashes_2( std::string& i_format, const uint32_t i_first_index, const uint32_t i_second_index,
{ std::vector< uint32_t >& o_hashes )
char* str = const_cast<char*>(i_format.data()); {
const uint32_t str_size = i_format.size(); char* str = const_cast<char*>(i_format.data());
const uint32_t str_size = i_format.size();
o_hashes.resize(100000000); o_hashes.resize( 100000000 );
uint32_t i = 0; uint32_t i = 0;
for (char a = '0'; a <= '9'; ++a) for( char a = '0'; a <= '9'; ++a )
{ {
str[i_first_index] = a; str[ i_first_index ] = a;
for (char b = '0'; b <= '9'; ++b) for( char b = '0'; b <= '9'; ++b )
{ {
str[i_first_index + 1] = b; str[ i_first_index + 1 ] = b;
for (char c = '0'; c <= '9'; ++c) for( char c = '0'; c <= '9'; ++c )
{ {
str[i_first_index + 2] = c; str[ i_first_index + 2 ] = c;
for (char d = '0'; d <= '9'; ++d) for( char d = '0'; d <= '9'; ++d )
{ {
str[i_first_index + 3] = d; str[ i_first_index + 3 ] = d;
for (char e = '0'; e <= '9'; ++e) for( char e = '0'; e <= '9'; ++e )
{ {
str[i_second_index] = e; str[ i_second_index ] = e;
for (char f = '0'; f <= '9'; ++f) for( char f = '0'; f <= '9'; ++f )
{ {
str[i_second_index + 1] = f; str[ i_second_index + 1 ] = f;
for (char g = '0'; g <= '9'; ++g) for( char g = '0'; g <= '9'; ++g )
{ {
str[i_second_index + 2] = g; str[ i_second_index + 2 ] = g;
for (char h = '0'; h <= '9'; ++h) for( char h = '0'; h <= '9'; ++h )
{ {
str[i_second_index + 3] = h; str[ i_second_index + 3 ] = h;
o_hashes[i] = ::crc32(0, reinterpret_cast<uint8_t*>(&(str[0])), str_size) ^ 0xFFFFFFFF; o_hashes[ i ] = ::crc32( 0, reinterpret_cast<uint8_t*>(&( str[ 0 ] )), str_size ) ^ 0xFFFFFFFF;
++i; ++i;
} }
} }
} }
} }
} }
} }
} }
} }
} }
} }
}
}

View file

@ -5,9 +5,8 @@
#include <vector> #include <vector>
#include <string> #include <string>
namespace xiv { namespace xiv::utils::crc32
namespace utils { {
namespace crc32 {
// Normal crc32 computation from a given intial crc value, use zlib.crc32 instead, the final XOR 0xFFFFFFFF is not done // Normal crc32 computation from a given intial crc value, use zlib.crc32 instead, the final XOR 0xFFFFFFFF is not done
uint32_t compute( const std::string& i_input, uint32_t init_crc = 0xFFFFFFFF ); uint32_t compute( const std::string& i_input, uint32_t init_crc = 0xFFFFFFFF );
@ -17,10 +16,10 @@ namespace crc32 {
uint32_t rev_compute( const std::string& i_input, uint32_t init_crc = 0 ); uint32_t rev_compute( const std::string& i_input, uint32_t init_crc = 0 );
void generate_hashes_1( std::string& i_format, const uint32_t i_first_index, std::vector< uint32_t >& o_hashes ); void generate_hashes_1( std::string& i_format, const uint32_t i_first_index, std::vector< uint32_t >& o_hashes );
void generate_hashes_2( std::string& i_format, const uint32_t i_first_index, const uint32_t i_second_index, std::vector< uint32_t >& o_hashes );
} void generate_hashes_2( std::string& i_format, const uint32_t i_first_index, const uint32_t i_second_index,
} std::vector< uint32_t >& o_hashes );
} }
#endif // XIV_UTILS_CRC32_H #endif // XIV_UTILS_CRC32_H

View file

@ -4,13 +4,7 @@
#include <sstream> #include <sstream>
#include <streambuf> #include <streambuf>
namespace xiv namespace xiv::utils::stream
{
namespace utils
{
namespace stream
{ {
} }
}
}

View file

@ -5,23 +5,17 @@
#include <iostream> #include <iostream>
#include <vector> #include <vector>
namespace xiv namespace xiv::utils::stream
{ {
namespace utils template< typename CharT, typename TraitsT = std::char_traits< CharT > >
{ class vectorwrapbuf :
namespace stream public std::basic_streambuf< CharT, TraitsT >
{ {
template<typename CharT, typename TraitsT = std::char_traits<CharT> > public:
class vectorwrapbuf : public std::basic_streambuf<CharT, TraitsT> vectorwrapbuf( std::vector< CharT >& vec )
{
public:
vectorwrapbuf(std::vector<CharT> &vec)
{ {
this->setg(vec.data(), vec.data(), vec.data() + vec.size()); this->setg( vec.data(), vec.data(), vec.data() + vec.size() );
} }
}; };
} }
}
}
#endif // XIV_UTILS_STREAM_H #endif // XIV_UTILS_STREAM_H

View file

@ -4,32 +4,28 @@
#include <zlib/zlib.h> #include <zlib/zlib.h>
#include <vector> #include <vector>
namespace xiv namespace xiv::utils::zlib
{
namespace utils
{
namespace zlib
{ {
void compress(const std::vector<char>& in, std::vector<char>& out) void compress( const std::vector< char >& in, std::vector< char >& out )
{ {
// Fetching upper bound for out size // Fetching upper bound for out size
auto out_size = compressBound(in.size()); auto out_size = compressBound( in.size() );
out.resize(out_size); out.resize( out_size );
auto ret = compress2(reinterpret_cast<uint8_t*>(out.data()), &out_size, auto ret = compress2( reinterpret_cast<uint8_t*>(out.data()), &out_size,
reinterpret_cast<const uint8_t*>(in.data()), in.size(), Z_BEST_COMPRESSION); reinterpret_cast<const uint8_t*>(in.data()), in.size(), Z_BEST_COMPRESSION );
if (ret != Z_OK) if( ret != Z_OK )
{ {
throw std::runtime_error("Error at zlib uncompress: " + std::to_string(ret)); throw std::runtime_error( "Error at zlib uncompress: " + std::to_string( ret ) );
} }
out.resize(out_size); out.resize( out_size );
} }
void no_header_decompress(uint8_t* in, uint32_t in_size, uint8_t* out, uint32_t out_size) void no_header_decompress( uint8_t* in, uint32_t in_size, uint8_t* out, uint32_t out_size )
{ {
z_stream strm; z_stream strm;
strm.zalloc = Z_NULL; strm.zalloc = Z_NULL;
strm.zfree = Z_NULL; strm.zfree = Z_NULL;
@ -38,10 +34,10 @@ void no_header_decompress(uint8_t* in, uint32_t in_size, uint8_t* out, uint32_t
strm.next_in = Z_NULL; strm.next_in = Z_NULL;
// Init with -15 because we do not have header in this compressed data // Init with -15 because we do not have header in this compressed data
auto ret = inflateInit2(&strm, -15); auto ret = inflateInit2( &strm, -15 );
if (ret != Z_OK) if( ret != Z_OK )
{ {
throw std::runtime_error("Error at zlib init: " + std::to_string(ret)); throw std::runtime_error( "Error at zlib init: " + std::to_string( ret ) );
} }
// Set pointers to the right addresses // Set pointers to the right addresses
@ -50,16 +46,14 @@ void no_header_decompress(uint8_t* in, uint32_t in_size, uint8_t* out, uint32_t
strm.next_out = out; strm.next_out = out;
// Effectively decompress data // Effectively decompress data
ret = inflate(&strm, Z_NO_FLUSH); ret = inflate( &strm, Z_NO_FLUSH );
if (ret != Z_STREAM_END) if( ret != Z_STREAM_END )
{ {
throw std::runtime_error("Error at zlib inflate: " + std::to_string(ret)); throw std::runtime_error( "Error at zlib inflate: " + std::to_string( ret ) );
} }
// Clean up // Clean up
inflateEnd(&strm); inflateEnd( &strm );
} }
} }
}
}

13
deps/datReader/zlib.h vendored
View file

@ -4,18 +4,13 @@
#include <cstdint> #include <cstdint>
#include <vector> #include <vector>
namespace xiv namespace xiv::utils::zlib
{
namespace utils
{
namespace zlib
{ {
void compress(const std::vector<char>& in, std::vector<char>& out); void compress( const std::vector< char >& in, std::vector< char >& out );
void no_header_decompress(uint8_t* in, uint32_t in_size, uint8_t* out, uint32_t out_size);
void no_header_decompress( uint8_t* in, uint32_t in_size, uint8_t* out, uint32_t out_size );
}
}
} }
#endif // XIV_UTILS_ZLIB_H #endif // XIV_UTILS_ZLIB_H

1
deps/ffxiv-actions vendored Submodule

@ -0,0 +1 @@
Subproject commit dde9b5bbfc7c0197de0b0b49b982a0ee9fe761ab

View file

@ -4,6 +4,10 @@
#include "PreparedStatement.h" #include "PreparedStatement.h"
#include <mysql.h> #include <mysql.h>
#ifdef _MSC_VER
// fixes compile error when compiling with vs2019
#include <stdexcept>
#endif
#include <vector> #include <vector>
Mysql::Connection::Connection( std::shared_ptr< MySqlBase > pBase, Mysql::Connection::Connection( std::shared_ptr< MySqlBase > pBase,

View file

@ -3,6 +3,8 @@
#include <memory> #include <memory>
#include <map> #include <map>
#include <string>
#include "MysqlCommon.h" #include "MysqlCommon.h"
typedef struct st_mysql MYSQL; typedef struct st_mysql MYSQL;

View file

@ -1,11 +0,0 @@
cmake_minimum_required(VERSION 3.0.2)
project(Sapphire)
if( WIN32 )
file( GLOB STACKWALKER_INCLUDE_FILES "${CMAKE_CURRENT_SOURCE_DIR}/*.h*" )
file( GLOB STACKWALKER_SOURCE_FILES "${CMAKE_CURRENT_SOURCE_DIR}/*.c*" )
add_library( stackwalker ${STACKWALKER_INCLUDE_FILES} ${STACKWALKER_SOURCE_FILES} )
endif()

File diff suppressed because it is too large Load diff

View file

@ -1,255 +0,0 @@
#ifndef __STACKWALKER_H__
#define __STACKWALKER_H__
#if defined(_MSC_VER)
/**********************************************************************
*
* StackWalker.h
*
*
*
* LICENSE (http://www.opensource.org/licenses/bsd-license.php)
*
* Copyright (c) 2005-2009, Jochen Kalmbach
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* Neither the name of Jochen Kalmbach nor the names of its contributors may be
* used to endorse or promote products derived from this software without
* specific prior written permission.
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* **********************************************************************/
// #pragma once is supported starting with _MSC_VER 1000,
// so we need not to check the version (because we only support _MSC_VER >= 1100)!
#pragma once
#include <windows.h>
#if _MSC_VER >= 1900
#pragma warning(disable : 4091)
#endif
// special defines for VC5/6 (if no actual PSDK is installed):
#if _MSC_VER < 1300
typedef unsigned __int64 DWORD64, *PDWORD64;
#if defined(_WIN64)
typedef unsigned __int64 SIZE_T, *PSIZE_T;
#else
typedef unsigned long SIZE_T, *PSIZE_T;
#endif
#endif // _MSC_VER < 1300
class StackWalkerInternal; // forward
class StackWalker
{
public:
typedef enum StackWalkOptions
{
// No addition info will be retrieved
// (only the address is available)
RetrieveNone = 0,
// Try to get the symbol-name
RetrieveSymbol = 1,
// Try to get the line for this symbol
RetrieveLine = 2,
// Try to retrieve the module-infos
RetrieveModuleInfo = 4,
// Also retrieve the version for the DLL/EXE
RetrieveFileVersion = 8,
// Contains all the above
RetrieveVerbose = 0xF,
// Generate a "good" symbol-search-path
SymBuildPath = 0x10,
// Also use the public Microsoft-Symbol-Server
SymUseSymSrv = 0x20,
// Contains all the above "Sym"-options
SymAll = 0x30,
// Contains all options (default)
OptionsAll = 0x3F
} StackWalkOptions;
StackWalker(int options = OptionsAll, // 'int' is by design, to combine the enum-flags
LPCSTR szSymPath = NULL,
DWORD dwProcessId = GetCurrentProcessId(),
HANDLE hProcess = GetCurrentProcess());
StackWalker(DWORD dwProcessId, HANDLE hProcess);
virtual ~StackWalker();
typedef BOOL(__stdcall* PReadProcessMemoryRoutine)(
HANDLE hProcess,
DWORD64 qwBaseAddress,
PVOID lpBuffer,
DWORD nSize,
LPDWORD lpNumberOfBytesRead,
LPVOID pUserData // optional data, which was passed in "ShowCallstack"
);
BOOL LoadModules();
BOOL ShowCallstack(
HANDLE hThread = GetCurrentThread(),
const CONTEXT* context = NULL,
PReadProcessMemoryRoutine readMemoryFunction = NULL,
LPVOID pUserData = NULL // optional to identify some data in the 'readMemoryFunction'-callback
);
BOOL ShowObject(LPVOID pObject);
#if _MSC_VER >= 1300
// due to some reasons, the "STACKWALK_MAX_NAMELEN" must be declared as "public"
// in older compilers in order to use it... starting with VC7 we can declare it as "protected"
protected:
#endif
enum
{
STACKWALK_MAX_NAMELEN = 1024
}; // max name length for found symbols
protected:
// Entry for each Callstack-Entry
typedef struct CallstackEntry
{
DWORD64 offset; // if 0, we have no valid entry
CHAR name[STACKWALK_MAX_NAMELEN];
CHAR undName[STACKWALK_MAX_NAMELEN];
CHAR undFullName[STACKWALK_MAX_NAMELEN];
DWORD64 offsetFromSmybol;
DWORD offsetFromLine;
DWORD lineNumber;
CHAR lineFileName[STACKWALK_MAX_NAMELEN];
DWORD symType;
LPCSTR symTypeString;
CHAR moduleName[STACKWALK_MAX_NAMELEN];
DWORD64 baseOfImage;
CHAR loadedImageName[STACKWALK_MAX_NAMELEN];
} CallstackEntry;
typedef enum CallstackEntryType
{
firstEntry,
nextEntry,
lastEntry
} CallstackEntryType;
virtual void OnSymInit(LPCSTR szSearchPath, DWORD symOptions, LPCSTR szUserName);
virtual void OnLoadModule(LPCSTR img,
LPCSTR mod,
DWORD64 baseAddr,
DWORD size,
DWORD result,
LPCSTR symType,
LPCSTR pdbName,
ULONGLONG fileVersion);
virtual void OnCallstackEntry(CallstackEntryType eType, CallstackEntry& entry);
virtual void OnDbgHelpErr(LPCSTR szFuncName, DWORD gle, DWORD64 addr);
virtual void OnOutput(LPCSTR szText);
StackWalkerInternal* m_sw;
HANDLE m_hProcess;
DWORD m_dwProcessId;
BOOL m_modulesLoaded;
LPSTR m_szSymPath;
int m_options;
int m_MaxRecursionCount;
static BOOL __stdcall myReadProcMem(HANDLE hProcess,
DWORD64 qwBaseAddress,
PVOID lpBuffer,
DWORD nSize,
LPDWORD lpNumberOfBytesRead);
friend StackWalkerInternal;
}; // class StackWalker
// The "ugly" assembler-implementation is needed for systems before XP
// If you have a new PSDK and you only compile for XP and later, then you can use
// the "RtlCaptureContext"
// Currently there is no define which determines the PSDK-Version...
// So we just use the compiler-version (and assumes that the PSDK is
// the one which was installed by the VS-IDE)
// INFO: If you want, you can use the RtlCaptureContext if you only target XP and later...
// But I currently use it in x64/IA64 environments...
//#if defined(_M_IX86) && (_WIN32_WINNT <= 0x0500) && (_MSC_VER < 1400)
#if defined(_M_IX86)
#ifdef CURRENT_THREAD_VIA_EXCEPTION
// TODO: The following is not a "good" implementation,
// because the callstack is only valid in the "__except" block...
#define GET_CURRENT_CONTEXT_STACKWALKER_CODEPLEX(c, contextFlags) \
do \
{ \
memset(&c, 0, sizeof(CONTEXT)); \
EXCEPTION_POINTERS* pExp = NULL; \
__try \
{ \
throw 0; \
} \
__except (((pExp = GetExceptionInformation()) ? EXCEPTION_EXECUTE_HANDLER \
: EXCEPTION_EXECUTE_HANDLER)) \
{ \
} \
if (pExp != NULL) \
memcpy(&c, pExp->ContextRecord, sizeof(CONTEXT)); \
c.ContextFlags = contextFlags; \
} while (0);
#else
// clang-format off
// The following should be enough for walking the callstack...
#define GET_CURRENT_CONTEXT_STACKWALKER_CODEPLEX(c, contextFlags) \
do \
{ \
memset(&c, 0, sizeof(CONTEXT)); \
c.ContextFlags = contextFlags; \
__asm call x \
__asm x: pop eax \
__asm mov c.Eip, eax \
__asm mov c.Ebp, ebp \
__asm mov c.Esp, esp \
} while (0)
// clang-format on
#endif
#else
// The following is defined for x86 (XP and higher), x64 and IA64:
#define GET_CURRENT_CONTEXT_STACKWALKER_CODEPLEX(c, contextFlags) \
do \
{ \
memset(&c, 0, sizeof(CONTEXT)); \
c.ContextFlags = contextFlags; \
RtlCaptureContext(&c); \
} while (0);
#endif
#endif //defined(_MSC_VER)
#endif // __STACKWALKER_H__

View file

@ -31,8 +31,8 @@
#include <mutex> #include <mutex>
#include <functional> #include <functional>
#include <experimental/filesystem> #include <filesystem>
namespace ci { namespace fs = std::experimental::filesystem; } namespace ci { namespace fs = std::filesystem; }
//! 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 {
@ -319,7 +319,7 @@ protected:
std::string mFilter; std::string mFilter;
std::function<void(const ci::fs::path&)> mCallback; std::function<void(const ci::fs::path&)> mCallback;
std::function<void(const std::vector<ci::fs::path>&)> mListCallback; std::function<void(const std::vector<ci::fs::path>&)> mListCallback;
std::map< std::string, std::experimental::filesystem::file_time_type > mModificationTimes; std::map< std::string, std::filesystem::file_time_type > mModificationTimes;
}; };
std::mutex mMutex; std::mutex mMutex;

View file

@ -0,0 +1,15 @@
-- Migration generated at 2019/07/06 03:52:54
-- 20190706035254_ConvertFixedSizeDataToBlobs.sql
ALTER TABLE `charainfo`
CHANGE COLUMN `TitleList` `TitleList` BLOB NULL DEFAULT NULL AFTER `ActiveTitle`,
CHANGE COLUMN `Achievement` `Achievement` BLOB NULL DEFAULT NULL AFTER `TitleList`,
CHANGE COLUMN `Aetheryte` `Aetheryte` BLOB NULL DEFAULT NULL AFTER `Achievement`,
CHANGE COLUMN `HowTo` `HowTo` BLOB NULL DEFAULT NULL AFTER `Aetheryte`,
CHANGE COLUMN `Minions` `Minions` BLOB NULL DEFAULT NULL AFTER `HowTo`,
CHANGE COLUMN `Mounts` `Mounts` BLOB NULL DEFAULT NULL AFTER `Minions`,
CHANGE COLUMN `Orchestrion` `Orchestrion` BLOB NULL DEFAULT NULL AFTER `Mounts`,
CHANGE COLUMN `QuestCompleteFlags` `QuestCompleteFlags` BLOB NULL DEFAULT NULL AFTER `ConfigFlags`,
CHANGE COLUMN `QuestTracking` `QuestTracking` BLOB NULL DEFAULT NULL AFTER `OpeningSequence`,
CHANGE COLUMN `Discovery` `Discovery` BLOB NULL DEFAULT NULL AFTER `GrandCompanyRank`,
CHANGE COLUMN `Unlocks` `Unlocks` BLOB NULL DEFAULT NULL AFTER `Pose`;

File diff suppressed because it is too large Load diff

View file

@ -400,13 +400,6 @@ CREATE TABLE `dbupdate` (
PRIMARY KEY(`name`) PRIMARY KEY(`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8; ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `discoveryinfo` (
`id` int(10) NOT NULL,
`map_id` int(3) NOT NULL,
`discover_id` int(3) NOT NULL,
PRIMARY KEY(`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `house` ( CREATE TABLE `house` (
`HouseId` int(10) UNSIGNED NOT NULL AUTO_INCREMENT, `HouseId` int(10) UNSIGNED NOT NULL AUTO_INCREMENT,
`LandSetId` int(10) UNSIGNED DEFAULT NULL, `LandSetId` int(10) UNSIGNED DEFAULT NULL,
@ -602,3 +595,8 @@ CREATE TABLE `charamonsternote` (
`UPDATE_DATE` datetime DEFAULT CURRENT_TIMESTAMP, `UPDATE_DATE` datetime DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY(`CharacterId`) PRIMARY KEY(`CharacterId`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1; ) ENGINE=InnoDB DEFAULT CHARSET=latin1;
CREATE TABLE `__Migration` (
`MigrationName` VARCHAR(250) NOT NULL,
PRIMARY KEY (`MigrationName`)
) ENGINE=InnoDB;

View file

@ -1,89 +0,0 @@
#ifndef _FORWARDS_H
#define _FORWARDS_H
#include <memory>
namespace Sapphire
{
class Cell;
class Zone;
class Item;
class ItemContainer;
class Inventory;
class Session;
class ZonePosition;
using ZonePtr = std::shared_ptr< Zone >;
using ItemPtr = std::shared_ptr< Item >;
using ItemContainerPtr = std::shared_ptr< ItemContainer >;
using InventoryPtr = std::shared_ptr< Inventory >;
using SessionPtr = std::shared_ptr< Session >;
using ZonePositionPtr = std::shared_ptr< ZonePosition >;
namespace StatusEffect
{
class StatusEffect;
class StatusEffectContainer;
using StatusEffectPtr = std::shared_ptr< StatusEffect >;
using StatusEffectContainerPtr = std::shared_ptr< StatusEffectContainer >;
}
namespace Entity
{
class Chara;
class Player;
class BattleNpc;
using ActorPtr = std::shared_ptr< Chara >;
using PlayerPtr = std::shared_ptr< Player >;
using BattleNpcPtr = std::shared_ptr< BattleNpc >;
}
namespace Event
{
class EventHandler;
using EventPtr = std::shared_ptr< EventHandler >;
}
namespace Action
{
class Action;
class ActionTeleport;
class EventAction;
using ActionPtr = std::shared_ptr< Action >;
using ActionTeleportPtr = std::shared_ptr< ActionTeleport >;
using EventActionPtr = std::shared_ptr< EventAction >;
}
namespace Network
{
class Hive;
class Acceptor;
class Connection;
class WorldConnection;
class SessionConnection;
class ZoneConnection;
using HivePtr = std::shared_ptr< Hive >;
using AcceptorPtr = std::shared_ptr< Acceptor >;
using ConnectionPtr = std::shared_ptr< Connection >;
using WorldConnectionPtr = std::shared_ptr< WorldConnection >;
using ZoneConnectionPtr = std::shared_ptr< ZoneConnection >;
using SessionConnectionPtr = std::shared_ptr< SessionConnection >;
namespace Packets
{
class GamePacket;
using GamePacketPtr = std::shared_ptr< GamePacket >;
}
}
namespace Scripting
{
using EventReturnCallback = std::function< void( Entity::Player&, uint32_t, uint16_t, uint16_t, uint16_t,
uint16_t ) >;
}
using ActionCallback = std::function< void( Entity::Player&, uint32_t, uint64_t ) >;
}
#endif

View file

@ -1,14 +0,0 @@
#include "LoginSession.h"
namespace Sapphire {
LoginSession::LoginSession( void )
{
//setSocket(NULL);
}
LoginSession::~LoginSession( void )
{
}
}

View file

@ -1,57 +0,0 @@
#pragma once
#ifndef _CLoginSession_H_
#define _CLoginSession_H_
#include <stdint.h>
#include <string>
#include <string.h>
namespace Sapphire
{
class LoginSession
{
private:
uint32_t m_ip;
uint32_t m_accountId;
uint8_t m_sessionId[56];
public:
std::string newCharName;
LoginSession( void );
~LoginSession( void );
uint32_t getIp()
{
return m_ip;
}
void setSessionId( uint8_t* sessionId )
{
memcpy( m_sessionId, sessionId, 56 );
}
void setIp( uint32_t ip )
{
m_ip = ip;
}
uint32_t getAccountId()
{
return m_accountId;
}
void setAccountId( uint32_t id )
{
m_accountId = id;
}
};
}
#endif

View file

@ -1,29 +1,24 @@
#include "PlayerMinimal.h" #include "PlayerMinimal.h"
#include <Util/Util.h>
#include <Common.h> #include <Common.h>
#include <Exd/ExdDataGenerated.h> #include <Exd/ExdDataGenerated.h>
#include <Database/DatabaseDef.h> #include <Database/DatabaseDef.h>
#include <nlohmann/json.hpp>
extern Sapphire::Data::ExdDataGenerated g_exdDataGen; extern Sapphire::Data::ExdDataGenerated g_exdDataGen;
namespace Sapphire { namespace Sapphire::Api {
using namespace Common; using namespace Common;
// player constructor // player constructor
PlayerMinimal::PlayerMinimal( void ) : PlayerMinimal::PlayerMinimal() :
m_id( 0 ) m_id( 0 )
{ {
}
// deconstructor
PlayerMinimal::~PlayerMinimal( void )
{
} }
// load player from the db // load player from the db
@ -84,64 +79,101 @@ void PlayerMinimal::load( uint32_t charId )
} }
} }
std::string PlayerMinimal::getLookString()
{
auto it = m_lookMap.begin();
std::string lookString;
for( ; it != m_lookMap.end(); ++it )
{
std::string s = std::to_string( it->second );
lookString += "\"" + s + "\"";
if( it != m_lookMap.end() )
{
lookString += ",";
}
}
return lookString.substr( 0, lookString.size() - 1 );
}
std::string PlayerMinimal::getModelString()
{
std::string modelString = "\""
+ std::to_string( m_modelEquip[ 0 ] ) + "\",\""
+ std::to_string( m_modelEquip[ 1 ] ) + "\",\""
+ std::to_string( m_modelEquip[ 2 ] ) + "\",\""
+ std::to_string( m_modelEquip[ 3 ] ) + "\",\""
+ std::to_string( m_modelEquip[ 4 ] ) + "\",\""
+ std::to_string( m_modelEquip[ 5 ] ) + "\",\""
+ std::to_string( m_modelEquip[ 6 ] ) + "\",\""
+ std::to_string( m_modelEquip[ 7 ] ) + "\",\""
+ std::to_string( m_modelEquip[ 8 ] ) + "\",\""
+ std::to_string( m_modelEquip[ 9 ] ) + "\"";
return modelString;
}
std::string PlayerMinimal::getInfoJson() std::string PlayerMinimal::getInfoJson()
{ {
std::string charDetails = "{\"content\":[\"" + std::string( getName() ) + "\"," + auto payload = nlohmann::json();
"[\"0\",\"0\",\"0\",\"0\",\"" + std::to_string( m_classLevel ) + auto& c = payload["content"];
"\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\"],"
"\"0\",\"0\",\"0\",\"" + // DisplayName
std::to_string( getBirthMonth() ) + c.push_back( getName() );
"\",\"" + std::to_string( getBirthDay() ) +
"\",\"" + std::to_string( getGuardianDeity() ) + // class levels
"\",\"" + std::to_string( m_class ) + auto levelsArray = nlohmann::json();
"\",\"0\",\"" + std::to_string( getZoneId() ) + for( int i = 0; i < Common::CLASSJOB_SLOTS; ++i )
"\",\"0\"," + {
"[" + getLookString() + "]," + // these must be strings
"\"" + std::to_string( m_modelMainWeapon ) + "\",\"" + std::to_string( m_modelSubWeapon ) + "\"," + levelsArray.push_back( std::to_string( m_classMap[ i ] ) );
"[" + getModelString() + "]," + }
"\"1\",\"0\",\"0\",\"0\",\"" + std::to_string( m_equipDisplayFlags ) +
"\",\"0\",\"\",\"0\",\"0\"]," + // ClassLv
"\"classname\":\"ClientSelectData\",\"classid\":116}"; c.push_back( levelsArray );
return charDetails;
// Race
c.push_back( "0" );
// Tribe
c.push_back( "0" );
// Sex
c.push_back( "0" );
// BirthMonth
c.push_back( std::to_string( getBirthMonth() ) );
// Birthday
c.push_back( std::to_string( getBirthDay() ) );
// GuardianDeity
c.push_back( std::to_string( getGuardianDeity() ) );
// Class
c.push_back( std::to_string( m_class ) );
// ZoneId
c.push_back( "0" );
// TerritoryType
c.push_back( std::to_string( getZoneId() ) );
// ContentFinderCondition
c.push_back( "0" );
// look map
auto lookArray = nlohmann::json();
for( auto& it : m_lookMap )
{
lookArray.push_back( std::to_string( it.second ) );
}
// Customize
c.push_back( lookArray );
// ModelMainWeapon
c.push_back( std::to_string( m_modelMainWeapon ) );
// ModelSubWeapon
c.push_back( std::to_string( m_modelSubWeapon ) );
// model
auto modelArray = nlohmann::json();
for( auto i : m_modelEquip )
{
modelArray.push_back( std::to_string( i ) );
}
// ModelEquip
c.push_back( modelArray );
// MainWeapon
c.push_back( "1" );
// SubWeapon
c.push_back( "0" );
// JobStone
c.push_back( "0" );
// RemakeFlag
c.push_back( "0" );
// ConfigFlags
c.push_back( std::to_string( m_equipDisplayFlags ) );
// Voice
c.push_back( "0" );
// WorldName
c.push_back( "" );
// LoginStatus
c.push_back( "0" );
// IsOutTerritory
c.push_back( "0" );
payload["classname"] = "ClientSelectData";
payload["classid"] = 116;
return payload.dump();
} }
uint8_t PlayerMinimal::getClassLevel() uint8_t PlayerMinimal::getClassLevel()
@ -150,30 +182,6 @@ uint8_t PlayerMinimal::getClassLevel()
return static_cast< uint8_t >( m_classMap[ classJobIndex ] ); return static_cast< uint8_t >( m_classMap[ classJobIndex ] );
} }
std::string PlayerMinimal::getClassString()
{
std::map< uint8_t, uint16_t >::iterator it;
it = m_classMap.begin();
std::string classString;
for( ; it != m_classMap.end(); ++it )
{
std::string s = std::to_string( it->second );
classString += "\"" + s + "\"";
if( it != m_classMap.end() )
{
classString += ",";
}
}
return classString.substr( 0, classString.size() - 1 );
}
void PlayerMinimal::saveAsNew() void PlayerMinimal::saveAsNew()
{ {

View file

@ -2,18 +2,19 @@
#define _PLAYERMINIMAL_H #define _PLAYERMINIMAL_H
#include <map> #include <map>
#include <stdint.h> #include <cstdint>
#include <string.h> #include <string>
#include <cstring>
namespace Sapphire namespace Sapphire::Api
{ {
class PlayerMinimal class PlayerMinimal
{ {
public: public:
PlayerMinimal( void ); PlayerMinimal();
~PlayerMinimal( void ); ~PlayerMinimal() = default;
// write player to the database // write player to the database
void write(); void write();
@ -23,14 +24,8 @@ namespace Sapphire
void saveAsNew(); void saveAsNew();
std::string getLookString();
std::string getInfoJson(); std::string getInfoJson();
std::string getModelString();
std::string getClassString();
uint8_t getClassLevel(); uint8_t getClassLevel();
// return the id of the actor // return the id of the actor

View file

@ -1,4 +1,4 @@
#include "SapphireAPI.h" #include "SapphireApi.h"
#include <Crypt/base64.h> #include <Crypt/base64.h>
#include "Session.h" #include "Session.h"
#include "PlayerMinimal.h" #include "PlayerMinimal.h"
@ -10,7 +10,9 @@
#include <Database/DatabaseDef.h> #include <Database/DatabaseDef.h>
bool Sapphire::Network::SapphireAPI::login( const std::string& username, const std::string& pass, std::string& sId ) using namespace Sapphire::Api;
bool SapphireApi::login( const std::string& username, const std::string& pass, std::string& sId )
{ {
std::string query = std::string query =
"SELECT account_id FROM accounts WHERE account_name = '" + username + "' AND account_pass = '" + pass + "';"; "SELECT account_id FROM accounts WHERE account_name = '" + username + "' AND account_pass = '" + pass + "';";
@ -53,7 +55,7 @@ bool Sapphire::Network::SapphireAPI::login( const std::string& username, const s
} }
bool Sapphire::Network::SapphireAPI::insertSession( const uint32_t accountId, std::string& sId ) bool SapphireApi::insertSession( const uint32_t accountId, std::string& sId )
{ {
// create session for the new sessionid and store to sessionlist // create session for the new sessionid and store to sessionlist
auto pSession = std::make_shared< Session >(); auto pSession = std::make_shared< Session >();
@ -66,7 +68,7 @@ bool Sapphire::Network::SapphireAPI::insertSession( const uint32_t accountId, st
} }
bool Sapphire::Network::SapphireAPI::createAccount( const std::string& username, const std::string& pass, std::string& sId ) bool SapphireApi::createAccount( const std::string& username, const std::string& pass, std::string& sId )
{ {
// get account from login name // get account from login name
auto pQR = g_charaDb.query( "SELECT account_id FROM accounts WHERE account_name = '" + username + "';" ); auto pQR = g_charaDb.query( "SELECT account_id FROM accounts WHERE account_name = '" + username + "';" );
@ -96,11 +98,11 @@ bool Sapphire::Network::SapphireAPI::createAccount( const std::string& username,
} }
int Sapphire::Network::SapphireAPI::createCharacter( const uint32_t accountId, const std::string& name, int SapphireApi::createCharacter( const uint32_t accountId, const std::string& name,
const std::string& infoJson, const std::string& infoJson,
const uint32_t gmRank ) const uint32_t gmRank )
{ {
Sapphire::PlayerMinimal newPlayer; Api::PlayerMinimal newPlayer;
newPlayer.setAccountId( accountId ); newPlayer.setAccountId( accountId );
newPlayer.setId( getNextCharId() ); newPlayer.setId( getNextCharId() );
@ -169,7 +171,7 @@ int Sapphire::Network::SapphireAPI::createCharacter( const uint32_t accountId, c
return newPlayer.getAccountId(); return newPlayer.getAccountId();
} }
void Sapphire::Network::SapphireAPI::deleteCharacter( std::string name, const uint32_t accountId ) void SapphireApi::deleteCharacter( std::string name, const uint32_t accountId )
{ {
PlayerMinimal deletePlayer; PlayerMinimal deletePlayer;
auto charList = getCharList( accountId ); auto charList = getCharList( accountId );
@ -190,26 +192,28 @@ void Sapphire::Network::SapphireAPI::deleteCharacter( std::string name, const ui
g_charaDb.execute( "DELETE FROM characlass WHERE CharacterId LIKE '" + std::to_string( id ) + "';" ); g_charaDb.execute( "DELETE FROM characlass WHERE CharacterId LIKE '" + std::to_string( id ) + "';" );
g_charaDb.execute( "DELETE FROM charaglobalitem WHERE CharacterId LIKE '" + std::to_string( id ) + "';" ); g_charaDb.execute( "DELETE FROM charaglobalitem WHERE CharacterId LIKE '" + std::to_string( id ) + "';" );
g_charaDb.execute( "DELETE FROM charainfoblacklist WHERE CharacterId LIKE '" + std::to_string( id ) + "';" ); g_charaDb.execute( "DELETE FROM charainfoblacklist WHERE CharacterId LIKE '" + std::to_string( id ) + "';" );
g_charaDb.execute( "DELETE FROM charainfofriendlist WHERE CharacterId LIKE '" + std::to_string( id ) + "';" );
g_charaDb.execute( "DELETE FROM charainfolinkshell WHERE CharacterId LIKE '" + std::to_string( id ) + "';" ); g_charaDb.execute( "DELETE FROM charainfolinkshell WHERE CharacterId LIKE '" + std::to_string( id ) + "';" );
g_charaDb.execute( "DELETE FROM charainfosearch WHERE CharacterId LIKE '" + std::to_string( id ) + "';" ); g_charaDb.execute( "DELETE FROM charainfosearch WHERE CharacterId LIKE '" + std::to_string( id ) + "';" );
g_charaDb.execute( "DELETE FROM charaitemcrystal WHERE CharacterId LIKE '" + std::to_string( id ) + "';" ); g_charaDb.execute( "DELETE FROM charaitemcrystal WHERE CharacterId LIKE '" + std::to_string( id ) + "';" );
g_charaDb.execute( "DELETE FROM charaitemcurrency WHERE CharacterId LIKE '" + std::to_string( id ) + "';" );
g_charaDb.execute( "DELETE FROM charaiteminventory WHERE CharacterId LIKE '" + std::to_string( id ) + "';" ); g_charaDb.execute( "DELETE FROM charaiteminventory WHERE CharacterId LIKE '" + std::to_string( id ) + "';" );
g_charaDb.execute( "DELETE FROM charaitemgearset WHERE CharacterId LIKE '" + std::to_string( id ) + "';" ); g_charaDb.execute( "DELETE FROM charaitemgearset WHERE CharacterId LIKE '" + std::to_string( id ) + "';" );
g_charaDb.execute( "DELETE FROM charamonsternote WHERE CharacterId LIKE '" + std::to_string( id ) + "';" );
g_charaDb.execute( "DELETE FROM charaquest WHERE CharacterId LIKE '" + std::to_string( id ) + "';" ); g_charaDb.execute( "DELETE FROM charaquest WHERE CharacterId LIKE '" + std::to_string( id ) + "';" );
g_charaDb.execute( "DELETE FROM charastatus WHERE CharacterId LIKE '" + std::to_string( id ) + "';" );
} }
std::vector< Sapphire::PlayerMinimal > Sapphire::Network::SapphireAPI::getCharList( uint32_t accountId ) std::vector< PlayerMinimal > SapphireApi::getCharList( uint32_t accountId )
{ {
std::vector< Sapphire::PlayerMinimal > charList; std::vector< Api::PlayerMinimal > charList;
auto pQR = g_charaDb.query( auto pQR = g_charaDb.query(
"SELECT CharacterId, ContentId FROM charainfo WHERE AccountId = " + std::to_string( accountId ) + ";" ); "SELECT CharacterId, ContentId FROM charainfo WHERE AccountId = " + std::to_string( accountId ) + ";" );
while( pQR->next() ) while( pQR->next() )
{ {
Sapphire::PlayerMinimal player; Api::PlayerMinimal player;
uint32_t charId = pQR->getUInt( 1 ); uint32_t charId = pQR->getUInt( 1 );
@ -220,7 +224,7 @@ std::vector< Sapphire::PlayerMinimal > Sapphire::Network::SapphireAPI::getCharLi
return charList; return charList;
} }
bool Sapphire::Network::SapphireAPI::checkNameTaken( std::string name ) bool SapphireApi::checkNameTaken( std::string name )
{ {
g_charaDb.escapeString( name ); g_charaDb.escapeString( name );
@ -234,7 +238,7 @@ bool Sapphire::Network::SapphireAPI::checkNameTaken( std::string name )
return true; return true;
} }
uint32_t Sapphire::Network::SapphireAPI::getNextCharId() uint32_t SapphireApi::getNextCharId()
{ {
uint32_t charId = 0; uint32_t charId = 0;
@ -250,7 +254,7 @@ uint32_t Sapphire::Network::SapphireAPI::getNextCharId()
return charId; return charId;
} }
uint64_t Sapphire::Network::SapphireAPI::getNextContentId() uint64_t SapphireApi::getNextContentId()
{ {
uint64_t contentId = 0; uint64_t contentId = 0;
@ -266,7 +270,7 @@ uint64_t Sapphire::Network::SapphireAPI::getNextContentId()
return contentId; return contentId;
} }
int Sapphire::Network::SapphireAPI::checkSession( const std::string& sId ) int SapphireApi::checkSession( const std::string& sId )
{ {
auto it = m_sessionMap.find( sId ); auto it = m_sessionMap.find( sId );
@ -277,7 +281,7 @@ int Sapphire::Network::SapphireAPI::checkSession( const std::string& sId )
} }
bool Sapphire::Network::SapphireAPI::removeSession( const std::string& sId ) bool SapphireApi::removeSession( const std::string& sId )
{ {
auto it = m_sessionMap.find( sId ); auto it = m_sessionMap.find( sId );

View file

@ -7,19 +7,15 @@
#include <memory> #include <memory>
#include "PlayerMinimal.h" #include "PlayerMinimal.h"
namespace Sapphire namespace Sapphire::Api
{ {
class Session; class Session;
}
namespace Sapphire::Network class SapphireApi
{
class SapphireAPI
{ {
public: public:
SapphireAPI() = default; SapphireApi() = default;
~SapphireAPI() = default; ~SapphireApi() = default;
using SessionMap = std::map< std::string, std::shared_ptr< Session > >; using SessionMap = std::map< std::string, std::shared_ptr< Session > >;
@ -34,7 +30,7 @@ namespace Sapphire::Network
bool insertSession( uint32_t accountId, std::string& sId ); bool insertSession( uint32_t accountId, std::string& sId );
std::vector< Sapphire::PlayerMinimal > getCharList( uint32_t accountId ); std::vector< Api::PlayerMinimal > getCharList( uint32_t accountId );
bool checkNameTaken( std::string name ); bool checkNameTaken( std::string name );

View file

@ -1,6 +1,7 @@
#include "Session.h" #include "Session.h"
namespace Sapphire { using namespace Sapphire::Api;
Session::Session() Session::Session()
{ {
@ -35,4 +36,3 @@ void Session::setAccountId( uint32_t id )
{ {
m_accountId = id; m_accountId = id;
} }
}

View file

@ -5,7 +5,7 @@
#include <string> #include <string>
#include <string.h> #include <string.h>
namespace Sapphire namespace Sapphire::Api
{ {
class Session class Session

View file

@ -22,25 +22,23 @@
//Added for the default_resource example //Added for the default_resource example
#include <fstream> #include <fstream>
#include <string> #include <string>
#include <experimental/filesystem> #include <filesystem>
#include <vector> #include <vector>
#include <algorithm> #include <algorithm>
#include <Framework.h>
#include <Logging/Logger.h> #include <Logging/Logger.h>
#include "Forwards.h" #include "SapphireApi.h"
#include "SapphireAPI.h"
#include <Util/CrashHandler.h> #include <Util/CrashHandler.h>
Sapphire::Common::Util::CrashHandler crashHandler; [[maybe_unused]] Sapphire::Common::Util::CrashHandler crashHandler;
Sapphire::Db::DbWorkerPool< Sapphire::Db::ZoneDbConnection > g_charaDb; Sapphire::Db::DbWorkerPool< Sapphire::Db::ZoneDbConnection > g_charaDb;
Sapphire::Data::ExdDataGenerated g_exdDataGen; Sapphire::Data::ExdDataGenerated g_exdDataGen;
Sapphire::Network::SapphireAPI g_sapphireAPI; Sapphire::Api::SapphireApi g_sapphireAPI;
namespace fs = std::experimental::filesystem; namespace fs = std::filesystem;
using namespace std; using namespace std;
using namespace Sapphire; using namespace Sapphire;
@ -59,7 +57,7 @@ Sapphire::Common::Config::ApiConfig m_config;
void reloadConfig() void reloadConfig()
{ {
auto pConfig = std::make_shared< Sapphire::ConfigMgr >(); auto pConfig = std::make_shared< Sapphire::Common::ConfigMgr >();
Logger::info( "Loading config " + configPath ); Logger::info( "Loading config " + configPath );
@ -106,7 +104,7 @@ bool loadSettings( int32_t argc, char* argv[] )
try try
{ {
arg = Sapphire::Util::toLowerCopy( std::string( args[ i ] ) ); arg = Common::Util::toLowerCopy( std::string( args[ i ] ) );
val = std::string( args[ i + 1 ] ); val = std::string( args[ i + 1 ] );
// trim '-' from start of arg // trim '-' from start of arg
@ -336,7 +334,7 @@ void createCharacter( shared_ptr< HttpServer::Response > response, shared_ptr< H
std::string name = json["name"]; std::string name = json["name"];
std::string infoJson = json["infoJson"]; std::string infoJson = json["infoJson"];
std::string finalJson = Sapphire::Util::base64Decode( infoJson ); std::string finalJson = Common::Util::base64Decode( infoJson );
// reloadConfig(); // reloadConfig();
@ -672,8 +670,9 @@ void defaultGet( shared_ptr< HttpServer::Response > response, shared_ptr< HttpSe
print_request_info( request ); print_request_info( request );
try try
{ {
auto web_root_path = fs::canonical( "web" ); auto web_root_path = fs::current_path() / "web";
auto path = fs::canonical( web_root_path / request->path ); auto path = web_root_path / request->path;
//Check if path is within web_root_path //Check if path is within web_root_path
if( distance( web_root_path.begin(), web_root_path.end() ) > distance( path.begin(), path.end() ) || if( distance( web_root_path.begin(), web_root_path.end() ) > distance( path.begin(), path.end() ) ||
!std::equal( web_root_path.begin(), web_root_path.end(), path.begin() ) ) !std::equal( web_root_path.begin(), web_root_path.end(), path.begin() ) )
@ -700,7 +699,7 @@ void defaultGet( shared_ptr< HttpServer::Response > response, shared_ptr< HttpSe
catch( const exception& ) catch( const exception& )
{ {
string content = "Path not found: " + request->path; string content = "Path not found: " + request->path;
*response << buildHttpResponse( 400, content ); *response << buildHttpResponse( 404, content );
} }
} }
@ -719,19 +718,19 @@ int main( int argc, char* argv[] )
Logger::setLogLevel( m_config.global.general.logLevel ); Logger::setLogLevel( m_config.global.general.logLevel );
server.resource[ "^/ZoneName/([0-9]+)$" ][ "GET" ] = &getZoneName; server.resource[ "^ZoneName/([0-9]+)$" ][ "GET" ] = &getZoneName;
server.resource[ "^/sapphire-api/lobby/createAccount" ][ "POST" ] = &createAccount; server.resource[ "^sapphire-api/lobby/createAccount" ][ "POST" ] = &createAccount;
server.resource[ "^/sapphire-api/lobby/login" ][ "POST" ] = &login; server.resource[ "^sapphire-api/lobby/login" ][ "POST" ] = &login;
server.resource[ "^/sapphire-api/lobby/deleteCharacter" ][ "POST" ] = &deleteCharacter; server.resource[ "^sapphire-api/lobby/deleteCharacter" ][ "POST" ] = &deleteCharacter;
server.resource[ "^/sapphire-api/lobby/createCharacter" ][ "POST" ] = &createCharacter; server.resource[ "^sapphire-api/lobby/createCharacter" ][ "POST" ] = &createCharacter;
server.resource[ "^/sapphire-api/lobby/insertSession" ][ "POST" ] = &insertSession; server.resource[ "^sapphire-api/lobby/insertSession" ][ "POST" ] = &insertSession;
server.resource[ "^/sapphire-api/lobby/checkNameTaken" ][ "POST" ] = &checkNameTaken; server.resource[ "^sapphire-api/lobby/checkNameTaken" ][ "POST" ] = &checkNameTaken;
server.resource[ "^/sapphire-api/lobby/checkSession" ][ "POST" ] = &checkSession; server.resource[ "^sapphire-api/lobby/checkSession" ][ "POST" ] = &checkSession;
server.resource[ "^/sapphire-api/lobby/getNextCharId" ][ "POST" ] = &getNextCharId; server.resource[ "^sapphire-api/lobby/getNextCharId" ][ "POST" ] = &getNextCharId;
server.resource[ "^/sapphire-api/lobby/getNextContentId" ][ "POST" ] = &getNextContentId; server.resource[ "^sapphire-api/lobby/getNextContentId" ][ "POST" ] = &getNextContentId;
server.resource[ "^/sapphire-api/lobby/getCharacterList" ][ "POST" ] = &getCharacterList; server.resource[ "^sapphire-api/lobby/getCharacterList" ][ "POST" ] = &getCharacterList;
server.resource[ "^(/frontier-api/ffxivsupport/view/get_init)(.*)" ][ "GET" ] = &get_init; server.resource[ "^(frontier-api/ffxivsupport/view/get_init)(.*)" ][ "GET" ] = &get_init;
server.resource[ "^(/frontier-api/ffxivsupport/information/get_headline_all)(.*)" ][ "GET" ] = &get_headline_all; server.resource[ "^(frontier-api/ffxivsupport/information/get_headline_all)(.*)" ][ "GET" ] = &get_headline_all;
server.default_resource[ "GET" ] = &defaultGet; server.default_resource[ "GET" ] = &defaultGet;

View file

@ -18,7 +18,7 @@
class case_insensitive_equals { class case_insensitive_equals {
public: public:
bool operator()(const std::string &key1, const std::string &key2) const { bool operator()(const std::string &key1, const std::string &key2) const {
return Sapphire::Util::toLowerCopy( key1 ) == Sapphire::Util::toLowerCopy( key2 ); return Sapphire::Common::Util::toLowerCopy( key1 ) == Sapphire::Common::Util::toLowerCopy( key2 );
} }
}; };
class case_insensitive_hash { class case_insensitive_hash {
@ -27,7 +27,7 @@ public:
{ {
std::size_t seed=0; std::size_t seed=0;
for( auto &c : key ) for( auto &c : key )
Sapphire::Util::hashCombine< char >( seed, std::tolower( c ) ); Sapphire::Common::Util::hashCombine< char >( seed, std::tolower( c ) );
return seed; return seed;
} }
}; };
@ -304,7 +304,7 @@ namespace SimpleWeb {
size_t path_end; size_t path_end;
if((path_end=line.find(' ', method_end+1))!=std::string::npos) { if((path_end=line.find(' ', method_end+1))!=std::string::npos) {
request->method=line.substr(0, method_end); request->method=line.substr(0, method_end);
request->path=line.substr(method_end+1, path_end-method_end-1); request->path=line.substr(method_end+2, path_end-method_end-2);
size_t protocol_end; size_t protocol_end;
if((protocol_end=line.find('/', path_end+1))!=std::string::npos) { if((protocol_end=line.find('/', path_end+1))!=std::string::npos) {
@ -388,7 +388,7 @@ namespace SimpleWeb {
auto range=request->header.equal_range("Connection"); auto range=request->header.equal_range("Connection");
for(auto it=range.first;it!=range.second;it++) { for(auto it=range.first;it!=range.second;it++) {
if( Sapphire::Util::toLowerCopy( it->second ) == "close" ) if( Sapphire::Common::Util::toLowerCopy( it->second ) == "close" )
return; return;
} }
if(http_version>1.05) if(http_version>1.05)

View file

@ -26,10 +26,6 @@ if( UNIX )
PUBLIC PUBLIC
pthread pthread
stdc++fs ) stdc++fs )
else()
target_link_libraries( common
PUBLIC
stackwalker )
endif() endif()
target_include_directories( common target_include_directories( common

View file

@ -21,6 +21,14 @@ namespace Sapphire::Common
const int32_t INVALID_GAME_OBJECT_ID = 0xE0000000; const int32_t INVALID_GAME_OBJECT_ID = 0xE0000000;
const uint64_t INVALID_GAME_OBJECT_ID64 = 0xE0000000; const uint64_t INVALID_GAME_OBJECT_ID64 = 0xE0000000;
const uint16_t MAX_PLAYER_LEVEL = 80;
const uint8_t CURRENT_EXPANSION_ID = 3;
const uint8_t CLASSJOB_TOTAL = 38;
const uint8_t CLASSJOB_SLOTS = 28;
const uint8_t TOWN_COUNT = 6;
/*! /*!
* @brief The maximum length (in ms) of a combo before it is canceled/voided. * @brief The maximum length (in ms) of a combo before it is canceled/voided.
* *
@ -41,13 +49,13 @@ namespace Sapphire::Common
uint8_t plot; uint8_t plot;
}; };
enum InventoryOperation : uint8_t enum InventoryOperation : uint16_t
{ {
Discard = 0x07, Discard = 0x013C,
Move = 0x08, Move = 0x013D,
Swap = 0x09, Swap = 0x013E,
Merge = 0x0C, Split = 0x013F,
Split = 0x0A Merge = 0x0141,
}; };
enum ClientLanguage : uint8_t enum ClientLanguage : uint8_t
@ -151,44 +159,46 @@ namespace Sapphire::Common
ModelRing2 = 9 ModelRing2 = 9
}; };
enum EquipSlotCategory : uint8_t enum class EquipSlotCategory : uint8_t
{ {
Unequippable = 0,
// main slots // main slots
CharaMainHand = 1, CharaMainHand = 0,
CharaOffHand = 2, CharaOffHand = 1,
CharaHead = 3, CharaHead = 2,
CharaBody = 4, CharaBody = 3,
CharaHands = 5, CharaHands = 4,
CharaWaist = 6, CharaWaist = 5,
CharaLegs = 7, CharaLegs = 6,
CharaFeet = 8, CharaFeet = 7,
CharaEars = 9, CharaEars = 8,
CharaNeck = 10, CharaNeck = 9,
CharaWrist = 11, CharaWrist = 10,
CharaRing = 12, CharaRing = 11,
CharaSoulCrystal = 17, CharaSoulCrystal = 12,
// specials
/* following slots not seem to exist any more.
when multi-slot gear is moved into equipment slot, normal slot listed above is used.
client will move any incompatible gears into armory but no InventoryModifiyHandler is sent.
server need to move those silently in order to sync with client.
*/
/*! Cannot equip gear to offhand slot */ /*! Cannot equip gear to offhand slot */
MainTwoHandedWeapon = 13, //MainTwoHandedWeapon = 13,
/*! Can be equipped in either main or offhand slot */ /*! Can be equipped in either main or offhand slot */
MainOrOffHand = 14, // unused //MainOrOffHand = 14, // unused
/*! Cannot equip gear to head */ /*! Cannot equip gear to head */
BodyDisallowHead = 15, //BodyDisallowHead = 15,
/*! Cannot equip gear to hands, legs and feet slots */ /*! Cannot equip gear to hands, legs and feet slots */
BodyDisallowHandsLegsFeet = 16, //BodyDisallowHandsLegsFeet = 16,
/*! Cannot equip gear to feet slot */ /*! Cannot equip gear to feet slot */
LegsDisallowFeet = 18, //LegsDisallowFeet = 18,
/*! Cannot equp gear to head, hands, legs, feet slots */ /*! Cannot equp gear to head, hands, legs, feet slots */
BodyDisallowAll = 19, //BodyDisallowAll = 19,
/*! Cannot equip gear to hands slot */ /*! Cannot equip gear to hands slot */
BodyDisallowHands = 20, //BodyDisallowHands = 20,
/*! Cannot equip gear to legs & feet slots */ /*! Cannot equip gear to legs & feet slots */
BodyDisallowLegsFeet = 21, //BodyDisallowLegsFeet = 21,
}; };
enum InventoryType : uint16_t enum InventoryType : uint16_t
@ -204,10 +214,12 @@ namespace Sapphire::Common
Currency = 2000, Currency = 2000,
Crystal = 2001, Crystal = 2001,
//UNKNOWN_0 = 2003, //UNKNOWN_0 = 2003,
KeyItem = 2004, KeyItem = 2004,
HandIn = 2005, HandIn = 2005,
DamagedGear = 2007, DamagedGear = 2007,
//UNKNOWN_1 = 2008, //UNKNOWN_1 = 2008,
// Temporary inventory that is used for the "trade" window
TradeInventory = 2009,
ArmoryOff = 3200, ArmoryOff = 3200,
ArmoryHead = 3201, ArmoryHead = 3201,
@ -216,13 +228,19 @@ namespace Sapphire::Common
ArmoryWaist = 3204, ArmoryWaist = 3204,
ArmoryLegs = 3205, ArmoryLegs = 3205,
ArmoryFeet = 3206, ArmoryFeet = 3206,
ArmoryNeck = 3207, ArmoryEar = 3207,
ArmoryEar = 3208, ArmoryNeck = 3208,
ArmoryWrist = 3209, ArmoryWrist = 3209,
ArmoryRing = 3300, ArmoryRing = 3300,
ArmorySoulCrystal = 3400, ArmorySoulCrystal = 3400,
ArmoryMain = 3500, ArmoryMain = 3500,
SaddleBag0 = 4000,
SaddleBag1 = 4001,
// These are the ones you get when paying for premium companion app
PremiumSaddleBag0 = 4100,
PremiumSaddleBag1 = 4101,
RetainerBag0 = 10000, RetainerBag0 = 10000,
RetainerBag1 = 10001, RetainerBag1 = 10001,
@ -396,7 +414,7 @@ namespace Sapphire::Common
struct StatusEffect struct StatusEffect
{ {
uint16_t effect_id; uint16_t effect_id;
uint16_t unknown1; uint16_t param;
float duration; float duration;
uint32_t sourceActorId; uint32_t sourceActorId;
}; };
@ -548,6 +566,30 @@ namespace Sapphire::Common
}; };
enum FieldMarkerStatus : uint32_t
{
A = 0x1,
B = 0x2,
C = 0x4,
D = 0x8,
One = 0x10,
Two = 0x20,
Three = 0x40,
Four = 0x80
};
// TODO: consolidate these two into one since FieldMarkerStatus == 1 << FieldMarkerId?
enum class FieldMarkerId : uint8_t
{
A,
B,
C,
D,
One,
Two,
Three,
Four
};
enum struct ActionAspect : uint8_t enum struct ActionAspect : uint8_t
{ {
None = 0, // Doesn't imply unaspected None = 0, // Doesn't imply unaspected
@ -565,19 +607,27 @@ namespace Sapphire::Common
None = 0, // ? None = 0, // ?
MagicPoints = 3, MagicPoints = 3,
TacticsPoints = 5, TacticsPoints = 5,
// WARGauge = 22, StatusEffect = 10,
// DRKGauge = 25, WARGauge = 22,
// AetherflowStack = 30, DRKGauge = 25,
// Status = 32, // AetherflowStack = 30,
// PLDGauge = 41, // Status = 32,
// RDMGaugeBoth = 74, SAMKenki = 39,
//// RDMGaugeBlack = 75, // not right? SAMSen = 40,
// DRGGauge3Eyes = 76, PLDGauge = 41,
GNBAmmo = 55,
WHMBloodLily = 56,
WHMLily = 57,
SAMMeditation = 63,
// RDMGaugeBoth = 74,
//// RDMGaugeBlack = 75, // not right?
// DRGGauge3Eyes = 76,
}; };
enum class ActionType : int8_t enum class AttackType : int8_t
{ {
WeaponOverride = -1, // Needs more investigation (takes the damage type of the equipped weapon)? //WeaponOverride = -1, // Needs more investigation (takes the damage type of the equipped weapon)?
Physical = -1, // seems to be the case
Unknown_0 = 0, Unknown_0 = 0,
Slashing = 1, Slashing = 1,
Piercing = 2, Piercing = 2,
@ -606,28 +656,41 @@ namespace Sapphire::Common
TpLoss = 12, TpLoss = 12,
TpGain = 13, TpGain = 13,
GpGain = 14, GpGain = 14,
ApplyStatusEffectTarget = 15,
ApplyStatusEffectSource = 16, // effect entry on target but buff applies to source, like storm's eye
StatusNoEffect = 20, // shifted one up from 5.18
/*! /*!
* @brief Tells the client that it should show combo indicators on actions. * @brief Tells the client that it should show combo indicators on actions.
* *
* @param flags Required to be 128, doesn't show combo rings on hotbars otherwise * @param flags Required to be 128, doesn't show combo rings on hotbars otherwise
* @param value The actionid that starts/continues the combo. eg, 3617 will start a spinning slash and/or syphon strike combo * @param value The actionid that starts/continues the combo. eg, 3617 will start a spinning slash and/or syphon strike combo
*/ */
StartActionCombo = 28, StartActionCombo = 27, // shifted one up from 5.18
ComboSucceed = 28, // shifted one up from 5.18, on retail this is not seen anymore, still working though.
Knockback = 33, Knockback = 33,
Mount = 38, Mount = 40, // shifted one down from 5.18
VFX = 59, // links to VFX sheet VFX = 59, // links to VFX sheet
}; };
enum class ActionHitSeverityType : uint8_t enum class ActionHitSeverityType : uint8_t
{ {
NormalDamage = 0, NormalDamage = 0,
CritHeal = 0, NormalHeal = 0,
CritDamage = 1, CritDamage = 1,
NormalHeal = 1, CritHeal = 1,
DirectHitDamage = 2, DirectHitDamage = 2,
CritDirectHitDamage = 3 CritDirectHitDamage = 3
}; };
enum class ActionEffectResultFlag : uint8_t
{
None = 0,
Absorbed = 0x04,
ExtendedValue = 0x40,
EffectOnSource = 0x80,
Reflected = 0xA0,
};
enum ItemActionType : uint16_t enum ItemActionType : uint16_t
{ {
ItemActionVFX = 852, ItemActionVFX = 852,
@ -644,15 +707,15 @@ namespace Sapphire::Common
struct EffectEntry struct EffectEntry
{ {
Common::ActionEffectType effectType; Common::ActionEffectType effectType;
Common::ActionHitSeverityType hitSeverity; uint8_t param0;
uint8_t param; uint8_t param1;
/*! /*!
* @brief Shows an additional percentage in the battle log * @brief Shows an additional percentage in the battle log
* *
* Has no effect on what is shown and stored in value * Has no effect on what is shown and stored in value
*/ */
int8_t bonusPercent; uint8_t param2;
uint8_t valueMultiplier; // This multiplies whatever value is in the 'value' param by 10. Possibly a workaround for big numbers uint8_t extendedValueHighestByte;
uint8_t flags; uint8_t flags;
int16_t value; int16_t value;
}; };
@ -968,8 +1031,6 @@ namespace Sapphire::Common
enum LevelTableEntry : uint8_t enum LevelTableEntry : uint8_t
{ {
PIE,
MP,
MAIN, MAIN,
SUB, SUB,
DIV, DIV,
@ -982,7 +1043,225 @@ namespace Sapphire::Common
{ {
SingleTarget = 1, SingleTarget = 1,
CircularAOE = 2, CircularAOE = 2,
Type3 = 3, // another single target? no idea how to call it
RectangularAOE = 4, RectangularAOE = 4,
CircularAoEPlaced = 7
};
enum class Role : uint8_t
{
None,
Tank,
Healer,
RangedPhysical,
RangedMagical,
Melee,
Crafter,
Gatherer
};
enum class AstCardType : uint8_t
{
None = 0,
Balance = 1,
Bole = 2,
Arrow = 3,
Spear = 4,
Ewer = 5,
Spire = 6,
Lord = 0x70,
Lady = 0x80,
};
enum class AstSealType : uint8_t
{
None = 0,
Sun = 1,
Moon = 2,
Celestrial = 3,
};
enum class DrgState : uint8_t
{
None = 0,
BloodOfTheDragon = 1,
LifeOfTheDragon = 2,
};
enum class SamSen : uint8_t
{
None = 0,
Setsu = 1,
Getsu = 2,
Ka = 4,
};
enum class SchDismissedFairy : uint8_t
{
None = 0,
Eos = 6,
Selene = 7,
};
enum class SmnPet : uint8_t
{
None = 0,
Ifrit = 3,
Titan = 4,
Garuda = 5,
};
enum class SmnPetGlam : uint8_t
{
None = 0,
Emerald = 1,
Topaz = 2,
Ruby = 3,
};
enum class BrdSong : uint8_t
{
Mage = 5,
Army = 0x0A,
Wanderer = 0x0F,
};
union JobGauge
{
struct
{
uint8_t gauge_data[15];
} _raw;
struct
{
uint32_t unused;
AstCardType card;
AstSealType seals[3];
} ast;
struct
{
uint16_t timeUntilNextPolyglot;
uint16_t elementTimer;
uint8_t elementStance;
uint8_t umbralhearts;
uint8_t polyglotStacks;
uint8_t enochainState;
} blm;
struct
{
uint16_t songTimer;
uint8_t songStacks;
uint8_t unused;
BrdSong song;
} brd;
struct
{
uint8_t feathers;
uint8_t esprit;
uint8_t stepOrder[4];
uint8_t completeSteps;
} dnc;
struct
{
uint16_t dragonTimer;
DrgState dragonState;
uint8_t eyes;
} drg;
struct
{
uint8_t blood;
uint8_t unused;
uint16_t darksideTimer;
uint8_t darkArts;
uint8_t unused2;
uint16_t shadowTimer;
} drk;
struct
{
uint8_t ammo;
uint8_t unused;
uint16_t maxTimerDuration;
uint8_t ammoComboStep;
} gnb;
struct
{
uint16_t overheatTimer;
uint16_t robotTimer;
uint8_t heat;
uint8_t battery;
uint8_t lastRobotBatteryPower;
uint8_t activeTimerFlag;
} mch;
struct
{
uint8_t greasedLightningTimer;
uint8_t unused;
uint8_t greasedLightningStacks;
uint8_t chakra;
uint8_t greasedLightningTimerFreezed;
} mnk;
struct
{
uint32_t hutonTimer;
uint8_t tenChiJinMudrasUsed;
uint8_t ninki;
uint8_t hutonManualCasts;
} nin;
struct
{
uint8_t oathGauge;
} pld;
struct
{
uint8_t whiteGauge;
uint8_t blackGauge;
} rdm;
struct
{
uint16_t unused;
uint8_t unused2;
uint8_t kenki;
uint8_t meditationStacks;
SamSen sen;
} sam;
struct
{
uint16_t unused;
uint8_t aetherflowStacks;
uint8_t fairyGauge;
uint16_t seraphTimer;
SchDismissedFairy dismissedFairy;
} sch;
struct
{
uint16_t timer;
SmnPet returnSummon;
SmnPetGlam petGlam;
uint8_t stacks;
} smn;
struct
{
uint8_t beastGauge;
} war;
struct
{
uint16_t unused;
uint16_t lilyTimer;
uint8_t lilies;
uint8_t bloodLilies;
} whm;
};
enum class LootMessageType : uint8_t
{
GetItem1 = 1, // p1: actorId, p4: itemId (HQ: itemId + 1,000,000 lol), p5: amount
GetItem2 = 3, // p1: actorId, p2: itemId, p3: amount, seems like same thing as GetItem1 but different param position.
FailedToGetLootNoFreeInventorySlot = 5, // p1: actorId
LootRolled = 7, // p1: actorId, p2: itemId, p3: amount
GetGil = 9, // p1: gil
EmptyCoffer = 11, // seems like no param
}; };
using PlayerStateFlagList = std::vector< PlayerStateFlag >; using PlayerStateFlagList = std::vector< PlayerStateFlag >;

View file

@ -6,8 +6,7 @@
/* This file has been automatically generated. /* This file has been automatically generated.
Changes will be lost upon regeneration. Changes will be lost upon regeneration.
To change the content edit tools/exd_common_gen */ To change the content edit tools/exd_common_gen */
namespace Sapphire { namespace Sapphire::Common {
namespace Common {
/////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////
//ActionCategory.exd //ActionCategory.exd
@ -173,6 +172,8 @@ enum class ClassJob : uint8_t
Samurai = 34, Samurai = 34,
Redmage = 35, Redmage = 35,
Bluemage = 36, Bluemage = 36,
Gunbreaker = 37,
Dancer = 38,
}; };
/////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////
@ -199,14 +200,10 @@ enum class ContentType : uint8_t
DisciplesoftheHand = 17, DisciplesoftheHand = 17,
RetainerVentures = 18, RetainerVentures = 18,
GoldSaucer = 19, GoldSaucer = 19,
one = 20,
DeepDungeons = 21, DeepDungeons = 21,
two = 22,
three = 23,
WondrousTails = 24, WondrousTails = 24,
CustomDeliveries = 25, CustomDeliveries = 25,
Eureka = 26, Eureka = 26,
four = 27,
}; };
/////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////
@ -217,7 +214,6 @@ enum class EmoteCategory : uint8_t
General = 1, General = 1,
Special = 2, Special = 2,
Expressions = 3, Expressions = 3,
one = 4,
}; };
/////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////
@ -227,7 +223,7 @@ enum class ExVersion : uint8_t
ARealmReborn = 0, ARealmReborn = 0,
Heavensward = 1, Heavensward = 1,
Stormblood = 2, Stormblood = 2,
three = 3, Shadowbringers = 3,
}; };
/////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////
@ -369,6 +365,8 @@ enum class ItemUICategory : uint8_t
SubmersibleBow = 103, SubmersibleBow = 103,
SubmersibleBridge = 104, SubmersibleBridge = 104,
BlueMagesArm = 105, BlueMagesArm = 105,
GunbreakersArm = 106,
DancersArm = 107,
}; };
/////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////
@ -393,7 +391,7 @@ enum class ItemSearchCategory : uint8_t
ConjurersArms = 15, ConjurersArms = 15,
ArcanistsArms = 16, ArcanistsArms = 16,
Shields = 17, Shields = 17,
ThrowingWeapons = 18, DancersArms = 18,
CarpentersTools = 19, CarpentersTools = 19,
BlacksmithsTools = 20, BlacksmithsTools = 20,
ArmorersTools = 21, ArmorersTools = 21,
@ -454,13 +452,15 @@ enum class ItemSearchCategory : uint8_t
DarkKnightsArms = 76, DarkKnightsArms = 76,
MachinistsArms = 77, MachinistsArms = 77,
AstrologiansArms = 78, AstrologiansArms = 78,
Airship_SubmersibleComponents = 79, AirshipSubmersibleComponents = 79,
OrchestrionComponents = 80, OrchestrionComponents = 80,
GardeningItems = 81, GardeningItems = 81,
Paintings = 82, Paintings = 82,
SamuraisArms = 83, SamuraisArms = 83,
RedMagesArms = 84, RedMagesArms = 84,
ScholarsArms = 85, ScholarsArms = 85,
GunbreakersArms = 86,
ThrowingWeapons = 87,
}; };
/////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////
@ -527,6 +527,8 @@ enum class Race : uint8_t
Miqote = 4, Miqote = 4,
Roegadyn = 5, Roegadyn = 5,
AuRa = 6, AuRa = 6,
Hrothgar = 7,
Viera = 8,
}; };
/////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////
@ -546,6 +548,10 @@ enum class Tribe : uint8_t
Hellsguard = 10, Hellsguard = 10,
Raen = 11, Raen = 11,
Xaela = 12, Xaela = 12,
Helions = 13,
TheLost = 14,
Rava = 15,
Veena = 16,
}; };
/////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////
@ -558,6 +564,7 @@ enum class Town : uint8_t
Uldah = 3, Uldah = 3,
Ishgard = 4, Ishgard = 4,
Kugane = 7, Kugane = 7,
TheCrystarium = 10,
}; };
/////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////
@ -680,7 +687,21 @@ enum class Weather : uint8_t
TrueBlue = 113, TrueBlue = 113,
TrueBlue1 = 114, TrueBlue1 = 114,
TrueBlue2 = 115, TrueBlue2 = 115,
UmbralTurbulence = 116,
TrueBlue3 = 117, TrueBlue3 = 117,
EverlastingLight = 118,
Gales2 = 119,
Termination = 120,
Termination1 = 121,
Dreams = 122,
Dreams1 = 123,
Dreams2 = 124,
Brilliance = 125,
Brilliance1 = 126,
Termination2 = 127,
Termination3 = 128,
EverlastingLight1 = 129,
Termination4 = 131,
}; };
/////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////
@ -703,8 +724,12 @@ enum class HousingAppeal : uint8_t
Library = 14, Library = 14,
PhotoStudio = 15, PhotoStudio = 15,
HauntedHouse = 16, HauntedHouse = 16,
Atelier = 17,
Bathhouse = 18,
Garden = 19,
FarEastern = 20,
}; };
}
} }
#endif #endif

View file

@ -1,16 +1,18 @@
#include "ConfigMgr.h" #include "ConfigMgr.h"
#include <iostream> #include <iostream>
#include <fstream> #include <filesystem>
#include <experimental/filesystem>
namespace fs = std::experimental::filesystem; namespace fs = std::filesystem;
using namespace Sapphire;
using namespace Sapphire::Common;
/** /**
* Loads an ini file and parses it * Loads an ini file and parses it
* @param configName the name of ini file relative to m_configFolderRoot to load alongside global.ini * @param configName the name of ini file relative to m_configFolderRoot to load alongside global.ini
* @return true if loading was successful * @return true if loading was successful
*/ */
bool Sapphire::ConfigMgr::loadConfig( const std::string& configName ) bool ConfigMgr::loadConfig( const std::string& configName )
{ {
// get global config // get global config
auto configFile = fs::path( fs::path( m_configFolderRoot ) / configName ); auto configFile = fs::path( fs::path( m_configFolderRoot ) / configName );
@ -29,7 +31,7 @@ bool Sapphire::ConfigMgr::loadConfig( const std::string& configName )
return true; return true;
} }
bool Sapphire::ConfigMgr::loadGlobalConfig( Common::Config::GlobalConfig& config, const std::string& configName ) bool ConfigMgr::loadGlobalConfig( Common::Config::GlobalConfig& config, const std::string& configName )
{ {
auto configFile = fs::path( fs::path( m_configFolderRoot ) / configName ); auto configFile = fs::path( fs::path( m_configFolderRoot ) / configName );
@ -71,7 +73,7 @@ bool Sapphire::ConfigMgr::loadGlobalConfig( Common::Config::GlobalConfig& config
return true; return true;
} }
bool Sapphire::ConfigMgr::copyDefaultConfig( const std::string& configName ) bool ConfigMgr::copyDefaultConfig( const std::string& configName )
{ {
fs::path configPath( m_configFolderRoot ); fs::path configPath( m_configFolderRoot );
configPath /= configName; configPath /= configName;

View file

@ -8,7 +8,7 @@
#include <stdint.h> #include <stdint.h>
#include "ConfigDef.h" #include "ConfigDef.h"
namespace Sapphire namespace Sapphire::Common
{ {
class ConfigMgr class ConfigMgr
{ {

View file

@ -41,7 +41,7 @@ static inline bool is_base64( uint8_t c )
return ( isalnum( c ) || ( c == '+' ) || ( c == '/' ) ); return ( isalnum( c ) || ( c == '+' ) || ( c == '/' ) );
} }
std::string Sapphire::Util::base64Encode( uint8_t const* bytes_to_encode, uint32_t in_len ) std::string Sapphire::Common::Util::base64Encode( uint8_t const* bytes_to_encode, uint32_t in_len )
{ {
std::string ret; std::string ret;
int32_t i = 0; int32_t i = 0;
@ -87,7 +87,7 @@ std::string Sapphire::Util::base64Encode( uint8_t const* bytes_to_encode, uint32
} }
std::string Sapphire::Util::base64Decode( std::string const& encoded_string ) std::string Sapphire::Common::Util::base64Decode( std::string const& encoded_string )
{ {
int32_t in_len = encoded_string.size(); int32_t in_len = encoded_string.size();
int32_t i = 0; int32_t i = 0;

View file

@ -1,6 +1,6 @@
#include <string> #include <string>
namespace Sapphire::Util namespace Sapphire::Common::Util
{ {
std::string base64Encode( uint8_t const*, uint32_t len ); std::string base64Encode( uint8_t const*, uint32_t len );

View file

@ -37,7 +37,7 @@
(b)[(i) + 3] = (uint8_t) ( (n) >> 24 ); \ (b)[(i) + 3] = (uint8_t) ( (n) >> 24 ); \
} }
void Sapphire::Util::md5_starts( md5_context* ctx ) void Sapphire::Common::Util::md5_starts( md5_context* ctx )
{ {
ctx->total[ 0 ] = 0; ctx->total[ 0 ] = 0;
ctx->total[ 1 ] = 0; ctx->total[ 1 ] = 0;
@ -48,7 +48,7 @@ void Sapphire::Util::md5_starts( md5_context* ctx )
ctx->state[ 3 ] = 0x10325476; ctx->state[ 3 ] = 0x10325476;
} }
void md5_process( Sapphire::Util::md5_context* ctx, uint8_t data[64] ) void md5_process( Sapphire::Common::Util::md5_context* ctx, uint8_t data[64] )
{ {
uint32_t X[16], A, B, C, D; uint32_t X[16], A, B, C, D;
@ -171,7 +171,7 @@ void md5_process( Sapphire::Util::md5_context* ctx, uint8_t data[64] )
ctx->state[ 3 ] += D; ctx->state[ 3 ] += D;
} }
void Sapphire::Util::md5_update( md5_context* ctx, uint8_t* input, uint32_t length ) void Sapphire::Common::Util::md5_update( md5_context* ctx, uint8_t* input, uint32_t length )
{ {
uint32_t left, fill; uint32_t left, fill;
@ -219,7 +219,7 @@ static uint8_t md5_padding[64] =
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
}; };
void Sapphire::Util::md5_finish( md5_context* ctx, uint8_t digest[16] ) void Sapphire::Common::Util::md5_finish( md5_context* ctx, uint8_t digest[16] )
{ {
uint32_t last, padn; uint32_t last, padn;
uint32_t high, low; uint32_t high, low;
@ -248,7 +248,7 @@ void Sapphire::Util::md5_finish( md5_context* ctx, uint8_t digest[16] )
* those are the standard RFC 1321 test vectors * those are the standard RFC 1321 test vectors
*/ */
void Sapphire::Util::md5( uint8_t* text, uint8_t* hash, int32_t size ) void Sapphire::Common::Util::md5( uint8_t* text, uint8_t* hash, int32_t size )
{ {
md5_context ctx; md5_context ctx;
md5_starts( &ctx ); md5_starts( &ctx );

View file

@ -3,7 +3,7 @@
#include <stdint.h> #include <stdint.h>
namespace Sapphire::Util namespace Sapphire::Common::Util
{ {
using md5_context = struct using md5_context = struct
{ {

View file

@ -1,6 +1,8 @@
#ifndef SAPPHIRE_DBCOMMON_H #ifndef SAPPHIRE_DBCOMMON_H
#define SAPPHIRE_DBCOMMON_H #define SAPPHIRE_DBCOMMON_H
#include <string>
namespace Sapphire::Db namespace Sapphire::Db
{ {
struct ConnectionInfo struct ConnectionInfo

View file

@ -4,7 +4,6 @@
#include "Logging/Logger.h" #include "Logging/Logger.h"
#include "PreparedStatement.h" #include "PreparedStatement.h"
#include "Framework.h"
Sapphire::Db::DbConnection::DbConnection( ConnectionInfo& connInfo ) : Sapphire::Db::DbConnection::DbConnection( ConnectionInfo& connInfo ) :
m_reconnecting( false ), m_reconnecting( false ),
@ -17,7 +16,7 @@ Sapphire::Db::DbConnection::DbConnection( ConnectionInfo& connInfo ) :
} }
Sapphire::Db::DbConnection::DbConnection( Sapphire::LockedWaitQueue< std::shared_ptr< Operation > >* queue, Sapphire::Db::DbConnection::DbConnection( Common::Util::LockedWaitQueue< std::shared_ptr< Operation > >* queue,
Sapphire::Db::ConnectionInfo& connInfo ) : Sapphire::Db::ConnectionInfo& connInfo ) :
m_reconnecting( false ), m_reconnecting( false ),
m_prepareError( false ), m_prepareError( false ),

View file

@ -42,7 +42,7 @@ namespace Sapphire::Db
DbConnection( ConnectionInfo& connInfo ); DbConnection( ConnectionInfo& connInfo );
// Constructor for asynchronous connections. // Constructor for asynchronous connections.
DbConnection( Sapphire::LockedWaitQueue< std::shared_ptr< Operation > >* queue, ConnectionInfo& connInfo ); DbConnection( Common::Util::LockedWaitQueue< std::shared_ptr< Operation > >* queue, ConnectionInfo& connInfo );
virtual ~DbConnection(); virtual ~DbConnection();
@ -92,7 +92,7 @@ namespace Sapphire::Db
bool m_prepareError; bool m_prepareError;
private: private:
LockedWaitQueue< std::shared_ptr< Operation > >* m_queue; Common::Util::LockedWaitQueue< std::shared_ptr< Operation > >* m_queue;
std::shared_ptr< DbWorker > m_worker; std::shared_ptr< DbWorker > m_worker;
std::shared_ptr< Mysql::Connection > m_pConnection; std::shared_ptr< Mysql::Connection > m_pConnection;
ConnectionInfo& m_connectionInfo; ConnectionInfo& m_connectionInfo;

View file

@ -2,7 +2,9 @@
#include "Operation.h" #include "Operation.h"
#include "Util/LockedWaitQueue.h" #include "Util/LockedWaitQueue.h"
Sapphire::Db::DbWorker::DbWorker( Sapphire::LockedWaitQueue< std::shared_ptr< Operation > >* newQueue, using namespace Sapphire::Common;
Sapphire::Db::DbWorker::DbWorker( Util::LockedWaitQueue< std::shared_ptr< Operation > >* newQueue,
DbConnection* pConn ) DbConnection* pConn )
{ {
m_pConn = pConn; m_pConn = pConn;

View file

@ -14,12 +14,12 @@ namespace Sapphire::Db
class DbWorker class DbWorker
{ {
public: public:
DbWorker( LockedWaitQueue< std::shared_ptr< Operation > >* newQueue, DbConnection* connection ); DbWorker( Common::Util::LockedWaitQueue< std::shared_ptr< Operation > >* newQueue, DbConnection* connection );
~DbWorker(); ~DbWorker();
private: private:
LockedWaitQueue< std::shared_ptr< Operation > >* m_queue; Common::Util::LockedWaitQueue< std::shared_ptr< Operation > >* m_queue;
DbConnection* m_pConn; DbConnection* m_pConn;
void workerThread(); void workerThread();

View file

@ -5,7 +5,6 @@
#include "StatementTask.h" #include "StatementTask.h"
#include "Operation.h" #include "Operation.h"
#include "ZoneDbConnection.h" #include "ZoneDbConnection.h"
#include "Framework.h"
#include "Logging/Logger.h" #include "Logging/Logger.h"
#include <mysql.h> #include <mysql.h>
@ -21,7 +20,7 @@ class PingOperation : public Sapphire::Db::Operation
template< class T > template< class T >
Sapphire::Db::DbWorkerPool< T >::DbWorkerPool() : Sapphire::Db::DbWorkerPool< T >::DbWorkerPool() :
m_queue( new Sapphire::LockedWaitQueue< std::shared_ptr< Operation > >() ), m_queue( new Common::Util::LockedWaitQueue< std::shared_ptr< Operation > >() ),
m_asyncThreads( 0 ), m_asyncThreads( 0 ),
m_synchThreads( 0 ) m_synchThreads( 0 )
{ {

View file

@ -83,7 +83,7 @@ namespace Sapphire::Db
const std::string& getDatabaseName() const; const std::string& getDatabaseName() const;
std::unique_ptr< Sapphire::LockedWaitQueue< std::shared_ptr< Operation > > > m_queue; std::unique_ptr< Common::Util::LockedWaitQueue< std::shared_ptr< Operation > > > m_queue;
std::array< std::vector< std::shared_ptr< T > >, IDX_SIZE > m_connections; std::array< std::vector< std::shared_ptr< T > >, IDX_SIZE > m_connections;
ConnectionInfo m_connectionInfo; ConnectionInfo m_connectionInfo;
uint8_t m_asyncThreads; uint8_t m_asyncThreads;

View file

@ -6,7 +6,7 @@ Sapphire::Db::ZoneDbConnection::ZoneDbConnection( ConnectionInfo& connInfo ) :
{ {
} }
Sapphire::Db::ZoneDbConnection::ZoneDbConnection( Sapphire::LockedWaitQueue< std::shared_ptr< Operation > >* q, Sapphire::Db::ZoneDbConnection::ZoneDbConnection( Common::Util::LockedWaitQueue< std::shared_ptr< Operation > >* q,
ConnectionInfo& connInfo ) : ConnectionInfo& connInfo ) :
DbConnection( q, connInfo ) DbConnection( q, connInfo )
{ {
@ -22,18 +22,20 @@ void Sapphire::Db::ZoneDbConnection::doPrepareStatements()
m_stmts.resize( MAX_STATEMENTS ); m_stmts.resize( MAX_STATEMENTS );
/// CHARA /// CHARA
prepareStatement( CHARA_SEL, "SELECT ContentId, Name, Hp, Mp, Tp, Gp, Mode, Mount, InvincibleGM, Voice, " prepareStatement( CHARA_SEL,
"Customize, ModelMainWeapon, ModelSubWeapon, ModelSystemWeapon, " "SELECT ContentId, Name, Hp, Mp, Tp, Gp, Mode, Mount, InvincibleGM, Voice, "
"ModelEquip, EmoteModeType, FirstLoginTime, Language, IsNewGame, " "Customize, ModelMainWeapon, ModelSubWeapon, ModelSystemWeapon, "
"IsNewAdventurer, TerritoryType, TerritoryId, PosX, PosY, PosZ, PosR, " "ModelEquip, EmoteModeType, FirstLoginTime, Language, IsNewGame, "
"OTerritoryType, OTerritoryId, OPosX, OPosY, OPosZ, OPosR, GuardianDeity, " "IsNewAdventurer, TerritoryType, TerritoryId, PosX, PosY, PosZ, PosR, "
"BirthDay, BirthMonth, Class, Status, TotalPlayTime, FirstClass, HomePoint, " "OTerritoryType, OTerritoryId, OPosX, OPosY, OPosZ, OPosR, GuardianDeity, "
"FavoritePoint, RestPoint, StartTown, ActiveTitle, TitleList, Achievement, " "BirthDay, BirthMonth, Class, Status, TotalPlayTime, FirstClass, HomePoint, "
"Aetheryte, HowTo, Minions, Mounts, Orchestrion, EquippedMannequin, ConfigFlags, " "FavoritePoint, RestPoint, StartTown, ActiveTitle, TitleList, Achievement, "
"QuestCompleteFlags, OpeningSequence, QuestTracking, GrandCompany, " "Aetheryte, HowTo, Minions, Mounts, Orchestrion, EquippedMannequin, ConfigFlags, "
"GrandCompanyRank, Discovery, GMRank, EquipDisplayFlags, Unlocks, CFPenaltyUntil, " "QuestCompleteFlags, OpeningSequence, QuestTracking, GrandCompany, "
"Pose " "GrandCompanyRank, Discovery, GMRank, EquipDisplayFlags, Unlocks, CFPenaltyUntil, "
"FROM charainfo WHERE CharacterId = ?;", CONNECTION_SYNC ); "Pose "
"FROM charainfo WHERE CharacterId = ?;",
CONNECTION_SYNC );
prepareStatement( CHARA_UP, prepareStatement( CHARA_UP,
@ -47,19 +49,23 @@ void Sapphire::Db::ZoneDbConnection::doPrepareStatements()
"ActiveTitle = ?, TitleList = ?, Achievement = ?, Aetheryte = ?, HowTo = ?, Minions = ?, Mounts = ?, Orchestrion = ?, " "ActiveTitle = ?, TitleList = ?, Achievement = ?, Aetheryte = ?, HowTo = ?, Minions = ?, Mounts = ?, Orchestrion = ?, "
"EquippedMannequin = ?, ConfigFlags = ?, QuestCompleteFlags = ?, OpeningSequence = ?, " "EquippedMannequin = ?, ConfigFlags = ?, QuestCompleteFlags = ?, OpeningSequence = ?, "
"QuestTracking = ?, GrandCompany = ?, GrandCompanyRank = ?, Discovery = ?, GMRank = ?, EquipDisplayFlags = ?, Unlocks = ?, " "QuestTracking = ?, GrandCompany = ?, GrandCompanyRank = ?, Discovery = ?, GMRank = ?, EquipDisplayFlags = ?, Unlocks = ?, "
"CFPenaltyUntil = ?, Pose = ? WHERE CharacterId = ?;", CONNECTION_ASYNC ); "CFPenaltyUntil = ?, Pose = ? WHERE CharacterId = ?;",
CONNECTION_ASYNC );
prepareStatement( CHARA_SEL_MINIMAL, "SELECT Name, Customize, ModelMainWeapon, ModelSubWeapon, ModelEquip, TerritoryType, GuardianDeity, " prepareStatement( CHARA_SEL_MINIMAL,
"Class, ContentId, BirthDay, BirthMonth, EquipDisplayFlags " "SELECT Name, Customize, ModelMainWeapon, ModelSubWeapon, ModelEquip, TerritoryType, GuardianDeity, "
"FROM charainfo WHERE CharacterId = ?;", CONNECTION_SYNC ); "Class, ContentId, BirthDay, BirthMonth, EquipDisplayFlags "
"FROM charainfo WHERE CharacterId = ?;",
CONNECTION_SYNC );
prepareStatement( CHARA_INS, "INSERT INTO charainfo (AccountId, CharacterId, ContentId, Name, Hp, Mp, " prepareStatement( CHARA_INS,
"Customize, Voice, IsNewGame, TerritoryType, PosX, PosY, PosZ, PosR, ModelEquip, " "INSERT INTO charainfo (AccountId, CharacterId, ContentId, Name, Hp, Mp, "
"IsNewAdventurer, GuardianDeity, Birthday, BirthMonth, Class, Status, FirstClass, " "Customize, Voice, IsNewGame, TerritoryType, PosX, PosY, PosZ, PosR, ModelEquip, "
"HomePoint, StartTown, Discovery, HowTo, QuestCompleteFlags, Unlocks, QuestTracking, " "IsNewAdventurer, GuardianDeity, Birthday, BirthMonth, Class, Status, FirstClass, "
"Aetheryte, GMRank, Mounts, Orchestrion, UPDATE_DATE ) " "HomePoint, StartTown, Discovery, HowTo, QuestCompleteFlags, Unlocks, QuestTracking, "
"VALUES ( ?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,NOW() );", "Aetheryte, GMRank, Mounts, Orchestrion, UPDATE_DATE ) "
"VALUES ( ?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,NOW() );",
CONNECTION_SYNC ); CONNECTION_SYNC );
prepareStatement( CHARA_UP_NAME, "UPDATE charainfo SET Name = ? WHERE CharacterId = ?;", CONNECTION_ASYNC ); prepareStatement( CHARA_UP_NAME, "UPDATE charainfo SET Name = ? WHERE CharacterId = ?;", CONNECTION_ASYNC );

View file

@ -112,7 +112,7 @@ namespace Sapphire::Db
ZoneDbConnection( ConnectionInfo& connInfo ); ZoneDbConnection( ConnectionInfo& connInfo );
ZoneDbConnection( Sapphire::LockedWaitQueue< std::shared_ptr< Operation > >* q, ConnectionInfo& connInfo ); ZoneDbConnection( Common::Util::LockedWaitQueue< std::shared_ptr< Operation > >* q, ConnectionInfo& connInfo );
~ZoneDbConnection(); ~ZoneDbConnection();

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -5,12 +5,16 @@
namespace Sapphire namespace Sapphire
{ {
class ConfigMgr;
class Framework; class Framework;
using ConfigMgrPtr = std::shared_ptr< ConfigMgr >;
using FrameworkPtr = std::shared_ptr< Framework >; using FrameworkPtr = std::shared_ptr< Framework >;
} }
namespace Sapphire::Common
{
class ConfigMgr;
using ConfigMgrPtr = std::shared_ptr< ConfigMgr >;
}
namespace Sapphire::Network namespace Sapphire::Network
{ {
class Hive; class Hive;

View file

@ -1,2 +0,0 @@
#include "Framework.h"
#include "Logging/Logger.h"

View file

@ -1,37 +0,0 @@
#ifndef _CORE_FRAMEWORK_H
#define _CORE_FRAMEWORK_H
#include <map>
#include <typeindex>
#include <typeinfo>
#include <memory>
#include <cassert>
namespace Sapphire
{
class Framework
{
using TypenameToObject = std::map< std::type_index, std::shared_ptr< void > >;
TypenameToObject ObjectMap;
public:
template< typename T >
std::shared_ptr< T > get()
{
auto iType = ObjectMap.find( typeid( T ) );
assert( !( iType == ObjectMap.end() ) );
return std::static_pointer_cast< T >( iType->second );
}
template< typename T >
void set( std::shared_ptr< T > value )
{
assert( value ); // why would anyone store nullptrs....
ObjectMap[ typeid( T ) ] = value;
}
};
}
#endif // _CORE_FRAMEWORK_H

View file

@ -1,6 +1,6 @@
#include "Logger.h" #include "Logger.h"
#define SPDLOG_LEVEL_NAMES { "trace", "debug", "info", "warning", "error", "fatal", "off" } #define SPDLOG_LEVEL_NAMES { "trace", "debug", "info", "warn", "error", "fatal", "off" }
#include <spdlog/spdlog.h> #include <spdlog/spdlog.h>
#include <spdlog/async.h> #include <spdlog/async.h>
@ -8,9 +8,9 @@
#include <spdlog/sinks/daily_file_sink.h> #include <spdlog/sinks/daily_file_sink.h>
// #include <iostream> // #include <iostream>
#include <experimental/filesystem> // or #include <filesystem> #include <filesystem> // or #include <filesystem>
namespace fs = std::experimental::filesystem; namespace fs = std::filesystem;
void Sapphire::Logger::init( const std::string& logPath ) void Sapphire::Logger::init( const std::string& logPath )
{ {

View file

@ -2,7 +2,10 @@
#include "Acceptor.h" #include "Acceptor.h"
#include "Connection.h" #include "Connection.h"
Sapphire::Network::Acceptor::Acceptor( HivePtr hive ) :
using namespace Sapphire;
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() ),
@ -10,21 +13,21 @@ Sapphire::Network::Acceptor::Acceptor( HivePtr hive ) :
{ {
} }
Sapphire::Network::Acceptor::~Acceptor() Network::Acceptor::~Acceptor()
{ {
} }
bool Sapphire::Network::Acceptor::onAccept( ConnectionPtr connection, const std::string& host, uint16_t port ) bool Network::Acceptor::onAccept( ConnectionPtr connection, const std::string& host, uint16_t port )
{ {
return true; return true;
} }
void Sapphire::Network::Acceptor::onError( const asio::error_code& error ) void Network::Acceptor::onError( const asio::error_code& error )
{ {
} }
void Sapphire::Network::Acceptor::startError( const asio::error_code& error ) void Network::Acceptor::startError( const asio::error_code& error )
{ {
uint32_t v1 = 1; uint32_t v1 = 1;
uint32_t v2 = 0; uint32_t v2 = 0;
@ -37,7 +40,7 @@ void Sapphire::Network::Acceptor::startError( const asio::error_code& error )
} }
} }
void Sapphire::Network::Acceptor::dispatchAccept( ConnectionPtr connection ) void Network::Acceptor::dispatchAccept( ConnectionPtr connection )
{ {
m_acceptor.async_accept( connection->getSocket(), m_acceptor.async_accept( connection->getSocket(),
connection->getStrand().wrap( std::bind( &Acceptor::handleAccept, connection->getStrand().wrap( std::bind( &Acceptor::handleAccept,
@ -46,7 +49,7 @@ void Sapphire::Network::Acceptor::dispatchAccept( ConnectionPtr connection )
connection ) ) ); connection ) ) );
} }
void Sapphire::Network::Acceptor::handleAccept( const asio::error_code& error, ConnectionPtr connection ) void Network::Acceptor::handleAccept( const asio::error_code& error, ConnectionPtr connection )
{ {
if( error || hasError() || m_hive->hasStopped() ) if( error || hasError() || m_hive->hasStopped() )
{ {
@ -72,17 +75,17 @@ void Sapphire::Network::Acceptor::handleAccept( const asio::error_code& error, C
} }
} }
void Sapphire::Network::Acceptor::stop() void Network::Acceptor::stop()
{ {
} }
void Sapphire::Network::Acceptor::accept( ConnectionPtr connection ) void Network::Acceptor::accept( ConnectionPtr connection )
{ {
m_io_strand.post( std::bind( &Acceptor::dispatchAccept, shared_from_this(), connection ) ); m_io_strand.post( std::bind( &Acceptor::dispatchAccept, shared_from_this(), connection ) );
} }
void Sapphire::Network::Acceptor::listen( const std::string& host, const uint16_t& port ) void Network::Acceptor::listen( const std::string& host, const uint16_t& port )
{ {
try try
{ {
@ -103,17 +106,17 @@ void Sapphire::Network::Acceptor::listen( const std::string& host, const uint16_
} }
Sapphire::Network::HivePtr Sapphire::Network::Acceptor::getHive() Network::HivePtr Network::Acceptor::getHive()
{ {
return m_hive; return m_hive;
} }
asio::ip::tcp::acceptor& Sapphire::Network::Acceptor::getAcceptor() asio::ip::tcp::acceptor& Network::Acceptor::getAcceptor()
{ {
return m_acceptor; return m_acceptor;
} }
bool Sapphire::Network::Acceptor::hasError() bool Network::Acceptor::hasError()
{ {
uint32_t v1 = 1; uint32_t v1 = 1;
uint32_t v2 = 1; uint32_t v2 = 1;

View file

@ -13,8 +13,8 @@
namespace Sapphire::Network::ActorControl namespace Sapphire::Network::ActorControl
{ {
enum ActorControlType : uint16_t enum ActorControlType : uint16_t
{ {
/*! Toggles weapon status -> Sheathed/UnSheathed /*! Toggles weapon status -> Sheathed/UnSheathed
\param param1 status 0|1 */ \param param1 status 0|1 */
ToggleWeapon = 0x00, ToggleWeapon = 0x00,
@ -24,6 +24,9 @@ enum ActorControlType : uint16_t
SetStatus = 0x02, SetStatus = 0x02,
CastStart = 0x03, CastStart = 0x03,
ToggleAggro = 0x04, ToggleAggro = 0x04,
/*!
* param1 = ClassJob ID
*/
ClassJobChange = 0x05, ClassJobChange = 0x05,
DefeatMsg = 0x06, DefeatMsg = 0x06,
GainExpMsg = 0x07, GainExpMsg = 0x07,
@ -98,6 +101,8 @@ enum ActorControlType : uint16_t
FreeEventPos = 0x8A, FreeEventPos = 0x8A,
DailyQuestSeed = 0x90, // param1 = the daily quest seed
SetBGM = 0xA1, SetBGM = 0xA1,
UnlockAetherCurrentMsg = 0xA4, UnlockAetherCurrentMsg = 0xA4,
@ -140,6 +145,15 @@ enum ActorControlType : uint16_t
SetPose = 0x127, SetPose = 0x127,
/*!
* This is used for general crafting events, I found some of them but some are missing:
*
* param1 = event type, the rest of the struct depends on this param.
* - 18 & 19: Quicksynth result, 19 means HQ result item, item ID is param2 and is + 1 000 000 when HQ.
* Quantity is param3 (possible quicksynth that gives more than one item in the future?)
*
* All the other values have unkown behavior for now.
*/
CraftingUnk = 0x12C, CraftingUnk = 0x12C,
GatheringSenseMsg = 0x130, GatheringSenseMsg = 0x130,
@ -173,6 +187,14 @@ enum ActorControlType : uint16_t
RelicInfuseMsg = 0x179, RelicInfuseMsg = 0x179,
/*!
* Sent as result of an aetherial reduction.
* param1 = Reduced item ID + 500 000 (idk what this 500 000 is but it's always here no matter what)
* param2 = First result item id (+ 1 000 000 if HQ)
* param3 = First result item quantity
* param4 = (Optional) Second result item id (+ 1 000 000 if HQ)
* param5 = (Optional) Second result item quantity
*/
AetherReductionDlg = 0x17D, AetherReductionDlg = 0x17D,
/*! /*!
@ -204,6 +226,22 @@ enum ActorControlType : uint16_t
ChallengeEntryCompleteMsg = 0x20B, ChallengeEntryCompleteMsg = 0x20B,
ChallengeEntryUnlockMsg = 0x20C, ChallengeEntryUnlockMsg = 0x20C,
/*!
* Sent when a player desynths an item, one packet per result type (one for consumed item, one for each obtained items, and one for exp if the player received exp)
* param1 = result type
* 4921 => Desynth item consumed
* 4922 => Desynth item obtained
* 4925 => Desynth exp obtained)
* 3553 => Reduction item used
* 3555 => Reduction item obtained
* param3 = u32 item id (+100 000 if item is HQ)
* param4 = item amount (used only for reduction it seems)
* param5 = exp amount (x 100)
*
* Idk exactly how reduce's param3 is formatted, it seems like it's item id + 500 000 but it seems too... shady.
*/
DesynthOrReductionResult = 0x20F,
GilTrailMsg = 0x211, GilTrailMsg = 0x211,
HuntingLogRankUnlock = 0x21D, HuntingLogRankUnlock = 0x21D,
@ -220,10 +258,22 @@ enum ActorControlType : uint16_t
GearSetEquipMsg = 0x321, GearSetEquipMsg = 0x321,
SetBait = 0x325, // param1: bait ID
SetFestival = 0x386, // param1: festival.exd index SetFestival = 0x386, // param1: festival.exd index
ToggleOrchestrionUnlock = 0x396, ToggleOrchestrionUnlock = 0x396,
Dismount = 0x3A1, // updated 4.5
EventBattleDialog = 0x39D,
/*!
* param1 = mountSpeed
* Retail sends 12 for mount speed star 1 unlocked and 15 for mount speed star 2 unlocked
* This also has to be sent before mounting finishes for it to take effect
*/
SetMountSpeed = 0x3A0, // updated 5.35 hotfix
Dismount = 0x3A2, // updated 5.35 hotfix
// Duty Recorder // Duty Recorder
BeginReplayAck = 0x3A2, BeginReplayAck = 0x3A2,
@ -300,6 +350,7 @@ enum ActorControlType : uint16_t
DismountReq = 0x65, DismountReq = 0x65,
SpawnCompanionReq = 0x66, SpawnCompanionReq = 0x66,
DespawnCompanionReq = 0x67,
RemoveStatusEffect = 0x68, RemoveStatusEffect = 0x68,
CastCancel = 0x69, CastCancel = 0x69,
@ -315,20 +366,26 @@ enum ActorControlType : uint16_t
UpdatedSeenHowTos = 0x133, UpdatedSeenHowTos = 0x133,
AllotAttribute = 0x135, AllotAttribute = 0x135,
ClearWaymarks = 0x13A, ClearFieldMarkers = 0x13A,
CameraMode = 0x13B, // param12, 1 = camera mode enable, 0 = disable CameraMode = 0x13B, // param12, 1 = camera mode enable, 0 = disable
CharaNameReq = 0x13D, // requests character name by content id CharaNameReq = 0x13D, // requests character name by content id
HuntingLogDetails = 0x194, HuntingLogDetails = 0x194,
Timers = 0x1AB, Timers = 0x1AB,
DyeItem = 0x1B5, DyeItem = 0x1B0, // updated 5.21
RequestChocoboInventory = 0x1C4, RequestChocoboInventory = 0x1C4,
EmoteReq = 0x1F4, EmoteReq = 0x1F4,
EmoteCancel = 0x1F6, EmoteCancel = 0x1F6,
PersistentEmoteCancel = 0x1F7, PersistentEmoteCancel = 0x1F7,
/*!
* param2 = pose ID
* 0 = idle pose 0 (just standing)
* 1 = idle pose 1
* 2-4 = idle poses 2-4
*/
PoseChange = 0x1F9, PoseChange = 0x1F9,
PoseReapply = 0x1FA, PoseReapply = 0x1FA,
PoseCancel = 0x1FB, PoseCancel = 0x1FB,
@ -337,6 +394,8 @@ enum ActorControlType : uint16_t
AchievementComp = 0x203, AchievementComp = 0x203,
AchievementCatChat = 0x206, AchievementCatChat = 0x206,
RequestEventBattle = 0x232C,
QuestJournalUpdateQuestVisibility = 0x2BE, QuestJournalUpdateQuestVisibility = 0x2BE,
QuestJournalClosed = 0x2BF, QuestJournalClosed = 0x2BF,

View file

@ -1,23 +1,21 @@
#include "Connection.h" #include "Connection.h"
#include "Hive.h" #include "Hive.h"
#include <functional> #include <functional>
#include "Framework.h"
Sapphire::Network::Connection::Connection( HivePtr hive, FrameworkPtr pFw ) : using namespace Sapphire;
Network::Connection::Connection( HivePtr hive ) :
m_hive( hive ), m_hive( hive ),
m_socket( hive->getService() ), m_socket( hive->getService() ),
m_io_strand( hive->getService() ), m_io_strand( hive->getService() ),
m_receive_buffer_size( 32000 ), m_receive_buffer_size( 32000 ),
m_error_state( 0 ), m_error_state( 0 )
m_pFw( pFw )
{ {
} }
Sapphire::Network::Connection::~Connection() Network::Connection::~Connection() = default;
{
}
void Sapphire::Network::Connection::bind( const std::string& ip, uint16_t port ) void Network::Connection::bind( const std::string& ip, uint16_t port )
{ {
asio::ip::tcp::endpoint endpoint( asio::ip::address::from_string( ip ), port ); asio::ip::tcp::endpoint endpoint( asio::ip::address::from_string( ip ), port );
m_socket.open( endpoint.protocol() ); m_socket.open( endpoint.protocol() );
@ -25,7 +23,7 @@ void Sapphire::Network::Connection::bind( const std::string& ip, uint16_t port )
m_socket.bind( endpoint ); m_socket.bind( endpoint );
} }
void Sapphire::Network::Connection::startSend() void Network::Connection::startSend()
{ {
if( !m_pending_sends.empty() ) if( !m_pending_sends.empty() )
{ {
@ -38,7 +36,7 @@ void Sapphire::Network::Connection::startSend()
} }
} }
void Sapphire::Network::Connection::startRecv( int32_t total_bytes ) void Network::Connection::startRecv( int32_t total_bytes )
{ {
if( total_bytes > 0 ) if( total_bytes > 0 )
{ {
@ -61,7 +59,7 @@ void Sapphire::Network::Connection::startRecv( int32_t total_bytes )
} }
} }
void Sapphire::Network::Connection::startError( const asio::error_code& error ) void Network::Connection::startError( const asio::error_code& error )
{ {
uint32_t v1 = 1; uint32_t v1 = 1;
uint32_t v2 = 0; uint32_t v2 = 0;
@ -74,7 +72,7 @@ void Sapphire::Network::Connection::startError( const asio::error_code& error )
} }
} }
void Sapphire::Network::Connection::handleConnect( const asio::error_code& error ) void Network::Connection::handleConnect( const asio::error_code& error )
{ {
if( error || hasError() || m_hive->hasStopped() ) if( error || hasError() || m_hive->hasStopped() )
{ {
@ -94,8 +92,8 @@ void Sapphire::Network::Connection::handleConnect( const asio::error_code& error
} }
} }
void Sapphire::Network::Connection::handleSend( const asio::error_code& error, void Network::Connection::handleSend( const asio::error_code& error,
std::list< std::vector< uint8_t > >::iterator itr ) std::list< std::vector< uint8_t > >::iterator itr )
{ {
if( error || hasError() || m_hive->hasStopped() ) if( error || hasError() || m_hive->hasStopped() )
{ {
@ -109,7 +107,7 @@ void Sapphire::Network::Connection::handleSend( const asio::error_code& error,
} }
} }
void Sapphire::Network::Connection::handleRecv( const asio::error_code& error, int32_t actual_bytes ) void Network::Connection::handleRecv( const asio::error_code& error, int32_t actual_bytes )
{ {
if( error || hasError() || m_hive->hasStopped() ) if( error || hasError() || m_hive->hasStopped() )
{ {
@ -128,7 +126,7 @@ void Sapphire::Network::Connection::handleRecv( const asio::error_code& error, i
} }
} }
void Sapphire::Network::Connection::dispatchSend( std::vector< uint8_t > buffer ) void Network::Connection::dispatchSend( std::vector< uint8_t > buffer )
{ {
bool should_start_send = m_pending_sends.empty(); bool should_start_send = m_pending_sends.empty();
m_pending_sends.push_back( buffer ); m_pending_sends.push_back( buffer );
@ -138,7 +136,7 @@ void Sapphire::Network::Connection::dispatchSend( std::vector< uint8_t > buffer
} }
} }
void Sapphire::Network::Connection::dispatchRecv( int32_t total_bytes ) void Network::Connection::dispatchRecv( int32_t total_bytes )
{ {
bool should_start_receive = m_pending_recvs.empty(); bool should_start_receive = m_pending_recvs.empty();
m_pending_recvs.push_back( total_bytes ); m_pending_recvs.push_back( total_bytes );
@ -149,7 +147,7 @@ void Sapphire::Network::Connection::dispatchRecv( int32_t total_bytes )
} }
void Sapphire::Network::Connection::connect( const std::string& host, uint16_t port ) void Network::Connection::connect( const std::string& host, uint16_t port )
{ {
asio::ip::tcp::resolver resolver( m_hive->getService() ); asio::ip::tcp::resolver resolver( m_hive->getService() );
asio::ip::tcp::resolver::query query( host, std::to_string( port ) ); asio::ip::tcp::resolver::query query( host, std::to_string( port ) );
@ -160,48 +158,48 @@ void Sapphire::Network::Connection::connect( const std::string& host, uint16_t p
} }
void Sapphire::Network::Connection::disconnect() void Network::Connection::disconnect()
{ {
onDisconnect(); onDisconnect();
m_socket.close(); m_socket.close();
} }
void Sapphire::Network::Connection::recv( int32_t total_bytes ) void Network::Connection::recv( int32_t total_bytes )
{ {
m_io_strand.post( std::bind( &Connection::dispatchRecv, shared_from_this(), total_bytes ) ); m_io_strand.post( std::bind( &Connection::dispatchRecv, shared_from_this(), total_bytes ) );
} }
void Sapphire::Network::Connection::send( const std::vector< uint8_t >& buffer ) void Network::Connection::send( const std::vector< uint8_t >& buffer )
{ {
m_io_strand.post( std::bind( &Connection::dispatchSend, shared_from_this(), buffer ) ); m_io_strand.post( std::bind( &Connection::dispatchSend, shared_from_this(), buffer ) );
} }
asio::ip::tcp::socket& Sapphire::Network::Connection::getSocket() asio::ip::tcp::socket& Network::Connection::getSocket()
{ {
return m_socket; return m_socket;
} }
asio::strand& Sapphire::Network::Connection::getStrand() asio::strand& Network::Connection::getStrand()
{ {
return m_io_strand; return m_io_strand;
} }
Sapphire::Network::HivePtr Sapphire::Network::Connection::getHive() Network::HivePtr Network::Connection::getHive()
{ {
return m_hive; return m_hive;
} }
void Sapphire::Network::Connection::setReceiveBufferSize( int32_t size ) void Network::Connection::setReceiveBufferSize( int32_t size )
{ {
m_receive_buffer_size = size; m_receive_buffer_size = size;
} }
int32_t Sapphire::Network::Connection::getReceiveBufferSize() const int32_t Network::Connection::getReceiveBufferSize() const
{ {
return m_receive_buffer_size; return m_receive_buffer_size;
} }
bool Sapphire::Network::Connection::hasError() bool Network::Connection::hasError()
{ {
uint32_t v1 = 1; uint32_t v1 = 1;
uint32_t v2 = 1; uint32_t v2 = 1;

View file

@ -12,12 +12,6 @@
#include "Acceptor.h" #include "Acceptor.h"
#include <memory> #include <memory>
namespace Sapphire
{
class Framework;
using FrameworkPtr = std::shared_ptr< Framework >;
}
namespace Sapphire::Network namespace Sapphire::Network
{ {
@ -41,9 +35,8 @@ namespace Sapphire::Network
std::list< std::vector< uint8_t > > m_pending_sends; std::list< std::vector< uint8_t > > m_pending_sends;
int32_t m_receive_buffer_size; int32_t m_receive_buffer_size;
std::atomic< uint32_t > m_error_state; std::atomic< uint32_t > m_error_state;
Sapphire::FrameworkPtr m_pFw;
Connection( HivePtr hive, FrameworkPtr pFw ); Connection( HivePtr hive );
virtual ~Connection(); virtual ~Connection();
@ -147,13 +140,13 @@ namespace Sapphire::Network
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
template< class T > template< class T >
std::shared_ptr< T > addServerToHive( const std::string& listenIp, uint32_t port, HivePtr pHive, FrameworkPtr pFw ) std::shared_ptr< T > addServerToHive( const std::string& listenIp, uint32_t port, HivePtr pHive )
{ {
try try
{ {
AcceptorPtr acceptor( new Acceptor( pHive ) ); AcceptorPtr acceptor( new Acceptor( pHive ) );
acceptor->listen( listenIp, port ); acceptor->listen( listenIp, port );
std::shared_ptr< T > connection( new T( pHive, acceptor, pFw ) ); std::shared_ptr< T > connection( new T( pHive, acceptor ) );
acceptor->accept( connection ); acceptor->accept( connection );
return connection; return connection;
} }

View file

@ -257,7 +257,7 @@ namespace Sapphire::Network::Packets
// The IPC type itself. // The IPC type itself.
m_ipcHdr.type = static_cast< ServerZoneIpcType >( m_data._ServerIpcType ); m_ipcHdr.type = static_cast< ServerZoneIpcType >( m_data._ServerIpcType );
m_ipcHdr.timestamp = Util::getTimeSeconds(); m_ipcHdr.timestamp = Common::Util::getTimeSeconds();
m_segHdr.size = sizeof( T ) + sizeof( FFXIVARR_IPC_HEADER ) + sizeof( FFXIVARR_PACKET_SEGMENT_HEADER ); m_segHdr.size = sizeof( T ) + sizeof( FFXIVARR_IPC_HEADER ) + sizeof( FFXIVARR_PACKET_SEGMENT_HEADER );
}; };

View file

@ -3,9 +3,10 @@
#include <string.h> // memcpy #include <string.h> // memcpy
using namespace Sapphire;
using namespace Sapphire::Network::Packets; using namespace Sapphire::Network::Packets;
PacketParseResult Sapphire::Network::Packets::getHeader( const std::vector< uint8_t >& buffer, PacketParseResult Network::Packets::getHeader( const std::vector< uint8_t >& buffer,
const uint32_t offset, const uint32_t offset,
FFXIVARR_PACKET_HEADER& header ) FFXIVARR_PACKET_HEADER& header )
{ {
@ -25,7 +26,7 @@ PacketParseResult Sapphire::Network::Packets::getHeader( const std::vector< uint
return Success; return Success;
} }
PacketParseResult Sapphire::Network::Packets::getSegmentHeader( const std::vector< uint8_t >& buffer, PacketParseResult Network::Packets::getSegmentHeader( const std::vector< uint8_t >& buffer,
const uint32_t offset, const uint32_t offset,
FFXIVARR_PACKET_SEGMENT_HEADER& header ) FFXIVARR_PACKET_SEGMENT_HEADER& header )
{ {
@ -42,7 +43,7 @@ PacketParseResult Sapphire::Network::Packets::getSegmentHeader( const std::vecto
return Success; return Success;
} }
PacketParseResult Sapphire::Network::Packets::getPackets( const std::vector< uint8_t >& buffer, PacketParseResult Network::Packets::getPackets( const std::vector< uint8_t >& buffer,
const uint32_t offset, const uint32_t offset,
const FFXIVARR_PACKET_HEADER& packetHeader, const FFXIVARR_PACKET_HEADER& packetHeader,
std::vector< FFXIVARR_PACKET_RAW >& packets ) std::vector< FFXIVARR_PACKET_RAW >& packets )
@ -81,7 +82,7 @@ PacketParseResult Sapphire::Network::Packets::getPackets( const std::vector< uin
return Success; return Success;
} }
PacketParseResult Sapphire::Network::Packets::getPacket( const std::vector< uint8_t >& buffer, const uint32_t offset, PacketParseResult Network::Packets::getPacket( const std::vector< uint8_t >& buffer, const uint32_t offset,
FFXIVARR_PACKET_RAW& packet ) FFXIVARR_PACKET_RAW& packet )
{ {
// Copy segment header // Copy segment header
@ -103,7 +104,7 @@ PacketParseResult Sapphire::Network::Packets::getPacket( const std::vector< uint
return Success; return Success;
} }
bool Sapphire::Network::Packets::checkHeader( const FFXIVARR_PACKET_HEADER& header ) bool Network::Packets::checkHeader( const FFXIVARR_PACKET_HEADER& header )
{ {
// Max size of the packet is capped at 1MB for now. // Max size of the packet is capped at 1MB for now.
if( header.size > 1 * 1024 * 1024 ) if( header.size > 1 * 1024 * 1024 )
@ -116,7 +117,7 @@ bool Sapphire::Network::Packets::checkHeader( const FFXIVARR_PACKET_HEADER& head
return true; return true;
} }
bool Sapphire::Network::Packets::checkSegmentHeader( const FFXIVARR_PACKET_SEGMENT_HEADER& header ) bool Network::Packets::checkSegmentHeader( const FFXIVARR_PACKET_SEGMENT_HEADER& header )
{ {
// Max size of individual message is capped at 256KB for now. // Max size of individual message is capped at 256KB for now.
if( header.size > 256 * 1024 ) if( header.size > 256 * 1024 )

View file

@ -2,41 +2,43 @@
#include <functional> #include <functional>
#include "Hive.h" #include "Hive.h"
using namespace Sapphire;
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
Sapphire::Network::Hive::Hive() : Network::Hive::Hive() :
m_work_ptr( new asio::io_service::work( m_io_service ) ), m_work_ptr( new asio::io_service::work( m_io_service ) ),
m_shutdown( 0 ) m_shutdown( 0 )
{ {
} }
Sapphire::Network::Hive::~Hive() Network::Hive::~Hive()
{ {
} }
asio::io_service& Sapphire::Network::Hive::getService() asio::io_service& Network::Hive::getService()
{ {
return m_io_service; return m_io_service;
} }
bool Sapphire::Network::Hive::hasStopped() bool Network::Hive::hasStopped()
{ {
uint32_t v1 = 1; uint32_t v1 = 1;
uint32_t v2 = 1; uint32_t v2 = 1;
return m_shutdown.compare_exchange_strong( v1, v2 ); return m_shutdown.compare_exchange_strong( v1, v2 );
} }
void Sapphire::Network::Hive::poll() void Network::Hive::poll()
{ {
m_io_service.poll(); m_io_service.poll();
} }
void Sapphire::Network::Hive::run() void Network::Hive::run()
{ {
m_io_service.run(); m_io_service.run();
} }
void Sapphire::Network::Hive::stop() void Network::Hive::stop()
{ {
uint32_t v1 = 1; uint32_t v1 = 1;
uint32_t v2 = 0; uint32_t v2 = 0;
@ -48,7 +50,7 @@ void Sapphire::Network::Hive::stop()
} }
} }
void Sapphire::Network::Hive::reset() void Network::Hive::reset()
{ {
uint32_t v1 = 0; uint32_t v1 = 0;
uint32_t v2 = 1; uint32_t v2 = 1;

View file

@ -5,7 +5,7 @@
#include <atomic> #include <atomic>
#include <memory> #include <memory>
namespace Sapphire:: Network namespace Sapphire::Network
{ {
class Hive : public std::enable_shared_from_this< Hive > class Hive : public std::enable_shared_from_this< Hive >

View file

@ -7,7 +7,9 @@
#include <string.h> #include <string.h>
#include <memory> #include <memory>
Sapphire::Network::Packets::PacketContainer::PacketContainer( uint32_t segmentTargetOverride ) : using namespace Sapphire;
Network::Packets::PacketContainer::PacketContainer( uint32_t segmentTargetOverride ) :
m_segmentTargetOverride( segmentTargetOverride ) m_segmentTargetOverride( segmentTargetOverride )
{ {
memset( &m_ipcHdr, 0, sizeof( FFXIVARR_PACKET_HEADER ) ); memset( &m_ipcHdr, 0, sizeof( FFXIVARR_PACKET_HEADER ) );
@ -15,12 +17,12 @@ Sapphire::Network::Packets::PacketContainer::PacketContainer( uint32_t segmentTa
m_ipcHdr.count = 0; m_ipcHdr.count = 0;
} }
Sapphire::Network::Packets::PacketContainer::~PacketContainer() Network::Packets::PacketContainer::~PacketContainer()
{ {
m_entryList.clear(); m_entryList.clear();
} }
void Sapphire::Network::Packets::PacketContainer::addPacket( Sapphire::Network::Packets::FFXIVPacketBasePtr entry ) void Network::Packets::PacketContainer::addPacket( Network::Packets::FFXIVPacketBasePtr entry )
{ {
m_entryList.push_back( entry ); m_entryList.push_back( entry );
@ -28,7 +30,7 @@ void Sapphire::Network::Packets::PacketContainer::addPacket( Sapphire::Network::
m_ipcHdr.count++; m_ipcHdr.count++;
} }
void Sapphire::Network::Packets::PacketContainer::fillSendBuffer( std::vector< uint8_t >& sendBuffer ) void Network::Packets::PacketContainer::fillSendBuffer( std::vector< uint8_t >& sendBuffer )
{ {
std::vector< uint8_t > tempBuffer( m_ipcHdr.size ); std::vector< uint8_t > tempBuffer( m_ipcHdr.size );
memset( &tempBuffer[ 0 ], 0, m_ipcHdr.size ); memset( &tempBuffer[ 0 ], 0, m_ipcHdr.size );
@ -67,7 +69,7 @@ void Sapphire::Network::Packets::PacketContainer::fillSendBuffer( std::vector< u
} }
std::string Sapphire::Network::Packets::PacketContainer::toString() std::string Network::Packets::PacketContainer::toString()
{ {
std::vector< uint8_t > tmpBuffer; std::vector< uint8_t > tmpBuffer;
@ -76,7 +78,7 @@ std::string Sapphire::Network::Packets::PacketContainer::toString()
std::string str = "\n"; std::string str = "\n";
for( uint32_t i = 0; i < m_ipcHdr.size; i++ ) for( uint32_t i = 0; i < m_ipcHdr.size; i++ )
{ {
str += Util::intToHexString( static_cast< int32_t >( tmpBuffer[ i ] & 0xFF ) ) + " "; str += Common::Util::intToHexString( static_cast< int32_t >( tmpBuffer[ i ] & 0xFF ) ) + " ";
if( ( i + 1 ) % 16 == 0 ) if( ( i + 1 ) % 16 == 0 )
str += "\n"; str += "\n";

View file

@ -4,10 +4,8 @@
#include <Common.h> #include <Common.h>
#include <Network/CommonNetwork.h> #include <Network/CommonNetwork.h>
namespace Sapphire { namespace Sapphire::Network::Packets::Server
namespace Network { {
namespace Packets {
namespace Server {
/** /**
* Structural representation of the packet sent by the server as response * Structural representation of the packet sent by the server as response
@ -31,10 +29,37 @@ struct FFXIVIpcTellErrNotFound : FFXIVIpcBasePacket< TellErrNotFound >
char receipientName[32]; char receipientName[32];
}; };
} /* Server */ struct FFXIVIpcFreeCompanyEvent : FFXIVIpcBasePacket< FreeCompanyEvent >
} /* Packets */ {
} /* Network */ uint16_t unknown;
} /* Sapphire */ uint16_t unknown1;
uint16_t unknown2;
uint16_t unknown3;
uint16_t unknown4;
char padding[6];
uint8_t eventID;
/*
* 0x0F Login
* 0x10 Logout
*/
uint8_t padding1;
char padding2[6];
uint16_t unknown5;
char parameter[46];
/**
* eventID | parameter usage
* 0x0F FC name
* 0x10 FC name
*/
char parameter1[32];
/**
* eventID | parameter1 usage
* 0x0F Character name
* 0x10 Character name
*/
};
} /* Sapphire::Common::Network::Packets::Server */

View file

@ -43,176 +43,219 @@ namespace Sapphire::Network::Packets
*/ */
enum ServerZoneIpcType : uint16_t enum ServerZoneIpcType : uint16_t
{ {
Ping = 0x0219, // updated 5.35 hotfix
Init = 0x0185, // updated 5.35 hotfix
// static opcode ( the ones that rarely, if ever, change ) ActorFreeSpawn = 0x0239, // updated 5.35 hotfix
Ping = 0x0065, InitZone = 0x03CD, // updated 5.35 hotfix
Init = 0x0066,
ActorFreeSpawn = 0x0191, EffectResult = 0x01C2, // updated 5.35 hotfix
InitZone = 0x019A, ActorControl = 0x02A4, // updated 5.35 hotfix
ActorControlSelf = 0x02C8, // updated 5.35 hotfix
ActorControlTarget = 0x0209, // updated 5.35 hotfix
AddStatusEffect = 0x0141, /*!
ActorControl142 = 0x0142, * @brief Used when resting
ActorControl143 = 0x0143, */
ActorControl144 = 0x0144, UpdateHpMpTp = 0x0319, // updated 5.35 hotfix
UpdateHpMpTp = 0x0145,
/////////////////////////////////////////////////// ///////////////////////////////////////////////////
ChatBanned = 0x006B, ChatBanned = 0xF06B,
Playtime = 0x006C, // updated 4.5 Playtime = 0x03A4, // updated 5.35 hotfix
Logout = 0x0077, // updated 4.5 Logout = 0x02AD, // updated 5.35 hotfix
CFNotify = 0x0078, CFNotify = 0x02C4, // updated 5.35 hotfix
CFMemberStatus = 0x0079, CFMemberStatus = 0x0079,
CFDutyInfo = 0x007A, CFDutyInfo = 0x007A,
CFPlayerInNeed = 0x007F, CFPlayerInNeed = 0xF07F,
CFPreferredRole = 0x0196, // updated 5.35 hotfix
CFCancel = 0x00EC, // updated 5.35 hotfix
SocialRequestError = 0xF0AD,
SocialRequestError = 0x00AD, CFRegistered = 0x010C, // updated 5.35 hotfix
SocialRequestResponse = 0x01C7, // updated 5.35 hotfix
CFRegistered = 0x00B8, // updated 4.1 SocialMessage = 0x0308, // updated 5.35 hotfix
SocialRequestResponse = 0x00BB, // updated 4.1 SocialMessage2 = 0x037C, // updated 5.35 hotfix
CancelAllianceForming = 0x00C6, // updated 4.2 CancelAllianceForming = 0x00C6, // updated 4.2
Chat = 0x00F7, // updated 4.5?
SocialList = 0x0103, // updated 4.5
UpdateSearchInfo = 0x0106, // updated 4.5
InitSearchInfo = 0x0107, // updated 4.4
ExamineSearchComment = 0x0102, // updated 4.1
ServerNoticeShort = 0x010B, // added 4.5
ServerNotice = 0x010C, // updated 4.5
SetOnlineStatus = 0x010D, // updated 4.5
CountdownInitiate = 0x0114, // updated 4.5
CountdownCancel = 0x0115, // updated 4.5
BlackList = 0x0118, // updated 4.5
LogMessage = 0x00D0, LogMessage = 0x00D0,
LinkshellList = 0x011F, // updated 4.5 Chat = 0x0349, // updated 5.35 hotfix
PartyChat = 0x0065,
MailDeleteRequest = 0x0120, // updated 4.5 WorldVisitList = 0xF0FE, // added 4.5
ReqMoogleMailList = 0x0121, // updated 4.5
ReqMoogleMailLetter = 0x0122, // updated 4.5
MailLetterNotification = 0x0123, // updated 4.5
MarketBoardItemListingCount = 0x0125, // updated 4.5 SocialList = 0x0216, // updated 5.35 hotfix
MarketBoardItemListing = 0x0126, // updated 4.5
MarketBoardItemListingHistory = 0x012A, // updated 4.5
MarketBoardSearchResult = 0x0139, // updated 4.5
ExamineSearchInfo = 0x03C3, // updated 5.35 hotfix
UpdateSearchInfo = 0x0121, // updated 5.35 hotfix
InitSearchInfo = 0x036F, // updated 5.35 hotfix
ExamineSearchComment = 0x0102, // updated 4.1
ServerNoticeShort = 0x0115, // updated 5.0
ServerNotice = 0x02F8, // updated 5.35 hotfix
SetOnlineStatus = 0x03D7, // updated 5.35 hotfix
CountdownInitiate = 0x0237, // updated 5.25
CountdownCancel = 0x00D9, // updated 5.18
PlayerAddedToBlacklist = 0x033F, // updated 5.1
PlayerRemovedFromBlacklist = 0x0385, // updated 5.1
BlackList = 0x02DB, // updated 5.35 hotfix
LinkshellList = 0x01F0, // updated 5.35 hotfix
MailDeleteRequest = 0xF12B, // updated 5.0
// 12D - 137 - constant gap between 4.5x -> 5.0
ReqMoogleMailList = 0xF138, // updated 5.0
ReqMoogleMailLetter = 0xF139, // updated 5.0
MailLetterNotification = 0x013A, // updated 5.0
MarketTaxRates = 0x01F8, // updated 5.35 hotfix
MarketBoardSearchResult = 0x032C, // updated 5.35 hotfix
MarketBoardItemListingCount = 0x038F, // updated 5.35 hotfix
MarketBoardItemListingHistory = 0x0186, // updated 5.35 hotfix
MarketBoardItemListing = 0x025F, // updated 5.35 hotfix
CharaFreeCompanyTag = 0x013B, // updated 4.5 CharaFreeCompanyTag = 0x013B, // updated 4.5
FreeCompanyBoardMsg = 0x013C, // updated 4.5 FreeCompanyBoardMsg = 0x013C, // updated 4.5
FreeCompanyInfo = 0x013D, // updated 4.5 FreeCompanyInfo = 0xF13D, // updated 4.5
ExamineFreeCompanyInfo = 0x013E, // updated 4.5 ExamineFreeCompanyInfo = 0xF13E, // updated 4.5
StatusEffectList = 0x0151, // updated 4.5 FreeCompanyUpdateShortMessage = 0xF157, // added 5.0
Effect = 0x0154, // updated 4.5
AoeEffect8 = 0x0157, // updated 4.5
AoeEffect16 = 0x0158, // updated 4.5
AoeEffect24 = 0x0159, // updated 4.5
AoeEffect32 = 0x015A, // updated 4.5
PersistantEffect = 0x015B, // updated 4.5
GCAffiliation = 0x0165, // updated 4.5 StatusEffectList = 0x0382, // updated 5.35 hotfix
EurekaStatusEffectList = 0x0167, // updated 5.18
BossStatusEffectList = 0x0312, // added 5.1
Effect = 0x0192, // updated 5.35 hotfix
AoeEffect8 = 0x012C, // updated 5.35 hotfix
AoeEffect16 = 0x03BF, // updated 5.3
AoeEffect24 = 0x027E, // updated 5.3
AoeEffect32 = 0x017E, // updated 5.3
PersistantEffect = 0x0317, // updated 5.35 hotfix
PlayerSpawn = 0x0175, // updated 4.5 GCAffiliation = 0xF16F, // updated 5.0
NpcSpawn = 0x0176, // updated 4.5
NpcSpawn2 = 0x0177, // ( Bigger statuseffectlist? ) updated 4.5
ActorMove = 0x0178, // updated 4.5
ActorSetPos = 0x017A, // updated 4.5 PlayerSpawn = 0x0179, // updated 5.35 hotfix
NpcSpawn = 0x03A8, // updated 5.35 hotfix
NpcSpawn2 = 0x01CB, // ( Bigger statuseffectlist? ) updated 5.3
ActorMove = 0x01BF, // updated 5.35 hotfix
ActorCast = 0x017C, // updated 4.5 ActorSetPos = 0x03DF, // updated 5.35 hotfix
PartyList = 0x017E, // updated 4.5 ActorCast = 0x0302, // updated 5.35 hotfix
SomeCustomiseChangePacketProbably = 0x00CD, // added 5.18
HateList = 0x0180, // updated 4.5 PartyList = 0x02B2, // updated 5.35 hotfix
ObjectSpawn = 0x0181, // updated 4.5 PartyMessage = 0x00AE, // updated 5.35 hotfix
ObjectDespawn = 0x0182, // updated 4.5 HateRank = 0x02CC, // updated 5.35 hotfix
UpdateClassInfo = 0x0183, // updated 4.5 HateList = 0x0198, // updated 5.35 hotfix
SilentSetClassJob = 0x0184, // updated 4.5 - seems to be the case, not sure if it's actually used for anything ObjectSpawn = 0x02B8, // updated 5.35 hotfix
InitUI = 0x0185, // updated 4.5 ObjectDespawn = 0xF34B, // updated 5.18
PlayerStats = 0x0186, // updated 4.5 UpdateClassInfo = 0x0235, // updated 5.35 hotfix
ActorOwner = 0x0187, // updated 4.5 SilentSetClassJob = 0x018E, // updated 5.0 - seems to be the case, not sure if it's actually used for anything
PlayerStateFlags = 0x0188, // updated 4.5 PlayerSetup = 0x0290, // updated 5.35 hotfix
PlayerClassInfo = 0x0189, // updated 4.5 PlayerStats = 0x023B, // updated 5.35 hotfix
ActorOwner = 0x00E8, // updated 5.35 hotfix
PlayerStateFlags = 0x00F8, // updated 5.35 hotfix
PlayerClassInfo = 0x02C3, // updated 5.35 hotfix
CharaVisualEffect = 0x02E2, // updated 5.35 hotfix
ModelEquip = 0x018B, // updated 4.5 ModelEquip = 0x0277, // updated 5.35 hotfix
Examine = 0x018C, // updated 4.5 Examine = 0x00BC, // updated 5.35 hotfix
CharaNameReq = 0x018D, // updated 4.5 CharaNameReq = 0x008E, // updated 5.35 hotfix
// nb: see #565 on github
UpdateRetainerItemSalePrice = 0xF19F, // updated 5.0
RetainerSaleHistory = 0x020E, // updated 5.21 hotfix
RetainerInformation = 0x01F9, // updated 5.35 hotfix
SetLevelSync = 0x1186, // not updated for 4.4, not sure what it is anymore SetLevelSync = 0x1186, // not updated for 4.4, not sure what it is anymore
ItemInfo = 0x0196, // updated 4.5 ItemInfo = 0x0214, // updated 5.35 hotfix
ContainerInfo = 0x0197, // updated 4.5 ContainerInfo = 0x00C5, // updated 5.35 hotfix
InventoryTransactionFinish = 0x0198, // updated 4.5 InventoryTransactionFinish = 0x02F0, // updated 5.35 hotfix
InventoryTransaction = 0x0199, // updated 4.5 InventoryTransaction = 0x01FD, // updated 5.35 hotfix
CurrencyCrystalInfo = 0x0379, // updated 5.35 hotfix
CurrencyCrystalInfo = 0x019B, // updated 4.5 InventoryActionAck = 0x03E4, // updated 5.35 hotfix
UpdateInventorySlot = 0x036A, // updated 5.35 hotfix
InventoryActionAck = 0x019D, // updated 4.5 HuntingLogEntry = 0x0146, // updated 5.35 hotfix
UpdateInventorySlot = 0x019E, // updated 4.5
HuntingLogEntry = 0x01A9, // added 4.5 EventPlay = 0x00F3, // updated 5.35 hotfix
EventPlay4 = 0x00AC, // updated 5.35 hotfix
EventPlay8 = 0x023F, // updated 5.35 hotfix
EventPlay16 = 0x025B, // updated 5.35 hotfix
EventPlay32 = 0x029A, // updated 5.35 hotfix
EventPlay64 = 0x02C1, // updated 5.35 hotfix
EventPlay128 = 0x038A, // updated 5.35 hotfix
EventPlay255 = 0x034B, // updated 5.35 hotfix
EventPlay = 0x01AB, // updated 4.5 EventStart = 0x009A, // updated 5.35 hotfix
DirectorPlayScene = 0x01AF, // updated 4.5 EventFinish = 0x007E, // updated 5.35 hotfix
EventOpenGilShop = 0x01B2, // updated 4.5
EventStart = 0x01B4, // updated 4.5
EventFinish = 0x01B5, // updated 4.5
EventLinkshell = 0x1169, EventLinkshell = 0x1169,
QuestActiveList = 0x01C8, // updated 4.5 QuestActiveList = 0x0117, // updated 5.35 hotfix
QuestUpdate = 0x01C9, // updated 4.5 QuestUpdate = 0x0073, // updated 5.35 hotfix
QuestCompleteList = 0x01CA, // updated 4.5 QuestCompleteList = 0x0240, // updated 5.35 hotfix
QuestFinish = 0x01CB, // updated 4.5 QuestFinish = 0x00E9, // updated 5.35 hotfix
MSQTrackerComplete = 0x01CC, // updated 4.5 MSQTrackerComplete = 0xF1D6, // updated 5.0
MSQTrackerProgress = 0xF1CD, // updated 4.5 ? this actually looks like the two opcodes have been combined, see #474 MSQTrackerProgress = 0xF1CD, // updated 4.5 ? this actually looks like the two opcodes have been combined, see #474
QuestMessage = 0x01D3, // updated 4.5 QuestMessage = 0x0381, // updated 5.35 hotfix
QuestTracker = 0x01D8, // updated 4.5 QuestTracker = 0x018B, // updated 5.35 hotfix
Mount = 0x01E8, // updated 4.5 Mount = 0x01B5, // updated 5.35 hotfix
DirectorVars = 0x01EA, // updated 4.5 DirectorVars = 0x00E6, // updated 5.18
DirectorPopUp = 0x01F5, // display dialogue pop-ups in duties and FATEs, for example, Teraflare's countdown SomeDirectorUnk1 = 0x0084, // updated 5.18
SomeDirectorUnk2 = 0xF0C1, // updated 5.18
SomeDirectorUnk4 = 0x0202, // updated 5.35 hotfix
SomeDirectorUnk8 = 0x028A, // updated 5.18
SomeDirectorUnk16 = 0x028C, // updated 5.18
DirectorPopUp = 0xF162, // updated 5.18 - display dialogue pop-ups in duties and FATEs, for example, Teraflare's countdown
DirectorPopUp4 = 0x0214, // updated 5.18
DirectorPopUp8 = 0x00F8, // updated 5.18
CFAvailableContents = 0xF1FD, // updated 4.2 CFAvailableContents = 0xF1FD, // updated 4.2
WeatherChange = 0x0205, // updated 4.5 WeatherChange = 0x027B, // updated 5.35 hotfix
PlayerTitleList = 0x0206, // updated 4.5? PlayerTitleList = 0x037D, // updated 5.1
Discovery = 0x0207, // updated 4.5? Discovery = 0x031B, // updated 5.35 hotfix
EorzeaTimeOffset = 0x0209, // updated 4.5 EorzeaTimeOffset = 0xF3B8, // updated 5.1
EquipDisplayFlags = 0x0215, // updated 4.5 EquipDisplayFlags = 0x00BE, // updated 5.35 hotfix
MiniCactpotInit = 0x0286, // added 5.31
ShopMessage = 0x0197, // updated 5.35 hotfix
LootMessage = 0x01B7, // updated 5.35 hotfix
/// Housing ////////////////////////////////////// /// Housing //////////////////////////////////////
LandSetInitialize = 0x0229, // updated 4.5 LandSetInitialize = 0x0234, // updated 5.0
LandUpdate = 0x022A, // updated 4.5 LandUpdate = 0x0235, // updated 5.0
YardObjectSpawn = 0x022B, // updated 4.5 YardObjectSpawn = 0xF236, // updated 5.0
HousingIndoorInitialize = 0x022C, // updated 4.5 HousingIndoorInitialize = 0x0237, // updated 5.0
LandPriceUpdate = 0x022D, // updated 4.5 LandPriceUpdate = 0x0238, // updated 5.0
LandInfoSign = 0x022E, // updated 4.5 LandInfoSign = 0x023D, // updated 5.35 hotfix
LandRename = 0x022F, // updated 4.5 LandRename = 0x023A, // updated 5.0
HousingEstateGreeting = 0x0230, // updated 4.5 HousingEstateGreeting = 0x023B, // updated 5.0
HousingUpdateLandFlagsSlot = 0x0231, // updated 4.5 HousingUpdateLandFlagsSlot = 0x023C, // updated 5.0
HousingLandFlags = 0x0232, // updated 4.5 HousingLandFlags = 0x022F, // updated 5.35 hotfix
HousingShowEstateGuestAccess = 0x0233, // updated 4.5 HousingShowEstateGuestAccess = 0x023E, // updated 5.0
HousingObjectInitialize = 0x0235, // updated 4.45 HousingObjectInitialize = 0x01AA, // updated 5.35 hotfix
HousingInternalObjectSpawn = 0x236, // updated 4.5 HousingInternalObjectSpawn = 0xF241, // updated 5.0
HousingWardInfo = 0x0238, // updated 4.5 HousingWardInfo = 0x02FD, // updated 5.35 hotfix
HousingObjectMove = 0x0239, // updated 4.5 HousingObjectMove = 0xF244, // updated 5.0
SharedEstateSettingsResponse = 0x0245, // updated 4.5 SharedEstateSettingsResponse = 0x0245, // updated 4.5
@ -225,16 +268,15 @@ namespace Sapphire::Network::Packets
DuelChallenge = 0x0277, // 4.2; this is responsible for opening the ui DuelChallenge = 0x0277, // 4.2; this is responsible for opening the ui
PerformNote = 0x0286, // updated 4.3 PerformNote = 0x0286, // updated 4.3
PrepareZoning = 0x0299, // updated 4.5 PrepareZoning = 0x026C, // updated 5.35 hotfix
ActorGauge = 0x0292, // updated 4.3 ActorGauge = 0x0112, // updated 5.35 hotfix
// Unknown IPC types that still need to be sent // daily quest info -> without them sent, login will take longer...
// TODO: figure all these out properly DailyQuests = 0x0139, // updated 5.35 hotfix
IPCTYPE_UNK_320 = 0x0253, // updated 4.5 DailyQuestRepeatFlags = 0x024C, // updated 5.35 hotfix
IPCTYPE_UNK_322 = 0x0255, // updated 4.5
/// Doman Mahjong ////////////////////////////////////// /// Doman Mahjong //////////////////////////////////////
MahjongOpenGui = 0x02BC, // only available in mahjong instance MahjongOpenGui = 0x02A4, // only available in mahjong instance
MahjongNextRound = 0x02BD, // initial hands(baipai), # of riichi(wat), winds, honba, score and stuff MahjongNextRound = 0x02BD, // initial hands(baipai), # of riichi(wat), winds, honba, score and stuff
MahjongPlayerAction = 0x02BE, // tsumo(as in drawing a tile) called chi/pon/kan/riichi MahjongPlayerAction = 0x02BE, // tsumo(as in drawing a tile) called chi/pon/kan/riichi
MahjongEndRoundTsumo = 0x02BF, // called tsumo MahjongEndRoundTsumo = 0x02BF, // called tsumo
@ -251,37 +293,43 @@ namespace Sapphire::Network::Packets
*/ */
enum ClientZoneIpcType : uint16_t enum ClientZoneIpcType : uint16_t
{ {
PingHandler = 0x0219, // updated 5.35 hotfix
InitHandler = 0x0185, // updated 5.35 hotfix
PingHandler = 0x0065, // unchanged 4.5 FinishLoadingHandler = 0x01BE, // updated 5.35 hotfix
InitHandler = 0x0066, // unchanged 4.5
FinishLoadingHandler = 0x0069, // unchanged 4.5 CFCommenceHandler = 0x0118, // updated 5.35 hotfix
CFCommenceHandler = 0x006F, CFCancelHandler = 0x0332, // updated 5.35 hotfix
CFRegisterDuty = 0x0289, // updated 5.35 hotfix
CFRegisterRoulette = 0x0088, // updated 5.35 hotfix
CFRegisterDuty = 0x0071, PlayTimeHandler = 0x02A8, // updated 5.35 hotfix
CFRegisterRoulette = 0x0072, LogoutHandler = 0x00EC, // updated 5.35 hotfix
PlayTimeHandler = 0x0073, // unchanged 4.5 CancelLogout = 0x03DB, // updated 5.35 hotfix
LogoutHandler = 0x0074, // unchanged 4.5
CFDutyInfoHandler = 0x0078, // updated 4.2 CFDutyInfoHandler = 0x0078, // updated 4.2
SocialReqSendHandler = 0x00AE, // updated 4.1 SocialReqSendHandler = 0x0387, // updated 5.35 hotfix
SocialResponseHandler = 0x028D, // updated 5.35 hotfix
CreateCrossWorldLS = 0x00AF, // updated 4.3 CreateCrossWorldLS = 0x00AF, // updated 4.3
ChatHandler = 0x00D7, // updated 4.5 ChatHandler = 0x0131, // updated 5.35 hotfix
PartyChatHandler = 0x0065,
PartySetLeaderHandler = 0x0208, // updated 5.35 hotfix
LeavePartyHandler = 0x0337, // updated 5.35 hotfix
KickPartyMemberHandler = 0x014C, // updated 5.35 hotfix
DisbandPartyHandler = 0x0205, // updated 5.35 hotfix
SocialListHandler = 0x00DF, // updated 4.5 SocialListHandler = 0x0340, // updated 5.35 hotfix
ReqSearchInfoHandler = 0x00E4, // updated 4.5 SetSearchInfoHandler = 0x0314, // updated 5.35 hotfix
ReqExamineSearchCommentHandler = 0x00E5, // updated 4.5 ReqSearchInfoHandler = 0x01E9, // updated 5.35 hotfix
ReqExamineSearchCommentHandler = 0x00E7, // updated 5.0
SetSearchInfoHandler = 0x00E2, // unchanged 4.5 ReqRemovePlayerFromBlacklist = 0x00F1, // updated 5.0
BlackListHandler = 0x0079, // updated 5.35 hotfix
PlayerSearchHandler = 0x00F4, // updated 5.0
BlackListHandler = 0x00F0, // updated 4.5 LinkshellListHandler = 0x024B, // updated 5.35 hotfix
PlayerSearchHandler = 0x00E6, // updated 4.5
LinkshellListHandler = 0x00F8, // updated 4.5
MarketBoardRequestItemListingInfo = 0x0102, // updated 4.5 MarketBoardRequestItemListingInfo = 0x0102, // updated 4.5
MarketBoardRequestItemListings = 0x0103, // updated 4.5 MarketBoardRequestItemListings = 0x0103, // updated 4.5
@ -291,58 +339,63 @@ namespace Sapphire::Network::Packets
FcInfoReqHandler = 0x011A, // updated 4.2 FcInfoReqHandler = 0x011A, // updated 4.2
FreeCompanyUpdateShortMessageHandler = 0x0123, // added 5.0
ReqMarketWishList = 0x012C, // updated 4.3 ReqMarketWishList = 0x012C, // updated 4.3
ReqJoinNoviceNetwork = 0x0129, // updated 4.2 ReqJoinNoviceNetwork = 0x0129, // updated 4.2
ReqCountdownInitiate = 0x0133, // updated 4.5 ReqCountdownInitiate = 0x009A, // updated 5.25
ReqCountdownCancel = 0x0134, // updated 4.5 ReqCountdownCancel = 0x0244, // updated 5.25
ClearWaymarks = 0x0135, // updated 4.5
ZoneLineHandler = 0x0137, // updated 4.5 ZoneLineHandler = 0x0279, // updated 5.35 hotfix
ClientTrigger = 0x0138, // updated 4.5 ClientTrigger = 0x03D3, // updated 5.35 hotfix
DiscoveryHandler = 0x0139, // updated 4.5 DiscoveryHandler = 0x00E3, // updated 5.35 hotfix
AddWaymark = 0x013A, // updated 4.5 PlaceFieldMarkerPreset = 0x023F, // updated 5.25
PlaceFieldMarker = 0x01BA, // updated 5.25
SkillHandler = 0x01CD, // updated 5.35 hotfix
GMCommand1 = 0x02AC, // updated 5.35 hotfix
GMCommand2 = 0x029F, // updated 5.35 hotfix
AoESkillHandler = 0x030C, // updated 5.35 hotfix
SkillHandler = 0x013B, // updated 4.5 UpdatePositionHandler = 0x0236, // updated 5.35 hotfix
GMCommand1 = 0x013C, // updated 4.5
GMCommand2 = 0x013D, // updated 4.5
AoESkillHandler = 0x13E, // updated 4.5
UpdatePositionHandler = 0x013F, // updated 4.5 InventoryModifyHandler = 0x0135, // updated 5.35 hotfix
UpdatePositionInstance = 0x0183, // updated 4.3
InventoryEquipRecommendedItems = 0x0149, // updated 5.0
InventoryModifyHandler = 0x0146, // updated 4.5 ( +4 ) ReqPlaceHousingItem = 0x014B, // updated 5.0
BuildPresetHandler = 0x0150, // updated 5.0
ReqPlaceHousingItem = 0x149, // updated 4.5 TalkEventHandler = 0x02A4, // updated 5.35 hotfix
EmoteEventHandler = 0x02C8, // updated 5.35 hotfix
WithinRangeEventHandler = 0x0209, // updated 5.35 hotfix
OutOfRangeEventHandler = 0x0319, // updated 5.35 hotfix
EnterTeriEventHandler = 0x0192, // updated 5.35 hotfix
ShopEventHandler = 0x0156, // updated 5.0
BuildPresetHandler = 0x014E, // updated 4.5 ReturnEventHandler = 0x02B4, // updated 5.35 hotfix
TalkEventHandler = 0x014F, // updated 4.5 TradeReturnEventHandler = 0x00A4, // updated 5.35 hotfix
EmoteEventHandler = 0x0150, // updated 4.5 TradeMultipleReturnEventHander = 0x035C, // updated 5.35 hotfix
WithinRangeEventHandler = 0x0151, // updated 4.5
OutOfRangeEventHandler = 0x0152, // updated 4.5
EnterTeriEventHandler = 0x0153, // updated 4.5
ShopEventHandler = 0x0155, // updated 4.5
ReturnEventHandler = 0x0158, // updated 4.5
TradeReturnEventHandler = 0x0159, // updated 4.5
LinkshellEventHandler = 0x016B, // updated 4.5 LinkshellEventHandler = 0x016B, // updated 4.5
LinkshellEventHandler1 = 0x016C, // updated 4.5 LinkshellEventHandler1 = 0x016C, // updated 4.5
LandRenameHandler = 0x0175, // updated 4.5 ReqEquipDisplayFlagsChange = 0x02F6, // updated 5.35 hotfix
HousingUpdateHouseGreeting = 0x0176, // updated 4.5
HousingUpdateObjectPosition = 0x0177, // updated 4.5
SetSharedEstateSettings = 0x017B, // updated 4.5 LandRenameHandler = 0xF177, // updated 5.0
HousingUpdateHouseGreeting = 0x0178, // updated 5.0
HousingUpdateObjectPosition = 0x0159, // updated 5.25
SetSharedEstateSettings = 0x017B, // updated 5.0
UpdatePositionInstance = 0x0345, // updated 5.35 hotfix
PerformNoteHandler = 0x029B, // updated 4.3 PerformNoteHandler = 0x029B, // updated 4.3
ReqEquipDisplayFlagsChange = 0x0173, // updated 4.5 WorldInteractionHandler = 0x00A9, // updated 5.35 hotfix
Dive = 0x02CC, // updated 5.35 hotfix
}; };
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -354,6 +407,8 @@ namespace Sapphire::Network::Packets
{ {
Tell = 0x0064, // updated for sb Tell = 0x0064, // updated for sb
TellErrNotFound = 0x0066, TellErrNotFound = 0x0066,
FreeCompanyEvent = 0x012C, // added 5.0
}; };
/** /**

View file

@ -4,10 +4,7 @@
#include <Common.h> #include <Common.h>
#include <Network/CommonNetwork.h> #include <Network/CommonNetwork.h>
namespace Sapphire { namespace Sapphire::Network::Packets::Server {
namespace Network {
namespace Packets {
namespace Server {
struct FFXIVIpcRetainerList : struct FFXIVIpcRetainerList :
FFXIVIpcBasePacket< LobbyRetainerList > FFXIVIpcBasePacket< LobbyRetainerList >
@ -152,7 +149,5 @@ struct FFXIVIpcLobbyError : FFXIVIpcBasePacket< LobbyError >
}; };
} }
}
}
}
#endif #endif

View file

@ -4,10 +4,8 @@
#include <Common.h> #include <Common.h>
#include <Network/CommonNetwork.h> #include <Network/CommonNetwork.h>
namespace Sapphire { namespace Sapphire::Network::Packets::Client
namespace Network { {
namespace Packets {
namespace Client {
struct FFXIVIpcGmCommand1 : struct FFXIVIpcGmCommand1 :
FFXIVIpcBasePacket< GMCommand1 > FFXIVIpcBasePacket< GMCommand1 >
@ -51,14 +49,25 @@ struct FFXIVIpcUpdatePosition :
FFXIVIpcBasePacket< UpdatePositionHandler > FFXIVIpcBasePacket< UpdatePositionHandler >
{ {
/* 0000 */ float rotation; /* 0000 */ float rotation;
/* 0004 */ uint8_t unk_1[ 3 ]; /* 0004 */ uint8_t animationType;
/* 0005 */ uint8_t animationState;
/* 0006 */ uint8_t clientAnimationType;
/* 0007 */ uint8_t headPosition; /* 0007 */ uint8_t headPosition;
/* 0008 */ uint8_t animationType; /* 0008 */ Common::FFXIVARR_POSITION3 position;
/* 0009 */ uint8_t animationState; /* 000C */ uint8_t unk[ 4 ]; // padding?
/* 000A */ uint8_t clientAnimationType;
/* 000B */ uint8_t unk_2;
/* 000C */ Common::FFXIVARR_POSITION3 position;
}; };
struct FFXIVIpcUpdatePositionInstance :
FFXIVIpcBasePacket< UpdatePositionInstance >
{
/* 0000 */ float rotation;
/* 0004 */ float interpolateRotation;
/* 0008 */ uint32_t flags;
/* 000C */ Common::FFXIVARR_POSITION3 position;
/* 0018 */ Common::FFXIVARR_POSITION3 interpolatePosition;
/* 0024 */ uint32_t unknown;
};
struct FFXIVIpcSkillHandler : struct FFXIVIpcSkillHandler :
FFXIVIpcBasePacket< SkillHandler > FFXIVIpcBasePacket< SkillHandler >
@ -198,6 +207,13 @@ struct FFXIVIpcChatHandler :
/* 001A */ char message[1012]; /* 001A */ char message[1012];
}; };
struct FFXIVIpcPartyChatHandler :
FFXIVIpcBasePacket< ChatHandler >
{
uint64_t unknown;
char message[1024];
};
struct FFXIVIpcShopEventHandler : struct FFXIVIpcShopEventHandler :
FFXIVIpcBasePacket< ShopEventHandler > FFXIVIpcBasePacket< ShopEventHandler >
{ {
@ -219,7 +235,7 @@ struct FFXIVIpcInventoryModifyHandler :
{ {
/* 0000 */ uint32_t seq; /* 0000 */ uint32_t seq;
/* 0004 */ Common::InventoryOperation action; /* 0004 */ Common::InventoryOperation action;
/* 0005 */ uint8_t pad_0005[7]; /* 0006 */ uint8_t pad_0006[6];
/* 000C */ uint16_t fromContainer; /* 000C */ uint16_t fromContainer;
/* 000E */ uint8_t pad_000E[2]; /* 000E */ uint8_t pad_000E[2];
/* 0010 */ uint8_t fromSlot; /* 0010 */ uint8_t fromSlot;
@ -325,9 +341,91 @@ struct FFXIVIpcMarketBoardRequestItemListingInfo :
/* 0000 */ uint32_t requestId; /* 0000 */ uint32_t requestId;
}; };
} struct FFXIVIpcFreeCompanyUpdateShortMessageHandler :
} FFXIVIpcBasePacket< FreeCompanyUpdateShortMessageHandler >
} {
char shortMessage[104];
uint8_t padding;
uint8_t unknown;
uint32_t unknown1;
uint16_t unknown2;
};
struct FFXIVIpcWorldInteractionHandler :
FFXIVIpcBasePacket< WorldInteractionHandler >
{
uint32_t action;
uint32_t param1;
uint32_t param2;
uint32_t param3;
uint32_t param4;
Common::FFXIVARR_POSITION3 position;
};
struct FFXIVIpcSocialReqSendHandler :
FFXIVIpcBasePacket< SocialReqSendHandler >
{
uint64_t unknown;
uint8_t p1;
uint8_t p2;
uint8_t socialType;
char name[32];
uint8_t padding[5];
};
struct FFXIVIpcSocialResponseHandler :
FFXIVIpcBasePacket< SocialResponseHandler >
{
uint64_t contentId;
uint8_t p1;
uint8_t p2;
uint8_t socialType;
uint8_t response;
uint32_t unknown;
};
struct FFXIVIpcPartySetLeaderHandler :
FFXIVIpcBasePacket< PartySetLeaderHandler >
{
uint64_t contentId;
uint8_t p1;
uint8_t p2;
char name[32];
uint8_t padding[6];
};
struct FFXIVIpcLeavePartyHandler :
FFXIVIpcBasePacket< LeavePartyHandler >
{
uint64_t empty;
};
struct FFXIVIpcKickPartyMemberHander :
FFXIVIpcBasePacket< KickPartyMemberHandler >
{
uint64_t contentId;
uint8_t p1;
uint8_t p2;
char name[32];
uint8_t padding[6];
};
struct FFXIVIpcDisbandPartyHandler :
FFXIVIpcBasePacket< DisbandPartyHandler >
{
uint64_t empty;
};
struct FFXIVIpcDive :
FFXIVIpcBasePacket< Dive >
{
float unknown;
Common::FFXIVARR_POSITION3 posTarget;
Common::FFXIVARR_POSITION3 posOriginal;
uint32_t padding;
};
} }
#endif //_CORE_NETWORK_PACKETS_ZONE_CLIENT_IPC_H #endif //_CORE_NETWORK_PACKETS_ZONE_CLIENT_IPC_H

File diff suppressed because it is too large Load diff

115
src/common/Service.h Normal file
View file

@ -0,0 +1,115 @@
#ifndef SAPPHIRE_SERVICE_H
#define SAPPHIRE_SERVICE_H
#include <memory>
#include <utility>
#include <cassert>
// stolen from: https://github.com/skypjack/entt/blob/master/src/entt/locator/locator.hpp
namespace Sapphire::Common
{
/**
* @brief Service locator, nothing more.
*
* A service locator can be used to do what it promises: locate services.<br/>
* Usually service locators are tightly bound to the services they expose and
* thus it's hard to define a general purpose class to do that. This template
* based implementation tries to fill the gap and to get rid of the burden of
* defining a different specific locator for each application.
*
* @tparam SvcType Type of service managed by the locator.
*/
template< typename SvcType >
struct Service
{
/*! @brief Type of service offered. */
using ServiceType = SvcType;
/*! @brief Default constructor, deleted on purpose. */
Service() = delete;
/*! @brief Default destructor, deleted on purpose. */
~Service() = delete;
/**
* @brief Tests if a valid service implementation is set.
* @return True if the service is set, false otherwise.
*/
static bool empty() noexcept
{
return !static_cast< bool >( service );
}
/**
* @brief Returns a weak pointer to a service implementation, if any.
*
* Clients of a service shouldn't retain references to it. The recommended
* way is to retrieve the service implementation currently set each and
* every time the need of using it arises. Otherwise users can incur in
* unexpected behaviors.
*
* @return A reference to the service implementation currently set, if any.
*/
static std::weak_ptr< SvcType > get() noexcept
{
return service;
}
/**
* @brief Returns a weak reference to a service implementation, if any.
*
* Clients of a service shouldn't retain references to it. The recommended
* way is to retrieve the service implementation currently set each and
* every time the need of using it arises. Otherwise users can incur in
* unexpected behaviors.
*
* @warning
* In case no service implementation has been set, a call to this function
* results in undefined behavior.
*
* @return A reference to the service implementation currently set, if any.
*/
static SvcType& ref() noexcept
{
return *service;
}
/**
* @brief Sets or replaces a service.
* @tparam Impl Type of the new service to use.
* @tparam Args Types of arguments to use to construct the service.
* @param args Parameters to use to construct the service.
*/
template< typename Impl = SvcType, typename... Args >
static void set( Args&& ... args )
{
service = std::make_shared< Impl >( std::forward< Args >( args )... );
}
/**
* @brief Sets or replaces a service.
* @param ptr Service to use to replace the current one.
*/
static void set( std::shared_ptr< SvcType > ptr )
{
assert( static_cast< bool >( ptr ) );
service = std::move( ptr );
}
/**
* @brief Resets a service.
*
* The service is no longer valid after a reset.
*/
static void reset()
{
service.reset();
}
private:
inline static std::shared_ptr< SvcType > service = nullptr;
};
}
#endif //SAPPHIRE_SERVICE_H

Some files were not shown because too many files have changed in this diff Show more