# Net-Games 网游系统架构文档 > **版本**: v2.0 > **更新日期**: 2026-04-09 > **状态**: 生产就绪 --- ## 1. 系统概述 ### 1.1 项目定位 基于 **Flask-SocketIO** 的多人实时棋牌游戏引擎,支持人类玩家与 AI 玩家对战。采用权威服务端架构,所有游戏逻辑在服务端验证执行。 ### 1.2 核心特性 - ✅ 权威服务端架构(防作弊) - ✅ 用户认证系统(登录/注册/积分) - ✅ 多角色支持:人类、规则AI、DeepSeek大模型AI - ✅ 房间制对战(2-3人) - ✅ AI托管机制(断线/超时自动托管) - ✅ 回合超时管理(30秒/回合) - ✅ 断线重连支持 - ✅ 单点登录控制 - ✅ 可扩展的游戏插件机制 ### 1.3 技术栈 | 层级 | 技术 | 说明 | |------|------|------| | 服务端 | Python 3.11 + Flask | Web框架 | | 实时通信 | Flask-SocketIO | WebSocket封装 | | 数据库 | SQLite | 用户认证、积分存储 | | 前端 | 原生HTML/JS/CSS | 无需构建 | | AI接口 | DeepSeek API | 大模型决策 | | 部署 | Systemd | 系统服务 | --- ## 2. 目录结构 ``` /home/ubuntu/nanocode/net-games/ ├── server.py # 主服务入口 (1772行) ├── config.py # 全局配置 ├── net_games_auth.db # SQLite数据库 │ ├── engine/ # 游戏引擎核心 │ ├── __init__.py │ ├── room_manager.py # 房间管理器 (391行) │ ├── game_base.py # 游戏基类 (236行) │ ├── player.py # 玩家抽象 (154行) │ ├── ai_adapter.py # AI适配器基类 │ └── test_game.py # 测试游戏 │ ├── doudizhu/ # 斗地主游戏实现 │ ├── __init__.py │ ├── game.py # 斗地主游戏逻辑 (470行) │ ├── game_logic.py # 牌型判断、规则 │ └── ai_adapters.py # 斗地主AI适配器 (443行) │ ├── chinese-chess/ # 中国象棋(预留) │ └── ... │ ├── client/ # 斗地主客户端 │ ├── index.html │ ├── style.css │ └── game.js # 前端逻辑 (1617行) │ ├── hub/ # 游戏大厅 │ └── index.html │ ├── docs/ # 文档 │ ├── ARCHITECTURE.md # 本文件 │ ├── API.md # API接口文档 │ ├── DATABASE.md # 数据库设计 │ ├── UI_DESIGN_GUIDELINES.md # UI设计规范 │ └── PHASE1_SUMMARY.md # 阶段总结 │ └── instance/ # 数据目录 └── net_games_auth.db ``` --- ## 3. 系统架构 ### 3.1 整体架构图 ``` ┌─────────────────────────────────────────────────────────────────┐ │ 客户端层 │ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │ │ 浏览器玩家 │ │ 浏览器玩家 │ │ AI玩家 │ │ │ │ (Socket.IO)│ │ (Socket.IO)│ │ (内部调用) │ │ │ └──────┬──────┘ └──────┬──────┘ └──────┬──────┘ │ └─────────┼────────────────┼────────────────┼────────────────────┘ │ │ │ └────────────────┴────────────────┘ │ WebSocket (Socket.IO) ▼ ┌─────────────────────────────────────────────────────────────────┐ │ 服务层 (Flask) │ │ ┌─────────────────────────────────────────────────────────┐ │ │ │ HTTP Routes │ │ │ │ /api/auth/* /api/user/* /api/rooms/* /api/admin/* │ │ │ └─────────────────────────────────────────────────────────┘ │ │ ┌─────────────────────────────────────────────────────────┐ │ │ │ Socket.IO Handlers │ │ │ │ connect create_room join_room game_action ... │ │ │ └─────────────────────────────────────────────────────────┘ │ │ ┌─────────────────────────────────────────────────────────┐ │ │ │ RoomManager (单例) │ │ │ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ │ │ │ │ Room #1 │ │ Room #2 │ │ Room #N │ │ │ │ │ │ 斗地主 │ │ 斗地主 │ │ 象棋 │ │ │ │ │ │ 3玩家 │ │ 2玩家 │ │ 2玩家 │ │ │ │ │ └────┬────┘ └────┬────┘ └────┬────┘ │ │ │ └───────┼────────────┼────────────┼───────────────────────┘ │ │ │ │ │ │ │ ▼ ▼ ▼ │ │ ┌─────────────────────────────────────────────────────────┐ │ │ │ Game Instances │ │ │ │ ┌──────────────┐ ┌──────────────┐ │ │ │ │ │ DoudizhuGame │ │ TestGame │ ... │ │ │ │ │ - game logic │ │ - game logic │ │ │ │ │ │ - state mgmt │ │ - state mgmt │ │ │ │ │ └──────┬───────┘ └──────────────┘ │ │ │ └─────────┼───────────────────────────────────────────────┘ │ │ │ │ │ ▼ │ │ ┌─────────────────────────────────────────────────────────┐ │ │ │ AI Adapter Center │ │ │ │ ┌──────────┐ ┌──────────────┐ ┌──────────────┐ │ │ │ │ │ RuleAI │ │ DeepSeekAI │ │ MinimaxAI │ │ │ │ │ │ (斗地主) │ │ (通用) │ │ (象棋预留) │ │ │ │ │ └──────────┘ └──────────────┘ └──────────────┘ │ │ │ └─────────────────────────────────────────────────────────┘ │ │ ┌─────────────────────────────────────────────────────────┐ │ │ │ Database (SQLite) │ │ │ │ ┌─────────┐ ┌─────────┐ │ │ │ │ │ users │ │ rooms │ (内存缓存) │ │ │ │ └─────────┘ └─────────┘ │ │ │ └─────────────────────────────────────────────────────────┘ │ └─────────────────────────────────────────────────────────────────┘ ``` ### 3.2 核心组件职责 | 组件 | 文件 | 职责 | |------|------|------| | **Flask App** | `server.py` | HTTP服务、Socket.IO、认证、API路由 | | **RoomManager** | `engine/room_manager.py` | 单例模式管理所有房间生命周期 | | **Room** | `engine/room_manager.py` | 房间状态、玩家管理、游戏实例容器 | | **GameBase** | `engine/game_base.py` | 游戏抽象基类,定义通用接口 | | **Player** | `engine/player.py` | 玩家基类,HumanPlayer/AIPlayer | | **AIAdapter** | `engine/ai_adapter.py` | AI决策接口统一封装 | | **DoudizhuGame** | `doudizhu/game.py` | 斗地主具体实现 | ### 3.3 关键数据流 #### 3.3.1 游戏操作处理流程 ``` ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ Client │ │ Server │ │ Room │ │ Game │ └────┬─────┘ └────┬─────┘ └────┬─────┘ └────┬─────┘ │ │ │ │ │ game_action │ │ │ │ ──────────────>│ │ │ │ │ handle_game_action │ │ │ ──────────────────────────────>│ │ │ │ │ │ │ │ game.handle_action() │ │ │ │ │ │ │ │ │ │ │ 验证操作合法性 │ │ │ │ 更新游戏状态 │ │ │ │ │ │ │ state_update │ │ │ <──────────────│ (broadcast) │ │ │ │ │ │ │ │ check_winner() │ │ │ │ ──────────────────────────────>│ │ │ │ │ │ game_ended │ │ │ │ <──────────────│ (broadcast) │ │ ``` #### 3.3.2 AI决策流程 ``` ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ Game │ │ Server │ │ AI Thread│ │ AIAdapter│ └────┬─────┘ └────┬─────┘ └────┬─────┘ └────┬─────┘ │ │ │ │ │ get_current_player() │ │ │ ───────────────────────────────>│ │ │ │ │ │ │ │ process_ai_turn│ │ │ │ ──────────────>│ │ │ │ │ make_decision()│ │ │ │ ──────────────>│ │ │ │ │ │ │ │ 异步API调用 │ │ │ │ (DeepSeek) │ │ │ │ <──────────────│ │ │ │ │ │ │ │ handle_action()│ │ │ │ ──────────────>│ │ │ state_update │ │ │ │ (broadcast) │ │ ``` --- ## 4. 核心类设计 ### 4.1 RoomManager (单例模式) ```python class RoomManager: _instance = None _lock = Lock() def __new__(cls): # 线程安全的单例 def create_room(game_type, max_players, config) def join_room(room_code, player) -> (bool, str) def start_game(room_id) -> (bool, str) def get_room(room_id=None, room_code=None) -> Room def cleanup_inactive_rooms(max_inactive_minutes=30) ``` ### 4.2 Room 类 ```python class Room: id: str # room_uuid code: str # A1B2C3 (6位房间号) game_type: str # doudizhu status: str # waiting/playing/ended/closed players: Dict[str, Player] seats: Dict[int, Optional[str]] host_id: Optional[str] game: Optional[GameBase] def add_player(player) -> bool def remove_player(player_id) -> bool def start_game(game_class) -> bool def to_dict(include_game_state=True) -> dict ``` ### 4.3 GameBase 抽象基类 ```python class GameBase(ABC): room_id: str game_type: str state: GameState players: Dict[str, Player] player_order: List[str] @abstractmethod def handle_action(player_id, action, data) -> dict @abstractmethod def get_valid_actions(player_id) -> List[str] @abstractmethod def check_winner() -> Optional[str] def to_dict() -> dict ``` ### 4.4 Player 类层次 ```python class Player(ABC): id: str name: str type: PlayerType is_connected: bool is_ai_controlled: bool # AI托管状态 offline_since: Optional[float] def connect(socket_id) def disconnect() def enable_ai_control() def disable_ai_control() class HumanPlayer(Player): @property def is_ai(self) -> False class AIPlayer(Player): ai_type: str # rule/deepseek/minimax @property def is_ai(self) -> True ``` --- ## 5. 关键机制 ### 5.1 单点登录与身份识别 ```python # 使用用户名或昵称作为身份标识 identity_key = current_user.username if current_user.is_authenticated else player_name # 活跃玩家映射 active_usernames: Dict[str, str] = {} # username -> player_id # 用户-房间映射(支持跨浏览器重连) user_room_map: Dict[str, str] = {} # username -> room_id # Socket-玩家映射 socket_player_map: Dict[str, str] = {} # socket_id -> player_id ``` **单点登录检查流程:** 1. 创建房间/加入房间时检查 `identity_key` 是否在 `active_usernames` 2. 如果存在且玩家在线,拒绝新连接 3. 如果存在但玩家离线,允许重连并替换 4. 断开连接时从 `active_usernames` 移除 ### 5.2 AI托管机制 **触发条件:** 1. 玩家主动断开连接(关闭浏览器)→ 30秒后自动托管 2. 回合超时(30秒无操作)→ 累计3次后自动托管 3. 玩家主动点击"托管"按钮 **托管流程:** ```python def ai_control_after_timeout(room_id, player_id, timeout=30): time.sleep(timeout) if player.offline_since is None: return # 已重连,取消托管 player.enable_ai_control() # 通知所有玩家 emit('player_ai_controlled', {...}) # 如果是当前回合,立即触发AI if current_turn == player_id: check_and_trigger_ai(room_id) ``` **取消托管:** - 玩家重连时自动取消托管 - 玩家手动点击"取消托管" ### 5.3 回合超时管理 ```python # 配置 TURN_TIMEOUT_SECONDS = 30 # 每回合30秒 MAX_TIMEOUT_COUNT = 3 # 最大超时3次 # 定时器管理 room_turn_timers: Dict[str, Timer] = {} # room_id -> Timer player_timeout_count: Dict[str, int] = {} # player_id -> count def start_turn_timer(room_id): cancel_turn_timer(room_id) timer = threading.Timer(TURN_TIMEOUT_SECONDS, handle_turn_timeout, args=[room_id]) room_turn_timers[room_id] = timer def handle_turn_timeout(room_id): player_timeout_count[player_id] += 1 if timeout_count >= MAX_TIMEOUT_COUNT: player.enable_ai_control() # 启用托管 else: _execute_auto_pass(room, game, player_id) # 自动不要 ``` ### 5.4 断线重连机制 **重连匹配优先级:** 1. 已登录用户通过 `username` 匹配 2. 通过 `player_id` 匹配(保存在localStorage) 3. 通过 `player_name` 匹配(已断开状态的玩家) **重连流程:** ``` 1. 客户端尝试 reconnect_room 2. 服务端通过 user_room_map 或 player_name 查找原玩家 3. 单点登录检查(确保没有其他活跃连接) 4. player.connect(new_socket_id) - 更新连接状态 5. player.disable_ai_control() - 取消托管 6. 加入 Socket.IO room 7. 广播 player_reconnected 事件 8. 恢复游戏状态 ``` ### 5.5 房间清理策略 ```python def cleanup_inactive_rooms(max_inactive_minutes=30): for room in rooms: all_disconnected = all(not p.is_connected for p in room.human_players) inactive_time = now - room.last_activity if all_disconnected: if room.status == 'ended' and inactive_time > 5*60: cleanup_room(room) # 已结束,5分钟后清理 elif inactive_time > 10*60: cleanup_room(room) # 进行中,10分钟后清理 elif inactive_time > max_inactive_minutes*60: cleanup_room(room) # 不活跃,30分钟后清理 ``` 清理任务每5分钟运行一次(后台线程)。 --- ## 6. 游戏扩展机制 ### 6.1 添加新游戏的步骤 1. **创建游戏目录** ``` newgame/ ├── __init__.py ├── game.py # 继承 GameBase ├── game_logic.py # 游戏规则 └── ai_adapters.py # AI适配器 ``` 2. **实现 GameBase 子类** ```python class NewGame(GameBase): @property def min_players(self) -> int: return 2 @property def max_players(self) -> int: return 2 def handle_action(self, player_id, action, data) -> dict: # 实现游戏逻辑 pass def check_winner(self) -> Optional[str]: # 检查获胜者 pass ``` 3. **注册游戏类型** (server.py) ```python from newgame import NewGame room_manager.register_game('newgame', NewGame) ``` ### 6.2 AI适配器接口 ```python class AIAdapter(ABC): @abstractmethod async def make_decision(self, game_state, available_actions, player_context): return { "action": "play", "data": {"card_ids": [...]}, "reasoning": "决策理由" } ``` --- ## 7. 部署与运维 ### 7.1 服务配置 ```ini # /etc/systemd/system/net-games.service [Unit] Description=Net-Games Server After=network.target [Service] Type=simple User=ubuntu WorkingDirectory=/home/ubuntu/nanocode/net-games Environment=NET_GAMES_HOST=0.0.0.0 Environment=NET_GAMES_PORT=8900 Environment=NET_GAMES_DEBUG=false Environment=DEEPSEEK_API_KEY=xxx ExecStart=/usr/bin/python3 /home/ubuntu/nanocode/net-games/server.py Restart=always RestartSec=10 [Install] WantedBy=multi-user.target ``` ### 7.2 端口规划 | 服务 | 端口 | 说明 | |------|------|------| | Net-Games | 8900 | 网游系统(本服务)| | Happy-Games | 8895 | 单机小游戏 | | Personal-Blog | 8888/8889 | 博客系统 | ### 7.3 监控指标 - 在线房间数 (`/api/stats`) - 在线玩家数 - AI调用次数/成本 - 平均游戏时长 --- ## 8. 安全设计 ### 8.1 认证安全 - 密码使用 werkzeug 哈希存储 - Session cookie 设置 HttpOnly, SameSite - Flask-Login 管理登录状态 ### 8.2 游戏安全 - 权威服务端:所有操作服务端验证 - 客户端仅展示,不执行游戏逻辑 - AI API Key 仅在服务端使用 ### 8.3 防作弊 - 牌面仅发送给对应玩家(player_view) - 操作合法性服务端验证 - 单点登录防止多开 --- ## 9. 更新日志 | 日期 | 版本 | 变更内容 | |------|------|----------| | 2026-04-09 | v2.0 | 更新为实际实现版本,添加认证系统、AI托管、超时管理、断线重连 | | 2026-04-08 | v1.0 | 初始设计文档,基础架构设计 | --- ## 10. 参考文档 - [API.md](./API.md) - 详细接口文档 - [DATABASE.md](./DATABASE.md) - 数据库设计 - [UI_DESIGN_GUIDELINES.md](./UI_DESIGN_GUIDELINES.md) - UI设计规范 --- *文档版本: v2.0* *最后更新: 2026-04-09* *维护者: 开发团队*