Datastoring a Plot

What I’m trying to achieve

  • A user spawns in with a plot (tycoon like)
  • The user can place objects on the plot, etc…

I’m trying to achieve a system where the data will save using tables. I have a current method to save the plot but its not all that good. I feel as if it could be improved tons!


What is the issue?

The issue currently is it being inefficent and doesn’t work 10% of the time. I’m wondering if someone could help or explain to me better on how I could use a table to save the data of these objects. Each object should load in on the position based off where there plot is (as it changes per server) How should I go about loading in the data and saving the positions?


What solutions have you tried so far?

I have tried to save positions in tables and then load them in based off the centerpoint of the plot. Didn’t work so well for me.

3 Likes

Are you using a grid-like system? This might be very inefficient but did you think of labelling each time as an ID per plot and saving it as a table then converting it to JSON and storing it?

Example:

Plot_1_1 = {
"Wall",
"Painting"  = {
 X,
 Y,
}
},
Plot_1_2 = {
"Wall",
},
Plot_1_3 = {
"Wall"
}
-- The first number argument is X and the second number argument is Y for table keys.

Another method is storing their CFrame values and when the game loads using a method to illiterate the table. Have a set of items stored somewhere that is the same names as the IDs use :FindFirstChild in their storage folder to find the correct items. Use the CFRAME argument within the item table to find the correct position of the item. If your game requires each item to have a plot value that might be a problem but it can be solved using a method checking if an item is in an area.

Example:

Table = {
 CFRAME
 OTHER INFO
}
Wall = {
 CFRAME
 OTHER INFO
}
Chair = {
 CFRAME
 OTHER INFO
}

Game loads in:

game.Players.PlayerAdded:Connect(function(plr)
	local DataStore = DATASTORE HERE
	for name,tableObject in pairs(DataStore) do -- illiterate through the table
		if STORAGE:FindFirstChild(name) then -- Check if there is an item named after the ID
			local foundObject = STORAGE:FindFirstChild(name):Clone() -- Clone the correct item
			foundObject:SetPrimaryPartCFrame(tableObject[1]) -- Set the model position. If it is a part only replace it with .CFrame
			-- If anything is required put it here
		end
	end
end)

Hope that gives you some methods to use

How are you saving item and position data?

And what does your code look like? We can tell you why it’s not working if we don’t even know how you’re doing it.

I deleted it due to my stupidity, I’m rewriting it now but it’s not going so well.

for i,v in pairs(TycoonValue.Value.Bin:GetChildren()) do
		local XPos = TycoonValue.Value.TycoonBaseplate.CFrame:inverse().X * v:GetPrimaryPartCFrame().X
		local YPos = TycoonValue.Value.TycoonBaseplate.CFrame:inverse().Y * v:GetPrimaryPartCFrame().Y
		local ZPos = TycoonValue.Value.TycoonBaseplate.CFrame:inverse().Z * v:GetPrimaryPartCFrame().Z
		ServerData[plr].TycoonPlacements[v.Name.."-"..i] = {
			['X'] = XPos;
			['Y'] = YPos;
			['Z'] = ZPos;
		} --TycoonValue.Value.TycoonBaseplate.CFrame:inverse() * v:GetPrimaryPartCFrame()
	end

This is saving the plot items, I haven’t wrote the loading yet.

1 Like

For my sandbox game which has really good/efficient saving, I use the CFrame methods: toWorldSpace and toObjectSpace

1 Like

First of all, good luck with your project!

If you have a primary part for all placeables, you can get those placeables’ primary part position by a basic CFrame formula. If I remember it right, it should be
Plot.CFrame:inverse() * Object.PrimaryPart.CFrame
and it basically subtracts plot CFrame from object PP CFrame. You also can use xuefei’s suggested methods.

Saving every placeable to a folder will give you chance to form a table easily. Like…

local SavingTable = {}
for i,v in pairs(Placed:GetChildren()) do
    local SavingCF = Plot.CFrame:inverse() * v.PrimaryPart.CFrame
    table.insert(SavingTable, {SavingCF, ItemID, ...})
end

Finally, use JsonEncode to turn SavingTable into a string as iRexBot suggested because you can’t save MetaTables(Tables inside tables).

3 Likes

Having the exact same issue with my sandbox tycoon, any help will be greatly appreciated.

This might be of use: Loading a Model's CFrame at the right Baseplate

1 Like

I did the method you said (which was brilliant by the way), I’m not sure why this is happening.

The console outputs that. The top string of numbers is the “SavingCF”

for i,v in pairs(TycoonValue.Value.Bin:GetChildren()) do
	local SavingCF = TycoonValue.Value.TycoonBaseplate.CFrame:inverse() * v.PrimaryPart.CFrame
	print(SavingCF)
	table.insert(ServerData[plr].TycoonPlacements, {SavingCF, ItemData.Objects[v.Name][7]})
end
local EncodedData = HttpService:JSONEncode(ServerData[plr])
print(EncodedData)

Take a look at the method I sent, its pretty easy to implement and worked for me.

Oh that’s a bit confusing :confused:
To be honest I never used this method. Maybe it is not possible to encode CFrame? In this case, you could save position and rotation instead of CFrame itself. Also feel free to use grilme’s method too, if it would be easier for you :slightly_smiling_face:

The second baseplate is where I orginally placed the chairs, then I got the one closer to the camera and the chairs went wild, not even on a baseplate.

for i,v in pairs(ServerData[plr].TycoonPlacements) do
		local CFramePosition = CFrame.new(unpack(v.Position))* CFrame.new(TycoonValue.Value.TycoonBaseplate.CFrame:components())
		local GenerateObject = Items:FindFirstChild(v.ObjName):Clone()
		GenerateObject.Parent = TycoonValue.Value.Bin
		GenerateObject:SetPrimaryPartCFrame(CFramePosition)
	end

Hmm, not sure. Take a look at the post I sent (Loading a Model's CFrame at the right Baseplate) the person on there managed to fix it.

Thats what I looked at?

Hmm, I don’t know. Is the code you posted for loading? What code do you use to save?

Here is loading

for i,v in pairs(ServerData[plr].TycoonPlacements) do
	local CFramePosition = CFrame.new(unpack(v.Position))* CFrame.new(TycoonValue.Value.TycoonBaseplate.CFrame:components())
	local GenerateObject = Items:FindFirstChild(v.ObjName):Clone()
	GenerateObject.Parent = TycoonValue.Value.Bin
	GenerateObject:SetPrimaryPartCFrame(CFramePosition)
end

And saving

for i,v in pairs(TycoonValue.Value.Bin:GetChildren()) do
	local SavingCF = {(v.PrimaryPart.CFrame * TycoonValue.Value.TycoonBaseplate.CFrame:Inverse()):components()}
	--print(SavingCF)
	table.insert(ServerData[plr].TycoonPlacements, {Position = SavingCF, ObjName = ItemData.Objects[v.Name][1]})
end

It spreads them out a ton, some not even near the baseplates.

1 Like

Hmm, not to sure.

@Tiffblocks do you have any insight into why it’s not working, since you came up with the method that @Jamie_Jr is trying to implement?

You said you implemented this method yourself. Do you see anything wrong with what I did?

No I implemented the method the Tiffblocks said in the post I sent, I can’t see anything wrong with it, wait for Tiff to reply because she will probably know.

I built a game in 2015 that allowed users to build on a plot, which they could save. I don’t think the saving itself works anymore, as I’m sure it used the old data persistence methods (e.g. Player:SaveString(), Player:LoadString()), but the actual packaging of plot data should still work.

I’ve just taken a look back at the code, and I’m pretty sure I could do much better now, but nevertheless, it may be of some help. See the attached place file.

Construct.rbxl (86.4 KB)