local function new(name,tab)
	local instance = Instance.new(name)
	for index,item in pairs(tab) do
		instance[index] = item
	end
	return instance
end

local function main(x,y,z,n,parent)
	local function block(cframe,size)
		return new("Part",{
			Material = Enum.Material.Cobblestone,
			Color = Color3.fromRGB(139, 132, 123),
			Anchored = true,
			CFrame = cframe,
			Size = size,
			Transparency = 0,
			Parent = parent
		})
	end
	
	local root = Vector3.new(x,y,z)
	local make

	local function noise(origin)
		return n(origin.X,origin.Y,origin.Z)
	end

	local function arb(origin)
		return math.noise(origin.X*0.77 + 0.123,origin.Y*0.77 + 0.123,origin.Z*0.77 + 0.123)
	end

	local function split(origin,size,stop,solid)
		stop = (stop or 1) - 1 -- A counter (which when reaching 0) will force the terrain to stop
		local t = math.round(((arb(origin)+1)/2)*3) -- An arbitrary value from 1-3 seeded by 'origin'
		if arb(origin*7) > 0.5 and size.Magnitude < 128 then return end
		if t == 1 or t == 2 then -- Split, with an option for a gap inbetween
			local dir
			local mag
			local s = 0
			local o = arb(origin) * 0.5 -- the shift for the splits for each sub block
			if arb(origin * 9) < 0 and not solid then -- an arbitrary boolean seeded from origin, should a gap between the blocks be made?
				if size.Magnitude < 256 then -- Make larger gaps smaller
					s = 0.1
				else
					s = 0.06
				end
			end
			if size.X > size.Y then
				if size.X > size.Z then
					-- X
					dir = Vector3.xAxis * size.X
				else
					-- Z
					dir = Vector3.zAxis * size.Z
				end
			else
				if size.Y > size.Z then
					-- Y
					dir = Vector3.yAxis * size.Y
					s = 0
				else
					-- Z
					dir = Vector3.zAxis * size.Z
				end
			end
			make(origin + dir * (0.25 + o * 0.5 + s * 0.5), size - dir * (0.5 + o + s),stop)
			make(origin - dir * (0.25 - o * 0.5 + s * 0.5), size - dir * (0.5 - o + s),stop)
		elseif t == 3  then -- shrink this part
			local size2 = Vector3.new(size.X * 0.8,size.Y,size.Z * 0.8)
			make(origin,size2,stop)
		end
	end

	function make(origin,size,stop)
		origin = (origin / 32):Floor() * 32
		size = (size / 32):Floor() * 32
		local mag = size.Magnitude
		local offset = (root - origin).Magnitude
		local val = noise(origin)
		local f = size.Magnitude * (1/1024) * 4
		--block(CFrame.new(origin),size)
		val = val/f + 3
		if offset > 2000 * f then return end
		if math.abs(val) < 8 then
			if (size.Magnitude < 64 + offset * val * 0.25) or stop == 0 then
				if val > 3 then
					block(CFrame.new(origin),size)
				elseif val > -2 then
					local block = block(CFrame.new(origin),size)
					block.Color = Color3.new(math.random(1,12)/20 + 0.2,0.2,0.2)
					block.Material = Enum.Material.Brick
				end
			else
				split(origin,size,stop,true)
			end
		end
		--[[if val < 8 and val > -8 then -- value is far enough into solid ground
			if val > 0 then -- positive is support 
				if (size.Magnitude < 256 - offset and size.Magnitude > 128 - offset) or stop == 0 then
					block(CFrame.new(origin),size)
				else
					split(origin,size,stop,true)
				end
			else -- negative is building
				if size.Magnitude < 128 - offset + val * 10 or stop == 0 then
					local block = block(CFrame.new(origin),size)
					block.Color = Color3.new(math.random(1,12)/20 + 0.2,0.2,0.2)
					block.Material = Enum.Material.Brick
				else
					split(origin,size,stop)
				end
			end
		end]]
	end

	make(root,Vector3.new(2048,2048,2048),16)
end

return {main = main}