How to make a somewhat good badge system(OUTDATED)(For beginners)

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

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 :slightly_smiling_face: 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 :smiley:

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

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

5 Likes

There are a Couple of issues, and some ways to simplify code that I would Like to point out.


For the First Part, you should make your tables Accessible outside the ModuleScript, this is so when the Person using this wants to do something with these Data Holders, they could:

local module = {}

module.Badge = {}
module.Cache = {}
module.Badges = {}
-- makes them accessible outside the Script
local BadgeService = require(game.ServerScriptService.BadgeService)

print(BadgeService.Cache, BadgeService.Badges) -- "{} {}" (nothing is currently inside)

Looking at this, it doesn’t make sense for you to be declaring Variables under certain classes, the code will already know what it is if you type in the arguments correctly, plus, the Script wouldn’t know that it IS the correct class because you are just making it assume that it is, you should instead check if the item actually is what it is rather than assuming, otherwise your code will have problems.


This isn’t a good system as everytime a Player joins, it would create a new Event to fire for those Players, Instead it would be faster, and way more efficient to do:

game.Players.PlayerAdded:Connect(function(player)
    -- Get Badges Here
end)

game.Players.PlayerRemoving:Connect(function(player)
    -- clear Badges here
end)

The Code will run for everyone, and not just for you,
PlayerAdded and PlayerRemoving run when a Player joins or leaves.
The code you provided will fire the Event for how many Players are in the game which may cause performance issues depending and the Amount of Players in game, and the amount of tasks the code is doing.


local Bool = (PlrBadges[BadgeName] == true) -- returns a Boolean (true or false)
return Bool -- Literally the exact same thing

if not Sucess then -- misspelled "success"
return -- does not require nil
end

4 Likes

Thanks for the feedback its really appreciated :raised_hands:i’ll make sure to update this tutorial and the module

3 Likes