DataStore2: Editing Player's Data If They're Offline

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! :slight_smile:

36 Likes

Just wanted to say thanks to:

This function paved the way for this little method, it wasn’t working at first but just required a little editing!

3 Likes

Fantastic! I will totally be using this in the future!

Cheers. (:

-coburn

1 Like

This tutorial is pretty good although I prefer sticking to regular datastore since I am more use to it.

1 Like

Its amazing! Thank you @InedibleGames

Thank you, glad it helped! 30charlimit

if I do players.playerremoving,it should work right?

what do you mean? 30charlimit…

When you refer to the possibility of there being data bugs if you attempt to get information while the user is online, is this only referring to editing the data? Or reading from it? Judging from the code I’m certain it’s fine to use GetData while the user is online, but I just want to make sure

It should be fine, I think I probably meant that there is 0 point in doing it while they’re online anyway since data is only retrieved once at start up and that user’s online session data will overwrite unless offline.

Please read the actual post, I am referring to no officially supported way to change a player’s data while they’re offline WITH DataStore2 as I do not update or manage DataStore2.

Hello, I am attempting to follow this tutorial but I have encountered a roadblock.

When I get to the point of
print(PlayerGameData)
I get an error stating that PlayerGameData is nil. I am not sure why as my script looks almost identical to yours, so I added some print checks in the GetData function to see where it seems to go wrong.

Once I get to the point of
local pages = orderedDataStore:GetSortedAsync(false, 1) print(pages)
the printed message is Instance, and when I print
local data = pages:GetCurrentPage() print(data)
The message comes out as simply {}
It seems as if there is no table for data and it is empty. I attached some screenshots of my code below, is there any reason that this seems to be an issue? Thanks.


1 Like

It looks like you need to put “local PlayerKey, PlayerGameData = GetData(MasterKey, UserId)” above Edit Data function