ProfileService Tutorial!

cause there are other things in ProfileService

ah yes, condescension is something i look for in all of my tutorials.

then just don’t make a tutorial

1 Like

(Opinion time here)

Guys, as all of you said, it is best to use what you need and what works well for your project.

I am looking to change to ProfileService since I am reading so many positive things about it, such as being fast and super reliable. But after all, it is the same DataStoreService with better-founded functions, basically added code to make it more secure and prevent glitches and errors which is always good ngl. For all of the people seeing this thread, if you have a small game that only stores a couple of values, not pets or any huge inventories, I would say the classic DataStore is fine as long as you don’t call it every 5 seconds.

You could obviously make your own module, as a lot of big games do btw to prevent exploits, I think I am going to stick to this path, a custom module since I have already added a lot of code to my datastore system. Takes time and skill as a lot of people said, but it’s a learning experience with a prize at the end. I am personally storing right now for my players, 3 classic values (Coins, Gems, Rebirths), and an inventory that stores Trails (they have names, xp, level, multiplier, rarity stored for each of them). I’ve only had one data loss and that was when I quit the studio while the data was loading (that was when I first coded my datastore), oops.

Having to change all of the system that loads and saves to a totally different one (and having to adapt the items) takes much more time than adding features to a one that works but can maybe fail if I add more stuff. If I knew about this when I started I would 100% go for ProfileService. At this point though, it is just better to code a custom one (and also learn a bunch of new stuff) and also take some code from ProfileService (give credit obv lol) and model it.

Thanks to anyone that took the time to read this post and I hope that you took a decision for your game, if you’ve already put a lot of time into your game, take how much you need to do it right. :heart:

2 Likes

You should only call DataStoreService when a player joins and leaves, I have no idea why someone would have to call DataStoreService all the time (which is what you might be implying).

But for anyone else reading this, if you’re just experimenting and learning, just follow from a regular tutorial. But I would suggest getting used to ProfileService as you will need it someday. Now some people might say making a custom data store system is better, although it might be a great learning experience, I still suggest focusing on being able to make a fun popular game instead of going toward the technical stuff. Even I never learned how to make my own custom data store system yet; because I don’t need to!

1 Like

Agreed. I believe as long as you have the time, it is great to learn how it works and experiment with different techniques, the only problem is finding the right tutorial, it is a harder task than it should be nowadays, everyone is after subs and likes.

You should only call DataStoreService when a player joins and leaves, I have no idea why someone would have to call DataStoreService all the time (which is what you might be implying).

Some people tend to save their player’s data very often or whenever it changes which is terrible.

1 Like

there isn’t <Profile>:SetAsync()

Hey anyone, is there a way to reverse data loss?

1 Like

Sadly there isn’t, but if your game is small enough you can give back people’s stuff, just make sure you’re careful to not give anyone bizarre amounts of stats. When my game was experiencing data loss, I did exactly that. But after implementing a data store system with no data loss, people will forget about the data loss you had in no time.

Hey, I was wondering - how do you check if a profileservice data value has changed? I just wanted to know because im using a remote to communicate what the server knows about that player’s data to the UI.

1 Like

Yeah so whenever it’s changed on the server, you want to fire that change to the client. To detect its been changed though, you need to use a callback function in a module script or regular script (a module script keeps it more organized)

local module = {}
local callbacks = {}

module.changedValue = function(name)--the name of the bind you want to change
       callbacks[name]()--running the function
end

module.addCallback = function(bind,func)
       callbacks[bind] = func
end

return module

--in another script

module.addCallback("Coins",function()
       --what you want ran when Coins get changed
end)

--you can also set it up this way too

function changeCoins()

end

module.addCallback("Coins",changeCoins)

There’s different ways to set this up, so there isn’t a correct way to do this.

1 Like

Thanks very much for this but i managed to find a function that had been implemented called :KeyInfoUpdated.
But I’m experiencing an error where the Profiles table is apparently nil, and gives the error ServerScriptService.PlayerConfig.PlayerValues:10: attempt to index nil with Instance
Here’s my code (its only like 12 lines)

local PlayerDataHandler = require(game:GetService("ServerScriptService"):WaitForChild("ProfileSystem"):WaitForChild("PlayerDataHandler"))


game:GetService("Players").PlayerAdded:Connect(function(player)
	if player then
		local landslot = Instance.new("NumberValue")
		landslot.Parent = player
		landslot.Name = "landslot"
		landslot.Value = 0
		local profile = PlayerDataHandler.Profiles[player] -- this is line 10, apparently Profiles is nil?
		if profile ~= nil then
			profile.KeyInfoUpdated("megabytes"):Connect(function()
				print("megabytes changed!")
			end)
		end
	end
end)

I’m a bit confused on this…

1 Like

do this

PlayerDataHandler.Profiles[player.UserId]

It happens to me too sometimes lol

1 Like

ah, I completely forgot it relied on userId…
im an idiot.

I updated the code to this and I still get the exact same error?

game:GetService("Players").PlayerAdded:Connect(function(player)
	if player then
		local landslot = Instance.new("NumberValue")
		landslot.Parent = player
		landslot.Name = "landslot"
		landslot.Value = 0
	end
end)

while true do
	for _, player in game:GetService("Players"):GetPlayers() do
		local profile = PlayerDataHandler.Profiles[player.UserId] -- this line again
		if not profile then continue end
		print(profile.Data.megabytes)
		profile.KeyInfoUpdated:Connect(function()
			print("profile updated")
		end)
	end
	
	task.wait(1)
end

How can I random generate a value without it being shared to every player? My problem is everytime I generate a new value to a stat, it’s the same for everyone.

function DataHandler:RandomItemFromTbl(tbl)
	local TotalWeight = 0

	for Piece, Weight in pairs(tbl) do
		TotalWeight = TotalWeight + Weight
	end

	local Chance = math.random(1, TotalWeight)
	local Counter = 0
	for Piece, Weight in pairs(tbl) do
		Counter = Counter + Weight
		if Chance <= Counter then
			return Piece
		end
	end
end

function DataHandler:characterSetUp(player)
	DataManager.Profiles[player].Data = DefaultStats --I use this so it resets everytime for rerolls
	if DataManager.Profiles[player].Data.IsFirstLoad ~= true then
		DataManager.Profiles[player].Data.IsFirstLoad = true
		if DataManager.Profiles[player].Data.Race == "None" then
			local newRace = DataHandler:RandomItemFromTbl(Info.Races)
			DataManager.Profiles[player].Data.Race = newRace
		end
	end


end

local function playerAdded(player)
	local profileData = ProfileStore:LoadProfileAsync("Player_"..player.UserId)

	if profileData ~= nil then
		profileData:AddUserId(player.UserId)
		profileData:Reconcile()

		profileData:ListenToRelease(function()	
			DataManager.Profiles[player] = nil
			player:Kick("Data error at releasing")
		end)

		if player:IsDescendantOf(game.Players) then
			DataManager.Profiles[player] = profileData
			DataHandler:characterSetUp(player)
			print(DataManager.Profiles[player].Data.Race)
		else
			profileData:Release()
		end

	else
		player:Kick("Data error")
	end

end



function DataHandler:Init()
	for _, player in game.Players:GetPlayers() do
		task.spawn(playerAdded,player)
	end
	game.Players.PlayerAdded:Connect(playerAdded)

	game.Players.PlayerRemoving:Connect(function(player)
		if DataManager.Profiles[player] ~= nil then
			DataManager.Profiles[player]:Release()
		end
	end)
end

the table:

module.Races = {
	["test1"] = 20,
	["test2"] = 20,
	["test3"] = 20,
	["test4"] = 20,
	["test5"] = 20,
	["test6"] = 20,
	["test7"] = 20,
	["test8"] = 20,
}

Edit: DataHandler:characterSetUp(player) only runs once?