Hey Developers,
In my game I use multiple Datastores. I also have multiple folders. I use different Datastores for these Folders, because (for example) I have a Donation Datastore which I cannot change because people already donated to my game. Now I ran into a Problem: I was planning on releasing an Update to my Obby game: Halos, Free Skips and Points. For each of these things I created multiple Folders because the Point Instance should be Visible, so I added these in the leaderstats Section. For the Things like Free Skips I had to add a Timer which goes down and saves when the Player leaves and should not be visible. So for each of these Values I am using different Datastores. And now I got this warning in output: DataStore request was added to queue. If request queue fills, further requests will be dropped. Try sending fewer requests.Key = User-1051459521 - Studio That means I created too many Datastores. As I said I cannot change every Value to 1 Datastore and I cannot create 1 Folder for all the 3 Values because some of these should be not visible for the player. So my question is if you can create a Script, that Saves multiple Folders (in this case the leaderstats, Free Skips folder and the Halo Folder) with their stuff in it (I ONLY use values for every Folder but I use accessories which are located in the Halos Folder). So I want to make a Script that Saves the different Folders with their Stuff in it. (for the halo save script I created this one):
game.Players.PlayerRemoving:Connect(function(player)
pcall(function()
local HaloSave = {}
for i, Halo in pairs(player.OwnedHalos:GetChildren()) do
if Halo then
table.insert(HaloSave,Halo.Name)
end
end
DataStore:SetAsync("User-"..player.UserId,HaloSave)
end)
end)
game:BindToClose(function()
for i,player in pairs(game.Players:GetPlayers()) do
local HaloSave = {}
for i, Halo in pairs(player:WaitForChild("OwnedHalos"):GetChildren()) do
if Halo then
table.insert(HaloSave,Halo.Name)
end
end
DataStore:SetAsync("User-"..player.UserId,HaloSave)
end
end)
local table = {}
for i,v in pairs(folders:GetChildren()) do
table[v.Name] = {}
for i,g in pairs(v:GetChildren()) do
for i,s in pairs(folders:GetChildren()) do
table[v.Name] = {}
table.insert(v.Name, g)
end
end
The code he gave you was assuming that all of your folders were under one larger folder. If you want to just use the code he gave you, just replace the āfoldersā variable with a list of all the different folders you would like to save. It will look something like this:
--First, you want to add all of your folders to the list:
local folders = {}
folders.insert( plr.leaderstats ) --using leaderstats as an example, do this for all of your folders
--Next, we will create a larger folder containing all of your other folders
local data = {}
for i,v in pairs(folders:GetChildren()) do
--for each folder, we are creating a subfolder in our data
data[v.Name] = {}
for i,g in pairs(v:GetChildren()) do
--this will put each item in that folder into the subfolder
data.insert(v.Name, g)
end
end
Let me know if something doesnāt work, Iām writing this on my phone right now which is a pain
Ok I tried to transfer that for my game. Here is the Code:
local DataStore = game:GetService("DataStoreService"):GetDataStore("MainData")
game.Players.PlayerRemoving:Connect(function(plr)
local folders = {}
folders.insert(plr.FreeSkips)
folders.insert(plr.OwnedHalos)
local data = {}
for i,v in pairs(folders:GetChildren()) do
data[v.Name] = {}
for i,g in pairs(v:GetChildren()) do
data.insert(v.Name, g)
end
end
DataStore:SetAsync("User-"..plr.UserId,data)
end)
(Sorry I am not experienced with Scripting) Does this Script Save the Children of the specific Folders?
Also ( I mentioned this in my first post), I save the Halo Folder in a weird way:
game.Players.PlayerAdded:Connect(function(plr)
pcall(function()
local Halo = DataStore:GetAsync("User-"..plr.UserId)
if Halo then
for i,v in pairs(Halo) do
local HaloFound = game.ReplicatedStorage.HaloEvents.Halos:FindFirstChild(v)
if HaloFound then
HaloFound:Clone().Parent = plr:WaitForChild("OwnedHalos")
end
end
end
end)
end)
This script basically checks for a Folder in Replicated Storage. If any Halo of the Halo Folder is the Same as there it gets cloned into the HaloFolder in the Player. Because you donāt the SetAsync here it wonāt be a Problem (sorry if thatās a stupid question), but will every accessory get cloned to the HaloFolder? Because you are creating a Main Folder for all the Folders u want to save⦠Maybe you have to add a Script that puts them back if you join the Game?
Oh and (I forgot), since there are Values in the FreeSkips Folder, and when the Player joins the first Time so he has no Data yet, I have to setup a Starter Value. Here is my current Code for setting up the several Folders and that is also the reason why the Datastore overfills with requests:
local DataStoreService = game:GetService("DataStoreService")
local DataStore = DataStoreService:GetDataStore("FreeSkipsDataSaves")
local ResetTime = 1800
function loadData(player)
local Key = "Player_"..player.UserId
local FreeSkipsFolder = Instance.new("Folder", player)
FreeSkipsFolder.Name = "FreeSkips"
local FreeSkips = Instance.new("IntValue", FreeSkipsFolder)
FreeSkips.Name = "FreeSkips"
local Time = Instance.new("IntValue", FreeSkipsFolder)
Time.Name = "Time"
local succes, err = pcall(function()
local data = DataStore:GetAsync(Key)
if data then
FreeSkips.Value = data[1]
Time.Value = data[2]
else
FreeSkips.Value = 0
Time.Value = ResetTime
end
end)
if err then
print("Could not load data!")
warn(err)
end
end
function saveData(player)
local Key = "Player_"..player.UserId
local FreeSkipsFolder = player:WaitForChild("FreeSkips")
local succes, err = pcall(function()
local stufftoSave = {
FreeSkipsFolder.FreeSkips.Value,
FreeSkipsFolder.Time.Value,
}
if FreeSkipsFolder then
DataStore:SetAsync(Key, stufftoSave)
end
end)
if err then
print("Could not save data!")
warn(err)
end
end
function onServerShutdown()
if game:GetService("RunService"):IsStudio() then
wait(2)
else
for _, player in pairs(game.Players:GetPlayers()) do
local finished = Instance.new("BindableEvent")
local FreeSkipsFolder = player:WaitForChild("FreeSkips")
local Key = "Player_"..player.UserId
local stufftoSave = {
FreeSkipsFolder.FreeSkips.Value,
FreeSkipsFolder.Time.Value,
}
if FreeSkipsFolder then
DataStore:SetAsync(Key, stufftoSave)
end
finished.Event:Wait()
end
end
end
game:BindToClose(onServerShutdown)
game.Players.PlayerAdded:Connect(loadData)
game.Players.PlayerRemoving:Connect(saveData)
I made a mistake in my original script: Datastores cannot save raw objects. This includes integer values, folders, etc.
To fix this issue (and a little time in the future), I would recommend the following steps:
Put everything into one script, in one space, so that the code isnāt too cluttered
When youāre saving the data, save the values of them
** This will require you to assign numerical or string values to the halos, I recommend integer values as a āHaloIDā in the halo
Create a function meant to āformatā your data so you can easily look back and know what to do with it, hereās an example:
function formatData(player)
local data = {}
local FreeSkipsFolder = player:WaitForChild("FreeSkips")
local skips = {}
for i,piece in pairs(FreeSkipsFolder:GetChildren()) do
table.insert(skips, piece.Value)
end
table.insert(data, skips)
local HalosFolder = player:WaitForChild("OwnedHalos")
local halos = {}
for i,halo in pairs(HalosFolder:GetChildren()) do
table.insert(halos, halo:WaitForChild("HaloID").Value)
end
table.insert(data, halos)
return data
end
This will stores things into the datastore in a way that would look something like this (please excuse my poor illustration skills):
woah u didnt need to write that all thank you firstly!!! I will try to use the Script later. Only 1 thing, the Halo save script works fine tho, it just uses a separate :SetAsync() function. Oh, and is a Script neccessary to unfolder all the saved folders?
When implementing this, use the function to easily save data, as well as edit how you save it. It should clean up the code a bit, so that your save data looks something like this:
function saveData(player)
local Key = "Player_"..player.UserId
local stuffToSave = formatData(player)
local succes, err = pcall(function()
if stuffToSave then
DataStore:SetAsync(Key, stuffToSave)
end
end)
if err then
warn('WARNING: COULD NOT SAVE PLAYER DATA: '..err)
end
end
Your loading may be a little more messy, but you can also make a function to match HaloIDās of the halos in ReplicatedStorage
function matchHaloData(player, haloData)
for i,halo in pairs(game.ReplicatedStorage.HaloEvents.Halos:GetChildren()) do
--table.find will return a value if an ID exists in the table, so if it does, we will clone that halo to the player 'inventory'
if table.find(haloData, halo.HaloID.Value) ~= nil then
halo:Clone().Parent = player:WaitForChild("OwnedHalos")
end
end
end
All of this leading to the Load function:
function loadData(player)
--CREATING FOLDERS
local Key = "Player_"..player.UserId
local SkipsFolder = Instance.new("Folder", player)
SkipsFolder.Name = "FreeSkips"
local Skips = Instance.new("IntValue", SkipsFolder)
local Time = Instance.new("IntValue", SkipsFolder)
Skips.Name = "FreeSkips" --May want to change this so it doesn't have the same name as the folder
Time.Name = "Time"
local HalosFolder = Instance.new("Folder", player)
HalosFolder.Name = "OwnedHalos"
--GETTING PLAYER DATA
local sucess, err = pcall(function()
local data = DataStore:GetAsync(Key)
if data then
--Setting up the Halos using the function we made earlier:
matchHaloData(player, data[2])
--Using the Data to set up skips
Skips.Value = data[1][1] -- The first section of the folder, first value: FreeSkips
Time.Value = data[1][2]
else
Skips.Value = 0
Time.Value = ResetTime
end
end)
if err then
warn('WARNING: COULD NOT LOAD PLAYER DATA: '..err)
end
end
Hereās what these functions would look like all in one place:
--Vars and Services
local DataStore = game:GetService('DataStoreService')
local ResetTime = 0 --Don't forget to set this later
--Functions
function formatData(player)
local data = {}
local FreeSkipsFolder = player:WaitForChild("FreeSkips")
local skips = {}
for i,piece in pairs(FreeSkipsFolder:GetChildren()) do
table.insert(skips, piece.Value)
end
table.insert(data, skips)
local HalosFolder = player:WaitForChild("OwnedHalos")
local halos = {}
for i,halo in pairs(HalosFolder:GetChildren()) do
table.insert(halos, halo:WaitForChild("HaloID").Value)
end
table.insert(data, halos)
return data
end
function saveData(player)
local Key = "Player_"..player.UserId
local stuffToSave = formatData(player)
local succes, err = pcall(function()
if stuffToSave then
DataStore:SetAsync(Key, stuffToSave)
end
end)
if err then
warn('WARNING: COULD NOT SAVE PLAYER DATA: '..err)
end
end
function matchHaloData(player, haloData)
for i,halo in pairs(game.ReplicatedStorage.HaloEvents.Halos:GetChildren()) do
--table.find will return a value if an ID exists in the table, so if it does, we will clone that halo to the player 'inventory'
if table.find(haloData, halo.HaloID.Value) ~= nil then
halo:Clone().Parent = player:WaitForChild("OwnedHalos")
end
end
end
function loadData(player)
--CREATING FOLDERS
local Key = "Player_"..player.UserId
local SkipsFolder = Instance.new("Folder", player)
SkipsFolder.Name = "FreeSkips"
local Skips = Instance.new("IntValue", SkipsFolder)
local Time = Instance.new("IntValue", SkipsFolder)
Skips.Name = "FreeSkips" --May want to change this so it doesn't have the same name as the folder
Time.Name = "Time"
local HalosFolder = Instance.new("Folder", player)
HalosFolder.Name = "OwnedHalos"
--GETTING PLAYER DATA
local sucess, err = pcall(function()
local data = DataStore:GetAsync(Key)
if data then
--Setting up the Halos using the function we made earlier:
matchHaloData(player, data[2])
--Using the Data to set up skips
Skips.Value = data[1][1] -- The first section of the folder, first value: FreeSkips
Time.Value = data[1][2]
else
Skips.Value = 0
Time.Value = ResetTime
end
end)
if err then
warn('WARNING: COULD NOT LOAD PLAYER DATA: '..err)
end
end
--Forgot Server Shutdown function on the last code: here it is
function onServerShutdown()
if game:GetService("RunService"):IsStudio() then
wait(2)
else
for _, player in pairs(game.Players:GetPlayers()) do
local finished = Instance.new("BindableEvent")
saveData(player) --It's easier to use the previous saveData function on each player than it is to write new code
finished.Event:Wait()
end
end
end
--Binding Events
game:BindToClose(onServerShutdown)
game.Players.PlayerAdded:Connect(loadData)
game.Players.PlayerRemoving:Connect(saveData)
Hope this helps
Also itās no prob, I donāt have the motivation to make my own stuff, but I love helping people with theirs
EDIT: I tried to comment where I could, but let me know if it either doesnāt work or if you need more info about a certain part, Iād be happy to DM you my discord tag and we can figure this out
Each halo will have an IntValue inside of it, with the value being a unique id for the Halo. It would be the same as calling them āHalo 1ā or āHalo 200398ā
Idea for this: Since all the Halos have different Names I just make a Script that when the Player Joins, changes the IntValues Value to the Name of the Halo. Would this work too?
local DataStoreService = game:GetService("DataStoreService")
local DataStore = DataStoreService:GetDataStore("leaderstatDataSaves")
function loadData(player)
local Key = "Player_"..player.UserId
local leaderstats = player:WaitForChild("leaderstats")
local Points = Instance.new("IntValue", leaderstats)
Points.Name = "Points"
local Wins = Instance.new("IntValue", leaderstats)
Wins.Name = "Wins"
local succes, err = pcall(function()
local data = DataStore:GetAsync(Key)
if data then
Points.Value = data[1]
Wins.Value = data[2]
else
Points.Value = 0
Wins.Value = 0
end
end)
if err then
print("Could not load data!")
warn(err)
end
end
function saveData(player)
local Key = "Player_"..player.UserId
local leaderstats = player:WaitForChild("leaderstats")
local succes, err = pcall(function()
local stufftoSave = {
leaderstats.Points.Value,
leaderstats.Wins.Value,
}
if leaderstats then
DataStore:SetAsync(Key, stufftoSave)
end
end)
if err then
print("Could not save data!")
warn(err)
end
end
function onServerShutdown()
if game:GetService("RunService"):IsStudio() then
wait(2)
else
for _, player in pairs(game.Players:GetPlayers()) do
local finished = Instance.new("BindableEvent")
local leaderstats = player:WaitForChild("leaderstats")
local Key = "Player_"..player.UserId
local stufftoSave = {
leaderstats.Points.Value,
leaderstats.Wins.Value,
}
if leaderstats then
DataStore:SetAsync(Key, stufftoSave)
end
finished.Event:Wait()
end
end
end
game:BindToClose(onServerShutdown)
game.Players.PlayerAdded:Connect(loadData)
game.Players.PlayerRemoving:Connect(saveData)