Is it possible to create a Table and save/Load it?

This helped me out in some way but I can’t get it working with my table somehow. I don’t know my problem and it’s frustrating me for the past 2 days…

Hello!

First of all, you should read through

as Blokav already mentioned.

Then you would create the structure inside ServerStorage when game.Players.PlayerAdded

You should also think of an structure of the array as well, I would choose something like this :

local Inventory = {
   Apple = 0;
   Banana = 0;
   Log = 0;
} 

When the player leaves with game.Players.PlayerRemoving you will want to loop through inventory in ServerStorage and create an array which you will save:

local HttpService = game:GetService("HttpService")
local DataStore   = game:GetService("DataStoreService"):GetDataStore("Data")

game.Players.PlayerRemoving:connect(function(Player)
	local dataToSave = {}
	for i, v in pairs(game.ServerStorage.Inventory:FindFirstChild(Player.Name):GetChildren()) do
	   if v:FindFirstChild("Amount") then
			dataToSave[v.Name] = v.Amount.Value
		end
	end 
	
	pcall(function()
		DataStore:SetAsync(Player.UserId,HttpService:JSONEncode(dataToSave))
	end)
end)

And then simply load it everytime player joins as I mentioned already :

local HttpService = game:GetService("HttpService")
local DataStore   = game:GetService("DataStoreService"):GetDataStore("Data")

game.Players.PlayerAdded:connect(function(Player)
	local newData = DataStore:GetAsync(Player.UserId)
	
	if newData then
		newData = HttpService:JSONDecode(newData)
		-- load data here, newData.Apple, newData.Banana, newData.Log, they return the amount of each.
	else
		-- create new data (player joined for the first time
	end
end) 

Hope I helped.

3 Likes

Problem is that I cannot create a strucute like you did, it won’t work with my system rn. hmm

You’ll want to use the HttpService - it has two functions, :JSONEncode() and :JSONDecode(), which allow you to encode and decode tables and strings respectively.

To use this simply pass the table as an argument into JSONEncode and save the returned string. When loading the data, you simply load the string and pass it into JSONDecode to get a table again.

This works for tables with non-numerical keys, but if a table contains more tables (common in object-orientated paradigm) you will need to recursively encode and decode the tables, otherwise data will be lost.

What’s your current system? Is it the ServerStorage one?

Jeah, Ive made a picture from my strucur at the start of this post :))
image

EDIT: It’s important maybe to know that this doesnt represant the leaderboard or something. I am storing the players inventory like this. So These arent the only thing that the player can have

Yeah! I saw that and I’ve showed you in my code how to build array structure out of that.

I’ll show you again :

local dataToSave = {}
for i, v in pairs(game.ServerStorage.Inventory:FindFirstChild(Player.Name):GetChildren()) do
	  if v:FindFirstChild("Amount") then
		dataToSave[v.Name] = v.Amount.Value
	end
end 

Now, inside array dataToSave you have structure like the one I’ve told you about :

{
Apple = 0;
Banana = 0;
Log = 0;
}

Oh so I need to add every item in my game to the dataToSave array?

No, only the ones that are in the ServerStorage as in the player’s inventory.

Then you save/load the array.

The compiler wouldn’t be able to convert to JSON because the table has objects in it. Even if it could, Roblox will automatically convert any variant passed in the SetAsync function into JSON (encoded it), then it is stored on roblox’s servers.

You have to use the magic of serialization and *deserialization. Serialization is basically converting a table into a form it can be saved in. Datastores can’t save objects, so you’ll have to store attributes of the object in a table and save it. When the player rejoins, a new instance of the object will be created and the attributes are set, or whatever.

Your saving portion of your script should look something like this:

function save(player) -- making this as a function so it can be called elsewhere
    local save = {Items = {}; Character = {}}
    for _, inv in pairs(game.ServerStorage[player.Name]) do
         if inv:IsA("StringValue") then -- or whatever type of value object you used for the things like "Apple", "Log"
            save.Items[inv.Name] = {Amount = inv.Amount.Value}
        end
    end
    -- serialize the "Character" folder
    yourDS:SetAsync("id-"..player.UserId, save)
end

When it comes to loading the data, deserialization comes in, where you reverse the action of serialization that happened.

The loading portion of your should look something like this:

function load(player) -- same reason as the "save" function above
    local saved = yourDS:GetAsync("id-"..player.UserId) or {} -- if the first value exists, it'll be assigned to the variable, otherwise an empty table is assigned
    for index, v in pairs(saved.Items) do
        local v = Instance.new("StringValue")
        local amt = Instance.new("IntValue")
        v.Name = index
        amt.Name = "Amount"
        amt.Value = v.Amount
        v.Parent = inventory folder for player
        amt.Parent = v
    end
end

Hope this helps

2 Likes

Alright guys me and @Sougood made it work now, I was very close.

Basicly I check all StringValues inside the players inventory and add this to a table

game.Players.PlayerRemoving:connect(function(Player)
		local inv = {}
		
		for i, v in pairs(game.ServerStorage.Inventory:FindFirstChild(Player.Name):GetChildren()) do
		   if v:FindFirstChild("Amount") then
				inv[v.Name] = v.Amount.Value
			end
		end 
	
		pcall(function()
			DataStore:SetAsync(Player.UserId,HttpService:JSONEncode(inv))
		end)
end)

This is all we need to save the Data as soon as a player leaves
(Please note that this is not that save because Data could still get lost when the server gets shutdowned I believe)

To load the actuall Data we run this If-Statement whenever a player joins

if newData then
		newData = HttpService:JSONDecode(newData)
		print("Existing Data")
		-- load data here, newData.Apple, newData.Banana, newData.Log, they return the amount of each.
		-- ima make few examples of here, hope you can continue
		if newData.Apple ~= nil then
			if newData.Apple > 0 then
				print("Found Apple!")
				local Apple = Instance.new("StringValue",folder)
				Apple.Name = "Apple"
				local amount = Instance.new("IntValue",Apple)
				amount.Name = "Amount"
				amount.Value = newData.Apple
			end
		end
		if newData.Banana ~= nil then
			if newData.Banana > 0 then
				local Banana = Instance.new("StringValue",folder)
				Banana.Name = "Banana"
				local amount = Instance.new("IntValue",Banana)
				amount.Name = "Amount"
				amount.Value = newData.Banana
			end
		end
.
.
.
--and so on

EDIT: Please note that this is build to work with my system so it might be diffrent for your system! but this is the general way to save a table and load it in!

15 Likes

I get an “Can’t Parse JSON” error.

2 Likes