Datastore Saving

Hey there!

I have just added a couple more data sets to my LONG list of data I need to save. I have noticed though, that the last three I added are not actually saving…:man_shrugging: I checked and made sure those three looked the same as all the others, and I can’t find anything. Then I thought it might be the fact that there is a ton of data that needs to be saved.

This is the way I did my datastore

function onPlayerEntered(player)
	
	--Create a key to store player stats
	local initKey = "user_" .. player.userId .. "_init"
	local stepsKey = "user_" .. player.userId .. "_steps"
	local pointsKey = "user_" .. player.userId .. "_points"
	local speedKey = "user_" .. player.userId .. "_speed"
	local trailKey = "user_" .. player.userId .. "_trail"
	local animKey = "user_" .. player.userId .. "_anim"
	local petKey = "user_" .. player.userId .. "_pet"
	local xpKey = "user_" .. player.userId .. "_xp"
	local levelKey = "user_" .. player.userId .. "_level"
	local orbsBadgeKey = "user_" .. player.userId .. "_orbsBadge"
	local winsBadgeKey = "user_" .. player.userId .. "_winsBadge"
	local particleKey = "user_" .. player.userId .. "_particle"
	local boughtKey = "user_" .. player.userId .. "_bought"
	local rebirthKey = "user_" .. player.userId .. "_rebirth"
	local placeKey = "user_" .. player.userId .. "_place"
	local PUAKey = "user_" .. player.userId .. "_PUAKey"
	local PUTKey = "user_" .. player.userId .. "_PUTKey"
	local snackKey = "user_" .. player.userId .. "_snackKey"
	
	--Creates default stats for new players
	if(datastore:GetAsync(initKey) == nil) then
		
		datastore:SetAsync(initKey, true)
		datastore:SetAsync(stepsKey, 0)
		datastore:SetAsync(pointsKey, 0)
		datastore:SetAsync(speedKey, 1)
		datastore:SetAsync(trailKey, "DefaultTrail")
		datastore:SetAsync(animKey, "DefaultAnim")
		datastore:SetAsync(petKey, "DefaultPet")
		datastore:SetAsync(xpKey, 0)
		datastore:SetAsync(levelKey, 1)
		datastore:SetAsync(orbsBadgeKey, 0)
		datastore:SetAsync(winsBadgeKey, 0)
		datastore:SetAsync(particleKey, "DefaultParticleTrail")
		datastore:SetAsync(boughtKey, {})
		datastore:SetAsync(rebirthKey, 0)
		datastore:SetAsync(placeKey, "Park")
		datastore:SetAsync(PUAKey, {})
		datastore:SetAsync(PUTKey, {})
		datastore:SetAsync(snackKey, 0)
     end


	local init = datastore:GetAsync(initKey)
	local steps = datastore:GetAsync(stepsKey)
	local points = datastore:GetAsync(pointsKey)
	local speed = datastore:GetAsync(speedKey)
	local trail = datastore:GetAsync(trailKey)
	local anim = datastore:GetAsync(animKey)
	local pet = datastore:GetAsync(petKey)
	local xp = datastore:GetAsync(xpKey)
	local level = datastore:GetAsync(levelKey)
	local orbsBadge = datastore:GetAsync(orbsBadgeKey)
	local winsBadge = datastore:GetAsync(winsBadgeKey)
	local particle = datastore:GetAsync(particleKey)
	local bought = datastore:GetAsync(boughtKey)
	local rebirth = datastore:GetAsync(rebirthKey)
	local place = datastore:GetAsync(placeKey)
	local PUA = datastore:GetAsync(PUAKey)
	local PUT = datastore:GetAsync(PUTKey)
	local snack = datastore:GetAsync(snackKey)
	
	_G.boughtArray[player.userId] = bought
	_G.petUpgradeAmount[player.userId] = PUA
	_G.petUpgradeTime[player.userId] = PUT

--[[ 
a lot of code to add the values from the datastore... example:

    local stepsBoard = Instance.new("IntValue")
	stepsBoard.Name = "Steps"
	stepsBoard.Value = steps
	stepsBoard.Parent = player

]]--

end

Then I have the code when the player leaves…

function onPlayerLeaving(player)
	
	
	local userId = player.UserId
	
	local steps = player.Steps.Value
	local speed = player.Speed.Value
	local points = player.Points.Value
	local trail = player.PlayerTrail.Value
	local anim = player.PlayerAnim.Value
	local pet = player.PlayerPet.Value
	local xp = player.XP.Value
	local level = player.Level.Value
	local orbsBadge = player.OrbsBadgeCount.Value
	local winsBadge = player.WinsBadgeCount.Value
	local particle = player.PlayerParticleTrail.Value
	local bought = _G.boughtArray[player.userId]
	local rebirth = player.Rebirths.Value
	local place = player.PlayerPlace.Value
	local PUA = _G.petUpgradeAmount[player.userId]
	local PUT = _G.petUpgradeTime[player.userId]
	local snack = player.SwiftSnacks.Value
	
	local stepsKey = "user_" .. player.userId .. "_steps"
	local pointsKey = "user_" .. player.userId .. "_points"
	local speedKey = "user_" .. player.userId .. "_speed"
	local trailKey = "user_" .. player.userId .. "_trail"
	local animKey = "user_" .. player.userId .. "_anim"
	local petKey = "user_" .. player.userId .. "_pet"
	local xpKey = "user_" .. player.userId .. "_xp"
	local levelKey = "user_" .. player.userId .. "_level"
	local orbsBadgeKey = "user_" .. player.userId .. "_orbsBadge"
	local winsBadgeKey = "user_" .. player.userId .. "_winsBadge"
	local particleKey = "user_" .. player.userId .. "_particle"
	local boughtKey = "user_" .. player.userId .. "_bought"
	local rebirthKey = "user_" .. player.userId .. "_rebirth"
	local placeKey = "user_" .. player.userId .. "_place"
	local PUAKey = "user_" .. player.userId .. "_PUA"
	local PUTKey = "user_" .. player.userId .. "_PUT"
	local snackKey = "user_" .. player.userId .. "_snack"
	
	datastore:SetAsync(stepsKey, steps)
	datastore:SetAsync(pointsKey, points)
	datastore:SetAsync(speedKey, speed)
	datastore:SetAsync(trailKey, trail)
	datastore:SetAsync(animKey, anim)
	datastore:SetAsync(petKey, pet)
	datastore:SetAsync(xpKey, xp)
	datastore:SetAsync(levelKey, level)
	datastore:SetAsync(orbsBadgeKey, orbsBadge)
	datastore:SetAsync(winsBadgeKey, winsBadge)
	datastore:SetAsync(particleKey, particle)
	datastore:SetAsync(boughtKey, bought)
	datastore:SetAsync(rebirthKey, rebirth)
	datastore:SetAsync(placeKey, place)
	datastore:SetAsync(PUAKey, PUA)
	datastore:SetAsync(PUTKey, PUT)
	datastore:SetAsync(snackKey, snack)
end

game.Players.PlayerRemoving:Connect(onPlayerLeaving)

So, the last three aren’t saving, so maybe a solution(unless you see a typo or easily see the answer) would be to bunch all those values so I only have to Set:Async like only once or twice, like in a table or something? How would I do that?

5 Likes

USE A TABLE To MAKE EVERYTHING CLEANER AND USE PCALL FOR SAVING AND LOADING DATA.

4 Likes

You are calling DataStore service WAY to many times. What I would do is save all of that data to one table, like so:

local ToSave = {}

for i, v in pairs(player:GetDescendants()) do
	if v:IsA("IntValue") or v:IsA("NumberValue") or v:IsA("StringValue") or v:IsA("BoolValue") then
		table.insert(ToSave,v.Value)--Inset its value
		table.insert(ToSave,v.Name) -- Insert its name
		table.insert(ToSave,v.Parent) -- Insert its parent
	end
end

datastore:SetAsync(plrkey, ToSave)

Then, all you have to do is unpack the table, like so:

local Success,data = pcall(function()
	return datastore:GetAsync(id)
end) 

local Entry = 1

repeat
	wait()
	player:FindFirstChild(data[Entry]):FindFirstChild(data[Entry] + 1).Value = data[Entry + 2]
	Entry = Entry + 3
until data[Entry] == nil

Keep in mind, I typed this off the top of my head, so I may have gotten a few things wrong. That is just an example to show you how to save data efficiently, without overloading datastoreservice.

Edit: If you have any questions about applying this, feel free to message me.

3 Likes

So I am using a special form of value for a player, specifically this

_G.petUpgradeTime[player.userId]

It is from this, which I forgot to put above the player entered function

local _G.petUpgradeTime = {}

How would I put this in, as it isn’t from the player?

Thanks by the way!

Also what would “plrkey” be linked to? And maybe to make this easier, is there a way to just save the existing lines I already have in a table? It is fine if there isn’t, I can try your way too, I am just curious.

What are you doing??? Store everything in a table and save the table

1 Like

That is the thing, I need to know how! To answer the question, I don’t what I am doing!:rofl::rofl: @Infinite_Visions sort of figured it out for me, I just need to figure out some more things.

1 Like

Its the same thing PlayerData:SetAsync(Key, {player.leaderstats.Cash.Value, player.leaderstats.Wins.Value, etc})

1 Like

Oh ok, thanks! So if I did that how would I find it again if it is just values, I need some way to reference them.

PlayerData:SetAsync("PlayerKey", {
	player.leaderstats.Cash.Value,
	player.leaderstats.Wins.Value,
	player.leaderstats.Deaths.Value
})

local data = PlayerData:GetAsync("PlayerKey")

player.leaderstats.Cash.Value = data[1]
player.leaderstats.Wins.Value = data[2]
player.leaderstats.Deaths.Value = data[3]
5 Likes

AHH! Ok thanks so much! I understand, this is going to help me a LOT!

1 Like

So I have noticed an issue, how would I add aditional information? Normally I would put

if(datastore:GetAsync(SomeRandomKey) == nil) then
datastore:SetAsync(SomeRandomKey, 0)
end

But it is only one key, and all the values are in the table, so how do I add a new one?

I dont understand do you mean saving a new table or getting the values from the table.

1 Like

So if I had a set of values, in the table, lets use your example cash, wins, and deaths, how would I do it if I wanted to add another value later on, like items, and put that in there with the rest of them, while keeping the existing values in tact?

You can use SetAsync()

New Script in ServerScriptService


local DataStore = game:GetService("DataStoreService")
local PlayerData = DataStore:GetDataStore("PlayerData")

DataStore:SetAsync("PlayerKey", {
   Wins.Value, Cash.Value, newValue
})

Or if it is in the same script, just add another value under the last value you are saving.

2 Likes

Oh ok I don’t think I explained my thing right, or if you have it right, I don’t understand what you mean in your last statement

When you helped me with using tables for data stores, I was would start like this,

local initKey = "user_" .. player.userId .. "_init"
local stepsKey = "user_" .. player.userId .. "_steps"
local pointsKey = "user_" .. player.userId .. "_points"

if(datastore:GetAsync(initKey) == nil) then
		
	datastore:SetAsync(initKey, true)
	datastore:SetAsync(stepsKey, 0)
	datastore:SetAsync(pointsKey, 0)
end
local init = datastore:GetAsync(initKey)
local steps = datastore:GetAsync(stepsKey)
local points = datastore:GetAsync(pointsKey)

And then I wanted to add another value, I would do it like this, while still keeping existing values from losing data,

local initKey = "user_" .. player.userId .. "_init"
local stepsKey = "user_" .. player.userId .. "_steps"
local pointsKey = "user_" .. player.userId .. "_points"
local speedKey = "user_" .. player.userId .. "_speed"

if(datastore:GetAsync(initKey) == nil) then
		
	datastore:SetAsync(initKey, true)
	datastore:SetAsync(stepsKey, 0)
	datastore:SetAsync(pointsKey, 0)
    datastore:SetAsync(speedKey, 1)
end

if(datastore:GetAsync(speedKey) == nil) then
   datastore:SetAsync(speedKey, 1)
end

local init = datastore:GetAsync(initKey)
local steps = datastore:GetAsync(stepsKey)
local points = datastore:GetAsync(pointsKey)
local speed = datastore:GetAsync(speedKey)

(the init key is actually just used for first time players)

So how can I do that for the table?
Like if the key is already something and isn’t nil, how can I check for a new value in the table, and if it isn’t there, add it in the table without messing up other values. Sorry, I am not explaining this very well.

1 Like

One key can save a table of values. If you wanted to save a new value you would just place it in the table that you are saving not using another key.

–Actual example

local DataStoreService = game:GetService("DataStoreService")
local PlayerData = DataStoreService:GetDataStore("PlayerData")

game.Players.PlayerAdded:Connect(function(player)
	local leaderstats = Instance.new("Folder")
	leaderstats.Name = "leaderstats"
	leaderstats.Parent = player 
	
	local steps = Instance.new("IntValue")
	steps.Name = "steps"
	steps.Parent = leaderstats

	local points = Instance.new("IntValue")
	points.Name = "points"
	points.Parent = leaderstats
	
	local speed = Instance.new("IntValue")
	speed.Name = "speed"
	speed.Parent = leaderstats
	
	local init = Instance.new("IntValue")
	init.Name = "init"
	init.Parent = leaderstats
	
	local Player_Key = "Data_"..player.UserId
	
	local data
	
	local S, E = pcall(function()
		data = PlayerData:GetAsync(Player_Key)
	end)
	
	if S then
		print(data)
		steps.Value = data[1]
		points.Value = data[2]
		speed.Value = data[3]
		init.Value = data[4]
		--etc
	else
		print(E)
	end
	
end)

game.Players.PlayerRemoving:Connect(function(player)
	local Player_Key = "Data_"..player.UserId
	
	pcall(function()
		PlayerData:SetAsync(Player_Key, {
			player.leaderstats.steps.value,
			player.leaderstats.points.value,
			player.leaderstats.speed.value,
			player.leaderstats.init.value
		}) 
	
	end)
	
end)
3 Likes