I’m using rbx-datastore2 with combined data stores, and I have a BeforeSave callback for the level and xp stores. My question is, will this work as expected with setting new values for other stores in the BeforeSave callback? Here’s how I have it setup.
Code
DataStore2.Combine('PlayerData', 'rank', 'level', 'xp', 'coins')
Players.PlayerAdded.Connect((player) => {
let rank = DataStore2<number>('rank', player)
let level = DataStore2<number>('level', player)
let xp = DataStore2<number>('xp', player)
let coins = DataStore2<number>('coins', player)
level.BeforeSave((currentLevel) => {
if (currentLevel > 1000) {
return 100
} else {
return currentLevel
}
})
xp.BeforeSave((currentXp) => {
let currentLevel = level.Get(1)
let maxXp = getMaxXpForLevel(currentLevel)
if (currentXp >= maxXp) {
let newXp = currentXp - maxXp
level.Increment(1, 1)
return newXp
} else {
return currentXp
}
})
})
For anyone dealing with GDPR, I believe this script I whipped up will work. Put this in your command bar then use clear(userId, name) (also in the command bar) to clear someone’s data.
If you use combined data stores, the name will be your master key. Otherwise, it’s your normal name.
local DataStoreService = game:GetService("DataStoreService")
function clear(userId, name)
local orderedDataStore = DataStoreService:GetOrderedDataStore(name .. "/" .. userId)
local dataStore = DataStoreService:GetDataStore(name .. "/" .. userId)
while true do
local pages = orderedDataStore:GetSortedAsync(false, 100)
local data = pages:GetCurrentPage()
for _, pair in pairs(data) do
print(("key: %d"):format(pair.key))
dataStore:RemoveAsync(pair.key)
orderedDataStore:RemoveAsync(pair.key)
end
if pages.IsFinished then
print(("finished (%d: %s)"):format(userId, name))
return
end
end
end
This fixes an issue with :Save() overriding itself when called more than once on the same store. As always, it’s published on the model and tell me if this breaks anything.
Is there a way to edit a player’s data through studio?
Like in the event I forget to shutdown a game for maintenance, and they happen to join while I’m editing something that requires Data stores & they run into it before it was planned for release.
You can by making a mock player to pass into DataStore2 and using the command line (i.e. a table with a UserId, and shims for whatever else DataStore2 uses like PlayerRemoving).
No, but you can have your code check if the player has no data in DataStore2 to make a check to the original data store. If there’s data in the original store, transfer it over to DataStore2.
As for what I mentioned, I believe you can do something like:
DataStore2("storeName", { UserId = userId, PlayerRemoving = Instance.new("BindableEvent").Event }), use that, then call :Save() on it. DataStore2 doesn’t check if it’s a real player.
Hey, I have been messing around with this for a bit now. I noticed when I setup a callback function for :OnUpdate() under as CombinedDataStore
It calls the callback function twice. So I did some digging and I noticed that when I call :Set() it triggers the callback function twice.
Should the _dontCallOnUpdate be true for when :Set() is called (snippet down below)? Since, self:_Update() being called twice anyways.
function CombinedDataStore:Set(value)
local tableResult = self.combinedStore:GetTable({})
tableResult[self.combinedName] = value
self.combinedStore:Set(tableResult, true)
self:_Update()
end
Right now, nothing being pass for _dontCallOnUpdate