How would you save lots of player data values? (280+)

Hi,
I am making a game, Dangerous DJs, Dangerous DJs - Roblox, and I need help with saving the players’ data. (Around 281 values, and it gives me overflow errors, which stops some data from being saved.)
I have searched around on google and the DevForum, tried putting wait() commands to slow down the datastore requests, and I haven’t been able to find a solution. The reason I need to save so many values, is that the players can create their own beats and melodies, and I want them to save. It takes a bit of time to make the beats, and other systems in the game rely on the saved stats.

Here is one of my scripts that is supposed to save 16 values:

--Save:
game.Players.PlayerRemoving:connect(function(player)
	local datastore = game:GetService("DataStoreService"):GetDataStore(player.Name.."Loop1")

	local statstorage = player:FindFirstChild("Loop1"):GetChildren()
for i =  1, #statstorage do
	datastore:SetAsync(statstorage[i].Name, statstorage[i].Value)
	print("saved data number "..i)
	
end
print("Stats successfully saved")	
end)


--Load:
game.Players.PlayerAdded:connect(function(player)
	wait(2.5)
		local datastore = game:GetService("DataStoreService"):GetDataStore(player.Name.."Loop1")
	
	player:WaitForChild("Loop1")
	wait(1)
	local stats = player:FindFirstChild("Loop1"):GetChildren()
	for i = 1, #stats do			
	stats[i].Value = datastore:GetAsync(stats[i].Name)
	print("stat numba "..i.." has been found")
		end
end)

This is a video of one of the systems that needs to have saved stats (Sorry about bad quality and audio lag, I was using the Roblox screen recording system):
Demo.wmv (2.1 MB)

Each of those tiles/notes will be represented as a string value, with the name the tile number, and the value the sound that it is supposed to play.

Also, I am having a problem where the tiles that play a sound take a bit longer than the tiles that dont play a sound.

Example:
Demo2.wmv (1.2 MB)

The blue outline indicates what tile is playing.

Here is the script that plays the notes:

--Tracks:------------------------------------------------------------------------------------------------------------------
track1 = script.Parent.Parent.Parent.Track1Buttons
track2 = script.Parent.Parent.Parent.Track2Buttons

--Track 1 function:----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
function play1()
	--Player:----------------------------------------------------------------------------------------------------------------
	local plr = script.Parent.Parent.Parent.Parent.Parent.Parent.Parent
	--Find the charater and sounds:------------------------------------------------------------------------------------------
	local char = game.Workspace:FindFirstChild(plr.Name)
	local sawpart = char:FindFirstChild("SawWaveSoundPart")
	local synthpart = char:FindFirstChild("BeepSoundPart")
	local errorpart = char:FindFirstChild("ErrorWaveSoundPart")

	--Find the buttons that are on:-------------------------------------------------------------------------------------------
	for index, button in pairs(track1:GetChildren()) do
		if button.ClassName == "TextButton" then
			if button.Text ~= "Empty (click to change)" then
				--Find the note:-------------------------------------------------------------------------------------------------
				for notes, note in pairs(button.Notes:GetChildren()) do
					if note.Value == true then
						notename = note.Name
					end
				end
				if button.Synth.Value == true then
					--Find the sound and play it:----------------------------------------------------------------------------------
					local sound = synthpart:FindFirstChild("Beep"..notename)
					
					button.BorderColor3 = Color3.new(0,0,255)

					sound.TimePosition = 0
					sound.Volume = .5
					sound.Playing = true
					wait(.17)
					sound.Volume = .4
					wait(.02)
					sound.Volume = .3
					wait(.02)
					sound.Volume = .2
					wait(.02)
					sound.Volume = .1
					wait(.02)
					sound.Playing = false
					
					button.BorderColor3 = Color3.new(0,255,0)
				elseif button.Saw.Value == true then
					--Find the sound and play it:----------------------------------------------------------------------------------
					local sound = sawpart:FindFirstChild("SawWave"..notename)
					
					button.BorderColor3 = Color3.new(0,0,255)

					sound.TimePosition = 0
					sound.Volume = .5
					sound.Playing = true
					wait(.17)
					sound.Volume = .4
					wait(.02)
					sound.Volume = .3
					wait(.02)
					sound.Volume = .2
					wait(.02)
					sound.Volume = .1
					wait(.02)
					sound.Playing = false
					
					button.BorderColor3 = Color3.new(0,255,0)
				elseif button.Error.Value == true then
					--Find the sound and play it:----------------------------------------------------------------------------------
					local sound = errorpart:FindFirstChild("ErrorWave"..notename)
					
					button.BorderColor3 = Color3.new(0,0,255)

					sound.TimePosition = 0
					sound.Volume = .5
					sound.Playing = true
					wait(.17)
					sound.Volume = .4
					wait(.02)
					sound.Volume = .3
					wait(.02)
					sound.Volume = .2
					wait(.02)
					sound.Volume = .1
					wait(.02)
					sound.Playing = false
				end
			else
				--If empty, wait:------------------------------------------------------------------------------------------------
				button.BorderColor3 = Color3.new(0,0,255)
				
				wait(.25)
				
				button.BorderColor3 = Color3.new(0,255,0)
			end
		end
	end
end

----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

--Track 2 function:----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
function play2()
	--Player:----------------------------------------------------------------------------------------------------------------
	local plr = script.Parent.Parent.Parent.Parent.Parent.Parent.Parent
	--Find the charater and sounds:------------------------------------------------------------------------------------------
	local char = game.Workspace:FindFirstChild(plr.Name)
	local sawpart = char:FindFirstChild("SawWaveSoundPart")
	local synthpart = char:FindFirstChild("BeepSoundPart")
	local errorpart = char:FindFirstChild("ErrorWaveSoundPart")

	--Find the buttons that are on:-------------------------------------------------------------------------------------------
	for index, button in pairs(track2:GetChildren()) do
		if button.ClassName == "TextButton" then
			if button.Text ~= "Empty (click to change)" then
				--Find the note:-------------------------------------------------------------------------------------------------
				for notes, note in pairs(button.Notes:GetChildren()) do
					if note.Value == true then
						notename = note.Name
					end
				end
				if button.Synth.Value == true then
					--Find the sound and play it:----------------------------------------------------------------------------------
					local sound = synthpart:FindFirstChild("Beep"..notename)
					
					button.BorderColor3 = Color3.new(0,0,255)

					sound.TimePosition = 0
					sound.Volume = .5
					sound.Playing = true
					wait(.17)
					sound.Volume = .4
					wait(.02)
					sound.Volume = .3
					wait(.02)
					sound.Volume = .2
					wait(.02)
					sound.Volume = .1
					wait(.02)
					sound.Playing = false
					
					button.BorderColor3 = Color3.new(0,255,0)
				elseif button.Saw.Value == true then
					--Find the sound and play it:----------------------------------------------------------------------------------
					local sound = sawpart:FindFirstChild("SawWave"..notename)
					
					button.BorderColor3 = Color3.new(0,0,255)

					sound.TimePosition = 0
					sound.Volume = .5
					sound.Playing = true
					wait(.17)
					sound.Volume = .4
					wait(.02)
					sound.Volume = .3
					wait(.02)
					sound.Volume = .2
					wait(.02)
					sound.Volume = .1
					wait(.02)
					sound.Playing = false
					
					button.BorderColor3 = Color3.new(0,255,0)
				elseif button.Error.Value == true then
					--Find the sound and play it:----------------------------------------------------------------------------------
					local sound = errorpart:FindFirstChild("ErrorWave"..notename)
					
					button.BorderColor3 = Color3.new(0,0,255)

					sound.TimePosition = 0
					sound.Volume = .5
					sound.Playing = true
					wait(.17)
					sound.Volume = .4
					wait(.02)
					sound.Volume = .3
					wait(.02)
					sound.Volume = .2
					wait(.02)
					sound.Volume = .1
					wait(.02)
					sound.Playing = false
					
					button.BorderColor3 = Color3.new(0,255,0)
				end
			else
				--If empty, wait:------------------------------------------------------------------------------------------------
				button.BorderColor3 = Color3.new(0,0,255)
				
				wait(.25)
				
				button.BorderColor3 = Color3.new(0,255,0)
			end
		end
	end
end

script.Parent.MouseButton1Click:Connect(play1)
script.Parent.MouseButton1Click:Connect(play2)

Thanks for reading, and sorry for the long post. Thanks! :slight_smile:

1 Like

The basic gist is you should be storing data in a table, not individual keys.

--Instead of:
DataStore:SetAsync('a' aData)
DataStore:SetAsync('b', bData)

--Do:
DataStore:SetAsync('data', {
    a = aData,
    b = bData,
})

That way, you use way less requests. If you need help with that, let me know.

3 Likes

Wait. What if saved each music note as a digit between 0 and 9, and then once the player was done making a song you would be able to save it as one big number. For instance a players song might be saved like this: 981306378499223019394. Each digit in this massive number would represent 1 note. If you wanted to have even more then 10 notes you could use letters and symbols too.
The next time the player plays the game and wants to play a song they composed previously, they would be able to play it only using one long number. Tell me if this weird idea would work or whether I completely forgot about something :smile:

2 Likes

I mean, that’s not insane, you’re basically encoding a song into the bits of a number. But it sounds like a pain to deal with.

Is there a reason you can’t just store it as an array of notes and save the array under one key?

One “note” could just be a string, but it could also be an array with a fixed number of objects or a table or a number.

That makes sense. I’ll try it, and let you know if I need help, because I have almost no experience with datastores. :slight_smile:

Something like this?

--Save:
game.Players.PlayerRemoving:connect(function(player)
	
	local datastore = game:GetService("DataStoreService"):GetDataStore(player.Name.."Loop1")


	datastore:SetAsync("Loop1", {
		a = player.Loop1.HiC1,
		b = player.Loop1.HiC2,
		c = player.Loop1.HiC3,
		d = player.Loop1.HiC4,
		e = player.Loop1.HiO1,
		f = player.Loop1.HiO2,
		g = player.Loop1.HiO3,
		h = player.Loop1.HiO4,
		i = player.Loop1.Snare1,
		j = player.Loop1.Snare2,
		k = player.Loop1.Snare3,
		l = player.Loop1.Snare4,
		m = player.Loop1.Kick1,
		n = player.Loop1.Kick2,
		o = player.Loop1.Kick3,
		p = player.Loop1.Kick4
	})
	
print("Stats successfully saved")	
end)


--Load:
game.Players.PlayerAdded:connect(function(player)
		local datastore = game:GetService("DataStoreService"):GetDataStore(player.Name.."Loop1")
	
	player:WaitForChild("Loop1")
	
	wait(1)
	
	local stats = player:FindFirstChild("Loop1"):GetChildren()
	stats.Value = datastore:GetAsync("Loop1")
	
	print("Loaded Loop1")
end)

Personally I instal every stat into a table, and save that one table into the DataStore.

1 Like

Yes it works but there is no need to name every key using the alphabet lol

1 Like