2
This commit is contained in:
358
src/client/GameClient.cpp
Normal file
358
src/client/GameClient.cpp
Normal 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();
|
||||
}
|
||||
Reference in New Issue
Block a user