Hello, so I am creating a racing game where your character is a ball and when you reach the end of the map you get your coins and stuff. But that’s not the issue. My data store scripts are returning nil for my “Coins” leaderstat value and I don’t know why. I haven’t worked with Data Stores much so I know there is something I’m doing wrong but don’t know what. The function that is returning nil is the :ChangeStat() function I’ve created in a module:
function PlayerStatManager:ChangeStat(player, statName, changeValue)
sessionData[player][statName] = sessionData[player][statName] + changeValue
updateboard(player)
end
(PlayerStatManager is a reference to the module)
And the end point of the maps is what triggers this function through a touched event but it keeps erroring saying “Attempt to index nil with ‘Coins’”. This is my script that uses the :ChangeStat() function:
local leaderstats = player:FindFirstChild("leaderstats")
if leaderstats then
local coins = leaderstats:FindFirstChild("Coins")
if coins and (coins:IsA("IntValue") or coins:IsA("NumberValue")) then
PlayerStatManager:ChangeStat(player, "Coins", 10)
else
warn("Finish script: 'Coins' stat not found or not a valid number value for player " .. player.Name)
end
hasFinishedValueHolder.Value = true
else
warn("Finish script: 'leaderstats' not found for player " .. player.Name)
end
end
I tried testing it on the Roblox client, but still errored out. It probably is a stupid mistake but for now I can’t see it as I’m inexperienced with Data Stores
It’s not a problem with datastores, it’s problem with tables.
The problem you’re having is this:
Table = {}
Table["Player"]["Currency"] = 10
if you’d run this code in studio it would give you the same error because if Table doesn’t contain the PlayerData it would not create 2 tables at once. This would work:
You need to check if sessionData[player] exists, if not then create the table sessionData[player] = {} after checking that you can safely get sessionData[player][statName] and change it
local function setupPlayerData(player)
local success, data = getPlayerData(player)
if not success then
--Could not access the DataStore, set session data for player to false
sessionData[player] = false
else
if not data then
--DataStores are working, but no data for this player
sessionData[player] = {Coins = 0}
savePlayerData(player)
else
--DataStore is working and data was found for this player
sessionData[player] = data
end
end
updateboard(player)
end
Plus the updateboard function if you need it:
local function updateboard(player)
for i,e in pairs(sessionData[player]) do
print(i,e)
player.leaderstats[i].Value = e
end
end
It seems normal, could it be in the way that you’re saving the data?
Try printing data if it prints {Coins = 2}
if it prints only the amount then just change last line to sessionData[player] = {Coins = data}
It never gets to that point, I tried checking if sessionData[player] exists and it is returning false
if not sessionData[player] then
warn("Player data has not been loaded!")
return
end
It is printing “Player data has not been loaded!”. The player exists but not their data, this makes sense that the updateboard function is not responding. I’m going to try and wait for leaderstats to show up and see if that works
EDIT: The leaderstats are found and sessionData[player] still returns nil. I tried creating a seperate table but same thing. Any ideas? I can post the whole module if that will be helpful
local PlayerStatManager = {}
local DSS = game:GetService("DataStoreService")
local playerData = DSS:GetDataStore("PlayerData")
local AUTOSAVE_INTERVAL = 60
local DATASTORE_RETRIES = 3
local sessionData = {}
--Function to Update the LeaderBoard
local function updateboard(player)
--local realsessiondata = sessionData[player]
sessionData[player] = {}
for i,e in pairs(sessionData[player]) do
print(i,e)
player:WaitForChild("leaderstats")[i].Value = e
end
end
function PlayerStatManager:ChangeStat(player, statName, changeValue)
if player and player:WaitForChild("leaderstats") and player.leaderstats:WaitForChild(statName) then
if not player then
warn("Player is nil!")
return
end
if not sessionData then
warn("Table doesn't exist")
return
end
if not sessionData[player] then
warn("Player data has not been loaded!")
return
end
sessionData[player][statName] = sessionData[player][statName] + changeValue
updateboard(player)
end
end
local function dataStoreRetry(dataStoreFunction)
local tries = 0
local success = true
local data = nil
repeat
tries = tries + 1
print(tries)
success = pcall(function() data = dataStoreFunction() end)
if not success then
wait(1)
end
until tries == DATASTORE_RETRIES or success
if not success then
error("Could not access DataStore! Data might not save!")
end
return success, data
end
local function getPlayerData(player)
return dataStoreRetry(function()
return playerData:GetAsync(player.UserId)
end)
end
local function savePlayerData(player)
if sessionData[player] then
return dataStoreRetry(function()
return playerData:SetAsync(player.UserId, sessionData[player])
end)
end
end
local function setupPlayerData(player)
local success, data = getPlayerData(player)
print(data)
if not success then
--Could not access the DataStore, set session data for player to false
sessionData[player] = false
else
if not data then
--DataStores are working, but no data for this player
sessionData[player] = {Coins = 0}
savePlayerData(player)
else
--DataStore is working and data was found for this player
sessionData[player] = {Coins = data}
end
end
updateboard(player)
end
local function autosave()
while wait(AUTOSAVE_INTERVAL) do
for player, data in pairs(sessionData) do
savePlayerData(player)
end
end
end
--Bind setupPlayerData to PlayerAdded to call it when player joins
game.Players.PlayerAdded:Connect(setupPlayerData)
--Call savePlayerData on PlayerRemoving to save player data when they leave
--Also delete the player from the sessionData, as the player isn't in game anymore
game.Players.PlayerRemoving:Connect(function(player)
savePlayerData(player)
sessionData[player] = nil
end)
--Start running autosave function in the background
spawn(autosave)
--Return the PlayerStatManager table to external scripts so they can access it
return PlayerStatManager