优化Steam网络管理,添加主机延迟获取功能,重构房间成员管理逻辑

This commit is contained in:
Ayndpa
2025-11-19 20:56:48 +08:00
parent cd7a035ba8
commit 455539cbf1
5 changed files with 152 additions and 80 deletions

View File

@@ -25,12 +25,14 @@ std::mutex connectionsMutex; // Add mutex for connections
int localPort = 0; int localPort = 0;
std::unique_ptr<TCPServer> server; std::unique_ptr<TCPServer> server;
int main() { int main()
{
boost::asio::io_context io_context; boost::asio::io_context io_context;
// Initialize Steam Networking Manager // Initialize Steam Networking Manager
SteamNetworkingManager steamManager; SteamNetworkingManager steamManager;
if (!steamManager.initialize()) { if (!steamManager.initialize())
{
std::cerr << "Failed to initialize Steam Networking Manager" << std::endl; std::cerr << "Failed to initialize Steam Networking Manager" << std::endl;
return 1; return 1;
} }
@@ -39,15 +41,17 @@ int main() {
SteamRoomManager roomManager(&steamManager); 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;
steamManager.shutdown(); steamManager.shutdown();
return -1; return -1;
} }
// Create window // Create window
GLFWwindow* window = glfwCreateWindow(1280, 720, "在线游戏工具", nullptr, nullptr); GLFWwindow *window = glfwCreateWindow(1280, 720, "在线游戏工具", nullptr, nullptr);
if (!window) { if (!window)
{
std::cerr << "Failed to create GLFW window" << std::endl; std::cerr << "Failed to create GLFW window" << std::endl;
glfwTerminate(); glfwTerminate();
SteamAPI_Shutdown(); SteamAPI_Shutdown();
@@ -59,7 +63,7 @@ int main() {
// Initialize ImGui // Initialize ImGui
IMGUI_CHECKVERSION(); IMGUI_CHECKVERSION();
ImGui::CreateContext(); ImGui::CreateContext();
ImGuiIO& io = ImGui::GetIO(); ImGuiIO &io = ImGui::GetIO();
(void)io; (void)io;
// Load Chinese font // Load Chinese font
io.Fonts->AddFontFromFileTTF("font.ttf", 18.0f, nullptr, io.Fonts->GetGlyphRangesChineseSimplifiedCommon()); io.Fonts->AddFontFromFileTTF("font.ttf", 18.0f, nullptr, io.Fonts->GetGlyphRangesChineseSimplifiedCommon());
@@ -80,25 +84,32 @@ int main() {
char filterBuffer[256] = ""; char filterBuffer[256] = "";
// Lambda to render invite friends UI // Lambda to render invite friends UI
auto renderInviteFriends = [&]() { auto renderInviteFriends = [&]()
{
ImGui::InputText("过滤朋友", filterBuffer, IM_ARRAYSIZE(filterBuffer)); ImGui::InputText("过滤朋友", filterBuffer, IM_ARRAYSIZE(filterBuffer));
ImGui::Text("朋友:"); ImGui::Text("朋友:");
for (const auto& friendPair : SteamUtils::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
std::transform(nameStr.begin(), nameStr.end(), nameStr.begin(), ::tolower); std::transform(nameStr.begin(), nameStr.end(), nameStr.begin(), ::tolower);
std::transform(filterStr.begin(), filterStr.end(), filterStr.begin(), ::tolower); std::transform(filterStr.begin(), filterStr.end(), filterStr.begin(), ::tolower);
if (filterStr.empty() || nameStr.find(filterStr) != std::string::npos) { if (filterStr.empty() || nameStr.find(filterStr) != std::string::npos)
{
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(roomManager.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());
std::cout << "Sent invite to " << friendPair.second << " with connect string: " << connectStr << std::endl; std::cout << "Sent invite to " << friendPair.second << " with connect string: " << connectStr << std::endl;
} else { }
else
{
std::cerr << "SteamFriends() is null! Cannot send invite." << std::endl; std::cerr << "SteamFriends() is null! Cannot send invite." << std::endl;
} }
} }
@@ -108,7 +119,8 @@ int main() {
}; };
// Main loop // Main loop
while (!glfwWindowShouldClose(window)) { while (!glfwWindowShouldClose(window))
{
// Poll events // Poll events
glfwPollEvents(); glfwPollEvents();
@@ -125,82 +137,128 @@ int main() {
// Create a window for online game tool // Create a window for online game tool
ImGui::Begin("在线游戏工具"); ImGui::Begin("在线游戏工具");
if (server) { if (server)
{
ImGui::Text("TCP服务器监听端口8888"); ImGui::Text("TCP服务器监听端口8888");
ImGui::Text("已连接客户端: %d", server->getClientCount()); ImGui::Text("已连接客户端: %d", server->getClientCount());
} }
ImGui::Separator(); ImGui::Separator();
if (!steamManager.isHost() && !steamManager.isConnected()) { if (!steamManager.isHost() && !steamManager.isConnected())
if (ImGui::Button("主持游戏房间")) { {
if (ImGui::Button("主持游戏房间"))
{
roomManager.startHosting(); roomManager.startHosting();
} }
if (ImGui::Button("搜索游戏房间")) { ImGui::InputText("房间ID", joinBuffer, IM_ARRAYSIZE(joinBuffer));
roomManager.searchLobbies(); if (ImGui::Button("加入游戏房间"))
} {
ImGui::InputText("主机Steam ID", joinBuffer, IM_ARRAYSIZE(joinBuffer));
if (ImGui::Button("加入游戏房间")) {
uint64 hostID = std::stoull(joinBuffer); uint64 hostID = std::stoull(joinBuffer);
if (steamManager.joinHost(hostID)) { if (steamManager.joinHost(hostID))
{
// Start TCP Server // Start TCP Server
server = std::make_unique<TCPServer>(8888, &steamManager); server = std::make_unique<TCPServer>(8888, &steamManager);
if (!server->start()) { if (!server->start())
{
std::cerr << "Failed to start TCP server" << std::endl; std::cerr << "Failed to start TCP server" << std::endl;
} }
} }
} }
// Display available lobbies
if (!roomManager.getLobbies().empty()) {
ImGui::Text("可用房间:");
for (const auto& lobbyID : roomManager.getLobbies()) {
std::string lobbyName = "房间 " + std::to_string(lobbyID.ConvertToUint64());
if (ImGui::Button(lobbyName.c_str())) {
roomManager.joinLobby(lobbyID);
} }
} if (steamManager.isHost())
} {
} ImGui::Text("正在主持游戏房间。邀请朋友!");
if (steamManager.isHost()) {
ImGui::Text("正在主持游戏房间。邀请朋友!");
ImGui::Separator(); ImGui::Separator();
ImGui::InputInt("本地端口", &localPort); ImGui::InputInt("本地端口", &localPort);
ImGui::Separator(); ImGui::Separator();
renderInviteFriends(); renderInviteFriends();
ImGui::Separator();
if (ImGui::Button("断开连接"))
{
roomManager.leaveLobby();
steamManager.disconnect();
if (server)
{
server->stop();
server.reset();
} }
if (steamManager.isConnected() && !steamManager.isHost()) { }
ImGui::Text("已连接到游戏房间。邀请朋友!"); }
if (steamManager.isConnected() && !steamManager.isHost())
{
ImGui::Text("已连接到游戏房间。邀请朋友!");
ImGui::Separator(); ImGui::Separator();
renderInviteFriends(); renderInviteFriends();
ImGui::Separator();
if (ImGui::Button("断开连接"))
{
roomManager.leaveLobby();
steamManager.disconnect();
if (server)
{
server->stop();
server.reset();
}
}
} }
ImGui::End(); ImGui::End();
// Room status window - only show when hosting or joined // Room status window - only show when hosting or connected
if (steamManager.isHost() || steamManager.isClient()) { if ((steamManager.isHost() || steamManager.isConnected()) && roomManager.getCurrentLobby().IsValid())
ImGui::Begin("房间状态");
if (server) {
ImGui::Text("房间内玩家: %d", server->getClientCount() + 1); // +1 for host
}
{ {
std::lock_guard<std::mutex> lockConn(connectionsMutex); ImGui::Begin("房间状态");
ImGui::Text("连接的好友: %d", (int)steamManager.getConnections().size()); if (!steamManager.isHost())
{
ImGui::Text("与主机延迟: %d ms", steamManager.getHostPing());
} }
ImGui::Separator(); ImGui::Separator();
ImGui::Text("用户列表:"); ImGui::Text("用户列表:");
if (ImGui::BeginTable("UserTable", 3, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg)) { int columnCount = steamManager.isHost() ? 2 : 1;
if (ImGui::BeginTable("UserTable", columnCount, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg))
{
ImGui::TableSetupColumn("名称"); ImGui::TableSetupColumn("名称");
if (steamManager.isHost())
{
ImGui::TableSetupColumn("延迟 (ms)"); ImGui::TableSetupColumn("延迟 (ms)");
ImGui::TableSetupColumn("连接类型"); }
ImGui::TableHeadersRow(); ImGui::TableHeadersRow();
{ {
for (const auto& pair : steamManager.getUserMap()) { std::vector<CSteamID> members = roomManager.getLobbyMembers();
CSteamID mySteamID = SteamUser()->GetSteamID();
for (const auto &memberID : members)
{
ImGui::TableNextRow(); ImGui::TableNextRow();
ImGui::TableNextColumn(); ImGui::TableNextColumn();
ImGui::Text("%s", pair.second.name.c_str()); const char *name = SteamFriends()->GetFriendPersonaName(memberID);
ImGui::Text("%s", name);
if (steamManager.isHost())
{
ImGui::TableNextColumn(); ImGui::TableNextColumn();
ImGui::Text("%d", pair.second.ping); if (memberID == mySteamID)
ImGui::TableNextColumn(); {
ImGui::Text("%s", pair.second.isRelay ? "中继" : "直连"); ImGui::Text("-");
}
else
{
// Find connection for this member
int ping = 0;
std::lock_guard<std::mutex> lockConn(connectionsMutex);
for (const auto &conn : steamManager.getConnections())
{
SteamNetConnectionInfo_t info;
if (steamManager.getInterface()->GetConnectionInfo(conn, &info))
{
if (info.m_identityRemote.GetSteamID() == memberID)
{
ping = steamManager.getConnectionPing(conn);
break;
}
}
}
ImGui::Text("%d", ping);
}
}
} }
} }
ImGui::EndTable(); ImGui::EndTable();
@@ -225,7 +283,8 @@ int main() {
steamManager.stopMessageHandler(); steamManager.stopMessageHandler();
// Cleanup // Cleanup
if (server) { if (server)
{
server->stop(); server->stop();
} }
ImGui_ImplOpenGL3_Shutdown(); ImGui_ImplOpenGL3_Shutdown();

View File

@@ -16,7 +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), server_(nullptr), localPort_(nullptr), messageHandler_(nullptr) io_context_(nullptr), server_(nullptr), localPort_(nullptr), messageHandler_(nullptr), hostPing_(0)
{ {
std::cout << "Initialized SteamNetworkingManager" << std::endl; std::cout << "Initialized SteamNetworkingManager" << std::endl;
} }
@@ -156,20 +156,27 @@ void SteamNetworkingManager::stopMessageHandler()
void SteamNetworkingManager::update() void SteamNetworkingManager::update()
{ {
std::lock_guard<std::mutex> lock(connectionsMutex); std::lock_guard<std::mutex> lock(connectionsMutex);
for (auto &pair : userMap) // Update ping to host/client connection
if (g_hConnection != k_HSteamNetConnection_Invalid)
{ {
HSteamNetConnection conn = pair.first;
UserInfo &userInfo = pair.second;
SteamNetConnectionInfo_t info;
SteamNetConnectionRealTimeStatus_t status; SteamNetConnectionRealTimeStatus_t status;
if (m_pInterface->GetConnectionInfo(conn, &info) && m_pInterface->GetConnectionRealTimeStatus(conn, &status, 0, nullptr)) if (m_pInterface->GetConnectionRealTimeStatus(g_hConnection, &status, 0, nullptr))
{ {
userInfo.ping = status.m_nPing; hostPing_ = status.m_nPing;
userInfo.isRelay = (info.m_idPOPRelay != 0);
} }
} }
} }
int SteamNetworkingManager::getConnectionPing(HSteamNetConnection conn) const
{
SteamNetConnectionRealTimeStatus_t status;
if (m_pInterface->GetConnectionRealTimeStatus(conn, &status, 0, nullptr))
{
return status.m_nPing;
}
return 0;
}
void SteamNetworkingManager::handleConnectionStatusChanged(SteamNetConnectionStatusChangedCallback_t *pInfo) void SteamNetworkingManager::handleConnectionStatusChanged(SteamNetConnectionStatusChangedCallback_t *pInfo)
{ {
std::lock_guard<std::mutex> lock(connectionsMutex); std::lock_guard<std::mutex> lock(connectionsMutex);
@@ -185,17 +192,11 @@ void SteamNetworkingManager::handleConnectionStatusChanged(SteamNetConnectionSta
g_hConnection = pInfo->m_hConn; g_hConnection = pInfo->m_hConn;
g_isConnected = true; g_isConnected = true;
std::cout << "Accepted incoming connection from " << pInfo->m_info.m_identityRemote.GetSteamID().ConvertToUint64() << std::endl; std::cout << "Accepted incoming connection from " << pInfo->m_info.m_identityRemote.GetSteamID().ConvertToUint64() << std::endl;
// Add user info // Log connection info
SteamNetConnectionInfo_t info; SteamNetConnectionInfo_t info;
SteamNetConnectionRealTimeStatus_t status; SteamNetConnectionRealTimeStatus_t status;
if (m_pInterface->GetConnectionInfo(pInfo->m_hConn, &info) && m_pInterface->GetConnectionRealTimeStatus(pInfo->m_hConn, &status, 0, nullptr)) 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; std::cout << "Incoming connection details: ping=" << status.m_nPing << "ms, relay=" << (info.m_idPOPRelay != 0 ? "yes" : "no") << std::endl;
} }
} }
@@ -203,17 +204,12 @@ void SteamNetworkingManager::handleConnectionStatusChanged(SteamNetConnectionSta
{ {
g_isConnected = true; g_isConnected = true;
std::cout << "Connected to host" << std::endl; std::cout << "Connected to host" << std::endl;
// Add user info // Log connection info
SteamNetConnectionInfo_t info; SteamNetConnectionInfo_t info;
SteamNetConnectionRealTimeStatus_t status; SteamNetConnectionRealTimeStatus_t status;
if (m_pInterface->GetConnectionInfo(pInfo->m_hConn, &info) && m_pInterface->GetConnectionRealTimeStatus(pInfo->m_hConn, &status, 0, nullptr)) if (m_pInterface->GetConnectionInfo(pInfo->m_hConn, &info) && m_pInterface->GetConnectionRealTimeStatus(pInfo->m_hConn, &status, 0, nullptr))
{ {
UserInfo userInfo; hostPing_ = status.m_nPing;
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; std::cout << "Outgoing connection details: ping=" << status.m_nPing << "ms, relay=" << (info.m_idPOPRelay != 0 ? "yes" : "no") << std::endl;
} }
} }
@@ -227,7 +223,7 @@ void SteamNetworkingManager::handleConnectionStatusChanged(SteamNetConnectionSta
{ {
connections.erase(it); connections.erase(it);
} }
userMap.erase(pInfo->m_hConn); hostPing_ = 0;
std::cout << "Connection closed" << std::endl; std::cout << "Connection closed" << std::endl;
} }
} }

View File

@@ -40,8 +40,9 @@ 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::map<HSteamNetConnection, UserInfo>& getUserMap() const { return userMap; }
const std::vector<HSteamNetConnection>& getConnections() const { return connections; } const std::vector<HSteamNetConnection>& getConnections() const { return connections; }
int getHostPing() const { return hostPing_; }
int getConnectionPing(HSteamNetConnection conn) const;
HSteamNetConnection getConnection() const { return g_hConnection; } HSteamNetConnection getConnection() const { return g_hConnection; }
ISteamNetworkingSockets* getInterface() const { return m_pInterface; } ISteamNetworkingSockets* getInterface() const { return m_pInterface; }
@@ -81,8 +82,8 @@ private:
// Connections // Connections
std::vector<HSteamNetConnection> connections; std::vector<HSteamNetConnection> connections;
std::map<HSteamNetConnection, UserInfo> userMap;
std::mutex connectionsMutex; std::mutex connectionsMutex;
int hostPing_; // Ping to host (for clients) or average ping (for host)
// Connection config // Connection config
int g_retryCount; int g_retryCount;

View File

@@ -269,3 +269,18 @@ void SteamRoomManager::stopHosting()
leaveLobby(); leaveLobby();
networkingManager_->getIsHost() = false; networkingManager_->getIsHost() = false;
} }
std::vector<CSteamID> SteamRoomManager::getLobbyMembers() const
{
std::vector<CSteamID> members;
if (currentLobby != k_steamIDNil)
{
int numMembers = SteamMatchmaking()->GetNumLobbyMembers(currentLobby);
for (int i = 0; i < numMembers; ++i)
{
CSteamID memberID = SteamMatchmaking()->GetLobbyMemberByIndex(currentLobby, i);
members.push_back(memberID);
}
}
return members;
}

View File

@@ -53,6 +53,7 @@ public:
CSteamID getCurrentLobby() const { return currentLobby; } CSteamID getCurrentLobby() const { return currentLobby; }
const std::vector<CSteamID>& getLobbies() const { return lobbies; } const std::vector<CSteamID>& getLobbies() const { return lobbies; }
std::vector<CSteamID> getLobbyMembers() const;
void setCurrentLobby(CSteamID lobby) { currentLobby = lobby; } void setCurrentLobby(CSteamID lobby) { currentLobby = lobby; }
void addLobby(CSteamID lobby) { lobbies.push_back(lobby); } void addLobby(CSteamID lobby) { lobbies.push_back(lobby); }