Wassup :DD you reading this. Today you’ll be learnin’ how to make a a somewhat safe badge system.
BEFORE we start. I’d recommended you atleast have some basic knowledge with coding in general. This might get a bit confusing if you’r just startin’ out.
Anyhow now when that’s out of the way let’s start
If you’re too lazy to read this tut: Badge Service - Roblox
Our first step will be to make a module. You can name it whatever you want. I’ll go with “Badge Service” because i like that name.
Second step will be setting up our code.
Now obviously. You dont have to add these comments like i’ve done. I just have them there to organize my code better.
Also you dont need the functions “Fetch/AttemptAward/AwardBadge”. You can use a normal pcall if you’d like. I just use these to make my code easier to read. Though i’d recommended you use these to follow along easily.
local Badge = {}
local Cache = {}
local Badges = {}
-- // Services
local BadgeService = game:GetService("BadgeService")
-- // End
-- // Funcs
local function Fetch()
end
local function AttemptAward()
end
local function HasBadge()
end
local function AddToCollection()
end
-- // End
-- // Methods
function Badge:LoadBadgesAsync()
end
function Badge:AwardBadge()
end
-- // End
return Badge
Alright DOPE. We now have the foundation up. Now we need to set up our parameters for our code this will give our functions the info they need to function properly.
local Badge = {}
local Cache = {}
local Badges = {}
-- // Services
local BadgeService = game:GetService("BadgeService")
-- // End
-- // Funcs
local function Fetch(PlayerId: number, BadgeId: number)
end
local function AttemptAward(PlayerId: number, BadgeId: number)
end
local function HasBadge(PlrBadges: {[string]: number}, BadgeName: string)
end
local function AddToCollection(PlrBadges: {[string]: number}, BadgeName: string)
end
-- // End
-- // Methods
function Badge:LoadBadgesAsync(PlayerId: number)
end
function Badge:AwardBadge(PlayerId: number, BadgeName: string)
end
-- // End
return Badge
NOW… Before we go any further. We need to set up our badges in the “Badges” dictionary. Add the badge name along with the id. Make sure they’re lower case in this case.
DONT use my badges btw. If you do that your code will error XD
local Badges = {
["100 wins"] = 19384757,
["10 kills"] = 1945886,
["5 deaths"] = 1838576
}
Alright. We’re now ready to start
First step will be to load all the player’s badges when they join. To do this we will have to call the method “LoadBadgesAsync()” along with their UserId as the argument.
local BadgeService = require(game.ServerScriptService.BadgeService)
game.Players.PlayerAdded:Connect(function(Player: Player)
BadgeService:LoadBadgesAsync(Player.UserId)
end)
function Badge:LoadBadgesAsync(PlayerId: number)
Cache[PlayerId] = {} -- // Create new table. This will store all our badges
local PlrBadges = Cache[PlayerId] -- // Get the dicitonary.
local Left: RBXScriptConnection = nil -- // For listening to when the player leaves.
Left = game.Players.PlayerRemoving:Connect(function(LeavingPlr: Player) -- // Assign it a connection.
if LeavingPlr.UserId == PlayerId then
Cache[PlayerId] = nil -- // Make sure to remove the players badge storage when they leave.
Left:Disconnect() -- // Also disconnect the connection so it doesnt take up memory.
Left = nil
end
end)
for BadgeName: string, BadgeId: number in Badges do
local OwnsBadge: boolean | nil = Fetch(PlayerId,BadgeId)
if OwnsBadge then
AddToCollection(PlrBadges,BadgeName)
end
end
end
We check the returned value(OwnsBadge) if its true. If it’s true(Player has the badge) we can add the badge name to the collection.
Though if didnt return true and nil instead we dont add it. As you can see from down below me. We’re only returning nil if something unexpected happened. Such as Roblox being down.
local function Fetch(PlayerId: number, BadgeId: number)
local Sucess: boolean, Owns: boolean | string = pcall(BadgeService.UserHasBadgeAsync,BadgeService,PlayerId,BadgeId)
if not Sucess then
warn("An unexpected error occured fetching badges: " ..tostring(Owns))
return nil
end
return Owns
end
Alright cool :DD we got loadin’ the players badges workin’ we can now continue to awarding the actual badges
Whenever you want to award a badge. Let’s say “10 kills” in this case. We need to call the method “AwardBadge()” along with the player’s userid as the first argument. And the badge name as the second argument.
For an example. I’ll be awarding the player the “10 kills” badge when they click a button.
local BadgeService = require(game.ServerScriptService.BadgeService)
local Detector: ClickDetector = game.Workspace.Button.Click
Detector.MouseClick:Connect(function(User: Player)
BadgeService:AwardBadge(User.UserId,"10 Kills") -- // Badge name isnt key senestive by the way.
end)
Now let’s set up the internal module functions.
local function HasBadge(PlrBadges: {[string]: number}, BadgeName: string)
if PlrBadges[BadgeName] == true then
return true
else
return false
end
end
local function AddToCollection(PlrBadges: {[string]: number}, BadgeName: string)
PlrBadges[BadgeName] = true
end
local function AttemptAward(PlayerId: number, BadgeId: number)
local Sucess: boolean, Awarded: boolean | string = pcall(BadgeService.AwardBadge,BadgeService,PlayerId,BadgeId)
if not Sucess then
warn("Couldnt award badge due to an unexpected error D:")
return nil
end
return Awarded
end
function Badge:AwardBadge(PlayerId: number, BadgeName: string)
local PlrBadges = Cache[PlayerId]
BadgeName = BadgeName:lower()
local OwnsBadge: boolean = HasBadge(PlrBadges,BadgeName)
if not OwnsBadge then
local BadgeId: number = Badges[BadgeName]
local WasArded: boolean = AttemptAward(PlayerId,BadgeId)
if WasArded then
AddToCollection(PlrBadges,BadgeName)
end
end
end
Now we’re basically done. You got somewhat of a safe badge system.
Also sorry if this was a bit advanced for anyone. I tried my best to make things easy/simple to follow along with.
If anyone has any sort of feedback good/negative. Make sure to leave them in toe replies. ALL feedback is very appreciated.
If you think anythin’ could have/be improved in this system. Also make sure to share it in the replies down below