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.