Saving a Island with potentially thousands of blocks

How could I make a datastore that saves a folder (more like several folders)
and loads it back in properly when rejoined without having to use a third party datastore?
image

I’ve tried things like JSONEncoding/Decoding and just basic table saving but you need UTF-8 characters. When I tried it with JSONEncoding/Decoding it obviously said that it’s over the max limit of characters it can handle.

Here’s my current code:

local dss = game:GetService("DataStoreService"):GetDataStore("****")
local BaseData = game.Workspace.IslandFolder.TerrainParts.Grass
local BaseDataSaving = {}



game.Players.PlayerAdded:Connect(function(player)
	local GenerateTerrainUI = player.PlayerGui:WaitForChild("GenerateIslandUI").TerrainSettings.GenerateTerrain
	local success, err = pcall(function()
		return dss:GetAsync(player.UserId)
	end)
	if success then
		GenerateTerrainUI.Visible = false
		for i,v in pairs(err) do
			local GrassPart = Instance.new("Part", BaseData)
			GrassPart.Name = v.Name
			GrassPart.Size = v.Size
			GrassPart.Position = v.Position
		end
	else
		GenerateTerrainUI.Visible = true
		print(err)
	end
end)

game.Players.PlayerRemoving:Connect(function(player)
	for i,v in pairs(BaseData:GetChildren()) do
	local PartInfo = {
	["Name"] = v.Name;
	["Size"] = v.Size;
	["Position"] = v.Position
	}
	table.insert(BaseDataSaving,PartInfo)
end
dss:SetAsync(player.UserId, BaseDataSaving)
end)
1 Like

Obviously you can’t save that many part even with JSON in one datastore,
that’s why you have to seperate it and save it to multiple datastores,

For every single block you’re storing the strings “Name”, “Size” and “Position”, as well as whatever v.Name is. To save a string you need 1 byte per character. This is incredibly wasteful. Instead of the name, store the “block type” as an integer. With just 1 byte you can then save 2^8 = 256 different block types. You don’t need to have the keys be strings either, you just need the first value to be the name, second value to be the size and third value to be the position.

You can read more about that on this post: Stravant's BitBuffer Module - Compact Storage Of Data [Tutorial]

2 Likes

Thank you, I’ll try to look into this!

personally I would make a system of varying number and according to the number some thing are different but I do not advise you to do it like that

All you need to save is a number and a serialized cframe. The number will represent the block type and the size. You can make a table that matches each number to their block type like this:

local items = {blockType1Size1, blockType1Size2, blockType2Size1}  -- etc
-- and then access it like this:

local block = items[3] -- example number
-- which is the key of the actual block in the items table

Then you have to save the CFrame. The easiest (not the best) way to do this is to add the components to a table like this:

local serialized = {cframe:GetComponents()}
-- turn it back into a cframe:
CFrame.new(table.unpack(serialized))

If you’re not rotating any of the blocks and you only need a position instead of a CFrame, you can use a Vector3 instead. Use Vector3 if you can because it takes up less data (it’s 3 numbers instead of 12 in the table).

local serialized = {vector.X, vector.Y, vector.Z}
-- turn it back into a Vector3:
Vector3.new(table.unpack(serialized))

To save the part’s full data, you can make the key the type in the final table and the value the serialized position/cframe. In this example i’ll use position (Vector3).

local items = {name1Size1, name2Size2, name3Size1} 
local savedObjects = {}

for _, part in ipairs(partfolder:GetChildren()) do
    -- if all blocks are cubes then x = y = z so you only need x
    local index = table.find(items, part.Name .. "Size" .. part.Size.X)
    savedObjects[index] = {part.Position.X, part.Position.Y, part.Position.Z}
end

-- then to deserialize:
for i, position in pairs(savedObjects) do
    local name = items[i]

    local block = blahblahgetblockfromname(name):Clone()
    block.Position = Vector3.new(table.unpack(position))
    block.Parent = partfolder
end