Merge remote-tracking branch 'origin/develop' into 191-dedicated-server-optimization

# Conflicts:
#	src/Components/Modules/News.cpp
This commit is contained in:
momo5502 2017-02-25 13:00:56 +01:00
commit 741d5788bd
16 changed files with 317 additions and 46 deletions

View File

@ -12,6 +12,11 @@ namespace Components
return Loader::Pregame;
}
bool Loader::IsPostgame()
{
return Loader::Postgame;
}
void Loader::Initialize()
{
Loader::Pregame = true;
@ -93,7 +98,7 @@ namespace Components
void Loader::Uninitialize()
{
Loader::PreDestroy();
Loader::PreDestroyNoPostGame();
std::reverse(Loader::Components.begin(), Loader::Components.end());
for (auto component : Loader::Components)
@ -119,14 +124,32 @@ namespace Components
{
Loader::Postgame = true;
std::reverse(Loader::Components.begin(), Loader::Components.end());
for (auto component : Loader::Components)
auto components = Loader::Components;
std::reverse(components.begin(), components.end());
for (auto component : components)
{
component->preDestroy();
}
}
}
void Loader::PreDestroyNoPostGame()
{
if (!Loader::Postgame)
{
auto components = Loader::Components;
std::reverse(components.begin(), components.end());
for (auto component : components)
{
component->preDestroy();
}
Loader::Postgame = true;
}
}
bool Loader::PerformUnitTests()
{
bool result = true;

View File

@ -25,11 +25,13 @@ namespace Components
static void Initialize();
static void Uninitialize();
static void PreDestroy();
static void PreDestroyNoPostGame();
static bool PerformUnitTests();
static bool PerformingUnitTests();
static void Register(Component* component);
static bool IsPregame();
static bool IsPostgame();
static Utils::Memory::Allocator* GetAlloctor();

View File

@ -66,8 +66,8 @@ namespace Components
}
else
{
//maxclientCount = Dvar::Var("sv_maxclients").get<int>();
maxclientCount = Game::Party_GetMaxPlayers(*Game::partyIngame);
maxclientCount = Dvar::Var("party_maxplayers").get<int>();
//maxclientCount = Game::Party_GetMaxPlayers(*Game::partyIngame);
clientCount = Game::PartyHost_CountMembers(reinterpret_cast<Game::PartyData_s*>(0x1081C00));
}

View File

@ -195,8 +195,50 @@ namespace Components
Logger::MessageMutex.unlock();
}
void Logger::RedirectOSPath(const char* file, char* folder)
{
if (Dvar::Var("g_log").get<std::string>() == file)
{
if (folder != "userraw"s)
{
if (Dvar::Var("g_log").get<bool>())
{
strcpy_s(folder, 256, "userraw");
}
}
}
}
__declspec(naked) void Logger::BuildOSPathStub()
{
__asm
{
pushad
push [esp + 28h]
push [esp + 30h]
call Logger::RedirectOSPath
add esp, 8h
popad
mov eax, [esp + 8h]
push ebp
push esi
mov esi, [esp + 0Ch]
push 64213Fh
retn
}
}
Logger::Logger()
{
Dvar::Register<bool>("iw4x_onelog", false, Game::dvar_flag::DVAR_FLAG_LATCHED | Game::dvar_flag::DVAR_FLAG_SAVED, "Only write the game log to the 'userraw' OS folder");
Utils::Hook(0x642139, Logger::BuildOSPathStub, HOOK_JUMP).install()->quick();
Logger::PipeOutput(nullptr);
QuickPatch::OnFrame(Logger::Frame);

View File

@ -39,6 +39,9 @@ namespace Components
static void PrintMessagePipe(const char* data);
static void EnqueueMessage(std::string message);
static void BuildOSPathStub();
static void RedirectOSPath(const char* file, char* folder);
static void NetworkLog(const char* data, bool gLog);
static std::string Format(const char** message);

View File

@ -169,9 +169,9 @@ namespace Components
return menu;
}
std::vector<Game::menuDef_t*> Menus::LoadMenu(std::string menu)
std::vector<std::pair<bool, Game::menuDef_t*>> Menus::LoadMenu(std::string menu)
{
std::vector<Game::menuDef_t*> menus;
std::vector<std::pair<bool, Game::menuDef_t*>> menus;
FileSystem::File menuFile(menu);
if (menuFile.exists())
@ -200,7 +200,7 @@ namespace Components
if (!_stricmp(token.string, "menudef"))
{
Game::menuDef_t* menudef = Menus::ParseMenu(handle);
if (menudef) menus.push_back(menudef);
if (menudef) menus.push_back({ true, menudef }); // Custom menu
}
}
@ -211,9 +211,9 @@ namespace Components
return menus;
}
std::vector<Game::menuDef_t*> Menus::LoadMenu(Game::menuDef_t* menudef)
std::vector<std::pair<bool, Game::menuDef_t*>> Menus::LoadMenu(Game::menuDef_t* menudef)
{
std::vector<Game::menuDef_t*> menus = Menus::LoadMenu(Utils::String::VA("ui_mp\\%s.menu", menudef->window.name));
std::vector<std::pair<bool, Game::menuDef_t*>> menus = Menus::LoadMenu(Utils::String::VA("ui_mp\\%s.menu", menudef->window.name));
if (menus.empty())
{
@ -222,11 +222,11 @@ namespace Components
//
// if (originalMenu)
// {
// menus.push_back(originalMenu);
// menus.push_back({ false, originalMenu });
// }
// else
// {
menus.push_back(menudef);
menus.push_back({ false, menudef }); // Native menu
// }
}
@ -235,7 +235,7 @@ namespace Components
Game::MenuList* Menus::LoadScriptMenu(const char* menu)
{
std::vector<Game::menuDef_t*> menus = Menus::LoadMenu(menu);
std::vector<std::pair<bool, Game::menuDef_t*>> menus = Menus::LoadMenu(menu);
if (menus.empty()) return nullptr;
// Allocate new menu list
@ -253,7 +253,10 @@ namespace Components
newList->menuCount = menus.size();
// Copy new menus
std::memcpy(newList->menus, menus.data(), menus.size() * sizeof(Game::menuDef_t *));
for(unsigned int i = 0; i < menus.size(); ++i)
{
newList->menus[i] = menus[i].second;
}
Menus::RemoveMenuList(newList->name);
Menus::MenuListList[newList->name] = newList;
@ -261,14 +264,60 @@ namespace Components
return newList;
}
void Menus::SafeMergeMenus(std::vector<std::pair<bool, Game::menuDef_t*>>* menus, std::vector<std::pair<bool, Game::menuDef_t*>> newMenus)
{
// Check if we overwrote a menu
for (unsigned int i = 0; i < menus->size(); ++i)
{
// Try to find the native menu
bool found = !menus->at(i).first; // Only if custom menu, try to find it
// If there is none, try to find a custom menu
if (!found)
{
for (auto& entry : Menus::MenuList)
{
if (menus->at(i).second == entry.second)
{
found = true;
break;
}
}
}
// Remove the menu if it has been deallocated (not found)
if (!found)
{
menus->erase(menus->begin() + i);
--i;
continue;
}
// Remove the menu if it has been loaded twice
for (auto& newMenu : newMenus)
{
if (menus->at(i).second->window.name == std::string(newMenu.second->window.name))
{
Menus::RemoveMenu(menus->at(i).second);
menus->erase(menus->begin() + i);
--i;
break;
}
}
}
Utils::Merge(menus, newMenus);
}
Game::MenuList* Menus::LoadMenuList(Game::MenuList* menuList)
{
std::vector<Game::menuDef_t*> menus;
std::vector<std::pair<bool, Game::menuDef_t*>> menus;
for (int i = 0; i < menuList->menuCount; ++i)
{
if (!menuList->menus[i]) continue;
Utils::Merge(&menus, Menus::LoadMenu(menuList->menus[i]));
Menus::SafeMergeMenus(&menus, Menus::LoadMenu(menuList->menus[i]));
}
// Load custom menus
@ -279,14 +328,14 @@ namespace Components
bool hasMenu = false;
for(auto &loadedMenu : menus)
{
if(loadedMenu->window.name == menu)
if(loadedMenu.second->window.name == menu)
{
hasMenu = true;
break;
}
}
if(!hasMenu) Utils::Merge(&menus, Menus::LoadMenu(menu));
if (!hasMenu) Menus::SafeMergeMenus(&menus, Menus::LoadMenu(menu));
}
}
@ -306,7 +355,10 @@ namespace Components
newList->menuCount = size;
// Copy new menus
std::memcpy(newList->menus, menus.data(), size * sizeof(Game::menuDef_t *));
for (unsigned int i = 0; i < menus.size(); ++i)
{
newList->menus[i] = menus[i].second;
}
Menus::RemoveMenuList(newList->name);
Menus::MenuListList[newList->name] = newList;

View File

@ -29,8 +29,9 @@ namespace Components
static Game::MenuList* LoadMenuList(Game::MenuList* menuList);
static Game::MenuList* LoadScriptMenu(const char* menu);
static std::vector<Game::menuDef_t*> LoadMenu(Game::menuDef_t* menudef);
static std::vector<Game::menuDef_t*> LoadMenu(std::string file);
static std::vector<std::pair<bool, Game::menuDef_t*>> LoadMenu(Game::menuDef_t* menudef);
static std::vector<std::pair<bool, Game::menuDef_t*>> LoadMenu(std::string file);
static void SafeMergeMenus(std::vector<std::pair<bool, Game::menuDef_t*>>* menus, std::vector<std::pair<bool, Game::menuDef_t*>> newMenus);
static Game::script_t* LoadMenuScript(std::string name, std::string buffer);
static int LoadMenuSource(std::string name, std::string buffer);

View File

@ -7,6 +7,8 @@ namespace Components
bool News::Terminate;
std::thread News::Thread;
std::string News::UpdaterArgs;
std::string News::UpdaterHash;
int News::UpdaterRefresh;
bool News::unitTest()
{
@ -50,6 +52,56 @@ namespace Components
TerminateProcess(GetCurrentProcess(), exitCode);
}
bool News::GetLatestUpdater()
{
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);
if (News::UpdaterHash.empty() || (News::UpdaterRefresh - Game::Sys_Milliseconds() > 900000)) // Check for updater Update every 15 mins max
{
News::UpdaterRefresh = Game::Sys_Milliseconds();
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;
}
const char* News::GetNewsText()
{
return Localization::Get("MPUI_MOTD_TEXT");
@ -95,21 +147,18 @@ namespace Components
std::thread([]()
{
std::string data = Utils::Cache::GetFile("/iw4/updater.exe");
if (data.empty())
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");
}
else
{
Console::SetSkipShutdown();
Utils::IO::WriteFile("updater.exe", data);
Command::Execute("wait 300; quit;", false);
}
}).detach();
}
@ -121,7 +170,8 @@ namespace Components
News::News()
{
News::UpdaterArgs.clear();
News::UpdaterHash.clear();
News::UpdaterRefresh = 0;
if (ZoneBuilder::IsEnabled() || Dedicated::IsEnabled()) return; // Maybe also dedi?
Dvar::Register<bool>("g_firstLaunch", true, Game::DVAR_FLAG_SAVED, "");
@ -152,10 +202,7 @@ namespace Components
Localization::Set("MPUI_CHANGELOG_TEXT", "Loading...");
Localization::Set("MPUI_MOTD_TEXT", NEWS_MOTD_DEFAULT);
if (Utils::IO::FileExists("updater.exe"))
{
remove("updater.exe");
}
//News::GetLatestUpdater();
// make newsfeed (ticker) menu items not cut off based on safe area
Utils::Hook::Nop(0x63892D, 5);
@ -209,6 +256,7 @@ namespace Components
News::~News()
{
News::UpdaterArgs.clear();
News::UpdaterHash.clear();
}
void News::preDestroy()

View File

@ -20,8 +20,13 @@ namespace Components
private:
static std::string UpdaterArgs;
static std::string UpdaterHash;
static int UpdaterRefresh;
static std::thread Thread;
static bool Terminate;
static bool GetLatestUpdater();
static bool DownloadUpdater();
static void CheckForUpdate();
static void ExitProcessStub(unsigned int exitCode);

View File

@ -302,8 +302,8 @@ namespace Components
}
else
{
//maxclientCount = Dvar::Var("sv_maxclients").get<int>();
maxclientCount = Game::Party_GetMaxPlayers(*Game::partyIngame);
maxclientCount = Dvar::Var("party_maxplayers").get<int>();
//maxclientCount = Game::Party_GetMaxPlayers(*Game::partyIngame);
clientCount = Game::PartyHost_CountMembers(reinterpret_cast<Game::PartyData_s*>(0x1081C00));
}

View File

@ -116,8 +116,8 @@ namespace Components
if (!maxclientCount)
{
//maxclientCount = Dvar::Var("sv_maxclients").get<int>();
maxclientCount = Game::Party_GetMaxPlayers(*Game::partyIngame);
maxclientCount = Dvar::Var("party_maxplayers").get<int>();
//maxclientCount = Game::Party_GetMaxPlayers(*Game::partyIngame);
}
Utils::InfoString info(Game::Dvar_InfoString_Big(1024));

View File

@ -146,6 +146,8 @@ namespace Components
Toast::Toast()
{
if (Dedicated::IsEnabled()) return;
Toast::ToastHandler = new WinToastLib::WinToastHandler;
WinToastLib::WinToast::instance()->setAppName(L"IW4x");
@ -170,13 +172,28 @@ namespace Components
void Toast::preDestroy()
{
// Destroying that on the main thread deadlocks, for whatever reason.
if (Dedicated::IsEnabled()) return;
// Destroying that on the main thread deadlocks.
// I did not write the library, so whatever.
std::thread([]()
// If we are not in the postgame state,
// we are not allowed to spawn threads,
// so just don't uninitialize the library.
// That means we did not uninitialize the game
// correctly anyways.
if (Loader::IsPostgame())
{
std::thread([]()
{
delete WinToastLib::WinToast::instance();
delete Toast::ToastHandler;
Toast::ToastHandler = nullptr;
}).join();
}
else
{
delete WinToastLib::WinToast::instance();
delete Toast::ToastHandler;
Toast::ToastHandler = nullptr;
}).join();
}
}
}

View File

@ -1,6 +1,6 @@
#pragma once
#define PROTOCOL 0x93
#define PROTOCOL 0x94
#define NUM_CUSTOM_CLASSES 15
// This allows us to compile our structures in IDA, for easier reversing :3

View File

@ -18,6 +18,10 @@ namespace Steam
Utils* Proxy::SteamUtils = nullptr;
User* Proxy::SteamUser_ = nullptr;
HANDLE Proxy::Process = nullptr;
HANDLE Proxy::CancelHandle = nullptr;
std::thread Proxy::WatchGuard;
uint32_t Proxy::AppId = 0;
std::recursive_mutex Proxy::CallMutex;
@ -325,6 +329,41 @@ namespace Steam
Proxy::UnregisterCalls();
}
void Proxy::LaunchWatchGuard()
{
if (Proxy::WatchGuard.joinable()) return;
HKEY hRegKey;
DWORD pid = 0;
if (RegOpenKeyExA(HKEY_CURRENT_USER, STEAM_REGISTRY_PROCESS_PATH, 0, KEY_QUERY_VALUE, &hRegKey) != ERROR_SUCCESS) return;
DWORD dwLength = sizeof(pid);
RegQueryValueExA(hRegKey, "pid", nullptr, nullptr, reinterpret_cast<BYTE*>(&pid), &dwLength);
RegCloseKey(hRegKey);
Proxy::CancelHandle = CreateEventA(nullptr, TRUE, FALSE, "CancelEvent");
if (!Proxy::CancelHandle) return;
Proxy::Process = OpenProcess(SYNCHRONIZE, FALSE, pid);
if (!Proxy::Process) return;
Proxy::WatchGuard = std::thread([]()
{
HANDLE handles[] = { Proxy::Process, Proxy::CancelHandle };
DWORD result = WaitForMultipleObjects(ARRAYSIZE(handles), handles, FALSE, INFINITE);
CloseHandle(Proxy::Process);
CloseHandle(Proxy::CancelHandle);
if (result == WAIT_OBJECT_0)
{
Proxy::SteamPipe = nullptr;
Proxy::SteamUser = nullptr;
Proxy::Uninititalize();
}
});
}
void Proxy::StartSteamIfNecessary()
{
if (Proxy::GetSteamDirectory().empty() || !Steam::Enabled()) return;
@ -348,6 +387,11 @@ namespace Steam
CloseHandle(hProcess);
});
allocator.reference(allocator.allocate(1), [](void*)
{
Proxy::LaunchWatchGuard();
});
DWORD exitCode;
if (!GetExitCodeProcess(process, &exitCode)) return;
if (exitCode == STILL_ACTIVE) return;
@ -375,6 +419,8 @@ namespace Steam
while (!interval.elapsed(15s) && !Proxy::GetActiveUser()) std::this_thread::sleep_for(10ms);
std::this_thread::sleep_for(1s);
}
Proxy::LaunchWatchGuard();
}
bool Proxy::Inititalize()
@ -442,6 +488,30 @@ namespace Steam
void Proxy::Uninititalize()
{
if(Proxy::WatchGuard.get_id() != std::this_thread::get_id() && Proxy::WatchGuard.joinable())
{
if (Proxy::CancelHandle)
{
SetEvent(Proxy::CancelHandle);
Proxy::WatchGuard.join();
}
else
{
Proxy::WatchGuard.detach();
}
}
Proxy::Process = nullptr;
Proxy::CancelHandle = nullptr;
Proxy::ClientEngine = nullptr;
Proxy::ClientUser = nullptr;
Proxy::ClientFriends = nullptr;
Proxy::SteamApps = nullptr;
Proxy::SteamFriends = nullptr;
Proxy::SteamUtils = nullptr;
Proxy::SteamUser_ = nullptr;
if (Proxy::SteamClient && Proxy::SteamPipe)
{
if (Proxy::SteamUser)
@ -452,6 +522,9 @@ namespace Steam
Proxy::SteamClient->ReleaseSteamPipe(Proxy::SteamPipe);
}
Proxy::SteamPipe = nullptr;
Proxy::SteamUser = nullptr;
Proxy::SteamClient = nullptr;
Proxy::Client = ::Utils::Library();
Proxy::Overlay = ::Utils::Library();
}

View File

@ -302,6 +302,10 @@ namespace Steam
static void* SteamPipe;
static void* SteamUser;
static HANDLE Process;
static HANDLE CancelHandle;
static std::thread WatchGuard;
static std::recursive_mutex CallMutex;
static std::vector<CallContainer> Calls;
static std::unordered_map<int32_t, void*> Callbacks;
@ -314,6 +318,7 @@ namespace Steam
static void UnregisterCalls();
static void StartSteamIfNecessary();
static void LaunchWatchGuard();
static void ResetActiveUser();
static uint32_t GetActiveUser();

View File

@ -9,7 +9,7 @@ namespace Utils
bool IsWineEnvironment();
template <typename T> void Merge(std::vector<T>* target, T* source, size_t length)
template <typename T> inline void Merge(std::vector<T>* target, T* source, size_t length)
{
if (source)
{
@ -20,7 +20,7 @@ namespace Utils
}
}
template <typename T> void Merge(std::vector<T>* target, std::vector<T> source)
template <typename T> inline void Merge(std::vector<T>* target, std::vector<T> source)
{
for (auto &entry : source)
{