diff --git a/game/client/src/main/java/net/minecraft/client/render/block/color/BlockColorCrystal.java b/game/client/src/main/java/net/minecraft/client/render/block/color/BlockColorCrystal.java
index 768ff8e96..db8742538 100644
--- a/game/client/src/main/java/net/minecraft/client/render/block/color/BlockColorCrystal.java
+++ b/game/client/src/main/java/net/minecraft/client/render/block/color/BlockColorCrystal.java
@@ -2,7 +2,7 @@ package net.minecraft.client.render.block.color;
 
 import net.minecraft.client.render.colorizer.Colorizer;
 import net.minecraft.core.world.WorldSource;
-import net.minecraft.core.world.noise.ImprovedNoise;
+import net.minecraft.core.world.noise.ImprovedPerlinNoise;
 import net.minecraft.core.world.pos.TilePosc;
 import org.jetbrains.annotations.NotNull;
 
@@ -13,7 +13,7 @@ public class BlockColorCrystal extends BlockColorCustom{
     public BlockColorCrystal(Colorizer colorizer) {
         super(colorizer);
     }
-    protected static ImprovedNoise crystalPerlinNoise = new ImprovedNoise(new Random(0));
+    protected static ImprovedPerlinNoise crystalPerlinNoise = new ImprovedPerlinNoise(new Random(0));
     @Override
     public int getWorldColor(@NotNull WorldSource source, @NotNull TilePosc tilePos, int tintIndex) {
 
diff --git a/game/client/src/main/java/net/minecraft/client/render/block/color/BlockColorLeavesOak.java b/game/client/src/main/java/net/minecraft/client/render/block/color/BlockColorLeavesOak.java
index 4185895da..14f36fc6c 100644
--- a/game/client/src/main/java/net/minecraft/client/render/block/color/BlockColorLeavesOak.java
+++ b/game/client/src/main/java/net/minecraft/client/render/block/color/BlockColorLeavesOak.java
@@ -4,7 +4,7 @@ import java.util.Random;
 
 import net.minecraft.client.render.colorizer.Colorizer;
 import net.minecraft.core.world.WorldSource;
-import net.minecraft.core.world.noise.ImprovedNoise;
+import net.minecraft.core.world.noise.ImprovedPerlinNoise;
 import net.minecraft.core.world.pos.TilePosc;
 import net.minecraft.core.world.season.Season;
 import net.minecraft.core.world.season.Seasons;
@@ -12,7 +12,7 @@ import org.jetbrains.annotations.NotNull;
 
 public class BlockColorLeavesOak extends BlockColorCustom {
 
-    private static final @NotNull ImprovedNoise fallColorPerlin = new ImprovedNoise(new Random(0));
+    private static final @NotNull ImprovedPerlinNoise fallColorPerlin = new ImprovedPerlinNoise(new Random(0));
 
     public BlockColorLeavesOak(Colorizer colorizer) {
         super(colorizer);
diff --git a/game/client/src/main/java/net/minecraft/client/render/block/color/BlockColorTallGrass.java b/game/client/src/main/java/net/minecraft/client/render/block/color/BlockColorTallGrass.java
index 3222c3591..46026e08a 100644
--- a/game/client/src/main/java/net/minecraft/client/render/block/color/BlockColorTallGrass.java
+++ b/game/client/src/main/java/net/minecraft/client/render/block/color/BlockColorTallGrass.java
@@ -5,13 +5,13 @@ import java.util.Random;
 import net.minecraft.client.render.colorizer.Colorizer;
 import net.minecraft.client.render.colorizer.Colorizers;
 import net.minecraft.core.world.WorldSource;
-import net.minecraft.core.world.noise.ImprovedNoise;
+import net.minecraft.core.world.noise.ImprovedPerlinNoise;
 import net.minecraft.core.world.pos.TilePosc;
 import org.jetbrains.annotations.NotNull;
 
 public class BlockColorTallGrass extends BlockColorCustom {
 	
-	protected static ImprovedNoise grassColorPerlin = new ImprovedNoise(new Random(0));
+	protected static ImprovedPerlinNoise grassColorPerlin = new ImprovedPerlinNoise(new Random(0));
 	
 	public BlockColorTallGrass(@NotNull Colorizer colorizer) {
 		super(colorizer);
diff --git a/game/core/src/main/java/net/minecraft/core/world/AuroraProvider.java b/game/core/src/main/java/net/minecraft/core/world/AuroraProvider.java
index 43cf3b070..347d007f5 100644
--- a/game/core/src/main/java/net/minecraft/core/world/AuroraProvider.java
+++ b/game/core/src/main/java/net/minecraft/core/world/AuroraProvider.java
@@ -1,18 +1,18 @@
 package net.minecraft.core.world;
 
-import net.minecraft.core.world.noise.ImprovedNoise;
+import net.minecraft.core.world.noise.ImprovedPerlinNoise;
 
 import java.util.Random;
 
 public class AuroraProvider
 {
-    private final ImprovedNoise noise;
+    private final ImprovedPerlinNoise noise;
     private final World world;
 
     public AuroraProvider(World world, long seed)
     {
         this.world = world;
-        noise = new ImprovedNoise(new Random(seed));
+        noise = new ImprovedPerlinNoise(new Random(seed));
     }
 
     public double getAuroraPresence(double x, double z, long worldTime, float celestialAngle)
diff --git a/game/core/src/main/java/net/minecraft/core/world/biome/provider/BiomeProviderB173.java b/game/core/src/main/java/net/minecraft/core/world/biome/provider/BiomeProviderB173.java
index 37d3867d4..65960f0a0 100644
--- a/game/core/src/main/java/net/minecraft/core/world/biome/provider/BiomeProviderB173.java
+++ b/game/core/src/main/java/net/minecraft/core/world/biome/provider/BiomeProviderB173.java
@@ -2,28 +2,30 @@ package net.minecraft.core.world.biome.provider;
 
 import net.minecraft.core.world.biome.Biome;
 import net.minecraft.core.world.biome.Biomes;
-import net.minecraft.core.world.noise.PerlinSimplexNoise;
+import net.minecraft.core.world.noise.FractalNoise2D;
+import net.minecraft.core.world.noise.FractalNoise3D;
+import net.minecraft.core.world.noise.Noise2D;
+import net.minecraft.core.world.noise.SimplexNoise;
 import org.jetbrains.annotations.NotNull;
 
 import java.util.Arrays;
-import java.util.Random;
 
 public class BiomeProviderB173
     extends BiomeProvider
 {
-    private static final float ZOOM = 2.0f;
-    private static final float TEMP_SCALE = 0.025F;
-    private static final float DOWNFALL_SCALE = 0.05F;
-    private static final float NOISE_SCALE = 0.25F;
+    private static final double ZOOM = 2.0;
+    private static final double TEMP_SCALE = 0.025;
+    private static final double DOWNFALL_SCALE = 0.05;
+    private static final double NOISE_SCALE = 0.25;
 
-    private final @NotNull PerlinSimplexNoise temperatureMap;
-    private final @NotNull PerlinSimplexNoise downfallMap;
-    private final @NotNull PerlinSimplexNoise noiseMap;
+    private final @NotNull FractalNoise2D<?> temperatureMap;
+    private final @NotNull FractalNoise2D<?> downfallMap;
+    private final @NotNull FractalNoise2D<?> noiseMap;
 
     public BiomeProviderB173(final long seed) {
-        this.temperatureMap = new PerlinSimplexNoise(new Random(seed * 9871L), 4);
-        this.downfallMap = new PerlinSimplexNoise(new Random(seed * 39811L), 4);
-        this.noiseMap = new PerlinSimplexNoise(new Random(seed * 543321L), 2);
+        this.temperatureMap = new FractalNoise2D<>(SimplexNoise.genOctaves(seed * 9871, 4));
+        this.downfallMap = new FractalNoise2D<>(SimplexNoise.genOctaves(seed * 39811, 4));
+        this.noiseMap = new FractalNoise2D<>(SimplexNoise.genOctaves(seed * 543321, 4));
     }
 
     @Override
@@ -35,19 +37,19 @@ public class BiomeProviderB173
         if (temperatures == null || temperatures.length < xSize * zSize) {
             temperatures = new double[xSize * zSize];
         }
-        this.temperatureMap.getRegion(temperatures, x, z, xSize, xSize, 0.025, 0.025, 0.25);
+        this.temperatureMap.setLacunarity(0.25).getRegion(temperatures, x, z, xSize, xSize, TEMP_SCALE, TEMP_SCALE);
 
         if (humidities == null || humidities.length < xSize * zSize) {
             humidities = new double[xSize * zSize];
         }
-        this.downfallMap.getRegion(humidities, x, z, xSize, xSize, 0.05, 0.05, 1.0 / 3.0);
+        this.downfallMap.setLacunarity(1.0 / 3.0).getRegion(humidities, x, z, xSize, xSize, DOWNFALL_SCALE, DOWNFALL_SCALE);
 
         if (varieties == null || varieties.length < xSize * zSize) {
             varieties = new double[xSize * zSize];
         }
         Arrays.fill(varieties, 0.0);
 
-        final double[] noises = this.noiseMap.getRegion(null, x, z, xSize, xSize, 0.25, 0.25, 0.5882352941176471D);
+        final double @NotNull [] noises = this.noiseMap.setLacunarity(10.0 / 17.0).getRegion(null, x, z, xSize, xSize, NOISE_SCALE, NOISE_SCALE);
 
         for (int xx = 0; xx < xSize; xx++) {
             for (int zz = 0; zz < zSize; zz++) {
@@ -93,9 +95,9 @@ public class BiomeProviderB173
         if (temperatures == null || temperatures.length < xSize * zSize) {
             temperatures = new double[xSize * zSize];
         }
+        this.temperatureMap.setLacunarity(0.25).getRegion(temperatures, x, z, xSize, xSize, TEMP_SCALE, TEMP_SCALE);
 
-        this.temperatureMap.getRegion(temperatures, x, z, xSize, xSize, 0.025, 0.025, 0.25);
-        final double[] noises = this.noiseMap.getRegion(null, x, z, xSize, zSize, 0.25, 0.25, 0.5882352941176471D);
+        final double @NotNull [] noises = this.noiseMap.setLacunarity(10.0 / 17.0).getRegion(null, x, z, xSize, zSize, NOISE_SCALE, NOISE_SCALE);
 
         int i = 0;
         for (int xx = 0; xx < xSize; xx++) {
@@ -125,8 +127,7 @@ public class BiomeProviderB173
         if (humidities == null || humidities.length < xSize * zSize) {
             humidities = new double[xSize * zSize];
         }
-
-        return this.downfallMap.getRegion(humidities, x, z, xSize, zSize, 0.05, 0.05, 0.5);
+        return this.downfallMap.setLacunarity(0.5).getRegion(humidities, x, z, xSize, zSize, DOWNFALL_SCALE, DOWNFALL_SCALE);
     }
 
     @Override
@@ -134,7 +135,6 @@ public class BiomeProviderB173
         if (varieties == null || varieties.length < xSize * zSize) {
             varieties = new double[xSize * zSize];
         }
-
         Arrays.fill(varieties, 0.0);
 
         return varieties;
@@ -145,7 +145,6 @@ public class BiomeProviderB173
         if (biomenesses == null || biomenesses.length < xSize * ySize * zSize) {
             biomenesses = new double[xSize * ySize * zSize];
         }
-
         Arrays.fill(biomenesses, 1.0);
 
         return biomenesses;
diff --git a/game/core/src/main/java/net/minecraft/core/world/biome/provider/BiomeProviderNether.java b/game/core/src/main/java/net/minecraft/core/world/biome/provider/BiomeProviderNether.java
index 22e0dcc4a..9491a3120 100644
--- a/game/core/src/main/java/net/minecraft/core/world/biome/provider/BiomeProviderNether.java
+++ b/game/core/src/main/java/net/minecraft/core/world/biome/provider/BiomeProviderNether.java
@@ -2,11 +2,12 @@ package net.minecraft.core.world.biome.provider;
 
 import net.minecraft.core.world.biome.Biome;
 import net.minecraft.core.world.biome.Biomes;
-import net.minecraft.core.world.noise.PerlinSimplexNoise;
+import net.minecraft.core.world.noise.FractalNoise2D;
+import net.minecraft.core.world.noise.FractalNoise3D;
+import net.minecraft.core.world.noise.SimplexNoise;
 import net.minecraft.core.world.type.WorldTypes;
 
 import java.util.Arrays;
-import java.util.Random;
 
 public final class BiomeProviderNether
     extends BiomeProvider
@@ -28,23 +29,22 @@ public final class BiomeProviderNether
             Biomes.NETHER_VOLCANIC_ISLANDS
     };
 
-    private final PerlinSimplexNoise temperatureNoise;
-    private final PerlinSimplexNoise fuzzinessNoise;
+    private final FractalNoise2D<?> temperatureNoise;
+    private final FractalNoise2D<?> fuzzinessNoise;
 
     private double temperatureXScale = 0.0125;
     private double temperatureZScale = 0.0125;
-    private double temperatureExponent = 0.25;
+    private double temperatureLacunarity = 0.25;
     private double temperatureFuzzPercentage = 0.01;
 
     private double fuzzinessXScale = 0.25;
     private double fuzzinessZScale = 0.25;
-    private double fuzzinessExponent = 1.0;
+    private double fuzzinessLacunarity = 1.0;
 
     public BiomeProviderNether(long seed)
     {
-        this.temperatureNoise = new PerlinSimplexNoise(new Random(seed * 5345L), 4);
-
-        this.fuzzinessNoise = new PerlinSimplexNoise(new Random(seed * 35864L), 2);
+        this.temperatureNoise = new FractalNoise3D<>(SimplexNoise.genOctaves(seed * 5345, 4));
+        this.fuzzinessNoise = new FractalNoise3D<>(SimplexNoise.genOctaves(seed * 35864, 2));
     }
 
     @Override
@@ -90,8 +90,8 @@ public final class BiomeProviderNether
     }
 
     public double getTemperature(double x, double z) {
-        double[] tnResult = temperatureNoise.getRegion(null, x, z, 1, 1, temperatureXScale, temperatureZScale, temperatureExponent);
-        double[] fnResult = fuzzinessNoise.getRegion(null, x, z, 1, 1, fuzzinessXScale, fuzzinessZScale, fuzzinessExponent);
+        double[] tnResult = temperatureNoise.setLacunarity(this.temperatureLacunarity).getRegion(null, x, z, 1, 1, temperatureXScale, temperatureZScale);
+        double[] fnResult = fuzzinessNoise.setLacunarity(this.fuzzinessLacunarity).getRegion(null, x, z, 1, 1, fuzzinessXScale, fuzzinessZScale);
 
         double fuzziness = fnResult[0] * 1.1 + 0.5;
 
@@ -118,8 +118,8 @@ public final class BiomeProviderNether
             temperatures = new double[xSize * zSize];
         }
 
-        double[] tnResult = temperatureNoise.getRegion(null, x, z, xSize, zSize, temperatureXScale, temperatureZScale, temperatureExponent);
-        double[] fnResult = fuzzinessNoise.getRegion(null, x, z, xSize, zSize, fuzzinessXScale, fuzzinessZScale, fuzzinessExponent);
+        double[] tnResult = temperatureNoise.setLacunarity(this.temperatureLacunarity).getRegion(null, x, z, xSize, zSize, temperatureXScale, temperatureZScale);
+        double[] fnResult = fuzzinessNoise.setLacunarity(this.fuzzinessLacunarity).getRegion(null, x, z, xSize, zSize, fuzzinessXScale, fuzzinessZScale);
 
         for (int dx = 0; dx < xSize; dx++)
         {
diff --git a/game/core/src/main/java/net/minecraft/core/world/biome/provider/BiomeProviderOverworld.java b/game/core/src/main/java/net/minecraft/core/world/biome/provider/BiomeProviderOverworld.java
index 01403dfc3..3083b182f 100644
--- a/game/core/src/main/java/net/minecraft/core/world/biome/provider/BiomeProviderOverworld.java
+++ b/game/core/src/main/java/net/minecraft/core/world/biome/provider/BiomeProviderOverworld.java
@@ -5,10 +5,11 @@ import net.minecraft.core.world.biome.Biome;
 import net.minecraft.core.world.biome.Biomes;
 import net.minecraft.core.world.biome.data.BiomeRange;
 import net.minecraft.core.world.biome.data.BiomeRangeMap;
-import net.minecraft.core.world.noise.PerlinSimplexNoise;
+import net.minecraft.core.world.noise.FractalNoise2D;
+import net.minecraft.core.world.noise.FractalNoise3D;
+import net.minecraft.core.world.noise.SimplexNoise;
 import net.minecraft.core.world.type.WorldType;
 
-import java.util.Random;
 import java.util.Set;
 
 public final class BiomeProviderOverworld
@@ -16,29 +17,29 @@ public final class BiomeProviderOverworld
 {
     private static final BiomeRangeMap brm = new BiomeRangeMap();
 
-    private final PerlinSimplexNoise temperatureNoise;
-    private final PerlinSimplexNoise humidityNoise;
-    private final PerlinSimplexNoise varietyNoise;
-    private final PerlinSimplexNoise fuzzinessNoise;
+    private final FractalNoise2D<?> temperatureMap;
+    private final FractalNoise2D<?> humidityMap;
+    private final FractalNoise2D<?> varietyMap;
+    private final FractalNoise2D<?> noiseMap;
 
     private double temperatureXScale = 0.0125;
     private double temperatureZScale = 0.0125;
-    private double temperatureExponent = 0.25;
-    private double temperatureFuzzPercentage = 0.01;
+    private double temperatureLacunarity = 0.25;
+    private double temperatureNoise = 0.01;
 
     private double humidityXScale = 0.025;
     private double humidityZScale = 0.025;
-    private double humidityExponent = 0.3;
-    private double humidityFuzzPercentage = 0.01;
+    private double humidityLacunarity = 0.3;
+    private double humidityNoise = 0.01;
 
     private double varietyXScale = 0.25;
     private double varietyZScale = 0.25;
-    private double varietyExponent = 0.3;
-    private double varietyFuzzPercentage = 0.0;
+    private double varietyLacunarity = 0.3;
+    private double varietyNoise = 0.0;
 
-    private double fuzzinessXScale = 0.25;
-    private double fuzzinessZScale = 0.25;
-    private double fuzzinessExponent = 1.0;
+    private double noiseXScale = 0.25;
+    private double noiseZScale = 0.25;
+    private double noiseLacunarity = 1.0;
 
     private final WorldType worldType;
 
@@ -46,38 +47,37 @@ public final class BiomeProviderOverworld
     {
         this.worldType = worldType;
 
-        this.temperatureNoise = new PerlinSimplexNoise(new Random(seed * 9871L), 4);
-        this.humidityNoise = new PerlinSimplexNoise(new Random(seed * 39811L), 4);
-        this.varietyNoise = new PerlinSimplexNoise(new Random(seed), 4);
-
-        this.fuzzinessNoise = new PerlinSimplexNoise(new Random(seed * 0x84a59L), 2);
+        this.temperatureMap = new FractalNoise3D<>(SimplexNoise.genOctaves(seed * 9871, 4));
+        this.humidityMap = new FractalNoise3D<>(SimplexNoise.genOctaves(seed * 39811, 4));
+        this.varietyMap = new FractalNoise3D<>(SimplexNoise.genOctaves(seed, 4));
+        this.noiseMap = new FractalNoise3D<>(SimplexNoise.genOctaves(seed * 543321, 2));
     }
 
-    public BiomeProviderOverworld withTemperatureScales(double xScale, double zScale, double exponent, double fuzzPercentage)
+    public BiomeProviderOverworld withTemperatureScales(double xScale, double zScale, double lacunarity, double noise)
     {
         this.temperatureXScale = xScale;
         this.temperatureZScale = zScale;
-        this.temperatureExponent = exponent;
-        this.temperatureFuzzPercentage = fuzzPercentage;
+        this.temperatureLacunarity = lacunarity;
+        this.temperatureNoise = noise;
 
         return this;
     }
 
-    public BiomeProviderOverworld withHumidityScales(double xScale, double zScale, double exponent, double fuzzPercentage)
+    public BiomeProviderOverworld withHumidityScales(double xScale, double zScale, double lacunarity, double noise)
     {
         this.humidityXScale = xScale;
         this.humidityZScale = zScale;
-        this.humidityExponent = exponent;
-        this.humidityFuzzPercentage = fuzzPercentage;
+        this.humidityLacunarity = lacunarity;
+        this.humidityNoise = noise;
 
         return this;
     }
 
-    public BiomeProviderOverworld withFuzzinessScales(double xScale, double zScale, double exponent)
+    public BiomeProviderOverworld withNoiseScales(double xScale, double zScale, double lacunarity)
     {
-        this.fuzzinessXScale = xScale;
-        this.fuzzinessZScale = zScale;
-        this.fuzzinessExponent = exponent;
+        this.noiseXScale = xScale;
+        this.noiseZScale = zScale;
+        this.noiseLacunarity = lacunarity;
 
         return this;
     }
@@ -132,8 +132,8 @@ public final class BiomeProviderOverworld
             temperatures = new double[xSize * zSize];
         }
 
-        double[] tnResult = temperatureNoise.getRegion(null, x, z, xSize, zSize, temperatureXScale, temperatureZScale, temperatureExponent);
-        double[] fnResult = fuzzinessNoise.getRegion(null, x, z, xSize, zSize, fuzzinessXScale, fuzzinessZScale, fuzzinessExponent);
+        double[] tnResult = temperatureMap.setLacunarity(this.temperatureLacunarity).getRegion(null, x, z, xSize, zSize, temperatureXScale, temperatureZScale);
+        double[] fnResult = noiseMap.setLacunarity(this.noiseLacunarity).getRegion(null, x, z, xSize, zSize, noiseXScale, noiseZScale);
 
         for (int dx = 0; dx < xSize; dx++)
         {
@@ -141,7 +141,7 @@ public final class BiomeProviderOverworld
             {
                 double fuzziness = fnResult[dx * zSize + dz] * 1.1 + 0.5;
 
-                double fuzzPctg = temperatureFuzzPercentage;
+                double fuzzPctg = temperatureNoise;
                 double valPctg = 1.0 - fuzzPctg;
                 double temperature = (tnResult[dx * zSize + dz] * 0.15 + 0.7) * valPctg + fuzziness * fuzzPctg;
 
@@ -169,8 +169,8 @@ public final class BiomeProviderOverworld
             humidities = new double[xSize * zSize];
         }
 
-        double[] hnResult = humidityNoise.getRegion(null, x, z, xSize, zSize, humidityXScale, humidityZScale, humidityExponent);
-        double[] fnResult = fuzzinessNoise.getRegion(null, x, z, xSize, zSize, fuzzinessXScale, fuzzinessZScale, fuzzinessExponent);
+        double[] hnResult = humidityMap.setLacunarity(this.humidityLacunarity).getRegion(null, x, z, xSize, zSize, humidityXScale, humidityZScale);
+        double[] fnResult = noiseMap.setLacunarity(this.noiseLacunarity).getRegion(null, x, z, xSize, zSize, noiseXScale, noiseZScale);
 
         for (int dx = 0; dx < xSize; dx++)
         {
@@ -178,7 +178,7 @@ public final class BiomeProviderOverworld
             {
                 double fuzziness = fnResult[dx * zSize + dz] * 1.1 + 0.5;
 
-                double fuzzPctg = humidityFuzzPercentage;
+                double fuzzPctg = humidityNoise;
                 double valPctg = 1.0 - fuzzPctg;
                 double humidity = (hnResult[dx * zSize + dz] * 0.15 + 0.5) * valPctg + fuzziness * fuzzPctg;
 
@@ -205,8 +205,8 @@ public final class BiomeProviderOverworld
             varieties = new double[xSize * zSize];
         }
 
-        double[] vnResult = varietyNoise.getRegion(null, x, z, xSize, zSize, varietyXScale, varietyZScale, varietyExponent);
-        double[] fnResult = fuzzinessNoise.getRegion(null, x, z, xSize, zSize, fuzzinessXScale, fuzzinessZScale, fuzzinessExponent);
+        double[] vnResult = varietyMap.setLacunarity(this.varietyLacunarity).getRegion(null, x, z, xSize, zSize, varietyXScale, varietyZScale);
+        double[] fnResult = noiseMap.setLacunarity(this.noiseLacunarity).getRegion(null, x, z, xSize, zSize, noiseXScale, noiseZScale);
 
         for (int dx = 0; dx < xSize; dx++)
         {
@@ -214,7 +214,7 @@ public final class BiomeProviderOverworld
             {
                 double fuzziness = fnResult[dx * zSize + dz] * 1.1 + 0.5;
 
-                double fuzzPctg = varietyFuzzPercentage;
+                double fuzzPctg = varietyNoise;
                 double valPctg = 1.0 - fuzzPctg;
                 double variety = (vnResult[dx * zSize + dz] * 0.15 + 0.5) * valPctg + fuzziness * fuzzPctg;
 
diff --git a/game/core/src/main/java/net/minecraft/core/world/generate/IceFloeLargeFeature.java b/game/core/src/main/java/net/minecraft/core/world/generate/IceFloeLargeFeature.java
index aa23ce91f..23e4b195a 100644
--- a/game/core/src/main/java/net/minecraft/core/world/generate/IceFloeLargeFeature.java
+++ b/game/core/src/main/java/net/minecraft/core/world/generate/IceFloeLargeFeature.java
@@ -7,8 +7,7 @@ import net.minecraft.core.world.biome.Biome;
 import net.minecraft.core.world.biome.Biomes;
 import net.minecraft.core.world.chunk.Chunk;
 import net.minecraft.core.world.generate.chunk.ChunkGeneratorResult;
-import net.minecraft.core.world.noise.PerlinNoise;
-import net.minecraft.core.world.noise.WorleyNoise;
+import net.minecraft.core.world.noise.*;
 import net.minecraft.core.world.pos.TilePos;
 import net.minecraft.core.world.type.WorldType;
 import org.jetbrains.annotations.NotNull;
@@ -19,15 +18,15 @@ import java.util.Random;
 
 public class IceFloeLargeFeature
     extends LargeFeature {
-    private @Nullable PerlinNoise perlinNoise = null;
-    private @Nullable PerlinNoise scalePerlinNoise = null;
+    private @Nullable Noise2D noise = null;
+    private @Nullable Noise2D scaleNoise = null;
     private @Nullable World lastWorld = null;
 
     @Override
     protected void doGeneration(@NotNull final World world, @NotNull final Random random, final int chunkX, final int chunkZ, final int baseChunkX, final int baseChunkZ, @NotNull final ChunkGeneratorResult result) {
-        if (this.perlinNoise == null || this.scalePerlinNoise == null || this.lastWorld != world) {
-            this.perlinNoise = new PerlinNoise(world.getRandomSeed(), 4);
-            this.scalePerlinNoise = new PerlinNoise(world.getRandomSeed(), 2);
+        if (this.noise == null || this.scaleNoise == null || this.lastWorld != world) {
+            this.noise = new FractalNoise2D<>(ImprovedPerlinNoise.genOctaves(world.getRandomSeed(), 4));
+            this.scaleNoise = new FractalNoise2D<>(ImprovedPerlinNoise.genOctaves(world.getRandomSeed(), 2));
             this.lastWorld = world;
         }
 
@@ -44,12 +43,14 @@ public class IceFloeLargeFeature
                 final @NotNull Biome biome = world.getBlockBiome(tilePos);
                 if (biome == Biomes.OVERWORLD_GLACIER) {
                     final float worleyScaleScale = 50.0f;
-                    final float worleyScale = 0.875f + (float) (this.scalePerlinNoise.getNormalized((baseChunkX * Chunk.CHUNK_SIZE_X + x) / worleyScaleScale, (baseChunkZ * Chunk.CHUNK_SIZE_Z + z) / worleyScaleScale)) * 0.25f;
+
+                    // TODO: NORMALIZE THIS
+                    final float worleyScale = 0.875f + (float) (this.scaleNoise.getValue((baseChunkX * Chunk.CHUNK_SIZE_X + x) / worleyScaleScale, (baseChunkZ * Chunk.CHUNK_SIZE_Z + z) / worleyScaleScale)) * 0.25f;
                     vec.x = (baseChunkX + ((float) x / (float) Chunk.CHUNK_SIZE_X)) * worleyScale;
                     vec.y = (baseChunkZ + ((float) z / (float) Chunk.CHUNK_SIZE_Z)) * worleyScale;
                     WorleyNoise.getWorleyDistance2d(vec, worley);
                     final float lineScale = 10.0f;
-                    final float lineWidth = (float) (this.perlinNoise.getValue((baseChunkX * Chunk.CHUNK_SIZE_X + x) / lineScale, (baseChunkZ * Chunk.CHUNK_SIZE_Z + z) / lineScale) / 2.0 + 0.5);
+                    final float lineWidth = (float) (this.noise.getValue((baseChunkX * Chunk.CHUNK_SIZE_X + x) / lineScale, (baseChunkZ * Chunk.CHUNK_SIZE_Z + z) / lineScale) / 2.0 + 0.5);
                     if (MathHelper.unsignedMod(worley.index, 15) != 0) {
                         if (worley.distance > 0.9f + lineWidth * 0.05f) {
                             continue;
diff --git a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/classic/ChunkGeneratorClassic.java b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/classic/ChunkGeneratorClassic.java
index 13650edd3..f795cddc6 100644
--- a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/classic/ChunkGeneratorClassic.java
+++ b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/classic/ChunkGeneratorClassic.java
@@ -9,34 +9,51 @@ import net.minecraft.core.world.generate.chunk.ChunkGeneratorResult;
 import net.minecraft.core.world.generate.chunk.perlin.SurfaceGenerator;
 import net.minecraft.core.world.generate.chunk.perlin.overworld.retro.ChunkDecoratorOverworldRetro;
 import net.minecraft.core.world.generate.chunk.perlin.overworld.retro.SurfaceGeneratorOverworldRetro;
-import net.minecraft.core.world.noise.CombinedPerlinNoise;
-import net.minecraft.core.world.noise.LegacyNoiseType;
-import net.minecraft.core.world.noise.PerlinNoise;
+import net.minecraft.core.world.noise.*;
+import net.minecraft.core.world.noise.operator.Constant2D;
+import net.minecraft.core.world.noise.operator.Warp2D;
 import org.jetbrains.annotations.NotNull;
 
 public class ChunkGeneratorClassic
     extends ChunkGenerator {
-    private final @NotNull CombinedPerlinNoise combinedA;
-    private final @NotNull CombinedPerlinNoise combinedB;
-    private final @NotNull CombinedPerlinNoise combinedC;
-    private final @NotNull CombinedPerlinNoise combinedD;
-    private final @NotNull PerlinNoise octavesA;
-    private final @NotNull PerlinNoise octavesB;
+    private final @NotNull Warp2D<FractalNoise2D<ImprovedPerlinNoise>, FractalNoise2D<ImprovedPerlinNoise>, Constant2D> combinedA;
+    private final @NotNull Warp2D<FractalNoise2D<ImprovedPerlinNoise>, FractalNoise2D<ImprovedPerlinNoise>, Constant2D> combinedB;
+    private final @NotNull Warp2D<FractalNoise2D<ImprovedPerlinNoise>, FractalNoise2D<ImprovedPerlinNoise>, Constant2D> combinedC;
+    private final @NotNull Warp2D<FractalNoise2D<ImprovedPerlinNoise>, FractalNoise2D<ImprovedPerlinNoise>, Constant2D> combinedD;
+    private final @NotNull FractalNoise2D<ImprovedPerlinNoise> octavesA;
+    private final @NotNull FractalNoise2D<ImprovedPerlinNoise> octavesB;
 
     private final @NotNull SurfaceGenerator sg;
     private final @NotNull CavesLargeFeature cg;
 
     public ChunkGeneratorClassic(@NotNull World world) {
         super(world, new ChunkDecoratorOverworldRetro(world));
-        long seed = world.getRandomSeed();
 
-        this.combinedA = new CombinedPerlinNoise(new PerlinNoise(seed, 8, 0, LegacyNoiseType.ALPHA), new PerlinNoise(seed, 8, 8, LegacyNoiseType.ALPHA));
-        this.combinedB = new CombinedPerlinNoise(new PerlinNoise(seed, 8, 16, LegacyNoiseType.ALPHA), new PerlinNoise(seed, 8, 24, LegacyNoiseType.ALPHA));
-        this.combinedC = new CombinedPerlinNoise(new PerlinNoise(seed, 8, 32, LegacyNoiseType.ALPHA), new PerlinNoise(seed, 8, 40, LegacyNoiseType.ALPHA));
-        this.combinedD = new CombinedPerlinNoise(new PerlinNoise(seed, 8, 48, LegacyNoiseType.ALPHA), new PerlinNoise(seed, 8, 56, LegacyNoiseType.ALPHA));
-
-        this.octavesA = new PerlinNoise(seed, 6, 64, LegacyNoiseType.ALPHA);
-        this.octavesB = new PerlinNoise(seed, 8, 70, LegacyNoiseType.ALPHA);
+        final long seed = world.getRandomSeed();
+
+        this.combinedA = new Warp2D<>(
+            new FractalNoise2D<>(ImprovedPerlinNoise.genOctaves(seed, 8, 0, ImprovedPerlinNoise.LegacyNoiseType.ALPHA)),
+            new FractalNoise2D<>(ImprovedPerlinNoise.genOctaves(seed, 8, 8, ImprovedPerlinNoise.LegacyNoiseType.ALPHA)),
+            new Constant2D(0.0)
+        );
+        this.combinedB = new Warp2D<>(
+            new FractalNoise2D<>(ImprovedPerlinNoise.genOctaves(seed, 8, 16, ImprovedPerlinNoise.LegacyNoiseType.ALPHA)),
+            new FractalNoise2D<>(ImprovedPerlinNoise.genOctaves(seed, 8, 24, ImprovedPerlinNoise.LegacyNoiseType.ALPHA)),
+            new Constant2D(0.0)
+        );
+        this.combinedC = new Warp2D<>(
+            new FractalNoise2D<>(ImprovedPerlinNoise.genOctaves(seed, 8, 32, ImprovedPerlinNoise.LegacyNoiseType.ALPHA)),
+            new FractalNoise2D<>(ImprovedPerlinNoise.genOctaves(seed, 8, 40, ImprovedPerlinNoise.LegacyNoiseType.ALPHA)),
+            new Constant2D(0.0)
+        );
+        this.combinedD = new Warp2D<>(
+            new FractalNoise2D<>(ImprovedPerlinNoise.genOctaves(seed, 8, 48, ImprovedPerlinNoise.LegacyNoiseType.ALPHA)),
+            new FractalNoise2D<>(ImprovedPerlinNoise.genOctaves(seed, 8, 56, ImprovedPerlinNoise.LegacyNoiseType.ALPHA)),
+            new Constant2D(0.0)
+        );
+
+        this.octavesA = new FractalNoise2D<>(ImprovedPerlinNoise.genOctaves(seed, 8, 64, ImprovedPerlinNoise.LegacyNoiseType.ALPHA));
+        this.octavesB = new FractalNoise2D<>(ImprovedPerlinNoise.genOctaves(seed, 8, 70, ImprovedPerlinNoise.LegacyNoiseType.ALPHA));
 
         this.sg = new SurfaceGeneratorOverworldRetro(world);
         this.cg = new CavesLargeFeature();
@@ -56,8 +73,8 @@ public class ChunkGeneratorClassic
         // Raising..
         for (int x = 0; x < Chunk.CHUNK_SIZE_X; x++) {
             for (int z = 0; z < Chunk.CHUNK_SIZE_Z; z++) {
-                final double noiseA = this.combinedA.get((chunkX * Chunk.CHUNK_SIZE_X + x) * mod, (chunkZ * Chunk.CHUNK_SIZE_Z + z) * mod) / 6.0D + -4;
-                double noiseB = this.combinedB.get((chunkX * Chunk.CHUNK_SIZE_X + x) * mod, (chunkZ * Chunk.CHUNK_SIZE_Z + z) * mod) / 5.0D + 10.0D + -4;
+                final double noiseA = this.combinedA.getValue((chunkX * Chunk.CHUNK_SIZE_X + x) * mod, (chunkZ * Chunk.CHUNK_SIZE_Z + z) * mod) / 6.0D + -4;
+                double noiseB = this.combinedB.getValue((chunkX * Chunk.CHUNK_SIZE_X + x) * mod, (chunkZ * Chunk.CHUNK_SIZE_Z + z) * mod) / 5.0D + 10.0D + -4;
                 if (this.octavesA.getValue(chunkX * Chunk.CHUNK_SIZE_X + x, chunkZ * Chunk.CHUNK_SIZE_Z + z) / 8.0D > 0.0D) {
                     noiseB = noiseA;
                 }
@@ -75,8 +92,8 @@ public class ChunkGeneratorClassic
         final int[] newHeightMap = heightMap;
         for (int x = 0; x < Chunk.CHUNK_SIZE_X; x++) {
             for (int z = 0; z < Chunk.CHUNK_SIZE_Z; z++) {
-                final double val = this.combinedC.get((chunkX * Chunk.CHUNK_SIZE_X + x) << 1, (chunkZ * Chunk.CHUNK_SIZE_Z + z) << 1) / 8.0D;
-                final int val2 = this.combinedD.get((chunkX * Chunk.CHUNK_SIZE_X + x) << 1, (chunkZ * Chunk.CHUNK_SIZE_Z + z) << 1) > 0.0D ? 1 : 0;
+                final double val = this.combinedC.getValue((chunkX * Chunk.CHUNK_SIZE_X + x) << 1, (chunkZ * Chunk.CHUNK_SIZE_Z + z) << 1) / 8.0D;
+                final int val2 = this.combinedD.getValue((chunkX * Chunk.CHUNK_SIZE_X + x) << 1, (chunkZ * Chunk.CHUNK_SIZE_Z + z) << 1) > 0.0D ? 1 : 0;
                 if (val > 2.0D) {
                     final int newHeight = ((newHeightMap[x + z * Chunk.CHUNK_SIZE_X] - val2) / 2 << 1) + val2;
                     newHeightMap[x + z * Chunk.CHUNK_SIZE_X] = newHeight;
diff --git a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/indev/LevelGenerator.java b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/indev/LevelGenerator.java
index b217a406e..e28b80a18 100644
--- a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/indev/LevelGenerator.java
+++ b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/indev/LevelGenerator.java
@@ -4,9 +4,9 @@ import net.minecraft.core.block.Blocks;
 import net.minecraft.core.world.World;
 import net.minecraft.core.world.chunk.Chunk;
 import net.minecraft.core.world.generate.chunk.ChunkGeneratorResult;
-import net.minecraft.core.world.noise.CombinedPerlinNoise;
-import net.minecraft.core.world.noise.LegacyNoiseType;
-import net.minecraft.core.world.noise.PerlinNoise;
+import net.minecraft.core.world.noise.*;
+import net.minecraft.core.world.noise.operator.Constant2D;
+import net.minecraft.core.world.noise.operator.Warp2D;
 import org.jetbrains.annotations.NotNull;
 
 public final class LevelGenerator {
@@ -45,10 +45,18 @@ public final class LevelGenerator {
             } else {
                 // Raising phase
 //                System.out.println("Raising..");
-                CombinedPerlinNoise heightNoiseGeneratorA = new CombinedPerlinNoise(new PerlinNoise(seed, 8, 0, LegacyNoiseType.ALPHA), new PerlinNoise(seed, 8, 8, LegacyNoiseType.ALPHA));
-                CombinedPerlinNoise heightNoiseGeneratorB = new CombinedPerlinNoise(new PerlinNoise(seed, 8, 16, LegacyNoiseType.ALPHA), new PerlinNoise(seed, 8, 24, LegacyNoiseType.ALPHA));
-                PerlinNoise heightNoiseGeneratorSelector = new PerlinNoise(seed, 6, 32, LegacyNoiseType.ALPHA);
-                PerlinNoise edgeNoiseGenerator = new PerlinNoise(seed, 2, 38, LegacyNoiseType.ALPHA);
+                var heightNoiseGeneratorA = new Warp2D<>(
+                    new FractalNoise2D<>(ImprovedPerlinNoise.genOctaves(seed, 8, 0, ImprovedPerlinNoise.LegacyNoiseType.ALPHA)),
+                    new FractalNoise2D<>(ImprovedPerlinNoise.genOctaves(seed, 8, 8, ImprovedPerlinNoise.LegacyNoiseType.ALPHA)),
+                    new Constant2D(0.0)
+                );
+                var heightNoiseGeneratorB = new Warp2D<>(
+                    new FractalNoise2D<>(ImprovedPerlinNoise.genOctaves(seed, 8, 16, ImprovedPerlinNoise.LegacyNoiseType.ALPHA)),
+                    new FractalNoise2D<>(ImprovedPerlinNoise.genOctaves(seed, 8, 24, ImprovedPerlinNoise.LegacyNoiseType.ALPHA)),
+                    new Constant2D(0.0)
+                );
+                FractalNoise2D<ImprovedPerlinNoise> heightNoiseGeneratorSelector = new FractalNoise2D<>(ImprovedPerlinNoise.genOctaves(seed, 6, 32, ImprovedPerlinNoise.LegacyNoiseType.ALPHA));
+                FractalNoise2D<ImprovedPerlinNoise> edgeNoiseGenerator = new FractalNoise2D<>(ImprovedPerlinNoise.genOctaves(seed, 2, 38, ImprovedPerlinNoise.LegacyNoiseType.ALPHA));
 
                 for (int x = 0; x < Chunk.CHUNK_SIZE_X; x++) {
                     double xDistanceFromCenter = Math.abs(((double) (x + xOffset) / ((double) this.sizeX - 1.0) - 0.5) * 2.0);
@@ -57,8 +65,8 @@ public final class LevelGenerator {
                         double zDistanceFromCenter = Math.abs(((double) (z + zOffset) / ((double) this.sizeZ - 1.0) - 0.5) * 2.0);
 
                         // Generate noise to use for height
-                        double heightNoiseA = heightNoiseGeneratorA.get((float) (x + xOffset) * 1.3F, (float) (z + zOffset) * 1.3F) / 6.0 + -4.0;
-                        double heightNoiseB = heightNoiseGeneratorB.get((float) (x + xOffset) * 1.3F, (float) (z + zOffset) * 1.3F) / 5.0 + 10.0 + -4.0;
+                        double heightNoiseA = heightNoiseGeneratorA.getValue((float) (x + xOffset) * 1.3F, (float) (z + zOffset) * 1.3F) / 6.0 + -4.0;
+                        double heightNoiseB = heightNoiseGeneratorB.getValue((float) (x + xOffset) * 1.3F, (float) (z + zOffset) * 1.3F) / 5.0 + 10.0 + -4.0;
                         double heightNoiseToUse = heightNoiseGeneratorSelector.getValue(x + xOffset, z + zOffset) / 8.0;
                         if (heightNoiseToUse > 0.0) {
                             heightNoiseB = heightNoiseA;
@@ -97,13 +105,21 @@ public final class LevelGenerator {
 
                 // Eroding phase
 //                System.out.println("Eroding..");
-                CombinedPerlinNoise erosionPowerNoiseGenerator = new CombinedPerlinNoise(new PerlinNoise(seed, 8, 40, LegacyNoiseType.ALPHA), new PerlinNoise(seed, 8, 48, LegacyNoiseType.ALPHA));
-                CombinedPerlinNoise erosionAmountNoiseGenerator = new CombinedPerlinNoise(new PerlinNoise(seed, 8, 56, LegacyNoiseType.ALPHA), new PerlinNoise(seed, 8, 64, LegacyNoiseType.ALPHA));
+                var erosionPowerNoiseGenerator = new Warp2D<>(
+                    new FractalNoise2D<>(ImprovedPerlinNoise.genOctaves(seed, 8, 40, ImprovedPerlinNoise.LegacyNoiseType.ALPHA)),
+                    new FractalNoise2D<>(ImprovedPerlinNoise.genOctaves(seed, 8, 48, ImprovedPerlinNoise.LegacyNoiseType.ALPHA)),
+                    new Constant2D(0.0)
+                );
+                var erosionAmountNoiseGenerator = new Warp2D<>(
+                    new FractalNoise2D<>(ImprovedPerlinNoise.genOctaves(seed, 8, 56, ImprovedPerlinNoise.LegacyNoiseType.ALPHA)),
+                    new FractalNoise2D<>(ImprovedPerlinNoise.genOctaves(seed, 8, 64, ImprovedPerlinNoise.LegacyNoiseType.ALPHA)),
+                    new Constant2D(0.0)
+                );
 
                 for (int x = 0; x < Chunk.CHUNK_SIZE_X; x++) {
                     for (int z = 0; z < Chunk.CHUNK_SIZE_Z; z++) {
-                        double erosionPower = erosionPowerNoiseGenerator.get((x + xOffset) << 1, (z + zOffset) << 1) / 8.0;
-                        int erosionAmount = erosionAmountNoiseGenerator.get((x + xOffset) << 1, (z + zOffset) << 1) > 0.0 ? 1 : 0;
+                        double erosionPower = erosionPowerNoiseGenerator.getValue((x + xOffset) << 1, (z + zOffset) << 1) / 8.0;
+                        int erosionAmount = erosionAmountNoiseGenerator.getValue((x + xOffset) << 1, (z + zOffset) << 1) > 0.0 ? 1 : 0;
 
                         if (erosionPower > 2.0) {
                             int height = heightMap[x + z * Chunk.CHUNK_SIZE_X];
@@ -116,8 +132,8 @@ public final class LevelGenerator {
 
             // Soiling phase
 //            System.out.println("Soiling..");
-            PerlinNoise soilNoiseGenerator = new PerlinNoise(seed, 8, 72, LegacyNoiseType.ALPHA);
-            PerlinNoise floatingLayerNoiseGenerator = new PerlinNoise(seed, 8, 80, LegacyNoiseType.ALPHA);
+            FractalNoise2D<ImprovedPerlinNoise> soilNoiseGenerator = new FractalNoise2D<>(ImprovedPerlinNoise.genOctaves(seed, 8, 72, ImprovedPerlinNoise.LegacyNoiseType.ALPHA));
+            FractalNoise2D<ImprovedPerlinNoise> floatingLayerNoiseGenerator = new FractalNoise2D<>(ImprovedPerlinNoise.genOctaves(seed, 8, 80, ImprovedPerlinNoise.LegacyNoiseType.ALPHA));
 
             for (int x = 0; x < Chunk.CHUNK_SIZE_X; x++) {
                 double xDistanceFromCenter = Math.abs(((double) (x + xOffset) / ((double) this.sizeX - 1.0) - 0.5) * 2.0);
@@ -168,8 +184,8 @@ public final class LevelGenerator {
 
             // Growing phase - no idea why it's called this because it's very clearly generating beaches
 //            System.out.println("Growing..");
-            PerlinNoise sandNoiseGenerator = new PerlinNoise(seed, 8, 88, LegacyNoiseType.ALPHA);
-            PerlinNoise gravelNoiseGenerator = new PerlinNoise(seed, 8, 96, LegacyNoiseType.ALPHA);
+            FractalNoise2D<ImprovedPerlinNoise> sandNoiseGenerator = new FractalNoise2D<>(ImprovedPerlinNoise.genOctaves(seed, 8, 88, ImprovedPerlinNoise.LegacyNoiseType.ALPHA));
+            FractalNoise2D<ImprovedPerlinNoise> gravelNoiseGenerator = new FractalNoise2D<>(ImprovedPerlinNoise.genOctaves(seed, 8, 96, ImprovedPerlinNoise.LegacyNoiseType.ALPHA));
             int beachHeight = waterLevel - 1;
             if (this.worldTheme == IndevWorldTheme.PARADISE) {
                 beachHeight += 2;
diff --git a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/drift/DensityGeneratorDrift.java b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/drift/DensityGeneratorDrift.java
index afb601249..00b03069e 100644
--- a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/drift/DensityGeneratorDrift.java
+++ b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/drift/DensityGeneratorDrift.java
@@ -3,27 +3,28 @@ package net.minecraft.core.world.generate.chunk.perlin.drift;
 import net.minecraft.core.world.World;
 import net.minecraft.core.world.chunk.Chunk;
 import net.minecraft.core.world.generate.chunk.perlin.DensityGenerator;
-import net.minecraft.core.world.noise.PerlinNoise;
+import net.minecraft.core.world.noise.FractalNoise3D;
+import net.minecraft.core.world.noise.ImprovedPerlinNoise;
 import org.jetbrains.annotations.NotNull;
 
 public class DensityGeneratorDrift
     implements DensityGenerator {
     private final @NotNull World world;
 
-    private final @NotNull PerlinNoise minLimitNoise;
-    private final @NotNull PerlinNoise maxLimitNoise;
-    private final @NotNull PerlinNoise mainNoise;
-//    private final PerlinNoise scaleNoise;
-//    private final PerlinNoise depthNoise;
+    private final @NotNull FractalNoise3D<ImprovedPerlinNoise> minLimitNoise;
+    private final @NotNull FractalNoise3D<ImprovedPerlinNoise> maxLimitNoise;
+    private final @NotNull FractalNoise3D<ImprovedPerlinNoise> mainNoise;
+//    private final FractalNoise2D<ImprovedPerlinNoise> scaleNoise;
+//    private final FractalNoise2D<ImprovedPerlinNoise> depthNoise;
 
     public DensityGeneratorDrift(@NotNull World world) {
         this.world = world;
 
-        this.minLimitNoise = new PerlinNoise(world.getRandomSeed(), 16, 0);
-        this.maxLimitNoise = new PerlinNoise(world.getRandomSeed(), 16, 16);
-        this.mainNoise = new PerlinNoise(world.getRandomSeed(), 8, 32);
-//        scaleNoise = new PerlinNoise(world.getRandomSeed(), 10, 48);
-//        depthNoise = new PerlinNoise(world.getRandomSeed(), 16, 58);
+        this.minLimitNoise = new FractalNoise3D<>(ImprovedPerlinNoise.genOctaves(world.getRandomSeed(), 16, 0));
+        this.maxLimitNoise = new FractalNoise3D<>(ImprovedPerlinNoise.genOctaves(world.getRandomSeed(), 16, 16));
+        this.mainNoise = new FractalNoise3D<>(ImprovedPerlinNoise.genOctaves(world.getRandomSeed(), 8, 32));
+//        this.scaleNoise = new FractalNoise2D<>(ImprovedPerlinNoise.genOctaves(world.getRandomSeed(), 10, 48));
+//        this.depthNoise = new FractalNoise2D<>(ImprovedPerlinNoise.genOctaves(world.getRandomSeed(), 16, 58));
     }
 
     @Override
diff --git a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/nether/ChunkDecoratorNether.java b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/nether/ChunkDecoratorNether.java
index bbe327f77..f9a00f5d1 100644
--- a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/nether/ChunkDecoratorNether.java
+++ b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/nether/ChunkDecoratorNether.java
@@ -8,7 +8,10 @@ import net.minecraft.core.world.biome.Biomes;
 import net.minecraft.core.world.chunk.Chunk;
 import net.minecraft.core.world.generate.chunk.ChunkDecorator;
 import net.minecraft.core.world.generate.feature.*;
-import net.minecraft.core.world.noise.PerlinNoise;
+import net.minecraft.core.world.noise.FractalNoise2D;
+import net.minecraft.core.world.noise.FractalNoise3D;
+import net.minecraft.core.world.noise.ImprovedPerlinNoise;
+import net.minecraft.core.world.noise.Noise2D;
 import org.jetbrains.annotations.NotNull;
 
 import java.util.Random;
@@ -16,11 +19,11 @@ import java.util.Random;
 public class ChunkDecoratorNether
     implements ChunkDecorator {
     private final @NotNull World world;
-    private final @NotNull PerlinNoise crystalDensityNoise;
+    private final @NotNull Noise2D crystalDensityNoise;
 
     public ChunkDecoratorNether(@NotNull World world) {
         this.world = world;
-        this.crystalDensityNoise = new PerlinNoise(world.getRandomSeed(), 6, 74);
+        this.crystalDensityNoise = new FractalNoise2D<>(ImprovedPerlinNoise.genOctaves(world.getRandomSeed(), 6, 74));
     }
 
     @Override
diff --git a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/nether/DensityGeneratorNether.java b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/nether/DensityGeneratorNether.java
index c43c0e0e9..cf29fbf42 100644
--- a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/nether/DensityGeneratorNether.java
+++ b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/nether/DensityGeneratorNether.java
@@ -7,14 +7,12 @@ import net.minecraft.core.world.biome.Biomes;
 import net.minecraft.core.world.biome.provider.BiomeProviderNether;
 import net.minecraft.core.world.chunk.Chunk;
 import net.minecraft.core.world.generate.chunk.perlin.DensityGenerator;
-import net.minecraft.core.world.noise.PerlinNoise;
-import net.minecraft.core.world.noise.PerlinSimplexNoise;
+import net.minecraft.core.world.noise.*;
 import net.minecraft.core.world.type.WorldType;
 import org.jetbrains.annotations.NotNull;
 
 import java.util.HashMap;
 import java.util.Map;
-import java.util.Random;
 
 public class DensityGeneratorNether
     implements DensityGenerator {
@@ -24,37 +22,36 @@ public class DensityGeneratorNether
 
     private final @NotNull World world;
 
-    private final @NotNull PerlinNoise minLimitNoise;
-    private final @NotNull PerlinNoise maxLimitNoise;
-    private final @NotNull PerlinNoise mainNoise;
-    private final @NotNull PerlinNoise scaleNoise;
-    private final @NotNull PerlinNoise depthNoise;
+    private final @NotNull Noise3D minLimitNoise;
+    private final @NotNull Noise3D maxLimitNoise;
+    private final @NotNull Noise3D mainNoise;
+    private final @NotNull Noise2D scaleNoise;
+    private final @NotNull Noise2D depthNoise;
 
-    private final @NotNull PerlinSimplexNoise poolNoiseOver;
-    private final @NotNull PerlinSimplexNoise poolNoiseUnder;
+    private final @NotNull FractalNoise2D<?> poolNoiseOver;
+    private final @NotNull FractalNoise2D<?> poolNoiseUnder;
 
-    private final @NotNull PerlinSimplexNoise ravineNoise2;
+    private final @NotNull FractalNoise2D<?> ravineNoise2;
 
-    private final @NotNull PerlinSimplexNoise islandNoise;
+    private final @NotNull FractalNoise2D<?> islandNoise;
 
     private final @NotNull Map<@NotNull Biome, @NotNull BiomeDensityGenerator> densityGeneratorMap = new HashMap<>();
 
     public DensityGeneratorNether(World world) {
         this.world = world;
 
-        this.minLimitNoise = new PerlinNoise(world.getRandomSeed(), 16, 0);
-        this.maxLimitNoise = new PerlinNoise(world.getRandomSeed(), 16, 16);
-        this.mainNoise = new PerlinNoise(world.getRandomSeed(), 8, 32);
-        this.scaleNoise = new PerlinNoise(world.getRandomSeed(), 10, 48);
-        this.depthNoise = new PerlinNoise(world.getRandomSeed(), 16, 58);
+        this.minLimitNoise = new FractalNoise3D<>(ImprovedPerlinNoise.genOctaves(world.getRandomSeed(), 16, 0));
+        this.maxLimitNoise = new FractalNoise3D<>(ImprovedPerlinNoise.genOctaves(world.getRandomSeed(), 16, 16));
+        this.mainNoise = new FractalNoise3D<>(ImprovedPerlinNoise.genOctaves(world.getRandomSeed(), 8, 32));
+        this.scaleNoise = new FractalNoise3D<>(ImprovedPerlinNoise.genOctaves(world.getRandomSeed(), 10, 48));
+        this.depthNoise = new FractalNoise3D<>(ImprovedPerlinNoise.genOctaves(world.getRandomSeed(), 16, 58));
 
-        Random rand = new Random(world.getRandomSeed());
+        final long seed = world.getRandomSeed();
 
-        this.islandNoise = new PerlinSimplexNoise(rand, 6);
-        this.ravineNoise2 = new PerlinSimplexNoise(rand, 4);
-
-        this.poolNoiseOver = new PerlinSimplexNoise(rand, 4);
-        this.poolNoiseUnder = new PerlinSimplexNoise(rand, 1);
+        this.islandNoise = new FractalNoise3D<>(SimplexNoise.genOctaves(seed, 6, 0));
+        this.ravineNoise2 = new FractalNoise3D<>(SimplexNoise.genOctaves(seed, 4, 6));
+        this.poolNoiseOver = new FractalNoise3D<>(SimplexNoise.genOctaves(seed, 4, 10));
+        this.poolNoiseUnder = new FractalNoise3D<>(SimplexNoise.genOctaves(seed, 1, 14));
 
         this.densityGeneratorMap.put(Biomes.NETHER_NETHER, this::generateDensityMapBiomeNether);
         this.densityGeneratorMap.put(Biomes.NETHER_VOLCANIC_ISLANDS, this::generateDensityMapBiomeNether);
@@ -230,7 +227,7 @@ public class DensityGeneratorNether
         double[] minLimitArray = this.minLimitNoise.getRegion(null, x, y, z, xSize, ySize, zSize, coordScale, heightScale, coordScale);
         double[] maxLimitArray = this.maxLimitNoise.getRegion(null, x, y, z, xSize, ySize, zSize, coordScale, heightScale, coordScale);
 
-        double[] ravineNoise = this.ravineNoise2.getRegion(null, x, z, xSize, zSize, ravineNoiseScale, ravineNoiseScale, 3.0D, 3.0D);
+        double[] ravineNoise = this.ravineNoise2.setLacunarity(3.0).setPersistence(3.0).getRegion(null, x, z, xSize, zSize, ravineNoiseScale, ravineNoiseScale);
 //        double[] ravineMod = ravineNoise2.getValue(null, x, z, xSize, zSize, ravineNoiseScale, ravineNoiseScale, 0.25D, 0.6D);
 
         int mainIndex = 0;
@@ -356,7 +353,7 @@ public class DensityGeneratorNether
         double[] mainNoiseArray = this.mainNoise.getRegion(null, x, y, z, xSize, ySize, zSize, coordScale / mainNoiseScaleX, heightScale / mainNoiseScaleY, coordScale / mainNoiseScaleZ);
         double[] minLimitArray = this.minLimitNoise.getRegion(null, x, y, z, xSize, ySize, zSize, coordScale, heightScale, coordScale);
         double[] maxLimitArray = this.maxLimitNoise.getRegion(null, x, y, z, xSize, ySize, zSize, coordScale, heightScale, coordScale);
-        double[] islandNoiseArray = this.islandNoise.getRegion(null, x, z, xSize, zSize, noiseScale, noiseScale, 2, 2);
+        double[] islandNoiseArray = this.islandNoise.setLacunarity(2.0).setPersistence(2.0).getRegion(null, x, z, xSize, zSize, noiseScale, noiseScale);
 
         int mainIndex = 0;
 
@@ -576,8 +573,8 @@ public class DensityGeneratorNether
         double[] mainNoiseArray = this.mainNoise.getRegion(null, x, y, z, xSize, ySize, zSize, coordScale / mainNoiseScaleX, heightScale / mainNoiseScaleY, coordScale / mainNoiseScaleZ);
         double[] minLimitArray = this.minLimitNoise.getRegion(null, x, y, z, xSize, ySize, zSize, coordScale, heightScale, coordScale);
         double[] maxLimitArray = this.maxLimitNoise.getRegion(null, x, y, z, xSize, ySize, zSize, coordScale, heightScale, coordScale);
-        double[] poolOverArray = this.poolNoiseOver.getRegion(null, x, z, xSize, zSize, poolNoiseScale, poolNoiseScale, 1, 0.2);
-        double[] poolUnderArray = this.poolNoiseUnder.getRegion(null, x, z, xSize, zSize, poolNoiseScale, poolNoiseScale, 0.01, 1);
+        double[] poolOverArray = this.poolNoiseOver.setLacunarity(1.0).setPersistence(0.2).getRegion(null, x, z, xSize, zSize, poolNoiseScale, poolNoiseScale);
+        double[] poolUnderArray = this.poolNoiseUnder.setLacunarity(0.01).setPersistence(1.0).getRegion(null, x, z, xSize, zSize, poolNoiseScale, poolNoiseScale);
         int mainIndex = 0;
 
         int depthScaleIndex = 0;
diff --git a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/nether/SurfaceGeneratorNether.java b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/nether/SurfaceGeneratorNether.java
index 945bdef32..39d364b46 100644
--- a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/nether/SurfaceGeneratorNether.java
+++ b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/nether/SurfaceGeneratorNether.java
@@ -7,7 +7,8 @@ import net.minecraft.core.world.biome.Biomes;
 import net.minecraft.core.world.chunk.Chunk;
 import net.minecraft.core.world.generate.chunk.ChunkGeneratorResult;
 import net.minecraft.core.world.generate.chunk.perlin.SurfaceGenerator;
-import net.minecraft.core.world.noise.PerlinNoise;
+import net.minecraft.core.world.noise.FractalNoise3D;
+import net.minecraft.core.world.noise.ImprovedPerlinNoise;
 import org.jetbrains.annotations.NotNull;
 
 import java.util.Random;
@@ -16,14 +17,14 @@ public class SurfaceGeneratorNether
     implements SurfaceGenerator {
     private final @NotNull World world;
 
-    private final @NotNull PerlinNoise beachNoise;
-    private final @NotNull PerlinNoise soilNoise;
+    private final @NotNull FractalNoise3D<ImprovedPerlinNoise> beachNoise;
+    private final @NotNull FractalNoise3D<ImprovedPerlinNoise> soilNoise;
 
     public SurfaceGeneratorNether(@NotNull World world) {
         this.world = world;
 
-        this.beachNoise = new PerlinNoise(world.getRandomSeed(), 4, 40);
-        this.soilNoise = new PerlinNoise(world.getRandomSeed(), 4, 44);
+        this.beachNoise = new FractalNoise3D<>(ImprovedPerlinNoise.genOctaves(world.getRandomSeed(), 4, 40));
+        this.soilNoise = new FractalNoise3D<>(ImprovedPerlinNoise.genOctaves(world.getRandomSeed(), 4, 44));
     }
 
     @Override
diff --git a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/nether/TerrainGeneratorNether.java b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/nether/TerrainGeneratorNether.java
index 559c013c1..616e14710 100644
--- a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/nether/TerrainGeneratorNether.java
+++ b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/nether/TerrainGeneratorNether.java
@@ -10,7 +10,9 @@ import net.minecraft.core.world.chunk.Chunk;
 import net.minecraft.core.world.chunk.ChunkSection;
 import net.minecraft.core.world.generate.chunk.perlin.DensityGenerator;
 import net.minecraft.core.world.generate.chunk.perlin.TerrainGeneratorLerp;
-import net.minecraft.core.world.noise.PerlinNoise;
+import net.minecraft.core.world.noise.FractalNoise3D;
+import net.minecraft.core.world.noise.ImprovedPerlinNoise;
+import net.minecraft.core.world.noise.Noise3D;
 import net.minecraft.core.world.type.WorldType;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
@@ -29,7 +31,7 @@ public class TerrainGeneratorNether
     private final Object2IntMap<Biome> fluidLookup = new Object2IntArrayMap<>();
     private int lastChunkX = Integer.MIN_VALUE;
     private int lastChunkZ = Integer.MIN_VALUE;
-    private final @NotNull PerlinNoise noise = new PerlinNoise(0L, 4, 0);
+    private final @NotNull Noise3D noise = new FractalNoise3D<>(ImprovedPerlinNoise.genOctaves(0L, 4, 0));
     private final double @NotNull [] cache = new double[Chunk.CHUNK_SIZE_X * Chunk.CHUNK_SIZE_Z * (Chunk.CHUNK_SECTIONS * ChunkSection.SECTION_SIZE_Y)];
 
     public TerrainGeneratorNether(@NotNull World world) {
diff --git a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/ChunkDecoratorOverworld.java b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/ChunkDecoratorOverworld.java
index 8d2144ccd..ec2dbef7a 100644
--- a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/ChunkDecoratorOverworld.java
+++ b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/ChunkDecoratorOverworld.java
@@ -13,7 +13,9 @@ import net.minecraft.core.block.Blocks;
 import net.minecraft.core.block.material.Materials;
 import net.minecraft.core.world.World;
 import net.minecraft.core.world.biome.Biomes;
-import net.minecraft.core.world.noise.PerlinNoise;
+import net.minecraft.core.world.noise.FractalNoise2D;
+import net.minecraft.core.world.noise.FractalNoise3D;
+import net.minecraft.core.world.noise.ImprovedPerlinNoise;
 import net.minecraft.core.world.type.WorldTypes;
 import net.minecraft.core.world.biome.Biome;
 import net.minecraft.core.world.biome.overworld.BiomeOutback;
@@ -27,14 +29,14 @@ import java.util.Random;
 public class ChunkDecoratorOverworld
     implements ChunkDecorator {
     private final @NotNull World world;
-    private final @NotNull PerlinNoise treeDensityNoise;
+    private final @NotNull FractalNoise2D<ImprovedPerlinNoise> treeDensityNoise;
     private final int treeDensityOverride;
 
     protected ChunkDecoratorOverworld(@NotNull World world, int treeDensityOverride) {
         this.world = world;
         this.treeDensityOverride = treeDensityOverride;
 
-        this.treeDensityNoise = new PerlinNoise(world.getRandomSeed(), 8, 74);
+        this.treeDensityNoise = new FractalNoise2D<>(ImprovedPerlinNoise.genOctaves(world.getRandomSeed(), 8, 74));
     }
 
     public ChunkDecoratorOverworld(@NotNull World world) {
diff --git a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/DensityGeneratorOverworld.java b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/DensityGeneratorOverworld.java
index 74e17969a..857db278a 100644
--- a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/DensityGeneratorOverworld.java
+++ b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/DensityGeneratorOverworld.java
@@ -1,33 +1,33 @@
 package net.minecraft.core.world.generate.chunk.perlin.overworld;
 
 import net.minecraft.core.world.World;
+import net.minecraft.core.world.noise.*;
 import net.minecraft.core.world.type.WorldTypes;
 import net.minecraft.core.world.chunk.Chunk;
 import net.minecraft.core.world.generate.chunk.perlin.DensityGenerator;
-import net.minecraft.core.world.noise.PerlinNoise;
 import org.jetbrains.annotations.NotNull;
 
 public class DensityGeneratorOverworld
     implements DensityGenerator {
     private final @NotNull World world;
 
-    private final @NotNull PerlinNoise minLimitNoise;
-    private final @NotNull PerlinNoise maxLimitNoise;
-    private final @NotNull PerlinNoise mainNoise;
-    private final @NotNull PerlinNoise scaleNoise;
-    private final @NotNull PerlinNoise depthNoise;
+    private final @NotNull Noise3D minLimitNoise;
+    private final @NotNull Noise3D maxLimitNoise;
+    private final @NotNull Noise3D mainNoise;
+    private final @NotNull Noise2D scaleNoise;
+    private final @NotNull Noise2D depthNoise;
 
     private final boolean generateRivers;
-    private final @NotNull PerlinNoise smoothingRiverNoise;
-    private final @NotNull PerlinNoise carvingRiverNoise;
+    private final @NotNull Noise2D smoothingRiverNoise;
+    private final @NotNull Noise2D carvingRiverNoise;
 
     protected DensityGeneratorOverworld(
         @NotNull World world,
-        @NotNull PerlinNoise minLimitNoise,
-        @NotNull PerlinNoise maxLimitNoise,
-        @NotNull PerlinNoise mainNoise,
-        @NotNull PerlinNoise scaleNoise,
-        @NotNull PerlinNoise depthNoise,
+        @NotNull Noise3D minLimitNoise,
+        @NotNull Noise3D maxLimitNoise,
+        @NotNull Noise3D mainNoise,
+        @NotNull Noise2D scaleNoise,
+        @NotNull Noise2D depthNoise,
         boolean generateRivers
     ) {
         this.world = world;
@@ -39,17 +39,17 @@ public class DensityGeneratorOverworld
         this.depthNoise = depthNoise;
 
         this.generateRivers = generateRivers;
-        this.smoothingRiverNoise = new PerlinNoise(world.getRandomSeed(), 1);
-        this.carvingRiverNoise = new PerlinNoise(world.getRandomSeed() + 1, 1);
+        this.smoothingRiverNoise = new FractalNoise2D<>(ImprovedPerlinNoise.genOctaves(world.getRandomSeed(), 1));
+        this.carvingRiverNoise = new FractalNoise2D<>(ImprovedPerlinNoise.genOctaves(world.getRandomSeed() + 1, 1));
     }
 
     public DensityGeneratorOverworld(@NotNull World world) {
         this(world,
-            new PerlinNoise(world.getRandomSeed(), 16, 0),
-            new PerlinNoise(world.getRandomSeed(), 16, 16),
-            new PerlinNoise(world.getRandomSeed(), 8, 32),
-            new PerlinNoise(world.getRandomSeed(), 10, 48),
-            new PerlinNoise(world.getRandomSeed(), 16, 58),
+            new FractalNoise3D<>(ImprovedPerlinNoise.genOctaves(world.getRandomSeed(), 16, 0)),
+            new FractalNoise3D<>(ImprovedPerlinNoise.genOctaves(world.getRandomSeed(), 16, 16)),
+            new FractalNoise3D<>(ImprovedPerlinNoise.genOctaves(world.getRandomSeed(), 8, 32)),
+            new FractalNoise2D<>(ImprovedPerlinNoise.genOctaves(world.getRandomSeed(), 10, 48)),
+            new FractalNoise2D<>(ImprovedPerlinNoise.genOctaves(world.getRandomSeed(), 16, 58)),
             true
         );
     }
diff --git a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/SurfaceGeneratorOverworld.java b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/SurfaceGeneratorOverworld.java
index 45c116ed5..f9c10f834 100644
--- a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/SurfaceGeneratorOverworld.java
+++ b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/SurfaceGeneratorOverworld.java
@@ -9,7 +9,7 @@ import net.minecraft.core.world.biome.Biomes;
 import net.minecraft.core.world.chunk.Chunk;
 import net.minecraft.core.world.generate.chunk.ChunkGeneratorResult;
 import net.minecraft.core.world.generate.chunk.perlin.SurfaceGenerator;
-import net.minecraft.core.world.noise.PerlinNoise;
+import net.minecraft.core.world.noise.*;
 import org.jetbrains.annotations.NotNull;
 
 public class SurfaceGeneratorOverworld
@@ -17,14 +17,19 @@ public class SurfaceGeneratorOverworld
 {
     private final World world;
 
-    private final PerlinNoise beachNoise;
-    private final PerlinNoise soilNoise;
-    private final PerlinNoise mainNoise;
+    private final Noise3D beachNoise;
+    private final Noise3D soilNoise;
+    private final Noise3D mainNoise;
 
     private final boolean generateStoneVariants;
 
-    protected SurfaceGeneratorOverworld(World world, PerlinNoise beachNoise, PerlinNoise soilNoise, PerlinNoise mainNoise, boolean generateStoneVariants)
-    {
+    protected SurfaceGeneratorOverworld(
+        World world,
+        Noise3D beachNoise,
+        Noise3D soilNoise,
+        Noise3D mainNoise,
+        boolean generateStoneVariants
+    ) {
         this.world = world;
         this.beachNoise = beachNoise;
         this.soilNoise = soilNoise;
@@ -35,9 +40,9 @@ public class SurfaceGeneratorOverworld
     public SurfaceGeneratorOverworld(World world)
     {
         this(world,
-             new PerlinNoise(world.getRandomSeed(), 4, 40),
-             new PerlinNoise(world.getRandomSeed(), 4, 44),
-             new PerlinNoise(world.getRandomSeed(), 8, 32),
+             new FractalNoise3D<>(ImprovedPerlinNoise.genOctaves(world.getRandomSeed(), 4, 40)),
+             new FractalNoise3D<>(ImprovedPerlinNoise.genOctaves(world.getRandomSeed(), 4, 44)),
+             new FractalNoise3D<>(ImprovedPerlinNoise.genOctaves(world.getRandomSeed(), 8, 32)),
              true
         );
     }
diff --git a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/b173/ChunkDecoratorOverworldB173.java b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/b173/ChunkDecoratorOverworldB173.java
index 973d8438e..9c3ce9602 100644
--- a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/b173/ChunkDecoratorOverworldB173.java
+++ b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/b173/ChunkDecoratorOverworldB173.java
@@ -8,8 +8,9 @@ import net.minecraft.core.world.biome.Biomes;
 import net.minecraft.core.world.chunk.Chunk;
 import net.minecraft.core.world.generate.chunk.ChunkDecorator;
 import net.minecraft.core.world.generate.feature.*;
-import net.minecraft.core.world.noise.LegacyNoiseType;
-import net.minecraft.core.world.noise.PerlinNoise;
+import net.minecraft.core.world.noise.FractalNoise2D;
+import net.minecraft.core.world.noise.FractalNoise3D;
+import net.minecraft.core.world.noise.ImprovedPerlinNoise;
 import org.jetbrains.annotations.NotNull;
 
 import java.util.Random;
@@ -17,12 +18,12 @@ import java.util.Random;
 public class ChunkDecoratorOverworldB173
     implements ChunkDecorator {
     private final @NotNull World world;
-    private final @NotNull PerlinNoise forestNoise;
+    private final @NotNull FractalNoise2D<ImprovedPerlinNoise> forestNoise;
 
     public ChunkDecoratorOverworldB173(final @NotNull World world) {
         this.world = world;
 
-        this.forestNoise = new PerlinNoise(world.getRandomSeed(), 8, 82, LegacyNoiseType.BETA);
+        this.forestNoise = new FractalNoise2D<>(ImprovedPerlinNoise.genOctaves(world.getRandomSeed(), 8, 82, ImprovedPerlinNoise.LegacyNoiseType.BETA));
     }
 
     @Override
diff --git a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/b173/DensityGeneratorOverworldB173.java b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/b173/DensityGeneratorOverworldB173.java
index 49b398e2b..7c009e847 100644
--- a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/b173/DensityGeneratorOverworldB173.java
+++ b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/b173/DensityGeneratorOverworldB173.java
@@ -2,8 +2,9 @@ package net.minecraft.core.world.generate.chunk.perlin.overworld.b173;
 
 import net.minecraft.core.world.World;
 import net.minecraft.core.world.generate.chunk.perlin.overworld.DensityGeneratorOverworld;
-import net.minecraft.core.world.noise.LegacyNoiseType;
-import net.minecraft.core.world.noise.PerlinNoise;
+import net.minecraft.core.world.noise.FractalNoise2D;
+import net.minecraft.core.world.noise.FractalNoise3D;
+import net.minecraft.core.world.noise.ImprovedPerlinNoise;
 import org.jetbrains.annotations.NotNull;
 
 public class DensityGeneratorOverworldB173
@@ -11,11 +12,11 @@ public class DensityGeneratorOverworldB173
 
     public DensityGeneratorOverworldB173(final @NotNull World world) {
         super(world,
-            new PerlinNoise(world.getRandomSeed(), 16, 0, LegacyNoiseType.BETA),
-            new PerlinNoise(world.getRandomSeed(), 16, 16, LegacyNoiseType.BETA),
-            new PerlinNoise(world.getRandomSeed(), 8, 32, LegacyNoiseType.BETA),
-            new PerlinNoise(world.getRandomSeed(), 10, 48, LegacyNoiseType.BETA),
-            new PerlinNoise(world.getRandomSeed(), 16, 58, LegacyNoiseType.BETA),
+            new FractalNoise3D<>(ImprovedPerlinNoise.genOctaves(world.getRandomSeed(), 16, 0)),
+            new FractalNoise3D<>(ImprovedPerlinNoise.genOctaves(world.getRandomSeed(), 16, 16)),
+            new FractalNoise3D<>(ImprovedPerlinNoise.genOctaves(world.getRandomSeed(), 8, 32)),
+            new FractalNoise2D<>(ImprovedPerlinNoise.genOctaves(world.getRandomSeed(), 10, 48)),
+            new FractalNoise2D<>(ImprovedPerlinNoise.genOctaves(world.getRandomSeed(), 16, 58)),
             false
         );
     }
diff --git a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/b173/SurfaceGeneratorOverworldB173.java b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/b173/SurfaceGeneratorOverworldB173.java
index add4478aa..975fe9c46 100644
--- a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/b173/SurfaceGeneratorOverworldB173.java
+++ b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/b173/SurfaceGeneratorOverworldB173.java
@@ -2,17 +2,18 @@ package net.minecraft.core.world.generate.chunk.perlin.overworld.b173;
 
 import net.minecraft.core.world.World;
 import net.minecraft.core.world.generate.chunk.perlin.overworld.SurfaceGeneratorOverworld;
-import net.minecraft.core.world.noise.LegacyNoiseType;
-import net.minecraft.core.world.noise.PerlinNoise;
+import net.minecraft.core.world.noise.FractalNoise2D;
+import net.minecraft.core.world.noise.FractalNoise3D;
+import net.minecraft.core.world.noise.ImprovedPerlinNoise;
 import org.jetbrains.annotations.NotNull;
 
 public class SurfaceGeneratorOverworldB173
     extends SurfaceGeneratorOverworld {
     public SurfaceGeneratorOverworldB173(final @NotNull World world) {
         super(world,
-            new PerlinNoise(world.getRandomSeed(), 4, 40, LegacyNoiseType.BETA),
-            new PerlinNoise(world.getRandomSeed(), 4, 44, LegacyNoiseType.BETA),
-            new PerlinNoise(world.getRandomSeed(), 8, 32, LegacyNoiseType.BETA),
+            new FractalNoise3D<>(ImprovedPerlinNoise.genOctaves(world.getRandomSeed(), 4, 40, ImprovedPerlinNoise.LegacyNoiseType.BETA)),
+            new FractalNoise3D<>(ImprovedPerlinNoise.genOctaves(world.getRandomSeed(), 4, 44, ImprovedPerlinNoise.LegacyNoiseType.BETA)),
+            new FractalNoise3D<>(ImprovedPerlinNoise.genOctaves(world.getRandomSeed(), 8, 32, ImprovedPerlinNoise.LegacyNoiseType.BETA)),
             false
         );
     }
diff --git a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/hell/ChunkDecoratorOverworldHell.java b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/hell/ChunkDecoratorOverworldHell.java
index 493abff0f..f1723b767 100644
--- a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/hell/ChunkDecoratorOverworldHell.java
+++ b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/hell/ChunkDecoratorOverworldHell.java
@@ -13,16 +13,18 @@ import net.minecraft.core.world.generate.chunk.ChunkFeatureDecorator;
 import net.minecraft.core.world.generate.feature.*;
 import net.minecraft.core.world.generate.feature.tree.WorldFeatureTree;
 import net.minecraft.core.world.generate.feature.tree.WorldFeatureTreeFancy;
-import net.minecraft.core.world.noise.PerlinNoise;
+import net.minecraft.core.world.noise.FractalNoise2D;
+import net.minecraft.core.world.noise.FractalNoise3D;
+import net.minecraft.core.world.noise.ImprovedPerlinNoise;
 import org.jetbrains.annotations.NotNull;
 
 public class ChunkDecoratorOverworldHell
     extends ChunkFeatureDecorator {
-    private final @NotNull PerlinNoise treeDensityNoise;
+    private final @NotNull FractalNoise2D<ImprovedPerlinNoise> treeDensityNoise;
 
     public ChunkDecoratorOverworldHell(final @NotNull World world) {
         super(world);
-        this.treeDensityNoise = new PerlinNoise(world.getRandomSeed(), 8, 74);
+        this.treeDensityNoise = new FractalNoise2D<>(ImprovedPerlinNoise.genOctaves(world.getRandomSeed(), 8, 74));
     }
 
     @Override
diff --git a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/retro/ChunkDecoratorOverworldRetro.java b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/retro/ChunkDecoratorOverworldRetro.java
index fa68e82fa..dcc1771f2 100644
--- a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/retro/ChunkDecoratorOverworldRetro.java
+++ b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/retro/ChunkDecoratorOverworldRetro.java
@@ -14,8 +14,9 @@ import net.minecraft.core.world.generate.chunk.ChunkDecorator;
 import net.minecraft.core.world.generate.feature.*;
 import net.minecraft.core.world.generate.feature.tree.WorldFeatureTree;
 import net.minecraft.core.world.generate.feature.tree.WorldFeatureTreeFancy;
-import net.minecraft.core.world.noise.LegacyNoiseType;
-import net.minecraft.core.world.noise.PerlinNoise;
+import net.minecraft.core.world.noise.FractalNoise2D;
+import net.minecraft.core.world.noise.FractalNoise3D;
+import net.minecraft.core.world.noise.ImprovedPerlinNoise;
 import org.jetbrains.annotations.NotNull;
 
 import java.util.Random;
@@ -23,14 +24,14 @@ import java.util.Random;
 public class ChunkDecoratorOverworldRetro
     implements ChunkDecorator {
     private final @NotNull World world;
-    private final @NotNull PerlinNoise treeDensityNoise;
+    private final @NotNull FractalNoise2D<ImprovedPerlinNoise> treeDensityNoise;
 
     private final boolean snowCovered;
 
     public ChunkDecoratorOverworldRetro(@NotNull World world) {
         this.world = world;
 
-        this.treeDensityNoise = new PerlinNoise(world.getRandomSeed(), 8, 74, LegacyNoiseType.ALPHA);
+        this.treeDensityNoise = new FractalNoise2D<>(ImprovedPerlinNoise.genOctaves(world.getRandomSeed(), 8, 74, ImprovedPerlinNoise.LegacyNoiseType.ALPHA));
 
         this.snowCovered = false;//new Random(world.getRandomSeed()).nextBoolean();
     }
diff --git a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/retro/DensityGeneratorOverworldRetro.java b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/retro/DensityGeneratorOverworldRetro.java
index e7f96ccc2..64a4d79cd 100644
--- a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/retro/DensityGeneratorOverworldRetro.java
+++ b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/retro/DensityGeneratorOverworldRetro.java
@@ -2,19 +2,20 @@ package net.minecraft.core.world.generate.chunk.perlin.overworld.retro;
 
 import net.minecraft.core.world.World;
 import net.minecraft.core.world.generate.chunk.perlin.overworld.DensityGeneratorOverworld;
-import net.minecraft.core.world.noise.LegacyNoiseType;
-import net.minecraft.core.world.noise.PerlinNoise;
+import net.minecraft.core.world.noise.FractalNoise2D;
+import net.minecraft.core.world.noise.FractalNoise3D;
+import net.minecraft.core.world.noise.ImprovedPerlinNoise;
 import org.jetbrains.annotations.NotNull;
 
 public class DensityGeneratorOverworldRetro
     extends DensityGeneratorOverworld {
     public DensityGeneratorOverworldRetro(@NotNull World world) {
         super(world,
-            new PerlinNoise(world.getRandomSeed(), 16, 0, LegacyNoiseType.ALPHA),
-            new PerlinNoise(world.getRandomSeed(), 16, 16, LegacyNoiseType.ALPHA),
-            new PerlinNoise(world.getRandomSeed(), 8, 32, LegacyNoiseType.ALPHA),
-            new PerlinNoise(world.getRandomSeed(), 10, 48, LegacyNoiseType.ALPHA),
-            new PerlinNoise(world.getRandomSeed(), 16, 58, LegacyNoiseType.ALPHA),
+            new FractalNoise3D<>(ImprovedPerlinNoise.genOctaves(world.getRandomSeed(), 16, 0)),
+            new FractalNoise3D<>(ImprovedPerlinNoise.genOctaves(world.getRandomSeed(), 16, 16)),
+            new FractalNoise3D<>(ImprovedPerlinNoise.genOctaves(world.getRandomSeed(), 8, 32)),
+            new FractalNoise2D<>(ImprovedPerlinNoise.genOctaves(world.getRandomSeed(), 10, 48)),
+            new FractalNoise2D<>(ImprovedPerlinNoise.genOctaves(world.getRandomSeed(), 16, 58)),
             false
         );
     }
diff --git a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/retro/SurfaceGeneratorOverworldRetro.java b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/retro/SurfaceGeneratorOverworldRetro.java
index ec1e983d9..0f7d2cd3a 100644
--- a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/retro/SurfaceGeneratorOverworldRetro.java
+++ b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/retro/SurfaceGeneratorOverworldRetro.java
@@ -2,17 +2,17 @@ package net.minecraft.core.world.generate.chunk.perlin.overworld.retro;
 
 import net.minecraft.core.world.World;
 import net.minecraft.core.world.generate.chunk.perlin.overworld.SurfaceGeneratorOverworld;
-import net.minecraft.core.world.noise.LegacyNoiseType;
-import net.minecraft.core.world.noise.PerlinNoise;
+import net.minecraft.core.world.noise.FractalNoise3D;
+import net.minecraft.core.world.noise.ImprovedPerlinNoise;
 import org.jetbrains.annotations.NotNull;
 
 public class SurfaceGeneratorOverworldRetro
     extends SurfaceGeneratorOverworld {
     public SurfaceGeneratorOverworldRetro(@NotNull World world) {
         super(world,
-            new PerlinNoise(world.getRandomSeed(), 4, 40, LegacyNoiseType.ALPHA),
-            new PerlinNoise(world.getRandomSeed(), 4, 44, LegacyNoiseType.ALPHA),
-            new PerlinNoise(world.getRandomSeed(), 8, 32, LegacyNoiseType.ALPHA),
+            new FractalNoise3D<>(ImprovedPerlinNoise.genOctaves(world.getRandomSeed(), 4, 40, ImprovedPerlinNoise.LegacyNoiseType.ALPHA)),
+            new FractalNoise3D<>(ImprovedPerlinNoise.genOctaves(world.getRandomSeed(), 4, 44, ImprovedPerlinNoise.LegacyNoiseType.ALPHA)),
+            new FractalNoise3D<>(ImprovedPerlinNoise.genOctaves(world.getRandomSeed(), 8, 32, ImprovedPerlinNoise.LegacyNoiseType.ALPHA)),
             false
         );
     }
diff --git a/game/core/src/main/java/net/minecraft/core/world/generate/feature/WorldFeatureMudPatch.java b/game/core/src/main/java/net/minecraft/core/world/generate/feature/WorldFeatureMudPatch.java
index 46f213224..aa5b02e60 100644
--- a/game/core/src/main/java/net/minecraft/core/world/generate/feature/WorldFeatureMudPatch.java
+++ b/game/core/src/main/java/net/minecraft/core/world/generate/feature/WorldFeatureMudPatch.java
@@ -2,13 +2,13 @@ package net.minecraft.core.world.generate.feature;
 
 import net.minecraft.core.block.Blocks;
 import net.minecraft.core.world.World;
-import net.minecraft.core.world.noise.ImprovedNoise;
+import net.minecraft.core.world.noise.ImprovedPerlinNoise;
 
 import java.util.Random;
 
 public class WorldFeatureMudPatch extends WorldFeature
 {
-    private static final ImprovedNoise noise = new ImprovedNoise(new Random(0));
+    private static final ImprovedPerlinNoise noise = new ImprovedPerlinNoise(new Random(0));
 
     @Override
 	public boolean place(World world, Random random, int x, int y, int z) {
diff --git a/game/core/src/main/java/net/minecraft/core/world/noise/CombinedPerlinNoise.java b/game/core/src/main/java/net/minecraft/core/world/noise/CombinedPerlinNoise.java
deleted file mode 100644
index b71b4b2ab..000000000
--- a/game/core/src/main/java/net/minecraft/core/world/noise/CombinedPerlinNoise.java
+++ /dev/null
@@ -1,17 +0,0 @@
-package net.minecraft.core.world.noise;
-
-import org.jetbrains.annotations.NotNull;
-
-public class CombinedPerlinNoise {
-    private final @NotNull PerlinNoise perlinNoiseA;
-    private final @NotNull PerlinNoise perlinNoiseB;
-
-    public CombinedPerlinNoise(final @NotNull PerlinNoise perlinNoiseA, final @NotNull PerlinNoise perlinNoiseB) {
-        this.perlinNoiseA = perlinNoiseA;
-        this.perlinNoiseB = perlinNoiseB;
-    }
-
-    public double get(final double x, final double y) {
-        return this.perlinNoiseA.getValue(x + this.perlinNoiseB.getValue(x, y), y);
-    }
-}
diff --git a/game/core/src/main/java/net/minecraft/core/world/noise/FractalBrownianNoise.java b/game/core/src/main/java/net/minecraft/core/world/noise/FractalBrownianNoise.java
deleted file mode 100644
index 90db48580..000000000
--- a/game/core/src/main/java/net/minecraft/core/world/noise/FractalBrownianNoise.java
+++ /dev/null
@@ -1,4 +0,0 @@
-package net.minecraft.core.world.noise;
-
-public class FractalBrownianNoise {
-}
diff --git a/game/core/src/main/java/net/minecraft/core/world/noise/FractalNoise2D.java b/game/core/src/main/java/net/minecraft/core/world/noise/FractalNoise2D.java
new file mode 100644
index 000000000..9e86a5bb6
--- /dev/null
+++ b/game/core/src/main/java/net/minecraft/core/world/noise/FractalNoise2D.java
@@ -0,0 +1,66 @@
+package net.minecraft.core.world.noise;
+
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+public class FractalNoise2D<T extends Noise2D>
+    implements Noise2D {
+    public static final double DEFAULT_LACUNARITY = 0.5;
+    public static final double DEFAULT_PERSISTENCE = 2.0;
+
+    protected final @NotNull T @NotNull [] octaves;
+
+    protected double lacunarity = DEFAULT_LACUNARITY;
+    protected double persistence = DEFAULT_PERSISTENCE;
+
+    public FractalNoise2D(final @NotNull T @NotNull [] octaves) {
+        this.octaves = octaves;
+    }
+
+    public final @NotNull FractalNoise2D<T> setLacunarity(final double lacunarity) {
+        this.lacunarity = lacunarity;
+        return this;
+    }
+
+    public final @NotNull FractalNoise2D<T> setPersistence(final double persistence) {
+        this.persistence = persistence;
+        return this;
+    }
+
+    @Override
+    public double getValue(final double x, final double z) {
+        double out = 0.0;
+        double frequency = 1.0;
+        double amplitude = 1.0;
+
+        for (final @NotNull T octave : this.octaves) {
+            out += octave.getValue(x * frequency, z * frequency) * amplitude;
+            frequency *= this.lacunarity;
+            amplitude *= this.persistence;
+        }
+
+        return out;
+    }
+
+    @Override
+    public double @NotNull [] addRegion(
+        double @Nullable [] out,
+        final double x, final double z,
+        final int xSize, final int zSize,
+        final double xScale, final double zScale,
+        double amplitude
+    ) {
+        if (out == null || out.length < xSize * zSize) {
+            out = new double[xSize * zSize];
+        }
+
+        double frequency = 1.0;
+        for (final @NotNull T octave : this.octaves) {
+            octave.addRegion(out, x, z, xSize, zSize, xScale * frequency, zScale * frequency, amplitude);
+            frequency *= this.lacunarity;
+            amplitude *= this.persistence;
+        }
+
+        return out;
+    }
+}
diff --git a/game/core/src/main/java/net/minecraft/core/world/noise/FractalNoise3D.java b/game/core/src/main/java/net/minecraft/core/world/noise/FractalNoise3D.java
new file mode 100644
index 000000000..65c2c7d0a
--- /dev/null
+++ b/game/core/src/main/java/net/minecraft/core/world/noise/FractalNoise3D.java
@@ -0,0 +1,50 @@
+package net.minecraft.core.world.noise;
+
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+public class FractalNoise3D<T extends Noise3D>
+    extends FractalNoise2D<T>
+    implements Noise3D {
+
+    public FractalNoise3D(final @NotNull T @NotNull [] octaves) {
+        super(octaves);
+    }
+
+    @Override
+    public double getValue(final double x, final double y, final double z) {
+        double out = 0.0;
+        double frequency = 1.0;
+        double amplitude = 1.0;
+
+        for (final @NotNull T octave : this.octaves) {
+            out += octave.getValue(x * frequency, y * frequency, z * frequency) * amplitude;
+            frequency *= this.lacunarity;
+            amplitude *= this.persistence;
+        }
+
+        return out;
+    }
+
+    @Override
+    public double @NotNull [] addRegion(
+        double @Nullable [] out,
+        final double x, final double y, final double z,
+        final int xSize, final int ySize, final int zSize,
+        final double xScale, final double yScale, final double zScale,
+        double amplitude
+    ) {
+        if (out == null || out.length < xSize * ySize * zSize) {
+            out = new double[xSize * ySize * zSize];
+        }
+
+        double frequency = 1.0;
+        for (final @NotNull T octave : this.octaves) {
+            octave.addRegion(out, x, y, z, xSize, ySize, zSize, xScale * frequency, yScale * frequency, zScale * frequency, amplitude);
+            frequency *= this.lacunarity;
+            amplitude *= this.persistence;
+        }
+
+        return out;
+    }
+}
diff --git a/game/core/src/main/java/net/minecraft/core/world/noise/ImprovedNoise.java b/game/core/src/main/java/net/minecraft/core/world/noise/ImprovedPerlinNoise.java
similarity index 82%
rename from game/core/src/main/java/net/minecraft/core/world/noise/ImprovedNoise.java
rename to game/core/src/main/java/net/minecraft/core/world/noise/ImprovedPerlinNoise.java
index 352940ae3..c46674408 100644
--- a/game/core/src/main/java/net/minecraft/core/world/noise/ImprovedNoise.java
+++ b/game/core/src/main/java/net/minecraft/core/world/noise/ImprovedPerlinNoise.java
@@ -1,24 +1,69 @@
 package net.minecraft.core.world.noise;
 
 import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
 
 import java.util.Random;
 
 // Derived from Ken Perlin's Improved Noise reference implementation: https://cs.nyu.edu/~perlin/noise/
-public class ImprovedNoise {
+public class ImprovedPerlinNoise
+    implements Noise3D {
+    public static @NotNull ImprovedPerlinNoise @NotNull [] genOctaves(final long seed, final int numOctaves) {
+        return genOctaves(seed, numOctaves, 0, LegacyNoiseType.DEFAULT);
+    }
+
+    public static @NotNull ImprovedPerlinNoise @NotNull [] genOctaves(final long seed, final int numOctaves, final int preOctaves) {
+        return genOctaves(seed, numOctaves, preOctaves, LegacyNoiseType.DEFAULT);
+    }
+
+    public static @NotNull ImprovedPerlinNoise @NotNull [] genOctaves(final long seed, final int numOctaves, final int preOctaves, final @NotNull LegacyNoiseType legacyNoiseType) {
+        final @NotNull Random random = new Random(seed);
+
+        for (int i = 0; i < preOctaves; i++) {
+            random.nextDouble();
+            random.nextDouble();
+            random.nextDouble();
+
+            for (int j = 0; j < 256; j++) {
+                random.nextInt(256 - j);
+            }
+        }
+
+        final @NotNull ImprovedPerlinNoise @NotNull [] octaves = new ImprovedPerlinNoise[numOctaves];
+        for (int i = 0; i < numOctaves; i++) {
+            octaves[i] = new ImprovedPerlinNoise(random, legacyNoiseType);
+        }
+
+        return octaves;
+    }
+
+    public enum LegacyNoiseType {
+        DEFAULT(true, true),
+        ALPHA(false, false),
+        BETA(true, false);
+
+        public final boolean handleEdgeCaseY;
+        public final boolean handleEdgeCaseZ;
+
+        LegacyNoiseType(final boolean handleEdgeCaseY, final boolean handleEdgeCaseZ) {
+            this.handleEdgeCaseY = handleEdgeCaseY;
+            this.handleEdgeCaseZ = handleEdgeCaseZ;
+        }
+    }
+
     private final @NotNull LegacyNoiseType legacyNoiseType;
 
     private final int @NotNull [] p;
-
     public final double xo;
     public final double yo;
+
     public final double zo;
 
-    public ImprovedNoise(final @NotNull Random random) {
+    public ImprovedPerlinNoise(final @NotNull Random random) {
         this(random, LegacyNoiseType.DEFAULT);
     }
 
-    public ImprovedNoise(final @NotNull Random random, final @NotNull LegacyNoiseType legacyNoiseType) {
+    public ImprovedPerlinNoise(final @NotNull Random random, final @NotNull LegacyNoiseType legacyNoiseType) {
         this.legacyNoiseType = legacyNoiseType;
 
         this.p = new int[512];
@@ -41,10 +86,12 @@ public class ImprovedNoise {
         }
     }
 
+    @Override
     public double getValue(final double x, final double z) {
         return this.getValue(x, z, 0);
     }
 
+    @Override
     public double getValue(double x, double y, double z) {
         // Find unit cube that contains point
         final int X = (int) Math.floor(x) & 255;
@@ -125,13 +172,29 @@ public class ImprovedNoise {
         return ((h & 1) == 0 ? u : -u) + ((h & 2) == 0 ? v : -v);
     }
 
-    public void add(
-        final double @NotNull [] out,
+    @Override
+    public double @NotNull [] addRegion(
+        final double @Nullable [] out,
+        final double x, final double z,
+        final int xSize, final int zSize,
+        final double xScale, final double zScale,
+        final double amplitude
+    ) {
+        return this.addRegion(out, x, z, 0, xSize, zSize, 1, xScale, zScale, 1.0, amplitude);
+    }
+
+    @Override
+    public double @NotNull [] addRegion(
+        double @Nullable [] out,
         final double x, final double y, final double z,
         final int xSize, final int ySize, final int zSize,
         final double xScale, final double yScale, final double zScale,
         final double amplitude
     ) {
+        if (out == null || out.length != xSize * ySize * zSize) {
+            out = new double[xSize * ySize * zSize];
+        }
+
         if (ySize == 1 && this.legacyNoiseType.handleEdgeCaseY) {
             int i = 0;
             for (int xi = 0; xi < xSize; xi++) {
@@ -320,5 +383,7 @@ public class ImprovedNoise {
                 }
             }
         }
+
+        return out;
     }
 }
diff --git a/game/core/src/main/java/net/minecraft/core/world/noise/LegacyNoiseType.java b/game/core/src/main/java/net/minecraft/core/world/noise/LegacyNoiseType.java
deleted file mode 100644
index bea0c9c24..000000000
--- a/game/core/src/main/java/net/minecraft/core/world/noise/LegacyNoiseType.java
+++ /dev/null
@@ -1,15 +0,0 @@
-package net.minecraft.core.world.noise;
-
-public enum LegacyNoiseType {
-    DEFAULT(true, true),
-    ALPHA(false, false),
-    BETA(true, false);
-
-    public final boolean handleEdgeCaseY;
-    public final boolean handleEdgeCaseZ;
-
-    LegacyNoiseType(final boolean handleEdgeCaseY, final boolean handleEdgeCaseZ) {
-        this.handleEdgeCaseY = handleEdgeCaseY;
-        this.handleEdgeCaseZ = handleEdgeCaseZ;
-    }
-}
diff --git a/game/core/src/main/java/net/minecraft/core/world/noise/Noise.java b/game/core/src/main/java/net/minecraft/core/world/noise/Noise.java
deleted file mode 100644
index 48e731b87..000000000
--- a/game/core/src/main/java/net/minecraft/core/world/noise/Noise.java
+++ /dev/null
@@ -1,20 +0,0 @@
-package net.minecraft.core.world.noise;
-
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-public interface Noise {
-    double getValue(final double x, final double y);
-    double getValue(final double x, final double y, final double z);
-
-    double @NotNull [] getRegion(
-        final double @Nullable [] out,
-        final double x, final double z,
-        final double xScale, final double zScale
-    );
-    double @NotNull [] getRegion(
-        final double @Nullable [] out,
-        final double x, final double y, final double z,
-        final double xScale, final double yScale, final double zScale
-    );
-}
diff --git a/game/core/src/main/java/net/minecraft/core/world/noise/Noise2D.java b/game/core/src/main/java/net/minecraft/core/world/noise/Noise2D.java
new file mode 100644
index 000000000..ff74b3833
--- /dev/null
+++ b/game/core/src/main/java/net/minecraft/core/world/noise/Noise2D.java
@@ -0,0 +1,31 @@
+package net.minecraft.core.world.noise;
+
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.Arrays;
+
+public interface Noise2D {
+    double getValue(final double x, final double z);
+
+    double @NotNull [] addRegion(
+        final double @Nullable [] out,
+        final double x, final double z,
+        final int xSize, final int zSize,
+        final double xScale, final double zScale,
+        final double amplitude
+    );
+
+    default double @NotNull [] getRegion(
+        final double @Nullable [] out,
+        final double x, final double z,
+        final int xSize, final int zSize,
+        final double xScale, final double zScale
+    ) {
+        if (out != null) {
+            Arrays.fill(out, 0.0);
+        }
+
+        return this.addRegion(out, x, z, xSize, zSize, xScale, zScale, 1.0);
+    }
+}
diff --git a/game/core/src/main/java/net/minecraft/core/world/noise/Noise3D.java b/game/core/src/main/java/net/minecraft/core/world/noise/Noise3D.java
new file mode 100644
index 000000000..94e3d969a
--- /dev/null
+++ b/game/core/src/main/java/net/minecraft/core/world/noise/Noise3D.java
@@ -0,0 +1,32 @@
+package net.minecraft.core.world.noise;
+
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.Arrays;
+
+public interface Noise3D
+    extends Noise2D {
+    double getValue(final double x, final double y, final double z);
+
+    double @NotNull [] addRegion(
+        final double @Nullable [] out,
+        final double x, final double y, final double z,
+        final int xSize, final int ySize, final int zSize,
+        final double xScale, final double yScale, final double zScale,
+        final double amplitude
+    );
+
+    default double @NotNull [] getRegion(
+        final double @Nullable [] out,
+        final double x, final double y, final double z,
+        final int xSize, final int ySize, final int zSize,
+        final double xScale, final double yScale, final double zScale
+    ) {
+        if (out != null) {
+            Arrays.fill(out, 0.0);
+        }
+
+        return this.addRegion(out, x, y, z, xSize, ySize, zSize, xScale, yScale, zScale, 1.0);
+    }
+}
diff --git a/game/core/src/main/java/net/minecraft/core/world/noise/PerlinNoise.java b/game/core/src/main/java/net/minecraft/core/world/noise/PerlinNoise.java
deleted file mode 100644
index ac9077f77..000000000
--- a/game/core/src/main/java/net/minecraft/core/world/noise/PerlinNoise.java
+++ /dev/null
@@ -1,136 +0,0 @@
-package net.minecraft.core.world.noise;
-
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-import java.util.Arrays;
-import java.util.Random;
-
-public class PerlinNoise {
-    private static final double MAX_2D = Math.sqrt(2.0 / 4.0);
-
-    private final @NotNull ImprovedNoise @NotNull [] octaves;
-    private final int numOctaves;
-    final double maxValue;
-
-    public PerlinNoise(final long seed, final int numOctaves) {
-        this(seed, numOctaves, LegacyNoiseType.DEFAULT);
-    }
-
-    public PerlinNoise(final long seed, final int numOctaves, final int preOctaves) {
-        this(seed, numOctaves, preOctaves, LegacyNoiseType.DEFAULT);
-    }
-
-    public PerlinNoise(final long seed, final int numOctaves, final @NotNull LegacyNoiseType legacyNoiseType) {
-        this(seed, numOctaves, 0, legacyNoiseType);
-    }
-
-    public PerlinNoise(final long seed, final int numOctaves, final int preOctaves, final @NotNull LegacyNoiseType legacyNoiseType) {
-        final @NotNull Random random = new Random(seed);
-
-        for (int i = 0; i < preOctaves; i++) {
-            random.nextDouble();
-            random.nextDouble();
-            random.nextDouble();
-
-            for (int j = 0; j < 256; j++) {
-                random.nextInt(256 - j);
-            }
-        }
-        this.numOctaves = numOctaves;
-        this.octaves = new ImprovedNoise[numOctaves];
-        for (int i = 0; i < numOctaves; i++) {
-            this.octaves[i] = new ImprovedNoise(random, legacyNoiseType);
-        }
-
-        double maxValue = 0.0;
-        double levelScale = 1.0;
-        for (int i = 0; i < this.numOctaves; i++) {
-            maxValue += MAX_2D / levelScale;
-            levelScale /= 2.0;
-        }
-
-        this.maxValue = maxValue;
-    }
-
-    public double getValue(final double x, final double y) {
-        final double lacunarity = 0.5;
-        final double persistence = 2.0;
-
-        double out = 0.0;
-        double frequency = 1.0;
-        double amplitude = 1.0;
-
-        for (int i = 0; i < this.numOctaves; i++) {
-            out += this.octaves[i].getValue(x * frequency, y * frequency) * amplitude;
-            frequency *= lacunarity;
-            amplitude *= persistence;
-        }
-
-        return out;
-    }
-
-    public double getValue(final double x, final double y, final double z) {
-        final double lacunarity = 0.5;
-        final double persistence = 2.0;
-
-        double out = 0.0;
-        double frequency = 1.0;
-        double amplitude = 1.0;
-
-        for (int i = 0; i < this.numOctaves; i++) {
-            out += this.octaves[i].getValue(x * frequency, y * frequency, z * frequency) * amplitude;
-            frequency *= lacunarity;
-            amplitude *= persistence;
-        }
-
-        return out;
-    }
-
-    public double getNormalized(final double x, final double y) {
-        final double value = this.getValue(x, y);
-
-        // Map to +-1.0
-        double workingValue = value / this.maxValue;
-
-        // Map to 0.0-1.0
-        workingValue = 0.5 + (workingValue / 2.0);
-
-        return workingValue;
-    }
-
-    public double @NotNull [] getRegion(
-        final double @Nullable [] densityArray,
-        final double x, final double z,
-        final int xSize, final int zSize,
-        final double scaleX, final double scaleZ
-    ) {
-        return this.getRegion(densityArray, x, 0, z, xSize, 1, zSize, scaleX, 1.0, scaleZ);
-    }
-
-    public double @NotNull [] getRegion(
-        double @Nullable [] noiseArray,
-        final double x, final double y, final double z,
-        final int xSize, final int ySize, final int zSize,
-        final double xScale, final double yScale, final double zScale
-    ) {
-        if (noiseArray == null) {
-            noiseArray = new double[xSize * ySize * zSize];
-        } else {
-            Arrays.fill(noiseArray, 0.0);
-        }
-
-        final double lacunarity = 0.5;
-        final double persistence = 2.0;
-
-        double frequency = 1.0;
-        double amplitude = 1.0;
-        for (int i = 0; i < this.numOctaves; i++) {
-            this.octaves[i].add(noiseArray, x, y, z, xSize, ySize, zSize, xScale * frequency, yScale * frequency, zScale * frequency, amplitude);
-            frequency *= lacunarity;
-            amplitude *= persistence;
-        }
-
-        return noiseArray;
-    }
-}
diff --git a/game/core/src/main/java/net/minecraft/core/world/noise/PerlinSimplexNoise.java b/game/core/src/main/java/net/minecraft/core/world/noise/PerlinSimplexNoise.java
deleted file mode 100644
index 0fd929e45..000000000
--- a/game/core/src/main/java/net/minecraft/core/world/noise/PerlinSimplexNoise.java
+++ /dev/null
@@ -1,51 +0,0 @@
-package net.minecraft.core.world.noise;
-
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-import java.util.Arrays;
-import java.util.Random;
-
-public class PerlinSimplexNoise {
-    private final @NotNull SimplexNoise @NotNull [] octaves;
-    private final int numOctaves;
-
-    public PerlinSimplexNoise(final @NotNull Random random, final int numOctaves) {
-        this.numOctaves = numOctaves;
-        this.octaves = new SimplexNoise[numOctaves];
-        for (int i = 0; i < numOctaves; i++) {
-            this.octaves[i] = new SimplexNoise(random);
-        }
-    }
-
-    public double @NotNull [] getRegion(
-        final double @Nullable [] out,
-        final double x, final double z,
-        final int xSize, final int zSize,
-        final double xScale, final double zScale,
-        final double lacunarity
-    ) {
-        return this.getRegion(out, x, z, xSize, zSize, xScale, zScale, lacunarity, 0.5);
-    }
-
-    public double @NotNull [] getRegion(double @Nullable [] out, final double x, final double z, final int xSize, final int zSize, double xScale, double zScale, final double lacunarity, final double persistence) {
-        xScale /= 1.5;
-        zScale /= 1.5;
-
-        if (out == null || out.length < xSize * zSize) {
-            out = new double[xSize * zSize];
-        } else {
-            Arrays.fill(out, 0.0);
-        }
-
-        double frequency = 1.0;
-        double amplitude = 1.0;
-        for (int l = 0; l < this.numOctaves; l++) {
-            this.octaves[l].add(out, x, z, xSize, zSize, xScale * frequency, zScale * frequency, 0.55D / amplitude);
-            frequency *= lacunarity;
-            amplitude *= persistence;
-        }
-
-        return out;
-    }
-}
diff --git a/game/core/src/main/java/net/minecraft/core/world/noise/SimplexNoise.java b/game/core/src/main/java/net/minecraft/core/world/noise/SimplexNoise.java
index ce482f915..cd5dacad0 100644
--- a/game/core/src/main/java/net/minecraft/core/world/noise/SimplexNoise.java
+++ b/game/core/src/main/java/net/minecraft/core/world/noise/SimplexNoise.java
@@ -1,18 +1,48 @@
 package net.minecraft.core.world.noise;
 
 import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
 
 import java.util.Random;
 
-public class SimplexNoise {
+// Derived from https://github.com/SRombauts/SimplexNoise
+public class SimplexNoise
+    implements Noise2D, Noise3D {
+    public static @NotNull SimplexNoise @NotNull [] genOctaves(final long seed, final int numOctaves) {
+        return genOctaves(seed, numOctaves, 0);
+    }
+
+    public static @NotNull SimplexNoise @NotNull [] genOctaves(final long seed, final int numOctaves, final int preOctaves) {
+        final @NotNull Random random = new Random(seed);
+
+        for (int i = 0; i < preOctaves; i++) {
+            random.nextDouble();
+            random.nextDouble();
+            random.nextDouble();
+
+            for (int j = 0; j < 256; j++) {
+                random.nextInt(256 - j);
+            }
+        }
+
+        final @NotNull SimplexNoise @NotNull [] octaves = new SimplexNoise[numOctaves];
+        for (int i = 0; i < numOctaves; i++) {
+            octaves[i] = new SimplexNoise(random);
+        }
+
+        return octaves;
+    }
+
     private static final int @NotNull [] @NotNull [] GRAD = {
-        {  1,  1,  0 }, { -1,  1,  0 }, {  1, -1,  0 },
-        { -1, -1,  0 }, {  1,  0,  1 }, { -1,  0,  1 },
-        {  1,  0, -1 }, { -1,  0, -1 }, {  0,  1,  1 },
-        {  0, -1,  1 }, {  0,  1, -1 }, {  0, -1, -1 }
+        { 1, 1, 0 }, { -1, 1, 0 }, { 1, -1, 0 },
+        { -1, -1, 0 }, { 1, 0, 1 }, { -1, 0, 1 },
+        { 1, 0, -1 }, { -1, 0, -1 }, { 0, 1, 1 },
+        { 0, -1, 1 }, { 0, 1, -1 }, { 0, -1, -1 }
     };
-    private static final double F2 = 0.5D * (Math.sqrt(3D) - 1.0D);
-    private static final double G2 = (3D - Math.sqrt(3D)) / 6D;
+    private static final double F2 = 0.5 * (Math.sqrt(3.0) - 1.0);
+    private static final double G2 = (3.0 - Math.sqrt(3.0)) / 6.0;
+    private static final double F3 = 1.0 / 3.0;
+    private static final double G3 = 1.0 / 6.0;
 
     private final int @NotNull [] p;
     public final double xo;
@@ -21,9 +51,9 @@ public class SimplexNoise {
 
     public SimplexNoise(final @NotNull Random random) {
         this.p = new int[512];
-        this.xo = random.nextDouble() * 256D;
-        this.yo = random.nextDouble() * 256D;
-        this.zo = random.nextDouble() * 256D;
+        this.xo = random.nextDouble() * 256;
+        this.yo = random.nextDouble() * 256;
+        this.zo = random.nextDouble() * 256;
 
         for (int i = 0; i < 256; i++) {
             this.p[i] = i;
@@ -43,98 +73,282 @@ public class SimplexNoise {
     }
 
     private static double dot(final int @NotNull [] vec, final double x, final double y) {
-        return (double) vec[0] * x + (double) vec[1] * y;
+        return vec[0] * x + vec[1] * y;
+    }
+
+    private static double dot(final int @NotNull [] vec, final double x, final double y, final double z) {
+        return vec[0] * x + vec[1] * y + vec[2] * z;
+    }
+
+    @Override
+    public double getValue(final double x, final double z) {
+        // Skew the input space to determine which simplex cell we're in
+        final double s = (x + z) * F2;
+        final int i = fastFloor(x + s);
+        final int k = fastFloor(z + s);
+
+        // Unskew the cell origin back to (x, z) space
+        final double t = (i + k) * G2;
+        final double X0 = i - t;
+        final double Z0 = k - t;
+        final double x0 = x - X0;
+        final double z0 = z - Z0;
+
+        // For the 2D case, the simplex shape is an equilateral triangle.
+        // Determine which simplex we are in.
+
+        // Offsets for second (middle) corner of simplex in (i, k) coords
+        final int i1, k1;
+
+        if (x0 > z0) {
+            // Lower triangle, XZ order: (0, 0) -> (1, 0) -> (1, 1)
+            i1 = 1;
+            k1 = 0;
+        } else {
+            // Upper triangle, ZX order: (0, 0) -> (0, 1) -> (1, 1)
+            i1 = 0;
+            k1 = 1;
+        }
+
+        // A step of (1, 0) in (i, k) means a step of (1 - c, -c) in (x, z), and
+        // a step of (0, 1) in (i, k) means a step of (-c, 1 - c) in (x, z), where
+        // c = (3 - sqrt(3)) / 6
+
+        // Offsets for middle corner in (x, z) unskewed coords
+        final double x1 = (x0 - i1) + G2;
+        final double z1 = (z0 - k1) + G2;
+
+        // Offsets for last corner in (x, z) unskewed coords
+        final double x2 = (x0 - 1.0) + 2.0 * G2;
+        final double z2 = (z0 - 1.0) + 2.0 * G2;
+
+        // Work out the hashed gradient indices of the three simplex corners
+        final int ib = i & 0xFF;
+        final int kb = k & 0xFF;
+        final int gi0 = this.p[ib + this.p[kb]] % 12;
+        final int gi1 = this.p[ib + i1 + this.p[kb + k1]] % 12;
+        final int gi2 = this.p[ib + 1 + this.p[kb + 1]] % 12;
+
+        // Calculate the contribution from the first corner
+        double t0 = 0.5 - x0 * x0 - z0 * z0;
+        final double n0;
+        if (t0 < 0.0) {
+            n0 = 0.0;
+        } else {
+            t0 *= t0;
+            n0 = t0 * t0 * dot(GRAD[gi0], x0, z0);
+        }
+
+        // Calculate the contribution from the second corner
+        double t1 = 0.5 - x1 * x1 - z1 * z1;
+        final double n1;
+        if (t1 < 0.0) {
+            n1 = 0.0;
+        } else {
+            t1 *= t1;
+            n1 = t1 * t1 * dot(GRAD[gi1], x1, z1);
+        }
+
+        // Calculate the contribution from the third corner
+        double t2 = 0.5 - x2 * x2 - z2 * z2;
+        final double n2;
+        if (t2 < 0.0) {
+            n2 = 0.0;
+        } else {
+            t2 *= t2;
+            n2 = t2 * t2 * dot(GRAD[gi2], x2, z2);
+        }
+
+        return 70.0 * (n0 + n1 + n2);
     }
 
-    // Values generated are guaranteed to be between -1.0 and 1.0, multiplied by amplitude.
-    public void add(
-        final double @NotNull [] out,
-        final double xOffset, final double zOffset,
+    @Override
+    public double getValue(final double x, final double y, final double z) {
+        // Skew the input space to determine which simplex cell we're in
+        final double s = (x + y + z) * F3;
+        final int i = fastFloor(x + s);
+        final int j = fastFloor(y + s);
+        final int k = fastFloor(z + s);
+
+        // Unskew the cell origin back to (x, y, z) space
+        final double t = (i + j + k) * G3;
+        final double X0 = i - t;
+        final double Y0 = j - t;
+        final double Z0 = k - t;
+        final double x0 = x - X0;
+        final double y0 = y - Y0;
+        final double z0 = z - Z0;
+
+        // For the 3D case, the simplex shape is a slightly irregular tetrahedron.
+        // Determine which simplex we are in.
+
+        // Offsets for second corner of simplex in (i, j, k) coords
+        final int i1, j1, k1;
+
+        // Offsets for third corner of simplex in (i, j, k) coords
+        final int i2, j2, k2;
+
+        if (x0 >= y0) {
+            if (y0 >= z0) {
+                // X, Y, Z order
+                i1 = 1; j1 = 0; k1 = 0;
+                i2 = 1; j2 = 1; k2 = 0;
+            } else if (x0 >= z0) {
+                // X, Z, Y order
+                i1 = 1; j1 = 0; k1 = 0;
+                i2 = 1; j2 = 0; k2 = 1;
+            } else {
+                // Z, X, Y order
+                i1 = 0; j1 = 0; k1 = 1;
+                i2 = 1; j2 = 0; k2 = 1;
+            }
+        } else {
+            if (y0 < z0) {
+                // Z, Y, X order
+                i1 = 0; j1 = 0; k1 = 1;
+                i2 = 0; j2 = 1; k2 = 1;
+            } else if (x0 < z0) {
+                // Y, Z, X order
+                i1 = 0; j1 = 1; k1 = 0;
+                i2 = 0; j2 = 1; k2 = 1;
+            } else {
+                // Y, X, Z order
+                i1 = 0; j1 = 1; k1 = 0;
+                i2 = 1; j2 = 1; k2 = 0;
+            }
+        }
+
+        // A step of (1, 0, 0) in (i, j, k) means a step of (1 - c, -c, -c) in (x, y, z),
+        // a step of (0, 1, 0) in (i, j, k) means a step of (-c, 1 - c, -c) in (x, y, z), and
+        // a step of (0, 0, 1) in (i, j, k) means a step of (-c, -c, 1 - c) in (x, y, z), where
+        // c = 1/6.
+
+        // Offsets for second corner in (x, y, z) coords
+        final double x1 = x0 - i1 + G3;
+        final double y1 = y0 - j1 + G3;
+        final double z1 = z0 - k1 + G3;
+
+        // Offsets for third corner in (x, y, z) coords
+        final double x2 = x0 - i2 + 2.0 * G3;
+        final double y2 = y0 - j2 + 2.0 * G3;
+        final double z2 = z0 - k2 + 2.0 * G3;
+
+        // Offsets for last corner in (x, y, z) coords
+        final double x3 = x0 - 1.0 + 3.0 * G3;
+        final double y3 = y0 - 1.0 + 3.0 * G3;
+        final double z3 = z0 - 1.0 + 3.0 * G3;
+
+        // Work out the hashed gradient indices of the four simplex corners
+        final int ib = i & 0xFF;
+        final int jb = j & 0xFF;
+        final int kb = k & 0xFF;
+        final int gi0 = this.p[ib + this.p[jb + this.p[kb]]] % 12;
+        final int gi1 = this.p[ib + i1 + this.p[jb + j1 + this.p[kb + k1]]] % 12;
+        final int gi2 = this.p[ib + i2 + this.p[jb + j2 + this.p[kb + k2]]] % 12;
+        final int gi3 = this.p[ib + 1 + this.p[jb + 1 + this.p[kb + 1]]] % 12;
+
+        // Calculate the contribution from the first corner
+        double t0 = 0.6 - x0 * x0 - y0 * y0 - z0 * z0;
+        final double n0;
+        if (t0 < 0.0) {
+            n0 = 0.0;
+        } else {
+            t0 *= t0;
+            n0 = t0 * t0 * dot(GRAD[gi0], x0, y0, z0);
+        }
+
+        // Calculate the contribution from the second corner
+        double t1 = 0.6 - x1 * x1 - y1 * y1 - z1 * z1;
+        final double n1;
+        if (t1 < 0.0) {
+            n1 = 0.0;
+        } else {
+            t1 *= t1;
+            n1 = t1 * t1 * dot(GRAD[gi1], x1, y1, z1);
+        }
+
+        // Calculate the contribution from the third corner
+        double t2 = 0.6 - x2 * x2 - y2 * y2 - z2 * z2;
+        final double n2;
+        if (t2 < 0.0) {
+            n2 = 0.0;
+        } else {
+            t2 *= t2;
+            n2 = t2 * t2 * dot(GRAD[gi2], x2, y2, z2);
+        }
+
+        // Calculate the contribution from the fourth corner
+        double t3 = 0.6 - x3 * x3 - y3 * y3 - z3 * z3;
+        final double n3;
+        if (t3 < 0.0) {
+            n3 = 0.0;
+        } else {
+            t3 *= t3;
+            n3 = t3 * t3 * dot(GRAD[gi3], x3, y3, z3);
+        }
+
+        return 32.0 * (n0 + n1 + n2 + n3);
+    }
+
+    @Override
+    public double @NotNull [] addRegion(
+        double @Nullable [] out,
+        final double x, final double z,
         final int xSize, final int zSize,
-        final double xScale, final double zScale,
-        final double amplitude
+        double xScale, double zScale,
+        double amplitude
     ) {
-        int index = 0;
-        for (int dx = 0; dx < xSize; dx++) {
-            final double x = (xOffset + (double) dx) * xScale + this.xo;
-            for (int dz = 0; dz < zSize; dz++) {
-                final double z = (zOffset + (double) dz) * zScale + this.yo;
-
-                // Skew the input space to determine which simplex cell we're in
-                final double s = (x + z) * F2;
-                final int i = fastFloor(x + s);
-                final int j = fastFloor(z + s);
-
-                // Unskew the cell origin back to (x, z) space
-                final double t = (double) (i + j) * G2;
-                final double X0 = (double) i - t;
-                final double Z0 = (double) j - t;
-                final double x0 = x - X0;
-                final double z0 = z - Z0;
-
-                // For the 2D case, the simplex shape is an equilateral triangle.
-                // Determine which simplex we are in.
-                final int i1;  // Offsets for second (middle) corner of simplex in (i, j) coords
-                final int j1;
-                if (x0 > z0) // Lower triangle, XZ order: (0, 0) -> (1, 0) -> (1, 1)
-                {
-                    i1 = 1;
-                    j1 = 0;
-                } else // Upper triangle, ZX order: (0, 0) -> (0, 1) -> (1, 1)
-                {
-                    i1 = 0;
-                    j1 = 1;
-                }
+        if (out == null || out.length != xSize * zSize) {
+            out = new double[xSize * zSize];
+        }
 
-                // A step of (1, 0) in (i, j) means a step of (1 - c, -c) in (x, z), and
-                // a step of (0, 1) in (i, j) means a step of (-c, 1 - c) in (x, z), where
-                // c = (3 - sqrt(3)) / 6
-
-                final double x1 = (x0 - (double) i1) + G2; // Offsets for middle corner in (x, z) unskewed coords
-                final double z1 = (z0 - (double) j1) + G2;
-                final double x2 = (x0 - 1.0D) + 2D * G2;  // Offsets for last corner in (x, z) unskewed coords
-                final double z2 = (z0 - 1.0D) + 2D * G2;
-
-                // Work out the hashed gradient indices of the three simplex corners
-                final int ib = i & 0xff;
-                final int jb = j & 0xff;
-                final int gi0 = this.p[ib + this.p[jb]] % 12;
-                final int gi1 = this.p[ib + i1 + this.p[jb + j1]] % 12;
-                final int gi2 = this.p[ib + 1 + this.p[jb + 1]] % 12;
-
-                // Calculate the contribution from the first corner
-                double t0 = 0.5D - x0 * x0 - z0 * z0;
-                final double n0;
-                if (t0 < 0.0D) {
-                    n0 = 0.0D;
-                } else {
-                    t0 *= t0;
-                    n0 = t0 * t0 * dot(GRAD[gi0], x0, z0);
-                }
+        xScale /= 1.5;
+        zScale /= 1.5;
+        amplitude *= 0.55;
 
-                // Calculate the contribution from the second corner
-                double t1 = 0.5D - x1 * x1 - z1 * z1;
-                final double n1;
-                if (t1 < 0.0D) {
-                    n1 = 0.0D;
-                } else {
-                    t1 *= t1;
-                    n1 = t1 * t1 * dot(GRAD[gi1], x1, z1);
-                }
+        int i = 0;
+        for (int xi = 0; xi < xSize; xi++) {
+            final double xx = (x + xi) * xScale + this.xo;
+            for (int zi = 0; zi < zSize; zi++) {
+                final double zz = (z + zi) * zScale + this.yo;
 
-                // Calculate the contribution from the third corner
-                double t2 = 0.5D - x2 * x2 - z2 * z2;
-                final double n2;
-                if (t2 < 0.0D) {
-                    n2 = 0.0D;
-                } else {
-                    t2 *= t2;
-                    n2 = t2 * t2 * dot(GRAD[gi2], x2, z2);
-                }
+                out[i++] += this.getValue(xx, zz) * amplitude;
+            }
+        }
 
-                final double value = 70 * (n0 + n1 + n2);
-                out[index++] += value * amplitude;
+        return out;
+    }
+
+    @Override
+    public double @NotNull [] addRegion(
+        double @Nullable [] out,
+        final double x, final double y, final double z,
+        final int xSize, final int ySize, final int zSize,
+        double xScale, double yScale, double zScale,
+        double amplitude
+    ) {
+        if (out == null || out.length != xSize * ySize * zSize) {
+            out = new double[xSize * ySize * zSize];
+        }
+
+        xScale /= 1.5;
+        yScale /= 1.5;
+        zScale /= 1.5;
+        amplitude *= 0.55;
+
+        int i = 0;
+        for (int xi = 0; xi < xSize; xi++) {
+            final double xx = (x + xi) * xScale + this.xo;
+            for (int zi = 0; zi < zSize; zi++) {
+                final double zz = (z + zi) * zScale + this.zo;
+                for (int yi = 0; yi < ySize; yi++) {
+                    final double yy = (y + yi) * yScale + this.yo;
+
+                    out[i++] = this.getValue(xx, yy, zz) * amplitude;
+                }
             }
         }
+
+        return out;
     }
 }
diff --git a/game/core/src/main/java/net/minecraft/core/world/noise/operator/Constant2D.java b/game/core/src/main/java/net/minecraft/core/world/noise/operator/Constant2D.java
new file mode 100644
index 000000000..7a2ee024a
--- /dev/null
+++ b/game/core/src/main/java/net/minecraft/core/world/noise/operator/Constant2D.java
@@ -0,0 +1,38 @@
+package net.minecraft.core.world.noise.operator;
+
+import net.minecraft.core.world.noise.Noise2D;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.Arrays;
+
+public class Constant2D
+    implements Noise2D {
+    protected final double value;
+
+    public Constant2D(final double value) {
+        this.value = value;
+    }
+
+    @Override
+    public double getValue(final double x, final double z) {
+        return this.value;
+    }
+
+    @Override
+    public double @NotNull [] addRegion(
+        double @Nullable [] out,
+        final double x, final double z,
+        final int xSize, final int zSize,
+        final double xScale, final double zScale,
+        final double amplitude
+    ) {
+        if (out == null || out.length < xSize * zSize) {
+            out = new double[xSize * zSize];
+        }
+
+        Arrays.fill(out, this.value);
+
+        return out;
+    }
+}
diff --git a/game/core/src/main/java/net/minecraft/core/world/noise/operator/Constant3D.java b/game/core/src/main/java/net/minecraft/core/world/noise/operator/Constant3D.java
new file mode 100644
index 000000000..5f821e403
--- /dev/null
+++ b/game/core/src/main/java/net/minecraft/core/world/noise/operator/Constant3D.java
@@ -0,0 +1,37 @@
+package net.minecraft.core.world.noise.operator;
+
+import net.minecraft.core.world.noise.Noise3D;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.Arrays;
+
+public class Constant3D
+    extends Constant2D
+    implements Noise3D {
+    public Constant3D(final double value) {
+        super(value);
+    }
+
+    @Override
+    public double getValue(final double x, final double y, final double z) {
+        return this.value;
+    }
+
+    @Override
+    public double @NotNull [] addRegion(
+        double @Nullable [] out,
+        final double x, final double y, final double z,
+        final int xSize, final int ySize, final int zSize,
+        final double xScale, final double yScale, final double zScale,
+        final double amplitude
+    ) {
+        if (out == null || out.length != xSize * ySize * zSize) {
+            out = new double[xSize * ySize * zSize];
+        }
+
+        Arrays.fill(out, this.value);
+
+        return out;
+    }
+}
diff --git a/game/core/src/main/java/net/minecraft/core/world/noise/operator/Emboss2D.java b/game/core/src/main/java/net/minecraft/core/world/noise/operator/Emboss2D.java
new file mode 100644
index 000000000..170772571
--- /dev/null
+++ b/game/core/src/main/java/net/minecraft/core/world/noise/operator/Emboss2D.java
@@ -0,0 +1,41 @@
+package net.minecraft.core.world.noise.operator;
+
+import net.minecraft.core.world.noise.Noise2D;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+public class Emboss2D<T extends Noise2D>
+    implements Noise2D {
+    protected final @NotNull T noise;
+
+    public Emboss2D(final @NotNull T noise) {
+        this.noise = noise;
+    }
+
+    @Override
+    public double getValue(final double x, final double z) {
+        return this.noise.getValue(x, z) - this.noise.getValue(x + 1.0, z + 1.0);
+    }
+
+    @Override
+    public double @NotNull [] addRegion(
+        double @Nullable [] out,
+        final double x, final double z,
+        final int xSize, final int zSize,
+        final double xScale, final double zScale,
+        final double amplitude
+    ) {
+        if (out == null || out.length < xSize * zSize) {
+            out = new double[xSize * zSize];
+        }
+
+        final double @NotNull [] valuesA = this.noise.addRegion(null, x, z, xSize, zSize, xScale, zScale, amplitude);
+        final double @NotNull [] valuesB = this.noise.addRegion(null, x + 1.0, z + 1.0, xSize, zSize, xScale, zScale, amplitude);
+
+        for (int i = 0; i < out.length; i++) {
+            out[i] += valuesA[i] - valuesB[i];
+        }
+
+        return out;
+    }
+}
diff --git a/game/core/src/main/java/net/minecraft/core/world/noise/operator/Emboss3D.java b/game/core/src/main/java/net/minecraft/core/world/noise/operator/Emboss3D.java
new file mode 100644
index 000000000..196fc3511
--- /dev/null
+++ b/game/core/src/main/java/net/minecraft/core/world/noise/operator/Emboss3D.java
@@ -0,0 +1,40 @@
+package net.minecraft.core.world.noise.operator;
+
+import net.minecraft.core.world.noise.Noise3D;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+public class Emboss3D<T extends Noise3D>
+    extends Emboss2D<T>
+    implements Noise3D {
+    public Emboss3D(@NotNull final T noise) {
+        super(noise);
+    }
+
+    @Override
+    public double getValue(final double x, final double y, final double z) {
+        return this.noise.getValue(x, y, z) - this.noise.getValue(x + 1.0, y + 1.0, z + 1.0);
+    }
+
+    @Override
+    public double @NotNull [] addRegion(
+        double @Nullable [] out,
+        final double x, final double y, final double z,
+        final int xSize, final int ySize, final int zSize,
+        final double xScale, final double yScale, final double zScale,
+        final double amplitude
+    ) {
+       if (out == null || out.length < xSize * ySize * zSize) {
+           out = new double[xSize * ySize * zSize];
+       }
+
+       final double @NotNull [] valuesA = this.noise.addRegion(null, x, y, z, xSize, ySize, zSize, xScale, yScale, zScale, amplitude);
+       final double @NotNull [] valuesB = this.noise.addRegion(null, x + 1.0, y + 1.0, z + 1.0, xSize, ySize, zSize, xScale, yScale, zScale, amplitude);
+
+       for (int i = 0; i < out.length; i++) {
+           out[i] += valuesA[i] - valuesB[i];
+       }
+
+       return out;
+    }
+}
diff --git a/game/core/src/main/java/net/minecraft/core/world/noise/operator/Rotate2D.java b/game/core/src/main/java/net/minecraft/core/world/noise/operator/Rotate2D.java
new file mode 100644
index 000000000..c0cb028a1
--- /dev/null
+++ b/game/core/src/main/java/net/minecraft/core/world/noise/operator/Rotate2D.java
@@ -0,0 +1,35 @@
+package net.minecraft.core.world.noise.operator;
+
+import net.minecraft.core.world.noise.Noise2D;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+public class Rotate2D<T extends Noise2D>
+    implements Noise2D {
+    protected final @NotNull T noise;
+    protected final double sin;
+    protected final double cos;
+
+    public Rotate2D(final @NotNull T noise, final double yRot) {
+        this.noise = noise;
+
+        this.sin = Math.sin(yRot);
+        this.cos = Math.cos(yRot);
+    }
+
+    @Override
+    public double getValue(final double x, final double z) {
+        return this.noise.getValue(x * this.cos + z * this.sin, z * this.cos - x * this.sin);
+    }
+
+    @Override
+    public double @NotNull [] addRegion(
+        final double @Nullable [] out,
+        final double x, final double z,
+        final int xSize, final int zSize,
+        final double xScale, final double zScale,
+        final double amplitude
+    ) {
+        throw new UnsupportedOperationException("Not implemented!");
+    }
+}
diff --git a/game/core/src/main/java/net/minecraft/core/world/noise/operator/Rotate3D.java b/game/core/src/main/java/net/minecraft/core/world/noise/operator/Rotate3D.java
new file mode 100644
index 000000000..1ff820244
--- /dev/null
+++ b/game/core/src/main/java/net/minecraft/core/world/noise/operator/Rotate3D.java
@@ -0,0 +1,45 @@
+package net.minecraft.core.world.noise.operator;
+
+import net.minecraft.core.world.noise.Noise3D;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+public class Rotate3D<T extends Noise3D>
+    extends Rotate2D<T>
+    implements Noise3D {
+    private final double @NotNull [] @NotNull [] rot;
+
+    public Rotate3D(@NotNull final T noise, final double xRot, final double yRot, final double zRot) {
+        super(noise, yRot);
+
+        final double cx = Math.cos(xRot), sx = Math.sin(xRot);
+        final double cy = Math.cos(yRot), sy = Math.sin(yRot);
+        final double cz = Math.cos(zRot), sz = Math.sin(zRot);
+
+        this.rot = new double[][] {
+            {  cy*cz,            -cy*sz,             sy    },
+            {  sx*sy*cz + cx*sz, -sx*sy*sz + cx*cz, -sx*cy },
+            { -cx*sy*cz + sx*sz,  cx*sy*sz + sx*cz,  cx*cy }
+        };
+    }
+
+    @Override
+    public double getValue(final double x, final double y, final double z) {
+        final double nx = this.rot[0][0] * x + this.rot[0][1] * y + this.rot[0][2] * z;
+        final double ny = this.rot[1][0] * x + this.rot[1][1] * y + this.rot[1][2] * z;
+        final double nz = this.rot[2][0] * x + this.rot[2][1] * y + this.rot[2][2] * z;
+
+        return this.noise.getValue(nx, ny, nz);
+    }
+
+    @Override
+    public double @NotNull [] addRegion(
+        final double @Nullable [] out,
+        final double x, final double y, final double z,
+        final int xSize, final int ySize, final int zSize,
+        final double xScale, final double yScale, final double zScale,
+        final double amplitude
+    ) {
+        throw new UnsupportedOperationException("Not implemented!");
+    }
+}
diff --git a/game/core/src/main/java/net/minecraft/core/world/noise/operator/Scale2D.java b/game/core/src/main/java/net/minecraft/core/world/noise/operator/Scale2D.java
new file mode 100644
index 000000000..2e504f3a4
--- /dev/null
+++ b/game/core/src/main/java/net/minecraft/core/world/noise/operator/Scale2D.java
@@ -0,0 +1,34 @@
+package net.minecraft.core.world.noise.operator;
+
+import net.minecraft.core.world.noise.Noise2D;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+public class Scale2D<T extends Noise2D>
+    implements Noise2D {
+    protected final @NotNull T noise;
+    protected final double xScale;
+    protected final double zScale;
+
+    public Scale2D(final @NotNull T noise, final double xScale, final double zScale) {
+        this.noise = noise;
+        this.xScale = 1.0 / xScale;
+        this.zScale = 1.0 / zScale;
+    }
+
+    @Override
+    public double getValue(final double x, final double z) {
+        return this.noise.getValue(x * this.xScale, z * this.zScale);
+    }
+
+    @Override
+    public double @NotNull [] addRegion(
+        final double @Nullable [] out,
+        final double x, final double z,
+        final int xSize, final int zSize,
+        final double xScale, final double zScale,
+        final double amplitude
+    ) {
+        return this.noise.addRegion(out, x, z, xSize, zSize, xScale * this.xScale, zScale * this.zScale, amplitude);
+    }
+}
diff --git a/game/core/src/main/java/net/minecraft/core/world/noise/operator/Scale3D.java b/game/core/src/main/java/net/minecraft/core/world/noise/operator/Scale3D.java
new file mode 100644
index 000000000..f578c5301
--- /dev/null
+++ b/game/core/src/main/java/net/minecraft/core/world/noise/operator/Scale3D.java
@@ -0,0 +1,33 @@
+package net.minecraft.core.world.noise.operator;
+
+import net.minecraft.core.world.noise.Noise3D;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+public class Scale3D<T extends Noise3D>
+    extends Scale2D<T>
+    implements Noise3D {
+    protected final double yScale;
+
+    public Scale3D(@NotNull final T noise, final double xScale, final double yScale, final double zScale) {
+        super(noise, xScale, zScale);
+
+        this.yScale = yScale;
+    }
+
+    @Override
+    public double getValue(final double x, final double y, final double z) {
+        return this.noise.getValue(x * this.xScale, y * this.yScale, z * this.zScale);
+    }
+
+    @Override
+    public double @NotNull [] addRegion(
+        final double @Nullable [] out,
+        final double x, final double y, final double z,
+        final int xSize, final int ySize, final int zSize,
+        final double xScale, final double yScale, final double zScale,
+        final double amplitude
+    ) {
+        return this.noise.addRegion(out, x, y, z, xSize, ySize, zSize, xScale * this.xScale, yScale * this.yScale, zScale * this.zScale, amplitude);
+    }
+}
diff --git a/game/core/src/main/java/net/minecraft/core/world/noise/operator/Warp2D.java b/game/core/src/main/java/net/minecraft/core/world/noise/operator/Warp2D.java
new file mode 100644
index 000000000..46e1b9380
--- /dev/null
+++ b/game/core/src/main/java/net/minecraft/core/world/noise/operator/Warp2D.java
@@ -0,0 +1,37 @@
+package net.minecraft.core.world.noise.operator;
+
+import net.minecraft.core.world.noise.Noise2D;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+public class Warp2D<A extends Noise2D, B extends Noise2D, C extends Noise2D>
+    implements Noise2D {
+    protected final @NotNull A base;
+    protected final @NotNull B warpX;
+    protected final @NotNull C warpZ;
+
+    public Warp2D(final @NotNull A base, final @NotNull B warpX, final @NotNull C warpZ) {
+        this.base = base;
+        this.warpX = warpX;
+        this.warpZ = warpZ;
+    }
+
+    @Override
+    public double getValue(final double x, final double z) {
+        return this.base.getValue(
+            x + this.warpX.getValue(x, z),
+            z + this.warpZ.getValue(x, z)
+        );
+    }
+
+    @Override
+    public double @NotNull [] addRegion(
+        final double @Nullable [] out,
+        final double x, final double z,
+        final int xSize, final int zSize,
+        final double xScale, final double zScale,
+        final double amplitude
+    ) {
+        throw new UnsupportedOperationException("Not implemented!");
+    }
+}
diff --git a/game/core/src/main/java/net/minecraft/core/world/noise/operator/Warp3D.java b/game/core/src/main/java/net/minecraft/core/world/noise/operator/Warp3D.java
new file mode 100644
index 000000000..f2c8dc289
--- /dev/null
+++ b/game/core/src/main/java/net/minecraft/core/world/noise/operator/Warp3D.java
@@ -0,0 +1,37 @@
+package net.minecraft.core.world.noise.operator;
+
+import net.minecraft.core.world.noise.Noise3D;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+public class Warp3D<A extends Noise3D, B extends Noise3D, C extends Noise3D, D extends Noise3D>
+    extends Warp2D<A, B, D>
+    implements Noise3D {
+    protected final @NotNull C warpY;
+
+    public Warp3D(final @NotNull A base, final @NotNull B warpX, final @NotNull C warpY, final @NotNull D warpZ) {
+        super(base, warpX, warpZ);
+
+        this.warpY = warpY;
+    }
+
+    @Override
+    public double getValue(final double x, final double y, final double z) {
+        return this.base.getValue(
+            x + this.warpX.getValue(x, y, z),
+            y + this.warpY.getValue(x, y, z),
+            z + this.warpZ.getValue(x, y, z)
+        );
+    }
+
+    @Override
+    public double @NotNull [] addRegion(
+        final double @Nullable [] out,
+        final double x, final double y, final double z,
+        final int xSize, final int ySize, final int zSize,
+        final double xScale, final double yScale, final double zScale,
+        final double amplitude
+    ) {
+        throw new UnsupportedOperationException("Not implemented!");
+    }
+}
diff --git a/game/core/src/main/java/net/minecraft/core/world/type/overworld/WorldTypeOverworldFloating.java b/game/core/src/main/java/net/minecraft/core/world/type/overworld/WorldTypeOverworldFloating.java
index 5eb54d04f..b3b168cae 100644
--- a/game/core/src/main/java/net/minecraft/core/world/type/overworld/WorldTypeOverworldFloating.java
+++ b/game/core/src/main/java/net/minecraft/core/world/type/overworld/WorldTypeOverworldFloating.java
@@ -19,7 +19,7 @@ public class WorldTypeOverworldFloating
         return new BiomeProviderOverworld(world.getRandomSeed(), this)
                 .withTemperatureScales(0.00625, 0.00625, 0.25, 0.01)
                 .withHumidityScales(0.0125, 0.0125, 0.3, 0.01)
-                .withFuzzinessScales(8, 8, 0.025);
+                .withNoiseScales(8, 8, 0.025);
     }
 
     @Override
diff --git a/game/core/src/main/java/net/minecraft/core/world/wind/WindProviderGeneric.java b/game/core/src/main/java/net/minecraft/core/world/wind/WindProviderGeneric.java
index d92ba3b2a..a4b99fffa 100644
--- a/game/core/src/main/java/net/minecraft/core/world/wind/WindProviderGeneric.java
+++ b/game/core/src/main/java/net/minecraft/core/world/wind/WindProviderGeneric.java
@@ -1,7 +1,7 @@
 package net.minecraft.core.world.wind;
 
 import net.minecraft.core.world.World;
-import net.minecraft.core.world.noise.ImprovedNoise;
+import net.minecraft.core.world.noise.ImprovedPerlinNoise;
 
 import java.util.Random;
 
@@ -11,8 +11,8 @@ public class WindProviderGeneric extends WindProvider {
     private long randomSeed = -1;
     private Random directionRandom = null;
     private Random intensityRandom = null;
-    private ImprovedNoise directionNoise = null;
-    private ImprovedNoise intensityNoise = null;
+    private ImprovedPerlinNoise directionNoise = null;
+    private ImprovedPerlinNoise intensityNoise = null;
     
     private long lastSampleTime = -1;
     private double lastDirectionSample = 0F;
@@ -22,9 +22,9 @@ public class WindProviderGeneric extends WindProvider {
         if (randomSeed != world.getRandomSeed() || directionRandom == null || intensityRandom == null || directionNoise == null || intensityNoise == null) {
             randomSeed = world.getRandomSeed();
             directionRandom = new Random(randomSeed * 0x3F6D);
-            directionNoise = new ImprovedNoise(directionRandom);
+            directionNoise = new ImprovedPerlinNoise(directionRandom);
             intensityRandom = new Random(randomSeed * 0x0C6F);
-            intensityNoise = new ImprovedNoise(intensityRandom);
+            intensityNoise = new ImprovedPerlinNoise(intensityRandom);
         }
     }
     
diff --git a/game/core/src/test/java/TestNoise.java b/game/core/src/test/java/TestNoise.java
index 1e7cc850a..28711ac46 100644
--- a/game/core/src/test/java/TestNoise.java
+++ b/game/core/src/test/java/TestNoise.java
@@ -1,19 +1,14 @@
-import net.minecraft.core.world.noise.ImprovedNoise;
-import net.minecraft.core.world.noise.PerlinNoise;
-import net.minecraft.core.world.noise.PerlinSimplexNoise;
-import net.minecraft.core.world.noise.SimplexNoise;
-import org.apache.logging.log4j.core.util.Assert;
+import net.minecraft.core.world.noise.*;
 import org.jetbrains.annotations.NotNull;
 import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.Test;
 
-import java.util.Arrays;
 import java.util.Random;
 
 public class TestNoise {
     @Test
     public void testImprovedPerlin() {
-        final @NotNull ImprovedNoise improvedNoise = new ImprovedNoise(new Random(0));
+        final @NotNull ImprovedPerlinNoise improvedNoise = new ImprovedPerlinNoise(new Random(0));
 
         // 2D single value read
         Assertions.assertEquals(-0.2610573416239221, improvedNoise.getValue(54.43272, 578.437364));
@@ -24,13 +19,13 @@ public class TestNoise {
         // 3D region read
         final double @NotNull [] expected = {-0.09566354243549174, -0.09566354243543021, -0.09566354243567703, -0.09566354243567703, -0.09566354243549227, -0.09566354243543072, -0.09566354243567755, -0.09566354243567755, -0.09566354243549227, -0.09566354243543072, -0.09566354243567755, -0.09566354243567755, -0.09566354243549227, -0.09566354243543072, -0.09566354243567755, -0.09566354243567755, -0.09566354243548755, -0.09566354243542602, -0.09566354243567284, -0.09566354243567284, -0.09566354243548808, -0.09566354243542653, -0.09566354243567336, -0.09566354243567336, -0.09566354243548808, -0.09566354243542653, -0.09566354243567336, -0.09566354243567336, -0.09566354243548808, -0.09566354243542653, -0.09566354243567336, -0.09566354243567336, -0.09566354243548755, -0.09566354243542602, -0.09566354243567284, -0.09566354243567284, -0.09566354243548808, -0.09566354243542653, -0.09566354243567336, -0.09566354243567336, -0.09566354243548808, -0.09566354243542653, -0.09566354243567336, -0.09566354243567336, -0.09566354243548808, -0.09566354243542653, -0.09566354243567336, -0.09566354243567336, -0.09566354243548755, -0.09566354243542602, -0.09566354243567284, -0.09566354243567284, -0.09566354243548808, -0.09566354243542653, -0.09566354243567336, -0.09566354243567336, -0.09566354243548808, -0.09566354243542653, -0.09566354243567336, -0.09566354243567336, -0.09566354243548808, -0.09566354243542653, -0.09566354243567336, -0.09566354243567336};
         final double @NotNull [] out = new double[4 * 4 * 4];
-        improvedNoise.add(out, 0.0, 0.0, 0.0, 4, 4, 4, 512.0, 512.0, 512.0, 1.0);
+        improvedNoise.getRegion(out, 0.0, 0.0, 0.0, 4, 4, 4, 512.0, 512.0, 512.0);
         Assertions.assertArrayEquals(expected, out);
     }
 
     @Test
     public void testImprovedPerlinFBM() {
-        final @NotNull PerlinNoise perlinNoise = new PerlinNoise(0, 8);
+        final @NotNull FractalNoise3D<ImprovedPerlinNoise> perlinNoise = new FractalNoise3D<>(ImprovedPerlinNoise.genOctaves(0, 8));
 
         // 2D single value read
         Assertions.assertEquals(-40.12729053826283, perlinNoise.getValue(54.43272, 578.437364));
@@ -56,20 +51,20 @@ public class TestNoise {
         final @NotNull SimplexNoise simplexNoise = new SimplexNoise(new Random(0));
 
         // 3D region read
-        final double @NotNull [] expected = new double[] {-0.1742994852638034, -0.03465459789724085, -0.3536905075085449, 0.118920155221024, -0.03465459789706194, -0.3536905075092016, 0.11892015522101985, -0.4494057992596276, -0.35369050750903475, 0.11892015522084308, -0.4494057992596276, -0.346400636257933, 0.11892015522086728, -0.44940579925952345, -0.346400636257933, 0.6678974698632795};
+        final double @NotNull [] expected = new double[] {-0.09586471689509188, -0.228595829818887, -0.2416644315036481, -0.1945297791296997, -0.013486861902244759, 0.12848897712900664, 0.36298350391367423, 0.3270423093833717, -0.2259120490081839, 0.4568503832347575, -0.04081097434424582, -0.28821378102132783, -0.19452977912996913, 0.37237182879586456, -0.24562845274014303, -0.2471731895927952};
         final double @NotNull [] out = new double[4 * 4];
-        simplexNoise.add(out, 0.0, 0.0, 4, 4, 512.0, 512.0, 1.0);
+        simplexNoise.getRegion(out, 0.0, 0.0, 4, 4, 512.0, 512.0);
         Assertions.assertArrayEquals(expected, out);
     }
 
     @Test
     public void testSimplexFBM() {
-        final @NotNull PerlinSimplexNoise perlinSimplexNoise = new PerlinSimplexNoise(new Random(0), 8);
+        final @NotNull FractalNoise3D<SimplexNoise> noise = new FractalNoise3D<>(SimplexNoise.genOctaves(0, 8));
 
         // 2D region read
         final double @NotNull [] expected = new double[] {50.84574324927897, 58.62470059533197, 29.96009128707059, -24.82665220496603, -14.95484987852672, -5.132647986808635, -56.84226192427461, -51.14227181041018, -8.522713417039947, 8.694440778390828, 1.1532938487621358, 24.27113975380712, -54.324564442351644, -14.929257621046592, 39.5916240857992, -38.96919968269769};
         final double @NotNull [] out = new double[4 * 4];
-        perlinSimplexNoise.getRegion(out, 0.0, 0.0, 4, 4, 512.0, 512.0, 0.5);
+        noise.getRegion(out, 0.0, 0.0, 4, 4, 512.0, 512.0);
         Assertions.assertArrayEquals(expected, out);
     }
 }
