# Net-Games 数据库设计文档 > **版本**: v2.0 > **更新日期**: 2026-04-09 > **数据库**: SQLite (开发/生产) --- ## 1. 技术选型 | 环境 | 数据库 | ORM | 说明 | |------|--------|-----|------| | 开发/生产 | SQLite | SQLAlchemy | 零配置,文件存储,适合当前规模 | **选择理由:** - 单机部署,无需外部数据库服务 - 数据量小(用户<1000,房间实时<100) - 备份简单(复制文件即可) - 未来可无缝迁移到PostgreSQL --- ## 2. 数据库文件 ``` /home/ubuntu/nanocode/net-games/ ├── net_games_auth.db # 主数据库(生产) └── instance/ └── net_games_auth.db # Flask实例目录(开发) ``` --- ## 3. 表结构设计 ### 3.1 users - 用户表 存储注册用户信息和游戏积分。 ```sql CREATE TABLE users ( id INTEGER PRIMARY KEY AUTOINCREMENT, username VARCHAR(80) UNIQUE NOT NULL, -- 登录用户名(唯一) nickname VARCHAR(80), -- 显示昵称(默认同用户名) password_hash VARCHAR(200) NOT NULL, -- 密码哈希 role VARCHAR(20) DEFAULT 'user', -- 角色: admin/user game_scores TEXT DEFAULT '{}', -- JSON格式各游戏积分 created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, last_login TIMESTAMP ); ``` **game_scores JSON格式:** ```json { "doudizhu": 100, "chinese_chess": 50 } ``` **Python模型** (server.py): ```python class User(db.Model): __tablename__ = 'users' id = db.Column(db.Integer, primary_key=True) username = db.Column(db.String(80), unique=True, nullable=False) nickname = db.Column(db.String(80), nullable=True) password_hash = db.Column(db.String(200), nullable=False) role = db.Column(db.String(20), default='user') game_scores = db.Column(db.Text, default='{}') created_at = db.Column(db.DateTime, default=db.func.current_timestamp()) def get_game_score(self, game_id): scores = json.loads(self.game_scores or '{}') return scores.get(game_id, 0) def add_game_score(self, game_id, points): scores = json.loads(self.game_scores or '{}') scores[game_id] = scores.get(game_id, 0) + points self.game_scores = json.dumps(scores) return scores[game_id] ``` **默认用户:** | 用户名 | 密码 | 昵称 | 角色 | |--------|------|------|------| | admin | abcd1234 | 管理员 | admin | | caixianming | cxm123456 | 蔡叔叔 | user | --- ### 3.2 内存数据 vs 持久化数据 **内存中维护(运行时):** | 数据 | 存储位置 | 说明 | |------|----------|------| | 房间列表 | RoomManager._rooms | Dict[room_id, Room] | | 玩家映射 | socket_player_map | Dict[socket_id, player_id] | | 用户映射 | user_socket_map | Dict[user_id, socket_id] | | 活跃用户 | active_usernames | Dict[username, player_id] | | 用户房间 | user_room_map | Dict[username, room_id] | **持久化存储(SQLite):** | 数据 | 表 | 说明 | |------|-----|------| | 用户信息 | users | 账号、密码、积分 | **注意:** 房间和玩家数据仅在内存中维护,游戏结束后房间被清理。如需持久化游戏记录,需要额外设计GameRecord表。 --- ## 4. 积分系统设计 ### 4.1 积分规则(斗地主) | 角色 | 胜利 | 失败 | |------|------|------| | 地主 | +6分 | -4分 | | 农民 | +3分 | -2分 | **AI玩家不计积分**,仅人类玩家累计积分。 ### 4.2 积分更新流程 ```python def calculate_and_update_scores(room, winner_id): score_changes = {} for pid, player in game.players.items(): if player.is_ai: score_changes[pid] = {'change': 0, 'is_ai': True} continue is_lord = (pid == game.lord_id) is_winner = (pid == winner_id) # 计算积分变动 if is_lord: change = 6 if is_winner else -4 else: change = 3 if is_winner else -2 # 更新数据库 db_user = User.query.filter_by(username=player.name).first() if db_user: new_total = db_user.add_game_score('doudizhu', change) db.session.commit() score_changes[pid] = { 'change': change, 'total': new_total, 'is_ai': False } return score_changes ``` ### 4.3 查询积分示例 ```python # 获取用户斗地主积分 user = User.query.filter_by(username='蔡叔叔').first() score = user.get_game_score('doudizhu') # 返回: 100 # 获取所有游戏积分 scores = json.loads(user.game_scores) # 返回: {'doudizhu': 100, ...} ``` --- ## 5. 预留表设计(未来扩展) ### 5.1 game_records - 游戏记录表(预留) 用于保存游戏历史记录和回放数据。 ```sql CREATE TABLE game_records ( id VARCHAR(32) PRIMARY KEY, room_id VARCHAR(32) NOT NULL, game_type VARCHAR(20) NOT NULL, started_at TIMESTAMP NOT NULL, ended_at TIMESTAMP, duration_seconds INTEGER, -- 玩家信息 (JSON数组) players JSON NOT NULL, /* 格式: [ {"player_id": "xxx", "name": "玩家A", "role": "landlord", "is_ai": false, "score_change": 6}, {"player_id": "ai_1", "name": "AI-规则", "role": "farmer", "is_ai": true, "ai_type": "rule", "score_change": -3} ] */ -- 结果 winner_id VARCHAR(32), result_type VARCHAR(20), -- normal/surrender/timeout -- 回放数据 (压缩存储) replay_data BLOB, -- JSON序列化后 gzip 压缩 -- 统计 total_turns INTEGER, max_combo INTEGER, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ); ``` ### 5.2 ai_usage - AI调用记录表(预留) 用于监控AI调用成本和性能。 ```sql CREATE TABLE ai_usage ( id INTEGER PRIMARY KEY AUTOINCREMENT, ai_type VARCHAR(20) NOT NULL, -- deepseek/rule/minimax model_name VARCHAR(50), -- deepseek-chat room_id VARCHAR(32), game_type VARCHAR(20), -- Token用量 input_tokens INTEGER, output_tokens INTEGER, total_tokens INTEGER, -- 性能 latency_ms INTEGER, -- 成本估算 (美元) estimated_cost DECIMAL(10,6), -- 调试信息 request_prompt TEXT, response_text TEXT, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ); ``` ### 5.3 rooms - 房间历史表(预留) 如需持久化房间信息,可创建此表。 ```sql CREATE TABLE rooms ( id VARCHAR(32) PRIMARY KEY, room_code VARCHAR(10) UNIQUE, game_type VARCHAR(20), status VARCHAR(20), -- waiting/playing/ended/closed created_at TIMESTAMP, started_at TIMESTAMP, ended_at TIMESTAMP, max_players INTEGER, config JSON, winner_id VARCHAR(32), final_state JSON, is_active BOOLEAN DEFAULT TRUE ); ``` --- ## 6. 数据库操作示例 ### 6.1 初始化数据库 ```python # server.py with app.app_context(): db.create_all() # 创建所有表 init_default_users() # 创建默认用户 ``` ### 6.2 常用查询 ```python # 用户认证 user = User.query.filter_by(username='caixianming').first() if user and user.check_password('password'): login_user(user) # 获取排行榜 top_players = User.query.filter( User.game_scores != '{}' ).order_by( User.id # 简化排序,实际需解析JSON ).limit(10).all() # 更新积分 user = User.query.filter_by(username='蔡叔叔').first() new_score = user.add_game_score('doudizhu', 6) db.session.commit() ``` ### 6.3 数据库备份 ```bash # 备份SQLite数据库 cp /home/ubuntu/nanocode/net-games/net_games_auth.db \ /home/ubuntu/nanocode/net-games/backups/net_games_auth_$(date +%Y%m%d).db ``` --- ## 7. 索引设计 ```sql -- 用户查询优化 CREATE INDEX idx_users_username ON users(username); CREATE INDEX idx_users_role ON users(role); -- 预留:游戏记录查询 -- CREATE INDEX idx_records_game_type ON game_records(game_type); -- CREATE INDEX idx_records_created ON game_records(created_at DESC); -- CREATE INDEX idx_records_winner ON game_records(winner_id); -- 预留:AI用量查询 -- CREATE INDEX idx_ai_usage_time ON ai_usage(created_at); -- CREATE INDEX idx_ai_usage_type ON ai_usage(ai_type); ``` --- ## 8. 数据保留策略 | 数据类型 | 当前策略 | 未来规划 | |----------|----------|----------| | 用户数据 | 永久保留 | 永久保留 | | 积分记录 | 实时计算,无历史 | 可考虑添加积分变动日志 | | 房间数据 | 内存存储,游戏结束即清理 | 如需持久化,添加rooms表 | | 游戏记录 | 不保存 | 如需回放,添加game_records表 | | AI调用记录 | 不保存 | 如需成本控制,添加ai_usage表 | --- ## 9. 更新日志 | 日期 | 版本 | 变更内容 | |------|------|----------| | 2026-04-09 | v2.0 | 更新为实际实现,当前仅使用users表,其他为预留设计 | | 2026-04-08 | v1.0 | 初始设计,包含完整ER图和多表设计 | --- ## 10. 总结 **当前实现 (v2.0):** - 极简设计,仅使用 `users` 表存储用户信息和积分 - 房间和玩家数据全部在内存中管理 - 适合当前小规模部署 **未来扩展方向:** 1. 添加 `game_records` 表保存游戏历史 2. 添加 `ai_usage` 表监控AI成本 3. 添加 `rooms` 表持久化房间信息 4. 如需更复杂功能,迁移到PostgreSQL --- *文档版本: v2.0* *最后更新: 2026-04-09* *数据库文件: net_games_auth.db*