diff --git a/game/core/src/main/java/net/minecraft/core/net/command/util/CommandHelper.java b/game/core/src/main/java/net/minecraft/core/net/command/util/CommandHelper.java
index 84f58dbe0..2c2fc15bc 100644
--- a/game/core/src/main/java/net/minecraft/core/net/command/util/CommandHelper.java
+++ b/game/core/src/main/java/net/minecraft/core/net/command/util/CommandHelper.java
@@ -175,7 +175,7 @@ public class CommandHelper {
         registerWorldFeatureClass(WorldFeatureLiquid.class);
         registerWorldFeatureClass(WorldFeatureMeadow.class);
         registerWorldFeatureClass(WorldFeatureMudPatch.class);
-        registerWorldFeatureClass(WorldFeatureNetherLava.class);
+        registerWorldFeatureClass(WorldFeatureNetherSpring.class);
         registerWorldFeatureClass(WorldFeatureOre.class);
         registerWorldFeatureClass(WorldFeaturePermaice.class);
         registerWorldFeatureClass(WorldFeaturePumice.class);
diff --git a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/ChunkDecorationBuilder.java b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/ChunkDecorationBuilder.java
new file mode 100644
index 000000000..ad4d89526
--- /dev/null
+++ b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/ChunkDecorationBuilder.java
@@ -0,0 +1,50 @@
+package net.minecraft.core.world.generate.chunk;
+
+import net.minecraft.core.world.World;
+import net.minecraft.core.world.biome.Biome;
+import net.minecraft.core.world.chunk.Chunk;
+import net.minecraft.core.world.generate.feature.WorldFeatureInterface;
+import net.minecraft.core.world.pos.TilePos;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.Arrays;
+import java.util.Random;
+
+public class ChunkDecorationBuilder implements ChunkDecoration
+{
+    private final WorldFeatureInterface worldFeature;
+    private @NotNull PlacementMethod placementMethod = PlacementMethods.OncePerChunk;
+    private @NotNull Biome[] biomeMask = new Biome[]{};
+    private @NotNull PositionSelector positionSelector = PositionSelectors.SurfaceBlock;
+    public ChunkDecorationBuilder(final @NotNull WorldFeatureInterface worldFeature){
+        this.worldFeature = worldFeature;
+    }
+
+    public ChunkDecorationBuilder withBiomeMask(@NotNull Biome[] biomes){
+        this.biomeMask = biomes;
+        return this;
+    }
+
+    public ChunkDecorationBuilder withPositionSelector(PositionSelector positionSelector){
+        this.positionSelector = positionSelector;
+        return this;
+    }
+
+    public ChunkDecorationBuilder withPlacementMethod(PlacementMethod placementMethod){
+        this.placementMethod = placementMethod;
+        return this;
+    }
+
+
+    @Override
+    public void placeDecoration(@NotNull World world, @NotNull Chunk chunk, int worldX, int worldZ, int minY, int maxY, int rangeY, @NotNull Random rand) {
+
+        if(biomeMask.length > 0){
+            if(!Arrays.asList(biomeMask).contains(world.getBlockBiome(new TilePos(worldX, minY, worldZ)))){
+                return;
+            }
+        }
+
+        placementMethod.placeFeature(new PlaceableFeature(this.worldFeature, this.positionSelector, minY, maxY, rangeY), world, chunk, rand);
+    }
+}
diff --git a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/PlaceableFeature.java b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/PlaceableFeature.java
new file mode 100644
index 000000000..3d083e012
--- /dev/null
+++ b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/PlaceableFeature.java
@@ -0,0 +1,34 @@
+package net.minecraft.core.world.generate.chunk;
+
+import net.minecraft.core.world.World;
+import net.minecraft.core.world.chunk.Chunk;
+import net.minecraft.core.world.generate.feature.WorldFeature;
+import net.minecraft.core.world.generate.feature.WorldFeatureInterface;
+import net.minecraft.core.world.pos.TilePos;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.Random;
+
+public class PlaceableFeature {
+    private final @NotNull PositionSelector positionSelector;
+    private final @NotNull WorldFeatureInterface feature;
+    private final int minY;
+    private final int maxY;
+    private final int rangeY;
+
+    public PlaceableFeature(final @NotNull WorldFeatureInterface feature, final @NotNull PositionSelector positionSelector, final int minY, final int maxY, final int rangeY) {
+        this.feature = feature;
+        this.positionSelector = positionSelector;
+        this.minY = minY;
+        this.maxY = maxY;
+        this.rangeY = rangeY;
+    }
+
+    public void placeFeature(@NotNull final World world, @NotNull final Chunk chunk, @NotNull final Random random){
+        final TilePos tilePosition = positionSelector.getValue(world, chunk, random, minY, maxY, rangeY);
+        if(feature instanceof WorldFeature){
+            ((WorldFeature) feature).init(1.0D, 1.0D, 1.0D);
+        }
+        feature.place(world, random, tilePosition);
+    }
+}
diff --git a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/PlacementMethod.java b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/PlacementMethod.java
new file mode 100644
index 000000000..935f845af
--- /dev/null
+++ b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/PlacementMethod.java
@@ -0,0 +1,43 @@
+package net.minecraft.core.world.generate.chunk;
+
+import net.minecraft.core.world.World;
+import net.minecraft.core.world.chunk.Chunk;
+import net.minecraft.core.world.noise.Noise2D;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.Random;
+
+public interface PlacementMethod {
+
+    void placeFeature(@NotNull PlaceableFeature feature, @NotNull World world, @NotNull Chunk chunk, @NotNull Random random);
+
+
+    class ChanceToPlace implements PlacementMethod {
+        private final int chance;
+        public ChanceToPlace(final int chance){
+            this.chance = chance;
+        }
+
+        @Override
+        public void placeFeature(@NotNull PlaceableFeature feature, @NotNull World world, @NotNull Chunk chunk, @NotNull Random random) {
+            if(random.nextInt(chance) == 0) {
+                feature.placeFeature(world, chunk, random);
+            }
+        }
+    }
+
+    class TriesPerChunk implements PlacementMethod {
+        private final int tries;
+        public TriesPerChunk(final int tries){
+            this.tries = tries;
+        }
+
+
+        @Override
+        public void placeFeature(@NotNull PlaceableFeature feature, @NotNull World world, @NotNull Chunk chunk, @NotNull Random random) {
+            for(int i = 0; i < tries; i++) {
+                feature.placeFeature(world, chunk, random);
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/PlacementMethods.java b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/PlacementMethods.java
new file mode 100644
index 000000000..96838d966
--- /dev/null
+++ b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/PlacementMethods.java
@@ -0,0 +1,12 @@
+package net.minecraft.core.world.generate.chunk;
+
+import net.minecraft.core.world.World;
+import net.minecraft.core.world.chunk.Chunk;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.Random;
+
+public class PlacementMethods {
+
+    public static PlacementMethod OncePerChunk = (PlaceableFeature::placeFeature);
+}
\ No newline at end of file
diff --git a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/PositionSelector.java b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/PositionSelector.java
new file mode 100644
index 000000000..217a09872
--- /dev/null
+++ b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/PositionSelector.java
@@ -0,0 +1,12 @@
+package net.minecraft.core.world.generate.chunk;
+
+import net.minecraft.core.world.World;
+import net.minecraft.core.world.chunk.Chunk;
+import net.minecraft.core.world.pos.TilePos;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.Random;
+
+public interface PositionSelector {
+    TilePos getValue (@NotNull final World world, @NotNull final Chunk chunk, @NotNull final Random random, final int minY, final int maxY, final int rangeY);
+}
diff --git a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/PositionSelectors.java b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/PositionSelectors.java
new file mode 100644
index 000000000..59064ac5a
--- /dev/null
+++ b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/PositionSelectors.java
@@ -0,0 +1,79 @@
+package net.minecraft.core.world.generate.chunk;
+
+import net.minecraft.core.world.World;
+import net.minecraft.core.world.chunk.Chunk;
+import net.minecraft.core.world.pos.TilePos;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.Random;
+
+public class PositionSelectors {
+    public static class HeightRangeUniform implements PositionSelector {
+
+        private final int range;
+
+        public HeightRangeUniform(final int range){
+            this.range = Math.min(range, 1);
+        }
+
+        @Override
+        public TilePos getValue(@NotNull World world, @NotNull Chunk chunk, @NotNull Random random, int minY, int maxY, int rangeY) {
+
+            int x = (chunk.pos.x() * 16) + random.nextInt(16);
+            int z = (chunk.pos.z() * 16) + random.nextInt(16);
+            int y = minY + random.nextInt(rangeY / range);
+            return new TilePos(x, y, z);
+        }
+    }
+
+    public static PositionSelector MinY = (world, chunk, random, minY, maxY, rangeY) -> {
+        int x = (chunk.pos.x() * 16) + random.nextInt(16);
+        int z = (chunk.pos.z() * 16) + random.nextInt(16);
+
+        return new TilePos(x, minY, z);
+    };
+
+
+    public static PositionSelector MaxY = (world, chunk, random, minY, maxY, rangeY) -> {
+        int x = (chunk.pos.x() * 16) + random.nextInt(16);
+        int z = (chunk.pos.z() * 16) + random.nextInt(16);
+
+        return new TilePos(x, maxY, z);
+    };
+
+    public static PositionSelector HeightRangeUniform = (world, chunk, random, minY, maxY, rangeY) -> {
+        int x = (chunk.pos.x() * 16) + random.nextInt(16);
+        int z = (chunk.pos.z() * 16) + random.nextInt(16);
+        int y = minY + random.nextInt(rangeY);
+        return new TilePos(x, y, z);
+    };
+
+    public static PositionSelector HeightRangeUniformFromOcean = (world, chunk, random, minY, maxY, rangeY) -> {
+        int x = (chunk.pos.x() * 16) + random.nextInt(16);
+        int z = (chunk.pos.z() * 16) + random.nextInt(16);
+        int y = world.getWorldType().getOceanY() + random.nextInt(rangeY - 8) + 4;
+        return new TilePos(x, y, z);
+    };
+
+    public static PositionSelector UpperHeightRangeUniform = (world, chunk, random, minY, maxY, rangeY) -> {
+        int x = (chunk.pos.x() * 16) + random.nextInt(16);
+        int z = (chunk.pos.z() * 16) + random.nextInt(16);
+        int y = rangeY / 2 + random.nextInt(rangeY - 8) + 4;
+        return new TilePos(x, y, z);
+    };
+
+    public static PositionSelector HeightRangeBiasedTop = (world, chunk, random, minY, maxY, rangeY) -> {
+        int x = (chunk.pos.x() * 16) + random.nextInt(16);
+        int z = (chunk.pos.z() * 16) + random.nextInt(16);
+        int y = minY + random.nextInt(random.nextInt(rangeY - (rangeY / 16)) + (rangeY / 16));
+        return new TilePos(x, y, z);
+    };
+
+    public static PositionSelector SurfaceBlock = (world, chunk, random, minY, maxY, rangeY) -> {
+        int x = (chunk.pos.x() * 16) + random.nextInt(16);
+        int z = (chunk.pos.z() * 16) + random.nextInt(16);
+        int y = world.getHeightValue(x, z);
+        return new TilePos(x, y, z);
+    };
+
+}
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 d66c6bc05..aa74514bc 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
@@ -1,284 +1,230 @@
 package net.minecraft.core.world.generate.chunk.perlin.nether;
 
-import net.minecraft.core.block.BlockLogicSand;
 import net.minecraft.core.block.Blocks;
 import net.minecraft.core.world.World;
 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.ChunkDecorator;
+import net.minecraft.core.world.generate.chunk.*;
 import net.minecraft.core.world.generate.feature.*;
 import net.minecraft.core.world.generate.feature.tree.WorldFeatureBoneshaleTree;
 import net.minecraft.core.world.noise.FractalNoise2D;
 import net.minecraft.core.world.noise.ImprovedPerlinNoise;
-import net.minecraft.core.world.noise.Noise2D;
-import net.minecraft.core.world.pos.TilePos;
 import org.jetbrains.annotations.NotNull;
 
-import java.util.Random;
-
 public class ChunkDecoratorNether
-    implements ChunkDecorator {
-    private final @NotNull World world;
-    private final @NotNull Noise2D crystalDensityNoise;
-
+        extends ChunkFeatureDecorator {
+    private final @NotNull FractalNoise2D<ImprovedPerlinNoise> crystalDensityNoise;
     public ChunkDecoratorNether(@NotNull World world) {
-        this.world = world;
-        this.crystalDensityNoise = new FractalNoise2D<>(ImprovedPerlinNoise.genOctaves(world.getRandomSeed(), 6, 74));
+        super(world);
+        this.crystalDensityNoise = new FractalNoise2D<>(ImprovedPerlinNoise.genOctaves(world.getRandomSeed(), 8, 74));
     }
 
     @Override
-    public void decorate(@NotNull Chunk chunk) {
-        int chunkX = chunk.pos.x;
-        int chunkZ = chunk.pos.z;
-
-        int minY = this.world.getWorldType().getMinY(world);
-        int maxY = this.world.getWorldType().getMaxY(world);
-        int rangeY = (maxY + 1) - minY;
-
-        Random rand = new Random((long) chunkX * 0x4f9939f508L + (long) chunkZ * 0x1ef1565bd5L);
-
-        BlockLogicSand.fallInstantly = true;
-        int x = chunkX * 16;
-        int z = chunkZ * 16;
-        Biome biome = this.world.getBlockBiome(x + 16, minY, z + 16);
-
-        final @NotNull TilePos ti = new TilePos();
-
-        if (biome == Biomes.NETHER_CRYSTAL_FOREST || biome == Biomes.NETHER_CRYSTAL_FIELD ) {
-            double noiseScale = 0.5;
-
-            int density = (int) ((this.crystalDensityNoise.getValue(x * noiseScale, z * noiseScale) - 6D + 30D) / 6D);
-
-            if (biome == Biomes.NETHER_CRYSTAL_FOREST) {
-                for (int i = 0; i < density + 4; i++) {
-                    ti.set(
-                            x + rand.nextInt(16) + 8,
-                            rangeY / 2 + rand.nextInt(rangeY - 8) + 4,
-                            z + rand.nextInt(16) + 8
-                    );
-
-                    boolean isCeiling = rand.nextInt(5) == 0;
-                    new WorldFeatureRubyglassCrystal(isCeiling).place(this.world, rand, ti);
-                }
-
-
-                for (int i = 0; i < density + 6; i++) {
-                    ti.set(
-                            x + rand.nextInt(16) + 8,
-                            rangeY / 2 + rand.nextInt(rangeY - 8) + 4,
-                            z + rand.nextInt(16) + 8
-                    );
-
-                    new WorldFeatureRubyglassCrystal(false, 25, 50).place(world, rand, ti);
-                }
-            }
-
-            ti.set(
-                    x + rand.nextInt(16) + 8,
-                    rangeY / 2 + rand.nextInt(rangeY - 8) + 4,
-                    z + rand.nextInt(16) + 8
-            );
-
-            new WorldFeatureRubyglassCrystal(false, 20, 30).place(world, rand, ti);
-
-
-            for (int i = 0; i < 20; i++) {
-                int xf = x + rand.nextInt(16) + 8;
-                int yf = this.world.getWorldType().getOceanY() + rand.nextInt(rangeY - 8) + 4;
-                int zf = z + rand.nextInt(16) + 8;
-                (new WorldFeatureRubyglassGrowthPatch()).place(world, rand, xf, yf, zf);
-            }
-
-            for(int l18 = 0; l18 < 30; l18++)
-            {
-                int l21 = x + rand.nextInt(16) + 8;
-                int k23 = minY + rand.nextInt(rand.nextInt(rangeY - (rangeY / 16)) + (rangeY / 16));
-                int l24 = z + rand.nextInt(16) + 8;
-                (new WorldFeatureNetherLava(Blocks.FLUID_WATER_FLOWING.id())).place(world, rand, l21, k23, l24);
-            }
-            if (rand.nextInt(4) == 0) {
-                int xf = x + rand.nextInt(16) + 8;
-                int yf = rangeY / 2 + rand.nextInt(rangeY - 8) + 4;
-                int zf = z + rand.nextInt(16) + 8;
-                new WorldFeaturePillar(Blocks.NETHERRACK.id(), true).place(world, rand, xf, yf, zf);
-            }
-        }
-
-        if (biome == Biomes.NETHER_VOLCANIC_ISLANDS) {
-            for(int l18 = 0; l18 < 50; l18++)
-            {
-                int l21 = x + rand.nextInt(16) + 8;
-                int k23 = minY + rand.nextInt(rand.nextInt(rangeY - (rangeY / 16)) + (rangeY / 16));
-                int l24 = z + rand.nextInt(16) + 8;
-                (new WorldFeatureNetherLava(Blocks.FLUID_LAVA_FLOWING.id())).place(world, rand, l21, k23, l24);
-            }
-
-            if (rand.nextInt(4) == 0) {
-                int xf = x + rand.nextInt(16) + 8;
-                int yf = rangeY / 2 + rand.nextInt(rangeY - 8) + 4;
-                int zf = z + rand.nextInt(16) + 8;
-                new WorldFeaturePillar(Blocks.COBBLE_BASALT.id(), true).place(world, rand, xf, yf, zf);
-            }
-
-            for (int i = 0; i < 2; i++) {
-                int xf1 = x + rand.nextInt(16) + 8;
-                int yf1 = world.getWorldType().getOceanY() + rand.nextInt(rangeY - 8) + 4;
-                int zf1 = z + rand.nextInt(16) + 8;
-                new WorldFeatureMagmaBoulder().place(world, rand, xf1, yf1, zf1);
-            }
-
-        }
-
-        if (biome == Biomes.NETHER_SULFUR_POOLS) {
-            if (rand.nextInt(8) != 0) {
-                new WorldFeatureTerrace(Blocks.FLUID_WATER_STILL, Blocks.BRIMSAND).place(world, rand, x, 0, z);
-            }
-
-            if (rand.nextInt(8) == 0) {
-                int xf = x + rand.nextInt(16) + 8;
-                int yf = rangeY / 2 + rand.nextInt(rangeY - 8) + 4;
-                int zf = z + rand.nextInt(16) + 8;
-                new WorldFeaturePillar(Blocks.COBBLE_BASALT.id(), true).place(world, rand, xf, yf, zf);
-            }
-
-            for(int l18 = 0; l18 < 30; l18++)
-            {
-                int l21 = x + rand.nextInt(16) + 8;
-                int k23 = minY + rand.nextInt(rand.nextInt(rangeY - (rangeY / 16)) + (rangeY / 16));
-                int l24 = z + rand.nextInt(16) + 8;
-                (new WorldFeatureNetherLava(Blocks.FLUID_LAVA_FLOWING.id())).place(world, rand, l21, k23, l24);
-            }
-
-            for (int i = 0; i < 1; i++) {
-                int xf1 = x + rand.nextInt(16) + 8;
-                int yf1 = world.getWorldType().getOceanY() + rand.nextInt(rangeY - 8) + 4;
-                int zf1 = z + rand.nextInt(16) + 8;
-                new WorldFeatureThermalSpire().place(world, rand, xf1, yf1, zf1);
-            }
-
-            for (int i = 0; i < 2; i++) {
-                int xf1 = x + rand.nextInt(16) + 8;
-                int yf1 = world.getWorldType().getOceanY() + rand.nextInt(rangeY - 8) + 4;
-                int zf1 = z + rand.nextInt(16) + 8;
-                new WorldFeatureMagmaBoulder().place(world, rand, xf1, yf1, zf1);
-            }
-        }
-
-        for (int i = 0; i < 10; i++) {
-            int xf = x + rand.nextInt(16);
-            int yf = rangeY / 2 + rand.nextInt(rangeY - 8) + 4;
-            int zf = z + rand.nextInt(16);
-            new WorldFeatureOre(Blocks.ORE_NETHERCOAL_NETHERRACK.id(), 12).place(this.world, rand, xf, yf, zf);
-        }
-
-        int max;
-
-        max = rand.nextInt(rand.nextInt(10) + 1);
-        for (int i = 0; i < max; i++) {
-            int xf = x + rand.nextInt(16) + 8;
-            int yf = this.world.getWorldType().getOceanY() + rand.nextInt(rangeY - 8) + 4;
-            int zf = z + rand.nextInt(16) + 8;
-            new WorldFeatureGlowstoneA().place(this.world, rand, xf, yf, zf);
-        }
-
-        for (int i = 0; i < 10; i++) {
-            int xf = x + rand.nextInt(16) + 8;
-            int yf = this.world.getWorldType().getOceanY() + rand.nextInt(rangeY - 8) + 4;
-            int zf = z + rand.nextInt(16) + 8;
-            new WorldFeatureGlowstoneB().place(this.world, rand, xf, yf, zf);
-        }
-
-
-        if (biome == Biomes.NETHER_VOLCANIC_ISLANDS) {
-            for (int i = 0; i < 20; i++) {
-                int xf = x + rand.nextInt(16);
-                int yf = rangeY / 2 + rand.nextInt(rangeY - 8) + 4;
-                int zf = z + rand.nextInt(16);
-                new WorldFeatureOre(Blocks.ORE_NETHERCOAL_NETHERRACK.id(), 16).place(this.world, rand, xf, yf, zf);
-            }
-        }
-
-        max = 4;
-
-        if(biome == Biomes.NETHER_VOLCANIC_ISLANDS || biome == Biomes.NETHER_SULFUR_POOLS) {
-            max = 8;
-        }
-        if(biome == Biomes.NETHER_CRYSTAL_FIELD || biome == Biomes.NETHER_CRYSTAL_FOREST) {
-            max = 0;
-        }
-
-        for(int i = 0; i < max; i++)
-        {
-            int xf = x + rand.nextInt(16) + 8;
-            int yf = this.world.getWorldType().getOceanY() + rand.nextInt(rangeY - 8) + 4;
-            int zf = z + rand.nextInt(16) + 8;
-            (new WorldFeatureFire()).place(this.world, rand, xf, yf, zf);
-        }
-
-        max = 2;
-
-        if(biome == Biomes.NETHER_OLD_WORLD) {
-            max = 8;
-        }
-
-        for(int i = 0; i < max; i++)
-        {
-            int xf = x + rand.nextInt(16) + 8;
-            int yf = this.world.getWorldType().getOceanY() + rand.nextInt(rangeY - 8) + 4;
-            int zf = z + rand.nextInt(16) + 8;
-            (new WorldFeatureNetherPatch(Blocks.BONE_PILE.id())).place(this.world, rand, xf, yf, zf);
-        }
-
-        max = 4;
-
-        if(biome == Biomes.NETHER_OLD_WORLD) {
-            max = 2;
-        }
-
-        for(int i = 0; i < max; i++)
-        {
-            int xf = x + rand.nextInt(16) + 8;
-            int yf = this.world.getWorldType().getOceanY() + rand.nextInt(rangeY - 8) + 4;
-            int zf = z + rand.nextInt(16) + 8;
-            (new WorldFeatureNetherPatch(Blocks.SOULCATCHER.id())).place(this.world, rand, xf, yf, zf);
-        }
-
-        if(biome == Biomes.NETHER_OLD_WORLD) {
-            double noiseScale = 0.5;
-
-            int density = (int) ((this.crystalDensityNoise.getValue(x * noiseScale, z * noiseScale) - 6D + 20D) / 6D);
-
-            for(int i = 0; i < density + 4; i++)
-            {
-                int xf = x + rand.nextInt(16) + 8;
-                int yf = this.world.getWorldType().getOceanY() + rand.nextInt(rangeY - 8) + 4;
-                int zf = z + rand.nextInt(16) + 8;
-                (new WorldFeatureBoneshaleTree(0, Blocks.BONESHALE.id())).place(this.world, rand, xf, yf, zf);
-            }
-        }
+    public void registerDecorations() {
+        this.register("minecraft:decoration/nether/default/lava_lake",
+                new ChunkDecorationBuilder(new WorldFeatureLake(Blocks.FLUID_LAVA_STILL.id()))
+                        .withPositionSelector(PositionSelectors.UpperHeightRangeUniform)
+                        .withPlacementMethod(new PlacementMethod.ChanceToPlace(4))
+        );
+        this.register("minecraft:decoration/nether/default/rubyglass_crystal_ceiling",
+                new ChunkDecorationBuilder(new WorldFeatureRubyglassCrystal(true))
+                        .withBiomeMask(new Biome[]{ Biomes.NETHER_CRYSTAL_FOREST })
+                        .withPositionSelector(PositionSelectors.UpperHeightRangeUniform)
+                        .withPlacementMethod(((feature, world, chunk, random) -> {
+                            int x = chunk.pos.x * 16;
+                            int z = chunk.pos.z * 16;
+                            int density = (int) ((this.crystalDensityNoise.getValue(x * 0.5, z * 0.5) - 6D + 30D) / 6D);
+
+                            for (int i = 0; i < density + 4; i++) {
+                                feature.placeFeature(world, chunk, random);
+                            }
+                        }))
+        );
+
+        this.register("minecraft:decoration/nether/default/rubyglass_crystal_floor",
+                new ChunkDecorationBuilder(new WorldFeatureRubyglassCrystal(false, 25, 50))
+                        .withBiomeMask(new Biome[]{ Biomes.NETHER_CRYSTAL_FOREST })
+                        .withPositionSelector(PositionSelectors.UpperHeightRangeUniform)
+                        .withPlacementMethod(((feature, world, chunk, random) -> {
+                            int x = chunk.pos.x * 16;
+                            int z = chunk.pos.z * 16;
+                            int density = (int) ((this.crystalDensityNoise.getValue(x * 0.5, z * 0.5) - 6D + 30D) / 6D);
+
+                            for (int i = 0; i < density + 4; i++) {
+                                feature.placeFeature(world, chunk, random);
+                            }
+                        }))
+        );
+
+        this.register("minecraft:decoration/nether/default/rubyglass_crystal_floor_2",
+                new ChunkDecorationBuilder(new WorldFeatureRubyglassCrystal(false,  20, 30))
+                        .withBiomeMask(new Biome[]{ Biomes.NETHER_CRYSTAL_FOREST })
+                        .withPositionSelector(PositionSelectors.UpperHeightRangeUniform)
+                        .withPlacementMethod(new PlacementMethod.TriesPerChunk(4))
+        );
+
+        this.register("minecraft:decoration/nether/default/rubyglass_sprout_patch",
+                new ChunkDecorationBuilder(new WorldFeatureRubyglassSproutPatch())
+                        .withBiomeMask(new Biome[]{ Biomes.NETHER_CRYSTAL_FOREST })
+                        .withPositionSelector(PositionSelectors.HeightRangeUniformFromOcean)
+                        .withPlacementMethod(new PlacementMethod.TriesPerChunk(20))
+        );
+
+        this.register("minecraft:decoration/nether/default/nether_water_spring",
+                new ChunkDecorationBuilder(new WorldFeatureNetherSpring(Blocks.FLUID_WATER_FLOWING.id()))
+                        .withBiomeMask(new Biome[]{ Biomes.NETHER_CRYSTAL_FOREST, Biomes.NETHER_OLD_WORLD })
+                        .withPositionSelector(PositionSelectors.HeightRangeBiasedTop)
+                        .withPlacementMethod(new PlacementMethod.TriesPerChunk(30))
+        );
+
+        this.register("minecraft:decoration/nether/default/nether_lava_spring",
+                new ChunkDecorationBuilder(new WorldFeatureNetherSpring(Blocks.FLUID_WATER_FLOWING.id()))
+                        .withBiomeMask(new Biome[]{ Biomes.NETHER_VOLCANIC_ISLANDS, Biomes.NETHER_SULFUR_POOLS, Biomes.NETHER_CRAG, Biomes.NETHER_SHELF })
+                        .withPositionSelector(PositionSelectors.HeightRangeBiasedTop)
+                        .withPlacementMethod(new PlacementMethod.TriesPerChunk(30))
+        );
+
+        this.register("minecraft:decoration/nether/default/nether_lava_spring_2",
+                new ChunkDecorationBuilder(new WorldFeatureNetherSpring(Blocks.FLUID_WATER_FLOWING.id()))
+                        .withBiomeMask(new Biome[]{ Biomes.NETHER_VOLCANIC_ISLANDS })
+                        .withPositionSelector(PositionSelectors.HeightRangeBiasedTop)
+                        .withPlacementMethod(new PlacementMethod.TriesPerChunk(20))
+        );
+
+        this.register("minecraft:decoration/nether/default/pillar_netherrack",
+                new ChunkDecorationBuilder(new WorldFeaturePillar(Blocks.NETHERRACK.id(), false))
+                        .withBiomeMask(new Biome[]{ Biomes.NETHER_CRYSTAL_FIELD, Biomes.NETHER_CRYSTAL_FOREST, Biomes.NETHER_CRAG, Biomes.NETHER_SHELF })
+                        .withPositionSelector(PositionSelectors.UpperHeightRangeUniform)
+                        .withPlacementMethod(new PlacementMethod.ChanceToPlace(4))
+        );
+
+        this.register("minecraft:decoration/nether/default/pillar_cobble_basalt",
+                new ChunkDecorationBuilder(new WorldFeaturePillar(Blocks.COBBLE_BASALT.id(), true))
+                        .withBiomeMask(new Biome[]{ Biomes.NETHER_SULFUR_POOLS })
+                        .withPositionSelector(PositionSelectors.UpperHeightRangeUniform)
+                        .withPlacementMethod(new PlacementMethod.TriesPerChunk(4))
+        );
+
+        this.register("minecraft:decoration/nether/default/boulder",
+                new ChunkDecorationBuilder(new WorldFeatureMagmaBoulder())
+                        .withBiomeMask(new Biome[]{ Biomes.NETHER_SULFUR_POOLS })
+                        .withPositionSelector(PositionSelectors.HeightRangeUniformFromOcean)
+                        .withPlacementMethod(new PlacementMethod.TriesPerChunk(2))
+        );
+
+        this.register("minecraft:decoration/nether/default/sulfur_pool_terrace",
+                new ChunkDecorationBuilder(new WorldFeatureTerrace(Blocks.FLUID_WATER_STILL, Blocks.BRIMSAND))
+                        .withBiomeMask(new Biome[]{ Biomes.NETHER_VOLCANIC_ISLANDS, Biomes.NETHER_SULFUR_POOLS })
+                        .withPositionSelector(PositionSelectors.MinY)
+                        .withPlacementMethod(PlacementMethods.OncePerChunk)
+        );
+
+        this.register("minecraft:decoration/nether/default/sulfur_pool_spire",
+                new ChunkDecorationBuilder(new WorldFeatureThermalSpire())
+                        .withBiomeMask(new Biome[]{ Biomes.NETHER_SULFUR_POOLS })
+                        .withPositionSelector(PositionSelectors.HeightRangeUniformFromOcean)
+                        .withPlacementMethod(new PlacementMethod.TriesPerChunk(12))
+        );
+
+        this.register("minecraft:decoration/nether/default/nether_coal_ore",
+                new ChunkDecorationBuilder(new WorldFeatureOre(Blocks.ORE_NETHERCOAL_NETHERRACK.id(), 12))
+                        .withPositionSelector(PositionSelectors.HeightRangeUniform)
+                        .withPlacementMethod(new PlacementMethod.TriesPerChunk(10))
+        );
+
+        this.register("minecraft:decoration/nether/default/nether_coal_ore_2",
+                new ChunkDecorationBuilder(new WorldFeatureOre(Blocks.ORE_NETHERCOAL_NETHERRACK.id(), 12))
+                        .withBiomeMask(new Biome[]{ Biomes.NETHER_VOLCANIC_ISLANDS })
+                        .withPositionSelector(PositionSelectors.HeightRangeUniform)
+                        .withPlacementMethod(new PlacementMethod.TriesPerChunk(20))
+        );
+
+        this.register("minecraft:decoration/nether/default/glowstone_1",
+                new ChunkDecorationBuilder(new WorldFeatureGlowstoneA())
+                        .withPositionSelector(PositionSelectors.HeightRangeUniformFromOcean)
+                        .withPlacementMethod(((feature, world, chunk, random) -> {
+                            int max = random.nextInt(random.nextInt(10) + 1);
+                            for (int i = 0; i < max; i++) {
+                                feature.placeFeature(world, chunk, random);
+                            }
+                        }))
+        );
+
+        this.register("minecraft:decoration/nether/default/glowstone_2",
+                new ChunkDecorationBuilder(new WorldFeatureGlowstoneB())
+                        .withPositionSelector(PositionSelectors.HeightRangeUniformFromOcean)
+                        .withPlacementMethod(new PlacementMethod.TriesPerChunk(10))
+        );
+
+        this.register("minecraft:decoration/nether/default/patch_fire_1",
+                new ChunkDecorationBuilder(new WorldFeatureFire())
+                        .withPositionSelector(PositionSelectors.HeightRangeUniformFromOcean)
+                        .withPlacementMethod(new PlacementMethod.TriesPerChunk(4))
+        );
+
+        this.register("minecraft:decoration/nether/default/patch_fire_2",
+                new ChunkDecorationBuilder(new WorldFeatureFire())
+                        .withBiomeMask(new Biome[]{ Biomes.NETHER_VOLCANIC_ISLANDS })
+                        .withPositionSelector(PositionSelectors.HeightRangeUniformFromOcean)
+                        .withPlacementMethod(new PlacementMethod.TriesPerChunk(4))
+        );
+
+        this.register("minecraft:decoration/nether/default/old_world_patch_bone_pile",
+                new ChunkDecorationBuilder(new WorldFeatureNetherPatch(Blocks.BONE_PILE.id()))
+                        .withBiomeMask(new Biome[]{ Biomes.NETHER_OLD_WORLD })
+                        .withPositionSelector(PositionSelectors.HeightRangeUniformFromOcean)
+                        .withPlacementMethod(new PlacementMethod.TriesPerChunk(4))
+        );
+
+        this.register("minecraft:decoration/nether/default/patch_bone_pile",
+                new ChunkDecorationBuilder(new WorldFeatureNetherPatch(Blocks.BONE_PILE.id()))
+                        .withPositionSelector(PositionSelectors.HeightRangeUniformFromOcean)
+                        .withPlacementMethod(new PlacementMethod.TriesPerChunk(1))
+        );
+
+        this.register("minecraft:decoration/nether/default/patch_soul_catcher",
+                new ChunkDecorationBuilder(new WorldFeatureNetherPatch(Blocks.SOULCATCHER.id()))
+                        .withPositionSelector(PositionSelectors.HeightRangeUniformFromOcean)
+                        .withPlacementMethod(new PlacementMethod.TriesPerChunk(2))
+        );
+
+        this.register("minecraft:decoration/nether/default/boneshale_tree",
+                new ChunkDecorationBuilder(((world, random, tilePos) -> {
+                    //todo refactor how spooner trees are instantiated
+                    WorldFeature wf = new WorldFeatureBoneshaleTree(0, Blocks.BONESHALE.id());
+                    wf.init(1.0D, 1.0D, 1.0D);
+                    return wf.place(world, random, tilePos);
+                }))
+                        .withBiomeMask(new Biome[]{ Biomes.NETHER_OLD_WORLD })
+                        .withPositionSelector(PositionSelectors.HeightRangeUniformFromOcean)
+                        .withPlacementMethod(new PlacementMethod.TriesPerChunk(6))
+        );
+    }
 
-        int oceanY = this.world.getWorldType().getOceanY();
-        int midY = oceanY + (this.world.getWorldType().getMaxY(world) - oceanY) / 2;
-        for (int dx = x + 8; dx < x + 8 + 16; dx++) {
-            for (int dz = z + 8; dz < z + 8 + 16; dz++) {
+    @Override
+    public void postDecorate(@NotNull World world, @NotNull Chunk chunk) {
+
+        int oceanY = world.getWorldType().getOceanY();
+        int worldX = chunk.pos.x() * 16;
+        int worldZ = chunk.pos.z() * 16;
+        int midY = oceanY + (world.getWorldType().getMaxY(world) - oceanY) / 2;
+        for (int dx = worldX; dx < worldX + 16; dx++) {
+            for (int dz = worldZ; dz < worldZ + 16; dz++) {
                 int dy = midY;
-                while (this.world.getBlockId(dx, dy, dz) == 0) {
+                while (world.getBlockId(dx, dy, dz) == 0) {
                     dy--;
                 }
                 dy++;
-                Biome localBiome = this.world.getBlockBiome(dx, dy, dz);
+                Biome localBiome = world.getBlockBiome(dx, dy, dz);
 
-                if (localBiome != null && localBiome.hasSurfaceSnow() && (dy > 0 && dy < this.world.getHeightBlocks())) {
-                    if (this.world.isAirBlock(dx, dy, dz) && this.world.getBlockMaterial(dx, dy - 1, dz).blocksMotion()) {
-                        this.world.setBlockWithNotify(dx, dy, dz, Blocks.LAYER_ASH.id());
+                if (localBiome != null && localBiome.hasSurfaceSnow() && (dy > 0 && dy < world.getHeightBlocks())) {
+                    if (world.isAirBlock(dx, dy, dz) && world.getBlockMaterial(dx, dy - 1, dz).blocksMotion()) {
+                        world.setBlock(dx, dy, dz, Blocks.LAYER_ASH.id());
                     }
                 }
             }
 
         }
-
-        BlockLogicSand.fallInstantly = false;
-
     }
 }
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 adcdae007..e5b822b5a 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
@@ -1,7 +1,6 @@
 package net.minecraft.core.world.generate.chunk.perlin.nether;
 
 import net.minecraft.core.world.World;
-import net.minecraft.core.world.biome.Biome;
 import net.minecraft.core.world.chunk.Chunk;
 import net.minecraft.core.world.generate.chunk.perlin.DensityGenerator;
 import net.minecraft.core.world.noise.*;
@@ -10,29 +9,11 @@ import org.jetbrains.annotations.NotNull;
 
 public class DensityGeneratorNether
     implements DensityGenerator {
-
-    public static class BiomeOverlapPair {
-        public boolean hasOverlap;
-        public Biome biomeA;
-        public Biome biomeB;
-        public float biomeAPercentage;
-        public float biomeBPercentage;
-    }
-
     private final @NotNull World world;
 
     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 FractalNoise2D<?> poolNoiseOver;
-    private final @NotNull FractalNoise2D<?> poolNoiseUnder;
-
-    private final @NotNull FractalNoise2D<?> ravineNoise2;
-
-    private final @NotNull FractalNoise2D<?> islandNoise;
 
     public DensityGeneratorNether(World world) {
         this.world = world;
@@ -40,15 +21,6 @@ public class DensityGeneratorNether
         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));
-
-        final long seed = world.getRandomSeed();
-
-        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));
     }
 
     @Override
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 a10760ca0..887ae1c37 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
@@ -27,13 +27,6 @@ public class SurfaceGeneratorNether
         this.soilNoise = new FractalNoise3D<>(ImprovedPerlinNoise.genOctaves(world.getRandomSeed(), 4, 44));
     }
 
-    private boolean safeToPlacePool(ChunkGeneratorResult result, int x, int y, int z) {
-        if(x<0||x>15||z<0||z>15) return true;
-        if(y < world.getWorldType().getMinY(world) || y > world.getWorldType().getMaxY(world)) return false;
-        int id = result.getBlock(x, y, z);
-        return id != 0;
-    }
-
     @Override
     public void generateSurface(@NotNull Chunk chunk, @NotNull ChunkGeneratorResult result) {
         int oceanY = this.world.getWorldType().getOceanY();
@@ -51,12 +44,10 @@ public class SurfaceGeneratorNether
         double[] sandBeachNoise = this.beachNoise.getRegion(null, chunkX * 16, chunkZ * 16, 0.0D, 16, 16, 1, beachScale, beachScale, 1.0D);
         double[] gravelBeachNoise = this.beachNoise.getRegion(null, chunkX * 16, 109.0134D, chunkZ * 16, 16, 1, 16, beachScale, 1.0D, beachScale);
         double[] soilThicknessNoise = this.soilNoise.getRegion(null, chunkX * 16, chunkZ * 16, 0.0D, 16, 16, 1, beachScale * 2D, beachScale * 2D, beachScale * 2D);
-        double[] sandPatchNoise = this.soilNoise.getRegion(null, chunkX * 16, chunkZ * 16, 0.0D, 16, 16, 1, beachScale * 2D, beachScale * 2D, beachScale);
         for (int z = 0; z < 16; z++) {
             for (int x = 0; x < 16; x++) {
                 boolean generateSoulSandBeach = sandBeachNoise[z + x * 16] + rand.nextDouble() * 0.2D > 0.0D;
                 boolean generateGravelBeach = gravelBeachNoise[z + x * 16] + rand.nextDouble() * 0.2D > 0.0D;
-                boolean generateSulfurPool = gravelBeachNoise[z + x * 16] / 3D + 3D + rand.nextDouble() * 0.5D > 3.D;
                 int soilThickness = (int) (soilThicknessNoise[z + x * 16] / 3D + 3D + rand.nextDouble() * 0.25D);
 
                 int currentLayerDepth = -1;
diff --git a/game/core/src/main/java/net/minecraft/core/world/generate/feature/WorldFeatureNetherLava.java b/game/core/src/main/java/net/minecraft/core/world/generate/feature/WorldFeatureNetherSpring.java
similarity index 94%
rename from game/core/src/main/java/net/minecraft/core/world/generate/feature/WorldFeatureNetherLava.java
rename to game/core/src/main/java/net/minecraft/core/world/generate/feature/WorldFeatureNetherSpring.java
index e9b913193..b71f37b38 100644
--- a/game/core/src/main/java/net/minecraft/core/world/generate/feature/WorldFeatureNetherLava.java
+++ b/game/core/src/main/java/net/minecraft/core/world/generate/feature/WorldFeatureNetherSpring.java
@@ -5,11 +5,11 @@ import net.minecraft.core.world.World;
 
 import java.util.Random;
 
-public class WorldFeatureNetherLava extends WorldFeature
+public class WorldFeatureNetherSpring extends WorldFeature
 {
     private final int blockId;
     @MethodParametersAnnotation(names = {"blockId"})
-    public WorldFeatureNetherLava(int blockId)
+    public WorldFeatureNetherSpring(int blockId)
     {
         this.blockId = blockId;
     }
diff --git a/game/core/src/main/java/net/minecraft/core/world/generate/feature/WorldFeatureRubyglassGrowthPatch.java b/game/core/src/main/java/net/minecraft/core/world/generate/feature/WorldFeatureRubyglassSproutPatch.java
similarity index 90%
rename from game/core/src/main/java/net/minecraft/core/world/generate/feature/WorldFeatureRubyglassGrowthPatch.java
rename to game/core/src/main/java/net/minecraft/core/world/generate/feature/WorldFeatureRubyglassSproutPatch.java
index 03ea15cca..eacb8d7bb 100644
--- a/game/core/src/main/java/net/minecraft/core/world/generate/feature/WorldFeatureRubyglassGrowthPatch.java
+++ b/game/core/src/main/java/net/minecraft/core/world/generate/feature/WorldFeatureRubyglassSproutPatch.java
@@ -7,11 +7,11 @@ import net.minecraft.core.world.pos.TilePos;
 
 import java.util.Random;
 
-public class WorldFeatureRubyglassGrowthPatch extends WorldFeature
+public class WorldFeatureRubyglassSproutPatch extends WorldFeature
 {
     private final int blockId;
 
-    public WorldFeatureRubyglassGrowthPatch()
+    public WorldFeatureRubyglassSproutPatch()
     {
         this.blockId = Blocks.RUBYGLASS_SPROUT.id();
     }
diff --git a/game/core/src/main/java/net/minecraft/core/world/generate/feature/tree/WorldFeatureBoneshaleTree.java b/game/core/src/main/java/net/minecraft/core/world/generate/feature/tree/WorldFeatureBoneshaleTree.java
index 95b96c0a3..c1e3a5439 100644
--- a/game/core/src/main/java/net/minecraft/core/world/generate/feature/tree/WorldFeatureBoneshaleTree.java
+++ b/game/core/src/main/java/net/minecraft/core/world/generate/feature/tree/WorldFeatureBoneshaleTree.java
@@ -1,7 +1,6 @@
 package net.minecraft.core.world.generate.feature.tree;
 
 import net.minecraft.core.block.Blocks;
-import net.minecraft.core.block.tag.BlockTags;
 import net.minecraft.core.util.helper.MathHelper;
 import net.minecraft.core.world.World;
 import net.minecraft.core.world.generate.feature.MethodParametersAnnotation;
@@ -45,11 +44,11 @@ public class WorldFeatureBoneshaleTree extends WorldFeature
         trunkHeightScale = 0.6D;
         branchDensity = 1.0D;
         branchSlope = 0.4D;
-        widthScale = 1.0D;
+        widthScale = 1.2D;
         foliageDensity = 1.0D;
         trunkWidth = 1;
         heightVariance = 12;
-        foliageHeight = 4;
+        foliageHeight = 5;
         this.leavesID = leavesID;
         this.logID = logID;
         this.heightMod = heightMod;
@@ -367,7 +366,7 @@ public class WorldFeatureBoneshaleTree extends WorldFeature
         int[] bottomPos = { origin[0], origin[1], origin[2] };
         int[] topPos = { origin[0], (origin[1] + height) - 1, origin[2] };
         int blockIdUnderneath = world.getBlockId(origin[0], origin[1] - 1, origin[2]);
-        if(blockIdUnderneath != Blocks.COBBLE_NETHERRACK.id())
+        if(blockIdUnderneath != Blocks.COBBLE_NETHERRACK.id() && blockIdUnderneath != Blocks.BLOCK_ASH.id() && blockIdUnderneath != Blocks.SOULSAND.id())
         {
             return false;
         }
