hello, my first time working with datastore, I need help optimizing a script where the objective is to save the name and value of more than 150 boolvalues
local DataStoreService = game:GetService("DataStoreService")
local SaveRats = DataStoreService:GetDataStore("SaveRats")
game.Players.PlayerAdded:Connect(function(Player)
local ratsFolder = Instance.new("Folder", Player)
ratsFolder.Name = "ratsFolder"
-- rats boolvalue
local ratsBool = {}
for i, v in pairs(workspace:WaitForChild("Rats"):GetChildren()) do
table.insert(ratsBool, v.Name)
local newRats = Instance.new("BoolValue", ratsFolder)
newRats.Name = ratsBool[i]
newRats.Value = false
end
local success, err = pcall(function()
return SaveRats:GetAsync(Player.UserId)
end)
local rats = ratsFolder:GetChildren()
if success then
for i = 1, #rats do
rats[i].Value = SaveRats:GetAsync(Player.UserId..rats[i].Name)
end
end
end)
game.Players.PlayerRemoving:Connect(function(Player)
local rats = Player.ratsFolder:GetChildren()
for i=1, #rats do
rats[i].Value = SaveRats:SetAsync(Player.userId..rats[i].Name,rats[i].Value)
end
end)
The script does not save some bools because this message “Not running script because past shutdown deadline” appears
game:BindToClose(function()
for i, player in pairs(game.Players:GetPlayers()) do
-- the same thing from PlayersRemoving except it does it for every player
local rats = player.ratsFolder:GetChildren()
for i=1, #rats do
rats[i].Value = SaveRats:SetAsync(player.userId..rats[i].Name,rats[i].Value)
end
end
end)
it keeps giving the same error because this script is saving the bools one by one causing the server to shut down before it saves, one idea I had was to put the 150 boolvalues ​​inside a table and then call SaveRats:SetAsync just once, but I don’t know how I can do this
table.insert(ratsBool, v.Name) was just to get the name of the rats that are in the workspace and put it in the bools so when the bool is true the rat will be destroyed
You’re creating an individual data store address for each rat in the player’s inventory; that’s creating a dozen different data store keys for one player (and will lead to data loss and rate limiting)
You’re doing 2 different data requests here.
One if for the Player’s UserId (which doesn’t seem to have any sort of data saved for it)
Is the Player’s UserId + the rat name, which shouldn’t be set up like that
This can stay the same, because you can store all the rat information to a table connected to the player’s UserId as a datastore address
local success, err = pcall(function()
return SaveRats:GetAsync(Player.UserId)
end)
The easiest way to fix this is to use tables. Store all the collected rats into a list and return that listen when the player’s data is loaded.
if success and err then -- the request can be successful, but that doesn't mean that the player has any data
-- This may not make sense right now because the way you save information is different
-- but, the way this is working is by looping through the player's data store information
-- and setting the found rats to the data store info (if found)
for _, name in err do
local value = ratsFolder:FindFirstChild(name) -- since you store the rat's name, look for the rat via its name
if not value then
warn(`Rat {name} does not exist`) -- This tells you if the rat trying to be loaded still exists within the game
continue -- Skip this iteration
end
value.Value = true -- since it exists in the data store, set the value of the rat BoolValue to true
end
elseif not success then
warn(err) -- THIS IS IMPORTANT!!! This tells you if there was a problem saving/loading data!
end
You don’t need to assign anything using SetAsync. SetAsync also returns DataStore key information, not the value being stored. (Docs)
You really just need to iterate over the player’s rat folder and store all of the info to a table.
local info = {} -- create a blank table to be saved
for _, rat in Player.ratsFolder:GetChildren() do
if rat.Value == true then -- check if this rat was found
table.insert(info, rat.Name) -- add the rat to the table
end
end
Now, you would do the same thing you did for loading the information (use a pcall).
local success, err = pcall(function()
SaveRats:SetAsync(Player.UserId, info) -- save the info using the player's userid as the key.
end)
if not success then
warn(err) -- like before, if there was a problem saving, let the console tell you what the issue is!
end
However, this is still not the most efficient way to save data. You’d want to also utilize game.BindToClose like @teamassists mentioned. Additionally, you should have a separate function to save data to make your code less repetitive (when talking about game.BindToClose).
local function SavePlayerData(Player: Player)
--... save info
end
game.Players.PlayerRemoving:Connect(SavePlayerData) -- this will call the function when the event fires
game:BindToClose(function()
for _, p in game.Players:GetPlayers() do -- loop through all the players still in the game
task.spawn(SavePlayerData, p) -- call the function on players still left in the game
end
end)
This was a guide on how to fix your data store script, also, the reason why you were running into shutdown deadline errors was because of the aforementioned multiple key storing.