If there’s anything I could improve upon or something that could cause my script to break, please let me know.
It’s pretty long so I don’t expect anybody to read the whole thing lol
local dataStore = {}
-- [[ Services ]] --
local DSS = game:GetService("DataStoreService")
local SSS = game:GetService("ServerScriptService")
local RS = game:GetService("RunService")
-- [[ Settings ]] --
local Settings = {
AutoSaveInterval = 30,
NotificationsColor = Color3.new(0, 1, 0),
SaveInStudio = false,
}
function dataStore.new(player, name)
local MAXINTERVAL = 60
local MININTERVAL = 10
local BASEINTERVAL = 30
if Settings.AutoSaveInterval < MININTERVAL or Settings.AutoSaveInterval > MAXINTERVAL then
Settings.AutoSaveInterval = BASEINTERVAL
end
local indexFormat = string.format("%d:%s", player.UserId, name)
if dataStore[indexFormat] then
return dataStore[indexFormat]
end
local self = {}
self.name = name;
self.player = player;
self.userId = player.UserId;
self.notifications = false;
self.__store = DSS:GetDataStore(name);
self.__lastEntry = -math.huge;
self.__queue = {};
self.__updateCallbacks = {};
self.__sent = 0;
local meta = {}
meta.__index = dataStore;
dataStore[indexFormat] = setmetatable(self, meta)
coroutine.wrap(dataStore.wrap)(dataStore[indexFormat])
return dataStore[indexFormat]
end
function dataStore.wrap(self)
local PlayerId = string.format("Player_%d", self.userId)
local function save()
if #self.__queue == 0 then
return
end
local lastIndex = self.__queue[#self.__queue]
if typeof(lastIndex) ~= "table" then
for i = 1, #self.__queue do
if self.__queue[i] then
lastIndex = self.__queue[i]
end
end
end
lastIndex[2] = tick()
self.__store:SetAsync(PlayerId, lastIndex)
if self.notifications then
self.__sent = self.__sent + 1
if self.__sent%5 == 0 or self.__sent == 1 then
local ChatService = require(SSS.ChatServiceRunner.ChatService)
local Speaker = ChatService:GetSpeaker(self.player.Name)
local extraData = {ChatColor = Settings.NotificationsColor}
local notification = string.format("Hey %s, your data has been saved!", self.player.Name)
Speaker:SendSystemMessage(notification, "All", extraData)
end
end
end
game:BindToClose(function()
if RS:IsStudio() and not Settings.SaveInStudio then
return
end
if tick() - self.__lastEntry < Settings.AutoSaveInterval then
repeat
RS.Heartbeat:Wait()
until tick() - self.__lastEntry >= Settings.AutoSaveInterval
end
save()
end)
while wait(Settings.AutoSaveInterval) do
self.__lastEntry = tick()
save()
for i, v in ipairs(self.__queue) do
table.remove(self.__queue, i)
end
if #self.__queue ~= 0 then
local _, index = next(self.__queue)
while index ~= nil do
self.__queue[index] = nil
_, index = next(self.__queue)
end
end
end
end
function dataStore.leaderstats(player, stats)
local leaderstats = player:FindFirstChild("leaderstats") or Instance.new("Folder", player)
leaderstats.Name = "leaderstats"
local ls = {}
for _, stat in pairs(stats) do
local newStat = Instance.new(stat.StatType .. "Value", leaderstats)
newStat.Name = stat.Name
local newStore = dataStore.new(player, stat.Alias or stat.Name)
newStat.Value = newStore:Get(stat.DefaultValue)
newStore:OnUpdate(function(value)
newStat.Value = value
end)
table.insert(ls, newStore)
end
--[[
{
Name = "",
Alias = "",
DefaultValue = 0,
StatType = "Int",
}
]]
return unpack(ls)
end
function dataStore:Get(defaultValue)
local defaultValue = defaultValue or 0
local PlayerId = string.format("Player_%d", self.userId)
if #self.__queue > 0 then
return self.__queue[#self.__queue][1]
else
local retrieved, result = pcall(function()
return self.__store:GetAsync(PlayerId)
end)
if retrieved then
if typeof(result) == "table" then
if result[2] ~= nil and tick() - result[2] >= Settings.AutoSaveInterval then
return result[1] or defaultValue
else
repeat
RS.Heartbeat:Wait()
if #self.__queue > 0 then
return self.__queue[#self.__queue]
end
until tick() - result[2] >= Settings.AutoSaveInterval
return result[1] or defaultValue
end
else
return defaultValue
end
else
local errorMsg = string.format("Error occurred: %q", result)
warn(errorMsg)
end
end
end
function dataStore:Set(value)
table.insert(self.__queue, {value, 0})
for _, callback in pairs(self.__updateCallbacks) do
callback(value)
end
end
function dataStore:SetNotificationsEnabled(boolean)
self.notifications = boolean
end
function dataStore:Increment(amnt, defaultValue)
local defaultValue = defaultValue or 0
self:Set(self:Get(defaultValue) + amnt)
end
function dataStore:OnUpdate(callback)
table.insert(self.__updateCallbacks, callback)
end
return dataStore