Player Experiencing Data Loss in my TD Game

Hi, right now i having a problem with my datastore but I cant find what’s wrong with it. some players lose their data for no reason in my tower defense game.

I made the datastore saving/load in a module script

Data Load:

function datastore:Load(player)

	if game.Players:FindFirstChild(player.Name) == nil then warn("Player not found; "..player.Name) return end

	local playerfolder = playerdatafolder:FindFirstChild(player.Name.." Folder")
	local datatable = {}
	local dataerrortable = {}
	local codered = false
	local success, fail = pcall(function()
		datatable = dsplayer:GetAsync("player-"..player.UserId)
	end)
	wait()
	if success then
		warn("Successfully load player data, Name: "..player.Name.." UserId: "..player.UserId)
	else
		warn("Failed to load player data, Name: "..player.Name.." UserId: "..player.UserId.." Errors; "..fail)
		replicatedstorage.GameFolder.EventFolder.PlayerEvent.LocalPrint:FireClient(player, "Your data failed to load, please report this to developers. Your data wont save after leaving the game. Error: "..fail, "Warn")
	end

	spawn(function()
		tableprintmodule.Print(datatable, player.UserId.." Data", true)
	end)

	local success, fail = pcall(function()
		for i, currency in pairs(playerfolder.PlayerCurrency:GetChildren()) do
			if currency then
				if datatable["Currency"] then
					if datatable["Currency"][currency.Name] then
						currency.Value = datatable["Currency"][currency.Name]
					end
				end
			end
		end
	end)
	if success then
		print(player.Name, "Currency Code: Green")
	else
		warn(player.Name, "Currency Code: Red")
		dataerrortable =  player.Name.." Currency Data failed to load; "..fail

	end
	
	local success, fail = pcall(function()
		for i, towerslot in pairs(playerfolder.PlayerTowerSlot:GetChildren()) do
			if towerslot  then
				if datatable["TowerSlot"] then
					if datatable["TowerSlot"]["Slot"..i] then
						towerslot.Value = datatable["TowerSlot"]["Slot"..i]
					end
				end
			end
		end
	end)
	if success then
		print(player.Name, "TowerSlot Code: Green")
	else
		warn(player.Name, "TowerSlot Code: Red")
		dataerrortable =  player.Name.." TowerSlot Data failed to load; "..fail
	end
	
	local success, fail = pcall(function()
		for i, tower in pairs(playerfolder.PlayerTower:GetChildren()) do
			if tower then
				if datatable["Tower"] then
					if datatable["Tower"][tower.Name] then
						tower.Purchased.Value = datatable["Tower"][tower.Name].Purchased
					end
				end
			end
		end
	end)
	if success then
		print(player.Name, "Tower Inv Code: Green")
	else
		warn(player.Name, "Tower Inv Code: Red")
		dataerrortable =  player.Name.." Tower Inventory Data failed to load; "..fail
	end
	
	local success, fail = pcall(function()
		for i, otherdata in pairs(playerfolder.PlayerOtherData:GetChildren()) do
			if otherdata then
				if datatable["Other"] then
					if datatable["Other"][otherdata.Name] then
						otherdata.Value = datatable["Other"][otherdata.Name]
					end
				end
			end
		end
	end)
	if success then
		print(player.Name, "Other Data Code: Green")
	else
		warn(player.Name, "Other Data Code: Red")
		dataerrortable =  player.Name.." Other Data failed to load; "..fail
	end
	
	replicatedstorage.GameFolder.EventFolder.PlayerEvent.PlayerDataLoaded:FireClient(player, player.Name)
	if codered == false then
		player.Dataloaded.Value = true
		replicatedstorage.GameFolder.EventFolder.PlayerEvent.LocalPrint:FireClient(player, "Your data successfully loaded. ", "Print")
	else
		player.Dataloaded.Value = false
		--replicatedstorage.GameFolder.EventFolder.PlayerEvent.LocalPrint:FireClient(player, "Your data failed to load, please report this to developers. Your data wont save after leaving the game.", "Warn")
		for i, logtext in ipairs(dataerrortable) do
			if logtext then
				replicatedstorage.GameFolder.EventFolder.PlayerEvent.LocalPrint:FireClient(player, logtext, "Warn")
			end
		end
	end
end

Data Saving;

function datastore:Save(player)
	if player.Dataloaded.Value == false then return end
	
	local playerfolder = playerdatafolder:FindFirstChild(player.Name.." Folder")

	local datatable = {
		["Tower"] = {};
		["Currency"] = {};
		["TowerSlot"] = {
			["Slot1"] = nil;
			["Slot2"] = nil;
			["Slot3"] = nil;
			["Slot4"] = nil;
			["Slot5"] = nil;
		};
		["Other"] = {
			["MatchID"] = "";
		};
	}

	spawn(function()
		local success, failure = pcall(function()
			for i, currency in pairs(playerfolder.PlayerCurrency:GetChildren()) do
				if currency then
					datatable.Currency[currency.Name] = currency.Value
				end
			end
			for i, towerdata in pairs(playerfolder.PlayerTower:GetChildren()) do
				if towerdata then
					datatable.Tower[towerdata.Name] = {
						["Purchased"] = towerdata.Purchased.Value
					}
				end
			end
			for i, towerslot in pairs(playerfolder.PlayerTowerSlot:GetChildren()) do
				if towerslot then
					datatable.TowerSlot[towerslot.Name] = towerslot.Value
				end
			end
			for i, otherdata in pairs(playerfolder.PlayerOtherData:GetChildren()) do
				if otherdata then
					if datatable.Other[otherdata.Name] then
						datatable.Other[otherdata.Name] = otherdata.Value
					end
				end
			end
		end)
		
		spawn(function()
			tableprintmodule.Print(datatable, player.UserId.." Data", true)
		end)
		
		if success then
			print("succcessfully load; ", player.Name, "data into table")
			
		end
		local success2, fail = pcall(function()
			dsplayer:SetAsync("player-"..player.UserId, datatable)
		end)
		if success2 then
			print("successfully save; ", player.Name)
		end
		wait(1)
		playerfolder:Destroy()
	end)
end

Any ideas on how to resolve it?, I’ve been trying to fix it for a few days since my game opened to the public. When my testers tested the game this issue never happen.

2 Likes

The DataLoss is it that players data isn’t saved but they still have their original data before joining game? Or is it a complete data reset?

The datastore:Save(player) function I would say remove the pcall local success, failure = pcall(function() reason why is because if an error occurs in that file the code will save the datatable above which has default other values. Atleast then if an error occurs in the pcall it won’t use datatable default values/

No. This is memoryStore we are talking about datastores :wink:

2 Likes

The error saving is probably from the waits try printing the result and remove waits since it just yelds it is useless in your code and deprecated also change spawn to task.spawn.
If this not work also try to add return true if sucess and return false if error

One thing I’d like to let you know is to not use SetAsync() if the player already has existing data. To update a players data that already exists in the DataStore, use UpdateAsync(), for new players that join your game for the first time and don’t have any data use SetAsync(). Using SetAsync() for updating data is a very bad practice and is reason behind most data loss problems.

You can find more about that here. Stop using SetAsync() to save player data

I also recommend checking out public modules like:

ProfileService - [ Save your player data with ProfileService! (DataStore Module) ] (Recommended as it is more feature rich and includes “session locking” to prevent item dupes)

OR

DataStore2 - [ How to use DataStore2 - Data Store caching and data loss prevention ]

Both handle issues with data loss and have many great features for saving/loading data, so you’d never have to worry about players losing their data again.

Now, as for your code the issue can lie in Roblox DataStore simply failing or you have updated player data with something blank. What we can do is to find the actual issue and we can do that by logging data saves.

I can see that your pcall function in Data Saving, at the bottom of the script, where youu :SetAsync() the users data, doesn’t actually handle the “fail” circumstance (What if success2 isn’t true? That would mean saving has failed due to an error! But considering you don’t handle that case anywhere in your script, if saving fails the script just doesn’t do anything about it and proceeds with the rest of the script, which is deleting the playerFolder after a second).

You should handle success2 if it’s not true, as it would mean the script failed to save to DataStore. You can add a logger to it that would let you know if user data has failed to save so you can determine the issue closer and handle it.

Also, check the data of players who are reporting data losses. If the data structure (datatable) is present but the data for each entry is nil, then it must mean your script isn’t properly saving the data. That can also help you with finding out the cause of data issues.

Hope this is of help, pleasure to assist you further.

2 Likes

Thank you for all of your feedback.

Right now I’m using Profileservices as my datastore module (and easy to learn). Thanks for your recommendation.