DataStore2 - How do you save tools using DataStore2?

Hello there.

This is my first post, so please tell me if I posted it in the wrong spot or if I did anything wrong. Thanks!

I am trying to save tools with DataStore2. I’ve tried doing it myself, and I’ve also searched it up on YouTube to no avail.

Leaderstats Script:

    local ReplicatedStorage = game:GetService("ReplicatedStorage")

    local Votes = ReplicatedStorage:WaitForChild("VotesEnableDisable")

    local DataStore2 = require(script.Parent.DataStore2)

    DataStore2.Combine("DATA", "Wins", "Tools")

    game:GetService("Players").PlayerAdded:Connect(function(Player)
    	local WinsStore = DataStore2("Wins", Player)
    	local ToolStore = DataStore2("Tools", Player)
    	
    	local Tools = {}
    	
    	game:GetService("ReplicatedStorage").PlayerAdded:FireAllClients()
    	
    	Player.CharacterAdded:Connect(function(Character)
    		Character.Humanoid.Died:Connect(function()
    			ReplicatedStorage.PlayerDied:FireAllClients(Player.Name)
    		end)
    	end)	
    	
    	local Leaderstats = Instance.new("Folder")
    	Leaderstats.Name = "leaderstats"
    	
    	local Wins = Instance.new("IntValue")
    	Wins.Name = "Wins"
    	Wins.Value = WinsStore:Get(0)
    	Wins.Parent = Leaderstats
    	
    	local InRound = Instance.new("BoolValue")
    	InRound.Name = "InRound"
    	InRound.Parent = Player
    	
    	local Afk = Instance.new("BoolValue")
    	Afk.Name = "Afk"
    	Afk.Parent = Player
    	
    	WinsStore:OnUpdate(function(NewWins)
    		Wins.Value = NewWins
    	end)
    	
    	ToolStore:OnUpdate(function(NewTool)
    		table.insert(Tools, 1, NewTool.Name)
    	end)
    	
    	Leaderstats.Parent = Player
    	
    	for _, ToolName in pairs(Tools) do
    		ReplicatedStorage[ToolName]:Clone().Parent = Player.Backpack
    	end
    end)

Shop Script:

local BuyEvent = game:GetService("ReplicatedStorage"):WaitForChild("BuyItem")

local DataStore2 = require(script.Parent.DataStore2)

BuyEvent.OnServerEvent:Connect(function(Player, ToolName)
	local ToolStore = DataStore2("Tools", Player)
	
	local Tool = game:GetService("ServerStorage"):FindFirstChild(ToolName)
	
	if Tool then
		if Player.leaderstats.Wins.Value >= script[ToolName].Value and not Player.StarterGear:FindFirstChild(ToolName) then
			Tool:Clone().Parent = Player.StarterGear
			Tool:Clone().Parent = Player.Backpack
			
			ToolStore:Set(Tool, true)
		end
	else
		Player:Kick("No exploiting please.")
	end
end)

Thank you for your time.

You cannot save instances or userdata, they must be in a data type supported for saving. If your tools aren’t uniquely created tools by players (meaning that the tools were made by you or a developer in comparison to objects a player has made in game if they are able to do so) then you can just get the name of the tool then save it. When the player joins back, you check for their data and the names of the tools will be there then you find the tools again.

In cases where you have to save specially unique objects that aren’t made by you or a fellow developer, you have to get data on the instance in form that you can read. This is called serialization.

3 Likes

I don’t think you read the code carefully enough. I used “.Name”.

I see you are attempting to save with a Tool instance? Here is what Tool is:
local Tool = game:GetService("ServerStorage"):FindFirstChild(ToolName)

Do you then perhaps mean: ToolStore:Set(ToolName, true)?

1 Like

So I use

ToolStore:Set(Tool.Name, true)

and remove the “.Name” in

table.insert(Tools, 1, NewTool.Name)

?

1 Like

I am not familiar with Datastore2 so I am treating it similarly to Datastore normally but if that is just like a :SetAsync method in real datastore then technically yes but you have a ToolName parameter you can use instead of Tool.Name.

1 Like

Okay, I will try that. Thanks.

1 Like

Nope. The script did not work.

Unfortunately, I don’t know how your code works otherwise as I focused on the second script but in general, you can’t save an Instance directly to datastore so while it may not have solved your problem, keep in mind to not save any userdata values like an Instance.

Well yes, as with all datastores you cannot datastore any instances, this includes tools. In short, strings, numbers and arrays(tables) are your primary data storing data types… Now to get a background of what’s going on here. First off, put DataStore2 up at the TOP OF YOUR SCRIPT bit of advice there, as it’s easier to get a read on it. print out every response from the OnServerEvent for me. So

BuyEvent.OnServerEvent:Connect(function(Player, ToolName)
	local ToolStore = DataStore2("Tools", Player)
	
	local Tool = game:GetService("ServerStorage"):FindFirstChild(ToolName)
	
	if Tool then
        print("Tool found!")
		if Player.leaderstats.Wins.Value >= script[ToolName].Value and not Player.StarterGear:FindFirstChild(ToolName) then
			Tool:Clone().Parent = Player.StarterGear
			Tool:Clone().Parent = Player.Backpack
			print("Setting "..tool.Name.." to the player's tool store")
			ToolStore:Set(Tool.Name, true)
		end
	else
		Player:Kick("No exploiting please.")
	end
end)

ALSO

DataStore2’s documentation specifically says to use DataStore2.Combine() with every datastore. So pleaseuse that right after you require the DataStore2 Module.

DataStore2.Combine(“ToolStore”, “DATA”) along with all the other stores you are going to be using. Note that it also states that using over 2 can throttle the store so I would suggest using either one datastore and constructing the store in a table format.

Thanks! What should I change to the Leaderstats script?

local ReplicatedStorage = game:GetService("ReplicatedStorage")

local Votes = ReplicatedStorage:WaitForChild("VotesEnableDisable")

local DataStore2 = require(script.Parent.DataStore2)

DataStore2.Combine("DATA", "Wins", "Tools")

game:GetService("Players").PlayerAdded:Connect(function(Player)
	local WinsStore = DataStore2("Wins", Player)
	local ToolStore = DataStore2("Tools", Player)
	
	local Tools = {}
	
	game:GetService("ReplicatedStorage").PlayerAdded:FireAllClients()
	
	Player.CharacterAdded:Connect(function(Character)
		Character.Humanoid.Died:Connect(function()
			ReplicatedStorage.PlayerDied:FireAllClients(Player.Name)
		end)
	end)	
	
	local Leaderstats = Instance.new("Folder")
	Leaderstats.Name = "leaderstats"
	
	local Wins = Instance.new("IntValue")
	Wins.Name = "Wins"
	Wins.Value = WinsStore:Get(0)
	Wins.Parent = Leaderstats
	
	local InRound = Instance.new("BoolValue")
	InRound.Name = "InRound"
	InRound.Parent = Player
	
	local Afk = Instance.new("BoolValue")
	Afk.Name = "Afk"
	Afk.Parent = Player
	
	WinsStore:OnUpdate(function(NewWins)
		Wins.Value = NewWins
	end)
	
	ToolStore:OnUpdate(function(NewTool)
		table.insert(Tools, 1, NewTool.Name)
	end)
	
	Leaderstats.Parent = Player
	
	for _, ToolName in pairs(Tools) do
		ReplicatedStorage[ToolName]:Clone().Parent = Player.Backpack
	end
end)

? What do you mean by that? I’m a bit confused.

What should I change to the script that saves and handles the OnUpdate function and creates the leaderboard?

Basically, what should I change to this?

local ReplicatedStorage = game:GetService("ReplicatedStorage")

local Votes = ReplicatedStorage:WaitForChild("VotesEnableDisable")

local DataStore2 = require(script.Parent.DataStore2)

DataStore2.Combine("DATA", "Wins", "Tools")

game:GetService("Players").PlayerAdded:Connect(function(Player)
	local WinsStore = DataStore2("Wins", Player)
	local ToolStore = DataStore2("Tools", Player)
	
	local Tools = {}
	
	game:GetService("ReplicatedStorage").PlayerAdded:FireAllClients()
	
	Player.CharacterAdded:Connect(function(Character)
		Character.Humanoid.Died:Connect(function()
			ReplicatedStorage.PlayerDied:FireAllClients(Player.Name)
		end)
	end)	
	
	local Leaderstats = Instance.new("Folder")
	Leaderstats.Name = "leaderstats"
	
	local Wins = Instance.new("IntValue")
	Wins.Name = "Wins"
	Wins.Value = WinsStore:Get(0)
	Wins.Parent = Leaderstats
	
	local InRound = Instance.new("BoolValue")
	InRound.Name = "InRound"
	InRound.Parent = Player
	
	local Afk = Instance.new("BoolValue")
	Afk.Name = "Afk"
	Afk.Parent = Player
	
	WinsStore:OnUpdate(function(NewWins)
		Wins.Value = NewWins
	end)
	
	ToolStore:OnUpdate(function(NewTool)
		table.insert(Tools, 1, NewTool.Name)
	end)
	
	Leaderstats.Parent = Player
	
	for _, ToolName in pairs(Tools) do
		ReplicatedStorage[ToolName]:Clone().Parent = Player.Backpack
	end
end)

Well if you plan on adding more to your game I’m pretty sure 2 datastores will work but anything beyond that will have a risk of throttle. But if you’re asking what you should change the datastore to then I would suggest using a array(table) instead of a number. However it should work fine if you’re only using 2 but in the long run, if you want to add any more stores to the game it’s a risk I believe.

What do you mean? I’m pretty much asking what I should change to that script?

This:

local ReplicatedStorage = game:GetService("ReplicatedStorage")

local Votes = ReplicatedStorage:WaitForChild("VotesEnableDisable")

local DataStore2 = require(script.Parent.DataStore2)

DataStore2.Combine("DATA", "Wins", "Tools")

game:GetService("Players").PlayerAdded:Connect(function(Player)
	local WinsStore = DataStore2("Wins", Player)
	local ToolStore = DataStore2("Tools", Player)
	
	local Tools = {}
	
	game:GetService("ReplicatedStorage").PlayerAdded:FireAllClients()
	
	Player.CharacterAdded:Connect(function(Character)
		Character.Humanoid.Died:Connect(function()
			ReplicatedStorage.PlayerDied:FireAllClients(Player.Name)
		end)
	end)	
	
	local Leaderstats = Instance.new("Folder")
	Leaderstats.Name = "leaderstats"
	
	local Wins = Instance.new("IntValue")
	Wins.Name = "Wins"
	Wins.Value = WinsStore:Get(0)
	Wins.Parent = Leaderstats
	
	local InRound = Instance.new("BoolValue")
	InRound.Name = "InRound"
	InRound.Parent = Player
	
	local Afk = Instance.new("BoolValue")
	Afk.Name = "Afk"
	Afk.Parent = Player
	
	WinsStore:OnUpdate(function(NewWins)
		Wins.Value = NewWins
	end)
	
	ToolStore:OnUpdate(function(NewTool)
		table.insert(Tools, 1, NewTool.Name)
	end)
	
	Leaderstats.Parent = Player
	
	for _, ToolName in pairs(Tools) do
		ReplicatedStorage[ToolName]:Clone().Parent = Player.Backpack
	end
end)

Well I told you how to fix it. You should at least try to do it yourself before asking me.

I’ve tried it and it didn’t get fixed.

Leaderstats:

local ReplicatedStorage = game:GetService("ReplicatedStorage")

local Votes = ReplicatedStorage:WaitForChild("VotesEnableDisable")

local DataStore2 = require(script.Parent.DataStore2)

DataStore2.Combine("DATA", "Wins", "Tools")

game:GetService("Players").PlayerAdded:Connect(function(Player)
	local WinsStore = DataStore2("Wins", Player)
    local ToolStore = DataStore2("Tools", Player)
    	
   	local Tools = {}
    	
    game:GetService("ReplicatedStorage").PlayerAdded:FireAllClients()
    	
    Player.CharacterAdded:Connect(function(Character)
    	Character.Humanoid.Died:Connect(function()
    		ReplicatedStorage.PlayerDied:FireAllClients(Player.Name)
    	end)
    end)	
    	
    local Leaderstats = Instance.new("Folder")
	Leaderstats.Name = "leaderstats"
    	
    local Wins = Instance.new("IntValue")
    Wins.Name = "Wins"
    Wins.Value = WinsStore:Get(0)
    Wins.Parent = Leaderstats
    	
    local InRound = Instance.new("BoolValue")
    InRound.Name = "InRound"
    InRound.Parent = Player
    	
    local Afk = Instance.new("BoolValue")
    Afk.Name = "Afk"
    Afk.Parent = Player
    	
    WinsStore:OnUpdate(function(NewWins)
    	Wins.Value = NewWins
    end)
    	
    ToolStore:OnUpdate(function(ToolName)
		table.insert(Tools, 1, ToolName)
    end)
    	
    Leaderstats.Parent = Player
    	
    for _, ToolName in pairs(Tools) do
    	ReplicatedStorage[ToolName]:Clone().Parent = Player.Backpack
    end
end)

Shop:

local DataStore2 = require(game:GetService("ServerScriptService"):WaitForChild("DataStore2"))

DataStore2.Combine("DATA", "Wins", "Tools")

local BuyEvent = game:GetService("ReplicatedStorage"):WaitForChild("BuyItem")

BuyEvent.OnServerEvent:Connect(function(Player, ToolName)
	local ToolStore = DataStore2("Tools", Player)
	
	local Tool = game:GetService("ServerStorage"):FindFirstChild(ToolName)
	
	if Tool then
		if Player.leaderstats.Wins.Value >= script[ToolName].Value and not Player.StarterGear:FindFirstChild(ToolName) then
			Tool:Clone().Parent = Player.StarterGear
			Tool:Clone().Parent = Player.Backpack
			
			ToolStore:Set(ToolName, true)
		end
	else
		Player:Kick("No exploiting please.")
	end
end)
1 Like

That’s a bit weird why it’s not working and I don’t know.