#include namespace Components { bool Discovery::IsTerminating = false; bool Discovery::IsPerforming = false; std::thread Discovery::Thread; std::string Discovery::Challenge; Dvar::Var Discovery::NetDiscoveryPortRangeMin; Dvar::Var Discovery::NetDiscoveryPortRangeMax; void Discovery::Perform() { IsPerforming = true; } Discovery::Discovery() { NetDiscoveryPortRangeMin = Dvar::Register("net_discoveryPortRangeMin", 25000, 0, 65535, Game::DVAR_NONE, "Minimum scan range port for local server discovery"); NetDiscoveryPortRangeMax = Dvar::Register("net_discoveryPortRangeMax", 35000, 1, 65536, Game::DVAR_NONE, "Maximum scan range port for local server discovery"); // An additional thread prevents lags // Not sure if that's the best way though IsPerforming = false; IsTerminating = false; Thread = std::thread([] { while (!IsTerminating) { if (IsPerforming) { const auto start = Game::Sys_Milliseconds(); Logger::Print("Starting local server discovery...\n"); Challenge = Utils::Cryptography::Rand::GenerateChallenge(); const auto minPort = NetDiscoveryPortRangeMin.get(); const auto maxPort = NetDiscoveryPortRangeMax.get(); Network::BroadcastRange(minPort, maxPort, std::format("discovery {}", Challenge)); Logger::Print("Discovery sent within {}ms, awaiting responses...\n", Game::Sys_Milliseconds() - start); IsPerforming = false; } std::this_thread::sleep_for(50ms); } }); Network::OnClientPacket("discovery", [](Network::Address& address, [[maybe_unused]] const std::string& data) { if (address.isSelf()) return; if (!address.isLocal()) { Logger::Print("Received discovery request from non-local address: {}\n", address.getString()); return; } Logger::Print("Received discovery request from {}\n", address.getString()); Network::SendCommand(address, "discoveryResponse", data); }); Network::OnClientPacket("discoveryResponse", [](Network::Address& address, [[maybe_unused]] const std::string& data) { if (address.isSelf()) return; if (!address.isLocal()) { Logger::Print("Received discovery response from non-local address: {}\n", address.getString()); return; } if (Utils::ParseChallenge(data) != Challenge) { Logger::Print("Received discovery with invalid challenge from: {}\n", address.getString()); return; } Logger::Print("Received discovery response from: {}\n", address.getString()); if (ServerList::IsOfflineList()) { ServerList::InsertRequest(address); } }); } void Discovery::preDestroy() { IsPerforming = false; IsTerminating = true; if (Thread.joinable()) { Thread.join(); } } }