#include "Client.h" #include #include BaseClient::BaseClient(boost::asio::io_context &io_context, const std::string &host, const std::string &port) : socket_(io_context) { tcp::resolver resolver(io_context); boost::asio::connect(socket_, resolver.resolve(host, port)); } void BaseClient::SendPacket(PacketID id, const void *payload, size_t payloadSize) { PacketHeader header; header.id = static_cast(id); header.size = static_cast(payloadSize); std::vector buffer(sizeof(PacketHeader) + payloadSize); std::memcpy(buffer.data(), &header, sizeof(PacketHeader)); if (payload && payloadSize > 0) { std::memcpy(buffer.data() + sizeof(PacketHeader), payload, payloadSize); } boost::asio::write(socket_, boost::asio::buffer(buffer)); } bool BaseClient::ReceiveHeader(PacketHeader &header) { try { boost::asio::read(socket_, boost::asio::buffer(&header, sizeof(header))); return true; } catch (...) { return false; } } bool BaseClient::Login(const std::string &nickname) { PKT_CS_Login loginPkt; std::memset(loginPkt.nickname, 0, sizeof(loginPkt.nickname)); std::strncpy(loginPkt.nickname, nickname.c_str(), sizeof(loginPkt.nickname) - 1); SendPacket(PacketID::CS_Login, &loginPkt, sizeof(loginPkt)); std::cout << "로그인 요청 보냄: " << nickname << std::endl; // 로그인 결과 대기 PacketHeader header; if (!ReceiveHeader(header) || header.id != static_cast(PacketID::SC_LoginResult)) { std::cerr << "로그인 응답을 받지 못했습니다." << std::endl; return false; } PKT_SC_LoginResult res; if (!ReceivePayload(res)) { std::cerr << "로그인 응답 수신 실패" << std::endl; return false; } if (res.result == 1) { std::cout << "로그인 성공!" << std::endl; return true; } else if (res.result == 0) { std::cerr << "로그인 실패: 이미 접속 중인 유저입니다." << std::endl; return false; } else { std::cerr << "로그인 실패: 알 수 없는 오류" << std::endl; return false; } } void BaseClient::StartReceive() { isRunning_ = true; receiveThread_ = std::jthread(&BaseClient::ReceiveLoop, this); } void BaseClient::StopReceive() { isRunning_ = false; socket_.close(); receiveThread_.request_stop(); } void BaseClient::ReceiveLoop(std::stop_token stopToken) { try { while (!stopToken.stop_requested() && isRunning_) { PacketHeader header; if (!ReceiveHeader(header)) break; HandlePacket(header); } } catch (...) { } } void BaseClient::HandlePacket(const PacketHeader &header) { PacketID id = static_cast(header.id); switch (id) { case PacketID::Chat: { std::vector buffer(header.size + 1, 0); boost::asio::read(socket_, boost::asio::buffer(buffer.data(), header.size)); std::cout << "\n" << buffer.data() << std::endl; } break; case PacketID::SC_UpgradeResult: HandleUpgradeResult(); break; case PacketID::SC_SellResult: HandleSellResult(); break; default: // 처리하지 않는 패킷은 페이로드만 건너뜀 if (header.size > 0) { std::vector dummy(header.size); boost::asio::read(socket_, boost::asio::buffer(dummy.data(), header.size)); } break; } } void BaseClient::HandleUpgradeResult() { PKT_SC_UpgradeResult res; if (ReceivePayload(res)) { currentLevel_ = res.currentLevel; currentGold_ = res.currentGold; // 강화 결과 출력은 채팅으로 } } void BaseClient::HandleSellResult() { PKT_SC_SellResult res; if (ReceivePayload(res)) { currentLevel_ = 0; currentGold_ = res.totalGold; // 판매 결과는 본인에게만 std::cout << "\n>> 판매 완료: " << res.earnedGold << " 골드 획득!" << std::endl; } } void InteractiveClient::Run() { std::cout << "닉네임을 입력하세요: "; std::cin >> nickname_; if (!Login(nickname_)) { std::cerr << "로그인에 실패하여 종료합니다." << std::endl; return; } // 로그인 후 비동기 수신 시작 StartReceive(); while (true) { if (currentLevel_ == 0) { std::cout << "\n[현재 검 없음, 골드: " << currentGold_ << "] 1. 검 구매 시도 (1000골드), 2. 종료\n입력: "; } else { std::cout << "\n[현재 검 레벨: " << currentLevel_ << ", 골드: " << currentGold_ << "] 1. 강화 시도, 2. 판매, 3. 종료\n입력: "; } int choice; if (!(std::cin >> choice)) break; if (currentLevel_ == 0) { if (choice == 1) { SendPacket(PacketID::CS_UpgradeSword); std::this_thread::sleep_for(std::chrono::milliseconds(100)); } else if (choice == 2) { break; } } else { if (choice == 1) { SendPacket(PacketID::CS_UpgradeSword); std::this_thread::sleep_for(std::chrono::milliseconds(100)); } else if (choice == 2) { SendPacket(PacketID::CS_SellSword); std::this_thread::sleep_for(std::chrono::milliseconds(100)); } else if (choice == 3) { break; } } } StopReceive(); } #include void ScenarioClient::Run() { std::ifstream is(scenarioFile_); if (!is.is_open()) { std::cerr << "시나리오 파일을 열 수 없습니다: " << scenarioFile_ << std::endl; return; } if (!(is >> nickname_)) return; if (!Login(nickname_)) { std::cerr << "로그인에 실패하여 종료합니다." << std::endl; return; } // 비동기 수신 시작 StartReceive(); std::string line; while (is >> line) { int choice = std::stoi(line); std::cout << "\n시나리오 입력 실행: " << choice << std::endl; if (currentLevel_ == 0) { if (choice == 1) { SendPacket(PacketID::CS_UpgradeSword); std::this_thread::sleep_for(std::chrono::milliseconds(100)); } else if (choice == 2) { break; } } else { if (choice == 1) { SendPacket(PacketID::CS_UpgradeSword); std::this_thread::sleep_for(std::chrono::milliseconds(100)); } else if (choice == 2) { SendPacket(PacketID::CS_SellSword); std::this_thread::sleep_for(std::chrono::milliseconds(100)); } else if (choice == 3) { break; } } std::this_thread::sleep_for(std::chrono::milliseconds(100)); } StopReceive(); }