|
|
|
@ -21,9 +21,20 @@
|
|
|
|
|
#include <storm/Error.hpp>
|
|
|
|
|
#include <storm/Log.hpp>
|
|
|
|
|
#include <bc/os/Path.hpp>
|
|
|
|
|
#include <bc/file/File.hpp>
|
|
|
|
|
|
|
|
|
|
CVar* Client::g_accountListVar;
|
|
|
|
|
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() {
|
|
|
|
|
// TODO
|
|
|
|
@ -139,6 +150,32 @@ int32_t InitializeEngineCallback(const void* a1, void* a2) {
|
|
|
|
|
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() {
|
|
|
|
|
// SFile::DisableSFileCheckDisk();
|
|
|
|
|
// SFile::EnableDirectAccess(0);
|
|
|
|
@ -158,12 +195,109 @@ void SetPaths() {
|
|
|
|
|
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() {
|
|
|
|
|
// TODO
|
|
|
|
|
|
|
|
|
|
ProcessCommandLine();
|
|
|
|
|
SetPaths();
|
|
|
|
|
|
|
|
|
|
// sub_403600("WoW.mfil");
|
|
|
|
|
// TODO:
|
|
|
|
|
// WowConfigureFileSystem::ReadBuildKeyFromFile("WoW.mfil");
|
|
|
|
|
|
|
|
|
|
// if (dword_B2FA10 != 2) {
|
|
|
|
|
// sub_403560();
|
|
|
|
@ -175,52 +309,78 @@ int32_t InitializeGlobal() {
|
|
|
|
|
// LOBYTE(v24) = OsDirectoryExists((int)"WTF/Account") == 0;
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// ClientServices::LoadCDKey();
|
|
|
|
|
|
|
|
|
|
SetPaths();
|
|
|
|
|
|
|
|
|
|
OpenArchives();
|
|
|
|
|
ClientServices::LoadCDKey();
|
|
|
|
|
|
|
|
|
|
ConsoleInitializeClientCommand();
|
|
|
|
|
|
|
|
|
|
ConsoleInitializeClientCVar("Config.wtf");
|
|
|
|
|
|
|
|
|
|
// TODO
|
|
|
|
|
// replace enUS with detected locale
|
|
|
|
|
ClientServices::InitLoginServerCVars(1, "enUS");
|
|
|
|
|
|
|
|
|
|
// sub_7663F0();
|
|
|
|
|
// TODO: CVar::ArchiveCodeRegisteredOnly();
|
|
|
|
|
|
|
|
|
|
// v18 = 0;
|
|
|
|
|
// v19 = 0;
|
|
|
|
|
// ptr = 0;
|
|
|
|
|
// v21 = 0;
|
|
|
|
|
|
|
|
|
|
// sub_406740(&v18, &CVar::Load);
|
|
|
|
|
// ::ForEveryRunOnceWTF::Execute(&v18, &CVar::Load);
|
|
|
|
|
|
|
|
|
|
// if (ptr) {
|
|
|
|
|
// 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)) {
|
|
|
|
|
// CVar::Set(v2, "enUS", 1, 0, 0, 1);
|
|
|
|
|
// }
|
|
|
|
|
if (!SStrCmp(locale->GetString(), "****", STORM_MAX_STR)) {
|
|
|
|
|
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()) {
|
|
|
|
|
// 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);
|
|
|
|
|
|
|
|
|
@ -343,19 +503,36 @@ int32_t InitializeGlobal() {
|
|
|
|
|
void CommonMain() {
|
|
|
|
|
StormInitialize();
|
|
|
|
|
|
|
|
|
|
// TODO
|
|
|
|
|
// - error log setup
|
|
|
|
|
// - misc other setup
|
|
|
|
|
// TODO:
|
|
|
|
|
// SErrCatchUnhandledExceptions();
|
|
|
|
|
// 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()) {
|
|
|
|
|
EventDoMessageLoop();
|
|
|
|
|
|
|
|
|
|
// TODO
|
|
|
|
|
// sub_406B70();
|
|
|
|
|
// TODO: DestroyGlobal();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// TODO
|
|
|
|
|
// - misc cleanup
|
|
|
|
|
// TODO:
|
|
|
|
|
// StormDestroy();
|
|
|
|
|
// Misc Cleanup
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void BlizzardAssertCallback(const char* a1, const char* a2, const char* a3, uint32_t a4) {
|
|
|
|
|