Files
nanocode/net-games/docs/ARCHITECTURE.md
T
Ubuntu 32b43f85bd a
2026-07-03 16:58:28 +08:00

22 KiB
Raw Blame History

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 (单例模式)

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 类

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 抽象基类

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 类层次

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 单点登录与身份识别

# 使用用户名或昵称作为身份标识
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. 玩家主动点击"托管"按钮

托管流程:

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 回合超时管理

# 配置
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 房间清理策略

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适配器
  1. 实现 GameBase 子类
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
  1. 注册游戏类型 (server.py)
from newgame import NewGame
room_manager.register_game('newgame', NewGame)

6.2 AI适配器接口

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 服务配置

# /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. 参考文档


文档版本: v2.0
最后更新: 2026-04-09
维护者: 开发团队