Too many water blocks on my 3D grid terrain system

  1. What do you want to achieve? Keep it simple and clear!
    I have a world generation system that generates a blocky world based on this table system its hard to explain. Its my first time making a terrain system like this.

  2. What is the issue? Include screenshots / videos if possible!
    What the issue here is I want water to generate and based on the system, Its a transparent material which generates other things around it. This leads to lots of water blocks being generated from large bodies of water. Im not sure how to make it so there is… Less water blocks. Like to combine them so that there is less water blocks but it still keeps its shape. Im not sure how to remotely start on something like this.

  1. What solutions have you tried so far? Did you look for solutions on the Developer Hub?
    As far as trying to find ways to even start this, Ive tried chat gpt. They were not too sure what they were dealing with though and ive tried searching for similar issues here but found nothing as far as i know. Now im trying to ask here.

After that, you should include more details if you have any. Try to make your topic as descriptive as possible, so that it’s easier for people to help you!

Ive put the code below so you can have a better idea of what your dealing with.

wait(6)

local Settings = {
	BlockSizes = 5,
	NoiseScale = 20,
}

local PerlinNoise = require(game.ServerScriptService.PerlinNoise)

function ChangeMessage(MessageText)
	for index,child in pairs (game.Players:GetChildren()) do
		if child:IsA("Player") then

			if child.PlayerGui:FindFirstChild("MessageGui") ~= nil then child.PlayerGui:FindFirstChild("MessageGui"):Destroy() end

			if MessageText ~= false and MessageText ~= nil then
				local gui = script.MessageGui:Clone()
				gui.Parent = child.PlayerGui
				gui.TextLabel.Text = MessageText
				gui.Enabled = true
			end

		end
	end
end

script.Parent.Loaded.Value = false

local findexistingworld = game.Workspace:FindFirstChild("Tfolder")
if findexistingworld ~= nil then
	findexistingworld:Destroy()
end

for _,v in pairs (script.Parent.Terrain:GetChildren()) do
	if v:IsA("BasePart") then
		v:Destroy()
	end
end

for _,v in pairs (script.Parent.Resources:GetChildren()) do
	if v:IsA("Model") then
		v:Destroy()
	end
end

for _,v in pairs (script.OreData:GetChildren()) do
	if v:IsA("ObjectValue") then
		v:Destroy()
	end
end

script.Parent.Baseplate.Position = Vector3.new(0, 10, 0)

local Blocks = game.Lighting.Blocks

local PrimePart = script.Parent.Baseplate

local worldsize = script.WorldSize.Value

local WorldDepth = script.WorldDepth.Value

local GroundDepth = script.GroundDepth.Value

local TotalWorldHight = GroundDepth + WorldDepth

local scripty = script

local terrainfolder = script.Parent.Terrain

local nodesFolder = script.Parent.Nodes

--local worldseed = script.WorldSeed.Value
local worldseed = math.random(1,1000000)

local HighestPoint = 0

local Base = script.Parent:FindFirstChild("Base")

if Base ~= nil then
	worldseed = game.Workspace.Ship.BasePlanetStats.WorldSeed.Value

	GroundDepth = game.Workspace.Ship.BasePlanetStats.GroundDepth.Value

	worldsize = game.Workspace.Ship.BasePlanetStats.WorldSize.Value

	WorldDepth = game.Workspace.Ship.BasePlanetStats.WorldDepth.Value
end
function GenerateOres()

	local ores = 0

	for _,child in pairs (scripty.Ores:GetChildren()) do
		if child:IsA("ObjectValue") then

			ores = ores + 1

			local oredata = Instance.new("ObjectValue")
			oredata.Name = child.Name
			oredata.Value = child.Value
			oredata.Parent = scripty.OreData

			local data1 = Instance.new("IntValue")
			data1.Name = "Rarity"
			data1.Value = child.Rarity.Value
			data1.Parent = oredata

			local data2 = Instance.new("IntValue")
			data2.Name = "Number"
			data2.Value = ores * 10000
			data2.Parent = oredata

		end
	end

end

GenerateOres()
ChangeMessage("Loading world...")
local Distance = 0

local pick = "SpawnSpot"

------Loading------
print("Starting main sequence")
----Generating grid----
print("Creating grid...")
local Grid = {}

for index = 1,worldsize do
	table.insert(Grid,{})--X
end

for index = 1,#Grid do
	local Xpos = Grid[index]
	for secondindex = 1,worldsize do
		table.insert(Xpos,{})--Z
	end
end

for index = 1,#Grid do
	local Xpos = Grid[index]
	for secondindex = 1,worldsize do
		local Zpos = Xpos[secondindex]
		for thirdindex = 1,TotalWorldHight do
			table.insert(Zpos,"")--Y. Also the spot the blocks are written
		end
	end
end
--print(Grid)
print("Finished creating grid.")
----Generating grid----

function FindBlockType(Xpos,Zpos,Ypos,LookingFor:string)
	local TargetLocation = Grid[Xpos][Zpos][Ypos]
	
	--print("Pos = "..Xpos..", "..Ypos..", "..Zpos)
	
	if Xpos > 1 and Zpos > 1 and Ypos > 0 and Xpos < worldsize and Zpos < worldsize and Ypos < TotalWorldHight then
		--print("Is within bounds")
		if Grid[Xpos][Zpos][Ypos+1] == LookingFor then--Up
			--print("Found "..LookingFor.."!")
			return true
		elseif Grid[Xpos][Zpos][Ypos-1] == LookingFor then--Down
			--print("Found "..LookingFor.."!")
			return true
		elseif Grid[Xpos][Zpos-1][Ypos] == LookingFor then--Back
			--print("Found "..LookingFor.."!")
			return true
		elseif Grid[Xpos][Zpos+1][Ypos] == LookingFor then--Forward
			--print("Found "..LookingFor.."!")
			return true
		elseif Grid[Xpos-1][Zpos][Ypos] == LookingFor then--Left
			--print("Found "..LookingFor.."!")
			return true
		elseif Grid[Xpos+1][Zpos][Ypos] == LookingFor then--Right
			--print("Found "..LookingFor.."!")
			return true
		end
	end
	return false
end

function IsEdgeBlock(Xpos,Zpos,Ypos)
	local TargetLocation = Grid[Xpos][Zpos][Ypos]

	--print("Pos = "..Xpos..", "..Ypos..", "..Zpos)
	
	local Edge = "None"
	local Limit = false
	
	if Xpos <= 1 then
		Edge = "Side"
		Limit = true
	elseif Zpos <= 1 then
		Edge = "Side"
		Limit = true
	elseif Ypos <= 1 then
		Edge = "Bottom"
		Limit = true
	elseif Xpos >= worldsize then
		Edge = "Side"
		Limit = true
	elseif Zpos >= worldsize then
		Edge = "Side"
		Limit = true
	elseif Ypos >= TotalWorldHight then
		Edge = "Top"
		Limit = true
	end
	
	return Limit, Edge
end

function IsExposedBlock(Xpos,Zpos,Ypos)
	if FindBlockType(Xpos,Zpos,Ypos,"Air") == true then
		return true
	elseif FindBlockType(Xpos,Zpos,Ypos,"Water") == true then
		return true
	end
	return false
end

----Writing grid data----
print("Starting writing world data sequence...")
--World height map--
print("Generating hight map...")
for Xpos = 1,#Grid do
	--print("X")
	local Xgrid = Grid[Xpos]
	for Zpos = 1,worldsize do
		--print("Z")
		--game:GetService("RunService").Heartbeat:Wait()
		local Zgrid = Xgrid[Zpos]
		for Ypos = 1,TotalWorldHight do
			--print("Y")
			local Ygrid = Zgrid[Ypos]
			--Stuff
			--wait(0.5)
			local perlinX = Xpos / Settings.NoiseScale
			local perlinZ = Zpos / Settings.NoiseScale
			local perlinY = Ypos / Settings.NoiseScale

			local noiseValue = math.noise(perlinX, worldseed, perlinZ) * WorldDepth
			
			--print("Noise = "..noiseValue)
			--print("Ypos = "..Ypos)
			if noiseValue > (Ypos - GroundDepth) then
				Zgrid[Ypos] = "Sand"
			elseif Ypos <= GroundDepth then
				Zgrid[Ypos] = "Water"
			else
				Zgrid[Ypos] = "Air"
			end

			--Stuff
		end
	end
end
print("Height map done.")
--World height map--

--Applying Perlin Worms--
print("Generating perlin worms...")
for Xpos = 1,#Grid do
	--print("X")
	local Xgrid = Grid[Xpos]
	for Zpos = 1,worldsize do
		--print("Z")
		--game:GetService("RunService").Heartbeat:Wait()
		local Zgrid = Xgrid[Zpos]
		for Ypos = 1,TotalWorldHight do
			--print("Y")
			local Ygrid = Zgrid[Ypos]
			--Stuff
			--wait(0.5)
			local perlinX = Xpos / Settings.NoiseScale
			local perlinZ = Zpos / Settings.NoiseScale
			local perlinY = Ypos / Settings.NoiseScale

			local noiseValue = math.noise(perlinX, perlinY, perlinZ)

			if noiseValue > 0.5 then
				Zgrid[Ypos] = "Air"
			end

			--Stuff
		end
	end
end
print("Perlin worms done.")
--Applying Perlin Worms--

--Adding world edges--
print("Applying world dedges...")
for Xpos = 1,#Grid do
	--print("X")
	local Xgrid = Grid[Xpos]
	for Zpos = 1,worldsize do
		--print("Z")
		--game:GetService("RunService").Heartbeat:Wait()
		local Zgrid = Xgrid[Zpos]
		for Ypos = 1,TotalWorldHight do
			--print("Y")
			local IsEdge, EdgeType = IsEdgeBlock(Xpos,Zpos,Ypos)
			if IsEdge == true then
				--print("Edge")
				Zgrid[Ypos] = "Bedrock"
			end
		end
	end
end
print("World edges done.")
--Adding world edges--

--print(Grid)
print("Writing world data done.")
----Writing grid data----

----Loading world from grid data----
print("Final generation...")
for Xpos = 1,#Grid do
	--print("X")
	game:GetService("RunService").Heartbeat:Wait()
	local Xgrid = Grid[Xpos]
	for Zpos = 1,worldsize do
		--print("Z")
		local Zgrid = Xgrid[Zpos]
		for Ypos = 1,TotalWorldHight do
			--print("Y")
			--warn("New line!")
			local DesiredBlock = Zgrid[Ypos]
			--local IsEdge, EdgeType = IsEdgeBlock(Xpos,Zpos,Ypos)
			if DesiredBlock ~= "Air" and IsExposedBlock(Xpos,Zpos,Ypos) == true then
				--print("Looking for block "..DesiredBlock)
				local block = Blocks:FindFirstChild(DesiredBlock):Clone()
				block.Parent = terrainfolder
				block.Size = Vector3.new(Settings.BlockSizes, Settings.BlockSizes, Settings.BlockSizes)
				block.Position = Vector3.new(Xpos, Ypos, Zpos) * Settings.BlockSizes
				block:SetAttribute("GridPos",Vector3.new(Xpos,Ypos,Zpos))
				Zgrid[Ypos] = "Updated"
			end
		end
	end
end
print("Final generation done.")
----Loading world from grid data----

----Spawning spawn----
part = Blocks:FindFirstChild(pick):Clone()
part.Parent = terrainfolder
part.Size = Vector3.new(10,10,10)
part.CanCollide = false
part.CFrame = PrimePart.CFrame * CFrame.new(0,TotalWorldHight,0)
part.Anchored = true
----Spawning spawn----

----Connecting to world changes----

local function UpdateBlock(Xpos,Zpos,Ypos)
	local DesiredBlock = Grid[Xpos][Zpos][Ypos]
	--local IsEdge, EdgeType = IsEdgeBlock(Xpos,Zpos,Ypos)
	if DesiredBlock ~= "Air" and DesiredBlock ~= "Updated" then
		--print("Looking for block "..DesiredBlock)
		local block = Blocks:FindFirstChild(DesiredBlock):Clone()
		block.Parent = terrainfolder
		block.Size = Vector3.new(Settings.BlockSizes, Settings.BlockSizes, Settings.BlockSizes)
		block.Position = Vector3.new(Xpos, Ypos, Zpos) * Settings.BlockSizes
		block:SetAttribute("GridPos",Vector3.new(Xpos,Ypos,Zpos))
		Grid[Xpos][Zpos][Ypos] = "Updated"
	end
end
	

terrainfolder.ChildRemoved:Connect(function(RemovedBlock)
	--print("Triggered!")
	local BlockPos:Vector3 = RemovedBlock:GetAttribute("GridPos")
	if BlockPos then
		--print("Activated!")
		local Xpos = BlockPos.X
		local Zpos = BlockPos.Z
		local Ypos = BlockPos.Y
		
		UpdateBlock(Xpos,Zpos,Ypos+1)--Up
		UpdateBlock(Xpos,Zpos,Ypos-1)--Down
		UpdateBlock(Xpos,Zpos-1,Ypos)--Back
		UpdateBlock(Xpos,Zpos+1,Ypos)--Forward
		UpdateBlock(Xpos-1,Zpos,Ypos)--Left
		UpdateBlock(Xpos+1,Zpos,Ypos)--Right
		
	end
end)
----Connecting to world changes----

print("Main sequence finished.")
------Loading------

print("World gen finished!")

Please do not ask people to write entire scripts or design entire systems for you. If you can’t answer the three questions above, you should probably pick a different category.

1 Like

It depends how you’re going about it, but here’s a generalized video for the concept:

I only did greedy meshing on the Y axis for mine.

2 Likes

Definitely looks exactly like something I’m looking for. I will give it a look and tell you about the results after.

1 Like

Might just be me but I cant figure this thing out. I keep getting weird drooping water… thingys… These.

1 Like

For every water block on the x and z axis, take the top water block and add half the block size to it, then take the bottom water block and subtract half the block size from it, then subtract the top number and the bottom number, and now you have the size that the part needs to be to fill that area on the Y axis. Then to position it correctly, just take the original top water block’s position and subtract half the new size from it.

2 Likes

I think I’m close but not quite right… Same result but less extreme. Sometimes math parts stump me but maybe you can tell me if I’m close or not and what I can do to make it correct.
This is the main changes I’ve added for now when trying to make something like this to work.

function GetRowOfBlocksOrSmt(Xpos,Zpos,Ypos,DesiredBlock:string)
	local RemainingBlocksAbove = TotalWorldHight - Ypos
	local NumberOfSameBlocks = 1--Including self
	for Index = 1,RemainingBlocksAbove do
		local CurrentBlock = Grid[Xpos][Zpos][Ypos+Index]
		if CurrentBlock == DesiredBlock then
			NumberOfSameBlocks = NumberOfSameBlocks + 1
			Grid[Xpos][Zpos][Ypos+Index] = "Updated"
		else
			break
		end
	end
	return NumberOfSameBlocks
end

----Loading world from grid data----
print("Final generation...")
for Xpos = 1,#Grid do
	--print("X")
	game:GetService("RunService").Heartbeat:Wait()
	local Xgrid = Grid[Xpos]
	for Zpos = 1,worldsize do
		--print("Z")
		local Zgrid = Xgrid[Zpos]
		for Ypos = 1,TotalWorldHight do
			--print("Y")
			--warn("New line!")
			local DesiredBlock = Zgrid[Ypos]
			--local IsEdge, EdgeType = IsEdgeBlock(Xpos,Zpos,Ypos)
			if DesiredBlock ~= "Air" and DesiredBlock ~= "Updated" and IsExposedBlock(Xpos,Zpos,Ypos) == true then
				--print("Looking for block "..DesiredBlock)
				if DesiredBlock == "Water" then
					local NumberOfSameBlocks = GetRowOfBlocksOrSmt(Xpos,Zpos,Ypos,DesiredBlock)
					local block = Blocks:FindFirstChild(DesiredBlock):Clone()
					block.Parent = terrainfolder
					block.Size = Vector3.new(Settings.BlockSizes, 1 + (NumberOfSameBlocks * Settings.BlockSizes) * 0.5, Settings.BlockSizes)
					block.Position = Vector3.new(Xpos, Ypos - (block.Size.Y)*0.5, Zpos) * Settings.BlockSizes
					block:SetAttribute("GridPos",Vector3.new(Xpos,Ypos,Zpos))
					Zgrid[Ypos] = "Updated"
				else
					local block = Blocks:FindFirstChild(DesiredBlock):Clone()
					block.Parent = terrainfolder
					block.Size = Vector3.new(Settings.BlockSizes, Settings.BlockSizes, Settings.BlockSizes)
					block.Position = Vector3.new(Xpos, Ypos, Zpos) * Settings.BlockSizes
					block:SetAttribute("GridPos",Vector3.new(Xpos,Ypos,Zpos))
					Zgrid[Ypos] = "Updated"
				end
			end
		end
	end
end
print("Final generation done.")
----Loading world from grid data----

1 Like

In your case, I would get the top water block by just getting the sea level height, and then the bottom block would be the Y height at that xz position + 1 block up.

I’m a bit too tired to read through any code right now, but I hope that helps.

1 Like

After a while I got a desirable result… Mostly threw random numbers at the problem until I got close but I used the other stuff as a baseline and im okay with the result I got.

Out of context, the game looks amazing! Keep it up!

Just make sure to test with other generation. If you got it working, it should be fine, but I ran into consistency issues in the past where it worked with one area of terrain but would have one random place that it didn’t work right in another area. Though that was regarding a different calculation.

Anyway, glad you were able to get it to work for you :+1:

What do I do if the solution stops working again? Am I able to re open the post or should I make a new one? Anyway what is happening is I redid the calculations to be able to work in three dimensions. For the most part it works but here and there is some inconsistencies like some of the blocks are in terrain and some are simply just not looking right. Its beyond me to figure out why its actually doing this.

local Blocks = game.Lighting.Blocks
local RaritySytem = require(script.RaritySystem)
local WeatherRarities = require(script.RaritySystem.WeatherRarities)
local WeatherGoal = RaritySytem.GetItem(WeatherRarities.Weather)

local biomes = {
	----Base biomes----
	--Full Humid--
	{name = "Snow", 
		tempCenter = -20, 
		humidityCenter = 100,
		SurfaceBlocks = {
			{Blocks.Snow, 1/1},
		},
		UndergroundBlocks = {
			{Blocks.Ice, 1/1},
			{Blocks.Dirt, 1/50},
			{Blocks.Gravel, 1/50},
			{Blocks.Sand, 1/50},
			{Blocks.IronOre, 1/200},
			{Blocks.CopperOre, 1/200},
		},
		WaterBlocks = {
			{Blocks.Ice, 1/1},
		},
	},

	{name = "Tundra", 
		tempCenter = 0, 
		humidityCenter = 100,
		SurfaceBlocks = {
			{Blocks.ColdGrass, 1/1},
		},
		UndergroundBlocks = {
			{Blocks.Ice, 1/1},
			{Blocks.Snow, 1/50},
			{Blocks.Gravel, 1/50},
			{Blocks.Sand, 1/50},
			{Blocks.IronOre, 1/200},
			{Blocks.CopperOre, 1/200},
		},
		WaterBlocks = {
			{Blocks.Ice, 1/1},
		},
	},

	{name = "Forest", 
		tempCenter = 20, 
		humidityCenter = 100,
		SurfaceBlocks = {
			{Blocks.Grass, 1/1},
			{Blocks.HumidGrass, 1/5},
		},
		UndergroundBlocks = {
			{Blocks.Stone, 1/1},
			{Blocks.Dirt, 1/50},
			{Blocks.Gravel, 1/50},
			{Blocks.Sand, 1/50},
			{Blocks.IronOre, 1/200},
			{Blocks.CopperOre, 1/200},
		},
		WaterBlocks = {
			{Blocks.Water, 1/1},
		},
	},

	{name = "Jungle", 
		tempCenter = 40, 
		humidityCenter = 100,
		SurfaceBlocks = {
			{Blocks.HumidGrass, 1/1},
		},
		UndergroundBlocks = {
			{Blocks.Stone, 1/1},
			{Blocks.Dirt, 1/50},
			{Blocks.Gravel, 1/50},
			{Blocks.Sand, 1/50},
			{Blocks.IronOre, 1/200},
			{Blocks.CopperOre, 1/200},
		},
		WaterBlocks = {
			{Blocks.Water, 1/1},
		},
	},

	{name = "Rainforest", 
		tempCenter = 60, 
		humidityCenter = 100,
		SurfaceBlocks = {
			{Blocks.HumidGrass, 1/1},
		},
		UndergroundBlocks = {
			{Blocks.Stone, 1/1},
			{Blocks.Dirt, 1/50},
			{Blocks.Gravel, 1/50},
			{Blocks.Sand, 1/50},
			{Blocks.IronOre, 1/200},
			{Blocks.CopperOre, 1/200},
		},
		WaterBlocks = {
			{Blocks.Water, 1/1},
		},
	},
	--Full Humid--
	--Half Humid--
	{name = "Glacier", 
		tempCenter = -20, 
		humidityCenter = 50,
		SurfaceBlocks = {
			{Blocks.Glacier, 1/1},
		},
		UndergroundBlocks = {
			{Blocks.Ice, 1/1},
			{Blocks.Dirt, 1/50},
			{Blocks.Gravel, 1/50},
			{Blocks.Sand, 1/50},
			{Blocks.IronOre, 1/200},
			{Blocks.CopperOre, 1/200},
		},
		WaterBlocks = {
			{Blocks.Ice, 1/1},
		},
	},

	{name = "Frost", 
		tempCenter = 0, 
		humidityCenter = 50,
		SurfaceBlocks = {
			{Blocks.Ice, 1/1},
		},
		UndergroundBlocks = {
			{Blocks.Ice, 1/1},
			{Blocks.IronOre, 1/200},
			{Blocks.CopperOre, 1/200},
		},
		WaterBlocks = {
			{Blocks.Ice, 1/1},
		},
	},

	{name = "Grassland", 
		tempCenter = 20, 
		humidityCenter = 50,
		SurfaceBlocks = {
			{Blocks.Grass, 1/1},
		},
		UndergroundBlocks = {
			{Blocks.Stone, 1/1},
			{Blocks.Dirt, 1/50},
			{Blocks.Gravel, 1/50},
			{Blocks.Sand, 1/50},
			{Blocks.IronOre, 1/200},
			{Blocks.CopperOre, 1/200},
		},
		WaterBlocks = {
			{Blocks.Water, 1/1},
		},
	},

	{name = "Savanah", 
		tempCenter = 40, 
		humidityCenter = 50,
		SurfaceBlocks = {
			{Blocks.HotGrass, 1/1},
		},
		UndergroundBlocks = {
			{Blocks.Stone, 1/1},
			{Blocks.Dirt, 1/50},
			{Blocks.Gravel, 1/50},
			{Blocks.Sand, 1/50},
			{Blocks.IronOre, 1/200},
			{Blocks.CopperOre, 1/200},
		},
		WaterBlocks = {
			{Blocks.DryDirt, 1/1},
		},
	},

	{name = "Deadlands", 
		tempCenter = 60, 
		humidityCenter = 50,
		SurfaceBlocks = {
			{Blocks.DryDirt, 1/1},
		},
		UndergroundBlocks = {
			{Blocks.DryDirt, 1/1},
			{Blocks.IronOre, 1/200},
			{Blocks.CopperOre, 1/200},
		},
		WaterBlocks = {
			{Blocks.DryDirt, 1/1},
		},
	},
	--Half Humid--
	--No Humid--
	{name = "Frozen", 
		tempCenter = -20, 
		humidityCenter = 0,
		SurfaceBlocks = {
			{Blocks.Permafrost, 1/1},
		},
		UndergroundBlocks = {
			{Blocks.Permafrost, 1/1},
			{Blocks.IronOre, 1/200},
			{Blocks.CopperOre, 1/200},
		},
		WaterBlocks = {
			{Blocks.Permafrost, 1/1},
		},
	},

	{name = "Cold",
		tempCenter = 0, 
		humidityCenter = 0,
		SurfaceBlocks = {
			{Blocks.ColdDirt, 1/1},
		},
		UndergroundBlocks = {
			{Blocks.Ice, 1/1},
			{Blocks.IronOre, 1/200},
			{Blocks.CopperOre, 1/200},
		},
		WaterBlocks = {
			{Blocks.Water, 1/1},
		},
	},

	{name = "Barren",
		tempCenter = 20, 
		humidityCenter = 0,
		SurfaceBlocks = {
			{Blocks.DryDirt, 1/1},
		},
		UndergroundBlocks = {
			{Blocks.DryDirt, 1/1},
			{Blocks.IronOre, 1/200},
			{Blocks.CopperOre, 1/200},
		},
		WaterBlocks = {
			{Blocks.Water, 1/1},
		},
	},

	{name = "Desert",
		tempCenter = 40, 
		humidityCenter = 0,
		SurfaceBlocks = {
			{Blocks.Sand, 1/1},
		},
		UndergroundBlocks = {
			{Blocks.SandStone, 1/1},
			{Blocks.IronOre, 1/200},
			{Blocks.CopperOre, 1/200},
		},
		WaterBlocks = {
			{Blocks.SandStone, 1/1},
		},
	},

	{name = "Wastelands",
		tempCenter = 60, 
		humidityCenter = 0,
		SurfaceBlocks = {
			{Blocks.DryDirt, 1/1},
		},
		UndergroundBlocks = {
			{Blocks.DryDirt, 1/1},
			{Blocks.IronOre, 1/200},
			{Blocks.CopperOre, 1/200},
		},
		WaterBlocks = {
			{Blocks.DryDirt, 1/1},
		},
	},
	--No Humid--
	----Base biomes----
}

local Settings = {
	BlockSizes = 6,
	NoiseScale = 14,
}

local GreedyBlocks = {
	Blocks.Water,
	--Blocks.Bedrock,
	--Blocks.WorldWall,
}

local PerlinNoise = require(game.ServerScriptService.PerlinNoise)

function ChangeMessage(MessageText)
	for index,child in pairs (game.Players:GetChildren()) do
		if child:IsA("Player") then

			if child.PlayerGui:FindFirstChild("MessageGui") ~= nil then child.PlayerGui:FindFirstChild("MessageGui"):Destroy() end

			if MessageText ~= false and MessageText ~= nil then
				local gui = script.MessageGui:Clone()
				gui.Parent = child.PlayerGui
				gui.TextLabel.Text = MessageText
				gui.Enabled = true
			end

		end
	end
end

function findClosestBiome(temperature, humidity)
	local closestBiome = nil
	local minDistance = math.huge

	for _, biome in ipairs(biomes) do
		local tempDistance = math.abs(biome.tempCenter - temperature)
		local humidityDistance = math.abs(biome.humidityCenter - humidity)

		local distance = tempDistance + humidityDistance

		if distance < minDistance then
			minDistance = distance
			closestBiome = biome
		end
	end

	return closestBiome
end

script.Parent.Loaded.Value = false

local findexistingworld = game.Workspace:FindFirstChild("Tfolder")
if findexistingworld ~= nil then
	findexistingworld:Destroy()
end

for _,v in pairs (script.Parent.Terrain:GetChildren()) do
	if v:IsA("BasePart") then
		v:Destroy()
	end
end

for _,v in pairs (script.Parent.Resources:GetChildren()) do
	if v:IsA("Model") then
		v:Destroy()
	end
end

for _,v in pairs (script.OreData:GetChildren()) do
	if v:IsA("ObjectValue") then
		v:Destroy()
	end
end

script.Parent.Baseplate.Position = Vector3.new(0, 10, 0)

local Blocks = game.Lighting.Blocks

local PrimePart = script.Parent.Baseplate

local worldsize = script.WorldSize.Value

local WorldDepth = script.WorldDepth.Value

local GroundDepth = script.GroundDepth.Value

local TotalWorldHight = GroundDepth + WorldDepth

local terrainfolder = script.Parent.Terrain

local nodesFolder = script.Parent.Nodes

--local worldseed = script.WorldSeed.Value
local worldseed = math.random(-1000000,1000000)

local HighestPoint = 0

local Base = script.Parent:FindFirstChild("Base")

if Base ~= nil then
	worldseed = game.Workspace.Ship.BasePlanetStats.WorldSeed.Value

	GroundDepth = game.Workspace.Ship.BasePlanetStats.GroundDepth.Value

	worldsize = game.Workspace.Ship.BasePlanetStats.WorldSize.Value

	WorldDepth = game.Workspace.Ship.BasePlanetStats.WorldDepth.Value
end
function GenerateOres()

	local ores = 0

	for _,child in pairs (script.Ores:GetChildren()) do
		if child:IsA("ObjectValue") then

			ores = ores + 1

			local oredata = Instance.new("ObjectValue")
			oredata.Name = child.Name
			oredata.Value = child.Value
			oredata.Parent = script.OreData

			local data1 = Instance.new("IntValue")
			data1.Name = "Rarity"
			data1.Value = child.Rarity.Value
			data1.Parent = oredata

			local data2 = Instance.new("IntValue")
			data2.Name = "Number"
			data2.Value = ores * 10000
			data2.Parent = oredata

		end
	end

end

local MaxOpperations = 50
local Opperations = MaxOpperations
function RunServerCooldown()--Special thingy that lets the server catch up after running a large opperation.
	if Opperations > 0 then
		Opperations = Opperations - 1
		--print(Opperations)
	else
		Opperations = MaxOpperations
		game:GetService("RunService").Heartbeat:Wait()
		--print("Cooldown")
	end
end
GenerateOres()
ChangeMessage("Loading world...")
local Distance = 0

local pick = "SpawnSpot"

------Loading------
print("Starting main sequence")
----Generating grid----
print("Creating grid...")
local Grid = {}

for index = 1,worldsize do
	table.insert(Grid,{})--X
end

for index = 1,#Grid do
	local Xpos = Grid[index]
	for secondindex = 1,worldsize do
		table.insert(Xpos,{})--Z
	end
end

for index = 1,#Grid do
	RunServerCooldown()
	local Xpos = Grid[index]
	for secondindex = 1,worldsize do
		local Zpos = Xpos[secondindex]
		for thirdindex = 1,TotalWorldHight do
			table.insert(Zpos,{
				--Also known as the Ypos but it keeps all the main data
				BlockName = "",
				IsGreedy = false,
				GreedyXsize = 1,
				GreedyYsize = 1,
				GreedyZsize = 1})
		end
	end
end
--print(Grid)
print("Finished creating grid.")
----Generating grid----

function FindBlockType(Xpos,Zpos,Ypos,LookingFor:string)
	local TargetLocation = Grid[Xpos][Zpos][Ypos]

	--print("Pos = "..Xpos..", "..Ypos..", "..Zpos)

	if Xpos > 1 and Zpos > 1 and Ypos > 0 and Xpos < worldsize and Zpos < worldsize and Ypos < TotalWorldHight then
		--print("Is within bounds")
		if Grid[Xpos][Zpos][Ypos+1] ~= nil and Grid[Xpos][Zpos][Ypos+1].BlockName == LookingFor then--Up
			--print("Found "..LookingFor.."!")
			return true
		elseif Grid[Xpos][Zpos][Ypos-1] ~= nil and Grid[Xpos][Zpos][Ypos-1].BlockName == LookingFor then--Down
			--print("Found "..LookingFor.."!")
			return true
		elseif Grid[Xpos][Zpos+1][Ypos] ~= nil and Grid[Xpos][Zpos+1][Ypos].BlockName == LookingFor then--Back
			--print("Found "..LookingFor.."!")
			return true
		elseif Grid[Xpos][Zpos-1][Ypos] ~= nil and Grid[Xpos][Zpos-1][Ypos].BlockName == LookingFor then--Forward
			--print("Found "..LookingFor.."!")
			return true
		elseif Grid[Xpos+1][Zpos][Ypos] ~= nil and Grid[Xpos+1][Zpos][Ypos].BlockName == LookingFor then--Left
			--print("Found "..LookingFor.."!")
			return true
		elseif Grid[Xpos-1][Zpos][Ypos] ~= nil and Grid[Xpos-1][Zpos][Ypos].BlockName == LookingFor then--Right
			--print("Found "..LookingFor.."!")
			return true
		end
	end
	return false
end

function IsEdgeBlock(Xpos,Zpos,Ypos)

	local Edge = "None"
	local Limit = false

	if Xpos <= 1 then
		Edge = "Side"
		Limit = true
	elseif Zpos <= 1 then
		Edge = "Side"
		Limit = true
	elseif Ypos <= 1 then
		Edge = "Bottom"
		Limit = true
	elseif Xpos >= worldsize then
		Edge = "Side"
		Limit = true
	elseif Zpos >= worldsize then
		Edge = "Side"
		Limit = true
	elseif Ypos >= TotalWorldHight then
		Edge = "Top"
		Limit = true
	end

	return Limit, Edge
end

function IsGreedyBlock(Xpos,Zpos,Ypos)
	for index = 1,#GreedyBlocks do
		if Grid[Xpos][Zpos][Ypos].BlockName == GreedyBlocks[index].Name then
			return true
		end
	end
	return false
end

function IsExposedBlock(Xpos,Zpos,Ypos)
	if FindBlockType(Xpos,Zpos,Ypos,"Air") == true then
		return true
	elseif FindBlockType(Xpos,Zpos,Ypos,"Water") == true then
		return true
	elseif FindBlockType(Xpos,Zpos,Ypos,"Greedy") == true then
		return true
	end
	return false
end

----Writing grid data----
print("Starting writing world data sequence...")
--World height map--
print("Generating hight map...")
for Xpos = 1,#Grid do
	--print("X")
	RunServerCooldown()
	local Xgrid = Grid[Xpos]
	for Zpos = 1,worldsize do
		--print("Z")
		--game:GetService("RunService").Heartbeat:Wait()
		local Zgrid = Xgrid[Zpos]
		for Ypos = 1,TotalWorldHight do
			--print("Y")
			local Ygrid = Zgrid[Ypos]
			--Stuff
			--wait(0.5)
			local perlinX = Xpos / Settings.NoiseScale
			local perlinZ = Zpos / Settings.NoiseScale
			local perlinY = Ypos / Settings.NoiseScale

			local noiseHillsValue = math.noise(perlinX, worldseed, perlinZ) * WorldDepth
			local noiseFlatsValue = math.noise(perlinX*0.2, worldseed*2, perlinZ*0.2) * WorldDepth

			local TempNoise = math.noise(perlinX*0.1, worldseed*3, perlinZ*0.1) * WorldDepth
			local HumidityNoise = math.noise(perlinX*0.1, worldseed*4, perlinZ*0.1) * WorldDepth

			local Biome = findClosestBiome(TempNoise*15,math.clamp(HumidityNoise*30,0,100))
			--print(Biome)
			--print("Noise = "..noiseValue)
			--print("Ypos = "..Ypos)
			if Ypos <= (GroundDepth*0.9) and noiseHillsValue > (Ypos - GroundDepth) or Ypos <= (GroundDepth*0.9) and noiseFlatsValue > (Ypos - GroundDepth) then
				local ChosenBlock = RaritySytem.GetItem(Biome.UndergroundBlocks)

				Zgrid[Ypos].BlockName = ChosenBlock.Name
				Zgrid[Ypos].IsGreedy = IsGreedyBlock(Xpos,Zpos,Ypos)
			elseif noiseHillsValue > (Ypos - GroundDepth) or noiseFlatsValue > (Ypos - GroundDepth) then
				local ChosenBlock = RaritySytem.GetItem(Biome.SurfaceBlocks)

				Zgrid[Ypos].BlockName = ChosenBlock.Name
				Zgrid[Ypos].IsGreedy = IsGreedyBlock(Xpos,Zpos,Ypos)
			elseif Ypos <= GroundDepth then
				local ChosenBlock = RaritySytem.GetItem(Biome.WaterBlocks)

				Zgrid[Ypos].BlockName = ChosenBlock.Name
				Zgrid[Ypos].IsGreedy = IsGreedyBlock(Xpos,Zpos,Ypos)
			else
				Zgrid[Ypos].BlockName = "Air"
				Zgrid[Ypos].IsGreedy = IsGreedyBlock(Xpos,Zpos,Ypos)
			end

			--Stuff
		end
	end
end
print("Height map done.")
--World height map--

--Applying Perlin Worms--
print("Generating perlin worms...")
for Xpos = 1,#Grid do
	--print("X")
	RunServerCooldown()
	local Xgrid = Grid[Xpos]
	for Zpos = 1,worldsize do
		--print("Z")
		--game:GetService("RunService").Heartbeat:Wait()
		local Zgrid = Xgrid[Zpos]
		for Ypos = 1,TotalWorldHight do
			--print("Y")
			local Ygrid = Zgrid[Ypos]
			--Stuff
			--wait(0.5)
			local perlinX = Xpos / Settings.NoiseScale
			local perlinZ = Zpos / Settings.NoiseScale
			local perlinY = Ypos / Settings.NoiseScale

			local noiseValue = math.noise(perlinX, perlinY, perlinZ)

			local Biome = findClosestBiome(20,100)

			if noiseValue > 0.5 then
				if Zgrid[Ypos].BlockName == "Water" then
					local ChosenBlock = RaritySytem.GetItem(Biome.SurfaceBlocks)

					Zgrid[Ypos].BlockName = ChosenBlock.Name
					Zgrid[Ypos].IsGreedy = IsGreedyBlock(Xpos,Zpos,Ypos)
				else
					Zgrid[Ypos].BlockName = "Air"
					Zgrid[Ypos].IsGreedy = IsGreedyBlock(Xpos,Zpos,Ypos)
				end
			end

			--Stuff
		end
	end
end
print("Perlin worms done.")
--Applying Perlin Worms--

--Adding world edges--
print("Applying world dedges...")
for Xpos = 1,#Grid do
	--print("X")
	RunServerCooldown()
	local Xgrid = Grid[Xpos]
	for Zpos = 1,worldsize do
		--print("Z")
		--game:GetService("RunService").Heartbeat:Wait()
		local Zgrid = Xgrid[Zpos]
		for Ypos = 1,TotalWorldHight do
			--print("Y")
			local IsEdge, EdgeType = IsEdgeBlock(Xpos,Zpos,Ypos)
			if IsEdge == true then
				--print("Edge")
				Zgrid[Ypos].BlockName = "Bedrock"
				Zgrid[Ypos].IsGreedy = IsGreedyBlock(Xpos,Zpos,Ypos)
			end
		end
	end
end
print("World edges done.")
--Adding world edges--

--Making blocks less greedy--
print("Making certain blocks less greedy...")
for Xpos = 1,#Grid do
	--print("X")
	RunServerCooldown()
	local Xgrid = Grid[Xpos]
	for Zpos = 1,worldsize do
		--print("Z")
		--game:GetService("RunService").Heartbeat:Wait()
		local Zgrid = Xgrid[Zpos]
		for Ypos = 1,TotalWorldHight do
			--print("Y")
			--if Zgrid[Ypos].IsGreedy == true and Grid[Xpos][Zpos][Ypos + 1] ~= nil and Grid[Xpos][Zpos][Ypos + 1].IsGreedy == true then
			--	print("Greed check true")
			--end
			if Zgrid[Ypos].IsGreedy == true 
				and Grid[Xpos] ~= nil 
				and Grid[Xpos][Zpos+1] ~= nil 
				and Grid[Xpos][Zpos+1][Ypos] ~= nil 
				and Grid[Xpos][Zpos+1][Ypos].IsGreedy == true 
				and Grid[Xpos][Zpos+1][Ypos].BlockName == Zgrid[Ypos].BlockName then

				--print("Greedy Z!")
				Grid[Xpos][Zpos+1][Ypos].GreedyZsize = Grid[Xpos][Zpos+1][Ypos].GreedyZsize + Zgrid[Ypos].GreedyZsize
				Zgrid[Ypos].IsGreedy = false
				if Zgrid[Ypos].BlockName == "Bedrock" or Zgrid[Ypos].BlockName == "WorldWall" then
					Zgrid[Ypos].BlockName = "DefaultGreedy"
				else
					Zgrid[Ypos].BlockName = "Greedy"
				end

			end
		end
	end
end

for Xpos = 1,#Grid do
	--print("X")
	RunServerCooldown()
	local Xgrid = Grid[Xpos]
	for Zpos = 1,worldsize do
		--print("Z")
		--game:GetService("RunService").Heartbeat:Wait()
		local Zgrid = Xgrid[Zpos]
		for Ypos = 1,TotalWorldHight do
			--print("Y")
			--if Zgrid[Ypos].IsGreedy == true and Grid[Xpos][Zpos][Ypos + 1] ~= nil and Grid[Xpos][Zpos][Ypos + 1].IsGreedy == true then
			--	print("Greed check true")
			--end
			if Zgrid[Ypos].IsGreedy == true 
				and Grid[Xpos+1] ~= nil 
				and Grid[Xpos+1][Zpos] ~= nil 
				and Grid[Xpos+1][Zpos][Ypos] ~= nil 
				and Grid[Xpos+1][Zpos][Ypos].IsGreedy == true 
				and Grid[Xpos+1][Zpos][Ypos].BlockName == Zgrid[Ypos].BlockName then

				--print("Greedy X!")
				Grid[Xpos+1][Zpos][Ypos].GreedyXsize = Grid[Xpos+1][Zpos][Ypos].GreedyXsize + Zgrid[Ypos].GreedyXsize
				Zgrid[Ypos].IsGreedy = false
				if Zgrid[Ypos].BlockName == "Bedrock" or Zgrid[Ypos].BlockName == "WorldWall" then
					Zgrid[Ypos].BlockName = "DefaultGreedy"
				else
					Zgrid[Ypos].BlockName = "Greedy"
				end


			end
		end
	end
end

for Xpos = 1,#Grid do
	--print("X")
	RunServerCooldown()
	local Xgrid = Grid[Xpos]
	for Zpos = 1,worldsize do
		--print("Z")
		--game:GetService("RunService").Heartbeat:Wait()
		local Zgrid = Xgrid[Zpos]
		for Ypos = 1,TotalWorldHight do
			--print("Y")
			--if Zgrid[Ypos].IsGreedy == true and Grid[Xpos][Zpos][Ypos + 1] ~= nil and Grid[Xpos][Zpos][Ypos + 1].IsGreedy == true then
			--	print("Greed check true")
			--end
			if Zgrid[Ypos].IsGreedy == true and Grid[Xpos][Zpos][Ypos + 1] ~= nil and Grid[Xpos][Zpos][Ypos + 1].IsGreedy == true and Grid[Xpos][Zpos][Ypos + 1].BlockName == Zgrid[Ypos].BlockName then

				--print("Greedy Y!")
				Grid[Xpos][Zpos][Ypos + 1].GreedyYsize = Grid[Xpos][Zpos][Ypos + 1].GreedyYsize + Zgrid[Ypos].GreedyYsize
				Zgrid[Ypos].IsGreedy = false
				if Zgrid[Ypos].BlockName == "Bedrock" or Zgrid[Ypos].BlockName == "WorldWall" then
					Zgrid[Ypos].BlockName = "DefaultGreedy"
				else
					Zgrid[Ypos].BlockName = "Greedy"
				end

			end
		end
	end
end
print("Greedy blocks done.")
--Making blocks less greedy--

--print(Grid)
print("Writing world data done.")
----Writing grid data----

local HighestPoint = 0

----Loading world from grid data----
print("Final generation...")
for Xpos = 1,#Grid do
	--print("X")
	game:GetService("RunService").Heartbeat:Wait()
	local Xgrid = Grid[Xpos]
	for Zpos = 1,worldsize do
		--print("Z")
		RunServerCooldown()
		local Zgrid = Xgrid[Zpos]
		for Ypos = 1,TotalWorldHight do
			--print("Y")
			--warn("New line!")
			local DesiredBlock = Zgrid[Ypos].BlockName
			--local IsEdge, EdgeType = IsEdgeBlock(Xpos,Zpos,Ypos)
			if DesiredBlock ~= "Air" and DesiredBlock ~= "Updated" and DesiredBlock ~= "Greedy" and DesiredBlock ~= "DefaultGreedy" and IsExposedBlock(Xpos,Zpos,Ypos) == true then
				--print("Looking for block "..DesiredBlock)
				if Zgrid[Ypos].IsGreedy == true then
					local block = Blocks:FindFirstChild(DesiredBlock):Clone()
					block.Parent = terrainfolder
					block.Size = Vector3.new(Zgrid[Ypos].GreedyXsize, Zgrid[Ypos].GreedyYsize, Zgrid[Ypos].GreedyZsize) * Settings.BlockSizes
					block.Position = (Vector3.new(Xpos - Zgrid[Ypos].GreedyXsize/2, Ypos - Zgrid[Ypos].GreedyYsize/2, Zpos - Zgrid[Ypos].GreedyZsize/2) + Vector3.new(0.5,0.5,0.5)) * Settings.BlockSizes
					block:SetAttribute("GridPos",Vector3.new(Xpos,Ypos,Zpos))
					Zgrid[Ypos].BlockName = "Updated"

					if block.Position.Y > HighestPoint then
						HighestPoint = block.Position.Y
					end

				else
					local block = Blocks:FindFirstChild(DesiredBlock):Clone()
					block.Parent = terrainfolder
					block.Size = Vector3.new(Settings.BlockSizes, Settings.BlockSizes, Settings.BlockSizes)
					block.Position = Vector3.new(Xpos, Ypos, Zpos) * Settings.BlockSizes
					block:SetAttribute("GridPos",Vector3.new(Xpos,Ypos,Zpos))
					Zgrid[Ypos].BlockName = "Updated"

					if block.Position.Y > HighestPoint then
						HighestPoint = block.Position.Y
					end

				end
			elseif DesiredBlock ~= "Air" and DesiredBlock ~= "Updated" and DesiredBlock ~= "Greedy" and DesiredBlock ~= "DefaultGreedy" and Zgrid[Ypos].IsGreedy == true then
				--print("Looking for block "..DesiredBlock)
				if Zgrid[Ypos].IsGreedy == true then
					local block = Blocks:FindFirstChild(DesiredBlock):Clone()
					block.Parent = terrainfolder
					block.Size = Vector3.new(Zgrid[Ypos].GreedyXsize, Zgrid[Ypos].GreedyYsize, Zgrid[Ypos].GreedyZsize) * Settings.BlockSizes
					block.Position = (Vector3.new(Xpos - Zgrid[Ypos].GreedyXsize/2, Ypos - Zgrid[Ypos].GreedyYsize/2, Zpos - Zgrid[Ypos].GreedyZsize/2) + Vector3.new(0.5,0.5,0.5)) * Settings.BlockSizes
					block:SetAttribute("GridPos",Vector3.new(Xpos,Ypos,Zpos))
					Zgrid[Ypos].BlockName = "Updated"

					if block.Position.Y > HighestPoint then
						HighestPoint = block.Position.Y
					end

				else
					local block = Blocks:FindFirstChild(DesiredBlock):Clone()
					block.Parent = terrainfolder
					block.Size = Vector3.new(Settings.BlockSizes, Settings.BlockSizes, Settings.BlockSizes)
					block.Position = Vector3.new(Xpos, Ypos, Zpos) * Settings.BlockSizes
					block:SetAttribute("GridPos",Vector3.new(Xpos,Ypos,Zpos))
					Zgrid[Ypos].BlockName = "Updated"

					if block.Position.Y > HighestPoint then
						HighestPoint = block.Position.Y
					end

				end
			end
		end
	end
end
print("Final generation done.")
----Loading world from grid data----

----Spawning spawn----
part = Blocks:FindFirstChild(pick):Clone()
part.Parent = terrainfolder
part.Size = Vector3.new(10,10,10)
part.CanCollide = false
part.CFrame = PrimePart.CFrame * CFrame.new(0,TotalWorldHight,0)
part.Anchored = true
----Spawning spawn----

----Connecting to world changes----

local function UpdateBlock(Xpos,Zpos,Ypos)
	local DesiredBlock = Grid[Xpos][Zpos][Ypos].BlockName
	--local IsEdge, EdgeType = IsEdgeBlock(Xpos,Zpos,Ypos)
	if DesiredBlock ~= "Air" and DesiredBlock ~= "Updated" and DesiredBlock ~= "Greedy" and DesiredBlock ~= "DefaultGreedy" then
		--print("Looking for block "..DesiredBlock)
		local block = Blocks:FindFirstChild(DesiredBlock):Clone()
		block.Parent = terrainfolder
		block.Size = Vector3.new(Settings.BlockSizes, Settings.BlockSizes, Settings.BlockSizes)
		block.Position = Vector3.new(Xpos, Ypos, Zpos) * Settings.BlockSizes
		block:SetAttribute("GridPos",Vector3.new(Xpos,Ypos,Zpos))
		Grid[Xpos][Zpos][Ypos].BlockName = "Updated"
	end
end


terrainfolder.ChildRemoved:Connect(function(RemovedBlock)
	--print("Triggered!")
	local BlockPos:Vector3 = RemovedBlock:GetAttribute("GridPos")
	if BlockPos then
		--print("Activated!")
		local Xpos = BlockPos.X
		local Zpos = BlockPos.Z
		local Ypos = BlockPos.Y

		UpdateBlock(Xpos,Zpos,Ypos+1)--Up
		UpdateBlock(Xpos,Zpos,Ypos-1)--Down
		UpdateBlock(Xpos,Zpos-1,Ypos)--Back
		UpdateBlock(Xpos,Zpos+1,Ypos)--Forward
		UpdateBlock(Xpos-1,Zpos,Ypos)--Left
		UpdateBlock(Xpos+1,Zpos,Ypos)--Right

	end
end)
----Connecting to world changes----

print("Main sequence finished.")
------Loading------

print("World gen finished!")

ChangeMessage(false)

wait()
script.Parent.Baseplate.CanCollide = false
local spawner = Instance.new("SpawnLocation")
spawner.Anchored = true
spawner.Parent = terrainfolder
spawner.Position = Vector3.new(worldsize*0.5,TotalWorldHight,worldsize*0.5) * Settings.BlockSizes




I know this doesn’t really answer your question, but I personally decided to just stick with only doing greedy meshing on the Y axis to save on calculations and also because it might end up actually being more parts if your terrain also has some depth to it.

If you’re worried about performance, anchored parts really aren’t an issue at all. The only lag would come from generating it in the first place. I did my terrain on the server using Parallel Lua, to which I then used a custom replication system, due to Roblox’s Streaming Enabled being a little too “free form” for what I need. On the client, I stuttered the replication so that it could happen over a series of frames, which greatly reduced the lag from a bunch of chunks being spawned in at once.

I will warn you that if you’re adding textures, you’ll want the client to add them and not all at once or there will be major execution issues. Though Roblox textures are also a bit “not great” as it leaves lines in between different parts. SurfaceGui ImageLabels don’t have this issue, but are much more expensive to render and I don’t recommend using that.

If you’re worried about the lines you see with normal parts when using transparency, either use glass or make them invisible and put your own textures over the water parts.

Oh they are transparent plastic on purpose for demonstration reasons to give people a better idea on how the script is working. I use glass material normally.

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.