iw4x-client/src/Components/Modules/News.cpp

278 lines
6.8 KiB
C++
Raw Normal View History

2017-01-19 16:23:59 -05:00
#include "STDInclude.hpp"
2017-02-04 14:45:27 -05:00
#define NEWS_MOTD_DEFAULT "Welcome to IW4x Multiplayer!"
2017-01-19 16:23:59 -05:00
namespace Components
{
bool News::Terminate;
std::thread News::Thread;
std::string News::UpdaterArgs;
std::string News::UpdaterHash;
2017-02-28 13:55:22 -05:00
std::mutex News::UpdaterMutex;
2017-01-19 16:23:59 -05:00
bool News::unitTest()
{
bool result = true;
if (News::Thread.joinable())
{
Logger::Print("Awaiting thread termination...\n");
News::Thread.join();
2017-02-04 14:45:27 -05:00
if (!strcmp(Localization::Get("MPUI_MOTD_TEXT"), NEWS_MOTD_DEFAULT))
2017-01-19 16:23:59 -05:00
{
Logger::Print("Failed to fetch motd!\n");
result = false;
}
else
{
Logger::Print("Successfully fetched motd.\n");
}
}
return result;
}
void News::ExitProcessStub(unsigned int exitCode)
{
std::this_thread::sleep_for(10ms);
STARTUPINFOA sInfo;
PROCESS_INFORMATION pInfo;
ZeroMemory(&sInfo, sizeof(sInfo));
ZeroMemory(&pInfo, sizeof(pInfo));
sInfo.cb = sizeof(sInfo);
CreateProcessA("updater.exe", const_cast<char*>(Utils::String::VA("updater.exe %s", News::UpdaterArgs.data())), nullptr, nullptr, false, NULL, nullptr, nullptr, &sInfo, &pInfo);
2017-01-19 16:23:59 -05:00
if (pInfo.hThread && pInfo.hThread != INVALID_HANDLE_VALUE) CloseHandle(pInfo.hThread);
if (pInfo.hProcess && pInfo.hProcess != INVALID_HANDLE_VALUE) CloseHandle(pInfo.hProcess);
2017-01-19 16:23:59 -05:00
TerminateProcess(GetCurrentProcess(), exitCode);
}
bool News::GetLatestUpdater()
{
2017-02-28 13:55:22 -05:00
std::lock_guard<std::mutex> _(News::UpdaterMutex);
if (Utils::IO::FileExists("updater.exe"))
{
// Generate hash of local updater.exe
std::string localUpdater = Utils::IO::ReadFile("updater.exe");
localUpdater = Utils::Cryptography::SHA1::Compute(localUpdater, true);
2017-02-25 07:13:58 -05:00
static Utils::Time::Interval updateInterval;
if (News::UpdaterHash.empty() || updateInterval.elapsed(15min)) // Check for updater Update every 15 mins max
{
2017-02-25 07:13:58 -05:00
updateInterval.update();
std::string data = Utils::Cache::GetFile("/json/updater"); // {"updater.exe":{"SHA1":"*HASH*"}}
std::string error;
json11::Json listData = json11::Json::parse(data, error);
if (error.empty() || listData.is_object())
{
News::UpdaterHash = listData["updater.exe"]["SHA1"].string_value();
}
}
if (!News::UpdaterHash.empty() && localUpdater != News::UpdaterHash)
{
remove("updater.exe");
}
}
if (!Utils::IO::FileExists("updater.exe"))
{
return News::DownloadUpdater();
}
return true;
}
bool News::DownloadUpdater()
{
std::string data = Utils::Cache::GetFile("/iw4/updater.exe");
if (!data.empty())
{
Utils::IO::WriteFile("updater.exe", data);
return true;
}
return false;
}
2017-01-19 16:23:59 -05:00
const char* News::GetNewsText()
{
return Localization::Get("MPUI_MOTD_TEXT");
}
void News::CheckForUpdate()
{
std::string _client = Utils::Cache::GetFile("/json/client");
2017-01-19 16:23:59 -05:00
if (!_client.empty())
2017-01-19 16:23:59 -05:00
{
std::string error;
json11::Json client = json11::Json::parse(_client.data(), error);
2017-01-19 16:23:59 -05:00
2017-02-25 07:22:40 -05:00
int revisionNumber;
2017-02-13 16:36:29 -05:00
if (client["revision"].is_number())
{
2017-02-13 16:36:29 -05:00
revisionNumber = client["revision"].int_value();
2017-01-19 16:23:59 -05:00
}
2017-02-13 16:36:29 -05:00
else if (client["revision"].is_string())
{
revisionNumber = atoi(client["revision"].string_value().data());
}
else return;
Dvar::Var("cl_updateversion").get<Game::dvar_t*>()->current.integer = revisionNumber;
Dvar::Var("cl_updateavailable").get<Game::dvar_t*>()->current.boolean = (revisionNumber > REVISION);
2017-01-19 16:23:59 -05:00
}
}
void News::LaunchUpdater(std::string params)
{
if (News::Updating()) return;
News::UpdaterArgs = params;
Localization::SetTemp("MENU_RECONNECTING_TO_PARTY", "Downloading updater");
Command::Execute("openmenu popup_reconnectingtoparty", true);
// Run the updater on shutdown
Utils::Hook::Set(0x6D72A0, News::ExitProcessStub);
std::thread([]()
{
if (News::GetLatestUpdater())
{
Console::SetSkipShutdown();
Command::Execute("wait 300; quit;", false);
}
else
{
Localization::ClearTemp();
News::UpdaterArgs.clear();
Command::Execute("closemenu popup_reconnectingtoparty", false);
Game::ShowMessageBox("Failed to download the updater!", "Error");
}
}).detach();
}
bool News::Updating()
{
return !News::UpdaterArgs.empty();
}
2017-01-19 16:23:59 -05:00
News::News()
{
News::UpdaterArgs.clear();
News::UpdaterHash.clear();
if (ZoneBuilder::IsEnabled() || Dedicated::IsEnabled()) return; // Maybe also dedi?
2017-01-19 16:23:59 -05:00
Dvar::Register<bool>("g_firstLaunch", true, Game::DVAR_FLAG_SAVED, "");
2017-01-19 16:23:59 -05:00
Dvar::Register<int>("cl_updateoldversion", REVISION, REVISION, REVISION, Game::DVAR_FLAG_WRITEPROTECTED, "Current version number.");
Dvar::Register<int>("cl_updateversion", 0, 0, -1, Game::DVAR_FLAG_WRITEPROTECTED, "New version number.");
Dvar::Register<bool>("cl_updateavailable", false, Game::DVAR_FLAG_WRITEPROTECTED, "New update is available.");
2017-01-19 16:23:59 -05:00
UIScript::Add("checkFirstLaunch", [](UIScript::Token)
{
if (Dvar::Var("g_firstLaunch").get<bool>())
{
Command::Execute("openmenu menu_first_launch", false);
//Dvar::Var("g_firstLaunch").set(false);
}
});
UIScript::Add("visitWebsite", [](UIScript::Token)
{
ShellExecuteA(nullptr, "open", Utils::Cache::GetStaticUrl("").data(), nullptr, nullptr, SW_SHOWNORMAL);
});
UIScript::Add("visitWiki", [](UIScript::Token)
{
ShellExecuteA(nullptr, "open", Utils::Cache::GetStaticUrl("/wiki/").data(), nullptr, nullptr, SW_SHOWNORMAL);
});
2017-01-19 16:23:59 -05:00
Localization::Set("MPUI_CHANGELOG_TEXT", "Loading...");
2017-02-04 14:45:27 -05:00
Localization::Set("MPUI_MOTD_TEXT", NEWS_MOTD_DEFAULT);
2017-01-19 16:23:59 -05:00
//News::GetLatestUpdater();
2017-01-19 16:23:59 -05:00
// make newsfeed (ticker) menu items not cut off based on safe area
Utils::Hook::Nop(0x63892D, 5);
// hook for getting the news ticker string
Utils::Hook::Nop(0x6388BB, 2); // skip the "if (item->text[0] == '@')" localize check
Utils::Hook(0x6388C1, News::GetNewsText, HOOK_CALL).install()->quick();
Command::Add("checkforupdate", [] (Command::Params*)
{
News::CheckForUpdate();
});
Command::Add("getautoupdate", [] (Command::Params*)
{
if (!Dvar::Var("cl_updateavailable").get<Game::dvar_t*>()->current.boolean) return;
News::LaunchUpdater("-update -c");
2017-01-19 16:23:59 -05:00
});
if (!Utils::IsWineEnvironment() && !Loader::PerformingUnitTests())
2017-01-19 16:23:59 -05:00
{
News::Terminate = false;
2017-01-25 08:34:53 -05:00
News::Thread = std::thread([]()
2017-01-19 16:23:59 -05:00
{
2017-02-04 15:52:49 -05:00
Changelog::LoadChangelog();
2017-02-04 14:26:46 -05:00
2017-01-25 08:34:53 -05:00
std::string data = Utils::Cache::GetFile("/iw4/motd.txt");
2017-01-25 08:34:53 -05:00
if (!data.empty())
{
Localization::Set("MPUI_MOTD_TEXT", data);
}
2017-01-19 16:23:59 -05:00
2017-01-25 08:34:53 -05:00
if (!Loader::PerformingUnitTests())
{
2017-02-28 13:26:12 -05:00
News::GetLatestUpdater();
2017-01-25 08:34:53 -05:00
while (!News::Terminate)
{
2017-01-25 08:34:53 -05:00
News::CheckForUpdate();
2017-01-25 08:34:53 -05:00
// Sleep for 3 minutes
for (int i = 0; i < 180 && !News::Terminate; ++i)
{
std::this_thread::sleep_for(1s);
2017-01-19 16:23:59 -05:00
}
}
}
});
}
}
News::~News()
{
News::UpdaterArgs.clear();
News::UpdaterHash.clear();
}
void News::preDestroy()
2017-01-19 16:23:59 -05:00
{
News::Terminate = true;
if (News::Thread.joinable())
{
News::Thread.join();
}
News::Thread = std::thread();
2017-01-19 16:23:59 -05:00
}
}