Datastore cannot use (SetAsync) on Dictionaries

As the title says, I can’t apply dictionaries to my datastores. This is strange to me because I’ve done it in the past and my dictionary isn’t complicated.

Error:

DataStoreService: ValueNotAllowed: Dictionary is not allowed in data stores. API: SetAsync, Data Store: PoopFlingers

Here is my DataStore script:

local DataStoreService = game:GetService("DataStoreService")
local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local KillsData = DataStoreService:GetOrderedDataStore("PoopFlingers","Kills")
local CoinsData = DataStoreService:GetOrderedDataStore("PoopFlingers","Coins")
local AbilitiesData = DataStoreService:GetOrderedDataStore("PoopFlingers","Abilities")

local Remotes = ReplicatedStorage.Remotes
local Bindables = ReplicatedStorage.Bindables
local Assets = ReplicatedStorage.Assets
local GlobalLeaderboard = workspace.GlobalLeaderboard


local sessionData = {}

local function RefreshLeaderboard()
	for i,v in GlobalLeaderboard.SurfaceGui:GetChildren() do if not v:IsA("UIListLayout") then v:Destroy() end end
	local success,pages = pcall(function()
		return KillsData:GetSortedAsync(false,10)
	end)
	if success then
		local entries = pages:GetCurrentPage()
		for rank,entry in pairs(entries) do
			local nE = string.gsub(entry.key,"kills","")
			local id = tonumber(nE)
			local name = Players:GetNameFromUserIdAsync(id)
			local item = script.Place:Clone()

			item.Parent = GlobalLeaderboard.SurfaceGui
			item.Kills.Text = tostring(entry.value)
			item.Title.Text = name
			item.Order.Text = tostring(rank)
		end
	end
end

local function InitAbilities(player)
	sessionData[player] = {}
	for i,v in Assets.Shop:GetChildren() do
		sessionData[player][v.Name] = false
	end
end

Players.PlayerAdded:Connect(function(player)
	local leaderstats = Instance.new("Folder")
	leaderstats.Name = "leaderstats"
	local kills = Instance.new("IntValue")
	kills.Name = "Kills"
	local coins = Instance.new("IntValue")
	coins.Name = "Coins"
	
	leaderstats.Parent = player
	kills.Parent = leaderstats
	coins.Parent = leaderstats
	local pK = tostring(player.UserId)
	if not AbilitiesData:GetAsync(pK.."abilities") then
		InitAbilities(player)
	end
	local coinsReceived,lastCoins = pcall(function()
		return CoinsData:GetAsync(pK.."coins")
	end)
	if coinsReceived and lastCoins then
		coins.Value = lastCoins
	end
	local killsReceived,lastKills = pcall(function()
		return KillsData:GetAsync(pK.."kills")
	end)
	if killsReceived and lastKills then
		kills.Value = lastKills
	end
	local abilitiesReceived,lastAbilities = pcall(function()
		return AbilitiesData:GetAsync(pK.."abilities")
	end)
	if abilitiesReceived and lastAbilities then
		for i,v in lastAbilities do
			sessionData[player][i] = v
		end
	end
	RefreshLeaderboard()
	while true do
		task.wait(50)
		if player.leaderstats.Kills.Value ~= 0 then
			KillsData:UpdateAsync(pK .. "kills",function(past)
				return player.leaderstats.Kills.Value
			end)
		end
	end
end)

Players.PlayerRemoving:Connect(function(player)
	local pK = tostring(player.UserId)
	
	if player.leaderstats.Coins.Value ~= 0 then
		local success,result = pcall(function()
			return CoinsData:SetAsync(pK .. "coins",player.leaderstats.Coins.Value)
		end)
	end
	if player.leaderstats.Kills.Value ~= 0 then
		local success,result = pcall(function()
			return KillsData:SetAsync(pK .. "kills",player.leaderstats.Kills.Value)
		end)
	end
	if sessionData[player] then
		for i,v in sessionData[player] do print(i,v) end
		local success,result = pcall(function()
			return AbilitiesData:SetAsync(pK .. "abilities",sessionData[player])
		end)
	end
end)

Bindables.OnServer.Event:Connect(function(signal,name,player)
	if signal == "Purchase" then
		print(player,name)
		sessionData[player][name] = true
	end
end)

Remotes.ToServer.OnServerEvent:Connect(function(player,signal,pos)
	if signal == "TriggerPoop" then
		print(sessionData[player])
		Bindables.OnServer:Fire("Projectile",player,pos,sessionData[player])
	end
end)

task.spawn(function()
	while true do
		task.wait(10)
		RefreshLeaderboard()
	end
end)

I’m using the sessionData table to index players creating a table and then putting the names of abilities inside of that table with a boolean stating if that ability has been purchased by the player or not.

Working code with dictionaries in datastores:

local DataStoreService = game:GetService("DataStoreService")
local Players = game:GetService("Players")
local CollectionService = game:GetService("CollectionService")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Data = DataStoreService:GetDataStore("monke_datastore")

local Remotes = ReplicatedStorage.Remotes
local Functions = ReplicatedStorage.Functions
local Items = ReplicatedStorage.Items
local Tools = Items.Tools

local sessionData = {}

local DataStore = {}

function DataStore:Start(player)
	sessionData[player] = {}
	sessionData[player]["Tools"] = {}
end

local function GetParent(tool)
	if tool.Parent:IsA("Model") and Players:GetPlayerFromCharacter(tool.Parent) then
		return Players:GetPlayerFromCharacter(tool.Parent)
	elseif tool.Parent.Parent:IsA("Player") then
		return tool.Parent.Parent
	end
end

local function Upgrades(tool)
	return function(attributeName)
		if attributeName ~= "CurrentUpgrade" then return end
		local serial = tool:GetAttribute("SerialNumber")
		local att = tool:GetAttribute(attributeName)
		local player = GetParent(tool)
		sessionData[player]["Tools"][serial] = {att,tool.Name,serial}
	end
end

function DataStore:CS()
	for i,tool in CollectionService:GetTagged("Tool") do
		tool.AttributeChanged:Connect(Upgrades(tool))
	end
	CollectionService:GetInstanceAddedSignal("Tool"):Connect(function(tool)
		tool.AttributeChanged:Connect(Upgrades(tool))
	end)
end

function DataStore:Init() -- All our tools should save and we should save our upgrade number in sessionData and in attributes
	Players.PlayerAdded:Connect(function(player)
		self:Start(player)
		local key = tostring(player.UserId)
		
		local folder = Instance.new("Folder")
		folder.Name = "leaderstats"
		
		local money = Instance.new("IntValue")
		money.Name = "Money"
		
		local bananas = Instance.new("IntValue")
		bananas.Name = "Bananas"
		
		local fish = Instance.new("IntValue")
		fish.Name = "Fish"
		
		CollectionService:AddTag(fish,"Currency")
		CollectionService:AddTag(bananas,"Currency")
		
		local successFish,resultFish = pcall(function()
			return Data:GetAsync("fish"..key)
		end)
		if successFish and resultFish then
			fish.Value = resultFish
		end
		local successBananas,resultBananas = pcall(function()
			return Data:GetAsync("bananas"..key)
		end)
		if successBananas and resultBananas then
			bananas.Value = resultBananas
		end
		local successMoney,resultMoney = pcall(function()
			return Data:GetAsync("money"..key)
		end)
		if successMoney and resultMoney then
			money.Value = resultMoney
		end
		local successTools,resultTools = pcall(function()
			return Data:GetAsync("tools"..key)
		end)
		if successTools and resultTools then
			for i,v in pairs(resultTools) do
				sessionData[player]["Tools"][i] = v
				local tool = Tools:FindFirstChild(sessionData[player]["Tools"][i][2]):Clone()
				tool:SetAttribute("SerialNumber",sessionData[player]["Tools"][i][3])
				tool:SetAttribute("CurrentUpgrade",sessionData[player]["Tools"][i][1])
				tool.Parent = player.Backpack
			end
		end
		player.CharacterRemoving:Connect(function(character)
			if character.Humanoid.Health <= 0 then return end
			local function FindTools()
				for i,v in player.Backpack:GetChildren() do
					local serial = v:GetAttribute("SerialNumber")
					sessionData[player]["Tools"][serial] = {v:GetAttribute("CurrentUpgrade"),v.Name,serial}
				end
				local tool = character:FindFirstChildOfClass("Tool")
				if tool then
					local serial = tool:GetAttribute("SerialNumber")
					sessionData[player]["Tools"][serial] = {tool:GetAttribute("CurrentUpgrade"),tool.Name,serial}
				end
				table.sort(sessionData[player]["Tools"],function(a,b) return a < b end)
			end
			FindTools()
			
			local successTools,resultTools = pcall(function()
				return Data:SetAsync("tools"..key,sessionData[player]["Tools"])
			end)
		end)
		bananas.Parent = player
		fish.Parent = player
		money.Parent = folder
		folder.Parent = player
	end)
	Players.PlayerRemoving:Connect(function(player)
		local key = tostring(player.UserId)
		local successMoney,resultMoney = pcall(function()
			return Data:SetAsync("money"..key,player.leaderstats.Money.Value)
		end)
		local successBananas,resultBananas = pcall(function()
			return Data:SetAsync("bananas"..key,player.Bananas.Value)
		end)
		local successFish,resultFish = pcall(function()
			return Data:SetAsync("fish"..key,player.Fish.Value)
		end)
	end)
	self:CS()
end

return DataStore

I’ve found the issue, you can only save dictionaries in regular datastores, but not in ordered datastores.

Is there a way I can avoid not using 2 datastores because I need to use ordered datastores for my global leaderboard.

1 Like