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

Merge branch 'upstream/master'

This commit is contained in:
NotAdam 2018-06-10 11:37:39 +00:00
commit 11de5be42d
7 changed files with 317 additions and 324 deletions

View file

@ -553,6 +553,7 @@ namespace Common {
AetherReductionDlg = 0x17D, AetherReductionDlg = 0x17D,
Unk6 = 0x19C, Unk6 = 0x19C,
EObjAnimation = 0x19D,
SetTitle = 0x1F4, SetTitle = 0x1F4,
@ -562,6 +563,7 @@ namespace Common {
SetFavorite = 0x1FC, SetFavorite = 0x1FC,
LearnTeleport = 0x1FD, LearnTeleport = 0x1FD,
OpenRecommendationGuide = 0x200,
ArmoryErrorMsg = 0x201, ArmoryErrorMsg = 0x201,
AchievementPopup = 0x203, AchievementPopup = 0x203,

View file

@ -7,16 +7,17 @@
#include <boost/format.hpp> #include <boost/format.hpp>
#include "Util/Util.h" #include "Util/Util.h"
Core::Network::Packets::GamePacket::GamePacket( uint16_t subType, uint16_t size, uint32_t id1, uint32_t id2, uint16_t type ) Core::Network::Packets::GamePacket::GamePacket( uint16_t subType, uint16_t size,
uint32_t id1, uint32_t id2, uint16_t type )
{ {
m_dataBuf = std::vector<uint8_t>( size ); m_dataBuf = std::vector< uint8_t >( size );
memset( &m_segHdr, 0, sizeof( m_segHdr ) ); memset( &m_segHdr, 0, sizeof( m_segHdr ) );
setHeader( size, type, id1, id2, subType, 0x00 ); setHeader( size, type, id1, id2, subType, 0x00 );
} }
void Core::Network::Packets::GamePacket::setHeader( uint16_t size, uint16_t type, uint32_t id1, uint32_t id2, uint16_t subType, uint32_t unknown ) void Core::Network::Packets::GamePacket::setHeader( uint16_t size, uint16_t type, uint32_t id1,
uint32_t id2, uint16_t subType, uint32_t unknown )
{ {
m_segHdr.size = size; m_segHdr.size = size;
@ -40,7 +41,7 @@ void Core::Network::Packets::GamePacket::setHeader( uint16_t size, uint16_t type
Core::Network::Packets::GamePacket::GamePacket( char * pData, uint16_t size, bool bWriteStamp ) Core::Network::Packets::GamePacket::GamePacket( char * pData, uint16_t size, bool bWriteStamp )
{ {
m_dataBuf = std::vector<uint8_t>( size ); m_dataBuf = std::vector< uint8_t >( size );
memcpy( &m_dataBuf[0], pData, size ); memcpy( &m_dataBuf[0], pData, size );
m_unknown2 = 0; m_unknown2 = 0;
@ -65,9 +66,12 @@ Core::Network::Packets::GamePacket::GamePacket( const Packets::FFXIVARR_PACKET_R
{ {
m_segHdr = packetData.segHdr; m_segHdr = packetData.segHdr;
m_dataBuf = std::vector<uint8_t>( m_segHdr.size ); m_dataBuf = std::vector< uint8_t >( m_segHdr.size );
memcpy( &m_dataBuf[0] + sizeof( Packets::FFXIVARR_PACKET_SEGMENT_HEADER ),
&packetData.data[0],
m_segHdr.size - sizeof( Packets::FFXIVARR_PACKET_SEGMENT_HEADER ) );
memcpy( &m_dataBuf[0] + sizeof( Packets::FFXIVARR_PACKET_SEGMENT_HEADER ), &packetData.data[0], m_segHdr.size - sizeof( Packets::FFXIVARR_PACKET_SEGMENT_HEADER ) );
memcpy( &m_dataBuf[0], &m_segHdr, sizeof( Packets::FFXIVARR_PACKET_SEGMENT_HEADER ) ); memcpy( &m_dataBuf[0], &m_segHdr, sizeof( Packets::FFXIVARR_PACKET_SEGMENT_HEADER ) );
m_subType = *reinterpret_cast< uint16_t* >( &m_dataBuf[0] + 0x12 ); m_subType = *reinterpret_cast< uint16_t* >( &m_dataBuf[0] + 0x12 );
@ -98,5 +102,5 @@ void Core::Network::Packets::GamePacket::savePacket()
std::string Core::Network::Packets::GamePacket::toString() const std::string Core::Network::Packets::GamePacket::toString() const
{ {
return Core::Util::binaryToHexDump( const_cast<uint8_t *>( &m_dataBuf[0] ), getSize() ); return Core::Util::binaryToHexDump( const_cast< uint8_t* >( &m_dataBuf[0] ), getSize() );
} }

View file

@ -20,7 +20,7 @@ template < typename T, typename T1 >
class GamePacketNew; class GamePacketNew;
template < typename T, typename T1 > template < typename T, typename T1 >
std::ostream& operator<< ( std::ostream& os, const GamePacketNew< T, T1 >& packet ); std::ostream& operator << ( std::ostream& os, const GamePacketNew< T, T1 >& packet );
template< class T > template< class T >
using ZoneChannelPacket = GamePacketNew< T, ServerZoneIpcType >; using ZoneChannelPacket = GamePacketNew< T, ServerZoneIpcType >;
@ -32,15 +32,15 @@ using ChatChannelPacket = GamePacketNew< T, ServerChatIpcType >;
* The base implementation of a game packet. Needed for parsing packets. * The base implementation of a game packet. Needed for parsing packets.
*/ */
template < typename T1 > template < typename T1 >
class FFXIVPacketBase class FFXIVIpcPacketBase
{ {
public: public:
virtual ~FFXIVPacketBase() = default; virtual ~FFXIVIpcPacketBase() = default;
/** /**
* @brief Gets the IPC type of this packet. (Useful for determining the * @brief Gets the IPC type of this packet. (Useful for determining the
* type of a parsed packet.) * type of a parsed packet.)
*/ */
virtual T1 ipcType( void ) = 0; virtual T1 ipcType() = 0;
}; };
/** /**
@ -50,7 +50,7 @@ public:
* 32 byte header information.) * 32 byte header information.)
*/ */
template < typename T, typename T1 > template < typename T, typename T1 >
class GamePacketNew : public FFXIVPacketBase< T1 > class GamePacketNew : public FFXIVIpcPacketBase< T1 >
{ {
public: public:
/** /**
@ -96,7 +96,7 @@ protected:
}; };
public: public:
virtual T1 ipcType( void ) virtual T1 ipcType()
{ {
return static_cast< T1 >( m_data._ServerIpcType ); return static_cast< T1 >( m_data._ServerIpcType );
}; };

View file

@ -5,131 +5,122 @@
using namespace Core::Network::Packets; using namespace Core::Network::Packets;
namespace Core PacketParseResult Core::Network::Packets::getHeader( const std::vector< uint8_t > &buffer,
const uint32_t offset,
FFXIVARR_PACKET_HEADER &header )
{ {
namespace Network const auto headerSize = sizeof( FFXIVARR_PACKET_HEADER );
{
namespace Packets
{
PacketParseResult getHeader( const std::vector< uint8_t > &buffer,
const uint32_t offset,
FFXIVARR_PACKET_HEADER &header )
{
const auto headerSize = sizeof( FFXIVARR_PACKET_HEADER );
// Check if we have enough bytes in the buffer. // Check if we have enough bytes in the buffer.
auto remainingBytes = buffer.size() - offset; auto remainingBytes = buffer.size() - offset;
if( remainingBytes < headerSize ) if( remainingBytes < headerSize )
return Incomplete; return Incomplete;
// Copy packet header. // Copy packet header.
memcpy( &header, buffer.data() + offset, headerSize ); memcpy( &header, buffer.data() + offset, headerSize );
if( !checkHeader(header) ) if( !checkHeader(header) )
return Malformed; return Malformed;
return Success; return Success;
} }
PacketParseResult getSegmentHeader( const std::vector< uint8_t > &buffer, PacketParseResult Core::Network::Packets::getSegmentHeader( const std::vector< uint8_t > &buffer,
const uint32_t offset, const uint32_t offset,
FFXIVARR_PACKET_SEGMENT_HEADER &header ) FFXIVARR_PACKET_SEGMENT_HEADER &header )
{ {
const auto headerSize = sizeof( FFXIVARR_PACKET_SEGMENT_HEADER ); const auto headerSize = sizeof( FFXIVARR_PACKET_SEGMENT_HEADER );
// Check if we have enough bytes in the buffer. // Check if we have enough bytes in the buffer.
auto remainingBytes = buffer.size() - offset; auto remainingBytes = buffer.size() - offset;
if( remainingBytes < headerSize ) if( remainingBytes < headerSize )
return Incomplete; return Incomplete;
// Copy segment header // Copy segment header
memcpy( &header, buffer.data() + offset, headerSize ); memcpy( &header, buffer.data() + offset, headerSize );
return Success; return Success;
} }
PacketParseResult getPackets( const std::vector< uint8_t > &buffer, PacketParseResult Core::Network::Packets::getPackets( const std::vector< uint8_t > &buffer,
const uint32_t offset, const uint32_t offset,
const FFXIVARR_PACKET_HEADER &packetHeader, const FFXIVARR_PACKET_HEADER &packetHeader,
std::vector< FFXIVARR_PACKET_RAW > &packets ) std::vector< FFXIVARR_PACKET_RAW > &packets )
{ {
// sanity check: check there's enough bytes in the buffer // sanity check: check there's enough bytes in the buffer
const auto bytesExpected = packetHeader.size - sizeof( struct FFXIVARR_PACKET_HEADER ); const auto bytesExpected = packetHeader.size - sizeof( struct FFXIVARR_PACKET_HEADER );
if( buffer.size() - offset < bytesExpected ) if( buffer.size() - offset < bytesExpected )
return Incomplete; return Incomplete;
// Loop each message // Loop each message
uint32_t count = 0; uint32_t count = 0;
uint32_t bytesProcessed = 0; uint32_t bytesProcessed = 0;
while( count < packetHeader.count ) while( count < packetHeader.count )
{ {
FFXIVARR_PACKET_RAW rawPacket; FFXIVARR_PACKET_RAW rawPacket;
// Copy ipc packet message // Copy ipc packet message
const auto packetResult = getPacket( buffer, offset + bytesProcessed, rawPacket ); const auto packetResult = getPacket( buffer, offset + bytesProcessed, rawPacket );
if( packetResult != Success ) if( packetResult != Success )
return packetResult; return packetResult;
// NOTE: isn't rawPacket is allocated on stack? // NOTE: isn't rawPacket is allocated on stack?
// why is okay to do this? // why is okay to do this?
packets.push_back( rawPacket ); packets.push_back( rawPacket );
// Add message size and count // Add message size and count
bytesProcessed += rawPacket.segHdr.size; bytesProcessed += rawPacket.segHdr.size;
count += 1; count += 1;
} }
// sanity check: check if we processed all bytes. // sanity check: check if we processed all bytes.
// this check can fail if size of messages don't add up to size reported from packet header. // this check can fail if size of messages don't add up to size reported from packet header.
if( bytesExpected != bytesProcessed ) if( bytesExpected != bytesProcessed )
return Malformed; return Malformed;
return Success; return Success;
} }
PacketParseResult getPacket( const std::vector< uint8_t > &buffer, const uint32_t offset, PacketParseResult Core::Network::Packets::getPacket( const std::vector< uint8_t > &buffer, const uint32_t offset,
FFXIVARR_PACKET_RAW &packet ) FFXIVARR_PACKET_RAW &packet )
{ {
// Copy segment header // Copy segment header
const auto headerResult = getSegmentHeader( buffer, offset, packet.segHdr ); const auto headerResult = getSegmentHeader( buffer, offset, packet.segHdr );
if( headerResult != Success ) if( headerResult != Success )
return headerResult; return headerResult;
// Check header sanity and it's size // Check header sanity and it's size
if( !checkSegmentHeader( packet.segHdr ) ) if( !checkSegmentHeader( packet.segHdr ) )
return Malformed; return Malformed;
const auto dataOffset = offset + sizeof( struct FFXIVARR_PACKET_SEGMENT_HEADER ); const auto dataOffset = offset + sizeof( struct FFXIVARR_PACKET_SEGMENT_HEADER );
const auto dataSize = packet.segHdr.size; const auto dataSize = packet.segHdr.size;
// Allocate data buffer and copy // Allocate data buffer and copy
packet.data.resize( dataSize ); packet.data.resize( dataSize );
memcpy( packet.data.data(), buffer.data() + dataOffset, dataSize ); memcpy( packet.data.data(), buffer.data() + dataOffset, dataSize );
return Success; return Success;
} }
bool checkHeader( const FFXIVARR_PACKET_HEADER &header ) bool Core::Network::Packets::checkHeader( const FFXIVARR_PACKET_HEADER &header )
{ {
// Max size of the packet is capped at 1MB for now. // Max size of the packet is capped at 1MB for now.
if( header.size > 1 * 1024 * 1024 ) if( header.size > 1 * 1024 * 1024 )
return false; return false;
// Max number of message is capped at 255 for now. // Max number of message is capped at 255 for now.
if( header.count > 255 ) if( header.count > 255 )
return false; return false;
return true; return true;
} }
bool checkSegmentHeader( const FFXIVARR_PACKET_SEGMENT_HEADER &header ) bool Core::Network::Packets::checkSegmentHeader( const FFXIVARR_PACKET_SEGMENT_HEADER &header )
{ {
// Max size of individual message is capped at 256KB for now. // Max size of individual message is capped at 256KB for now.
if( header.size > 256 * 1024 ) if( header.size > 256 * 1024 )
return false; return false;
return true; return true;
}
}
}
} }

View file

@ -2,62 +2,49 @@
#define _GAMEPACKETPARSER_H #define _GAMEPACKETPARSER_H
#include "CommonNetwork.h" #include "CommonNetwork.h"
namespace Core namespace Core {
{ namespace Network {
namespace Network namespace Packets {
enum PacketParseResult
{ {
namespace Packets /// Dissected game packet successfully
{ Success,
enum PacketParseResult
{
/// Dissected game packet successfully
Success,
/// Buffer is too short to dissect a message. /// Buffer is too short to dissect a message.
Incomplete, Incomplete,
/// Invalid data detected.
Malformed
};
/// Read packet header from buffer with given offset. /// Invalid data detected.
/// Buffer with given offset must be pointing to start of the new FFXIV packet. Malformed
PacketParseResult getHeader( };
const std::vector< uint8_t > &buffer,
const uint32_t offset,
FFXIVARR_PACKET_HEADER &header
);
/// Read packet header from buffer with given offset. /// Read packet header from buffer with given offset.
/// Buffer with given offset must be pointing to start of FFXIVARR_PACKET_SEGMENT_HEADER data. /// Buffer with given offset must be pointing to start of the new FFXIV packet.
/// Keep in mind that this function does check for data validity. Call checkSegmentHeader() if that's needed. PacketParseResult getHeader( const std::vector< uint8_t > &buffer, const uint32_t offset,
PacketParseResult getSegmentHeader( FFXIVARR_PACKET_HEADER &header );
const std::vector< uint8_t > &buffer,
const uint32_t offset,
FFXIVARR_PACKET_SEGMENT_HEADER &header
);
/// Read packets from the buffer with given offset. /// Read packet header from buffer with given offset.
/// Buffer with given offset must be pointing to end of FFXIVARR_PACKET_HEADER data. /// Buffer with given offset must be pointing to start of FFXIVARR_PACKET_SEGMENT_HEADER data.
PacketParseResult getPackets( /// Keep in mind that this function does check for data validity. Call checkSegmentHeader() if that's needed.
const std::vector< uint8_t > &buffer, PacketParseResult getSegmentHeader( const std::vector< uint8_t > &buffer, const uint32_t offset,
const uint32_t offset, FFXIVARR_PACKET_SEGMENT_HEADER &header );
const FFXIVARR_PACKET_HEADER &header,
std::vector< Packets::FFXIVARR_PACKET_RAW > &packets);
/// Read single packet from the buffer with given offset.
/// Buffer with an offset must be pointing to start of FFXIVARR_PACKET_SEGMENT_HEADER data.
PacketParseResult getPacket(
const std::vector< uint8_t > &buffer,
const uint32_t offset,
FFXIVARR_PACKET_RAW &packet
);
bool checkHeader(const FFXIVARR_PACKET_HEADER &header); /// Read packets from the buffer with given offset.
bool checkSegmentHeader(const FFXIVARR_PACKET_SEGMENT_HEADER &header); /// Buffer with given offset must be pointing to end of FFXIVARR_PACKET_HEADER data.
PacketParseResult getPackets( const std::vector< uint8_t > &buffer, const uint32_t offset,
const FFXIVARR_PACKET_HEADER &header,
std::vector< Packets::FFXIVARR_PACKET_RAW > &packets );
} /// Read single packet from the buffer with given offset.
} /// Buffer with an offset must be pointing to start of FFXIVARR_PACKET_SEGMENT_HEADER data.
PacketParseResult getPacket( const std::vector< uint8_t > &buffer, const uint32_t offset,
FFXIVARR_PACKET_RAW &packet );
bool checkHeader(const FFXIVARR_PACKET_HEADER &header);
bool checkSegmentHeader(const FFXIVARR_PACKET_SEGMENT_HEADER &header);
}
}
} }

View file

@ -107,11 +107,14 @@ namespace Packets {
ActorCast = 0x0178, // updated 4.3 ActorCast = 0x0178, // updated 4.3
PartyList = 0x017A, // updated 4.3
HateList = 0x017B, // updated 4.3 HateList = 0x017B, // updated 4.3
ObjectSpawn = 0x017D, // updated 4.3 ObjectSpawn = 0x017D, // updated 4.3
ObjectDespawn = 0x017E, // updated 4.3 ObjectDespawn = 0x017E, // updated 4.3
SetLevelSync = 0x017F, // updated 4.3
InventoryActionAck = 0x0180, // updated 4.2 ? InventoryActionAck = 0x0180, // updated 4.2 ?
InitUI = 0x0181, // updated 4.3 InitUI = 0x0181, // updated 4.3

View file

@ -612,146 +612,152 @@ struct FFXIVIpcInitUI : FFXIVIpcBasePacket<InitUI>
// plain C types for a bit until the packet is actually fixed. // plain C types for a bit until the packet is actually fixed.
// makes conversion between different editors easier. // makes conversion between different editors easier.
uint64_t contentId; uint64_t contentId;
uint32_t unknown8; unsigned int unknown8;
uint32_t unknownC; unsigned int unknownC;
uint32_t charId; unsigned int charId;
uint32_t restedExp; unsigned int restedExp;
uint32_t companionCurrentExp; unsigned int companionCurrentExp;
uint32_t unknown3C; unsigned int unknown3C;
uint32_t fishCaught; unsigned int fishCaught;
uint32_t useBaitCatalogId; unsigned int useBaitCatalogId;
uint32_t pvpWolfFoldMatches; unsigned int pvpWolfFoldMatches;
uint16_t pvpWolfFoldWeeklyMatches; unsigned short pvpWolfFoldWeeklyMatches;
uint16_t pvpWolfFoldWeeklyVictories; unsigned short pvpWolfFoldWeeklyVictories;
uint16_t pvpStats[6]; unsigned short pvpStats[6];
uint16_t playerCommendations; unsigned short playerCommendations;
uint16_t pvpStats1; unsigned short pvpStats1;
uint16_t frontlineCampaigns[4]; unsigned char frontlineCampaigns[4];
uint16_t frontlineCampaignsWeekly; unsigned short frontlineCampaignsWeekly;
uint16_t currentRelic; unsigned char currentRelic;
uint16_t currentBook; unsigned char currentBook;
uint16_t masterCrafterMask; unsigned char masterCrafterMask;
uint16_t unknown69; unsigned char unknown69;
uint16_t unknown6A; unsigned char unknown6A;
uint16_t unknown6B; unsigned char unknown6B;
uint16_t unknown6C[4]; unsigned char unknown6C[4];
uint16_t unknown50[34]; unsigned char unknown70[34];
uint16_t unknown18; unsigned short unknown18;
uint16_t maxLevel; unsigned char maxLevel;
uint16_t expansion; unsigned char expansion;
uint16_t unknown76; unsigned char unknown;
uint16_t race; unsigned char race;
uint16_t tribe; unsigned char tribe;
uint16_t gender; unsigned char gender;
uint16_t currentJob; unsigned char currentJob;
uint16_t currentClass; unsigned char currentClass;
uint16_t deity; unsigned char deity;
uint16_t namedayMonth; unsigned char namedayMonth;
uint16_t namedayDay; unsigned char namedayDay;
uint16_t cityState; unsigned char cityState;
uint16_t homepoint; unsigned char homepoint;
uint16_t unknown26; unsigned char unknown26;
uint16_t petHotBar; unsigned char petHotBar;
uint16_t companionRank; unsigned char companionRank;
uint16_t companionStars; unsigned char companionStars;
uint16_t companionSp; unsigned char companionSp;
uint16_t companionUnk2B; unsigned char companionUnk2B;
uint16_t companionColor; unsigned char companionColor;
uint16_t companionFavoFeed; unsigned char companionFavoFeed;
uint16_t companionUnk89; unsigned char companionUnk2E;
uint16_t companionUnk90[5]; unsigned char companionTimePassed[4];
uint16_t unknown90[7]; unsigned short unknown38[11];
uint16_t unknown9E;
uint16_t unknownA0; unsigned int exp[25];
uint32_t exp[25]; unsigned char unknown564[16];
uint16_t unknown564[16]; unsigned int pvpFrontlineOverall1st;
uint32_t pvpFrontlineOverall1st; unsigned int pvpFrontlineOverall2nd;
uint32_t pvpFrontlineOverall2nd; unsigned int pvpFrontlineOverall3rd;
uint32_t pvpFrontlineOverall3rd; unsigned char relicBookCompletion1[4];
uint16_t relicBookCompletion1[4]; unsigned short levels[25];
uint16_t levels[25]; unsigned short levelsPadding;
uint16_t levelsPadding; unsigned char unknown__[16];
uint16_t unknown15C[8]; unsigned short fishingRecordsFish[26];
uint16_t fishingRecordsFish[26]; unsigned short fishingRecordsFishWeight[26];
uint16_t fishingRecordsFishWeight[26]; unsigned char unknownMask554[44];
uint16_t unknownMask554[44];
uint16_t companion_name[21]; unsigned char companion_name[21];
uint16_t companionDefRank; unsigned char companionDefRank;
uint16_t companionAttRank; unsigned char companionAttRank;
uint16_t companionHealRank; unsigned char companionHealRank;
uint16_t mountGuideMask[16]; unsigned char mountGuideMask[16];
char name[32]; char name[32];
uint16_t unknownOword[16]; unsigned char unknownOword[16];
uint16_t unknown258; unsigned char unlockBitmask[64];
uint16_t unlockBitmask[64]; unsigned char aetheryte[17];
uint16_t aetheryte[17]; unsigned char discovery[421];
uint16_t discovery[421]; unsigned char howto[33];
uint16_t howto[33]; unsigned char minions[38];
uint16_t minions[38]; unsigned char chocoboTaxiMask[8];
uint16_t chocoboTaxiMask[8]; unsigned char contentClearMask[111];
uint16_t contentClearMask[111]; unsigned char contentClearPadding;
uint16_t contentClearPadding; unsigned short unknown428[8];
uint16_t unknown428[8]; unsigned char companionBardingMask[8];
uint16_t companionBardingMask[8]; unsigned char companionEquippedHead;
uint16_t companionEquippedHead; unsigned char companionEquippedBody;
uint16_t companionEquippedBody; unsigned char companionEquippedFeet;
uint16_t companionEquippedFeet; unsigned char companionUnk4[4];
uint16_t companionUnk4[4]; unsigned char companion_fields[11];
uint16_t companion_fields[11];
uint16_t fishingGuideMask[89]; unsigned char fishingGuideMask[89];
uint16_t fishingSpotVisited[25]; unsigned char fishingSpotVisited[25];
uint16_t unknownMask4Padding;
uint16_t rankAmalJaa;
uint16_t rankSylph; unsigned char unknownMask4Padding;
uint16_t rankKobold;
uint16_t rankSahagin; unsigned char rankAmalJaa;
uint16_t rankIxal; unsigned char rankSylph;
uint16_t rankVanu; unsigned char rankKobold;
uint16_t rankVath; unsigned char rankSahagin;
uint16_t rankMoogle; unsigned char rankIxal;
uint16_t rankKojin; unsigned char rankVanu;
uint16_t rankAnata; unsigned char rankVath;
uint16_t expAmalJaa; unsigned char rankMoogle;
uint16_t expSylph; unsigned char rankKojin;
uint16_t expKobold; unsigned char rankAnata;
uint16_t expSahagin; unsigned short expAmalJaa;
uint16_t expIxal; unsigned short expSylph;
uint16_t expVanu; unsigned short expKobold;
uint16_t expVath; unsigned short expSahagin;
uint16_t expMoogle; unsigned short expIxal;
uint16_t expKojin; unsigned short expVanu;
uint16_t expAnata; unsigned short expVath;
uint16_t unknown596[10]; unsigned short expMoogle;
uint16_t unknown5A0[5]; unsigned short expKojin;
uint16_t unknownMask59E[5]; unsigned short expAnata;
uint16_t unknown5A3[18]; unsigned char unknown596[10];
uint16_t unknownMask5C1[28]; unsigned short unknown5A0[5];
uint16_t unknown_03411; unsigned char unknownMask59E[5];
uint32_t unknownDword5E0; unsigned char unknown5A3[18];
uint16_t pvpFrontlineWeekly1st; unsigned char unknownMask5C1[28];
uint16_t pvpFrontlineWeekly2nd; unsigned char unknown_03411;
uint16_t pvpFrontlineWeekly3rd; unsigned int unknownDword5E0;
uint16_t relicBookCompletion2[8]; unsigned short pvpFrontlineWeekly1st;
uint16_t sightseeingMask[26]; unsigned short pvpFrontlineWeekly2nd;
uint16_t unknown_XXX; unsigned short pvpFrontlineWeekly3rd;
uint16_t unknown61E[20]; unsigned char relicBookCompletion2[8];
uint16_t unknown656[29]; unsigned char sightseeingMask[26];
uint16_t unknown63F[22]; unsigned short unknown_XXX;
uint16_t tripleTriadCards[28];
uint16_t unknown671[11]; unsigned char unknown61E;
uint16_t unknownMask67C[22]; unsigned char unknown61F[32];
uint16_t unknown692[3]; unsigned char unknown63F[22];
uint16_t orchestrionMask[40]; unsigned char tripleTriadCards[28];
uint16_t hallOfNoviceCompleteMask[3]; unsigned char unknown671[11];
uint16_t unknownMask6C0[11]; unsigned char unknownMask67C[22];
uint16_t unknownMask6CB[16]; unsigned char unknown692[3];
uint16_t unknown6DB[14]; unsigned char orchestrionMask[40];
uint16_t unlockedRaids[28]; unsigned char hallOfNoviceCompleteMask[3];
uint16_t unlockedDungeons[18]; unsigned char unknownMask6C0[11];
uint16_t unlockedGuildhests[10]; unsigned char unknownMask6CB[16];
uint16_t unlockedTrials[7]; unsigned char unknown6DB[14];
uint16_t unlockedPvp[5]; unsigned char unlockedRaids[28];
uint16_t unknownMask72D[28]; unsigned char unlockedDungeons[18];
unsigned char unlockedGuildhests[10];
unsigned char unlockedTrials[7];
unsigned char unlockedPvp[5];
unsigned char unknownMask72D[28];
// unsigned char unknownMask749[18];
//unsigned char unknown749[13];
}; };