FiveM Lua漂移排行榜Bug:如何通过玩家ID对比避免重复占位
FiveM漂移排行榜重复玩家问题修复方案
问题描述
开发的漂移排行榜存在Bug:未正确校验玩家ID,导致同一玩家可占据榜单多个名次。例如玩家A以10分位居榜首、玩家B以5分排第二时,玩家A只要跑出7分的中间分数,就会同时占据第二名位置。
问题根源
- 原
checkLeaderboard函数直接将旧条目设为nil,导致数组出现空洞,ipairs遍历不彻底,旧条目可能残留 - 榜单更新逻辑混乱:空榜单单独处理、遍历插入时机不对,导致删除旧条目后仍可能重复添加
GetPlacement函数未处理11、12、13这类特殊数字,会出现“12nd”的错误表述
修复步骤
- 彻底移除玩家旧榜单条目:遍历榜单时用
table.remove删除旧条目,而非设为nil,保证数组连续性 - 统一榜单更新流程:不管榜单是否为空,先删除玩家所有旧条目,再根据新分数决定插入位置
- 修复排名后缀逻辑:处理11-13的特殊情况,避免错误的后缀
修复后完整代码
LEADERBOARD_CLEAR_TIME = 15 -- 单位:分钟 local Players = {} local Leaderboards = {} RegisterCommand('cleardriftscores', function(source) if IsPlayerAceAllowed(source, 'drift') then -- Ace权限校验 clearLeaderboard() end end) RegisterNetEvent("SaveScore") AddEventHandler("SaveScore", function(client, data) local identifier = GetPlayerIdentifier(source, 0) local playerName = GetPlayerName(source) local newScore = data.curScore -- 更新个人最佳成绩 if Players[identifier] then if Players[identifier].pb < newScore then local oldScore = Players[identifier].pb Players[identifier].pb = newScore chatMessage(source, string.format("恭喜!你刷新了个人漂移链最高分:从^2%s^0提升到^2%s^0!", oldScore, newScore)) end else Players[identifier] = { pb = newScore } end -- 先移除该玩家在榜单中的所有旧条目 removePlayerFromLeaderboard(identifier) -- 插入新分数到正确位置 local inserted = false for k, v in ipairs(Leaderboards) do if v.score < newScore then table.insert(Leaderboards, k, { score = newScore, name = playerName, id = identifier }) chatMessage(-1, string.format("^2%s^0以^2%s^0的分数超越了^2%s^0的^2%s^0!当前排名第^2%s^0", playerName, newScore, v.name, v.score, GetPlacement(k))) inserted = true break end end -- 如果没找到比自己低的分数,就插在最后 if not inserted then table.insert(Leaderboards, { score = newScore, name = playerName, id = identifier }) local placement = #Leaderboards if placement == 1 then chatMessage(-1, string.format("^2%s^0开启了本次漂移排行榜,分数为^2%s^0!", playerName, newScore)) else chatMessage(-1, string.format("^2%s^0提交了^2%s^0的漂移分数,当前排名第^2%s^0", playerName, newScore, GetPlacement(placement))) end end -- 保持榜单按分数降序排列(兜底逻辑) table.sort(Leaderboards, function(a, b) return a.score > b.score end) end) function chatMessage(target, msg) TriggerClientEvent('chat:addMessage', target or -1, { color = { 255, 0, 0}, multiline = true, args = {"[漂移排行榜] ", msg} }) end -- 移除玩家在榜单中的所有条目 function removePlayerFromLeaderboard(identifier) -- 倒序遍历,避免删除元素后索引错乱 for k = #Leaderboards, 1, -1 do if Leaderboards[k].id == identifier then table.remove(Leaderboards, k) end end end -- 修复后的排名后缀函数 function GetPlacement(number) local lastTwoDigits = number % 100 -- 处理11、12、13的特殊情况 if lastTwoDigits >= 11 and lastTwoDigits <= 13 then return number .. 'th' end local lastDigit = number % 10 local placement = 'th' if lastDigit == 1 then placement = 'st' elseif lastDigit == 2 then placement = 'nd' elseif lastDigit == 3 then placement = 'rd' end return number .. placement end function clearLeaderboard() Leaderboards = {} chatMessage(-1, "漂移排行榜已清空!") end -- 排行榜自动重置线程 Citizen.CreateThread(function() while true do while #Leaderboards == 0 do Citizen.Wait(0) end -- 提前5分钟提醒 Citizen.Wait((LEADERBOARD_CLEAR_TIME * 60 * 1000) - (5 * 60 * 1000)) chatMessage(-1, "漂移排行榜将在5分钟后清空!") Citizen.Wait(3 * 60 * 1000) chatMessage(-1, "漂移排行榜将在2分钟后清空!") Citizen.Wait(1 * 60 * 1000) chatMessage(-1, "漂移排行榜将在1分钟后清空!") Citizen.Wait(1 * 60 * 1000) clearLeaderboard() end end)
内容的提问来源于stack exchange,提问作者Gavino
相关产品推荐
相关产品推荐

