So in my game from defeating players you gain a stat called souls, and the more souls you have there are milestones that award you with your accomplishments (e.g reach 1,000 souls and gain a badge called soul destroyer or smth).
So what I did was I made a changed event on souls that checks if you have enough to be awarded before awarding you. And if you do have enough souls then it checks if you already have the badge and if you don’t it awards you with the badge.
Okay now where the problem lies is that the check part is being overused. UserHasBadgeAsync is being used way too often, and I even made a check to see if changed has ran 10 times for each player before checking. TO NO AVAIL. Even this system causes throttling. Example Below:
souls.Changed:Connect(function()
num += 1
if num >= 10 then
num = 0
-- for loop through a table of soul badges and requirements
-- check for badge on each one
end
end)
(Sorry for the bad indenting, but I’m sure it isn’t too difficult to understand this piece of code)
And you may be thinking “Why not just create a throttling function for UserHasBadgeAsync?” WELL I DID YOU SEE ITS RIGHT HERE:
function CheckBadgeOwnership(player, badgeId)
if not player then
return "Error"
end
badgeRequests[player.UserId] = badgeRequests[player.UserId] or { count = 0, lastRequestTime = 0 }
local userRequests = badgeRequests[player.UserId]
if userRequests.cd and os.time() < userRequests.cd + 5 then
return "Cooldown"
else
if userRequests.cd and os.time() > userRequests.cd + 5 then
badgeRequests[player.UserId].cd = nil
userRequests.cd = nil
end
end
local BADGE_THROTTLE_LIMIT = 30
if userRequests.count >= BADGE_THROTTLE_LIMIT then
badgeRequests[player.UserId].cd = os.time()
badgeRequests[player.UserId].count = 0
return "Error"
end
badgeRequests[player.UserId].count += 1
local hasBadge = badgeservice:UserHasBadgeAsync(player.UserId, badgeId)
return hasBadge
end
And yet we’re still having the same warning messages below:
Does anyone know what I could try doing in my code to make this less of an occurring warning? I don’t want this warning to spam my error reports on my game.
local BadgeService = game:GetService("BadgeService")
local BadgeCache = {}
function CheckBadgeOwnership(player, badgeId)
if not player then
return "Error"
end
if typeof(BadgeCache[player.UserId]) ~= "table" then
BadgeCache[player.UserId] = {}
end
local hasBadge = false
local info = BadgeCache[player.UserId][badgeId]
if info == nil then
hasBadge = BadgeService:UserHasBadgeAsync(player.UserId, badgeId)
BadgeCache[player.UserId][badgeId] = {
["hasBadge"] = hasBadge,
["lastCheck"] = os.time(),
}
else
hasBadge = info.hasBadge
end
return hasBadge
end
it basically just stores if the user has the badge so it can be quickly checked.
this approach, you minimize the number of calls to UserHasBadgeAsync and avoid throttling much
local BadgeService = game:GetService("BadgeService")
local HttpService = game:GetService("HttpService")
local badgeRequests = {}
local badgeRequirements = {
[123456789] = 1000, -- Example badge ID and requirement
[987654321] = 5000,
}
local function CheckBadgeOwnership(player, badgeId)
if not player then
return "Error"
end
badgeRequests[player.UserId] = badgeRequests[player.UserId] or { count = 0, lastRequestTime = 0, badges = {} }
local userRequests = badgeRequests[player.UserId]
-- Check cache first
if userRequests.badges[badgeId] ~= nil then
return userRequests.badges[badgeId]
end
-- Throttling mechanism
local BADGE_THROTTLE_LIMIT = 30
if userRequests.count >= BADGE_THROTTLE_LIMIT then
if os.time() < userRequests.lastRequestTime + 60 then
return "Cooldown"
else
userRequests.count = 0
end
end
userRequests.count += 1
userRequests.lastRequestTime = os.time()
-- Call UserHasBadgeAsync
local hasBadge = BadgeService:UserHasBadgeAsync(player.UserId, badgeId)
userRequests.badges[badgeId] = hasBadge
return hasBadge
end
local function AwardBadges(player, souls)
for badgeId, requirement in pairs(badgeRequirements) do
if souls >= requirement then
if CheckBadgeOwnership(player, badgeId) == false then
BadgeService:AwardBadge(player.UserId, badgeId)
end
end
end
end
-- Batch processing
local function ProcessPlayers()
while true do
for _, player in pairs(game.Players:GetPlayers()) do
local souls = player:FindFirstChild("souls")
if souls then
AwardBadges(player, souls.Value)
end
end
wait(10) -- Adjust the interval as needed
end
end
game:GetService("RunService").Stepped:Connect(ProcessPlayers)