How to save a Dictionary to a DataStore?

I’m trying to save a Dictionary to a Datastore. There is a Script which handles the Data when the player first starts. What it does is, if the Player’s Place1 is nil (meaning that’s the first time they’ve joined), their Place1 will be set to a dictionary containing information that can be used to load their place and play it. Here is the code in the Script:

local StartingMapFormat = {
	Object1 = {
		ClassName = "Part",
		Name = "Baseplate",
		Size = Vector3.new(100, 1, 100),
		Position = Vector3.new(0, -0.5, 0),
		BrickColor = BrickColor.new("Medium stone grey"),
		Material = Enum.Material.Plastic,
		Anchored = true,
	}
}

game.Players.PlayerAdded:Connect(function(Player)
	if DSS:GetAsync("Place1~"..Player.UserId) == nil then
		DSS:SetAsync("Place1~"..Player.UserId, StartingMapFormat)
	end
end)

When I run this code, the error

104: Cannot store Dictionary in data store. Data stores can only accept valid UTF-8 characters.

appers.

I was wondering if there are any alternatives to saving a dictionary, or just simply why it says DataStores only accept valid UTF-8 Characters.

I’ve tried reading into UTF-8 and it made no sense whatsoever. Any help would be great, thanks!

5 Likes

You should be able to save tables into Datastores normally, but I don’t think you can store things like Enums or BrickColors. Those are Roblox specific values that don’t really fit with the traditional http request. I could be wrong so don’t quote me on that

That being said you could always use JSONEncode on the data and then decode it when loading. JSONEncode “stringifies” a value and is usually used to convert values to be compatible with the traditional HTTP request.

Code
local StartingMapFormat = {
	Object1 = {
		ClassName = "Part",
		Name = "Baseplate",
		Size = Vector3.new(100, 1, 100),
		Position = Vector3.new(0, -0.5, 0),
		BrickColor = BrickColor.new("Medium stone grey"),
		Material = Enum.Material.Plastic,
		Anchored = true,
	}
}

game.Players.PlayerAdded:Connect(function(Player)
	if DSS:GetAsync("Place1~"..Player.UserId) == nil then
		DSS:SetAsync("Place1~"..Player.UserId, game:GetService("HttpService"):JSONEncode(StartingMapFormat))
	end
end)

Loading:

 game:GetService("HttpService"):JSONDecode(DSS:GetAsync("Place1~"..Player.UserId))
15 Likes

Thanks! Yeah I’ll definitely use the JSONEncode method since that seems more reasonable of a fix. I appreciate the help!

2 Likes

Im pretty sure you can save dictionaries as long as the over-arching container is not a dictionary.

In your example

local StartingMapFormat = {
	[1] = { --or just get rid of [1] = entirely
		ClassName = "Part",
		Name = "Baseplate",
		Size = Vector3.new(100, 1, 100),
		Position = Vector3.new(0, -0.5, 0),
		BrickColor = BrickColor.new("Medium stone grey"),
		Material = Enum.Material.Plastic,
		Anchored = true,
	}
}

I don’t think this would work because the http error was mainly saying that there were invalid characters (non UTF-8).

I believe it’s because of the userdata values he’s trying to save. (Vector3, BrickColor, Enum) These values do not translate to any format in an http request. This is why I advised him to use JSONEncode to stringify the table - so he could keep all of his data (including the dictionary) and parse it very easily.
There is another solution that would work and keep the dictionary.

Here's the alternative method

Instead of sending a string, you can send JSON objects. (Lua tables).
The code below has been modified to send a lua table with a dictionary with 100% valid characters. This would still save.

local StartingMapFormat = {
	Object1 = {
		ClassName = "Part",
		Name = "Baseplate",
		Size ={100, 1, 100},
		Position = {0, -0.5, 0},
		BrickColor ="Medium stone grey",
		Material = "Plastic",
		Anchored = true,
	}
}

game.Players.PlayerAdded:Connect(function(Player)
	if DSS:GetAsync("Place1~"..Player.UserId) == nil then
		DSS:SetAsync("Place1~"..Player.UserId, StartingMapFormat)
	end
end)

The only problem with this alternative is that when loading you would have to parse out each value and put it into a real value. (i.e. Part.Size = Vector3.new(data.Object1.Size))

TL;DR: The error was saying it was having trouble saving that specific dictionary in the datastore because it can’t send userdata values over an http request.

5 Likes