How to use DataStore2 - Data Store caching and data loss prevention

That’s pretty bad :crying_cat_face:

Are you combining datastores btw? It might be some form of throttling.

Thankfully if you’re using the OrderedBackups method you should be able to get the past saves.

I’m combining datastores on every script yes, also using OrderedBackups method

1 Like

Would I combine any keys before or after defining the datastores? For example:
Would I do

local DataStore2 = require(1936396537)
game.Players.PlayerAdded:Connect(function(player)
    local cashDataStore = DataStore2("cash", player)
    local bankDataStore = DataStore2("bank", player)
    DataStore2.Combine("master", "cash", "bank")
end

or

local DataStore2 = require(1936396537)
game.Players.PlayerAdded:Connect(function(player)
    DataStore2.Combine("master", "cash", "bank")
    local cashDataStore = DataStore2("cash", player)
    local bankDataStore = DataStore2("bank", player)
end

? Any help is appreciated!
(Sorry for the previous bad code)

local Datastore2 = require() -- USE the DateStore2 Module, requiring the Id is outdated
Datastore2.Combine("MainKey","Cash","Bank")

game:GetService("Players").PlayerAdded:Connect(function(player)
   local cashDataStore = Datastore2("Cash", player)
   local bankDataStore = Datastore2("Bank", player)
end)

@SnowyStxrm Please don’t require the module Id since that is very outdated. You can get the up-to-date version here. I would require it before the playerAdded Event, like I have shown in the code above. Hope this helps.

3 Likes

You combine it even before the player joins. You should only combine once.

1 Like

If you want a module that combines , automates, and handles DS2, you can use my module, DS2Handler

local DataStore2 = require(script.DataStore2)

DataStore2.Combine("Data", "A", "B", "C")

game.Players.PlayerAdded:Connect(function(player)
	local A = DataStore2("A", player) 
	local B = DataStore2("B", player)
	local C = DataStore2("C", player)
	
	A:SetBackup(3)
	B:SetBackup(3)
	C:SetBackup(3) -- Is this redundant?
	
	local AValue = A:Get(100)
	local BValue = B:Get(50)
	local CValue = C:Get(0)
	
	local ABackedUp = A:IsBackup()
	local BBackedUp = B:IsBackup()
	local CBackedUp = C:IsBackup() -- Is this redundant?
end

If for some reason A fails and C succeeds, there will exist a duplication glitch. Would this ever happen? And if so is there a built in way I could prevent it from happening and still be able to call :Increment() on the dataStores?

I want if A fails and becomes a backup, C becomes a backup too.

I’m pretty sure you don’t need to use :IsBackup() for all ‘datastores’. They’re combined, so they should end up in the same thing.

:IsBackup() should be used as an argument to decide on something.
It will return you true or false, if it is a backup or not.

if A:IsBackup() then
    print("Data is backup!")
end
1 Like

They’re all combined under one data store, so it’s impossible for one to be a backup and for others not to be.

1 Like

I’ve made this simple script so I can use DataStore2 easily and it’s really amazing how DataStore2 is so flexible that anyone can create amazing stuff with it easily and makes the data saving safe.

You just need to edit the keysData Table


local keysData = {
	{"money",
		"leaderstats",
		"Cash",
		"IntValue",
		100
	},
	
	{"gems",
		"leaderstats",
		"Gems",
		"IntValue",
		5
	},
	
	{"lifes", -- Key
		"stats", -- Value's Parent's Name
		"Lifes", -- Value's Name
		"DoubleConstrainedValue", -- Value's Class Name
		3, -- Value
		0, -- Min Value
		3 -- Max Value (Only used when the Value's Class Name is DoubleConstrainedValue)
	}
}

The Value’s Parents will be auto created if can’t be found under Players>Player

1 Like

I can’t thank you enough for making this! <3
It’s super helpful and prevented me from going insane after tuns of dataloss

1 Like

So, seems like a neat little module, but I definitely think there should be some methods included for destroying data. I’m kind of surprised that there aren’t any.

I’ve debounced every teleportation function, made the autosave apply to only the ones who started activity in the game, and made the intervals much longer to crack down on throttling like what you suspected, and you said that calling SaveAll() and confirming using AfterSave before teleportation was appropriate.

However, people still complain about data not saving after a teleport. I couldn’t imagine how often this can occur to a game with 600 to 1200 concurrent players and I’ve been spending nearly 3 months fixing attempt after attempt and I just couldn’t find any solution.

Just to recap, I have five combined keys, increased the autosave intervals from 200s to 400s, and have up to 16 to 23 players per server.

How does Zombie Strike really save everyone’s data before teleporting?

The relevant lines of code are here: zombie-strike/LobbyHandler.server.lua at master · Kampfkarren/zombie-strike · GitHub

The whole of the teleportation system is in a Promise. That Promise waits for Promise.all(playerPromises) before teleporting, playerPromises being a table of promises of DataStore2.SaveAll, for each player.

That’s actually because it’s super expensive to do so with the berezaa method, you have to delete a bunch of keys, and every time you leave the game, you’re creating a new key, so it’s a LOT of data to delete which doesn’t make sense for a module.

Essentially, you teleport the players only if the SaveAsync function, the one similar to this case, doesn’t error. If it does, it would prevent the teleport. So you’re saying the SaveAsync function should be used before a teleport instead of calling SaveAll.

Also, one more problem I’m facing is where I’ve absolute valued all money gains to ensure that it’s positive, then I pass it through :Increment method, and some players are complaining about their money going down instead of going up, even when I passed a positive number in. What’s going on there?

We want failed saves to not teleport you, correct. This was an intentional design choice for Zombie Strike.

SaveAsync and SaveAll have the same backend, so use whatever is more convenient.

I don’t know, but it’s probably not an issue in DataStore2–this is the first I’ve ever heard of something like this.

1 Like

Basically, Save() and SaveAll() actually calls SaveAsync(), and catches errors automatically, then retries the save until it’s confirmed to be saved? And the increment function subtracting with a positive number is surely strange.

Also, does the amount of keys affect how easily the system will throttle? And would there be a Datastore2 update that would handle teleportation? It’s been difficult to fix the issue if players losing stats from teleportation despite AfterSave confirming that it’s saved before proceeding and it’s just getting more rampant.

Is this module still recommended to be used? I used to use it back in the day and I certainly loved it. I just want to make sure it still works well and isn’t an abandoned module.

DataStore2 still works perfectly fine, though I have no real plans of updating it as I have plans to make another data store saving module with a different, less beginner friendly philosophy.

1 Like