SetAsync Not working (saving player data)

  1. What do I want to achieve?
    I would like it so when the player leaves it saves there data

  2. What is the issue?
    The data does not save!

  3. What solutions have you tried so far?
    I dont what I can do so thats why Im coming here, there are no Output errors

game.Players.PlayerRemoving:Connect(function(plr)
	for i, v in pairs(plr.Inventory.Trails:GetChildren()) do
		ds:SetAsync(plr.UserId, v.Value) 
	end
end)

The script is in server script service, and help would be much appreciated :happy1:

Did you enabled studio access to api services?

Yeah I always have it enabled.

Also youā€™re making a loop and saving the items in the loop one after the other so lets say the table looked like this Blue trail, Red trail then it will only save Red trail because it would save the Blue trail but then since Red trail is next itā€™ll save the Red trail to the same key and since youā€™re saving a Value it wont save both.
You can make a table and then add all trails to that table then save that table

Example

local TrailsTable = {}

For _,trail in pairs(TrailsFolder:GetChildren()) do
   table.insert(TrailsTable,trail.Value)
end

Datastore:SetAsync(player.UserId,TrailsTable)

Also idk if this is in a server script or local script but itā€™ll only work in a server script

2 Likes

it still does not work, what am I doing wrong?

local R_Trail6 = Instance.new("NumberValue", folder2)
	R_Trail6.Name = "Silver Trail"
	R_Trail6.Value = ds:GetAsync(plr.UserId) or 0

this is the script that saves the players data

game.Players.PlayerRemoving:Connect(function(plr)
	local Crate1Table = {}

	for _,trail in pairs(plr.Inventory.Trails:GetChildren()) do
		table.insert(Crate1Table, trail.Value)
	end

	ds:SetAsync(plr.UserId, Crate1Table)
end)
Redundant

You are setting the key (plr.UserId) to v.Value every single iteration in the loop. You are overwriting the last entry with the next.

Another problem with this approach is that datastores have a limit on how many requests in a set amount of time. This means that if 10 players leave at once, the game will start to queue the data. This leaves you prone to data loss if the server crashes/etc.

You should save the data as a table. Save the Bandwith!

local data = {}
for i, v in pairs(plr.Inventory.Trails:GetChildren()) do
	table.insert(data, v.Value)
end

ds:SetAsync(plr.UserId, data) 

Hopefully this helps!

EDIT: Just realized someone already suggested this! My apologies. The following is still important:

Also, try not to use SetAsync every time you need to save. Use UpdateAsync() instead to prevent data loss. See this thread.

Did you debugged v.Value first ? Try printing this first and see if it returns nil or something else.

And I donā€™t think that Trails can have a ā€˜Valueā€™ proprety even if it is a custom attribute.

You are trying to set a (?)Value to a table. You need to unpack the table before you can use the data.

My recommendation would be to save a 2-dimensional table in the first place. This allows you to find the data with a key (trailā€™s name) and pull the necessary value from said table.

{{"ValueName", "Value"}, {"Value2Name", "Value"}}

You can save it like this:

local data = {}
for i, v in pairs(plr.Inventory.Trails:GetChildren()) do
     table.insert(data, {v.Name, v.Value})
end
ds:SetAsync(plr.UserId, data) 

To unpack this data, you can create a search function that loops through each table inside of the big table. Once you get a match, you can pull the value from said nested table.

I totally understand if this is confusing, so please donā€™t hesitate to ask if you have any questions.

No what I do is, I make a value and call it the name of a trail, if the value is more then 0 it will show a ui, when the ui is pressed it gives the player a trail

Yes but is Trail Folder containing Trails or Values ? And I think you should be unpacking your table before assining a Value like @frriend suggested

its filled with Values not trails

Here is what the output is when I print the value names
image

Like I said above, the same principle applies. You can save a big table with item as a table within. The name is the key (Silver Trail/Evil Trail/etc.) and its value as the value. This is important because when you pull the data you need to make sure the value of the monkey trail is exactly what it is supposed to be.

When you loop through and save, there is a chance that it will save out of order. That is why this is important.

EDIT: Now that Iā€™m thinking about it, you can use dictionaries instead.
{[ā€œMonke Trailā€] = 0, [Rainbow Trail] = 0}

how would I go about doing that? sorry im just really bad at these type of things

Note: Dictionaries would be a lot easier to deal with in this context.

Saving Data:

local data = {}
for i, v in pairs(plr.Inventory.Trails:GetChildren()) do
     data[v.Name] = v.Value
end
ds:SetAsync(plr.UserId, data) 

Loading Data:

local data = ds:GetAsync(plr.UserId)
for i, v in next, data do
   local find = plr.Inventory.Trails:FindFirstChild(i)
   if find then find.Value = v end
end

Totally wrote this on the fly, so it may take some tweaking before it works. Hopefully, this helps!

Thank you for writing this! So if I am correct,

local data = {}
for i, v in pairs(plr.Inventory.Trails:GetChildren()) do
     data[v.Name] = v.Value
end
ds:SetAsync(plr.UserId, data) 

is used when the player leaves and

local data = ds:GetAsync(plr.UserId)
for i, v in next, data do
   local find = plr.Inventory.Trails:FindFirstChild(i)
   if find then find.Value = v end
end

is used when the player joins?

1 Like

Correct! In my mind this should work, Iā€™m not able to test it currently haha. Make sure that your trails inventory has been populated before you call the load function, or it will throw an error.

Just tested it and seems it still does not work, I must be doing something wrong but I cant seem figure it out, there are no errors

Any errors in the console? If not, could i see how you are implementing it?

there are no error on the console and here
image