From 3b85a5f3bbdd8da63f27c2e72220f8899391ecc7 Mon Sep 17 00:00:00 2001 From: Ayndpa Date: Tue, 18 Nov 2025 18:28:52 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=BC=BAP2P=E8=BF=9E=E6=8E=A5?= =?UTF-8?q?=E7=9A=84=E5=8F=AF=E9=9D=A0=E6=80=A7=EF=BC=8C=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E7=94=A8=E6=88=B7=E4=BF=A1=E6=81=AF=E7=AE=A1=E7=90=86=E5=92=8C?= =?UTF-8?q?=E8=BF=9E=E6=8E=A5=E9=87=8D=E8=AF=95=E6=9C=BA=E5=88=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- online_game_tool.cpp | 120 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 115 insertions(+), 5 deletions(-) diff --git a/online_game_tool.cpp b/online_game_tool.cpp index 38b12f0..e6657f2 100644 --- a/online_game_tool.cpp +++ b/online_game_tool.cpp @@ -35,6 +35,13 @@ ISteamNetworkingSockets* m_pInterface = nullptr; bool forwarding = false; std::unique_ptr server; +// Connection config for improved P2P reliability +SteamNetworkingConfigValue_t g_connectionConfig[2]; +int g_retryCount = 0; +const int MAX_RETRIES = 3; +CSteamID g_hostSteamID; +int g_currentVirtualPort = 0; + // New variables for multiple connections and TCP clients std::vector connections; std::map clientMap; @@ -43,11 +50,23 @@ int localPort = 0; bool g_isHost = false; bool g_isClient = false; +// User info structure +struct UserInfo { + CSteamID steamID; + std::string name; + int ping; + bool isRelay; +}; +std::map userMap; + // Callback function for connection status changes void OnSteamNetConnectionStatusChanged(SteamNetConnectionStatusChangedCallback_t *pInfo) { std::lock_guard lock(clientMutex); - std::cout << "Connection status changed: " << pInfo->m_info.m_eState << std::endl; + std::cout << "Connection status changed: " << pInfo->m_info.m_eState << " for connection " << pInfo->m_hConn << std::endl; + if (pInfo->m_info.m_eState == k_ESteamNetworkingConnectionState_ProblemDetectedLocally) { + std::cout << "Connection failed: " << pInfo->m_info.m_szEndDebug << std::endl; + } if (pInfo->m_eOldState == k_ESteamNetworkingConnectionState_None && pInfo->m_info.m_eState == k_ESteamNetworkingConnectionState_Connecting) { // Incoming connection, accept it @@ -55,7 +74,19 @@ void OnSteamNetConnectionStatusChanged(SteamNetConnectionStatusChangedCallback_t connections.push_back(pInfo->m_hConn); g_hConnection = pInfo->m_hConn; // Keep for backward compatibility if needed g_isConnected = true; - std::cout << "Accepted incoming connection" << std::endl; + std::cout << "Accepted incoming connection from " << pInfo->m_info.m_identityRemote.GetSteamID().ConvertToUint64() << std::endl; + // Add user info + SteamNetConnectionInfo_t info; + SteamNetConnectionRealTimeStatus_t status; + if (m_pInterface->GetConnectionInfo(pInfo->m_hConn, &info) && m_pInterface->GetConnectionRealTimeStatus(pInfo->m_hConn, &status, 0, nullptr)) { + UserInfo userInfo; + userInfo.steamID = pInfo->m_info.m_identityRemote.GetSteamID(); + userInfo.name = SteamFriends()->GetFriendPersonaName(userInfo.steamID); + userInfo.ping = status.m_nPing; + userInfo.isRelay = (info.m_idPOPRelay != 0); + userMap[pInfo->m_hConn] = userInfo; + std::cout << "Incoming connection details: ping=" << status.m_nPing << "ms, relay=" << (info.m_idPOPRelay != 0 ? "yes" : "no") << std::endl; + } // Removed: Create TCP Client here - now lazy connect on first message } else if (pInfo->m_eOldState == k_ESteamNetworkingConnectionState_Connecting && pInfo->m_info.m_eState == k_ESteamNetworkingConnectionState_Connected) @@ -63,6 +94,18 @@ void OnSteamNetConnectionStatusChanged(SteamNetConnectionStatusChangedCallback_t // Client connected successfully g_isConnected = true; std::cout << "Connected to host" << std::endl; + // Add user info + SteamNetConnectionInfo_t info; + SteamNetConnectionRealTimeStatus_t status; + if (m_pInterface->GetConnectionInfo(pInfo->m_hConn, &info) && m_pInterface->GetConnectionRealTimeStatus(pInfo->m_hConn, &status, 0, nullptr)) { + UserInfo userInfo; + userInfo.steamID = pInfo->m_info.m_identityRemote.GetSteamID(); + userInfo.name = SteamFriends()->GetFriendPersonaName(userInfo.steamID); + userInfo.ping = status.m_nPing; + userInfo.isRelay = (info.m_idPOPRelay != 0); + userMap[pInfo->m_hConn] = userInfo; + std::cout << "Outgoing connection details: ping=" << status.m_nPing << "ms, relay=" << (info.m_idPOPRelay != 0 ? "yes" : "no") << std::endl; + } } else if (pInfo->m_info.m_eState == k_ESteamNetworkingConnectionState_ClosedByPeer || pInfo->m_info.m_eState == k_ESteamNetworkingConnectionState_ProblemDetectedLocally) { @@ -78,6 +121,8 @@ void OnSteamNetConnectionStatusChanged(SteamNetConnectionStatusChangedCallback_t ++it; } } + // Remove from userMap + userMap.erase(pInfo->m_hConn); // Cleanup TCP Client if (clientMap.count(pInfo->m_hConn)) { clientMap[pInfo->m_hConn]->disconnect(); @@ -86,6 +131,21 @@ void OnSteamNetConnectionStatusChanged(SteamNetConnectionStatusChangedCallback_t std::cout << "Cleaned up TCP Client for connection" << std::endl; } std::cout << "Connection closed" << std::endl; + + // Retry connection if client and retries left + if (g_isClient && !g_isConnected && g_retryCount < MAX_RETRIES) { + g_retryCount++; + g_currentVirtualPort++; + SteamNetworkingIdentity identity; + identity.SetSteamID(g_hostSteamID); + HSteamNetConnection newConn = m_pInterface->ConnectP2P(identity, g_currentVirtualPort, 2, g_connectionConfig); + if (newConn != k_HSteamNetConnection_Invalid) { + g_hConnection = newConn; + std::cout << "Retrying connection attempt " << g_retryCount << " with virtual port " << g_currentVirtualPort << std::endl; + } else { + std::cerr << "Failed to initiate retry connection" << std::endl; + } + } } } @@ -93,11 +153,14 @@ void SteamFriendsCallbacks::OnGameRichPresenceJoinRequested(GameRichPresenceJoin CSteamID hostSteamID = pCallback->m_steamIDFriend; if (!g_isHost && !g_isConnected) { g_isClient = true; + g_hostSteamID = hostSteamID; + g_retryCount = 0; + g_currentVirtualPort = 0; SteamNetworkingIdentity identity; identity.SetSteamID(hostSteamID); - g_hConnection = m_pInterface->ConnectP2P(identity, 0, 0, nullptr); + g_hConnection = m_pInterface->ConnectP2P(identity, g_currentVirtualPort, 2, g_connectionConfig); if (g_hConnection != k_HSteamNetConnection_Invalid) { - std::cout << "Joined game room via invite from " << hostSteamID.ConvertToUint64() << std::endl; + std::cout << "Joined game room via invite from " << hostSteamID.ConvertToUint64() << ", attempting connection with virtual port " << g_currentVirtualPort << std::endl; // Start TCP Server server = std::make_unique(8888); if (!server->start()) { @@ -125,6 +188,10 @@ int main() { m_pInterface = SteamNetworkingSockets(); + // Initialize connection config for better P2P reliability + g_connectionConfig[0].SetInt32(k_ESteamNetworkingConfig_TimeoutInitial, 10000); // 10 seconds initial timeout + g_connectionConfig[1].SetInt32(k_ESteamNetworkingConfig_NagleTime, 0); // Disable Nagle for UDP + // Initialize GLFW if (!glfwInit()) { std::cerr << "Failed to initialize GLFW" << std::endl; @@ -187,6 +254,21 @@ int main() { // Poll networking m_pInterface->RunCallbacks(); + // Update user info + { + std::lock_guard lock(clientMutex); + for (auto conn : connections) { + SteamNetConnectionInfo_t info; + SteamNetConnectionRealTimeStatus_t status; + if (m_pInterface->GetConnectionInfo(conn, &info) && m_pInterface->GetConnectionRealTimeStatus(conn, &status, 0, nullptr)) { + if (userMap.count(conn)) { + userMap[conn].ping = status.m_nPing; + userMap[conn].isRelay = (info.m_idPOPRelay != 0); + } + } + } + } + // Receive messages from Steam and forward to TCP server { std::lock_guard lock(clientMutex); @@ -241,11 +323,14 @@ int main() { hListenSock = m_pInterface->CreateListenSocketP2P(0, 0, nullptr); if (hListenSock != k_HSteamListenSocket_Invalid) { g_isHost = true; + std::cout << "Created listen socket for hosting game room" << std::endl; // Set Rich Presence std::string connectStr = std::to_string(SteamUser()->GetSteamID().ConvertToUint64()); SteamFriends()->SetRichPresence("connect", connectStr.c_str()); SteamFriends()->SetRichPresence("status", "主持游戏房间"); std::cout << "Hosting game room. Connection string: " << connectStr << std::endl; + } else { + std::cerr << "Failed to create listen socket for hosting" << std::endl; } } ImGui::InputText("主机Steam ID", joinBuffer, IM_ARRAYSIZE(joinBuffer)); @@ -253,11 +338,15 @@ int main() { uint64 hostID = std::stoull(joinBuffer); CSteamID hostSteamID(hostID); g_isClient = true; + g_hostSteamID = hostSteamID; + g_retryCount = 0; + g_currentVirtualPort = 0; // Connect to host SteamNetworkingIdentity identity; identity.SetSteamID(hostSteamID); - g_hConnection = m_pInterface->ConnectP2P(identity, 0, 0, nullptr); + g_hConnection = m_pInterface->ConnectP2P(identity, g_currentVirtualPort, 2, g_connectionConfig); if (g_hConnection != k_HSteamNetConnection_Invalid) { + std::cout << "Attempting to connect to host " << hostSteamID.ConvertToUint64() << " with virtual port " << g_currentVirtualPort << std::endl; // Connection initiated, wait for callback to confirm std::cout << "Connecting to host..." << std::endl; // Start TCP Server @@ -305,6 +394,27 @@ int main() { ImGui::Text("连接的好友: %d", (int)connections.size()); ImGui::Text("活跃的TCP客户端: %d", (int)clientMap.size()); } + ImGui::Separator(); + ImGui::Text("用户列表:"); + if (ImGui::BeginTable("UserTable", 3, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg)) { + ImGui::TableSetupColumn("名称"); + ImGui::TableSetupColumn("延迟 (ms)"); + ImGui::TableSetupColumn("连接类型"); + ImGui::TableHeadersRow(); + { + std::lock_guard lock(clientMutex); + for (const auto& pair : userMap) { + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::Text("%s", pair.second.name.c_str()); + ImGui::TableNextColumn(); + ImGui::Text("%d", pair.second.ping); + ImGui::TableNextColumn(); + ImGui::Text("%s", pair.second.isRelay ? "中继" : "直连"); + } + } + ImGui::EndTable(); + } ImGui::End(); }