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

DataStore loss in studio, what can I improve with my DataStore script?

Here is how I store my data, but when I was testing in studio with one of the players that I test on it had lost some data. Is there something I should be worried about or could it be because it was in studio?

How ever, is there a better way to store data? I have heard that "UpdateAsync()" could be better than "SetAsync()". So what can I change to make it so there is like no chance for data loss?

I also have other scripts that save other values, is it bad to have several scripts for datastore or is it okay?

local DataStoreBoughtTitles = game:GetService("DataStoreService"):GetDataStore("TitlesBoughtData")
local titleData = {
	["Poor"] = false,
	["Noob"] = false,
	["Casual"] = false,
	["Sad"] = false,
	["Happy"] = false,
	["Cool"] = false,
	["Iconic"] = false,
	["Bold"] = false,
	["Patient"] = false,
	["Super"] = false,
	["Competitive"] = false,
	["Brave"] = false,
	["Worthy"] = false,
	["Monster"] = false,
	["Fighter"] = false,
	["Deadly"] = false,
	["Untouchable"] = false,
	["Champion"] = false,
	["Fearless"] = false,
	["Myth"] = false,
	
	["Good"] = false,
	["Talented"] = false,
	["Skilled"] = false,
	["Pro"] = false,
	["Expert"] = false,
	["Godly"] = false,
	["Legend"] = false,
	["Unbeatable"] = false,
	
	["VIP"] = false,
	["Rich"] = false,
	["Winner"] = false
}

game.Players.PlayerAdded:Connect(function(player)
	local titles = player:FindFirstChild("Titles")
	local ID = "Player".."-"..player.UserId
	local savedTitlesData = nil
	wait(0)
	local titles = Instance.new("Folder",player); titles.Name = "Titles"
	for name, value in pairs(titleData) do
		local new = Instance.new("BoolValue")
		new.Name = name
		new.Value = value
		new.Parent = titles
	end
	
	local s, e = pcall(function()
		savedTitlesData = DataStoreBoughtTitles:GetAsync(ID)
	end)
	
	if s then
		print("Getting Data For: " .. player.Name)
		if savedTitlesData then
			for name, value in pairs(savedTitlesData) do
				player.Titles[name].Value = value
			end
			print("Data Loaded For: " .. player.Name)
		else
			print("Created New Data For: " .. player.Name)	
		end
	else
		warn("Error Getting Data For: " .. player.Name)
	end
end)

game.Players.PlayerRemoving:Connect(function(player)
	local titlesDataforStore = {}
	local ID = "Player".."-"..player.UserId
	
	for name, value in pairs(player.Titles:GetChildren()) do
		titlesDataforStore[value.Name] = value.Value
	end
	
	local success = pcall(DataStoreBoughtTitles.SetAsync, DataStoreBoughtTitles, "Player".."-"..player.UserId, titlesDataforStore)
	
	if success then
		print("Successfully Saved Data For: " .. player.Name)
	end
	
end)

game:BindToClose(function()
	-- When game is ready to shutdown
	for i, player in pairs(game.Players:GetPlayers()) do
		if player then
			player:Kick("This game is shutting down")
		end
	end

	wait(5)
end)

Here is another one, I have two more scripts that have the same layout but saves other values. And the one up there I also have two more scripts with the same layout but saves other values.

local DataStoreService = game:GetService("DataStoreService")
local playerData = DataStoreService:GetDataStore("PlayerData")

local function onPlayerJoin(player)
	local leaderstats = Instance.new("Folder")
	leaderstats.Name = "leaderstats"
	leaderstats.Parent = player
	
	local bits = Instance.new("IntValue")
	bits.Name = "Bits"
	bits.Parent = leaderstats
	
	local wins = Instance.new("IntValue")
	wins.Name = "Wins"
	wins.Parent = leaderstats
	
	local rank = Instance.new("IntValue")
	rank.Name = "Rank"
	rank.Parent = leaderstats
	
	local playerUserId =  "Player_"..player.UserId
	local data = playerData:GetAsync(playerUserId)
	if data then
		bits.Value = data["Bits"]
		wins.Value = data["Wins"]
		rank.Value = data["Rank"]
	else
		bits.Value = 0
		wins.Value = 0
		rank.Value = 1
	end
end

local function create_table(player)
	local player_stats = {}
	for _, stat in pairs(player.leaderstats:GetChildren()) do
	player_stats[stat.Name] = stat.Value
	end
	return player_stats
end

local function onPlayerExit(player)
	local player_stats = create_table(player)
	local success, err = pcall(function()
		local playerUserId = "Player_"..player.UserId
		playerData:SetAsync(playerUserId, player_stats)
	end)

	if not success then
		warn("Could not save data")
	end
end

game.Players.PlayerAdded:Connect(onPlayerJoin)
game.Players.PlayerRemoving:Connect(onPlayerExit)

I'm going to release a new game soon and I don't want players to loose their data. So I would appreciate any kind of help!

If there is any questions, please ask :) Thanks for the help, Xsodar

1 answer

The problem is that studio shutdowns the run time almost instantly so your code does not have enough time to run. This can also happen for the last player to leave the game server so its recommended to yield the server until everything is saved.

For this you can use this function to yield your server for a little longer:

game:BindToClose(function()
	
	wait(3)

end)

The only limitation is that you can only yield a server up to 30 seconds with this function. I personally use it to save the players data as well but this should be enough to make it work on studio.

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