SetAsync Not working (saving player data)

So you cannot set E_Trail3’s Value to ds:GetAsync(plr.UserId). The data saved is a table. If you want to include this, you need to pack it on removal. Try adding a print in the player added for loop and tell me the result.

Also, are you running any code before playeradded that could yeild the script? This can cause playeradded to not fire in time for the first players to a server (you in studio)

No other code other than
image
here is the print
image
0 being the value

1 Like

May I recommend using Pcall() When saving and loading data

2 Likes

This could be an issue with key length and saving dictionaries in a DataStore. You can try saving to a 2D array instead.

Saving Data:

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) 

Loading Data:

local function search(data, key)
	for _, v in ipairs(data) do
		if (v[1] == key) then
			return v[2]
		end
	end
	
	return nil
end

local data = ds:GetAsync(plr.UserId)

for i, v in pairs(plr.Inventory.Trails:GetChildren()) do
     local findValue = search(data, v.Name)

     if find then v.Value = findValue else print("didn't find") end
end

EDIT: Totally second this.

Hey, You can use like this.

Saving Player data

local yes = {}

for i,v in pairs(YourStuffgetchrilends()) do
     table.insert(yes, v.Name)
end

yourdata:SetAsync(player.UserId, yes)

Getting player data

local yestable = data:GetAsync(player.UserId)

for i,v in pairs(yestable) do
     print(v)
end

Yes use this.

While this would work, its unpredictable and I wouldn’t do it this way. The order of items in a folder can be unpredictable, especially if new trails are added… The solution I provided allows you to verify by key (trail name).

It’s just fine, I am just showing a example.

1 Like

This is either due to two reasons: the game is not able to save the player’s data in time or the data is too much.

In the case of the situation relating to the first reason. Consider pausing the game’s closure and allowing the player’s data to be saved. You can do this using:

game:BindToClose(function()
	wait(5)
end)

Alternatively, you can use coroutine.wrap() for data saving.

If your data happens to not save due to your data consisting of instances. You can serialize your data by turning instances into strings and using those strings to retrieve the given trails or items.

2 Likes

This some how is the first time I am hearing of Pcall() I am unaware of how to use it

1 Like

pcall basically wraps a function to prevent it from halting your code. Instead it will do whatever you want it to.

Usage:

success, err = pcall(function() true = false end)

if error then
warn("True doesn't equal false!")
end

in your context, you can wrap your set/get asyncs in this to provide a more detailed warning message and avoid the game breaking if it fails.

Im getting an error on

table.Insert(data, {v.Name, v.Value}

image

Oops, try table.insert instead. I capitalized accidentally.

The reason why your script doesn’t work is because a lot of requests sent for SetAsync which can lead to a data reset.
Here is what you should do:

game.Players.PlayerRemoving:Connect(function(plr)
    local trail
	for i, v in pairs(plr.Inventory.Trails:GetChildren()) do
		trail[v.Name] = v.Value
	end
    if trail then
        ds:SetAsync(plr.UserId, trail) 
    end
end)

But that’s not it, because its only saving 1 trail. So in order to save all of them, we have to make a table for it that stores all of the trails.
Another thing to mention is that you need to use pcalls to detect whether the data saved or not.
This is how you use pcall:

local noerror,error = pcall(function()
       game.Woerkspace.Gravity = 100
end)
if noerror then
        print("Function is fully working!")
else
        print("Function got an error!\nError: "..error)
end

So this is what your script should look like:

game.Players.PlayerRemoving:Connect(function(plr)
    local trail = {}
    local success,errormsg = pcall()
	      for i, v in pairs(plr.Inventory.Trails:GetChildren()) do
		      trail[v.Name] = v.Value
	      end
    end)
    if trail and success then
        ds:SetAsync(plr.UserId, trail) 
    else
         print("Data has not saved!\nError: "..errormsg)
    end
end)

Extra

Use UpdateAsync. Since its more efficient than SetAsync this reference’s description should explain it
Here is how you use UpdateAsync:

local dataToSave = 10
ds:UpdateAsync(plr.UserId,function(OldData)
                   return 10
end))

Now this is what your script should look like now:

game.Players.PlayerRemoving:Connect(function(plr)
    local trail = {}
    local success,errormsg = pcall()
	      for i, v in pairs(plr.Inventory.Trails:GetChildren()) do
		      trail[v.Name] = v.Value
	      end
    end)
    if trail and success then
        ds:UpdateAsync(plr.UserId, function(OldData)
                return trail
        end))
    else
         print("Data has not saved!\nError: "..errormsg)
    end
end)

oh my bad, I thought I turned the Insert to insert, this time no errors but it does not work the out put says 0(x15)

1 Like

Could you print out the values of the trails prior to saving? Just trying to make sure that they aren’t all zero to begin with lol.

I’ve updated my reply by the way

the values are 0, I make a 1 (blue trail), 1 then I leave

Are you setting this through studio’s explore tab? If so, these changes are local to you and are not edited on the server. You need to do it through the command line.

The player is getting removed before the second save occurs.

I am using the dev console to change the value

1 Like