# **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\)| | \+-----------------+ \+-----------------+ | | | \+----------^----------+ \+---------^---------------+---------^-----+ | | | | (Lobby/Battle) | | | | | | | | \+----------v----------+ \+---------v---------------+ | | | | GameLobby (单例) | | BattleRoomManager | | | | | (std::map\)| | (管理所有战斗房间) | | | | | (负责聊天/邀请) | | (std::map\) | | | | \+---------------------+ \+-----------------------+ | | | | | | \+-------------------------------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\ 实例,用于记录战报。 * 实现 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 打印战报。