修复自动存点挂机经验重复累加和离线僵尸吃经验的漏洞,完善对应单元测试

This commit is contained in:
pllx
2026-07-06 22:39:20 +08:00
parent 7b46a08a46
commit a20bcf13be
2 changed files with 78 additions and 1 deletions
+21 -1
View File
@@ -87,14 +87,22 @@ class AutoSaveExp extends Command
$totalProcessed = 0;
$usersByUsername = $this->preloadOnlineUsers($roomMap);
$processedUsernames = [];
foreach ($roomMap as $roomId => $usernames) {
foreach ($usernames as $username) {
// 如果本轮已经处理过该用户,跳过发放经验(防止多房间/多开重复吃经验)
if (isset($processedUsernames[$username])) {
continue;
}
$user = $usersByUsername->get($username);
if (! $user) {
continue;
}
$this->processUser($user, $roomId, $expGainRaw, $jjbGainRaw, $superLevel);
$processedUsernames[$username] = true;
$totalProcessed++;
}
}
@@ -125,7 +133,19 @@ class AutoSaveExp extends Command
// Laravel 的 Redis facade 会自动加配置的前缀,与 ChatStateService 存入时完全一致
$usernames = Redis::hkeys("room:{$roomId}:users");
if (! empty($usernames)) {
$roomMap[(int) $roomId] = $usernames;
$activeUsernames = [];
foreach ($usernames as $username) {
// 检查活跃标记是否存在(90秒内)
if (Redis::exists("room:{$roomId}:alive:{$username}")) {
$activeUsernames[] = $username;
} else {
// 懒清理僵尸数据
Redis::hdel("room:{$roomId}:users", $username);
}
}
if (! empty($activeUsernames)) {
$roomMap[(int) $roomId] = $activeUsernames;
}
}
}