diff --git a/Source/Client/Session.h b/Source/Client/Session.h index 6897ba48..874992dd 100644 --- a/Source/Client/Session.h +++ b/Source/Client/Session.h @@ -249,7 +249,9 @@ public: /* 5448 */ int unknown_5448; /* 544C */ unsigned char unknown_544C[0x04]; /* 5450 */ int unknown_5450; - /* 5454 */ unsigned char unknown_5454[0x14]; + /* 5454 */ unsigned char unknown_5454[0x0C]; + /* 5460 */ int unknown_5460; + /* 5464 */ int unknown_5464; /* 5468 */ int unknown_5468; /* 546C */ unsigned char unknown_546C[0x04]; /* 5470 */ int unknown_5470; @@ -258,7 +260,9 @@ public: /* 54A0 */ int unknown_54A0; /* 54A4 */ int unknown_54A4; /* 54A8 */ int unknown_54A8; - /* 54AC */ unsigned char unknown_54AC[0x90]; + /* 54AC */ std::string unknown_54AC; + /* 54C4 */ std::string unknown_54C4; + /* 54DC */ unsigned char unknown_54DC[0x60]; /* 553C */ std::string m_serverName; /* 5554 */ unsigned char unknown_5554[4]; /* 5558 */ int unknown_5558; @@ -289,7 +293,18 @@ public: /* 56B8 */ unsigned char unknown_56B8[0x242]; /* 58FA */ char unknown_58FA[0x18]; /* 5912 */ unsigned char unknown_5912; - /* 5913 */ unsigned char unknown_5913[0xA9]; + /* 5913 */ unsigned char unknown_5913[0x25]; + /* 5938 */ int unknown_5938; + /* 593C */ int unknown_593C; + /* 5940 */ int unknown_5940; + /* 5944 */ int unknown_5944; + /* 5948 */ int unknown_5948; + /* 594C */ int unknown_594C; + /* 5950 */ std::string unknown_5950; + /* 5968 */ int unknown_5968; + /* 596C */ int unknown_596C; + /* 5970 */ int unknown_5970; + /* 5974 */ unsigned char unknown_5974[0x48]; /* 59BC */ int unknown_59BC; /* 59C0 */ int unknown_59C0; /* 59C4 */ int unknown_59C4; @@ -569,6 +584,11 @@ public: std::string GetWeaponEffectActName(int job, int sex, int weapon, int weaponItem, int effect, int costume); std::string GetWeaponEffectSprName(int job, int sex, int weapon, int weaponItem, int effect, int costume); void CollectCardItems(); + std::uint32_t ReadReplayMessenger(const std::vector& data); + std::uint32_t ReadReplayItems(const std::vector& data); + std::uint32_t ReadReplayShops(const std::vector& data); + std::uint32_t ReadReplayExtra(const std::vector& data); + std::uint32_t ReadReplayReserved(const std::vector& data); void SetHomunculusAutoFeed(bool enabled); void SetPetAutoFeed(bool enabled); void SendHomunculusAutoFeedOption(unsigned char enabled); @@ -763,6 +783,9 @@ static_assert(offsetof(CSession, unknown_5214) == 0x5214); static_assert(offsetof(CSession, unknown_0E94) == 0xE94); static_assert(offsetof(CSession, unknown_103C) == 0x103C); static_assert(offsetof(CSession, unknown_5450) == 0x5450); +static_assert(offsetof(CSession, unknown_54C4) == 0x54C4); +static_assert(offsetof(CSession, unknown_5950) == 0x5950); +static_assert(offsetof(CSession, unknown_5970) == 0x5970); static_assert(offsetof(CSession, unknown_59BC) == 0x59BC); static_assert(offsetof(CSession, m_hotkeyScript) == 0x59D8); static_assert(offsetof(CSession, m_lastIntervalTime) == 0x6188); diff --git a/Source/Contents/ClientState.cpp b/Source/Contents/ClientState.cpp index 73480ed5..d8e2f2e7 100644 --- a/Source/Contents/ClientState.cpp +++ b/Source/Contents/ClientState.cpp @@ -6,6 +6,36 @@ #include "UI/Window/UIWindowMgr.h" #include +#include +#include + +namespace { +#pragma pack(push, 1) + struct ReplayBlockHeader { + /* 0000 */ std::int16_t id; + /* 0002 */ std::uint32_t bytes; + }; + + struct ReplayShopNameRecord { + /* 0000 */ std::int16_t unknown; + /* 0002 */ char name[16]; + /* 0012 */ int shopId; + }; +#pragma pack(pop) + + struct ReplayShopItemRecord { + /* 0000 */ int shopId; + /* 0004 */ unsigned int index; + /* 0008 */ int itemId; + /* 000C */ int first; + /* 0010 */ int second; + }; + + struct ReplayShopFlagRecord { + /* 0000 */ int shopId; + /* 0004 */ char flag; + }; +} // GLOBAL: gl_24492 bool g_homunculusAutoFeed; @@ -13,6 +43,308 @@ bool g_homunculusAutoFeed; // GLOBAL: gl_24493 bool g_petAutoFeed; +// OFFSET: 0x00E46620 +// FUNCTION: fn_24211 +std::uint32_t CSession::ReadReplayMessenger(const std::vector& data) { + if (data.begin() == data.end()) { + return 0xFFFFFFFF; + } + + std::uint32_t offset = 6; + ReplayBlockHeader header{}; + std::memcpy(&header, data.data(), sizeof(header)); + if (header.id != 4000) { + return 0xFFFFFFFF; + } + + while (offset < data.size()) { + header = {}; + std::memcpy(&header, data.data() + offset, sizeof(header)); + offset += 6; + const unsigned char* source = data.data() + offset; + switch (header.id) { + case 4501: + return offset; + case 4010: + std::memcpy(&this->unknown_5938, source, header.bytes); + offset += header.bytes; + break; + case 4011: + std::memcpy(&this->unknown_5460, source, header.bytes); + offset += header.bytes; + break; + case 4012: + std::memcpy(&this->unknown_5464, source, header.bytes); + offset += header.bytes; + break; + case 4013: { + char buffer[260]; + std::memset(buffer, 0, sizeof(buffer)); + std::memcpy(buffer, source, header.bytes); + offset += header.bytes; + this->unknown_54AC = buffer; + break; + } + case 4014: { + char buffer[260]; + std::memset(buffer, 0, sizeof(buffer)); + std::memcpy(buffer, source, header.bytes); + offset += header.bytes; + this->unknown_54C4 = buffer; + break; + } + case 4015: + offset = ReadMessengerMembers(this->m_partyMembers, offset, header.bytes, data); + break; + case 4016: + offset = ReadMessengerMembers(this->m_friends, offset, header.bytes, data); + break; + default: + offset += header.bytes; + break; + } + } + + return offset; +} + +// OFFSET: 0x00E46920 +// FUNCTION: fn_24212 +std::uint32_t CSession::ReadReplayItems(const std::vector& data) { + if (data.begin() == data.end()) { + return 0xFFFFFFFF; + } + + std::uint32_t offset = 6; + ReplayBlockHeader header{}; + std::memcpy(&header, data.data(), sizeof(header)); + if (header.id != 4500) { + return 0xFFFFFFFF; + } + + while (offset < data.size()) { + header = {}; + std::memcpy(&header, data.data() + offset, sizeof(header)); + offset += 6; + const unsigned char* source = data.data() + offset; + switch (header.id) { + case 4501: + case 4703: + return offset; + case 4510: + offset = ReadItemList(this->m_inventoryItems, offset, header.bytes, data); + break; + case 4511: + offset = ReadItemList(this->unknown_1718, offset, header.bytes, data); + break; + case 4512: + offset = ReadItemList(this->unknown_1720, offset, header.bytes, data); + break; + case 4513: + offset = ReadItemList(this->unknown_1728, offset, header.bytes, data); + break; + case 4514: + offset = ReadItemList(this->unknown_1730, offset, header.bytes, data); + break; + case 4515: + offset = ReadItemList(this->unknown_1738, offset, header.bytes, data); + break; + case 4516: + offset = ReadItemList(this->unknown_1740, offset, header.bytes, data); + break; + case 4517: + offset = ReadItemList(this->unknown_1748, offset, header.bytes, data); + break; + case 4518: + offset = ReadItemList(this->unknown_1750, offset, header.bytes, data); + break; + case 4519: + offset = ReadItemList(this->unknown_1758, offset, header.bytes, data); + break; + case 4520: + offset = ReadItemList(this->unknown_1760, offset, header.bytes, data); + break; + case 4521: + offset = ReadItemList(this->unknown_1768, offset, header.bytes, data); + break; + case 4522: + offset = ReadItemList(this->unknown_1770, offset, header.bytes, data); + break; + case 4601: + offset = ReadItemArray(this->unknown_17F0, offset, header.bytes, data); + break; + case 4602: + offset = ReadItemArray(this->unknown_21A0, offset, header.bytes, data); + break; + case 4603: + offset = ReadItemArray(this->unknown_2B50, offset, header.bytes, data); + break; + case 4604: + offset = ReadItemArray(this->unknown_3500, offset, header.bytes, data); + break; + case 4605: + offset = ReadItemArray(this->m_exchangeItems, offset, header.bytes, data); + break; + case 4606: + offset = ReadItemArray(this->m_itemSlots, offset, header.bytes, data); + break; + case 4701: + std::memcpy(&this->unknown_5210, source, header.bytes); + offset += header.bytes; + break; + case 4702: + std::memcpy(&this->unknown_5214, source, header.bytes); + offset += header.bytes; + break; + default: + offset += header.bytes; + break; + } + } + + return offset; +} + +// OFFSET: 0x00E46DC0 +// FUNCTION: fn_24213 +std::uint32_t CSession::ReadReplayShops(const std::vector& data) { + if (data.begin() == data.end()) { + return 0xFFFFFFFF; + } + + std::uint32_t offset = 6; + ReplayBlockHeader header{}; + std::memcpy(&header, data.data(), sizeof(header)); + if (header.id != 7500) { + return 0xFFFFFFFF; + } + + while (offset < data.size()) { + header = {}; + std::memcpy(&header, data.data() + offset, sizeof(header)); + offset += 6; + const unsigned char* source = data.data() + offset; + switch (header.id) { + case 7501: + return offset; + case 7502: { + ReplayShopNameRecord record{}; + std::memcpy(&record, source, header.bytes); + offset += header.bytes; + std::string name(record.name); + this->AddShopName(name, record.shopId); + break; + } + case 7504: { + ReplayShopItemRecord record{}; + std::memcpy(&record, source, header.bytes); + offset += header.bytes; + g_session.SetShopItem(record.shopId, record.index, record.itemId, record.first, record.second); + break; + } + case 7505: { + ReplayShopFlagRecord record{}; + std::memcpy(&record, source, header.bytes); + offset += header.bytes; + g_session.SetShopFlag(record.shopId, record.flag); + break; + } + default: + offset += header.bytes; + break; + } + } + + return offset; +} + +// OFFSET: 0x00E470D0 +// FUNCTION: fn_24214 +std::uint32_t CSession::ReadReplayExtra(const std::vector& data) { + if (data.begin() == data.end()) { + return 0xFFFFFFFF; + } + + std::uint32_t offset = 6; + ReplayBlockHeader header{}; + std::memcpy(&header, data.data(), sizeof(header)); + if (header.id != 5500) { + return 0xFFFFFFFF; + } + + while (offset < data.size()) { + header = {}; + std::memcpy(&header, data.data() + offset, sizeof(header)); + offset += 6; + const unsigned char* source = data.data() + offset; + bool done = false; + switch (header.id) { + case 5501: + done = true; + break; + case 5510: + std::memcpy(&this->unknown_593C, source, header.bytes); + offset += header.bytes; + break; + case 5511: + std::memcpy(&this->unknown_5940, source, header.bytes); + offset += header.bytes; + break; + case 5512: + std::memcpy(&this->unknown_5944, source, header.bytes); + offset += header.bytes; + break; + case 5513: + std::memcpy(&this->unknown_5948, source, header.bytes); + offset += header.bytes; + break; + case 5514: + std::memcpy(&this->unknown_594C, source, header.bytes); + offset += header.bytes; + break; + case 5515: { + char buffer[260]; + std::memset(buffer, 0, sizeof(buffer)); + std::memcpy(buffer, source, header.bytes); + offset += header.bytes; + this->unknown_5950 = buffer; + break; + } + case 5516: + std::memcpy(&this->unknown_5968, source, header.bytes); + offset += header.bytes; + break; + case 5517: + std::memcpy(&this->unknown_596C, source, header.bytes); + offset += header.bytes; + break; + case 5518: + std::memcpy(&this->unknown_5970, source, header.bytes); + offset += header.bytes; + break; + default: + offset += header.bytes; + break; + } + + if (done) { + break; + } + } + + if (this->unknown_593C == 1) { + g_windowMgr.EnsureWindow(0x89); + } + + return offset; +} + +// OFFSET: 0x00E47410 +// FUNCTION: fn_24215 +std::uint32_t CSession::ReadReplayReserved(const std::vector&) { + return 0; +} + // OFFSET: 0x00E488C0 // FUNCTION: fn_24221 void CSession::UpdateBodyStyle(int job, int style, int renderJob) {