I want to save the data of all the models in a specific location in the workspace. For this, I use a table which saves the name of the model and the CFrame of the PrimaryPart.
However, when I try this out, I get the following error:
18:57:32.884 - 104: Cannot store Array in data store. Data stores can only accept valid UTF-8 characters.
Is there any way to save this information, or in what other way can I get the information that determines the right model and its location in the model inside the workspace?
This is the script I use, a Script in a TextButton:
local clicked = false
script.Parent.MouseButton1Click:Connect(function()
if clicked == false then
clicked = true
local ds = game:GetService("DataStoreService"):GetDataStore("ItemsStorage")
local player = game.Players:FindFirstChild(script.Parent.Parent.Parent.Parent.Parent.Name)
local data = {}
local items = workspace.Base.ItemHolder:GetChildren()
local progressBar = script.Parent.Parent.ProgressBar
local button = script.Parent
progressBar.Visible = true
for i = 1, #items do
local item = items[i]
local mainPart = item.PrimaryPart
table.insert(data, item.Name)
wait()
table.insert(data, mainPart.CFrame)
wait()
progressBar.ProgressFrame.Size = UDim2.new(((1 / #items) * i), 0, 1, 0)
end
progressBar.ProgressFrame.Size = UDim2.new(1, 0, 1, 0)
ds:SetAsync(player.UserId, data)
progressBar.Message.Text = "Saved successfully!"
wait(2)
progressBar.Message.Text = ""
progressBar.Visible = false
for i = 30, 0, -1 do -- add a wait time to only be able to save every 30 seconds
button.Text = i
wait(1)
end
button.Text = "Save"
clicked = false
end
end)
CFrames are not saveable, you’ll need to serialize it.
I’d preferably save it’s Position and LookVector in individual arrays in a dictionary.
For example:
local MyCFrame = CFrame.new(Vector3.new(1,2,3), Vector3.new(3,2,1))
local MyPosition = MyCFrame.Position
local MyLookVector = MyCFrame.LookVector
local CFrameData = {
Position = {MyPosition.X, MyPosition.Y, MyPosition.Z};
LookVector = {MyLookVector.X, MyLookVector.Y, MyLookVector.Z};
}
--// Now you can save it
DataStore:SetAsync("key", CFrameData)
--// And get it
local Data = DataStore:GetAsync("key")
--// Yet also reconstruct it
local MyCFrame = CFrame.new(Vector3.new(unpack(Data.Position)), Vector3.new(unpack(Data.LookVector)))
FYI: I’d recommend that you use a LocalScript for listening on MouseButton1Click and integrate a RemoteEvent with a debounce - otherwise if a player spam clicked, they could continously cause the server to save their data.
Okay so… I think I’ve been able to follow your steps, and I’ve got 2 buttons with scripts now, one to save and one to load. I’ll show them right here.
Save:
local clicked = false
script.Parent.MouseButton1Click:Connect(function()
if clicked == false then
clicked = true
local ds = game:GetService("DataStoreService"):GetDataStore("ItemsStorage")
local player = game.Players:FindFirstChild(script.Parent.Parent.Parent.Parent.Parent.Name)
local data = {}
local items = workspace.Base.ItemHolder:GetChildren()
local progressBar = script.Parent.Parent.ProgressBar
local button = script.Parent
progressBar.Visible = true
for i = 1, #items do
local item = items[i]
local mainPart = item.PrimaryPart
local mainCFrame = mainPart.CFrame
local mainPos = mainCFrame.Position
local mainLookVector = mainCFrame.LookVector
local CFrameData = {
Position = {mainPos.X, mainPos.Y, mainPos.Z};
LookVector = {mainLookVector.X, mainLookVector.Y, mainLookVector.Z};
}
table.insert(data, item.Name)
wait()
table.insert(data, CFrameData)
wait()
progressBar.ProgressFrame.Size = UDim2.new(((1 / #items) * i), 0, 1, 0)
end
progressBar.ProgressFrame.Size = UDim2.new(1, 0, 1, 0)
ds:SetAsync(player.UserId, data)
progressBar.Message.Text = "Saved successfully!"
wait(2)
progressBar.Message.Text = ""
progressBar.Visible = false
for i = 30, 0, -1 do
button.Text = i
wait(1)
end
button.Text = "Save"
clicked = false
end
end)
Load script:
local clicked = false
script.Parent.MouseButton1Click:Connect(function()
if clicked == false then
clicked = true
local ds = game:GetService("DataStoreService"):GetDataStore("ItemsStorage")
local player = game.Players:FindFirstChild(script.Parent.Parent.Parent.Parent.Parent.Name)
local data = {}
local progressBar = script.Parent.Parent.ProgressBar
local button = script.Parent
progressBar.Visible = true
data = ds:GetAsync(player.UserId)
for i = 1, #data, 2 do
wait(1)
local item = data[i]
local model = game.ReplicatedStorage.Items:FindFirstChild(item):Clone() -- I forgot the = here
model.Parent = workspace
local mainCFrame = CFrame.new(Vector3.new(unpack(data[i + 1].Position)), Vector3.new(unpack(data[i + 1].LookVector)))
model.PrimaryPart.CFrame = mainCFrame
end
clicked = false
end
end)
Is there any way you can think of that fixes this? The mainpart in each model rotates as well when you rotate the model, so I wouldn’t know how it could be rotated like this.