I want to save some folders with some values, but the folders are in the player and the script must doesn’t know what kind of folder they are because when I add something new to the folders I don’t need to edit the script, this will save my time, i like that:).
Save when player left.
Load when player joined.
I’ve already seen tutorials on this topic, but didn’t find anything that could help me.
So you basically want to traverse the player folders and find all values and then serialize/deserialize them?
Just use GetDescendants() and cherry-pick only these instances whose class is ValueBase.
After you cherry-picked all value based instances, check their type if it’s NumberValue, StringValue or whatever else, take the value from it and save to datastore, or load the datastore and set the value.
What’s the difference with GetChildren()) and GetDescendants()?
I use the GetChildren()) to get all parts.
GetChildren())
for _,part in ipairs(workspace:GetChildren) do
if part.ClassName == "Part" or part.ClassName == "Model" or part.ClassName == "Folder" then
part:Destroy()
end
end
GetDescendants()
for _,part in ipairs(workspace:GetDescendants()) do
if part:IsA("Part") or part:IsA("Model") or part:IsA("Folder") then
part:Destroy()
end
end
GetChildren() only checks for instances under specified one (one level check) GetDescendants() checks all instances and their instances under them and so on (recursive traverse)
Your GetChildren implementation wont work since you’re missing parentheses in ipairs, you’re not using it as function.
Okay, but to be honest, I don’t understand saving data and I think it would be difficult for me. I can make the most common scripts that act on the world (game.Workspace/ReplicationStorage) and local scripts that act on the player (game.Players) and that’s all I can do, so I don’t understand how to implement what was written above.
What’s difficult to understand for you? I’ll try to explain it. I think I’ll not show some examples, but I can try to explain the theoretical part of it.
I read this today: Saving Data | Documentation - Roblox Creator Hub
But when it came to the example “Gold Rush”(Place), the script was not quite the same as in the documentation. Maybe i miss something?
Do not use the example game but try to utilize the example code provided you in the article.
This article basically shows you basic use of datastore, which is the part where I described that it is easy. It gets difficult when there are too much data in the game, but that’s not your current situation I’d say.
SetAsync saves data to datastore GetAsync loads data from datastore
It’s working but i need “Saving folders with values in the easiest way”
local DataStoreService = game:GetService("DataStoreService")
local goldStore = DataStoreService:GetDataStore("PlayerGold")
game.Players.PlayerAdded:Connect(function(player)
local playerUserID = player.UserId
local playerGold = 250
-- Read data store key
local getSuccess, currentGold = pcall(function()
return goldStore:GetAsync(playerUserID)
end)
if getSuccess then
print(currentGold)
end
end)
game.Players.PlayerRemoving:Connect(function(player)
local playerUserID = player.UserId
local playerGold = player.leaderstats.Money.Value
-- Set data store key
local setSuccess, errorMessage = pcall(function()
goldStore:SetAsync(playerUserID, playerGold)
end)
if not setSuccess then
warn(errorMessage)
end
end)
Here’s my attempt of creating an easy dynamic way to convert a folder/value structure to a dictionary and vice versa:
local function isIntVal(val: number)
--IntValues in the range of x < -2^51 < 2^51 < x
--Will be converted to NumberValues on next decode
local safeMaxInt = 2^51
if val < -safeMaxInt or val > safeMaxInt then return false end
return val == math.floor(val)
end
local function toReal(num: number): number
local offset = 10^(-15)
repeat
num += offset*5
offset *= 10
until not isIntVal(num)
return num
end
local function toDictionary(root: Instance): {}
local data = {}
for _, child in pairs(root:GetChildren()) do
if child:IsA("NumberValue") and isIntVal(child.Value) then
data[child.Name] = toReal(child.Value)
elseif child:IsA("ValueBase") then
data[child.Name] = child.Value
elseif child:IsA("Folder") then
data[child.Name] = toDictionary(child)
end
end
return data
end
local function toFolders(dict: {}, folder: Folder?): Folder
local folder = folder or Instance.new("Folder")
local easyTypes = {"BrickColor", "CFrame", "Color3", "Ray", "Vector3"}
for name, value in pairs(dict) do
local valType = typeof(value)
local val
if valType == "number" and isIntVal(value) then
val = Instance.new("IntValue")
elseif valType == "number" then
val = Instance.new("NumberValue")
elseif valType == "boolean" then
val = Instance.new("BoolValue")
elseif valType == "string" then
val = Instance.new("StringValue")
elseif valType == "Instance" or valType == "nil" then
val = Instance.new("ObjectValue")
elseif table.find(easyTypes, valType) then
val = Instance.new(valType.."Value")
elseif valType == "table" then
val = Instance.new("Folder")
toFolders(value, val)
else
warn("Failed to load key", name, "and value", value, "ignoring...")
continue
end
val.Name = name
if valType ~= "table" then val.Value = value end
val.Parent = folder
end
return folder
end
Example usage:
--According to game logic specified on topic description
--For saving:
local dict = toDictionary(player)
--For loading:
local folder = toFolders(dict)
for _, child in pairs(folder:GetChildren()) do
child.Parent = player
end
Keep in mind that datastores don’t allow the saving of instances. So for that you have to add an extra step on top of this to convert them into another data type, for example serializing them as strings or only storing the necessary pieces of information to recreate them.
game.Players.PlayerAdded:Connect(function(player)
local dict = --the dictionary you fetched from DS
local folder = toFolders(dict)
for _, child in pairs(folder:GetChildren()) do
child.Parent = player
print(child)
end
end)
game.Players.PlayerRemoving:Connect(function(player)
local dict = toDictionary(player)
print(dict)
--save dictionary here
end)
Sir,if you don’t know scripting too much like Datastore,variables,i wouldn’t recommended opening this post.but you should understand what they say.
Just a example:woman_bald:t6:
local DataStore = game:GetService("DataStoreService")
local D = DataStore:GetDataStore("PlayerData")
game:GetService("Players").PlayerAdded:Connect(function(Plr)
local success,data = pcall(function()
return D:GetAsync(Plr.UserId)
end)
if success then
if data ~= nil then
for i,v in data do
print("bro got scared and got smarter and it is the "..v.." Number⚠️❌🐷🔎😱🥵")
end
end
end
end)
game:GetService("Players").PlayerRemoving:Connect(function(Plr)
D:SetAsync(Plr.UserId,{math.random(0,1000),math.random(0,1000),math.random(0,1000),math.random(0,1000),math.random(0,1000),math.random(0,1000),math.random(0,1000),math.random(0,1000),math.random(0,1000),math.random(0,1000)})
end)
local DataStoreService = game:GetService("DataStoreService")
local STORE = DataStoreService:GetDataStore("STR")
game.Players.PlayerAdded:Connect(function(Player)
local Key = tostring(Player.UserId)
local DataPlayer = STORE:GetAsync(Key)
if DataPlayer ~= nil then
--ASGSA
for NameFolder,CheckFolder in pairs(DataPlayer) do
local NewFolder = Instance.new("Folder")
NewFolder.Name = NameFolder
NewFolder.Parent = Player
for _,CheckValue in pairs(CheckFolder) do
local ThisVal = nil
if CheckValue["TypeValue"] == "String" then
local NewValue = Instance.new("StringValue")
ThisVal = NewValue
elseif CheckValue["TypeValue"] == "BoolValue" then
local NewValue = Instance.new("BoolValue")
ThisVal = NewValue
elseif CheckValue["TypeValue"] == "IntValue" then
local NewValue = Instance.new("IntValue")
ThisVal = NewValue
elseif CheckValue["TypeValue"] == "NumberValue" then
local NewValue = Instance.new("NumberValue")
ThisVal = NewValue
end
if ThisVal then
ThisVal.Value = CheckValue["Value"]
ThisVal.Name = CheckValue["NameValue"]
ThisVal.Parent = NewFolder
end
end
end
end
end)
local BlackListSave = {
}
game.Players.PlayerRemoving:Connect(function(Player)
local TableToSave = {}
for _,CheckingFolder in pairs(Player:GetChildren()) do
if CheckingFolder:IsA("Folder") then
for _,CheckValue in pairs(CheckingFolder:GetChildren()) do
if CheckValue:IsA("ValueBase") then
if table.find(BlackListSave,CheckValue.Name) == nil then
if table.find(TableToSave,CheckingFolder.Name) == nil then
local TableToInst = {}
table.insert(TableToSave,TableToInst)
TableToSave[CheckingFolder.Name] = TableToSave[1]
TableToSave[1] = nil
end
local ThisTable = TableToSave[CheckingFolder.Name]
if ThisTable then
if CheckValue:IsA("StringValue") then
local ThisValue = {
["TypeValue"] = "String",
["NameValue"] = CheckValue.Name,
["Value"] = CheckValue.Value
}
table.insert(ThisTable,ThisValue)
elseif CheckValue:IsA("BoolValue") then
local ThisValue = {
["TypeValue"] = "BoolValue",
["NameValue"] = CheckValue.Name,
["Value"] = CheckValue.Value
}
table.insert(ThisTable,ThisValue)
elseif CheckValue:IsA("IntValue") then
local ThisValue = {
["TypeValue"] = "IntValue",
["NameValue"] = CheckValue.Name,
["Value"] = CheckValue.Value
}
table.insert(ThisTable,ThisValue)
elseif CheckValue:IsA("NumberValue") then
local ThisValue = {
["TypeValue"] = "NumberValue",
["NameValue"] = CheckValue.Name,
["Value"] = CheckValue.Value
}
table.insert(ThisTable,ThisValue)
-- Else Value
end
end
end
end
end
end
end
local Key = tostring(Player.UserId)
STORE:SetAsync(Key,TableToSave)
end)
It doesn’t work
Game published, API Services enabled, what wrong?
Maybe, the problem is another scripts creating folder with values?
This script looks like it actually works, but it’s don’t.