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

I’ve made a datastore script for my survival game yesterday with 4 different tables

local SavedMinerals = {}
local SavedResources = {}
local SavedFood = {}
local SavedStats = {}

and I cant figure out how to fix it.
Heres the whole script

local DatastoreService = game:GetService("DataStoreService")
local DataKey1 = 1
local Datastore1 = DatastoreService:GetDataStore(DataKey1)
local DataKey2 = 2
local Datastore2 = DatastoreService:GetDataStore(DataKey2)
local DataKey3 = 3
local Datastore3 = DatastoreService:GetDataStore(DataKey3)
local DataKey4 = 4
local Datastore4 = DatastoreService:GetDataStore(DataKey4)

local SavedMinerals = {}
local SavedResources = {}
local SavedFood = {}
local SavedStats = {}

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

wait(2)
	
--//Stats	

SavedStats.Stats = Instance.new("Folder",plr) SavedStats.Stats.Name = 'Stats';

SavedStats.Strength = Instance.new("IntValue",SavedStats.Stats) SavedStats.Strength.Name = 'Strength';
SavedStats.Speed = Instance.new("IntValue",SavedStats.Stats) SavedStats.Speed.Name = 'Speed';
SavedStats.Charm = Instance.new("IntValue",SavedStats.Stats) SavedStats.Charm.Name = 'Charm';
SavedStats.Karma = Instance.new("IntValue",SavedStats.Stats) SavedStats.Karma.Name = 'Karma';
SavedStats.Trust = Instance.new("IntValue",SavedStats.Stats) SavedStats.Trust.Name = 'Trust';

SavedStats.Building = Instance.new("IntValue",SavedStats.Stats) SavedStats.Building.Name = 'Building Level';
SavedStats.Crafting = Instance.new("IntValue",SavedStats.Stats) SavedStats.Crafting.Name = 'Crafting Level';
SavedStats.Forging = Instance.new("IntValue",SavedStats.Stats) SavedStats.Forging.Name = 'Forging Level';
SavedStats.Violence = Instance.new("IntValue",SavedStats.Stats) SavedStats.Violence.Name = 'Violence Level';
SavedStats.Immune = Instance.new("IntValue",SavedStats.Stats) SavedStats.Immune.Name = 'Immune System';
SavedStats.Socialization = Instance.new("IntValue",SavedStats.Stats) SavedStats.Socialization.Name = 'Socialization Level';

SavedStats.Level = Instance.new("IntValue",SavedStats.Stats) SavedStats.Level.Name = 'Level';
	
--//Minerals
	
SavedMinerals.Minerals = Instance.new("Folder",plr) SavedMinerals.Minerals.Name = 'Materials';

SavedMinerals.Coal = Instance.new("IntValue",SavedMinerals.Minerals) SavedMinerals.Coal.Name = 'Coal';
SavedMinerals.Stone = Instance.new("IntValue",SavedMinerals.Minerals) SavedMinerals.Stone.Name = 'Stone';

SavedMinerals.Amethyst = Instance.new("IntValue",SavedMinerals.Minerals) SavedMinerals.Amethyst.Name = 'Amethyst';
SavedMinerals.Gold = Instance.new("IntValue",SavedMinerals.Minerals) SavedMinerals.Gold.Name = 'Gold';

SavedMinerals.Diamond = Instance.new("IntValue",SavedMinerals.Minerals) SavedMinerals.Diamond.Name = 'Diamond';
SavedMinerals.Emerald = Instance.new("IntValue",SavedMinerals.Minerals) SavedMinerals.Emerald.Name = 'Emerald';

SavedMinerals.Sulfur = Instance.new("IntValue",SavedMinerals.Minerals) SavedMinerals.Sulfur.Name = 'Sulfur';
SavedMinerals.Copper = Instance.new("IntValue",SavedMinerals.Minerals) SavedMinerals.Copper.Name = 'Copper';

SavedMinerals.Steel = Instance.new("IntValue",SavedMinerals.Minerals) SavedMinerals.Steel.Name = 'Steel';
SavedMinerals.Iron = Instance.new("IntValue",SavedMinerals.Minerals) SavedMinerals.Iron.Name = 'Iron';

--//Resources
	
SavedResources.Resources = Instance.new("Folder",plr) SavedResources.Resources.Name = 'Resources';

SavedResources.Wood = Instance.new("IntValue",SavedResources.Resources) SavedResources.Wood.Name = 'Wood';
SavedResources.Sticks = Instance.new("IntValue",SavedResources.Resources) SavedResources.Sticks.Name = 'Sticks';

SavedResources.Sugar = Instance.new("IntValue",SavedResources.Resources) SavedResources.Sugar.Name = 'Sugar';
SavedResources.Ice = Instance.new("IntValue",SavedResources.Resources) SavedResources.Ice.Name = 'Ice';

SavedResources.Plastic = Instance.new("IntValue",SavedResources.Resources) SavedResources.Plastic.Name = 'Plastic';
SavedResources.Glass = Instance.new("IntValue",SavedResources.Resources) SavedResources.Glass.Name = 'Glass';

SavedResources.Fur = Instance.new("IntValue",SavedResources.Resources) SavedResources.Fur.Name = 'Fur';
SavedResources.Cloth = Instance.new("IntValue",SavedResources.Resources) SavedResources.Cloth.Name = 'Cloth';

SavedResources.Hide = Instance.new("IntValue",SavedResources.Resources) SavedResources.Hide.Name = 'Hide';
SavedResources.Paper = Instance.new("IntValue",SavedResources.Resources) SavedResources.Paper.Name = 'Paper';

SavedResources.Wool = Instance.new("IntValue",SavedResources.Resources) SavedResources.Wool.Name = 'Wool';
SavedResources.Metal = Instance.new("IntValue",SavedResources.Resources) SavedResources.Metal.Name = 'Metal';

SavedResources.IceShard = Instance.new("IntValue",SavedResources.Resources) SavedResources.IceShard.Name = 'Ice Shard';
SavedResources.MetalScrap = Instance.new("IntValue",SavedResources.Resources) SavedResources.MetalScrap.Name = 'Metal Scrap';

--//Food

SavedFood.Food = Instance.new("Folder",plr) SavedFood.Food.Name = 'Food';

SavedFood.Beef = Instance.new("IntValue",SavedFood.Food) SavedFood.Beef.Name = 'Beef';
SavedFood.Chicken = Instance.new("IntValue",SavedFood.Food) SavedFood.Chicken.Name = 'Chicken';

SavedFood.Steak = Instance.new("IntValue",SavedFood.Food) SavedFood.Steak.Name = 'Steak';
SavedFood.Pork = Instance.new("IntValue",SavedFood.Food) SavedFood.Pork.Name = 'Pork';

SavedFood.Bacon = Instance.new("IntValue",SavedFood.Food) SavedFood.Bacon.Name = 'Bacon';
SavedFood.Bread = Instance.new("IntValue",SavedFood.Food) SavedFood.Bread.Name = 'Ice cold Bread';

SavedFood.Laughter = Instance.new("IntValue",SavedFood.Food) SavedFood.Laughter.Name = 'Laughter';
SavedFood.Leaves = Instance.new("IntValue",SavedFood.Food) SavedFood.Leaves.Name = 'Leaves';

SavedFood.Apples = Instance.new("IntValue",SavedFood.Food) SavedFood.Apples.Name = 'Apples';
SavedFood.Bananas = Instance.new("IntValue",SavedFood.Food) SavedFood.Bananas.Name = 'Bananas';

SavedFood.Oranges = Instance.new("IntValue",SavedFood.Food) SavedFood.Oranges.Name = 'Oranges';
SavedFood.Rice = Instance.new("IntValue",SavedFood.Food) SavedFood.Rice.Name = 'Rice';

SavedFood.RabbitFoot = Instance.new("IntValue",SavedFood.Food) SavedFood.RabbitFoot.Name = 'Rabbit Foot';
SavedFood.Souls = Instance.new("IntValue",SavedFood.Souls) SavedFood.Souls.Name = 'Souls';

SavedFood.Lettuce = Instance.new("IntValue",SavedFood.Food) SavedFood.Lettuce.Name = 'Lettuce';
SavedFood.Grass = Instance.new("IntValue",SavedFood.Souls) SavedFood.Grass.Name = 'Grass';



--//Loading Data

Datastore1:SetAsync(plr.UserId, SavedMinerals)
Datastore2:SetAsync(plr.UserId, SavedResources)
Datastore3:SetAsync(plr.UserId, SavedFood)
Datastore4:SetAsync(plr.UserId, SavedStats)

end) 

game.Players.PlayerRemoving:Connect(function(plr)
	
	--//Saving Data
	Datastore1:SetAsync(plr.UserId, SavedMinerals)
	Datastore2:SetAsync(plr.UserId, SavedResources)
	Datastore3:SetAsync(plr.UserId, SavedFood)
	Datastore4:SetAsync(plr.UserId, SavedStats)

end)

I`m extremely new to scripting so I really do not understand datastores much.
3 Likes

you’re not able to store instances. in this case you created folders, int values, number values, etc. those are objects and not UTF-8 compatible. all that’s UTF-8 compatible are string and numbers. you’ll need to convert the folders and values into a table without the objects in order to save it.

4 Likes

uhh… How do I put them into a table?

all I need is a 6 line piece of code real quick

you store it as following:

local Table = {
    Table = {}
    ValueName = Value
}

Folders are basically just tables but in a digital form. recreating a folder would be just like what i showed above.

if we were to make it physical into studio it’d look like this
image

You can do tedious, repeating code like that much more efficiently.
https://developer.roblox.com/en-us/articles/Roblox-Coding-Basics-Loops
https://developer.roblox.com/articles/For-Loops

I’d give an example, but I don’t know how to with this situation.

1 Like

Write a recursive function that returns a table and for all other ValueObjects, creates a key-value pair in the top-level folder. You can use that to run through the data file.

local function folderToDictionary(folder)
    local dictionary = {}

    for _, object in ipairs(folder:GetChildren()) do
        if object:IsA("Folder") then
            dictionary[object.Name] = folderToDictionary(object)
        elseif object:IsA("ValueBase") or object.ClassName:match("Value") then
            dictionary[object.Name] = object.Value
        end
    end

    return dictionary
end
15 Likes

You need to store any binary data in under 7 bits (your max byte is 127). Otherwise you need to form valid Unicode characters with anything above that.

1 Like

How would I add it to a Data-Store?

local DataKey = -1 ;
local DatastoreService = game:GetService(“DataStoreService”) ;
local Data1 = DatastoreService:GetDataStore(DataKey) ;
local RunService = game:GetService(“RunService”) ;
local folder = script.Parent ;

–//DataKeys\–
–[[

-1 (Development 1) (Testing)
-2 (Development 2)
-3 (Development 3)
-4 (Development 4)
-5 (Development 5)

]]

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

local function folderToDictionary(folder, plr, dictionary)

local dictionary = {}	;

for _, object in ipairs(folder:GetDescendants()) do

    if object:IsA("Folder") then

local Folder = Instance.new("Folder",plr)

Folder.Name = object.Name

for _, int in ipairs(object:GetDescendants()) do

if int:IsA(“ValueBase”) or int.ClassName:match(“Value”) then

local Value = Instance.new(int.ClassName,Folder)

Value.Name = int.Name	

end
end

    end

end

return dictionary

end

folderToDictionary(folder, plr)
Data1:SetAsync(plr.UserId, ‘what now’)

game.Players.PlayerRemoving:Connect(function(plr)

Data1:SetAsync(plr.UserId, ‘what now’)

end)
end)

folderToDictionary is a callback function. You have to assign the return value to a variable. Declare a variable and call the function to set the variable’s value as the return of the call.

local data = folderToDictionary(dataFile)

It only accepts one argument as well, not two. The player argument you passed to it will be discarded. It’s not necessary either, because all it does is convert folders into dictionaries and return them back to the calling scope.

This function should be ran in PlayerRemoving and then the variable should be passed to SetAsync.

Don’t put the function in PlayerAdded and keep your PlayerRemoving one out of there as well. Furthermore, you may need to write a catcher function to account for players already existing in the server as you have yielding functions at the top of your script.

3 Likes