From 8cd3846220bf73ac920fa130f981bb879f29aa55 Mon Sep 17 00:00:00 2001 From: ragnarok-clanker Date: Fri, 30 Oct 2026 19:28:31 +0000 Subject: [PATCH] Decompile 3 functions in Source/Client/Mode/LoginMode.cpp, Source/Client/Mode/CLoginMode.h Batch #6010 by eAthena: 0 byte-identical, 3 confirmed by peer review. - fn_22271 GetMacAddress: logic confirmed by peer review - fn_22278 CLoginMode::ReceiveCharacterPage: logic confirmed by peer review - fn_22295 CLoginMode::ReceiveRefuseLogin: logic confirmed by peer review Peer-reviewed-by: ragnarok-clanker, Lumen, SapitoSucio, superintelligence Accepted without human review: peers confirmed the logic ("same" ahead by at least 3, with 70% of the votes). --- Source/Client/Mode/CLoginMode.h | 17 ++- Source/Client/Mode/LoginMode.cpp | 201 +++++++++++++++++++++++++++++++ 2 files changed, 216 insertions(+), 2 deletions(-) diff --git a/Source/Client/Mode/CLoginMode.h b/Source/Client/Mode/CLoginMode.h index 57eafa21..7fd8219e 100644 --- a/Source/Client/Mode/CLoginMode.h +++ b/Source/Client/Mode/CLoginMode.h @@ -17,16 +17,25 @@ struct MapStatePacket; struct WindowDialogs; struct LoginErrorPacket; struct LoginErrorDetailPacket; +struct CharacterPagePacket; +struct RefuseLoginPacket; #pragma pack(push, 1) struct CharacterInfo { /* 0000 */ std::uint32_t gid; - /* 0004 */ unsigned char unknown_0004[0x86]; + /* 0004 */ unsigned char unknown_0004[0x50]; + /* 0054 */ std::int16_t job; + /* 0056 */ unsigned char unknown_0056[0x2]; + /* 0058 */ std::int16_t unknown_0058; + /* 005A */ unsigned char unknown_005A[0x10]; + /* 006A */ std::int16_t bodyStyle; + /* 006C */ unsigned char unknown_006C[0x1E]; /* 008A */ unsigned char slot; /* 008B */ unsigned char unknown_008B[0x3]; /* 008E */ char mapName[16]; /* 009E */ std::int32_t deleteDate; - /* 00A2 */ unsigned char unknown_00A2[0x0D]; + /* 00A2 */ unsigned char unknown_00A2[0x0C]; + /* 00AE */ unsigned char sex; }; struct CharacterSlotExtension { @@ -78,12 +87,14 @@ public: void SubD8EDC0(int); void ReceiveCharacterResult(const CharacterResultPacket* packet, WindowDialogs& dialogs); void SubD8F560(int); + void ReceiveCharacterPage(const CharacterPagePacket* packet); void ReceiveCharacterList(const CharacterListPacket* packet); void ReceiveDeleteCharacter(const CharacterDeletePacket* packet, WindowDialogs& dialogs); void ReceiveDeleteCancel(const CharacterDeletePacket* packet, WindowDialogs& dialogs); void ReceiveDeleteReservation(const CharacterDeletePacket* packet, WindowDialogs& dialogs); void ReceiveMapStates(const MapStatePacket* packet, WindowDialogs& dialogs); void SubD91780(int); + void ReceiveRefuseLogin(const RefuseLoginPacket* packet); void SubD97B20(int); void SubD97EF0(int); void SubD97F00(int); @@ -93,6 +104,7 @@ public: }; int GetClientType(); +std::string GetMacAddress(); const char* GetUserCountText(unsigned short userCount); void OpenAccountRegistration(); @@ -100,6 +112,7 @@ void OpenAccountRegistration(); static_assert(sizeof(CharacterInfo) == 0xAF); static_assert(offsetof(CharacterInfo, slot) == 0x8A); static_assert(offsetof(CharacterInfo, mapName) == 0x8E); +static_assert(offsetof(CharacterInfo, sex) == 0xAE); static_assert(sizeof(MapStateEntry) == 0x14); static_assert(sizeof(CharacterSlotExtension) == 0x14); static_assert(offsetof(CLoginMode, characterCount) == 0x1CC); diff --git a/Source/Client/Mode/LoginMode.cpp b/Source/Client/Mode/LoginMode.cpp index be4a9388..45549c26 100644 --- a/Source/Client/Mode/LoginMode.cpp +++ b/Source/Client/Mode/LoginMode.cpp @@ -26,6 +26,8 @@ #include #include #include +#include +#include #include #pragma pack(push, 1) @@ -91,8 +93,23 @@ struct LoginErrorDetailPacket { /* 0008 */ char detail[20]; /* 001C */ char text[1]; }; + +struct CharacterPagePacket { + /* 0000 */ std::int16_t id; + /* 0002 */ std::int16_t length; + /* 0004 */ CharacterInfo characters[1]; +}; + +struct RefuseLoginPacket { + /* 0000 */ std::int16_t id; + /* 0002 */ unsigned char result; + /* 0003 */ char blockDate[20]; +}; #pragma pack(pop) +// GLOBAL: gl_25054 +int g_charServerAccountIdPending; + static_assert(sizeof(CharacterSlotsPacket) == 0x1D); static_assert(offsetof(AcceptEnterPacket, characters) == 0x1B); @@ -270,6 +287,33 @@ int GetClientType() { } } +// OFFSET: 0x00D8E3A0 +// FUNCTION: fn_22271 +std::string GetMacAddress() { + ULONG size = 0; + if (GetAdaptersInfo(nullptr, &size) == ERROR_BUFFER_OVERFLOW) { + IP_ADAPTER_INFO* adapter = reinterpret_cast(new (std::nothrow) char[size]); + memset(adapter, 0, size); + GetAdaptersInfo(adapter, &size); + if (adapter != nullptr) { + char text[100]; + memset(text, 0, sizeof(text)); + const std::uint8_t source[] = {0x32, 0x2B, 0x1F, 0xFB, 0x90, 0xCE, 0x71, 0x3D, 0x4F, 0x36, 0x08, 0x93, 0x8F, 0xB3, 0x6C, + 0x2A, 0x27, 0x29, 0x75, 0x8E, 0x98, 0xDB, 0x73, 0x57, 0x3A, 0x3E, 0x1D, 0x91, 0xE5, 0xEB}; + thread_local EncryptedName format(source); + _snprintf(text, sizeof(text), format.Text(), adapter->Address[0], adapter->Address[1], adapter->Address[2], + adapter->Address[3], adapter->Address[4], adapter->Address[5]); + delete[] reinterpret_cast(adapter); + return text; + } + } + + const std::uint8_t source[] = {0xF0, 0x76, 0xE8, 0x25, 0xD3, 0xB4, 0xE6, 0xC8, 0xEC, 0x73, 0xF1, 0x3A, 0xD4, 0xAC, 0xF8, 0xCD, + 0xF7, 0x47}; + thread_local EncryptedName fallback(source); + return fallback.Text(); +} + // OFFSET: 0x00D8E700 // FUNCTION: fn_22272 int CLoginMode::GetMaxCharacterSlot() { @@ -408,6 +452,66 @@ void CLoginMode::ReceiveCharacterResult(const CharacterResultPacket* packet, Win } } +// OFFSET: 0x00D8F040 +// FUNCTION: fn_22278 +void CLoginMode::ReceiveCharacterPage(const CharacterPagePacket* packet) { + const unsigned int count = (packet->length - 4) / sizeof(CharacterInfo); + if ((packet->length - 4) % sizeof(CharacterInfo) != 0) { + char text[256]; + memset(text, 0, sizeof(text)); + const std::uint8_t source[] = {0x4C, 0x07, 0x04, 0xFD, 0xDC, 0x06, 0xCD, 0x46, 0x5D, 0x10, 0x0C, 0xE1, 0xDB, 0x0A, 0xAB, 0x23, + 0x7C, 0x26, 0x3F, 0xCA, 0xBD, 0x20, 0xEB, 0x71, 0x60, 0x3D, 0x64, 0x8E, 0xBD, 0x06, 0xD1, 0x42, + 0x5D, 0x0E, 0x06, 0xFB, 0xD8, 0x17, 0xC6, 0x4A, 0x41, 0x09, 0x0A, 0x9D, 0xBD, 0x36, 0xF0, 0x79, + 0x6A, 0x6F, 0x7F, 0x8F, 0xB8, 0x21, 0x99}; + thread_local EncryptedName format(source); + StringFormat(text, sizeof(text), static_cast(-1), format.Text(), sizeof(CharacterInfo)); + reinterpret_cast(&g_windowMgr)->Confirm(text, 0, true, true, 0, "Message", 280, 120, 0); + return; + } + + const unsigned int total = this->unknown_01D8 + count; + if (total > 68) { + char text[256]; + memset(text, 0, sizeof(text)); + const std::uint8_t source[] = {0xE8, 0xE7, 0xCC, 0xDF, 0xF2, 0xCE, 0xF3, 0x90, 0xF9, 0xF0, 0xC4, 0xC3, 0xF5, 0xC2, 0x95, 0xF5, + 0xE8, 0xC1, 0xF9, 0xAD, 0xFC, 0xFB, 0xC2, 0xA7, 0x8B, 0x8A, 0xE9, 0xAD, 0x9C, 0xAD, 0x82, 0xB1, + 0xAB}; + thread_local EncryptedName format(source); + StringFormat(text, sizeof(text), static_cast(-1), format.Text(), total, 68); + reinterpret_cast(&g_windowMgr)->Confirm(text, 0, true, true, 0, "Message", 280, 120, 0); + return; + } + + memcpy_s(&this->characters[this->unknown_01D8], sizeof(this->characters) - this->unknown_01D8 * sizeof(CharacterInfo), + packet->characters, count * sizeof(CharacterInfo)); + __time32_t now; + _time32(&now); + for (int i = 0; i < static_cast(count); ++i) { + if (this->characters[this->unknown_01D8 + i].sex == 99) { + this->characters[this->unknown_01D8 + i].sex = g_session.unknown_0E9C[0]; + } + if (this->characters[this->unknown_01D8 + i].deleteDate != 0) { + this->characters[this->unknown_01D8 + i].deleteDate += now; + } + CharacterInfo& character = this->characters[this->unknown_01D8 + i]; + this->characters[this->unknown_01D8 + i].bodyStyle = + static_cast(g_session.GetBodyStyle(character.job, character.bodyStyle, character.unknown_0058)); + } + + this->unknown_01D8 += count; + if (count != 3) { + this->characterCount = this->unknown_01D8; + g_session.unknown_59BC = this->unknown_01D8; + this->unknown_01D8 = 0; + this->characterDeleted = false; + for (long long i = 0; i < this->characterCount; ++i) { + char* mapName = this->characters[i].mapName; + StringFormat(mapName, sizeof(this->characters[i].mapName), static_cast(-1), "%s", g_session.GatName2RswName(mapName)); + } + this->pendingCursorType = 7; + } +} + // OFFSET: 0x00D8F560 // FUNCTION: fn_22279 void CLoginMode::SubD8F560(int) { @@ -667,6 +771,103 @@ bool sub_D92B70() { void nullsub_486(int) { } +// OFFSET: 0x00D92DA0 +// FUNCTION: fn_22295 +void CLoginMode::ReceiveRefuseLogin(const RefuseLoginPacket* packet) { + char text[260]; + memset(text, 0, sizeof(text)); + { + const char* message = LookupMessage(3202); + const std::uint8_t source[] = {0x40, 0x6A, 0x45}; + thread_local EncryptedName format(source); + StringFormat(text, sizeof(text), static_cast(-1), format.Text(), message); + } + + switch (packet->result) { + case 1: { + const char* message = LookupMessage(3196); + const std::uint8_t source[] = {0x9C, 0x76, 0x77}; + thread_local EncryptedName format(source); + StringFormat(text, sizeof(text), static_cast(-1), format.Text(), message); + break; + } + case 2: { + const char* message = LookupMessage(3197); + const std::uint8_t source[] = {0x50, 0xBE, 0xED}; + thread_local EncryptedName format(source); + StringFormat(text, sizeof(text), static_cast(-1), format.Text(), message); + break; + } + case 3: { + const char* message = LookupMessage(3198); + const std::uint8_t source[] = {0xD8, 0xCA, 0xBB}; + thread_local EncryptedName format(source); + StringFormat(text, sizeof(text), static_cast(-1), format.Text(), message); + break; + } + case 4: { + const char* message = LookupMessage(3199); + const std::uint8_t source[] = {0xD8, 0xA4, 0x4D}; + thread_local EncryptedName format(source); + StringFormat(text, sizeof(text), static_cast(-1), format.Text(), message); + break; + } + case 5: { + const char* message = LookupMessage(3200); + const std::uint8_t source[] = {0x4E, 0xCA, 0xC7}; + thread_local EncryptedName format(source); + StringFormat(text, sizeof(text), static_cast(-1), format.Text(), message); + break; + } + case 6: { + const char* message = LookupMessage(3201); + const std::uint8_t source[] = {0xAA, 0xEA, 0xEB}; + thread_local EncryptedName format(source); + StringFormat(text, sizeof(text), static_cast(-1), format.Text(), message); + break; + } + case 7: { + const char* message = LookupMessage(3214); + const std::uint8_t source[] = {0xB2, 0x82, 0xE1}; + thread_local EncryptedName format(source); + StringFormat(text, sizeof(text), static_cast(-1), format.Text(), message); + break; + } + case 8: + case 100: + case 102: { + const char* message = LookupMessage(3202); + const std::uint8_t source[] = {0xE8, 0x82, 0x99}; + thread_local EncryptedName format(source); + StringFormat(text, sizeof(text), static_cast(-1), format.Text(), message); + break; + } + case 9: { + const char* message = LookupMessage(3911); + const std::uint8_t source[] = {0x5A, 0x66, 0x8D}; + thread_local EncryptedName format(source); + StringFormat(text, sizeof(text), static_cast(-1), format.Text(), message); + break; + } + case 101: { + char blockDate[21] = {}; + memcpy_s(blockDate, 20, packet->blockDate, 20); + StringFormat(text, sizeof(text), static_cast(-1), LookupMessage(449), blockDate); + break; + } + default: + break; + } + + GetRagConnection().Close(); + const int result = packet->result; + const std::uint8_t source[] = {0xBE, 0x24, 0x2B, 0xBC, 0x03, 0x2C, 0x05}; + thread_local EncryptedName format(source); + reinterpret_cast(&g_windowMgr)->Confirm(FormatString(format.Text(), text, result), 0, true, false, 0, "Message", 280, 120, 0); + g_charServerAccountIdPending = 0; + this->pendingCursorType = 3; +} + // OFFSET: 0x00D93B10 // FUNCTION: fn_22296 void nullsub_487(int) {