How to use DataStore2 - Data Store caching and data loss prevention

OnUpdate takes a function. You are not passing a function.

money:OnUpdate(function()
    print(money:Get())
end)
2 Likes

It is erroring…

local DefaultValue = {
	Gears = {0};
	Cosmetics = {0};
}

local DatastoreName = "Datastore"

local PlayerData = {}

local DataStore2 = require(script.Parent:WaitForChild("DataStore2"))

game.Players.PlayerAdded:Connect(function(Player)
	local Storage = DataStore2(DatastoreName, Player)
	PlayerData[Player.UserId] = Storage:Get() or DefaultValue -- this loads the data
	
	while true do
		wait(200)
		Storage:Set(PlayerData[Player.UserId])
	end
end)


game.Players.PlayerRemoving:Connect(function(Player)
	local Storage = DataStore2(DatastoreName, Player)
	Storage:Set(PlayerData[Player.UserId]) -- this saves the data
end)

game:BindToClose(function()
	for _, Player in pairs(game.Players:GetPlayers()) do
		local Storage = DataStore2(DatastoreName, Player)
		Storage:Set(PlayerData[Player.UserId]) -- this saves the data
	end
end)

“error when player left! Invalid at input.Cosmetics because: Mixed Array/Dictionary”

Not sure what I have done wrong and how I can fix it. Help is definitely appreciated!!

1 Like

I recommend reading your error.

This is completely pointless. You should be calling :Set every time the data changes instead of just every 200 seconds. You are treating DataStore2 the same way you would normal data stores, which you should not.

game:BindToClose(function()
	for _, Player in pairs(game.Players:GetPlayers()) do
		local Storage = DataStore2(DatastoreName, Player)
		Storage:Set(PlayerData[Player.UserId]) -- this saves the data
	end
end)

Same with this. This makes absolutely no sense, :Set doesn’t save the data.

I recommend reading the documentation for DataStore2.

1 Like

How to use datastore2.combine?

2 Likes

You need to read the “Documentation” section where it has explanations for its API

datastore2.Combine("MainKey","coins","levels","XP", etc.. )

Have a good day

3 Likes

Hi! My problem is that data is just not saving eventhough OnUpdate fires and when I print the data inside it prints as expectedly. Also every other key I change with that purchase like money, gets updated but not saved upon rejoining. Please help! (not testing in studio)

local datastore2 = require(script.Parent:WaitForChild("DataStore2"))
datastore2.Combine("DATA", "money", "weapon")

local weapons = {
	["CandyCane"] = {10000000000, false},  -- PRICE, OWNED
	["DoubleRevolver"] = {1230, false},
	["DoubleRifle"] = {5280, false},
	["GoldenRevolver"] = {590, false},
	["Minigun"] = {1000000000000, false},
	["SingleRifle"] = {1850, false},	
	["GoldenRifle"] = {2660, false}
}

coroutine.wrap(function() -- new thread so I can run this and OnUpdate()
	someInvoke.OnServerInvoke = function(plr, gun)  -- invoke when buying guns, gun - gun.Name
		local weaponStore = datastore2("weapon", plr)
		datastore2("money", plr):Increment(-price, 0)
		weaponStore[gun][2] = true 
		datastore2("weapon", plr):Set(weaponStore)  -- seting owned to true
		game:GetService("ServerStorage").Weapons[gun]:Clone().Parent = plr.Character
		print("done") -- it prints done
		return 1
	end	
end)() 	

game:GetService("Players").PlayerAdded:Connect(function(plr)
	local weaponStore = datastore2("weapon", plr)
	print(table.unpack(weaponStore:GetTable(weapons)["GoldenRevolver"])) -- always prints 590, false
	weaponStore:OnUpdate(function()
		print(weaponStore:GetTable(weapons)["GoldenRevolver"][2]) -- after I do Set() it prints true
	end)
end)
1 Like

I’m still confused with this script line. What’s the target of the require? Is it the MainModule or something?

local DataStore2 = require(ServerScriptService.DataStore2)
2 Likes

yeah its the mainmodule of the datastore2

3 Likes

Is it possible to save player’s backpack using DataStore2. If yes, how?

2 Likes

Its actually simple.

You need to have a few thimgs set-up first,

A folder which will store all the tools/instances.

A table in your script as example follows:

Local tools = {
  ["Sword"] = REFERENCE_TO_YOUR_TOOL_FROM_THE_FOLDER

--Etc
}

Then using datastore2 make a store which saves the backpack as a table, ex {sword,axe}

If you want to add a tool or any instance to the player’s backpack. You don’t actually parent it to the players backpack but add the name to the table and listen for OnUpdate and find the added instance from the added name from the tools table, in this case, and parent it to the players backpack.

When the player joins loop through the table and find the name from folder and parent it to the players backpack.

2 Likes

I was reading a bit more into :SetBackup() and I’m not sure which approach is valid to check whether a datastore is using a backup version.

This function below is the first thing that is run when a player joins the game.
Do I have to call :Get() before checking whether the datastore is a backup?

PlayerDataDatastores.CheckForIsBackup = function(player)
	local PlayerDataDataStore = DataStore2("PlayerData", player)
	PlayerDataDataStore:SetBackup(5)

    --is it necessary to use :Get() / :GetTable() before using the IsBackup()?

	if PlayerDataDataStore:IsBackup() then
		player:Kick("There was an error with loading your data. Please rejoin the game!")
		return "isBackup"
	end
	return PlayerDataDataStore
end

The documentation shows the following:

local coinsStore = DataStore2("coins", player)
coinsStore:SetBackup(5)
print(coinsStore:IsBackup()) -- will print "true" if DataStore2 couldn't successfully get the data
1 Like

Yes, because otherwise there’s no time for it to actually try to retrieve the data.

2 Likes

So if :Get(defaultValue) would fail with :SetBackup(5) and no defaultvalue is set in :SetBackup(), will the next :Get(defaultValue) fill the backup datastore value with the defaultvalue because it’s nil?

EDIT: Documentation says it will act as if the datastore would not have data.

Just a quick question, but how many characters does this method use on one key compared to saving it regularly. I plan on making something that will… let’s say… come close to the 4 million character limit. If everything for one player gets saved on one key, is it character efficient?

Also what if I wanted to use my datastore editor on this? What would the key be and what would the datastore name be?

I’ve been looking for an answer for months, and no one seems to understand how to do this, so I figured I would go to the source.
All I’m trying to do is save a player’s inventory as a table of StringValues, but it keeps erroring saying “attempt to call a nil value” even though the table being called returns a list of values when printed.

Here is my script:

game.Players.PlayerAdded:Connect(function(plr)
local dataTools = DataStore2("ToolDS",plr)
local dataTools ={
		"Kingdom Key",
		"Potion,"
	}
--Other parts of the script work just fine, so I cut to the end where it errors.
game.Players.PlayerRemoving:Connect(function()
		print("Saving tools")
	local SG = plr:WaitForChild("StarterGear")
	for _,v in pairs(SG:GetChildren()) do
			table.insert(dataTools, v.Name)
			print(dataTools) --<<This returns a table of the player's StarterGear
		end
	DataStore2.SaveAll(plr) --<<This is where it says "attempt to call a nil value."
end)
end)

I don’t understand what it’s referring to as the “nil value.” And I don’t know if serialization would be more effective since the game has over 80 items the player can own.

I don’t use Datastore2 anymore but does .SaveAll exist?

I can’t seem to find it on the documentation either. I can only find :Save.

https://kampfkarren.github.io/Roblox/api/#datastore2saveall
It’s still in the documentation, but even when using dataTools:Save() or dataTools:Set() or dataTools:Update() it still returns the same result. Attempt to call nil value.

Make sure you are doing DataStore2:Save() and not dataTools:Save()

DataStore2:Save(dataTools)

Still says “attempt to call a nil value.”

1 Like

The error you’re getting can only have one reason

  • The function you calling doesn’t exist