This is what worked for me:
local startPosition = Vector3.new(0, 200, 0)
local downRayDirection = Vector3.new(0, -1, 0)
local upRayDirection = Vector3.new(0, 1, 0)
local stepSize = 64
local directions = {
Vector3.new(1, 0, 0),
Vector3.new(-1, 0, 0),
Vector3.new(0, 0, 1),
Vector3.new(0, 0, -1)
}
local raycastParams = RaycastParams.new()
raycastParams.FilterType = Enum.RaycastFilterType.Include
raycastParams.FilterDescendantsInstances = {workspace.Terrain}
raycastParams.IgnoreWater = false
local sizeXP = 0
local sizeZP = 0
local sizeXN = 0
local sizeZN = 0
local heightP = 0
local heightN = 0
for i, dir in ipairs(directions) do
local position = startPosition
local size = 0
while true do
local downRayResults = workspace:Raycast(position, downRayDirection * 1000, raycastParams)
if downRayResults and downRayResults.Instance then
size = size + stepSize
heightP = math.max(downRayResults.Position.Y, heightP)
local upRayResults = workspace:Raycast(position - Vector3.new(0, 400, 0), upRayDirection * 1000, raycastParams)
if upRayResults then
heightN = math.min(upRayResults.Position.Y, heightN)
end
position = position + dir * stepSize
else
break
end
end
if dir == Vector3.new(1, 0, 0) then
sizeXP = size
elseif dir == Vector3.new(-1, 0, 0) then
sizeXN = -size
elseif dir == Vector3.new(0, 0, 1) then
sizeZP = size
elseif dir == Vector3.new(0, 0, -1) then
sizeZN = -size
end
end
print("Size in XP direction:", sizeXP)
print("Size in ZP direction:", sizeZP)
print("Size in XN direction:", sizeXN)
print("Size in ZN direction:", sizeZN)
print("Size in YP direction:", heightP)
print("Size in YN direction:", heightN)
print("Size in X direction:", sizeXP + math.abs(sizeXN))
print("Size in Y direction:", heightP + math.abs(heightN))
print("Size in Z direction:", sizeZP + math.abs(sizeZN))
Keep in mind it can be inaccurate up to stepSize. The height is also only check 200 studs above/below startPosition.