Hey, I made this script wchich is supposed to save the data of the currently edited world while a player leaves. Each world is supposed to be stored in its own DataStore instead of storing all of them in one because of the 4MB limit of data that can be stored in a DataStore. However for some reason the loop that adds all the blocks and their data to the blocksData table stops at some point. It only prints out names of a few blocks and then it stops. There are no erros in the output. Does anybody know why is this happening?
Here’s the part of my script responsible for saving data:
game.Players.PlayerRemoving:Connect(function(player)
local blocksAmount = #workspace.Blocks:GetDescendants()
local data = {}
data.Saves = {}
for i, v in pairs(player.Saves:GetChildren()) do
local saveData = {}
saveData.Name = v.Name
saveData.DateCreated = v.DateCreated.Value
saveData.Seed = v.Seed.Value
table.insert(data.Saves, saveData)
end
PlayerData:UpdateAsync(player.UserId, function()
return game.HttpService:JSONEncode(data)
end)
print("player data")
print(player.Saves:GetChildren())
for i, v in pairs(player.Saves:GetChildren()) do
local SaveBlocksData = DataStoreService:GetDataStore("SaveBlocks"..v.SaveId.Value)
print("SaveBlocks"..v.SaveId.Value)
local blocksData = {}
blocksData.Blocks = {}
for ii, vv in pairs(workspace.Blocks:GetDescendants()) do
if vv:IsA("Part") or vv:IsA("BasePart") then
print(vv.Name)
local blockInfo = {}
blockInfo.Name = vv.Name
blockInfo.XPosition = vv.Position.X
blockInfo.YPosition = vv.Position.Y
blockInfo.ZPosition = vv.Position.Z
blockInfo.XOrientation = vv.Orientation.X
blockInfo.YOrientation = vv.Orientation.Y
blockInfo.ZOrientation = vv.Orientation.Z
blockInfo.Anchored = vv.Anchored
table.insert(blocksData.Blocks, blockInfo)
end
end
print(blocksData)
SaveBlocksData:UpdateAsync(player.UserId, function()
return game.HttpService:JSONEncode(blocksData)
end)
print("updated data")
end
end)```
It’s a problem as old as game engines itself unfortunately. When the player leaves the game, the server removes the player object and anything attached to it running. Because DB calls take a long time (in computer time anyway, not human time), your best bet is to collect all the “player vital” data you need first, then collect all the block data, then have them both do the DB call to save it. That way, if the player object is gone it won’t matter since you already stored the important data somewhere else. Without knowing exactly how your game works, it might be best to create a separate function for saving the world blocks assuming those aren’t attached to the player object itself? That way you can save your player data first, then fire off a “separate” function to do the world block saving that won’t depend on the player being there at that very instant.
Have you tried using task.spawn() for both saves to prevent yielding over the other? This should allow synchronous data saving and I don’t think it would error unless you’re requesting more than the limit since, from what I’m seeing, you create a different key for each individual block save. It would only error if you try to set the data on the same key within the 6 second cooldown period. (Correct me if I’m wrong )
Well, since I’m not limiting the world’s size or max blocks that can be placed in the world, players can expand it pretty much infinitly, so at some point the limit may be reached. I already reached it once when I was messing around with this save system and all saves were in the same DataStore.
I removed auto-saving when the player leaves and instead added the ability to save a world manually and everything works just fine now. Thanks for pointing out the issue!
You should use SetAsync over UpdateAsync if you are not going to use the currently saved data. Also, you do not need to JSONEncode the data as Roblox already does that internally.
Thanks for the advice.
Before I started using JSONEncode, I was getting an error that was telling me that I can’t store Dictionaries inside DataStores. The error stopped appearing after I started encoding the data.