Issue with Datastore Script

Hello,

I am currently using the script below to save a player’s leaderstats, which are Credits, Playtime, and Prizes Won. The script also checks to see if a player has data from a previous datastore, and transfers it over to the newer datastore if they do.

If a player doesn’t have old or new data, their leaderstats are defaulted to 300, 0, 0, and the data saves correctly. However, if the player has old data (Ex: 445, 3, 2), the script fails to transfer the data to the newer datastore and instead, their values are set to 0, 0, 0. What might be causing this?

Thank You! :slight_smile:

local DataStoreService = game:GetService("DataStoreService")
local newDataStore = DataStoreService:GetDataStore("LeaderstatsData") -- New DataStore
local oldDataStoreA = DataStoreService:GetDataStore("LeaderstatsData") -- Old Credits
local oldDataStoreB = DataStoreService:GetDataStore("LeaderstatsData2") -- Old Playtime
local oldDataStoreC = DataStoreService:GetDataStore("LeaderstatsData3") -- Old Prizes Won

-- Default player data
local function getDefaultData()
	return {
		Credits = 300,
		Playtime = 0,
		PrizesWon = 0
	}
end

-- Load player data
local function loadPlayerData(player)
	local success, playerData = pcall(function()
		return newDataStore:GetAsync("DataKey_" .. player.UserId)
	end)

	if success and playerData then
		return playerData -- Data found in new DataStore
	else
		if not success then
			warn("Failed to load data for player", player.UserId)
		end

		-- Attempt to load from old DataStores
		local oldCredits, oldPlaytime, oldPrizesWon

		local successA = pcall(function()
			oldCredits = oldDataStoreA:GetAsync(player.UserId)
		end)

		local successB = pcall(function()
			oldPlaytime = oldDataStoreB:GetAsync(player.UserId)
		end)

		local successC = pcall(function()
			oldPrizesWon = oldDataStoreC:GetAsync(player.UserId)
		end)

		-- Check if any old data exists and migrate it
		if successA or successB or successC then
			warn("Migrating old data for player", player.UserId)
			local migratedData = {
				Credits = oldCredits or 300,
				Playtime = oldPlaytime or 0,
				PrizesWon = oldPrizesWon or 0
			}

			-- Save migrated data to the new DataStore
			pcall(function()
				newDataStore:SetAsync("DataKey_" .. player.UserId, migratedData)
			end)

			return migratedData
		else
			-- No data found in old DataStores, apply defaults
			return getDefaultData()
		end
	end
end
-- Save player data
local function savePlayerData(player)
	local playerData = {
		Credits = player.leaderstats.Credits.Value,
		Playtime = player.leaderstats.Playtime.Value,
		PrizesWon = player.leaderstats["Prizes Won"].Value
	}

	local success, errorMessage = pcall(function()
		newDataStore:SetAsync("DataKey_" .. player.UserId, playerData)
	end)

	if not success then
		warn("Failed to save data for player", player.UserId, errorMessage)
	end
end

-- Player added event
game.Players.PlayerAdded:Connect(function(player)
	-- Create leaderstats folder
	local leaderstats = Instance.new("Folder")
	leaderstats.Name = "leaderstats"
	leaderstats.Parent = player

	-- Create leaderstats values
	local credits = Instance.new("IntValue", leaderstats)
	credits.Name = "Credits"

	local playtime = Instance.new("IntValue", leaderstats)
	playtime.Name = "Playtime"

	local prizesWon = Instance.new("IntValue", leaderstats)
	prizesWon.Name = "Prizes Won"

	-- Load and apply player data
	local playerData = loadPlayerData(player)
	credits.Value = playerData.Credits
	playtime.Value = playerData.Playtime
	prizesWon.Value = playerData.PrizesWon
end)

-- Player removing event
game.Players.PlayerRemoving:Connect(savePlayerData)

-- Periodic autosave
task.spawn(function()
	while task.wait(60) do
		for _, player in pairs(game.Players:GetPlayers()) do
			savePlayerData(player)
		end
	end
end)

I have never bothered with DataStore services, because I use the ProfileStore library. It makes saving and reading data effortless, without bothering with any of these issues. I suggest using it to avoid the whole issue of saving data and reading it. I’ve heard many good responses regarding this module script, and I suggest you inserting it.

replace the successA, successB & successC lines to smth like this.

local successA, oldCredits = pcall(function()
	return oldDataStoreA:GetAsync(player.UserId)
end

I can check it out. If I were ever to make the switch, would it be possible to transfer a player’s data stored within the datastores to the ProfIleStore, and how would it be done?

I’ll edit the scripts and report back with results.

1 Like

I’ve modified the “success” lines to:

		local successA, oldCredits = pcall(function()
			return oldDataStoreA:GetAsync(player.UserId)
		end)
		
		local successB, oldPlaytime = pcall(function()
			return oldDataStoreB:GetAsync(player.UserId)
		end)
		
		local successC, oldPrizesWon = pcall(function()
			return oldDataStoreC:GetAsync(player.UserId)
		end)

This is a beginner’s question (I’m not heavily experienced with lua), but I added )'s after each end statement to resolve an error with the local statements. Will this affect the code?

it wont, i just forgot to put it there

I tested the code within Roblox Studio using the player test feature. I reimplemented the old datastore script and played the game to change the values. I then exited out of the game and replaced the old datastore script with the new script, and changed the datastore key from DataKey_ to DataKeyt_, something random and temporary. I then rejoined with the test account and the old data didn’t transfer over to the new datastore.

Was there something wrong with my test process, or is there still an issue with the script?

What was printed / warned in the output?

Also i suggest not changing the keys because it might mess up the process, if you want your actual data saved you could write it down somewhere and set it back with the command bar later

There don’t seem to be any errors related to the save script in the output.

Why not use just one datastore… this all for the player only anyways.

Slight re-wright
local DataStoreService = game:GetService("DataStoreService")
local newDataStore = DataStoreService:GetDataStore("LeaderstatsData")

local function getDefaultData()
	return {
		Credits = 300,
		Playtime = 0,
		PrizesWon = 0
	}
end

local function loadPlayerData(player)
	local success, playerData = pcall(function()
		return newDataStore:GetAsync("DataKey_" .. player.UserId)
	end)

	if success and playerData then
		return playerData
	else
		if not success then
			warn("Failed to load data for player", player.UserId)
		end

		local oldData = getDefaultData()
		local dataStores = {
			{DataStore = DataStoreService:GetDataStore("LeaderstatsData"), Field = "Credits"},
			{DataStore = DataStoreService:GetDataStore("LeaderstatsData2"), Field = "Playtime"},
			{DataStore = DataStoreService:GetDataStore("LeaderstatsData3"), Field = "PrizesWon"}
		}

		for _, store in pairs(dataStores) do
			local successOld, oldValue = pcall(function()
				return store.DataStore:GetAsync(player.UserId)
			end)

			if successOld and oldValue then
				oldData[store.Field] = oldValue
			end
		end

		pcall(function()
			newDataStore:SetAsync("DataKey_" .. player.UserId, oldData)
		end)

		return oldData
	end
end

local function savePlayerData(player)
	local playerData = {
		Credits = player.leaderstats.Credits.Value,
		Playtime = player.leaderstats.Playtime.Value,
		PrizesWon = player.leaderstats["Prizes Won"].Value
	}

	local success, errorMessage = pcall(function()
		newDataStore:SetAsync("DataKey_" .. player.UserId, playerData)
	end)

	if not success then
		warn("Failed to save data for player", player.UserId, errorMessage)
	end
end

game.Players.PlayerAdded:Connect(function(player)
	local leaderstats = Instance.new("Folder")
	leaderstats.Name = "leaderstats"
	leaderstats.Parent = player

	local credits = Instance.new("IntValue", leaderstats)
	credits.Name = "Credits"

	local playtime = Instance.new("IntValue", leaderstats)
	playtime.Name = "Playtime"

	local prizesWon = Instance.new("IntValue", leaderstats)
	prizesWon.Name = "Prizes Won"

	local playerData = loadPlayerData(player)
	credits.Value = playerData.Credits
	playtime.Value = playerData.Playtime
	prizesWon.Value = playerData.PrizesWon
end)

game.Players.PlayerRemoving:Connect(savePlayerData)

while true do task.wait(60)
	for _, player in pairs(game.Players:GetPlayers()) do
		savePlayerData(player)
	end
end

Sure be easier to keep track of things…