I am storing a table of items the player owns in DataStore2 and when they open a case I want to update but the value is not saving to DataStore2.
When I leave the game and rejoin the data is suddenly gone and when I open another case the data is gone and replaced with the item from the latest case.
local data = ToolsDataStore:Get()
print(data) -- returns {} because data does not save from previous sessions
table.insert(data, Item)
print(data) -- returns {[1] = "Whatever the item name is"}
ToolsDataStore:Set(data)
print(ToolsDataStore:Get()) -- returns {[1] = "Whatever the item name is"}
1.Do you have any other values left after you exit that are not related to the table? Maybe you just didn’t create the bool value named “SaveInStudio” in ServerStorage and didn’t set it to true ?
Is this the structure of your main script responsible for datastore2?
DataStore2.Combine("DATA", "tablef")
Players.PlayerAdded:Connect(function(player)
local tableStore = DataStore2("tablef", player)
local leaderstats = Instance.new("Folder")
leaderstats.Name = "leaderstats"
leaderstats.Parent = player
local tablef = tableStore:Get({})
tableStore:OnUpdate(function(newValue)
tablef = newValue
end)
end)
Perhaps you forgot to combine the resulting table?
I still think it’s about the structure of your script responsible for datastore2, since you can still use Get() and Set() functions in other scripts.
This is the entire script that handles datastores.
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Players = game:GetService("Players")
local ServerScriptService = game:GetService("ServerScriptService")
local IncrementEvent = ReplicatedStorage.Increment
local DataStore2 = require(ServerScriptService.DataStore2)
DataStore2.ClearCache()
DataStore2.Combine("DATA", "Bucks")
DataStore2.Combine("DATA", "XP")
DataStore2.Combine("DATA", "Rebirths")
DataStore2.Combine("DATA", "Tools")
DataStore2.Combine("DATA", "Equipped Tools")
Players.PlayerAdded:Connect(function(player)
local BucksDataStore = DataStore2("Bucks", player)
local XPDataStore = DataStore2("XP", player)
local RebirthsDataStore = DataStore2("Rebirths", player)
local ToolsDataStore = DataStore2("Tools", player)
--local EquippedToolsDataStore = DataStore2("Equipped Tools", player)
-- Functions to interpet data
-- Functions to update leaderstats
local function SetBucksLeaderstat()
player.leaderstats.Bucks.Value = BucksDataStore:Get()
end
local function SetLevelLeaderstat()
local XP = XPDataStore:Get()
local Level = 1
local RequiredXP = 100
-- Iterate until we find the correct level
while task.wait() do
if XP >= RequiredXP then
Level = Level + 1 -- Move to the next level
XP = XP - RequiredXP -- Subtract XP used to level up from XP
RequiredXP = RequiredXP + 100 -- Increase the XP required for the next level
else
player.leaderstats.Level.Value = Level
break
end
end
end
-- Functions to update inventory
local function UpdateInventory(Value)
-- Add item to inventory
if Value then
local Item = Value
local data = ToolsDataStore:Get()
print(data)
table.insert(data, Item)
print(data)
ToolsDataStore:Set(data)
print(ToolsDataStore:Get())
end
-- Update Inventory
--[[for i,v in ToolsDataStore:Get() do
print(v)
for i,w in ipairs(require(game.ReplicatedStorage.ToolsModule)) do
if v == w.Name then
require(game.ReplicatedStorage.ToolsModule).AddToolToInventory(player.UserId, w.Name, w.Description, w.Rarity, w.ImageId)
end
end
end]]
end
-- Updates data when remote event called
IncrementEvent.Event:Connect(function(UserId, DataStore, Value)
if UserId == player.UserId then
if DataStore == "XPDataStore" then
XPDataStore:Increment(Value)
SetLevelLeaderstat()
end
if DataStore == "BucksDataStore" then
BucksDataStore:Increment(Value)
SetBucksLeaderstat()
end
if DataStore == "ToolsDataStore" then
UpdateInventory(Value)
end
end
end)
-- Load players data when they join
player:WaitForChild("leaderstats")
player.leaderstats:WaitForChild("Bucks")
player.leaderstats:WaitForChild("Level")
if BucksDataStore:Get() == nil then
BucksDataStore:Set(0)
else
SetBucksLeaderstat()
end
if XPDataStore:Get() == nil then
XPDataStore:Set(0)
else
SetLevelLeaderstat()
end
if ToolsDataStore:Get() ~= nil then
UpdateInventory()
end
-- Equip players previously equipped tools when they join
--if EquippedToolsDataStore:Get() ~= nil then
--[[print(EquippedToolsDataStore:Get())
for i,v in EquippedToolsDataStore:Get() do
for i,w in ipairs(require(game.ReplicatedStorage.ToolsModule)) do
if v == w.Name then
require(game.ReplicatedStorage.ToolsModule).EquipTool(player.UserId, w.Name, w.Description, w.Rarity, w.ImageId)
end
end
end]]
--end
end)
First of all, I have never seen such an unorganized space in my life
Second, this script work for me:
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Players = game:GetService("Players")
local ServerScriptService = game:GetService("ServerScriptService")
local IncrementEvent = ReplicatedStorage.Increment
local DataStore2 = require(ServerScriptService.DataStore2)
DataStore2.ClearCache()
DataStore2.Combine("DATA", "Bucks")
DataStore2.Combine("DATA", "XP")
DataStore2.Combine("DATA", "Rebirths")
DataStore2.Combine("DATA", "Tools")
DataStore2.Combine("DATA", "Equipped Tools")
Players.PlayerAdded:Connect(function(player)
local BucksDataStore = DataStore2("Bucks", player)
local XPDataStore = DataStore2("XP", player)
local RebirthsDataStore = DataStore2("Rebirths", player)
local ToolsDataStore = DataStore2("Tools", player)
--local EquippedToolsDataStore = DataStore2("Equipped Tools", player)
local toolsData = ToolsDataStore:Get({})
-- Functions to interpet data
-- Functions to update leaderstats
local function SetBucksLeaderstat()
player.leaderstats.Bucks.Value = BucksDataStore:Get()
end
local function SetLevelLeaderstat()
local XP = XPDataStore:Get()
local Level = 1
local RequiredXP = 100
-- Iterate until we find the correct level
while task.wait() do
if XP >= RequiredXP then
Level = Level + 1 -- Move to the next level
XP = XP - RequiredXP -- Subtract XP used to level up from XP
RequiredXP = RequiredXP + 100 -- Increase the XP required for the next level
else
player.leaderstats.Level.Value = Level
break
end
end
end
-- Functions to update inventory
local function UpdateInventory(Value)
-- Add item to inventory
local Item = Value
local data = ToolsDataStore:Get()
print(data)
table.insert(data, Item)
print(data)
ToolsDataStore:Set(data)
print(ToolsDataStore:Get())
-- Update Inventory
--[[for i,v in ToolsDataStore:Get() do
print(v)
for i,w in ipairs(require(game.ReplicatedStorage.ToolsModule)) do
if v == w.Name then
require(game.ReplicatedStorage.ToolsModule).AddToolToInventory(player.UserId, w.Name, w.Description, w.Rarity, w.ImageId)
end
end
end]]
end
-- Updates data when remote event called
IncrementEvent.Event:Connect(function(UserId, DataStore, Value)
if UserId == player.UserId then
if DataStore == "XPDataStore" then
XPDataStore:Increment(Value)
SetLevelLeaderstat()
end
if DataStore == "BucksDataStore" then
BucksDataStore:Increment(Value)
SetBucksLeaderstat()
end
if DataStore == "ToolsDataStore" then
UpdateInventory(Value)
end
end
end)
-- Load players data when they join
player:WaitForChild("leaderstats")
player.leaderstats:WaitForChild("Bucks")
player.leaderstats:WaitForChild("Level")
if BucksDataStore:Get() == nil then
BucksDataStore:Set(0)
else
SetBucksLeaderstat()
end
if XPDataStore:Get() == nil then
XPDataStore:Set(0)
else
SetLevelLeaderstat()
end
if ToolsDataStore:Get() ~= nil then
UpdateInventory("idk")
end
-- Equip players previously equipped tools when they join
--if EquippedToolsDataStore:Get() ~= nil then
--[[print(EquippedToolsDataStore:Get())
for i,v in EquippedToolsDataStore:Get() do
for i,w in ipairs(require(game.ReplicatedStorage.ToolsModule)) do
if v == w.Name then
require(game.ReplicatedStorage.ToolsModule).EquipTool(player.UserId, w.Name, w.Description, w.Rarity, w.ImageId)
end
end
end]]
--end
end)
And I also don’t see the point in using ClearCashe. Previously, it was used to clear the entire date in the datastore, but now, apparently, this function is deprecated
local Players = game:GetService("Players")
local ServerScriptService = game:GetService("ServerScriptService")
local Workspace = game:GetService("Workspace")
local DataStore2 = require(ServerScriptService.DataStore2)
-- Combine every key you use. This will eventually be the default, but for now read the "Gotchas" section to understand why we need this.
DataStore2.Combine("DATA", "points")
Players.PlayerAdded:Connect(function(player)
local pointsStore = DataStore2("points", player)
local leaderstats = Instance.new("Folder")
leaderstats.Name = "leaderstats"
local points = Instance.new("NumberValue")
points.Name = "Points"
points.Value = pointsStore:Get(0) -- The "0" means that by default, they'll have 0 points
points.Parent = leaderstats
pointsStore:OnUpdate(function(newPoints)
-- This function runs every time the value inside the data store changes.
points.Value = newPoints
end)
leaderstats.Parent = player
end)
--The player will now have leaderstats
--Now, we have to let the player actually get points. Write the following code after the connection:
Workspace.PointsPart.ClickDetector.MouseClick:Connect(function(player)
local pointsStore = DataStore2("points", player)
pointsStore:Increment(1) -- Give them 1 point
end)
Thanks a lot for the help. I added task.wait(5) as the first line in the UpdateInventory() function and it fixed everything. I removed DataStore2.ClearCache() from my code and changed the functions that would set leaderstats when you first join the game to longer check if the user has data and use DataStore:Get(default value) instead. Could you elaborate more on how my code is unorganized? To me everything is compartmentalized and easy to understand, but that’s probably just because I wrote it.
First, you don’t need to split the combination of one container into different lines.
I prefer this option more: DataStore2.Combine("DATA", "Bucks", "XP", "Rebirths", "Tools", "Equipped Tools")
Secondly, since I have not seen your new script, I will say in advance that for int, float, etc. values, it is best to create new values yourself, as presented in this code:
local leaderstats = Instance.new("Folder")
leaderstats.Name = "leaderstats"
local points = Instance.new("NumberValue")
points.Name = "Points"
points.Value = pointsStore:Get(0) -- The "0" means that by default, they'll have 0 points
points.Parent = leaderstats
Third, do not forget that ABSOLUTELY all values need to be constantly updated:
pointsStore:OnUpdate(function(newPoints)
-- This function runs every time the value inside the data store changes.
points.Value = newPoints
end)
And last but not least, this is my personal taste - do not write various functions and events in the code block itself, where you create and update your values, because this is, in fact, the center of your entire economy.
The leaderstats are created in another script, but I will move them to this one. I stopped using the :OnUpdate() function because I couldn’t get it to recognize when a value was changed outside of the script the :OnUpdate() function was in. As for creating functions inside of this script, is there a way to make it so if one function errors the rest of the script doesn’t stop with it and keeps functioning? Could I acheive that with spawn(function()?
The fact is that the :onUpdate function is always launched when you use the :Set() function and it changes the value not for the server, but for local scripts (this is a kind of thin thread between the server and the client), this in turn is necessary for various actions (for example, without the onUpdate function, your gui stats (if any) simply will not be to be updated:
Thanks. For updating values I call a BindableEvent and the script included above then updates the values. If the values need to be sent to the client, I’ll send them to client then through a remote.
I will. I’m still unsure what was wrong though because task.wait(5) doesn’t seem like something that would fix data not saving lol. I had to do this when saving the Bucks and XP values in the round system because otherwise the value I saved second would not save.
Bucks:Increment(1)
task.wait() -- removing this causes XP to not save
XP:Increment(1)
By the way, I just noticed that you used a remote event to change the values in the datastore. And I really hope that you don’t start this remote event from the client, because the fact is that hackers can at any time not only start the remote function themselves, but also change the values that come to the server.
That is, they can simply run a remote event where the value is 10000000000
It’s a BindableEvent because I couldn’t get DataStore:OnUpdate() to recognize when I use DataStore:Increment(number) in another script. If I could get that to work then I would just trigger the functions from DataStore:OnUpdate() and instead of calling a BindableEvent when I want to update something I would just do DataStore:Increment(number).