Hello! Ive recently been trying to make a system that saves peoples builds. The problem is the person can change their location. What I did was make each plot have the sam x and y but add a z. So for example plot 1 z: 120 plot 2 z 220 etc. I need some help with calculating this change i tried doing this but it sort of worked but not well. Peoples plots got seperated.

The variable “Pos” is the persons new position

tonumber(split[3]) is his old position

‘’’
local maths = nil

if pos >= tonumber(split[3]) then
maths = pos-tonumber(split[3])
if maths >= 99 then
else
maths = 0
end
print("changes add".. maths)
elseif pos <= tonumber(split[3]) then
maths = tonumber(split[3])-pos
if maths >= 99 then
else
maths = 0
end
print("changes subtract".. maths)
elseif pos == tonumber(split[3]) then
print("no changed need")
maths = 0
end
local position2 = Vector3.new(tonumber(split[1]), tonumber(split[2]), tonumber(split[3])+maths)
local position1 = Vector3.new(tonumber(split[1]), tonumber(split[2]), tonumber(split[3])-maths)
local orien = Vector3.new(tonumber(split[5]), tonumber(split[6]), tonumber(split[7]))
if maths >= 0 then
clone:SetPrimaryPartCFrame(CFrame.new(position2) * CFrame.Angles(math.rad(orien.X), math.rad(orien.Y), math.rad(orien.Z)))
else
clone:SetPrimaryPartCFrame(CFrame.new(position1) * CFrame.Angles(math.rad(orien.X), math.rad(orien.Y), math.rad(orien.Z)))
end

I’m not too sure what you’re asking here. Are you trying to make objects load proportionally to the plot’s CFrame, regardless of the plot’s CFrame?

I think a better approach would be to learn about object and world space. When saving, get each objects’ CFrame in the plot’s object space, use this relative vector/CFrame to save to the data store. Then when loading, translate this back into world space using the new plot’s CFrame. This will handle all cases, such as plot position changes, as well as plot rotation changes.

local plot = path.to.plot -- your plot (a part)
-- for saving,
local plotData = {}
for _, object in plot:GetDescendants() do -- let's say each descendant of the plot is a part
local relativeCFrame = plot.CFrame:ToObjectSpace(object.CFrame) -- this will be another cframe but will be relative to the plot's cframe
table.insert(plotData, {object.Name;relativeCFrame:GetComponents()} -- CFrame:GetComponents() will be 12 numbers, there are better ways to optimize how many components are saved but that's up to you to decide
end
-- for loading,
for _, objectInfo in data do
local objectName = objectInfo[1]
local objectModel = path.to.models:FindFirstChild(objectName):Clone()
table.remove(objectInfo, 1) -- we need to remove the object's name since we don't need it for creating the object's new CFrame
local objectCFrameRelative = CFrame.new(unpack(objectInfo))
local objectCFrameWorld = plot.CFrame:ToWorldSpace(objectCFrameRelative) -- translate it back to world space
objectModel.CFrame = objectCFrameWorld
objectModel.Parent = plot
end

Here is the code I created it just puts everything in the center of the base

split[1] = x

split[2] = y

split[3] = z

and pos posy posx you probably know x y z

‘’'local zDifference = pos - tonumber(split[3])

print(zDifference)
local xdifference = posx - tonumber(split[1])
print(xdifference)
local ydifference = posy - tonumber(split[2])
-- Define a threshold value (in studs) for whether to move the models or not
local threshold = 99
-- If the Z-axis difference is greater than or equal to the threshold, move the models
-- Otherwise, keep them at the same position
--local maths = zDifference >= threshold and zDifference or 0
-- Calculate the adjusted positions based on the Z-axis difference
local position2 = Vector3.new(tonumber(split[1])+xdifference, tonumber(split[2]), tonumber(split[3]) + zDifference)
-- Define the orientation of the model (you already have it in the split table)
local orien = Vector3.new(tonumber(split[5]), tonumber(split[6]), tonumber(split[7]))
clone:SetPrimaryPartCFrame(CFrame.new(position2) * CFrame.Angles(math.rad(orien.X), math.rad(orien.Y), math.rad(orien.Z)))

Sorry didn’t have time to go through this earlier.

You should just be able to call plot.CFrame:ToObjectSpace(otherPart.CFrame), then use that returned cframe’s components to be saved to the datastore. Then use clonedObject.CFrame = plot.CFrame:ToWorldSpace(savedCFrame) to translate it back to world space.

Ohhh So that means I first get the players plot and get it cframe by using plot.CFrame:ToObjectSpace(partsCFrame). So that moves the parts cframe to the Plots cframe and keeps it rotation and position. Also to do this we have to loop through all of the parts saved. I saved the position and orientation to the datastore so I can just convert that into a cframe. So I loop through the data in the datastore look for the part that got saved set its primarypartCFrame to plot.CFrame:ToWorldSpace(Part.PrimaryPart.CFrame) which in this case I made the primary part for all objects cover the entire model. So that would move the objects to the plot instead of moving the plot to the objects correct?

Im getting the error from this one: table.insert(tabletosave, tostring(base.CFrame:ToObjectSpace(CFrame.new(v.MainPart.CFrame.p).X))…" “…tostring(base.CFrame:ToObjectSpace(CFrame.new(v.MainPart.CFrame.p).Y))…” “…tostring(base.CFrame:ToObjectSpace(CFrame.new(v.MainPart.CFrame.p).X)) …” “…v.Name…” “…tostring(v.MainPart.Orientation.X)…” “…tostring(v.MainPart.Orientation.Y)…” "…tostring(v.MainPart.Orientation.Z))

Im not sure if the other one works yet but do you think it does. Sorry im not really advanced in coding yet

Oh I see. :ToObjectSpace requires another CFrame so you need to just be doing local toBeSaved = base.CFrame:ToObjectSpace(v.MainPart.CFrame). Then you can use toBeSaved’s components to save it to your datastore

local base = path.to.base
for _, child in base:GetChildren() do
local relativeCFrame = base.CFrame:ToObjectSpace(child.CFrame)
-- do whatever you need with relativeCFrame to save it to the datastore
end

Not quite the same, you are creating too many CFrames and are trying to get numbers in object space which just won’t work since a single number cannot be translated from world to object and object to world space. An easier way to serialize that data would be to just do

local relativeCFrame = base.CFrame:ToObjectSpace(v.MainPart.CFrame) -- this is a CFrame, it contains both rotational and positional data relative to your plot
local pos = relativeCFrame.Position
local serializedPos = table.concat(pos.X, pos.Y, pos.Z, ' ')
local serializedOrientation = table.concat({relativeCFrame:ToOrientation()})
local serializedCFrame = serializedPos .. ' ' .. serializedOrientation

You should now be left with a string of 6 numbers separated by spaces (serializedCFrame) which you can insert into the data to be saved.

Then for deserializing,

local posX, posY, posZ, orientationX, orientationY, orientationZ = unpack(serializedString:split(' ')
local relativeCFrameFromStore = CFrame.new(posX, posY, posZ) * CFrame.fromOrientation(orientationX, orientationY, orientationZ)
-- now for loading
object:PivotTo(base.CFrame:ToWorldSpace(relativeCFrameFromStore))

Thank you so much! I used a method similar to what you wrote and it saved and loaded! Ill message you if anything else happens but it probably wont. Here is the code I used: