批量提取游戏信息并插入数据库的自动化实践

本文介绍如何从 33 个子游戏项目中自动提取游戏配置信息,并批量插入到 MySQL 数据库的完整流程。通过 Python 脚本自动解析 C++ 头文件,生成 SQL 插入脚本,实现游戏配置信息的快速入库。

**关键词**:游戏开发;数据库;Python;SQL;自动化;MySQL


1. 项目背景

在一个大型游戏平台项目中,我们需要管理 33 个子游戏的配置信息。每个游戏都有一个 `CMD_Game.h` 头文件,其中定义了游戏 ID、游戏名称等关键信息。传统的手动录入方式效率低下且容易出错,因此我们需要一个自动化的解决方案。

1.1 数据结构

数据库表 `GameGameItem` 包含以下关键字段:

| 字段名 | 类型 | 说明 |

|--------|------|------|

| GameID | INT | 游戏唯一标识 |

| GameName | NVARCHAR | 游戏名称 |

| SuportType | INT | 支持类型 |

| DataBaseAddr | NVARCHAR | 数据库地址 |

| DataBaseName | NVARCHAR | 数据库名称 |

| ServerVersion | INT | 服务器版本号 |

| ClientVersion | INT | 客户端版本号 |

| ServerDLLName | NVARCHAR | 服务器 DLL 文件名 |

| ClientExeName | NVARCHAR | 客户端 EXE 文件名 |


2. 游戏信息源分析

2.1 项目结构

```

game/

├── 21 点/

│ └── 消息定义/

│ └── CMD_Game.h

├── 斗地主/

│ └── 消息定义/

│ └── CMD_Game.h

├── 捕鱼达人/

│ └── 消息定义/

│ └── CMD_Game.h

└── ... (共 33 个游戏)

```

2.2 CMD_Game.h 文件格式

每个游戏的 `CMD_Game.h` 文件包含类似以下定义:

```cpp

// 游戏属性

#define KIND_ID 200 // 游戏 ID

#define GAME_NAME TEXT("斗地主") // 游戏名字

```


3. 自动化提取脚本

3.1 Python 提取脚本

```python

-*- coding: utf-8 -*-

"""

从 CMD_*.h 文件中提取游戏 ID 和游戏名称

生成 SQL 插入脚本

"""

import os

import re

def parse_cmd_h_file(file_path):

"""解析 CMD_*.h 文件,提取游戏 ID 和名称"""

game_id = None

game_name = None

try:

with open(file_path, 'r', encoding='gbk', errors='ignore') as f:

content = f.read()

查找 KIND_ID 定义

kind_id_match = re.search(r'#define\s+KIND_ID\s+(\d+)', content)

if kind_id_match:

game_id = int(kind_id_match.group(1))

查找 GAME_NAME 定义

game_name_match = re.search(r'#define\s+GAME_NAME\s+TEXT\("([^"]+)"\)', content)

if game_name_match:

game_name = game_name_match.group(1)

return game_id, game_name

except:

return None, None

def main():

script_dir = os.path.dirname(os.path.abspath(file))

print("=" * 80)

print("从 CMD_*.h 文件提取游戏信息")

print("=" * 80)

print()

games = {}

files_checked = 0

遍历所有 CMD_*.h 文件

for root, dirs, files in os.walk(script_dir):

跳过编译输出目录和旗舰版(避免重复)

dirs[:] = [d for d in dirs if d not in ['bin', 'obj', 'Debug', 'Release',

'.vs', '中间目录', '运行', '编译日志', '旗舰版游戏']]

for file in files:

if file.upper().startswith('CMD_'):

file_path = os.path.join(root, file)

files_checked += 1

game_id, game_name = parse_cmd_h_file(file_path)

if game_id and game_name:

game_dir = os.path.basename(os.path.dirname(os.path.dirname(file_path)))

if game_id not in games:

games[game_id] = {'name': game_name, 'dir': game_dir, 'file': file}

print(f"GameID {game_id}: {game_name} (来自:{game_dir}/{file})")

print()

print("=" * 80)

print(f"检查了 {files_checked} 个文件")

print(f"找到 {len(games)} 个游戏")

print("=" * 80)

生成 SQL 脚本

sql_path = os.path.join(script_dir, 'insert_all_games.sql')

with open(sql_path, 'w', encoding='utf-8-sig') as f:

f.write("-- ============================================\n")

f.write("-- 游戏信息插入脚本 (从 CMD_*.h 自动生成)\n")

f.write("-- 数据库:WHQJPlatformDB\n")

f.write("-- 表名:GameGameItem\n")

f.write("-- ============================================\n\n")

f.write("USE WHQJPlatformDB;\n")

f.write("GO\n\n")

f.write("-- 删除旧数据\n")

f.write("DELETE FROM GameGameItem WHERE GameID >= 100\n")

f.write("GO\n\n")

按 GameID 排序

for game_id in sorted(games.keys()):

game_info = games[game_id]

game_name = game_info['name']

server_dll = f"Game{game_id}Server.dll"

client_exe = f"Game{game_id}.exe"

f.write(f"INSERT INTO GameGameItem (GameID, GameName, SuportType, DataBaseAddr, ")

f.write(f"DataBaseName, ServerVersion, ClientVersion, ServerDLLName, ClientExeName) ")

f.write(f"VALUES ({game_id}, N'{game_name}', 31, '127.0.0.1', 'WHQJPlatformDB', ")

f.write(f"101122049, 101122049, '{server_dll}', '{client_exe}')\n")

f.write("GO\n")

f.write("\n-- 验证\n")

f.write("SELECT GameID, GameName FROM GameGameItem ORDER BY GameID\n")

f.write("GO\n")

print(f"\nSQL 脚本已保存至:{sql_path}")

打印游戏列表

print("\n完整游戏列表:")

print("-" * 80)

for game_id in sorted(games.keys()):

game_info = games[game_id]

print(f" {game_id}: {game_info['name']} ({game_info['dir']})")

if name == "main":

import sys

sys.exit(main())

```

3.2 使用方法

  1. 将脚本保存为 `extract_all_games.py`

  2. 放置在游戏根目录下

  3. 运行脚本:`python extract_all_games.py`

  4. 生成的 SQL 文件:`insert_all_games.sql`


4. SQL 插入脚本

4.1 SQL Server 版本

```sql

-- ============================================

-- 游戏信息插入脚本 (从 CMD_*.h 自动生成)

-- 数据库:WHQJPlatformDB

-- 表名:GameGameItem

-- ============================================

USE WHQJPlatformDB

GO

-- 删除旧数据

DELETE FROM GameGameItem WHERE GameID >= 100

GO

-- 扑克类游戏(12 个)

INSERT INTO GameGameItem (GameID, GameName, SuportType, DataBaseAddr, DataBaseName,

ServerVersion, ClientVersion, ServerDLLName, ClientExeName)

VALUES (200, N'斗地主', 31, '127.0.0.1', 'WHQJPlatformDB', 101122049, 101122049,

'Game200Server.dll', 'Game200.exe')

GO

-- ... 其他游戏

```

4.2 MySQL 版本

```sql

-- ============================================

-- 游戏信息插入脚本 (MySQL 版本)

-- 从 CMD_*.h 自动生成

-- 数据库:WHQJPlatformDB

-- 表名:GameGameItem

-- ============================================

USE WHQJPlatformDB;

-- 删除旧数据

DELETE FROM GameGameItem WHERE GameID >= 100;

-- 批量插入游戏数据

INSERT INTO GameGameItem (GameID, GameName, SuportType, DataBaseAddr, DataBaseName,

ServerVersion, ClientVersion, ServerDLLName, ClientExeName)

VALUES

(3, '德州扑克', 31, '127.0.0.1', 'WHQJPlatformDB', 101122049, 101122049,

'DZShowHandServer.dll', 'DZShowHand.exe'),

(51, '浙江十三水', 31, '127.0.0.1', 'WHQJPlatformDB', 101122049, 101122049,

'ThirteenZJServer.dll', 'ThirteenZJ.exe'),

(56, '疯狂三张', 31, '127.0.0.1', 'WHQJPlatformDB', 101122049, 101122049,

'ThreeMadnessServer.dll', 'ThreeMadness.exe'),

(57, '八人牛牛', 31, '127.0.0.1', 'WHQJPlatformDB', 101122049, 101122049,

'OxEightServer.dll', 'OxEight.exe'),

(104, '百人牛牛', 31, '127.0.0.1', 'WHQJPlatformDB', 101122049, 101122049,

'OxBattleServer.dll', 'OxBattle.exe'),

(200, '斗地主', 31, '127.0.0.1', 'WHQJPlatformDB', 101122049, 101122049,

'LandServer.dll', 'Land.exe');

-- ... 其他游戏

-- 验证查询

SELECT GameID, GameName FROM GameGameItem ORDER BY GameID;

```


5. 执行结果

5.1 成功插入的游戏列表(33 个)

| GameID | 游戏名称 | ServerDLLName | ClientExeName |

|--------|----------|---------------|---------------|

| 3 | 德州扑克 | DZShowHandServer.dll | DZShowHand.exe |

| 33 | 六人三公 | OxBattleServer.dll | OxBattle.exe |

| 51 | 浙江十三水 | ThirteenZJServer.dll | ThirteenZJ.exe |

| 56 | 疯狂三张 | ThreeMadnessServer.dll | ThreeMadness.exe |

| 57 | 八人牛牛 | OxEightServer.dll | OxEight.exe |

| 104 | 百人牛牛 | OxBattleServer.dll | OxBattle.exe |

| 118 | 百人骰宝 | Game118Server.dll | Game118.exe |

| 122 | 欢乐 30 秒 | BaccaratNewServer.dll | BaccaratNew.exe |

| 123 | 飞禽走兽 | AnimalBattleServer.dll | AnimalBattle.exe |

| 127 | 金鲨银鲨 | SharkBattleServer.dll | SharkBattle.exe |

| 140 | 豪车俱乐部 | LuxuryCarServer.dll | LuxuryCar.exe |

| 143 | 百人推筒子 | 28GangBattleServer.dll | 28GangBattle.exe |

| 144 | 红黑大战 | RedBlackBattleServer.dll | RedBlackBattle.exe |

| 145 | 龙虎斗 | DragonTigerBattleServer.dll | DragonTigerBattle.exe |

| 147 | 五星宏辉 | FiveStarServer.dll | FiveStar.exe |

| 148 | 红包扫雷 | HBSLServer.dll | HBSL.exe |

| 200 | 斗地主 | LandServer.dll | Land.exe |

| 238 | 510K(定制版) | 510KEXServer.dll | 510KEX.exe |

| 240 | 跑得快 | RunFastServer.dll | RunFast.exe |

| 241 | 21 点 | BlackJackServer.dll | BlackJack.exe |

| 302 | 血战麻将 | SparrowXZServer.dll | SparrowXZ.exe |

| 389 | 红中麻将 | SparrowHZHServer.dll | SparrowHZH.exe |

| 391 | 新广东麻将 | SparrowGDEXServer.dll | SparrowGDEX.exe |

| 401 | 五子棋 | Game401Server.dll | Game401.exe |

| 510 | 李逵劈鱼 | FishLKServer.dll | FishLK.exe |

| 511 | 摇钱树 | FishYQSServer.dll | FishYQS.exe |

| 516 | 水浒传 | WaterMarginServer.dll | WaterMargin.exe |

| 520 | 足球连线 | Line39Server.dll | Line39.exe |

| 522 | 超级水果连线 | SuperFruitServer.dll | SuperFruit.exe |

| 527 | 捕鱼达人 | FishDRServer.dll | FishDR.exe |

| 532 | ATT 连环炮 | ATTServer.dll | ATT.exe |

| 614 | 3D 森林王国 | Server_3DSLWG.dll | 3DSLWG.exe |

| 707 | 襄阳卡五星 | SparrowXYKWXServer.dll | SparrowXYKWX.exe |

5.2 游戏分类统计

| 游戏类型 | 数量 | 代表游戏 |

|----------|------|----------|

| 扑克类 | 12 | 斗地主、德州扑克、牛牛 |

| 麻将类 | 5 | 红中麻将、血战麻将 |

| 街机类 | 7 | 飞禽走兽、金鲨银鲨 |

| 捕鱼类 | 4 | 捕鱼达人、李逵劈鱼 |

| 老虎机 | 4 | 超级水果连线、豪车俱乐部 |

| 其他 | 1 | 五子棋 |


6. 数据库操作命令

6.1 MySQL 执行命令

```bash

执行插入脚本

mysql -u root -p WHQJPlatformDB < insert_all_games_mysql.sql

验证数据

mysql -u root -p WHQJPlatformDB -e "SELECT COUNT(*) FROM GameGameItem"

导出游戏列表

mysql -u root -p WHQJPlatformDB -e "SELECT GameID, GameName FROM GameGameItem ORDER BY GameID"

```

6.2 SQL Server 执行命令

```bash

使用 sqlcmd 执行

sqlcmd -S 127.0.0.1 -d WHQJPlatformDB -i insert_all_games.sql

验证数据

sqlcmd -S 127.0.0.1 -d WHQJPlatformDB -Q "SELECT COUNT(*) FROM GameGameItem"

```


7. 技术要点

7.1 编码处理

  • 源文件使用 GBK 编码读取

  • SQL 文件使用 UTF-8 with BOM 编码保存

  • 避免中文乱码问题

7.2 正则表达式

```python

匹配 KIND_ID

r'#define\s+KIND_ID\s+(\d+)'

匹配 GAME_NAME

r'#define\s+GAME_NAME\s+TEXT\("([^"]+)"\)'

```

7.3 批量插入优化

  • 使用批量 INSERT 语句减少数据库交互

  • 先删除旧数据避免主键冲突

  • 添加事务保证数据一致性


8. 扩展应用

8.1 更新服务器 DLL 名称

从实际编译的项目文件中提取真实的服务器 DLL 名称:

```python

def parse_vcxproj(file_path):

"""解析.vcxproj 文件,提取目标文件名"""

with open(file_path, 'r', encoding='utf-8', errors='ignore') as f:

content = f.read()

提取目标文件名

target_name_match = re.search(r'<TargetName>([^<]+)</TargetName>', content)

target_name = target_name_match.group(1) if target_name_match else None

return target_name

```

8.2 生成更新脚本

```sql

-- 更新 ServerDLLName 字段

UPDATE GameGameItem

SET ServerDLLName = 'LandServer.dll'

WHERE GameID = 200;

-- 更新 ClientExeName 字段(去掉 Server 和.dll,加上.exe)

UPDATE GameGameItem

SET ClientExeName = CONCAT(REPLACE(REPLACE(ServerDLLName, 'Server', ''), '.dll', ''), '.exe')

WHERE GameID >= 100;

```


9. 总结

本文介绍了一种从游戏项目头文件中自动提取配置信息并批量插入数据库的方法。主要优势包括:

  1. **自动化**:无需手动录入,减少人为错误

  2. **可维护**:脚本可重复使用,适应项目变化

  3. **高效率**:33 个游戏配置信息,几秒钟完成入库

  4. **跨平台**:支持 MySQL 和 SQL Server 两种数据库

该方法可推广到任何需要从源代码中提取配置信息的场景,具有很高的实用价值。


附录:完整代码

A.1 提取脚本(extract_all_games.py)

见第 3 节

A.2 MySQL 插入脚本(insert_all_games_mysql.sql)

见第 4.2 节

A.3 更新脚本(update_server_dll.sql)

```sql

-- 更新 ServerDLLName 字段为目标文件名

UPDATE GameGameItem SET ServerDLLName = 'DZShowHandServer.dll' WHERE GameID = 3;

UPDATE GameGameItem SET ServerDLLName = 'OxBattleServer.dll' WHERE GameID = 33;

-- ... 其他更新

-- 验证更新结果

SELECT GameID, GameName, ServerDLLName FROM GameGameItem ORDER BY GameID;

```


**作者简介**:林宏权,游戏后端开发工程师,专注于游戏服务器架构和自动化运维工具开发。

**版权声明**:本文为原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

相关推荐
卢傢蕊37 分钟前
MySQL全量、增量备份与恢复
数据库·mysql
码农垦荒笔记1 小时前
MySQL主从延迟根因诊断法:从现象到本质的全链路排查指南
数据库·mysql·主从复制
我不是8神1 小时前
CAP 定理与 etcd 核心知识点总结
数据库·etcd
kiku18181 小时前
Mysql故障排查与优化
数据库·mysql
刘~浪地球2 小时前
Redis 从入门到精通(二):数据类型详解
数据库·redis·缓存
小韩博2 小时前
代码审计-PHP原生开发篇&SQL注入&数据库监控&正则搜索&文件定位&静态分析
数据库·sql
qq_196976172 小时前
python的sql解析库-sqlparse
数据库·python·sql
Saniffer_SH2 小时前
【每日一题】一台可编程的PCIe 6.0主机 + 一套自动化CTS验证平台 + 一个轻量级链路分析系统
运维·服务器·测试工具·fpga开发·自动化·计算机外设·硬件架构
淡定一生23333 小时前
数据仓库建模方法
大数据·数据库·数据仓库
洛菡夕3 小时前
MySQL故障排查与生产环境优化
数据库·mysql