I am building a tycoon game, and the game has 6 plots. 3 of these plots are rotated by 180 degrees comparing to the other 3
The problem is, if you place an object on plot A, load into plot B,the object will flip by 180 degrees, but this will fix by reloading into plot B again.
However, when loaded into plot A again (after loading into B twice), the object will be flipped by 180 degrees, with the only way to reverse this being loading into plot B and into plot A again.
here is the code used for saving and loading objects
-- saving
for i, obj in ipairs(plot.BuildMat.itemHolder:GetChildren()) do -- gets all objects from the itemHolder folder, located inside the plot
table.insert(data, {
["name"] = obj.Name,
["transform"] = {
["x"] = plot.BuildMat.CFrame:ToObjectSpace(CFrame.new(obj.PrimaryPart.CFrame.p)).X;
["y"] = plot.BuildMat.CFrame:ToObjectSpace(CFrame.new(obj.PrimaryPart.CFrame.p)).Y;
["z"] = plot.BuildMat.CFrame:ToObjectSpace(CFrame.new(obj.PrimaryPart.CFrame.p)).Z;
["r"] = obj.PrimaryPart.Orientation.Y
--saves the object position, and y rotation
}
})
end
-- loading
for i, saved in ipairs(data) do -- get the objects from the DataStore
local loadedModel:Model = replicatedStorage.models:FindFirstChild(saved.name):Clone() -- most models dont differentiate from one another, so the model gets pulled from replicatedStorage.
if loadedModel then
loadedModel:PivotTo(plot.BuildMat.CFrame * CFrame.new(saved.transform.x, saved.transform.y, saved.transform.z) * CFrame.Angles(0, math.rad(saved.transform.r), 0))
loadedModel.Parent = plot.BuildMat.itemHolder
else
return
end
end
--plot.BuildMat is the plot itself. contains the itemHolder folder
--code has been simplified, all other things function perfectly fine.
the above code perfectly loads in the object position, however I do not quite understand how to save rotation into ObjectSpace.
I’m assuming you’re wanting to save the objects relative to the baseplate’s orientation? In that case, just save the offset between the baseplate’s orientation and the object’s orientation (same with position). Then on load, just set the object’s position and orientation relative to the baseplate’s position and orientation.
Although generally, with a grid placement system like The Sims, you’ll only need to save the grid position and object rotation without having to worry about any offsets as that can be calculated automatically.
so far, all my attempts to turn the rotation into ObjectSpace resulted in rotation reset. I am unsure of any other ways to fix this issue, but maybe ObjectSpace is not the best solution
also, the rotation is more similar to chillthrill709 - Build A Boat For Treasure, mixed with Welcome to Bloxburg, rather than The Sims. This is due to there being multiple plots, as its a multiplayer game.
Bloxburg was directly inspired by The Sims. My point was that type of building / object placement system.
You appear to be using math.rad a bit excessively. You only need to use math.rad when setting CFrame.Angles().
I’d give a better example, but I’m about to get off as it’s very late. If I remember to and you still need help, I’ll throw something together to better show what I’m talking about.
Okay so I threw this together. I’m still waking up so this is pretty garbage (plus you only need the one rotation axis that’s actually relevant, but here’s sort of what I meant):
Old Code (Ignore)
local httpService = game:GetService('HttpService')
local replicatedStorage = game:GetService('ReplicatedStorage')
local objects = replicatedStorage:WaitForChild('Housing Objects')
local plots = workspace:WaitForChild('Plots')
local plot1 = plots:WaitForChild('Plot 1')
local plot2 = plots:WaitForChild('Plot 2')
function OrientationToCFrame(orientation)
return CFrame.Angles(math.rad(orientation.X),math.rad(orientation.Y),math.rad(orientation.Z))
end
local ConvertVector3 = {}
function ConvertVector3:ToArray(vector3)
return {vector3.X,vector3.Y,vector3.Z}
end
function ConvertVector3:ToVector3(array)
return Vector3.new(array[1],array[2],array[3])
end
function SavePlot(plot)
local data = {}
data.Objects = {}
data.Orientation = ConvertVector3:ToArray(plot.Baseplate.Orientation)
for _,object in plot.Models:GetChildren() do
local temp = {}
temp.Name = object.Name
temp.Position = ConvertVector3:ToArray(object.PrimaryPart.Position-plot.Baseplate.Position)
temp.Orientation = ConvertVector3:ToArray(object.PrimaryPart.Orientation-plot.Baseplate.Orientation)
table.insert(data.Objects,temp)
end
return httpService:JSONEncode(data)
end
function LoadPlot(plot,data)
data = httpService:JSONDecode(data)
for _,object in data.Objects do
local temp = objects:FindFirstChild(object.Name)
if temp then
local model = temp:Clone()
model:PivotTo(plot.Baseplate.CFrame*CFrame.new(ConvertVector3:ToVector3(object.Position))*OrientationToCFrame(ConvertVector3:ToVector3(object.Orientation)))
model.Parent = plot.Models
model = nil
temp = nil
end
end
end
task.wait(3) --Just to let everything load for the test
LoadPlot(plot2,SavePlot(plot1))
I believe by making a plotcframe, you can use a module, and use Object:PivotTo(plotcframe*ObjectprimaryCframe). for example I do not know if i got it the cframes flipped inside hte brackets. but heres an example, for the object to be in the center of the plot its cframe would have to be like (0,0,0) and whenever the plotcframe is rotated so will the Object, because its primary cframe is the same.
Yes, that’s all there is to it. I used json to save all of the data as a string. But again, you can just save the Y axis (I think that’s the relevant rotation) for all of the offset stuff instead of the full Vector3s.
I placed my objects in the front-left corner of plot A.
when I reloaded into plot A (see below, step 1), everything works fine.
when I reloaded from A to B (step 2), it was fine at first, but then when I reloaded again from B to B (step 3), the objects that were in the front-left, are now in the back-right corner. reloading again (step 4) fixes this, but reloading for the 3rd (step 3 again) time puts the objects into back-right again. This only appears to be:
my apologies for making this the way it is, I find it easier to explain like this instead of studio screenshots
also forgot to mention that now, at least the rotation is generally the way its supposed to be, but the objects themselves get rotated as if the plot was 180 rotated (it wasnt)
Thank you MightyDantheman, i used some of your cde, with some of mine, and there are no problems now…
for all the people in the future who read this, here is what the new saving and loading code looks like
important stuff:
local players = game:GetService("Players")
local replicatedStorage = game:GetService("ReplicatedStorage")
local HttpService = game:GetService("HttpService")
local plotManager = require(script.Parent.ServerModules.PlotManager) - this assigns plots
local dataStoreService = game:GetService("DataStoreService")
local dataStore = dataStoreService:GetDataStore("BuildingSystemStore") - saves
local tries = 3
local dataloaded = nil
local objects = replicatedStorage:WaitForChild('models') - where the object template is saved
function OrientationToCFrame(orientation)
return CFrame.Angles(math.rad(orientation.X),math.rad(orientation.Y),math.rad(orientation.Z))
end
local ConvertVector3 = {}
function ConvertVector3:ToArray(vector3)
return {vector3.X,vector3.Y,vector3.Z}
end
function ConvertVector3:ToVector3(array)
return Vector3.new(array[1],array[2],array[3])
end
saving function:
function SavePlot(plot)
local data = {}
data.Objs = {}
data.Rotate = ConvertVector3:ToArray(plot.BuildMat.Orientation)
for _,object in plot.BuildMat.itemHolder:GetChildren() do
local temp = {}
temp.Name = object.Name
temp.Position = ConvertVector3:ToArray(Vector3.new(plot.BuildMat.CFrame:ToObjectSpace(CFrame.new(object.PrimaryPart.CFrame.p)).X, plot.BuildMat.CFrame:ToObjectSpace(CFrame.new(object.PrimaryPart.CFrame.p)).Y, plot.BuildMat.CFrame:ToObjectSpace(CFrame.new(object.PrimaryPart.CFrame.p)).Z))
temp.Orientation = ConvertVector3:ToArray(object.PrimaryPart.Orientation-plot.BuildMat.Orientation)
table.insert(data.Objs,temp)
end
return HttpService:JSONEncode(data)
end
load function:
function LoadPlot(plot,data)
if data == nil then
data = {}
end
data = HttpService:JSONDecode(data)
for _,object in data.Objs do
local temp = objects:FindFirstChild(object.Name)
if temp then
local model = temp:Clone()
model:PivotTo(plot.BuildMat.CFrame*CFrame.new(ConvertVector3:ToVector3(object.Position))*OrientationToCFrame(ConvertVector3:ToVector3(object.Orientation)))
model.Parent = plot.BuildMat.itemHolder
model = nil
temp = nil
end
end
end
the above functions have been provided by MightyDantheman
modified a little bit by me
To save:
local ToSet = SavePlot(plot) -- i have a module script that assigns plots when a user joins, and when requested, provides the path to that plot
local success, err
repeat
success, err = pcall(function()
dataStore:SetAsync(player.UserId, toSave)
end)
until success -- dont reccomend, as it might make too many requests. Implement your own feature here
to load:
local data
local success, err
repeat
success, err = pcall(function()
data = dataStore:GetAsync(player.UserId)
end)
until success
if data then
LoadPlot(plot, data) - again, specify your own plot info and data.
end
hope this helps anyone else thats making a tycoon game!
Sorry for the super late response. If your solution works, that’s great. I kinda forgot to apply the orientation from the baseplate and messed up the order a bit, but this is my updated code:
local httpService = game:GetService('HttpService')
local replicatedStorage = game:GetService('ReplicatedStorage')
local objects = replicatedStorage:WaitForChild('Housing Objects')
local plots = workspace:WaitForChild('Plots')
local plot1 = plots:WaitForChild('Plot 1')
local plot2 = plots:WaitForChild('Plot 2')
local plot3 = plots:WaitForChild('Plot 3')
function OrientationToCFrame(orientation)
return CFrame.Angles(math.rad(orientation.X),math.rad(orientation.Y),math.rad(orientation.Z))
end
local ConvertVector3 = {}
function ConvertVector3:ToArray(vector3)
return {vector3.X,vector3.Y,vector3.Z}
end
function ConvertVector3:ToVector3(array)
return Vector3.new(array[1],array[2],array[3])
end
function SavePlot(plot)
local data = {}
data.Objects = {}
data.Orientation = ConvertVector3:ToArray(plot.Baseplate.Orientation)
for _,object in plot.Models:GetChildren() do
local temp = {}
temp.Name = object.Name
temp.Position = ConvertVector3:ToArray(object.PrimaryPart.Position-plot.Baseplate.Position)
temp.Orientation = ConvertVector3:ToArray(object.PrimaryPart.Orientation)
table.insert(data.Objects,temp)
end
return httpService:JSONEncode(data)
end
function LoadPlot(plot,data)
data = httpService:JSONDecode(data)
for _,object in data.Objects do
local temp = objects:FindFirstChild(object.Name)
if temp then
local model = temp:Clone()
model:PivotTo(plot.Baseplate.CFrame*OrientationToCFrame(ConvertVector3:ToVector3(data.Orientation))*CFrame.new(ConvertVector3:ToVector3(object.Position))*OrientationToCFrame(ConvertVector3:ToVector3(object.Orientation)))
model.Parent = plot.Models
model = nil
temp = nil
end
end
end
task.wait(3)
local plot1Data = SavePlot(plot1)
LoadPlot(plot3,plot1Data)
local plot3Data = SavePlot(plot3)
plot1.Models:ClearAllChildren()
LoadPlot(plot1,plot3Data)
LoadPlot(plot2,plot3Data)