This is also causing sometimes players to get stuck in place for a long time without a Rejoin button.
Saving twice in a row won’t throttle because the 2nd save won’t have any new data–it won’t actually perform a real save.
Still having reports of data loss. The money is in an Int that never gives problems, but the tycoon objects are in a table that fails a lot. There is a save() on buying a tycoon object, and a AfterSave that removes the “wait” gui. The gui is removed so the table should be saved.
The save() was added because of data loss.
That’s pretty bad
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
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.
You combine it even before the player joins. You should only combine once.
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
They’re all combined under one data store, so it’s impossible for one to be a backup and for others not to be.
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
I can’t thank you enough for making this! <3
It’s super helpful and prevented me from going insane after tuns of dataloss
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.