"Data stores can only accept valid UTF-8 characters."

im really sorry if you guys got annoyed for this.

1 Like

set it as the data instead of inserting, also partInstance.Position = Vector3.new(obj[3], obj[4], obj[5]) – im pretty sure that this wont work instead do this: Position = {X = obj[3], Y = obj[4], Z = obj[5]}

1 Like

It’s probably because you can’t save tables directly to DataStores.
Try wrapping the table in HttpService:JSONEncode(), which converts it into a string. When you load the table, use HttpService:JSONDecode() to return it to its original state.

may you tell me how should i do that?

you can save tables in a datastore.

Please read this quoted post. That’s why I’m saying this, correct me if I’m wrong.

You can save tables in a datastore but to you can also specifically convert something that can’t be saved in a datastore into JSONEncode().

1 Like

To save:

local success, err
	repeat
		success, err = pcall(function()
			autoSavingStore:SetAsync(key, function()
				return game:GetService("HttpService"):JSONEncode(data)
			end)
		end)
		
		task.wait()
	until success

To load:

local function load(player: Player)
	local key = keyPrefix .. tostring(player.UserId)
	local success, err
	local data
	
	repeat
		success,err = pcall(function()
			data = autoSavingStore:GetAsync(key)
		end)
	until success or not players:FindFirstChild(player.Name)
	
	if not data then return end
	if success then
		data = game:GetService("HttpService"):JSONDecode(data)

Hmm. I didn’t know that. Thanks

2 Likes

is that correct?

local players = game:GetService("Players")
local dataStoreService = game:GetService("DataStoreService")
local autoSavingStore = dataStoreService:GetDataStore("F3XAutoSave")
local keyPrefix = "Player: "

local function save(player: Player)
	local key = keyPrefix .. tostring(player.UserId)
	local data = {}

	for i, obj: BasePart in ipairs(workspace:FindFirstChild("Builds"):WaitForChild(player.Name):GetDescendants()) do
		if obj:IsA("BasePart") then
			table.insert(data, {
				-- PART PROPERTIES
				obj.Name,
				obj.CanCollide,
				obj.Position.X,
				obj.Position.Y,
				obj.Position.Z,
				obj.Orientation.X,
				obj.Orientation.Y,
				obj.Orientation.Z,
				obj.Anchored,
				obj.Size.X,
				obj.Size.Y,
				obj.Size.Z,
				obj.Color.R,
				obj.Color.G,
				obj.Color.B,
				(string.match(tostring(workspace.Baseplate.TopSurface), "%.(%w+)$")),
				(string.match(tostring(workspace.Baseplate.BottomSurface), "%.(%w+)$")),
				(string.match(tostring(workspace.Baseplate.LeftSurface), "%.(%w+)$")),
				(string.match(tostring(workspace.Baseplate.RightSurface), "%.(%w+)$")),
				(string.match(tostring(workspace.Baseplate.BackSurface), "%.(%w+)$")),
				(string.match(tostring(workspace.Baseplate.FrontSurface), "%.(%w+)$")),
				obj.Transparency,
				obj.Reflectance,
				string.match(tostring(obj.Material), "%.(%w+)$")
			})

			local success, err
			repeat
				success, err = pcall(function()
					autoSavingStore:SetAsync(key, function()
						return game:GetService("HttpService"):JSONEncode(data)
					end)
				end)

				task.wait()
			until success
		end
    end
end

local function load(player: Player)
	local key = keyPrefix .. tostring(player.UserId)
	local success, err
	local data

	repeat
		success,err = pcall(function()
			data = autoSavingStore:GetAsync(key)
		end)
	until success or not players:FindFirstChild(player.Name)

	if not data then return end
	if success then
		data = game:GetService("HttpService"):JSONDecode(data)
		for i, obj in ipairs(data) do
			local partInstance = Instance.new("Part")
			partInstance.Name=obj[1]
			partInstance.CanCollide=obj[2]
			partInstance.Position = Vector3.new(obj[3], obj[4], obj[5])
			partInstance.CFrame *= CFrame.Angles(math.rad(obj[6]),math.rad(obj[7]),math.rad(obj[8]))
			partInstance.Anchored=obj[9]
			partInstance.Size = Vector3.new(obj[10], obj[11], obj[12])
			partInstance.Color = Color3.new(obj[13],obj[14],obj[15])
			partInstance.TopSurface = Enum.SurfaceType[obj[16]]
			partInstance.BottomSurface = Enum.SurfaceType[obj[17]]
			partInstance.LeftSurface = Enum.SurfaceType[obj[18]]
			partInstance.RightSurface = Enum.SurfaceType[obj[19]]
			partInstance.BackSurface = Enum.SurfaceType[obj[20]]
			partInstance.FrontSurface = Enum.SurfaceType[obj[21]]
			partInstance.Transparency = obj[22]
			partInstance.Reflectance = obj[23]
			partInstance.Material = Enum.Material[obj[24]]
		end
	else
		warn(tostring(err))
	end
end

players.PlayerAdded:Connect(load)
players.PlayerRemoving:Connect(save)
game:BindToClose(function()
	for i, plr: Player in ipairs(players:GetPlayers()) do
		save(plr)
	end
end)

Yes, but this is probably not the cause for the error you’re facing.

i still get the error :confused: , it is not working

hold on a minute, i forgot to add the httpservice, i will add that rn mb

i added the httpservice variable and applied it but it still doesn’t work… :frowning:

try changing the colon to an underscore in the keyPrefix

the key is customizable, also when i tried to change it , didnt work.

Hello,
I checked your script and the issue seems to occur because you’re using a function in SetAsync()


(which is what you should use for UpdateAsync
image

Here is the updated script:

local players = game:GetService("Players")
local dataStoreService = game:GetService("DataStoreService")
local autoSavingStore = dataStoreService:GetDataStore("FX3AutoSave")
local keyPrefix = "Player_"

local function save(player: Player)
	local key = keyPrefix .. tostring(player.UserId)
	local data = {}

	for i, obj: BasePart in ipairs(workspace:FindFirstChild("Builds"):WaitForChild(player.Name):GetDescendants()) do
		if obj:IsA("BasePart") then
			table.insert(data, {
				-- PART PROPERTIES
				obj.Name,
				obj.CanCollide,
				obj.CFrame.X,
				obj.CFrame.Y,
				obj.CFrame.Z,
				obj.Orientation.X,
				obj.Orientation.Y,
				obj.Orientation.Z,
				obj.Anchored,
				obj.Size.X,
				obj.Size.Y,
				obj.Size.Z,
				obj.Color.R,
				obj.Color.G,
				obj.Color.B,
				(string.match(tostring(workspace.Baseplate.TopSurface), "%.(%w+)$")),
				(string.match(tostring(workspace.Baseplate.BottomSurface), "%.(%w+)$")),
				(string.match(tostring(workspace.Baseplate.LeftSurface), "%.(%w+)$")),
				(string.match(tostring(workspace.Baseplate.RightSurface), "%.(%w+)$")),
				(string.match(tostring(workspace.Baseplate.BackSurface), "%.(%w+)$")),
				(string.match(tostring(workspace.Baseplate.FrontSurface), "%.(%w+)$")),
				obj.Transparency,
				obj.Reflectance,
				string.match(tostring(obj.Material), "%.(%w+)$")
			})


			local success, err
			repeat
				success, err = pcall(function()
					autoSavingStore:SetAsync(key, data)
				end)

				task.wait()
			until success

			if not success then
				warn(tostring(err))
			end
		end
	end
end
local function load(player: Player)
	local key = keyPrefix .. tostring(player.UserId)
	local success, err
	local data

	repeat
		success,err = pcall(function()
			data = autoSavingStore:GetAsync(key)
		end)
	until success or not players:FindFirstChild(player.Name)

	if not data then return end
	if success then
		for i, obj in ipairs(data) do
			local partInstance = Instance.new("Part")
			partInstance.Name=obj[1]
			partInstance.CanCollide=obj[2]
			partInstance.CFrame = CFrame.new(obj[3], obj[4], obj[5])
			partInstance.CFrame *= CFrame.Angles(math.rad(obj[6]),math.rad(obj[7]),math.rad(obj[8]))
			partInstance.Anchored=obj[9]
			partInstance.Size = Vector3.new(obj[10], obj[11], obj[12])
			partInstance.Color = Color3.new(obj[13],obj[14],obj[15])
			partInstance.TopSurface = Enum.SurfaceType[obj[16]]
			partInstance.BottomSurface = Enum.SurfaceType[obj[17]]
			partInstance.LeftSurface = Enum.SurfaceType[obj[18]]
			partInstance.RightSurface = Enum.SurfaceType[obj[19]]
			partInstance.BackSurface = Enum.SurfaceType[obj[20]]
			partInstance.FrontSurface = Enum.SurfaceType[obj[21]]
			partInstance.Transparency = obj[22]
			partInstance.Reflectance = obj[23]
			partInstance.Material = Enum.Material[obj[24]]
		end
	else
		warn(tostring(err))
	end
end

players.PlayerAdded:Connect(load)
players.PlayerRemoving:Connect(save)
game:BindToClose(function()
	for i, plr: Player in ipairs(players:GetPlayers()) do
		save(plr)
	end
end)

Some people mentioned data serialization with JSONEncode & JSONDecode which might be a good practise but imo it makes data harder to manipulate and may fail.
Hope that helps! :pray:t2:

1 Like

thank you so muchhhh, this is worked just like what i wanted!

1 Like

one question tho, how do i detect if the part have a decal so i add its options too

You could do:

if part:FindFirstChildWhichIsA("Decal") then
    local decal = part:FindFirstChildWhichIsA("Decal")
    -- save decal --
end

I’d advice you to create a recursive function that serializes the properties into a table outside of the SaveData func, so basically, you’re executing that serialize func on an instance which runs itself on all of the instance’s children and so on until you reach the end.

1 Like