Ok so in my 7 months of scripting I find myself constantly having to make a new datastore for every project I undertook, so I tried making a more easily customisable one.
However as i’m continually striving to improve I would like to know any bad practises / potentially damaging flaws this new datastore I made has.
All feedback appreciated
Model: https://www.roblox.com/library/4218353378/Customizable-Datastore
code:
-- Configurations --
AddNewValues = true --If you add a new value to the datalist it will auto load on exisitng data stores
SaveAttempts = 3 -- if there is a datastore error how many times the script will try again and save
SaveVersionId = 1 -- if you have AddNewValues as true, change this whenever you change the standard data list to update players onto new save
-- Vars --
local DSS = game:GetService("DataStoreService")
local PlayerDataStore = DSS:GetDataStore("PlayerData2")
local DataList = {
SurvivalStats = {
Thirst = {Current = 100, Max = 100};
Health = {Current = 100, Max = 100};
Stamina = {Current = 100, Max = 100};
Hunger = {Current = 100, Max = 100};
};
Core = {
Gold = 0;
Position = {X = 0, Y = 0, Z = 0};
Level = {Level = 1, XpNeeded = 10, Xp = 5};
};
}
local function CapitalFirst(str)
return str:sub(1,1):upper()..str:sub(2).. "Value"
end
function SetUpPlayerFunctions(Player, Data)
-- Here is where you put your custom functions which you want to occur
end
function TableToFolder(Table, Parent)
for i,v in pairs(Table) do
if typeof(v) ~= "table" then
local T = CapitalFirst(typeof(v))
if T == "BooleanValue" then
T = "BoolValue"
end
local Value = Instance.new(T)
Value.Name = i
Value.Parent = Parent
Value.Value = v
else
local F = Instance.new("Folder")
F.Parent = Parent
F.Name = i
TableToFolder(v, F)
end
end
return Parent
end
function AddNewValuesFunc(Table, Parent)
for i,v in pairs(Table) do
local P = Parent:FindFirstChild(i)
if typeof(v) ~= "table" then
if not P then
local T = CapitalFirst(typeof(v))
if T == "BooleanValue" then
T = "BoolValue"
end
local Value = Instance.new(T)
Value.Name = i
Value.Parent = Parent
Value.Value = v
end
else
if not P then
P = Instance.new("Folder")
P.Parent = Parent
P.Name = i
end
AddNewValuesFunc(v, P)
end
end
return Parent
end
function IterateThroughFolder(Folder)
local Table = {}
for i,v in pairs(Folder:GetChildren()) do
if #v:GetChildren() == 0 or not v:IsA("Folder") then
Table[v.Name] = v.Value
else
Table[v.Name] = IterateThroughFolder(v)
end
end
return Table
end
function SaveData(Player)
if Player.Loaded.Value then
local DataTable = IterateThroughFolder(Player.Data)
DataTable["VersionNumber"] = SaveVersionId
local S, E = pcall(function()
PlayerDataStore:SetAsync(Player.UserId, DataTable)
end)
local C = 0
if not S then
repeat
C = C + 1
S, E = pcall(function()
PlayerDataStore:SetAsync(Player.UserId, DataTable)
end)
wait(3)
until S or C > SaveAttempts
end
end
end
function LoadData(Player)
local Loaded = Instance.new("BoolValue")
Loaded.Name = "Loaded"
Loaded.Parent = Player
Loaded.Value = false
local S, E = pcall(function()
Data = PlayerDataStore:GetAsync(Player.UserId)
end)
local C = 0
if not S then
repeat
C = C + 1
S, E = pcall(function()
Data = PlayerDataStore:GetAsync(Player.UserId)
end)
wait(3)
until S or C > SaveAttempts
end
if not S then
Player:Kick("Data failed to load, if issue persists contact a dev")
end
if not Data then
print(Player.Name.. " is a new player")
Data = DataList
end
local CoreFolder = Instance.new("Folder")
CoreFolder.Parent = Player
CoreFolder.Name = "Data"
TableToFolder(Data, CoreFolder)
if not Player.Data:FindFirstChild("VersionNumber") then
local Value = Instance.new("IntValue")
Value.Name = "VersionNumber"
Value.Parent = Player.Data
Value.Value = SaveVersionId
end
if AddNewValues and Player.Data.VersionNumber.Value ~= SaveVersionId then
AddNewValuesFunc(DataList, Player.Data)
end
if not Player.Character then
Player.CharacterAdded:wait()
end
SetUpPlayerFunctions(Player, Player.Data)
Loaded.Value = true
end
game.Players.PlayerAdded:Connect(LoadData)
game.Players.PlayerRemoving:Connect(SaveData)