Datastore runs but doesn's save players info

Hi, I’ve been trying to bring an old RPG back to life and to do so I had to update the old data persistence script with a new datastore script. I’ve gotten data scripts to work before and I have watched tutorials on how to properly do datastore from alvinblox. I’ve also scoured through devforum the past couple days looking at every datastore topic I could even find and while those helped me fix a LOT of my problems, some new ones that I just can’t find answers to popped up as well. For some reason this script just will not save the players data. Please see if you can find anything wrong with my script so far.

Note: the blarglepart is simply to help me easily check if player data is saving by updating the values

local dataStoreService = game:GetService("DataStoreService")
local playerService = game:GetService("Players")

local dataStore = dataStoreService:GetDataStore("Data")
local playerCount = 0
local playerLeaveEvent = Instance.new("BindableEvent")

playerService.PlayerAdded:Connect(function(player)
	local level = Instance.new("IntValue")
	level.Name = "Level"
	level.Value = 1
	level.Parent = player

	local xp = Instance.new("IntValue")
	xp.Name = "Current"
	xp.Value = 0
	xp.Parent = level

	local maxExp = Instance.new("IntValue")
	maxExp.Name = "Max"
	maxExp.Value = 100
	maxExp.Parent = level
	
	local gold = Instance.new("IntValue")
	gold.Name = "Gold"
	gold.Value = 0
	gold.Parent = level

	xp.Changed:Connect(function(val)
		if xp.Value >= maxExp.Value then
			-- Do stuff

			level.Value += 1
			xp.Value = xp.Value - maxExp.Value
			maxExp.Value *= 2
		end
	end)
	
	local savedLevel
	local savedExp
	local savedGold
	
	local success = pcall(function()
		savedLevel = dataStore:GetAsync(player.UserId)
		savedExp = dataStore:GetAsync(player.UserId)
		savedGold = dataStore:GetAsync(player.UserId)
	end)
	
	if success then
		if savedLevel and savedExp and savedGold then
			level.Value = savedLevel
			xp.Value = savedExp
			gold.Value = savedGold
		end
	else
		level.Value = 1
		xp.Value = 0
		gold.Value = 10
	end
	
	playerCount += 1
end)

playerService.PlayerRemoving:Connect(function(player)
	local level = player.Level
	local xp = player.Level.Current
	local gold = player.Level.Gold
	
	pcall(function()
		dataStore:SetAsync(player.UserId, level.Value)
		dataStore:SetAsync(player.UserId, xp.Value)
		dataStore:SetAsync(player.UserId, gold.Value)
	end)
	
	playerCount -= 1
	playerLeaveEvent:Fire()
end)


workspace:WaitForChild("BlarglePart").ClickDetector.MouseClick:Connect(function(player)
	player.Level.Current.Value += 29
end)


game:BindToClose(function()
	while playerCount > 0 do
		playerLeaveEvent.Event:Wait()
	end
end)

Hmm, weird question though what would the player leave event do because I’m assuming that’s what saves the data am I correct?

No, the playerLeaveEvent() function is simply for the BindToClose(function(). It allows me to tell it to wait for the event to fire, and since the event doesn’t fire until the saving of the characters values is done, it keeps the game from closing before it finishes, thus helping ensure the players data is saved. I believe that was from one of AlvinBlox’s videos I watched.

Are you testing this in Roblox Studio?

You cannot save multiple values to a same DataStore, instead use a table to save your values. I’ve covered a similar situation in this post: Datastore sets every value to 0 - #9 by Sarchyx

1 Like

what you’re doing is essentially saving every value into plr.UserId, try changing up the keys a bit like this:

dataStore:SetAsync("level"..player.UserId, level.Value)
		dataStore:SetAsync("xp"..player.UserId, xp.Value)
		dataStore:SetAsync("gold"..player.UserId, gold.Value)

and when getting the values :


		savedLevel = dataStore:GetAsync("level"..player.UserId)
		savedExp = dataStore:GetAsync("xp"..player.UserId)
		savedGold = dataStore:GetAsync("gold"..player.UserId)

and of course paste this everywhere you save/get the data

2 Likes

I’ve tested both in Roblox Studio AND on a published game and neither work. In fact, in the published game their are MORE problems but I believe they will be fixed either once I fix this problem, or afterwards through some debugging. I’m sorry, I should have stated in the Original Post.

@iscriptfast A better alternative would be saving everything in a dictionary to a single key instead, which lowers the amount of data store requests.


@cjjjimmy You should take advantage of pcalls and print any errors caught by pcalls.

1 Like

You are a legend my friend thank you! This single-handedly fixed all the problems I had! May I ask what exactly does changing it like this do?? Every other datastore I’ve done was the other way and it worked fine. I can’t help but think this is due to my lack of understanding of SetAsync and GetAsync.

1 Like

What Denis said has already fixed my problem but I had plans to make it a table once I was finished fixing this problem. The DataStore is working for all three currently like this but I am aware that using a table is much more efficient. I will definitely check that post to better help me with the change, thank you!

OH YEA. I totally forgot to do that… Would have probably been able to figure out my own problem had I done that from the start smh. Thank you for the tip!

what it does is it’s saving different keys for different values instead of the same for all, which lets you, in turn, get those values separately.

If you want to use tables, please also JSONEncode them at :SetAsync() and Decode them at GetAsync() because roblox tends to be weird with tables and it’s a lot more efficient this way too.

Though I don’t recommend using tables if you don’t know anything about how they work since it could confuse things even more

If you need any more help let me or @COUNTYL1MITS know! :+1:

1 Like

You do not need to encode the dictionaries to JSON strings, as Roblox already internally encodes them to JSON.

1 Like

not really, you’re essentially just getting a value and assigning it to everything else, since that value exist and everything else checks out, it won’t error at all

I’m definitely going to try implementing a table like in that post because it’s very easy to understand in that context! Thank you so much!

This works absolutely fantastically! Thank you for all the help! I understand DataStore even more now!

local Players = game:GetService("Players")
local DataStores = game:GetService("DataStoreService")
local DataStore = DataStores:GetDataStore("DataStore")
local PlayerLeftEvent = Instance.new("BindableEvent")

local ProtectedCall = pcall

Players.PlayerAdded:Connect(function(Player)
	local Level = Instance.new("IntValue")
	Level.Name = "Level"
	Level.Parent = Player

	local Exp = Instance.new("IntValue")
	Exp.Name = "Current"
	Exp.Parent = Level

	local MaxExp = Instance.new("IntValue")
	MaxExp.Name = "Max"
	MaxExp.Parent = Level

	local Gold = Instance.new("IntValue")
	Gold.Name = "Gold"
	Gold.Value = 0
	Gold.Parent = Level

	Exp.Changed:Connect(function(NewExp)
		if NewExp >= MaxExp.Value then
			Level.Value += 1
			Exp.Value -= MaxExp.Value
			MaxExp.Value *= 2
		end
	end)

	local Success, Result = ProtectedCall(function()
		return DataStore:GetAsync(Player.UserId)
	end)
	
	if Success then
		if Result then
			if type(Result) == "table" then
				Level.Value = Result[1] or 1
				Exp.Value = Result[2] or 0
				MaxExp.Value = Result[3] or 100
				Gold.Value = Result[4] or 0
			end
		end
	else
		warn(Result)
	end
end)

Players.PlayerRemoving:Connect(function(Player)
	local Success, Result = ProtectedCall(function()
		return DataStore:SetAsync(Player.UserId, {Player.Level.Value, Player.Level.Exp.Value, Player.Level.MaxExp.Value, Player.Level.Gold.Value})
	end)
	
	if Success then
	else
		warn(Result)
	end

	PlayerLeftEvent:Fire()
end)

game:BindToClose(function()
	for _, Player in ipairs(Players:GetPlayers()) do
		local Success, Result = ProtectedCall(function()
			return DataStore:SetAsync(Player.UserId, {Player.Level.Value, Player.Level.Exp.Value, Player.Level.MaxExp.Value, Player.Level.Gold.Value})
		end)

		if Success then
		else
			warn(Result)
		end
	end
end)

Bare in mind that you’re not parenting the instanced BindableEvent anywhere so its parent is nil.

This saves player stats using a table as suggested and will also save “MaxExp” as well. I’ve also binded a function to BindToClose so that if/when the server is shutdown every player’s stats are saved.