LeaderstatService | Making leaderstats easier than they already are

LeaderstatService


Tutorial

Making leaderstats is pretty simple, but the code can also look pretty ugly.

Well, today you can turn this:

game.Players.PlayerAdded:Connect(function(plr)
	local Cash = Instance.new("IntValue")
	Cash.Name = "Cash"
	Cash.Value = 1000
	Cash.Parent = plr
end)

Into this!

game.Players.PlayerAdded:Connect(function(player)
	LSService:Create(player, "Cash", "IntValue", 1000)
end)

It’s extremely beginner friendly and easy to use, here’s how it works:

	LSService:Create(
		player, --// The player you want to give the leaderstat
		"Cash", --// The name of your leaderstat
		"IntValue", --// The class of your value (IntValue, StringValue, ect.)
		100 --// Value of your leaderstat [OPTIONAL: Defaults to 0]
	)

And - it also comes with a delete function! (if you need to delete your leaderstat)
Here’s how that works:

	LSService:Delete(
		player, --// The player that owns the leaderstat
		"Cash" --// The name of the leaderstat.
	)

Extra Information

It comes with server sided output logging, like this:
:white_check_mark: Created new leaderstat for fvazer: Cash
:white_check_mark: Delete leaderstat ‘Cash’ for fvazer

These can be disabled by entering the module and setting debugmode to false at the top.

Error output logging cannot be disabled.


Get it!

Roblox

Get the module here and insert it into ServerStorage.

File

LeaderstatService.lua (1.3 KB)

GitHub

13 Likes

Update #1

  • Now returns the leaderstat instance when Create is called.
2 Likes

Pretty interesting. What features will you add to this that will make it more viable to use rather than creating the basic leaderstats script like in the beginning of the post?

1 Like

Well, I want to keep this module pretty simple and beginner friendly so I wont be adding anything extremely complex.

I might add a simple :EditValue function instead of the Developer needing to do player.leaderstats.cash.value

2 Likes

Does this system save using datastore2?

It doesn’t save anything, it’s simply just a wrapper to create leaderstats.

However saving it shouldn’t be too hard if you use a module like DS2 or ProfileService.

Do you have any plans to add saving? If so could you notify me when you do?

I have created a pull request for this.

2 Likes

Could you possibly add chaining?
Would make it easier for people to create several different values without repeating the same thing.

(If you’re going to do this, add a getter function also)

game.Players.PlayerAdded:Connect(function(player)
	LSService
        :Create(player, "Cash", "IntValue", 1000)
        :Create(player, "XP", "IntValue", 0)
end)

Even having some sort of better syntax.

local Contructor = LSService.new()

game.Players.PlayerAdded:Connect(function(player)
    Constructor.make(player) {
         ["Cash"] = {
              Value = 1000,
              Type = "IntValue"
         }
    }	
end)
Simpler
--Just making an array, calling a function that was returned, and making that array an argument for the function. Would even promote organization because you can have a template variable.

local Contructor = LSService.new()

game.Players.PlayerAdded:Connect(function(player)
    Constructor.make(player)({
         ["Cash"] = {
              Value = 1000,
              Type = "IntValue"
         }
    })
end)

Well, that’s my two cents. Nice job on this module.

1 Like

Even though I could create a module that does this in a matter of 10 minutes, no noob could, so I appreciate this module for making noob’s developing experience easier.

If this module included data saving, I was instantly use it for all my projects that need saving leader stats.

Also, how would I use the :EditValue method in a script that doesn’t have the leaderstat defined? For example, if I had a server script that was this:

game.Players.PlayerAdded:Connect(function(player)
	LSService:Create(player, "Bobux", "IntValue", 0)
end)

and another script inside of a part like this:

script.Parent.Touched:Connect(function(hit)
    if hit.Parent:FindFirstChild("Humanoid") then
        local plr = game.Players:GetPlayerFromCharacter(hit.Parent)
        plr.leaderstats.Bobux.Value += 1 --// How would I use :EditValue here?
    end
end

Great job!

1 Like

Sure, I’ll possibly add saving in the future using ProfileService, since I’m more familiar with that.

I’m not too confident with adding this, how would I? I’m not an expert at modules, just basic stuff.

Since I don’t know how to use OOP, it’d probably be like this:

LSService:SetValue(player, statName, newValue)
1 Like

OOP wouldn’t work regardless, your method would work the best, but you would need to have a table of all leaderstats if you were to do that.

Even with the :EditValue method, it would probably be the same amount of bytes as just doing it the old fashioned way.

Still, a pretty good fix.

or, what you could do, for edit value, is look through the player’s leaderstat folder, find the value with the same name (or id) as the one in the second parameter of :EditValue method, which is probably a better way to do it.

Speaking of IDs, you could give each leaderstat an ID, and you can reference it later.

1 Like

I have a minor suggestion, not sure if you’re 100% up to doing this, but you could incorporate a function called .CreateLeaderstatFromTable(TableName) and it would loop through the table of specified names with their starting amounts, etc. That way, all someone has to do is create one table, use the batch function that was created to save them extra lines of code.

There is definitely better ways of doing this but that is probably the most beginner friendly one I got.

I forgot to mention use case, it’s so you don’t need to spam :Create so many times.

2 Likes

Why not automatically detect the type instead of having to define it yourself?

1 Like

Well its really easy:

Just returning self will do:

image

Not sure if there are any bad sides to this but please tell me of them if there are.

2 Likes

Hey guys, I’m currently rewriting this module with automatic saving and stuff.

It should be out tommorow in its testing stages!

StatService

Complete rewrite

Fixed your code. Next time don’t use abreviations.

local debugmode = true

--// Leaderstat Service
--// Created on 13/11/2021 by Endernymous edited by chainreactionist on 20/11/2021
local module = {}

function module:Create(Player: Player, Name: string, Type: string , Value: Instance| string | number | Ray | boolean | CFrame | BrickColor | Color3 | Vector3)
	if Player:FindFirstChild("leaderstats") then
		-- already exists
		local instance = Instance.new(Type)
		instance.Name = Name
		instance.Value = Value or 0
		instance.Parent = Player:FindFirstChild("leaderstats")
		
		if debugmode then
			print("? Created new leaderstat for "..Player.Name..": "..instance.Name)
		end
		
		return instance
	else
		-- doesn't exist
		local lsfolder = Instance.new("Folder")
		lsfolder.Name = "leaderstats"
		lsfolder.Parent = Player
		print("? Created "..Player.Name.."'s 'leaderstats' folder.")
		
		local instance = Instance.new(Type)
		instance.Name = Name
		instance.Value = Value or 0
		instance.Parent = Player:FindFirstChild("leaderstats")
		
		if debugmode then
			print("? Created new leaderstat for "..Player.Name..": "..instance.Name)
		end
		
		return instance
	end
end

function module:Delete(Player, Name)
	if Player:FindFirstChild("leaderstats") then
		if Player.leaderstats:FindFirstChild(Name) then
			Player.leaderstats[Name]:Destroy()
			
			if debugmode then
				print("? Deleted leaderstat '"..Name.."' for "..Player.Name)
			end
		else
			warn("? Failed to delete leaderstat for "..Player.Name..": User has no leaderstat called "..Name)
		end
	else
		warn("? Failed to delete leaderstat for "..Player.Name..": User has no 'leaderstats' folder.")
	end
end

return module

Didn’t test it tho if u run into issues be sure to let me know :wink: