Add more than one value to data store script?

Hello everyone, following How Would I Go About Making a boost last for a certain amount of time? - #6 by Lit_skillzYT 's advice, I am going to save the player’s boost time left to a datastore script, so that even if they leave, when they rejoin, they can still use the boost.
However, my current data store script doesn’t seem to be able to accomodate two values:

local DataStoreService = game:GetService("DataStoreService")
local Players = game:GetService("Players")
local RunService = game:GetService("RunService")

local function waitForRequestBudget(requestType)
	local currentBudget = DataStoreService:GetRequestBudgetForRequestType(requestType)

	while currentBudget < 1 do
		currentBudget = DataStoreService:GetRequestBudgetForRequestType(requestType)
		wait(5)
	end
end

local function safeCall(playerName, func, self, requestType, ...)
	local success, ret

	repeat
		if requestType then
			waitForRequestBudget(requestType) 
		end
		success, ret = pcall(func, self, ...)

		if not success then
			print("Error: " .. ret)
			if string.find(ret, "501") or string.find(ret, "504") then
				return
			end
		end
	until (success) or (playerName and not Players:FindFirstChild(playerName))

	return success, ret
end

local function setUp(player)
	local name = player.Name
	local userId = player.UserId
	local key = "Player_" .. userId

	local leaderstats = Instance.new("Folder")
	leaderstats.Name = "leaderstats"

	local GoldCoins = Instance.new("IntValue")
	GoldCoins.Name = "GoldCoins"

	local dataStore = DataStoreService:GetDataStore(key)
	local orderedDataStore = DataStoreService:GetOrderedDataStore(key)

	local _, pages = safeCall(name, orderedDataStore.GetSortedAsync, orderedDataStore, Enum.DataStoreRequestType.GetSortedAsync, false, 100)
	local currentPage = pages:GetCurrentPage()

	if #currentPage > 0 then
		for _, dataStoreKey in ipairs(currentPage) do
			if not Players:FindFirstChild(name) then return end
			dataStoreKey = dataStoreKey.value
			local success, ret = safeCall(name, dataStore.GetAsync, dataStore, Enum.DataStoreRequestType.GetAsync, dataStoreKey)

			if success then
				GoldCoins.Value = ret
				GoldCoins.Parent = leaderstats
				leaderstats.Parent = player
				break
			end
		end
	else
		GoldCoins.Value = 0
		GoldCoins.Parent = leaderstats
		leaderstats.Parent = player
	end
end

local function save(player, dontWait)
	local userId = player.UserId
	local key = "Player_" .. userId
	local leaderstats = player:FindFirstChild("leaderstats")

	if leaderstats then
		local GoldCoinsValue = leaderstats.GoldCoins.Value

		local dataStore = DataStoreService:GetDataStore(key)
		local orderedDataStore = DataStoreService:GetOrderedDataStore(key)

		local _, pages = safeCall(nil, orderedDataStore.GetSortedAsync, orderedDataStore, Enum.DataStoreRequestType.GetSortedAsync, false, 1)
		local latest = pages:GetCurrentPage()[1] or 0
		local should = (type(latest) == "table" and latest.value or 0) + 1


		safeCall(nil, orderedDataStore.UpdateAsync, orderedDataStore, (not dontWait and Enum.DataStoreRequestType.UpdateAsync), should, function()
			return should
		end)
		safeCall(nil, dataStore.UpdateAsync, dataStore, (not dontWait and Enum.DataStoreRequestType.UpdateAsync), should, function()
			return GoldCoinsValue
		end)
	end
end

local function onShutdown()
	if RunService:IsStudio() then
		task.wait(2)
	else
		local finished = Instance.new("BindableEvent")
		local allPlayers = Players:GetPlayers()
		local leftPlayers = #allPlayers

		for _,player in ipairs(allPlayers) do
			coroutine.wrap(function()
				save(player, true)
				leftPlayers -= 1
				if leftPlayers == 0 then
					finished:Fire()
				end
			end)()
		end

		finished.Event:Wait()
	end
end

for _, player in ipairs(Players:GetPlayers()) do
	coroutine.wrap(setUp)(player)
end

Players.PlayerAdded:Connect(setUp)
Players.PlayerRemoving:Connect(save)
game:BindToClose(onShutdown)

while true do
	wait(60)
	for _, player in ipairs(Players:GetPlayers()) do
		coroutine.wrap(save)(player)
	end
end

How would I let it save two values?

2 Likes

you can create a table to save more than 1 value.

How would I do that though?
30 cahrs

here’s an example :

local DataStoreService = game:GetService("DataStore")
local Data = DataStoreService:GetDataStore("DATA")

Data:SetAsync(plr.UserId.."-DATA",{plr.Gold.Value,plr.Wins.Value})

local data
data = Data:GetAsync(plr.UserId.."-DATA")
if data then
print(DATA[1]) -- Gold Value
print(DATA[2]) -- Wins Value
end

to save a table to datastores just make a table and encode is with HttpService:Encode before saving. When loading the table just load it in and call HttpService:Decode on it to retrieve the table.

Edit: You cannot use orderedDataStores to save tables so instead use normal dataStores, which should work for what you’re doing. The only reason you would want an orderedDataStore is if you’re making a leaderboard, in which case you would need to make a separate orderedDataStore for each leaderboard.

Also I recommend making a global variable (define at the top of the script) for the dataStore instead of calling DataStoreService:GetDataStore() every time you want to save.

Are there any tutorials about this that I can read/watch?

Its quite simple to use datastores, so I don’t really think you need a tutorial.
I will provide some example code as well as links to dataStores and HttpService:JSONEncode/HttpService:JSONDecode
Also I realized that its actually JSONEncode instead of just encode, mb.

Example Code:

local dss = game:GetService("DataStoreService")
local hts = game:GetService("HttpService")

local myStore = dss:GetDataStore("VeryCoolRobloxDatastore") -- any datastore key

local userId = 1 -- exaple player's userid

-- saving data:
local dataToSave = {gold = 1, wins = 1}
pcall(function()
	myStore:SetAsync(tostring(userId), hts:JSONEncode(dataToSave))
end)

-- loading data:
local dataToSave = {gold = 1, wins = 1}
local success, data pcall(function()
	return myStore:GetAsync(tostring(userId))
end)
data = hts:JSONDecode(data)

If you feel you still need a tutorial then there are plenty on youtube.

Hope I could help!

Edit: Forgot to say that you only need to json encoding/decoding if you’re saving a table to the datastore.

What about memory leaks though? Do they happen often with simple datastores? Or is it OK?

I’m pretty sure that dataStores don’t cause memory leaks when used correctly, although I am definitely not an expert on that subject.