Inventory won't save data table

Hey. I made an inventory system, basically, at the beginning it loads the data the player has, and then I don’t save each time it changed, rather when they leave, I make an empty table loop through the scrolling frame and get all the instances’ name and insert them to the table, but for some reason, it won’t save the data. Here are both of my codes:

Inventory saver:

local inventoryDataStore = dataStoreService:GetDataStore("InventoryDataStoreTwo");

game:BindToClose(function()
	for _, v in ipairs(game.Players:GetPlayers()) do
		local userId = v.UserId;
		
		local newTable = {};
		
		for _, v in ipairs(v.PlayerGui.Inventory.ImageLabel.Inventory:GetChildren()) do
			if not v:IsA("UIGridLayout") and not v:IsA("Script") then
				table.insert(newTable, #newTable + 1, v.Name);
			end
		end
		
		local succed = pcall(function()
			local data = inventoryDataStore:GetAsync(userId);
			
			if data then
				inventoryDataStore:UpdateAsync(userId, function()
					return newTable
				end)
			else
			end
		end)
	end
end)

Inventory loader:

local dataStoreService = game:GetService("DataStoreService");

local dataStore = dataStoreService:GetDataStore("InventoryDataStoreTwo");

local function load()
	local succed = pcall(function()
		local player = script.Parent.Parent.Parent.Parent.Parent;
		
		local data = dataStore:GetAsync(player.UserId);
		
		if data then
			for _, v in ipairs(data) do
				local templateClone = script.Template:Clone();
				
				templateClone.Parent = script.Parent
				
				templateClone.Name = tostring(v)
			end
		else
			local freeItems = {"Taco"};
			
			for _, v in ipairs(freeItems) do
				local templateClone = script.Template:Clone();

				templateClone.Parent = script.Parent

				templateClone.Name = tostring(v)
			end
		end
	end)
end;

load()

Tables cannot be directly saved. You must use JSONEncode and JSONDecode to convert it to a string.

What API would I use to do that?

HttpService. I put links to each topic in my response.

here’s an example:

local table = {"item1", "item2", "item3"}
local http = game:GetService("HttpService")
local dss = game:GetService("DataStoreService")
local ds = dss:GetDataStore("DataStore")

function save(player, tbl) -- Takes a player object and a table
  if not tbl then return end
  local ntbl = http:JSONEncode(tbl)
  local s,f = pcall(function()
    ds:UpdateAsync(player.UserId, ntbl) 
  end)
  if f then
   print(f)
 end
end

you would load using JSONDecode instead of Encode

2 Likes

also, I noticed that you only save when the game closes, this means that if there is more than one player in the server, when they leave their data will not be saved. You can fix this using

game.Players.PlayerAdded:Connect(function(player)

end)

Should my code be like this:

local dataStoreService = game:GetService("DataStoreService");

local dataStore = dataStoreService:GetDataStore("InventoryDataStore5");

local httpService = game:GetService("HttpService");

game:BindToClose(function()
	for _, v in ipairs(game.Players:GetPlayers()) do
		local userId = v.UserId;
		
		local newTable = {"Taco", "Chips"};
		
		for _, v in ipairs(v.PlayerGui.Inventory.ImageLabel.Inventory:GetChildren()) do
			if not v:IsA("UIGridLayout") and not v:IsA("Script") then
				table.insert(newTable, #newTable + 1, v.Name);
			end
		end
		
		local succed = pcall(function()
			local data = inventoryDataStore:GetAsync(userId);
			
			if data then
				inventoryDataStore:UpdateAsync(userId, function()
					return game:GetService("HttpService"):JSONEncode(newTable)
				end)
			else
			end
		end)
	end
end)

And:

local dataStoreService = game:GetService("DataStoreService");

local dataStore = dataStoreService:GetDataStore("InventoryDataStore5");

local httpService = game:GetService("HttpService");

local function load()
	local succed = pcall(function()
		local player = script.Parent.Parent.Parent.Parent.Parent;
		
		local data = dataStore:GetAsync(player.UserId);
		
		if data then
			for _, v in ipairs(httpService:JSONDecode(data)) do
				local templateClone = script.Template:Clone();
				
				templateClone.Parent = script.Parent
				
				templateClone.Name = tostring(v)
			end
		else
			local freeItems = {"Taco"};
			
			for _, v in ipairs(freeItems) do
				local templateClone = script.Template:Clone();

				templateClone.Parent = script.Parent

				templateClone.Name = tostring(v)
			end
		end
	end)
end;

load()

delete the data variable in your pcall and it might work

I deleted the data variable but still doesn’t work.

are you testing in studio? you might have API services disabled

API services access is enabled.

use this one for now

local dss = game:GetService("DataStoreService")
local ds = dss:GetDataStore("InventoryDataStore5")
local http = game:GetService("HttpService")
function load(player)
 local data
 local s,f = pcall(function()
   data = ds:GetAsync(player.UserId)
  if not data then
  -- give default
  data = http:JSONEncode({"Taco", "Chips"})
 end
 end)
  return http:JSONDecode(data)
end



function save(player,tbl)
 local s,f = pcall(function()
  local new = http:JSONEncode(tbl)
  ds:UpdateAsync(player.UserId, function(old)
   if old == new then
    return old
  else
  return new
 end
 end)
 if f then
  print(f)
 end
 end

game:BindToClose(function()
  local itable = {}
  for i,v in pairs(game.Players:GetPlayers()) do
    local itable = {}
    for a,b in pairs(v.PlayerGui.Inventory.ImageLabel.Inventory:GetChildren()) do
     itable[#itable+1] = b.Name
   end
  save(v,itable)
 end
end)

game.Players.PlayerRemoving:Connect(function(player)
    local itable = {}
    for a,b in pairs(v.PlayerGui.Inventory.ImageLabel.Inventory:GetChildren()) do
     itable[#itable+1] = b.Name
   end
   save(player, itable)
end)

game.Players.PlayerAdded:Connect(function(player)
   local data = load(player)
   -- returns table, do load thing
end
1 Like

Also, to note, tables can be directly saved without converting them to JSON strings. Roblox already does this to save them. When they’re returned using GetAsync they’re auto-decoded back.

1 Like

It doesn’t work. Did I make any mistake in my code?

try following this

local DataStoreService = game:GetService("DataStoreService")
local Players = game:GetService("Players")

local DataStore = DataStoreService:GetDataStore("data store name", "data store scope (if you have one)")

local function load(player) -- load data function
   local success, err = pcall(function()
       return DataStore:GetAsync(player.UserId) -- get the player's pre-existing data, return nil if there is none
   end)

   if not success then return warn (err) else return err end -- if it cannot get the player's data then it sends a warning in the output (the reason why it couldn't get the data), if it can, it returns the data (which can be nil)
end

local function save(player) -- the function the load data
   local success, err = pcall(function()
      DataStore:UpdateAsync(player.UserId, function(oldData) 
          if not oldData then return {} end -- if there is no data to update, then it will return a table by default

          local newData = oldData
          -- code here
          return newData
      end
   end)

   if not success then warn (err) end -- like the first check, it will send a warning in the output
end

Players.PlayerAdded:Connect(load)
Players.PLayerRemoving:Connect(save)

-- alternate for loading player data
  Players.PlayerAdded:Connect(function(player)
     local Playerdata = load(player)

     if Playerdata then
        -- code here
     else
        warn ("no playerdata to load")
     end
  end)

Thank you for replying. Even though I have solved this problem using DataStore2, if your solution works it may help other players. :+1: :slight_smile:

1 Like