Python在Discord多用户游戏中存储用户资产及数据的实现咨询
解决Discord多用户游戏的货币存储问题
首先得明确:Discord每个用户都有一个永久唯一的ID(user.id,字符串类型),这玩意儿比用户名靠谱一万倍——用户名能改,但ID永远不变,所以用它当核心标识来存储用户数据是最优解,完全能避免重名问题。
下面分两种场景给你方案,从简单到进阶:
一、本地JSON存储:适合小型测试/小众服务器
如果你的游戏用户不多,用JSON文件做持久化存储足够了,代码简单还不用额外装服务。我把你的示例改成符合Discord Bot逻辑的写法(注意:Discord Bot不能用input(),得用命令交互):
import json import discord from discord.ext import commands # 初始化Bot,记得开启对应的Intents intents = discord.Intents.default() intents.message_content = True bot = commands.Bot(command_prefix='!', intents=intents) # 存储用户数据的JSON文件路径 USER_DATA_FILE = "user_currency.json" # 加载本地存储的用户数据 def load_user_data(): try: with open(USER_DATA_FILE, 'r', encoding='utf-8') as f: return json.load(f) except FileNotFoundError: # 文件不存在时返回空字典,相当于初始化 return {} # 保存用户数据到本地文件 def save_user_data(data): with open(USER_DATA_FILE, 'w', encoding='utf-8') as f: json.dump(data, f, indent=4, ensure_ascii=False) # Bot启动时加载数据 @bot.event async def on_ready(): global user_data user_data = load_user_data() print(f"已登录为 {bot.user},加载了 {len(user_data)} 个用户的数据") # 查看余额的命令 @bot.command(name="balance", help="查看你的当前货币余额") async def check_balance(ctx): # 获取用户的唯一ID,转成字符串存(JSON键必须是字符串) user_id = str(ctx.author.id) # 如果用户是第一次使用,自动初始化余额为0 if user_id not in user_data: user_data[user_id] = { "username": ctx.author.name, "currency": 0 } save_user_data(user_data) # 发送余额信息 await ctx.send(f"@{ctx.author.name},你当前的货币余额是:{user_data[user_id]['currency']}") # 工作赚货币的命令 @bot.command(name="work", help="工作赚取货币") async def work_for_currency(ctx): user_id = str(ctx.author.id) # 同样先检查用户是否存在,不存在就初始化 if user_id not in user_data: user_data[user_id] = { "username": ctx.author.name, "currency": 0 } # 模拟工作赚100货币,你可以改成随机值或者根据工作类型调整 earnings = 100 user_data[user_id]['currency'] += earnings # 保存修改后的数据 save_user_data(user_data) await ctx.send(f"@{ctx.author.name},工作完成!你赚到了 {earnings} 货币,当前余额:{user_data[user_id]['currency']}") # 替换成你的Bot令牌,从Discord开发者平台获取 bot.run("YOUR_BOT_TOKEN_HERE")
这个方案的核心逻辑:
- 用
user_id作为字典的键,彻底避免重名问题 - 每次修改数据后都调用
save_user_data(),确保重启Bot后数据不丢失 - 不需要用户输入用户名,直接从Discord的上下文(
ctx)获取用户信息,交互更流畅
二、数据库存储:适合用户量较大的服务器
如果你的游戏用户越来越多,JSON文件的读写效率会下降,这时候建议用数据库。轻量型的用SQLite(不用额外装服务,文件型数据库),规模大了可以换PostgreSQL/MySQL。
给你一个SQLite的示例:
import sqlite3 import discord from discord.ext import commands intents = discord.Intents.default() intents.message_content = True bot = commands.Bot(command_prefix='!', intents=intents) # 连接SQLite数据库,不存在则自动创建 conn = sqlite3.connect('user_currency.db') cursor = conn.cursor() # 创建用户表,用user_id作为主键(保证唯一) cursor.execute('''CREATE TABLE IF NOT EXISTS users (user_id TEXT PRIMARY KEY, username TEXT, currency INTEGER DEFAULT 0)''') conn.commit() @bot.event async def on_ready(): print(f"已登录为 {bot.user}") @bot.command(name="balance") async def check_balance(ctx): user_id = str(ctx.author.id) # 查询用户余额 cursor.execute('SELECT currency FROM users WHERE user_id = ?', (user_id,)) result = cursor.fetchone() if not result: # 用户不存在,插入初始数据 cursor.execute('INSERT INTO users (user_id, username) VALUES (?, ?)', (user_id, ctx.author.name)) conn.commit() await ctx.send(f"@{ctx.author.name},你当前的货币余额是:0") else: await ctx.send(f"@{ctx.author.name},你当前的货币余额是:{result[0]}") @bot.command(name="work") async def work_for_currency(ctx): user_id = str(ctx.author.id) earnings = 100 cursor.execute('SELECT currency FROM users WHERE user_id = ?', (user_id,)) result = cursor.fetchone() if not result: # 新用户直接插入带 earnings 的数据 cursor.execute('INSERT INTO users (user_id, username, currency) VALUES (?, ?, ?)', (user_id, ctx.author.name, earnings)) else: # 老用户更新余额 new_balance = result[0] + earnings cursor.execute('UPDATE users SET currency = ? WHERE user_id = ?', (new_balance, user_id)) conn.commit() await ctx.send(f"@{ctx.author.name},工作完成!你赚到了 {earnings} 货币,当前余额:{earnings if not result else new_balance}") bot.run("YOUR_BOT_TOKEN_HERE")
这个方案的优势:
- 数据库的读写效率远高于JSON文件,适合用户量增长的场景
- 支持更复杂的查询(比如排行榜、统计数据),扩展性更强
对你原有代码的调整建议
你原来的start()函数用了input(),这在Discord Bot里是行不通的——Discord是异步交互系统,必须用Bot的命令/事件系统来处理用户请求,不能像控制台程序那样等待输入。上面的示例都改成了Discord.py的标准命令格式,这样才能在Discord服务器上正常运行。
另外再强调一遍:绝对不要用用户名作为唯一标识,用户随时能改用户名,但user.id是永久不变的,这才是唯一可靠的用户ID。
内容的提问来源于stack exchange,提问作者Drakonix
相关产品推荐
相关产品推荐

