init
This commit is contained in:
commit
b887f15662
21 changed files with 1038 additions and 0 deletions
42
include/DatabaseManager.h
Normal file
42
include/DatabaseManager.h
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
#pragma once
|
||||
|
||||
#include <boost/asio.hpp>
|
||||
#include <boost/asio/awaitable.hpp>
|
||||
#include <boost/mysql.hpp>
|
||||
#include <memory>
|
||||
#include <queue>
|
||||
#include <string>
|
||||
|
||||
class DatabaseManager {
|
||||
public:
|
||||
static DatabaseManager &GetInstance();
|
||||
|
||||
bool Init(boost::asio::io_context &io_context, const std::string &host,
|
||||
uint16_t port, const std::string &user, const std::string &password,
|
||||
const std::string &db);
|
||||
|
||||
struct UserData {
|
||||
std::string nickname;
|
||||
uint64_t gold;
|
||||
uint32_t swordLevel;
|
||||
};
|
||||
|
||||
boost::asio::awaitable<UserData> LoadUser(std::string nickname);
|
||||
boost::asio::awaitable<void> SaveUser(std::string nickname, uint64_t gold,
|
||||
uint32_t swordLevel);
|
||||
|
||||
private:
|
||||
DatabaseManager() = default;
|
||||
|
||||
// 비동기 Mutex 역할을 할 함수들
|
||||
boost::asio::awaitable<void> Lock();
|
||||
void Unlock();
|
||||
|
||||
std::unique_ptr<boost::mysql::tcp_ssl_connection> conn_;
|
||||
std::unique_ptr<boost::asio::strand<boost::asio::io_context::executor_type>>
|
||||
strand_;
|
||||
|
||||
// 비동기 락 시스템을 위한 상태 변수
|
||||
bool is_locked_ = false;
|
||||
std::queue<std::shared_ptr<boost::asio::steady_timer>> waiting_queue_;
|
||||
};
|
||||
15
include/Logger.h
Normal file
15
include/Logger.h
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
#pragma once
|
||||
#include <iostream>
|
||||
#include <mutex>
|
||||
|
||||
class Logger {
|
||||
public:
|
||||
// 가변 인자 템플릿과 Fold Expression을 사용하여 여러 인자를 안전하게 출력
|
||||
template <typename... Args> static void Log(Args &&...args) {
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
(std::cout << ... << std::forward<Args>(args)) << std::endl;
|
||||
}
|
||||
|
||||
private:
|
||||
static inline std::mutex mutex_;
|
||||
};
|
||||
25
include/NetworkService.h
Normal file
25
include/NetworkService.h
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
#pragma once
|
||||
|
||||
#include <boost/asio.hpp>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
|
||||
using boost::asio::ip::tcp;
|
||||
|
||||
class NetworkService {
|
||||
public:
|
||||
NetworkService(uint16_t port, int threadCount);
|
||||
~NetworkService();
|
||||
|
||||
void Run();
|
||||
void Stop();
|
||||
|
||||
private:
|
||||
void DoAccept();
|
||||
|
||||
boost::asio::io_context io_context_;
|
||||
std::vector<std::jthread> threads_;
|
||||
tcp::acceptor acceptor_;
|
||||
boost::asio::executor_work_guard<boost::asio::io_context::executor_type>
|
||||
work_guard_;
|
||||
};
|
||||
83
include/Packet.h
Normal file
83
include/Packet.h
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
|
||||
// 표준 헤더 크기: 2바이트 크기 + 2바이트 ID
|
||||
#pragma pack(push, 1)
|
||||
struct PacketHeader {
|
||||
uint16_t size;
|
||||
uint16_t id;
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
// 처리를 쉽게 하기 위한 단순 패킷 래퍼
|
||||
struct Packet {
|
||||
PacketHeader header;
|
||||
// Payload 데이터 (벡터 또는 문자열)
|
||||
std::vector<uint8_t> payload;
|
||||
};
|
||||
|
||||
enum class PacketID : uint16_t {
|
||||
Ping = 1,
|
||||
// 로그인 요청 (PKT_CS_Login)
|
||||
Login = 10,
|
||||
Chat = 20,
|
||||
|
||||
// 검 키우기 관련 패킷
|
||||
// 강화 요청
|
||||
CS_UpgradeSword = 30,
|
||||
// 강화 결과 응답
|
||||
SC_UpgradeResult = 31,
|
||||
// 판매 요청
|
||||
CS_SellSword = 35,
|
||||
// 판매 결과 응답
|
||||
SC_SellResult = 36,
|
||||
// 랭킹 조회 요청
|
||||
CS_RankingRequest = 40,
|
||||
// 랭킹 리스트 응답
|
||||
SC_RankingList = 41,
|
||||
};
|
||||
|
||||
// 게임 규칙 관련 상수
|
||||
namespace GameConfig {
|
||||
const uint32_t MAX_SWORD_LEVEL = 20;
|
||||
const uint64_t INITIAL_GOLD = 10000;
|
||||
} // namespace GameConfig
|
||||
|
||||
// 고정 크기 데이터 전송을 위한 구조체 정의
|
||||
#pragma pack(push, 1)
|
||||
struct PKT_CS_Login {
|
||||
// 유저 닉네임 (최대 32자)
|
||||
char nickname[32];
|
||||
};
|
||||
|
||||
struct PKT_SC_UpgradeResult {
|
||||
// 0: 파괴, 1: 성공, 2: 실패
|
||||
uint8_t result;
|
||||
// 현재 강화 레벨
|
||||
uint32_t currentLevel;
|
||||
// 현재 보유 골드
|
||||
uint64_t currentGold;
|
||||
};
|
||||
|
||||
struct PKT_SC_SellResult {
|
||||
// 판매 후 획득 골드
|
||||
uint64_t earnedGold;
|
||||
// 현재 총 골드
|
||||
uint64_t totalGold;
|
||||
};
|
||||
|
||||
struct RankingEntry {
|
||||
// 유저 이름 (최대 32자)
|
||||
char username[32];
|
||||
// 검 레벨
|
||||
uint32_t swordLevel;
|
||||
};
|
||||
|
||||
struct PKT_SC_RankingList {
|
||||
// 랭킹 리스트 개수
|
||||
uint32_t count;
|
||||
// 이후 RankingEntry[count] 만큼 데이터가 따라옴
|
||||
};
|
||||
#pragma pack(pop)
|
||||
15
include/PacketHandler.h
Normal file
15
include/PacketHandler.h
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
#pragma once
|
||||
|
||||
#include "Packet.h"
|
||||
#include "Session.h"
|
||||
#include <boost/asio/awaitable.hpp>
|
||||
#include <memory>
|
||||
|
||||
class Session;
|
||||
|
||||
class PacketHandler {
|
||||
public:
|
||||
// 패킷 종류에 따라 비동기 로직 디스패칭 (코루틴 방식)
|
||||
static boost::asio::awaitable<void>
|
||||
HandlePacket(std::shared_ptr<Session> session, const Packet packet);
|
||||
};
|
||||
43
include/Session.h
Normal file
43
include/Session.h
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
#pragma once
|
||||
|
||||
#include "Packet.h"
|
||||
#include <boost/asio.hpp>
|
||||
#include <deque>
|
||||
#include <memory>
|
||||
#include <span>
|
||||
|
||||
using boost::asio::ip::tcp;
|
||||
|
||||
class Session : public std::enable_shared_from_this<Session> {
|
||||
public:
|
||||
Session(tcp::socket socket);
|
||||
~Session();
|
||||
|
||||
void Start();
|
||||
void Send(std::span<const uint8_t> data);
|
||||
|
||||
void SetNickname(const std::string &nickname);
|
||||
const std::string &GetNickname() const;
|
||||
|
||||
void SetGold(uint64_t gold);
|
||||
uint64_t GetGold() const;
|
||||
|
||||
void SetSwordLevel(uint32_t level);
|
||||
uint32_t GetSwordLevel() const;
|
||||
|
||||
private:
|
||||
void DoReadHeader();
|
||||
void DoReadBody();
|
||||
void DoWrite();
|
||||
|
||||
tcp::socket socket_;
|
||||
PacketHeader packetHeader_;
|
||||
std::vector<uint8_t> packetBody_;
|
||||
|
||||
// 스레드 안전성과 순서 보장을 위한 출력 패킷 큐
|
||||
std::deque<std::vector<uint8_t>> writeQueue_;
|
||||
|
||||
std::string nickname_;
|
||||
uint64_t gold_ = 0;
|
||||
uint32_t swordLevel_ = 0;
|
||||
};
|
||||
20
include/SessionManager.h
Normal file
20
include/SessionManager.h
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
#pragma once
|
||||
|
||||
#include "Session.h"
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <set>
|
||||
#include <span>
|
||||
|
||||
class SessionManager {
|
||||
public:
|
||||
static SessionManager &GetInstance();
|
||||
|
||||
void Join(std::shared_ptr<Session> session);
|
||||
void Leave(std::shared_ptr<Session> session);
|
||||
void Broadcast(PacketHeader header, std::span<const uint8_t> body);
|
||||
|
||||
private:
|
||||
std::mutex mutex_;
|
||||
std::set<std::shared_ptr<Session>> sessions_;
|
||||
};
|
||||
63
include/SwordLogic.h
Normal file
63
include/SwordLogic.h
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
#pragma once
|
||||
|
||||
#include "Packet.h"
|
||||
#include <cstdint>
|
||||
#include <random>
|
||||
|
||||
class SwordLogic {
|
||||
public:
|
||||
// 강화 비용 계산
|
||||
static uint64_t GetUpgradeCost(uint32_t currentLevel) {
|
||||
// 0강은 무료
|
||||
if (currentLevel == 0)
|
||||
return 0;
|
||||
// 레벨이 오를수록 비용 증가
|
||||
return (currentLevel * 1000) + 500;
|
||||
}
|
||||
|
||||
// 판매 가격 계산
|
||||
static uint64_t GetSellPrice(uint32_t currentLevel) {
|
||||
if (currentLevel == 0)
|
||||
return 100;
|
||||
// 성공 횟수에 비례하여 상승
|
||||
return (currentLevel * 2000) + 1000;
|
||||
}
|
||||
|
||||
// 강화 시도 결과 계산 (0: 파괴, 1: 성공, 2: 실패)
|
||||
static uint8_t TryUpgrade(uint32_t currentLevel) {
|
||||
// 최대 레벨 도달 시 실패 처리
|
||||
if (currentLevel >= GameConfig::MAX_SWORD_LEVEL)
|
||||
return 2;
|
||||
|
||||
static std::random_device rd;
|
||||
static std::mt19937 gen(rd());
|
||||
std::uniform_int_distribution<int> dis(1, 100);
|
||||
int randVal = dis(gen);
|
||||
|
||||
// 확률 설정
|
||||
int successProb = 0;
|
||||
int destroyProb = 0;
|
||||
|
||||
if (currentLevel < 10) {
|
||||
// 0~9강: 성공 확률 높음, 파괴 없음
|
||||
// 90% ~ 45%
|
||||
successProb = 90 - (currentLevel * 5);
|
||||
destroyProb = 0;
|
||||
} else {
|
||||
// 10~19강: 성공 확률 낮음, 파괴 존재
|
||||
// 40% ~ 4%
|
||||
successProb = 40 - ((currentLevel - 10) * 4);
|
||||
// 5% ~ 23%
|
||||
destroyProb = 5 + ((currentLevel - 10) * 2);
|
||||
}
|
||||
|
||||
// 성공
|
||||
if (randVal <= successProb)
|
||||
return 1;
|
||||
// 파괴
|
||||
if (randVal <= (successProb + destroyProb))
|
||||
return 0;
|
||||
// 실패
|
||||
return 2;
|
||||
}
|
||||
};
|
||||
Loading…
Add table
Add a link
Reference in a new issue