I’m using Berezza’s method a storing data for my datastore module.
His method makes you name the datastore key on the timestamp where it was saved on. You create an ordereddatastore on the timestamp of the save. So when a player joins it gets the latest datastore if that datastore is corrupted to moves onto the last save and so on and so on until there are no more saves.
When using my module I have a common issue with :BindToClose() yielding forever. I’ve looked further into this and the yielding problem is the :Set() function. Using test prints I figured out that wthin the :Set() function the cause is OrderDataStore:SetAsync().
Module:
--[[
DataStore(Player, DataStoreName) - Gives you a datastore
DataStore:Set(data) - Gets data store.
DataStore:Save() - Saves data store
DataStore:Get(defaultValue, MaxRetries(3)) - Gets datastore and sets up a datastore. Use it when calling a datastore after.
DataStore:SetBackupAsData(backupValue(number)) - Sets a backup as the current data
--]]
local DSS = game:GetService("DataStoreService")
local DataStoreMeta = {}
function DataStoreMeta:Set(data)
local timeKey = os.time()
-- Update cache data
print("Got time stamp")
self.Data = data
print("Updated data")
-- Update ordered data store data
self.OrderedDataStore:SetAsync(timeKey, timeKey)
print("Added ordered data store")
-- Get datastore
local DataStore = self.DataStore
-- Set data store
DataStore:SetAsync(timeKey, data)
print("Added datastore value")
return data
end
function DataStoreMeta:Get(defaultValue, maxRetries)
if maxRetries==nil then -- Default retries
maxRetries = 3
end
local pages = self.OrderedDataStore:GetSortedAsync(false, 10)
local RecentSaves = pages:GetCurrentPage()
local Key
local Failed = false
local ReTries = 0
repeat
if RecentSaves~=nil then
for i,data in ipairs(RecentSaves) do
if data~=nil then
Key = data.value
break
end
end
if Key==nil then
ReTries = ReTries+1
local succ,err = pcall(function()
RecentSaves = pages:AdvanceToNextPageAsync()
end)
if not succ then -- Is there another page to advance to?
Failed = true -- End of page
end
wait()
end
end
until Key~=nil or Failed or ReTries>=maxRetries
if Key~=nil then -- If key isn't nil
local DataStore = self.DataStore
local data = DataStore:GetAsync(Key)
if data~=nil then -- If the data isn't nil
self.Data = data
return data
else -- Data is nil. Put default values in
data = self:Set(defaultValue)
self.Data = data
return data
end
else -- No page found. Put default values in
local data = self:Set(defaultValue)
self.Data = data
return data -- Update default values
end
end
function DataStoreMeta:SetBackupAsData(backupnumber)
local timeKey = os.time()
local pages = self.OrderedDataStore:GetSortedAsync(false, math.huge)
local chosenDataStore = pages[backupnumber]
local data = self.DataStore:GetAsync(chosenDataStore.key)
if data~=nil and chosenDataStore~=nil and chosenDataStore.value~=nil then -- Backup isn't nil
self.DataStore:SetAsync(timeKey, data) -- Update current data to backup
self.OrderedDataStore:SetAsync(timeKey, timeKey)
return data
else
return false
end
end
local module = {}
local DataStoreMetaTable = {}
DataStoreMetaTable.__index = DataStoreMeta
local DataStoreCaches = {}
local function DataStore(player, dataStorename)
local dataStore = {}
if DataStoreCaches[player] and DataStoreCaches[player][dataStorename]~=nil then -- Is there a cache for it?
dataStore = DataStoreCaches[player][dataStorename]
else
dataStore.Data = nil -- I'm gonna add a default value later
dataStore.DataStore = DSS:GetDataStore(dataStorename, player.UserId)
dataStore.Player = {}
dataStore.Player.Name = player.Name
dataStore.Player.UserId = player.UserId
dataStore.Player.Object = player
dataStore.ServerData={}
dataStore.ServerData.DataStoreName = dataStorename
dataStore.OrderedDataStore = DSS:GetOrderedDataStore(dataStorename .. "_OrderedDataStore", player.UserId)
if DataStoreCaches[player]==nil then -- Player cache table?
DataStoreCaches[player]={}
end
DataStoreCaches[player][dataStorename] = dataStore -- Add cache
end
setmetatable(dataStore, DataStoreMetaTable) -- Turn datastore into a metatable
local RemovingFired = false
game:BindToClose(function() -- Game is shutting down
repeat wait() until RemovingFired -- Allow game to close once data is save
end)
game:GetService("Players").PlayerRemoving:Connect(function(discconectUser)
if player==discconectUser then
print("User disconnected")
dataStore:Set(dataStore.Data) -- Save the data
print("Saved successfully")
RemovingFired = true -- Once data is saved allow the game to close
end
end)
return dataStore
end
return DataStore
The main problem is within the module the module but I provided the script just in case.
Datastore Handler:
local DataModule = require(game:GetService("ServerScriptService"):WaitForChild("CoreModules"):WaitForChild("DataStoreModule")) -- DataStore module
function playerAdded(plr)
local dataStore = DataModule(plr, "Credits") -- Get user datastore
print(tostring(dataStore.Data), "is before")
dataStore:Get(0) -- Set up data store.
print(tostring(dataStore.Data), "is after")
local newModel = Instance.new("Model")
newModel.Name = "leaderstats"
newModel.Parent = plr
local newValue = Instance.new("NumberValue")
newValue.Name = "Credits"
newValue.Value = dataStore.Data
wait(1)
dataStore:Set(dataStore.Data)
end
game:GetService("Players").PlayerAdded:Connect(playerAdded) -- Player been added?
if game:GetService("RunService"):IsStudio() then
for _,plr in pairs(game:GetService("Players"):GetPlayers()) do
playerAdded(plr)
end
end