重构Steam网络管理,整合房间管理功能,添加多路复用支持,优化TCP服务器和消息处理

This commit is contained in:
Ayndpa
2025-11-19 16:49:36 +08:00
parent 0e65ecb8ca
commit f661b1d369
12 changed files with 217 additions and 192 deletions

View File

@@ -0,0 +1,80 @@
#include "multiplex_manager.h"
#include <iostream>
#include <cstring>
MultiplexManager::MultiplexManager(ISteamNetworkingSockets* steamInterface, HSteamNetConnection steamConn)
: steamInterface_(steamInterface), steamConn_(steamConn), nextId_(1) {}
MultiplexManager::~MultiplexManager() {
// Close all sockets
std::lock_guard<std::mutex> lock(mapMutex_);
for (auto& pair : clientMap_) {
pair.second->close();
}
clientMap_.clear();
}
uint32_t MultiplexManager::addClient(std::shared_ptr<tcp::socket> socket) {
std::lock_guard<std::mutex> lock(mapMutex_);
uint32_t id = nextId_++;
clientMap_[id] = socket;
return id;
}
void MultiplexManager::removeClient(uint32_t id) {
std::lock_guard<std::mutex> lock(mapMutex_);
auto it = clientMap_.find(id);
if (it != clientMap_.end()) {
it->second->close();
clientMap_.erase(it);
}
}
std::shared_ptr<tcp::socket> MultiplexManager::getClient(uint32_t id) {
std::lock_guard<std::mutex> lock(mapMutex_);
auto it = clientMap_.find(id);
if (it != clientMap_.end()) {
return it->second;
}
return nullptr;
}
void MultiplexManager::sendTunnelPacket(uint32_t id, const char* data, size_t len, int type) {
// Packet format: uint32_t id, uint32_t type, then data if type==0
size_t packetSize = sizeof(uint32_t) * 2 + (type == 0 ? len : 0);
std::vector<char> packet(packetSize);
uint32_t* pId = reinterpret_cast<uint32_t*>(&packet[0]);
uint32_t* pType = reinterpret_cast<uint32_t*>(&packet[sizeof(uint32_t)]);
*pId = id;
*pType = type;
if (type == 0 && data) {
std::memcpy(&packet[sizeof(uint32_t) * 2], data, len);
}
steamInterface_->SendMessageToConnection(steamConn_, packet.data(), packet.size(), k_nSteamNetworkingSend_Reliable, nullptr);
}
void MultiplexManager::handleTunnelPacket(const char* data, size_t len) {
if (len < sizeof(uint32_t) * 2) {
std::cerr << "Invalid tunnel packet size" << std::endl;
return;
}
uint32_t id = *reinterpret_cast<const uint32_t*>(data);
uint32_t type = *reinterpret_cast<const uint32_t*>(data + sizeof(uint32_t));
if (type == 0) {
// Data packet
size_t dataLen = len - sizeof(uint32_t) * 2;
const char* packetData = data + sizeof(uint32_t) * 2;
auto socket = getClient(id);
if (socket) {
boost::asio::async_write(*socket, boost::asio::buffer(packetData, dataLen), [](const boost::system::error_code&, std::size_t) {});
} else {
std::cerr << "No client found for id " << id << std::endl;
}
} else if (type == 1) {
// Disconnect packet
removeClient(id);
std::cout << "Client " << id << " disconnected" << std::endl;
} else {
std::cerr << "Unknown packet type " << type << std::endl;
}
}

View File

@@ -0,0 +1,33 @@
#pragma once
#include <unordered_map>
#include <memory>
#include <mutex>
#include <vector>
#include <boost/asio.hpp>
#include <steam_api.h>
#include <isteamnetworkingsockets.h>
#include <steamnetworkingtypes.h>
using boost::asio::ip::tcp;
class MultiplexManager {
public:
MultiplexManager(ISteamNetworkingSockets* steamInterface, HSteamNetConnection steamConn);
~MultiplexManager();
uint32_t addClient(std::shared_ptr<tcp::socket> socket);
void removeClient(uint32_t id);
std::shared_ptr<tcp::socket> getClient(uint32_t id);
void sendTunnelPacket(uint32_t id, const char* data, size_t len, int type);
void handleTunnelPacket(const char* data, size_t len);
private:
ISteamNetworkingSockets* steamInterface_;
HSteamNetConnection steamConn_;
std::unordered_map<uint32_t, std::shared_ptr<tcp::socket>> clientMap_;
std::mutex mapMutex_;
uint32_t nextId_;
};

View File

@@ -15,6 +15,8 @@
#include "tcp_server.h" #include "tcp_server.h"
#include "tcp/tcp_client.h" #include "tcp/tcp_client.h"
#include "steam/steam_networking_manager.h" #include "steam/steam_networking_manager.h"
#include "steam/steam_room_manager.h"
#include "steam/steam_utils.h"
using boost::asio::ip::tcp; using boost::asio::ip::tcp;
@@ -36,6 +38,9 @@ int main() {
return 1; return 1;
} }
// Initialize Steam Room Manager
SteamRoomManager roomManager(&steamManager);
// Initialize GLFW // Initialize GLFW
if (!glfwInit()) { if (!glfwInit()) {
std::cerr << "Failed to initialize GLFW" << std::endl; std::cerr << "Failed to initialize GLFW" << std::endl;
@@ -81,7 +86,7 @@ int main() {
auto renderInviteFriends = [&]() { auto renderInviteFriends = [&]() {
ImGui::InputText("过滤朋友", filterBuffer, IM_ARRAYSIZE(filterBuffer)); ImGui::InputText("过滤朋友", filterBuffer, IM_ARRAYSIZE(filterBuffer));
ImGui::Text("朋友:"); ImGui::Text("朋友:");
for (const auto& friendPair : steamManager.getFriendsList()) { for (const auto& friendPair : SteamUtils::getFriendsList()) {
std::string nameStr = friendPair.second; std::string nameStr = friendPair.second;
std::string filterStr(filterBuffer); std::string filterStr(filterBuffer);
// Convert to lowercase for case-insensitive search // Convert to lowercase for case-insensitive search
@@ -91,7 +96,7 @@ int main() {
ImGui::PushID(friendPair.first.ConvertToUint64()); ImGui::PushID(friendPair.first.ConvertToUint64());
if (ImGui::Button(("邀请 " + friendPair.second).c_str())) { if (ImGui::Button(("邀请 " + friendPair.second).c_str())) {
// Send invite via Steam with lobby ID as connect string // Send invite via Steam with lobby ID as connect string
std::string connectStr = std::to_string(steamManager.getCurrentLobby().ConvertToUint64()); std::string connectStr = std::to_string(roomManager.getCurrentLobby().ConvertToUint64());
// Safety check for SteamFriends // Safety check for SteamFriends
if (SteamFriends()) { if (SteamFriends()) {
SteamFriends()->InviteUserToGame(friendPair.first, connectStr.c_str()); SteamFriends()->InviteUserToGame(friendPair.first, connectStr.c_str());
@@ -131,10 +136,10 @@ int main() {
if (!steamManager.isHost() && !steamManager.isConnected()) { if (!steamManager.isHost() && !steamManager.isConnected()) {
if (ImGui::Button("主持游戏房间")) { if (ImGui::Button("主持游戏房间")) {
steamManager.startHosting(); roomManager.startHosting();
} }
if (ImGui::Button("搜索游戏房间")) { if (ImGui::Button("搜索游戏房间")) {
steamManager.searchLobbies(); roomManager.searchLobbies();
} }
ImGui::InputText("主机Steam ID", joinBuffer, IM_ARRAYSIZE(joinBuffer)); ImGui::InputText("主机Steam ID", joinBuffer, IM_ARRAYSIZE(joinBuffer));
if (ImGui::Button("加入游戏房间")) { if (ImGui::Button("加入游戏房间")) {
@@ -148,12 +153,12 @@ int main() {
} }
} }
// Display available lobbies // Display available lobbies
if (!steamManager.getLobbies().empty()) { if (!roomManager.getLobbies().empty()) {
ImGui::Text("可用房间:"); ImGui::Text("可用房间:");
for (const auto& lobbyID : steamManager.getLobbies()) { for (const auto& lobbyID : roomManager.getLobbies()) {
std::string lobbyName = "房间 " + std::to_string(lobbyID.ConvertToUint64()); std::string lobbyName = "房间 " + std::to_string(lobbyID.ConvertToUint64());
if (ImGui::Button(lobbyName.c_str())) { if (ImGui::Button(lobbyName.c_str())) {
steamManager.joinLobby(lobbyID); roomManager.joinLobby(lobbyID);
} }
} }
} }

View File

@@ -57,35 +57,9 @@ void SteamMessageHandler::pollMessages() {
ISteamNetworkingMessage* pIncomingMsg = pIncomingMsgs[i]; ISteamNetworkingMessage* pIncomingMsg = pIncomingMsgs[i];
const char* data = (const char*)pIncomingMsg->m_pData; const char* data = (const char*)pIncomingMsg->m_pData;
size_t size = pIncomingMsg->m_cbSize; size_t size = pIncomingMsg->m_cbSize;
// Normal forwarding // Handle tunnel packets with multiplexing
if (server_) { if (server_ && server_->getMultiplexManager()) {
server_->sendToAll((const char*)pIncomingMsg->m_pData, pIncomingMsg->m_cbSize); server_->getMultiplexManager()->handleTunnelPacket(data, size);
}
// 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<TCPClient>("localhost", localPort_);
if (client->connect()) {
client->setReceiveCallback([conn, this](const char* data, size_t size) {
std::lock_guard<std::mutex> lock(clientMutex_);
m_pInterface_->SendMessageToConnection(conn, data, size, k_nSteamNetworkingSend_Reliable, nullptr);
});
client->setDisconnectCallback([conn, this]() {
std::lock_guard<std::mutex> 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(); pIncomingMsg->Release();
} }

View File

@@ -16,8 +16,7 @@ void SteamNetworkingManager::OnSteamNetConnectionStatusChanged(SteamNetConnectio
SteamNetworkingManager::SteamNetworkingManager() SteamNetworkingManager::SteamNetworkingManager()
: m_pInterface(nullptr), hListenSock(k_HSteamListenSocket_Invalid), g_isHost(false), g_isClient(false), g_isConnected(false), : m_pInterface(nullptr), hListenSock(k_HSteamListenSocket_Invalid), g_isHost(false), g_isClient(false), g_isConnected(false),
g_hConnection(k_HSteamNetConnection_Invalid), g_hConnection(k_HSteamNetConnection_Invalid),
io_context_(nullptr), clientMap_(nullptr), clientMutex_(nullptr), server_(nullptr), localPort_(nullptr), messageHandler_(nullptr), io_context_(nullptr), clientMap_(nullptr), clientMutex_(nullptr), server_(nullptr), localPort_(nullptr), messageHandler_(nullptr)
roomManager_(nullptr)
{ {
std::cout << "Initialized SteamNetworkingManager" << std::endl; std::cout << "Initialized SteamNetworkingManager" << std::endl;
} }
@@ -26,7 +25,6 @@ SteamNetworkingManager::~SteamNetworkingManager()
{ {
stopMessageHandler(); stopMessageHandler();
delete messageHandler_; delete messageHandler_;
delete roomManager_;
shutdown(); shutdown();
} }
@@ -85,36 +83,19 @@ bool SteamNetworkingManager::initialize()
&allowWithoutAuth); &allowWithoutAuth);
// Create callbacks after Steam API init // Create callbacks after Steam API init
roomManager_ = new SteamRoomManager(this);
SteamNetworkingUtils()->InitRelayNetworkAccess(); SteamNetworkingUtils()->InitRelayNetworkAccess();
SteamNetworkingUtils()->SetGlobalCallback_SteamNetConnectionStatusChanged(OnSteamNetConnectionStatusChanged); SteamNetworkingUtils()->SetGlobalCallback_SteamNetConnectionStatusChanged(OnSteamNetConnectionStatusChanged);
m_pInterface = SteamNetworkingSockets(); m_pInterface = SteamNetworkingSockets();
// Clear Rich Presence on startup
SteamFriends()->ClearRichPresence();
std::cout << "Cleared Rich Presence on startup" << std::endl;
// Check if callbacks are registered // Check if callbacks are registered
std::cout << "Steam API initialized" << std::endl; std::cout << "Steam API initialized" << std::endl;
// Get friends list
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({friendID, name});
}
return true; return true;
} }
void SteamNetworkingManager::shutdown() void SteamNetworkingManager::shutdown()
{ {
if (roomManager_)
roomManager_->leaveLobby();
if (g_hConnection != k_HSteamNetConnection_Invalid) if (g_hConnection != k_HSteamNetConnection_Invalid)
{ {
m_pInterface->CloseConnection(g_hConnection, 0, nullptr, false); m_pInterface->CloseConnection(g_hConnection, 0, nullptr, false);
@@ -123,66 +104,9 @@ void SteamNetworkingManager::shutdown()
{ {
m_pInterface->CloseListenSocket(hListenSock); m_pInterface->CloseListenSocket(hListenSock);
} }
// Clear Rich Presence on shutdown
SteamFriends()->ClearRichPresence();
SteamAPI_Shutdown(); SteamAPI_Shutdown();
} }
bool SteamNetworkingManager::createLobby()
{
if (roomManager_)
return roomManager_->createLobby();
return false;
}
void SteamNetworkingManager::leaveLobby()
{
if (roomManager_)
roomManager_->leaveLobby();
}
bool SteamNetworkingManager::searchLobbies()
{
if (roomManager_)
return roomManager_->searchLobbies();
return false;
}
bool SteamNetworkingManager::joinLobby(CSteamID lobbyID)
{
if (roomManager_)
return roomManager_->joinLobby(lobbyID);
return false;
}
const std::vector<CSteamID>& SteamNetworkingManager::getLobbies() const
{
static std::vector<CSteamID> empty;
if (roomManager_)
return roomManager_->getLobbies();
return empty;
}
CSteamID SteamNetworkingManager::getCurrentLobby() const
{
if (roomManager_)
return roomManager_->getCurrentLobby();
return k_steamIDNil;
}
bool SteamNetworkingManager::startHosting()
{
if (roomManager_)
return roomManager_->startHosting();
return false;
}
void SteamNetworkingManager::stopHosting()
{
if (roomManager_)
roomManager_->stopHosting();
}
bool SteamNetworkingManager::joinHost(uint64 hostID) bool SteamNetworkingManager::joinHost(uint64 hostID)
{ {
CSteamID hostSteamID(hostID); CSteamID hostSteamID(hostID);

View File

@@ -9,9 +9,7 @@
#include <isteamnetworkingsockets.h> #include <isteamnetworkingsockets.h>
#include <isteamnetworkingutils.h> #include <isteamnetworkingutils.h>
#include <steamnetworkingtypes.h> #include <steamnetworkingtypes.h>
#include <isteammatchmaking.h>
#include "steam_message_handler.h" #include "steam_message_handler.h"
#include "steam_room_manager.h"
// Forward declarations // Forward declarations
class TCPClient; class TCPClient;
@@ -35,18 +33,6 @@ public:
bool initialize(); bool initialize();
void shutdown(); void shutdown();
// Hosting
bool startHosting();
void stopHosting();
// Lobby
bool createLobby();
void leaveLobby();
bool searchLobbies();
bool joinLobby(CSteamID lobbyID);
const std::vector<CSteamID>& getLobbies() const;
CSteamID getCurrentLobby() const;
// Joining // Joining
bool joinHost(uint64 hostID); bool joinHost(uint64 hostID);
void disconnect(); void disconnect();
@@ -55,12 +41,21 @@ public:
bool isHost() const { return g_isHost; } bool isHost() const { return g_isHost; }
bool isClient() const { return g_isClient; } bool isClient() const { return g_isClient; }
bool isConnected() const { return g_isConnected; } bool isConnected() const { return g_isConnected; }
const std::vector<std::pair<CSteamID, std::string>>& getFriendsList() const { return friendsList; }
const std::map<HSteamNetConnection, UserInfo>& getUserMap() const { return userMap; } const std::map<HSteamNetConnection, UserInfo>& getUserMap() const { return userMap; }
const std::vector<HSteamNetConnection>& getConnections() const { return connections; } const std::vector<HSteamNetConnection>& getConnections() const { return connections; }
HSteamNetConnection getConnection() const { return g_hConnection; } HSteamNetConnection getConnection() const { return g_hConnection; }
ISteamNetworkingSockets* getInterface() const { return m_pInterface; } ISteamNetworkingSockets* getInterface() const { return m_pInterface; }
// For SteamRoomManager access
std::unique_ptr<TCPServer>*& getServer() { return server_; }
int*& getLocalPort() { return localPort_; }
boost::asio::io_context*& getIOContext() { return io_context_; }
std::map<HSteamNetConnection, std::shared_ptr<TCPClient>>*& getClientMap() { return clientMap_; }
std::mutex*& getClientMutex() { return clientMutex_; }
HSteamListenSocket& getListenSock() { return hListenSock; }
ISteamNetworkingSockets* getInterface() { return m_pInterface; }
bool& getIsHost() { return g_isHost; }
void setMessageHandlerDependencies(boost::asio::io_context& io_context, std::map<HSteamNetConnection, std::shared_ptr<TCPClient>>& clientMap, std::mutex& clientMutex, std::unique_ptr<TCPServer>& server, int& localPort); void setMessageHandlerDependencies(boost::asio::io_context& io_context, std::map<HSteamNetConnection, std::shared_ptr<TCPClient>>& clientMap, std::mutex& clientMutex, std::unique_ptr<TCPServer>& server, int& localPort);
// Message handler // Message handler
@@ -74,9 +69,6 @@ public:
void setHostSteamID(CSteamID id) { g_hostSteamID = id; } void setHostSteamID(CSteamID id) { g_hostSteamID = id; }
CSteamID getHostSteamID() const { return g_hostSteamID; } CSteamID getHostSteamID() const { return g_hostSteamID; }
friend class SteamFriendsCallbacks;
friend class SteamMatchmakingCallbacks;
private: private:
// Steam API // Steam API
ISteamNetworkingSockets* m_pInterface; ISteamNetworkingSockets* m_pInterface;
@@ -99,12 +91,6 @@ private:
const int MAX_RETRIES = 3; const int MAX_RETRIES = 3;
int g_currentVirtualPort; int g_currentVirtualPort;
// Friends
std::vector<std::pair<CSteamID, std::string>> friendsList;
// Room manager
SteamRoomManager* roomManager_;
// Message handler dependencies // Message handler dependencies
boost::asio::io_context* io_context_; boost::asio::io_context* io_context_;
std::map<HSteamNetConnection, std::shared_ptr<TCPClient>>* clientMap_; std::map<HSteamNetConnection, std::shared_ptr<TCPClient>>* clientMap_;

View File

@@ -3,7 +3,7 @@
#include <iostream> #include <iostream>
#include <algorithm> #include <algorithm>
SteamFriendsCallbacks::SteamFriendsCallbacks(SteamNetworkingManager *manager) : manager_(manager) SteamFriendsCallbacks::SteamFriendsCallbacks(SteamNetworkingManager *manager, SteamRoomManager *roomManager) : manager_(manager), roomManager_(roomManager)
{ {
std::cout << "SteamFriendsCallbacks constructor called" << std::endl; std::cout << "SteamFriendsCallbacks constructor called" << std::endl;
} }
@@ -30,10 +30,10 @@ void SteamFriendsCallbacks::OnGameRichPresenceJoinRequested(GameRichPresenceJoin
{ {
manager_->joinHost(id); manager_->joinHost(id);
// Start TCP Server if dependencies are set // Start TCP Server if dependencies are set
if (manager_->server_ && !(*manager_->server_)) if (manager_->getServer() && !(*manager_->getServer()))
{ {
*manager_->server_ = std::make_unique<TCPServer>(8888, manager_); *manager_->getServer() = std::make_unique<TCPServer>(8888, manager_);
if (!(*manager_->server_)->start()) if (!(*manager_->getServer())->start())
{ {
std::cerr << "Failed to start TCP server" << std::endl; std::cerr << "Failed to start TCP server" << std::endl;
} }
@@ -52,7 +52,7 @@ void SteamFriendsCallbacks::OnGameRichPresenceJoinRequested(GameRichPresenceJoin
if (!manager_->isHost() && !manager_->isConnected()) if (!manager_->isHost() && !manager_->isConnected())
{ {
std::cout << "Joining lobby from invite: " << id << std::endl; std::cout << "Joining lobby from invite: " << id << std::endl;
manager_->joinLobby(lobbySteamID); roomManager_->joinLobby(lobbySteamID);
} }
else else
{ {
@@ -86,7 +86,7 @@ void SteamFriendsCallbacks::OnGameLobbyJoinRequested(GameLobbyJoinRequested_t *p
if (!manager_->isHost() && !manager_->isConnected()) if (!manager_->isHost() && !manager_->isConnected())
{ {
std::cout << "Joining lobby from request: " << lobbyID.ConvertToUint64() << std::endl; std::cout << "Joining lobby from request: " << lobbyID.ConvertToUint64() << std::endl;
manager_->joinLobby(lobbyID); roomManager_->joinLobby(lobbyID);
} }
else else
{ {
@@ -99,16 +99,16 @@ void SteamFriendsCallbacks::OnGameLobbyJoinRequested(GameLobbyJoinRequested_t *p
} }
} }
SteamMatchmakingCallbacks::SteamMatchmakingCallbacks(SteamNetworkingManager *manager) : manager_(manager) {} SteamMatchmakingCallbacks::SteamMatchmakingCallbacks(SteamNetworkingManager *manager, SteamRoomManager *roomManager) : manager_(manager), roomManager_(roomManager) {}
void SteamMatchmakingCallbacks::OnLobbyCreated(LobbyCreated_t *pCallback) void SteamMatchmakingCallbacks::OnLobbyCreated(LobbyCreated_t *pCallback)
{ {
if (pCallback->m_eResult == k_EResultOK) if (pCallback->m_eResult == k_EResultOK)
{ {
manager_->roomManager_->setCurrentLobby(pCallback->m_ulSteamIDLobby); roomManager_->setCurrentLobby(pCallback->m_ulSteamIDLobby);
std::cout << "Lobby created: " << manager_->roomManager_->getCurrentLobby().ConvertToUint64() << std::endl; std::cout << "Lobby created: " << roomManager_->getCurrentLobby().ConvertToUint64() << std::endl;
// Set Rich Presence with lobby ID // Set Rich Presence with lobby ID
std::string lobbyStr = std::to_string(manager_->roomManager_->getCurrentLobby().ConvertToUint64()); std::string lobbyStr = std::to_string(roomManager_->getCurrentLobby().ConvertToUint64());
SteamFriends()->SetRichPresence("connect", lobbyStr.c_str()); SteamFriends()->SetRichPresence("connect", lobbyStr.c_str());
SteamFriends()->SetRichPresence("status", "主持游戏房间"); SteamFriends()->SetRichPresence("status", "主持游戏房间");
SteamFriends()->SetRichPresence("steam_display", "#StatusWithConnectFormat"); SteamFriends()->SetRichPresence("steam_display", "#StatusWithConnectFormat");
@@ -122,11 +122,11 @@ void SteamMatchmakingCallbacks::OnLobbyCreated(LobbyCreated_t *pCallback)
void SteamMatchmakingCallbacks::OnLobbyListReceived(LobbyMatchList_t *pCallback) void SteamMatchmakingCallbacks::OnLobbyListReceived(LobbyMatchList_t *pCallback)
{ {
manager_->roomManager_->clearLobbies(); roomManager_->clearLobbies();
for (uint32 i = 0; i < pCallback->m_nLobbiesMatching; ++i) for (uint32 i = 0; i < pCallback->m_nLobbiesMatching; ++i)
{ {
CSteamID lobbyID = SteamMatchmaking()->GetLobbyByIndex(i); CSteamID lobbyID = SteamMatchmaking()->GetLobbyByIndex(i);
manager_->roomManager_->addLobby(lobbyID); roomManager_->addLobby(lobbyID);
} }
std::cout << "Received " << pCallback->m_nLobbiesMatching << " lobbies" << std::endl; std::cout << "Received " << pCallback->m_nLobbiesMatching << " lobbies" << std::endl;
} }
@@ -135,7 +135,7 @@ void SteamMatchmakingCallbacks::OnLobbyEntered(LobbyEnter_t *pCallback)
{ {
if (pCallback->m_EChatRoomEnterResponse == k_EChatRoomEnterResponseSuccess) if (pCallback->m_EChatRoomEnterResponse == k_EChatRoomEnterResponseSuccess)
{ {
manager_->roomManager_->setCurrentLobby(pCallback->m_ulSteamIDLobby); roomManager_->setCurrentLobby(pCallback->m_ulSteamIDLobby);
std::cout << "Entered lobby: " << pCallback->m_ulSteamIDLobby << std::endl; std::cout << "Entered lobby: " << pCallback->m_ulSteamIDLobby << std::endl;
// Only join host if not the host // Only join host if not the host
if (!manager_->isHost()) if (!manager_->isHost())
@@ -144,10 +144,10 @@ void SteamMatchmakingCallbacks::OnLobbyEntered(LobbyEnter_t *pCallback)
if (manager_->joinHost(hostID.ConvertToUint64())) if (manager_->joinHost(hostID.ConvertToUint64()))
{ {
// Start TCP Server if dependencies are set // Start TCP Server if dependencies are set
if (manager_->server_ && !(*manager_->server_)) if (manager_->getServer() && !(*manager_->getServer()))
{ {
*manager_->server_ = std::make_unique<TCPServer>(8888, manager_); *manager_->getServer() = std::make_unique<TCPServer>(8888, manager_);
if (!(*manager_->server_)->start()) if (!(*manager_->getServer())->start())
{ {
std::cerr << "Failed to start TCP server" << std::endl; std::cerr << "Failed to start TCP server" << std::endl;
} }
@@ -165,8 +165,8 @@ SteamRoomManager::SteamRoomManager(SteamNetworkingManager *networkingManager)
: networkingManager_(networkingManager), currentLobby(k_steamIDNil), : networkingManager_(networkingManager), currentLobby(k_steamIDNil),
steamFriendsCallbacks(nullptr), steamMatchmakingCallbacks(nullptr) steamFriendsCallbacks(nullptr), steamMatchmakingCallbacks(nullptr)
{ {
steamFriendsCallbacks = new SteamFriendsCallbacks(networkingManager_); steamFriendsCallbacks = new SteamFriendsCallbacks(networkingManager_, this);
steamMatchmakingCallbacks = new SteamMatchmakingCallbacks(networkingManager_); steamMatchmakingCallbacks = new SteamMatchmakingCallbacks(networkingManager_, this);
} }
SteamRoomManager::~SteamRoomManager() SteamRoomManager::~SteamRoomManager()
@@ -227,11 +227,11 @@ bool SteamRoomManager::startHosting()
return false; return false;
} }
networkingManager_->hListenSock = networkingManager_->m_pInterface->CreateListenSocketP2P(0, 0, nullptr); networkingManager_->getListenSock() = networkingManager_->getInterface()->CreateListenSocketP2P(0, 0, nullptr);
if (networkingManager_->hListenSock != k_HSteamListenSocket_Invalid) if (networkingManager_->getListenSock() != k_HSteamListenSocket_Invalid)
{ {
networkingManager_->g_isHost = true; networkingManager_->getIsHost() = true;
std::cout << "Created listen socket for hosting game room" << std::endl; std::cout << "Created listen socket for hosting game room" << std::endl;
// Rich Presence is set in OnLobbyCreated callback // Rich Presence is set in OnLobbyCreated callback
return true; return true;
@@ -246,11 +246,11 @@ bool SteamRoomManager::startHosting()
void SteamRoomManager::stopHosting() void SteamRoomManager::stopHosting()
{ {
if (networkingManager_->hListenSock != k_HSteamListenSocket_Invalid) if (networkingManager_->getListenSock() != k_HSteamListenSocket_Invalid)
{ {
networkingManager_->m_pInterface->CloseListenSocket(networkingManager_->hListenSock); networkingManager_->getInterface()->CloseListenSocket(networkingManager_->getListenSock());
networkingManager_->hListenSock = k_HSteamListenSocket_Invalid; networkingManager_->getListenSock() = k_HSteamListenSocket_Invalid;
} }
leaveLobby(); leaveLobby();
networkingManager_->g_isHost = false; networkingManager_->getIsHost() = false;
} }

View File

@@ -5,28 +5,31 @@
#include <mutex> #include <mutex>
class SteamNetworkingManager; // Forward declaration class SteamNetworkingManager; // Forward declaration
class SteamRoomManager; // Forward declaration for callbacks
class SteamFriendsCallbacks class SteamFriendsCallbacks
{ {
public: public:
SteamFriendsCallbacks(SteamNetworkingManager *manager); SteamFriendsCallbacks(SteamNetworkingManager *manager, SteamRoomManager *roomManager);
void OnGameRichPresenceJoinRequested(GameRichPresenceJoinRequested_t *pCallback); void OnGameRichPresenceJoinRequested(GameRichPresenceJoinRequested_t *pCallback);
void OnGameLobbyJoinRequested(GameLobbyJoinRequested_t *pCallback); void OnGameLobbyJoinRequested(GameLobbyJoinRequested_t *pCallback);
private: private:
SteamNetworkingManager *manager_; SteamNetworkingManager *manager_;
SteamRoomManager *roomManager_;
}; };
class SteamMatchmakingCallbacks class SteamMatchmakingCallbacks
{ {
public: public:
SteamMatchmakingCallbacks(SteamNetworkingManager *manager); SteamMatchmakingCallbacks(SteamNetworkingManager *manager, SteamRoomManager *roomManager);
void OnLobbyCreated(LobbyCreated_t *pCallback); void OnLobbyCreated(LobbyCreated_t *pCallback);
void OnLobbyListReceived(LobbyMatchList_t *pCallback); void OnLobbyListReceived(LobbyMatchList_t *pCallback);
void OnLobbyEntered(LobbyEnter_t *pCallback); void OnLobbyEntered(LobbyEnter_t *pCallback);
private: private:
SteamNetworkingManager *manager_; SteamNetworkingManager *manager_;
SteamRoomManager *roomManager_;
}; };
class SteamRoomManager class SteamRoomManager

13
steam/steam_utils.cpp Normal file
View File

@@ -0,0 +1,13 @@
#include "steam_utils.h"
#include <iostream>
std::vector<std::pair<CSteamID, std::string>> SteamUtils::getFriendsList() {
std::vector<std::pair<CSteamID, std::string>> 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({friendID, name});
}
return friendsList;
}

9
steam/steam_utils.h Normal file
View File

@@ -0,0 +1,9 @@
#pragma once
#include <vector>
#include <string>
#include <steam_api.h>
class SteamUtils {
public:
static std::vector<std::pair<CSteamID, std::string>> getFriendsList();
};

View File

@@ -3,19 +3,20 @@
#include <iostream> #include <iostream>
#include <algorithm> #include <algorithm>
TCPServer::TCPServer(int port, SteamNetworkingManager* manager) : port_(port), running_(false), acceptor_(io_context_), work_(boost::asio::make_work_guard(io_context_)), hasAcceptedConnection_(false), manager_(manager), forwarding_(false) {} TCPServer::TCPServer(int port, SteamNetworkingManager* manager) : port_(port), running_(false), acceptor_(io_context_), work_(boost::asio::make_work_guard(io_context_)), manager_(manager) {}
TCPServer::~TCPServer() { stop(); } TCPServer::~TCPServer() { stop(); }
bool TCPServer::start() { bool TCPServer::start() {
try { try {
hasAcceptedConnection_ = false;
tcp::endpoint endpoint(tcp::v4(), port_); tcp::endpoint endpoint(tcp::v4(), port_);
acceptor_.open(endpoint.protocol()); acceptor_.open(endpoint.protocol());
acceptor_.set_option(tcp::acceptor::reuse_address(true)); acceptor_.set_option(tcp::acceptor::reuse_address(true));
acceptor_.bind(endpoint); acceptor_.bind(endpoint);
acceptor_.listen(); acceptor_.listen();
multiplexManager_ = std::make_unique<MultiplexManager>(manager_->getInterface(), manager_->getConnection());
running_ = true; running_ = true;
serverThread_ = std::thread([this]() { serverThread_ = std::thread([this]() {
std::cout << "Server thread started" << std::endl; std::cout << "Server thread started" << std::endl;
@@ -33,12 +34,12 @@ bool TCPServer::start() {
void TCPServer::stop() { void TCPServer::stop() {
running_ = false; running_ = false;
hasAcceptedConnection_ = false;
io_context_.stop(); io_context_.stop();
if (serverThread_.joinable()) { if (serverThread_.joinable()) {
serverThread_.join(); serverThread_.join();
} }
acceptor_.close(); acceptor_.close();
multiplexManager_.reset();
} }
void TCPServer::sendToAll(const std::string& message, std::shared_ptr<tcp::socket> excludeSocket) { void TCPServer::sendToAll(const std::string& message, std::shared_ptr<tcp::socket> excludeSocket) {
@@ -64,46 +65,41 @@ void TCPServer::start_accept() {
acceptor_.async_accept(*socket, [this, socket](const boost::system::error_code& error) { acceptor_.async_accept(*socket, [this, socket](const boost::system::error_code& error) {
if (!error) { if (!error) {
std::cout << "New client connected" << std::endl; std::cout << "New client connected" << std::endl;
uint32_t id = multiplexManager_->addClient(socket);
{ {
std::lock_guard<std::mutex> lock(clientsMutex_); std::lock_guard<std::mutex> lock(clientsMutex_);
clients_.push_back(socket); clients_.push_back(socket);
} }
hasAcceptedConnection_ = true; start_read(socket, id);
start_read(socket);
} }
if (running_ && !hasAcceptedConnection_) { if (running_) {
start_accept(); start_accept();
} }
}); });
} }
void TCPServer::start_read(std::shared_ptr<tcp::socket> socket) { void TCPServer::start_read(std::shared_ptr<tcp::socket> socket, uint32_t id) {
auto buffer = std::make_shared<std::vector<char>>(1024); auto buffer = std::make_shared<std::vector<char>>(1024);
socket->async_read_some(boost::asio::buffer(*buffer), [this, socket, buffer](const boost::system::error_code& error, std::size_t bytes_transferred) { socket->async_read_some(boost::asio::buffer(*buffer), [this, socket, buffer, id](const boost::system::error_code& error, std::size_t bytes_transferred) {
if (!error) { if (!error) {
std::cout << "Received " << bytes_transferred << " bytes from TCP client" << std::endl; std::cout << "Received " << bytes_transferred << " bytes from TCP client " << id << std::endl;
if (!forwarding_) {
forwarding_ = true;
if (manager_->isConnected()) { if (manager_->isConnected()) {
std::cout << "Forwarding TCP message to Steam connection" << std::endl; multiplexManager_->sendTunnelPacket(id, buffer->data(), bytes_transferred, 0);
manager_->getInterface()->SendMessageToConnection(manager_->getConnection(), buffer->data(), bytes_transferred, k_nSteamNetworkingSend_Reliable, nullptr);
} else { } else {
std::cout << "Not connected to Steam, skipping forward" << std::endl; std::cout << "Not connected to Steam, skipping forward" << std::endl;
} }
forwarding_ = false;
}
sendToAll(buffer->data(), bytes_transferred, socket); sendToAll(buffer->data(), bytes_transferred, socket);
start_read(socket); start_read(socket, id);
} else { } else {
std::cout << "TCP client disconnected or error: " << error.message() << std::endl; std::cout << "TCP client " << id << " disconnected or error: " << error.message() << std::endl;
// Send disconnect packet
if (manager_->isConnected()) {
multiplexManager_->sendTunnelPacket(id, nullptr, 0, 1);
}
// Remove client // Remove client
multiplexManager_->removeClient(id);
std::lock_guard<std::mutex> lock(clientsMutex_); std::lock_guard<std::mutex> lock(clientsMutex_);
clients_.erase(std::remove(clients_.begin(), clients_.end(), socket), clients_.end()); clients_.erase(std::remove(clients_.begin(), clients_.end(), socket), clients_.end());
// Reset to allow new connection
hasAcceptedConnection_ = false;
if (running_) {
start_accept();
}
} }
}); });
} }

View File

@@ -6,9 +6,11 @@
#include <string> #include <string>
#include <thread> #include <thread>
#include <mutex> #include <mutex>
#include <unordered_map>
#include <isteamnetworkingsockets.h> #include <isteamnetworkingsockets.h>
#include <isteamnetworkingutils.h> #include <isteamnetworkingutils.h>
#include <steamnetworkingtypes.h> #include <steamnetworkingtypes.h>
#include "../multiplex/multiplex_manager.h"
class SteamNetworkingManager; class SteamNetworkingManager;
@@ -25,10 +27,11 @@ public:
void sendToAll(const std::string& message, std::shared_ptr<tcp::socket> excludeSocket = nullptr); void sendToAll(const std::string& message, std::shared_ptr<tcp::socket> excludeSocket = nullptr);
void sendToAll(const char* data, size_t size, std::shared_ptr<tcp::socket> excludeSocket = nullptr); void sendToAll(const char* data, size_t size, std::shared_ptr<tcp::socket> excludeSocket = nullptr);
int getClientCount(); int getClientCount();
MultiplexManager* getMultiplexManager() { return multiplexManager_.get(); }
private: private:
void start_accept(); void start_accept();
void start_read(std::shared_ptr<tcp::socket> socket); void start_read(std::shared_ptr<tcp::socket> socket, uint32_t id);
int port_; int port_;
bool running_; bool running_;
@@ -38,7 +41,6 @@ private:
std::vector<std::shared_ptr<tcp::socket>> clients_; std::vector<std::shared_ptr<tcp::socket>> clients_;
std::mutex clientsMutex_; std::mutex clientsMutex_;
std::thread serverThread_; std::thread serverThread_;
bool hasAcceptedConnection_;
SteamNetworkingManager* manager_; SteamNetworkingManager* manager_;
bool forwarding_; std::unique_ptr<MultiplexManager> multiplexManager_;
}; };