sword_game/server/PacketHandler.cpp

173 lines
5.5 KiB
C++

#include "PacketHandler.h"
#include "DatabaseManager.h"
#include "Logger.h"
#include "Protocol.pb.h"
#include "SessionManager.h"
#include "SwordLogic.h"
#include <boost/asio/use_awaitable.hpp>
#include <cstring>
#include <string>
boost::asio::awaitable<void>
PacketHandler::HandlePacket(std::shared_ptr<Session> session,
const Packet packet) {
switch (static_cast<PacketID>(packet.header.id)) {
case PacketID::Ping: {
Logger::Log("Ping 수신됨");
session->SendPacket(PacketID::Ping);
} break;
case PacketID::CS_Login: {
Protocol::CS_Login pkt;
if (!pkt.ParseFromArray(packet.payload.data(), packet.payload.size())) {
Logger::Log("로그인 패킷 파싱 실패");
co_return;
}
std::string nickname = pkt.nickname();
auto userData = co_await DatabaseManager::GetInstance().LoadUser(nickname);
// 골드와 검 레벨 설정 (닉네임은 TryJoin에서 설정)
session->SetGold(userData.gold);
session->SetSwordLevel(userData.swordLevel);
Protocol::SC_LoginResult loginResult;
// 중복 체크
if (!SessionManager::GetInstance().TryJoin(session, userData.nickname)) {
Logger::Log("중복 로그인 거부: ", nickname);
loginResult.set_success(false);
session->SendPacket(PacketID::SC_LoginResult, loginResult);
co_return;
}
Logger::Log("클라이언트 로그인 성공: ", nickname,
" (Gold: ", session->GetGold(),
", Level: ", session->GetSwordLevel(), ")");
loginResult.set_success(true);
loginResult.set_gold(session->GetGold());
loginResult.set_sword_level(session->GetSwordLevel());
session->SendPacket(PacketID::SC_LoginResult, loginResult);
} break;
case PacketID::CS_UpgradeSword: {
auto currentLevel = session->GetSwordLevel();
auto cost = SwordLogic::GetUpgradeCost(currentLevel);
auto currentGold = session->GetGold();
Protocol::SC_UpgradeResult res;
if (currentGold < cost) {
// 골드 부족
res.set_result(2);
} else {
session->SetGold(currentGold - cost);
auto result = SwordLogic::TryUpgrade(currentLevel);
res.set_result(result);
// 성공
if (result == 1) {
session->SetSwordLevel(currentLevel + 1);
// 파괴
} else if (result == 0) {
session->SetSwordLevel(0);
}
co_await DatabaseManager::GetInstance().SaveUser(
session->GetNickname(), session->GetGold(), session->GetSwordLevel());
}
res.set_current_level(session->GetSwordLevel());
res.set_current_gold(session->GetGold());
// 결과 패킷 전송
session->SendPacket(PacketID::SC_UpgradeResult, res);
// 브로드캐스트
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.current_level(), ")");
}
} break;
case PacketID::CS_SellSword: {
auto currentLevel = session->GetSwordLevel();
auto price = SwordLogic::GetSellPrice(currentLevel);
auto newGold = session->GetGold() + price;
session->SetGold(newGold);
session->SetSwordLevel(0);
co_await DatabaseManager::GetInstance().SaveUser(
session->GetNickname(), session->GetGold(), session->GetSwordLevel());
Protocol::SC_SellResult res;
res.set_earned_gold(price);
res.set_total_gold(newGold);
session->SendPacket(PacketID::SC_SellResult, res);
Logger::Log("검 판매 [", session->GetNickname(), "]: ", price,
" 골드 획득");
} break;
case PacketID::Chat: {
std::string msg(packet.payload.begin(), packet.payload.end());
Logger::Log("채팅 [", session->GetNickname(), "]: ", msg);
SessionManager::GetInstance().Broadcast(packet.header, packet.payload);
} break;
case PacketID::CS_RankingRequest: {
Protocol::CS_RankingRequest pkt;
if (!pkt.ParseFromArray(packet.payload.data(), packet.payload.size())) {
Logger::Log("랭킹 요청 패킷 파싱 실패");
co_return;
}
auto rankResult = co_await DatabaseManager::GetInstance().GetRanking(
(int)pkt.type(), session->GetNickname());
Protocol::SC_RankingList res;
res.set_type(pkt.type());
res.set_my_rank(rankResult.myRank);
res.set_my_value(rankResult.myValue);
for (const auto &entry : rankResult.topEntries) {
auto *newEntry = res.add_entries();
newEntry->set_rank(entry.rank);
newEntry->set_nickname(entry.nickname);
newEntry->set_value(entry.value);
}
session->SendPacket(PacketID::SC_RankingList, res);
} break;
default:
Logger::Log("알 수 없는 패킷 ID: ", packet.header.id);
break;
}
co_return;
}