Badges wont work sometimes

in my game, become an interminable rooms entity, X variants are broken. They will not respond.
Code:

script.Parent.MouseButton1Click:Connect(function()
	warn("Pressed")
	--wait(0.1)
	--print("OKAY")
	if game.BadgeService:UserHasBadgeAsync(script.Parent.Parent.Parent.Parent.Parent, 1016378472273827) == true then
			warn("True")
			for i, obj in pairs(script.Parent.Parent:GetChildren()) do
				if obj:IsA("ScrollingFrame") then
					obj.Visible = false
				end
			end
			script.Parent.Parent.XVariants.Visible = true
		else
			warn("False")
			--workspace["Alarm Buzzer 3 (SFX)"]:Play()
		end
	--werid
end)--133444357522939bellzaaaaerrtrwtycewgu798Q67.NTG3ETt23gGVF3478tb23igbb362f7b7-=-=-948839382

You have not really explained what the bug is. Will be assuming it’s related to the BadgeService line due to the title.

UserHasBadgeAsync needs to be used in a pcall. This query can fail for a multitude of reasons, meaning this probably isn’t a Roblox bug. Your badge-related query will sometimes error, and because you don’t pcall + retry it, the rest of the script won’t function as you intend.

2 Likes

Can you show me how? its the first if statement.

sometimes if you do to many request i believe

Hello!
Thanks for reaching out with your bug report. Our team is looking into it - first, could you provide some extra context as to your issue? Please describe the purpose of this code snippet, and what specific errors/issues you are encountering.

1 Like

the snippet is supposed to open a menu which is for X variants of the entities in my game, it checks if the player has the badge, (its server-sided), and then opens if they do.
however, due to a bug, it never works due to other badges constantly being checked by loops.

Thank you for the extra context!

With the information you have given me, we can’t yet call this problem a “bug”, as a bug generally means there is some unexpected / undocumented behavior. If the issue is that it doesn’t work since other badges are constantly being checked by loops, then my first instinct would be that you are hitting the UserHasBadgeAsync universe-level rate limit of 50 + 35 * [number of players] requests per minute (see the documentation here).

This may or may not be the problem, so here are my recommended steps:

  1. Wrap the UserHasBadgeAsync() function in a pcall(). That way, you can catch any errors that might occur and print them to your console. If the issue is the rate limit, you should see the error "TooManyRequests". Here’s a good dev forum post describing how pcall() works.
  2. If this is not the case, let me know and I can take a deeper look into if this is in fact a bug. Otherwise, I would create a cache that stores if a player has a specific badge. This way, you only need to call the UserHasBadgeAsync() function once for each player for each badge.

Let me know if you have any questions on this!

2 Likes

it is toomanyrequests. are there any ways i can ignore this?

Unfortunately not - the limits are set in place in order to protect network resources. With that said, I can help you implement the caching solution, as that will likely resolve the issue.

First, would you be able to send me some code of other places you use UserHasBadgeAsync()? You mentioned that badges are being constantly checked by loops.

2 Likes

Really nice seeing an engineer taking the time to help someone fix a script :slightly_smiling_face:

I have a bug with badges but it’s more to do with how they’re displayed on the website rather than the backend functionality. Would I be able to file this for you to look at, or do you not work with the badges HTML? Just asking because I don’t want to file the report just for it to go unanswered for months. :slightly_smiling_face:

1 Like

Thanks for the compliment! I try my best to make sure everyone’s concerns are addressed :smile:

And yes, go ahead and file the bug report or DM me privately with the concern, and I’ll see what I can do.

2 Likes
wait(0.1)
d = false
local BaseText = script.Parent.Text
game["Run Service"].Heartbeat:Connect(function()
	if d == false then
		d = true
		if game.BadgeService:UserHasBadgeAsync(script.Parent.Parent.Parent.Parent.Parent.Parent.UserId, 300622221016883) == false then
			script.Parent.Text = BaseText .. " (Requires badge: Unexpected Pumpkin, Rejoin when got)"
			script.Parent.BackgroundTransparency = 0.5
			script.Parent.TextTransparency = 0.5
			script.Parent.Interactable = false
		else
			script.Parent.Text = BaseText
			script.Parent.BackgroundTransparency = 0
			script.Parent.TextTransparency = 0
			script.Parent.Interactable = true
		end
		d = false
	end
end)

-PK-15

Thanks for sending over the code! Please correct me if I’m wrong, but it appears you are doing constant checks to see if a user has a specific badge; this way you can change the properties of the script’s parent item.

If that is the case, the current issue with the logic is that the Heartbeat fires every frame, and thus also calls UserHasBadgeAsync() every frame - this certainly leads to you hitting the rate limit. The script you first sent me also calls the UserHasBadgeAsync() on every mouse click, meaning if a player clicks rapidly over time, they will also exhaust the rate limit.

It’s a bit complex, but here’s my recommendations as to how you can get around these limits.

  1. Instead of checking the badge status on a refresh loop, I would adjust your high-level logic a bit.
  • Rather than having the client constantly check if its player owns the badge, have the server notify the client if the badge status changes. That is, upon AwardBadge(), fire an event to the client, and upon receiving that event, the client can update the properties of the script.Parent.
  • Upon the initial load, the client can call UserHasBadgeAsync() exactly once to set up the initial state. Or even better, it can get the badge status from the server using the caching method described in 2.

A small caveat here is that this won’t catch any badges awarded via the HTTP Badges API, in which case you may need to keep your current logic (although it definitely should not run every frame). Assuming you are only ever awarding badges through the game code, the above solution should work fine.

  1. For the action on mouse click, add a server-side cache. This cache will store a mapping between a player + badge and a boolean that designates if they own that badge. This can be stored using a table, or depending on your player count, something like MemoryStoreService.
  • On mouse click, instead of having the LocalScript call BadgeService, fire an event to the Server to get the badge status for that player. The server will try to read the player + badge status from the cache. If it does not exist (when a player first loads in), the server can call UserHasBadgeAsync(), populate the cache, and return that status to the client.
  • On AwardBadge(), the server can also write true to the cache for that player + badge.

These two implementation changes should (in theory) bring you well below the limit. Let me know if you have any other questions, and I hope this was helpful!

3 Likes

I am also going to set this bug report as CLOSED for the sake of bookkeeping, but feel free to continue asking questions in the thread!

2 Likes