优化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;
std::unique_ptr<TCPServer> server;
int main() {
int main()
{
boost::asio::io_context io_context;
// Initialize Steam Networking Manager
SteamNetworkingManager steamManager;
if (!steamManager.initialize()) {
if (!steamManager.initialize())
{
std::cerr << "Failed to initialize Steam Networking Manager" << std::endl;
return 1;
}
@@ -39,15 +41,17 @@ int main() {
SteamRoomManager roomManager(&steamManager);
// Initialize GLFW
if (!glfwInit()) {
if (!glfwInit())
{
std::cerr << "Failed to initialize GLFW" << std::endl;
steamManager.shutdown();
return -1;
}
// Create window
GLFWwindow* window = glfwCreateWindow(1280, 720, "在线游戏工具", nullptr, nullptr);
if (!window) {
GLFWwindow *window = glfwCreateWindow(1280, 720, "在线游戏工具", nullptr, nullptr);
if (!window)
{
std::cerr << "Failed to create GLFW window" << std::endl;
glfwTerminate();
SteamAPI_Shutdown();
@@ -59,7 +63,7 @@ int main() {
// Initialize ImGui
IMGUI_CHECKVERSION();
ImGui::CreateContext();
ImGuiIO& io = ImGui::GetIO();
ImGuiIO &io = ImGui::GetIO();
(void)io;
// Load Chinese font
io.Fonts->AddFontFromFileTTF("font.ttf", 18.0f, nullptr, io.Fonts->GetGlyphRangesChineseSimplifiedCommon());
@@ -80,25 +84,32 @@ int main() {
char filterBuffer[256] = "";
// Lambda to render invite friends UI
auto renderInviteFriends = [&]() {
auto renderInviteFriends = [&]()
{
ImGui::InputText("过滤朋友", filterBuffer, IM_ARRAYSIZE(filterBuffer));
ImGui::Text("朋友:");
for (const auto& friendPair : SteamUtils::getFriendsList()) {
for (const auto &friendPair : SteamUtils::getFriendsList())
{
std::string nameStr = friendPair.second;
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 (filterStr.empty() || nameStr.find(filterStr) != std::string::npos)
{
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
std::string connectStr = std::to_string(roomManager.getCurrentLobby().ConvertToUint64());
// Safety check for SteamFriends
if (SteamFriends()) {
if (SteamFriends())
{
SteamFriends()->InviteUserToGame(friendPair.first, connectStr.c_str());
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;
}
}
@@ -108,7 +119,8 @@ int main() {
};
// Main loop
while (!glfwWindowShouldClose(window)) {
while (!glfwWindowShouldClose(window))
{
// Poll events
glfwPollEvents();
@@ -125,82 +137,128 @@ int main() {
// Create a window for online game tool
ImGui::Begin("在线游戏工具");
if (server) {
if (server)
{
ImGui::Text("TCP服务器监听端口8888");
ImGui::Text("已连接客户端: %d", server->getClientCount());
}
ImGui::Separator();
if (!steamManager.isHost() && !steamManager.isConnected()) {
if (ImGui::Button("主持游戏房间")) {
if (!steamManager.isHost() && !steamManager.isConnected())
{
if (ImGui::Button("主持游戏房间"))
{
roomManager.startHosting();
}
if (ImGui::Button("搜索游戏房间")) {
roomManager.searchLobbies();
}
ImGui::InputText("主机Steam ID", joinBuffer, IM_ARRAYSIZE(joinBuffer));
if (ImGui::Button("加入游戏房间")) {
ImGui::InputText("房间ID", joinBuffer, IM_ARRAYSIZE(joinBuffer));
if (ImGui::Button("加入游戏房间"))
{
uint64 hostID = std::stoull(joinBuffer);
if (steamManager.joinHost(hostID)) {
if (steamManager.joinHost(hostID))
{
// Start TCP Server
server = std::make_unique<TCPServer>(8888, &steamManager);
if (!server->start()) {
if (!server->start())
{
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::InputInt("本地端口", &localPort);
ImGui::Separator();
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();
renderInviteFriends();
ImGui::Separator();
if (ImGui::Button("断开连接"))
{
roomManager.leaveLobby();
steamManager.disconnect();
if (server)
{
server->stop();
server.reset();
}
}
}
ImGui::End();
// Room status window - only show when hosting or joined
if (steamManager.isHost() || steamManager.isClient()) {
ImGui::Begin("房间状态");
if (server) {
ImGui::Text("房间内玩家: %d", server->getClientCount() + 1); // +1 for host
}
// Room status window - only show when hosting or connected
if ((steamManager.isHost() || steamManager.isConnected()) && roomManager.getCurrentLobby().IsValid())
{
std::lock_guard<std::mutex> lockConn(connectionsMutex);
ImGui::Text("连接的好友: %d", (int)steamManager.getConnections().size());
ImGui::Begin("房间状态");
if (!steamManager.isHost())
{
ImGui::Text("与主机延迟: %d ms", steamManager.getHostPing());
}
ImGui::Separator();
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("名称");
if (steamManager.isHost())
{
ImGui::TableSetupColumn("延迟 (ms)");
ImGui::TableSetupColumn("连接类型");
}
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::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::Text("%d", pair.second.ping);
ImGui::TableNextColumn();
ImGui::Text("%s", pair.second.isRelay ? "中继" : "直连");
if (memberID == mySteamID)
{
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();
@@ -225,7 +283,8 @@ int main() {
steamManager.stopMessageHandler();
// Cleanup
if (server) {
if (server)
{
server->stop();
}
ImGui_ImplOpenGL3_Shutdown();

View File

@@ -16,7 +16,7 @@ void SteamNetworkingManager::OnSteamNetConnectionStatusChanged(SteamNetConnectio
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), server_(nullptr), localPort_(nullptr), messageHandler_(nullptr)
io_context_(nullptr), server_(nullptr), localPort_(nullptr), messageHandler_(nullptr), hostPing_(0)
{
std::cout << "Initialized SteamNetworkingManager" << std::endl;
}
@@ -156,20 +156,27 @@ void SteamNetworkingManager::stopMessageHandler()
void SteamNetworkingManager::update()
{
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;
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;
userInfo.isRelay = (info.m_idPOPRelay != 0);
hostPing_ = status.m_nPing;
}
}
}
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)
{
std::lock_guard<std::mutex> lock(connectionsMutex);
@@ -185,17 +192,11 @@ void SteamNetworkingManager::handleConnectionStatusChanged(SteamNetConnectionSta
g_hConnection = pInfo->m_hConn;
g_isConnected = true;
std::cout << "Accepted incoming connection from " << pInfo->m_info.m_identityRemote.GetSteamID().ConvertToUint64() << std::endl;
// Add user info
// Log connection info
SteamNetConnectionInfo_t info;
SteamNetConnectionRealTimeStatus_t status;
if (m_pInterface->GetConnectionInfo(pInfo->m_hConn, &info) && m_pInterface->GetConnectionRealTimeStatus(pInfo->m_hConn, &status, 0, nullptr))
{
UserInfo userInfo;
userInfo.steamID = pInfo->m_info.m_identityRemote.GetSteamID();
userInfo.name = SteamFriends()->GetFriendPersonaName(userInfo.steamID);
userInfo.ping = status.m_nPing;
userInfo.isRelay = (info.m_idPOPRelay != 0);
userMap[pInfo->m_hConn] = userInfo;
std::cout << "Incoming connection details: ping=" << status.m_nPing << "ms, relay=" << (info.m_idPOPRelay != 0 ? "yes" : "no") << std::endl;
}
}
@@ -203,17 +204,12 @@ void SteamNetworkingManager::handleConnectionStatusChanged(SteamNetConnectionSta
{
g_isConnected = true;
std::cout << "Connected to host" << std::endl;
// Add user info
// Log connection info
SteamNetConnectionInfo_t info;
SteamNetConnectionRealTimeStatus_t status;
if (m_pInterface->GetConnectionInfo(pInfo->m_hConn, &info) && m_pInterface->GetConnectionRealTimeStatus(pInfo->m_hConn, &status, 0, nullptr))
{
UserInfo userInfo;
userInfo.steamID = pInfo->m_info.m_identityRemote.GetSteamID();
userInfo.name = SteamFriends()->GetFriendPersonaName(userInfo.steamID);
userInfo.ping = status.m_nPing;
userInfo.isRelay = (info.m_idPOPRelay != 0);
userMap[pInfo->m_hConn] = userInfo;
hostPing_ = status.m_nPing;
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);
}
userMap.erase(pInfo->m_hConn);
hostPing_ = 0;
std::cout << "Connection closed" << std::endl;
}
}

View File

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

View File

@@ -269,3 +269,18 @@ void SteamRoomManager::stopHosting()
leaveLobby();
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; }
const std::vector<CSteamID>& getLobbies() const { return lobbies; }
std::vector<CSteamID> getLobbyMembers() const;
void setCurrentLobby(CSteamID lobby) { currentLobby = lobby; }
void addLobby(CSteamID lobby) { lobbies.push_back(lobby); }