feat: 강화 결과 채팅으로 모든 클라이언트가 같이 공유

This commit is contained in:
bumpsoo 2026-02-05 12:20:54 +00:00
parent 1e922ca3e8
commit b9c5a22989
3 changed files with 109 additions and 41 deletions

View file

@ -67,16 +67,60 @@ bool BaseClient::Login(const std::string &nickname) {
}
}
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<PacketID>(header.id);
switch (id) {
case PacketID::Chat: {
std::vector<char> 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<uint8_t> 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;
std::string resultStr =
(res.result == 1) ? "성공" : (res.result == 0 ? "파괴!!!" : "실패");
std::cout << ">> 강화 결과: " << resultStr
<< " (현재레벨: " << currentLevel_
<< ", 남은골드: " << currentGold_ << ")" << std::endl;
// 강화 결과 출력은 채팅으로
}
}
@ -85,8 +129,9 @@ void BaseClient::HandleSellResult() {
if (ReceivePayload(res)) {
currentLevel_ = 0;
currentGold_ = res.totalGold;
std::cout << ">> 판매 결과: " << res.earnedGold
<< " 골드 획득! (총 골드: " << currentGold_ << ")" << std::endl;
// 판매 결과는 본인에게만
std::cout << "\n>> 판매 완료: " << res.earnedGold << " 골드 획득!"
<< std::endl;
}
}
@ -98,9 +143,13 @@ void InteractiveClient::Run() {
return;
}
// 로그인 후 비동기 수신 시작
StartReceive();
while (true) {
if (currentLevel_ == 0) {
std::cout << "\n[현재 검 없음] 1. 검 구매 시도, 2. 종료\n입력: ";
std::cout << "\n[현재 검 없음, 골드: " << currentGold_
<< "] 1. 검 구매 시도 (1000골드), 2. 종료\n입력: ";
} else {
std::cout << "\n[현재 검 레벨: " << currentLevel_
<< ", 골드: " << currentGold_
@ -114,34 +163,24 @@ void InteractiveClient::Run() {
if (currentLevel_ == 0) {
if (choice == 1) {
SendPacket(PacketID::CS_UpgradeSword);
PacketHeader header;
if (ReceiveHeader(header) &&
header.id == static_cast<uint16_t>(PacketID::SC_UpgradeResult)) {
HandleUpgradeResult();
}
std::this_thread::sleep_for(std::chrono::milliseconds(100));
} else if (choice == 2) {
break;
}
} else {
if (choice == 1) {
SendPacket(PacketID::CS_UpgradeSword);
PacketHeader header;
if (ReceiveHeader(header) &&
header.id == static_cast<uint16_t>(PacketID::SC_UpgradeResult)) {
HandleUpgradeResult();
}
std::this_thread::sleep_for(std::chrono::milliseconds(100));
} else if (choice == 2) {
SendPacket(PacketID::CS_SellSword);
PacketHeader header;
if (ReceiveHeader(header) &&
header.id == static_cast<uint16_t>(PacketID::SC_SellResult)) {
HandleSellResult();
}
std::this_thread::sleep_for(std::chrono::milliseconds(100));
} else if (choice == 3) {
break;
}
}
}
StopReceive();
}
#include <fstream>
@ -161,6 +200,9 @@ void ScenarioClient::Run() {
return;
}
// 비동기 수신 시작
StartReceive();
std::string line;
while (is >> line) {
int choice = std::stoi(line);
@ -169,33 +211,23 @@ void ScenarioClient::Run() {
if (currentLevel_ == 0) {
if (choice == 1) {
SendPacket(PacketID::CS_UpgradeSword);
PacketHeader header;
if (ReceiveHeader(header) &&
header.id == static_cast<uint16_t>(PacketID::SC_UpgradeResult)) {
HandleUpgradeResult();
}
std::this_thread::sleep_for(std::chrono::milliseconds(100));
} else if (choice == 2) {
break;
}
} else {
if (choice == 1) {
SendPacket(PacketID::CS_UpgradeSword);
PacketHeader header;
if (ReceiveHeader(header) &&
header.id == static_cast<uint16_t>(PacketID::SC_UpgradeResult)) {
HandleUpgradeResult();
}
std::this_thread::sleep_for(std::chrono::milliseconds(100));
} else if (choice == 2) {
SendPacket(PacketID::CS_SellSword);
PacketHeader header;
if (ReceiveHeader(header) &&
header.id == static_cast<uint16_t>(PacketID::SC_SellResult)) {
HandleSellResult();
}
std::this_thread::sleep_for(std::chrono::milliseconds(100));
} else if (choice == 3) {
break;
}
}
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
StopReceive();
}

View file

@ -1,8 +1,10 @@
#pragma once
#include "Packet.h"
#include <atomic>
#include <boost/asio.hpp>
#include <string>
#include <thread>
using boost::asio::ip::tcp;
@ -29,6 +31,10 @@ public:
bool Login(const std::string &nickname);
// 비동기 수신 시작
void StartReceive();
void StopReceive();
virtual void Run() = 0;
protected:
@ -37,6 +43,12 @@ protected:
uint64_t currentGold_ = 0;
std::string nickname_;
std::jthread receiveThread_;
std::atomic<bool> isRunning_{false};
void ReceiveLoop(std::stop_token stopToken);
void HandlePacket(const PacketHeader &header);
void HandleUpgradeResult();
void HandleSellResult();
};

View file

@ -103,6 +103,7 @@ PacketHandler::HandlePacket(std::shared_ptr<Session> session,
res.currentLevel = session->GetSwordLevel();
res.currentGold = session->GetGold();
// 결과 패킷 전송
PacketHeader header;
header.id = static_cast<uint16_t>(PacketID::SC_UpgradeResult);
header.size = sizeof(PKT_SC_UpgradeResult);
@ -112,11 +113,34 @@ PacketHandler::HandlePacket(std::shared_ptr<Session> session,
std::memcpy(buffer.data(), &header, sizeof(PacketHeader));
std::memcpy(buffer.data() + sizeof(PacketHeader), &res,
sizeof(PKT_SC_UpgradeResult));
session->Send(buffer);
Logger::Log("강화 시도 [", session->GetNickname(), "]: ", (int)res.result,
" (레벨: ", currentLevel, "->", res.currentLevel, ")");
// 브로드캐스트
if (currentGold >= cost) {
uint32_t attemptedLevel = currentLevel + 1;
std::string resultText;
if (res.result == 1) {
resultText = "를 달성했습니다!";
} else if (res.result == 0) {
resultText = " 시도 중 검이 파괴되었습니다!";
} else {
resultText = " 달성에 실패했습니다!";
}
std::string chatMsg = "채팅] " + session->GetNickname() +
" 님이 검 강화 단계 " +
std::to_string(attemptedLevel) + resultText;
PacketHeader chatHeader;
chatHeader.id = static_cast<uint16_t>(PacketID::Chat);
chatHeader.size = static_cast<uint16_t>(chatMsg.size());
std::vector<uint8_t> chatPayload(chatMsg.begin(), chatMsg.end());
SessionManager::GetInstance().Broadcast(chatHeader, chatPayload);
Logger::Log("강화 시도 [", session->GetNickname(), "]: ", (int)res.result,
" (레벨: ", currentLevel, "->", res.currentLevel, ")");
}
} break;
case PacketID::CS_SellSword: {