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

快速启停游戏时Discord.Net游戏状态同步异常问题排查

问题分析与修复方案

核心问题1:Activity对象引用比较失效

Discord的Activity对象在每次PresenceUpdated事件触发时会生成新实例,即使游戏名称和类型完全一致,对象引用也不同。原代码中用!newPresence.Activities.Contains(game)做引用比较,会导致无法正确识别已关闭的游戏,进而无法赋值正确的gameName,后续移除逻辑自然失效。

核心问题2:字符串转换枚举的不必要风险

原代码用Convert.ToString(e.Type) == "Playing"判断活动类型,既低效又容易出错(比如枚举字符串名变更),应该直接使用Discord API提供的ActivityType.Playing枚举值比较。

核心问题3:共享集合的线程安全保障不足

即使尝试过锁,如果锁的范围没有覆盖所有对users集合的读写操作(Add/Any/FindIndex/RemoveAt),快速操作时依然会出现数据不一致的情况。


具体修复代码

1. 修复游戏关闭时的名称识别逻辑

将原代码中获取关闭游戏名的部分替换为:

// 直接用枚举判断Playing类型,避免字符串转换
var oldPlayingActivities = oldPresence.Activities.Where(e => e.Type == ActivityType.Playing).ToList();
var newPlayingActivities = newPresence.Activities.Where(e => e.Type == ActivityType.Playing).ToList();

// 判断是否有Playing活动被移除
if (oldPlayingActivities.Count > newPlayingActivities.Count)
{
    // 通过游戏名称匹配找到被移除的游戏,而非引用比较
    var closedGame = oldPlayingActivities.FirstOrDefault(game => 
        !newPlayingActivities.Any(n => n.Name == game.Name));
    if (closedGame != null)
    {
        gameName = closedGame.Name;
        shouldDo = true;
    }
}

2. 给users集合添加完整的线程锁

首先在类级别声明锁对象:

private readonly object _usersLock = new object();

然后所有操作users的代码都包裹在锁内:

// 游戏移除逻辑
if (shouldDo)
{
    User localUser = new User(Convert.ToString(user), gameName);
    lock (_usersLock)
    {
        int index = users.FindIndex(u => u.userName == localUser.userName && u.game == localUser.game);
        if (index != -1)
        {
            Console.WriteLine(gameName);
            Console.WriteLine(DateTime.Now.Subtract(users[index].date));
            // dataBase.AddPlayerGame(1, "saba", DateTime.Now.Subtract(users[index].date));
            users.RemoveAt(index);
        }
    }
}

// 游戏添加逻辑
if (!shouldDo && newPlayingActivities.Any())
{
    string newGame = newPlayingActivities.First().Name;
    User localUser = new User(Convert.ToString(user), newGame);
    lock (_usersLock)
    {
        if (!users.Any(e => e.userName == localUser.userName && e.game == localUser.game))
        {
            users.Add(localUser);
            Console.WriteLine("game added");
        }
    }
}

3. 优化线程调用(可选)

如果单线程运行仍有问题,建议用Task替代手动创建Thread,或通过信号量控制并发:

// 替换原线程创建代码
await Task.Run(() => ActivityHandler(user, oldPresence, newPresence));

额外注意事项

  • 确保User类的userName和game属性能正确匹配,避免因大小写、空格等格式问题导致无法找到对应项。
  • 快速操作时,Discord可能合并或延迟触发PresenceUpdated事件,可增加活动时间戳判断,避免重复或错误的添加/移除操作。

内容的提问来源于stack exchange,提问作者skami0_0

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 00:55:05