mirror of
https://github.com/ChuXunYu/OnlineRpg.git
synced 2026-01-30 23:41:26 +00:00
1
This commit is contained in:
166
关键模块与接口.md
Normal file
166
关键模块与接口.md
Normal file
@@ -0,0 +1,166 @@
|
||||
# **1\. 数据库 Schema (SQLite)**
|
||||
|
||||
\-- 用户表 (Users)
|
||||
CREATE TABLE IF NOT EXISTS Users (
|
||||
UserID INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
Username TEXT NOT NULL UNIQUE,
|
||||
PasswordHash TEXT NOT NULL,
|
||||
CreatedAt DATETIME DEFAULT CURRENT\_TIMESTAMP
|
||||
);
|
||||
|
||||
\-- 角色表 (Characters)
|
||||
CREATE TABLE IF NOT EXISTS Characters (
|
||||
CharacterID INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
UserID INTEGER NOT NULL,
|
||||
ClassName TEXT NOT NULL, \-- e.g., "Warrior", "Mage"
|
||||
Level INTEGER NOT NULL DEFAULT 1,
|
||||
HP INTEGER NOT NULL DEFAULT 100,
|
||||
MP INTEGER NOT NULL DEFAULT 50,
|
||||
Attack INTEGER NOT NULL DEFAULT 10,
|
||||
Speed INTEGER NOT NULL DEFAULT 5,
|
||||
FOREIGN KEY(UserID) REFERENCES Users(UserID)
|
||||
);
|
||||
|
||||
# **2\. 网络通信协议 (Protocol.h)**
|
||||
|
||||
使用 | 分隔的文本协议。所有消息以换行符 \\n 结束。
|
||||
|
||||
## **2.1. 客户端 \-\> 服务器 (C2S)**
|
||||
|
||||
* **注册**: C2S\_REG|username|password\\n
|
||||
* **登录**: C2S\_LOGIN|username|password\\n
|
||||
* **大厅聊天**: C2S\_CHAT|message\_content\\n
|
||||
* **获取列表**: C2S\_LIST\_PLAYERS\\n
|
||||
* **邀请对战**: C2S\_INVITE|target\_username\\n
|
||||
* **回应邀请**: C2S\_INVITE\_RSP|inviter\_username|accept\_or\_reject\\n (e.g., "accept" / "reject")
|
||||
* **战斗行动**: C2S\_BATTLE\_ACTION|skill\_name|target\_name\\n
|
||||
|
||||
## **2.2. 服务器 \-\> 客户端 (S2C)**
|
||||
|
||||
* **通用响应**: S2C\_RESPONSE|OK|message\\n 或 S2C\_RESPONSE|ERROR|error\_message\\n
|
||||
* **登录成功**: S2C\_LOGIN\_OK|username|ClassName|Level|HP|MP\\n
|
||||
* **大厅消息**: S2C\_MSG|sender\_username|message\_content\\n
|
||||
* **玩家列表**: S2C\_LIST\_PLAYERS|user1,user2,user3\\n
|
||||
* **收到邀请**: S2C\_INVITE|inviter\_username\\n
|
||||
* **邀请结果**: S2C\_INVITE\_RESULT|target\_username|result\\n (e.g., "accepted" / "rejected")
|
||||
* **战斗开始**: S2C\_BATTLE\_START|opponent\_name|opponent\_class\\n
|
||||
* **战斗回合**: S2C\_BATTLE\_TURN|YOUR\_TURN\\n 或 S2C\_BATTLE\_TURN|OPPONENT\_TURN\\n
|
||||
* **战斗战报**: S2C\_BATTLE\_LOG|log\_message\\n
|
||||
* **战斗结束**: S2C\_BATTLE\_END|WIN\\n 或 S2C\_BATTLE\_END|LOSE\\n
|
||||
|
||||
# **3\. 关键类接口定义 (C++ Header 风格)**
|
||||
|
||||
## **3.1. Core: HistoryLog.h (模板 \+ 链表)**
|
||||
|
||||
\#pragma once
|
||||
\#include \<vector\>
|
||||
|
||||
// 必须手写实现链表节点
|
||||
template \<typename T\>
|
||||
struct Node {
|
||||
T data;
|
||||
Node\<T\>\* next;
|
||||
Node(T d) : data(d), next(nullptr) {}
|
||||
};
|
||||
|
||||
// 必须使用手写的 Node\<T\> 作为底层结构
|
||||
template \<typename T\>
|
||||
class HistoryLog {
|
||||
private:
|
||||
Node\<T\>\* head;
|
||||
int size;
|
||||
|
||||
public:
|
||||
HistoryLog();
|
||||
\~HistoryLog(); // 必须正确释放链表所有节点的内存
|
||||
|
||||
void add(T logEntry); // 在链表头部插入
|
||||
std::vector\<T\> getAllEntries(); // 遍历链表,返回一个 vector
|
||||
int getSize();
|
||||
};
|
||||
|
||||
## **3.2. Core: ICharacter.h & ISkill.h (多态)**
|
||||
|
||||
\#pragma once
|
||||
\#include \<string\>
|
||||
\#include \<vector\>
|
||||
|
||||
class ICharacter; // 前向声明
|
||||
|
||||
// 技能基类
|
||||
class ISkill {
|
||||
public:
|
||||
virtual \~ISkill() {}
|
||||
virtual std::string getName() \= 0;
|
||||
virtual void execute(ICharacter& caster, ICharacter& target) \= 0; // 纯虚函数
|
||||
};
|
||||
|
||||
// 角色基类
|
||||
class ICharacter {
|
||||
protected:
|
||||
std::string m\_name;
|
||||
int m\_hp;
|
||||
int m\_maxHp;
|
||||
int m\_speed;
|
||||
std::vector\<ISkill\*\> m\_skills; // STL
|
||||
|
||||
public:
|
||||
virtual \~ICharacter(); // 必须是虚析构函数,并清理 m\_skills
|
||||
virtual std::string getName() { return m\_name; }
|
||||
virtual int getHp() { return m\_hp; }
|
||||
virtual bool isAlive() { return m\_hp \> 0; }
|
||||
virtual int getSpeed() { return m\_speed; }
|
||||
virtual ISkill\* getSkill(const std::string& name);
|
||||
|
||||
virtual void takeDamage(int damage) \= 0; // 纯虚函数
|
||||
virtual void heal(int amount) \= 0;
|
||||
};
|
||||
|
||||
// 派生类 (示例)
|
||||
class Warrior : public ICharacter {
|
||||
public:
|
||||
Warrior(std::string name);
|
||||
virtual void takeDamage(int damage) override; // 重写,实现格挡逻辑
|
||||
virtual void heal(int amount) override;
|
||||
};
|
||||
|
||||
class Mage : public ICharacter {
|
||||
public:
|
||||
Mage(std::string name);
|
||||
virtual void takeDamage(int damage) override; // 重写,实现法力护盾逻辑
|
||||
virtual void heal(int amount) override;
|
||||
};
|
||||
|
||||
## **3.3. Server: ClientHandler.h (网络 \+ STL \+ 多线程)**
|
||||
|
||||
\#pragma once
|
||||
\#include \<thread\>
|
||||
\#include \<string\>
|
||||
\#include "SocketWrapper.h" // 假设已封装
|
||||
|
||||
class GameServer; // 前向声明
|
||||
|
||||
class ClientHandler {
|
||||
public:
|
||||
// 构造函数,传入 socket 描述符和服务器实例指针
|
||||
ClientHandler(int socketFd, GameServer\* server);
|
||||
\~ClientHandler();
|
||||
|
||||
void startHandlerThread(); // 启动 run() 循环
|
||||
void stopHandler(); // 停止循环并关闭 socket
|
||||
void sendMessage(const std::string& message); // 发送消息给这个客户端
|
||||
|
||||
private:
|
||||
void run(); // 线程主循环 (recv, parse, handle)
|
||||
void parseCommand(const std::string& command);
|
||||
|
||||
int m\_socketFd;
|
||||
GameServer\* m\_server; // 用于回调服务器 (e.g., 广播)
|
||||
std::thread m\_thread; // STL
|
||||
bool m\_isRunning;
|
||||
|
||||
// 玩家状态
|
||||
std::string m\_username;
|
||||
enum class State { Unauthenticated, Lobby, InBattle };
|
||||
State m\_state;
|
||||
};
|
||||
111
系统架构设计.md
Normal file
111
系统架构设计.md
Normal file
@@ -0,0 +1,111 @@
|
||||
# **1\. 系统架构图 (C/S 架构)**
|
||||
|
||||
\+-------------------------------------------------------------------------+
|
||||
| \[ 客户端 A (Console) \] |
|
||||
| \+--------------------+ \+--------------------+ |
|
||||
| | GameClient | | 主线程 (Input) | |
|
||||
| | (负责网络通信) | | (发送聊天/指令) | |
|
||||
| \+--------------------+ \+--------------------+ |
|
||||
| | SocketWrapper | | 接收线程 (Recv) | |
|
||||
| | (封装Socket API) | | (打印聊天/战报) | |
|
||||
| \+--------------------+ \+--------------------+ |
|
||||
\+-------------^----------------------------------+ |
|
||||
| (TCP/IP) |
|
||||
| |
|
||||
\+-------------v----------------------------------+ |
|
||||
| \[ 客户端 B (Console) \] |
|
||||
| (结构同 A) |
|
||||
\+-------------^----------------------------------+ |
|
||||
| (TCP/IP) |
|
||||
| |
|
||||
\+-------------v-----------------------------------------------------------+
|
||||
| \[ 服务器 (GameServer Console) \] |
|
||||
| |
|
||||
| \+---------------------+ \+-----------------------------------------+ |
|
||||
| | GameServer (主线程) | | \[ 线程池 / 并发管理 \] | |
|
||||
| | (Socket, Bind, Listen)| | | |
|
||||
| | (Loop: Accept) | | \+-----------------+ \+-----------------+ | |
|
||||
| | | | | ClientHandler A | | ClientHandler B | | |
|
||||
| | (管理所有 Client) | | | (Thread A) | | (Thread B) | | |
|
||||
| | (std::map\<fd, Ptr\>)| | \+-----------------+ \+-----------------+ | |
|
||||
| \+----------^----------+ \+---------^---------------+---------^-----+ |
|
||||
| | | (Lobby/Battle) | |
|
||||
| | | | |
|
||||
| \+----------v----------+ \+---------v---------------+ | |
|
||||
| | GameLobby (单例) | | BattleRoomManager | | |
|
||||
| | (std::map\<name, Ptr\>)| | (管理所有战斗房间) | | |
|
||||
| | (负责聊天/邀请) | | (std::map\<id, Ptr\>) | | |
|
||||
| \+---------------------+ \+-----------------------+ | |
|
||||
| | |
|
||||
| \+-------------------------------v-------+ |
|
||||
| | \[ 数据库接口 (Database) \] | |
|
||||
| | (封装 SQLite API) | |
|
||||
| | (使用 Mutex 保证线程安全) | |
|
||||
| \+-------------------^-------------------+ |
|
||||
| | |
|
||||
\+---------------------------------------------------+---------------------+
|
||||
|
|
||||
\+---v---+
|
||||
| DB |
|
||||
| (users.db)|
|
||||
\+-------+
|
||||
|
||||
# **2\. 关键组件职责**
|
||||
|
||||
1. **GameClient (客户端)**
|
||||
* 负责连接服务器。
|
||||
* **必须**使用多线程:一个线程(主线程)负责捕获用户输入 (cin) 并 send;另一个线程(子线程)负责阻塞 recv 并打印服务器消息 (cout)。
|
||||
* 负责提供控制台的菜单和界面。
|
||||
2. **GameServer (服务器)**
|
||||
* 负责监听端口 (listen) 和接受新连接 (accept)。
|
||||
* 每接受一个新连接,**必须**创建一个 ClientHandler 实例,并在一个**新线程 (std::thread)** 中运行它。
|
||||
* **必须**使用 std::map (STL) 来存储所有 ClientHandler 的指针或引用,以便管理。
|
||||
* **必须**使用 std::mutex (STL) 来保护这个 map,防止多线程冲突。
|
||||
3. **ClientHandler (服务器)**
|
||||
* 在独立的线程中运行,代表一个已连接的客户端。
|
||||
* 负责该客户端的 recv 循环,解析客户端发来的命令 (使用 Protocol.h)。
|
||||
* 根据命令,调用 GameLobby (聊天/邀请) 或 BattleRoomManager (战斗) 的功能。
|
||||
* 负责处理该客户端的异常掉线,并通知 GameServer 将自己从 map 中移除。
|
||||
4. **GameLobby (服务器)**
|
||||
* 管理所有处于“大厅”状态的玩家。
|
||||
* 实现 broadcastMessage() (广播聊天),需要加锁 (std::mutex) 遍历 GameServer 的客户端 map 并发送。
|
||||
* 实现 handleInvite() (处理邀请逻辑)。
|
||||
5. **BattleRoom (服务器)**
|
||||
* 负责处理一场 1v1 战斗。
|
||||
* 持有**多态**的 ICharacter\* 指针。
|
||||
* 持有**模板+链表**实现的 HistoryLog\<string\> 实例,用于记录战报。
|
||||
* 实现 runTurn() 战斗循环逻辑,调用 ISkill 的 execute 方法。
|
||||
6. **Database (服务器)**
|
||||
* 封装 SQLite3 的 C API。
|
||||
* 提供上层易用的接口:bool registerUser(user, pass)等。
|
||||
* **必须**保证是线程安全的(例如,对所有数据库写操作使用一个全局 std::mutex)。
|
||||
|
||||
# **3\. 关键数据流**
|
||||
|
||||
## **3.1. 数据流:玩家A 发送大厅聊天**
|
||||
|
||||
1. **\[Client A\]**:主线程 cin 捕获输入 "Hello"。
|
||||
2. **\[Client A\]**:GameClient 将其打包为 "CHAT|Hello",通过 SocketWrapper::send() 发出。
|
||||
3. **\[Server\]**:ClientHandler A (线程A) 的 recv() 循环收到数据。
|
||||
4. **\[Server\]**:ClientHandler A 解析出是 CHAT 命令。
|
||||
5. **\[Server\]**:ClientHandler A 调用 GameLobby::broadcastMessage("A: Hello")。
|
||||
6. **\[Server\]**:GameLobby **加锁**访问 GameServer 的客户端 map。
|
||||
7. **\[Server\]**:GameLobby 遍历 map,对所有**非战斗中**的 ClientHandler (如 B, C, D) 调用 send("MSG|A: Hello")。
|
||||
8. **\[Client B,C,D\]**:接收线程 (子线程) 的 recv() 收到消息,cout 打印 "A: Hello" 到控制台。
|
||||
|
||||
## **3.2. 数据流:玩家A 攻击 玩家B (战斗中)**
|
||||
|
||||
1. **\[Server\]**:BattleRoom (线程C) 判定轮到 A 行动。
|
||||
2. **\[Server\]**:BattleRoom 向 ClientHandler A (线程A) 发送 "TURN|YOUR\_TURN"。
|
||||
3. **\[Client A\]**:接收线程收到 "TURN|YOUR\_TURN",cout 打印 "轮到你行动"。
|
||||
4. **\[Client A\]**:主线程 cin 捕获输入 "attack B"。
|
||||
5. **\[Client A\]**:GameClient 打包为 "BATTLE|USE\_SKILL|Fireball|B",send() 发出。
|
||||
6. **\[Server\]**:ClientHandler A (线程A) 收到数据,解析后调用 BattleRoom::handleAction("A", "Fireball", "B")。
|
||||
7. \[Server\]:BattleRoom (线程C) 加锁(防止多线程同时修改战斗状态),执行战斗逻辑:
|
||||
a. ICharacter\* charA \= ...;
|
||||
b. ISkill\* skill \= charA-\>getSkill("Fireball");
|
||||
c. skill-\>execute(charA, charB); (多态调用)
|
||||
d. string log \= "A 对 B 使用了\[火球\]...";
|
||||
e. m\_historyLog.add(log); (模板+链表调用)
|
||||
8. **\[Server\]**:BattleRoom (线程C) 将战报 log 广播给 ClientHandler A 和 ClientHandler B。
|
||||
9. **\[Client A, B\]**:接收线程收到 log,cout 打印战报。
|
||||
58
详细需求规格.md
Normal file
58
详细需求规格.md
Normal file
@@ -0,0 +1,58 @@
|
||||
# **1\. 涉众 (Actors)**
|
||||
|
||||
* **玩家 (Player)**:唯一的用户类型。
|
||||
|
||||
# **2\. 功能需求 (Use Cases)**
|
||||
|
||||
## **2.1. UC-01: 用户账户管理**
|
||||
|
||||
* **As a** 玩家, **I want to** 在客户端启动时,可以选择“注册”或“登录”。
|
||||
* **Acceptance Criteria:**
|
||||
1. **注册**:需要提供唯一的“用户名”和“密码”。服务器检查用户名是否已存在于数据库。
|
||||
2. **登录**:需要提供“用户名”和“密码”。服务器在数据库中验证。
|
||||
3. **数据持久化**:注册信息必须使用 SQLite 数据库存储。
|
||||
4. **安全**:密码应在数据库中加盐哈希存储(*开发注:如果时间紧张,MVP 阶段可降级为明文存储*)。
|
||||
|
||||
## **2.2. UC-02: 游戏大厅 (Lobby)**
|
||||
|
||||
* **As a** 玩家, **I want to** 登录成功后进入游戏大厅,以便和其他玩家互动。
|
||||
* **Acceptance Criteria:**
|
||||
1. **公共聊天**:玩家可以发送消息,该消息应被广播给所有**当前在大厅中**的其他玩家。
|
||||
2. **接收聊天**:玩家可以实时看到大厅中的所有公共聊天消息。
|
||||
3. **玩家列表**:玩家可以输入特定命令(如 /list),从服务器获取当前所有在线玩家的列表。
|
||||
|
||||
## **2.3. UC-03: 战斗邀请与匹配**
|
||||
|
||||
* **As a** 玩家, **I want to** 邀请大厅里的其他玩家进行 1v1 对战。
|
||||
* **Acceptance Criteria:**
|
||||
1. **发起邀请**:玩家A可以向玩家B(必须在线且不在战斗中)发送对战邀请。
|
||||
2. **接收邀请**:玩家B会收到“玩家A向你发起决斗,是否接受?(y/n)”的提示。
|
||||
3. **响应**:玩家B响应后,结果会通知给玩家A。
|
||||
4. **状态变更**:一旦双方同意,服务器应将两名玩家的状态标记为“战斗中”,他们将不再接收大厅聊天。
|
||||
|
||||
## **2.4. UC-04: 回合制战斗 (1v1)**
|
||||
|
||||
* **As a** 玩家, **I want to** 在战斗房间中,和对手轮流行动,直到一方 HP 降为 0。
|
||||
* **Acceptance Criteria:**
|
||||
1. **战斗逻辑在服务器**:所有战斗计算(伤害、闪避、Buff)**必须**在服务器上进行。
|
||||
2. **角色职业**:至少实现 2 个职业(如 Warrior, Mage),它们具有不同的属性和技能。
|
||||
3. **技能系统**:每个职业至少有 2 个技能(如 Fireball, Heal)。
|
||||
4. **回合制**:服务器根据角色“速度”属性决定行动顺序。轮到某玩家时,服务器通知其客户端“请行动”。
|
||||
5. **行动**:玩家客户端发送行动指令(如 "USE:Fireball:Target\_B")。
|
||||
6. **战报**:服务器执行行动后,将结果(如 "A对B使用了\[火球\],造成50伤害")广播给**战斗中的两名**玩家。
|
||||
7. **胜负**:一方 HP \<= 0 时,战斗结束。服务器宣布胜利者,并将双方T出战斗房间,状态改回“在线”。
|
||||
|
||||
# **3\. 非功能需求**
|
||||
|
||||
1. **技术栈 (强制)**
|
||||
* **多态**:必须用于实现 ICharacter (角色基类) 和 ISkill (技能基类)。
|
||||
* **STL**:必须深度使用 std::map (管理客户端), std::vector (管理战斗序列), std::thread (并发), std::mutex (线程同步)。
|
||||
* **模板 \+ 链表**:必须**手写一个泛型链表类** HistoryLog\<T\> (模板),用于存储战斗日志(链表)。
|
||||
* **网络编程**:必须使用**原生 Socket API** (Winsock/POSIX Sockets) 并自行封装。
|
||||
* **数据库**:必须使用 **SQLite3** 库进行数据持久化。
|
||||
2. **性能**
|
||||
* 服务器必须能稳定处理至少 10 个并发的客户端连接。
|
||||
* 网络通信延迟在局域网内应无明显卡顿。
|
||||
3. **健壮性**
|
||||
* 服务器必须处理客户端的异常断开(如 Ctrl+C),并正确清理其资源(从 map 中移除,释放战斗房间等)。
|
||||
* 客户端必须处理连接服务器失败、或中途与服务器断开连接的异常。
|
||||
29
项目愿景与范围.md
Normal file
29
项目愿景与范围.md
Normal file
@@ -0,0 +1,29 @@
|
||||
# **1\. 项目名称**
|
||||
|
||||
C++ 在线回合制对战游戏 (Project: OnlineRpg)
|
||||
|
||||
# **2\. 项目背景与目标**
|
||||
|
||||
本项目旨在为《C++程序设计》课程开发一个结课作业。目标是创建一个C/S架构的、多玩家在线的、控制台界面的回合制对战游戏。
|
||||
|
||||
项目**首要目标**是展示对 C++ 核心特性和库的深度理解和综合运用,特别是**多态、模板、STL、链表、网络编程**和**数据库**技术。
|
||||
|
||||
项目的**次要目标**是实现一个功能完整、可玩性高的小型游戏原型。
|
||||
|
||||
# **3\. 核心功能范围 (MVP)**
|
||||
|
||||
为确保在 8 周的开发周期内完成,我们的最小可行产品 (MVP) 范围如下:
|
||||
|
||||
1. **用户系统 (C/S \+ DB)**:玩家可以通过客户端注册和登录服务器,数据必须持久化。
|
||||
2. **游戏大厅 (C/S \+ Chat)**:玩家登录后进入大厅,可以看到大厅的公共聊天信息,并可以发送聊天。
|
||||
3. **玩家列表与邀请 (C/S)**:玩家在大厅可以查看当前所有在线玩家列表,并向指定玩家发起“对战邀请”。
|
||||
4. **1v1 战斗 (C/S \+ Polymorphism)**:玩家接受邀请后,双方进入一个独立的战斗房间。战斗在服务器上进行,客户端只负责收发指令和战报。
|
||||
5. **战斗回放 (Template \+ Linked List)**:战斗结束后,服务器能生成一份该场战斗的完整日志(战报回放)。
|
||||
|
||||
# **4\. 关键约束**
|
||||
|
||||
1. **开发语言**:必须使用 C++。
|
||||
2. **运行环境**:必须是**控制台 (Terminal)** 应用,不涉及图形化界面 (GUI)。
|
||||
3. **技术强制要求**:必须在项目中明确使用(并能在报告中阐述)所有 6 项关键技术。
|
||||
4. **平台**:应能跨平台编译(Windows Winsock / Linux POSIX Sockets)。
|
||||
5. **依赖**:除 SQLite3 的 C 语言库外,**禁止**使用任何大型第三方网络库或游戏引擎(如 Boost.Asio, libevent, Unreal, Unity 等)。
|
||||
44
验收标准.md
Normal file
44
验收标准.md
Normal file
@@ -0,0 +1,44 @@
|
||||
# **项目验收标准 (Checklist)**
|
||||
|
||||
以下清单用于验证项目是否满足《C++程序设计》结课作业的核心要求。
|
||||
|
||||
## **1\. 功能验收**
|
||||
|
||||
* \[ \] **UC-01 (账户)**:可以成功注册新用户,数据库 Users 表中出现新纪录。
|
||||
* \[ \] **UC-01 (账户)**:可以使用已注册的账户成功登录。
|
||||
* \[ \] **UC-02 (大厅)**:客户端A 在大厅发送消息,客户端B、C (均在大厅) 能收到。
|
||||
* \[ \] **UC-02 (大厅)**:客户端可以正确获取在线玩家列表。
|
||||
* \[ \] **UC-03 (邀请)**:客户端A 邀请 B,B 收到提示并能接受或拒绝。
|
||||
* \[ \] **UC-04 (战斗)**:A 和 B 进入战斗后,不再收到大厅聊天。
|
||||
* \[ \] **UC-04 (战斗)**:战斗逻辑在服务器端正确执行(e.g., A 攻击 B,B 的 HP 减少)。
|
||||
* \[ \] **UC-04 (战斗)**:客户端能正确收发战报,并显示回合制提示。
|
||||
* \[ \] **UC-04 (战斗)**:一方 HP 归零后,服务器能正确宣布胜负,并将双方踢回大厅。
|
||||
* \[ \] **健壮性**:客户端A 强行退出 (Ctrl+C),服务器能检测到,并在玩家列表中移除 A。
|
||||
|
||||
## **2\. 关键技术验收 (强制)**
|
||||
|
||||
* \[ \] **多态**:
|
||||
* \[ \] 提供了 ICharacter 和 ISkill 抽象基类。
|
||||
* \[ \] 提供了至少 2 种职业和 2 种技能的派生类。
|
||||
* \[ \] BattleRoom 仅通过 ICharacter\* 和 ISkill\* (基类指针) 来执行战斗逻辑。
|
||||
* \[ \] **STL**:
|
||||
* \[ \] GameServer 使用 std::map 管理 ClientHandler。
|
||||
* \[ \] GameServer (或 ClientHandler) 使用 std::thread 为每个客户端创建了线程。
|
||||
* \[ \] GameLobby 和 BattleRoom 在访问共享数据(如 map, 战斗状态)时,使用了 std::mutex。
|
||||
* \[ \] BattleRoom 使用 std::vector \+ \<algorithm\> (std::sort) 来管理行动顺序。
|
||||
* \[ \] **模板 \+ 链表**:
|
||||
* \[ \] 提供了 HistoryLog.h 文件。
|
||||
* \[ \] 该文件**手写**实现了泛型的 Node\<T\> 结构体。
|
||||
* \[ \] 该文件**手写**实现了泛型类 HistoryLog\<T\>。
|
||||
* \[ \] HistoryLog\<T\> **必须**使用 Node\<T\>\* (链表) 作为其底层数据结构,**而不是** std::list 或 std::vector。
|
||||
* \[ \] BattleRoom 成功实例化并使用了 HistoryLog\<string\>。
|
||||
* \[ \] **网络编程**:
|
||||
* \[ \] 提供了 SocketWrapper (或等效) 类来封装原生 Socket API。
|
||||
* \[ \] 服务器实现了 bind, listen, accept 的 C/S 模型。
|
||||
* \[ \] 客户端实现了 connect 模型。
|
||||
* \[ \] 客户端使用了**多线程**来分别处理 send 和 recv。
|
||||
* \[ \] **数据库**:
|
||||
* \[ \] 项目集成了 sqlite3.c / sqlite3.h。
|
||||
* \[ \] 提供了 Database 封装类。
|
||||
* \[ \] Users 和 Characters 表已按设计创建。
|
||||
* \[ \] 注册和登录功能已通过数据库 SELECT/INSERT 验证。
|
||||
Reference in New Issue
Block a user