1
Fork 0
mirror of https://github.com/SapphireServer/Sapphire.git synced 2025-04-25 22:17:45 +00:00

Merge branch 'develop' of https://github.com/SapphireMordred/Sapphire into develop

# Conflicts:
#	.appveyor.yml
#	.gitmodules
#	.travis.yml
#	CMakeLists.txt
#	CMakeSettings.json
#	README.md
#	cmake/FindMySQL.cmake
#	cmake/paths.cmake
#	deps/datReader/Dat.cpp
#	deps/datReader/Dat.h
#	deps/datReader/DatCat.cpp
#	deps/datReader/DatCat.h
#	deps/datReader/DatCategories/bg/lgb.h
#	deps/datReader/DatCategories/bg/sgb.h
#	deps/datReader/Exd.cpp
#	deps/datReader/Exd.h
#	deps/datReader/ExdCat.cpp
#	deps/datReader/ExdCat.h
#	deps/datReader/ExdData.cpp
#	deps/datReader/ExdData.h
#	deps/datReader/Exh.cpp
#	deps/datReader/Exh.h
#	deps/datReader/File.cpp
#	deps/datReader/File.h
#	deps/datReader/GameData.cpp
#	deps/datReader/GameData.h
#	deps/datReader/Index.cpp
#	deps/datReader/Index.h
#	deps/datReader/SqPack.cpp
#	deps/datReader/SqPack.h
#	deps/datReader/bparse.cpp
#	deps/datReader/bparse.h
#	deps/datReader/conv.cpp
#	deps/datReader/conv.h
#	deps/datReader/crc32.cpp
#	deps/datReader/crc32.h
#	deps/datReader/stream.cpp
#	deps/datReader/stream.h
#	deps/datReader/zlib.cpp
#	deps/datReader/zlib.h
#	deps/mysqlConnector/Connection.cpp
#	deps/mysqlConnector/Connection.h
#	deps/watchdog/Watchdog.h
#	sql/schema/inserts.sql
#	sql/schema/schema.sql
#	src/api/PlayerMinimal.h
#	src/api/SapphireApi.cpp
#	src/api/main.cpp
#	src/common/Common.h
#	src/common/CommonGen.h
#	src/common/Config/ConfigMgr.cpp
#	src/common/Database/DbCommon.h
#	src/common/Database/DbConnection.cpp
#	src/common/Database/DbWorkerPool.cpp
#	src/common/Exd/ExdDataGenerated.cpp
#	src/common/Exd/ExdDataGenerated.h
#	src/common/Logging/Logger.cpp
#	src/common/Network/CommonActorControl.h
#	src/common/Network/Connection.cpp
#	src/common/Network/Connection.h
#	src/common/Network/PacketDef/Ipcs.h
#	src/common/Network/PacketDef/Zone/ClientZoneDef.h
#	src/common/Network/PacketDef/Zone/ServerZoneDef.h
#	src/common/Util/Util.cpp
#	src/common/Util/UtilMath.cpp
#	src/common/Util/UtilMath.h
#	src/dbm/DbManager.cpp
#	src/dbm/main.cpp
#	src/lobby/Forwards.h
#	src/lobby/GameConnection.cpp
#	src/lobby/GameConnection.h
#	src/lobby/ServerLobby.cpp
#	src/lobby/mainLobbyServer.cpp
#	src/scripts/action/common/ActionSprint3.cpp
#	src/scripts/common/CmnDefCutSceneReplay.cpp
#	src/scripts/common/GilShop.cpp
#	src/scripts/common/aethernet/Aetheryte.cpp
#	src/scripts/common/aethernet/HousingAethernet.cpp
#	src/scripts/common/eobj/HousingEstateEntrance.cpp
#	src/scripts/common/housing/CmnDefHousingSignboard.cpp
#	src/scripts/common/warptaxi/WarpTaxi.cpp
#	src/scripts/instances/questbattles/ChasingShadows.cpp
#	src/scripts/quest/ManFst001.cpp
#	src/scripts/quest/ManFst002.cpp
#	src/scripts/quest/ManFst003.cpp
#	src/scripts/quest/ManFst004.cpp
#	src/scripts/quest/ManFst005.cpp
#	src/scripts/quest/ManSea001.cpp
#	src/scripts/quest/ManSea002.cpp
#	src/scripts/quest/ManSea003.cpp
#	src/scripts/quest/ManWil001.cpp
#	src/scripts/quest/ManWil002.cpp
#	src/scripts/quest/ManWil003.cpp
#	src/scripts/quest/ManWil004.cpp
#	src/scripts/quest/subquest/gridania/SubFst001.cpp
#	src/scripts/quest/subquest/gridania/SubFst002.cpp
#	src/scripts/quest/subquest/gridania/SubFst003.cpp
#	src/scripts/quest/subquest/gridania/SubFst004.cpp
#	src/scripts/quest/subquest/gridania/SubFst005.cpp
#	src/scripts/quest/subquest/gridania/SubFst008.cpp
#	src/scripts/quest/subquest/gridania/SubFst009.cpp
#	src/scripts/quest/subquest/gridania/SubFst010.cpp
#	src/scripts/quest/subquest/gridania/SubFst011.cpp
#	src/scripts/quest/subquest/gridania/SubFst013.cpp
#	src/scripts/quest/subquest/gridania/SubFst014.cpp
#	src/scripts/quest/subquest/gridania/SubFst015.cpp
#	src/scripts/quest/subquest/gridania/SubFst019.cpp
#	src/scripts/quest/subquest/gridania/SubFst026.cpp
#	src/scripts/quest/subquest/gridania/SubFst029.cpp
#	src/scripts/quest/subquest/gridania/SubFst030.cpp
#	src/scripts/quest/subquest/gridania/SubFst034.cpp
#	src/scripts/quest/subquest/gridania/SubFst039.cpp
#	src/scripts/quest/subquest/gridania/SubFst041.cpp
#	src/scripts/quest/subquest/gridania/SubFst045.cpp
#	src/scripts/quest/subquest/limsa/SubSea001.cpp
#	src/scripts/quest/subquest/limsa/SubSea012.cpp
#	src/scripts/quest/subquest/uldah/SubWil000.cpp
#	src/scripts/quest/subquest/uldah/SubWil001.cpp
#	src/scripts/quest/subquest/uldah/SubWil002.cpp
#	src/scripts/quest/subquest/uldah/SubWil004.cpp
#	src/scripts/quest/subquest/uldah/SubWil006.cpp
#	src/scripts/quest/subquest/uldah/SubWil007.cpp
#	src/scripts/quest/subquest/uldah/SubWil018.cpp
#	src/scripts/quest/subquest/uldah/SubWil019.cpp
#	src/scripts/quest/subquest/uldah/SubWil020.cpp
#	src/scripts/quest/subquest/uldah/SubWil021.cpp
#	src/scripts/quest/subquest/uldah/SubWil022.cpp
#	src/scripts/quest/subquest/uldah/SubWil027.cpp
#	src/scripts/quest/subquest/uldah/SubWil028.cpp
#	src/scripts/quest/subquest/uldah/SubWil029.cpp
#	src/tools/action_parse/main.cpp
#	src/tools/discovery_parser/main.cpp
#	src/tools/event_object_parser/instance.tmpl
#	src/tools/event_object_parser/main.cpp
#	src/tools/event_object_parser/questbattle.tmpl
#	src/tools/exd_common_gen/main.cpp
#	src/tools/exd_struct_gen/ExdData.cpp.tmpl
#	src/tools/exd_struct_gen/ExdData.h.tmpl
#	src/tools/exd_struct_gen/main.cpp
#	src/tools/exd_struct_test/main.cpp
#	src/tools/mob_parse/main.cpp
#	src/tools/nav_export/lgb.h
#	src/tools/nav_export/main.cpp
#	src/tools/nav_export/nav/TiledNavmeshGenerator.cpp
#	src/tools/nav_export/navmesh_exporter.h
#	src/tools/nav_export/obj_exporter.h
#	src/tools/pcb_reader/lgb.h
#	src/tools/pcb_reader/main.cpp
#	src/tools/pcb_reader/nav/TiledNavmeshGenerator.cpp
#	src/tools/pcb_reader/navmesh_exporter.h
#	src/tools/pcb_reader/obj_exporter.h
#	src/tools/quest_parser/main.cpp
#	src/tools/questbattle_bruteforce/main.cpp
#	src/world/Action/Action.cpp
#	src/world/Action/Action.h
#	src/world/Action/ActionLut.h
#	src/world/Action/ActionLutData.cpp
#	src/world/Action/EffectBuilder.cpp
#	src/world/Action/EffectBuilder.h
#	src/world/Action/EffectResult.cpp
#	src/world/Action/EffectResult.h
#	src/world/Action/EventAction.cpp
#	src/world/Action/EventAction.h
#	src/world/Action/ItemAction.cpp
#	src/world/Action/ItemAction.h
#	src/world/Actor/Actor.cpp
#	src/world/Actor/Actor.h
#	src/world/Actor/BNpc.cpp
#	src/world/Actor/BNpc.h
#	src/world/Actor/Chara.cpp
#	src/world/Actor/Chara.h
#	src/world/Actor/EventObject.cpp
#	src/world/Actor/EventObject.h
#	src/world/Actor/Npc.cpp
#	src/world/Actor/Npc.h
#	src/world/Actor/Player.cpp
#	src/world/Actor/Player.h
#	src/world/Actor/PlayerEvent.cpp
#	src/world/Actor/PlayerInventory.cpp
#	src/world/Actor/PlayerQuest.cpp
#	src/world/Actor/PlayerSql.cpp
#	src/world/Event/Director.cpp
#	src/world/Event/Director.h
#	src/world/Event/EventHandler.h
#	src/world/ForwardsZone.h
#	src/world/Inventory/HousingItem.cpp
#	src/world/Inventory/HousingItem.h
#	src/world/Inventory/Item.cpp
#	src/world/Inventory/Item.h
#	src/world/Inventory/ItemContainer.cpp
#	src/world/Inventory/ItemContainer.h
#	src/world/Linkshell/Linkshell.h
#	src/world/Manager/ActionMgr.cpp
#	src/world/Manager/ActionMgr.h
#	src/world/Manager/DebugCommandMgr.cpp
#	src/world/Manager/DebugCommandMgr.h
#	src/world/Manager/EventMgr.cpp
#	src/world/Manager/EventMgr.h
#	src/world/Manager/HousingMgr.cpp
#	src/world/Manager/HousingMgr.h
#	src/world/Manager/InventoryMgr.cpp
#	src/world/Manager/InventoryMgr.h
#	src/world/Manager/ItemMgr.cpp
#	src/world/Manager/ItemMgr.h
#	src/world/Manager/LinkshellMgr.cpp
#	src/world/Manager/LinkshellMgr.h
#	src/world/Manager/MarketMgr.cpp
#	src/world/Manager/MarketMgr.h
#	src/world/Manager/NaviMgr.cpp
#	src/world/Manager/NaviMgr.h
#	src/world/Manager/PlayerMgr.cpp
#	src/world/Manager/PlayerMgr.h
#	src/world/Manager/RNGMgr.cpp
#	src/world/Manager/RNGMgr.h
#	src/world/Manager/ShopMgr.cpp
#	src/world/Manager/ShopMgr.h
#	src/world/Manager/TerritoryMgr.cpp
#	src/world/Manager/TerritoryMgr.h
#	src/world/Math/CalcBattle.cpp
#	src/world/Math/CalcStats.cpp
#	src/world/Math/CalcStats.h
#	src/world/Navi/NaviProvider.cpp
#	src/world/Navi/NaviProvider.h
#	src/world/Network/GameConnection.cpp
#	src/world/Network/GameConnection.h
#	src/world/Network/Handlers/ActionHandler.cpp
#	src/world/Network/Handlers/CFHandlers.cpp
#	src/world/Network/Handlers/ClientTriggerHandler.cpp
#	src/world/Network/Handlers/EventHandlers.cpp
#	src/world/Network/Handlers/GMCommandHandlers.cpp
#	src/world/Network/Handlers/InventoryHandler.cpp
#	src/world/Network/Handlers/PacketHandlers.cpp
#	src/world/Network/PacketWrappers/ActorControlSelfPacket.h
#	src/world/Network/PacketWrappers/EffectPacket.h
#	src/world/Network/PacketWrappers/ExaminePacket.h
#	src/world/Network/PacketWrappers/NpcSpawnPacket.h
#	src/world/Network/PacketWrappers/PlayerSetupPacket.h
#	src/world/Network/PacketWrappers/PlayerSpawnPacket.h
#	src/world/Network/PacketWrappers/UpdateInventorySlotPacket.h
#	src/world/Script/NativeScriptApi.cpp
#	src/world/Script/NativeScriptApi.h
#	src/world/Script/NativeScriptMgr.cpp
#	src/world/Script/NativeScriptMgr.h
#	src/world/Script/ScriptLoader.cpp
#	src/world/Script/ScriptMgr.cpp
#	src/world/Script/ScriptMgr.h
#	src/world/ServerMgr.cpp
#	src/world/ServerMgr.h
#	src/world/Session.cpp
#	src/world/Session.h
#	src/world/StatusEffect/StatusEffect.cpp
#	src/world/StatusEffect/StatusEffect.h
#	src/world/Territory/Cell.cpp
#	src/world/Territory/House.cpp
#	src/world/Territory/House.h
#	src/world/Territory/Housing/HousingInteriorTerritory.cpp
#	src/world/Territory/Housing/HousingInteriorTerritory.h
#	src/world/Territory/HousingZone.cpp
#	src/world/Territory/HousingZone.h
#	src/world/Territory/InstanceContent.cpp
#	src/world/Territory/InstanceContent.h
#	src/world/Territory/Land.cpp
#	src/world/Territory/Land.h
#	src/world/Territory/QuestBattle.cpp
#	src/world/Territory/QuestBattle.h
#	src/world/Territory/Territory.cpp
#	src/world/Territory/Territory.h
#	src/world/mainGameServer.cpp
This commit is contained in:
Mordred 2021-11-22 23:29:45 +01:00
commit dceff7eed6
297 changed files with 26272 additions and 12399 deletions

View file

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

3
.gitmodules vendored
View file

@ -7,3 +7,6 @@
[submodule "deps/recastnavigation"]
path = deps/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:
- ubuntu-toolchain-r-test
packages:
- g++-7
- g++-8
env:
- MATRIX_EVAL="CC=gcc-7 && CXX=g++-7"
- MATRIX_EVAL="CC=gcc-8 && CXX=g++-8"
- CXX=g++-8
# Setup 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}/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 ${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 #

View file

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

View file

@ -18,7 +18,7 @@ Sapphire requires the following software:
| *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 |
Please check the [wiki](https://github.com/SapphireMordred/Sapphire/wiki) for detailed installation/build instructions for your OS.

View file

@ -85,6 +85,8 @@ find_path(MYSQL_INCLUDE_DIR
"${PROGRAM_FILES_64}/MySQL/MySQL Server 5.7/include"
"${PROGRAM_FILES_64}/MySQL/include"
"${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"
"[HKEY_LOCAL_MACHINE\\SOFTWARE\\MySQL AB\\MySQL Server 5.7;Location]/include"
"$ENV{ProgramFiles}/MySQL/MySQL Server 5.7/include"
@ -124,6 +126,8 @@ if( WIN32 )
"${PROGRAM_FILES_64}/MySQL/MySQL Server 5.7/lib/opt"
"${PROGRAM_FILES_64}/MySQL/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"
"[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"
@ -177,6 +181,8 @@ if( WIN32 )
"${PROGRAM_FILES_64}/MySQL/MySQL Server 5.7/bin/opt"
"${PROGRAM_FILES_64}/MySQL/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"
"[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"

View file

@ -13,3 +13,4 @@ endif()
# Create log folder
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/data )

509
deps/datReader/Dat.cpp vendored
View file

@ -4,308 +4,319 @@
#include "File.h"
namespace
{
const uint32_t model_section_count = 0xB;
namespace {
const uint32_t model_section_count = 0xB;
}
namespace xiv
namespace xiv::dat
{
namespace dat
{
struct DatFileHeader
{
uint32_t size;
FileType entry_type;
uint32_t total_uncompressed_size;
uint32_t unknown[0x2];
};
struct DatFileHeader
{
uint32_t size;
FileType entry_type;
uint32_t total_uncompressed_size;
uint32_t unknown[0x2];
};
struct DatBlockRecord
{
uint32_t offset;
uint32_t size;
uint32_t unknown[0x4];
SqPackBlockHash block_hash;
};
struct DatBlockRecord
{
uint32_t offset;
uint32_t size;
uint32_t unknown[0x4];
SqPackBlockHash block_hash;
};
struct DatBlockHeader
{
uint32_t size;
uint32_t unknown1;
uint32_t compressed_size;
uint32_t uncompressed_size;
};
struct DatBlockHeader
{
uint32_t size;
uint32_t unknown1;
uint32_t compressed_size;
uint32_t uncompressed_size;
};
struct DatStdFileBlockInfos
{
uint32_t offset;
uint16_t size;
uint16_t uncompressed_size;
};
struct DatStdFileBlockInfos
{
uint32_t offset;
uint16_t size;
uint16_t uncompressed_size;
};
struct DatMdlFileBlockInfos
{
uint32_t unknown1;
uint32_t uncompressed_sizes[::model_section_count];
uint32_t compressed_sizes[::model_section_count];
uint32_t offsets[::model_section_count];
uint16_t block_ids[::model_section_count];
uint16_t block_counts[::model_section_count];
uint32_t unknown2[0x2];
};
struct DatMdlFileBlockInfos
{
uint32_t unknown1;
uint32_t uncompressed_sizes[::model_section_count];
uint32_t compressed_sizes[::model_section_count];
uint32_t offsets[::model_section_count];
uint16_t block_ids[::model_section_count];
uint16_t block_counts[::model_section_count];
uint32_t unknown2[0x2];
};
struct DatTexFileBlockInfos
{
uint32_t offset;
uint32_t size;
uint32_t uncompressed_size;
uint32_t block_id;
uint32_t block_count;
};
}
struct DatTexFileBlockInfos
{
uint32_t offset;
uint32_t size;
uint32_t uncompressed_size;
uint32_t block_id;
uint32_t block_count;
};
}
namespace xiv
namespace xiv::utils::bparse
{
namespace utils
{
namespace bparse
{
template <>
inline void reorder<xiv::dat::DatFileHeader>(xiv::dat::DatFileHeader& i_struct)
{
xiv::utils::bparse::reorder(i_struct.size);
xiv::utils::bparse::reorder(i_struct.entry_type);
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<>
inline void reorder< xiv::dat::DatFileHeader >( xiv::dat::DatFileHeader& i_struct )
{
xiv::utils::bparse::reorder( i_struct.size );
xiv::utils::bparse::reorder( i_struct.entry_type );
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 <>
inline void reorder<xiv::dat::DatBlockRecord>(xiv::dat::DatBlockRecord& i_struct)
{
xiv::utils::bparse::reorder(i_struct.offset);
xiv::utils::bparse::reorder(i_struct.size);
for (int32_t i = 0; i < 0x4; ++i) { xiv::utils::bparse::reorder(i_struct.unknown[i]); }
xiv::utils::bparse::reorder(i_struct.block_hash);
}
template<>
inline void reorder< xiv::dat::DatBlockRecord >( xiv::dat::DatBlockRecord& i_struct )
{
xiv::utils::bparse::reorder( i_struct.offset );
xiv::utils::bparse::reorder( i_struct.size );
for( int32_t i = 0; i < 0x4; ++i )
{
xiv::utils::bparse::reorder( i_struct.unknown[ i ] );
}
xiv::utils::bparse::reorder( i_struct.block_hash );
}
template <>
inline void reorder<xiv::dat::DatBlockHeader>(xiv::dat::DatBlockHeader& i_struct)
{
xiv::utils::bparse::reorder(i_struct.size);
xiv::utils::bparse::reorder(i_struct.unknown1);
xiv::utils::bparse::reorder(i_struct.compressed_size);
xiv::utils::bparse::reorder(i_struct.uncompressed_size);
}
template<>
inline void reorder< xiv::dat::DatBlockHeader >( xiv::dat::DatBlockHeader& i_struct )
{
xiv::utils::bparse::reorder( i_struct.size );
xiv::utils::bparse::reorder( i_struct.unknown1 );
xiv::utils::bparse::reorder( i_struct.compressed_size );
xiv::utils::bparse::reorder( i_struct.uncompressed_size );
}
template <>
inline void reorder<xiv::dat::DatStdFileBlockInfos>(xiv::dat::DatStdFileBlockInfos& i_struct)
{
xiv::utils::bparse::reorder(i_struct.offset);
xiv::utils::bparse::reorder(i_struct.size);
xiv::utils::bparse::reorder(i_struct.uncompressed_size);
}
template<>
inline void reorder< xiv::dat::DatStdFileBlockInfos >( xiv::dat::DatStdFileBlockInfos& i_struct )
{
xiv::utils::bparse::reorder( i_struct.offset );
xiv::utils::bparse::reorder( i_struct.size );
xiv::utils::bparse::reorder( i_struct.uncompressed_size );
}
template <>
inline void reorder<xiv::dat::DatMdlFileBlockInfos>(xiv::dat::DatMdlFileBlockInfos& i_struct)
{
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) { 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<>
inline void reorder< xiv::dat::DatMdlFileBlockInfos >( xiv::dat::DatMdlFileBlockInfos& i_struct )
{
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 )
{
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 <>
inline void reorder<xiv::dat::DatTexFileBlockInfos>(xiv::dat::DatTexFileBlockInfos& i_struct)
{
xiv::utils::bparse::reorder(i_struct.offset);
xiv::utils::bparse::reorder(i_struct.size);
xiv::utils::bparse::reorder(i_struct.uncompressed_size);
xiv::utils::bparse::reorder(i_struct.block_id);
xiv::utils::bparse::reorder(i_struct.block_count);
}
template<>
inline void reorder< xiv::dat::DatTexFileBlockInfos >( xiv::dat::DatTexFileBlockInfos& i_struct )
{
xiv::utils::bparse::reorder( i_struct.offset );
xiv::utils::bparse::reorder( i_struct.size );
xiv::utils::bparse::reorder( i_struct.uncompressed_size );
xiv::utils::bparse::reorder( i_struct.block_id );
xiv::utils::bparse::reorder( i_struct.block_count );
}
}
}
};
using xiv::utils::bparse::extract;
namespace xiv
{
namespace dat
namespace xiv::dat
{
Dat::Dat( const std::experimental::filesystem::path& i_path, uint32_t i_nb ) :
SqPack( i_path ),
m_num( i_nb )
{
auto block_record = extract<DatBlockRecord>(m_handle);
block_record.offset *= 0x80;
isBlockValid(block_record.offset, block_record.size, block_record.block_hash);
}
Dat::Dat( const std::filesystem::path& i_path, uint32_t i_nb ) :
SqPack( i_path ),
m_num( i_nb )
{
auto block_record = extract< DatBlockRecord >( m_handle );
block_record.offset *= 0x80;
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> outputFile(new File());
{
std::unique_ptr< File > Dat::getFile( uint32_t i_offset )
{
std::unique_ptr< File > outputFile( new File() );
{
// 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
m_handle.seekg(i_offset);
auto file_header = extract<DatFileHeader>(m_handle);
m_handle.seekg( i_offset );
auto file_header = extract< DatFileHeader >( m_handle );
switch (file_header.entry_type)
switch( file_header.entry_type )
{
case FileType::empty:
throw std::runtime_error("File is empty");
case FileType::empty:
throw std::runtime_error( "File is empty" );
case FileType::standard:
{
outputFile->_type = FileType::standard;
case 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
std::vector<DatStdFileBlockInfos> std_file_block_infos;
extract<DatStdFileBlockInfos>( m_handle, number_of_blocks, std_file_block_infos );
// Just extract offset infos for the blocks to extract
std::vector< DatStdFileBlockInfos > std_file_block_infos;
extract< DatStdFileBlockInfos >( m_handle, number_of_blocks, std_file_block_infos );
// Pre allocate data vector for the whole file
outputFile->_data_sections.resize(1);
auto& data_section = outputFile->_data_sections.front();
// Pre allocate data vector for the whole file
outputFile->_data_sections.resize( 1 );
auto& data_section = outputFile->_data_sections.front();
data_section.reserve(file_header.total_uncompressed_size);
// Extract each block
for (auto& file_block_info : std_file_block_infos)
data_section.reserve( file_header.total_uncompressed_size );
// Extract each block
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:
{
outputFile->_type = FileType::model;
case FileType::texture:
{
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
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);
std::vector< DatTexFileBlockInfos > texBlockInfo;
extract< DatTexFileBlockInfos >( m_handle, sectionCount, texBlockInfo );
// Preallocate sufficient space
outputFile->_data_sections.resize(::model_section_count);
// 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 );
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
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(current_offset, data_section);
current_offset += block_sizes[mdlBlockInfo.block_ids[i] + j];
}
extractBlock( current_offset, data_section );
current_offset += block_sizes[ section_infos.block_id + j ];
}
}
break;
}
}
break;
case FileType::texture:
{
outputFile->_type = FileType::texture;
// 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)));
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 )
{
m_handle.seekg(i_offset);
void Dat::extractBlock( uint32_t i_offset, std::vector< char >& o_data )
{
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
const uint32_t data_size = o_data.size();
o_data.resize(data_size + block_header.uncompressed_size);
// Resizing the vector to write directly into it
const uint32_t data_size = o_data.size();
o_data.resize( data_size + block_header.uncompressed_size );
// 32000 in compressed_size means it is not compressed so take uncompressed_size
if (block_header.compressed_size == 32000)
{
m_handle.read(o_data.data() + data_size, block_header.uncompressed_size);
}
else
{
// 32000 in compressed_size means it is not compressed so take uncompressed_size
if( block_header.compressed_size == 32000 )
{
m_handle.read( o_data.data() + data_size, block_header.uncompressed_size );
}
else
{
// If it is compressed use zlib
// Read the data to be decompressed
std::vector<char> temp_buffer(block_header.compressed_size);
m_handle.read(temp_buffer.data(), block_header.compressed_size);
std::vector< char > temp_buffer( 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()),
temp_buffer.size(),
reinterpret_cast<uint8_t*>(o_data.data() + data_size),
block_header.uncompressed_size);
}
}
utils::zlib::no_header_decompress( reinterpret_cast<uint8_t*>(temp_buffer.data()),
temp_buffer.size(),
reinterpret_cast<uint8_t*>(o_data.data() + data_size),
block_header.uncompressed_size );
}
}
uint32_t Dat::getNum() const
{
return m_num;
}
uint32_t Dat::getNum() const
{
return m_num;
}
}
}

47
deps/datReader/Dat.h vendored
View file

@ -5,41 +5,38 @@
#include <mutex>
#include <experimental/filesystem>
#include <filesystem>
namespace xiv
{
namespace dat
namespace xiv::dat
{
class File;
class File;
class Dat : public SqPack
{
public:
// Full path to the dat file
Dat( const std::experimental::filesystem::path& i_path, uint32_t i_nb );
virtual ~Dat();
class Dat : public SqPack
{
public:
// Full path to the dat file
Dat( const std::filesystem::path& i_path, uint32_t i_nb );
virtual ~Dat();
// Retrieves a file given the offset in the dat file
std::unique_ptr<File> getFile( uint32_t i_offset );
// Retrieves a file given the offset in the dat file
std::unique_ptr<File> getFile( uint32_t i_offset );
// 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
void extractBlock( uint32_t i_offset, std::vector<char>& o_data );
// 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
void extractBlock( uint32_t i_offset, std::vector<char>& o_data );
// Returns the dat number
uint32_t getNum() const;
// Returns the dat number
uint32_t getNum() const;
protected:
// File reading mutex to have only one thread reading the file at a time
std::mutex m_fileMutex;
protected:
// File reading mutex to have only one thread reading the file at a time
std::mutex m_fileMutex;
// Dat nb
uint32_t m_num;
};
// Dat nb
uint32_t m_num;
};
}
}
#endif // XIV_DAT_DAT_H

View file

@ -10,7 +10,7 @@ namespace xiv
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_catNum( catNum ),
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";
// 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( 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_catNum( catNum ),
m_chunk( chunk )
{
// 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( 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 <vector>
#include <experimental/filesystem>
#include <filesystem>
namespace xiv {
namespace dat {
class Index;
class Dat;
class File;
// A category represents an .index and its associated .datX
class Cat
namespace xiv::dat
{
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
// 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();
class Index;
// Returns .index of the category
const Index& getIndex() const;
class Dat;
// Retrieve a file from the category given its hashes
std::unique_ptr<File> getFile( uint32_t dir_hash, uint32_t filename_hash ) const;
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::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 doesDirExist( uint32_t dir_hash ) const;
bool doesFileExist( uint32_t dir_hash, uint32_t filename_hash ) const;
bool doesDirExist( uint32_t dir_hash ) const;
// Returns thename of the category
const std::string& getName() const;
// Returns thename of the category
const std::string& getName() const;
// Returns the number of the category
uint32_t getCatNum() const;
// Returns the number of the category
uint32_t getCatNum() const;
protected:
const std::string m_name;
const uint32_t m_catNum;
const uint32_t m_chunk;
protected:
const std::string m_name;
const uint32_t m_catNum;
const uint32_t m_chunk;
// The .index
std::unique_ptr<Index> m_index;
// The .index
std::unique_ptr< Index > m_index;
// The .datXs such as dat nb X => m_dats[X]
std::vector<std::unique_ptr<Dat>> m_dats;
};
// The .datXs such as dat nb X => m_dats[X]
std::vector< std::unique_ptr< Dat>> m_dats;
};
}
}
#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 "vec3.h"
#include "sgb.h"
#include "LgbTypes.h"
// garbage to skip model loading
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#
// based on https://github.com/ufx/SaintCoinach/blob/master/SaintCoinach/Graphics/Lgb/
struct LGB_FILE;
struct LGB_FILE_HEADER;
struct LGB_GROUP;
struct LGB_GROUP_HEADER;
enum class LgbEntryType :
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
class LgbEntry
{
public:
char* m_buf;
uint32_t m_offset;
LGB_ENTRY_HEADER header;
InstanceObject header;
LGB_ENTRY()
LgbEntry()
{
m_buf = nullptr;
m_offset = 0;
memset( &header, 0, sizeof( header ) );
};
LGB_ENTRY( char* buf, uint32_t offset )
LgbEntry( char* buf, uint32_t offset )
{
m_buf = buf;
m_offset = offset;
header = *reinterpret_cast< LGB_ENTRY_HEADER* >( buf + offset );
header = *reinterpret_cast< InstanceObject* >( buf + offset );
};
const LgbEntryType getType() const
@ -100,30 +46,16 @@ public:
return header.type;
};
virtual ~LGB_ENTRY()
virtual ~LgbEntry()
{
};
};
struct LGB_BGPARTS_HEADER :
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
class LGB_BGPARTS_ENTRY : public LgbEntry
{
public:
LGB_BGPARTS_HEADER header;
BgPartsData data;
std::string name;
std::string modelFileName;
std::string collisionFileName;
@ -132,124 +64,94 @@ public:
{
};
LGB_BGPARTS_ENTRY( char* buf, uint32_t offset ) :
LGB_ENTRY( buf, offset )
LGB_BGPARTS_ENTRY( char* buf, uint32_t offset ) : LgbEntry( buf, offset )
{
header = *reinterpret_cast<LGB_BGPARTS_HEADER*>( buf + offset );
data = *reinterpret_cast< BgPartsData* >( buf + offset );
name = std::string( buf + offset + header.nameOffset );
modelFileName = std::string( buf + offset + header.modelFileOffset );
collisionFileName = std::string( buf + offset + header.collisionFileOffset );
modelFileName = std::string( buf + offset + data.modelFileOffset );
collisionFileName = std::string( buf + offset + data.collisionFileOffset );
};
};
struct LGB_GIMMICK_HEADER :
public LGB_ENTRY_HEADER
{
uint32_t gimmickFileOffset;
char unknownBytes[100];
};
class LGB_GIMMICK_ENTRY :
public LGB_ENTRY
class LGB_GIMMICK_ENTRY : public LgbEntry
{
public:
LGB_GIMMICK_HEADER header;
GimmickData data;
std::string name;
std::string gimmickFileName;
LGB_GIMMICK_ENTRY( char* buf, uint32_t offset ) :
LGB_ENTRY( buf, offset )
LGB_GIMMICK_ENTRY( char* buf, uint32_t offset ) : LgbEntry( buf, offset )
{
header = *reinterpret_cast<LGB_GIMMICK_HEADER*>( buf + offset );
data = *reinterpret_cast< GimmickData* >( buf + offset );
name = std::string( buf + offset + header.nameOffset );
gimmickFileName = std::string( buf + offset + header.gimmickFileOffset );
//std::cout << "\t " << gimmickFileName << " unknown: " << header.unknown << "\n";
gimmickFileName = std::string( buf + offset + data.gimmickFileOffset );
};
};
struct LGB_ENPC_HEADER :
public LGB_ENTRY_HEADER
{
uint32_t enpcId;
uint8_t unknown1[0x24];
};
class LGB_ENPC_ENTRY :
public LGB_ENTRY
class LGB_ENPC_ENTRY : public LgbEntry
{
public:
LGB_ENPC_HEADER header;
ENpcData data;
std::string name;
LGB_ENPC_ENTRY( char* buf, uint32_t offset ) :
LGB_ENTRY( buf, offset )
LgbEntry( buf, offset )
{
header = *reinterpret_cast< LGB_ENPC_HEADER* >( 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";
data = *reinterpret_cast< ENpcData* >( buf + offset );
name = std::string( buf + offset + header.nameOffset );
};
};
struct LGB_MAPRANGE_HEADER :
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
class LGB_EOBJ_ENTRY : public LgbEntry
{
public:
LGB_MAPRANGE_HEADER header;
EObjData data;
std::string name;
LGB_MAPRANGE_ENTRY( char* buf, uint32_t offset ) :
LGB_ENTRY( buf, offset )
LGB_EOBJ_ENTRY( char* buf, uint32_t offset ) : LgbEntry( buf, offset )
{
header = *reinterpret_cast< LGB_MAPRANGE_HEADER* >( buf + offset );
data = *reinterpret_cast< EObjData* >( buf + offset );
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
{
uint32_t id;
@ -272,15 +174,13 @@ struct LGB_GROUP
LGB_FILE* parent;
LGB_GROUP_HEADER header;
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 )
{
parent = parentStruct;
header = *reinterpret_cast< LGB_GROUP_HEADER* >( buf + offset );
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;
for( auto i = 0; i < header.entryCount; ++i )
{
@ -288,8 +188,7 @@ struct LGB_GROUP
try
{
const auto type = *reinterpret_cast<LgbEntryType*>( buf + entryOffset );
// garbage to skip model loading
const auto type = *reinterpret_cast< LgbEntryType* >( buf + entryOffset );
if( type == LgbEntryType::BgParts )
{
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 ) );
}
else if( type == LgbEntryType::ExitRange )
{
entries.push_back( std::make_shared< LGB_EXIT_RANGE_ENTRY >( buf, entryOffset ) );
}
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
{
entries.push_back( std::make_shared< LGB_ENTRY >( buf, entryOffset ) );
entries.push_back( std::make_shared< LgbEntry >( buf, entryOffset ) );
}
}
catch( std::exception& e )
{
@ -344,8 +245,7 @@ struct LGB_FILE
std::vector< LGB_GROUP > groups;
std::string m_name;
LGB_FILE( char* buf, const std::string& name ) :
LGB_FILE( buf )
LGB_FILE( char* buf, const std::string& name ) : LGB_FILE( buf )
{
m_name = name;
}
@ -356,8 +256,6 @@ struct LGB_FILE
if( strncmp( &header.magic[ 0 ], "LGB1", 4 ) != 0 || strncmp( &header.magic2[ 0 ], "LGP1", 4 ) != 0 )
throw std::runtime_error( "Invalid LGB file!" );
//groups.resize(header.groupCount);
constexpr auto baseOffset = sizeof( header );
for( auto i = 0; i < header.groupCount; ++i )
{

View file

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

592
deps/datReader/Exd.cpp vendored
View file

@ -1,380 +1,332 @@
#include "Exd.h"
#include "bparse.h"
#include "stream.h"
#include <fstream>
#include "Exh.h"
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 ExdHeader
{
char magic[0x4];
uint16_t unknown;
uint16_t unknown2;
uint32_t index_size;
};
struct ExdRecordIndex
{
uint32_t id;
uint32_t offset;
};
}
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::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
namespace xiv::exd
{
namespace exd
{
Exd::Exd( std::shared_ptr< Exh > exh, const std::vector< std::shared_ptr< dat::File > >& files )
{
_exh = exh;
Exd::Exd( std::shared_ptr<Exh> i_exh, const std::vector<std::shared_ptr<dat::File>>& i_files )
// Iterates over all the files
for( auto& file : files )
{
std::vector< char > dataCpy = file->get_data_sections().front();
// Extract the header
auto exdHeader = extract< ExdHeader >( dataCpy, 0 );
const uint32_t recordCount = exdHeader.index_size / sizeof( ExdRecordIndex );
for( uint32_t i = 0; i < recordCount; ++i )
{
_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};
}
}
auto recordIndex = extract< ExdRecordIndex >( dataCpy, 32 + ( i * sizeof( ExdRecordIndex ) ) );
_idCache[ recordIndex.id ] = ExdCacheEntry{ file, recordIndex.offset + 6, extract< uint8_t >( dataCpy, recordIndex.offset + 5 ) };
}
}
}
Exd::~Exd()
Exd::~Exd()
{
}
const std::vector< Field > Exd::get_row( uint32_t id, uint32_t subRow )
{
auto cacheEntryIt = _idCache.find( id );
if( cacheEntryIt == _idCache.end() || subRow >= cacheEntryIt->second.subRows )
throw std::runtime_error( "Id + SubId combination not found: " + std::to_string( id ) + "." + std::to_string( subRow ) );
auto dataCpy = cacheEntryIt->second.file->get_data_sections().front();
std::vector< Field > fields;
fields.reserve( _exh->get_members().size() );
uint32_t baseOffset = cacheEntryIt->second.offset + ( subRow * _exh->get_header().data_offset + 2 * ( subRow + 1 ) );
for( auto& memberEntry : _exh->get_exh_members() )
{
// Switch depending on the type to extract
switch( memberEntry.type )
{
case DataType::string:
// Extract the offset to the actual string
// Then extract the actual string from that offset
{
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 >( dataCpy, baseOffset + memberEntry.offset ) );
break;
case DataType::int8:
fields.emplace_back( extract< int8_t >( dataCpy, baseOffset + memberEntry.offset ) );
break;
case DataType::uint8:
fields.emplace_back( extract< uint8_t >( dataCpy, baseOffset + memberEntry.offset ) );
break;
case DataType::int16:
fields.emplace_back( extract< int16_t >( dataCpy, baseOffset + memberEntry.offset, false ) );
break;
case DataType::uint16:
fields.emplace_back( extract< uint16_t >( dataCpy, baseOffset + memberEntry.offset, false ) );
break;
case DataType::int32:
fields.emplace_back( extract< int32_t >( dataCpy, baseOffset + memberEntry.offset, false ) );
break;
case DataType::uint32:
fields.emplace_back( extract< uint32_t >( dataCpy, baseOffset + memberEntry.offset, false ) );
break;
case DataType::float32:
fields.emplace_back( extract< float >( dataCpy, baseOffset + memberEntry.offset, false ) );
break;
case DataType::uint64:
fields.emplace_back( extract< uint64_t >( dataCpy, baseOffset + memberEntry.offset, false ) );
break;
default:
auto type = static_cast< uint16_t >( memberEntry.type );
if( type < 0x19 || type > 0x20 )
throw std::runtime_error( "Unknown DataType: " + std::to_string( type ) );
fields.emplace_back( ( extract< uint8_t >( dataCpy, baseOffset + memberEntry.offset ) & ( 1 << ( type - 0x19 ) ) ) != 0 );
break;
}
}
return fields;
const std::vector<Field> Exd::get_row( uint32_t id, uint32_t subRow )
}
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 ) );
auto dataCpy = cacheEntryIt->second.file->get_data_sections().front();
std::vector< Field > fields;
fields.reserve( _exh->get_members().size() );
auto stringBaseOffset = cacheEntryIt->second.offset + _exh->get_header().data_offset;
for( auto& memberEntry : _exh->get_exh_members() )
{
// Switch depending on the type to extract
switch( memberEntry.type )
{
case DataType::string:
// Extract the offset to the actual string
// Then extract the actual string from that offset
{
auto stringOffset = extract< uint32_t >( dataCpy, cacheEntryIt->second.offset + memberEntry.offset, false );
fields.emplace_back( utils::bparse::extract_cstring( dataCpy, stringBaseOffset + stringOffset ) );
}
break;
auto cacheEntryIt = _idCache.find( id );
if( cacheEntryIt == _idCache.end() )
throw std::runtime_error( "Id not found: " + std::to_string( id ) );
case DataType::boolean:
fields.emplace_back( extract< bool >( dataCpy, cacheEntryIt->second.offset + memberEntry.offset ) );
break;
// Iterates over all the files
const uint32_t member_count = _exh->get_members().size();
auto& file_ptr = cacheEntryIt->second.file;
case DataType::int8:
fields.emplace_back( extract< int8_t >( dataCpy, cacheEntryIt->second.offset + memberEntry.offset ) );
break;
std::vector< char > dataCpy = file_ptr->get_data_sections().front();
std::istringstream iss( std::string( dataCpy.begin(), dataCpy.end() ) );
case DataType::uint8:
fields.emplace_back( extract< uint8_t >( dataCpy, cacheEntryIt->second.offset + memberEntry.offset ) );
break;
// 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 );
case DataType::int16:
fields.emplace_back( extract< int16_t >( dataCpy, cacheEntryIt->second.offset + memberEntry.offset, false ) );
break;
uint8_t subRows = *reinterpret_cast< uint8_t* >( &dataCpy[ cacheEntryIt->second.offset + 5 ] );
case DataType::uint16:
fields.emplace_back( extract< uint16_t >( dataCpy, cacheEntryIt->second.offset + memberEntry.offset, false ) );
break;
if( subRow >= subRows )
throw std::runtime_error( "Out of bounds sub-row!" );
case DataType::int32:
fields.emplace_back( extract< int32_t >( dataCpy, cacheEntryIt->second.offset + memberEntry.offset, false ) );
break;
int offset = cacheEntryIt->second.offset + 6 + ( subRow * _exh->get_header().data_offset + 2 * ( subRow + 1 ) );
case DataType::uint32:
fields.emplace_back( extract< uint32_t >( dataCpy, cacheEntryIt->second.offset + memberEntry.offset, false ) );
break;
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 );
case DataType::float32:
fields.emplace_back( extract< float >( dataCpy, cacheEntryIt->second.offset + memberEntry.offset, false ) );
break;
// Switch depending on the type to extract
switch( member_entry.type )
{
case DataType::uint64:
fields.emplace_back( extract< uint64_t >( dataCpy, cacheEntryIt->second.offset + memberEntry.offset, false ) );
break;
default:
auto type = static_cast< uint16_t >( memberEntry.type );
if( type < 0x19 || type > 0x20 )
throw std::runtime_error( "Unknown DataType: " + std::to_string( type ) );
fields.emplace_back( ( extract< uint8_t >( dataCpy, cacheEntryIt->second.offset + memberEntry.offset ) & ( 1 << ( type - 0x19 ) ) ) != 0 );
break;
}
}
return fields;
}
// Get all rows
const std::map< ExdRow, std::vector< Field >, exdRowSort > Exd::get_rows()
{
std::map< ExdRow, std::vector< Field >, exdRowSort > data;
// Iterates over all the cached ids
const uint32_t memberCount = _exh->get_members().size();
for( auto& cacheEntry : _idCache )
{
std::vector< char > dataCpy = cacheEntry.second.file->get_data_sections().front();
auto baseOffset = cacheEntry.second.offset;
auto stringBaseOffset = baseOffset + _exh->get_header().data_offset;
for( int32_t i = 0; i < cacheEntry.second.subRows; i++ )
{
// Get the vector fields for the given record and preallocate it
ExdRow row = { cacheEntry.first, i };
auto& fields = data[ row ];
fields.reserve( memberCount );
if( _exh->get_header().variant == 2 )
baseOffset = cacheEntry.second.offset + ( i * _exh->get_header().data_offset + 2 * ( i + 1 ) );
for( auto& memberEntry : _exh->get_exh_members() )
//for( auto& member_entry : _exh->get_members() )
{
// Switch depending on the type to extract
switch( memberEntry.type )
{
case DataType::string:
// Extract the offset to the actual string
// Seek to it then extract the actual string
// Extract the offset to the actual string
// Then extract the actual string from that offset
{
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" ) );
if( _exh->get_header().variant == 1 )
{
auto stringOffset = extract< uint32_t >( dataCpy, baseOffset + memberEntry.offset, false );
fields.emplace_back( utils::bparse::extract_cstring( dataCpy, stringBaseOffset + stringOffset ) );
}
else if( _exh->get_header().variant == 2 )
{
throw std::runtime_error( "String not implemented for variant 2!" );
}
}
break;
break;
case DataType::boolean:
fields.emplace_back( extract<bool>( iss, "bool" ) );
break;
fields.emplace_back( extract< bool >( dataCpy, baseOffset + memberEntry.offset ) );
break;
case DataType::int8:
fields.emplace_back( extract<int8_t>( iss, "int8_t" ) );
break;
fields.emplace_back( extract< int8_t >( dataCpy, baseOffset + memberEntry.offset ) );
break;
case DataType::uint8:
fields.emplace_back( extract<uint8_t>( iss, "uint8_t" ) );
break;
fields.emplace_back( extract< uint8_t >( dataCpy, baseOffset + memberEntry.offset ) );
break;
case DataType::int16:
fields.emplace_back( extract<int16_t>( iss, "int16_t", false ) );
break;
fields.emplace_back( extract< int16_t >( dataCpy, baseOffset + memberEntry.offset, false ) );
break;
case DataType::uint16:
fields.emplace_back( extract<uint16_t>( iss, "uint16_t", false ) );
break;
fields.emplace_back( extract< uint16_t >( dataCpy, baseOffset + memberEntry.offset, false ) );
break;
case DataType::int32:
fields.emplace_back( extract<int32_t>( iss, "int32_t", false ) );
break;
fields.emplace_back( extract< int32_t >( dataCpy, baseOffset + memberEntry.offset, false ) );
break;
case DataType::uint32:
fields.emplace_back( extract<uint32_t>( iss, "uint32_t", false ) );
break;
fields.emplace_back( extract< uint32_t >( dataCpy, baseOffset + memberEntry.offset, false ) );
break;
case DataType::float32:
fields.emplace_back( extract<float>( iss, "float", false ) );
break;
fields.emplace_back( extract< float >( dataCpy, baseOffset + memberEntry.offset, false ) );
break;
case DataType::uint64:
fields.emplace_back( extract<uint64_t>( iss, "uint64_t", false ) );
break;
fields.emplace_back( extract< uint64_t >( dataCpy, baseOffset + memberEntry.offset, 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;
auto type = static_cast< uint16_t >( memberEntry.type );
if( type < 0x19 || type > 0x20 )
throw std::runtime_error( "Unknown DataType: " + std::to_string( type ) );
fields.emplace_back( ( extract< uint8_t >( dataCpy, baseOffset + memberEntry.offset ) & ( 1 << ( type - 0x19 ) ) ) != 0 );
break;
}
}
}
}
return data;
}
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;
}
}
}

77
deps/datReader/Exd.h vendored
View file

@ -3,20 +3,20 @@
#include <memory>
#include <map>
#include <unordered_map>
#include <set>
#include <variant>
#include "File.h"
namespace xiv
{
namespace exd
namespace xiv::exd
{
class Exh;
class Exh;
// Field type containing all the possible types in the data files
using Field = std::variant<
// Field type containing all the possible types in the data files
using Field = std::variant<
std::string,
bool,
int8_t,
@ -28,39 +28,58 @@ using Field = std::variant<
float,
uint64_t >;
struct ExdCacheEntry
{
std::shared_ptr<dat::File> file;
uint32_t offset;
};
struct ExdCacheEntry
{
std::shared_ptr< dat::File > file;
uint32_t offset;
uint8_t subRows;
};
struct ExdRow
{
uint32_t rowId;
uint8_t subRowId;
};
struct exdRowSort
{
constexpr bool operator()( const ExdRow& _Left, const ExdRow& _Right ) const
{
if( _Left.rowId == _Right.rowId )
return _Left.subRowId < _Right.subRowId;
return _Left.rowId < _Right.rowId;
}
};
// Data for a given language
class Exd
{
public:
// exh: the header
// files: the multiple exd files
Exd()
{
}
Exd( std::shared_ptr< Exh > exh, const std::vector< std::shared_ptr< dat::File > >& files );
// Data for a given language
class Exd
{
public:
// i_exh: the header
// i_files: the multiple exd files
Exd() {}
Exd(std::shared_ptr<Exh> i_exh, const std::vector<std::shared_ptr<dat::File>>& i_files);
~Exd();
// 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
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
const std::map<uint32_t, std::vector<Field>>& get_rows();
const std::map< ExdRow, std::vector< Field >, exdRowSort > get_rows();
protected:
// 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::vector<std::shared_ptr<dat::File>> _files;
std::shared_ptr<Exh> _exh;
protected:
std::shared_ptr< Exh > _exh;
std::map< uint32_t, ExdCacheEntry > _idCache;
};
};
}
}
#endif // XIV_EXD_EXD_H

View file

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

View file

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

View file

@ -7,50 +7,47 @@
#include "ExdCat.h"
namespace xiv
{
namespace exd
namespace xiv::exd {
ExdData::ExdData( dat::GameData& i_game_data ) try :
_game_data( i_game_data )
{
//XIV_INFO(xiv_exd_logger, "Initializing ExdData");
ExdData::ExdData(dat::GameData& i_game_data) try :
_game_data(i_game_data)
{
//XIV_INFO(xiv_exd_logger, "Initializing ExdData");
// Fetch the root.exl and get a stream from it
auto root_exl = i_game_data.getFile( "exd/root.exl" );
std::vector< char > dataCpy = root_exl->get_data_sections().front();
xiv::utils::stream::vectorwrapbuf< char > databuf( dataCpy );
std::istream stream( &databuf );
// Fetch the root.exl and get a stream from it
auto root_exl = i_game_data.getFile("exd/root.exl");
std::vector< char > dataCpy = root_exl->get_data_sections().front();
xiv::utils::stream::vectorwrapbuf<char> databuf(dataCpy);
std::istream stream(&databuf);
// Iterates over the lines while skipping the first one
std::string line;
std::getline( stream, line ); // extract first line EXLT,2
std::getline( stream, line );
// Iterates over the lines while skipping the first one
std::string line;
std::getline(stream, line); // extract first line EXLT,2
std::getline(stream, line);
// Until the EOF
while( !line.empty() )
{
// 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
while (!line.empty())
{
// Format is cat_name,XX
// XX being an internal identifier
// Get only the cat_name
auto sep = line.find(',');
auto category = line.substr(0, sep);
// Add to the list of category name
// creates the empty category in the cats map
// instantiate the creation mutex for this category
_cat_names.push_back( category );
_cats[ category ] = std::unique_ptr< Cat >();
_cat_creation_mutexes[ category ] = std::make_unique< std::mutex >();
// Add to the list of category name
// creates the empty category in the cats map
// instantiate the creation mutex for this category
_cat_names.push_back(category);
_cats[category] = std::unique_ptr<Cat>();
_cat_creation_mutexes[category] = std::unique_ptr<std::mutex>(new std::mutex());
std::getline(stream, line);
}
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
throw std::runtime_error( "ExdData initialization failed: " + std::string( e.what() ) );
// In case of failure here, client is supposed to catch the exception because it is not recoverable on our side
throw std::runtime_error( "ExdData initialization failed: " + std::string( e.what() ) );
}
ExdData::~ExdData()
@ -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
auto cat_it = _cats.find(i_cat_name);
if (cat_it == _cats.end())
{
throw std::runtime_error("Category not found: " + i_cat_name);
}
// Get the category from its name
auto cat_it = _cats.find( i_cat_name );
if( cat_it == _cats.end() )
{
throw std::runtime_error( "Category not found: " + i_cat_name );
}
if (cat_it->second)
{
// If valid return it
return *(cat_it->second);
}
else
{
// If not, create it and return it
create_category(i_cat_name);
return *(_cats[i_cat_name]);
}
if( cat_it->second )
{
// If valid return it
return *( cat_it->second );
}
else
{
// If not, create it and return it
create_category( i_cat_name );
return *( _cats[ i_cat_name ] );
}
}
void ExdData::create_category(const std::string& i_cat_name)
void ExdData::create_category( const std::string& i_cat_name )
{
// Lock mutex in this scope
std::lock_guard<std::mutex> lock(*(_cat_creation_mutexes[i_cat_name]));
// Maybe after unlocking it has already been created, so check (most likely if it blocked)
if (!_cats[i_cat_name])
{
_cats[i_cat_name] = std::unique_ptr<Cat>(new Cat(_game_data, i_cat_name));
}
// Lock mutex in this scope
std::lock_guard< std::mutex > lock( *( _cat_creation_mutexes[ i_cat_name ] ) );
// Maybe after unlocking it has already been created, so check (most likely if it blocked)
if( !_cats[ i_cat_name ] )
{
_cats[ i_cat_name ] = std::make_unique< Cat >( _game_data, i_cat_name );
}
}
}
}

View file

@ -5,7 +5,8 @@
#include <memory>
#include <mutex>
#include <experimental/filesystem>
#include <filesystem>
#include <vector>
namespace xiv
{
@ -34,7 +35,7 @@ namespace xiv
const Cat& get_category(const std::string& i_cat_name);
// Export in csv in base flder i_ouput_path
void export_as_csvs(const std::experimental::filesystem::path& i_output_path);
void export_as_csvs(const std::filesystem::path& i_output_path);
protected:
// Lazy instantiation of category

View file

@ -7,71 +7,69 @@
using xiv::utils::bparse::extract;
namespace xiv
{
namespace exd
{
Exh::Exh(const dat::File& i_file)
namespace xiv::exd
{
Exh::Exh( const dat::File& i_file )
{
// Get a stream from the file
std::vector< char > dataCpy = i_file.get_data_sections().front();
std::istringstream iss( std::string( dataCpy.begin(), dataCpy.end() ) );
// Extract header and skip to member definitions
_header = extract<ExhHeader>(iss);
iss.seekg(0x20);
_header = extract< ExhHeader >( iss );
iss.seekg( 0x20 );
// 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);
_members[member.offset] = member;
_exh_defs.push_back( member );
auto member = extract< ExhMember >( iss );
_members[ member.offset ] = member;
_exh_defs.push_back( member );
}
// Extract all the exd_defs
_exd_defs.reserve(_header.exd_count);
for (auto i = 0; i < _header.exd_count; ++i)
_exd_defs.reserve( _header.exd_count );
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
_languages.reserve(_header.language_count);
for (auto i = 0; i < _header.language_count; ++i)
_languages.reserve( _header.language_count );
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;
}
}
const std::vector<ExhExdDef>& Exh::get_exd_defs() const
{
const std::vector< ExhExdDef >& Exh::get_exd_defs() const
{
return _exd_defs;
}
}
const std::vector<Language>& Exh::get_languages() const
{
const std::vector< Language >& Exh::get_languages() const
{
return _languages;
}
}
const std::map<uint32_t, ExhMember>& Exh::get_members() const
{
const std::map< uint32_t, ExhMember >& Exh::get_members() const
{
return _members;
}
}
const std::vector<ExhMember>& Exh::get_exh_members() const
{
return _exh_defs;
}
const std::vector< ExhMember >& Exh::get_exh_members() const
{
return _exh_defs;
}
}
}

190
deps/datReader/Exh.h vendored
View file

@ -5,99 +5,131 @@
#include "bparse.h"
namespace xiv
namespace xiv::exd
{
namespace exd
{
enum class DataType : uint16_t
{
string = 0,
boolean = 1,
int8 = 2,
uint8 = 3,
int16 = 4,
uint16 = 5,
int32 = 6,
uint32 = 7,
float32 = 9,
uint64 = 11,
};
enum class DataType :
uint16_t
{
string = 0,
boolean = 1,
int8 = 2,
uint8 = 3,
int16 = 4,
uint16 = 5,
int32 = 6,
uint32 = 7,
float32 = 9,
uint64 = 11,
};
struct ExhHeader
{
char magic[0x4];
uint16_t unknown;
uint16_t data_offset;
uint16_t field_count;
uint16_t exd_count;
uint16_t language_count;
uint16_t unknown1;
uint8_t u2;
uint8_t variant;
};
struct ExhHeader
{
char magic[0x4];
uint16_t unknown;
uint16_t data_offset;
uint16_t field_count;
uint16_t exd_count;
uint16_t language_count;
uint16_t unknown1;
uint8_t u2;
uint8_t variant;
};
struct ExhMember
{
DataType type;
uint16_t offset;
};
struct ExhMember
{
DataType type;
uint16_t offset;
};
struct ExhExdDef
{
uint32_t start_id;
uint32_t count_id;
};
}
struct ExhExdDef
{
uint32_t start_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 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
{
class File;
}
namespace exd
{
namespace dat
{
class File;
}
enum Language : uint16_t;
namespace exd
{
// Header file for exd data
class Exh
{
public:
// The header file
Exh( const dat::File& i_file );
~Exh();
enum Language :
uint16_t;
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;
// Header file for exd data
class Exh
{
public:
// The header file
Exh( const dat::File& i_file );
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;
};
~Exh();
}
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

View file

@ -2,44 +2,41 @@
#include <fstream>
namespace xiv
{
namespace dat
namespace xiv::dat
{
File::File() :
_type(FileType::empty)
{
}
File::File() :
_type( FileType::empty )
{
}
File::~File()
{
}
File::~File()
{
}
FileType File::get_type() const
{
return _type;
}
FileType File::get_type() const
{
return _type;
}
const std::vector<std::vector<char>>& File::get_data_sections() const
{
return _data_sections;
}
const std::vector< std::vector< char>>& File::get_data_sections() const
{
return _data_sections;
}
std::vector<std::vector<char>>& File::access_data_sections()
{
return _data_sections;
}
std::vector< std::vector< char>>& File::access_data_sections()
{
return _data_sections;
}
void File::exportToFile(const std::experimental::filesystem::path& i_path) const
{
std::ofstream ofs( i_path.string(), std::ios_base::binary | std::ios_base::out );
for( auto& data_section : _data_sections )
{
void File::exportToFile( const std::filesystem::path& i_path ) const
{
std::ofstream ofs( i_path.string(), std::ios_base::binary | std::ios_base::out );
for( auto& data_section : _data_sections )
{
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 <experimental/filesystem>
#include <filesystem>
#include <stdint.h>
#include "bparse.h"
namespace xiv
namespace xiv::dat
{
namespace dat
{
enum class FileType : uint32_t
{
empty = 1,
standard = 2,
model = 3,
texture = 4,
};
}
};
enum class FileType :
uint32_t
{
empty = 1,
standard = 2,
model = 3,
texture = 4,
};
namespace xiv
{
namespace dat
{
class Dat;
class Dat;
// Basic file from the dats
class File
{
friend class Dat;
// Basic file from the dats
class File
{
friend class Dat;
public:
File();
~File();
public:
File();
FileType get_type() const;
~File();
// Getters functions for the data in the file
const std::vector<std::vector<char>>& get_data_sections() const;
std::vector<std::vector<char>>& access_data_sections();
FileType get_type() const;
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:
FileType _type;
std::vector<std::vector<char>> _data_sections;
};
std::vector< std::vector< char>>& access_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

View file

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

View file

@ -5,80 +5,89 @@
#include <unordered_map>
#include <mutex>
#include <experimental/filesystem>
#include <filesystem>
#include <vector>
namespace xiv
{
namespace dat
namespace xiv::dat
{
class Cat;
class File;
class Cat;
// 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::experimental::filesystem::path& path );
~GameData();
class File;
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
const std::vector<uint32_t>& getCatNumbers() const;
~GameData();
// Return a specific category by its number (see getCatNumbers() for loops)
const Cat& getCategory( uint32_t catNum );
// Return a specific category by it's name (e.g.: "exd"/"game_script"/ etc...)
const Cat& getCategory( const std::string& catName );
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 );
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
std::unique_ptr<File> getFile( const std::string& path );
// Return a specific category by its number (see getCatNumbers() for loops)
const Cat& getCategory( uint32_t catNum );
// Checks that a file exists
bool doesFileExist( const std::string& path );
// Return a specific category by it's name (e.g.: "exd"/"game_script"/ etc...)
const Cat& getCategory( const std::string& catName );
// Checks that a dir exists, there must be a trailing / in the 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 );
const Cat& getExCategory( const std::string& catName, uint32_t exNum, const std::string& path );
protected:
// Return a specific category given a path (calls const Cat& getCategory(const std::string& catName))
const Cat& getCategoryFromPath( const std::string& path );
// Retrieve a file from the dats given its filename
std::unique_ptr< File > getFile( const std::string& path );
// From a full path, returns the dirHash and the filenameHash
void getHashes( const std::string& path, uint32_t& dirHash, uint32_t& filenameHash ) const;
// Checks that a file exists
bool doesFileExist( const std::string& path );
// Lazy instantiation of category
void createCategory( uint32_t catNum );
// Checks that a dir exists, there must be a trailing / in the 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 );
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
const std::experimental::filesystem::path m_path;
// From a full path, returns the dirHash and the filenameHash
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
std::unordered_map<uint32_t, std::unique_ptr<Cat>> m_cats;
// Lazy instantiation of category
void createCategory( uint32_t catNum );
// List of all the categories numbers, is equal to m_cats.keys()
std::vector<uint32_t> m_catNums;
void createExCategory( uint32_t catNum );
// 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;
};
// Path given to constructor, pointing to the folder with the .index/.datX files
const std::filesystem::path m_path;
// Stored categories, indexed by their number, categories are instantiated and parsed individually when they are needed
std::unordered_map< uint32_t, std::unique_ptr< Cat>> m_cats;
// 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

View file

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

View file

@ -5,55 +5,59 @@
#include <unordered_map>
#include <experimental/filesystem>
#include <filesystem>
namespace xiv {
namespace dat {
struct IndexBlockRecord;
class Index : public SqPack
namespace xiv::dat
{
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 HashTableEntry
{
struct IndexBlockRecord;
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 dirHash;
uint32_t filenameHash;
uint32_t datOffset;
};
};
// HashTable has dir hashes -> filename hashes -> HashTableEntry
using DirHashTable = std::unordered_map< uint32_t, HashTableEntry >;
using HashTable = std::unordered_map< uint32_t, DirHashTable >;
// HashTable has dir hashes -> filename hashes -> HashTableEntry
using DirHashTable = std::unordered_map< uint32_t, HashTableEntry >;
using HashTable = std::unordered_map< uint32_t, DirHashTable >;
// Get the number of dat files the index is linked to
uint32_t getDatCount() const;
// Get the number of dat files the index is linked to
uint32_t getDatCount() const;
bool doesFileExist( uint32_t dir_hash, uint32_t filename_hash ) const;
bool doesDirExist( uint32_t dir_hash ) const;
bool doesFileExist( uint32_t dir_hash, uint32_t filename_hash ) const;
// Returns the whole HashTable
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;
bool doesDirExist( uint32_t dir_hash ) const;
protected:
// Checks that the block is valid with regards to its hash
void isIndexBlockValid( const IndexBlockRecord& i_index_block_record );
// Returns the whole HashTable
const HashTable& getHashTable() const;
uint32_t m_datCount;
HashTable m_hashTable;
};
// 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:
// 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

View file

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

View file

@ -3,64 +3,56 @@
#include <fstream>
#include <experimental/filesystem>
#include <filesystem>
#include "bparse.h"
namespace xiv
namespace xiv::dat
{
namespace dat
{
struct SqPackBlockHash
{
uint8_t hash[0x14];
uint32_t padding[0xB];
};
}
struct SqPackBlockHash
{
uint8_t hash[0x14];
uint32_t padding[0xB];
};
}
namespace xiv {
namespace utils {
namespace bparse {
template <> inline void reorder<xiv::dat::SqPackBlockHash>( xiv::dat::SqPackBlockHash& i_struct )
{
for( auto i = 0; i < 0x14; ++i )
{
xiv::utils::bparse::reorder( i_struct.hash[i] );
}
for( auto i = 0; i < 0xB; ++i )
{
xiv::utils::bparse::reorder( i_struct.padding[i] );
}
}
}
}
namespace xiv::utils::bparse
{
template<>
inline void reorder< xiv::dat::SqPackBlockHash >( xiv::dat::SqPackBlockHash& i_struct )
{
for( auto i = 0; i < 0x14; ++i )
{
xiv::utils::bparse::reorder( i_struct.hash[ i ] );
}
for( auto i = 0; i < 0xB; ++i )
{
xiv::utils::bparse::reorder( i_struct.padding[ i ] );
}
}
};
namespace xiv
{
namespace dat
namespace xiv::dat
{
class SqPack
{
class SqPack
{
public:
// Full path to the sqpack file
SqPack( const std::experimental::filesystem::path& i_path );
virtual ~SqPack();
public:
// Full path to the sqpack file
SqPack( const std::filesystem::path& i_path );
protected:
// 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 );
virtual ~SqPack();
// File handle
std::ifstream m_handle;
};
protected:
// 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

View file

@ -6,3 +6,8 @@ std::string xiv::utils::bparse::extract_cstring( std::istream& i_stream, const s
std::getline( i_stream, temp_str, '\0' );
return temp_str;
}
std::string xiv::utils::bparse::extract_cstring( std::vector< char >& data, uint32_t pos )
{
return &data[ pos ];
}

View file

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

View file

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

View file

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

View file

@ -65,116 +65,111 @@ namespace internal
}
}
namespace xiv
{
namespace utils
{
namespace crc32
namespace xiv::utils::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
auto& crc_table = internal::get_crc_table();
auto& crc_table = internal::get_crc_table();
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;
}
}
uint32_t rev_compute(const std::string& i_input, uint32_t init_crc)
{
auto& rev_crc_table = internal::get_rev_crc_table();
uint32_t rev_compute( const std::string& i_input, uint32_t init_crc )
{
auto& rev_crc_table = internal::get_rev_crc_table();
auto crc = init_crc;
const auto input_size = i_input.size();
// 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
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;
}
}
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());
const uint32_t str_size = i_format.size();
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());
const uint32_t str_size = i_format.size();
o_hashes.resize(10000);
o_hashes.resize( 10000 );
uint32_t i = 0;
for (char a = '0'; a <= '9'; ++a)
{
str[i_first_index] = a;
for (char b = '0'; b <= '9'; ++b)
{
str[i_first_index + 1] = b;
for (char c = '0'; c <= '9'; ++c)
{
str[i_first_index + 2] = c;
for (char d = '0'; d <= '9'; ++d)
{
str[i_first_index + 3] = d;
o_hashes[i] = ::crc32(0, reinterpret_cast<uint8_t*>(&(str[0])), str_size) ^ 0xFFFFFFFF;
++i;
}
}
}
}
}
uint32_t i = 0;
for( char a = '0'; a <= '9'; ++a )
{
str[ i_first_index ] = a;
for( char b = '0'; b <= '9'; ++b )
{
str[ i_first_index + 1 ] = b;
for( char c = '0'; c <= '9'; ++c )
{
str[ i_first_index + 2 ] = c;
for( char d = '0'; d <= '9'; ++d )
{
str[ i_first_index + 3 ] = d;
o_hashes[ i ] = ::crc32( 0, reinterpret_cast<uint8_t*>(&( str[ 0 ] )), str_size ) ^ 0xFFFFFFFF;
++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)
{
char* str = const_cast<char*>(i_format.data());
const uint32_t str_size = i_format.size();
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();
o_hashes.resize(100000000);
o_hashes.resize( 100000000 );
uint32_t i = 0;
for (char a = '0'; a <= '9'; ++a)
{
str[i_first_index] = a;
for (char b = '0'; b <= '9'; ++b)
{
str[i_first_index + 1] = b;
for (char c = '0'; c <= '9'; ++c)
{
str[i_first_index + 2] = c;
for (char d = '0'; d <= '9'; ++d)
{
str[i_first_index + 3] = d;
for (char e = '0'; e <= '9'; ++e)
{
str[i_second_index] = e;
for (char f = '0'; f <= '9'; ++f)
{
str[i_second_index + 1] = f;
for (char g = '0'; g <= '9'; ++g)
{
str[i_second_index + 2] = g;
for (char h = '0'; h <= '9'; ++h)
{
str[i_second_index + 3] = h;
o_hashes[i] = ::crc32(0, reinterpret_cast<uint8_t*>(&(str[0])), str_size) ^ 0xFFFFFFFF;
++i;
}
}
}
}
}
}
}
}
}
uint32_t i = 0;
for( char a = '0'; a <= '9'; ++a )
{
str[ i_first_index ] = a;
for( char b = '0'; b <= '9'; ++b )
{
str[ i_first_index + 1 ] = b;
for( char c = '0'; c <= '9'; ++c )
{
str[ i_first_index + 2 ] = c;
for( char d = '0'; d <= '9'; ++d )
{
str[ i_first_index + 3 ] = d;
for( char e = '0'; e <= '9'; ++e )
{
str[ i_second_index ] = e;
for( char f = '0'; f <= '9'; ++f )
{
str[ i_second_index + 1 ] = f;
for( char g = '0'; g <= '9'; ++g )
{
str[ i_second_index + 2 ] = g;
for( char h = '0'; h <= '9'; ++h )
{
str[ i_second_index + 3 ] = h;
o_hashes[ i ] = ::crc32( 0, reinterpret_cast<uint8_t*>(&( str[ 0 ] )), str_size ) ^ 0xFFFFFFFF;
++i;
}
}
}
}
}
}
}
}
}
}
}
}

View file

@ -5,9 +5,8 @@
#include <vector>
#include <string>
namespace xiv {
namespace utils {
namespace crc32 {
namespace xiv::utils::crc32
{
// 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 );
@ -17,10 +16,10 @@ namespace crc32 {
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_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

View file

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

View file

@ -5,23 +5,17 @@
#include <iostream>
#include <vector>
namespace xiv
namespace xiv::utils::stream
{
namespace utils
{
namespace stream
{
template<typename CharT, typename TraitsT = std::char_traits<CharT> >
class vectorwrapbuf : public std::basic_streambuf<CharT, TraitsT>
{
public:
vectorwrapbuf(std::vector<CharT> &vec)
template< typename CharT, typename TraitsT = std::char_traits< CharT > >
class vectorwrapbuf :
public std::basic_streambuf< CharT, TraitsT >
{
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

View file

@ -4,32 +4,28 @@
#include <zlib/zlib.h>
#include <vector>
namespace xiv
{
namespace utils
{
namespace zlib
namespace xiv::utils::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
auto out_size = compressBound(in.size());
out.resize(out_size);
auto out_size = compressBound( in.size() );
out.resize( 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);
auto ret = compress2( reinterpret_cast<uint8_t*>(out.data()), &out_size,
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;
strm.zalloc = 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;
// Init with -15 because we do not have header in this compressed data
auto ret = inflateInit2(&strm, -15);
if (ret != Z_OK)
auto ret = inflateInit2( &strm, -15 );
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
@ -50,16 +46,14 @@ void no_header_decompress(uint8_t* in, uint32_t in_size, uint8_t* out, uint32_t
strm.next_out = out;
// Effectively decompress data
ret = inflate(&strm, Z_NO_FLUSH);
if (ret != Z_STREAM_END)
ret = inflate( &strm, Z_NO_FLUSH );
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
inflateEnd(&strm);
}
inflateEnd( &strm );
}
}
}
}

13
deps/datReader/zlib.h vendored
View file

@ -4,18 +4,13 @@
#include <cstdint>
#include <vector>
namespace xiv
{
namespace utils
{
namespace zlib
namespace xiv::utils::zlib
{
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 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 );
}
}
}
#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 <mysql.h>
#ifdef _MSC_VER
// fixes compile error when compiling with vs2019
#include <stdexcept>
#endif
#include <vector>
Mysql::Connection::Connection( std::shared_ptr< MySqlBase > pBase,

View file

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

View file

@ -31,8 +31,8 @@
#include <mutex>
#include <functional>
#include <experimental/filesystem>
namespace ci { namespace fs = std::experimental::filesystem; }
#include <filesystem>
namespace ci { namespace fs = std::filesystem; }
//! Exception for when Watchdog can't locate a file or parse the wildcard
class WatchedFileSystemExc : public std::exception {
@ -319,7 +319,7 @@ protected:
std::string mFilter;
std::function<void(const ci::fs::path&)> mCallback;
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;

File diff suppressed because it is too large Load diff

View file

@ -400,13 +400,6 @@ CREATE TABLE `dbupdate` (
PRIMARY KEY(`name`)
) 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` (
`HouseId` int(10) UNSIGNED NOT NULL AUTO_INCREMENT,
`LandSetId` int(10) UNSIGNED DEFAULT NULL,

View file

@ -2,8 +2,9 @@
#define _PLAYERMINIMAL_H
#include <map>
#include <stdint.h>
#include <string.h>
#include <cstdint>
#include <string>
#include <cstring>
namespace Sapphire::Api
{

View file

@ -192,13 +192,15 @@ void SapphireApi::deleteCharacter( std::string name, const uint32_t accountId )
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 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 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 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 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 charastatus WHERE CharacterId LIKE '" + std::to_string( id ) + "';" );
}
std::vector< PlayerMinimal > SapphireApi::getCharList( uint32_t accountId )

View file

@ -22,24 +22,23 @@
//Added for the default_resource example
#include <fstream>
#include <string>
#include <experimental/filesystem>
#include <filesystem>
#include <vector>
#include <algorithm>
#include <Framework.h>
#include <Logging/Logger.h>
#include "SapphireApi.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::Data::ExdDataGenerated g_exdDataGen;
Sapphire::Api::SapphireApi g_sapphireAPI;
namespace fs = std::experimental::filesystem;
namespace fs = std::filesystem;
using namespace std;
using namespace Sapphire;
@ -671,8 +670,9 @@ void defaultGet( shared_ptr< HttpServer::Response > response, shared_ptr< HttpSe
print_request_info( request );
try
{
auto web_root_path = fs::canonical( "web" );
auto path = fs::canonical( web_root_path / request->path );
auto web_root_path = fs::current_path() / "web";
auto path = web_root_path / request->path;
//Check if path is within web_root_path
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() ) )
@ -718,19 +718,19 @@ int main( int argc, char* argv[] )
Logger::setLogLevel( m_config.global.general.logLevel );
server.resource[ "^/ZoneName/([0-9]+)$" ][ "GET" ] = &getZoneName;
server.resource[ "^/sapphire-api/lobby/createAccount" ][ "POST" ] = &createAccount;
server.resource[ "^/sapphire-api/lobby/login" ][ "POST" ] = &login;
server.resource[ "^/sapphire-api/lobby/deleteCharacter" ][ "POST" ] = &deleteCharacter;
server.resource[ "^/sapphire-api/lobby/createCharacter" ][ "POST" ] = &createCharacter;
server.resource[ "^/sapphire-api/lobby/insertSession" ][ "POST" ] = &insertSession;
server.resource[ "^/sapphire-api/lobby/checkNameTaken" ][ "POST" ] = &checkNameTaken;
server.resource[ "^/sapphire-api/lobby/checkSession" ][ "POST" ] = &checkSession;
server.resource[ "^/sapphire-api/lobby/getNextCharId" ][ "POST" ] = &getNextCharId;
server.resource[ "^/sapphire-api/lobby/getNextContentId" ][ "POST" ] = &getNextContentId;
server.resource[ "^/sapphire-api/lobby/getCharacterList" ][ "POST" ] = &getCharacterList;
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[ "^ZoneName/([0-9]+)$" ][ "GET" ] = &getZoneName;
server.resource[ "^sapphire-api/lobby/createAccount" ][ "POST" ] = &createAccount;
server.resource[ "^sapphire-api/lobby/login" ][ "POST" ] = &login;
server.resource[ "^sapphire-api/lobby/deleteCharacter" ][ "POST" ] = &deleteCharacter;
server.resource[ "^sapphire-api/lobby/createCharacter" ][ "POST" ] = &createCharacter;
server.resource[ "^sapphire-api/lobby/insertSession" ][ "POST" ] = &insertSession;
server.resource[ "^sapphire-api/lobby/checkNameTaken" ][ "POST" ] = &checkNameTaken;
server.resource[ "^sapphire-api/lobby/checkSession" ][ "POST" ] = &checkSession;
server.resource[ "^sapphire-api/lobby/getNextCharId" ][ "POST" ] = &getNextCharId;
server.resource[ "^sapphire-api/lobby/getNextContentId" ][ "POST" ] = &getNextContentId;
server.resource[ "^sapphire-api/lobby/getCharacterList" ][ "POST" ] = &getCharacterList;
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.default_resource[ "GET" ] = &defaultGet;

View file

@ -304,7 +304,7 @@ namespace SimpleWeb {
size_t path_end;
if((path_end=line.find(' ', method_end+1))!=std::string::npos) {
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;
if((protocol_end=line.find('/', path_end+1))!=std::string::npos) {

View file

@ -6,6 +6,7 @@
#include "CommonGen.h"
#include "Vector3.h"
#include "Network/PacketDef/Ipcs.h"
// +---------------------------------------------------------------------------
// The following enumerations are structures to require their type be included.
@ -25,7 +26,9 @@ namespace Sapphire::Common
const uint8_t CURRENT_EXPANSION_ID = 3;
const uint8_t CLASSJOB_TOTAL = 38;
const uint8_t CLASSJOB_SLOTS = 28;
const uint8_t CLASSJOB_SLOTS = 30;
const uint8_t TOWN_COUNT = 6;
/*!
* @brief The maximum length (in ms) of a combo before it is canceled/voided.
@ -47,13 +50,13 @@ namespace Sapphire::Common
uint8_t plot;
};
enum InventoryOperation : uint8_t
enum InventoryOperation : uint16_t
{
Discard = 0x07,
Move = 0x08,
Swap = 0x09,
Merge = 0x0C,
Split = 0x0A
Discard = Network::Packets::ClientZoneIpcType::InventoryModifyHandler + 7,
Move = Network::Packets::ClientZoneIpcType::InventoryModifyHandler + 8,
Swap = Network::Packets::ClientZoneIpcType::InventoryModifyHandler + 9,
Split = Network::Packets::ClientZoneIpcType::InventoryModifyHandler + 10,
Merge = Network::Packets::ClientZoneIpcType::InventoryModifyHandler + 12
};
enum ClientLanguage : uint8_t
@ -157,44 +160,29 @@ namespace Sapphire::Common
ModelRing2 = 9
};
enum EquipSlotCategory : uint8_t
enum class EquipSlotCategory : uint8_t
{
Unequippable = 0,
// main slots
CharaMainHand = 1,
CharaOffHand = 2,
CharaHead = 3,
CharaBody = 4,
CharaHands = 5,
CharaWaist = 6,
CharaLegs = 7,
CharaFeet = 8,
CharaEars = 9,
CharaNeck = 10,
CharaWrist = 11,
CharaRing = 12,
CharaSoulCrystal = 17,
// specials
/*! Cannot equip gear to offhand slot */
MainTwoHandedWeapon = 13,
/*! Can be equipped in either main or offhand slot */
MainOrOffHand = 14, // unused
/*! Cannot equip gear to head */
BodyDisallowHead = 15,
/*! Cannot equip gear to hands, legs and feet slots */
BodyDisallowHandsLegsFeet = 16,
/*! Cannot equip gear to feet slot */
LegsDisallowFeet = 18,
/*! Cannot equp gear to head, hands, legs, feet slots */
BodyDisallowAll = 19,
/*! Cannot equip gear to hands slot */
BodyDisallowHands = 20,
/*! Cannot equip gear to legs & feet slots */
BodyDisallowLegsFeet = 21,
MainHand = 1,
OffHand = 2,
Head = 3,
Body = 4,
Hands = 5,
Waist = 6,
Legs = 7,
Feet = 8,
Ears = 9,
Neck = 10,
Wrist = 11,
Ring = 12,
MainTwoHandedWeapon = 13,
//MainOrOffHand = 14, // unused
BodyDisallowHead = 15,
BodyDisallowHandsLegsFeet = 16,
SoulCrystal = 17,
LegsDisallowFeet = 18,
BodyDisallowAll = 19,
BodyDisallowHands = 20,
BodyDisallowLegsFeet = 21,
};
enum InventoryType : uint16_t
@ -214,6 +202,8 @@ namespace Sapphire::Common
HandIn = 2005,
DamagedGear = 2007,
//UNKNOWN_1 = 2008,
// Temporary inventory that is used for the "trade" window
TradeInventory = 2009,
ArmoryOff = 3200,
ArmoryHead = 3201,
@ -222,8 +212,8 @@ namespace Sapphire::Common
ArmoryWaist = 3204,
ArmoryLegs = 3205,
ArmoryFeet = 3206,
ArmoryNeck = 3207,
ArmoryEar = 3208,
ArmoryEar = 3207,
ArmoryNeck = 3208,
ArmoryWrist = 3209,
ArmoryRing = 3300,
@ -232,6 +222,9 @@ namespace Sapphire::Common
SaddleBag0 = 4000,
SaddleBag1 = 4001,
// These are the ones you get when paying for premium companion app
PremiumSaddleBag0 = 4100,
PremiumSaddleBag1 = 4101,
RetainerBag0 = 10000,
RetainerBag1 = 10001,
@ -405,7 +398,7 @@ namespace Sapphire::Common
struct StatusEffect
{
uint16_t effect_id;
uint16_t unknown1;
uint16_t param;
float duration;
uint32_t sourceActorId;
};
@ -557,6 +550,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
{
None = 0, // Doesn't imply unaspected
@ -574,19 +591,27 @@ namespace Sapphire::Common
None = 0, // ?
MagicPoints = 3,
TacticsPoints = 5,
// WARGauge = 22,
// DRKGauge = 25,
// AetherflowStack = 30,
// Status = 32,
// PLDGauge = 41,
// RDMGaugeBoth = 74,
//// RDMGaugeBlack = 75, // not right?
// DRGGauge3Eyes = 76,
StatusEffect = 10,
WARGauge = 22,
DRKGauge = 25,
// AetherflowStack = 30,
// Status = 32,
SAMKenki = 39,
SAMSen = 40,
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,
Slashing = 1,
Piercing = 2,
@ -615,28 +640,41 @@ namespace Sapphire::Common
TpLoss = 12,
TpGain = 13,
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.
*
* @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
*/
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,
Mount = 38,
Mount = 40, // shifted one down from 5.18
VFX = 59, // links to VFX sheet
};
enum class ActionHitSeverityType : uint8_t
{
NormalDamage = 0,
CritHeal = 0,
NormalHeal = 0,
CritDamage = 1,
NormalHeal = 1,
CritHeal = 1,
DirectHitDamage = 2,
CritDirectHitDamage = 3
};
enum class ActionEffectResultFlag : uint8_t
{
None = 0,
Absorbed = 0x04,
ExtendedValue = 0x40,
EffectOnSource = 0x80,
Reflected = 0xA0,
};
enum ItemActionType : uint16_t
{
ItemActionVFX = 852,
@ -653,15 +691,15 @@ namespace Sapphire::Common
struct EffectEntry
{
Common::ActionEffectType effectType;
Common::ActionHitSeverityType hitSeverity;
uint8_t param;
uint8_t param0;
uint8_t param1;
/*!
* @brief Shows an additional percentage in the battle log
*
* Has no effect on what is shown and stored in value
*/
int8_t bonusPercent;
uint8_t valueMultiplier; // This multiplies whatever value is in the 'value' param by 10. Possibly a workaround for big numbers
uint8_t param2;
uint8_t extendedValueHighestByte;
uint8_t flags;
int16_t value;
};
@ -719,6 +757,7 @@ namespace Sapphire::Common
BetweenAreas = 24,
BoundByDuty = 28,
Performing = 40,
WatchingCutscene = 50, // this is actually just a dummy, this id is different
@ -989,6 +1028,7 @@ namespace Sapphire::Common
{
SingleTarget = 1,
CircularAOE = 2,
Type3 = 3, // another single target? no idea how to call it
RectangularAOE = 4,
CircularAoEPlaced = 7
};
@ -1005,8 +1045,209 @@ namespace Sapphire::Common
Gatherer
};
using PlayerStateFlagList = std::vector< PlayerStateFlag >;
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
};
}
#endif

File diff suppressed because it is too large Load diff

View file

@ -1,9 +1,8 @@
#include "ConfigMgr.h"
#include <iostream>
#include <fstream>
#include <experimental/filesystem>
#include <filesystem>
namespace fs = std::experimental::filesystem;
namespace fs = std::filesystem;
using namespace Sapphire;
using namespace Sapphire::Common;

View file

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

View file

@ -4,7 +4,6 @@
#include "Logging/Logger.h"
#include "PreparedStatement.h"
#include "Framework.h"
Sapphire::Db::DbConnection::DbConnection( ConnectionInfo& connInfo ) :
m_reconnecting( false ),

View file

@ -5,7 +5,6 @@
#include "StatementTask.h"
#include "Operation.h"
#include "ZoneDbConnection.h"
#include "Framework.h"
#include "Logging/Logger.h"
#include <mysql.h>

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -8,9 +8,9 @@
#include <spdlog/sinks/daily_file_sink.h>
// #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 )
{

View file

@ -24,6 +24,9 @@ namespace Sapphire::Network::ActorControl
SetStatus = 0x02,
CastStart = 0x03,
ToggleAggro = 0x04,
/*!
* param1 = ClassJob ID
*/
ClassJobChange = 0x05,
DefeatMsg = 0x06,
GainExpMsg = 0x07,
@ -108,6 +111,8 @@ namespace Sapphire::Network::ActorControl
ScreenFadeOut = 0xAA,
CeremonyDecoration = 0xB9,
ZoneIn = 0xC8,
ZoneInDefaultPos = 0xC9,
@ -142,6 +147,15 @@ namespace Sapphire::Network::ActorControl
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,
GatheringSenseMsg = 0x130,
@ -175,6 +189,14 @@ namespace Sapphire::Network::ActorControl
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,
/*!
@ -193,7 +215,19 @@ namespace Sapphire::Network::ActorControl
SetFavorite = 0x1FC,
LearnTeleport = 0x1FD,
OpenRecommendationGuide = 0x200,
/*!
* param1 = event type bitmask
* 1 = Quest
* 2 = GuildLeveAssignment
* 4 = GuildOrderGuide
* 8 = TripleTriad
* 16 = CustomTalk
* 32 = PreHandler
*/
BeginMapUpdate = 0x1FF,
FinishMapUpdate = 0x200,
//OpenRecommendationGuide = 0x200,
ArmoryErrorMsg = 0x201,
AchievementPopup = 0x203,
@ -208,11 +242,19 @@ namespace Sapphire::Network::ActorControl
/*!
* 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 => Item consumed, 4922 => Item obtained, 4925 => Exp obtained)
* param3 = item id (used for result types 4921 & 4922)
* 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.
*/
DesynthResult = 0x20F,
DesynthOrReductionResult = 0x20F,
GilTrailMsg = 0x211,
@ -230,18 +272,22 @@ namespace Sapphire::Network::ActorControl
GearSetEquipMsg = 0x321,
SetBait = 0x325, // param1: bait ID
SetFestival = 0x386, // param1: festival.exd index
ToggleOrchestrionUnlock = 0x396,
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 = 0x39F,
SetMountSpeed = 0x3A0, // updated 5.35 hotfix
Dismount = 0x3A1, // updated 4.5
Dismount = 0x3A2, // updated 5.35 hotfix
// Duty Recorder
BeginReplayAck = 0x3A2,
@ -318,6 +364,7 @@ namespace Sapphire::Network::ActorControl
DismountReq = 0x65,
SpawnCompanionReq = 0x66,
DespawnCompanionReq = 0x67,
RemoveStatusEffect = 0x68,
CastCancel = 0x69,
@ -331,6 +378,7 @@ namespace Sapphire::Network::ActorControl
TitleList = 0x12F,
UpdatedSeenHowTos = 0x133,
CutscenePlayed = 0x134, // param1 = cutscene id
AllotAttribute = 0x135,
ClearFieldMarkers = 0x13A,
@ -340,13 +388,19 @@ namespace Sapphire::Network::ActorControl
Timers = 0x1AB,
DyeItem = 0x1B5,
DyeItem = 0x1B0, // updated 5.21
RequestChocoboInventory = 0x1C4,
EmoteReq = 0x1F4,
EmoteCancel = 0x1F6,
PersistentEmoteCancel = 0x1F7,
/*!
* param2 = pose ID
* 0 = idle pose 0 (just standing)
* 1 = idle pose 1
* 2-4 = idle poses 2-4
*/
PoseChange = 0x1F9,
PoseReapply = 0x1FA,
PoseCancel = 0x1FB,
@ -355,6 +409,8 @@ namespace Sapphire::Network::ActorControl
AchievementComp = 0x203,
AchievementCatChat = 0x206,
RequestEventBattle = 0x232C,
QuestJournalUpdateQuestVisibility = 0x2BE,
QuestJournalClosed = 0x2BF,

View file

@ -1,17 +1,15 @@
#include "Connection.h"
#include "Hive.h"
#include <functional>
#include "Framework.h"
using namespace Sapphire;
Network::Connection::Connection( HivePtr hive, FrameworkPtr pFw ) :
Network::Connection::Connection( HivePtr hive ) :
m_hive( hive ),
m_socket( hive->getService() ),
m_io_strand( hive->getService() ),
m_receive_buffer_size( 32000 ),
m_error_state( 0 ),
m_pFw( pFw )
m_error_state( 0 )
{
}

View file

@ -35,9 +35,8 @@ namespace Sapphire::Network
std::list< std::vector< uint8_t > > m_pending_sends;
int32_t m_receive_buffer_size;
std::atomic< uint32_t > m_error_state;
FrameworkPtr m_pFw;
Connection( HivePtr hive, FrameworkPtr pFw );
Connection( HivePtr hive );
virtual ~Connection();
@ -141,13 +140,13 @@ namespace Sapphire::Network
//-----------------------------------------------------------------------------
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
{
AcceptorPtr acceptor( new Acceptor( pHive ) );
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 );
return connection;
}

View file

@ -43,207 +43,252 @@ namespace Sapphire::Network::Packets
*/
enum ServerZoneIpcType : uint16_t
{
Ping = 0x02A8, // updated 5.58 hotfix
Init = 0x013C, // updated 5.58 hotfix
// static opcode ( the ones that rarely, if ever, change )
Ping = 0x0065,
Init = 0x0066,
ActorFreeSpawn = 0x00B5, // updated 5.58 hotfix
InitZone = 0x0320, // updated 5.58 hotfix
ActorFreeSpawn = 0x0191,
InitZone = 0x019A,
EffectResult = 0x0387, // updated 5.58 hotfix
ActorControl = 0x00B0, // updated 5.58 hotfix
ActorControlSelf = 0x02B6, // updated 5.58 hotfix
ActorControlTarget = 0x03C5, // updated 5.58 hotfix
EffectResult = 0x0141,
ActorControl = 0x0142,
ActorControlSelf = 0x0143,
ActorControlTarget = 0x0144,
UpdateHpMpTp = 0x0145, // used when resting
/*!
* @brief Used when resting
*/
UpdateHpMpTp = 0x01A7, // updated 5.58 hotfix
///////////////////////////////////////////////////
ChatBanned = 0x006B,
Playtime = 0x0100, // updated 5.0
Logout = 0x0077, // updated 5.0
CFNotify = 0x0078,
ChatBanned = 0xF06B,
Playtime = 0x0179, // updated 5.58 hotfix
Logout = 0x0214, // updated 5.58 hotfix
CFNotify = 0x0327, // updated 5.58 hotfix
CFMemberStatus = 0x0079,
CFDutyInfo = 0x007A,
CFPlayerInNeed = 0x007F,
CFDutyInfo = 0x03AA, // updated 5.58 hotfix
CFPlayerInNeed = 0xF07F,
CFPreferredRole = 0x024B, // updated 5.58 hotfix
CFCancel = 0x01AC, // updated 5.58 hotfix
SocialRequestError = 0xF0AD,
SocialRequestError = 0x00AD,
CFRegistered = 0x029F, // updated 5.58 hotfix
SocialRequestResponse = 0x0082, // updated 5.58 hotfix
SocialMessage = 0x03CB, // updated 5.58 hotfix
SocialMessage2 = 0x01D7, // updated 5.58 hotfix
CancelAllianceForming = 0xF0C6, // updated 4.2
CFRegistered = 0x00B8, // updated 4.1
SocialRequestResponse = 0x00BB, // updated 4.1
CancelAllianceForming = 0x00C6, // updated 4.2
LogMessage = 0x0118, // updated 5.58 hotfix
LogMessage = 0x00D0,
Chat = 0x00FE, // updated 5.58 hotfix
PartyChat = 0x0065,
Chat = 0x0104, // updated 5.0
WorldVisitList = 0xF0FE, // added 4.5
WorldVisitList = 0x00FE, // added 4.5
SocialList = 0x015F, // updated 5.58 hotfix
SocialList = 0x010D, // updated 5.0
ExamineSearchInfo = 0x0133, // updated 5.58 hotfix
UpdateSearchInfo = 0x03E5, // updated 5.58 hotfix
InitSearchInfo = 0x0321, // updated 5.58 hotfix
ExamineSearchComment = 0x03AD, // updated 5.58 hotfix
ExamineSearchInfo = 0x010F, // added 5.0
UpdateSearchInfo = 0x0110, // updated 5.0
InitSearchInfo = 0x0111, // updated 5.0
ExamineSearchComment = 0x0102, // updated 4.1
ServerNoticeShort = 0x0333, // updated 5.58 hotfix
ServerNotice = 0x0171, // updated 5.58 hotfix
SetOnlineStatus = 0x037B, // updated 5.58 hotfix
ServerNoticeShort = 0x0115, // updated 5.0
ServerNotice = 0x0116, // updated 5.0
SetOnlineStatus = 0x0117, // updated 5.0
CountdownInitiate = 0x0111, // updated 5.58 hotfix
CountdownCancel = 0x0231, // updated 5.58 hotfix
CountdownInitiate = 0x011E, // updated 5.0
CountdownCancel = 0x011F, // updated 5.0
PlayerAddedToBlacklist = 0x024E, // updated 5.58 hotfix
PlayerRemovedFromBlacklist = 0x011D, // updated 5.58 hotfix
BlackList = 0x03C0, // updated 5.58 hotfix
PlayerAddedToBlacklist = 0x0120, // updated 5.0
PlayerRemovedFromBlacklist = 0x0121, // updated 5.0
BlackList = 0x0123, // updated 5.0
LinkshellList = 0x02E2, // updated 5.58 hotfix
LinkshellList = 0x012A, // updated 5.0
MailDeleteRequest = 0x012B, // updated 5.0
MailDeleteRequest = 0xF12B, // updated 5.0
// 12D - 137 - constant gap between 4.5x -> 5.0
ReqMoogleMailList = 0x0138, // updated 5.0
ReqMoogleMailLetter = 0x0139, // updated 5.0
ReqMoogleMailList = 0xF138, // updated 5.0
ReqMoogleMailLetter = 0xF139, // updated 5.0
MailLetterNotification = 0x013A, // updated 5.0
MarketBoardItemListingCount = 0x013B, // updated 5.0
MarketBoardItemListing = 0x013C, // updated 5.0
MarketBoardItemListingHistory = 0x012A, // updated 4.5
MarketBoardSearchResult = 0x0139, // updated 4.5
MarketTaxRates = 0x01F8, // updated 5.35 hotfix
MarketBoardSearchResult = 0x01F1, // updated 5.58 hotfix
MarketBoardItemListingCount = 0x0068, // updated 5.58 hotfix
MarketBoardItemListingHistory = 0x01BA, // updated 5.58 hotfix
MarketBoardItemListing = 0x0076, // updated 5.58 hotfix
CharaFreeCompanyTag = 0x013B, // updated 4.5
FreeCompanyBoardMsg = 0x013C, // updated 4.5
FreeCompanyInfo = 0x013D, // updated 4.5
ExamineFreeCompanyInfo = 0x013E, // updated 4.5
FreeCompanyBoardMsg = 0x03DB, // updated 5.58 hotfix
FreeCompanyInfo = 0x01F7, // updated 5.58 hotfix
ExamineFreeCompanyInfo = 0x0324, // updated 5.58 hotfix
FreeCompanyUpdateShortMessage = 0x0157, // added 5.0
FreeCompanyUpdateShortMessage = 0xF157, // added 5.0
StatusEffectList = 0x015B, // updated 5.0
EurekaStatusEffectList = 0x015C, // updated 5.0
Effect = 0x015E, // updated 5.0
AoeEffect8 = 0x0161, // updated 5.0
AoeEffect16 = 0x0162, // updated 5.0
AoeEffect24 = 0x0163, // updated 5.0
AoeEffect32 = 0x0164, // updated 5.0
PersistantEffect = 0x0165, // updated 5.0
StatusEffectList = 0x0074, // updated 5.58 hotfix
EurekaStatusEffectList = 0x0167, // updated 5.18
BossStatusEffectList = 0x0312, // added 5.1
Effect = 0x03CA, // updated 5.58 hotfix
AoeEffect8 = 0x03C4, // updated 5.58 hotfix
AoeEffect16 = 0x00FA, // updated 5.58 hotfix
AoeEffect24 = 0x0339, // updated 5.58 hotfix
AoeEffect32 = 0x023C, // updated 5.58 hotfix
PersistantEffect = 0x025D, // updated 5.58 hotfix
GCAffiliation = 0x016F, // updated 5.0
GCAffiliation = 0x0094, // updated 5.58 hotfix
PlayerSpawn = 0x017F, // updated 5.0
NpcSpawn = 0x0180, // updated 5.0
NpcSpawn2 = 0x0181, // ( Bigger statuseffectlist? ) updated 5.0
ActorMove = 0x0182, // updated 5.0
PlayerSpawn = 0x01D8, // updated 5.58 hotfix
NpcSpawn = 0x00D2, // updated 5.58 hotfix
NpcSpawn2 = 0x01CB, // ( Bigger statuseffectlist? ) updated 5.3
ActorMove = 0x00F8, // updated 5.58 hotfix
ActorSetPos = 0x0184, // updated 5.0
ActorSetPos = 0x0299, // updated 5.58 hotfix
ActorCast = 0x0186, // updated 5.0
SomeCustomiseChangePacketProbably = 0x0187, // added 5.0
PartyList = 0x0188, // updated 5.0
HateRank = 0x0189, // updated 5.0
HateList = 0x018A, // updated 5.0
ObjectSpawn = 0x018B, // updated 5.0
ObjectDespawn = 0x018C, // updated 5.0
UpdateClassInfo = 0x018D, // updated 5.0
SilentSetClassJob = 0x018E, // updated 5.0 - seems to be the case, not sure if it's actually used for anything
PlayerSetup = 0x018F, // updated 5.0
PlayerStats = 0x0190, // updated 5.0
ActorOwner = 0x0192, // updated 5.0
PlayerStateFlags = 0x0193, // updated 5.0
PlayerClassInfo = 0x0194, // updated 5.0
ActorCast = 0x015D, // updated 5.58 hotfix
SomeCustomiseChangePacketProbably = 0x00CD, // added 5.18
ModelEquip = 0x0196, // updated 5.0
Examine = 0x0197, // updated 5.0
CharaNameReq = 0x0198, // updated 5.0
PartyList = 0x0349, // updated 5.58 hotfix
PartyMessage = 0x00A4, // updated 5.58 hotfix
HateRank = 0x0150, // updated 5.58 hotfix
HateList = 0x0243, // updated 5.58 hotfix
ObjectSpawn = 0x0125, // updated 5.58 hotfix
ObjectDespawn = 0x0148, // updated 5.58 hotfix
UpdateClassInfo = 0x0084, // updated 5.58 hotfix
SilentSetClassJob = 0xF18E, // updated 5.0 - seems to be the case, not sure if it's actually used for anything
PlayerSetup = 0x01D5, // updated 5.58 hotfix
PlayerStats = 0x0295, // updated 5.58 hotfix
ActorOwner = 0x0260, // updated 5.58 hotfix
PlayerStateFlags = 0x03BF, // updated 5.58 hotfix
PlayerClassInfo = 0x0131, // updated 5.58 hotfix
CharaVisualEffect = 0x0292, // updated 5.58 hotfix
ModelEquip = 0x03A2, // updated 5.58 hotfix
Examine = 0x0365, // updated 5.58 hotfix
CharaNameReq = 0x01F0, // updated 5.58 hotfix
// nb: see #565 on github
UpdateRetainerItemSalePrice = 0x019F, // updated 5.0
UpdateRetainerItemSalePrice = 0xF19F, // updated 5.0
RetainerSaleHistory = 0x03CE, // updated 5.58 hotfix
RetainerInformation = 0x022F, // updated 5.58 hotfix
SetLevelSync = 0x1186, // not updated for 4.4, not sure what it is anymore
ItemInfo = 0x01A1, // updated 5.0
ContainerInfo = 0x01A2, // updated 5.0
InventoryTransactionFinish = 0x01A3, // updated 5.0
InventoryTransaction = 0x01A4, // updated 5.0
CurrencyCrystalInfo = 0x01A5, // updated 5.0
ItemInfo = 0x01CC, // updated 5.58 hotfix
ContainerInfo = 0x025C, // updated 5.58 hotfix
InventoryTransactionFinish = 0x0176, // updated 5.58 hotfix
InventoryTransaction = 0x027F, // updated 5.58 hotfix
CurrencyCrystalInfo = 0x0345, // updated 5.58 hotfix
InventoryActionAck = 0x01A7, // updated 5.0
UpdateInventorySlot = 0x01A8, // updated 5.0
InventoryActionAck = 0x03B8, // updated 5.58 hotfix
UpdateInventorySlot = 0x02F7, // updated 5.58 hotfix
HuntingLogEntry = 0x01B3, // updated 5.0
HuntingLogEntry = 0x01D9, // updated 5.58 hotfix
EventPlay = 0x01B5, // updated 5.0
DirectorPlayScene = 0x01B9, // updated 5.0
EventOpenGilShop = 0x01BC, // updated 5.0
EventPlay = 0x016B, // updated 5.58 hotfix
EventPlay4 = 0x010A, // updated 5.58 hotfix
EventPlay8 = 0x0337, // updated 5.58 hotfix
EventPlay16 = 0x0269, // updated 5.58 hotfix
EventPlay32 = 0x023E, // updated 5.58 hotfix
EventPlay64 = 0x00DE, // updated 5.58 hotfix
EventPlay128 = 0x02D0, // updated 5.58 hotfix
EventPlay255 = 0x0362, // updated 5.58 hotfix
EventStart = 0x01BE, // updated 5.0
EventFinish = 0x01BF, // updated 5.0
EventContinue = 0x00B6, // updated 5.58 hotfix
EventStart = 0x02DA, // updated 5.58 hotfix
EventFinish = 0x0235, // updated 5.58 hotfix
EventLinkshell = 0x1169,
QuestActiveList = 0x01D2, // updated 5.0
QuestUpdate = 0x01D3, // updated 5.0
QuestCompleteList = 0x01D4, // updated 5.0
QuestActiveList = 0x0097, // updated 5.58 hotfix
QuestUpdate = 0x01B2, // updated 5.58 hotfix
QuestCompleteList = 0x006D, // updated 5.58 hotfix
QuestFinish = 0x01D5, // updated 5.0
MSQTrackerComplete = 0x01D6, // updated 5.0
QuestFinish = 0x021B, // updated 5.58 hotfix
MSQTrackerComplete = 0x0348, // updated 5.58 hotfix
MSQTrackerProgress = 0xF1CD, // updated 4.5 ? this actually looks like the two opcodes have been combined, see #474
QuestMessage = 0x01DE, // updated 5.0
QuestMessage = 0x0220, // updated 5.58 hotfix
QuestTracker = 0x01E3, // updated 5.0
QuestTracker = 0x00D8, // updated 5.58 hotfix
Mount = 0x01F3, // updated 5.0
Mount = 0x01E1, // updated 5.58 hotfix
DirectorVars = 0x01F5, // updated 5.0
DirectorPopUp = 0x0200, // updated 5.0 - display dialogue pop-ups in duties and FATEs, for example, Teraflare's countdown
DirectorVars = 0x0154, // updated 5.58 hotfix
SomeDirectorUnk1 = 0x0084, // updated 5.18
SomeDirectorUnk2 = 0xF0C1, // updated 5.18
SomeDirectorUnk4 = 0x03DD, // updated 5.58 hotfix
SomeDirectorUnk8 = 0x028A, // updated 5.18
SomeDirectorUnk16 = 0x028C, // updated 5.18
DirectorPopUp = 0x03DF, // updated 5.58 hotfix
DirectorPopUp4 = 0x019B, // updated 5.58 hotfix
DirectorPopUp8 = 0x0271, // updated 5.58 hotfix
CFAvailableContents = 0xF1FD, // updated 4.2
WeatherChange = 0x0210, // updated 5.0
PlayerTitleList = 0x0211, // updated 5.0
Discovery = 0x0212, // updated 5.0
WeatherChange = 0x0323, // updated 5.58 hotfix
PlayerTitleList = 0x014E, // updated 5.58 hotfix
Discovery = 0x01C2, // updated 5.58 hotfix
EorzeaTimeOffset = 0x0214, // updated 5.0
EorzeaTimeOffset = 0x0070, // updated 5.58 hotfix
EquipDisplayFlags = 0x0220, // updated 5.0
EquipDisplayFlags = 0x02C6, // updated 5.58 hotfix
MiniCactpotInit = 0x0286, // added 5.31
ShopMessage = 0x0287, // updated 5.58 hotfix
LootMessage = 0x0383, // updated 5.58 hotfix
ResultDialog = 0x0273, // updated 5.58 hotfix
DesynthResult = 0x0238, // updated 5.58 hotfix
/// Housing //////////////////////////////////////
LandSetInitialize = 0x0234, // updated 5.0
LandUpdate = 0x0235, // updated 5.0
YardObjectSpawn = 0x0236, // updated 5.0
HousingIndoorInitialize = 0x0237, // updated 5.0
LandPriceUpdate = 0x0238, // updated 5.0
LandInfoSign = 0x0239, // updated 5.0
LandRename = 0x023A, // updated 5.0
HousingEstateGreeting = 0x023B, // updated 5.0
HousingUpdateLandFlagsSlot = 0x023C, // updated 5.0
HousingLandFlags = 0x023D, // updated 5.0
HousingShowEstateGuestAccess = 0x023E, // updated 5.0
LandSetInitialize = 0x0159, // updated 5.58 hotfix
LandUpdate = 0x0228, // updated 5.58 hotfix
YardObjectSpawn = 0x023D, // updated 5.58 hotfix
HousingIndoorInitialize = 0x0210, // updated 5.58 hotfix
LandPriceUpdate = 0x0300, // updated 5.58 hotfix
LandInfoSign = 0x03E7, // updated 5.58 hotfix
LandRename = 0x01BF, // updated 5.58 hotfix
HousingEstateGreeting = 0x0126, // updated 5.58 hotfix
HousingUpdateLandFlagsSlot = 0x0157, // updated 5.58 hotfix
HousingLandFlags = 0x03B1, // updated 5.58 hotfix
HousingShowEstateGuestAccess = 0x00CC, // updated 5.58 hotfix
HousingObjectInitialize = 0x0240, // updated 5.0
HousingInternalObjectSpawn = 0x241, // updated 5.0
HousingObjectInitialize = 0x0112, // updated 5.58 hotfix
HousingInternalObjectSpawn = 0x02C8, // updated 5.58 hotfix
HousingWardInfo = 0x0243, // updated 5.0
HousingObjectMove = 0x0244, // updated 5.0
HousingWardInfo = 0x012A, // updated 5.58 hotfix
HousingObjectMove = 0x0265, // updated 5.58 hotfix
SharedEstateSettingsResponse = 0x0245, // updated 4.5
SharedEstateSettingsResponse = 0x030E, // updated 5.58 hotfix
LandUpdateHouseName = 0x0257, // updated 4.5
LandUpdateHouseName = 0x017C, // updated 5.58 hotfix
LandSetMap = 0x025B, // updated 4.5
LandSetMap = 0x02E5, // updated 5.58 hotfix
CeremonySetActorAppearance = 0x02ED, // updated 5.58 hotfix
//////////////////////////////////////////////////
DuelChallenge = 0x0277, // 4.2; this is responsible for opening the ui
PerformNote = 0x0286, // updated 4.3
PerformNote = 0x0127, // updated 5.58 hotfix
PrepareZoning = 0x02A4, // updated 5.0
ActorGauge = 0x0292, // updated 4.3
PrepareZoning = 0x02AB, // updated 5.58 hotfix
ActorGauge = 0x01C1, // updated 5.58 hotfix
DutyGauge = 0x02E5, // updated 5.58 hotfix
// daily quest info -> without them sent, login will take longer...
DailyQuests = 0x025E, // updated 5.0
DailyQuestRepeatFlags = 0x0260, // updated 5.0
DailyQuests = 0x02D6, // updated 5.58 hotfix
DailyQuestRepeatFlags = 0x01AB, // updated 5.58 hotfix
MapUpdate = 0x0394, // updated 5.58 hotfix
MapUpdate4 = 0x036F, // updated 5.58 hotfix
MapUpdate8 = 0x0311, // updated 5.58 hotfix
MapUpdate16 = 0x0108, // updated 5.58 hotfix
MapUpdate32 = 0x007A, // updated 5.58 hotfix
MapUpdate64 = 0x02A0, // updated 5.58 hotfix
MapUpdate128 = 0x0303, // updated 5.58 hotfix
/// Doman Mahjong //////////////////////////////////////
MahjongOpenGui = 0x02A4, // only available in mahjong instance
@ -252,10 +297,20 @@ namespace Sapphire::Network::Packets
MahjongEndRoundTsumo = 0x02BF, // called tsumo
MahjongEndRoundRon = 0x2C0, // called ron or double ron (waiting for action must be flagged from discard packet to call)
MahjongTileDiscard = 0x02C1, // giri (discarding a tile.) chi(1)/pon(2)/kan(4)/ron(8) flags etc..
MahjongPlayersInfo = 0x02C2, // actor id, name, rating and stuff..
MahjongPlayersInfo = 0xF2C2, // actor id, name, rating and stuff..
// 2C3 and 2C4 are currently unknown
MahjongEndRoundDraw = 0x02C5, // self explanatory
MahjongEndGame = 0x02C6, // finished oorasu(all-last) round; shows a result screen.
/// Airship & Submarine //////////////////////////////////////
AirshipExplorationResult = 0x0203, // updated 5.58 hotfix
AirshipStatus = 0x030C, // updated 5.58 hotfix
AirshipStatusList = 0x02FE, // updated 5.58 hotfix
AirshipTimers = 0x0166, // updated 5.58 hotfix
SubmarineExplorationResult = 0x00AA, // updated 5.58 hotfix
SubmarineProgressionStatus = 0x0357, // updated 5.58 hotfix
SubmarineStatusList = 0x01EF, // updated 5.58 hotfix
SubmarineTimers = 0x0247, // updated 5.58 hotfix
};
/**
@ -263,102 +318,111 @@ namespace Sapphire::Network::Packets
*/
enum ClientZoneIpcType : uint16_t
{
PingHandler = 0x0288, // updated 5.58 hotfix
InitHandler = 0x02EB, // updated 5.58 hotfix
PingHandler = 0x0065, // unchanged 5.0
InitHandler = 0x0066, // unchanged 5.0
FinishLoadingHandler = 0x013C, // updated 5.58 hotfix
FinishLoadingHandler = 0x0069, // unchanged 5.0
CFCommenceHandler = 0x0381, // updated 5.58 hotfix
CFCommenceHandler = 0x006F,
CFCancelHandler = 0x02B2, // updated 5.58 hotfix
CFRegisterDuty = 0x01BD, // updated 5.58 hotfix
CFRegisterRoulette = 0x037A, // updated 5.58 hotfix
PlayTimeHandler = 0x02B7, // updated 5.58 hotfix
LogoutHandler = 0x00A0, // updated 5.58 hotfix
CancelLogout = 0x01AC, // updated 5.58 hotfix
CFDutyInfoHandler = 0xF078, // updated 4.2
SocialReqSendHandler = 0x00D7, // updated 5.58 hotfix
SocialResponseHandler = 0x023B, // updated 5.58 hotfix
CreateCrossWorldLS = 0x035D, // updated 5.58 hotfix
CFRegisterDuty = 0x0071,
CFRegisterRoulette = 0x0072,
PlayTimeHandler = 0x0073, // unchanged 5.0
LogoutHandler = 0x0074, // unchanged 5.0
CancelLogout = 0x0075, // updated 5.0
ChatHandler = 0x03B0, // updated 5.58 hotfix
PartyChatHandler = 0x0065,
PartySetLeaderHandler = 0x036C, // updated 5.58 hotfix
LeavePartyHandler = 0x019D, // updated 5.58 hotfix
KickPartyMemberHandler = 0x0262, // updated 5.58 hotfix
DisbandPartyHandler = 0x0276, // updated 5.58 hotfix
CFDutyInfoHandler = 0x0078, // updated 4.2
SocialReqSendHandler = 0x00AE, // updated 4.1
CreateCrossWorldLS = 0x00AF, // updated 4.3
ChatHandler = 0x00D9, // updated 5.0
SocialListHandler = 0x00E1, // updated 5.0
SetSearchInfoHandler = 0x00E4, // updated 5.0
ReqSearchInfoHandler = 0x00E6, // updated 5.0
SocialListHandler = 0x01CA, // updated 5.58 hotfix
SetSearchInfoHandler = 0x01D4, // updated 5.58 hotfix
ReqSearchInfoHandler = 0x014F, // updated 5.58 hotfix
ReqExamineSearchCommentHandler = 0x00E7, // updated 5.0
ReqRemovePlayerFromBlacklist = 0x00F1, // updated 5.0
BlackListHandler = 0x00F2, // updated 5.0
PlayerSearchHandler = 0x00F4, // updated 5.0
ReqRemovePlayerFromBlacklist = 0x00B4, // updated 5.58 hotfix
BlackListHandler = 0x00F2, // updated 5.58 hotfix
PlayerSearchHandler = 0x037D, // updated 5.58 hotfix
LinkshellListHandler = 0x00FA, // updated 5.0
LinkshellListHandler = 0x03B6, // updated 5.58 hotfix
MarketBoardRequestItemListingInfo = 0x0102, // updated 4.5
MarketBoardRequestItemListings = 0x0103, // updated 4.5
MarketBoardSearch = 0x0107, // updated 4.5
MarketBoardRequestItemListingInfo = 0x00F4, // updated 5.58 hotfix
MarketBoardRequestItemListings = 0x0122, // updated 5.58 hotfix
MarketBoardSearch = 0x0082, // updated 5.58 hotfix
ReqExamineFcInfo = 0x0113, // updated 4.1
ReqExamineFcInfo = 0x037B, // updated 5.58 hotfix
FcInfoReqHandler = 0x011A, // updated 4.2
FcInfoReqHandler = 0x03D4, // updated 5.58 hotfix
FreeCompanyUpdateShortMessageHandler = 0x0123, // added 5.0
ReqMarketWishList = 0x012C, // updated 4.3
ReqMarketWishList = 0x00C3, // updated 5.58 hotfix
ReqJoinNoviceNetwork = 0x0129, // updated 4.2
ReqCountdownInitiate = 0x0135, // updated 5.0
ReqCountdownCancel = 0x0136, // updated 5.0
ReqCountdownInitiate = 0x02EC, // updated 5.58 hotfix
ReqCountdownCancel = 0x0068, // updated 5.58 hotfix
ZoneLineHandler = 0x0139, // updated 5.0
ClientTrigger = 0x013A, // updated 5.0
DiscoveryHandler = 0x013B, // updated 5.0
ZoneLineHandler = 0x008D, // updated 5.58 hotfix
ClientTrigger = 0x03DB, // updated 5.58 hotfix
DiscoveryHandler = 0x038B, // updated 5.58 hotfix
PlaceFieldMarker = 0x013C, // updated 5.0
PlaceFieldMarkerPreset = 0x026D, // updated 5.58 hotfix
PlaceFieldMarker = 0x0371, // updated 5.58 hotfix
SkillHandler = 0x02DC, // updated 5.58 hotfix
GMCommand1 = 0x0272, // updated 5.58 hotfix
GMCommand2 = 0x00E9, // updated 5.58 hotfix
AoESkillHandler = 0x0152, // updated 5.58 hotfix
SkillHandler = 0x013D, // updated 5.0
GMCommand1 = 0x013E, // updated 5.0
GMCommand2 = 0x013F, // updated 5.0
AoESkillHandler = 0x140, // updated 5.0
UpdatePositionHandler = 0x01AF, // updated 5.58 hotfix
UpdatePositionHandler = 0x0141, // updated 5.0
InventoryModifyHandler = 0x029E, // updated 5.58 hotfix
InventoryModifyHandler = 0x0148, // updated 5.0
InventoryEquipRecommendedItems = 0x0149, // updated 5.0
InventoryEquipRecommendedItems = 0x01C9, // updated 5.58 hotfix
ReqPlaceHousingItem = 0x014B, // updated 5.0
BuildPresetHandler = 0x014F, // updated 5.0
ReqPlaceHousingItem = 0x02D4, // updated 5.58 hotfix
BuildPresetHandler = 0x0223, // updated 5.58 hotfix
TalkEventHandler = 0x0151, // updated 5.0
EmoteEventHandler = 0x0152, // updated 5.0
WithinRangeEventHandler = 0x0153, // updated 5.0
OutOfRangeEventHandler = 0x0154, // updated 5.0
EnterTeriEventHandler = 0x0155, // updated 5.0
ShopEventHandler = 0x0156, // updated 5.0
ReturnEventHandler = 0x015A, // updated 5.0?
TradeReturnEventHandler = 0x015B, // updated 5.0?
TalkEventHandler = 0x0387, // updated 5.58 hotfix
EmoteEventHandler = 0x00B0, // updated 5.58 hotfix
WithinRangeEventHandler = 0x02B6, // updated 5.58 hotfix
OutOfRangeEventHandler = 0x03C5, // updated 5.58 hotfix
EnterTeriEventHandler = 0x01A7, // updated 5.58 hotfix
ShopEventHandler = 0x0384, // updated 5.58 hotfix
ReturnEventHandler = 0x00FA, // updated 5.58 hotfix
TradeReturnEventHandler = 0x0339, // updated 5.58 hotfix
TradeReturnEventHandler2 = 0x023C, // updated 5.58 hotfix
EventYield2Handler = 0x021D, // updated 5.58 hotfix
EventYield16Handler = 0x0207, // updated 5.58 hotfix
LinkshellEventHandler = 0x016B, // updated 4.5
LinkshellEventHandler1 = 0x016C, // updated 4.5
ReqEquipDisplayFlagsChange = 0x0175, // updated 5.0
ReqEquipDisplayFlagsChange = 0x02A5, // updated 5.58 hotfix
LandRenameHandler = 0x0177, // updated 5.0
HousingUpdateHouseGreeting = 0x0178, // updated 5.0
HousingUpdateObjectPosition = 0x0179, // updated 5.0
LandRenameHandler = 0x028E, // updated 5.58 hotfix
HousingUpdateHouseGreeting = 0x0343, // updated 5.58 hotfix
HousingUpdateObjectPosition = 0x012C, // updated 5.58 hotfix
HousingEditExterior = 0x027B, // updated 5.58 hotfix
HousingEditInterior = 0x02E3, // updated 5.58 hotfix
SetSharedEstateSettings = 0x017B, // updated 5.0
UpdatePositionInstance = 0x0180, // updated 5.0
PerformNoteHandler = 0x029B, // updated 4.3
SetSharedEstateSettings = 0x00D2, // updated 5.58 hotfix
UpdatePositionInstance = 0x00F8, // updated 5.58 hotfix
PerformNoteHandler = 0x0243, // updated 5.58 hotfix
WorldInteractionHandler = 0x0274, // updated 5.58 hotfix
Dive = 0x0320, // updated 5.58 hotfix
};
////////////////////////////////////////////////////////////////////////////////
@ -369,6 +433,7 @@ namespace Sapphire::Network::Packets
enum ServerChatIpcType : uint16_t
{
Tell = 0x0064, // updated for sb
PublicContentTell = 0x00FB, // added 4.5, this is used when receiving a /tell in PublicContent instances such as Eureka or Bozja
TellErrNotFound = 0x0066,
FreeCompanyEvent = 0x012C, // added 5.0
@ -380,6 +445,7 @@ namespace Sapphire::Network::Packets
enum ClientChatIpcType : uint16_t
{
TellReq = 0x0064,
PublicContentTellReq = 0x0326, // updated 5.35 hotfix, this is used when sending a /tell in PublicContent instances such as Eureka or Bozja
};

View file

@ -49,15 +49,26 @@ struct FFXIVIpcUpdatePosition :
FFXIVIpcBasePacket< UpdatePositionHandler >
{
/* 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;
/* 0008 */ Common::FFXIVARR_POSITION3 position;
/* 000C */ uint8_t animationType;
/* 000D */ uint8_t animationState;
/* 000E */ uint8_t clientAnimationType;
/* 000F */ uint8_t unk_2;
/* 000C */ uint8_t unk[ 4 ]; // padding?
};
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 :
FFXIVIpcBasePacket< SkillHandler >
{
@ -196,6 +207,13 @@ struct FFXIVIpcChatHandler :
/* 001A */ char message[1012];
};
struct FFXIVIpcPartyChatHandler :
FFXIVIpcBasePacket< ChatHandler >
{
uint64_t unknown;
char message[1024];
};
struct FFXIVIpcShopEventHandler :
FFXIVIpcBasePacket< ShopEventHandler >
{
@ -217,7 +235,7 @@ struct FFXIVIpcInventoryModifyHandler :
{
/* 0000 */ uint32_t seq;
/* 0004 */ Common::InventoryOperation action;
/* 0005 */ uint8_t pad_0005[7];
/* 0006 */ uint8_t pad_0006[6];
/* 000C */ uint16_t fromContainer;
/* 000E */ uint8_t pad_000E[2];
/* 0010 */ uint8_t fromSlot;
@ -333,6 +351,126 @@ struct FFXIVIpcFreeCompanyUpdateShortMessageHandler :
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;
};
struct FFXIVIpcHousingEditExterior :
FFXIVIpcBasePacket< HousingEditExterior >
{
uint16_t landId;
uint8_t unknown[6];
uint8_t removeFlag;
uint8_t unknown2;
uint16_t container[9];
uint16_t slot[9];
uint16_t padding;
};
struct FFXIVIpcHousingEditInterior :
FFXIVIpcBasePacket< HousingEditInterior >
{
uint64_t unknown;
uint16_t container[10];
uint16_t slot[10];
};
struct FFXIVIpcEventYieldHandler :
FFXIVIpcBasePacket< EventYield2Handler >
{
uint32_t eventId;
uint16_t scene;
uint16_t padding;
uint64_t unknown;
};
struct FFXIVIpcEventYield16Handler :
FFXIVIpcBasePacket< EventYield16Handler >
{
uint32_t eventId;
uint16_t scene;
uint16_t padding;
uint32_t params[16];
};
struct FFXIVIpcCFCommenceHandler :
FFXIVIpcBasePacket< CFCommenceHandler >
{
uint8_t param;
uint8_t dummy[7];
};
}
#endif //_CORE_NETWORK_PACKETS_ZONE_CLIENT_IPC_H

View file

@ -46,6 +46,19 @@ namespace Sapphire::Network::Packets::Server
char msg[1012];
};
struct FFXIVIpcPartyChat : FFXIVIpcBasePacket< PartyChat >
{
uint64_t unknown;
uint64_t contentId;
uint32_t charaId;
uint8_t u1;
uint8_t u2;
uint8_t u3;
char name[32];
char message[1024];
uint8_t padding;
};
struct FFXIVIpcChatBanned : FFXIVIpcBasePacket< ChatBanned >
{
uint8_t padding[4]; // I was not sure reinterpreting ZST is valid behavior in C++.
@ -244,6 +257,7 @@ namespace Sapphire::Network::Packets::Server
uint8_t rank;
uint16_t padding;
uint8_t lsName[20];
uint8_t unk[16];
} entry[8];
};
@ -283,6 +297,17 @@ namespace Sapphire::Network::Packets::Server
char unk2[0x4]; // This has probs something to do with the support desk (inquiry id?)
};
struct FFFXIVIpcMarketTaxRates : FFXIVIpcBasePacket< MarketTaxRates >
{
// Same handler as MiniCactpotInit
uint32_t type;
uint16_t category;
uint8_t unknown1;
uint8_t unknown2;
uint32_t taxRate[Common::TOWN_COUNT]; // In the order of Common::Town
uint64_t unknown3;
};
struct FFFXIVIpcMarketBoardItemListingCount : FFXIVIpcBasePacket< MarketBoardItemListingCount >
{
uint32_t itemCatalogId;
@ -322,15 +347,7 @@ namespace Sapphire::Network::Packets::Server
bool hq;
uint8_t materiaCount;
uint8_t onMannequin;
/**
* 0x01 Limsa Lominsa
* 0x02 Gridania
* 0x03 Ul'dah
* 0x04 Ishgard
* 0x07 Kugane
* 0x0A Crystarium
*/
uint8_t retainerCity;
Common::Town marketCity;
uint16_t dyeId;
uint16_t padding3;
uint32_t padding4;
@ -419,8 +436,9 @@ namespace Sapphire::Network::Packets::Server
uint32_t max_hp;
uint16_t current_mp;
uint16_t max_mp;
uint16_t currentTp;
uint16_t unknown1;
uint8_t shieldPercentage;
uint8_t unknown1;
uint16_t unknown2;
Common::StatusEffect effect[30];
uint32_t padding;
};
@ -437,17 +455,16 @@ namespace Sapphire::Network::Packets::Server
*/
struct FFXIVIpcEffectResult : FFXIVIpcBasePacket< EffectResult >
{
uint32_t unknown;
uint32_t globalSequence;
uint32_t actor_id;
uint8_t unknown1;
uint8_t unknown2;
uint16_t padding1;
uint32_t current_hp;
uint16_t current_mp;
uint16_t current_tp;
uint32_t max_hp;
uint16_t max_mp;
uint16_t max_something;
uint16_t current_mp;
uint8_t unknown1;
uint8_t classId;
uint8_t shieldPercentage;
uint8_t entryCount;
uint16_t unknown2;
struct StatusEntry
{
@ -455,12 +472,11 @@ namespace Sapphire::Network::Packets::Server
uint8_t unknown3;
uint16_t id;
uint16_t param;
uint16_t unknown5; // Sort this out (old right half of power/param property)
uint16_t unknown4; // Sort this out (old right half of power/param property)
float duration;
uint32_t sourceActorId;
} statusEntries[4];
uint32_t unknown4;
};
/**
@ -525,33 +541,6 @@ namespace Sapphire::Network::Packets::Server
/* 0012 */ uint32_t unknown_12;
};
/**
* Structural representation of the packet sent by the server
* for battle actions
*/
struct EffectHeader
{
uint64_t animationTargetId; // who the animation targets
uint32_t actionId; // what the casting player casts, shown in battle log/ui
uint32_t globalEffectCounter; // seems to only increment on retail?
float animationLockTime; // maybe? doesn't seem to do anything
uint32_t someTargetId; // always 00 00 00 E0, 0x0E000000 is the internal def for INVALID TARGET ID
uint16_t hiddenAnimation; // if 0, always shows animation, otherwise hides it. counts up by 1 for each animation skipped on a caster
uint16_t rotation;
uint16_t actionAnimationId; // the animation that is played by the casting character
uint8_t variation; // variation in the animation
Common::ActionEffectDisplayType effectDisplayType;
uint8_t unknown20; // is read by handler, runs code which gets the LODWORD of animationLockTime (wtf?)
uint8_t effectCount; // ignores effects if 0, otherwise parses all of them
uint16_t padding_21;
};
struct FFXIVIpcEffect : FFXIVIpcBasePacket< Effect >
{
uint64_t animationTargetId; // who the animation targets
@ -596,17 +585,35 @@ namespace Sapphire::Network::Packets::Server
template< int size >
struct FFXIVIpcAoeEffect
{
EffectHeader header;
uint64_t animationTargetId; // who the animation targets
Common::EffectEntry effects[size];
uint32_t actionId; // what the casting player casts, shown in battle log/ui
uint32_t globalSequence; // seems to only increment on retail?
float animationLockTime; // maybe? doesn't seem to do anything
uint32_t someTargetId; // always 00 00 00 E0, 0x0E000000 is the internal def for INVALID TARGET ID
uint16_t sourceSequence; // if 0, always shows animation, otherwise hides it. counts up by 1 for each animation skipped on a caster
uint16_t rotation;
uint16_t actionAnimationId; // the animation that is played by the casting character
uint8_t variation; // variation in the animation
Common::ActionEffectDisplayType effectDisplayType;
uint8_t unknown20; // is read by handler, runs code which gets the LODWORD of animationLockTime (wtf?)
uint8_t effectCount; // ignores effects if 0, otherwise parses all of them
uint16_t padding_21[3];
uint16_t padding;
struct
{
Common::EffectEntry entries[8];
} effects[size];
uint16_t padding_6A[3];
uint32_t effectTargetId[size];
Common::FFXIVARR_POSITION3 position;
uint32_t effectFlags;
uint32_t padding_78;
uint64_t effectTargetId[size];
uint16_t unkFlag[3]; // all 0x7FFF
uint16_t unk[3];
};
struct FFXIVIpcAoeEffect8 :
@ -669,11 +676,11 @@ namespace Sapphire::Network::Packets::Server
uint32_t displayFlags;
uint16_t fateID;
uint16_t mPCurr;
uint16_t tPCurr;
uint16_t mPMax;
uint16_t tPMax;
uint16_t unk; // == 0
uint16_t modelChara;
uint16_t rotation;
uint16_t currentMount;
uint16_t activeMinion;
uint8_t spawnIndex;
uint8_t state;
@ -687,21 +694,20 @@ namespace Sapphire::Network::Packets::Server
uint8_t classJob;
uint8_t u26d;
uint16_t u27a;
uint8_t currentMount;
uint8_t mountHead;
uint8_t mountBody;
uint8_t mountFeet;
uint8_t mountColor;
uint8_t scale;
uint32_t u29b;
uint32_t u30b;
uint8_t elementData[6];
uint8_t unknown5_5[3];
Common::StatusEffect effect[30];
Common::FFXIVARR_POSITION3 pos;
uint32_t models[10];
char name[32];
uint8_t look[26];
char fcTag[6];
uint32_t unk30;
uint32_t unk30[2];
};
/**
@ -744,10 +750,10 @@ namespace Sapphire::Network::Packets::Server
uint32_t displayFlags;
uint16_t fateID;
uint16_t mPCurr;
uint16_t tPCurr;
uint16_t mPMax;
uint16_t tPMax;
uint16_t unknown1;
uint16_t unknown2;
uint16_t modelChara;
uint16_t currentMount;
uint16_t rotation;
uint16_t activeMinion;
uint8_t spawnIndex;
@ -762,15 +768,13 @@ namespace Sapphire::Network::Packets::Server
uint8_t classJob;
uint8_t u26d;
uint16_t u27a;
uint8_t currentMount;
uint8_t mountHead;
uint8_t mountBody;
uint8_t mountFeet;
uint8_t mountColor;
uint8_t scale;
uint16_t elementalLevel; // Eureka
uint16_t element; // Eureka
uint32_t u30b;
uint8_t elemental[6];
uint8_t unknown5_5[3];
Common::StatusEffect effect[30];
Common::FFXIVARR_POSITION3 pos;
uint32_t models[10];
@ -782,7 +786,7 @@ namespace Sapphire::Network::Packets::Server
uint8_t bNPCPartSlot;
uint8_t unk32;
uint16_t unk33;
uint32_t unk34;
uint32_t unk34[2];
};
/**
@ -840,10 +844,11 @@ namespace Sapphire::Network::Packets::Server
uint16_t action_id;
Common::SkillType skillType;
uint8_t unknown;
uint32_t unknown_1; // Also action id
uint32_t unknown_1; // action id or mount id
float cast_time;
uint32_t target_id;
float rotation; // In radians
uint16_t rotation;
uint16_t flag; // 1 = interruptible blinking cast bar
uint32_t unknown_2;
uint16_t posX;
uint16_t posY;
@ -922,15 +927,17 @@ namespace Sapphire::Network::Packets::Server
//Current instance can be confirmed at any time using the /instance text command." ( 7B F8 69 )
uint8_t unknown5;
uint32_t unknown7;
uint32_t unknown8;
uint16_t festivalId;
uint16_t additionalFestivalId;
uint32_t unknown9;
uint32_t unknown10;
uint32_t unknown11;
uint32_t unknown12[4];
uint32_t festivalId;
uint32_t unknown12[3];
uint32_t additionalFestivalId;
uint32_t unknown13[3];
Common::FFXIVARR_POSITION3 pos;
uint32_t unknown13;
uint32_t unknown14[3];
uint32_t unknown15;
};
@ -978,6 +985,7 @@ namespace Sapphire::Network::Packets::Server
unsigned char expansion;
unsigned char unknown76;
unsigned char unknown77;
unsigned char very_unknown;
unsigned char race;
unsigned char tribe;
unsigned char gender;
@ -1004,7 +1012,7 @@ namespace Sapphire::Network::Packets::Server
unsigned char craftingMasterMask;
unsigned char unknown95[9];
unsigned char unknown9F[2];
unsigned char unknownA1[3];
unsigned char unknownA1[6];
unsigned int exp[Common::CLASSJOB_SLOTS];
unsigned int unknown108;
unsigned int pvpTotalExp;
@ -1012,6 +1020,7 @@ namespace Sapphire::Network::Packets::Server
unsigned int pvpExp;
unsigned int pvpFrontlineOverallRanks[3];
unsigned short levels[Common::CLASSJOB_SLOTS];
/*
unsigned short unknown15C[9];
unsigned short u1;
unsigned short u2;
@ -1025,8 +1034,17 @@ namespace Sapphire::Network::Packets::Server
unsigned char companionDefRank;
unsigned char companionAttRank;
unsigned char companionHealRank;
unsigned char u19[2];
unsigned char mountGuideMask[19];
unsigned char u19[8];
unsigned char mountGuideMask[22];
unsigned char u19_2;
*/
unsigned char unknown5_55a[178];
unsigned char companionName[21];
unsigned char companionDefRank;
unsigned char companionAttRank;
unsigned char companionHealRank;
unsigned char mountGuideMask[29];
//==
char name[32];
unsigned char unknownOword[16];
unsigned char unknownOw;
@ -1034,13 +1052,14 @@ namespace Sapphire::Network::Packets::Server
unsigned char aetheryte[21];
unsigned char discovery[445];
unsigned char howto[34];
unsigned char minions[45];
unsigned char minions[55];
unsigned char chocoboTaxiMask[10];
unsigned char watchedCutscenes[124];
unsigned char companionBardingMask[10];
unsigned char watchedCutscenes[137];
unsigned char companionBardingMask[11];
unsigned char companionEquippedHead;
unsigned char companionEquippedBody;
unsigned char companionEquippedLegs;
/*
unsigned char unknown52A[4];
unsigned char unknownMask52E[11];
unsigned char fishingGuideMask[105];
@ -1050,7 +1069,11 @@ namespace Sapphire::Network::Packets::Server
unsigned char beastRank[11];
unsigned char unknownPvp5AB[11];
unsigned char unknown5B9[5];
*/
unsigned char unknown5_45b[236];
//==
unsigned char pose;
/*
unsigned char unknown5B91;
unsigned char challengeLogComplete[9];
unsigned char weaponPose;
@ -1064,24 +1087,34 @@ namespace Sapphire::Network::Packets::Server
unsigned char u13;
unsigned char aetherCurrentMask[22];
unsigned char u10[3];
unsigned char orchestrionMask[40];
*/
unsigned char unknown5_55b[295];
//==
unsigned char orchestrionMask[40]; // this field may already be extended, if it is, the beginning bytes are at the end of unknown5_55b
unsigned char hallOfNoviceCompletion[3];
unsigned char animaCompletion[11];
unsigned char u14[16];
unsigned char u15[13];
unsigned char unknown5_55c[35];
unsigned char unlockedRaids[28];
unsigned char unlockedDungeons[18];
unsigned char unlockedGuildhests[10];
unsigned char unlockedTrials[8];
unsigned char unlockedPvp[5];
/*
at least 8 bytes at most 10 bytes in unlockedTrials not confirmed, adjust unlockedPvp so they share a total of 15 bytes and sync with clearedTrials/clearedPvp.
*/
unsigned char unlockedTrials[9];
unsigned char unlockedPvp[6];
//==
unsigned char clearedRaids[28];
unsigned char clearedDungeons[18];
unsigned char clearedGuildhests[10];
unsigned char clearedTrials[8];
unsigned char clearedPvp[5];
unsigned char clearedTrials[9];
unsigned char clearedPvp[6];
/*
unsigned short fishingRecordsFishWeight[26];
unsigned int exploratoryMissionNextTimestamp;
unsigned char pvpLevel;
*/
unsigned char unknown5_55d[9];
//==
};
@ -1205,7 +1238,8 @@ namespace Sapphire::Network::Packets::Server
uint32_t appearanceCatalogId;
uint64_t crafterId;
uint8_t quality;
uint8_t unknown[3];
uint8_t stain;
uint8_t unknown[2];
struct Materia
{
uint16_t materiaId;
@ -1300,8 +1334,7 @@ namespace Sapphire::Network::Packets::Server
struct FFXIVIpcInventoryTransaction : FFXIVIpcBasePacket< InventoryTransaction >
{
uint32_t sequence;
uint8_t type;
uint8_t padding;
uint16_t type;
uint16_t padding1;
uint32_t ownerId;
uint32_t storageId;
@ -1406,11 +1439,39 @@ namespace Sapphire::Network::Packets::Server
uint8_t unknown[8];
};
struct FFXIVIpcEventPlay16 : FFXIVIpcBasePacket< EventPlay16 >
{
uint64_t actorId;
uint32_t eventId;
uint16_t scene;
uint16_t padding;
uint32_t flags;
uint32_t param3;
uint8_t paramSize;
uint8_t padding1[3];
uint32_t param[16];
uint32_t padding2;
};
template< int ArgCount >
struct FFXIVIpcEventPlayN
{
uint64_t actorId;
uint32_t eventId;
uint16_t scene;
uint16_t padding;
uint32_t sceneFlags;
uint32_t unknown;
uint8_t paramSize;
uint8_t padding2[3];
uint32_t params[ArgCount];
};
/**
* Structural representation of the packet sent by the server
* to play an event
*/
struct FFXIVIpcDirectorPlayScene : FFXIVIpcBasePacket< DirectorPlayScene >
struct FFXIVIpcDirectorPlayScene : FFXIVIpcBasePacket< EventPlay32 >
{
uint64_t actorId;
uint32_t eventId;
@ -1439,15 +1500,10 @@ namespace Sapphire::Network::Packets::Server
/* 000C */ uint32_t padding1;
};
struct FFXIVIpcEventOpenGilShop : FFXIVIpcBasePacket< EventOpenGilShop >
struct FFXIVIpcEventPlay255 :
FFXIVIpcBasePacket< EventPlay255 >,
FFXIVIpcEventPlayN< 255 >
{
uint64_t actorId;
uint32_t eventId;
uint16_t scene;
uint16_t padding;
uint32_t sceneFlags;
uint32_t unknown_wtf[0x101];
};
@ -1494,8 +1550,8 @@ namespace Sapphire::Network::Packets::Server
*/
struct FFXIVIpcQuestCompleteList : FFXIVIpcBasePacket< QuestCompleteList >
{
uint8_t questCompleteMask[480];
uint8_t unknownCompleteMask[32];
uint8_t questCompleteMask[487];
uint8_t unknownCompleteMask[73];
};
/**
@ -1546,15 +1602,14 @@ namespace Sapphire::Network::Packets::Server
/**
* Structural representation of the packet sent by the server
* to send a unviel a map
* to send a unveil a map
*/
struct FFXIVIpcDiscovery : FFXIVIpcBasePacket< Discovery >
{
/* 0000 */ uint32_t map_part_id;
/* 0004 */ uint32_t map_id;
/* 0000 */ uint32_t mapPartId;
/* 0004 */ uint32_t mapId;
};
/**
* UNKOWN TYPE
*/
@ -1676,6 +1731,80 @@ namespace Sapphire::Network::Packets::Server
uint8_t bitmask;
};
struct FFXIVIpcMiniCactPotInit : FFXIVIpcBasePacket< MiniCactpotInit >
{
/*
* Looks like this shares a handler with MarketTaxRates and a few
* other packets, so these first fields are most likely discriminators
* or other metadata for the handler itself.
*/
uint32_t type;
uint16_t category;
uint8_t unknown1;
uint8_t unknown2;
/*
* Always 18 for this packet, incidentally the number of payouts plus 1.
* Used similarly for MarketTaxRates => for (auto i = 0; i <= indexEnd; i++) {}
*/
uint8_t indexEnd;
uint8_t unknown3;
uint16_t padding1;
/*
* On clicking a number, the client sends a ClientTrigger (DirectorSync) with an unknown
* param2, param5; param1 session, param3 column, param4 row; zero param6, and the server
* replies with an ActorControlSelf (DirectorUpdate) with an unknown param2; param1 session,
* param3 column, param4 row, param5 digit; zero param6. After a line is selected,
* the server replies with 9 DirectorUpdate packets, in order (column, row), containing every
* number on the board (why tho). Finally, one last DirectorUpdate is sent with parameters
* param1 session, param3 payout index; unknown param2, param4; zero param5, param6.
*/
uint32_t column; // zero-based
uint32_t row;
uint32_t firstDigit;
uint32_t payouts[19]; // In in-game display order
uint32_t unknown4;
/*
* All of the below fields seem to be gibberish, and change completely between
* draws and characters.
*/
uint32_t unknown5;
uint32_t unknown6;
uint32_t unknown7;
uint32_t unknown8;
uint16_t unknown9;
uint16_t unknown10;
uint32_t unknown11;
uint64_t unknown12;
};
/**
* Structural representation of the packet sent by the server
* to place/remove field marker presets
*/
struct FFXIVIpcPlaceFieldMarkerPreset : FFXIVIpcBasePacket< PlaceFieldMarkerPreset >
{
/*! which fieldmarks to show */
Common::FieldMarkerStatus status;
/*! A coordinates would be (float)Xints[0]/1000.0, (float)Yints[0]/1000.0, (float)Zints[0]/1000.0 */
uint32_t Xints[8];
uint32_t Yints[8];
uint32_t Zints[8];
};
/**
* Structural representation of the packet sent by the server
* to place/remove a field marker
*/
struct FFXIVIpcPlaceFieldMarker : FFXIVIpcBasePacket< PlaceFieldMarker >
{
Common::FieldMarkerId markerId;
uint8_t status;
uint8_t pad[2];
uint32_t Xint;
uint32_t Yint;
uint32_t Zint;
};
/**
* Structural representation of the packet sent by the server
* to mount a player
@ -1683,6 +1812,7 @@ namespace Sapphire::Network::Packets::Server
struct FFXIVIpcMount : FFXIVIpcBasePacket< Mount >
{
uint32_t id;
uint32_t padding[3];
};
/**
@ -1719,7 +1849,7 @@ namespace Sapphire::Network::Packets::Server
uint32_t bNPCName;
uint32_t textId;
uint32_t popupTimeMs;
uint32_t pad3[4];
uint32_t param[6];
};
@ -1731,7 +1861,7 @@ namespace Sapphire::Network::Packets::Server
struct FFXIVIpcPerformNote : FFXIVIpcBasePacket< PerformNote >
{
uint8_t data[32];
uint8_t data[16];
};
struct FFXIVIpcHousingUpdateLandFlagsSlot : FFXIVIpcBasePacket< HousingUpdateLandFlagsSlot >
@ -1900,7 +2030,7 @@ namespace Sapphire::Network::Packets::Server
uint32_t housePrice;
uint8_t infoFlags;
Common::HousingAppeal houseAppeal[3];
char estateOwnerName[30];
char estateOwnerName[32];
} houseInfoEntry[60];
};
@ -1963,7 +2093,7 @@ namespace Sapphire::Network::Packets::Server
uint16_t rotation;
int16_t unknown24a;
int16_t unknown24b;
uint16_t unknown28a;
uint16_t flag;
int16_t unknown28c;
uint32_t housingLink;
Common::FFXIVARR_POSITION3 position;
@ -1989,6 +2119,230 @@ namespace Sapphire::Network::Packets::Server
char otherName[32];
};
struct FFXIVIpcRetainerInformation : FFXIVIpcBasePacket< RetainerInformation >
{
uint8_t unknown0[8];
uint64_t retainerId;
uint8_t hireOrder;
uint8_t itemCount;
uint8_t unknown5[2];
uint32_t gil;
uint8_t sellingCount;
uint8_t cityId;
uint8_t classJob;
uint8_t level;
uint8_t unknown11[4];
uint32_t retainerTask;
uint32_t retainerTaskComplete;
uint8_t unknown14;
char retainerName[20];
};
struct FFXIVIpcCharaVisualEffect : FFXIVIpcBasePacket< CharaVisualEffect >
{
uint32_t id;
uint32_t padding;
};
struct FFXIVIpcCFCancel : FFXIVIpcBasePacket< CFCancel >
{
uint32_t cancelReason;
uint32_t unknown2;
};
struct FFXIVIpcShopMessage : FFXIVIpcBasePacket< ShopMessage >
{
uint32_t shopId;
uint32_t msgType;
uint32_t unknown2;
uint32_t itemId;
uint32_t amount;
uint32_t price;
uint32_t unknown6;
uint32_t unknown7;
};
struct FFXIVIpcLootMessage : FFXIVIpcBasePacket< LootMessage >
{
Common::LootMessageType msgType;
uint8_t padding[3];
uint32_t param1;
uint32_t param2;
uint32_t param3;
uint32_t param4;
uint32_t param5;
uint32_t param6;
uint32_t param7;
};
struct FFXIVIpcSocialMessage : FFXIVIpcBasePacket< SocialMessage >
{
uint64_t contentId;
uint32_t expireTime;
uint8_t p1;
uint8_t p2;
uint8_t socialType;
uint8_t padding;
uint8_t type;
uint8_t unknown4;
char name[32];
uint8_t padding2[6];
};
struct FFXIVIpcSocialMessage2 : FFXIVIpcBasePacket< SocialMessage2 >
{
uint64_t contentId;
uint32_t unknown3;
uint8_t p1;
uint8_t p2;
uint8_t socialType;
uint8_t padding;
char name[32];
};
struct FFXIVIpcSocialRequestResponse : FFXIVIpcBasePacket< SocialRequestResponse >
{
uint64_t contentId;
uint32_t unknown3;
uint8_t u1AlwaysOne;
uint8_t response;
uint8_t u2AlwaysOne;
char name[32];
uint8_t padding;
};
struct FFXIVIpcPartyList : FFXIVIpcBasePacket< PartyList >
{
struct
{
char name[32];
uint64_t contentId;
uint32_t charaId;
uint32_t u1;
uint32_t u2;
uint32_t hp;
uint32_t maxHp;
uint16_t mp;
uint16_t maxMp;
uint16_t u3;
uint16_t zoneId;
uint8_t gposeSelectable;
uint8_t classId;
uint8_t u5;
uint8_t level;
uint8_t otherData[368];
} member[8];
uint64_t someContentId1;
uint64_t someContentId2;
uint8_t leaderIndex;
uint8_t partySize;
uint16_t padding1;
uint32_t padding2;
};
struct FFXIVIpcPartyMessage : FFXIVIpcBasePacket< PartyMessage >
{
uint64_t leaderContentId;
uint64_t memberContentId;
uint8_t u1;
uint8_t u2;
uint16_t type;
uint8_t partySize; // ?
char leaderName[32];
char memberName[32];
uint8_t padding[3];
};
struct FFXIVIpcEventContinue : FFXIVIpcBasePacket< EventContinue >
{
uint32_t eventId;
uint16_t scene;
uint16_t unknown;
uint64_t unknown2;
};
struct FFXIVDirectorUnk4 : FFXIVIpcBasePacket< SomeDirectorUnk4 >
{
uint32_t param[4];
uint64_t unknown;
};
struct FFXIVCeremonySetActorAppearance : FFXIVIpcBasePacket< CeremonySetActorAppearance >
{
uint8_t u1;
uint8_t questBL;
uint16_t padding1;
uint32_t u3;
struct
{
uint64_t mainWeaponModel;
uint64_t secWeaponModel;
uint64_t craftToolModel;
uint32_t c_u6;
uint32_t c_u7;
uint32_t charId;
uint16_t u4;
uint16_t guardianDeity;
uint32_t u5;
uint32_t models[10];
uint8_t look[26];
uint16_t padding3;
} actors[2];
};
//For quests this is only used for pre-accepted ones. Accepted quests are getting handled by the client.
template< int ArgCount >
struct FFXIVIpcMapUpdateN
{
uint8_t entryCount;
uint8_t padding[ 3 ];
uint32_t iconIds[ ArgCount ];
uint32_t levelIds[ ArgCount ];
uint32_t eventIds[ ArgCount ]; // possible event ids for this: Quest, GuildLeveAssignment, GuildOrderGuide, TripleTriad, CustomTalk, PreHandler
uint8_t additionalData[ ArgCount ]; // use unknown
};
struct FFXIVIpcMapUpdate :
FFXIVIpcBasePacket< MapUpdate >,
FFXIVIpcMapUpdateN< 2 >
{
};
struct FFXIVIpcMapUpdate4 :
FFXIVIpcBasePacket< MapUpdate4 >,
FFXIVIpcMapUpdateN< 4 >
{
};
struct FFXIVIpcMapUpdate8 :
FFXIVIpcBasePacket< MapUpdate8 >,
FFXIVIpcMapUpdateN< 8 >
{
};
struct FFXIVIpcMapUpdate16 :
FFXIVIpcBasePacket< MapUpdate16 >,
FFXIVIpcMapUpdateN< 16 >
{
};
struct FFXIVIpcMapUpdate32 :
FFXIVIpcBasePacket< MapUpdate32 >,
FFXIVIpcMapUpdateN< 32 >
{
};
struct FFXIVIpcMapUpdate64 :
FFXIVIpcBasePacket< MapUpdate64 >,
FFXIVIpcMapUpdateN< 64 >
{
};
struct FFXIVIpcMapUpdate128 :
FFXIVIpcBasePacket< MapUpdate128 >,
FFXIVIpcMapUpdateN< 128 >
{
};
}
#endif /*_CORE_NETWORK_PACKETS_SERVER_IPC_H*/

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

View file

@ -129,7 +129,7 @@ uint32_t Util::getTimeSeconds()
uint64_t Util::getEorzeanTimeStamp()
{
return static_cast< uint64_t >( getTimeSeconds() * 20.571428571428573f );
return static_cast< uint64_t >( getTimeSeconds() * 20.571428571428573 );
}
void Util::valueToFlagByteIndexValue( uint32_t inVal, uint8_t& outVal, uint16_t& outIndex )

View file

@ -77,3 +77,8 @@ uint8_t Util::floatToUInt8Rot( float val )
{
return static_cast< uint8_t >( 0x80 * ( ( val + PI ) ) / PI );
}
float Util::floatFromUInt16Rot( uint16_t rot )
{
return rot / 32768.0f * PI - PI;
}

View file

@ -25,6 +25,8 @@ namespace Sapphire::Common::Util
uint16_t floatToUInt16Rot( float val );
float floatFromUInt16Rot( uint16_t rot );
uint8_t floatToUInt8Rot( float val );
template < typename T >

View file

@ -5,14 +5,14 @@
#include <streambuf>
#include <sstream>
#include <Logging/Logger.h>
#include <experimental/filesystem>
#include <filesystem>
#include <common/Util/Util.h>
using namespace Sapphire;
using namespace Sapphire::Common;
namespace fs = std::experimental::filesystem;
namespace fs = std::filesystem;
DbManager::DbManager( const std::string& host, const std::string& database, const std::string& user, const std::string& pw, uint16_t port ) :
m_host( host ),

View file

@ -3,14 +3,14 @@
#include <cctype>
#include <set>
#include <common/Logging/Logger.h>
#include <experimental/filesystem>
#include <filesystem>
#include <MySqlConnector.h>
#include <common/Util/CrashHandler.h>
#include <common/Config/ConfigMgr.h>
Sapphire::Common::Util::CrashHandler crashHandler;
[[maybe_unused]] Sapphire::Common::Util::CrashHandler crashHandler;
namespace filesys = std::experimental::filesystem;
namespace fs = std::filesystem;
#include <fstream>
#include <streambuf>
@ -30,19 +30,19 @@ std::vector< std::string > getAllFilesInDir( const std::string& dirPath,
try
{
// Check if given path exists and points to a directory
if( filesys::exists( dirPath ) && filesys::is_directory( dirPath ) )
if( fs::exists( dirPath ) && fs::is_directory( dirPath ) )
{
// Create a Recursive Directory Iterator object and points to the starting of directory
filesys::recursive_directory_iterator iter( dirPath );
fs::recursive_directory_iterator iter( dirPath );
// Create a Recursive Directory Iterator object pointing to end.
filesys::recursive_directory_iterator end;
fs::recursive_directory_iterator end;
// Iterate till end
while( iter != end )
{
// Check if current entry is a directory and if exists in skip list
if( filesys::is_directory( iter->path() ) &&
if( fs::is_directory( iter->path() ) &&
( std::find( dirSkipList.begin(), dirSkipList.end(), iter->path().filename() ) != dirSkipList.end() ) )
{
// Skip the iteration of current directory pointed by iterator

View file

@ -12,11 +12,6 @@ x ## Ptr make_ ## x( Args &&...args ) { \
return std::make_shared< x >( std::forward< Args >( args ) ... ); }\
typedef std::vector< x > x ## PtrList;
namespace Sapphire
{
TYPE_FORWARD( Framework );
}
namespace Sapphire::Lobby
{
TYPE_FORWARD( LobbySession );

View file

@ -25,9 +25,8 @@ extern Lobby::ServerLobby g_serverLobby;
extern Lobby::RestConnector g_restConnector;
Lobby::GameConnection::GameConnection( Sapphire::Network::HivePtr pHive,
Sapphire::Network::AcceptorPtr pAcceptor,
FrameworkPtr pFw ) :
Sapphire::Network::Connection( pHive, pFw ),
Sapphire::Network::AcceptorPtr pAcceptor ) :
Sapphire::Network::Connection( pHive ),
m_pAcceptor( pAcceptor ),
m_bEncryptionInitialized( false )
{
@ -42,7 +41,7 @@ Lobby::GameConnection::~GameConnection()
// overwrite the parents onConnect for our game socket needs
void Lobby::GameConnection::onAccept( const std::string& host, uint16_t port )
{
auto connection = make_GameConnection( m_hive, m_pAcceptor, m_pFw );
auto connection = make_GameConnection( m_hive, m_pAcceptor );
m_pAcceptor->accept( connection );
Logger::info( "Connect from {0}", m_socket.remote_endpoint().address().to_string() );
@ -267,7 +266,7 @@ bool Lobby::GameConnection::sendServiceAccountList( FFXIVARR_PACKET_RAW& packet,
}
else
{
Logger::info( "Could not retrieve session: {0}", std::string( ( char* ) &packet.data[ 0 ] + 0x20 ) );
Logger::info( "Could not retrieve session: {0}", std::string( ( char* ) &packet.data[ 0 ] + 0x22 ) );
sendError( 1, 5006, 13001, tmpId );
return true;
@ -453,8 +452,8 @@ void Lobby::GameConnection::generateEncryptionKey( uint32_t key, const std::stri
m_baseKey[ 2 ] = 0x34;
m_baseKey[ 3 ] = 0x12;
memcpy( m_baseKey + 0x04, &key, 4 );
m_baseKey[ 8 ] = 0x88;
m_baseKey[ 9 ] = 0x13;
m_baseKey[ 8 ] = 0x18;
m_baseKey[ 9 ] = 0x15;
memcpy( ( char* ) m_baseKey + 0x0C, keyPhrase.c_str(), keyPhrase.size() );
Common::Util::md5( m_baseKey, m_encKey, 0x2C );
}

View file

@ -41,7 +41,7 @@ namespace Sapphire::Lobby
std::vector< uint8_t > m_packets;
public:
GameConnection( Network::HivePtr pHive, Network::AcceptorPtr pAcceptor, FrameworkPtr pFw );
GameConnection( Network::HivePtr pHive, Network::AcceptorPtr pAcceptor );
~GameConnection();

View file

@ -10,7 +10,6 @@
#include <Logging/Logger.h>
#include <Config/ConfigMgr.h>
#include "Framework.h"
#include "ServerLobby.h"
@ -65,9 +64,8 @@ namespace Sapphire::Lobby
Logger::setLogLevel( m_config.global.general.logLevel );
auto pFw = make_Framework();
auto hive = Network::make_Hive();
Network::addServerToHive< GameConnection >( m_ip, m_port, hive, pFw );
Network::addServerToHive< GameConnection >( m_ip, m_port, hive );
Logger::info( "Lobby server running on {0}:{1}", m_ip, m_port );

View file

@ -2,7 +2,7 @@
#include <Util/CrashHandler.h>
Sapphire::Common::Util::CrashHandler crashHandler;
[[maybe_unused]] Sapphire::Common::Util::CrashHandler crashHandler;
Sapphire::Lobby::ServerLobby g_serverLobby( "lobby.ini" );

View file

@ -0,0 +1,27 @@
#include <ScriptObject.h>
#include <Actor/Player.h>
#include <Action/Action.h>
#include <Inventory/Item.h>
class ActionDye2472 :
public Sapphire::ScriptAPI::ActionScript
{
public:
ActionDye2472() :
Sapphire::ScriptAPI::ActionScript( 2472 )
{
}
void onExecute( Sapphire::World::Action::Action& action ) override
{
auto sourceChara = action.getSourceChara();
if( !sourceChara->isPlayer() )
return;
//TODO: Effect
sourceChara->getAsPlayer()->dyeItemFromDyeingInfo();
}
};
EXPOSE_SCRIPT(ActionDye2472);

View file

@ -18,6 +18,8 @@ public:
if( !sourceChara->isPlayer() )
return;
action.getEffectbuilder()->applyStatusEffect( sourceChara, 50, 30 );
sourceChara->getAsPlayer()->addStatusEffectByIdIfNotExist( 50, 20000, *sourceChara, 30 );
}
};

View file

@ -32,7 +32,7 @@ public:
// todo: this is fucked
};
player.playScene( getId(), 1, 0xFB2EC8F8, 0, 1, returnScene, callback );
player.playScene( getId(), 1, FADE_OUT | CONDITION_CUTSCENE | HIDE_UI, 0, 1, returnScene, callback );
}
void onTalk( uint32_t eventId, Entity::Player& player, uint64_t actorId ) override

View file

@ -1,8 +1,8 @@
#include <ScriptObject.h>
#include <Actor/Player.h>
#include <Framework.h>
#include <Manager/ShopMgr.h>
#include <Service.h>
using namespace Sapphire;
@ -25,25 +25,30 @@ public:
private:
void shopInteractionCallback( Entity::Player& player, const Event::SceneResult& result )
{
// item purchase
if( result.param1 == 768 )
// buy, sell, buy back
if( result.param1 == 768 || result.param1 == 512 )
{
// buy
if( result.param2 == 1 )
{
auto shopMgr = framework()->get< Sapphire::World::Manager::ShopMgr >();
shopMgr->purchaseGilShopItem( player, result.eventId, result.param3, result.param4 );
auto& shopMgr = Common::Service< Sapphire::World::Manager::ShopMgr >::ref();
shopMgr.purchaseGilShopItem( player, result.eventId, result.param3, result.param4 );
}
// sell
// can't sell if the vendor is yourself (eg, housing permit shop)
else if( result.param2 == 2 && result.actorId != player.getId() )
{
auto& shopMgr = Common::Service< Sapphire::World::Manager::ShopMgr >::ref();
shopMgr.shopSellItem( player, result.eventId, result.param3, result.param4 );
}
//buy back
else if( result.param2 == 3 && result.actorId != player.getId() )
{
auto& shopMgr = Common::Service< Sapphire::World::Manager::ShopMgr >::ref();
shopMgr.shopBuyBack( player, result.eventId, result.param3 );
}
player.playGilShop( result.eventId, SCENE_FLAGS, std::bind( &GilShop::shopInteractionCallback, this, std::placeholders::_1, std::placeholders::_2 ) );
player.playGilShop( result.eventId, SCENE_FLAGS, result.param2, std::bind( &GilShop::shopInteractionCallback, this, std::placeholders::_1, std::placeholders::_2 ) );
return;
}
@ -53,7 +58,7 @@ private:
void shopCallback( Entity::Player& player, const Event::SceneResult& result )
{
player.playGilShop( result.eventId, SCENE_FLAGS, std::bind( &GilShop::shopInteractionCallback, this, std::placeholders::_1, std::placeholders::_2 ) );
player.playGilShop( result.eventId, SCENE_FLAGS, 0, std::bind( &GilShop::shopInteractionCallback, this, std::placeholders::_1, std::placeholders::_2 ) );
}
};

View file

@ -1,9 +1,8 @@
#include <ScriptObject.h>
#include <Actor/Player.h>
#include <Framework.h>
#include <Exd/ExdDataGenerated.h>
#include <Service.h>
using namespace Sapphire;
@ -33,7 +32,7 @@ public:
{
player.playScene( eventId, 2, 0, [this]( Entity::Player& player, const Event::SceneResult& result )
{
if( result.param1 == 256 )
if( result.param1 == 256 && result.param2 != 0 )
{
player.teleport( result.param2, 2 );
}
@ -59,7 +58,8 @@ public:
{
if( player.isAetheryteRegistered( eventId & 0xFFFF ) )
{
player.playScene( eventId, 0, 1, [this]( Entity::Player& player, const Event::SceneResult& result )
// eventParam4 (or params[1] if using EventPlay8, which is actually used on retail) anything bigger than 1 will show select instance menu item
player.playScene( eventId, 0, 1, 0, 1, 2, [this]( Entity::Player& player, const Event::SceneResult& result )
{
if( result.param1 == 256 ) // set homepoint
{
@ -68,7 +68,7 @@ public:
}
else if( result.param1 == 512 ) // aethernet access
{
if( result.param2 == 4 )
if( result.param2 == 4 && result.param3 != 0 )
{
player.teleport( result.param3, 2 );
}
@ -108,11 +108,9 @@ public:
void onTalk( uint32_t eventId, Entity::Player& player, uint64_t actorId ) override
{
auto pExdData = framework()->get< Sapphire::Data::ExdDataGenerated >();
if( !pExdData )
return;
auto& exdData = Common::Service< Sapphire::Data::ExdDataGenerated >::ref();
auto aetherInfo = pExdData->get< Sapphire::Data::Aetheryte >( eventId & 0xFFFF );
auto aetherInfo = exdData.get< Sapphire::Data::Aetheryte >( eventId & 0xFFFF );
if( !aetherInfo )
return;

View file

@ -1,10 +1,10 @@
#include <ScriptObject.h>
#include <Actor/Player.h>
#include <Framework.h>
#include <Exd/ExdDataGenerated.h>
#include <Territory/HousingZone.h>
#include <Manager/PlayerMgr.h>
#include <Service.h>
using namespace Sapphire;
@ -21,16 +21,14 @@ public:
{
player.playScene( eventId, 0, HIDE_HOTBAR | NO_DEFAULT_CAMERA, [this, eventId]( Entity::Player& player, const Event::SceneResult& result )
{
auto pExdData = framework()->get< Sapphire::Data::ExdDataGenerated >();
if( !pExdData )
return;
auto& exdData = Common::Service< Sapphire::Data::ExdDataGenerated >::ref();
auto housingZone = std::dynamic_pointer_cast< HousingZone >( player.getCurrentTerritory() );
if( !housingZone )
return;
// param2 is the index starting from 0 inside housingaethernet.exd, but the ID column starts at 0x001E0000........ wtf
auto pHousingAethernet = pExdData->get< Sapphire::Data::HousingAethernet >( getId() + result.param2 );
auto pHousingAethernet = exdData.get< Sapphire::Data::HousingAethernet >( getId() + result.param2 );
if( !pHousingAethernet )
return;
@ -39,11 +37,11 @@ public:
return;
// todo: this needs to be done properly and used queued zoning + aethernet animation
// moving a player inside an event will crash the game so we end it hre
// moving a player inside an event will crash the game so we end it here
player.eventFinish( eventId, 1 );
auto playerMgr = framework()->get< Sapphire::World::Manager::PlayerMgr >();
playerMgr->movePlayerToLandDestination( player, pHousingAethernet->level, housingZone->getWardNum() );
auto& playerMgr = Common::Service< Sapphire::World::Manager::PlayerMgr >::ref();
playerMgr.movePlayerToLandDestination( player, pHousingAethernet->level, housingZone->getWardNum() );
} );
}
};

View file

@ -1,11 +1,11 @@
#include <ScriptObject.h>
#include <Actor/Player.h>
#include <Service.h>
#include "Actor/EventObject.h"
#include "Territory/HousingZone.h"
#include "Manager/TerritoryMgr.h"
#include "Territory/Land.h"
#include "Framework.h"
using namespace Sapphire;
@ -26,9 +26,7 @@ public:
if( result.param2 != 1 )
return;
auto terriMgr = framework()->get< Sapphire::World::Manager::TerritoryMgr >();
if( !terriMgr )
return;
auto& terriMgr = Common::Service< Sapphire::World::Manager::TerritoryMgr >::ref();
auto zone = std::dynamic_pointer_cast< HousingZone >( player.getCurrentTerritory() );
if( !zone )
@ -40,7 +38,7 @@ public:
ident.wardNum = zone->getWardNum();
ident.worldId = 67;
auto internalZone = terriMgr->findOrCreateHousingInterior( ident );
auto internalZone = terriMgr.findOrCreateHousingInterior( ident );
if( !internalZone )
{
// an error occurred during event movement
@ -60,6 +58,7 @@ public:
switch( land->getSize() )
{
// todo: think there's actually a poprange for this? double czech
case 0:
{
pos = { 0.1321167f, 0.f, 2.746273f };
@ -79,7 +78,7 @@ public:
return;
}
player.setInstance( internalZone, pos );
player.setInstance( internalZone, pos, player.getRot() );
} );
}
};

View file

@ -5,7 +5,7 @@
#include <Network/PacketWrappers/ActorControlSelfPacket.h>
#include <Network/CommonActorControl.h>
#include <Exd/ExdDataGenerated.h>
#include "Framework.h"
#include <Service.h>
using namespace Sapphire;
@ -25,9 +25,6 @@ public:
{
auto callback = [ this ]( Entity::Player& player, const Event::SceneResult& result )
{
auto pFw = framework();
if( !pFw )
return LandPurchaseResult::ERR_INTERNAL;
// Purchase Land
if( result.param2 == 2 )
{
@ -36,9 +33,9 @@ public:
auto pTerritory = player.getCurrentTerritory();
auto pHousing = std::dynamic_pointer_cast< HousingZone >( pTerritory );
auto pHouMgr = pFw->get< HousingMgr >();
auto& pHouMgr = Common::Service< HousingMgr >::ref();
LandPurchaseResult res = pHouMgr->purchaseLand( player, activeLand.plot,
LandPurchaseResult res = pHouMgr.purchaseLand( player, activeLand.plot,
static_cast< uint8_t >( result.param2 ) );
switch( res )

View file

@ -1,9 +1,14 @@
#include <ScriptObject.h>
#include <Actor/Player.h>
#include <datReader/DatCategories/bg/LgbTypes.h>
#include <datReader/DatCategories/bg/lgb.h>
#include "Territory/InstanceObjectCache.h"
#include <Exd/ExdDataGenerated.h>
#include <Framework.h>
#include <Manager/PlayerMgr.h>
#include <Service.h>
using namespace Sapphire;
@ -27,13 +32,27 @@ public:
player.eventFinish( 1310721, 0 );
player.eventFinish( getId(), 1 );
auto exdData = framework()->get< Sapphire::Data::ExdDataGenerated >();
auto warp = exdData->get< Sapphire::Data::Warp >( getId() );
auto& exdData = Common::Service< Data::ExdDataGenerated >::ref();
auto& popRange = Common::Service< Sapphire::InstanceObjectCache >::ref();
auto warp = exdData.get< Sapphire::Data::Warp >( getId() );
if( !warp )
return;
auto playerMgr = framework()->get< Sapphire::World::Manager::PlayerMgr >();
playerMgr->movePlayerToLandDestination( player, warp->level, result.param3 );
auto& playerMgr = Common::Service< Sapphire::World::Manager::PlayerMgr >::ref();
auto pPop = popRange.getPopRange( warp->territoryType, warp->popRange );
if( !pPop )
{
std::cout << "not found...";
}
else
{
std::cout << "found!!";
}
playerMgr.movePlayerToLandDestination( player, warp->popRange, result.param3 );
}
else
{
@ -56,11 +75,9 @@ public:
void onTalk( uint32_t eventId, Entity::Player& player, uint64_t actorId ) override
{
auto exdData = framework()->get< Sapphire::Data::ExdDataGenerated >();
if( !exdData )
return;
auto& exdData = Common::Service< Sapphire::Data::ExdDataGenerated >::ref();
auto warp = exdData->get< Sapphire::Data::Warp >( eventId );
auto warp = exdData.get< Sapphire::Data::Warp >( eventId );
if( !warp )
return;

View file

@ -38,7 +38,7 @@ private:
public:
ChasingShadows() : Sapphire::ScriptAPI::QuestBattleScript( 11 ) {}
void onPlayerSetup( Sapphire::QuestBattle& instance, Entity::Player& player )
void onPlayerSetup( Sapphire::QuestBattle& instance, Entity::Player& player ) override
{
player.setRot( 3.f );
player.setPos( { 323.f, -1.28f, -320.f } );

View file

@ -2,7 +2,7 @@
#include <ScriptObject.h>
#include "Manager/EventMgr.h"
#include "Event/EventHandler.h"
#include "Framework.h"
#include <Service.h>
// Quest Script: ManFst001_00039
// Quest Name: Coming to Gridania
@ -96,8 +96,8 @@ public:
void onTalk( uint32_t eventId, Entity::Player& player, uint64_t actorId ) override
{
auto pEventMgr = m_framework->get< World::Manager::EventMgr >();
auto actor = pEventMgr->mapEventActorToRealActor( static_cast< uint32_t >( actorId ) );
auto& pEventMgr = Common::Service< World::Manager::EventMgr >::ref();
auto actor = pEventMgr.mapEventActorToRealActor( static_cast< uint32_t >( actorId ) );
if( actor == ACTOR0 )
Scene00000( player );

View file

@ -2,7 +2,7 @@
#include <ScriptObject.h>
#include "Event/EventHandler.h"
#include "Manager/EventMgr.h"
#include "Framework.h"
#include <Service.h>
// Quest Script: ManFst002_00124
// Quest Name: Close to Home
@ -193,8 +193,8 @@ public:
void onTalk( uint32_t eventId, Entity::Player& player, uint64_t actorId ) override
{
auto pEventMgr = m_framework->get< World::Manager::EventMgr >();
auto actor = pEventMgr->mapEventActorToRealActor( static_cast< uint32_t >( actorId ) );
auto& pEventMgr = Common::Service< World::Manager::EventMgr >::ref();
auto actor = pEventMgr.mapEventActorToRealActor( static_cast< uint32_t >( actorId ) );
if( actor == ACTOR0 )
Scene00000( player );

View file

@ -1,7 +1,7 @@
#include <Actor/Player.h>
#include "Manager/EventMgr.h"
#include <ScriptObject.h>
#include "Framework.h"
#include <Service.h>
// Quest Script: ManFst003_00123
// Quest Name: Close to Home
@ -82,8 +82,8 @@ public:
void onTalk( uint32_t eventId, Entity::Player& player, uint64_t actorId ) override
{
auto pEventMgr = m_framework->get< World::Manager::EventMgr >();
auto actor = pEventMgr->mapEventActorToRealActor( static_cast< uint32_t >( actorId ) );
auto& pEventMgr = Common::Service< World::Manager::EventMgr >::ref();
auto actor = pEventMgr.mapEventActorToRealActor( static_cast< uint32_t >( actorId ) );
if( actor == Actor0 )
{

View file

@ -1,7 +1,7 @@
#include <Actor/Player.h>
#include "Manager/EventMgr.h"
#include <ScriptObject.h>
#include "Framework.h"
#include <Service.h>
// Quest Script: ManFst004_00124
// Quest Name: Close to Home
@ -80,8 +80,8 @@ public:
void onTalk( uint32_t eventId, Entity::Player& player, uint64_t actorId ) override
{
auto pEventMgr = m_framework->get< World::Manager::EventMgr >();
auto actor = pEventMgr->mapEventActorToRealActor( static_cast< uint32_t >( actorId ) );
auto& pEventMgr = Common::Service< World::Manager::EventMgr >::ref();
auto actor = pEventMgr.mapEventActorToRealActor( static_cast< uint32_t >( actorId ) );
if( actor == ManFst004::Actor0 )
{

View file

@ -2,7 +2,7 @@
#include "Manager/EventMgr.h"
#include "Manager/TerritoryMgr.h"
#include <ScriptObject.h>
#include "Framework.h"
#include <Service.h>
// Quest Script: ManFst005_00445
// Quest Name: Chasing Shadows
@ -61,8 +61,8 @@ class ManFst005 : public Sapphire::ScriptAPI::EventScript
// Event Handlers
void onTalk( uint32_t eventId, Entity::Player& player, uint64_t actorId ) override
{
auto pEventMgr = m_framework->get< World::Manager::EventMgr >();
auto actor = pEventMgr->mapEventActorToRealActor( static_cast< uint32_t >( actorId ) );
auto& pEventMgr = Common::Service< World::Manager::EventMgr >::ref();
auto actor = pEventMgr.mapEventActorToRealActor( static_cast< uint32_t >( actorId ) );
if( actor == Actor0 )
{
@ -142,11 +142,10 @@ class ManFst005 : public Sapphire::ScriptAPI::EventScript
{
if( result.param2 == 1 )
{
auto pTeriMgr = framework()->get< Sapphire::World::Manager::TerritoryMgr >();
if( !pTeriMgr )
return;
auto& pTeriMgr = Common::Service< Sapphire::World::Manager::TerritoryMgr >::ref();
player.eventFinish( result.eventId, 0 );
pTeriMgr->createAndJoinQuestBattle( player, Questbattle0 );
pTeriMgr.createAndJoinQuestBattle( player, Questbattle0 );
}
} );
}

View file

@ -1,7 +1,7 @@
#include <Actor/Player.h>
#include "Manager/EventMgr.h"
#include <ScriptObject.h>
#include "Framework.h"
#include <Service.h>
// Quest Script: ManSea001_00107
// Quest Name: Coming to Limsa Lominsa
@ -142,8 +142,8 @@ public:
void onTalk( uint32_t eventId, Entity::Player& player, uint64_t actorId ) override
{
auto pEventMgr = m_framework->get< World::Manager::EventMgr >();
auto actor = pEventMgr->mapEventActorToRealActor( static_cast< uint32_t >( actorId ) );
auto& pEventMgr = Common::Service< World::Manager::EventMgr >::ref();
auto actor = pEventMgr.mapEventActorToRealActor( static_cast< uint32_t >( actorId ) );
if( actor == ACTOR0 )
Scene00000( player );

View file

@ -1,7 +1,7 @@
#include <Actor/Player.h>
#include "Manager/EventMgr.h"
#include <ScriptObject.h>
#include "Framework.h"
#include <Service.h>
// Quest Script: ManSea002_00108
// Quest Name: Close to Home
@ -48,8 +48,8 @@ public:
void onTalk( uint32_t eventId, Entity::Player& player, uint64_t actorId ) override
{
auto pEventMgr = m_framework->get< World::Manager::EventMgr >();
auto actor = pEventMgr->mapEventActorToRealActor( static_cast< uint32_t >( actorId ) );
auto& pEventMgr = Common::Service< World::Manager::EventMgr >::ref();
auto actor = pEventMgr.mapEventActorToRealActor( static_cast< uint32_t >( actorId ) );
if( actor == ACTOR0 )
{

View file

@ -1,7 +1,7 @@
#include <Actor/Player.h>
#include "Manager/EventMgr.h"
#include <ScriptObject.h>
#include "Framework.h"
#include <Service.h>
// Quest Script: ManSea003_00109
// Quest Name: Close to Home
@ -64,8 +64,8 @@ public:
void onTalk( uint32_t eventId, Entity::Player& player, uint64_t actorId ) override
{
auto pEventMgr = m_framework->get< World::Manager::EventMgr >();
auto actor = pEventMgr->mapEventActorToRealActor( static_cast< uint32_t >( actorId ) );
auto& pEventMgr = Common::Service< World::Manager::EventMgr >::ref();
auto actor = pEventMgr.mapEventActorToRealActor( static_cast< uint32_t >( actorId ) );
if( actor == Actor0 )
{

View file

@ -1,7 +1,7 @@
#include <Actor/Player.h>
#include "Manager/EventMgr.h"
#include <ScriptObject.h>
#include "Framework.h"
#include <Service.h>
// Quest Script: ManWil001_00594
// Quest Name: Coming to Ul'dah
@ -174,8 +174,8 @@ public:
void onTalk( uint32_t eventId, Entity::Player& player, uint64_t actorId ) override
{
auto pEventMgr = m_framework->get< World::Manager::EventMgr >();
auto actor = pEventMgr->mapEventActorToRealActor( static_cast< uint32_t >( actorId ) );
auto& pEventMgr = Common::Service< World::Manager::EventMgr >::ref();
auto actor = pEventMgr.mapEventActorToRealActor( static_cast< uint32_t >( actorId ) );
if( actor == ACTOR0 )
{

View file

@ -1,7 +1,7 @@
#include <Actor/Player.h>
#include <Manager/EventMgr.h>
#include <ScriptObject.h>
#include "Framework.h"
#include <Service.h>
// Quest Script: ManWil002_00568
// Quest Name: Close to Home
@ -70,8 +70,8 @@ public:
void onTalk( uint32_t eventId, Entity::Player& player, uint64_t actorId ) override
{
auto pEventMgr = m_framework->get< World::Manager::EventMgr >();
auto actor = pEventMgr->mapEventActorToRealActor( static_cast< uint32_t >( actorId ) );
auto& pEventMgr = Common::Service< World::Manager::EventMgr >::ref();
auto actor = pEventMgr.mapEventActorToRealActor( static_cast< uint32_t >( actorId ) );
if( actor == Actor0 )
{

View file

@ -1,7 +1,7 @@
#include <Actor/Player.h>
#include <Manager/EventMgr.h>
#include <ScriptObject.h>
#include "Framework.h"
#include <Service.h>
// Quest Script: ManWil003_00569
// Quest Name: Close to Home
@ -70,8 +70,8 @@ public:
void onTalk( uint32_t eventId, Entity::Player& player, uint64_t actorId ) override
{
auto pEventMgr = m_framework->get< World::Manager::EventMgr >();
auto actor = pEventMgr->mapEventActorToRealActor( static_cast< uint32_t >( actorId ) );
auto& pEventMgr = Common::Service< World::Manager::EventMgr >::ref();
auto actor = pEventMgr.mapEventActorToRealActor( static_cast< uint32_t >( actorId ) );
if( actor == Actor0 )
{

View file

@ -1,7 +1,7 @@
#include <Actor/Player.h>
#include <Manager/EventMgr.h>
#include <ScriptObject.h>
#include "Framework.h"
#include <Service.h>
// Quest Script: ManWil004_00570
// Quest Name: Close to Home
@ -70,8 +70,8 @@ public:
void onTalk( uint32_t eventId, Entity::Player& player, uint64_t actorId ) override
{
auto pEventMgr = m_framework->get< World::Manager::EventMgr >();
auto actor = pEventMgr->mapEventActorToRealActor( static_cast< uint32_t >( actorId ) );
auto& pEventMgr = Common::Service< World::Manager::EventMgr >::ref();
auto actor = pEventMgr.mapEventActorToRealActor( static_cast< uint32_t >( actorId ) );
if( actor == Actor0 )
{

View file

@ -0,0 +1,190 @@
#include <Actor/Player.h>
#include "Manager/EventMgr.h"
#include <ScriptObject.h>
#include <Service.h>
using namespace Sapphire;
// Quest Script: ClsArc000_00021
// Quest Name: Way of the Archer
// Quest ID: 65557
// Start NPC: 1000197
// End NPC: 1000200
class ClsArc000 : public Sapphire::ScriptAPI::EventScript
{
private:
// Basic quest information
// Quest vars / flags used
// GetQuestUI8AL
// GetQuestUI8BH
// GetQuestUI8BL
// Steps in this quest ( 0 is before accepting,
// 1 is first, 255 means ready for turning it in
enum Sequence : uint8_t
{
Seq0 = 0,
Seq1 = 1,
Seq2 = 2,
SeqFinish = 255,
};
// Quest rewards
static constexpr auto RewardExpFactor = 100;
static constexpr auto RewardItem = 4657;
static constexpr auto RewardItemCount = 5;
// Entities found in the script data of the quest
static constexpr auto Actor0 = 1000197;
static constexpr auto Actor1 = 1000200;
static constexpr auto Enemy0 = 37;
static constexpr auto Enemy1 = 49;
static constexpr auto Enemy2 = 47;
static constexpr auto LocFace0 = 604;
static constexpr auto LocFace1 = 605;
static constexpr auto LogmessageMonsterNotePageUnlock = 1008;
static constexpr auto Seq0Actor0 = 0;
static constexpr auto Seq1Actor1 = 1;
static constexpr auto Seq3Actor1 = 2;
static constexpr auto UnlockImageMonsterNote = 32;
public:
ClsArc000() : Sapphire::ScriptAPI::EventScript( 65557 ){};
~ClsArc000(){};
//////////////////////////////////////////////////////////////////////
// Event Handlers
void onTalk( uint32_t eventId, Entity::Player& player, uint64_t actorId ) override
{
auto pEventMgr = Common::Service< World::Manager::EventMgr >::ref();
auto actor = pEventMgr.mapEventActorToRealActor( static_cast< uint32_t >( actorId ) );
if( actor == Actor0 )
Scene00000( player );
if( actor == Actor1 && player.getQuestSeq( getId() ) == Seq1 )
Scene00001( player );
if( actor == Actor1 && player.getQuestSeq( getId() ) == SeqFinish )
Scene00002( player );
}
void onBNpcKill( uint32_t npcId, Entity::Player& player ) override
{
if( npcId != Enemy0 && npcId != Enemy1 && npcId != Enemy2 )
return;
if ( npcId == Enemy0 )
{
auto currentKC37 = player.getQuestUI8AL( getId() );
if ( currentKC37 + 1 >= 3 )
{
checkQuestCompletion( player, 1 );
player.setQuestUI8AL( getId(), currentKC37 + 1 );
}
else
{
player.setQuestUI8AL( getId(), currentKC37 + 1 );
player.sendQuestMessage( getId(), 1, 2, currentKC37 + 1, 3 );
}
}
if ( npcId == Enemy1 )
{
auto currentKC49 = player.getQuestUI8BH( getId() );
if ( currentKC49 + 1 >= 3 )
{
checkQuestCompletion( player, 2 );
player.setQuestUI8BH( getId(), currentKC49 + 1 );
}
else
{
player.setQuestUI8BH( getId(), currentKC49 + 1 );
player.sendQuestMessage( getId(), 2, 2, currentKC49 + 1, 3 );
}
}
if ( npcId == Enemy2 )
{
auto currentKC47 = player.getQuestUI8BL( getId() );
if ( currentKC47 + 1 >= 3 )
{
checkQuestCompletion( player, 3 );
player.setQuestUI8BL( getId(), currentKC47 + 1 );
}
else
{
player.setQuestUI8BL( getId(), currentKC47 + 1 );
player.sendQuestMessage( getId(), 3, 2, currentKC47 + 1, 3 );
}
}
}
private:
void checkQuestCompletion( Entity::Player& player, uint32_t varIdx )
{
if( varIdx == 1 )
player.sendQuestMessage( getId(), 1, 0, 0, 0 );
else if( varIdx == 2 )
player.sendQuestMessage( getId(), 2, 0, 0, 0 );
else
player.sendQuestMessage( getId(), 3, 0, 0, 0 );
auto questId = getId();
auto QUEST_ONKILL_37 = player.getQuestUI8AL( questId );
auto QUEST_ONKILL_49 = player.getQuestUI8BH( questId );
auto QUEST_ONKILL_47 = player.getQuestUI8BL( questId );
if( QUEST_ONKILL_37 >= 3 && QUEST_ONKILL_49 >= 3 && QUEST_ONKILL_47 >= 3 )
{
player.updateQuest( questId, SeqFinish );
}
}
void Scene00000( Entity::Player& player )
{
player.playScene( getId(), 0, HIDE_HOTBAR,
[ & ]( Entity::Player& player, const Event::SceneResult& result )
{
if( result.param2 == 1 )
{
player.updateQuest( getId(), Seq1 );
}
} );
}
void Scene00001( Entity::Player& player )
{
player.playScene( getId(), 1, SET_EOBJ_BASE | HIDE_HOTBAR | INVIS_EOBJ,
[ & ]( Entity::Player& player, const Event::SceneResult& result )
{
if( result.param2 == 1 )
{
player.sendQuestMessage( getId(), 0, 0, 0, 0 );
player.updateQuest( getId(), Seq2 );
}
} );
}
void Scene00002( Entity::Player& player )
{
player.playScene( getId(), 2, HIDE_HOTBAR,
[ & ]( Entity::Player& player, const Event::SceneResult& result )
{
if( result.param2 == 1 )
{
if( player.giveQuestRewards( getId(), 0 ) )
{
player.learnAction( 21 );
player.finishQuest( getId() );
}
}
} );
}
};
EXPOSE_SCRIPT( ClsArc000 );

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