Hello!
I’ve been working on this script for awhile and was just wondering how efficient it was. It includes packing from folders to tables and vice versa. It also verifies all data is there and it’s very easy to add more arguments, problem is that it looks like spaghetti code so I was wondering if it was as efficient as I thought or if it could be improved.
local DataStoreService = game:GetService('DataStoreService')
local DataStore = DataStoreService:GetDataStore('adsaddsdasdads')
local HttpService = game:GetService('HttpService')
local RS = game:GetService('ReplicatedStorage')
local Remotes = RS:WaitForChild('Remotes')
local defaultMusic = {}
local defaultData = {
['General'] = {
['MusicIDs'] = defaultMusic;
['Coins'] = 0;
['Experience'] = 0;
['RequiredExperience'] = 100;
['Stage'] = 0;
['Gamepasses'] = {};
['Inventory'] = {
['Pets'] = {};
['Accessories'] = {};
['Crates'] = {};
};
['BanInfo'] = {
['Banned'] = false;
['ExpiryDate'] = 'nil';
['BanReason'] = 'nil';
};
};
['LoginInfo'] = {
['TimeStamp'] = os.time();
['Streak'] = 0;
};
}
local function unpackTable(tbl, parent)
for i,v in pairs(tbl) do
if tostring(typeof(v)) == 'table' then
local folder = Instance.new('Folder', parent)
folder.Name = i
unpackTable(v, folder)
elseif tostring(typeof(v)) == 'boolean' then
local bool = Instance.new('BoolValue', parent)
bool.Name = i
bool.Value = v
elseif tostring(typeof(v)) == 'string' then
local value = Instance.new('StringValue', parent)
value.Name = i
value.Value = v
print(i,v)
elseif tostring(typeof(v)) == 'number' then
local value = Instance.new('IntValue', parent)
value.Name = i
value.Value = v
print(i,v)
end
end
end
local function loadData(data, plr)
local dataFolder = Instance.new('Folder', plr)
dataFolder.Name = 'PlayerData'
local generalInfo = Instance.new('Folder', dataFolder)
generalInfo.Name = 'General'
local loginInfo = Instance.new('Folder', dataFolder)
loginInfo.Name = 'LoginInfo'
for i,v in pairs(data['General']) do
if tostring(typeof(v)) == 'table' then
local folder = Instance.new('Folder', generalInfo)
folder.Name = i
unpackTable(v, folder)
elseif tostring(typeof(v)) == 'boolean' then
local bool = Instance.new('BoolValue', generalInfo)
bool.Name = i
bool.Value = v
elseif tostring(typeof(v)) == 'string' then
local value = Instance.new('StringValue', generalInfo)
value.Name = i
value.Value = v
print(i,v)
elseif tostring(typeof(v)) == 'number' then
local value = Instance.new('NumberValue', generalInfo)
value.Name = i
value.Value = v
print(i,v)
end
end
for i,v in pairs(data['LoginInfo']) do
if tostring(typeof(v)) == 'table' then
local folder = Instance.new('Folder', loginInfo)
folder.Name = i
unpackTable(v, folder)
elseif tostring(typeof(v)) == 'boolean' then
local bool = Instance.new('BoolValue', loginInfo)
bool.Name = i
bool.Value = v
elseif tostring(typeof(v)) == 'string' then
local value = Instance.new('StringValue', loginInfo)
value.Name = i
value.Value = v
elseif tostring(typeof(v)) == 'number' then
local value = Instance.new('NumberValue', loginInfo)
value.Name = i
value.Value = v
end
end
local loc = Instance.new('StringValue', plr)
loc.Name = 'Location'
loc.Value = 'MainIsland'
Remotes.DataFinished:FireClient(plr)
end
local function verifyPermission(data, plr)
if data['General']['BanInfo']['Banned'] == true then
Remotes.SetBan:FireClient(plr, data['BanInfo'])
else
loadData(data, plr)
end
end
local function verifyData(data, plr)
local mod = false
if not data['General'] then
data = defaultData
end
if not data['General']['MusicIDs'] then
data['General']['MusicIDs'] = defaultMusic
mod = true
end
if not data['General']['Coins'] or tostring(typeof(data['Coins'])) ~= 'number' then
data['General']['Coins'] = 0
mod = true
end
if not data['General']['Experience'] or tostring(typeof(data['Experience'])) ~= 'number' then
data['General']['Experience'] = 0
mod = true
end
if not data['General']['RequiredExperience'] or tostring(typeof(data['RequiredExperience'])) ~= 'number' then
data['General']['RequiredExperience'] = 100
mod = true
end
if not data['General']['Stage'] or tostring(typeof(data['Stage'])) ~= 'number' then
data['General']['Stage'] = 0
mod = true
end
if not data['General']['Gamepasses'] or tostring(typeof(data['Gamepasses'])) ~= 'table' then
data['General']['Gamepasses'] = {}
mod = true
end
if not data['General']['Inventory'] or tostring(typeof(data['Inventory'])) ~= 'table' then
data['General']['Inventory'] = {
['Pets'] = {};
['Accessories'] = {};
['Crates'] = {};
}
mod = true
elseif data['General']['Inventory'] then
if not data['General']['Inventory']['Pets'] or tostring(typeof(data['Inventory']['Pets'])) ~= 'table' then
data['General']['Inventory']['Pets'] = {}
mod = true
end
if not data['General']['Inventory']['Accessories'] or tostring(typeof(data['Inventory']['Accessories'])) ~= 'table' then
data['General']['Inventory']['Accessories'] = {}
mod = true
end
if not data['General']['Inventory']['Crates'] or tostring(typeof(data['Inventory']['Crates'])) ~= 'table' then
data['General']['Inventory']['Crates'] = {}
mod = true
end
end
if not data['General']['BanInfo'] or tostring(typeof(data['BanInfo'])) ~= 'table' then
data['General']['BanInfo'] = {
['Banned'] = false;
['ExpiryDate'] = nil;
['BanReason'] = nil;
}
mod = true
elseif data['General']['BanInfo'] then
if data['General']['BanInfo']['Banned'] == nil then
data['General']['BanInfo']['Banned'] = false
mod = true
end
if not data['General']['BanInfo']['ExpiryDate'] or tostring(typeof(data['BanInfo']['ExpiryDate'])) ~= 'string' then
data['General']['BanInfo']['ExpiryDate'] = 'nil'
mod = true
end
if not data['General']['BanInfo']['BanReason'] or tostring(typeof(data['BanInfo']['BanReason'])) ~= 'string' then
data['General']['BanInfo']['BanReason'] = 'nil'
mod = true
end
end
if not data['General']['Settings'] or tostring(typeof(data['General']['Settings'])) ~= 'table' then
data['General']['Settings'] = {}
data['General']['Settings']['UIPrimaryColour'] = {['R'] = 86; ['G'] = 146; ['B'] = 127}
data['General']['Settings']['UISecondaryColour'] = {['R'] = 255; ['G'] = 255; ['B'] = 255}
data['General']['Settings']['UIFont'] = 'SourceSans'
data['General']['Settings']['GlobalShadows'] = true
data['General']['Settings']['PlayerMode'] = 'Visible'
data['General']['Settings']['ResetKeybind'] = 'R'
mod = true
elseif data['General']['Settings'] then
if not data['General']['Settings']['UIPrimaryColour'] then
data['General']['Settings']['UIPrimaryColour'] = {['R'] = 86; ['G'] = 146; ['B'] = 127}
mod = true
end
if not data['General']['Settings']['UISecondaryColour'] then
data['General']['Settings']['UISecondaryColour'] = {['R'] = 255; ['G'] = 255; ['B'] = 255}
mod = true
end
if not data['General']['Settings']['UIFont'] then
data['Settings']['UIFont'] = 'SourceSans'
mod = true
end
if data['General']['Settings']['GlobalShadows'] == nil then
data['General']['Settings']['GlobalShadows'] = true
mod = true
end
if not data['General']['Settings']['PlayerMode'] then
data['General']['Settings']['PlayerMode'] = 'Visible'
mod = true
end
if not data['General']['Settings']['ResetKeybind'] then
data['General']['Settings']['ResetKeybind'] = 'R'
mod = true
end
end
if not data['LoginInfo'] then
data['LoginInfo'] = {
['TimeStamp'] = os.time();
['Streak'] = 0;
};
mod = true
elseif data['LoginInfo'] then
if not data['TimeStamp'] then
data['TimeStamp'] = os.time();
mod = true
end
if not data['Streak'] then
data['Streak'] = 0
mod = true
end
end
local key = 'DATA_'..plr.UserId
if mod == true then
local s,e = pcall(function()
DataStore:SetAsync(key, HttpService:JSONEncode(data))
end)
end
return data
end
game.Players.PlayerAdded:Connect(function(plr)
local key = 'DATA_'..plr.UserId
local dataSaves = Instance.new('BoolValue', plr)
dataSaves.Name = 'DataSaves'
local data
local s,e = pcall(function()
data = DataStore:GetAsync(key)
end)
if s then
if not data then
data = defaultData
data = HttpService:JSONEncode(data)
local s,e = pcall(function()
DataStore:SetAsync(key, data)
end)
if not s then
return plr:Kick('Unable to set blank data: '..tostring(e)..'.')
end
data = HttpService:JSONDecode(data)
dataSaves.Value = true
local data = verifyData(data, plr)
else
data = HttpService:JSONDecode(data)
print(data)
dataSaves.Value = true
local data = verifyData(data, plr)
end
verifyPermission(data, plr)
else
plr:Kick('Unable to load data: '..tostring(e)..'.')
end
end)
local function unloadData(tbl)
local returnedData = {}
for i,v in pairs(tbl:GetChildren()) do
if v:IsA('ValueBase') then
returnedData[v.Name] = v.Value
elseif v:IsA('Folder') then
returnedData[v.Name] = unloadData(v)
end
end
return returnedData
end
local function saveData(plr)
local key = 'DATA_'..plr.UserId
local compiledData = {}
if plr:FindFirstChild('DataSaves') then
if plr:FindFirstChild('DataSaves').Value == true then
compiledData['General'] = {}
for i,v in pairs(plr:FindFirstChild('PlayerData'):FindFirstChild('General'):GetChildren()) do
if v:IsA('ValueBase') then
compiledData['General'][v.Name] = v.Value
elseif v:IsA('Folder') then
print(i,v)
compiledData['General'][v.Name] = unloadData(v)
end
end
compiledData['LoginInfo'] = {}
local loginInfo = plr:FindFirstChild('PlayerData'):FindFirstChild('LoginInfo')
if os.time() - loginInfo:FindFirstChild('TimeStamp').Value > 86400 then
compiledData['LoginInfo']['TimeStamp'] = os.time()
else
compiledData['LoginInfo']['TimeStamp'] = loginInfo:FindFirstChild('TimeStamp').Value
end
compiledData['LoginInfo']['Streak'] = loginInfo:FindFirstChild('Streak').Value
print(compiledData)
end
end
local data = HttpService:JSONEncode(compiledData)
local s,e = pcall(function()
DataStore:SetAsync(key, data)
end)
if not s then
warn('Unable to set data for '..tostring(plr)..'. '..tostring(e))
end
end
game.Players.PlayerRemoving:Connect(function(plr)
saveData(plr)
end)
game:BindToClose(function()
for i,plr in pairs(game:GetService('Players'):GetPlayers()) do
saveData(plr)
end
end)