Script doesn't award badges

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.

1 Like

There a reason:
image
image


my code remake:

game.Players.PlayerAdded:Connect(function(player)
    -- You Played Badge
    if BS:UserHasBadgeAsync(player.UserId, YouPlayedBadgeId) == false then
        pcall(BS.AwardBadge, BS, player.UserId, YouPlayedBadgeId)
	    print("You Played badge given")
    end
    ---------
    player.leaderstats.Wins.Changed:Connect(function()
      -- Win Badges

         -- First Win Badge
        if BS:UserHasBadgeAsync(player.UserId, FirstWinBadgeId) == false and 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 and 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 and player.leaderstats.Wins.Value >= 10 then
	        pcall(BS.AwardBadge, BS, player.UserId, TenWinBadgeId)
	        print("10 Wins Badge Given")
        end

    end)
  -------
end)
3 Likes

Bro? How is there no errors? Look at this:
image
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)
2 Likes

You mind telling me how this works?

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.

1 Like

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 :grinning:

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
1 Like

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.