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

What is causing many players to lose data?

Many players have said that they have lost levels after a game gets shutdown or they leave the game and join back but many players also have said this never happens to them is there an error in my datastore?

--
local Data = game:GetService("DataStoreService")
	local GrainStore = Data:GetDataStore("Grain")
	local XPStore = Data:GetDataStore("XP")
	local SpecStore = Data:GetDataStore("Element1")
	local ClanStore = Data:GetDataStore("Clan")
	local Eye1Store = Data:GetDataStore("Eyes")
	local SpecStore2 = Data:GetDataStore("Element2")
	local speshStore = Data:GetDataStore("Special")
    local JinStore = Data:GetDataStore("Jin")	
    local HairStore = Data:GetDataStore("Hair")
    local ColorStore = Data:GetDataStore("HairColor")	
    local SpinStore = Data:GetDataStore("Spins")
    local VillageStore = Data:GetDataStore("Village")
    local SageStore = Data:GetDataStore("Sage")
    local BlindStore = Data:GetDataStore("Blindness")
	local SpecsStore = Data:GetDataStore("Spec")
	local specs2Store = Data:GetDataStore("Spec2")
	local SpecStore3 = Data:GetDataStore("Element3")
	
function onPlayerEntered(newPlayer)


         
       
	 
       
		local stats = Instance.new("IntValue")
		stats.Name = "stats"
		
	local spins = Instance.new("IntValue")
        spins.Name = "Spins" 
        spins.Value = 0

       local Village = Instance.new("StringValue")
       Village.Name = "Village"
       Village.Value = "None"      
       
        local Sage = Instance.new("StringValue")
        Sage.Name = "Sage"
        Sage.Value = "None"
     
		local Grains = Instance.new("IntValue")
		Grains.Name = "Level"
		Grains.Value = 0
		
		local Color = Instance.new("StringValue")
		Color.Name = "HairColor"
		Color.Value = "Tawny"

		local XP = Instance.new("IntValue")
		XP.Name = "XP"
		XP.Value = 0
        		
		local Jin = Instance.new("IntValue")
		Jin.Name = "Jin"
		Jin.Value = 0
		
		local Hair = Instance.new("StringValue")
		Hair.Name = "Hair"
		Hair.Value = "None"
		
		
		local Chakra = Instance.new("IntValue")
		Chakra.Name = "Chakra"
		Chakra.Value = 3000
		
		local Nature = Instance.new("IntValue")
		Nature.Name = "Nature"
		Nature.Value = 5000
		
		local Blindness = Instance.new("IntValue")
		Blindness.Name = "Blindness"
		Blindness.Value = 0
		
		local Special = Instance.new("StringValue")
		Special.Name = "Element1"
		Special.Value = "None"
		
		local Special2 = Instance.new("StringValue")
		Special2.Name = "Element2"
		Special2.Value = "None"
		
		local Clan = Instance.new("StringValue")
		Clan.Name = "Clan"
		Clan.Value = "None"
		
		local Spec = Instance.new("StringValue")
		Spec.Name = "Spec"
		Spec.Value = "None"
		
		local Spec2 = Instance.new("StringValue")
		Spec2.Name = "Spec2"
		Spec2.Value = "None"
        
        local Eye1 = Instance.new("StringValue")
        Eye1.Name = "Eyes"
        Eye1.Value = "Normal"

 

        local spesh = Instance.new("StringValue")
        spesh.Name = "Special"
        spesh.Value = "Nunn"



		local Special3 = Instance.new("StringValue")
		Special3.Name = "Element3"
		Special3.Value = "None"    


        spins.Parent = stats
        Sage.Parent = stats
        Village.Parent = stats
        Color.Parent = stats
        Hair.Parent = stats
        spesh.Parent = stats
        Eye1.Parent = stats
        Jin.Parent = stats
        Clan.Parent = stats
		Grains.Parent = stats
        XP.Parent = stats
		Special.Parent = stats
		Special2.Parent = stats
		Chakra.Parent = stats
		Nature.Parent = stats
		Blindness.Parent = stats
		Spec.Parent = stats
		Spec2.Parent = stats
		Special3.Parent = stats
		stats.Parent = newPlayer

		

		if GrainStore:GetAsync("Points1_"..newPlayer.Name) ~= nil then
					Grains.Value = GrainStore:GetAsync("Points1_"..newPlayer.Name)
            else
				  Grains.Value = 0
            end
           

		if XPStore:GetAsync("Points1_"..newPlayer.Name) ~= nil then
					XP.Value = XPStore:GetAsync("Points1_"..newPlayer.Name)
            else
					XP.Value = 60
		            end
		
		
		if BlindStore:GetAsync("Points1_"..newPlayer.Name) ~= nil then
					Blindness.Value = BlindStore:GetAsync("Points1_"..newPlayer.Name)
            else
					Blindness.Value = 0
            end
           


		if SpecStore:GetAsync("Points1_"..newPlayer.Name) ~= nil then
					Special.Value = SpecStore:GetAsync("Points1_"..newPlayer.Name)
            else
					Special.Value = "None"
            end
           


		if ClanStore:GetAsync("Points1_"..newPlayer.Name) ~= nil then
					Clan.Value = ClanStore:GetAsync("Points1_"..newPlayer.Name)
            else
					Clan.Value = "None"
		            end
		
		if SpecsStore:GetAsync("Points1_"..newPlayer.Name) ~= nil then
					Spec.Value = SpecsStore:GetAsync("Points1_"..newPlayer.Name)
            else
					Spec.Value = "None"
		            end
		
		if specs2Store:GetAsync("Points1_"..newPlayer.Name) ~= nil then
					Spec2.Value = specs2Store:GetAsync("Points1_"..newPlayer.Name)
            else
					Spec2.Value = "None"
            end
           



		if Eye1Store:GetAsync("Points1_"..newPlayer.Name) ~= nil then
					Eye1.Value = Eye1Store:GetAsync("Points1_"..newPlayer.Name)
            else
					Eye1.Value = "Normal"
            end
           

		
		

		if SpecStore2:GetAsync("Points1_"..newPlayer.Name) ~= nil then
					Special2.Value = SpecStore2:GetAsync("Points1_"..newPlayer.Name)
            else
					Special2.Value = "None"
            end
           

		
		if speshStore:GetAsync("Points1_"..newPlayer.Name) ~= nil then
					spesh.Value = speshStore:GetAsync("Points1_"..newPlayer.Name)
            else
					spesh.Value = "Nun"
            end
           
      

		if JinStore:GetAsync("Points1_"..newPlayer.Name) ~= nil then
					Jin.Value = JinStore:GetAsync("Points1_"..newPlayer.Name)
            else
					Jin.Value = 0
            end
           


		if HairStore:GetAsync("Points1_"..newPlayer.Name) ~= nil then
					Hair.Value = HairStore:GetAsync("Points1_"..newPlayer.Name)
            else
					Hair.Value = "None"
            end
           


		if ColorStore:GetAsync("Points1_"..newPlayer.Name) ~= nil then
					Color.Value = ColorStore:GetAsync("Points1_"..newPlayer.Name)
            else
					Color.Value = "Tawny"
            end
           



		if SpinStore:GetAsync("Points1_"..newPlayer.Name) ~= nil then
					spins.Value = SpinStore:GetAsync("Points1_"..newPlayer.Name)
            else
					spins.Value = 5
            end
           
			
		if VillageStore:GetAsync("Points1_"..newPlayer.Name) ~= nil then
					Village.Value = VillageStore:GetAsync("Points1_"..newPlayer.Name)
            else
					Village.Value = "None"
            end
           


		if SageStore:GetAsync("Points1_"..newPlayer.Name) ~= nil then
					Sage.Value = SageStore:GetAsync("Points1_"..newPlayer.Name)
            else
					Sage.Value = "None"
            end


           if SpecStore3:GetAsync("Points1_"..newPlayer.Name) ~= nil then
					Special3.Value = SpecStore3:GetAsync("Points1_"..newPlayer.Name)
            else
					Special3.Value = "None"
            end




newPlayer.CharacterAdded:connect(function(c) 
--
--
end) 
end 

game.Players.PlayerRemoving:connect(function(newPlayer)
	VillageStore:SetAsync("Points1_"..newPlayer.Name, newPlayer.stats.Village.Value)
	 SageStore:SetAsync("Points1_"..newPlayer.Name,  newPlayer.stats.Sage.Value)
	 SpinStore:SetAsync("Points1_"..newPlayer.Name, newPlayer.stats.Spins.Value)
	  ColorStore:SetAsync("Points1_"..newPlayer.Name, newPlayer.stats.HairColor.Value)
	 HairStore:SetAsync("Points1_"..newPlayer.Name, newPlayer.stats.Hair.Value)
	  JinStore:SetAsync("Points1_"..newPlayer.Name, newPlayer.stats.Jin.Value)
	  speshStore:SetAsync("Points1_"..newPlayer.Name, newPlayer.stats.Special.Value)
	 SpecStore2:SetAsync("Points1_"..newPlayer.Name, newPlayer.stats.Element2.Value)
	  Eye1Store:SetAsync("Points1_"..newPlayer.Name, newPlayer.stats.Eyes.Value)
	 ClanStore:SetAsync("Points1_"..newPlayer.Name, newPlayer.stats.Clan.Value)
	SpecsStore:SetAsync("Points1_"..newPlayer.Name, newPlayer.stats.Spec.Value)
	specs2Store:SetAsync("Points1_"..newPlayer.Name, newPlayer.stats.Spec2.Value)
	SpecStore:SetAsync("Points1_"..newPlayer.Name, newPlayer.stats.Element1.Value)
	 XPStore:SetAsync("Points1_"..newPlayer.Name, newPlayer.stats.XP.Value)
	 BlindStore:SetAsync("Points1_"..newPlayer.Name, newPlayer.stats.Blindness.Value)
	SpecStore3:SetAsync("Points1_"..newPlayer.Name, newPlayer.stats.Element3.Value)
	GrainStore:SetAsync("Points1_"..newPlayer.Name, newPlayer.stats.Level.Value)
end)

game.Players.PlayerAdded:connect(onPlayerEntered)

1 answer

✓ Accepted answer

Improvements

Use :GetService() for the Players service

Use a table to account for adding so many variables (you could also place the values with their defaults in the StarterPlayer or ServerStorage and not have to instantiate them by hand)

Issues

Use pcall(function()) to make sure your request to ROBLOX was performed as expected, in your below code if an error occurs, the entire remainder of the thread would be broken (in addition it helps account for throttling too many requests in a short period of time)

For shutdowns, use game:BindToClose() as the :PlayerRemoving() event is not guaranteed to run in that instance

Revised Server Script

local Data = game:GetService("DataStoreService")

local statTable = {
	{"Level", "IntValue", 0}, -- "Grain"
	{"XP", "IntValue", 0},
	{"Spins", "IntValue", 0},
	{"Jin", "IntValue", 0},
	{"Blindness", "IntValue", 0},
	{"Chakra", "IntValue", 3000},
	{"Nature", "IntValue", 5000},
	{"HairColor", "StringValue", "Tawny"},
	{"Hair", "StringValue", "None"},
	{"Eyes", "StringValue", "Normal"},
	{"Village", "StringValue", "None"},
	{"Sage", "StringValue", "None"},
	{"Element1", "StringValue", "None"},
	{"Element2", "StringValue", "None"},
	{"Element3", "StringValue", "None"},
	{"Clan", "StringValue", "None"},
	{"Spec", "StringValue", "None"},
	{"Spec2", "StringValue", "None"},
	{"Special", "StringValue", "Nunn"},
}

local function CreateData(newPlayer)
	-- Instantiating Organizer
	local stats = Instance.new("IntValue")
	stats.Name = "stats"
	stats.Parent = newPlayer
	
	for _, tbl in pairs(statTable) do
		-- Create a new Instance for each Stat
		local item = Instance.new(tbl[2])
		item.Name = tbl[1]
		item.Value = tbl[3]
		
		-- Determines what DataStore to Check
		local Store = nil
		if tbl[1] == "Level" then
			Store = Data:GetDataStore("Grain")
		elseif tbl[1] ~= "Nature" and tbl[1] ~= "Chakra" then
			Store = Data:GetDataStore(tbl[1])
		end
		
		-- If the DataStore exists
		if Store then
			local LoadData = nil
			-- Provides a yield if GetAsync has an issue, instead of an error that would break the script
			local success, result = pcall(function()
				LoadData = Store:GetAsync("Points1_"..newPlayer.Name)
			end)
			
			-- if LoadData is Retrieved, set the value of the stat to it
			if success then
				if LoadData then
					item.Value = LoadData
				end
			else
				-- otherwise yield the issue, the Data did not Load properly
				warn(result)
			end
			
			-- the stat is configured, give it a parent
			item.Parent = stats
		end
	end
end

local function SaveData(newPlayer)
	for _, tbl in pairs(statTable) do
		-- find the child in the stat table in the player (yields if the stat doesn't exist)
		local item = newPlayer:WaitForChild("stats"):WaitForChild(tbl[1])
		
		-- Determine the corresponding DataStore
		local Store = nil
		if tbl[1] == "Level" then
			Store = Data:GetDataStore("Grain")
		elseif tbl[1] ~= "Nature" and tbl[1] ~= "Chakra" then
			Store = Data:GetDataStore(tbl[1])
		end
		
		-- If the Store Exists
		if Store then
			-- Update the DataStore value
			local success, result = pcall(function()
				Store:SetAsync("Points1_"..newPlayer.Name, item.Value)
			end)
			
			-- if there was an error, yield it, the Data did not Save properly
			if not success then
				warn(result)
			end
		end
	end
end

-- If a player joins the game
game:GetService("Players").PlayerAdded:Connect(function(player)
	player.CharacterAdded:Connect(function(c) 
		-- code elided
	end)
	
	CreateData(player)
end)

-- If a player voluntarily leaves the game
game:GetService("Players").PlayerRemoving:Connect(function(newPlayer)
	SaveData(newPlayer)
end)

-- If the game is shut down by a developer
game:BindToClose(function()
	for _, player in pairs(game:GetService("Players"):GetPlayers()) do
		SaveData(player)
	end
end)

These changes tell you if data was saved and what the problem with the request is, though it won't prevent people from losing some of their progress since their last save (which you can't guarantee anyway, and only occurs for stats that yield warnings)

Additonally, I would use a single table to store all player's data in one datastore, but you'd have to account for players who had data before the table was used, so the above simply preserves the data as you have it.

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