This commit is contained in:
2025-10-26 20:44:58 +08:00
parent e287aadd3c
commit e73c08abf7
45 changed files with 280774 additions and 0 deletions

171
include/common/Database.h Normal file
View File

@@ -0,0 +1,171 @@
#pragma once
#include <string>
#include <vector>
#include <mutex>
#include <memory>
// 前向声明 SQLite 结构
struct sqlite3;
/**
* @brief 用户数据结构
*/
struct UserData {
int userId;
std::string username;
std::string passwordHash;
std::string createdAt;
};
/**
* @brief 角色数据结构
*/
struct CharacterData {
int characterId;
int userId;
std::string className;
int level;
int hp;
int mp;
int attack;
int speed;
};
/**
* @brief 数据库管理类
*
* 技术点: 数据库 (Database) - SQLite3
* 线程安全: 使用 std::mutex 保护所有数据库操作
*/
class Database {
private:
sqlite3* m_db;
std::string m_dbPath;
mutable std::mutex m_mutex; // 保证线程安全 (STL)
bool m_isOpen;
public:
/**
* @brief 构造函数
* @param dbPath 数据库文件路径
*/
explicit Database(const std::string& dbPath);
/**
* @brief 析构函数
*/
~Database();
// 禁止拷贝
Database(const Database&) = delete;
Database& operator=(const Database&) = delete;
/**
* @brief 打开数据库连接
*/
bool open();
/**
* @brief 关闭数据库连接
*/
void close();
/**
* @brief 初始化数据库表结构
*/
bool initializeTables();
/**
* @brief 检查数据库是否已打开
*/
bool isOpen() const { return m_isOpen; }
// ===== 用户相关操作 =====
/**
* @brief 注册新用户
* @param username 用户名
* @param password 密码 (将被哈希)
* @return bool 是否成功
*/
bool registerUser(const std::string& username, const std::string& password);
/**
* @brief 验证用户登录
* @param username 用户名
* @param password 密码
* @return bool 是否验证成功
*/
bool verifyUser(const std::string& username, const std::string& password);
/**
* @brief 检查用户名是否存在
*/
bool userExists(const std::string& username);
/**
* @brief 获取用户ID
*/
int getUserId(const std::string& username);
/**
* @brief 获取用户数据
*/
bool getUserData(const std::string& username, UserData& userData);
// ===== 角色相关操作 =====
/**
* @brief 创建角色
* @param userId 用户ID
* @param className 职业名称
* @return bool 是否成功
*/
bool createCharacter(int userId, const std::string& className);
/**
* @brief 获取用户的角色数据
*/
bool getCharacterData(int userId, CharacterData& charData);
/**
* @brief 更新角色数据
*/
bool updateCharacter(const CharacterData& charData);
/**
* @brief 检查用户是否有角色
*/
bool hasCharacter(int userId);
// ===== 工具函数 =====
/**
* @brief 执行 SQL 语句
* @param sql SQL 语句
* @return bool 是否成功
*/
bool executeSql(const std::string& sql);
/**
* @brief 获取最后插入的行 ID
*/
int getLastInsertId();
/**
* @brief 获取最后的错误信息
*/
std::string getLastError();
private:
/**
* @brief 密码哈希函数 (简单实现)
* 注意: 生产环境应使用更安全的哈希算法 (如 bcrypt, argon2)
*/
std::string hashPassword(const std::string& password);
/**
* @brief 验证密码
*/
bool verifyPassword(const std::string& password, const std::string& hash);
};

98
include/common/Protocol.h Normal file
View File

@@ -0,0 +1,98 @@
#pragma once
#include <string>
#include <vector>
#include <map>
/**
* @brief 网络通信协议定义
*
* 协议格式: COMMAND|param1|param2|...\n
* 所有消息以换行符 \n 结尾
*/
namespace Protocol {
// ===== 协议命令定义 =====
// === 客户端 -> 服务器 (C2S) ===
const std::string C2S_REGISTER = "C2S_REG"; // 注册: C2S_REG|username|password
const std::string C2S_LOGIN = "C2S_LOGIN"; // 登录: C2S_LOGIN|username|password
const std::string C2S_CHAT = "C2S_CHAT"; // 聊天: C2S_CHAT|message
const std::string C2S_LIST_PLAYERS = "C2S_LIST"; // 玩家列表: C2S_LIST
const std::string C2S_INVITE = "C2S_INVITE"; // 邀请: C2S_INVITE|target_username
const std::string C2S_INVITE_RSP = "C2S_INVITE_RSP"; // 邀请响应: C2S_INVITE_RSP|inviter|accept/reject
const std::string C2S_BATTLE_ACTION = "C2S_ACTION"; // 战斗行动: C2S_ACTION|skill_index|target
const std::string C2S_LOGOUT = "C2S_LOGOUT"; // 登出: C2S_LOGOUT
// === 服务器 -> 客户端 (S2C) ===
const std::string S2C_RESPONSE = "S2C_RESPONSE"; // 通用响应: S2C_RESPONSE|OK/ERROR|message
const std::string S2C_LOGIN_OK = "S2C_LOGIN_OK"; // 登录成功: S2C_LOGIN_OK|username|class|level|hp|mp
const std::string S2C_MSG = "S2C_MSG"; // 大厅消息: S2C_MSG|sender|message
const std::string S2C_LIST_PLAYERS = "S2C_LIST"; // 玩家列表: S2C_LIST|user1,user2,user3
const std::string S2C_INVITE = "S2C_INVITE"; // 收到邀请: S2C_INVITE|inviter_username
const std::string S2C_INVITE_RESULT = "S2C_INV_RES"; // 邀请结果: S2C_INV_RES|target|accepted/rejected
const std::string S2C_BATTLE_START = "S2C_BAT_START"; // 战斗开始: S2C_BAT_START|opponent|class
const std::string S2C_BATTLE_TURN = "S2C_BAT_TURN"; // 回合通知: S2C_BAT_TURN|YOUR_TURN/OPP_TURN
const std::string S2C_BATTLE_LOG = "S2C_BAT_LOG"; // 战斗日志: S2C_BAT_LOG|log_message
const std::string S2C_BATTLE_END = "S2C_BAT_END"; // 战斗结束: S2C_BAT_END|WIN/LOSE
const std::string S2C_SYSTEM = "S2C_SYSTEM"; // 系统消息: S2C_SYSTEM|message
// ===== 协议工具函数 =====
/**
* @brief 构建协议消息
* @param command 命令
* @param params 参数列表
* @return std::string 完整的协议消息 (包含换行符)
*/
std::string buildMessage(const std::string& command,
const std::vector<std::string>& params = {});
/**
* @brief 解析协议消息
* @param message 原始消息
* @param command 输出参数: 命令
* @param params 输出参数: 参数列表
* @return bool 解析是否成功
*/
bool parseMessage(const std::string& message,
std::string& command,
std::vector<std::string>& params);
/**
* @brief 构建响应消息
*/
std::string buildResponse(bool success, const std::string& message);
/**
* @brief 构建登录成功消息
*/
std::string buildLoginOk(const std::string& username,
const std::string& className,
int level, int hp, int mp);
/**
* @brief 构建聊天消息
*/
std::string buildChatMessage(const std::string& sender,
const std::string& message);
/**
* @brief 构建玩家列表消息
*/
std::string buildPlayerList(const std::vector<std::string>& players);
/**
* @brief 构建邀请消息
*/
std::string buildInvite(const std::string& inviter);
/**
* @brief 构建战斗日志消息
*/
std::string buildBattleLog(const std::string& logMessage);
/**
* @brief 构建系统消息
*/
std::string buildSystemMessage(const std::string& message);
}

View File

@@ -0,0 +1,139 @@
#pragma once
#include <string>
#ifdef _WIN32
#include <winsock2.h>
#include <ws2tcpip.h>
#pragma comment(lib, "ws2_32.lib")
typedef SOCKET SocketFd;
#define INVALID_SOCKET_FD INVALID_SOCKET
#define SOCKET_ERROR_CODE WSAGetLastError()
#else
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
typedef int SocketFd;
#define INVALID_SOCKET_FD -1
#define SOCKET_ERROR_CODE errno
#define closesocket close
#endif
/**
* @brief Socket 封装类
*
* 技术点: 网络编程 (Network Programming) - 原生 Socket API 封装
* 跨平台支持: Windows (Winsock) 和 Linux (POSIX Sockets)
*/
class SocketWrapper {
private:
SocketFd m_socket;
bool m_isValid;
public:
/**
* @brief 构造函数
*/
SocketWrapper();
/**
* @brief 构造函数 (使用现有socket)
*/
explicit SocketWrapper(SocketFd socket);
/**
* @brief 析构函数
*/
~SocketWrapper();
// 禁止拷贝
SocketWrapper(const SocketWrapper&) = delete;
SocketWrapper& operator=(const SocketWrapper&) = delete;
/**
* @brief 初始化 Winsock (仅 Windows)
*/
static bool initializeWinsock();
/**
* @brief 清理 Winsock (仅 Windows)
*/
static void cleanupWinsock();
/**
* @brief 创建 Socket
*/
bool create();
/**
* @brief 绑定地址和端口
*/
bool bind(const std::string& address, int port);
/**
* @brief 监听连接
*/
bool listen(int backlog = 10);
/**
* @brief 接受客户端连接
*/
SocketFd accept(std::string& clientAddress, int& clientPort);
/**
* @brief 连接到服务器
*/
bool connect(const std::string& address, int port);
/**
* @brief 发送数据
*/
int send(const char* data, int length);
/**
* @brief 发送字符串
*/
int send(const std::string& message);
/**
* @brief 接收数据
*/
int recv(char* buffer, int length);
/**
* @brief 接收一行数据 (以 \n 结尾)
*/
std::string recvLine();
/**
* @brief 设置为非阻塞模式
*/
bool setNonBlocking(bool nonBlocking);
/**
* @brief 设置 Socket 选项
*/
bool setReuseAddr(bool reuse);
/**
* @brief 关闭 Socket
*/
void close();
/**
* @brief 检查 Socket 是否有效
*/
bool isValid() const { return m_isValid; }
/**
* @brief 获取原始 Socket 描述符
*/
SocketFd getSocket() const { return m_socket; }
/**
* @brief 获取最后的错误信息
*/
static std::string getLastError();
};