diff --git a/src/Components/Modules/Dedicated.cpp b/src/Components/Modules/Dedicated.cpp index 7d8474e3..c73eb23b 100644 --- a/src/Components/Modules/Dedicated.cpp +++ b/src/Components/Modules/Dedicated.cpp @@ -3,6 +3,7 @@ namespace Components { Dvar::Var Dedicated::Dedi; + std::vector Dedicated::FrameCallbacks; bool Dedicated::IsDedicated() { @@ -97,6 +98,37 @@ namespace Components } } + void Dedicated::Heartbeat() + { + int masterPort = Dvar::Var("masterPort").Get(); + const char* masterServerName = Dvar::Var("masterServerName").Get(); + + Network::Address master(Utils::VA("%s:%u", masterServerName, masterPort)); + + Logger::Print("Sending heartbeat to master: %s:%u\n", masterServerName, masterPort); + + Network::Send(master, Utils::VA("heartbeat %s\n", "IW4")); + } + + void Dedicated::OnFrame(Dedicated::Callback callback) + { + Dedicated::FrameCallbacks.push_back(callback); + } + + void Dedicated::FrameStub() + { + for (auto callback : Dedicated::FrameCallbacks) + { + callback(); + } + + __asm + { + mov eax, 5A8E80h + call eax + } + } + Dedicated::Dedicated() { Dedicated::Dedi = Dvar::Register("dedicated", 0, 0, 2, Game::dvar_flag::DVAR_FLAG_SERVERINFO | Game::dvar_flag::DVAR_FLAG_WRITEPROTECTED, "Start as dedicated"); @@ -159,12 +191,12 @@ namespace Components // Map rotation Utils::Hook::Set(0x4152E8, Dedicated::MapRotate); + // Dedicated frame handler + Utils::Hook(0x4B0F81, Dedicated::FrameStub, HOOK_CALL).Install()->Quick(); + // isHost script call return 0 Utils::Hook::Set(0x5DEC04, 0); - // map_rotate func - //*(DWORD*)0x4152E8 = (DWORD)SV_MapRotate_f; - // sv_network_fps max 1000, and uncheat Utils::Hook::Set(0x4D3C67, 0); // ? Utils::Hook::Set(0x4D3C69, 1000); @@ -180,6 +212,23 @@ namespace Components // stop saving a config_mp.cfg Utils::Hook::Set(0x60B240, 0xC3); + + // Heartbeats + Dedicated::OnFrame([] () + { + static int LastHeartbeat = 0; + + if (Dvar::Var("sv_maxclients").Get() > 0 && !LastHeartbeat || (Game::Com_Milliseconds() - LastHeartbeat) > 120 * 1000) + { + LastHeartbeat = Game::Com_Milliseconds(); + Dedicated::Heartbeat(); + } + }); } } + + Dedicated::~Dedicated() + { + Dedicated::FrameCallbacks.clear(); + } } diff --git a/src/Components/Modules/Dedicated.hpp b/src/Components/Modules/Dedicated.hpp index 70ba9923..5b8ac3f3 100644 --- a/src/Components/Modules/Dedicated.hpp +++ b/src/Components/Modules/Dedicated.hpp @@ -3,16 +3,24 @@ namespace Components class Dedicated : public Component { public: + typedef void(*Callback)(); + Dedicated(); + ~Dedicated(); const char* GetName() { return "Dedicated"; }; static bool IsDedicated(); + static void Heartbeat(); + + static void OnFrame(Callback callback); + private: static Dvar::Var Dedi; + static std::vector FrameCallbacks; static void MapRotate(); - + static void FrameStub(); static void InitDedicatedServer(); }; } diff --git a/src/Components/Modules/Menus.cpp b/src/Components/Modules/Menus.cpp index 52e6e534..466fba1c 100644 --- a/src/Components/Modules/Menus.cpp +++ b/src/Components/Modules/Menus.cpp @@ -475,6 +475,8 @@ namespace Components Menus::Menus() { + if (Dedicated::IsDedicated()) return; + AssetHandler::OnFind(Game::XAssetType::ASSET_TYPE_MENUFILE, Menus::MenuFileLoad); //Utils::Hook(0x63FE80, Menus::MenuFileLoad, HOOK_JUMP).Install()->Quick(); diff --git a/src/Components/Modules/Party.cpp b/src/Components/Modules/Party.cpp index e1808a51..00abe503 100644 --- a/src/Components/Modules/Party.cpp +++ b/src/Components/Modules/Party.cpp @@ -140,7 +140,14 @@ namespace Components { int clientCount = 0; - for (int i = 0; i < *Game::svs_numclients; i++) + int maxClients = *Game::svs_numclients; + + if (!maxClients) + { + maxClients = Dvar::Var("sv_maxclients").Get(); + } + + for (int i = 0; i < maxClients; i++) { if (Game::svs_clients[i].state >= 3) { @@ -157,7 +164,9 @@ namespace Components info.Set("fs_game", Dvar::Var("fs_game").Get()); info.Set("xuid", Utils::VA("%llX", Steam::SteamUser()->GetSteamID().Bits)); info.Set("clients", Utils::VA("%i", clientCount)); - info.Set("sv_maxclients", Utils::VA("%i", *Game::svs_numclients)); + info.Set("sv_maxclients", Utils::VA("%i", maxClients)); + info.Set("protocol", Utils::VA("%i", PROTOCOL)); + info.Set("checksum", Utils::VA("%d", Game::Com_Milliseconds())); // Set matchtype // 0 - No match, connecting not possible @@ -177,7 +186,7 @@ namespace Components info.Set("matchtype", "0"); } - Network::Send(address, Utils::VA("infoResponse\n%s\n", info.Build().data())); + Network::Send(address, Utils::VA("infoResponse\n\\%s\n", info.Build().data())); }); Network::Handle("infoResponse", [] (Network::Address address, std::string data) diff --git a/src/Components/Modules/ServerList.cpp b/src/Components/Modules/ServerList.cpp index 37b7be09..7e5458b7 100644 --- a/src/Components/Modules/ServerList.cpp +++ b/src/Components/Modules/ServerList.cpp @@ -84,7 +84,7 @@ namespace Components Logger::Print("Sending serverlist request to master: %s:%u\n", masterServerName, masterPort); - Network::Send(ServerList::RefreshContainer.Host, "getservers IW4 145 full empty"); + Network::Send(ServerList::RefreshContainer.Host, Utils::VA("getservers IW4 %i full empty", PROTOCOL)); //Network::Send(ServerList::RefreshContainer.Host, "getservers 0 full empty\n"); } @@ -129,7 +129,10 @@ namespace Components } } - ServerList::OnlineList.push_back(server); + if (server.MatchType) + { + ServerList::OnlineList.push_back(server); + } ServerList::RefreshContainer.Servers.erase(i);