Compare commits

...

2 Commits

Author SHA1 Message Date
VDm
745dfcc129 feat(client): add CheckAvailableLocales method 2025-03-02 01:42:32 +04:00
VDm
86153ccf53 feat(client): implement locale related calls 2025-03-01 23:41:31 +04:00
5 changed files with 218 additions and 34 deletions

View File

@ -21,9 +21,20 @@
#include <storm/Error.hpp> #include <storm/Error.hpp>
#include <storm/Log.hpp> #include <storm/Log.hpp>
#include <bc/os/Path.hpp> #include <bc/os/Path.hpp>
#include <bc/file/File.hpp>
CVar* Client::g_accountListVar; CVar* Client::g_accountListVar;
HEVENTCONTEXT Client::g_clientEventContext; HEVENTCONTEXT Client::g_clientEventContext;
char Client::g_currentLocaleName[5] = {};
static uint8_t s_expansionLevel = 0;
static bool g_hasIsoLocale[12] = {};
static char* s_localeArray[12] = {
"deDE", "enGB", "enUS", "esES", "frFR", "koKR",
"zhCN", "zhTW", "enCN", "enTW", "esMX", "ruRU"
};
void AsyncFileInitialize() { void AsyncFileInitialize() {
// TODO // TODO
@ -139,6 +150,32 @@ int32_t InitializeEngineCallback(const void* a1, void* a2) {
return 1; return 1;
} }
uint8_t GetExpansionLevel() {
return s_expansionLevel;
}
const char* UpdateInstallLocation() {
// TODO
return nullptr;
}
bool UpdateInstallLocationForName(int32_t a1, size_t size, const char* filename, char* buffer, const char* locale) {
if (a1 == 2) {
auto location = UpdateInstallLocation();
if (!location) {
return false;
}
SStrPrintf(buffer, size, "%s%s%s", location, "Data\\", filename);
} else {
SStrPrintf(buffer, size, "%s%s", "Data\\", filename);
}
for (auto i = SStrStr(buffer, "****"); i; i = SStrStr(buffer, "****")) {
size_t offset = static_cast<size_t>(i - buffer);
memcpy(&buffer[offset], locale, 4);
}
return true;
}
void SetPaths() { void SetPaths() {
// SFile::DisableSFileCheckDisk(); // SFile::DisableSFileCheckDisk();
// SFile::EnableDirectAccess(0); // SFile::EnableDirectAccess(0);
@ -158,12 +195,109 @@ void SetPaths() {
OsSetCurrentDirectory(datadir); OsSetCurrentDirectory(datadir);
} }
bool IsCommonMpqExists() {
char path1[1024];
SStrPrintf(path1, sizeof(path1), "%s%s", "Data\\", "common.MPQ");
for (auto i = SStrStr(path1, "****"); i; i = SStrStr(path1, "****")) {
size_t offset = static_cast<size_t>(i - path1);
memcpy(&path1[offset], "----", 4);
}
char path2[1024];
SStrPrintf(path2, sizeof(path2), "%s%s", "..\\Data\\", "common.MPQ");
for (auto i = SStrStr(path2, "****"); i; i = SStrStr(path2, "****")) {
size_t offset = static_cast<size_t>(i - path2);
memcpy(&path2[offset], "----", 4);
}
auto location = UpdateInstallLocation();
if (location) {
char path3[1024];
SStrPrintf(path3, sizeof(path3), "%s%s%s", location, "Data\\", "common.MPQ");
for (auto i = SStrStr(path3, "****"); i; i = SStrStr(path3, "****")) {
size_t offset = static_cast<size_t>(i - path3);
memcpy(&path3[offset], "----", 4);
}
if (!Blizzard::File::Exists(path1) && !Blizzard::File::Exists(path2)) {
return Blizzard::File::Exists(path3);
}
} else if (!Blizzard::File::Exists(path1)) {
return Blizzard::File::Exists(path2);
}
return true;
}
size_t GetLocaleIndex(const char* locale) {
for (size_t i = 0; i < 12; ++i) {
if (SStrCmpI(locale, s_localeArray[i], 4) == 0) {
return i;
}
}
return 2; // s_localeArray[2] == "enUS"
}
void CheckAvailableLocales(char* locale) {
if (!IsCommonMpqExists()) {
return;
}
for (size_t localeIndex = 0; localeIndex < 12; ++localeIndex) {
g_hasIsoLocale[localeIndex] = false;
const char* filename = "****\\locale-****.MPQ";
char path[1024];
SStrPrintf(path, sizeof(path), "%s%s", "Data\\", filename);
for (auto i = SStrStr(path, "****"); i; i = SStrStr(path, "****")) {
size_t offset = static_cast<size_t>(i - path);
memcpy(&path[offset], s_localeArray[localeIndex], 4);
}
if (Blizzard::File::Exists(path)) {
g_hasIsoLocale[localeIndex] = true;
continue;
}
SStrPrintf(path, sizeof(path), "%s%s", "..\\Data\\", filename);
for (auto i = SStrStr(path, "****"); i; i = SStrStr(path, "****")) {
size_t offset = static_cast<size_t>(i - path);
memcpy(&path[offset], s_localeArray[localeIndex], 4);
}
if (Blizzard::File::Exists(path)) {
g_hasIsoLocale[localeIndex] = true;
continue;
}
if (UpdateInstallLocationForName(2, sizeof(path), filename, path, s_localeArray[localeIndex]) &&
Blizzard::File::Exists(path)) {
g_hasIsoLocale[localeIndex] = true;
}
}
size_t localeIndex = GetLocaleIndex(locale);
for (size_t i = 0; i < 12; ++i) {
if (g_hasIsoLocale[localeIndex]) {
break;
}
localeIndex = (localeIndex + 1) % 12;
}
SStrCopy(locale, s_localeArray[localeIndex], STORM_MAX_STR);
}
bool LocaleChangedCallback(CVar*, const char*, const char* value, void*) {
SStrCopy(Client::g_currentLocaleName, value, sizeof(Client::g_currentLocaleName));
return true;
}
int32_t InitializeGlobal() { int32_t InitializeGlobal() {
// TODO
ProcessCommandLine(); ProcessCommandLine();
SetPaths();
// sub_403600("WoW.mfil"); // TODO:
// WowConfigureFileSystem::ReadBuildKeyFromFile("WoW.mfil");
// if (dword_B2FA10 != 2) { // if (dword_B2FA10 != 2) {
// sub_403560(); // sub_403560();
@ -175,52 +309,78 @@ int32_t InitializeGlobal() {
// LOBYTE(v24) = OsDirectoryExists((int)"WTF/Account") == 0; // LOBYTE(v24) = OsDirectoryExists((int)"WTF/Account") == 0;
// } // }
// ClientServices::LoadCDKey(); ClientServices::LoadCDKey();
SetPaths();
OpenArchives();
ConsoleInitializeClientCommand(); ConsoleInitializeClientCommand();
ConsoleInitializeClientCVar("Config.wtf"); ConsoleInitializeClientCVar("Config.wtf");
// TODO: CVar::ArchiveCodeRegisteredOnly();
// TODO
// replace enUS with detected locale
ClientServices::InitLoginServerCVars(1, "enUS");
// sub_7663F0();
// v18 = 0; // v18 = 0;
// v19 = 0; // v19 = 0;
// ptr = 0; // ptr = 0;
// v21 = 0; // v21 = 0;
// sub_406740(&v18, &CVar::Load); // ::ForEveryRunOnceWTF::Execute(&v18, &CVar::Load);
// if (ptr) { // if (ptr) {
// SMemFree(ptr, a_pad, -2, 0); // SMemFree(ptr, a_pad, -2, 0);
// } // }
// CVar::Register("dbCompress", "Database compression", 0, "-1", 0, 5, 0, 0, 0); CVar::Register(
"dbCompress",
"Database compression",
0,
"-1",
nullptr,
CATEGORY::DEFAULT,
false,
nullptr,
false
);
// v2 = CVar::Register("locale", "Set the game locale", 0, "****", &LocaleChangedCallback, 5, 0, 0, 0); CVar* locale = CVar::Register(
"locale",
"Set the game locale",
0,
"****",
&LocaleChangedCallback,
CATEGORY::DEFAULT,
false,
nullptr,
false
);
// if (!SStrCmp(v2->m_stringValue.m_str, "****", 0x7FFFFFFFu)) { if (!SStrCmp(locale->GetString(), "****", STORM_MAX_STR)) {
// CVar::Set(v2, "enUS", 1, 0, 0, 1); locale->Set("enUS", true, false, false, true);
// } }
// CVar::Register("useEnglishAudio", "override the locale and use English audio", 0, "0", 0, 5, 0, 0, 0); CVar::Register(
"useEnglishAudio",
"override the locale and use English audio",
0,
"0",
nullptr,
CATEGORY::DEFAULT,
false,
nullptr,
false
);
// TODO: SFile::IsTrial() check
// if (sub_422140()) { // if (sub_422140()) {
// sub_4036B0(v24, 0, a2, (int)v2, (char)v24); // sub_4036B0(v24, 0, a2, (int)v2, (char)v24);
// } // }
// SStrCopy(&a1a, v2->m_stringValue.m_str, 5); char existingLocale[5] = {};
SStrCopy(existingLocale, locale->GetString(), sizeof(existingLocale));
CheckAvailableLocales(existingLocale);
locale->Set(existingLocale, true, false, false, true);
// sub_402D50(&a1a);
// CVar::Set(v2, &a1a, 1, 0, 0, 1); OpenArchives();
// TODO: This method should be placed inside OpenArchives
ClientServices::InitLoginServerCVars(1, locale->GetString());
// SStrPrintf(dest, 260, "%s%s", *(_DWORD *)off_AB6158, v2->m_stringValue.m_str); // SStrPrintf(dest, 260, "%s%s", *(_DWORD *)off_AB6158, v2->m_stringValue.m_str);
@ -343,19 +503,36 @@ int32_t InitializeGlobal() {
void CommonMain() { void CommonMain() {
StormInitialize(); StormInitialize();
// TODO // TODO:
// - error log setup // SErrCatchUnhandledExceptions();
// - misc other setup // OsSystemInitialize("Blizzard Entertainment World of Warcraft", 0);
// int option = 1;
// StormSetOption(10, &option, sizeof(option));
// StormSetOption(11, &option, sizeof(option));
// OsSystemEnableCpuLog();
// SetPaths() moved into InitializeGlobal()
// int sendErrorLogs = 1;
// if (!SRegLoadValue("World of Warcraft\\Client", "SendErrorLogs", 0, &sendErrorLogs)) {
// sendErrorLogs = 1;
// SRegSaveValue("World of Warcraft\\Client", "SendErrorLogs", 0, sendErrorLogs);
// }
// SErrSetLogTitleString("World of WarCraft (build 12340)");
// SErrSetLogTitleCallback(WowLogHeader);
// if (sendErrorLogs) {
// SErrRegisterHandler(SendErrorLog);
// }
if (InitializeGlobal()) { if (InitializeGlobal()) {
EventDoMessageLoop(); EventDoMessageLoop();
// TODO: DestroyGlobal();
// TODO
// sub_406B70();
} }
// TODO // TODO:
// - misc cleanup // StormDestroy();
// Misc Cleanup
} }
void BlizzardAssertCallback(const char* a1, const char* a2, const char* a3, uint32_t a4) { void BlizzardAssertCallback(const char* a1, const char* a2, const char* a3, uint32_t a4) {

View File

@ -9,6 +9,7 @@ class CVar;
namespace Client { namespace Client {
extern CVar* g_accountListVar; extern CVar* g_accountListVar;
extern HEVENTCONTEXT g_clientEventContext; extern HEVENTCONTEXT g_clientEventContext;
extern char g_currentLocaleName[5];
} }
void ClientPostClose(int32_t a1); void ClientPostClose(int32_t a1);

View File

@ -264,6 +264,11 @@ const char* ClientServices::GetDefaultPatchListString() {
return "public-test.patch.battle.net:1119/patch"; return "public-test.patch.battle.net:1119/patch";
} }
bool ClientServices::LoadCDKey() {
// TODO
return true;
}
void ClientServices::InitLoginServerCVars(int32_t overwrite, const char* locale) { void ClientServices::InitLoginServerCVars(int32_t overwrite, const char* locale) {
if ((ClientServices::s_realmListBNVar == nullptr || ClientServices::s_realmListVar == nullptr) || overwrite != 0 ) { if ((ClientServices::s_realmListBNVar == nullptr || ClientServices::s_realmListVar == nullptr) || overwrite != 0 ) {
ClientServices::s_decorateAccountName = CVar::Register( ClientServices::s_decorateAccountName = CVar::Register(

View File

@ -45,6 +45,7 @@ class ClientServices : public LoginResponse {
static void InitLoginServerCVars(int32_t overwrite, const char* locale); static void InitLoginServerCVars(int32_t overwrite, const char* locale);
static const char* GetDefaultRealmlistString(); static const char* GetDefaultRealmlistString();
static const char* GetDefaultPatchListString(); static const char* GetDefaultPatchListString();
static bool LoadCDKey();
// Virtual member functions // Virtual member functions
virtual int32_t GetLoginServerType(); virtual int32_t GetLoginServerType();

View File

@ -37,7 +37,7 @@ class CVar : public TSHashObject<CVar, HASHKEY_STRI> {
int32_t GetInt(); int32_t GetInt();
const char* GetString(void); const char* GetString(void);
void InternalSet(const char*, bool, bool, bool, bool); void InternalSet(const char*, bool, bool, bool, bool);
bool Set(const char*, bool, bool, bool, bool); bool Set(const char* value, bool setValue, bool setReset, bool setDefault, bool a6);
bool Reset(); bool Reset();
bool Default(); bool Default();
int32_t Update(); int32_t Update();