Saving a value through datastore

So this is not about leaderstats data but saving data from previous sessions. If a player has a title equipped and they leave, the next time they join, the same title should be located on their avatar. Another example would be pets. If a player has a pet equipped, the next time they join, the pet should already be sitting next to their avatar.

So I am using this script in serverscriptservice to create leaderstats and values. In the script, it creates the values previousstyle and previoustitle. I want previoustitle to equal the text on top of the character’s head and then save that value when the player leaves. Here is my script:

local dss = game:GetService("DataStoreService")
local ds = dss:GetDataStore("DATA")
local tools = game.ReplicatedStorage:WaitForChild("Tools")
local titles = game.ReplicatedStorage:WaitForChild("Titles")




function saveData(plrLeaving)
	if not plrLeaving:GetAttribute('DataSuccess') then
		return
	end
	local ownedTools = {}
	for i, tool in pairs(plrLeaving.OwnedTools:GetChildren()) do
		table.insert(ownedTools, tool.Name)
	end
	local ownedTitles = {}
	for i, title in pairs(plrLeaving.OwnedTitles:GetChildren()) do
		table.insert(ownedTitles, title.Name)
	end

	local title;
	pcall(function()
		title = plrLeaving.Character.Head.NameTag.Title.Text
	end)

	local output = {
		Titles = ownedTitles,
		Tools = ownedTools,
		Coins = plrLeaving.leaderstats.Coins.Value,
		Wins = plrLeaving.leaderstats.Wins.Value,
		Skips = plrLeaving.leaderstats.Skips.Value,
		Style = "", -- BE SURE TO SAVE THE STYLE!
		Title = title,
	}

	local success, err = pcall(function()
		ds:SetAsync(plrLeaving.UserId, game.HttpService:JSONEncode(output))
	end)
end

game.Players.PlayerAdded:Connect(function(plr)


	local toolsOwned = {}
	local titlesOwned = {}
	local style = ""
	local title = ""
	local coins = 0
	local wins = 0
	local skips = 0

	local packedData;
	local s, err = pcall(function()
		packedData = ds:GetAsync(plr.UserId)
	end)

	if s then
		plr:SetAttribute('DataSuccess', true)
	else
		print(tostring(err))
	end

	if packedData then
		local s = pcall(function()
			packedData = game.HttpService:JSONDecode(packedData)
		end)
		if typeof(packedData) == 'table' then
			titlesOwned = packedData.Titles or titlesOwned
			toolsOwned = packedData.Tools or toolsOwned
			coins = packedData.Coins or coins
			wins = packedData.Wins or wins
			skips = packedData.Skips or skips
			title = packedData.Titled or title
		else
			plr:SetAttribute('DataSuccess', false)
		end
	end


	if not plr:GetAttribute('DataSuccess') then
		-- notify the player that their data did not load successfully.
		local msg = Instance.new('Message')
		msg.Name = '__ALEXSMESSAGE'
		msg.Text = 'Failed to load your data. Please rejoin.'
		msg.Parent = plr:WaitForChild('PlayerGui')
		game.Debris:AddItem(msg, 5)
	end

	local ls = Instance.new("Folder", plr)
	ls.Name = "leaderstats"

	local coinsValue = Instance.new("IntValue", ls)
	coinsValue.Name = "Coins"
	coinsValue.Value = coins

	local winsValue = Instance.new("IntValue", ls)
	winsValue.Name = "Wins"
	winsValue.Value = wins

	local skipsValue = Instance.new("IntValue", plr)
	skipsValue.Name = "Skips"
	skipsValue.Value = skips


	local previoustitle = Instance.new("StringValue", plr)
	previoustitle.Name = "previoustitle"
	previoustitle.Value = title

	local previousstyle = Instance.new("StringValue", plr)
	previousstyle.Name = "previousstyle"
	previousstyle.Value = style

	plr.CharacterAdded:Connect(function(char)
		--Varibles
		local head = char.Head
		local newtext = nametag:Clone() 
		local uppertext = newtext:WaitForChild("Name")
		local lowertext = newtext.Title
		local humanoid = char.Humanoid

		humanoid.DisplayDistanceType = Enum.HumanoidDisplayDistanceType.None -- use enum instead of a string

		--Main Text
		newtext.Parent = head
		newtext.Adornee = head
		uppertext.Text = plr.Name 

		if plr.previoustitle.Value ~= "" then
			lowertext.Text = plr.previoustitle.Value
		end

		--"If" Statements
		--You can add as many of these as you wish, just change it to the player's name.

	end)







	local ownedFolder2 = Instance.new("Folder", plr)
	ownedFolder2.Name = "OwnedTools"

	local ownedFolder3 = Instance.new("Folder", plr)
	ownedFolder3.Name = "OwnedTitles"

	for i, owned in pairs(toolsOwned) do

		if tools:FindFirstChild(owned) then

			tools[owned]:Clone().Parent = ownedFolder2
		end
	end

	for i, owned in pairs(titlesOwned) do

		if titles:FindFirstChild(owned) then

			titles[owned]:Clone().Parent = ownedFolder3
		end
	end

end)


game.Players.PlayerRemoving:Connect(saveData)

game:BindToClose(function()

	for i, plrLeaving in pairs(game.Players:GetPlayers()) do
		coroutine.wrap(function()
			saveData(plrLeaving)
		end)()
	end

	-- stall the server
	if not game:GetService('RunService'):IsStudio() then
		while wait() do
			if math.floor(os.clock()%5)== 0 then
				print('OMG WE ALL FINNA DIE')
			end
		end
	end
end)

spawn(function()
	while wait(60) do 
		for i, plrLeaving in pairs(game.Players:GetPlayers()) do
			coroutine.wrap(function()
				saveData(plrLeaving)
			end)()
		end
	end
end)


As you can see in the script, it creates a string value called previoustitle. I want it to set the value of previous title to plr.Character.Head.Nametag.Title.Text and whenever a player leaves, the title equipped before the player left is the one they have equipped now.

Lots of nice people have helped me with this script but none of them have seemed to figure out how to to do this and make it work properly. Can you help me?

1 Like

Hi anyone reading, are you able to help me?

When loading / saving, you’ll want to SetAsync and GetAsync of the UserId or whatever else you may index it by.

Yes, I do that here:

ds:SetAsync(plrLeaving.UserId, game.HttpService:JSONEncode(output))

It saves Title inside and sets previoustitle.Value to Title but it doesn’t save the value previoustitle for some reason.

You never jsonDecode when you are loading the data. You may want to see if this may be a reason why ( nvm just saw it)

All the other values are loading. I think its a problem with setting the value but im not sure.

Could it be that the character is unloaded before it can be called?

No, all the other values are loading (leaderstats, other stuff, etc). Previoustitle is loading but the value is not set or setted when the player left. I have no idea how to fix this.

Do you have a title being used while leaving? If so, can you print ‘output’ and tell me what it print?

Yes, the title is

plr.Character.Head.Nametag.Title.Text

It is on top of the player’s head and I want it to be saved to the previoustitle value and loaded when the player joins back.

I meant a title as in the text of it not being nil or empty

I don’t know why you would need proof that the value is empty. Studio is not working currently for me but I can assure you it is “”.

image

If the value is “”, then there is no value to be saved, though?

I have already told you what is not working and that is why I am looking for help. I set the value through this part:

local previoustitle = Instance.new("StringValue", plr)
	previoustitle.Name = "previoustitle"
	previoustitle.Value = title

I don’t know why it isn’t working. Does title have to be set?

If you want it to have a value, title would need to be set in the PlayerAdded function, otherwise there wont be a value to save if not changed while in the game.

So then what do I need to set title to and where?

In your packedData block of code, instead of saying title = packedData.Titled, do title = packedData.Title

Did not work, thank you for trying though :slight_smile:

Anyone reading, are you able to help me?