DataStore+ | OrderedBackups with flexibility and ease of use

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.

Download | :sparkles: Documentation :sparkles: | GitHub

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)
35 Likes

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.

3 Likes

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.

This is great! The current system that I have set up in my place is extremely primitive, so I look forward to implementing this. :~)

1 Like

If you end up using it I would love some feedback :D

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.

2 Likes

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.

How do DS2 backups save? (For upcoming module) - #3 by LucasTutoriaisSaimo

If you know stuff from ds2 I would like some help here :)

(And I can’t really test data-loss cuz it’s so random and yeah :/)

OrderedBackups were implemented shortly after this message, making the message above less important.

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.

1 Like

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 now :Remove() works on OrderedBackups.

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

pls add Session Locking as a feature

1 Like

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

I could upload the source to GitHub for you to link in the post.

1 Like

I thought the original point of this module was the use of messaging service so your making less requests? What happened to this?

1 Like

If you want to, sure. I tried making this: LucasMZReal/DataStorePlus: DataStore+ aims at allowing developers use the berezaa method, commonly known as OrderedBackups, without much tinkering required. Just Get, Set, Update. (github.com)

not even sure if its public or whatever but anyways

imma try something

I’ve tried making a GitHub page, sorry if it looks bad, I’m bad at this.