Setting up a Datastore

So, obviously, every game will have many values that they want to save. Coins, gems, levels, exp, items owned, stats, etc…

First of all, is it normal for me to be saving this much stuff or am I doing something wrong?

			sessionData[player] = {
			-- Currencies
				["Coins"] = 0,
			-- Player stats
				["Health"] = 100, ["Energy"] = 100,
			-- Multipliers
				["Damage Multiplier"] = 1, ["Defence Multiplier"] = 1, ["Health Multiplier"] = 1, ["Energy Multiplier"] = 1, 
				["Coins Multiplier"] = 1, ["Speed Multiplier"] = 1, ["Jump Power Multiplier"] = 1,
			-- The stats
				["Strength"] = 0, ["Defence"] = 0, ["Speed"] = 0, ["Jump Power"] = 0
}

I’m just wondering because pretty much every tutorial on datastores out there only gives an example on one value. Which brings me on to my next question; how do you store a large amount of values? I’ve been storing them all in a modulescript, which has the sessionData of each player. Due to this I’ve never figured out how to use UpdateAsync() instead of SetAsync() considering I have so many values.

As right now I’m just practising with DataStores, I’ve began to look into DataStore2 as many have told me how useful it is. However, once again, an example is only given with 1 value. It also has a specific datastore, "pointsDataStore". This too, brought more confusion to me. With many values would I have a specific datastore for each one? Because previously I stored all data in one datastore.

I only continued to use this method because I’ve never encountered data loss. (Haven’t had a popular game either though, peaking at just over 100 concurrent players.

7 Likes

All of the tutorials use only one value so that they are easy to understand. Saving data in tables in generally better than saving individual values, due to things like DataStore limits and efficiency.

Don’t worry about how much data you are saving, either, because that is totally normal :wink:

UpdateAsync gives you more control over what happens when you save data, and in a situation using tables, you do this by changing the values within the table.

For example, if you wanted to just do what SetAsync does:

local new = {}

DataStore:UpdateAsync(key, function(old)
    return new
end)

Or if you wanted to modify specific values within the table:

local new = {gold = 1, timestamp = tick()}

DataStore:UpdateAsync(key, function(old)
    -- Increment a specific value within the table
    old.gold = old.gold + new.gold

    -- Set a value in the table
    old.timestamp = new.timestamp

    -- Return the modified table (this is what will be saved)
    return old
end)

UpdateAsync essentially makes it so that you can do the following faster and more reliably:

local new = {gold = 1}
local old = DataStore:GetAsync(key)
old.gold = old.gold + new.gold
DataStore:SetAsync(key, old)
8 Likes

It’s actually as simple as it seems, just set up a table and you’re good to go.
In Dedoxed, I have quite a few stored values and they all work just fine.

image

I’ve actually calculated the data limit and its absolutely massive. So you don’t need to worry about making a datastore “too big”.

It’s also worth mentioning to be careful about how you structure your datastores. Currently, you can only store a single datatype per datastore, otherwise, it will error. To circumvent this, the only way to store more than one datatype is by using strings. With strings, you can store specially formatted text to be decoded into its proper values once needed. For example, if you wanted to store a color3 value, you could do “33|234|2” where all you need to do is do some simple string manipulation in order to change it back to a color3 value. If you plan to store more than one type of value in the future, its a good idea to format it this way. It’s a little tedious at times but is ultimately a better idea than making a new datastore every time you need a different type of value.

9 Likes

I’d like to add that if, for some reason, you think you may be getting close to the datastore limit e.g. storing lots of information about different parts, then consider using a compression algorithm to compress the table before saving it, and then decompressing it when getting it again.

Here’s a good compression module by 1waffle1 which I am using in one of my WIP games: Text compression

Of course this should only be used after you’re 100% sure that you’re storing as little information as possible! :slight_smile:

4 Likes

@EmeraldSlash

Okay so I understand how I’d change int values within a table now, but what if I had a table of items owned?

i.e.

sessionData = {["Coins"] = 100, other stats...., ["Items"] = {"Wooden Sword", "Iron Sword"}

So to update the coins I would do what you did in your example, but for the Items table, would I simply just insert the item to the table?
table.insert(old["Items"], ItemToInsert

@Stratiz

I wasn’t worried about making a datastore ‘too big’, I was just a little confused considering every tutorial out there has a specific datastore for each piece of data. E.g. "PointsDataStore". Though that clears it up, thanks :slight_smile:

@mario118118

Awesome, I’ll keep that in mind for the future :stuck_out_tongue:

Thanks everyone!

1 Like

Yup, that’s how you’d add them!

It might be easier to use a dictionary for items, as then you can easily find whether a player has the item and add more versions of that item directly.

Items = {["Sword"] = 1, ["Item2"] = 5}

This way you can check if a player owns an item by simply doing

local data = items["Sword"] -- would return amount the player owns, or nil if it doesn't exist
if data ~= nil then
    items["Sword"] = data + 1 -- add a sword
    items["Sword"] = ((data - 1) > 0 and (data - 1)) or nil -- take one from the sword, or make it nil if the player now doesn't own a sword
end

[On mobile, but it should work correctly]

3 Likes

That’s a really good idea heh, thank you!

So I’ve managed to change things up to UpdateAsync() and understand it properly;

Before:

local function savePlayerData(player)
	if sessionData[player] then
		return playerData:SetAsync(player.UserId, sessionData[player])
	end
end

After:

local function savePlayerData(player)
	if sessionData[player] then
		playerData:UpdateAsync(player.UserId, function(oldData)
			for i, v in pairs(oldData) do
				if sessionData[player][i] then
					print(i.." ".."Old: "..oldData[i].." ".."New: "..sessionData[player][i])
					oldData[i] = sessionData[player][i]
				end
			end
			return oldData
		end) 
	end
end

However, I have one more, last, question. How do I create backup data or such to prevent data loss? Any method other than Datastore2.

1 Like

Essentially you just save a copy of the data to another DataStore. That’s pretty much what a backup is.

DataStore:SetAsync(key, value)
BackupDataStore:SetAsync(key, value)

It might be prudent to put previous (instead of current) saves into the backup DataStore, so that there’s a short history of the player’s data.

Where you use the backup is a slightly tougher question, one which I am not quite sure how to answer. For example, you could use it when GetAsync calls to the main DataStore fail, say, 2 times in a row. Or you could use it manually when a user messages you about data loss.

This is where I’d recommend you use DataStore2 as it does a lot of the thinking for you :wink:

2 Likes

Would I be able to use Datastore2 just for the backup without having to change my whole datastore setup to be compatible with it?

I’m not sure, you might be able to. I’d probably consider it a waste unless you’re using it for everything else though.

1 Like

Coolio, I’ll consider the choices :stuck_out_tongue:

Also, why is it so highly recommended by everyone, yet barely any of the top games use it?

1 Like

It’s probably upopular on the front page because a lot people haven’t heard of it, can’t be bothered learning it, don’t think they need it, etc. It is recommended here because it truly is a good, robust, high quality system.

But being on the front page doesn’t necessarily require good technology, instead it requires good gameplay. Kids don’t really care about the way you save data, but they do care about how fun your game is :wink:

1 Like

Idk why but that made me giggle a little heheh :smiley: .

Anyway, thanks for all the help!

1 Like