This commit is contained in:
2025-10-26 20:44:58 +08:00
parent e287aadd3c
commit e73c08abf7
45 changed files with 280774 additions and 0 deletions

358
src/client/GameClient.cpp Normal file
View File

@@ -0,0 +1,358 @@
#include "client/GameClient.h"
#include "common/Protocol.h"
#include <iostream>
#include <sstream>
#include <thread>
#include <chrono>
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<std::string> 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();
}