Saving a value through datastore

I tried doing this:

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


	local toolsOwned = {}
	local titlesOwned = {}
	local style = ""
	local title = plr.Character.Head.Nametag.Title.Text

But it breaks the entire script.

Try printing what packed data is after you call GetAsync(). Also, put a print statement after your conditional where you’re checking to make sure packedData is a table. My guess is the script is evaluating that if statement to be false and it’s not changing “title”, so it just appears to be “” every time someone plays.

Also, Lua tables already JsonEncode and Decode themselves, so you don’t need to do that.

All of the other values (Skips, Wins, Coins) are loading but the previoustitle is not. I think the problem is that there is nothing set in previoustitle so there is nothing so save/load. Can you help me with that?

Have you tried printing out what “title” is equal to in your saveData function? If it’s equal to “” then it’s not getting the text inside the pcall function.

Yeah, I think thats the issue. I don’t know what to set it to though without the whole program breaking. I tried this:

	local toolsOwned = {}
	local titlesOwned = {}
	local style = ""
	local title = plr.Character.Head.Nametag.Title.Text

But it didn’t work.

A player’s character is instantly removed once a player leaves. The player’s client is around a little bit longer, but the character isn’t. You have three options here I think:

  1. You could try running the Player.CharacterRemoving event to grab the leaving player’s character right before they leave and store the text in the title variable through that.

  2. Store the NameTag’s text inside a StringValue located in the player somewhere

  3. Store the entire NameTag inside the player, and just set the adornee to the player’s character’s head.

My guess is that the character is being deleted instantly, and so because that line of code is inside a pcall, no error ever gets thrown, so title is just equal to nil since the script could find the character.

I understood until you said this. What does it mean?

Instead of parenting the nametag to the character in your playerAdded event, parent it to the player instead.

--Main Text
		newtext.Parent = head -- Get rid of this line in your character added event, and parent the nametag to the player instead.
		newtext.Adornee = head
		uppertext.Text = plr.Name 

So this is my current script:

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.Title or title
		else
			plr:SetAttribute('DataSuccess', false)
		end
	end
	print(3)

	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
	print(4)
	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", ls)
	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
	print(5)
	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
		print(6)
		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)

	print(7)
	
	plr.CharacterRemoving:Connect(function()
		title = plr.Character.Head.Nametag.Title.Text
		
	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)

When the player leaves, it uses this event and saves title to the top of the character’s head.

plr.CharacterRemoving:Connect(function()
		title = plr.Character.Head.Nametag.Title.Text
		
	end)

And then it saves it:

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

When the player joins back it loads it:


	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.Title or title
		else
			plr:SetAttribute('DataSuccess', false)
		end
	end
	print(3)

But its still not working.

One of my issues is this part

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

What do I need to change title to here?

The three things that I listed above were three separate things I told said you could do, that’s why I called them options. They aren’t supposed to be used together. If you are going the route of parenting the entire nametag to the player instead of the character, then

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

That should be your new pcall function to assign title. You can remove the plrLeaving.CharacterRemoving() event since you are just parenting the nametag to the player anyways.

This is what your completed should look like I think.

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.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 = plr
		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)

Didn’t seem to work, thank you for helping though!