Hey everyone!
I’m sure most of us have used DataStore2 at some point and can appreciate it’s usefulness from handling caching for us and handling saving for us while utilising berezaa’s method of saving.
If you do not understand what DataStore2 is or how it works, please take a read of this:
How to use DataStore2
Now as a game developer, I usually need to change people’s data e.g through bugs or say a moderator in your game needs to change an exploiter’s stats I’m sure this is very uncommon for most people but we know there is no officially supported way to change a player’s data if they’re offline.
The past few hours I’ve been working on a way to do this, now I’m not sure if there’s any massive errors that can arise from this but I do know one thing: Use this only in a private server as DataStore2 makes a lot of API calls already so you don’t want to prevent another user in your game from having their data saved.
Let’s get to the tutorial!
Now, you must have multiple keys in your DataStore2 for one user and you must be using DataStore2.Combine(masterkey, …) to make sure these keys combine into one massive dictionary to be saved under one datastore. We also need the ID of the user whos data we want to edit!
This is very important because otherwise using more than 1 key is using exponentially more API calls than necessary.
At the top of the script, you’ll want to require your DataStore2 module, get the DataStoreService and define your master key:
local DataStore2 = require(game.ServerScriptService.MainModule)
local DataStoreService = game:GetService("DataStoreService")
local MasterKey = "MyMasterKey"
local UserId = "60001022"
Here we just require the DataStore2 module and get the DataStoreService along with defining our master key. Make sure you path the datastore2 module properly! We will be making use of the DataStoreService itself too.
Next, I will create a function named ‘GetData’ which will return our data of the specified user.
DataStore2 uses OrderedDataStores to record backups of data and this is very useful method which helps to prevent dataloss. Now DataStore2 stores your key in a simple manner: ‘DataStoreName/UserId’. This is very clean and is very useful for us as we can directly find our wanted save but first we need to find the latest save the user currently has.
DataStore2 saves os.time() to the OrderedDataStore so you can get the key of the latest save which is even better for us!
function GetData(dataStoreName, UserId)
local orderedDataStore = DataStoreService:GetOrderedDataStore(dataStoreName .. "/" .. UserId)
local dataStore = DataStoreService:GetDataStore(dataStoreName .. "/" .. UserId)
end
The use of this function would be:
GetData(masterKey, UserId)
We pass in the masterKey, aka the DataStoreName and the UserId of the user’s whos data we want to edit.
Let’s get onto actually retrieving this data. To find the latest backup, we can use orderedDataStore:GetSortedAsync. If we sort in descending order, we can get the latest backup because os.time() only increases in value.
local pages = orderedDataStore:GetSortedAsync(false, 1)
local data = pages:GetCurrentPage()
We declare that pages is a Pages object that sorts in descending order and returns only a page size of 1, so that way we only get one key back!
Data is getting the current page for us so we can take the value from OrderedDataStore
if data[1] ~= nil then
return data[1]["key"], dataStore:GetAsync(data[1]["key"])
end
Here we check if the data actually exists and then we return the key itself so we can utilise it later. We also use GetAsync using the key to get the player’s actual data! To get this data, use:
local PlayerKey, PlayerGameData = GetData(MasterKey, UserId)
If you iterate through PlayerGameData you can see that you are currently iterating through that player’s stats which is exciting! This means we have successfully retrieved the player’s latest data!
Here’s our finished function!
function GetData(dataStoreName, UserId)
local orderedDataStore = DataStoreService:GetOrderedDataStore(dataStoreName .. "/" .. UserId)
local dataStore = DataStoreService:GetDataStore(dataStoreName .. "/" .. UserId)
local pages = orderedDataStore:GetSortedAsync(false, 1)
local data = pages:GetCurrentPage()
if data[1] ~= nil then
return data[1]["key"], dataStore:GetAsync(data[1]["key"])
end
end
But how do we edit it?
function EditData(OrderedDataKey, dataStoreName, UserId, PlayerGameData, KeyToChange, NewValue)
local dataStore = DataStoreService:GetDataStore(dataStoreName .. "/" .. UserId)
PlayerGameData[KeyToChange] = NewValue
dataStore:SetAsync(OrderedDataKey, PlayerGameData)
end
Yeah I agree, this function may look like a bit of a monster with all of its parameters. But here in this function, we simply get the datastore again.
PlayerGameData is the data we retrieved just then and then say you have a key that stores the cash such as ‘CashKey’ and you want to change the value to 25, you pass ‘CashKey’ and 25 as KeyToChange and NewValue respectively. Right after, we save it to the exact same key we passed and saved it as PlayerKey.
Here’s an example of use:
EditData(PlayerKey, MasterKey, UserId, PlayerGameData, "Cash", 25)
Now that that is done, you can test if the value actually saved to by reusing the GetData function and printing the cash key as so:
local PlayerKey, PlayerGameData = GetData(MasterKey, UserId)
print(PlayerGameData["Cash"])
This method is not officially supported and it is probably very hacky but it does the job and works for me.
ONLY DO THIS IS IF THE PLAYER IS 100% OFFLINE AS THERE COULD BE SOME VERY BAD DATA BUGS OR JUST NOT WORK AT ALL!
Thank you so much for reading, please correct me if there are any mistakes!