Merge pull request #4 from liu5580/main
添加CMakeLists.txt,修复macOS26编译运行openGL版本不支持错误
This commit is contained in:
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
[submodule "imgui"]
|
||||||
|
path = imgui
|
||||||
|
url = https://github.com/ocornut/imgui.git
|
||||||
46
CMakeLists.txt
Normal file
46
CMakeLists.txt
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.10)
|
||||||
|
project(ConnectTool)
|
||||||
|
|
||||||
|
set(CMAKE_CXX_STANDARD 17)
|
||||||
|
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||||
|
|
||||||
|
# Find packages
|
||||||
|
find_package(OpenGL REQUIRED)
|
||||||
|
find_package(glfw3 REQUIRED)
|
||||||
|
find_package(Boost REQUIRED)
|
||||||
|
|
||||||
|
# Include directories
|
||||||
|
include_directories(${CMAKE_SOURCE_DIR})
|
||||||
|
include_directories(${CMAKE_SOURCE_DIR}/imgui)
|
||||||
|
include_directories(${CMAKE_SOURCE_DIR}/imgui/backends)
|
||||||
|
include_directories(${CMAKE_SOURCE_DIR}/steamworks/public)
|
||||||
|
include_directories(${CMAKE_SOURCE_DIR}/steamworks/public/steam)
|
||||||
|
include_directories(${CMAKE_SOURCE_DIR}/net)
|
||||||
|
|
||||||
|
# Source files
|
||||||
|
file(GLOB SOURCES
|
||||||
|
"online_game_tool.cpp"
|
||||||
|
"imgui/*.cpp"
|
||||||
|
"imgui/backends/imgui_impl_glfw.cpp"
|
||||||
|
"imgui/backends/imgui_impl_opengl3.cpp"
|
||||||
|
"net/*.cpp"
|
||||||
|
"steam/*.cpp"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Create executable
|
||||||
|
add_executable(ConnectTool ${SOURCES})
|
||||||
|
|
||||||
|
# Link libraries
|
||||||
|
target_link_libraries(ConnectTool
|
||||||
|
glfw
|
||||||
|
OpenGL::GL
|
||||||
|
Boost::headers
|
||||||
|
${CMAKE_SOURCE_DIR}/steamworks/redistributable_bin/osx/libsteam_api.dylib
|
||||||
|
)
|
||||||
|
|
||||||
|
# Copy libsteam_api.dylib to output directory for runtime
|
||||||
|
add_custom_command(TARGET ConnectTool POST_BUILD
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E copy
|
||||||
|
${CMAKE_SOURCE_DIR}/steamworks/redistributable_bin/osx/libsteam_api.dylib
|
||||||
|
$<TARGET_FILE_DIR:ConnectTool>/libsteam_api.dylib
|
||||||
|
)
|
||||||
@@ -1,32 +1,32 @@
|
|||||||
|
#include "steam/steam_networking_manager.h"
|
||||||
|
#include "steam/steam_room_manager.h"
|
||||||
|
#include "steam/steam_utils.h"
|
||||||
|
#include "tcp_server.h"
|
||||||
#include <GLFW/glfw3.h>
|
#include <GLFW/glfw3.h>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <boost/asio.hpp>
|
||||||
|
#include <cstring>
|
||||||
|
#include <filesystem>
|
||||||
|
#include <fstream>
|
||||||
#include <imgui.h>
|
#include <imgui.h>
|
||||||
#include <imgui_impl_glfw.h>
|
#include <imgui_impl_glfw.h>
|
||||||
#include <imgui_impl_opengl3.h>
|
#include <imgui_impl_opengl3.h>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <vector>
|
#include <map>
|
||||||
|
#include <memory>
|
||||||
|
#include <mutex>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
#include <mutex>
|
#include <vector>
|
||||||
#include <map>
|
|
||||||
#include <algorithm>
|
|
||||||
#include <cstring>
|
|
||||||
#include <boost/asio.hpp>
|
|
||||||
#include <memory>
|
|
||||||
#include <fstream>
|
|
||||||
#include <filesystem>
|
|
||||||
#include "tcp_server.h"
|
|
||||||
#include "steam/steam_networking_manager.h"
|
|
||||||
#include "steam/steam_room_manager.h"
|
|
||||||
#include "steam/steam_utils.h"
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#define GLFW_EXPOSE_NATIVE_WIN32
|
#define GLFW_EXPOSE_NATIVE_WIN32
|
||||||
#include <GLFW/glfw3native.h>
|
#include <GLFW/glfw3native.h>
|
||||||
#else
|
#else
|
||||||
|
#include <signal.h>
|
||||||
#include <sys/file.h>
|
#include <sys/file.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <signal.h>
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
using boost::asio::ip::tcp;
|
using boost::asio::ip::tcp;
|
||||||
@@ -43,21 +43,19 @@ HANDLE g_hMutex = nullptr;
|
|||||||
HANDLE g_hMapFile = nullptr;
|
HANDLE g_hMapFile = nullptr;
|
||||||
HWND *g_pSharedHwnd = nullptr;
|
HWND *g_pSharedHwnd = nullptr;
|
||||||
|
|
||||||
bool checkSingleInstance()
|
bool checkSingleInstance() {
|
||||||
{
|
g_hMutex = CreateMutexW(nullptr, FALSE,
|
||||||
g_hMutex = CreateMutexW(nullptr, FALSE, L"Global\\OnlineGameTool_SingleInstance_Mutex");
|
L"Global\\OnlineGameTool_SingleInstance_Mutex");
|
||||||
if (GetLastError() == ERROR_ALREADY_EXISTS)
|
if (GetLastError() == ERROR_ALREADY_EXISTS) {
|
||||||
{
|
|
||||||
// Another instance exists, try to find and activate it
|
// Another instance exists, try to find and activate it
|
||||||
g_hMapFile = OpenFileMappingW(FILE_MAP_READ, FALSE, L"Global\\OnlineGameTool_HWND_Share");
|
g_hMapFile = OpenFileMappingW(FILE_MAP_READ, FALSE,
|
||||||
if (g_hMapFile != nullptr)
|
L"Global\\OnlineGameTool_HWND_Share");
|
||||||
{
|
if (g_hMapFile != nullptr) {
|
||||||
HWND* pHwnd = (HWND*)MapViewOfFile(g_hMapFile, FILE_MAP_READ, 0, 0, sizeof(HWND));
|
HWND *pHwnd =
|
||||||
if (pHwnd != nullptr && *pHwnd != nullptr && IsWindow(*pHwnd))
|
(HWND *)MapViewOfFile(g_hMapFile, FILE_MAP_READ, 0, 0, sizeof(HWND));
|
||||||
{
|
if (pHwnd != nullptr && *pHwnd != nullptr && IsWindow(*pHwnd)) {
|
||||||
// Restore and bring to front
|
// Restore and bring to front
|
||||||
if (IsIconic(*pHwnd))
|
if (IsIconic(*pHwnd)) {
|
||||||
{
|
|
||||||
ShowWindow(*pHwnd, SW_RESTORE);
|
ShowWindow(*pHwnd, SW_RESTORE);
|
||||||
}
|
}
|
||||||
SetForegroundWindow(*pHwnd);
|
SetForegroundWindow(*pHwnd);
|
||||||
@@ -65,44 +63,39 @@ bool checkSingleInstance()
|
|||||||
}
|
}
|
||||||
CloseHandle(g_hMapFile);
|
CloseHandle(g_hMapFile);
|
||||||
}
|
}
|
||||||
if (g_hMutex)
|
if (g_hMutex) {
|
||||||
{
|
|
||||||
CloseHandle(g_hMutex);
|
CloseHandle(g_hMutex);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create shared memory for HWND
|
// Create shared memory for HWND
|
||||||
g_hMapFile = CreateFileMappingW(INVALID_HANDLE_VALUE, nullptr, PAGE_READWRITE, 0, sizeof(HWND), L"Global\\OnlineGameTool_HWND_Share");
|
g_hMapFile =
|
||||||
if (g_hMapFile != nullptr)
|
CreateFileMappingW(INVALID_HANDLE_VALUE, nullptr, PAGE_READWRITE, 0,
|
||||||
{
|
sizeof(HWND), L"Global\\OnlineGameTool_HWND_Share");
|
||||||
g_pSharedHwnd = (HWND*)MapViewOfFile(g_hMapFile, FILE_MAP_ALL_ACCESS, 0, 0, sizeof(HWND));
|
if (g_hMapFile != nullptr) {
|
||||||
|
g_pSharedHwnd = (HWND *)MapViewOfFile(g_hMapFile, FILE_MAP_ALL_ACCESS, 0, 0,
|
||||||
|
sizeof(HWND));
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void storeWindowHandle(GLFWwindow* window)
|
void storeWindowHandle(GLFWwindow *window) {
|
||||||
{
|
if (g_pSharedHwnd != nullptr) {
|
||||||
if (g_pSharedHwnd != nullptr)
|
|
||||||
{
|
|
||||||
*g_pSharedHwnd = glfwGetWin32Window(window);
|
*g_pSharedHwnd = glfwGetWin32Window(window);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void cleanupSingleInstance()
|
void cleanupSingleInstance() {
|
||||||
{
|
if (g_pSharedHwnd != nullptr) {
|
||||||
if (g_pSharedHwnd != nullptr)
|
|
||||||
{
|
|
||||||
UnmapViewOfFile(g_pSharedHwnd);
|
UnmapViewOfFile(g_pSharedHwnd);
|
||||||
g_pSharedHwnd = nullptr;
|
g_pSharedHwnd = nullptr;
|
||||||
}
|
}
|
||||||
if (g_hMapFile != nullptr)
|
if (g_hMapFile != nullptr) {
|
||||||
{
|
|
||||||
CloseHandle(g_hMapFile);
|
CloseHandle(g_hMapFile);
|
||||||
g_hMapFile = nullptr;
|
g_hMapFile = nullptr;
|
||||||
}
|
}
|
||||||
if (g_hMutex != nullptr)
|
if (g_hMutex != nullptr) {
|
||||||
{
|
|
||||||
CloseHandle(g_hMutex);
|
CloseHandle(g_hMutex);
|
||||||
g_hMutex = nullptr;
|
g_hMutex = nullptr;
|
||||||
}
|
}
|
||||||
@@ -113,14 +106,12 @@ void cleanupSingleInstance()
|
|||||||
int g_lockfd = -1;
|
int g_lockfd = -1;
|
||||||
std::string g_lockFilePath;
|
std::string g_lockFilePath;
|
||||||
|
|
||||||
void signalHandler(int signum)
|
void signalHandler(int signum) {
|
||||||
{
|
|
||||||
// Signal received to bring window to front
|
// Signal received to bring window to front
|
||||||
std::cout << "Received signal to activate window" << std::endl;
|
std::cout << "Received signal to activate window" << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool checkSingleInstance()
|
bool checkSingleInstance() {
|
||||||
{
|
|
||||||
std::string tempDir;
|
std::string tempDir;
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
const char *tmpdir = getenv("TMPDIR");
|
const char *tmpdir = getenv("TMPDIR");
|
||||||
@@ -132,25 +123,21 @@ bool checkSingleInstance()
|
|||||||
g_lockFilePath = tempDir + "/OnlineGameTool.lock";
|
g_lockFilePath = tempDir + "/OnlineGameTool.lock";
|
||||||
|
|
||||||
g_lockfd = open(g_lockFilePath.c_str(), O_CREAT | O_RDWR, 0666);
|
g_lockfd = open(g_lockFilePath.c_str(), O_CREAT | O_RDWR, 0666);
|
||||||
if (g_lockfd < 0)
|
if (g_lockfd < 0) {
|
||||||
{
|
|
||||||
std::cerr << "Failed to open lock file" << std::endl;
|
std::cerr << "Failed to open lock file" << std::endl;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try to acquire exclusive lock
|
// Try to acquire exclusive lock
|
||||||
if (flock(g_lockfd, LOCK_EX | LOCK_NB) != 0)
|
if (flock(g_lockfd, LOCK_EX | LOCK_NB) != 0) {
|
||||||
{
|
|
||||||
// Lock failed, another instance is running
|
// Lock failed, another instance is running
|
||||||
// Read PID and send signal
|
// Read PID and send signal
|
||||||
char pidBuf[32];
|
char pidBuf[32];
|
||||||
ssize_t bytesRead = read(g_lockfd, pidBuf, sizeof(pidBuf) - 1);
|
ssize_t bytesRead = read(g_lockfd, pidBuf, sizeof(pidBuf) - 1);
|
||||||
if (bytesRead > 0)
|
if (bytesRead > 0) {
|
||||||
{
|
|
||||||
pidBuf[bytesRead] = '\0';
|
pidBuf[bytesRead] = '\0';
|
||||||
pid_t existingPid = atoi(pidBuf);
|
pid_t existingPid = atoi(pidBuf);
|
||||||
if (existingPid > 0)
|
if (existingPid > 0) {
|
||||||
{
|
|
||||||
// Send SIGUSR1 to existing instance
|
// Send SIGUSR1 to existing instance
|
||||||
kill(existingPid, SIGUSR1);
|
kill(existingPid, SIGUSR1);
|
||||||
}
|
}
|
||||||
@@ -172,17 +159,14 @@ bool checkSingleInstance()
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void storeWindowHandle(GLFWwindow* window)
|
void storeWindowHandle(GLFWwindow *window) {
|
||||||
{
|
|
||||||
// GLFW doesn't provide a standard way to bring window to front on Unix
|
// GLFW doesn't provide a standard way to bring window to front on Unix
|
||||||
// but we can request attention
|
// but we can request attention
|
||||||
glfwRequestWindowAttention(window);
|
glfwRequestWindowAttention(window);
|
||||||
}
|
}
|
||||||
|
|
||||||
void cleanupSingleInstance()
|
void cleanupSingleInstance() {
|
||||||
{
|
if (g_lockfd >= 0) {
|
||||||
if (g_lockfd >= 0)
|
|
||||||
{
|
|
||||||
flock(g_lockfd, LOCK_UN);
|
flock(g_lockfd, LOCK_UN);
|
||||||
close(g_lockfd);
|
close(g_lockfd);
|
||||||
g_lockfd = -1;
|
g_lockfd = -1;
|
||||||
@@ -191,31 +175,26 @@ void cleanupSingleInstance()
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int main()
|
int main() {
|
||||||
{
|
|
||||||
// Check for single instance
|
// Check for single instance
|
||||||
if (!checkSingleInstance())
|
if (!checkSingleInstance()) {
|
||||||
{
|
|
||||||
std::cout << "另一个实例已在运行,正在激活该窗口..." << std::endl;
|
std::cout << "另一个实例已在运行,正在激活该窗口..." << std::endl;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize Steam API first
|
// Initialize Steam API first
|
||||||
if (!SteamAPI_Init())
|
if (!SteamAPI_Init()) {
|
||||||
{
|
|
||||||
std::cerr << "Failed to initialize Steam API" << std::endl;
|
std::cerr << "Failed to initialize Steam API" << std::endl;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
boost::asio::io_context io_context;
|
boost::asio::io_context io_context;
|
||||||
auto work_guard = boost::asio::make_work_guard(io_context);
|
auto work_guard = boost::asio::make_work_guard(io_context);
|
||||||
std::thread io_thread([&io_context]()
|
std::thread io_thread([&io_context]() { io_context.run(); });
|
||||||
{ io_context.run(); });
|
|
||||||
|
|
||||||
// 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;
|
||||||
SteamAPI_Shutdown();
|
SteamAPI_Shutdown();
|
||||||
return 1;
|
return 1;
|
||||||
@@ -225,17 +204,23 @@ 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef __APPLE__
|
||||||
|
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
|
||||||
|
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);
|
||||||
|
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); // 3.2+ only
|
||||||
|
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // Required on Mac
|
||||||
|
#endif
|
||||||
|
|
||||||
// Create window
|
// Create window
|
||||||
GLFWwindow *window = glfwCreateWindow(1280, 720, "在线游戏工具 - 1.0.0", nullptr, nullptr);
|
GLFWwindow *window =
|
||||||
if (!window)
|
glfwCreateWindow(1280, 720, "在线游戏工具 - 1.0.0", nullptr, nullptr);
|
||||||
{
|
if (!window) {
|
||||||
std::cerr << "Failed to create GLFW window" << std::endl;
|
std::cerr << "Failed to create GLFW window" << std::endl;
|
||||||
glfwTerminate();
|
glfwTerminate();
|
||||||
cleanupSingleInstance();
|
cleanupSingleInstance();
|
||||||
@@ -254,12 +239,18 @@ int main()
|
|||||||
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());
|
||||||
ImGui::StyleColorsDark();
|
ImGui::StyleColorsDark();
|
||||||
|
|
||||||
// Initialize ImGui backends
|
// Initialize ImGui backends
|
||||||
ImGui_ImplGlfw_InitForOpenGL(window, true);
|
ImGui_ImplGlfw_InitForOpenGL(window, true);
|
||||||
ImGui_ImplOpenGL3_Init("#version 130");
|
const char *glsl_version = "#version 130";
|
||||||
|
#ifdef __APPLE__
|
||||||
|
glsl_version = "#version 150";
|
||||||
|
#endif
|
||||||
|
ImGui_ImplOpenGL3_Init(glsl_version);
|
||||||
|
|
||||||
// Set message handler dependencies
|
// Set message handler dependencies
|
||||||
steamManager.setMessageHandlerDependencies(io_context, server, localPort);
|
steamManager.setMessageHandlerDependencies(io_context, server, localPort);
|
||||||
@@ -272,38 +263,32 @@ int main()
|
|||||||
char filterBuffer[256] = "";
|
char filterBuffer[256] = "";
|
||||||
|
|
||||||
// Lambda to get connection info for a member
|
// Lambda to get connection info for a member
|
||||||
auto getMemberConnectionInfo = [&](const CSteamID &memberID, const CSteamID &hostSteamID) -> std::pair<int, std::string>
|
auto getMemberConnectionInfo =
|
||||||
{
|
[&](const CSteamID &memberID,
|
||||||
|
const CSteamID &hostSteamID) -> std::pair<int, std::string> {
|
||||||
int ping = 0;
|
int ping = 0;
|
||||||
std::string relayInfo = "-";
|
std::string relayInfo = "-";
|
||||||
|
|
||||||
if (steamManager.isHost())
|
if (steamManager.isHost()) {
|
||||||
{
|
|
||||||
// Find connection for this member
|
// Find connection for this member
|
||||||
std::lock_guard<std::mutex> lockConn(connectionsMutex);
|
std::lock_guard<std::mutex> lockConn(connectionsMutex);
|
||||||
for (const auto &conn : steamManager.getConnections())
|
for (const auto &conn : steamManager.getConnections()) {
|
||||||
{
|
|
||||||
SteamNetConnectionInfo_t info;
|
SteamNetConnectionInfo_t info;
|
||||||
if (steamManager.getInterface()->GetConnectionInfo(conn, &info))
|
if (steamManager.getInterface()->GetConnectionInfo(conn, &info)) {
|
||||||
{
|
if (info.m_identityRemote.GetSteamID() == memberID) {
|
||||||
if (info.m_identityRemote.GetSteamID() == memberID)
|
|
||||||
{
|
|
||||||
ping = steamManager.getConnectionPing(conn);
|
ping = steamManager.getConnectionPing(conn);
|
||||||
relayInfo = steamManager.getConnectionRelayInfo(conn);
|
relayInfo = steamManager.getConnectionRelayInfo(conn);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
// Client only shows ping to host, not to other clients
|
// Client only shows ping to host, not to other clients
|
||||||
if (memberID == hostSteamID)
|
if (memberID == hostSteamID) {
|
||||||
{
|
|
||||||
ping = steamManager.getHostPing();
|
ping = steamManager.getHostPing();
|
||||||
if (steamManager.getConnection() != k_HSteamNetConnection_Invalid)
|
if (steamManager.getConnection() != k_HSteamNetConnection_Invalid) {
|
||||||
{
|
relayInfo =
|
||||||
relayInfo = steamManager.getConnectionRelayInfo(steamManager.getConnection());
|
steamManager.getConnectionRelayInfo(steamManager.getConnection());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -312,31 +297,29 @@ int main()
|
|||||||
};
|
};
|
||||||
|
|
||||||
// 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(),
|
||||||
std::transform(filterStr.begin(), filterStr.end(), filterStr.begin(), ::tolower);
|
::tolower);
|
||||||
if (filterStr.empty() || nameStr.find(filterStr) != std::string::npos)
|
std::transform(filterStr.begin(), filterStr.end(), filterStr.begin(),
|
||||||
{
|
::tolower);
|
||||||
|
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 to lobby
|
// Send invite via Steam to lobby
|
||||||
if (SteamMatchmaking())
|
if (SteamMatchmaking()) {
|
||||||
{
|
SteamMatchmaking()->InviteUserToLobby(roomManager.getCurrentLobby(),
|
||||||
SteamMatchmaking()->InviteUserToLobby(roomManager.getCurrentLobby(), friendPair.first);
|
friendPair.first);
|
||||||
std::cout << "Sent lobby invite to " << friendPair.second << std::endl;
|
std::cout << "Sent lobby invite to " << friendPair.second
|
||||||
}
|
<< std::endl;
|
||||||
else
|
} else {
|
||||||
{
|
std::cerr << "SteamMatchmaking() is null! Cannot send invite."
|
||||||
std::cerr << "SteamMatchmaking() is null! Cannot send invite." << std::endl;
|
<< std::endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ImGui::PopID();
|
ImGui::PopID();
|
||||||
@@ -350,17 +333,17 @@ int main()
|
|||||||
double lastFrameTime = glfwGetTime();
|
double lastFrameTime = glfwGetTime();
|
||||||
|
|
||||||
// Main loop
|
// Main loop
|
||||||
while (!glfwWindowShouldClose(window))
|
while (!glfwWindowShouldClose(window)) {
|
||||||
{
|
|
||||||
// Frame rate control based on window focus
|
// Frame rate control based on window focus
|
||||||
bool isFocused = glfwGetWindowAttrib(window, GLFW_FOCUSED);
|
bool isFocused = glfwGetWindowAttrib(window, GLFW_FOCUSED);
|
||||||
double targetFrameTime = isFocused ? targetFrameTimeForeground : targetFrameTimeBackground;
|
double targetFrameTime =
|
||||||
|
isFocused ? targetFrameTimeForeground : targetFrameTimeBackground;
|
||||||
|
|
||||||
double currentTime = glfwGetTime();
|
double currentTime = glfwGetTime();
|
||||||
double deltaTime = currentTime - lastFrameTime;
|
double deltaTime = currentTime - lastFrameTime;
|
||||||
if (deltaTime < targetFrameTime)
|
if (deltaTime < targetFrameTime) {
|
||||||
{
|
std::this_thread::sleep_for(
|
||||||
std::this_thread::sleep_for(std::chrono::duration<double>(targetFrameTime - deltaTime));
|
std::chrono::duration<double>(targetFrameTime - deltaTime));
|
||||||
}
|
}
|
||||||
lastFrameTime = glfwGetTime();
|
lastFrameTime = glfwGetTime();
|
||||||
|
|
||||||
@@ -379,50 +362,41 @@ 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();
|
||||||
}
|
}
|
||||||
ImGui::InputText("房间ID", joinBuffer, IM_ARRAYSIZE(joinBuffer));
|
ImGui::InputText("房间ID", joinBuffer, IM_ARRAYSIZE(joinBuffer));
|
||||||
if (ImGui::Button("加入游戏房间"))
|
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (steamManager.isHost() || steamManager.isConnected())
|
if (steamManager.isHost() || steamManager.isConnected()) {
|
||||||
{
|
ImGui::Text(steamManager.isHost() ? "正在主持游戏房间。邀请朋友!"
|
||||||
ImGui::Text(steamManager.isHost() ? "正在主持游戏房间。邀请朋友!" : "已连接到游戏房间。邀请朋友!");
|
: "已连接到游戏房间。邀请朋友!");
|
||||||
ImGui::Separator();
|
ImGui::Separator();
|
||||||
if (ImGui::Button("断开连接"))
|
if (ImGui::Button("断开连接")) {
|
||||||
{
|
|
||||||
roomManager.leaveLobby();
|
roomManager.leaveLobby();
|
||||||
steamManager.disconnect();
|
steamManager.disconnect();
|
||||||
if (server)
|
if (server) {
|
||||||
{
|
|
||||||
server->stop();
|
server->stop();
|
||||||
server.reset();
|
server.reset();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (steamManager.isHost())
|
if (steamManager.isHost()) {
|
||||||
{
|
|
||||||
ImGui::InputInt("本地端口", &localPort);
|
ImGui::InputInt("本地端口", &localPort);
|
||||||
}
|
}
|
||||||
ImGui::Separator();
|
ImGui::Separator();
|
||||||
@@ -432,12 +406,12 @@ int main()
|
|||||||
ImGui::End();
|
ImGui::End();
|
||||||
|
|
||||||
// Room status window - only show when hosting or connected
|
// Room status window - only show when hosting or connected
|
||||||
if ((steamManager.isHost() || steamManager.isConnected()) && roomManager.getCurrentLobby().IsValid())
|
if ((steamManager.isHost() || steamManager.isConnected()) &&
|
||||||
{
|
roomManager.getCurrentLobby().IsValid()) {
|
||||||
ImGui::Begin("房间状态");
|
ImGui::Begin("房间状态");
|
||||||
ImGui::Text("用户列表:");
|
ImGui::Text("用户列表:");
|
||||||
if (ImGui::BeginTable("UserTable", 3, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg))
|
if (ImGui::BeginTable("UserTable", 3,
|
||||||
{
|
ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg)) {
|
||||||
ImGui::TableSetupColumn("名称");
|
ImGui::TableSetupColumn("名称");
|
||||||
ImGui::TableSetupColumn("延迟 (ms)");
|
ImGui::TableSetupColumn("延迟 (ms)");
|
||||||
ImGui::TableSetupColumn("连接类型");
|
ImGui::TableSetupColumn("连接类型");
|
||||||
@@ -446,30 +420,24 @@ int main()
|
|||||||
std::vector<CSteamID> members = roomManager.getLobbyMembers();
|
std::vector<CSteamID> members = roomManager.getLobbyMembers();
|
||||||
CSteamID mySteamID = SteamUser()->GetSteamID();
|
CSteamID mySteamID = SteamUser()->GetSteamID();
|
||||||
CSteamID hostSteamID = steamManager.getHostSteamID();
|
CSteamID hostSteamID = steamManager.getHostSteamID();
|
||||||
for (const auto &memberID : members)
|
for (const auto &memberID : members) {
|
||||||
{
|
|
||||||
ImGui::TableNextRow();
|
ImGui::TableNextRow();
|
||||||
ImGui::TableNextColumn();
|
ImGui::TableNextColumn();
|
||||||
const char *name = SteamFriends()->GetFriendPersonaName(memberID);
|
const char *name = SteamFriends()->GetFriendPersonaName(memberID);
|
||||||
ImGui::Text("%s", name);
|
ImGui::Text("%s", name);
|
||||||
ImGui::TableNextColumn();
|
ImGui::TableNextColumn();
|
||||||
|
|
||||||
if (memberID == mySteamID)
|
if (memberID == mySteamID) {
|
||||||
{
|
|
||||||
ImGui::Text("-");
|
ImGui::Text("-");
|
||||||
ImGui::TableNextColumn();
|
ImGui::TableNextColumn();
|
||||||
ImGui::Text("-");
|
ImGui::Text("-");
|
||||||
}
|
} else {
|
||||||
else
|
auto [ping, relayInfo] =
|
||||||
{
|
getMemberConnectionInfo(memberID, hostSteamID);
|
||||||
auto [ping, relayInfo] = getMemberConnectionInfo(memberID, hostSteamID);
|
|
||||||
|
|
||||||
if (relayInfo != "-")
|
if (relayInfo != "-") {
|
||||||
{
|
|
||||||
ImGui::Text("%d", ping);
|
ImGui::Text("%d", ping);
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
ImGui::Text("-");
|
ImGui::Text("-");
|
||||||
}
|
}
|
||||||
ImGui::TableNextColumn();
|
ImGui::TableNextColumn();
|
||||||
@@ -499,16 +467,14 @@ int main()
|
|||||||
steamManager.stopMessageHandler();
|
steamManager.stopMessageHandler();
|
||||||
|
|
||||||
// Cleanup
|
// Cleanup
|
||||||
if (server)
|
if (server) {
|
||||||
{
|
|
||||||
server->stop();
|
server->stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stop io_context and join thread
|
// Stop io_context and join thread
|
||||||
work_guard.reset();
|
work_guard.reset();
|
||||||
io_context.stop();
|
io_context.stop();
|
||||||
if (io_thread.joinable())
|
if (io_thread.joinable()) {
|
||||||
{
|
|
||||||
io_thread.join();
|
io_thread.join();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user