Files
OnlineRpg/src/client/GameClient.cpp
2025-10-26 20:44:58 +08:00

359 lines
11 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#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();
}