Hello, this is DataStore+, this module allows you to have OrderedBackups without the limitation of DS2, which is having a player instance, having to combine stuff, etc. This works like normal DataStores for YOU, but on the back-end, it will be saving the data with multiple tecnics and backups.
Any questions, you can ask down-below, via DM’s too.
Basic Usage:
local dataStorePlus = require(game.ServerScriptService.DataStorePlus)
local dataStore = dataStorePlus:GetDataStore("PlayerData")
local function onPlayerAdded(plr)
local fold = Instance.new("Folder", plr)
fold.Name = "leaderstats"
local cash = Instance.new("IntValue", fold)
cash.Name = "Cash"
local minutes = Instance.new("IntValue", fold)
minutes.Name = "Minutes"
local dataId = Instance.new("IntValue", plr)
dataId.Name = "DataId"
local data, sucess = dataStore:Get(plr.UserId)
print(data)
if data and sucess then
cash.Value = data.Cash
minutes.Value = data.Minutes
dataId.Value = data.DataId
end
if not sucess then
local value = Instance.new("BoolValue", plr)
value.Name = "CannotSave"
value.Value = true
plr:Kick("DataStore services might be down! Your data is safe!")
else
spawn(function()
while true do
wait(1)
if plr then
plr.leaderstats.Minutes.Value += 1
else
break
end
end
end)
end
end
for _, plr in ipairs(game.Players:GetPlayers()) do
coroutine.wrap(onPlayerAdded)(plr)
end
game.Players.PlayerAdded:Connect(onPlayerAdded)
local function SavePlayerData(plr)
if not plr:FindFirstChild("CannotSave") then
local data = {
Cash = plr.leaderstats.Cash.Value;
Minutes = plr.leaderstats.Minutes.Value;
DataId = plr.DataId.Value + 1;
}
local s, x = dataStore:Update(plr.UserId, function(oldData, backup_oldData)
if (not oldData) and backup_oldData then
oldData = backup_oldData
end
--// Use backuped data to compare data, you can choose not to do so, or build a
--// different system
print(oldData)
if oldData then
if oldData then
if oldData.DataId and oldData.DataId == plr.DataId.Value then
print("save")
return data
-- Save
else
print("dont")
return nil
-- Don't
end
end
else
print("save, no data")
return data
end
end)
end
end
game.Players.PlayerRemoving:Connect(SavePlayerData)
game:BindToClose(function()
if not game:GetService("RunService"):IsStudio() then
for _, plr in ipairs(game.Players:GetPlayers()) do
coroutine.wrap(onPlayerAdded)(plr)
end
wait(30)
else
wait(1.75)
end
end)
This is great! While working on a small project a few months ago I looked for a way to store non-player data while also being able to use the the onUpdate function. This definitely solves that problem.
Updated the module to use UpdateAsync to get data. If you’re wondering why I did that, that’s because UpdateAsync at least from my sources claim that UpdateAsync will “queue” it’s calls. Meaning that one call can only run at a time. Meaning, I can be more accurate in the case of data loss when doing :Get(), :GetAsync() also caches results, so it becomes more annoying to do stuff.
Out of curiousity, what tests have you performed against data loss? I know that this is a fairly new module and I would like to know if it is as secure as DataStore2. This is all new to me anyway. ;p Thanks.
No, it’s sadly not as good as DS2, and the only reason for that, is that I don’t know how DS2 backups work, I even tried making a post about it, but no one answered.
I plan on adding the same system DS2 uses for saving data though if I get examples of how DS2 backups work both in Standard and OrderedBackups mode.
Mostly, this module is better than normal datastores. It keeps a backup, tries to protect itself from data being nil, and other stuff. And tries to use the best methods to save and get data with no funny business.
From my understanding, DS2 will have a main normal version, if it fails to get that, it will check on OrderedDataStores for “backups” which are just past versions of the data; Basically it keeps the data from older versions (I think)
Update: no, my module does have that, in a way it can be a downside, but can be great for session locking.
Ds2 only keeps the “backups” and their indicators on OrderedDataStores.
True xD
Well I’m going to implement it once I sort out how I’m going to structure my data. (I had like at least five different stores for different things pertaining to one player)
Should I wait for the update to implement the module or will it automatically update since it’s on the website?
Hm if you require it maybe it could come with the orderedbackups thing but since that’s inside the settings module not really, anyway, I would just recommend seeing if I’m going to implement, i’m gonna try, you can be sure of that, I’m doing that right now; :)
Because your past-data woudn’t migrate to OrderedBackups that way.
I have been for the past 2/3 hours fixing glitches and over-looks in OrderedBackups, I’ve found a bunch since OrderedBackups was made in a rush, there have been also some internal additions like better data-protection and checking on :Update(). If you’re using this module, make sure to update it to the newest version. This update should not effect any of your data;
Also, to anyone who is getting a reminder from ROBLOX to remove player data, just remember, :Remove(), if you’re using the OrderedBackups method, it’s just like a “mark as empty” and not actually deleting data.
Roblox legally needs you to delete any instance of that data, :Remove() won’t do that, that’s because that would be REALLY expensive to do. I can’t do anything. DS2 also doesn’t allow that because of this.
You can paste this on your console, and change the variables DataStore and key to your datastore and key, and it should delete every single data, and EVERYTHING from that key on OrderedBackups.
Code
local dataStore = "DataStoreName"
local key = "UserId/Key"
local normalDs = game:GetService("DataStoreService"):GetDataStore(dataStore)
local orderedDs = game:GetService("DataStoreService"):GetOrderedDataStore(dataStore..'/'..key)
local backupDs = game:GetService("DataStoreService"):GetDataStore(dataStore.."/Backups")
local ordered = orderedDs:GetSortedAsync(false, 10)
local page = ordered:GetCurrentPage()
normalDs:RemoveAsync(key)
repeat
for pos, info in ipairs(page) do
local version_ = info.value
backupDs:RemoveAsync("124695835/"..version_)
orderedDs:RemoveAsync(info.key)
end
if not ordered.IsFinished then
ordered:AdvanceToNextPageAsync()
page = ordered:GetCurrentPage()
end
until ordered.IsFinished print("finished")
I was just messing around with how DS2 saves OrderedBackups and, I noticed that, DS2 saves backups very similarly, and my method was right. I am just really making stuff written differently, but data from DS2 could actually COLLIDE with this module. Now you woudn’t actually see any data being gotten from DS2. But, the way that I’m getting the DataStoreName for the OrderedDataStores are EXACTLY the same. Look at this!
In a way, my module can be better. And that’s because I actually kind of allowed people to just get normal datastores and move them to orderedDataStores. It uses orderedBackups on :Get() only when it cannot find data on the main version. So, because I’m basically shaping data just like normal datastores, and only not doing so when I cannot get any data, that means that you can move over your already existing data to OrderedBackups without much hasle. DS2 does not save this primary version like I do. It ONLY uses the OrderedBackups, the way of getting data is also different. I keep my backups in another datastore which is backup specific. DataStore2 only gets data from a orderedDataStore and a MainDataStore. I have a MainDataStore, an versioning DataStore (orderedDS) and another one for backups. The good thing about DS2 is that, if there’s no backups, then it won’t get any version, and will be kind of just not many requests. The downside for my version is that if it cannot find data in the normal datastore, then it would have to get from OrderedBackups, which requires me to check the versions on OrderedBackups, and try all versions from newest-to-oldest until I get data. This is what happends in DS2, but it doesn’t have the MainDataStore. It only keeps the versions and stuff. Now, the good thing, is that, first of all, if I do find data, that means that it’s not gonna go through orderedDataStores and, will be faster. When THERE IS data. When there’s not, then there’s a lot of requests to make sure I find data, but at the same time, this is only really true for when DataStores are down, on a case where the player doesn’t actually have data, it doesn’t need to anything. It won’t check for backups or anything. It will just be nil and fine.
I made a video tutorial on the basis of DataStore+, mainly I would recommend that you understand how UpdateAsync works. Because that’s the best method to save data.
Just a warning, the video ends very randomly, and that’s because my phone turned off, and I use my phone as a microphone, meaning that, I had to stop the video, THANKFULLY that was literally the end and I was literally gonna stop talking about the module at that time. So it doesn’t have a huge effect here.
(btw for some reason yt is kind of faulty right now and uploads are taking a long while to process. If it’s not processed while reading this, wait a bit.)
Is there a github to look at the source code of the module, I don’t want to look it in studio anyways also if this just uses non instances what is the use case for this
I tried my best at the newest versions to add the flexibility to add session locking, this isn’t really about it, but now when doing UpdateAsync you can ignore backups, on which you will only update the main version. That should be better. This module is more about you being able to add your own system using OrderedBackups without ugly lines of code. And also easily convert already existing games to OrderedBackups, if you know how to set up session locking, it shouldn’t be that hard to do so in this module :P
If you have BTRoblox you can look at the source code via the explorer icon, and double click the main module, the code should show. Otherwise no, I don’t give a GitHub because I don’t know how to mess with GitHub, I actually was trying to mess around with it yesterday lol