Scripting HelpersARCHIVE
A little piece of Roblox history. Preserved for everyone, one question at a time.Read about the archive →
✓ ANSWER ACCEPTED

Why does DataStore only save the Stats and not the BoolValues?

Hi!

I can't get my DataStore script to save the Tools purchased. I don't know why. I don't get any error for it. The leaderstats save, the Tools do not. I've included my entire Leaderboard/DataStore script.

I've included two versions I've been advised to try for the DataStore, the first one tries to save it into a Folder, the second one checks for BoolValues, but neither one will save the Tools, just the leaderstats.

First attempt with a Folder:

game.Players.ChildAdded:connect(function(newPlayer)
	local stats = Instance.new('IntValue')
	stats.Name = 'leaderstats'
	
	local points = Instance.new('IntValue', stats)
	points.Name = 'Points'
	points.Value = 0
	
	local experience = Instance.new('IntValue', stats)
	experience.Name = 'EXP'
	experience.Value = 0
	
	local wins = Instance.new('IntValue', stats)
	wins.Name = 'Wins'
	wins.Value = 0
	
	local kills = Instance.new('IntValue', stats)
	kills.Name = 'Kills'
	kills.Value = 0
	
	local level = Instance.new('IntValue', stats)
	level.Name = 'Level'
	level.Value = 1


	
-- MAX HEALTH INCREASE
if newPlayer.Character and newPlayer.Character:FindFirstChild("Humanoid") then
    newPlayer.Character.Humanoid.MaxHealth = 100 + level.Value*10
end

level.Changed:connect(function(value)
    if newPlayer.Character and newPlayer.Character:FindFirstChild("Humanoid") then
        newPlayer.Character.Humanoid.MaxHealth = 100 + level.Value*10
    end
end)

newPlayer.CharacterAdded:connect(function(character)
    character:WaitForChild("Humanoid").MaxHealth = 100 + level.Value*10
end)


-- EXP NEEDED TO LEVEL UP	
experience.Changed:connect(function()
    local required=(level.Value*70) -- Number reflects the EXP points needed to level up.
    if experience.Value >= required then
        level.Value=level.Value+1
        experience.Value=experience.Value-required 
 			end
end)	
	
--DATASTORE
	
	stats.Parent = newPlayer
	local datastore = game:GetService("DataStoreService"):GetDataStore(newPlayer.Name.."Stats")
	local tools = game.ServerStorage.ToolStorage;-- ADDED FOR TOOLS
	
	local stats = stats:GetChildren()
    for i = 1, #stats do           
    	stats[i].Value = datastore:GetAsync(stats[i].Name)
		print("stat number "..i.." has been found")
	end
	
	local save_interval = 60 * 2 -- every 2 minutes
	wait(save_interval)
	
	while newPlayer.Parent do
		local stats = newPlayer.leaderstats:GetChildren()
	    for i = 1, #stats do           
	    	datastore:SetAsync(stats[i].Name, stats[i].Value)
			print("stat number "..i.." has been auto-saved")
	end
		local data = false
	print("DataStoreBackSave1")
	newPlayer.CharacterAdded:connect(function(char) -- this will run everytime the Player's Character has been added in workspace.
		if not data then
			data = datastore:GetAsync(newPlayer.UserId);
		end
		
		if data then
			--If it does, loop and clone respective tools.
			for _,v in next,data do
				local tool = tools:FindFirstChild(v);
				if tool then
					tool:Clone().Parent = newPlayer.Backpack;
				end
			end
		end
	end)
end
		
		wait(save_interval)
end)

game.Players.ChildRemoved:connect(function(oldPlayer)
	local datastore = game:GetService("DataStoreService"):GetDataStore(oldPlayer.Name.."Stats")
	
	local stats = oldPlayer.leaderstats:GetChildren()
    for i = 1, #stats do           
    	datastore:SetAsync(stats[i].Name, stats[i].Value)
		print("stat number "..i.." has been saved")
		
	 --Make a table to hold all the data
    local toolList = {};

    --Iterate through the backpack and fill the table in

    for _,v in next,oldPlayer.Backpack:GetChildren() do
        --Make sure it's actually a tool

        if v:IsA("Tool") or v:IsA("HopperBin") then
            toolList[#toolList+1] = v.Name;
        end
    end
    --Save the table

    datastore:SetAsync(oldPlayer.UserId,toolList);
end
print("DataStoreBackSave2")
end)

Second attempt with BoolValues:

stats.Parent = newPlayer
    
    local datastore = game:GetService("DataStoreService"):GetDataStore(newPlayer.Name.."Stats")
    
    local stats = stats:GetChildren()
    for i = 1, #stats do          
        stats[i].Value = datastore:GetAsync(stats[i].Name)
        print("stat number "..i.." has been found")
    end
    
    local save_interval = 60 * 2 -- every 2 minutes
    
    wait(save_interval)
    
    while newPlayer.Parent do
        local stats = newPlayer.leaderstats:GetChildren()
        for i = 1, #stats do           
            datastore:SetAsync(stats[i].Name, stats[i].Value)
            print("stat number "..i.." has been auto-saved")
        end
        
        wait(save_interval)
    end


newPlayer.PlayerGui:WaitForChild("HasM9").Changed:Connect(function()
if newPlayer.PlayerGui.HasM9.Value == true then
local DataStorem9 = game:GetService("DataStoreService"):GetDataStore("HasM9")
game.ServerStorage.ToolStorage.M9:Clone().Parent = newPlayer.Backpack
DataStorem9:SetAsync(newPlayer.userId, true)

end
end)


end)



game.Players.ChildRemoved:connect(function(oldPlayer)
    local datastore = game:GetService("DataStoreService"):GetDataStore(oldPlayer.Name.."Stats")
    
    local stats = oldPlayer.leaderstats:GetChildren()
    for i = 1, #stats do          
        datastore:SetAsync(stats[i].Name, stats[i].Value)
        print("stat number "..i.." has been saved")
end


oldPlayer.PlayerGui:WaitForChild("HasM9").Changed:Connect(function()
if oldPlayer.PlayerGui.HasM9.Value == true then
local DataStorem9 = game:GetService("DataStoreService"):GetDataStore("HasM9")
DataStorem9:SetAsync(oldPlayer.userId, true)

end
end)

end)

I could really appreciate some help here, this has been bothering me for months now. x.x

10 comments

0

You should be able to.

0

I agree, but it doesn't. When the player dies, or leaves the game and returns, the item is no longer in their backpack.

0

would you like to see my data store

0

Sure! Would be happy to see one that saves the tools! :) Sent a friend request.

0

will do tommorow as on my phone of now

0

^ Many thanks good sir! :)

0

https://uploadfiles.io/ <<read your roblox messages for instructions

0

Ah! Saw this late, sent the message, uploaded the file - https://ufile.io/lswdu

0

I uploaded on google drive because it was easier

1 answer

✓ Accepted answer

Unfortunately, your question was a bit more complex than I though it was, but I am sure I can still answer it.
Step 1. You want to create a folder of bool values in the player, each one named for ex: HasM9, HasM82 etc, each one should be false.
Then you want to create your data-store, I haven't changed mine to fit your question, but I have added lots of comments so you know what to do with the code.
Note : You should save tables on your keys, not individual values, each key can take alot, and it will lower how many times you access the data-store, lowering the chance of the data store budget being reached. Make sure to also use one datastore, not lots of datastores, unless each datastore holds different types of data, e.g XP datastore, Gun datastore etc. Your datastore should have a Unique name, this prevents the data you have saved being overwritten by data that has been saved in other games, also make sure your keys have unique names, and use Player.UserId, because if a player changes their name, they lose all of their data.
A Module script, in ServerScriptService

local module = {}
local DataStoreService = game:GetService("DataStoreService") --get DataStoreService
local InventoryItems = DataStoreService:GetDataStore("InventoryItems") --Change it to whatever you want to call it e.g :GetDataStore("examplename"), should be complex name
AUTOSAVE_INTERVAL = 120 --should be no lower than 60 (DataStore Budget)

game.Players.PlayerAdded:Connect(function(Player) --When a player is added to the game, load in their data
	local Key = 'PlayerIdNum-'..Player.UserId.."_InvItemKey" --"This is the key you use to save players data on (must be no longer than 50 characters and must be unique)
	--The key is also what you use to load data as well so it MUST be the exact same variable in the other parts of the script
	--Values to Save (create them also, e.g instance.new)
	local InvData = Player:WaitForChild("Backpack"):WaitForChild("Inventory") --The folder of values you want to save
	local Bananas = InvData:WaitForChild("Bananas")
	local Apples = InvData:WaitForChild("Apples")
	local FirstAid = InvData:WaitForChild("FirstAid")
	local Coconuts = InvData:WaitForChild("Coconuts")
	local MetalScraps = InvData:WaitForChild("MetalScraps")
	local Logs = InvData:WaitForChild("Logs")
	local Sticks = InvData:WaitForChild("Sticks")
	
	
	--DataStore Stuff
	--The table that is used to save it after it is all loaded in
	local StoreToSet = {}
	--Get the data and store it
	local DataToGet = InventoryItems:GetAsync(Key) --Returns the data the key stores (as a table)
	--Changing the table back into values
	if DataToGet ~= nil then --If there is a table
		if #DataToGet >= 1 then --If the table length is 1 or more
			print("Has Data")
			--For each value you have, copy the below code (MUST BE IN ORDER OF SAVED IN!)
			if DataToGet[1] ~= nil then --if the first bit of data in the table does exist
				Bananas.Value = DataToGet[1] --Set the values of bananas as that value
				table.insert(StoreToSet , DataToGet[1]) --Store it in another table so it can be saved
			end
			if DataToGet[2] ~= nil then
				Apples.Value = DataToGet[2]
				table.insert(StoreToSet , DataToGet[2])
			end
			if DataToGet[3] ~= nil then
				FirstAid.Value = DataToGet[3]
				table.insert(StoreToSet , DataToGet[3])
			end
			if DataToGet[4] ~= nil then
				Coconuts.Value = DataToGet[4]
				table.insert(StoreToSet , DataToGet[4])
			end
			if DataToGet[5] ~= nil then
				MetalScraps.Value = DataToGet[5]
				table.insert(StoreToSet , DataToGet[5])
			end
			if DataToGet[6] ~= nil then
				Logs.Value = DataToGet[6]
				table.insert(StoreToSet , DataToGet[6])
			end
			if DataToGet[7] ~= nil then
				Sticks.Value = DataToGet[7]
				table.insert(StoreToSet , DataToGet[7])
			end
		print(DataToGet[1], DataToGet[2], DataToGet[3], DataToGet[4], DataToGet[5], DataToGet[6], DataToGet[7] .. " Data") --Print the data values
		end
	else
		DataToGet = {} --Create a table, since there was no data or table returned in the GetAsync (this only happens with new players)
		DataToGet[1] = Bananas.Value --The first bit of data in the table is equal to Bananas.Value
		Bananas.Value = 0 --Make sure it is 0
		table.insert(StoreToSet , DataToGet[1]) --Insert it into table, so it can be saved, so next time they join, it loads a table
		DataToGet[2] = Apples.Value
		Apples.Value = 0
		table.insert(StoreToSet , DataToGet[2])
		DataToGet[3] = FirstAid.Value
		FirstAid.Value = 0
		table.insert(StoreToSet , DataToGet[3])
		DataToGet[4] = Coconuts.Value
		Coconuts.Value = 0
		table.insert(StoreToSet , DataToGet[4])
		DataToGet[5] = MetalScraps.Value
		MetalScraps.Value = 0
		table.insert(StoreToSet , DataToGet[5])
		DataToGet[6] = Logs.Value
		Logs.Value = 0
		table.insert(StoreToSet , DataToGet[6])
		DataToGet[7] = Sticks.Value
		Sticks.Value = 0
		table.insert(StoreToSet , DataToGet[7])
		print(DataToGet[1], DataToGet[2], DataToGet[3], DataToGet[4], DataToGet[5], DataToGet[6], DataToGet[7] .. " New Data") --Print new data (all should be 0)
	end
	InventoryItems:SetAsync(Key, StoreToSet) --Set the data to the key as a table, so next time they join there is a table to load in (only affects the first time they join)
end)

game.Players.PlayerRemoving:Connect(function(Player) --When the player leaves the game, save their data
	local Key = 'PlayerIdNum-'..Player.UserId.."_InvItemKey" --"This is the key you use to save players data on (must be no longer than 50 characters and must be unique)
	--The key is also what you use to load data as well so it MUST be the exact same variable in the other parts of the script
	--Values to Save
	local InvData = Player:WaitForChild("Backpack"):WaitForChild("Inventory")
	local Bananas = InvData:WaitForChild("Bananas")
	local Apples = InvData:WaitForChild("Apples")
	local FirstAid = InvData:WaitForChild("FirstAid")
	local Coconuts = InvData:WaitForChild("Coconuts")
	local MetalScraps = InvData:WaitForChild("MetalScraps")
	local Logs = InvData:WaitForChild("Logs")
	local Sticks = InvData:WaitForChild("Sticks")
	--Put what you need to save here (THE ORDER YOU USE IN THIS IS THE ORDER YOU MUST USE WHEN THEY JOIN)
	local DataToSave = {
		Bananas.Value, --must put.Value after or it will error
		Apples.Value,
		FirstAid.Value,
		Coconuts.Value,
		MetalScraps.Value,
		Logs.Value,
		Sticks.Value,
	}
	InventoryItems:SetAsync(Key, DataToSave)
end)

--You may want to reorder this
--Autosaving
spawn(function()
	while wait(AUTOSAVE_INTERVAL) do
		for i, Player in pairs (game:GetService("Players"):GetChildren()) do --for every player in the game, save
			print("Auto-saving " .. Player.Name .. "'s Data")
			local Key = 'PlayerIdNum-'..Player.UserId.."_InvItemKey"
			local InvData = Player:WaitForChild("Backpack"):WaitForChild("Inventory")
			local Bananas = InvData:WaitForChild("Bananas")
			local Apples = InvData:WaitForChild("Apples")
			local FirstAid = InvData:WaitForChild("FirstAid")
			local Coconuts = InvData:WaitForChild("Coconuts")
			local MetalScraps = InvData:WaitForChild("MetalScraps")
			local Logs = InvData:WaitForChild("Logs")
			local Sticks = InvData:WaitForChild("Sticks")
			local DataToSave = {
				Bananas.Value,
				Apples.Value,
				FirstAid.Value,
				Coconuts.Value,
				MetalScraps.Value,
				Logs.Value,
				Sticks.Value,
			}
			InventoryItems:SetAsync(Key, DataToSave)
			print("Successfully Auto-saved " .. Player.Name .. "'s Data")
		end
	end
end)

return module

A normal script, but a child/decendent of/inside of the module script

require(script.Parent)

After this, you will want another script that reads the values and gives them the tools based on the bool value, e.g:(local)

local player = game.Players.LocalPlayer
if player.Folder.HasM9.Value == true then
	local m9 = game.replicatedstorage.M9:Clone()
	m9.Parent = player.Backpack
end

I hope you can edit the script I have provided, to help you with your problem, if it has helped, please remember to accept the answer! :)

14 comments

0

Good sir, thank you for this amazing response. I've followed your instructions, changed what needed to be changed, but unfortunately, its still not saving the items. I feel the error must be on me here, as your script looks excellent and makes sense. Line 10 and Line 120, per the DevConsole is where my script ends, "Stack End". The message I receive is -

0

"Infinite yield possible on 'Players.PlayerName.Backpack:WaitForChild("Inventory")' I wonder if the problem is due to me storing the values inside a folder named 'Inventory' inside PlayerGui? Is there a different way I should phrase it?

0

Wait, do I also need a Custom Inventory for this script to work properly?

0

I just put it as a folder inside of player with the valus in it not custom just make sure everything is spelled correctly and in the write place e.g you said it was playergui so you would do Player:WaitForChild ("PlayerGui"):WaitForChild ("Inventory") but make sure that the folder is called Inventory and its spelled correctly

0

Thanks for the response, I made sure it says Player:WaitForChild ("PlayerGui"):WaitForChild ("Inventory") , same error, Stack is ending on it at Line10, I made sure the Inventory folder inside PlayerGui with the Values is spelled correctly. The BoolValues are successfully enabling when purchased, and stay enabled after player death, but even when the Tool can be seen inside StarterGear, it doesn't

0

clone back into the backpack. Or save when the player leaves the game and return. Also getting an error for that third script, which I named "ToolGiverCheck": 19:52:27.371 - ServerScriptService.ToolsDataStore.ToolGiverCheck:2: attempt to index local 'player' (a nil value) Do I need to keep that script apart from the ToolsDataStore?

0

Keep the last script seperate (its meant to be in the player, and be a local script) and I reccomemd you put inventory folder in the players backpack (put it in starterpack, if not creating with instance .new)

0

If you accept this answer and create a new question with all of your scripts and say where everything is located I can help you more

0

And just noticed your previous comment, pasted the link above - https://ufile.io/lswdu

0

I sent you a message on Roblox, but still having some problems here. :( It doesn't recognize StarterPack as a valid member of Player.

0

Thats because starterpaxk isn't park of plaer. it is backpack in player.

0

Excellent! Okay,in the ToolGiverCheck that was getting hung up, I replaced the "StarterPack" with "Backpack". The script no longer stopped, but it keeps cloning the purchased Tool until the player dies. XD; Aside from that, its still not saving the Tools, or the Stats now, once a player dies/leaves the game.

1

I really don't know then. Best to create a new question with all your new code

0

I will do that (edit: have)! Thank you very much for all your help! :) Couldn't have gotten this far without you!

This discussion is preserved as it was. New answers, comments, and votes are closed.