My DataStore is not Saving my Data Table. It doesn't work half of the time

  1. What do you want to achieve?
    I want my script to save and load the player’s data 100% of the time, if possible. (Probably not)

  2. What is the issue?
    The Data Store script I wrote is only working 50% of the time, according to my players. It either doesn’t save or load the player’s data properly, they start losing their data when they continue to play the game.

  3. What solutions have you tried so far?
    I’ve tried to scour all over the DevForum, but I couldn’t find a problem similar to mine. If there is a topic that is similar please tell me, I’m desperate here.

By the way, all of the data is being stored within Replicated Storage. Also my game is single player, so if that helps the solution please help me.

Server Script in ServerScriptService

--Data Store
local DataStoreService = game:GetService("DataStoreService")
local PlayerDataStore = DataStoreService:GetDataStore("PlayerData")

local players = game:GetService("Players")

local function saveData(player)
	local playerData = {
		game.ReplicatedStorage.PlayerData.GotFlashDrive.Value;
		game.ReplicatedStorage.PlayerData.GotWeaponParts.Value;
		game.ReplicatedStorage.PlayerData.GotArmor.Value;
		game.ReplicatedStorage.PlayerData.P9Ammo.Value;
		game.ReplicatedStorage.PlayerData.P9MaxAmmo.Value;
		game.ReplicatedStorage.PlayerData.MaleFlag.Value;
		game.ReplicatedStorage.PlayerData.FemaleFlag.Value;
		game.ReplicatedStorage.PlayerData.GotAshley.Value;
		game.ReplicatedStorage.PlayerData.GotCrowbar.Value;
		game.ReplicatedStorage.PlayerData.SavedM4A1Ammo.Value;
		game.ReplicatedStorage.PlayerData.SavedM4A1MaxAmmo.Value;
		game.ReplicatedStorage.PlayerData.Saved870Ammo.Value;
		game.ReplicatedStorage.PlayerData.Saved870MaxAmmo.Value;
		game.ReplicatedStorage.PlayerData.GotM4A1.Value;
		game.ReplicatedStorage.PlayerData.GotShotgun.Value
	}
	print("The player has probably saved data!")
	return playerData
end

local function setUp(player)
	local userID = player.UserId
	local key = "Player_"..userID

	local flashDrive = game.ReplicatedStorage.PlayerData.GotFlashDrive
	local weaponParts = game.ReplicatedStorage.PlayerData.GotWeaponParts
	local gotArmor = game.ReplicatedStorage.PlayerData.GotArmor
	local P9Ammo = game.ReplicatedStorage.PlayerData.P9Ammo
	local P9MaxAmmo = game.ReplicatedStorage.PlayerData.P9MaxAmmo
	local male = game.ReplicatedStorage.PlayerData.MaleFlag
	local female = game.ReplicatedStorage.PlayerData.FemaleFlag
	local gotAshley = game.ReplicatedStorage.PlayerData.GotAshley
	local gotCrowbar = game.ReplicatedStorage.PlayerData.GotCrowbar
	local M4A1Ammo = game.ReplicatedStorage.PlayerData.SavedM4A1Ammo
	local M4A1MaxAmmo = game.ReplicatedStorage.PlayerData.SavedM4A1MaxAmmo
	local remingtonAmmo = game.ReplicatedStorage.PlayerData.Saved870Ammo
	local remingtonMaxAmmo = game.ReplicatedStorage.PlayerData.Saved870MaxAmmo
	local gotM4A1 = game.ReplicatedStorage.PlayerData.GotM4A1
	local gotRemington = game.ReplicatedStorage.PlayerData.GotShotgun

	local data
	local success, err = pcall(function()
		data = PlayerDataStore:GetAsync(key)
	end)

	if success and data then
		print("The player had a success, right? ",success)
		flashDrive.Value = data[1]
		weaponParts.Value = data[2]
		gotArmor.Value = data[3]
		P9Ammo.Value = data[4]
		P9MaxAmmo.Value = data[5]
		male.Value = data[6]
		female.Value = data[7]
		gotAshley.Value = data[8]
		gotCrowbar.Value = data[9]
		M4A1Ammo.Value = data[10]
		M4A1MaxAmmo.Value = data[11]
		remingtonAmmo.Value = data[12]
		remingtonMaxAmmo.Value = data[13]
		gotM4A1.Value = data[14]
		gotRemington.Value = data[15]
	else
		print("Uh oh... Player didnt get the data.")
		print(err)
	end
end

players.PlayerAdded:Connect(setUp)

players.PlayerRemoving:Connect(function(player)
	task.wait(2)
	local success, err = pcall(function()
		return PlayerDataStore:UpdateAsync(player.UserId, saveData)
	end)
	if success then
		print("Saved players data?")
	else
		warn("Player Removing, ", err)
	end
	task.wait(2)
end)

game:BindToClose(function(player)
	task.wait(2)
	local success, err = pcall(function()
		return PlayerDataStore:UpdateAsync(player.UserId, saveData)
	end)
	if success then
		print("Saved players data?")
	else
		warn("Bind To Close ", err)
	end
	task.wait(2)
end)

BindToClose doesnt provide a player argument

i think this is the issue, if the datastore fails to load it overwrites the save data when the player leaves as it doesnt store whether the data successfully loaded or not
If you do this though, you need to make sure new players with nil save data dont get marked as failure to load
you should add retries and sanity checks

So I should add some repeats – until saves?
Also what are sanity checks, if you don’t mind me asking?

why add task.wait?, it dont make sense

Can I ask why you’re storing data in replicated storage? It just seems really strange…

Also even if you need to keep the data on the server for some reason, why? You stated it’s a single player game so the server is only going to be up while they are in the server so it’s not like you need to keep the data for other players that could join

As the person above said, why are you storing the values in Replicated Storage, it is unnecessary.

Store the players data in a table.

If you need to get the players data in another script, there are many ways to do so without having to make value instances, for example you can use _G or shared, or BindableFunctions.

Here is a script that uses _G to store the data so you can access it from other scripts.

-- # Services
local Players = game:GetService('Players')
local DataStoreService = game:GetService('DataStoreService')

-- # Data Store
local DataStore = DataStoreService:GetDataStore('UserData')

-- # Data Template
local DataTemplate = {
	['GotFlashDrive'] = false;
	['GotWeaponParts'] = false;
	['GotArmor'] = false;
	
	['P9Ammo'] = 0;
	['P9MaxAmmo'] = 0;
	
	['MaleFlag'] = '';
	['FemaleFlag'] = '';
	
	['GotAshley'] = false;
	['GotCrowbar'] = false;
	
	['SavedM4A1Ammo'] = 0;
	['SavedM4A1MaxAmmo'] = 0;
	
	['Saved870Ammo'] = 0;
	['Saved870MaxAmmo'] = 0;
	
	['GotM4A1'] = false;
	['GotShotgun'] = false;
}

-- # Profiles
_G.Profiles = {}

-- # Functions
local function PlayerAdded(player: Player)
	local UserId: number = player.UserId
	
	local Succ, Data = pcall(function()
		return DataStore:GetAsync(tostring(UserId))
	end)
	
	if Succ and typeof(Data) == 'table' then
		_G.Profiles[player] = Data
	else
		_G.Profiles[player] = DataTemplate
	end
end

local function PlayerRemoving(player: Player)
	local UserId: number = player.UserId
	
	local Attempts = 0
	
	while true do
		local Succ, err = pcall(function()
			DataStore:SetAsync(tostring(UserId), _G.Profiles[player])
		end)
		
		Attempts += 1
		
		if Succ == true then
			break
		else
			if Attempts >= 10 then
				break
			end
		end
		
		task.wait(3)
	end
	
	_G.Profiles[player] = nil
end

-- # Connections
for _, v in ipairs(Players:GetPlayers()) do
	PlayerAdded(v)
end

Players.PlayerAdded:Connect(PlayerAdded)
Players.PlayerRemoving:Connect(PlayerRemoving)

game:BindToClose(function()
	for _, v in ipairs(Players:GetPlayers()) do
		PlayerRemoving(v)
	end
end)

Some other script:

-- # Services
local Players = game:GetService('Players')

-- # Functions
local function PlayerAdded(player: Player)
	task.wait(5)
	
	-- # Get Players Data
	local Profile = _G.Profiles[player]
	print(Profile)
	
	-- # Set Player Data
	_G.Profiles[player]['P9Ammo'] = 50
end

-- # Connections
for _, v in pairs(Players:GetPlayers()) do
	PlayerAdded(v)
end

Players.PlayerAdded:Connect(PlayerAdded)

I put the values in replicated storage because I didn’t know how to reference those values for in game. Back then I just thought it was easier to do this, so I went with it. I was also too lazy to change it because I was afraid that if I did, I would lose everyone’s data. Plus I didn’t think much of it because I just thought that if it works, it works because I’m only saving one person’s data.

TLDR: (I don’t have much experience in data stores… At all.)

For the succes error,repeat it a few times,because it doesnt save it for the first time as there are a lot of things to saved