Serializing
The solution to transmitting or compacting any incompatible data is known as serialization. Likewise, the receiving or unpacking of any serialized data is known as deserialization.
For a better idea, say I want to drop a 5x5x5 ice cube into a 1x1 square hole. I can serialize the ice cube by converting it back into it's liquid form (water), and the water will easily flow right through the 1x1 opening. I can then deserialize the water by freezing it back into a 5x5x5 ice cube once it's on the other side, and I've successfully transmitted data that we otherwise wouldn't be able to!
Applying this to ROBLOX and data store
Every instance of CFrame comes in the data type of userdata. It's important to know that when saving data to data store, it's not as simple as just passing it from point A to point B as you would arguments to a function. These incompatible data types need to be properly encoded before being transmitted.
The only data types that don't need to be encoded before they're sent off to ROBLOX's backend, are strings and integers. Now you're probably thinking, "then why are we able to save tables?". This is because ROBLOX actually encodes the table (to a string value) before it's sent off to their data storage. The encoding format they use to do this is known as JavaScript Object Notation (or JSON), which is quite popular. I'll leave you some more information on JSON here if you're interested.
Solution
Alright, hopefully I didn't bore you too much with all that information. On to the fun part, implementing all of this in code. Now just like I said before, the only data that can actually be saved to data store are strings and integers. So how can we save other data types...? By converting them into strings or integers!
Sometimes serializing data can be a real pain, because it may not have many descriptive attributes. Luckily for us, encoding and decoding a CFrame is very easy! We can utilize a function called components which we can call as a method on a CFrame instance that returns all the information about the CFrame as it's unpacked matrix! Here's an example.
local function encodeCFrame(cf)
return {cf:components()}
end
This now converts the CFrame data into a table, which is automatically encoded by ROBLOX. You'll now be able to save this CFrame value once it's been passed through this function. All that's left is decoding, which is equally simplistic!
local function decodeCFrame(cf)
return CFrame.new(unpack(cf))
end
Combining this together to create a save and load system, would yield something like this:
local DataStore = game:GetService("DataStoreService")
local storage = DataStore:GetDataStore("Test")
local function encodeCFrame(cf)
return {cf:components()}
end
local function decodeCFrame(cf)
return CFrame.new(unpack(cf))
end
local myCFrame = CFrame.new(1, 5, 1) * CFrame.Angles(0, math.pi, 0)
storage:SetAsync("CFrame", encodeCFrame(myCFrame))
print(storage:GetAsync("CFrame"))
Hope I didn't go overboard on explanation, but there it is. If you have any questions, feel free to write a comment and let me know.
Edit for future readers
It came to my attention that I forgot to mention booleans! Boolean values (like strings, and integers), also do not need to be encoded to be saved directly to data store. The same goes for nil values as well, although it's (still) equivalent to nothing.
1 comment
Next time search google first; this has been answered before.