Can You Make A Leaderstats Then Save Player Data In Server Storage?

Hello there fellow developers,

I dont know if the topic is appropriate to the category but, I have a problem. I want to make a leaderstats that save player data INSIDE server storage. I want to make a leaderboard that cannot be access by clients(I want to make a non seen, secure leaderboard if it’s not clear). I dont know how to make it or if it’s possible because I haven’t got to advanced scripting. Any suggestions in the comments will be accepted.

1 Like

To set everything up:

  1. Put the script in the serverscriptservice.
  2. Create a folder in the ServerStorage called 'PlayerData` (this is where a folder containing the player’s data is going to be made when the data loads from the datastore.)
  3. Create a remote function in the replicated storage called getData this is how the client gets data from the datastore.
local DatastoreService = game:GetService("DataStoreService")
local myDataStore = DatastoreService:GetDataStore("Saves_Version_1") 

--this is a list of data that can't be shared with the client
local unsharableData = {"numResets"}

--converts the data to a table to allow it to be saved in the datastore
function serializeData(player)
	local data = {}
	local playerFolder = game.ServerStorage.PlayerData[player.Name]
	
	for _, child in pairs(playerFolder:GetChildren())do
		data[child.Name] = child.Value
	end
	
	return data
end

--loads the players data from the datastore
function loadDataFromDatastore(player)
	--create a folder/values for the players's data
	local playerFolder = Instance.new("Folder")
	playerFolder.Name = player.Name
		
	local numResets = Instance.new("IntValue")
	numResets.Parent = playerFolder
	numResets.Name = "numResets"
	
	local coins = Instance.new("IntValue")
	coins.Parent = playerFolder
	coins.Name = "Coins"
	
	playerFolder.Parent = game.ServerStorage.PlayerData
	
	-- loadas the players data from datastore
	local data
	local success, err = pcall(function()
		data = myDataStore:GetAsync(player.UserId) or {}
	end)
	
	--if the datastore got the data successfully, set the data in the folder to be the data from the datastore 
	if success then
		print("data has successfully loaded for " .. player.Name)
		numResets.Value = data.numResets or 0 --if the player hasnt played before, give them the default resets value of zero
		coins.Value = data.Coins or 5 --if the player hasnt played before, give them the default coins value of 5
	else
		warn(err)
	end
	
	return playerFolder
end

--when this function is called, it converts the players data to a table and saves that table to the datastore
function saveDataToDatastore(player)
	local data = serializeData(player)
	local success, err = pcall(function()
		myDataStore:SetAsync(player.UserId, data)
	end)
	
	if success then
		print("data has successfully saved for " .. player.Name)
	end
	--print out an error if the data didnt save succesfully 
	assert(success, err)
end

------------------------------------------------------------------------

--loads the players data when they join the game
game.Players.PlayerAdded:Connect(function(player)
	local playerFolder = loadDataFromDatastore(player)
end)

--saves the data when the player leaves the game
game.Players.PlayerRemoving:Connect(function(player)
	saveDataToDatastore(player)	
end)

--save everyones data when the game shuts down
game:BindToClose(function()
	for _, player in pairs(game.Players:GetPlayers())do
		saveDataToDatastore(player)
	end
end)


-- use this remote function to get data from the client. 
-- if the data theyre trying to get is not in the `unshareableData` table, then return that data
-- otherwise, return a string that says the data could not be shared. 
-- eg, the player can see how many coins they have but they cant see their number of resets
game.ReplicatedStorage.getData.OnServerInvoke = function(player,requestedDataName)
	local canShareData = not table.find(unsharableData, requestedDataName)
	local playerFolder = game.ServerStorage.PlayerData[player.Name]
	
	if canShareData then
		return playerFolder[requestedDataName]
	else
		return "DATA COULD NOT BE SHARED TO CLIENT " .. requestedDataName
	end
end

Comments explain what everything does, but message me if you have any more questions.

8 Likes

I will but, please wait I have to do something.

@YXFrosty are you looking for a leaderboard at Leaderboard - Roblox that is created by @Roblox?

Hold on :v
What does this mean? That DataStore is not a good way to store player’s data?.. I dont understand what means “Store data in Server Storage” :v

So… DataStoreService is able to work from LocalSctipts?.. So a player can change the DataStore values as exploit?.. :confused:

@Dev_Peashie same i don’t understand what it means. :face_with_raised_eyebrow:

2 Likes

@VERIFlBLOX I have updated the title. Do you understand it now?

Nope… DataStore service is only accesible from Scripts IN server… theres not way that Clients can change values if you are using DataStoreService. DataStoreService | Documentation - Roblox Creator Hub

So, I thinks there’s no need for you to find a way to save data inside Server Storage… I don’t even know if saving “tables” or something in there would be a nice idea or possible :v

Well I am making an anti exploit script that if a player got reseted by the server 3 times, they would get kick. If the player have been kick 3 times by the server, they would get ban.

Hm…, interesting. we will wait what the other developers would say.

So you want to Keep the Ban List secure from being changed by Clients?

I still think that DataStoreService still your friend :3
But yeah, lets see what experienced devs think about this

Just don’t put the “TimesKicked” value in the leaderstats and players won’t be able to see it by any normal means.

@YXFrosty Yes i understand now.

There is no reason to put the PlayerData folder in ServerStorage, you can store it in ReplicatedStorage instead.

1 Like

I dont really see why this would be needed since most of the time you need to access your data somehow through the client.

While this IS Possible, I don’t really see a reason as to why you would have your data sit in ServerStorage?

There is some reason why I want it to be in Server Storage. The reason is because I want it to be secure. I’am making this for an anti cheat. I thought about this: “What if exploiter can change the value”. Therefore I need this. They can just change the value so they will NEVER get ban.

The Server will not detect the change because the Client is changing it for themselves ONLY.

An Anti Cheat should be running on the server so I dont see a reason as to why it would be hidden in ServerStorage.

oh…, I didn’t think about that. I thought you can change value… Well lesson learn now I’m getting smarter. Thank for the info then I would never know if you can’t change the value.

2 Likes

Sorry, this is really late and may not be helpful anymore, but–

If you want to store client data, it’s a good idea to do it in ServerStorage or ServerScriptService. Do not store it in ReplicatedStorage – clients can access replicated storage, so data can be easily changed there. SS and SSS can only be accessed by the server.

DataStore is also a reliable and secure way to store player data, but it has some limitations. There is a limit to the amount of requests you can send in a certain amount of time, so if you are changing values frequently, it’s better to store the values in SSS and save them to datastore when a player leaves the game.

You may store your data in the replicated storage without having to worry about hackers changing the values. They can view the values but they can’t change it on the server. Your data is safe from hackers either way.

2 Likes