How would I make a star save system like in adventure forward two?

What I want to achieve: I want to make a collectable item that when collected, adds on to the leaderboard. If you already collected the item and you collect it again, it won’t add on to your leaderboard.

My issue: I made a similar post on this in the past. I got an answer but didn’t understand it, so I tried to reply to the guy who gave me the answer but got no response. He said that I could make a table and check the datastore whenever the player touches/ collects the item in order to see if they got the item or not

solutions I’ve tried so far: I tried making an item that adds on to your leaderboard if you don’t have any items and won’t add on to your leaderboard if you have any items. I duplicated the item and play tested it and it worked! My problem is that it’s unorganized (I have to make another leaderboard per collectable item). This can work in the longrun if the player ignores the messy leaderboards, but I want it to be more organized. The script I used in order to make my “sorta working” script is from the solution of this post [FIXED] How to make a coin disappear only for one player?

Bonus help: This would be a helpful additional answer, but isn’t the main one I’m looking for, so you don’t have to answer this upcoming question, but I also want to make your leaderboard data save when you go to other places using teleport service.

this is the script I’m using

local debounce = false
local db=true
local remote = game.ReplicatedStorage.MaterialEvent 
game.Players.PlayerAdded:Connect(function(p)
	Instance.new('Folder',p).Name='leaderstats'
	Instance.new('IntValue',p.leaderstats).Name='MaterialOne'
end)
script.Parent.Touched:Connect(function(hit)
	local plr = game.Players:GetPlayerFromCharacter(hit.Parent)
	if plr and db then
		if plr.leaderstats.MaterialOne.Value == 0 then
		if debounce == false then
			debounce = true
			db = false
			plr.leaderstats.MaterialOne.Value = plr.leaderstats.MaterialOne.Value + 1
            		remote:FireClient(plr, script.Parent)
			db = true 
			wait(9000000)
			debounce = true
			if plr.leaderstats.MaterialOne.Value == 1 then
			if debounce == false then
			debounce = true
			db = false
			plr.leaderstats.MaterialOne.Value = plr.leaderstats.MaterialOne.Value + 0
            		remote:FireClient(plr, script.Parent)
			db = true 
			wait(9000000)
						debounce = true
						end
		end
		end
		end
		end
	end)


local remote = game.ReplicatedStorage.MaterialEvent

There’s a ton of conditional checks that you’re implementing here, what you could do instead is implement the leaderstats inside ServerScriptService, and reference the Star Giver Script inside the Star

--Star Part
local DataService = game:GetService("DataStoreService")
local StarData = DataService:GetDataStore("PlayerStats")

local Star = script.Parent
local DB = false
local remote = game.ReplicatedStorage:WaitForChild("MaterialEvent")

Star.Touched:Connect(function(Hit)
	local plr = game.Players:GetPlayerFromCharacter(Hit.Parent)
	
	if plr and not DB then
		DB = true
		
		if plr.leaderstats.MaterialOne.Value == 0 then
			plr.leaderstats.MaterialOne.Value += 1
			remote:FireClient(plr, Star)
            StarData:SetAsync(plr.UserId, plr.leaderstats.MaterialOne.Value) --We want to save this as soon as the player gets the star
		end
	end
end)

I suppose you just could call SetAsync whenever a player does not have the specific star

You could name everything a different name and make it an for i,v in pairs()
add to plr
save in table the values and then add back to plr, and if plr has the things then it deletes the things for plr by using remoteevents.