rodecomp/Source/Contents/Configuration/ServiceConfiguration.cpp
ragnarok-clanker c8cd69a8bf Maintenance: direct admin merge of fn_17817 sub_AD1C90 (0xAD1C90), protector-damaged
Merged directly by the admin, bypassing peer review, because part of the
original function was overwritten by the client's protector and can never
match. Task 16009 is marked done on purpose; do not resubmit it.

- Jump table 0xAD29E4: modes 0/1 go to 0xAD1E58, now "jmp 0x027AB0FE" into
  an empty protector stub. Bytes 0xAD1E58..0xAD237D are garbage.
- The rest of case 0/1 survives from 0xAD237E (g_serviceFlag07 = 29,
  strstr(g_launchServerName, "QmSakray"), key/address pair, StringFormat
  into g_serviceAddress, then the admin/monster-job tail); ported as is.
- Live WinDbg run (servertype=primary): 0xAD1C90 is never called; the
  protector loader in .data6 (sub_3DE8027) replaces it at runtime.
- Based on attempt 57915 (batch 10359), with g_session.unknown_58FA replaced
  by g_launchServerName (same address, 0x1737F32). Key/string decryption
  verified against the binary. td check --includers: no errors.
2026-11-03 21:39:07 +00:00

691 lines
26 KiB
C++

#include "Client/Input/InputCharset.h"
#include "Client/Input/LanguageTC.h"
#include "Contents/Configuration/ServiceConfiguration.h"
#include "Archive/PakRegistry.h"
#include "Client/Application/ErrorDialog.h"
#include "Client/Registry.h"
#include "Client/Session.h"
#include "Contents/MapSkyMgr.h"
#include "File/CommonObject.h"
#include "File/File.h"
#include "File/ResourcePath.h"
#include "Network/TextEncoding.h"
#include "Render/DeviceContext/DCSurface.h"
#include "Resource/Bitmap/BitmapResource.h"
#include "Resource/ResourceMgr.h"
#include "Resource/XmlNode.h"
#include "UI/Text/UIBalloonText.h"
#include "Utility/Text/TextTokens.h"
#include "Utility/Cipher/XorBytes.h"
#include "Utility/Text/FormatString.h"
#include "UI/Window/UILoginWnd.h"
#include <cstddef>
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iterator>
#include <string>
#include <vector>
#include <windows.h>
// GLOBAL: gl_24542
signed char g_language = 0;
// GLOBAL: gl_24544
CLanguageBase* g_serverLanguage;
// GLOBAL: gl_24972
unsigned char g_startupSecondPhase;
// GLOBAL: gl_24760
bool g_serviceFlag05;
// GLOBAL: gl_24761
bool g_serviceFlag06;
// GLOBAL: gl_24529
int g_serviceType = 0;
// GLOBAL: gl_24968
const char* g_licenceFileName = "";
// GLOBAL: gl_24969
const char* g_clientExeName = "";
// GLOBAL: gl_24970
const char* g_patcherExeName = "";
// GLOBAL: gl_24971
const char* g_runPatcherMessage = "";
// GLOBAL: gl_21921
const char* g_windowName = "";
// GLOBAL: gl_24669
const char* g_serviceHost = "";
// GLOBAL: gl_24670
const char* g_servicePort = "";
// GLOBAL: gl_24671
const char* g_serviceOverrideKey = "";
// GLOBAL: gl_24974
char g_launchServerName[24];
// GLOBAL: gl_25024
std::vector<std::string> g_loadingScreens;
// GLOBAL: gl_25276
bool g_hideAccountList;
// GLOBAL: gl_25277
bool g_extendedSlot;
// GLOBAL: gl_25278
bool g_readFolder;
// GLOBAL: gl_25279
bool g_clientInfoLoaded;
// GLOBAL: gl_25280
char g_homepageUrl[256];
// GLOBAL: gl_25364
int g_serviceFlag07;
// GLOBAL: gl_25365
char g_serviceAddress[129];
// GLOBAL: gl_25366
const int s_adminIds[45] = {
100118, 4663634, 4663643, 4663644, 4663633, 4663642, 4663649, 4663632, 4663638, 4663645,
9100774, 9100775, 9100776, 9100777, 9100720, 9100721, 9100722, 9100723, 9100778, 9100724,
9100725, 9100726, 9100727, 9100728, 9100729, 9100730, 9100731, 9100732, 9100733, 9100779,
9100780, 9100734, 9100781, 9100782, 9100783, 9100784, 9100785, 9100786, 9100787, 9100788,
9100789, 9100790, 9100791, 9100792, 9100793
};
// GLOBAL: gl_25367
const int s_monsterJobIds[48] = {
100118, 3304363, 3304378, 3304372, 4663634, 4663643, 4663644, 4663633, 4663642, 4663649,
4663632, 4663638, 4663645, 9100774, 9100775, 9100776, 9100777, 9100720, 9100721, 9100722,
9100723, 9100778, 9100724, 9100725, 9100726, 9100727, 9100728, 9100729, 9100730, 9100731,
9100732, 9100733, 9100779, 9100780, 9100734, 9100781, 9100782, 9100783, 9100784, 9100785,
9100786, 9100787, 9100788, 9100789, 9100790, 9100791, 9100792, 9100793
};
template <std::size_t Length, std::uint64_t Key>
class EncryptedText {
public:
explicit EncryptedText(const std::uint8_t (&source)[Length]) : m_encrypted(true) {
for (std::uint64_t index = 0; index < Length; ++index) {
this->m_text[index] = source[index];
}
}
~EncryptedText() {
for (std::uint64_t index = 0; index < Length; ++index) {
this->m_text[index] = 0;
}
}
const char* Text() {
if (this->m_encrypted) {
utility::XorBytes(this->m_text, Length, Key);
this->m_encrypted = false;
}
return reinterpret_cast<const char*>(this->m_text);
}
private:
/* 0000 */ std::uint8_t m_text[Length];
bool m_encrypted;
};
// INLINED
template <std::uint64_t Key, std::size_t Length>
const char* DecryptText(const std::uint8_t (&source)[Length]) {
thread_local EncryptedText<Length, Key> text(source);
return text.Text();
}
// OFFSET: 0x00ACFCF0
// FUNCTION: fn_17807
const char* GetLicenceText() {
// GLOBAL: gl_24973
static std::string text;
if (text.empty()) {
CFile file;
if (file.Open(g_licenceFileName, 0, true, false)) {
text.assign(static_cast<const char*>(file.GetData()), file.GetSize());
file.Close();
} else {
const std::uint8_t source[] = {0x25, 0x64, 0x85, 0x80, 0xD2, 0x91, 0xEC, 0x9D, 0x1F, 0x6E, 0xDD, 0xB1, 0xA7, 0xBB, 0xC4, 0xD1, 0x0E,
0x25, 0x85, 0xED, 0xEB, 0xB4, 0xCE, 0xD8, 0x05, 0x68, 0xC0, 0xEB, 0xF3, 0xA5, 0xD9, 0x94, 0x6B};
text = DecryptText<0xBDADDD87C5A50B6BULL>(source);
}
}
return text.c_str();
}
void sub_AD1270();
void InitializeLanguage();
// OFFSET: 0x00ACFF90
// FUNCTION: fn_17808
void InitializeServiceStrings() {
sub_AD1270();
switch (g_serviceType) {
case 0:
case 1:
case 2:
case 3:
case 4:
case 5:
case 6:
case 7:
case 8:
case 9:
case 10:
case 11:
case 12:
case 13:
case 14:
case 15:
case 17:
case 18:
case 19:
case 20:
break;
default: {
const std::uint8_t source[] = {0x5C, 0xC7, 0x2C, 0x31, 0xB6, 0x2A, 0x1B, 0xF3, 0x5A, 0xCC, 0x35, 0x29,
0xB0, 0x3E, 0x10, 0x87, 0x70, 0xD9, 0x22, 0x7F, 0xF8, 0x7C, 0x54, 0xD3};
ShowErrorDialog(GetRenderSystemHolder()->system, DecryptText<0xD3755DD95F47A909ULL>(source), 0);
break;
}
}
InitializeLanguage();
if (g_serviceType == 0 || g_serviceType == 6) {
g_nameBalloonFontHeight = 13;
g_serviceFlag05 = true;
} else {
g_nameBalloonFontHeight = 12;
g_serviceFlag05 = false;
}
g_serviceFlag06 = g_serviceFlag05;
SYSTEMTIME time;
GetLocalTime(&time);
{
const std::uint8_t source[] = {0x63, 0x0B, 0xC5, 0x25, 0x3A, 0x20, 0xE4, 0x69, 0x2E, 0x40, 0xB7, 0x3D, 0x2B, 0x37, 0x81};
g_licenceFileName = DecryptText<0x078143534999254DULL>(source);
}
g_startupSecondPhase = static_cast<unsigned char>(time.wSecond) & 3;
{
const std::uint8_t source[] = {0xD6, 0x0E, 0xED, 0x63, 0x08, 0x00, 0xD7, 0xCA, 0xD9, 0x26, 0xF9, 0x76, 0x09, 0x08, 0xD1, 0xD6,
0xA5, 0x32, 0xE4, 0x71, 0x0B, 0x3D, 0xF7, 0xCE, 0xE2, 0x0F, 0xEA, 0x65, 0x10, 0x0A, 0xA5};
g_subKey = DecryptText<0xAFA5617F178B6185ULL>(source);
}
{
const std::uint8_t source[] = {0xBB, 0xB2, 0x5A, 0x69, 0x54, 0x5B, 0x64, 0x8E, 0xE9};
g_windowName = DecryptText<0xE50B2935073DD3E9ULL>(source);
}
switch (g_serviceMode) {
case 2: {
const std::uint8_t client[] = {0x59, 0xD4, 0xEE, 0x5C, 0x67, 0xD3, 0xF6, 0xAC, 0x79, 0x9B, 0xEC, 0x6D, 0x6C, 0xB7};
g_clientExeName = DecryptText<0xC399B7091589B50BULL>(client);
const std::uint8_t patcher[] = {0x50, 0x03, 0xAB, 0x90, 0x32, 0x73, 0xB4, 0x0F, 0x37, 0x08, 0xB7, 0x9A, 0x5D};
g_patcherExeName = DecryptText<0x7FC1015DFFCF6D19ULL>(patcher);
const std::uint8_t message[] = {0x69, 0x8D, 0xCC, 0x8E, 0x92, 0xC2, 0x73, 0x75, 0x4C, 0x8F, 0x89, 0xBD, 0x80,
0xC0, 0x1A, 0x69, 0x5D, 0x8E, 0xC6, 0x9D, 0xCF, 0xC2, 0x2B, 0x62, 0x39};
g_runPatcherMessage = DecryptText<0x0753A7E1EFA9E139ULL>(message);
break;
}
case 3: {
const std::uint8_t client[] = {0x1F, 0xB0, 0xAC, 0x80, 0x8C, 0x1E, 0xA1, 0x1B, 0x63, 0xB4, 0xB3, 0xA2, 0xF9};
g_clientExeName = DecryptText<0x7FCD77F9C7CBD14DULL>(client);
const std::uint8_t patcher[] = {0x64, 0xF6, 0xB2, 0xEF, 0x25, 0xC8, 0x4F, 0xE5, 0x46, 0xFB, 0xBE, 0x83};
g_patcherExeName = DecryptText<0xCB3FBD4183DB8323ULL>(patcher);
const std::uint8_t message[] = {0xBF, 0x4F, 0xB0, 0x8E, 0x6A, 0x34, 0xB1, 0x49, 0x9A, 0x4D, 0xF5, 0xBD,
0x78, 0x36, 0xD6, 0x4E, 0x86, 0x4F, 0xB1, 0xC1, 0x7C, 0x29, 0xF4, 0x3B};
g_runPatcherMessage = DecryptText<0x3B915119EFD523EFULL>(message);
break;
}
default: {
const std::uint8_t dev[] = {0xEB, 0x2A, 0x5D, 0xE3};
if (std::strstr(g_launchServerName, DecryptText<0x3F5315DFE32B4FAFULL>(dev))) {
const std::uint8_t client[] = {0xED, 0xDC, 0xB8, 0x51, 0x2C, 0x5F, 0xEC, 0x58, 0xEE, 0xF0, 0xF1, 0x5A, 0x35, 0x48, 0x83};
g_clientExeName = DecryptText<0x33832D4D3FDFBDBFULL>(client);
const std::uint8_t patcher[] = {0xA1, 0xA2, 0x9D, 0xDE, 0xC5, 0x78, 0x05, 0x2C, 0xBC, 0xED, 0x8C, 0xC5, 0xC8, 0x0D};
g_patcherExeName = DecryptText<0x7D750DADBDE9C3F1ULL>(patcher);
const std::uint8_t message[] = {0x45, 0xFF, 0xD6, 0xA0, 0x94, 0x26, 0x71, 0x9F, 0x60, 0xFD, 0x93, 0x93, 0x86,
0x24, 0x3F, 0x8C, 0x67, 0xFC, 0xD8, 0x90, 0xAA, 0x6D, 0x34, 0x95, 0x70, 0x93};
g_runPatcherMessage = DecryptText<0xED5143E7C1B39315ULL>(message);
} else {
const std::uint8_t client[] = {0x8B, 0x58, 0x74, 0x17, 0xAA, 0xF1, 0x12, 0x94, 0xF7, 0x5C, 0x6B, 0x1C, 0xCB};
g_clientExeName = DecryptText<0xFF7D83CB791339D9ULL>(client);
const std::uint8_t patcher[] = {0xC5, 0x9C, 0x65, 0xD0, 0x39, 0x10, 0xE5, 0x1F, 0xF0, 0x85, 0x74, 0xB3};
g_patcherExeName = DecryptText<0x31956551B311FD95ULL>(patcher);
const std::uint8_t message[] = {0xC1, 0xAF, 0xD8, 0x00, 0x16, 0xF4, 0x1D, 0x4B, 0xE4, 0xAD, 0x9D, 0x33,
0x04, 0xF6, 0x53, 0x58, 0xE3, 0xAC, 0xD6, 0x4F, 0x00, 0xE9, 0x58, 0x39};
g_runPatcherMessage = DecryptText<0x393D916561BDC391ULL>(message);
}
break;
}
}
}
// OFFSET: 0x00AD0F60
// FUNCTION: fn_17809
void LoadLoadingScreens(int count) {
if (count == 0) {
switch (g_serviceType) {
case 0:
count = 7;
break;
case 1:
case 15:
count = 12;
break;
case 3:
count = 4;
break;
case 5:
case 7:
count = 8;
break;
case 6:
count = 9;
break;
default:
count = 1;
break;
}
}
for (int index = 0; index < count; ++index) {
const std::uint8_t source[] = {0x7D, 0x32, 0xFB, 0x1D, 0xCD, 0x4D, 0x4C, 0xB4, 0x7B, 0x79, 0xFB, 0x2B, 0xB0, 0x39, 0xD5, 0x15,
0xD2, 0xFC, 0x5F, 0x8E, 0x63, 0xE4, 0xAC, 0x49, 0x8F, 0xF9, 0x15, 0x8D, 0x7D, 0xE4, 0x89};
char name[256];
std::sprintf(name, DecryptText<0x7989830DE73B9DBDULL>(source), index);
if (ResourceMgr::Instance().Exists(name)) {
g_loadingScreens.push_back(std::string(name));
}
}
}
// OFFSET: 0x00AD1270
// FUNCTION: fn_17810
void sub_AD1270() {
if (ResourceExists("etcinfo.txt", 0)) {
CCommonObject storage;
g_loadingScreens.clear();
std::vector<char*> tokens;
storage.LoadTokens(tokens, "etcinfo.txt", 0);
for (auto token = tokens.begin(); token != tokens.end(); ++token) {
if (std::strcmp(*token, "loadingscreen") == 0) {
const int count = std::atoi(token[1]);
if (count > 0) {
LoadLoadingScreens(count);
}
} else if (std::strcmp(*token, "event") == 0) {
if (std::atoi(token[1]) > 0) {
g_pakRegistry.Add("event.grf");
}
} else if (std::strcmp(*token, "weather") == 0) {
std::string mapName(token[1]);
token += 2;
std::string weather(*token);
LowercaseText(mapName);
LowercaseText(weather);
g_weatherEffect.AddMapWeather(mapName, weather);
}
}
}
if (g_loadingScreens.empty()) {
LoadLoadingScreens(0);
}
}
// OFFSET: 0x00AD1780
// FUNCTION: fn_17811
void InitializeLanguage() {
// GLOBAL: gl_25359
static CLanguageBase defaultCharset;
// GLOBAL: gl_25360
static CLanguageTC traditionalChineseCharset;
// GLOBAL: gl_25361
static CLanguageTH thaiCharset;
// GLOBAL: gl_25362
static CLanguageArabic arabicCharset;
switch (g_serviceType) {
case 0:
g_language = 0;
g_textCodePage = 949;
g_serverLanguage = &defaultCharset;
break;
case 2:
g_language = 2;
g_textCodePage = 932;
g_serverLanguage = &defaultCharset;
break;
case 3:
g_language = 3;
g_serverLanguage = &traditionalChineseCharset;
g_textCodePage = 936;
break;
case 4:
g_language = 4;
g_serverLanguage = &traditionalChineseCharset;
g_textCodePage = 950;
break;
case 5:
g_language = 5;
g_serverLanguage = &thaiCharset;
g_textCodePage = 874;
break;
case 10:
g_language = 1;
g_inlineCharset = 1;
g_textCodePage = 0;
g_serverLanguage = &defaultCharset;
break;
case 11:
g_language = 1;
g_inlineCharset = 0;
g_textCodePage = 0;
g_serverLanguage = &defaultCharset;
break;
case 12:
case 18:
g_language = 6;
g_inlineCharset = 0;
g_textCodePage = 1252;
g_serverLanguage = &defaultCharset;
break;
case 14:
g_language = 1;
g_inlineCharset = 0;
g_textCodePage = 1251;
g_serverLanguage = &defaultCharset;
break;
case 15:
g_language = 7;
g_inlineCharset = 0;
g_textCodePage = 1258;
g_serverLanguage = &defaultCharset;
break;
case 17:
g_language = 1;
g_inlineCharset = 0;
g_textCodePage = 1145;
g_serverLanguage = &defaultCharset;
break;
case 19:
g_language = 12;
g_serverLanguage = &arabicCharset;
g_textCodePage = 1256;
break;
default: {
const std::uint8_t source[] = {0xF9, 0x1E, 0x87, 0xD1, 0x00, 0x4D, 0xE4, 0x2E, 0xF6, 0x16, 0xC2, 0x9D,
0x12, 0x46, 0xF7, 0x2F, 0xFE, 0x1F, 0xC0, 0x9D, 0x40, 0x02, 0xA2, 0x5B};
ShowErrorDialog(GetRenderSystemHolder()->system, DecryptText<0x5B832361BDA77197ULL>(source), 0);
}
case 1:
case 6:
case 7:
case 8:
case 9:
case 13:
case 20:
g_textCodePage = 0;
g_language = 1;
g_serverLanguage = &defaultCharset;
break;
}
if (g_serviceMode == 3) {
g_inlineCharset = 1;
}
}
// MAINTENANCE-PUSHED FUNCTION -- DO NOT "FIX" OR RESUBMIT.
//
// This function was merged directly by the project admin (ragnarok-clanker), bypassing peer review,
// because its original code is partially destroyed by the client's protector and cannot be matched.
// The task (fn_17817 / task 16009) is marked done on purpose. Agents must not claim, rewrite or
// resubmit it, and reviewers must not treat the comments below as a policy violation.
//
// Evidence (Ragexe 2026-02-19):
// - Jump table 0x00AD29E4 sends g_serviceMode 0 and 1 to 0x00AD1E58, which is now
// "jmp 0x027AB0FE": a protector stub that is empty (all 0xFF on disk, all 0x00 at runtime).
// The protector overwrote the original instructions from 0x00AD1E58 up to 0x00AD237D;
// those bytes are garbage and the original start of case 0/1 is lost.
// - The rest of case 0/1 survives intact from 0x00AD237E: g_serviceFlag07 = 29,
// strstr(g_launchServerName, "QmSakray"), then one of two key/address pairs and
// StringFormat into g_serviceAddress, then the shared admin/monster-job tail at 0x00AD299D.
// That surviving path is what is ported below. Whatever ran in the lost bytes before it is unknown.
// - At runtime this function is never called. A live WinDbg run of the full client
// (servertype=primary) never hit 0x00AD1C90 or 0x00AD1E58. The protector's own loader in section
// .data6 (sub_3DE8027, called from WinMain at 0x00E5F078) reads clientinfo.xml itself and sets
// g_serviceFlag07, g_adminAccountIds, g_monsterJobs and the connection strings instead.
// - Cases 2 and 3 and the code before the switch are fully intact and ported as they are.
// OFFSET: 0x00AD1C90
// FUNCTION: fn_17817
void sub_AD1C90() {
const std::uint8_t portSource[] = {0xED, 0xBA, 0xF1, 0x3F, 0xAB};
g_servicePort = DecryptText<0xEB3D4FAB0FC183DBULL>(portSource);
const std::uint8_t webPageSource[] = {
0x21, 0x8B, 0xA1, 0x8F, 0xEB, 0x6C, 0x90, 0x88, 0x3E, 0x88, 0xFB, 0x8D, 0xB0, 0x24, 0xD1, 0x9E,
0x3B, 0x90, 0xBE, 0xD1, 0xB2, 0x2C, 0x91, 0x94, 0x3B, 0xFF
};
g_webPageUrl = DecryptText<0xFFBF43D1FFD5FF49ULL>(webPageSource);
g_extendedSlot = true;
g_serviceOverrideKey = "";
g_adminAccountIds.clear();
g_monsterJobs.clear();
switch (g_serviceMode) {
case 0:
case 1: {
// Original instructions between 0x00AD1E58 and 0x00AD237D were overwritten by the protector
// (jump into the empty stub 0x027AB0FE). The code from here on starts at 0x00AD237E.
g_serviceFlag07 = 29;
if (std::strstr(g_launchServerName, "QmSakray")) {
const std::uint8_t keySource[] = {
0x3C, 0x83, 0xDA, 0xE6, 0x72, 0x9C, 0xCE, 0x77, 0x36, 0xDF, 0xC7, 0xAA, 0x64, 0x9F, 0x82, 0x37,
0x38, 0x9A, 0x9B, 0xA8, 0x6C, 0xDF, 0x88, 0x37, 0x6D, 0xC7, 0x8C, 0xFB, 0x33, 0xF1
};
g_serviceOverrideKey = DecryptText<0x45E3F103CBB5F157ULL>(keySource);
const std::uint8_t addressSource[] = {
0xB4, 0x35, 0xC2, 0x4A, 0x6E, 0x14, 0x1E, 0x1C, 0xBE, 0x69, 0xDF, 0x06, 0x78, 0x17, 0x52, 0x5F,
0xB0, 0x2C, 0x83, 0x04, 0x70, 0x57, 0x58, 0x5F, 0xE5, 0x71, 0x94, 0x52, 0x2E, 0x79
};
const std::uint8_t formatSource[] = {0xAC, 0x4E, 0x6D};
StringFormat(g_serviceAddress, sizeof(g_serviceAddress), static_cast<std::size_t>(-1), DecryptText<0x2F2701A7E56D3D89ULL>(formatSource), DecryptText<0x2D33791F67AD47DFULL>(addressSource));
} else {
const std::uint8_t keySource[] = {
0x4E, 0xE3, 0x68, 0x8E, 0x80, 0x62, 0x50, 0x58, 0x0B, 0xE3, 0x66, 0xC4, 0x8F, 0x60, 0x41, 0x04,
0x4E, 0xBF, 0x64, 0xCC, 0xCF, 0x6A, 0x41, 0x51, 0x13, 0xA8, 0x37, 0x93, 0xE1
};
g_serviceOverrideKey = DecryptText<0x6B3301E1A3079125ULL>(keySource);
const std::uint8_t addressSource[] = {
0x08, 0x4B, 0x12, 0x8C, 0x38, 0xD2, 0xFA, 0xAD, 0x00, 0x40, 0x50, 0xD2, 0x77, 0xC7, 0xFE, 0xA4,
0x0D, 0x58, 0x0F, 0xCE, 0x32, 0x9B, 0xFC, 0xAC, 0x4D, 0x52, 0x0F, 0x9B, 0x6F, 0x8C, 0xAA, 0xF7,
0x63
};
const std::uint8_t formatSource[] = {0xAC, 0x4E, 0x6D};
StringFormat(g_serviceAddress, sizeof(g_serviceAddress), static_cast<std::size_t>(-1), DecryptText<0x2F2701A7E56D3D89ULL>(formatSource), DecryptText<0xC39FB559A17D3963ULL>(addressSource));
}
g_adminAccountIds.assign(std::begin(s_adminIds), std::end(s_adminIds));
g_monsterJobs.assign(std::begin(s_monsterJobIds), std::end(s_monsterJobIds));
break;
}
case 2: {
g_serviceFlag07 = 14;
const std::uint8_t hostSource[] = {0x9E, 0x98, 0xF7, 0x19, 0x26, 0x5F, 0x8F, 0x5F, 0x9A, 0x8F, 0xF0, 0x05, 0x17};
g_serviceHost = DecryptText<0x71B7691737C5A1AFULL>(hostSource);
break;
}
case 3: {
const std::uint8_t hostSource[] = {
0x3F, 0x6A, 0x58, 0xAD, 0x8A, 0x26, 0xAF, 0xA7, 0x3F, 0x6F, 0x5E, 0xAD, 0x8A, 0x20, 0xA8, 0x89
};
g_serviceHost = DecryptText<0x899D11BB83695B0DULL>(hostSource);
g_serviceFlag07 = 29;
const std::uint8_t portSource[] = {0xC3, 0x1C, 0x63, 0xD9, 0xD7};
g_servicePort = DecryptText<0x2B8725D7E95325F5ULL>(portSource);
g_adminAccountIds.assign(std::begin(s_adminIds), std::end(s_adminIds));
g_monsterJobs.assign(std::begin(s_monsterJobIds), std::end(s_monsterJobIds));
break;
}
default:
break;
}
}
// OFFSET: 0x00AD2A00
// FUNCTION: fn_17818
void ReadClientInfo(XmlNode* clientInfo) {
XmlNode* serviceType =
clientInfo->FindChild(DecryptText<0x5B8F49AF09390D1BULL>({0x68, 0x68, 0x4B, 0x7F, 0xC6, 0x2A, 0xEA, 0x2F, 0x62, 0x7D, 0x5C, 0x09}));
if (serviceType) {
if (serviceType->Text() == std::string(DecryptText<0x3F557BE333F95F6DULL>({0x06, 0x30, 0x8B, 0x56, 0x82, 0x7B}))) {
g_serviceType = 0;
} else if (serviceType->Text() == std::string(DecryptText<0x474DC581D5E98357ULL>({0x36, 0xEE, 0x8C, 0xA7, 0xE8, 0xA6, 0x2C, 0x47}))) {
g_serviceType = 1;
} else if (serviceType->Text() == std::string(DecryptText<0x01FF9313695DD9DFULL>({0xB5, 0xB8, 0x2D, 0x08, 0x7D, 0x93}))) {
g_serviceType = 2;
} else if (serviceType->Text() == std::string(DecryptText<0x1BF915E1F37DFDFDULL>({0x9E, 0x95, 0x14, 0x9D, 0x80, 0x15}))) {
g_serviceType = 3;
} else if (serviceType->Text() == std::string(DecryptText<0x49C3759B77DBD3C1ULL>({0xB5, 0xB2, 0xB2, 0x00, 0xFA, 0x1B, 0xC3}))) {
g_serviceType = 4;
} else if (serviceType->Text() == std::string(DecryptText<0x6DED3DD1CF75AD9BULL>({0xEF, 0xC5, 0x14, 0xA6, 0xD1}))) {
g_serviceType = 5;
} else if (serviceType->Text() ==
std::string(DecryptText<0x91E147EBBD47C39FULL>({0xF6, 0xAD, 0x23, 0xD2, 0x85, 0x22, 0x92, 0xF8, 0xFE, 0xC3}))) {
g_serviceType = 6;
} else if (serviceType->Text() ==
std::string(DecryptText<0xD1538513DF975701ULL>({0x71, 0x3F, 0xFE, 0xB3, 0x7A, 0xF5, 0x23, 0xB8, 0x6F, 0x32, 0x97}))) {
g_serviceType = 7;
} else if (serviceType->Text() ==
std::string(DecryptText<0xA1A55B4D1597EDD3ULL>({0xBE, 0x8C, 0xFB, 0x74, 0x34, 0x28, 0xCC, 0xC0, 0xD3}))) {
g_serviceType = 8;
} else if (serviceType->Text() ==
std::string(DecryptText<0x4F1791FB1503C713ULL>({0x60, 0xAE, 0x6D, 0x72, 0x9A, 0xE1, 0x78, 0x3D, 0x76, 0xC7}))) {
g_serviceType = 9;
} else if (serviceType->Text() ==
std::string(DecryptText<0x7D993F650D2785FFULL>({0x98, 0xE0, 0x55, 0x60, 0x04, 0x51, 0xE0, 0x7D}))) {
g_serviceType = 10;
} else if (serviceType->Text() == std::string(DecryptText<0x61FF87ED7BF39BE1ULL>({0x88, 0xF5, 0x97, 0x12, 0x8C, 0x87}))) {
g_serviceType = 11;
} else if (serviceType->Text() == std::string(DecryptText<0x151F77EBEBBB2147ULL>({0x25, 0x53, 0xDA, 0x91, 0x82, 0x1B, 0x1F}))) {
g_serviceType = 12;
} else if (serviceType->Text() ==
std::string(DecryptText<0x2D394DBD0F332733ULL>({0x52, 0x52, 0x40, 0x7B, 0xCF, 0x2C, 0x55, 0x44, 0x52, 0x27}))) {
g_serviceType = 13;
} else if (serviceType->Text() == std::string(DecryptText<0x69D345DB950F336DULL>({0x1F, 0x46, 0x7C, 0xE6, 0xB2, 0x24, 0xD3}))) {
g_serviceType = 14;
} else if (serviceType->Text() ==
std::string(DecryptText<0xC7912587FFF31B71ULL>({0x07, 0x72, 0x96, 0x8B, 0xE9, 0x44, 0xFC, 0xC7}))) {
g_serviceType = 15;
} else if (serviceType->Text() == std::string(DecryptText<0x2D3B15774149D5DDULL>({0xBE, 0xBD, 0x20, 0x2D, 0x12, 0x15}))) {
g_serviceType = 17;
} else if (serviceType->Text() == std::string(DecryptText<0x9B17C9EFDBB39F2FULL>({0x49, 0xED, 0xD2, 0xB5, 0x8C, 0xAC, 0x17}))) {
g_serviceType = 18;
} else if (serviceType->Text() == std::string(DecryptText<0x0BEB63A5C905B3A7ULL>({0xD2, 0xD2, 0x60, 0xC9}))) {
g_serviceType = 19;
} else if (serviceType->Text() == std::string(DecryptText<0x8B3FEB5B8BD5C3C3ULL>({0xA6, 0xB6, 0xD5}))) {
g_serviceType = 20;
} else {
ShowErrorDialog(GetRenderSystemHolder()->system,
DecryptText<0x8F1B5BFD5F6175B5ULL>({0xE6, 0x10, 0x13, 0x29, 0x94, 0x38, 0x7E, 0xDB, 0xCC, 0x05, 0x04,
0x7F, 0xB8, 0x29, 0x69, 0xE0, 0xC7, 0x55, 0x40, 0x7E, 0xFD}),
0);
}
} else if (!g_clientInfoLoaded) {
ShowErrorDialog(GetRenderSystemHolder()->system,
DecryptText<0x078333BB9725B7C9ULL>(
{0x87, 0xD8, 0x05, 0xC4, 0xDE, 0x41, 0xF5, 0x6E, 0xAA, 0xD2, 0x71, 0xEE, 0xCB, 0x56, 0xA3, 0x26, 0xE8, 0xB7}),
0);
}
XmlNode* serverType =
clientInfo->FindChild(DecryptText<0xF5657D1F3DE5CDC7ULL>({0xB4, 0xA8, 0x97, 0x4B, 0x7A, 0x0F, 0x11, 0x8C, 0xB7, 0xA8, 0xE5}));
if (serverType) {
if (serverType->Text() == std::string(DecryptText<0x69FD1D9733D3CFC1ULL>({0xB1, 0xBD, 0xBA, 0x5E, 0xF6, 0x6F, 0x84, 0x69}))) {
g_serviceMode = g_serviceMode == 13 ? 13 : 0;
} else if (serverType->Text() == std::string(DecryptText<0xF7530137154D8FE5ULL>({0x96, 0xEE, 0x26, 0x67, 0x56, 0x78, 0x53}))) {
g_serviceMode = 1;
} else if (serverType->Text() == std::string(DecryptText<0x8B65CD61012B5931ULL>({0x5D, 0x36, 0x48, 0x60, 0x0D, 0xCD}))) {
g_serviceMode = 2;
} else if (serverType->Text() == std::string(DecryptText<0x17359BF953C367B3ULL>({0xC3, 0x0C, 0xC3}))) {
g_serviceMode = 5;
} else {
ShowErrorDialog(GetRenderSystemHolder()->system,
DecryptText<0x2FF3C5036D070127ULL>({0x74, 0x64, 0x75, 0x1B, 0x66, 0xB7, 0xA7, 0x56, 0x57, 0x64,
0x27, 0x28, 0x71, 0xB7, 0x9C, 0x5D, 0x07, 0x20, 0x26, 0x6D}),
0);
}
} else if (!g_clientInfoLoaded) {
ShowErrorDialog(
GetRenderSystemHolder()->system,
DecryptText<0x93E7A3A1F587CDC5ULL>({0x8B, 0xA2, 0xA7, 0xA6, 0xC4, 0xD1, 0x91, 0xF6, 0xB7, 0x99, 0xFE, 0x85, 0xC4, 0x83, 0xC6, 0xB2, 0xC5}),
0);
}
if (clientInfo->FindChild(DecryptText<0xC52FB5FBB94FF917ULL>(
{0x7F, 0x90, 0x2B, 0xDC, 0x9A, 0xD6, 0x4C, 0xAA, 0x62, 0x97, 0x3B, 0xD5, 0x92, 0xC6, 0x5B, 0xC5}))) {
g_hideAccountList = true;
}
if (clientInfo->FindChild(DecryptText<0x812BE72BCD5707B7ULL>({0xD2, 0x7F, 0x23, 0xA8, 0x45, 0x83, 0x4E, 0xE5, 0xC4, 0x6B, 0x38, 0xB9, 0x2B}))) {
g_extendedSlot = true;
}
if (clientInfo->FindChild(DecryptText<0x59278F63D79F3DA1ULL>({0xD3, 0x58, 0xFE, 0xB3, 0x05, 0xE0, 0x4B, 0x3D, 0xC4, 0x4F, 0x9F}))) {
g_readFolder = true;
}
XmlNode* loading = clientInfo->FindChild(DecryptText<0x1D6D75EDE7CD311FULL>({0x73, 0x5E, 0xAC, 0x83, 0x84, 0x1B, 0x0A, 0x1D}));
if (loading) {
for (XmlNode* image = loading->FindChild(DecryptText<0x3375B1C7DBB5FD55ULL>({0x3C, 0x90, 0xD4, 0xBC, 0xA2, 0xB1})); image;
image = image->FindSibling(DecryptText<0xD98F03A52D35636DULL>({0x04, 0x0E, 0x54, 0x4A, 0xC0, 0x03}))) {
char path[256];
std::sprintf(path,
DecryptText<0x0F0F8B6B8F9D19D1ULL>(
{0x11, 0xB6, 0x5D, 0x75, 0xAB, 0x45, 0xCA, 0xC2, 0x17, 0xFD, 0x5D, 0x43, 0xD6, 0x31, 0x53, 0x2A, 0xA2, 0x19}),
image->Text().c_str());
g_loadingScreens.push_back(std::string(path));
}
}
XmlNode* homepage =
clientInfo->FindChild(DecryptText<0x31D7C1EDA345E36DULL>({0x1B, 0x8A, 0x20, 0xD4, 0x85, 0xAE, 0xBA, 0x54, 0x1D, 0x82, 0x22, 0xC6, 0xED}));
if (homepage) {
sprintf_s(g_homepageUrl, sizeof(g_homepageUrl), "%s", homepage->Text().c_str());
}
g_clientInfoLoaded = true;
}