I’m currently trying to figure out how to set values from GetAsync to match with the Object’s values when loadData is running. I have been trying to do this for the past three hours, so that’s why I’m asking for help here.
The structure (Object Values) can look like this:
--// This is the code so far and it isn't working for some reason.
local function loadData(player)
local PlayerKey = "data:"..player.UserId
local Data = PlayerData:GetAsync(PlayerKey)
if not Data then --// In this scenario I have data and this doesn't matter.
return warn("Server | ".. player.Name .. " has no data!")
end
if Data then
warn("Server | ".. player.Name .. " has data!")
for _, Index in pairs(player.PlayerData:GetDescendants()) do
if Index:IsA("Folder") then
Data[Index.Name] = {}
elseif Index:IsA("ValueBase") then
Data[Index.Name] = Index.Value
end
end
end
end
I’m not sure if this is intentional or not, but when you go to load the data in your for loop (I assume that’s what you’re wanting to do?) you’re actually overwriting/setting keys in the returned data table.
So, you get the player’s data:
local Data = PlayerData:GetAsync(PlayerKey)
But then you write to it:
Data[Index.Name] = {}
I would think you’d want to read from it instead, and set it to the player’s values accordingly.
With all that said, I think you’re going about this the right way. You’d just have to read from Data instead of writing to it.
I’ll write you some pseudocode in hopes of you learning from that, as I don’t really know how to assist you with your current code.
function loadData(player) --//Handles the loading of player data
local data = someDataStore:GetAsync(player.UserId)
--//Do all of your folder/instance drawing here. Then, we'll run a loop on the player's data to load all of their stuff.
for I, folder_data in pairs(data) do --Iterate over the player's saved data
for value_name, value in pairs(folder_data) do
player[folder_data][value_name].Value = value --Find the value in the player and set it to their saved value.
end
end
end
function saveData(player) --//Handles the saving of player data
local tab = {} --Define a table to save to DataStore, we'll add player data to this
for I, folder in pairs(player:GetChildren()) do --Iterate over the folders of player
tab[folder.Name] = {} --Create data for this folder.
for i2, value in pairs(folder:GetChildren()) do --Iterate over each folder and store their values.
tab[folder.Name][value.Name] = value --Write a new field for this folder's data.
end
end
someDataStore:SetAsync(player.UserId, tab) --Save data. I use SetAsync, not the best practice.
end
This is very barebones and untested, but I think the logic is pretty close to what you’d be looking for. If you need further clarification let me know!
I think player[folder_data][value_name].Value = value does not work because there can be tables inside the tables instead of values only. I am just really bad at iterating & etc.
Example of how it can look like:
Datastore example: Currencies: Pets:
Error:
ServerScriptService.Assets.Modules.DataService.Datastore:46: bad argument #2 to '?' (string expected, got table)
First I’d suggest naming your values depending on it’s job, for instance the money value name would be Money, then you’ll just have a function to get the value’s value and return them as a table :
function getDataFromFolder(player) -- assuming that PlayerData is under the player object
local dataFolder = player:FindFirstChild("PlayerData")
if not dataFolder then warn("Couldn't find data folder!") return end
local data = { -- set up the data table that you'll save in the datastore
currency = {}, -- currency
inventory = {} -- inventory
}
local currencyFolder = dataFolder.Currency -- the currency folder should exist if dataFolder exists
local inventoryFolder = dataFolder.Inventory -- same thing
for _,val in ipairs(currencyFolder:GetChildren()) do -- loop through the folder's children and get the values value + name
data.currency[val.Name] = val.Value -- yes
end
for _,val in ipairs(inventoryFolder:GetChildren()) do -- loop through the folder's children and get the values value + name
data.inventory[val.Name] = val.Value -- yes
end
return data -- here you got yourself the data table which has the inventory and money
end
-- Now to save the data all you have to do is just SetAsync :shrug: and to load it you do :
function loadDataToFolder(data,player) -- again assuming that PlayerData is under the player object and data is the table from GetAsync
local dataFolder = player:FindFirstChild("PlayerData") -- also assuming you already created PlayerData if not then uh create it!
if not dataFolder then warn("no data folder?") return end
local currencyFolder = dataFolder.Currency
local inventoryFolder = dataFolder.Inventory
-- now all you have to do is loop through the data.Currency and data.Inventory table and set the values :
for name,val in pairs(data.currency) do
local currentValue = currencyFolder:FindFirstChild(name)
if not currentValue then continue end -- Didn't find the value so we continue to the next index
currentValue.Value = val
end
for name,val in pairs(data.inventory) do
local currentValue = inventoryFolder:FindFirstChild(name)
if not currentValue then continue end -- Didn't find the value so we continue to the next index
currentValue.Value = val
end
end