JsonDecode giving me a string instead of the table I am using

  1. What do you want to achieve?
    Hello everyone, I have been working on making a datastore for my game which only uses :GetAsync() and :SetAsync() once to be efficient with how I am saving and retrieving data for the players. I ended up using JsonEncode and JsonDecode after getting some help in another post I made asking about how to save embedded tables for my datastore.

  2. What is the issue?
    So, I am now using JsonEncode and JsonDecode to save and load the embedded tables holding my player data. Although my script should be setup properly for both the encode and decode, when decoding the table of player data the table is decoded as a string rather than the actual table. This is not what I want as it’s not a table, just a string for the table which I can’t use.

  3. What solutions have you tried so far?
    I got the idea and help with using JsonEncode and JsonDecode from another helpful developer in this post: https://devforum.roblox.com/t/could-i-use-embedded-tables-to-create-a-datastore-to-save-multiple-tables-of-data-to-one-key/1181212/8

Here is my datastore script, if there is anything bad about it feel free to let me know so I can improve it:

local httpService = game:GetService("HttpService")

local dataStoreService = game:GetService("DataStoreService")

local players = game:GetService("Players")

local dataStore = dataStoreService:GetDataStore("TestData")

local data = {
	leaderstats = {
		["Strength"] = 0;
		["Coins"] = 0;
		["Gems"] = 0;
	},
	
	SwordsPurchased = {
		["Sword1"] = true;
		["Sword2"] = false;
		["Sword3"] = false;
	}
}

game.Players.PlayerAdded:Connect(function(player)
	local dataFromStore = nil
	
	local _playerData
	
	for tableName, embeddedTable in pairs(data) do
		local folder = Instance.new("Folder")
		folder.Name = tableName
		folder.Parent = player
		
		for name, value in pairs(embeddedTable) do
			if tableName == "leaderstats" then
				local new = Instance.new("NumberValue")
				new.Name = name
				new.Value = value
				
				if folder.Name == tableName then
					new.Parent = folder
				end
			elseif tableName == "SwordsPurchased" then
				local new = Instance.new("BoolValue")
				new.Name = name
				new.Value = value
				
				if folder.Name == tableName then
					new.Parent = folder
				end
			end
		end
	end
	
	local success, err = pcall(function()
		dataFromStore = dataStore:GetAsync("uid-".. player.UserId)

		_playerData = httpService:JSONDecode(dataFromStore)

		warn(_playerData)
	end)

	if success then
		print("Getting PlayerData for Player: ".. player.Name ..", ID: ".. player.UserId)
		if dataFromStore then
			for tableName, embeddedTable in pairs(dataFromStore) do
				for name, value in pairs(embeddedTable) do
					if tableName == "leaderstats" then
						player.leaderstats[name].Value = value
					elseif tableName == "PurchasedSwords" then
						player.PurchasedSwords[name].Value = value
					end
				end
			end
			print("PlayerData loaded for Player: ".. player.Name ..", ID: ".. player.UserId)
		else
			print("Creating new PlayerData for Player: ".. player.Name ..", ID: ".. player.UserId)
		end
	else
		warn("Error loading PlayerData for Player: ".. player.Name ..", ID: ".. player.UserId ..". Please contact a developer in the chance that data is permanently lost.")
	end
end)

game.Players.PlayerRemoving:Connect(function(player)
	local dataForStore = {
		leaderstats = {
			["Strength"] = 0;
			["Coins"] = 0;
			["Gems"] = 0;
		},

		SwordsPurchased = {
			["Sword1"] = true;
			["Sword2"] = false;
			["Sword3"] = false;
		}
	}
	
	for tableName, embeddedTable in pairs(dataForStore) do
		if tableName == "leaderstats" then
			for name, value in pairs(player.leaderstats:GetChildren()) do
				embeddedTable[value.Name] = value.Value
			end
		elseif tableName == "PurchasedSwords" then
			for name, value in pairs(player.PurchasedSwords:GetChildren()) do
				embeddedTable[value.Name] = value.Value
			end
		end
	end
	
	local Jsond = httpService:JSONEncode(dataForStore)
	
	warn(Jsond)
	
	local success, err = pcall(dataStore.SetAsync, dataStore, "uid-".. player.UserId, Jsond)
	
	if success then
		print("Successfully Saved PlayerData for Player: ".. player.Name ..", ID: ".. player.UserId)
	end
end)

The tables for the player data aren’t finished yet. This is all the data I have that the game needs currently.

If there is any better option for saving the table feel free to let me know. I am always open to making a better script, especially when it comes to making a better datastore.

1 Like

I am just saying - data stores can store tables.

2 Likes

Would it matter if I have the embedded tables inside of my main data table? Or could I simply just save the data table and be fine? I am aware that you could save tables regularly, I just wasn’t sure if there would be any issues putting tables inside of a table that I am saving.

Yep. Datastores save all default lua instances. (basically anything that can be understood by different scripts)

2 Likes

Ah, thank you very much. For some reason I was thinking that using embedded tables would cause some sort complication. Turns out I was unnecessarily complicating how I was saving player data! Thanks for the clarification!

1 Like