Hi all, I was attempting to make StringValues be saved within a folder inside the player named “BombInventory.” To elaborate, if a player has a StringValue named “Value” inside of the folder and leaves the server, I want the StringValue named “Value” be saved of its name once the player rejoins.
The problem is, after inserting a default StringValue named “Value” it seems that the name turns to “nil” upon reconnect.
I have done some “Print” tests to try and figure out where in the code would be setting the name to this, but I could not find it. In studio, I noticed that the last print statement printed out everything that was in the folder including “Value”.
--// Variables
local DataStoreService = game:GetService("DataStoreService")
local bombData = DataStoreService:GetDataStore("bombData")
local StoredBombs = {}
game.Players.PlayerAdded:Connect(function(player)
local PlayerBombInventory = Instance.new("Folder")
PlayerBombInventory.Name = "BombInventory"
PlayerBombInventory.Parent = player
local data = bombData:GetAsync(tostring(player.userId))
if data then
for i,v in pairs(data) do
print(tostring(v.Name))
local BombValue = Instance.new("StringValue")
BombValue.Name = tostring(v.Name)
BombValue.Value = tostring(v.Value)
BombValue.Parent = PlayerBombInventory
end
else
print("Data not found")
end
end)
game.Players.PlayerRemoving:Connect(function(player)
for i, v in next, player.BombInventory:GetChildren() do
table.insert(StoredBombs,tostring(v.Name))
print(tostring(v.Name))
end
local success, err = pcall(function()
return bombData:SetAsync(tostring(player.UserId),StoredBombs)
end)
end)
You might want to check if your pcall ever errors, perhaps for example you’re testing in studio with api services disabled?
Also you should define the StoredBombs table inside the PlayerRemoving handler, otherwise every next person will receive the previous person’s bombs automatically.
Aaaaalso the way you load the saved data is incorrect, you never save the values, only the names. Try doing something like this:
--// Variables
local DataStoreService = game:GetService("DataStoreService")
local bombData = DataStoreService:GetDataStore("bombData")
game.Players.PlayerAdded:Connect(function(player)
local PlayerBombInventory = Instance.new("Folder")
PlayerBombInventory.Name = "BombInventory"
PlayerBombInventory.Parent = player
local data = bombData:GetAsync(tostring(player.userId))
if data then
for i,v in pairs(data) do
print(tostring(v.Name))
local BombValue = Instance.new("StringValue")
BombValue.Name = tostring(v.Name)
BombValue.Value = tostring(v.Value)
BombValue.Parent = PlayerBombInventory
end
else
print("Data not found")
end
end)
game.Players.PlayerRemoving:Connect(function(player)
local StoredBombs = {}
for i, v in next, player.BombInventory:GetChildren() do
table.insert(StoredBombs, {Name = v.Name, Value = v.Value})
print(tostring(v.Name))
end
local success, err = pcall(function()
return bombData:SetAsync(tostring(player.UserId),StoredBombs)
end)
if not success then
warn("Save error:",err)
end
end)
Throw it into ServerScriptService
(all you do is add String/Number/Bool values into the InitialData folder… saving/loading/autosaving is automatic)
to update a value with it, you’ll do something like.
local dm = require(script.Parent.DataManager)
function addCash(player, amount)
local cash = dm:GetData(player).Cash
cash.Value = cash.Value + amount
end
However what you want to access when you create BombValue is this:
{
{Name = "StandardBomb", Value = 1},
{Name = "SpecialBomb", Value = 2},
{Name = "ChristmasBomb", Value = 3},
}
So, to fix this your PlayerRemoving should look like this:
game.Players.PlayerRemoving:Connect(function(player)
for i, v in next, player.BombInventory:GetChildren() do
table.insert(StoredBombs,{Name = tostring(v.Name), Value = v.Value}) -- Changed line to rectify
print(tostring(v.Name))
end
local success, err = pcall(function()
return bombData:SetAsync(tostring(player.UserId),StoredBombs)
end)
end)
its inefficient to use PlayerRemoving alone, it wont always save.
he’ll need to use this in combination with a pcall inside of BindToClose, along with a loop that retries X amount of times, not to mention an autosave feature.
if he has none of these then there is no garuntee it’ll save and his players will lose data.
and then he’ll be back to having the same issue, based on his data changes.
im sorry, but its the proper way to do it or else he is going to be back at square one, so i’m sure he would definitely care about this, even if its not right now.
game.Players.PlayerAdded:Connect(function(player)
--load player
end
game.Players.PlayerRemoving:Connect(function(player)
--save player
--dispose of values
end
game.BindToClose:Connect(function()
--save all players with a loop and a pcall
end)
It is not important for most cases - in fact, it’s only really important if he is going to frequently shut down the game. You can direct him to Best Practices, but again, the user is asking for a specific answer for their specific question.
actually if he doesn’t use BindToClose the very last player will rarely save and he wont be able to test his saving functions in studio evertime, which could be the whole source of his current issue and corrupt his data, based on his design.
there is loads of people reporting issues about it, you can search the forum yourself to see.
This is incorrect. Whilst it is best practice as it may lead to data loss, the user isn’t asking about that.
And this is definitely not the cause of their issues. Please read the marked solution for the issue, or my post. Please do not confuse this user by misleading them about the issue here.
its not misleading, I’ve literally had the same issue with not being able to save in studio and last player not saving, if you all aren’t going to teach him the proper way to save data, then its pointless, but okay im glad you found your problem @Auxicon
As you know, a table is like a row of values. What table.insert does is it inserts a value at the end of the table.
local tbl = {1,2}
table.insert(tbl, 3) --the table now looks like this: {1, 2, 3}
but since tables can hold any kind of value, they can hold other tables too! Which is exactly what I did in my code, basically making it look like { {Name = "something", Value = "something else"}, {Name = "something", Value = "something else"} }, or to format it better
{
{Name = "something", Value = "something else"},
{Name = "something", Value = "something else"}
}
Also, if you’re unfamiliar with dictionary tables you might be confused by the look of that table.
You know how regular tables hold values under numerical keys:
local tbl = {"hello", "world"}
print(tbl[1]) --> hello
print(tbl[2]) --> world
Dictionary tables basically let you use strings (or any other object but let’s focus on strings) as the key, for example:
local tbl = {
hello = "world"
["another way of doing this"] = "hi there!"
}
print(tbl.hello) --> world
The downside of them is they don’t have a specific “order” since the values aren’t identified by numbers anymore, but you can still loop through them with pairs() normally!
It’s really not pointless, because that’s not what the post is asking, lol. This is not a question on best practices or resolving data saving, it’s that a DataStore is fetching nil and there can be any number of causes for this to happen beyond a malformed save request.
It’s misleading in the sense that you were needlessly arguing best practices on saving and straying away from answering the actual question instead of answering the question which is that certain fields in the DataStore are returning nil. Clearly their current code works, it’s not that their data doesn’t save. So it’s best to address the actual problem.
In the future, please actually address the question in the OP rather than leading them on a wild goose chase. Best practices on data saving is irrelevant to the topic, it’s about fields returning nil.
he has already found the solution, there really wasn’t a need to ping me in order to keep this ordeal going on and if you notice I was asking him questions before unix interrupted by becoming passive aggressive. (while also “misleading” the original poster too and his post wasn’t the chosen solution), lets be fair and respectful here, no more ‘positive’ flaming please?
thanks though, i’ll take this into consideration next time I post.