Trying to implement saving into Zblock's Placement System but I cant seem to do it

What do you mean with what code I used?

what code u put to save? the script?

You actually can save instances with datastore. However this is deemed very unnecessary since datastores has limits. So that is why it is good practice to only save the positions (…for instance).

I used
saveStore:SetAsync(Scope, Data)

Whole script:

local DSService = game:GetService("DataStoreService")
local saveStore = DSService:GetDataStore('saveStore_003')
local SavingModule = require(game.ReplicatedStorage.Modules.SavingModule)
local HTTP = game:GetService("HttpService")

game.Players.PlayerAdded:Connect(function(Player)
	local Scope = 'id-'..Player.userId
	
	local Data = SavingModule.Serialize()
	
	local GetSaved = saveStore:GetAsync(Scope)
	if GetSaved then
		print(GetSaved[1])
		SavingModule.deSerialize(workspace.Plots.Plot, GetSaved[1])
	else
		saveStore:SetAsync(Scope, Data)
	end
end)

game.Players.PlayerRemoving:Connect(function(Player)
	local Scope = 'id-'..Player.userId
	
	local Data = SavingModule.Serialize()
	print(Data)
	saveStore:SetAsync(Scope, Data)
	
end)

i don’t see where u save the data, and i don’t what the things in module does

A similar thread has been posted on the forum. I recommend checking out datastore 2, it is easy to comprehend and the module itself is very versatile. And since you’re probably making a building-system you’d need a lot of compression in your data so again, I refer back to the datastore 2 system, give it a try.

What I caught you doing in your serialization function is that you stored your keys as string indexes which is BAD PRACTICE!

Yours is the equivalency of this:
mytable = {
[“randomString”] = blah
}

Instead you should actually be doing this:

myTable = {
[1] = blah
}

So,

I tried another approach. I basically have the same system but as you mentioned I use Datastore 2.

But I changed up the Deserialization and Serialization Function:

local M = {}


function encode_cframe(cf)
    return string.format(string.rep("%f ",12), cf:components())
end

function decode_cframe(cf)
    local tab = {}
    for s in string.gmatch(cf, "%d+") do
        table.insert(tab,tonumber(cf))
    end
    return CFrame.new(unpack(tab))
end

function M.Serialize()
	local serial = {}
	
	local ItemHolder = workspace.Plots.Plot.ItemHolder
	
	for i,v in pairs(ItemHolder:GetChildren()) do
		serial[v.Name] = encode_cframe(v.PrimaryPart.CFrame)
	end
	return serial
end

function M.deSerialize(canvasPart, data)
	data = data or {}
	for i,v in pairs(data) do
		local CF = v
		local modelName = i
		
		print(modelName)
		
		if game.ReplicatedStorage.Models:FindFirstChild(modelName) then
			local newModel = game.ReplicatedStorage.Models:FindFirstChild(modelName):Clone()
			newModel.Parent = canvasPart.ItemHolder
			newModel:SetPrimaryPartCFrame(CF)
		end
	end
end

return M

Problem is that I can not save CFrame’s so I tried encoding it into a number and then when I want to load it I would decode it. But when I try to decode it, it returns 0,0,0 etc

So I removed the Decoding thing into deSerialize and because of the way I encoded it the CFrame is normal but with no commas so it’s not a real CFrame

So I try playing it but it returns this error because it’s not a real CFrame:
[21:40:58.770 - Unable to cast string to CoordinateFrame

How would I make a better function to encode and decode cframe to convert a cframe into a string and a string into a cframe?

Edit: Spelling Errors

As @NicholasY4815 said, you need to save each individual number.

nameOfCFrame = {
   x = CFrame.x,
   y = CFrame.y,
   z = CFrame.z,
   -- Any other values
}

Yeah but how do I link those CFrame values to an Object?

And what do I do when I need to load it?

Not the case. You can’t save unserialised instances to DataStores because the service does not support userdata in the first place. It’s only meant to store pure data (strings, numbers and tables) which are coerced into a JSON format under the hood. Roblox datatypes and classes cannot be converted back and forth from a JSON format and even if they could, it could result in unexpected behaviour (e.g. lost metatable).

Nothing to say they can’t just implement serialisation to achieve what Save/LoadInstance did but that’d eat up the space you’re given, so its not worth the jump especially when you can “save instances” in just a few letters and numbers.

When I JSON encode the dictionary and I print it for debugging it returns:
{“Table”:22.38999176025390625,“Chair”:5.1999912261962890625}

I did CFrame:GetComponents()

And it seems that I do not get the full CFrame.

And If I remove :GetComponents() then it returns as null:
{“Table”:null,“Chair”:null}

That’s possible because GetComponents returns the values that make up the CFrame and this is a legal format for DataStores. You aren’t working in terms of the CFrame, you’re working in terms of the values that make it up.

As for why you aren’t getting all the components, values may be getting dropped. Its best to print out the entire return of GetComponents, iterative or not, to check if the formats you’re attempting to work with are legal for JSON.

1 Like

Alright, So I printed out the entire return of GetComponents and I get:

22.389991760254 2.1449809074402 1.4000090360641 1 0 0 0 1 0 0 0 1

Using this:

nameOfCFrame = {
x = CFrame.x,
y = CFrame.y,
z = CFrame.z,
-- Any other values
}

I believe you could just do:

CFrame.new(nameOfCFrame.x,nameOfCFrame.y,nameOfCFrame.z,any other values) 

This would be for when you want to turn the data back into a CFrame to be used and set the CFrame of whichever model is needed.

Yeah but how would I link the CFrame values with the actual model I want to load in?

Well if you have a Primary Part on the model:
Model:SetPrimaryPartCFrame(CFrameValue)

No not that, when saving the CFrame values in a seperate dictionary how do I know which CFrame corresponds to the right model when I want to load it?

Sorry, I didn’t understand. You could do this:

nameOfCFrame = {
    ModelName = Model.Name
    x = CFrame.x,
    y = CFrame.y,
    z = CFrame.z,
    -- Any other values
}

then when loading:

local Model = WhereYouKeepTheModels:FindFirstChild(nameOfCFrame.ModelName)
local NewCFrame = CFrame.new(nameOfCFrame.x,nameOfCFrame.y,nameOfCFrame.z,any other values) 
Model:SetPrimaryPartCFrame(NewCFrame)

I understand you withdrew your post but I just wanted to clarify.

My example would be used in a system such as this where you would loop through all the models currently added.

 Table[1] = {
    ModelName = Model.Name
    x = CFrame.x,
    y = CFrame.y,
    z = CFrame.z,
    -- Any other values
}

Then Table[2] would be model 2.

Anyway hope this helps! :+1:

1 Like

Sorry I am new to Dictionaries and CFrames.

I also want to store rotations and I can’t just get it from X,Y,Z
So how would I write the rotation values from CFrame into the dictionary.