Hello Developers .
I’ve come to a situation in which I need to load 120 badges to a GUI in seconds when players join.
I keep getting the TooManyRequests error.
When I get that error, I wait around 15 seconds to let the service refresh and then continue.
It all works well but sums up to about a minute of loading time… Which is a lot.
I’ve seen games that load dozens of badges and data in seconds, how do they do that?
Does anyone know how to decrease the loading time? Load so many badges quickly?
You could possibly get around this request limit by using HttpService and a proxy. The requests need to be proxyed to the badge api (api documentation: badges.roblox.com/docs). Note this has a limit of 500 requests a minute and requires http service to be enabled.
If your approach is the table way you can iterate over each key value pair. This way you could write a function which do stuff for your badges. (I dunno, i havent worked with badges yet) But an example would be like
local BadgeService = game:GetService("BadgeService");
local badges = {
badge1 = 65465416,
badge2 = 56465456
}
local funtion doSomethingWithBadge(badgeName, badgeId)
local success, badgeInfo = pcall(function()
return BadgeService:GetBadgeInfoAsync(badgeId);
end)
if success then return badgeInfo; end;
return nil;
end)
-- Make iteration happen
for badgeName, badgeId in pairs(badges) do
local badge = doSomethingWithBade(badgeName, badgeId);
if badge ~= nil then
-- do stuff with the badge info
print(badge);
end
end
Anyway, this is code which is not tested, further the less this should work
You can do that, otherwise check out this part of the documentation.
In the example provided in the documentation you should do it like this
local BadgeService = game:GetService("BadgeService")
local Players = game:GetService("Players")
local badgeID = 00000000 -- Change this to your badge ID
local function onPlayerAdded(player)
-- Check if the player has the badge
local success, hasBadge = pcall(function()
return BadgeService:UserHasBadgeAsync(player.UserId, badgeID)
end)
-- If there's an error, issue a warning and exit the function
if not success then
warn("Error while checking if player has badge!")
return
end
if hasBadge then
-- Handle player's badge ownership as needed
end
end
-- Connect "PlayerAdded" events to the "onPlayerAdded()" function
Players.PlayerAdded:Connect(onPlayerAdded)
If this doesn’t work for you, you probably didn’t explain the whole picture, show some code, show some of your own research. Are there any other scripts running which you might have forgot about? Have you imported some kind of model with a nasty script in it?, at this point its a wild guess for me, I hope you figure it out. Cheers
What you can also do is check for all badges when they join the first time, save all badges that they own in a datastore and when rejoining, only fetch the badgedata of the badges they doesn’t own yet. Then you will have much less calls to the badgeservice
DataStoreService is also a service that can fail from time to time, especially with lots of data stored, and players can delete their own badges, which will cause inaccurate results.
This will also require server intervention. Right now I only use the client for this.
Isn’t there a risk for a 120 slots/indexes long dictionary to eventually exceed the datastore size limit?
You will never exceed the datastore limit, you can just make a row with key userid and value table of badgeid’s (for example {1,2,7,9}). Even with 1000 badges with length 8 you will never pass the limit.
Badge deleting is a thing, but since the player did achieve it, it doesn’t really matter if he owns it now or not.
What you are claiming about datastoreservive failing with lots of data stored is false. The amount of data stored doesn’t matter, and if datastoreservice is down all games are affected by it.
Next to that, badgeservice can also fail.
Question: why do you need to check 120 badges in the first place? Are those badges from different places, or are they from the game you are checking from?
Since I also need the badge description it could be problematic, also, the larger the data the more time it takes to load it. Although that might not be a big difference, not sure…
A GUI that lists all badges that the player has in the game. Badge hunting game.
I was thinking about this and reading through the other solutions people provided while working on my own game. You see. My new game is going to have a lot of generated stuff going on. The server needs to build my world for every new server. Sometimes this might take some time, but I don’t want the player able to play because the world is not loaded in yet.
Kinda similair story with your badges, you need your badges in order to play your game.
I know this sounds crazy, but a few things popped up in mind.
loading screen
* Yes, I know,… This doesnt cut down your loading time,
play with coroutines
The first one is obvious, the second one however, (No clue if this is going to work, aka not tested)
Look at the orignal code and the code that i added:
ORIGINAL
NEW
local BadgeService = game:GetService("BadgeService");
local badges = {
badge1 = 65465416,
badge2 = 56465456
}
local funtion doSomethingWithBadge(badgeName, badgeId)
local success, badgeInfo = pcall(function()
return BadgeService:GetBadgeInfoAsync(badgeId);
end)
if success then return badgeInfo; end;
return nil;
end)
-- Make iteration happen
for badgeName, badgeId in pairs(badges) do
coroutine.resume(coroutine.create(
function()
local badge = doSomethingWithBade(badgeName, badgeId);
if badge ~= nil then
-- do stuff with the badge info
print(badge);
end
end
))
end
I dunno if this solves the API limitation or if it makes it worse. Curious tho.
This might cutdown your loading time
I thought of dividing it into threads, but all this time I thought it fails because requests are sent too quickly.
It’ll work if the service is based on Request Count and not Request Speed. So it might reduce the time. That’s actually brilliant, I will try it , Thanks!
There’s already a 20 second loading screen , so that ain’t a very good solution.
I actually do this from the client, the service works with LocalPlayer.
It’s also brilliant to try it from the server. Perhaps there’s a limit on the Client to prevent Exploiter from Slowing down the service.
Thanks for the help! I’ll try that and let you know if it worked.
I felt like posting an update, as this is something that many games might need.
Two solutions that were ideal and worked:
Offered by @OofUndefined :
He offered to efficiently split the badges into many threads. It speeds up the process as UserHasBadgeAsync yields .
It worked very well , took around 40 seconds,but it was ideal and a good solution .
Partially suggested by @Abcreator, To use HttpService, with the Roblox Badges API:
This solution was actually brilliant. I’ve managed to get 70 Badges from1 Http request from this part of the API:
I got all badges from the game that were awarded to the player, and in no more than 20 seconds, I’ve received all badges that the player has, with only 2 Http Requests Per player.
Thank you so much, Abcreator and OofUndefined.
Both of your solutions work well
(120 badges in the Badge GUI, completely loaded, sometimes even before the loading screen finishes).