Why is this data store code returning a boolean?

I recently wrote a simple data store module, borrowing a lot of the code from the Developer Hub. Here is the code:

local PlayerDataManager = {}

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

local PlayerDataStore = DataStoreService:GetDataStore("PlayerData")

local sessionData = {}

local DATASTORE_RETRIES = 5
local AUTOSAVE_INTERVAL = 60
local TIME_BETWEEN_RETRIES = 1

local NEW_USER_DATA = {
	PlotName = "Generic Plot Name",
	PlotData = {}
}


-- Tries a given data store command (e.g. setting data or getting data) and handles retrying and errors
local function dataStoreCommand(command)
	
	local tries = 0
	local success = true
	local data = nil
	
	repeat
		
		success = pcall(function()
			data = command()
		end)
		if not success then
			wait(TIME_BETWEEN_RETRIES)
		end
		
	until tries == DATASTORE_RETRIES or success == true
	
	if not success then
		
		error("Data could not be accessed!")
		
	end
	
	return success, data
	
end


-- Takes the player's session data and upload it to the data store
local function savePlayerData(player)
	
	return dataStoreCommand(function()
		
		return PlayerDataStore:SetAsync(player.UserId, sessionData[player])
		
	end)
	
end


-- This function will run in the background, saving data every AUTOSAVE_INTERVAL seconds
local function autosave()
	
	while true do
		
		wait(AUTOSAVE_INTERVAL)
		for player, data in pairs(sessionData) do
			savePlayerData(player)
		end
		
	end
	
end


-- Get the player's data from the data store
local function getPlayerData(player)

	return dataStoreCommand(function()
		
		return PlayerDataStore:GetAsync(player.UserId)

	end)

end


-- Whenever a player joins the server
local function setUpPlayerData(player)
	
	local success, data = getPlayerData(player)
	if success then
		if data then
			
			-- Player has played before, and we successfully got their data
			sessionData[player] = data
			
			-- Get a keys left table. This will help us determine if the player has all of the data keys
			local keysLeft = {}
			for key, value in pairs(NEW_USER_DATA) do
				
				table.insert(keysLeft, key)
				
			end
			
			-- Remove a value from keys left for every key the player has
			for key, value in pairs(sessionData[player]) do
				
				table.remove(keysLeft, table.find(keysLeft, key))
				
			end
			
			-- Check if there are any keys left in the table
			if table.getn(keysLeft) > 0 then
				
				-- There are! Set the missing keys to the NEW_USER_DATA correspondents
				for key, value in pairs(keysLeft) do
					
					sessionData[player][key] = NEW_USER_DATA[key]
					
				end
				
			end
			
		else
			
			-- First time player. Set their data to the default
			sessionData[player] = NEW_USER_DATA
			
		end
	else
		
		-- Could not access data. Something must be wrong at Roblox
		sessionData[player] = nil
		error(player.Name .. "'s data could not be accessed!")
		
	end
	
end


-- Will run when a player is leaving the server
local function saveSessionDataToCloud(player)
	
	-- Make sure to not save the data if our initial fetching failed
	if getPlayerData(player) then

		dataStoreCommand(function()
			return savePlayerData(player)
		end)	

	end
	
end


-- Function to change a specific player data key
function PlayerDataManager:ChangeData(player, dataName, newData)
	
	sessionData[player.UserId][dataName] = newData
	
end


-- Function to get a player's data or a specific data key
function PlayerDataManager:GetPlayerData(player, dataName)
	
	if dataName then
		
		local success, data = getPlayerData(player)
		return data[dataName]
		
	else
		
		local success, data = getPlayerData(player)
		return data
		
	end
	
end


-- Connect these two functions to PlayerAdded and PlayerRemoving
Players.PlayerAdded:Connect(setUpPlayerData)
Players.PlayerRemoving:Connect(saveSessionDataToCloud)

-- Run the autosave in the background
spawn(autosave)

return PlayerDataManager

However when I use this code in combination with a simple script that uses the PlayerDataManager:GetPlayerData function, the module returns the boolean true, instead of a player data dictionary. I’ve debugged it all the way to the GetAsync function, so it seems like the actual data inside of the data store is messed up.

No ideas on why this would happen. Can’t seem to find any other people who are having this problem.

1 Like