BadgeService3 | Set up badges for free in your project!

Oh ok, then yes @motlopoway, you would have to use a for loop or keep that number somewhere for the :GetBadges(), since :GetOwnedBadges() returns an array, you can use # on it.

Your request was added to the milestones of this module.

@motlopoway also added that to milestones, some function could be useful.

2 Likes

(pool removed, just went with per-profile onBadgeAwarded event)

I actually forgot to talk about this, but I still recommend using :Delete() if you’re working with your own solution. In this case basic datastores, BadgeService3 currently yields for 5 seconds before garbage collecting the profile automatically. I still highly recommend that you do a DeepCopy of the profile.Data table before trying to save if you’re messing around with basic datastore use. This is not needed if you’re using a solution like ProfileService/DS2 which changes data as it changes.

1 Like

Shouldn’t it just be called BadgeService4?

That’s a bit much lol! I just call it a v2, BadgeService4 would sound weird. BadgeService3 already does, It should have been called BadgeService2 from the start to be honest.

2 Likes

Update released, 1.5.0

Changes:

  • :onBadgeAwarded(function(badgeId) RBXScriptSignal added. Will fire only when a badge is awarded.

  • New customizable settings! Look at these!

["usesBadgeImageForNotifications"] = false;
["isNotificationsDisabled"] = false;
["usesGoldBadgeNotification"] = false;
["defaultBadgeNotificationImage"] = "rbxassetid://6170641771";
["notificationDuration"] = 5;
["autoGarbageCollectProfileTime"] = 5;
["NotificationDescription"] = 'You have been awarded "%s"!';
["NotificationTitle"] = "Badge Awarded!"
  • New function added to BadgeService3, :SetGlobalSettings(SettingsTable), this function will change the settings you ask for!

  • New usable “variable” into badges, Image which can be set to a image id, not a decal id, and with the setting usesBadgeImageForNotifications enabled, it will use that as the notification image for that badge.

  • New function added :GetBadgeAmount() will return you the number of all badges.

  • :GetBadges() will now return the badges, and also the result from :GetBadgeAmount()

Customization highlights:

  • Disable notifications! isNotificationsDisabled
  • Add your own notification system if you want! using :onBadgeAwarded()
  • Use the default, gold color for the badge notification! usesGoldBadgeNotification
  • Change the default notification image to whatever you want! defaultBadgeNotificationImage
  • Use specific badge images! usesBadgeImageForNotifications
  • Change the notification’s text, and description! NotificationDescription and NotificationTitle
  • more…

If you use BadgeService3, please follow the update topic.
That’s where updates will be kept now.

1 Like

Here’s an tutorial for anyone using DataStore2. I will also be making a dedicated tutorial on how to use it with Profile Service. There are some extra tips inside this video as well.

2 Likes

Not gonna switch from old version because profile service/DS2 is too confusing to me. Old badgeService3 has force save which I can use for my autosave script and it is more friendly to me.

Idk, if this would work but would it be possible to use them across places, if you got a badge in one place? Could you script it to give you a tool in another?

Here’s an example of how this module can be used with the Nevermore Engine:

local Nevermore = require(game:GetService("ReplicatedStorage"):WaitForChild("Nevermore"))

local DataStoreService = game:GetService("DataStoreService")
local Players = game:GetService("Players")

local PlayerDataStoreManager = Nevermore("PlayerDataStoreManager")
local badgeService3 = Nevermore(game.ReplicatedStorage.BadgeService3)

local dataStoreManager = PlayerDataStoreManager.new(DataStoreService:GetDataStore("PlayerData"), function(player) return tostring(player.UserId) end)

function loadBadges(player, store)
	return store:Load("Badges", {}):Then(function(data)
		return badgeService3:LoadProfile(player, data)
	end):Catch(function(...)
		warn("Failed to load", ...)
	end)
end

function handlePlayerAdded(player)
	local dataStore = dataStoreManager:GetDataStore(player)
	local badgeStore = dataStore:GetSubStore("BadgeStore")
	
	loadBadges(player, badgeStore):Then(function(profile)
		delay(5, function()
			if profile.Data then
				profile:AwardBadge("Welcome")
			end
		end)

		profile:onUpdate(function()
			badgeStore:Store(profile.Data)
		end)		
	end):Catch(function()
		player:Kick()
	end)
end

Players.PlayerAdded:Connect(handlePlayerAdded)
for _, player in pairs(Players:GetPlayers()) do
	handlePlayerAdded(player)
end
1 Like

You don’t actually need to use any of these two services, you can make your own data saving solution, in this case even integrate it into your old BadgeService3 solution, how ever it is a big more tricky to do so with BadgeService3 v1, it isn’t that hard but it is a bit harder. I can make a v1 handler for you if you like, it shouldn’t be that hard to convert your scripts into.

Also thanks for letting me know you used BadgeService3 v1.

Also I don’t know what you mean by force save? :thinking:

The old version has :SavePlayerData(plr) function or something like that, not sure but theres a function to save player data manually

Speaking of which I think that you should keep the old version as well (and the old documentation) because its more easier and simple to use. The old one is just better for me because it does the saving and loading automatically. Or make the v2 more simple to use

The biggest problem for me is that it’s too complex to use for “crappy” develolers like me.

You’re not crappy… You’re a beginner, when I made that I was probably about your skill.

I moved away from BadgeService3 v1 because of a bunch of problems and this, eventually does the same except it doesn’t save, to learn it is easier, it’s just harder to set up. Anyways you can message me if you want a handler for it. I can make it act just like BadgeService3.

3 Likes

Looks clever. Quick question:

Is this badge just a notification, or one that appears on there profile / Inventory?

Thank you.

It uses datastores, so no. It doesn’t show up on your profile.


3 Likes

BadgeService3 has been updated to 2.0.0.

This release is more so a bug fix, and optimization and memory leak fix. If you use it, please update it.

The Signal API here was updated / replaced, so it fixes some issues from the past.
You shoudn’t have any problems migrating to this new version, simply get your ‘Badges’ sub-module, delete the rest, and replace the old stuff with the new code and you should be fine.

You can now use :Connect() on the Signals, like: badgeProfile.onBadgeAwarded:Connect(), and also you can still use badgeProfile:onBadgeAwarded().

You can download it from here:

https://www.roblox.com/library/6525256722/BadgeService3

3 Likes

BadgeService3 v2 was updated to 3.0.0

Updating is recommended.

There were some updates on which no one was particularly notified of, there were no releases as they were minor updates.

This reply will show significant changes in the module, other things are simple code changes which improve things, but don’t change behaviour.

The updates that I will mention below are changes which can break your current installation of BadgeService3, which might require you to re-write certain parts of your scripts.

If you specifically messed with .Data then, please read below.


This update is a complete re-write, and with it, there are some behaviour changes, these can break your scripts if you messed with .Data specifically.

Should I worry?

If you did one of these, you should look into re-writing some code if needed.

  • If you used .Data to check for if someone owns a badge or anything.
  • If you awarded badges through .Data;
  • If you mutated .Data at all;
  • If you saved .Data together with a bunch of other data. In the sense of literally mixing everything, if you had a ‘partition’ like PlayerData.Badges, you’re safe from this.

What changed with .Data?

.Data is NOT a dictionary anymore. Before it was a dictionary with this base in mind:

{
    [badgeId] = true;
}

Now it’s an array, like this:

{
    badgeId1,
    badgeId2
}

Why was this changed?

I should not have done it with a dictionary anyways, I did it with dictionaries instead for the first time because that would mean that there’s no duplicates, which isn’t an issue unless you handled it poorly.

One thing this helps with, is converting from older data from the v1, since it follows the same format.

Data in datastores are saved in a JSON string, and using arrays is WAY less costly,
It can save up to about 6 characters for each badge owned!

Example:

Old - Dictionary

["WelcomeBadge": true, "10Kills": true, "20Kills": true]

New - Array

["WelcomeBadge", "10Kills", "20Kills"]

Does past data get automatically converted?

The answer to that is yes! BadgeService3 will automatically convert the data if needed.

Data can only get converted when you call any of these functions:

  • :AwardBadge
  • :RemoveBadge
  • :OwnsBadge
  • :GetOwnedBadges

This conversion is only done once, and only if needed.

The table reference to .Data is changed to the converted data, and .OnUpdate is fired.

I haven’t done any of that, what do I need / should change?

Not much, most of the changes are actually syntax changes.
With that said, events are now PastalCase. You can still use camelCase, but the right way now is .OnUpdate, and not .onUpdate.

Here’s the most noted changes:

  • .Data is now an array.

  • :WaitForProfile doesn’t use Heartbeat anymore, instead it will check whenever a new badge profile is loaded, and check if it’s the player you’re checking.

  • :GetOwnedBadges is now faster.

There really aren’t many, it’s mostly a optimization and code organization update, but it helps the future of the module.

3 Likes

Update 3.0.0 > 3.2.0


  • Updated Signal Class
  • Fixed issue where having a string url instead of a number assetId in Badge.Image would not allow notifications to use that Badge’s Image.

Now, I also made all settings full-on PascalCase, therefore if you messed with any settings, please change it so that your code is using PascalCase on them.

3 Likes

The problem with this is that does it actually display the badge on the user’s profile?

No it does not. It is just a replacement for people without funding and also engages the player more.

3 Likes