#include "client/GameClient.h" #include "common/Protocol.h" #include #include #include #include GameClient::GameClient(const std::string& serverAddress, int serverPort) : m_serverAddress(serverAddress), m_serverPort(serverPort), m_isRunning(false), m_isConnected(false), m_isAuthenticated(false), m_inBattle(false), m_waitingForTurn(false) { } GameClient::~GameClient() { disconnect(); } bool GameClient::connect() { if (!m_socket.create()) { std::cerr << "创建socket失败" << std::endl; return false; } if (!m_socket.connect(m_serverAddress, m_serverPort)) { std::cerr << "连接服务器失败" << std::endl; return false; } m_isConnected = true; m_isRunning = true; // 启动接收线程 m_recvThread = std::thread(&GameClient::recvLoop, this); std::cout << "成功连接到服务器!" << std::endl; return true; } void GameClient::disconnect() { if (!m_isRunning) { return; } m_isRunning = false; m_socket.close(); if (m_recvThread.joinable()) { m_recvThread.join(); } std::cout << "已断开与服务器的连接" << std::endl; } void GameClient::run() { if (!connect()) { return; } while (m_isRunning && m_isConnected) { if (!m_isAuthenticated) { showMainMenu(); } else if (m_inBattle && m_waitingForTurn) { // 只在战斗中且轮到玩家时才显示战斗菜单 showBattleMenu(); } else if (!m_inBattle) { // 不在战斗中,显示大厅菜单 showLobbyMenu(); } else { // 在战斗中但不是玩家回合,等待 std::this_thread::sleep_for(std::chrono::milliseconds(100)); } } } bool GameClient::sendMessage(const std::string& message) { return m_socket.send(message); } void GameClient::recvLoop() { while (m_isRunning) { std::string message = m_socket.recvLine(); if (message.empty()) { if (m_isRunning) { std::cerr << "\n连接已断开" << std::endl; m_isConnected = false; m_isRunning = false; } break; } handleServerMessage(message); } } void GameClient::handleServerMessage(const std::string& message) { std::string command; std::vector params; if (!Protocol::parseMessage(message, command, params)) { std::cerr << "解析服务器消息失败" << std::endl; return; } if (command == Protocol::S2C_RESPONSE) { if (params.size() >= 2) { std::cout << "\n[服务器] " << params[1] << std::endl; showPrompt(); } } else if (command == Protocol::S2C_LOGIN_OK) { if (params.size() >= 5) { m_username = params[0]; m_isAuthenticated = true; std::cout << "\n【登录成功】" << std::endl; std::cout << "欢迎," << params[0] << "!" << std::endl; std::cout << "职业:" << params[1] << ",等级:" << params[2] << std::endl; std::cout << "生命值:" << params[3] << ",魔法值:" << params[4] << std::endl; showPrompt(); } } else if (command == Protocol::S2C_MSG) { if (params.size() >= 2) { std::cout << "\n【聊天】" << params[0] << ":" << params[1] << std::endl; showPrompt(); } } else if (command == Protocol::S2C_LIST_PLAYERS) { if (!params.empty()) { std::cout << "\n【在线玩家】:" << params[0] << std::endl; } else { std::cout << "\n【在线玩家】:(无)" << std::endl; } showPrompt(); } else if (command == Protocol::S2C_INVITE) { if (!params.empty()) { std::cout << "\n*** " << params[0] << " 邀请你战斗!***" << std::endl; std::cout << "输入 'accept " << params[0] << "' 接受,或 'reject " << params[0] << "' 拒绝" << std::endl; showPrompt(); } } else if (command == Protocol::S2C_INVITE_RESULT) { if (params.size() >= 2) { std::cout << "\n【邀请】" << params[0] << " " << params[1] << " 了你的邀请" << std::endl; showPrompt(); } } else if (command == Protocol::S2C_BATTLE_START) { m_inBattle = true; if (params.size() >= 2) { std::cout << "\n*** 战斗开始!***" << std::endl; std::cout << "对手:" << params[0] << "(" << params[1] << ")" << std::endl; std::cout << "====================" << std::endl; showPrompt(); } } else if (command == Protocol::S2C_BATTLE_TURN) { if (!params.empty()) { if (params[0] == "YOUR_TURN") { std::cout << "\n>>> 你的回合 <<<" << std::endl; std::cout << "输入 'attack' 使用普通攻击" << std::endl; m_waitingForTurn = true; showPrompt(); } else { std::cout << "\n>>> 对手的回合..." << std::endl; m_waitingForTurn = false; } } } else if (command == Protocol::S2C_BATTLE_LOG) { if (!params.empty()) { std::cout << "【战斗】" << params[0] << std::endl; } } else if (command == Protocol::S2C_BATTLE_END) { m_inBattle = false; m_waitingForTurn = false; if (!params.empty()) { std::cout << "\n*** 战斗结束!***" << std::endl; if (params[0] == "WIN") { std::cout << "你赢了!恭喜!" << std::endl; } else if (params[0] == "LOSE") { std::cout << "你输了。下次加油!" << std::endl; } else { std::cout << "平局!" << std::endl; } std::cout << "====================" << std::endl; showPrompt(); } } else if (command == Protocol::S2C_SYSTEM) { if (!params.empty()) { std::cout << "\n[System] " << params[0] << std::endl; showPrompt(); } } } void GameClient::showMainMenu() { printTitle("主菜单"); std::cout << "1. 注册" << std::endl; std::cout << "2. 登录" << std::endl; std::cout << "3. 退出" << std::endl; printSeparator(); showPrompt(); std::string input; std::getline(std::cin, input); if (input == "1") { handleRegister(); } else if (input == "2") { handleLogin(); } else if (input == "3") { disconnect(); } } void GameClient::showLobbyMenu() { printTitle("游戏大厅"); std::cout << "1. 聊天" << std::endl; std::cout << "2. 查看在线玩家" << std::endl; std::cout << "3. 邀请战斗" << std::endl; std::cout << "4. 查看战斗状态" << std::endl; std::cout << "5. 登出" << std::endl; printSeparator(); std::string input; showPrompt(); std::getline(std::cin, input); handleLobbyInput(input); } void GameClient::showBattleMenu() { printTitle("战斗中"); std::cout << "输入 'attack' 或 '攻击' 使用普通攻击" << std::endl; printSeparator(); std::string input; showPrompt(); std::getline(std::cin, input); handleBattleInput(input); } void GameClient::handleRegister() { std::string username, password; std::cout << "用户名:"; std::getline(std::cin, username); std::cout << "密码:"; std::getline(std::cin, password); std::string msg = Protocol::buildMessage(Protocol::C2S_REGISTER, {username, password}); sendMessage(msg); } void GameClient::handleLogin() { std::string username, password; std::cout << "用户名:"; std::getline(std::cin, username); std::cout << "密码:"; std::getline(std::cin, password); std::string msg = Protocol::buildMessage(Protocol::C2S_LOGIN, {username, password}); sendMessage(msg); } void GameClient::handleLobbyInput(const std::string& input) { if (input.empty()) { return; } // 检查是否是邀请响应命令(accept 或 reject) if (input.find("accept ") == 0 || input.find("reject ") == 0) { size_t spacePos = input.find(' '); if (spacePos != std::string::npos) { std::string response = input.substr(0, spacePos); // "accept" 或 "reject" std::string inviter = input.substr(spacePos + 1); // 邀请者用户名 bool accept = (response == "accept"); std::string msg = Protocol::buildMessage(Protocol::C2S_INVITE_RSP, {inviter, accept ? "yes" : "no"}); sendMessage(msg); } return; } if (input == "1") { // Chat std::cout << "消息:"; std::string message; std::getline(std::cin, message); if (!message.empty()) { std::string msg = Protocol::buildMessage(Protocol::C2S_CHAT, {message}); sendMessage(msg); } } else if (input == "2") { // List players std::string msg = Protocol::buildMessage(Protocol::C2S_LIST_PLAYERS); sendMessage(msg); } else if (input == "3") { // Invite to battle std::cout << "目标玩家用户名:"; std::string target; std::getline(std::cin, target); if (!target.empty()) { std::string msg = Protocol::buildMessage(Protocol::C2S_INVITE, {target}); sendMessage(msg); } } else if (input == "4") { // Check battle status std::cout << "战斗状态:" << (m_inBattle ? "战斗中" : "未在战斗") << std::endl; } else if (input == "5") { // Logout std::string msg = Protocol::buildMessage(Protocol::C2S_LOGOUT); sendMessage(msg); m_isAuthenticated = false; m_username.clear(); } else { std::cout << "无效选项。请输入1-5。" << std::endl; } } void GameClient::handleBattleInput(const std::string& input) { if (input.empty()) { return; } if (input == "attack" || input == "攻击") { // 简化版:总是攻击对手(skillIndex=0, target=对手名) std::string msg = Protocol::buildMessage(Protocol::C2S_BATTLE_ACTION, {"0", "opponent"}); sendMessage(msg); m_waitingForTurn = false; } else { std::cout << "无效命令。请输入 'attack' 或 '攻击'" << std::endl; } } void GameClient::showPrompt() { if (m_inBattle) { std::cout << "【战斗】> " << std::flush; } else if (m_isAuthenticated) { std::cout << "【" << m_username << "】> " << std::flush; } else { std::cout << "> " << std::flush; } } void GameClient::clearScreen() { #ifdef _WIN32 system("cls"); #else system("clear"); #endif } void GameClient::printSeparator() { std::cout << "================================" << std::endl; } void GameClient::printTitle(const std::string& title) { printSeparator(); std::cout << " " << title << std::endl; printSeparator(); }