I have a script which is supposed to award players badges upon reaching a certain win count.
local BS = game:GetService("BadgeService")
local Players = game:GetService("Players")
--Badges
local YouPlayedBadgeId = 2129097380
local FirstWinBadgeId = 2129451058
local FiveWinBadgeId = 2129465393
local TenWinBadgeId = 2129465411
local TwentyFiveWinBadgeId = 2129465417
local FiftyWinBadgeId = 2129465418
--[[ tbd
local HundrethWinBadgeId = something
--]]
game.Players.PlayerAdded:Connect(function(player)
print("player has joined")
-- You Played Badge
if BS:UserHasBadgeAsync(player.UserId, YouPlayedBadgeId) == false then
pcall(BS.AwardBadge, BS, player.UserId, YouPlayedBadgeId)
print("You Played badge given")
end
-- First Win Badge
if BS:UserHasBadgeAsync(player.UserId, FirstWinBadgeId) == false then
player.leaderstats.Wins.Changed:Connect(function()
if player.leaderstats.Wins.Value >= 1 then
pcall(BS.AwardBadge, BS, player.UserId, FirstWinBadgeId)
print("First Win badge given")
end
-- 5 Wins Badge
if BS:UserHasBadgeAsync(player.UserId, FiveWinBadgeId) == false then
player.leaderstats.Wins.Changed:Connect(function()
if player.leaderstats.Wins.Value >= 5 then
pcall(BS.AwardBadge, BS, player.UserId, FiveWinBadgeId)
print("5 Wins Badge Given")
end
-- 10 Wins Badge
if BS:UserHasBadgeAsync(player.UserId, TenWinBadgeId) == false then
player.leaderstats.Wins.Changed:Connect(function()
if player.leaderstats.Wins.Value >= 10 then
pcall(BS.AwardBadge, BS, player.UserId, TenWinBadgeId)
print("10 Wins Badge Given")
end
-- 25 Wins Badge
if BS:UserHasBadgeAsync(player.UserId, TwentyFiveWinBadgeId) == false then
player.leaderstats.Wins.Changed:Connect(function()
if player.leaderstats.Wins.Value >= 25 then
pcall(BS.AwardBadge, BS, player.UserId, TwentyFiveWinBadgeId)
print("25 Wins Badge Given")
end
-- 50 Wins Badge
if BS:UserHasBadgeAsync(player.UserId, FiftyWinBadgeId) == false then
player.leaderstats.Wins.Changed:Connect(function()
if player.leaderstats.Wins.Value >= 50 then
pcall(BS.AwardBadge, BS, player.UserId, FiftyWinBadgeId)
print("50 Wins Badge Given")
end
end)
end
end)
end
end)
end
end)
end
end)
end
end)
The script only awards the first 2 badges, and Iām not sure why. The script doesnāt give errors and I tried them outside of studio and still no luck.
I tried removing the first two badges from the script and it works fine, but I want them all to be in it.
Bro? How is there no errors? Look at this:
There will be many syntax errors here, how did this happen?
(edit: there are no syntax errors, but the ālogicā doesnāt work)
Try this code:
local BS = game:GetService("BadgeService")
local Badges = {
[0] = 2129097380,
[1] = 2129451058,
[5] = 2129465393
[10] = 2129465411,
[25] = 2129465417,
[50] = 2129465418
[100] = nil,
}
game.Players.PlayerAdded:Connect(function(player)
local function update()
for wins, id in pairs(Badges) do
local userwins = player.leaderstats.Wins.Value
if userwins >= wins and not BS:UserHasBadgeAsync(player.UserId, id) then
BS:AwardBadge(player.UserId, id)
end
end
end
player.leaderstats.Wins.Changed:Connect(update)
task.spawn(update)
end)
Sure. The list Badges contains the badge ids, where the key is the minimum wins, and the value is the Id.
Then, for every player added, it will connect to the Wins.Changed event, and also call the event one time.
The connection will check their wins and iterate all the wins badges, see if they have enough wins, and that they donāt already have it. If so, they are awarded the badge.
The connection is called once because of the āWelcomeā badge, and also because of the possibility of you adding more badges.
I would like to add some things that can improve this:
Small thing but have a Players variable for the service, it looks better I promise.
Make the PlayerAdded connection function into a local function, then call it on every player when the script first runs. With Deferred events I believe just having it connected can cause some player to already have had join and it not registering.
Use :GetPropertyChangedSignal("Value") instead of .Changed, as it is legacy. (Also as a side note you didnāt need to call task.spawn there since thatās on a separate thread (coroutine) anyway)
Retrying, also, currently if thereās one error checking a certain badge it will stop the entire thread because of the error and other badges wonāt be checked
BS sounds like something else
I was actually previously writing about how you might wanna be wanting to cache the results here, and Iām still gonna be doing it, but :UserOwnsBadgeAsync does seem to cache that, though for a small duration. The only reason that Iām gonna still have it is because I believe that :UserOwnsBadgeAsync still yields around one frame for compatibility reasons and I would like that not to be the case.
local Players = game:GetService("Players")
local BadgeService = game:GetService("BadgeService")
local PlayersOwnedBadges: {[Player]: {[number]: boolean}} = {}
local Badges: {[number]: number} = { -- winsNeeded, badgeId
[1] = 12549815,
[10] = 12541535
}
local function AwardBadgeAsync(player: Player, badgeID: number)
local ownedBadges = PlayersOwnedBadges[player]
ownedBadges[badgeID] = true
local tries = 0
while true do
tries += 1
local functionErrored, wasAwardedSucessfully = pcall(
BadgeService.AwardBadge, BadgeService,
player.UserId, badgeID
)
if functionErrored == false and wasAwardedSucessfully == true then
break
elseif tries >= 5 then
ownedBadges[badgeID] = false
warn("Could not award badge to ".. player.Name.. " successfully.")
break
end
end
end
local function AwardDeservingBadges(player)
local ownedBadges = PlayersOwnedBadges[player]
local playerWins = player.leaderstats.Wins
for winsNeeded, badgeID in Badges do
local isOwned = ownedBadges[badgeID]
if isOwned then
continue
end
if playerWins.Value >= winsNeeded then
task.spawn(AwardBadgeAsync, player, badgeID)
else
break
end
end
end
local function OnPlayerAdded(player)
local ownedBadges = {}
for _, badgeID in Badges do
local isOwned = false
while true do
local success, response = pcall(
BadgeService.UserOwnsBadgeAsync, BadgeService,
player.UserId, badgeID
)
if success then
isOwned = response
break
end
end
ownedBadges[badgeID] = isOwned
end
player.leaderstats.Wins:GetPropertyChangedSignal("Value"):Connect(function()
AwardDeservingBadges(player)
end)
AwardBadgeAsync(player)
end
local function OnPlayerRemoved(player)
PlayersOwnedBadges[player] = nil
end
Players.PlayerAdded:Connect(OnPlayerAdded)
Players.PlayerRemoving:Connect(OnPlayerRemoved)
for _, player in ipairs(Players:GetPlayers()) do
task.defer(OnPlayerAdded, player)
end