diff --git a/r5dev/engine/net.cpp b/r5dev/engine/net.cpp index de76d444..476e307c 100644 --- a/r5dev/engine/net.cpp +++ b/r5dev/engine/net.cpp @@ -8,6 +8,7 @@ #include "engine/net.h" #ifndef NETCONSOLE #include "core/logdef.h" +#include "tier0/frametask.h" #include "tier1/cvar.h" #include "vstdlib/callback.h" #include "mathlib/color.h" @@ -140,7 +141,14 @@ void NET_PrintFunc(const char* fmt, ...) //----------------------------------------------------------------------------- void NET_Shutdown(void* thisptr, const char* szReason, uint8_t bBadRep, bool bRemoveNow) { - _DownloadPlaylists_f(); // Re-load playlist from disk after getting disconnected from the server. + if (!ThreadInMainThread()) + { + g_TaskScheduler->Dispatch([]() + { + // Re-load playlist from disk the next frame. + _DownloadPlaylists_f(); + }, 0); + } v_NET_Shutdown(thisptr, szReason, bBadRep, bRemoveNow); } diff --git a/r5dev/gameui/IBrowser.cpp b/r5dev/gameui/IBrowser.cpp index f4b62fcf..49796df2 100644 --- a/r5dev/gameui/IBrowser.cpp +++ b/r5dev/gameui/IBrowser.cpp @@ -14,6 +14,7 @@ History: #include "core/stdafx.h" #include "core/init.h" #include "core/resource.h" +#include "tier0/fasttimer.h" #include "tier0/frametask.h" #include "tier0/commandline.h" #include "tier1/IConVar.h" @@ -45,22 +46,12 @@ History: CBrowser::CBrowser(void) { memset(m_szServerAddressBuffer, '\0', sizeof(m_szServerAddressBuffer)); - static std::thread request([this]() - { - RefreshServerList(); -#ifndef CLIENT_DLL - while (true) - { - UpdateHostingStatus(); - std::this_thread::sleep_for(std::chrono::milliseconds(5000)); - } -#endif // !CLIENT_DLL - }); - request.detach(); + std::thread refresh(&CBrowser::RefreshServerList, this); + refresh.detach(); std::thread think(&CBrowser::Think, this); - think.detach(); + think.detach(); // !FIXME: Run from SDK MainFrame when finished. m_pszBrowserTitle = "Server Browser"; m_rLockedIconBlob = GetModuleResource(IDB_PNG2); @@ -132,6 +123,28 @@ void CBrowser::RunFrame(void) ImGui::PopStyleVar(nVars); } +//----------------------------------------------------------------------------- +// Purpose: runs tasks for the browser while not being drawn +// (!!! RunTask and RunFrame must be called from the same thread !!!) +//----------------------------------------------------------------------------- +void CBrowser::RunTask() +{ + static bool bInitialized = false; + static CFastTimer timer; + + if (!bInitialized) + { + timer.Start(); + bInitialized = true; + } + + if (timer.GetDurationInProgress().GetSeconds() > pylon_host_update_interval->GetDouble()) + { + UpdateHostingStatus(); + timer.Start(); + } +} + //----------------------------------------------------------------------------- // Purpose: think //----------------------------------------------------------------------------- @@ -159,6 +172,8 @@ void CBrowser::Think(void) //----------------------------------------------------------------------------- void CBrowser::DrawSurface(void) { + std::lock_guard l(m_Mutex); + ImGui::BeginTabBar("CompMenu"); if (ImGui::BeginTabItem("Browsing")) { @@ -190,7 +205,10 @@ void CBrowser::BrowserPanel(void) ImGui::SameLine(); if (ImGui::Button("Refresh List")) { - RefreshServerList(); + m_svServerListMessage.clear(); + + std::thread refresh(&CBrowser::RefreshServerList, this); + refresh.detach(); } ImGui::EndGroup(); ImGui::TextColored(ImVec4(1.00f, 0.00f, 0.00f, 1.00f), m_svServerListMessage.c_str()); @@ -219,10 +237,11 @@ void CBrowser::BrowserPanel(void) ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthStretch, 5); ImGui::TableHeadersRow(); - for (NetGameServer_t& server : g_pServerListManager->m_vServerList) + g_pServerListManager->m_Mutex.lock(); + for (const NetGameServer_t& server : g_pServerListManager->m_vServerList) { const char* pszHostName = server.m_svHostName.c_str(); - const char* pszHostMap = server.m_svMapName.c_str(); + const char* pszHostMap = server.m_svHostMap.c_str(); const char* pszPlaylist = server.m_svPlaylist.c_str(); const char* pszHostPort = server.m_svGamePort.c_str(); @@ -247,15 +266,16 @@ void CBrowser::BrowserPanel(void) ImGui::TableNextColumn(); string svConnectBtn = "Connect##"; - svConnectBtn.append(server.m_svHostName + server.m_svIpAddress + server.m_svMapName); + svConnectBtn.append(server.m_svHostName + server.m_svIpAddress + server.m_svHostMap); if (ImGui::Button(svConnectBtn.c_str())) { g_pServerListManager->ConnectToServer(server.m_svIpAddress, pszHostPort, server.m_svEncryptionKey); } } - } + g_pServerListManager->m_Mutex.unlock(); + ImGui::EndTable(); ImGui::PopStyleVar(nVars); } @@ -291,21 +311,13 @@ void CBrowser::BrowserPanel(void) //----------------------------------------------------------------------------- void CBrowser::RefreshServerList(void) { - static bool bThreadLocked = false; - m_svServerListMessage.clear(); + DevMsg(eDLL_T::CLIENT, "Refreshing server list with matchmaking host '%s'\n", pylon_matchmaking_hostname->GetString()); + + std::string svServerListMessage; + g_pServerListManager->RefreshServerList(svServerListMessage); - if (!bThreadLocked) - { - std::thread t([this]() - { - bThreadLocked = true; - DevMsg(eDLL_T::CLIENT, "Refreshing server list with matchmaking host '%s'\n", pylon_matchmaking_hostname->GetString()); - g_pServerListManager->GetServerList(m_svServerListMessage); - bThreadLocked = false; - }); - - t.detach(); - } + std::lock_guard l(m_Mutex); + m_svServerListMessage = svServerListMessage; } //----------------------------------------------------------------------------- @@ -380,7 +392,8 @@ void CBrowser::HiddenServersModal(void) void CBrowser::HostPanel(void) { #ifndef CLIENT_DLL - static string svServerNameErr = ""; + static string svServerNameErr = ""; // Member? + std::lock_guard l(g_pServerListManager->m_Mutex); ImGui::InputTextWithHint("##ServerHost_ServerName", "Server Name (Required)", &g_pServerListManager->m_Server.m_svHostName); ImGui::InputTextWithHint("##ServerHost_ServerDesc", "Server Description (Optional)", &g_pServerListManager->m_Server.m_svDescription); @@ -398,13 +411,13 @@ void CBrowser::HostPanel(void) ImGui::EndCombo(); } - if (ImGui::BeginCombo("Map##ServerHost_MapListBox", g_pServerListManager->m_Server.m_svMapName.c_str())) + if (ImGui::BeginCombo("Map##ServerHost_MapListBox", g_pServerListManager->m_Server.m_svHostMap.c_str())) { for (auto& item : g_vAllMaps) { - if (ImGui::Selectable(item.c_str(), item == g_pServerListManager->m_Server.m_svMapName)) + if (ImGui::Selectable(item.c_str(), item == g_pServerListManager->m_Server.m_svHostMap)) { - g_pServerListManager->m_Server.m_svMapName = item; + g_pServerListManager->m_Server.m_svHostMap = item; } } ImGui::EndCombo(); @@ -437,10 +450,9 @@ void CBrowser::HostPanel(void) if (ImGui::Button("Start Server", ImVec2((ImGui::GetWindowSize().x - 10), 32))) { svServerNameErr.clear(); - if (!g_pServerListManager->m_Server.m_svHostName.empty() && !g_pServerListManager->m_Server.m_svPlaylist.empty() && !g_pServerListManager->m_Server.m_svMapName.empty()) + if (!g_pServerListManager->m_Server.m_svHostName.empty() && !g_pServerListManager->m_Server.m_svPlaylist.empty() && !g_pServerListManager->m_Server.m_svHostMap.empty()) { g_pServerListManager->LaunchServer(); // Launch server. - UpdateHostingStatus(); // Update hosting status. } else { @@ -452,7 +464,7 @@ void CBrowser::HostPanel(void) { svServerNameErr = "No playlist assigned."; } - else if (g_pServerListManager->m_Server.m_svMapName.empty()) + else if (g_pServerListManager->m_Server.m_svHostMap.empty()) { svServerNameErr = "No level name assigned."; } @@ -463,10 +475,9 @@ void CBrowser::HostPanel(void) if (ImGui::Button("Force Start", ImVec2((ImGui::GetWindowSize().x - 10), 32))) { svServerNameErr.clear(); - if (!g_pServerListManager->m_Server.m_svPlaylist.empty() && !g_pServerListManager->m_Server.m_svMapName.empty()) + if (!g_pServerListManager->m_Server.m_svPlaylist.empty() && !g_pServerListManager->m_Server.m_svHostMap.empty()) { g_pServerListManager->LaunchServer(); // Launch server. - UpdateHostingStatus(); // Update hosting status. } else { @@ -474,7 +485,7 @@ void CBrowser::HostPanel(void) { svServerNameErr = "No playlist assigned."; } - else if (g_pServerListManager->m_Server.m_svMapName.empty()) + else if (g_pServerListManager->m_Server.m_svHostMap.empty()) { svServerNameErr = "No level name assigned."; } @@ -499,10 +510,9 @@ void CBrowser::HostPanel(void) if (ImGui::Button("Change Level", ImVec2((ImGui::GetWindowSize().x - 10), 32))) { - if (!g_pServerListManager->m_Server.m_svMapName.empty()) + if (!g_pServerListManager->m_Server.m_svHostMap.empty()) { - strncpy_s(g_pHostState->m_levelName, g_pServerListManager->m_Server.m_svMapName.c_str(), MAX_MAP_NAME); // Copy new map into hoststate levelname. - g_pHostState->m_iNextState = HostStates_t::HS_CHANGE_LEVEL_MP; // Force CHostState::FrameUpdate to change the level. + g_pServerListManager->LaunchServer(); } else { @@ -513,15 +523,22 @@ void CBrowser::HostPanel(void) if (ImGui::Button("Stop Server", ImVec2((ImGui::GetWindowSize().x - 10), 32))) { ProcessCommand("LeaveMatch"); // TODO: use script callback instead. - g_pHostState->m_iNextState = HostStates_t::HS_GAME_SHUTDOWN; // Force CHostState::FrameUpdate to shutdown the server for dedicated. + g_TaskScheduler->Dispatch([]() + { + // Force CHostState::FrameUpdate to shutdown the server for dedicated. + g_pHostState->m_iNextState = HostStates_t::HS_GAME_SHUTDOWN; + }, 0); } } else { if (ImGui::Button("Reload Playlist", ImVec2((ImGui::GetWindowSize().x - 10), 32))) { - _DownloadPlaylists_f(); - KeyValues::InitPlaylists(); // Re-Init playlist. + g_TaskScheduler->Dispatch([]() + { + _DownloadPlaylists_f(); + KeyValues::InitPlaylists(); // Re-Init playlist. + }, 0); } } #endif // !CLIENT_DLL @@ -538,7 +555,9 @@ void CBrowser::UpdateHostingStatus(void) return; } + std::lock_guard l(g_pServerListManager->m_Mutex); g_pServerListManager->m_HostingStatus = g_pHostState->m_bActiveGame ? EHostStatus_t::HOSTING : EHostStatus_t::NOT_HOSTING; // Are we hosting a server? + switch (g_pServerListManager->m_HostingStatus) { case EHostStatus_t::NOT_HOSTING: @@ -573,23 +592,7 @@ void CBrowser::UpdateHostingStatus(void) break; } - SendHostingPostRequest(); - break; - } - default: - break; - } -#endif // !CLIENT_DLL -} - -//----------------------------------------------------------------------------- -// Purpose: sends the hosting POST request to the comp server -//----------------------------------------------------------------------------- -void CBrowser::SendHostingPostRequest(void) -{ -#ifndef CLIENT_DLL - bool result = g_pMasterServer->PostServerHost(m_svHostRequestMessage, m_svHostToken, - NetGameServer_t + NetGameServer_t gameServer // !FIXME: create from main thread. { g_pServerListManager->m_Server.m_svHostName, g_pServerListManager->m_Server.m_svDescription, @@ -606,8 +609,34 @@ void CBrowser::SendHostingPostRequest(void) std::chrono::duration_cast( std::chrono::system_clock::now().time_since_epoch() ).count() - } - ); + }; + + std::thread post(&CBrowser::SendHostingPostRequest, this, gameServer); + post.detach(); + + break; + } + default: + break; + } +#endif // !CLIENT_DLL +} + +//----------------------------------------------------------------------------- +// Purpose: sends the hosting POST request to the comp server +// Input : &gameServer - +//----------------------------------------------------------------------------- +void CBrowser::SendHostingPostRequest(const NetGameServer_t& gameServer) +{ +#ifndef CLIENT_DLL + string svHostRequestMessage; + string svHostToken; + bool result = g_pMasterServer->PostServerHost(svHostRequestMessage, svHostToken, gameServer); + + std::lock_guard l(m_Mutex); + + m_svHostRequestMessage = svHostRequestMessage; + m_svHostToken = svHostToken; if (result) { @@ -634,7 +663,7 @@ void CBrowser::SendHostingPostRequest(void) void CBrowser::ProcessCommand(const char* pszCommand) const { Cbuf_AddText(Cbuf_GetCurrentPlayer(), pszCommand, cmd_source_t::kCommandSrcCode); - //g_DelayedCallTask->AddFunc(Cbuf_Execute, 0); // Run in main thread. + //g_TaskScheduler->Dispatch(Cbuf_Execute, 0); // Run in main thread. } //----------------------------------------------------------------------------- @@ -645,20 +674,26 @@ void CBrowser::SettingsPanel(void) ImGui::InputTextWithHint("Hostname", "Matchmaking Server String", &m_szMatchmakingHostName); if (ImGui::Button("Update Hostname")) { - pylon_matchmaking_hostname->SetValue(m_szMatchmakingHostName.c_str()); - if (g_pMasterServer) - { - delete g_pMasterServer; - g_pMasterServer = new CPylon(pylon_matchmaking_hostname->GetString()); - } + ProcessCommand(fmt::format("{:s} \"{:s}\"", "pylon_matchmaking_hostname", m_szMatchmakingHostName.c_str()).c_str()); } ImGui::InputText("Netkey", const_cast(g_svNetKey.c_str()), ImGuiInputTextFlags_ReadOnly); if (ImGui::Button("Regenerate Encryption Key")) { - NET_GenerateKey(); + g_TaskScheduler->Dispatch(NET_GenerateKey, 0); } } +//----------------------------------------------------------------------------- +// Purpose: hooked to 'MP_HostName_Changed_f' to sync hostname field with +// the 'pylon_matchmaking_hostname' ConVar (!!! DO NOT USE !!!). +// Input : *pszHostName - +//----------------------------------------------------------------------------- +void CBrowser::SetHostName(const char* pszHostName) +{ + std::lock_guard l(m_Mutex); + m_szMatchmakingHostName = pszHostName; +} + //----------------------------------------------------------------------------- // Purpose: sets the browser front-end style //----------------------------------------------------------------------------- diff --git a/r5dev/gameui/IBrowser.h b/r5dev/gameui/IBrowser.h index e822af84..b906a243 100644 --- a/r5dev/gameui/IBrowser.h +++ b/r5dev/gameui/IBrowser.h @@ -17,7 +17,7 @@ public: virtual void Think(void); virtual void RunFrame(void); - virtual void RunTask(void){}; + virtual void RunTask(void); virtual void DrawSurface(void); @@ -28,16 +28,18 @@ public: void HostPanel(void); void UpdateHostingStatus(void); - void SendHostingPostRequest(void); + void SendHostingPostRequest(const NetGameServer_t& gameServer); void ProcessCommand(const char* pszCommand) const; void SettingsPanel(void); + void SetHostName(const char* pszHostName); virtual void SetStyleVar(void); const char* m_pszBrowserTitle = nullptr; bool m_bActivate = false; + private: bool m_bInitialized = false; char m_szServerAddressBuffer[256] = { '\0' }; @@ -46,7 +48,8 @@ private: ImGuiStyle_t m_Style = ImGuiStyle_t::NONE; ID3D11ShaderResourceView* m_idLockedIcon = nullptr; - MODULERESOURCE m_rLockedIconBlob; + MODULERESOURCE m_rLockedIconBlob; + mutable std::mutex m_Mutex; //////////////////// // Server List // diff --git a/r5dev/gameui/IConsole.cpp b/r5dev/gameui/IConsole.cpp index 5004a1f4..c81eff08 100644 --- a/r5dev/gameui/IConsole.cpp +++ b/r5dev/gameui/IConsole.cpp @@ -43,7 +43,7 @@ CConsole::CConsole(void) snprintf(m_szSummary, sizeof(m_szSummary), "%zu history items", m_vHistory.size()); std::thread think(&CConsole::Think, this); - think.detach(); + think.detach(); // !FIXME: Run from SDK MainFrame when finished. } //----------------------------------------------------------------------------- @@ -528,7 +528,7 @@ void CConsole::ProcessCommand(const char* pszCommand) DevMsg(eDLL_T::COMMON, "] %s\n", pszCommand); Cbuf_AddText(Cbuf_GetCurrentPlayer(), pszCommand, cmd_source_t::kCommandSrcCode); - //g_DelayedCallTask->AddFunc(Cbuf_Execute, 0); // Run in main thread. + //g_TaskScheduler->Dispatch(Cbuf_Execute, 0); // Run in main thread. m_nHistoryPos = -1; for (size_t i = m_vHistory.size(); i-- > 0; ) diff --git a/r5dev/launcher/IApplication.cpp b/r5dev/launcher/IApplication.cpp index cd1d3abe..0b0e395d 100644 --- a/r5dev/launcher/IApplication.cpp +++ b/r5dev/launcher/IApplication.cpp @@ -93,7 +93,7 @@ bool CModAppSystemGroup::Create(CModAppSystemGroup* pModAppSystemGroup) g_pHLClient = nullptr; } - g_FrameTasks.push_back(std::move(g_DelayedCallTask)); + g_FrameTasks.push_back(std::move(g_TaskScheduler)); g_bAppSystemInit = true; return CModAppSystemGroup_Create(pModAppSystemGroup); diff --git a/r5dev/netconsole/netconsole.cpp b/r5dev/netconsole/netconsole.cpp index b856b438..1be07505 100644 --- a/r5dev/netconsole/netconsole.cpp +++ b/r5dev/netconsole/netconsole.cpp @@ -54,8 +54,14 @@ bool CNetCon::Init(void) this->TermSetup(); - std::thread tFrame(&CNetCon::RunFrame, this); - tFrame.detach(); + static std::thread frame([this]() + { + for (;;) + { + this->RunFrame(); + } + }); + frame.detach(); return true; } @@ -130,6 +136,8 @@ void CNetCon::UserInput(void) m_bQuitApplication = true; return; } + + std::lock_guard l(m_Mutex); if (m_abConnEstablished) { if (svInput.compare("disconnect") == 0) @@ -202,18 +210,17 @@ void CNetCon::UserInput(void) //----------------------------------------------------------------------------- void CNetCon::RunFrame(void) { - for (;;) + if (m_abConnEstablished) { - if (m_abConnEstablished) - { - std::this_thread::sleep_for(std::chrono::milliseconds(50)); - this->Recv(); - } - else if (m_abPromptConnect) - { - std::cout << "Enter : "; - m_abPromptConnect = false; - } + std::this_thread::sleep_for(std::chrono::milliseconds(50)); + std::lock_guard l(m_Mutex); + + this->Recv(); + } + else if (m_abPromptConnect) + { + std::cout << "Enter : "; + m_abPromptConnect = false; } } diff --git a/r5dev/netconsole/netconsole.h b/r5dev/netconsole/netconsole.h index 93f707d5..1a50adfc 100644 --- a/r5dev/netconsole/netconsole.h +++ b/r5dev/netconsole/netconsole.h @@ -45,4 +45,6 @@ private: bool m_bQuitApplication; std::atomic m_abPromptConnect; std::atomic m_abConnEstablished; + + mutable std::mutex m_Mutex; }; \ No newline at end of file diff --git a/r5dev/networksystem/listmanager.cpp b/r5dev/networksystem/listmanager.cpp index 18422a43..bf9db4aa 100644 --- a/r5dev/networksystem/listmanager.cpp +++ b/r5dev/networksystem/listmanager.cpp @@ -7,6 +7,7 @@ //=============================================================================// #include "core/stdafx.h" +#include "tier0/threadtools.h" #include "tier0/frametask.h" #include "tier1/cmd.h" #include "tier1/cvar.h" @@ -26,13 +27,28 @@ CServerListManager::CServerListManager(void) } //----------------------------------------------------------------------------- -// Purpose: get server list from pylon. +// Purpose: get server list from pylon // Input : &svMessage - +// Output : amount of servers found //----------------------------------------------------------------------------- -void CServerListManager::GetServerList(string& svMessage) +size_t CServerListManager::RefreshServerList(string& svMessage) { + ClearServerList(); + vector vServerList = g_pMasterServer->GetServerList(svMessage); + + std::lock_guard l(m_Mutex); + m_vServerList = vServerList; + + return m_vServerList.size(); +} + +//----------------------------------------------------------------------------- +// Purpose: clears the server list +//----------------------------------------------------------------------------- +void CServerListManager::ClearServerList(void) +{ + std::lock_guard l(m_Mutex); m_vServerList.clear(); - m_vServerList = g_pMasterServer->GetServerList(svMessage); } //----------------------------------------------------------------------------- @@ -41,23 +57,32 @@ void CServerListManager::GetServerList(string& svMessage) void CServerListManager::LaunchServer(void) const { #ifndef CLIENT_DLL - DevMsg(eDLL_T::ENGINE, "Starting server with name: \"%s\" map: \"%s\" playlist: \"%s\"\n", m_Server.m_svHostName.c_str(), m_Server.m_svMapName.c_str(), m_Server.m_svPlaylist.c_str()); + + if (!ThreadInMainThread()) + { + g_TaskScheduler->Dispatch([this]() + { + this->LaunchServer(); + }, 0); + return; + } + + DevMsg(eDLL_T::ENGINE, "Starting server with name: \"%s\" map: \"%s\" playlist: \"%s\"\n", m_Server.m_svHostName.c_str(), m_Server.m_svHostMap.c_str(), m_Server.m_svPlaylist.c_str()); /* * Playlist gets parsed in two instances, first in KeyValues::ParsePlaylists with all the neccessary values. * Then when you would normally call launchplaylist which calls StartPlaylist it would cmd call mp_gamemode which parses the gamemode specific part of the playlist.. */ KeyValues::ParsePlaylists(m_Server.m_svPlaylist.c_str()); - mp_gamemode->SetValue(m_Server.m_svPlaylist.c_str()); if (g_pHostState->m_bActiveGame) { - ProcessCommand(fmt::format("{:s} \"{:s}\"", "changelevel", m_Server.m_svMapName).c_str()); + ProcessCommand(fmt::format("{:s} \"{:s}\"", "changelevel", m_Server.m_svHostMap).c_str()); } else // Initial launch. { - ProcessCommand(fmt::format("{:s} \"{:s}\"", "map", m_Server.m_svMapName).c_str()); + ProcessCommand(fmt::format("{:s} \"{:s}\"", "map", m_Server.m_svHostMap).c_str()); } #endif // !CLIENT_DLL @@ -99,7 +124,7 @@ void CServerListManager::ConnectToServer(const string& svServer, const string& s void CServerListManager::ProcessCommand(const char* pszCommand) const { Cbuf_AddText(Cbuf_GetCurrentPlayer(), pszCommand, cmd_source_t::kCommandSrcCode); - //g_DelayedCallTask->AddFunc(Cbuf_Execute, 0); // Run in main thread. + //g_TaskScheduler->Dispatch(Cbuf_Execute, 0); // Run in main thread. } CServerListManager* g_pServerListManager = new CServerListManager(); \ No newline at end of file diff --git a/r5dev/networksystem/listmanager.h b/r5dev/networksystem/listmanager.h index af322c48..5849084e 100644 --- a/r5dev/networksystem/listmanager.h +++ b/r5dev/networksystem/listmanager.h @@ -4,35 +4,38 @@ enum EHostStatus_t { - NOT_HOSTING, - HOSTING + NOT_HOSTING, + HOSTING }; enum EServerVisibility_t { - OFFLINE, - HIDDEN, - PUBLIC + OFFLINE, + HIDDEN, + PUBLIC }; class CServerListManager { public: - CServerListManager(); + CServerListManager(); - void GetServerList(string& svMessage); + size_t RefreshServerList(string& svMessage); + void ClearServerList(void); - void LaunchServer(void) const; - void ConnectToServer(const string& svIp, const string& svPort, const string& svNetKey) const; - void ConnectToServer(const string& svServer, const string& svNetKey) const; + void LaunchServer(void) const; + void ConnectToServer(const string& svIp, const string& svPort, const string& svNetKey) const; + void ConnectToServer(const string& svServer, const string& svNetKey) const; - void ProcessCommand(const char* pszCommand) const; + void ProcessCommand(const char* pszCommand) const; - EHostStatus_t m_HostingStatus; + EHostStatus_t m_HostingStatus; EServerVisibility_t m_ServerVisibility; NetGameServer_t m_Server; vector m_vServerList; + + mutable std::mutex m_Mutex; }; extern CServerListManager* g_pServerListManager; diff --git a/r5dev/networksystem/pylon.cpp b/r5dev/networksystem/pylon.cpp index fd20fff0..08b47f97 100644 --- a/r5dev/networksystem/pylon.cpp +++ b/r5dev/networksystem/pylon.cpp @@ -71,15 +71,17 @@ vector CPylon::GetServerList(string& svOutMessage) DevMsg(eDLL_T::ENGINE, "%s - Sending server list request to comp-server:\n%s\n", __FUNCTION__, svRequestBody.c_str()); } - httplib::Result htResults = m_HttpClient.Post("/servers", jsRequestBody.dump(4).c_str(), jsRequestBody.dump(4).length(), "application/json"); - if (htResults && pylon_showdebug->GetBool()) + httplib::Client htClient(pylon_matchmaking_hostname->GetString()); htClient.set_connection_timeout(10); + httplib::Result htResult = htClient.Post("/servers", jsRequestBody.dump(4).c_str(), jsRequestBody.dump(4).length(), "application/json"); + + if (htResult && pylon_showdebug->GetBool()) { - DevMsg(eDLL_T::ENGINE, "%s - replied with '%d'.\n", __FUNCTION__, htResults->status); + DevMsg(eDLL_T::ENGINE, "%s - replied with '%d'.\n", __FUNCTION__, htResult->status); } - if (htResults && htResults->status == 200) // STATUS_OK + if (htResult && htResult->status == 200) // STATUS_OK { - nlohmann::json jsResultBody = nlohmann::json::parse(htResults->body); + nlohmann::json jsResultBody = nlohmann::json::parse(htResult->body); if (jsResultBody["success"].is_boolean() && jsResultBody["success"].get()) { for (auto& obj : jsResultBody["servers"]) @@ -120,11 +122,11 @@ vector CPylon::GetServerList(string& svOutMessage) } else { - if (htResults) + if (htResult) { - if (!htResults->body.empty()) + if (!htResult->body.empty()) { - nlohmann::json jsResultBody = nlohmann::json::parse(htResults->body); + nlohmann::json jsResultBody = nlohmann::json::parse(htResult->body); if (jsResultBody["err"].is_string()) { @@ -132,13 +134,13 @@ vector CPylon::GetServerList(string& svOutMessage) } else { - svOutMessage = string("Failed to reach comp-server: ") + std::to_string(htResults->status); + svOutMessage = string("Failed to reach comp-server: ") + std::to_string(htResult->status); } return vslList; } - svOutMessage = string("Failed to reach comp-server: ") + std::to_string(htResults->status); + svOutMessage = string("Failed to reach comp-server: ") + std::to_string(htResult->status); return vslList; } @@ -162,7 +164,7 @@ bool CPylon::PostServerHost(string& svOutMessage, string& svOutToken, const NetG jsRequestBody["name"] = slServerListing.m_svHostName; jsRequestBody["description"] = slServerListing.m_svDescription; jsRequestBody["hidden"] = slServerListing.m_bHidden; - jsRequestBody["map"] = slServerListing.m_svMapName; + jsRequestBody["map"] = slServerListing.m_svHostMap; jsRequestBody["playlist"] = slServerListing.m_svPlaylist; jsRequestBody["ip"] = slServerListing.m_svIpAddress; jsRequestBody["port"] = slServerListing.m_svGamePort; @@ -181,15 +183,17 @@ bool CPylon::PostServerHost(string& svOutMessage, string& svOutToken, const NetG DevMsg(eDLL_T::ENGINE, "%s - Sending post host request to comp-server:\n%s\n", __FUNCTION__, svRequestBody.c_str()); } - httplib::Result htResults = m_HttpClient.Post("/servers/add", svRequestBody.c_str(), svRequestBody.length(), "application/json"); - if (htResults && pylon_showdebug->GetBool()) + httplib::Client htClient(pylon_matchmaking_hostname->GetString()); htClient.set_connection_timeout(10); + httplib::Result htResult = htClient.Post("/servers/add", svRequestBody.c_str(), svRequestBody.length(), "application/json"); + + if (htResult && pylon_showdebug->GetBool()) { - DevMsg(eDLL_T::ENGINE, "%s - Comp-server replied with '%d'\n", __FUNCTION__, htResults->status); + DevMsg(eDLL_T::ENGINE, "%s - Comp-server replied with '%d'\n", __FUNCTION__, htResult->status); } - if (htResults && htResults->status == 200) // STATUS_OK + if (htResult && htResult->status == 200) // STATUS_OK { - nlohmann::json jsResultBody = nlohmann::json::parse(htResults->body); + nlohmann::json jsResultBody = nlohmann::json::parse(htResult->body); if (jsResultBody["success"].is_boolean() && jsResultBody["success"].get()) { if (jsResultBody["token"].is_string()) @@ -218,11 +222,11 @@ bool CPylon::PostServerHost(string& svOutMessage, string& svOutToken, const NetG } else { - if (htResults) + if (htResult) { - if (!htResults->body.empty()) + if (!htResult->body.empty()) { - nlohmann::json jsResultBody = nlohmann::json::parse(htResults->body); + nlohmann::json jsResultBody = nlohmann::json::parse(htResult->body); if (jsResultBody["err"].is_string()) { @@ -230,7 +234,7 @@ bool CPylon::PostServerHost(string& svOutMessage, string& svOutToken, const NetG } else { - svOutMessage = string("Failed to reach comp-server ") + std::to_string(htResults->status); + svOutMessage = string("Failed to reach comp-server ") + std::to_string(htResult->status); } svOutToken = string(); @@ -238,7 +242,7 @@ bool CPylon::PostServerHost(string& svOutMessage, string& svOutToken, const NetG } svOutToken = string(); - svOutMessage = string("Failed to reach comp-server: ") + std::to_string(htResults->status); + svOutMessage = string("Failed to reach comp-server: ") + std::to_string(htResult->status); return false; } @@ -269,20 +273,21 @@ bool CPylon::GetServerByToken(NetGameServer_t& slOutServer, string& svOutMessage DevMsg(eDLL_T::ENGINE, "%s - Sending token connect request to comp-server:\n%s\n", __FUNCTION__, svRequestBody.c_str()); } - httplib::Result htResults = m_HttpClient.Post("/server/byToken", jsRequestBody.dump(4).c_str(), jsRequestBody.dump(4).length(), "application/json"); + httplib::Client htClient(pylon_matchmaking_hostname->GetString()); htClient.set_connection_timeout(10); + httplib::Result htResult = htClient.Post("/server/byToken", jsRequestBody.dump(4).c_str(), jsRequestBody.dump(4).length(), "application/json"); if (pylon_showdebug->GetBool()) { - DevMsg(eDLL_T::ENGINE, "%s - Comp-server replied with '%d'\n", __FUNCTION__, htResults->status); + DevMsg(eDLL_T::ENGINE, "%s - Comp-server replied with '%d'\n", __FUNCTION__, htResult->status); } - if (htResults && htResults->status == 200) // STATUS_OK + if (htResult && htResult->status == 200) // STATUS_OK { - if (!htResults->body.empty()) + if (!htResult->body.empty()) { - nlohmann::json jsResultBody = nlohmann::json::parse(htResults->body); + nlohmann::json jsResultBody = nlohmann::json::parse(htResult->body); - if (htResults && jsResultBody["success"].is_boolean() && jsResultBody["success"]) + if (htResult && jsResultBody["success"].is_boolean() && jsResultBody["success"]) { slOutServer = NetGameServer_t { @@ -322,11 +327,11 @@ bool CPylon::GetServerByToken(NetGameServer_t& slOutServer, string& svOutMessage } else { - if (htResults) + if (htResult) { - if (!htResults->body.empty()) + if (!htResult->body.empty()) { - nlohmann::json jsResultBody = nlohmann::json::parse(htResults->body); + nlohmann::json jsResultBody = nlohmann::json::parse(htResult->body); if (jsResultBody["err"].is_string()) { @@ -334,13 +339,13 @@ bool CPylon::GetServerByToken(NetGameServer_t& slOutServer, string& svOutMessage } else { - svOutMessage = string("Failed to reach comp-server: ") + std::to_string(htResults->status); + svOutMessage = string("Failed to reach comp-server: ") + std::to_string(htResult->status); } return false; } - svOutMessage = string("Failed to reach comp-server: ") + std::to_string(htResults->status); + svOutMessage = string("Failed to reach comp-server: ") + std::to_string(htResult->status); return false; } @@ -365,10 +370,12 @@ bool CPylon::GetClientIsBanned(const string& svIpAddress, uint64_t nOriginID, st jsRequestBody["oid"] = nOriginID; jsRequestBody["ip"] = svIpAddress; - httplib::Result htResults = m_HttpClient.Post("/banlist/isBanned", jsRequestBody.dump(4).c_str(), jsRequestBody.dump(4).length(), "application/json"); - if (htResults && htResults->status == 200) + httplib::Client htClient(pylon_matchmaking_hostname->GetString()); htClient.set_connection_timeout(10); + httplib::Result htResult = htClient.Post("/banlist/isBanned", jsRequestBody.dump(4).c_str(), jsRequestBody.dump(4).length(), "application/json"); + + if (htResult && htResult->status == 200) { - nlohmann::json jsResultBody = nlohmann::json::parse(htResults->body); + nlohmann::json jsResultBody = nlohmann::json::parse(htResult->body); if (jsResultBody["success"].is_boolean() && jsResultBody["success"].get()) { if (jsResultBody["banned"].is_boolean() && jsResultBody["banned"].get()) @@ -381,4 +388,4 @@ bool CPylon::GetClientIsBanned(const string& svIpAddress, uint64_t nOriginID, st return false; } /////////////////////////////////////////////////////////////////////////////// -CPylon* g_pMasterServer(new CPylon("r5a-comp-sv.herokuapp.com")); +CPylon* g_pMasterServer(new CPylon()); diff --git a/r5dev/networksystem/pylon.h b/r5dev/networksystem/pylon.h index 9640f493..c5b0b81d 100644 --- a/r5dev/networksystem/pylon.h +++ b/r5dev/networksystem/pylon.h @@ -6,20 +6,9 @@ void KeepAliveToPylon(); class CPylon { public: - CPylon(string serverString) : m_HttpClient(serverString.c_str()) - { - m_HttpClient.set_connection_timeout(10); - } - vector GetServerList(string& svOutMessage); bool PostServerHost(string& svOutMessage, string& svOutToken, const NetGameServer_t& slServerListing); bool GetServerByToken(NetGameServer_t& slOutServer, string& svOutMessage, const string& svToken); bool GetClientIsBanned(const string& svIpAddress, uint64_t nOriginID, string& svOutErrCl); - - CPylon* pR5net = nullptr; - CPylon* GetR5Net() { return pR5net; } - -private: - httplib::Client m_HttpClient; }; extern CPylon* g_pMasterServer; diff --git a/r5dev/networksystem/serverlisting.h b/r5dev/networksystem/serverlisting.h index b4c74f95..b838fd7d 100644 --- a/r5dev/networksystem/serverlisting.h +++ b/r5dev/networksystem/serverlisting.h @@ -17,7 +17,7 @@ struct NetGameServer_t string m_svDescription; bool m_bHidden; - string m_svMapName = "mp_lobby"; + string m_svHostMap = "mp_lobby"; string m_svPlaylist = "dev_default"; string m_svIpAddress; diff --git a/r5dev/squirrel/sqinit.cpp b/r5dev/squirrel/sqinit.cpp index 225c2c57..4465ef06 100644 --- a/r5dev/squirrel/sqinit.cpp +++ b/r5dev/squirrel/sqinit.cpp @@ -123,11 +123,26 @@ namespace VSquirrel } namespace UI { + //----------------------------------------------------------------------------- + // Purpose: refreshes the server list + //----------------------------------------------------------------------------- + SQRESULT RefreshServerCount(HSQUIRRELVM v) + { + string svMessage; // Refresh svListing list. + size_t iCount = g_pServerListManager->RefreshServerList(svMessage); + + sq_pushinteger(v, static_cast(iCount)); + + return SQ_OK; + } + //----------------------------------------------------------------------------- // Purpose: get server's current name from serverlist index //----------------------------------------------------------------------------- SQRESULT GetServerName(HSQUIRRELVM v) { + std::lock_guard l(g_pServerListManager->m_Mutex); + SQInteger iServer = sq_getinteger(v, 1); SQInteger iCount = static_cast(g_pServerListManager->m_vServerList.size()); @@ -148,6 +163,8 @@ namespace VSquirrel //----------------------------------------------------------------------------- SQRESULT GetServerDescription(HSQUIRRELVM v) { + std::lock_guard l(g_pServerListManager->m_Mutex); + SQInteger iServer = sq_getinteger(v, 1); SQInteger iCount = static_cast(g_pServerListManager->m_vServerList.size()); @@ -168,6 +185,8 @@ namespace VSquirrel //----------------------------------------------------------------------------- SQRESULT GetServerMap(HSQUIRRELVM v) { + std::lock_guard l(g_pServerListManager->m_Mutex); + SQInteger iServer = sq_getinteger(v, 1); SQInteger iCount = static_cast(g_pServerListManager->m_vServerList.size()); @@ -177,7 +196,7 @@ namespace VSquirrel return SQ_ERROR; } - string svServerMapName = g_pServerListManager->m_vServerList[iServer].m_svMapName; + string svServerMapName = g_pServerListManager->m_vServerList[iServer].m_svHostMap; sq_pushstring(v, svServerMapName.c_str(), -1); return SQ_OK; @@ -188,6 +207,8 @@ namespace VSquirrel //----------------------------------------------------------------------------- SQRESULT GetServerPlaylist(HSQUIRRELVM v) { + std::lock_guard l(g_pServerListManager->m_Mutex); + SQInteger iServer = sq_getinteger(v, 1); SQInteger iCount = static_cast(g_pServerListManager->m_vServerList.size()); @@ -208,6 +229,8 @@ namespace VSquirrel //----------------------------------------------------------------------------- SQRESULT GetServerCurrentPlayers(HSQUIRRELVM v) { + std::lock_guard l(g_pServerListManager->m_Mutex); + SQInteger iServer = sq_getinteger(v, 1); SQInteger iCount = static_cast(g_pServerListManager->m_vServerList.size()); @@ -227,6 +250,8 @@ namespace VSquirrel //----------------------------------------------------------------------------- SQRESULT GetServerMaxPlayers(HSQUIRRELVM v) { + std::lock_guard l(g_pServerListManager->m_Mutex); + SQInteger iServer = sq_getinteger(v, 1); SQInteger iCount = static_cast(g_pServerListManager->m_vServerList.size()); @@ -246,10 +271,8 @@ namespace VSquirrel //----------------------------------------------------------------------------- SQRESULT GetServerCount(HSQUIRRELVM v) { - string svMessage; - - g_pServerListManager->GetServerList(svMessage); // Refresh svListing list. - sq_pushinteger(v, static_cast(g_pServerListManager->m_vServerList.size())); + size_t iCount = g_pServerListManager->m_vServerList.size(); + sq_pushinteger(v, static_cast(iCount)); return SQ_OK; } @@ -320,6 +343,8 @@ namespace VSquirrel //----------------------------------------------------------------------------- SQRESULT SetEncKeyAndConnect(HSQUIRRELVM v) { + std::lock_guard l(g_pServerListManager->m_Mutex); + SQInteger iServer = sq_getinteger(v, 1); SQInteger iCount = static_cast(g_pServerListManager->m_vServerList.size()); @@ -351,9 +376,11 @@ namespace VSquirrel return SQ_OK; // Adjust browser settings. + std::lock_guard l(g_pServerListManager->m_Mutex); + g_pServerListManager->m_Server.m_svHostName = svServerName; g_pServerListManager->m_Server.m_svDescription = svServerDescription; - g_pServerListManager->m_Server.m_svMapName = svServerMapName; + g_pServerListManager->m_Server.m_svHostMap = svServerMapName; g_pServerListManager->m_Server.m_svPlaylist = svServerPlaylist; g_pServerListManager->m_ServerVisibility = eServerVisibility; diff --git a/r5dev/squirrel/sqinit.h b/r5dev/squirrel/sqinit.h index 4d857d62..7b5cc778 100644 --- a/r5dev/squirrel/sqinit.h +++ b/r5dev/squirrel/sqinit.h @@ -37,6 +37,7 @@ namespace VSquirrel } namespace UI { + SQRESULT RefreshServerCount(HSQUIRRELVM v); SQRESULT GetServerName(HSQUIRRELVM v); SQRESULT GetServerDescription(HSQUIRRELVM v); SQRESULT GetServerMap(HSQUIRRELVM v); diff --git a/r5dev/squirrel/sqscript.cpp b/r5dev/squirrel/sqscript.cpp index c9ef30bc..47bd4450 100644 --- a/r5dev/squirrel/sqscript.cpp +++ b/r5dev/squirrel/sqscript.cpp @@ -81,6 +81,8 @@ void Script_RegisterUIFunctions(CSquirrelVM* pSquirrelVM) { Script_RegisterFunction(pSquirrelVM, "SDKNativeTest", "Script_SDKNativeTest", "Native UI test function", "void", "", &VSquirrel::SHARED::SDKNativeTest); + Script_RegisterFunction(pSquirrelVM, "RefreshServerList", "Script_RefreshServerList", "Refreshes the public server list and returns the count", "int", "", &VSquirrel::UI::RefreshServerCount); + // Functions for retrieving server browser data Script_RegisterFunction(pSquirrelVM, "GetServerName", "Script_GetServerName", "Gets the name of the server at the specified index of the server list", "string", "int", &VSquirrel::UI::GetServerName); Script_RegisterFunction(pSquirrelVM, "GetServerDescription", "Script_GetServerDescription", "Gets the description of the server at the specified index of the server list", "string", "int", &VSquirrel::UI::GetServerDescription); @@ -249,7 +251,7 @@ void Script_Execute(const SQChar* code, SQCONTEXT context) { if (!ThreadInMainThread()) { - g_DelayedCallTask->AddFunc([code, context]() + g_TaskScheduler->Dispatch([code, context]() { string scode(code); Script_Execute(scode.c_str(), context); diff --git a/r5dev/tier0/frametask.cpp b/r5dev/tier0/frametask.cpp index 9b89f103..e0f2deaa 100644 --- a/r5dev/tier0/frametask.cpp +++ b/r5dev/tier0/frametask.cpp @@ -44,7 +44,7 @@ bool CFrameTask::IsFinished() const // Input : functor - // frames - //----------------------------------------------------------------------------- -void CFrameTask::AddFunc(std::function functor, int frames) +void CFrameTask::Dispatch(std::function functor, int frames) { std::lock_guard l(m_Mutex); m_DelayedCalls.emplace_back(frames, functor); @@ -52,4 +52,4 @@ void CFrameTask::AddFunc(std::function functor, int frames) //----------------------------------------------------------------------------- std::list g_FrameTasks; -CFrameTask* g_DelayedCallTask = new CFrameTask(); +CFrameTask* g_TaskScheduler = new CFrameTask(); diff --git a/r5dev/tier0/frametask.h b/r5dev/tier0/frametask.h index 15cd3c06..44420e61 100644 --- a/r5dev/tier0/frametask.h +++ b/r5dev/tier0/frametask.h @@ -3,6 +3,13 @@ #include "public/iframetask.h" +//=============================================================================// +// This class is set up to run before each frame (main thread). +// Commited tasks are scheduled to execute after 'i' frames. +// ---------------------------------------------------------------------------- +// A usecase for scheduling tasks in the main thread would be (for example) +// calling 'KeyValues::ParsePlaylists(...)' from the render thread. +//=============================================================================// class CFrameTask : public IFrameTask { public: @@ -10,14 +17,14 @@ public: virtual void RunFrame(); virtual bool IsFinished() const; - void AddFunc(std::function functor, int frames); + void Dispatch(std::function functor, int frames); private: - std::mutex m_Mutex; + mutable std::mutex m_Mutex; std::list m_DelayedCalls; }; extern std::list g_FrameTasks; -extern CFrameTask* g_DelayedCallTask; +extern CFrameTask* g_TaskScheduler; #endif // TIER0_FRAMETASK_H diff --git a/r5dev/tier1/IConVar.cpp b/r5dev/tier1/IConVar.cpp index 254dafb1..7b034a92 100644 --- a/r5dev/tier1/IConVar.cpp +++ b/r5dev/tier1/IConVar.cpp @@ -199,7 +199,8 @@ void ConVar::Init(void) const net_useRandomKey = ConVar::Create("net_useRandomKey" , "1" , FCVAR_RELEASE , "Use random base64 netkey for game packets.", false, 0.f, false, 0.f, nullptr, nullptr); //------------------------------------------------------------------------- // NETWORKSYSTEM | - pylon_matchmaking_hostname = ConVar::Create("pylon_matchmaking_hostname", "r5a-comp-sv.herokuapp.com", FCVAR_RELEASE , "Holds the pylon matchmaking hostname.", false, 0.f, false, 0.f, nullptr, nullptr); + pylon_matchmaking_hostname = ConVar::Create("pylon_matchmaking_hostname", "r5a-comp-sv.herokuapp.com", FCVAR_RELEASE , "Holds the pylon matchmaking hostname.", false, 0.f, false, 0.f, &MP_HostName_Changed_f, nullptr); + pylon_host_update_interval = ConVar::Create("pylon_host_update_interval", "5" , FCVAR_RELEASE , "Length of time in seconds between each status update interval to master server.", true, 5.f, false, 0.f, nullptr, nullptr); pylon_showdebug = ConVar::Create("pylon_showdebug" , "0" , FCVAR_DEVELOPMENTONLY, "Shows debug output for pylon.", false, 0.f, false, 0.f, nullptr, nullptr); //------------------------------------------------------------------------- // RTECH API | diff --git a/r5dev/tier1/cvar.cpp b/r5dev/tier1/cvar.cpp index b90b6baf..2164f462 100644 --- a/r5dev/tier1/cvar.cpp +++ b/r5dev/tier1/cvar.cpp @@ -166,6 +166,7 @@ ConVar* net_encryptionEnable = nullptr; ConVar* net_useRandomKey = nullptr; ConVar* net_usesocketsforloopback = nullptr; ConVar* pylon_matchmaking_hostname = nullptr; +ConVar* pylon_host_update_interval = nullptr; ConVar* pylon_showdebug = nullptr; //----------------------------------------------------------------------------- // RTECH API | diff --git a/r5dev/tier1/cvar.h b/r5dev/tier1/cvar.h index 739d0afb..9c815b91 100644 --- a/r5dev/tier1/cvar.h +++ b/r5dev/tier1/cvar.h @@ -161,6 +161,7 @@ extern ConVar* net_encryptionEnable; extern ConVar* net_useRandomKey; extern ConVar* net_usesocketsforloopback; extern ConVar* pylon_matchmaking_hostname; +extern ConVar* pylon_host_update_interval; extern ConVar* pylon_showdebug; //------------------------------------------------------------------------- // RTECH API | diff --git a/r5dev/vstdlib/callback.cpp b/r5dev/vstdlib/callback.cpp index 5934a010..458d014f 100644 --- a/r5dev/vstdlib/callback.cpp +++ b/r5dev/vstdlib/callback.cpp @@ -61,6 +61,18 @@ void MP_GameMode_Changed_f(IConVar* pConVar, const char* pOldString, float flOld SetupGamemode(mp_gamemode->GetString()); } +/* +===================== +MP_HostName_Changed_f +===================== +*/ +void MP_HostName_Changed_f(IConVar* pConVar, const char* pOldString, float flOldValue) +{ +#ifndef DEDICATED + g_pBrowser->SetHostName(pylon_matchmaking_hostname->GetString()); +#endif // !DEDICATED +} + #ifndef DEDICATED /* ===================== diff --git a/r5dev/vstdlib/callback.h b/r5dev/vstdlib/callback.h index a560bc38..643d62a3 100644 --- a/r5dev/vstdlib/callback.h +++ b/r5dev/vstdlib/callback.h @@ -5,14 +5,12 @@ inline CMemory p_SetupGamemode; inline auto SetupGamemode = p_SetupGamemode.RCast(); /* ==== CONCOMMANDCALLBACK ============================================================================================================================================== */ -inline CMemory p_Host_Map_f; -inline auto _Host_Map_f = p_Host_Map_f.RCast(); - inline CMemory p_DownloadPlaylists_f; inline auto _DownloadPlaylists_f = p_DownloadPlaylists_f.RCast(); /////////////////////////////////////////////////////////////////////////////// void MP_GameMode_Changed_f(IConVar* pConVar, const char* pOldString, float flOldValue); +void MP_HostName_Changed_f(IConVar* pConVar, const char* pOldString, float flOldValue); #ifndef DEDICATED void GameConsole_Invoke_f(const CCommand& args); void ServerBrowser_Invoke_f(const CCommand& args); @@ -67,22 +65,15 @@ class VCallback : public IDetour virtual void GetAdr(void) const { spdlog::debug("| FUN: SetupGamemode : {:#18x} |\n", p_SetupGamemode.GetPtr()); - spdlog::debug("| FUN: Host_Map_f : {:#18x} |\n", p_Host_Map_f.GetPtr()); spdlog::debug("| FUN: DownloadPlaylist_f : {:#18x} |\n", p_DownloadPlaylists_f.GetPtr()); spdlog::debug("+----------------------------------------------------------------+\n"); } virtual void GetFun(void) const { p_SetupGamemode = g_GameDll.FindPatternSIMD(reinterpret_cast("\x40\x53\x48\x83\xEC\x20\x48\x8B\xD9\x48\xC7\xC0\x00\x00\x00\x00"), "xxxxxxxxxxxx????"); -#if defined (GAMEDLL_S0) || defined (GAMEDLL_S1) - p_Host_Map_f = g_GameDll.FindPatternSIMD(reinterpret_cast("\x48\x89\x5C\x24\x18\x55\x41\x56\x41\x00\x00\x00\x00\x40\x02"), "xxxxxxxxx????xx"); -#elif defined (GAMEDLL_S2) || defined (GAMEDLL_S3) - p_Host_Map_f = g_GameDll.FindPatternSIMD(reinterpret_cast("\x40\x55\x41\x56\x41\x57\x48\x81\xEC\x00\x00\x00\x00\x83\x3D"), "xxxxxxxxx????xx"); -#endif p_DownloadPlaylists_f = g_GameDll.FindPatternSIMD(reinterpret_cast("\x33\xC9\xC6\x05\x00\x00\x00\x00\x00\xE9\x00\x00\x00\x00"), "xxxx?????x????"); SetupGamemode = p_SetupGamemode.RCast(); /*40 53 48 83 EC 20 48 8B D9 48 C7 C0 ?? ?? ?? ??*/ - _Host_Map_f = p_Host_Map_f.RCast(); /*40 55 41 56 41 57 48 81 EC ?? ?? ?? ?? 83 3D*/ _DownloadPlaylists_f = p_DownloadPlaylists_f.RCast(); /*33 C9 C6 05 ?? ?? ?? ?? ?? E9 ?? ?? ?? ??*/ } virtual void GetVar(void) const { } diff --git a/r5dev/windows/console.cpp b/r5dev/windows/console.cpp index 602b0037..291ac95f 100644 --- a/r5dev/windows/console.cpp +++ b/r5dev/windows/console.cpp @@ -136,7 +136,7 @@ DWORD __stdcall ProcessConsoleWorker(LPVOID) // Execute the command. Cbuf_AddText(Cbuf_GetCurrentPlayer(), sCommand.c_str(), cmd_source_t::kCommandSrcCode); - //g_DelayedCallTask->AddFunc(Cbuf_Execute, 0); + //g_TaskScheduler->Dispatch(Cbuf_Execute, 0); sCommand.clear();