You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 08:13:07