From b308a644ff13cc31d31d7fb071508cf41b38acd8 Mon Sep 17 00:00:00 2001 From: Ayndpa Date: Tue, 18 Nov 2025 19:05:50 +0800 Subject: [PATCH] =?UTF-8?q?=E9=87=8D=E6=9E=84=E4=BB=A3=E7=A0=81=EF=BC=8C?= =?UTF-8?q?=E5=88=A0=E9=99=A4=E4=B8=8D=E5=BF=85=E8=A6=81=E7=9A=84=E6=96=87?= =?UTF-8?q?=E4=BB=B6=EF=BC=8C=E6=B7=BB=E5=8A=A0=E6=8E=A7=E5=88=B6=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E5=8C=85=E5=A4=84=E7=90=86=E5=92=8CSteam=E6=B6=88?= =?UTF-8?q?=E6=81=AF=E5=A4=84=E7=90=86=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- control_packets.cpp | 19 +++ control_packets.h | 8 ++ imgui_hello.cpp | 72 ------------ online_game_tool.cpp | 84 ++++--------- p2p_chat.cpp | 240 -------------------------------------- steam_friends.cpp | 103 ---------------- steam_message_handler.cpp | 90 ++++++++++++++ steam_message_handler.h | 39 +++++++ tcp/tcp_client.cpp | 9 +- tcp/tcp_server.cpp | 12 +- tcp/tcp_server.h | 1 + 11 files changed, 194 insertions(+), 483 deletions(-) create mode 100644 control_packets.cpp create mode 100644 control_packets.h delete mode 100644 imgui_hello.cpp delete mode 100644 p2p_chat.cpp delete mode 100644 steam_friends.cpp create mode 100644 steam_message_handler.cpp create mode 100644 steam_message_handler.h diff --git a/control_packets.cpp b/control_packets.cpp new file mode 100644 index 0000000..f0e9115 --- /dev/null +++ b/control_packets.cpp @@ -0,0 +1,19 @@ +#include "control_packets.h" +#include +#include + +// 假设需要访问全局变量,但为了简单,这里只打印 +// 如果需要,可以传递引用或使用全局 + +void handleControlPacket(const char* data, size_t size, HSteamNetConnection conn) { + std::string_view packetData(data, size); + std::cout << "Received control packet: " << packetData << " from connection " << conn << std::endl; + // 这里添加处理逻辑,例如解析JSON或命令 + // 例如,如果data是"ping",回复"pong" + if (packetData == "ping") { + // 发送回复,但需要接口 + // 暂时只打印 + std::cout << "Responding to ping" << std::endl; + } + // 可以扩展为更多控制命令 +} \ No newline at end of file diff --git a/control_packets.h b/control_packets.h new file mode 100644 index 0000000..27dc8d5 --- /dev/null +++ b/control_packets.h @@ -0,0 +1,8 @@ +#ifndef CONTROL_PACKETS_H +#define CONTROL_PACKETS_H + +#include + +void handleControlPacket(const char* data, size_t size, HSteamNetConnection conn); + +#endif // CONTROL_PACKETS_H \ No newline at end of file diff --git a/imgui_hello.cpp b/imgui_hello.cpp deleted file mode 100644 index d07d342..0000000 --- a/imgui_hello.cpp +++ /dev/null @@ -1,72 +0,0 @@ -#include -#include -#include -#include -#include - -int main() { - // Initialize GLFW - if (!glfwInit()) { - std::cerr << "Failed to initialize GLFW" << std::endl; - return -1; - } - - // Create window - GLFWwindow* window = glfwCreateWindow(1280, 720, "Dear ImGui Hello World", nullptr, nullptr); - if (!window) { - std::cerr << "Failed to create GLFW window" << std::endl; - glfwTerminate(); - return -1; - } - glfwMakeContextCurrent(window); - glfwSwapInterval(1); // Enable vsync - - // Initialize ImGui - IMGUI_CHECKVERSION(); - ImGui::CreateContext(); - ImGuiIO& io = ImGui::GetIO(); - (void)io; - ImGui::StyleColorsDark(); - - // Initialize ImGui backends - ImGui_ImplGlfw_InitForOpenGL(window, true); - ImGui_ImplOpenGL3_Init("#version 130"); - - // Main loop - while (!glfwWindowShouldClose(window)) { - // Poll events - glfwPollEvents(); - - // Start ImGui frame - ImGui_ImplOpenGL3_NewFrame(); - ImGui_ImplGlfw_NewFrame(); - ImGui::NewFrame(); - - // Create a simple window - ImGui::Begin("Hello, World!"); - ImGui::Text("Welcome to Dear ImGui!"); - ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / io.Framerate, io.Framerate); - ImGui::End(); - - // Rendering - ImGui::Render(); - int display_w, display_h; - glfwGetFramebufferSize(window, &display_w, &display_h); - glViewport(0, 0, display_w, display_h); - glClearColor(0.45f, 0.55f, 0.60f, 1.00f); - glClear(GL_COLOR_BUFFER_BIT); - ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData()); - - // Swap buffers - glfwSwapBuffers(window); - } - - // Cleanup - ImGui_ImplOpenGL3_Shutdown(); - ImGui_ImplGlfw_Shutdown(); - ImGui::DestroyContext(); - glfwDestroyWindow(window); - glfwTerminate(); - - return 0; -} diff --git a/online_game_tool.cpp b/online_game_tool.cpp index e6657f2..7a10545 100644 --- a/online_game_tool.cpp +++ b/online_game_tool.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -17,6 +18,7 @@ #include #include "tcp_server.h" #include "tcp/tcp_client.h" +#include "steam_message_handler.h" using boost::asio::ip::tcp; @@ -192,6 +194,12 @@ int main() { 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 boost::asio io_context + boost::asio::io_context io_context; + + // Create Steam Message Handler + SteamMessageHandler messageHandler(io_context, m_pInterface, connections, clientMap, clientMutex, server, g_isHost, localPort); + // Initialize GLFW if (!glfwInit()) { std::cerr << "Failed to initialize GLFW" << std::endl; @@ -223,17 +231,6 @@ int main() { ImGui_ImplGlfw_InitForOpenGL(window, true); ImGui_ImplOpenGL3_Init("#version 130"); - // TCP Client for local port forwarding - // Removed: TCPClient* client = nullptr; - // Removed: bool isLocalConnected = false; - - // Steam Networking variables - bool isHost = false; - bool isClient = false; - char joinBuffer[256] = ""; - char filterBuffer[256] = ""; - // Removed: char portBuffer[256] = ""; - // Get friends list std::vector> friendsList; int friendCount = SteamFriends()->GetFriendCount(k_EFriendFlagAll); @@ -243,6 +240,15 @@ int main() { friendsList.push_back({friendID, name}); } + // Start message handler + messageHandler.start(); + + // Steam Networking variables + bool isHost = false; + bool isClient = false; + char joinBuffer[256] = ""; + char filterBuffer[256] = ""; + // Main loop while (!glfwWindowShouldClose(window)) { // Poll events @@ -251,59 +257,6 @@ int main() { // Run Steam callbacks SteamAPI_RunCallbacks(); - // 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); - for (auto conn : connections) { - ISteamNetworkingMessage* pIncomingMsg = nullptr; - int numMsgs = m_pInterface->ReceiveMessagesOnConnection(conn, &pIncomingMsg, 1); - if (numMsgs > 0 && pIncomingMsg) { - // std::cout << "Received " << pIncomingMsg->m_cbSize << " bytes" << std::endl; - if (server) { - server->sendToAll((const char*)pIncomingMsg->m_pData, pIncomingMsg->m_cbSize); - } - // Lazy connect: Create TCP Client on first message if not already connected - if (clientMap.find(conn) == clientMap.end() && g_isHost && localPort > 0) { - TCPClient* client = new TCPClient("localhost", localPort); - if (client->connect()) { - client->setReceiveCallback([conn](const char* data, size_t size) { - std::lock_guard lock(clientMutex); - m_pInterface->SendMessageToConnection(conn, data, size, k_nSteamNetworkingSend_Reliable, nullptr); - }); - clientMap[conn] = client; - std::cout << "Created TCP Client for connection on first message" << std::endl; - } else { - std::cerr << "Failed to connect TCP Client for connection" << std::endl; - delete client; - } - } - // Send to corresponding TCP client if exists (for host) - if (clientMap.count(conn)) { - clientMap[conn]->send((const char*)pIncomingMsg->m_pData, pIncomingMsg->m_cbSize); - } - pIncomingMsg->Release(); - } - } - } - // Start ImGui frame ImGui_ImplOpenGL3_NewFrame(); ImGui_ImplGlfw_NewFrame(); @@ -431,6 +384,9 @@ int main() { glfwSwapBuffers(window); } + // Stop message handler + messageHandler.stop(); + // Cleanup if (g_hConnection != k_HSteamNetConnection_Invalid) { m_pInterface->CloseConnection(g_hConnection, 0, nullptr, false); diff --git a/p2p_chat.cpp b/p2p_chat.cpp deleted file mode 100644 index 2f2f903..0000000 --- a/p2p_chat.cpp +++ /dev/null @@ -1,240 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -// Global variables for callbacks -HSteamNetConnection g_hConnection = k_HSteamNetConnection_Invalid; -bool g_isConnected = false; - -// Callback function for connection status changes -void OnSteamNetConnectionStatusChanged(SteamNetConnectionStatusChangedCallback_t *pInfo) -{ - std::cout << "Connection status changed: " << pInfo->m_info.m_eState << std::endl; - if (pInfo->m_eOldState == k_ESteamNetworkingConnectionState_None && pInfo->m_info.m_eState == k_ESteamNetworkingConnectionState_Connecting) - { - // Incoming connection, accept it - SteamNetworkingSockets()->AcceptConnection(pInfo->m_hConn); - g_hConnection = pInfo->m_hConn; - g_isConnected = true; - std::cout << "Accepted incoming connection" << std::endl; - } - else if (pInfo->m_eOldState == k_ESteamNetworkingConnectionState_Connecting && pInfo->m_info.m_eState == k_ESteamNetworkingConnectionState_Connected) - { - // Client connected successfully - g_isConnected = true; - std::cout << "Connected to host" << std::endl; - } - else if (pInfo->m_info.m_eState == k_ESteamNetworkingConnectionState_ClosedByPeer || pInfo->m_info.m_eState == k_ESteamNetworkingConnectionState_ProblemDetectedLocally) - { - // Connection closed - g_isConnected = false; - g_hConnection = k_HSteamNetConnection_Invalid; - std::cout << "Connection closed" << std::endl; - } -} - -int main() { - // Initialize Steam API - if (!SteamAPI_Init()) { - std::cerr << "Failed to initialize Steam API" << std::endl; - return 1; - } - - // Initialize Steam Networking Sockets - SteamNetworkingUtils()->InitRelayNetworkAccess(); - - // Set global callback for connection status changes - SteamNetworkingUtils()->SetGlobalCallback_SteamNetConnectionStatusChanged(OnSteamNetConnectionStatusChanged); - - // Initialize GLFW - if (!glfwInit()) { - std::cerr << "Failed to initialize GLFW" << std::endl; - SteamAPI_Shutdown(); - return -1; - } - - // Create window - GLFWwindow* window = glfwCreateWindow(1280, 720, "Steam P2P Chat", nullptr, nullptr); - if (!window) { - std::cerr << "Failed to create GLFW window" << std::endl; - glfwTerminate(); - SteamAPI_Shutdown(); - return -1; - } - glfwMakeContextCurrent(window); - glfwSwapInterval(1); // Enable vsync - - // Initialize ImGui - IMGUI_CHECKVERSION(); - ImGui::CreateContext(); - ImGuiIO& io = ImGui::GetIO(); - (void)io; - // Load Chinese font if available - io.Fonts->AddFontFromFileTTF("font.ttf", 18.0f, nullptr, io.Fonts->GetGlyphRangesChineseSimplifiedCommon()); - ImGui::StyleColorsDark(); - - // Initialize ImGui backends - ImGui_ImplGlfw_InitForOpenGL(window, true); - ImGui_ImplOpenGL3_Init("#version 130"); - - // Steam Networking variables - HSteamListenSocket hListenSock = k_HSteamListenSocket_Invalid; - ISteamNetworkingSockets* m_pInterface = SteamNetworkingSockets(); - - // Chat variables - std::vector messages; - char inputBuffer[256] = ""; - CSteamID selectedFriend; - bool isHost = false; - bool isClient = false; - char filterBuffer[256] = ""; - - // Get friends list - std::vector friendsList; - int friendCount = SteamFriends()->GetFriendCount(k_EFriendFlagAll); - for (int i = 0; i < friendCount; ++i) { - CSteamID friendID = SteamFriends()->GetFriendByIndex(i, k_EFriendFlagAll); - friendsList.push_back(friendID); - } - - // Main loop - while (!glfwWindowShouldClose(window)) { - // Poll events - glfwPollEvents(); - - // Run Steam callbacks - SteamAPI_RunCallbacks(); - - // Poll networking - m_pInterface->RunCallbacks(); - - // Receive messages - if (g_isConnected) { - ISteamNetworkingMessage* pIncomingMsg = nullptr; - int numMsgs = m_pInterface->ReceiveMessagesOnConnection(g_hConnection, &pIncomingMsg, 1); - if (numMsgs > 0 && pIncomingMsg) { - std::string msg((char*)pIncomingMsg->m_pData, pIncomingMsg->m_cbSize); - messages.push_back("Friend: " + msg); - pIncomingMsg->Release(); - } - } - - // Start ImGui frame - ImGui_ImplOpenGL3_NewFrame(); - ImGui_ImplGlfw_NewFrame(); - ImGui::NewFrame(); - - // Main menu - ImGui::Begin("Steam P2P Chat"); - if (!isHost && !g_isConnected) { - if (ImGui::Button("Host Chat Room")) { - // Create listen socket - hListenSock = m_pInterface->CreateListenSocketP2P(0, 0, nullptr); - if (hListenSock != k_HSteamListenSocket_Invalid) { - isHost = true; - // Set Rich Presence - std::string connectStr = std::to_string(SteamUser()->GetSteamID().ConvertToUint64()); - SteamFriends()->SetRichPresence("connect", connectStr.c_str()); - SteamFriends()->SetRichPresence("status", "Hosting Chat Room"); - std::cout << "Hosting chat room. Connect string: " << connectStr << std::endl; - } - } - static char joinBuffer[256] = ""; - ImGui::InputText("Host Steam ID", joinBuffer, IM_ARRAYSIZE(joinBuffer)); - if (ImGui::Button("Join Chat Room")) { - uint64 hostID = std::stoull(joinBuffer); - CSteamID hostSteamID(hostID); - isClient = true; - // Connect to host - SteamNetworkingIdentity identity; - identity.SetSteamID(hostSteamID); - g_hConnection = m_pInterface->ConnectP2P(identity, 0, 0, nullptr); - if (g_hConnection != k_HSteamNetConnection_Invalid) { - // Connection initiated, wait for callback to confirm - std::cout << "Connecting to host..." << std::endl; - } - } - } - if (isHost) { - ImGui::Text("Hosting chat room. Invite friends!"); - ImGui::Separator(); - ImGui::InputText("Filter Friends", filterBuffer, IM_ARRAYSIZE(filterBuffer)); - ImGui::Text("Friends:"); - for (size_t i = 0; i < friendsList.size(); ++i) { - const char* name = SteamFriends()->GetFriendPersonaName(friendsList[i]); - std::string nameStr(name); - std::string filterStr(filterBuffer); - // Convert to lowercase for case-insensitive search - std::transform(nameStr.begin(), nameStr.end(), nameStr.begin(), ::tolower); - std::transform(filterStr.begin(), filterStr.end(), filterStr.begin(), ::tolower); - if (filterStr.empty() || nameStr.find(filterStr) != std::string::npos) { - if (ImGui::Button((std::string("Invite ") + name).c_str())) { - SteamFriends()->InviteUserToGame(friendsList[i], ""); - } - } - } - } - ImGui::End(); - - // Chat window - if (g_isConnected) { - ImGui::Begin("Chat Room"); - ImGui::Text("Chatting"); - - // Display messages - ImGui::BeginChild("Messages", ImVec2(0, -ImGui::GetFrameHeightWithSpacing() - 30), true); - for (const auto& msg : messages) { - ImGui::TextWrapped("%s", msg.c_str()); - } - ImGui::EndChild(); - - // Input - if (ImGui::InputText("Message", inputBuffer, IM_ARRAYSIZE(inputBuffer), ImGuiInputTextFlags_EnterReturnsTrue)) { - if (strlen(inputBuffer) > 0) { - uint32 msgSize = static_cast(strlen(inputBuffer) + 1); - m_pInterface->SendMessageToConnection(g_hConnection, inputBuffer, msgSize, k_nSteamNetworkingSend_Reliable, nullptr); - messages.push_back("You: " + std::string(inputBuffer)); - memset(inputBuffer, 0, sizeof(inputBuffer)); - } - } - ImGui::End(); - } - - // Rendering - ImGui::Render(); - int display_w, display_h; - glfwGetFramebufferSize(window, &display_w, &display_h); - glViewport(0, 0, display_w, display_h); - glClearColor(0.45f, 0.55f, 0.60f, 1.00f); - glClear(GL_COLOR_BUFFER_BIT); - ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData()); - - // Swap buffers - glfwSwapBuffers(window); - } - - // Cleanup - if (g_hConnection != k_HSteamNetConnection_Invalid) { - m_pInterface->CloseConnection(g_hConnection, 0, nullptr, false); - } - if (hListenSock != k_HSteamListenSocket_Invalid) { - m_pInterface->CloseListenSocket(hListenSock); - } - ImGui_ImplOpenGL3_Shutdown(); - ImGui_ImplGlfw_Shutdown(); - ImGui::DestroyContext(); - glfwDestroyWindow(window); - glfwTerminate(); - SteamAPI_Shutdown(); - - return 0; -} \ No newline at end of file diff --git a/steam_friends.cpp b/steam_friends.cpp deleted file mode 100644 index 85f03ab..0000000 --- a/steam_friends.cpp +++ /dev/null @@ -1,103 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include - -int main() { - // Initialize Steam API - if (!SteamAPI_Init()) { - std::cerr << "Failed to initialize Steam API" << std::endl; - return 1; - } - - // Initialize GLFW - if (!glfwInit()) { - std::cerr << "Failed to initialize GLFW" << std::endl; - SteamAPI_Shutdown(); - return -1; - } - - // Create window - GLFWwindow* window = glfwCreateWindow(1280, 720, "Steam Friends List", nullptr, nullptr); - if (!window) { - std::cerr << "Failed to create GLFW window" << std::endl; - glfwTerminate(); - SteamAPI_Shutdown(); - return -1; - } - glfwMakeContextCurrent(window); - glfwSwapInterval(1); // Enable vsync - - // Initialize ImGui - IMGUI_CHECKVERSION(); - ImGui::CreateContext(); - ImGuiIO& io = ImGui::GetIO(); - (void)io; - // Load Chinese font - io.Fonts->AddFontFromFileTTF("font.ttf", 18.0f, nullptr, io.Fonts->GetGlyphRangesChineseSimplifiedCommon()); - ImGui::StyleColorsDark(); - - // Initialize ImGui backends - ImGui_ImplGlfw_InitForOpenGL(window, true); - ImGui_ImplOpenGL3_Init("#version 130"); - - // Get friends list - std::vector friendsList; - int friendCount = SteamFriends()->GetFriendCount(k_EFriendFlagAll); - for (int i = 0; i < friendCount; ++i) { - CSteamID friendID = SteamFriends()->GetFriendByIndex(i, k_EFriendFlagAll); - const char* name = SteamFriends()->GetFriendPersonaName(friendID); - friendsList.push_back(std::string("Friend ") + std::to_string(i + 1) + ": " + name); - } - - // Main loop - while (!glfwWindowShouldClose(window)) { - // Poll events - glfwPollEvents(); - - // Start ImGui frame - ImGui_ImplOpenGL3_NewFrame(); - ImGui_ImplGlfw_NewFrame(); - ImGui::NewFrame(); - - // Create a window for friends list - ImGui::Begin("Steam Friends List"); - ImGui::Text("Number of friends: %d", friendCount); - ImGui::Separator(); - if (friendCount > 0) { - ImGui::Columns(4, nullptr, true); // 4 columns, with borders - for (const auto& friendName : friendsList) { - ImGui::Text("%s", friendName.c_str()); - ImGui::NextColumn(); - } - ImGui::Columns(1); // Reset to 1 column - } - ImGui::End(); - - // Rendering - ImGui::Render(); - int display_w, display_h; - glfwGetFramebufferSize(window, &display_w, &display_h); - glViewport(0, 0, display_w, display_h); - glClearColor(0.45f, 0.55f, 0.60f, 1.00f); - glClear(GL_COLOR_BUFFER_BIT); - ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData()); - - // Swap buffers - glfwSwapBuffers(window); - } - - // Cleanup - ImGui_ImplOpenGL3_Shutdown(); - ImGui_ImplGlfw_Shutdown(); - ImGui::DestroyContext(); - glfwDestroyWindow(window); - glfwTerminate(); - SteamAPI_Shutdown(); - - return 0; -} \ No newline at end of file diff --git a/steam_message_handler.cpp b/steam_message_handler.cpp new file mode 100644 index 0000000..d098537 --- /dev/null +++ b/steam_message_handler.cpp @@ -0,0 +1,90 @@ +#include "steam_message_handler.h" +#include +#include +#include +#include +#include +#include + +// Constants for control packets +const char* CONTROL_PREFIX = "CONTROL:"; +const size_t CONTROL_PREFIX_LEN = 8; + +SteamMessageHandler::SteamMessageHandler(boost::asio::io_context& io_context, ISteamNetworkingSockets* interface, std::vector& connections, std::map& clientMap, std::mutex& clientMutex, std::unique_ptr& server, bool& g_isHost, int& localPort) + : io_context_(io_context), m_pInterface_(interface), connections_(connections), clientMap_(clientMap), clientMutex_(clientMutex), server_(server), g_isHost_(g_isHost), localPort_(localPort), running_(false) {} + +SteamMessageHandler::~SteamMessageHandler() { + stop(); +} + +void SteamMessageHandler::start() { + if (running_) return; + running_ = true; + thread_ = std::thread([this]() { run(); }); +} + +void SteamMessageHandler::stop() { + if (!running_) return; + running_ = false; + if (thread_.joinable()) { + thread_.join(); + } +} + +void SteamMessageHandler::run() { + while (running_) { + // Poll networking + m_pInterface_->RunCallbacks(); + + // Update user info (assuming userMap is accessible, but for simplicity, skip or add as param) + // Note: userMap update might need to be handled elsewhere or passed + + // Receive messages + pollMessages(); + + // Sleep a bit to avoid busy loop + std::this_thread::sleep_for(std::chrono::milliseconds(10)); + } +} + +void SteamMessageHandler::pollMessages() { + std::lock_guard lock(clientMutex_); + for (auto conn : connections_) { + ISteamNetworkingMessage* pIncomingMsgs[10]; + int numMsgs = m_pInterface_->ReceiveMessagesOnConnection(conn, pIncomingMsgs, 10); + for (int i = 0; i < numMsgs; ++i) { + ISteamNetworkingMessage* pIncomingMsg = pIncomingMsgs[i]; + const char* data = (const char*)pIncomingMsg->m_pData; + size_t size = pIncomingMsg->m_cbSize; + if (size >= CONTROL_PREFIX_LEN && memcmp(data, CONTROL_PREFIX, CONTROL_PREFIX_LEN) == 0) { + // Handle control packet + handleControlPacket(data + CONTROL_PREFIX_LEN, size - CONTROL_PREFIX_LEN, conn); + } else { + // Normal forwarding + if (server_) { + server_->sendToAll((const char*)pIncomingMsg->m_pData, pIncomingMsg->m_cbSize); + } + // Lazy connect: Create TCP Client on first message if not already connected + if (clientMap_.find(conn) == clientMap_.end() && g_isHost_ && localPort_ > 0) { + TCPClient* client = new TCPClient("localhost", localPort_); + if (client->connect()) { + client->setReceiveCallback([conn, this](const char* data, size_t size) { + std::lock_guard lock(clientMutex_); + m_pInterface_->SendMessageToConnection(conn, data, size, k_nSteamNetworkingSend_Reliable, nullptr); + }); + clientMap_[conn] = client; + std::cout << "Created TCP Client for connection on first message" << std::endl; + } else { + std::cerr << "Failed to connect TCP Client for connection" << std::endl; + delete client; + } + } + // Send to corresponding TCP client if exists (for host) + if (clientMap_.count(conn)) { + clientMap_[conn]->send((const char*)pIncomingMsg->m_pData, pIncomingMsg->m_cbSize); + } + } + pIncomingMsg->Release(); + } + } +} \ No newline at end of file diff --git a/steam_message_handler.h b/steam_message_handler.h new file mode 100644 index 0000000..957dc51 --- /dev/null +++ b/steam_message_handler.h @@ -0,0 +1,39 @@ +#ifndef STEAM_MESSAGE_HANDLER_H +#define STEAM_MESSAGE_HANDLER_H + +#include +#include +#include +#include +#include +#include +#include "tcp_server.h" +#include "tcp/tcp_client.h" +#include "control_packets.h" + +class SteamMessageHandler { +public: + SteamMessageHandler(boost::asio::io_context& io_context, ISteamNetworkingSockets* interface, std::vector& connections, std::map& clientMap, std::mutex& clientMutex, std::unique_ptr& server, bool& g_isHost, int& localPort); + ~SteamMessageHandler(); + + void start(); + void stop(); + +private: + void run(); + void pollMessages(); + + boost::asio::io_context& io_context_; + ISteamNetworkingSockets* m_pInterface_; + std::vector& connections_; + std::map& clientMap_; + std::mutex& clientMutex_; + std::unique_ptr& server_; + bool& g_isHost_; + int& localPort_; + + std::thread thread_; + bool running_; +}; + +#endif // STEAM_MESSAGE_HANDLER_H \ No newline at end of file diff --git a/tcp/tcp_client.cpp b/tcp/tcp_client.cpp index 44a6c93..e16f1fd 100644 --- a/tcp/tcp_client.cpp +++ b/tcp/tcp_client.cpp @@ -43,9 +43,10 @@ void TCPClient::send(const std::string& message) { void TCPClient::send(const char* data, size_t size) { if (!connected_) return; // std::cout << "Sending " << size << " bytes" << std::endl; - boost::asio::async_write(*socket_, boost::asio::buffer(data, size), [](const boost::system::error_code& error, std::size_t) { + boost::asio::async_write(*socket_, boost::asio::buffer(data, size), [this](const boost::system::error_code& error, std::size_t) { if (error) { std::cerr << "Send failed: " << error.message() << std::endl; + disconnect(); } }); } @@ -75,7 +76,11 @@ void TCPClient::handle_read(const boost::system::error_code& error, std::size_t } start_read(); } else { - std::cerr << "Read failed: " << error.message() << std::endl; + if (error == boost::asio::error::eof) { + std::cout << "Connection closed by peer" << std::endl; + } else { + std::cerr << "Read failed: " << error.message() << std::endl; + } disconnect(); } } \ No newline at end of file diff --git a/tcp/tcp_server.cpp b/tcp/tcp_server.cpp index e506d89..655a579 100644 --- a/tcp/tcp_server.cpp +++ b/tcp/tcp_server.cpp @@ -2,12 +2,13 @@ #include #include -TCPServer::TCPServer(int port) : port_(port), running_(false), acceptor_(io_context_), work_(boost::asio::make_work_guard(io_context_)) {} +TCPServer::TCPServer(int port) : port_(port), running_(false), acceptor_(io_context_), work_(boost::asio::make_work_guard(io_context_)), hasAcceptedConnection_(false) {} TCPServer::~TCPServer() { stop(); } bool TCPServer::start() { try { + hasAcceptedConnection_ = false; tcp::endpoint endpoint(tcp::v4(), port_); acceptor_.open(endpoint.protocol()); acceptor_.set_option(tcp::acceptor::reuse_address(true)); @@ -31,6 +32,7 @@ bool TCPServer::start() { void TCPServer::stop() { running_ = false; + hasAcceptedConnection_ = false; io_context_.stop(); if (serverThread_.joinable()) { serverThread_.join(); @@ -65,9 +67,10 @@ void TCPServer::start_accept() { std::lock_guard lock(clientsMutex_); clients_.push_back(socket); } + hasAcceptedConnection_ = true; start_read(socket); } - if (running_) { + if (running_ && !hasAcceptedConnection_) { start_accept(); } }); @@ -92,6 +95,11 @@ void TCPServer::start_read(std::shared_ptr socket) { // Remove client std::lock_guard lock(clientsMutex_); clients_.erase(std::remove(clients_.begin(), clients_.end(), socket), clients_.end()); + // Reset to allow new connection + hasAcceptedConnection_ = false; + if (running_) { + start_accept(); + } } }); } \ No newline at end of file diff --git a/tcp/tcp_server.h b/tcp/tcp_server.h index d9a0108..a599dd1 100644 --- a/tcp/tcp_server.h +++ b/tcp/tcp_server.h @@ -42,4 +42,5 @@ private: std::vector> clients_; std::mutex clientsMutex_; std::thread serverThread_; + bool hasAcceptedConnection_; }; \ No newline at end of file