diff --git a/online_game_tool.cpp b/online_game_tool.cpp index 0ec33ab..e7bb94d 100644 --- a/online_game_tool.cpp +++ b/online_game_tool.cpp @@ -14,7 +14,7 @@ #include #include "tcp_server.h" #include "tcp/tcp_client.h" -#include "steamnet/steam_networking_manager.h" +#include "steam/steam_networking_manager.h" using boost::asio::ip::tcp; diff --git a/steam/steam_message_handler.cpp b/steam/steam_message_handler.cpp new file mode 100644 index 0000000..89a58d5 --- /dev/null +++ b/steam/steam_message_handler.cpp @@ -0,0 +1,93 @@ +#include "steam_message_handler.h" +#include +#include +#include +#include +#include +#include + +SteamMessageHandler::SteamMessageHandler(boost::asio::io_context& io_context, ISteamNetworkingSockets* interface, std::vector& connections, std::map>& clientMap, std::mutex& clientMutex, std::mutex& connectionsMutex, std::unique_ptr& server, bool& g_isHost, int& localPort) + : io_context_(io_context), m_pInterface_(interface), connections_(connections), clientMap_(clientMap), clientMutex_(clientMutex), connectionsMutex_(connectionsMutex), 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(1)); + } +} + +void SteamMessageHandler::pollMessages() { + std::vector currentConnections; + { + std::lock_guard lockConn(connectionsMutex_); + currentConnections = connections_; + } + std::lock_guard lock(clientMutex_); + for (auto conn : currentConnections) { + 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; + // 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) { + auto client = std::make_shared("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); + }); + client->setDisconnectCallback([conn, this]() { + std::lock_guard lock(clientMutex_); + if (clientMap_.count(conn)) { + clientMap_[conn]->disconnect(); + clientMap_.erase(conn); + std::cout << "TCP client disconnected, removed from map" << std::endl; + } + }); + 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; + } + } + // 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/steamnet/steam_message_handler.h b/steam/steam_message_handler.h similarity index 88% rename from steamnet/steam_message_handler.h rename to steam/steam_message_handler.h index ffdfdde..429d22f 100644 --- a/steamnet/steam_message_handler.h +++ b/steam/steam_message_handler.h @@ -10,7 +10,6 @@ #include #include "tcp_server.h" #include "tcp/tcp_client.h" -#include "control_packets.h" class SteamMessageHandler { public: @@ -23,7 +22,6 @@ public: private: void run(); void pollMessages(); - void handleControlPacket(const char* data, size_t size, HSteamNetConnection conn); boost::asio::io_context& io_context_; ISteamNetworkingSockets* m_pInterface_; diff --git a/steamnet/steam_networking_manager.cpp b/steam/steam_networking_manager.cpp similarity index 59% rename from steamnet/steam_networking_manager.cpp rename to steam/steam_networking_manager.cpp index 87c7257..88bb723 100644 --- a/steamnet/steam_networking_manager.cpp +++ b/steam/steam_networking_manager.cpp @@ -13,107 +13,11 @@ void SteamNetworkingManager::OnSteamNetConnectionStatusChanged(SteamNetConnectio } } -SteamFriendsCallbacks::SteamFriendsCallbacks(SteamNetworkingManager *manager) : manager_(manager) -{ - std::cout << "SteamFriendsCallbacks constructor called" << std::endl; -} - -void SteamFriendsCallbacks::OnGameRichPresenceJoinRequested(GameRichPresenceJoinRequested_t *pCallback) -{ - std::cout << "GameRichPresenceJoinRequested received" << std::endl; - if (manager_) - { - const char *connectStr = pCallback->m_rgchConnect; - std::cout << "Connect string: '" << (connectStr ? connectStr : "null") << "'" << std::endl; - if (connectStr && connectStr[0] != '\0') - { - try - { - uint64 id = std::stoull(connectStr); - std::string str = connectStr; - std::cout << "Parsed ID: " << id << std::endl; - if (str.find("7656119") == 0) - { - // It's a Steam ID, join host directly - std::cout << "Parsed Steam ID: " << id << ", joining host" << std::endl; - if (!manager_->isHost() && !manager_->isConnected()) - { - manager_->joinHost(id); - // Start TCP Server if dependencies are set - if (manager_->server_ && !(*manager_->server_)) - { - *manager_->server_ = std::make_unique(8888, manager_); - if (!(*manager_->server_)->start()) - { - std::cerr << "Failed to start TCP server" << std::endl; - } - } - } - else - { - std::cout << "Already host or connected, ignoring join request" << std::endl; - } - } - else - { - // Assume it's a lobby ID - CSteamID lobbySteamID(id); - std::cout << "Parsed lobby ID: " << id << std::endl; - if (!manager_->isHost() && !manager_->isConnected()) - { - std::cout << "Joining lobby from invite: " << id << std::endl; - manager_->joinLobby(lobbySteamID); - } - else - { - std::cout << "Already host or connected, ignoring invite" << std::endl; - } - } - } - catch (const std::exception &e) - { - std::cerr << "Failed to parse connect string: " << connectStr << " error: " << e.what() << std::endl; - } - } - else - { - std::cerr << "Empty connect string in join request" << std::endl; - } - } - else - { - std::cout << "Manager is null" << std::endl; - } -} - -void SteamFriendsCallbacks::OnGameLobbyJoinRequested(GameLobbyJoinRequested_t *pCallback) -{ - std::cout << "GameLobbyJoinRequested received" << std::endl; - if (manager_) - { - CSteamID lobbyID = pCallback->m_steamIDLobby; - std::cout << "Lobby ID: " << lobbyID.ConvertToUint64() << std::endl; - if (!manager_->isHost() && !manager_->isConnected()) - { - std::cout << "Joining lobby from request: " << lobbyID.ConvertToUint64() << std::endl; - manager_->joinLobby(lobbyID); - } - else - { - std::cout << "Already host or connected, ignoring lobby join request" << std::endl; - } - } - else - { - std::cout << "Manager is null" << std::endl; - } -} - SteamNetworkingManager::SteamNetworkingManager() : m_pInterface(nullptr), hListenSock(k_HSteamListenSocket_Invalid), g_isHost(false), g_isClient(false), g_isConnected(false), g_hConnection(k_HSteamNetConnection_Invalid), io_context_(nullptr), clientMap_(nullptr), clientMutex_(nullptr), server_(nullptr), localPort_(nullptr), messageHandler_(nullptr), - steamFriendsCallbacks(nullptr), steamMatchmakingCallbacks(nullptr), currentLobby(k_steamIDNil) + roomManager_(nullptr) { std::cout << "Initialized SteamNetworkingManager" << std::endl; } @@ -122,8 +26,7 @@ SteamNetworkingManager::~SteamNetworkingManager() { stopMessageHandler(); delete messageHandler_; - delete steamFriendsCallbacks; - delete steamMatchmakingCallbacks; + delete roomManager_; shutdown(); } @@ -213,8 +116,7 @@ bool SteamNetworkingManager::initialize() std::cout << "[SteamNet] STUN servers: " << stunServersBuffer << std::endl; // Create callbacks after Steam API init - steamFriendsCallbacks = new SteamFriendsCallbacks(this); - steamMatchmakingCallbacks = new SteamMatchmakingCallbacks(this); + roomManager_ = new SteamRoomManager(this); SteamNetworkingUtils()->InitRelayNetworkAccess(); SteamNetworkingUtils()->SetGlobalCallback_SteamNetConnectionStatusChanged(OnSteamNetConnectionStatusChanged); @@ -242,7 +144,8 @@ bool SteamNetworkingManager::initialize() void SteamNetworkingManager::shutdown() { - leaveLobby(); + if (roomManager_) + roomManager_->leaveLobby(); if (g_hConnection != k_HSteamNetConnection_Invalid) { m_pInterface->CloseConnection(g_hConnection, 0, nullptr, false); @@ -258,82 +161,57 @@ void SteamNetworkingManager::shutdown() bool SteamNetworkingManager::createLobby() { - SteamAPICall_t hSteamAPICall = SteamMatchmaking()->CreateLobby(k_ELobbyTypePublic, 4); - if (hSteamAPICall == k_uAPICallInvalid) - { - std::cerr << "Failed to create lobby" << std::endl; - return false; - } - // Call result will be handled by callback - return true; + if (roomManager_) + return roomManager_->createLobby(); + return false; } void SteamNetworkingManager::leaveLobby() { - if (currentLobby != k_steamIDNil) - { - SteamMatchmaking()->LeaveLobby(currentLobby); - currentLobby = k_steamIDNil; - } + if (roomManager_) + roomManager_->leaveLobby(); } bool SteamNetworkingManager::searchLobbies() { - lobbies.clear(); - SteamAPICall_t hSteamAPICall = SteamMatchmaking()->RequestLobbyList(); - if (hSteamAPICall == k_uAPICallInvalid) - { - std::cerr << "Failed to request lobby list" << std::endl; - return false; - } - // Results will be handled by callback - return true; + if (roomManager_) + return roomManager_->searchLobbies(); + return false; } bool SteamNetworkingManager::joinLobby(CSteamID lobbyID) { - if (SteamMatchmaking()->JoinLobby(lobbyID) != k_EResultOK) - { - std::cerr << "Failed to join lobby" << std::endl; - return false; - } - // Connection will be handled by callback - return true; + if (roomManager_) + return roomManager_->joinLobby(lobbyID); + return false; +} + +const std::vector& SteamNetworkingManager::getLobbies() const +{ + static std::vector empty; + if (roomManager_) + return roomManager_->getLobbies(); + return empty; +} + +CSteamID SteamNetworkingManager::getCurrentLobby() const +{ + if (roomManager_) + return roomManager_->getCurrentLobby(); + return k_steamIDNil; } bool SteamNetworkingManager::startHosting() { - if (!createLobby()) - { - return false; - } - - 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; - // Rich Presence is set in OnLobbyCreated callback - return true; - } - else - { - std::cerr << "Failed to create listen socket for hosting" << std::endl; - leaveLobby(); - return false; - } + if (roomManager_) + return roomManager_->startHosting(); + return false; } void SteamNetworkingManager::stopHosting() { - if (hListenSock != k_HSteamListenSocket_Invalid) - { - m_pInterface->CloseListenSocket(hListenSock); - hListenSock = k_HSteamListenSocket_Invalid; - } - leaveLobby(); - g_isHost = false; + if (roomManager_) + roomManager_->stopHosting(); } bool SteamNetworkingManager::joinHost(uint64 hostID) @@ -461,66 +339,4 @@ void SteamNetworkingManager::handleConnectionStatusChanged(SteamNetConnectionSta userMap.erase(pInfo->m_hConn); std::cout << "Connection closed" << std::endl; } -} - -SteamMatchmakingCallbacks::SteamMatchmakingCallbacks(SteamNetworkingManager *manager) : manager_(manager) {} - -void SteamMatchmakingCallbacks::OnLobbyCreated(LobbyCreated_t *pCallback) -{ - if (pCallback->m_eResult == k_EResultOK) - { - manager_->currentLobby = pCallback->m_ulSteamIDLobby; - std::cout << "Lobby created: " << manager_->currentLobby.ConvertToUint64() << std::endl; - // Set Rich Presence with lobby ID - std::string lobbyStr = std::to_string(manager_->currentLobby.ConvertToUint64()); - SteamFriends()->SetRichPresence("connect", lobbyStr.c_str()); - SteamFriends()->SetRichPresence("status", "主持游戏房间"); - SteamFriends()->SetRichPresence("steam_display", "#StatusWithConnectFormat"); - std::cout << "Set Rich Presence connect to: " << lobbyStr << std::endl; - } - else - { - std::cerr << "Failed to create lobby" << std::endl; - } -} - -void SteamMatchmakingCallbacks::OnLobbyListReceived(LobbyMatchList_t *pCallback) -{ - manager_->lobbies.clear(); - for (uint32 i = 0; i < pCallback->m_nLobbiesMatching; ++i) - { - CSteamID lobbyID = SteamMatchmaking()->GetLobbyByIndex(i); - manager_->lobbies.push_back(lobbyID); - } - std::cout << "Received " << pCallback->m_nLobbiesMatching << " lobbies" << std::endl; -} - -void SteamMatchmakingCallbacks::OnLobbyEntered(LobbyEnter_t *pCallback) -{ - if (pCallback->m_EChatRoomEnterResponse == k_EChatRoomEnterResponseSuccess) - { - manager_->currentLobby = pCallback->m_ulSteamIDLobby; - std::cout << "Entered lobby: " << pCallback->m_ulSteamIDLobby << std::endl; - // Only join host if not the host - if (!manager_->isHost()) - { - CSteamID hostID = SteamMatchmaking()->GetLobbyOwner(pCallback->m_ulSteamIDLobby); - if (manager_->joinHost(hostID.ConvertToUint64())) - { - // Start TCP Server if dependencies are set - if (manager_->server_ && !(*manager_->server_)) - { - *manager_->server_ = std::make_unique(8888, manager_); - if (!(*manager_->server_)->start()) - { - std::cerr << "Failed to start TCP server" << std::endl; - } - } - } - } - } - else - { - std::cerr << "Failed to enter lobby" << std::endl; - } } \ No newline at end of file diff --git a/steamnet/steam_networking_manager.h b/steam/steam_networking_manager.h similarity index 73% rename from steamnet/steam_networking_manager.h rename to steam/steam_networking_manager.h index 2f8ed4c..50acacc 100644 --- a/steamnet/steam_networking_manager.h +++ b/steam/steam_networking_manager.h @@ -11,33 +11,13 @@ #include #include #include "steam_message_handler.h" +#include "steam_room_manager.h" // Forward declarations class TCPClient; class TCPServer; class SteamNetworkingManager; -// Callback class for Steam Friends -class SteamFriendsCallbacks { -public: - SteamFriendsCallbacks(SteamNetworkingManager* manager); - STEAM_CALLBACK(SteamFriendsCallbacks, OnGameRichPresenceJoinRequested, GameRichPresenceJoinRequested_t); - STEAM_CALLBACK(SteamFriendsCallbacks, OnGameLobbyJoinRequested, GameLobbyJoinRequested_t); -private: - SteamNetworkingManager* manager_; -}; - -// Callback class for Steam Matchmaking -class SteamMatchmakingCallbacks { -public: - SteamMatchmakingCallbacks(SteamNetworkingManager* manager); - STEAM_CALLBACK(SteamMatchmakingCallbacks, OnLobbyCreated, LobbyCreated_t); - STEAM_CALLBACK(SteamMatchmakingCallbacks, OnLobbyListReceived, LobbyMatchList_t); - STEAM_CALLBACK(SteamMatchmakingCallbacks, OnLobbyEntered, LobbyEnter_t); -private: - SteamNetworkingManager* manager_; -}; - // User info structure struct UserInfo { CSteamID steamID; @@ -64,8 +44,8 @@ public: void leaveLobby(); bool searchLobbies(); bool joinLobby(CSteamID lobbyID); - const std::vector& getLobbies() const { return lobbies; } - CSteamID getCurrentLobby() const { return currentLobby; } + const std::vector& getLobbies() const; + CSteamID getCurrentLobby() const; // Joining bool joinHost(uint64 hostID); @@ -109,10 +89,6 @@ private: HSteamNetConnection g_hConnection; CSteamID g_hostSteamID; - // Lobby - std::vector lobbies; - CSteamID currentLobby; - // Connections std::vector connections; std::map userMap; @@ -125,8 +101,9 @@ private: // Friends std::vector> friendsList; - SteamFriendsCallbacks* steamFriendsCallbacks; - SteamMatchmakingCallbacks* steamMatchmakingCallbacks; + + // Room manager + SteamRoomManager* roomManager_; // Message handler dependencies boost::asio::io_context* io_context_; @@ -139,6 +116,8 @@ private: // Callback static void OnSteamNetConnectionStatusChanged(SteamNetConnectionStatusChangedCallback_t *pInfo); void handleConnectionStatusChanged(SteamNetConnectionStatusChangedCallback_t *pInfo); + + friend class SteamRoomManager; }; #endif // STEAM_NETWORKING_MANAGER_H \ No newline at end of file diff --git a/steam/steam_room_manager.cpp b/steam/steam_room_manager.cpp new file mode 100644 index 0000000..9e6810b --- /dev/null +++ b/steam/steam_room_manager.cpp @@ -0,0 +1,256 @@ +#include "steam_room_manager.h" +#include "steam_networking_manager.h" +#include +#include + +SteamFriendsCallbacks::SteamFriendsCallbacks(SteamNetworkingManager *manager) : manager_(manager) +{ + std::cout << "SteamFriendsCallbacks constructor called" << std::endl; +} + +void SteamFriendsCallbacks::OnGameRichPresenceJoinRequested(GameRichPresenceJoinRequested_t *pCallback) +{ + std::cout << "GameRichPresenceJoinRequested received" << std::endl; + if (manager_) + { + const char *connectStr = pCallback->m_rgchConnect; + std::cout << "Connect string: '" << (connectStr ? connectStr : "null") << "'" << std::endl; + if (connectStr && connectStr[0] != '\0') + { + try + { + uint64 id = std::stoull(connectStr); + std::string str = connectStr; + std::cout << "Parsed ID: " << id << std::endl; + if (str.find("7656119") == 0) + { + // It's a Steam ID, join host directly + std::cout << "Parsed Steam ID: " << id << ", joining host" << std::endl; + if (!manager_->isHost() && !manager_->isConnected()) + { + manager_->joinHost(id); + // Start TCP Server if dependencies are set + if (manager_->server_ && !(*manager_->server_)) + { + *manager_->server_ = std::make_unique(8888, manager_); + if (!(*manager_->server_)->start()) + { + std::cerr << "Failed to start TCP server" << std::endl; + } + } + } + else + { + std::cout << "Already host or connected, ignoring join request" << std::endl; + } + } + else + { + // Assume it's a lobby ID + CSteamID lobbySteamID(id); + std::cout << "Parsed lobby ID: " << id << std::endl; + if (!manager_->isHost() && !manager_->isConnected()) + { + std::cout << "Joining lobby from invite: " << id << std::endl; + manager_->joinLobby(lobbySteamID); + } + else + { + std::cout << "Already host or connected, ignoring invite" << std::endl; + } + } + } + catch (const std::exception &e) + { + std::cerr << "Failed to parse connect string: " << connectStr << " error: " << e.what() << std::endl; + } + } + else + { + std::cerr << "Empty connect string in join request" << std::endl; + } + } + else + { + std::cout << "Manager is null" << std::endl; + } +} + +void SteamFriendsCallbacks::OnGameLobbyJoinRequested(GameLobbyJoinRequested_t *pCallback) +{ + std::cout << "GameLobbyJoinRequested received" << std::endl; + if (manager_) + { + CSteamID lobbyID = pCallback->m_steamIDLobby; + std::cout << "Lobby ID: " << lobbyID.ConvertToUint64() << std::endl; + if (!manager_->isHost() && !manager_->isConnected()) + { + std::cout << "Joining lobby from request: " << lobbyID.ConvertToUint64() << std::endl; + manager_->joinLobby(lobbyID); + } + else + { + std::cout << "Already host or connected, ignoring lobby join request" << std::endl; + } + } + else + { + std::cout << "Manager is null" << std::endl; + } +} + +SteamMatchmakingCallbacks::SteamMatchmakingCallbacks(SteamNetworkingManager *manager) : manager_(manager) {} + +void SteamMatchmakingCallbacks::OnLobbyCreated(LobbyCreated_t *pCallback) +{ + if (pCallback->m_eResult == k_EResultOK) + { + manager_->roomManager_->setCurrentLobby(pCallback->m_ulSteamIDLobby); + std::cout << "Lobby created: " << manager_->roomManager_->getCurrentLobby().ConvertToUint64() << std::endl; + // Set Rich Presence with lobby ID + std::string lobbyStr = std::to_string(manager_->roomManager_->getCurrentLobby().ConvertToUint64()); + SteamFriends()->SetRichPresence("connect", lobbyStr.c_str()); + SteamFriends()->SetRichPresence("status", "主持游戏房间"); + SteamFriends()->SetRichPresence("steam_display", "#StatusWithConnectFormat"); + std::cout << "Set Rich Presence connect to: " << lobbyStr << std::endl; + } + else + { + std::cerr << "Failed to create lobby" << std::endl; + } +} + +void SteamMatchmakingCallbacks::OnLobbyListReceived(LobbyMatchList_t *pCallback) +{ + manager_->roomManager_->clearLobbies(); + for (uint32 i = 0; i < pCallback->m_nLobbiesMatching; ++i) + { + CSteamID lobbyID = SteamMatchmaking()->GetLobbyByIndex(i); + manager_->roomManager_->addLobby(lobbyID); + } + std::cout << "Received " << pCallback->m_nLobbiesMatching << " lobbies" << std::endl; +} + +void SteamMatchmakingCallbacks::OnLobbyEntered(LobbyEnter_t *pCallback) +{ + if (pCallback->m_EChatRoomEnterResponse == k_EChatRoomEnterResponseSuccess) + { + manager_->roomManager_->setCurrentLobby(pCallback->m_ulSteamIDLobby); + std::cout << "Entered lobby: " << pCallback->m_ulSteamIDLobby << std::endl; + // Only join host if not the host + if (!manager_->isHost()) + { + CSteamID hostID = SteamMatchmaking()->GetLobbyOwner(pCallback->m_ulSteamIDLobby); + if (manager_->joinHost(hostID.ConvertToUint64())) + { + // Start TCP Server if dependencies are set + if (manager_->server_ && !(*manager_->server_)) + { + *manager_->server_ = std::make_unique(8888, manager_); + if (!(*manager_->server_)->start()) + { + std::cerr << "Failed to start TCP server" << std::endl; + } + } + } + } + } + else + { + std::cerr << "Failed to enter lobby" << std::endl; + } +} + +SteamRoomManager::SteamRoomManager(SteamNetworkingManager *networkingManager) + : networkingManager_(networkingManager), currentLobby(k_steamIDNil), + steamFriendsCallbacks(nullptr), steamMatchmakingCallbacks(nullptr) +{ + steamFriendsCallbacks = new SteamFriendsCallbacks(networkingManager_); + steamMatchmakingCallbacks = new SteamMatchmakingCallbacks(networkingManager_); +} + +SteamRoomManager::~SteamRoomManager() +{ + delete steamFriendsCallbacks; + delete steamMatchmakingCallbacks; +} + +bool SteamRoomManager::createLobby() +{ + SteamAPICall_t hSteamAPICall = SteamMatchmaking()->CreateLobby(k_ELobbyTypePublic, 4); + if (hSteamAPICall == k_uAPICallInvalid) + { + std::cerr << "Failed to create lobby" << std::endl; + return false; + } + // Call result will be handled by callback + return true; +} + +void SteamRoomManager::leaveLobby() +{ + if (currentLobby != k_steamIDNil) + { + SteamMatchmaking()->LeaveLobby(currentLobby); + currentLobby = k_steamIDNil; + } +} + +bool SteamRoomManager::searchLobbies() +{ + lobbies.clear(); + SteamAPICall_t hSteamAPICall = SteamMatchmaking()->RequestLobbyList(); + if (hSteamAPICall == k_uAPICallInvalid) + { + std::cerr << "Failed to request lobby list" << std::endl; + return false; + } + // Results will be handled by callback + return true; +} + +bool SteamRoomManager::joinLobby(CSteamID lobbyID) +{ + if (SteamMatchmaking()->JoinLobby(lobbyID) != k_EResultOK) + { + std::cerr << "Failed to join lobby" << std::endl; + return false; + } + // Connection will be handled by callback + return true; +} + +bool SteamRoomManager::startHosting() +{ + if (!createLobby()) + { + return false; + } + + networkingManager_->hListenSock = networkingManager_->m_pInterface->CreateListenSocketP2P(0, 0, nullptr); + + if (networkingManager_->hListenSock != k_HSteamListenSocket_Invalid) + { + networkingManager_->g_isHost = true; + std::cout << "Created listen socket for hosting game room" << std::endl; + // Rich Presence is set in OnLobbyCreated callback + return true; + } + else + { + std::cerr << "Failed to create listen socket for hosting" << std::endl; + leaveLobby(); + return false; + } +} + +void SteamRoomManager::stopHosting() +{ + if (networkingManager_->hListenSock != k_HSteamListenSocket_Invalid) + { + networkingManager_->m_pInterface->CloseListenSocket(networkingManager_->hListenSock); + networkingManager_->hListenSock = k_HSteamListenSocket_Invalid; + } + leaveLobby(); + networkingManager_->g_isHost = false; +} \ No newline at end of file diff --git a/steam/steam_room_manager.h b/steam/steam_room_manager.h new file mode 100644 index 0000000..a35a9fe --- /dev/null +++ b/steam/steam_room_manager.h @@ -0,0 +1,58 @@ +#pragma once +#include +#include +#include +#include + +class SteamNetworkingManager; // Forward declaration + +class SteamFriendsCallbacks +{ +public: + SteamFriendsCallbacks(SteamNetworkingManager *manager); + void OnGameRichPresenceJoinRequested(GameRichPresenceJoinRequested_t *pCallback); + void OnGameLobbyJoinRequested(GameLobbyJoinRequested_t *pCallback); + +private: + SteamNetworkingManager *manager_; +}; + +class SteamMatchmakingCallbacks +{ +public: + SteamMatchmakingCallbacks(SteamNetworkingManager *manager); + void OnLobbyCreated(LobbyCreated_t *pCallback); + void OnLobbyListReceived(LobbyMatchList_t *pCallback); + void OnLobbyEntered(LobbyEnter_t *pCallback); + +private: + SteamNetworkingManager *manager_; +}; + +class SteamRoomManager +{ +public: + SteamRoomManager(SteamNetworkingManager *networkingManager); + ~SteamRoomManager(); + + bool createLobby(); + void leaveLobby(); + bool searchLobbies(); + bool joinLobby(CSteamID lobbyID); + bool startHosting(); + void stopHosting(); + + CSteamID getCurrentLobby() const { return currentLobby; } + const std::vector& getLobbies() const { return lobbies; } + + void setCurrentLobby(CSteamID lobby) { currentLobby = lobby; } + void addLobby(CSteamID lobby) { lobbies.push_back(lobby); } + void clearLobbies() { lobbies.clear(); } + +private: + SteamNetworkingManager *networkingManager_; + CSteamID currentLobby; + std::vector lobbies; + SteamFriendsCallbacks *steamFriendsCallbacks; + SteamMatchmakingCallbacks *steamMatchmakingCallbacks; +}; \ No newline at end of file diff --git a/steamnet/control_packets.cpp b/steamnet/control_packets.cpp deleted file mode 100644 index f0e9115..0000000 --- a/steamnet/control_packets.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#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/steamnet/control_packets.h b/steamnet/control_packets.h deleted file mode 100644 index 27dc8d5..0000000 --- a/steamnet/control_packets.h +++ /dev/null @@ -1,8 +0,0 @@ -#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/steamnet/steam_message_handler.cpp b/steamnet/steam_message_handler.cpp deleted file mode 100644 index e2e0fe7..0000000 --- a/steamnet/steam_message_handler.cpp +++ /dev/null @@ -1,111 +0,0 @@ -#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::mutex& connectionsMutex, std::unique_ptr& server, bool& g_isHost, int& localPort) - : io_context_(io_context), m_pInterface_(interface), connections_(connections), clientMap_(clientMap), clientMutex_(clientMutex), connectionsMutex_(connectionsMutex), server_(server), g_isHost_(g_isHost), localPort_(localPort), running_(false) {} - -SteamMessageHandler::~SteamMessageHandler() { - stop(); -} - -void SteamMessageHandler::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; - // Add handling logic here - if (packetData == "ping") { - std::cout << "Responding to ping" << std::endl; - } -} - -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(1)); - } -} - -void SteamMessageHandler::pollMessages() { - std::vector currentConnections; - { - std::lock_guard lockConn(connectionsMutex_); - currentConnections = connections_; - } - std::lock_guard lock(clientMutex_); - for (auto conn : currentConnections) { - 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) { - auto client = std::make_shared("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); - }); - client->setDisconnectCallback([conn, this]() { - std::lock_guard lock(clientMutex_); - if (clientMap_.count(conn)) { - clientMap_[conn]->disconnect(); - clientMap_.erase(conn); - std::cout << "TCP client disconnected, removed from map" << std::endl; - } - }); - 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; - } - } - // 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/tcp/tcp_server.cpp b/tcp/tcp_server.cpp index dddc2f3..cf8e389 100644 --- a/tcp/tcp_server.cpp +++ b/tcp/tcp_server.cpp @@ -1,5 +1,5 @@ #include "tcp_server.h" -#include "../steamnet/steam_networking_manager.h" +#include "../steam/steam_networking_manager.h" #include #include