So basically I’m trying to store points and weapons. For some reason the script isn’t able to detect anything within the table provided for the async, after the UserId is provided. As evident, I am using print statements to see if the points and “child” table are there.
game.Players.PlayerAdded:Connect(function(plr)
local leaderstats = script.leaderstats:Clone()
leaderstats.Parent = plr
local data
local success, error = pcall(function()
--data = PointsDS:GetAsync(tostring(plr.UserId))
--if data == nil then
data = PointsDS:SetAsync(tostring(plr.UserId),{
Points = 0,
Weapons = {"S_Classic", "L_Classic", "T_Classic"}
})
--end
end)
if success and data then
print(data) -- line 21
print(data.Points) -- line 22
print(data.Weapons) -- line 23
leaderstats.Points.Value = data.Points -- line 24
for i, weapon in pairs(data.Weapons) do -- line 25
ShopEvent:FireClient(plr, "Update", data.Weapons)
end
else
task.wait(1)
plr:Kick("Data failed to load.")
end
PlrWeapons.S_Classic:Clone().Parent = plr.Backpack
PlrWeapons.L_Classic:Clone().Parent = plr.Backpack
PlrWeapons.T_Classic:Clone().Parent = plr.Backpack
while true do
leaderstats.Points.Value += 1
task.wait(10)
end
end)
data = PointsDS:GetAsync(tostring(plr.UserId)) or {
Points = 0,
Weapons = {"S_Classic", "L_Classic", "T_Classic"}
} -- GetAsync doesn't let you put the default values in - you have to add it after the fact
I purposefully set the data in order to make sure that whenever I change stuff within the table with data, it will always update. I’ve done it this way only for testing.
In that case, you’ll need to set the value of data differently - that’s where the issue is occuring.
(Because it’s just for testing, you can get away with using GetAsync directly after the SetAsync)
game.Players.PlayerAdded:Connect(function(plr)
local leaderstats = script.leaderstats:Clone()
leaderstats.Parent = plr
local data
local success, error = pcall(function()
data = PointsDS:GetAsync(tostring(plr.UserId))
if data == nil then
data = PointsDS:SetAsync(tostring(plr.UserId),{
Points = 0,
Weapons = {"S_Classic", "L_Classic", "T_Classic"}
})
end
end)
if success and data then
print(data)
print(data.Points)
print(data.Weapons)
leaderstats.Points.Value = data.Points
for i, weapon in pairs(data.Weapons) do
ShopEvent:FireClient(plr, "Update", data.Weapons)
end
else
task.wait(1)
plr:Kick("Data failed to load.")
end
PlrWeapons.S_Classic:Clone().Parent = plr.Backpack
PlrWeapons.L_Classic:Clone().Parent = plr.Backpack
PlrWeapons.T_Classic:Clone().Parent = plr.Backpack
while true do
leaderstats.Points.Value += 1
task.wait(10)
end
end)
Haven’t used data stores yet (haven’t reached that stage of development), but I think I see why your code, old and new, still doesn’t update the data variable.
Even under this new version, the protected call is still not returning a table. SetAsync returns a version identifier of a GlobalDataStore, not whatever you have sent to it. Only if the data is valid prior will the data variable be correct thanks to GetAsync, but if the player has no save, data will have the wrong type assigned to it. Send the default data using a variable first, then return that variable.
data = PointsDS:GetAsync(tostring(plr.UserId))
if data == nil then
-- Assign the default save data to a local variable first. That way, the data can both be
-- saved and returned/assigned to "data".
local defaultSaveData = {
Points = 0,
Weapons = {"S_Classic", "L_Classic", "T_Classic"}
}
PointsDS:SetAsync(tostring(plr.UserId), defaultSaveData)
data = defaultSaveData
end
OR
data = PointsDS:GetAsync(tostring(plr.UserId))
if data == nil then
-- Assign the default data directly to "data", then send that same variable to the data store.
data = {
Points = 0,
Weapons = {"S_Classic", "L_Classic", "T_Classic"}
}
PointsDS:SetAsync(tostring(plr.UserId), data)
end
You are still trying to use the result of SetAsync as a means to access data.
I recommend that the code within the pcall to instead be something like this:
data = PointsDS:GetAsync(tostring(plr.UserId))
if data == nil then
data = { -- set the default values
Points = 0,
Weapons = {"S_Classic", "L_Classic", "T_Classic"}
}
PointsDS:SetAsync(tostring(plr.UserId), data)
end
If you already have some saving logic elsewhere in the script, you can probably just remove the SetAsync altogether from this portion of the code, and could instead replace the contents of the pcall with
data = PointsDS:GetAsync(tostring(plr.UserId)) or {
Points = 0,
Weapons = {"S_Classic", "L_Classic", "T_Classic"}
}
game.Players.PlayerAdded:Connect(function(plr)
local leaderstats = script.leaderstats:Clone()
leaderstats.Parent = plr
local data
local success, error = pcall(function()
data = PointsDS:GetAsync(tostring(plr.UserId))
if data == nil then
data = {
Points = 0,
Weapons = {"S_Classic", "L_Classic", "T_Classic"}
}
PointsDS:SetAsync(tostring(plr.UserId), data)
end
end)
if success and data then
print(data)
print(data.Points)
print(data.Weapons)
leaderstats.Points.Value = data.Points
for i, weapon in pairs(data.Weapons) do
ShopEvent:FireClient(plr, "Update", data.Weapons)
end
else
task.wait(1)
plr:Kick("Data failed to load.")
end
PlrWeapons.S_Classic:Clone().Parent = plr.Backpack
PlrWeapons.L_Classic:Clone().Parent = plr.Backpack
PlrWeapons.T_Classic:Clone().Parent = plr.Backpack
while true do
leaderstats.Points.Value += 1
task.wait(10)
end
end)
I’ll take a quick guess. Have you saved the default data once without the Weapons table? Just to be sure, try overwriting the save data at least once with the nested Weapons table in it.
@Y_VRN I’ve tried what you asked, and have properly cleared the data and saved. Now the weapons table is working. Output is alright. Now it’s just a matter of saving data when changes occur to points or weapons.
Since the main issue with the code seems to be resolved, I would like to suggest some tweaks for improvement.
Rather than having all that in the pcall, it could be placed outside of its scope.
local success, data = pcall(PointsDS.GetAsync, PointsDS, tostring(plr.UserId))
if success then
if data == nil then
data = {
Points = 0,
Weapons = {"S_Classic", "L_Classic", "T_Classic"}
}
elseif data ~= nil then
-- if there is save data present
end
elseif not success then
-- error handling if GetAsync failed
end
...
PointsDS:SetAsync(tostring(plr.UserId), data)
It makes it somewhat more readable, not to mention it’ll set up the default data if GetAsync threw an exception, which the original code didn’t account for.
I recommend making just a small change to this section of the code so that it doesn’t run until the server closes.
while plr:IsDescendantOf(game.Players) do -- while the player's in the game
leaderstats.Points.Value += 1
task.wait(10)
end