I have had a similar issue with trying to store cframes in datastores, and using HttpService:JSONEncode
and HttpService:JSONDecode
will not work on cframes. (I have tested this out don’t worry )
all datastore do is take a value and assign it to a variable in a datastore but he wants to store heap data in a data store but he cant do that by putting a table in a datastore so if he converts the table to a string then its valid data and it can be converted back to a table
what kind of data did u give it? can u give an example?
As a suggestion, could you please use punctuation? It makes sentences easier to read.
There is a difference between arrays and dictionaries, arrays don’t have keys, dictionaries do
-- array
{"hi", 1092, false}
-- dictionary
{coins = 1029, level = 52, message = "hi"}
-- another way to do it is like this
{["coins"] = 1029, ["level"] = 52, ["message"] = "hi"}
Edit: Some people have pointed out already, you can’t store CFrames in data stores, you will have to take the values of the CFrame and store it
I don’t remember, as it was a while back, but, Ima go ahead and edit this post, and ping you when I find out.
EDIT:
Here is what happens when I load a JSON
encoded cframe from a datastore:
…nil
… quite literally… nil
here is the code I use:
local dataStoreService = game:GetService("DataStoreService")
local dataStore = dataStoreService:GetDataStore("Idk")
game.Players.PlayerAdded:Connect(function(plr)
local key = "key-"..plr.UserId
local data
pcall(function()
data = dataStore:GetAsync(key)
end)
print(data)
if data then
print("Before JSON Decode: "..data)
local decoded = game:GetService("HttpService"):JSONDecode(data)
print("After JSON Decode: "..data)
end
end)
game.Players.PlayerRemoving:Connect(function(plr)
local key = "key-"..plr.UserId
local data = workspace.Baseplate.CFrame
print("Before JSON Encode: ")
print(data)
local encoded = game:GetService("HttpService"):JSONEncode(data)
print("After JSON Encode: ")
print(data)
pcall(function()
dataStore:SetAsync(key, data)
end)
end)
DataStores cannot store metatables such as CFrames, they can store dictionaries, but all keys must be strings, and the data contained must be a Lua datatype
These datatypes include:
- string
- number
- boolean
- array (as a dictionary with string or numeric keys)
The issue you are having is because you trying to store a CFrame as a value, which is not allowed in DataStores as this is a metatable object.
The best approach to saving a CFrame is to use a dictionary that hold the values of the CFrame, and then reconstruct the CFrame when it is next loaded
An example of this could be:
local SaveableCFrame = {X = CFrame.x, Y = CFrame.y, Z = CFrame.z ...}
Reconstruction involves taking the string keys and parsing them back into CFrame.new()
return CFrame.new(loadedData.X, loadedData.Y, loadedData.Z)
I need to save more than one CFrame in one table. I mean, player can place on his slot ten parts. And i need to save them all. How to do that?
for _, model in pairs(workspace.Slots:FindFirstChild(player.Name).Items:GetChildren()) do
local primaryPart = model.PrimaryPart
local pos = primaryPart.Position - base.Position
local dir = primaryPart.Orientation
local modelData = {
Name = model.Name,
Position = {X = pos.X, Y = pos.Y, Z = pos.Z},
Orientation = {X = dir.X, Y = dir.Y, Z = dir.Z}
}
models[#models + 1] = modelData
end
Assuming you make a table for each model/ item/ part, you could put the cframe data in each
table.
save a table that stores all of the components of the CFrame
{slot1 = {}, slot2 = {}, slot3 = {}}
and so on, you could then store the data in there, however, I recommend rounding the numbers, so there is less chance of hitting the 260 000 character limit.
Why would you need to store the exact position and rotation however? Compression is a very strong principle when dealing with DataStores
Avoid using CFrame directly when dealing with datastores, usually Position and Orientation will do the job just fine (which are easier to turn into dictionaries aswell), if you must have CFrame, using a constructor function along the lines of
CFrame.new(data.Position.X, data.Position.Y, data.Position.Z) * CFrame.fromOrientation(data.Rotation.X, data.Rotation.Y, data.Rotation.Z)
will turn the dictionary back into a CFrame
(you may want to run your rotation through math.rad() since CFrame stores rotation as radians, not degrees)
Can’t you just do something like this to save the data:
function cframeToTable(cf)
return {cf:GetComponents()};
end
function tableToCframe(t)
return CFrame.new(table.unpack(t));
end
-- Save the data
local tbl = {}
for i, v in pairs(parts:GetDescendants()) do -- Idk if I typed "Descendants" correctly. xD
table.insert(tbl, cframeToTable(v.CFrame))
end
-- Then use :SetAsync to save the data.
???
No, because this doesn’t have compression. You’d use a lot more data than you need.
Furthermore, does table.insert accept 1 argument?
Can anybody just rework my script for it’s work correctly?
local ds = game:GetService("DataStoreService")
local slotDs = ds:GetOrderedDataStore("Slot")
game.Players.PlayerAdded:Connect(function(plr)
local slot = workspace.Slots:FindFirstChild("EmptySlot")
slot.Name = plr.Name
slot.Owner.Value = plr
end)
game.Players.PlayerRemoving:Connect(function(plr)
savePlace(plr)
local slot = workspace.Slots:FindFirstChild(plr.Name)
slot.Name = "EmptySlot"
slot.Owner.Value = nil
end)
function savePlace(player)
local models = {}
local base = workspace.Slots:FindFirstChild(player.Name).PrimaryPart
for _, model in pairs(workspace.Slots:FindFirstChild(player.Name).Items:GetChildren()) do
local primaryPart = model.PrimaryPart
local pos = primaryPart.Position - base.Position
local dir = primaryPart.Orientation
local modelData = {
Name = model.Name,
Position = {X = pos.X, Y = pos.Y, Z = pos.Z},
Orientation = {X = dir.X, Y = dir.Y, Z = dir.Z}
}
models[#models + 1] = modelData
end
slotDs:SetAsync(player.UserId, models)
print('done')
end
You can only save positive integers in ordered data stores
My bad, I went ahead and updated the post, and fixed it.
Ok… xd
As a suggestion, you could use roblox studio to program stuff, to minimize chance of making mistakes.
I’m doing that rn and it’s much easier than using this chatbox.
I need to go so thank you all guys for helping me to solve this problem.
I’ll come back soon. So if somebody can please try to remake my script upper. Thank you.
Well, the thing I will change is this part
local slotDs = ds:GetOrderedDataStore("Slot")
OrderedDataStores can only store positive integers, it can’t store arrays or strings or anything except positive integers, so you should really be using a GlobalDataStore
local slotDs = ds:GetDataStore("Slot")
If i might ask, what is :GetOrderedDataStore for?