Datastore difficulties

Expected behavior

  1. Player taps “Spin” button
  2. New BoolValue is created in players inventory folder
  3. Player leaves
  4. Player rejoins and the new data still exist

Actual behavior

  1. Player taps “Spin” button
  2. New BoolValue is created in players inventory folder
  3. Player leaves
  4. Player Rejoins and the data is gone (this is what I want to solve)

local Players = game:GetService("Players")
local DataStoreService = game:GetService("DataStoreService")
local DataStore = DataStoreService:GetDataStore("leaderstats")
local RunService = game:GetService("RunService")
local ReplicatedStorage = game:GetService("ReplicatedStorage")

local Data = {
	Strength = 0;
	Rebirths = 0;
	Cash = 1000;
	Speed = 20;
	Items = 0;
	Inventory = nil
}



local playersavetable = {};

local function loadStarterData(Player)
		local leaderstats = Instance.new("Folder")
		leaderstats.Name = "leaderstats"
		leaderstats.Parent = Player
		local Inventory = Instance.new("Folder")
		Inventory.Name = "Inventory"
		Inventory.Parent = leaderstats
		for statname, statvalue in pairs(Data) do
			if type(statvalue) == 'number' then
			local intvalue = Instance.new("IntValue")
			intvalue.Name = statname
			intvalue.Value = statvalue
			intvalue.Parent = leaderstats
			else if type(statvalue) == 'boolean' then
			local intvalue = Instance.new("BoolValue")
			intvalue.Name = statname
			intvalue.Value = statvalue
			intvalue.Parent = Inventory
		end
	end
		end
		end

local function loadData(player)
	local Data
	local s, e = pcall(function()
	Data = DataStore:GetAsync('UserId'..player.UserId)
	end)
	
	if s then 
		print (player.Name.."Data loaded")
	else
		print(player.Name.."Data failed to load")
	end
	
	if Data then
		for statname, statvalue in pairs(Data) do
			if type(statvalue) == "number" then
			player.leaderstats[statname].Value = statvalue
			else if type(statvalue) == "boolean" then
			player.leaderstats.Inventory[statname].Value = statvalue
			end
			end
		end
		print(player.Name.."Data has been loaded")
	else
		print(player.Name.."No data found! generating..")
		end
	end

local function saveData(player)
	--if RunService:IsStudio() then return end
	local Data = {}
	for _, stat in ipairs(player.leaderstats:GetChildren()) do
   if not stat:IsA("Folder") then
       Data[stat.Name] = stat.Value
   end
end
	local s, e = pcall(function()
		DataStore:SetAsync('UserId'..player.UserId, Data)
	end)
		if s then 
	print(player.Name.."Data has been saved")
		else
	warn (player.Name.."Data failed to save"..e)
	end
end

ReplicatedStorage.SaveEvent.OnServerEvent:Connect(function(player)
 saveData(player)	
end)

Players.PlayerAdded:Connect(function(player)
	playersavetable[player] = tick()
	loadStarterData(player)
	loadData(player)
end)

Players.PlayerRemoving:Connect(function(player)
	saveData(player)
end)

This script has no errors in the output so I have no clue what is wrong with it. I have tried looking on some other places on the devforum and tweaking the script myself but It has not helped matters much.

If anyone has any questions then feel free to ask!

NOTE: The “spinner” I mentioned Is a modified version of this open source spinner Creating a Crate/Spin System

It’s most likely due to the server not being able to save the player’s data fast enough, which means you’re trying to get the parent of nil. This is most likely why you saw no errors (since it’s on leave).
You could try implementing a connection in the PlayerAdded, like this:

Players.PlayerAdded:Connect(function(player)
	playersavetable[player] = tick()
	loadStarterData(player)
	loadData(player)
   
   local leaderstats = player:WaitForChild("leaderstats")
   
   Players.PlayerRemoving:Connect(function(vplayer)
      if vplayer == player then
         saveData(vplayer)
      end
   end)
end)

This would require some extra work (since you’d have to possibly add in something to check if there is a leaderstats arg), but most likely solves your problem.

What does vplayer mean?

30chars

It’s just the variable zQ86 is using for the player leaving the server.

1 Like

I tried adding this to the code that you provided

local Inventory = player:WaitForChild("Inventory")

I thought this would also wait for the Inventory folder but that idea didn’t work.

You mention me trying to save data to fast? would it fix it to just add a wait(2) to saving and loading?

EDIT: Replied to myself by mistake, sorry.

No. I said the error is probably due to the server not being able to save the player’s data fast enough. Slowing it down more wouldn’t give enough time. Like I said at the end of my post:

Oh, by the way, you did player:WaitForChild("Inventory") instead of leaderstats:WaitForChild("Inventory").

1 Like

I made a tutorial that covers data potentially not saving because of server shutting down too quick. How to properly save player data in data stores upon server close

1 Like

OP’s problem isn’t about the server shutting down and player data not being saved, but instead about a player leaving and their data not saving.

Which falls back to the server shutting down when they leave. If the data is not saving, it’s through fault of OP’s code, or the server closing too quick. You yourself replied with this.

1 Like
local Data = {
	Strength = 0;
	Rebirths = 0;
	Cash = 1000;
	Speed = 20;
	Items = 0;
	Inventory = nil
}

I tried changing

Inventory = nil

to

Inventory = {}

I am unsure if thats a better method if we are going to be saving stuff in the players Inventory

That’s most likely unimportant to the problem you have, as you were only changing a nil variable to a table. It’s due to how you’re trying to save it. You could try using Datastore2 and seeing if the player doesn’t lose their data.

Is there anyway I can just make my script for datastore2 without rewriting the whole thing? My game is unreleased so data loss isn’t a concern.

You could keep the basics of what you did without Datastore2 and transfer it. It’s best you keep the original script as a reference.

I can not find anything like what I am doing for datastore2 when looking on the devforum

I am referring to this part of the code

local Data = {
	Strength = 0;
	Rebirths = 0;
	Cash = 1000;
	Speed = 20;
	Items = 0;
	Inventory = nil
}



local playersavetable = {};

local function loadStarterData(Player)
		local leaderstats = Instance.new("Folder")
		leaderstats.Name = "leaderstats"
		leaderstats.Parent = Player
		local Inventory = Instance.new("Folder")
		Inventory.Name = "Inventory"
		Inventory.Parent = leaderstats
		for statname, statvalue in pairs(Data) do
			if type(statvalue) == 'number' then
			local intvalue = Instance.new("IntValue")
			intvalue.Name = statname
			intvalue.Value = statvalue
			intvalue.Parent = leaderstats
			else if type(statvalue) == 'boolean' then
			local intvalue = Instance.new("BoolValue")
			intvalue.Name = statname
			intvalue.Value = statvalue
			intvalue.Parent = Inventory
		end
	end
		end
		end

local function loadData(player)
	local Data
	local s, e = pcall(function()
	Data = DataStore:GetAsync('UserId'..player.UserId)
	end)
	
	if s then 
		print (player.Name.."Data loaded")
	else
		print(player.Name.."Data failed to load")
	end
	
	if Data then
		for statname, statvalue in pairs(Data) do
			if type(statvalue) == "number" then
			player.leaderstats[statname].Value = statvalue
			else if type(statvalue) == "boolean" then
			player.leaderstats.Inventory[statname].Value = statvalue
			end
			end
		end
		print(player.Name.."Data has been loaded")
	else
		print(player.Name.."No data found! generating..")
		end
	end

local function saveData(player)
	--if RunService:IsStudio() then return end
	local Data = {}
	for _, stat in ipairs(player.leaderstats:GetChildren()) do
   if not stat:IsA("Folder") then
       Data[stat.Name] = stat.Value
   end
end
	local s, e = pcall(function()
		DataStore:SetAsync('UserId'..player.UserId, Data)
	end)
		if s then 
	print(player.Name.."Data has been saved")
		else
	warn (player.Name.."Data failed to save"..e)
	end
end

everything I’ve seen on datastore2 makes to process of creating and saving data much more manual and tedious, am I missing something?

Datastore2 prevents data loss more than the Datastore service does. Also, your SaveData function should have two extra args (since you’re connecting the PlayerRemoved event to the PlayerAdded event.)

I am aware of the advantages of datastore2, I am saying that from the examples and threads I have seen that the whole procces seems more manual and tedious. I mean like all the variables are created manually rather then just a few simple lines of code.


local function loadStarterData(Player)
		local leaderstats = Instance.new("Folder")
		leaderstats.Name = "leaderstats"
		leaderstats.Parent = Player
		local Inventory = Instance.new("Folder")
		Inventory.Name = "Inventory"
		Inventory.Parent = leaderstats
		for statname, statvalue in pairs(Data) do
			if type(statvalue) == 'number' then
			local intvalue = Instance.new("IntValue")
			intvalue.Name = statname
			intvalue.Value = statvalue
			intvalue.Parent = leaderstats
			else if type(statvalue) == 'boolean' then
			local intvalue = Instance.new("BoolValue")
			intvalue.Name = statname
			intvalue.Value = statvalue
			intvalue.Parent = Inventory
		end
	end
		end
		end

same with loading

	if Data then
		for statname, statvalue in pairs(Data) do
			if type(statvalue) == "number" then
			player.leaderstats[statname].Value = statvalue
			else if type(statvalue) == "boolean" then
			player.leaderstats.Inventory[statname].Value = statvalue
			end
			end
		end

I have seen NOTHING like this for datastore2 so I am sorta stuck.

Then you should do some testing with Datastore2. Please read the rest of the reply too, since it’s likely important to help you.

Yes, I read the whole reply. I tried those two functions and I even tried modifying your suggestion when it failed.

and I also fixed my little mistake but got the same results

Could you send me the modified version of your PlayerAdded/Removing scripts?

Players.PlayerAdded:Connect(function(player)
	playersavetable[player] = tick()
	loadStarterData(player)
	loadData(player)
   
   local leaderstats = player:WaitForChild("leaderstats")
   local Inventory = leaderstats:WaitForChild("Inventory")
   
   Players.PlayerRemoving:Connect(function(vplayer)
      if vplayer == player then
         saveData(vplayer)
      end
   end)
end)

The modification was the one line of code as I mentioned earlier.