diff --git a/game/client/src/main/java/net/minecraft/client/entity/player/PlayerLocal.java b/game/client/src/main/java/net/minecraft/client/entity/player/PlayerLocal.java
index 74b32badc..9c354cfe4 100644
--- a/game/client/src/main/java/net/minecraft/client/entity/player/PlayerLocal.java
+++ b/game/client/src/main/java/net/minecraft/client/entity/player/PlayerLocal.java
@@ -46,6 +46,7 @@ import net.minecraft.core.util.helper.GetSkinUrlThread;
 import net.minecraft.core.util.helper.MathHelper;
 import net.minecraft.core.world.Dimension;
 import net.minecraft.core.world.World;
+import net.minecraft.core.world.pos.TilePos;
 import net.minecraft.core.world.pos.TilePosc;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
@@ -419,11 +420,14 @@ public class PlayerLocal extends Player {
         final int blockZ = MathHelper.floor(z);
         final double dX = x - (double) blockX;
         final double dZ = z - (double) blockZ;
-        if (doesBlockPushOut(blockX, blockY, blockZ) || (doesBlockPushOut(blockX, blockY + 1, blockZ) && !isShort)) {
-            final boolean flagWest = !doesBlockPushOut(blockX - 1, blockY, blockZ) && (isShort || !doesBlockPushOut(blockX - 1, blockY + 1, blockZ));
-            final boolean flagEast = !doesBlockPushOut(blockX + 1, blockY, blockZ) && (isShort || !doesBlockPushOut(blockX + 1, blockY + 1, blockZ));
-            final boolean flagNorth = !doesBlockPushOut(blockX, blockY, blockZ - 1) && (isShort || !doesBlockPushOut(blockX, blockY + 1, blockZ - 1));
-            final boolean flagSouth = !doesBlockPushOut(blockX, blockY, blockZ + 1) && (isShort || !doesBlockPushOut(blockX, blockY + 1, blockZ + 1));
+        final var query1 = new TilePos();
+        final var query2 = new TilePos();
+        query1.set(blockX, blockY, blockZ);
+        if (doesBlockPushOut(query1) || (doesBlockPushOut(query1.up(query2)) && !isShort)) {
+            final boolean flagWest = !doesBlockPushOut(query1.add(-1,0,0, query2)) && (isShort || !doesBlockPushOut(query1.add(-1,1,0, query2)));
+            final boolean flagEast = !doesBlockPushOut(query1.add(+1,0,0, query2)) && (isShort || !doesBlockPushOut(query1.add(+1,0,0, query2)));
+            final boolean flagNorth = !doesBlockPushOut(query1.add(0,0,-1, query2)) && (isShort || !doesBlockPushOut(query1.add(0,1,-1, query2)));
+            final boolean flagSouth = !doesBlockPushOut(query1.add(0,0,+1, query2)) && (isShort || !doesBlockPushOut(query1.add(0,1,+1, query2)));
             Direction pushDirection = Direction.NONE;
             double minLength = Double.MAX_VALUE;
             if (flagWest && dX < minLength) {
diff --git a/game/client/src/main/java/net/minecraft/client/enums/MusicFrequency.java b/game/client/src/main/java/net/minecraft/client/enums/MusicFrequency.java
index f10ae9c1f..1e6801804 100644
--- a/game/client/src/main/java/net/minecraft/client/enums/MusicFrequency.java
+++ b/game/client/src/main/java/net/minecraft/client/enums/MusicFrequency.java
@@ -5,7 +5,7 @@ import net.minecraft.core.util.helper.ITranslatable;
 public enum MusicFrequency
     implements ITranslatable
 {
-    CONTINUOUS(0),
+    CONTINUOUS(10),
     FREQUENT(3000),
     DEFAULT(6000),
     UNUSUAL(12000),
diff --git a/game/client/src/main/java/net/minecraft/client/render/ItemRenderer.java b/game/client/src/main/java/net/minecraft/client/render/ItemRenderer.java
index 98ec47006..c77be5e92 100644
--- a/game/client/src/main/java/net/minecraft/client/render/ItemRenderer.java
+++ b/game/client/src/main/java/net/minecraft/client/render/ItemRenderer.java
@@ -19,6 +19,7 @@ import net.minecraft.client.render.texture.stitcher.TextureRegistry;
 import net.minecraft.client.render.tessellator.TessellatorGeneral;
 import net.minecraft.core.block.Block;
 import net.minecraft.core.entity.Entity;
+import net.minecraft.core.entity.player.Player;
 import net.minecraft.core.item.ItemStack;
 import net.minecraft.core.util.helper.LightIndexHelper;
 import net.minecraft.core.util.helper.MathHelper;
@@ -153,7 +154,7 @@ public class ItemRenderer {
             Block<?> block = this.mc.currentWorld.getBlockType(blockPos);
             int meta = this.mc.currentWorld.getBlockData(blockPos);
             BlockModel<?> model = BlockModelDispatcher.getInstance().getDispatch(block);
-            if (this.mc.currentWorld.isBlockNormalCube(blockPos)) {
+            if (this.mc.currentWorld.shouldBlockSuffocateEntities(blockPos, Player.class)) {
                 renderInsideOfBlock(partialTicks, model.getOverlayTexture(meta));
             } else {
                 TilePos queryPos = new TilePos();
diff --git a/game/client/src/main/java/net/minecraft/client/render/tessellator/TessellatorFont.java b/game/client/src/main/java/net/minecraft/client/render/tessellator/TessellatorFont.java
index a5a6a24dc..226579478 100644
--- a/game/client/src/main/java/net/minecraft/client/render/tessellator/TessellatorFont.java
+++ b/game/client/src/main/java/net/minecraft/client/render/tessellator/TessellatorFont.java
@@ -15,6 +15,12 @@ import java.nio.ByteBuffer;
 
 public class TessellatorFont {
     private static final Logger LOGGER = LogUtils.getLogger();
+    private static final float[] mesh = {
+        0,  1,
+        1,  1,
+        0,  0,
+        1,  0,
+    };
     private boolean drawing = false;
 
     private int texture = -1;
@@ -41,14 +47,7 @@ public class TessellatorFont {
         this.vboMesh = GL41.glGenBuffers();
 
         GL41.glBindVertexArray(this.vao);
-
         GL41.glBindBuffer(GL41.GL_ARRAY_BUFFER, this.vboMesh);
-        float[] mesh = {
-            0,  1,
-            1,  1,
-            0,  0,
-            1,  0,
-        };
         GL41.glBufferData(GL41.GL_ARRAY_BUFFER, mesh, GL41.GL_STATIC_DRAW);
         GL41.glVertexAttribPointer(0, 2, GL41.GL_FLOAT, false, 0, 0);
 
@@ -158,22 +157,26 @@ public class TessellatorFont {
         this.drawing = false;
 
         GL41.glBindVertexArray(vao);
-        GL41.glBindBuffer(GL41.GL_ARRAY_BUFFER, vbo);
+        GL41.glBindBuffer(GL41.GL_ARRAY_BUFFER, this.vboMesh);
+        GL41.glVertexAttribPointer(0, 2, GL41.GL_FLOAT, false, 0, 0);
 
-        int vertSize = 2 * Float.BYTES + 9;
-        int offset = 0;
-        GL41.glVertexAttribPointer(0, 2, GL41.GL_FLOAT, false, vertSize, offset); offset += Float.BYTES * 2; // Pos XY
-        GL41.glVertexAttribPointer(1, 2, GL41.GL_UNSIGNED_BYTE, false, vertSize, offset); offset += 2; // Width Height
-        GL41.glVertexAttribPointer(2, 4, GL41.GL_UNSIGNED_BYTE, true, vertSize, offset); offset += 4; // Color
-        GL41.glVertexAttribPointer(3, 2, GL41.GL_UNSIGNED_BYTE, false, vertSize, offset); offset += 2; // UV
-        GL41.glVertexAttribPointer(4, 1, GL41.GL_UNSIGNED_BYTE, false, vertSize, offset); offset += 1; // Config
-        GL41.glVertexAttrib1f(5, LightIndexHelper.lightIndex2i(15, 15));
+        GL41.glBindBuffer(GL41.GL_ARRAY_BUFFER, vbo);
+        setAttribOffset(0);
+        GL41.glVertexAttrib1f(6, LightIndexHelper.lightIndex2i(15, 15));
 
         GL41.glEnableVertexAttribArray(0);
         GL41.glEnableVertexAttribArray(1);
         GL41.glEnableVertexAttribArray(2);
         GL41.glEnableVertexAttribArray(3);
         GL41.glEnableVertexAttribArray(4);
+        GL41.glEnableVertexAttribArray(5);
+
+        GL41.glVertexAttribDivisor(0, 0); // Vertices, always reuse the same 4 vertices
+        GL41.glVertexAttribDivisor(1, 1); // Data, one per quad
+        GL41.glVertexAttribDivisor(2, 1); // Data, one per quad
+        GL41.glVertexAttribDivisor(3, 1); // Data, one per quad
+        GL41.glVertexAttribDivisor(4, 1); // Data, one per quad
+        GL41.glVertexAttribDivisor(5, 1); // Data, one per quad
 
         GL41.glBufferData(GL41.GL_ARRAY_BUFFER, this.data.flip(), GL41.GL_STREAM_DRAW);
         GL41.glBindVertexArray(0);
@@ -234,7 +237,7 @@ public class TessellatorFont {
         }
     }
 
-    private void setAttribOffset(int offset) {
+    private static void setAttribOffset(int offset) {
         int vertSize = 2 * Float.BYTES + 9;
         int _offset = offset * vertSize;
         GL41.glVertexAttribPointer(1, 2, GL41.GL_FLOAT, false, vertSize, _offset); _offset += Float.BYTES * 2; // Pos XY
@@ -257,14 +260,15 @@ public class TessellatorFont {
 
             GL41.glBindVertexArray(this.vao);
             GL41.glBindBuffer(GL41.GL_ARRAY_BUFFER, this.vbo);
-            GL41.glVertexAttrib1f(5, GLRenderer.getLightIndex());
+            GL41.glVertexAttrib1f(6, GLRenderer.getLightIndex());
 
             for (int i = 0, size = this.metadata.length; i < size; i += 3) {
                 int texture = this.metadata[i];
                 int start = this.metadata[i + 1];
                 int count = this.metadata[i + 2];
                 GL41.glBindTexture(GL41.GL_TEXTURE_2D, texture);
-                GL41.glDrawArraysInstanced(DrawMode.TRIANGLE_STRIP.cap, start, 4, count);
+                setAttribOffset(start);
+                GL41.glDrawArraysInstanced(DrawMode.TRIANGLE_STRIP.cap, 0, 4, count);
             }
 
 
diff --git a/game/core/src/main/java/net/minecraft/core/block/Block.java b/game/core/src/main/java/net/minecraft/core/block/Block.java
index eacadee31..af0cb7f8e 100644
--- a/game/core/src/main/java/net/minecraft/core/block/Block.java
+++ b/game/core/src/main/java/net/minecraft/core/block/Block.java
@@ -303,7 +303,22 @@ public final class Block<T extends BlockLogic>
     public boolean renderAsNormalBlockOnCondition(final @NotNull WorldSource source, final @NotNull TilePosc tilePos) {
         return this.logic.renderAsNormalBlockOnCondition(source, tilePos);
     }
-    
+
+    @Override
+    public boolean suffocatesEntities(@NotNull WorldSource source, @NotNull TilePosc tilePos, @NotNull Class<? extends Entity> entityClass) {
+        return this.logic.suffocatesEntities(source, tilePos, entityClass);
+    }
+
+    @Override
+    public boolean pushesEntities(@NotNull WorldSource source, @NotNull TilePosc tilePos, @NotNull Class<? extends Entity> entityClass) {
+        return this.logic.pushesEntities(source, tilePos, entityClass);
+    }
+
+    @Override
+    public boolean canBoostMinecarts(@NotNull WorldSource source, @NotNull TilePosc tilePos) {
+        return this.logic.canBoostMinecarts(source, tilePos);
+    }
+
     @Override
     public @NotNull ItemStack @Nullable [] getBreakResult(final @NotNull World world, final @NotNull EnumDropCause dropCause, final @NotNull TilePosc tilePos, final int data, final @Nullable TileEntity tileEntity) {
         return this.logic.getBreakResult(world, dropCause, tilePos, data, tileEntity);
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockInterface.java b/game/core/src/main/java/net/minecraft/core/block/BlockInterface.java
index b7e321b4a..cb1924579 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockInterface.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockInterface.java
@@ -44,6 +44,11 @@ interface BlockInterface {
 
     boolean renderAsNormalBlockOnCondition(final @NotNull WorldSource source, final @NotNull TilePosc tilePos);
 
+    boolean suffocatesEntities(final @NotNull WorldSource source, final @NotNull TilePosc tilePos, @NotNull Class<? extends Entity> entityClass);
+    boolean pushesEntities(final @NotNull WorldSource source, final @NotNull TilePosc tilePos, @NotNull Class<? extends Entity> entityClass);
+
+    boolean canBoostMinecarts(final @NotNull WorldSource source, final @NotNull TilePosc tilePos);
+
     @Deprecated
     default boolean renderAsNormalBlockOnCondition(final @NotNull WorldSource world, final int x, final int y, final int z) {
         return this.renderAsNormalBlockOnCondition(world, new TilePos(x, y, z));
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogic.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogic.java
index b4b393752..2830d7ace 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogic.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogic.java
@@ -90,6 +90,21 @@ public class BlockLogic implements BlockInterface, IItemConvertible {
         return this.isCubeShaped();
     }
 
+    @Override
+    public boolean suffocatesEntities(@NotNull WorldSource source, @NotNull TilePosc tilePos, @NotNull Class<? extends Entity> entityClass) {
+        return this.block.getMaterial().isSolidBlocking() && this.renderAsNormalBlockOnCondition(source, tilePos);
+    }
+
+    @Override
+    public boolean pushesEntities(@NotNull WorldSource source, @NotNull TilePosc tilePos, @NotNull Class<? extends Entity> entityClass) {
+        return this.suffocatesEntities(source, tilePos, entityClass);
+    }
+
+    @Override
+    public boolean canBoostMinecarts(@NotNull WorldSource source, @NotNull TilePosc tilePos) {
+        return this.block.getMaterial().isSolidBlocking() && this.renderAsNormalBlockOnCondition(source, tilePos);
+    }
+
     @Override
     public @NotNull ItemStack @Nullable [] getBreakResult(final @NotNull World world, final @NotNull EnumDropCause dropCause, final @NotNull TilePosc tilePos, final int data, final @Nullable TileEntity tileEntity) {
         return this.getBreakResult(world, dropCause, data, tileEntity);
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicActivator.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicActivator.java
index 6999b675c..6f3aead64 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicActivator.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicActivator.java
@@ -159,6 +159,7 @@ public class BlockLogicActivator
 
     @Override
     public void updateTick(final @NotNull World world, final @NotNull TilePosc tilePos, final @NotNull Random rand, final boolean isRandomTick) {
+        if (isRandomTick) return;
         this.useItem(world, tilePos, rand);
     }
 
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicButton.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicButton.java
index 68835d3a5..84e005a2d 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicButton.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicButton.java
@@ -325,9 +325,9 @@ public class BlockLogicButton
 
     @Override
     public void updateTick(final @NotNull World world, final @NotNull TilePosc tilePos, final @NotNull Random rand, final boolean isRandomTick) {
-        if (world.isClientSide) {
-            return;
-        }
+        if (world.isClientSide) return;
+        if (isRandomTick) return;
+
         final int meta = world.getBlockData(tilePos);
         if ((meta & MASK_POWERED) == 0) {
             return;
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicConduit.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicConduit.java
index ac1c40dad..38fa673b5 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicConduit.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicConduit.java
@@ -1,6 +1,7 @@
 package net.minecraft.core.block;
 
 import net.minecraft.core.block.material.Material;
+import net.minecraft.core.entity.Entity;
 import net.minecraft.core.entity.Mob;
 import net.minecraft.core.entity.player.Player;
 import net.minecraft.core.item.ItemStack;
@@ -55,6 +56,7 @@ public class BlockLogicConduit extends BlockLogic {
 
     @Override
     public void updateTick(final @NotNull World world, final @NotNull TilePosc tilePos, final @NotNull Random rand, final boolean isRandomTick) {
+        if (isRandomTick) return;
         onNeighborChanged(world, tilePos, this.block);
     }
 
@@ -83,6 +85,11 @@ public class BlockLogicConduit extends BlockLogic {
         return false;
     }
 
+    @Override
+    public boolean suffocatesEntities(@NotNull WorldSource source, @NotNull TilePosc tilePos, @NotNull Class<? extends Entity> entityClass) {
+                return true;
+    }
+
     @Override
     public boolean isSignalSource() {return true;}
 
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicDispenser.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicDispenser.java
index e94c41206..faacd85aa 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicDispenser.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicDispenser.java
@@ -150,6 +150,7 @@ public class BlockLogicDispenser extends BlockLogicVeryRotatable {
 
     @Override
     public void updateTick(final @NotNull World world, final @NotNull TilePosc tilePos, final @NotNull Random rand, final boolean isRandomTick) {
+        if (isRandomTick) return;
         this.dispenseItem(world, tilePos, rand);
     }
 }
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicFarmland.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicFarmland.java
index 6568dc84f..8b3c7b905 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicFarmland.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicFarmland.java
@@ -206,6 +206,11 @@ public class BlockLogicFarmland
         return false;
     }
 
+    @Override
+    public boolean suffocatesEntities(@NotNull WorldSource source, @NotNull TilePosc tilePos, @NotNull Class<? extends Entity> entityClass) {
+        return true;
+    }
+
     @Override
     public boolean isEquivalent(@NotNull World world, @NotNull TilePosc thisPos, @NotNull TilePosc thatPos) {
         final @Nullable Block<?> bBlock = world.getBlockType(thatPos);
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicGlass.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicGlass.java
index a7983be81..842bb56a7 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicGlass.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicGlass.java
@@ -2,9 +2,13 @@ package net.minecraft.core.block;
 
 import net.minecraft.core.block.entity.TileEntity;
 import net.minecraft.core.block.material.Material;
+import net.minecraft.core.entity.Entity;
 import net.minecraft.core.enums.EnumDropCause;
 import net.minecraft.core.item.ItemStack;
 import net.minecraft.core.world.World;
+import net.minecraft.core.world.WorldSource;
+import net.minecraft.core.world.pos.TilePosc;
+
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
@@ -23,4 +27,9 @@ public class BlockLogicGlass extends BlockLogicTransparent
             default -> null;
         };
     }
+
+    @Override
+    public boolean pushesEntities(@NotNull WorldSource source, @NotNull TilePosc tilePos, @NotNull Class<? extends Entity> entityClass) {
+        return true;
+    }
 }
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicGlassSteel.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicGlassSteel.java
new file mode 100644
index 000000000..18fb94987
--- /dev/null
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicGlassSteel.java
@@ -0,0 +1,24 @@
+package net.minecraft.core.block;
+
+import net.minecraft.core.block.entity.TileEntity;
+import net.minecraft.core.block.material.Material;
+import net.minecraft.core.enums.EnumDropCause;
+import net.minecraft.core.item.ItemStack;
+import net.minecraft.core.world.World;
+
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+public class BlockLogicGlassSteel extends BlockLogicGlass
+{
+
+    public BlockLogicGlassSteel(@NotNull Block<?> block, @NotNull Material material)
+    {
+        super(block, material);
+    }
+
+    @Override
+    public ItemStack[] getBreakResult(@NotNull World world, @NotNull EnumDropCause dropCause, int data, @Nullable TileEntity tileEntity) {
+        return new ItemStack[] { new ItemStack(this.block) };
+    }
+}
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicGlassTinted.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicGlassTinted.java
index b75b54631..5e74e25e4 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicGlassTinted.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicGlassTinted.java
@@ -1,12 +1,7 @@
 package net.minecraft.core.block;
 
-import net.minecraft.core.block.entity.TileEntity;
 import net.minecraft.core.block.material.Materials;
-import net.minecraft.core.enums.EnumDropCause;
-import net.minecraft.core.item.ItemStack;
-import net.minecraft.core.world.World;
 import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
 
 public class BlockLogicGlassTinted extends BlockLogicGlass
 {
@@ -22,12 +17,4 @@ public class BlockLogicGlassTinted extends BlockLogicGlass
     {
         return true;
     }
-
-    @Override
-    public ItemStack[] getBreakResult(@NotNull World world, @NotNull EnumDropCause dropCause, int data, @Nullable TileEntity tileEntity) {
-        return switch (dropCause) {
-            case SILK_TOUCH, PICK_BLOCK -> new ItemStack[]{new ItemStack(this)};
-            default -> null;
-        };
-    }
 }
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicIce.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicIce.java
index 2dffdb031..3266769eb 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicIce.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicIce.java
@@ -3,12 +3,14 @@ package net.minecraft.core.block;
 import net.minecraft.core.block.entity.TileEntity;
 import net.minecraft.core.block.material.Material;
 import net.minecraft.core.block.material.Materials;
+import net.minecraft.core.entity.Entity;
 import net.minecraft.core.entity.player.Player;
 import net.minecraft.core.enums.EnumDropCause;
 import net.minecraft.core.enums.LightLayer;
 import net.minecraft.core.item.ItemStack;
 import net.minecraft.core.sound.SoundCategory;
 import net.minecraft.core.world.World;
+import net.minecraft.core.world.WorldSource;
 import net.minecraft.core.world.biome.Biome;
 import net.minecraft.core.world.biome.BiomeTags;
 import net.minecraft.core.world.pos.TilePos;
@@ -49,12 +51,12 @@ public class BlockLogicIce extends BlockLogicTransparent {
 	public void updateTick(@NotNull World world, @NotNull TilePosc tilePos, @NotNull Random rand, boolean isRandomTick)
     {
         if (isRandomTick && rand.nextInt(8) == 0 && world.getWorldType().hasTag(WorldTypeTags.HOT)) {
-            world.setBlockTypeNotify(tilePos, Blocks.FLUID_WATER_STILL);
+            world.setBlockTypeNotify(tilePos, Blocks.FLUID_WATER_FLOWING);
         }
 
         if(world.getSavedLightValue(LightLayer.Block, tilePos) > 11 - this.block.lightBlock())
         {
-            world.setBlockTypeNotify(tilePos, Blocks.FLUID_WATER_STILL);
+            world.setBlockTypeNotify(tilePos, Blocks.FLUID_WATER_FLOWING);
         }
     }
 
@@ -63,4 +65,9 @@ public class BlockLogicIce extends BlockLogicTransparent {
     {
         return Material.PISTON_PUSHABLE;
     }
+
+    @Override
+    public boolean pushesEntities(@NotNull WorldSource source, @NotNull TilePosc tilePos, @NotNull Class<? extends Entity> entityClass) {
+        return true;
+    }
 }
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicLayerAsh.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicLayerAsh.java
index 013332665..b09358de3 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicLayerAsh.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicLayerAsh.java
@@ -14,7 +14,7 @@ import net.minecraft.core.world.pos.TilePosc;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
-public class BlockLogicLayerAsh extends BlockLogicLayerBase
+public class BlockLogicLayerAsh extends BlockLogicLayerSupportable
 {
 
     public BlockLogicLayerAsh(Block<? extends BlockLogicLayerBase> block, Block<?> fullBlock, Material material)
@@ -28,12 +28,11 @@ public class BlockLogicLayerAsh extends BlockLogicLayerBase
     public void onEntityWalkedOn(@NotNull World world, @NotNull TilePosc tilePos, @NotNull Entity entity) {
         TilePos emberPos = tilePos.down(new TilePos());
 
-        if (world.getBlockId(emberPos.x(), emberPos.y(), emberPos.z()) == Blocks.EMBER.id()) {
-            BlockLogic logic = Blocks.EMBER.getLogic();
-            if (logic instanceof BlockLogicEmber) {
-                if(entity instanceof Player || entity instanceof MobWolf) {
-                    ((BlockLogicEmber) logic).ignite(world, emberPos, entity);
-                }
+        if (world.getBlockType(emberPos) == Blocks.EMBER) {
+            if (entity instanceof Player || entity instanceof MobWolf) {
+                assert Blocks.EMBER.getLogic() instanceof BlockLogicEmber;
+                final var ember = (BlockLogicEmber) Blocks.EMBER.getLogic();
+                ember.ignite(world, emberPos, entity);
             }
         }
     }
@@ -51,26 +50,6 @@ public class BlockLogicLayerAsh extends BlockLogicLayerBase
         world.markBlockNeedsUpdate(tilePos);
     }
 
-    @Override
-    public boolean canPlaceAt(@NotNull World world, @NotNull TilePosc tilePos) {
-        TilePos down = tilePos.down(new TilePos());
-        Block<?> b = world.getBlockType(down);
-        if(!b.isSolidRender()) {
-            return false;
-        } else {
-            Material material = world.getBlockMaterial(down);
-            return material.blocksMotion();
-        }
-    }
-
-    @Override
-    public void onNeighborChanged(@NotNull World world, @NotNull TilePosc tilePos, final @NotNull Block<?> block) {
-        if (!canPlaceAt(world, tilePos)) {
-            dropWithCause(world, EnumDropCause.WORLD, tilePos, world.getBlockData(tilePos), null, null);
-            world.setBlockTypeNotify(tilePos, Blocks.AIR);
-        }
-    }
-
     @Override
     public @NotNull ItemStack @Nullable [] getBreakResult(@NotNull World world, @NotNull EnumDropCause dropCause, int data, @Nullable TileEntity tileEntity) {
         return switch (dropCause) {
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicLayerLeaves.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicLayerLeaves.java
index 07cc209bc..b01bf518f 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicLayerLeaves.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicLayerLeaves.java
@@ -16,7 +16,7 @@ import org.joml.primitives.AABBdc;
 
 import java.util.Random;
 
-public class BlockLogicLayerLeaves extends BlockLogicLayerBase {
+public class BlockLogicLayerLeaves extends BlockLogicLayerSupportable {
     public static final int MASK_PERMANENT = 0b1000_0000;
 
     public BlockLogicLayerLeaves(Block<? extends BlockLogicLayerLeaves> block, Block<?> fullBlock, Material material) {
@@ -47,27 +47,6 @@ public class BlockLogicLayerLeaves extends BlockLogicLayerBase {
         world.markBlockNeedsUpdate(tilePos);
     }
 
-    @Override
-    public boolean canPlaceAt(@NotNull World world, @NotNull TilePosc tilePos) {
-        TilePos down = tilePos.down(new TilePos());
-        Block<?> b = world.getBlockType(down);
-        if (b == null || (!b.isSolidRender() && !(b.getLogic() instanceof BlockLogicLeavesBase))) {
-            return false;
-        } else {
-            Material material = world.getBlockMaterial(down);
-            return material.blocksMotion();
-        }
-    }
-
-    @Override
-    public void onNeighborChanged(@NotNull World world, @NotNull TilePosc tilePos, final @NotNull Block<?> block) {
-        // Remove if no longer valid
-        if (!canPlaceAt(world, tilePos)) {
-            dropWithCause(world, EnumDropCause.WORLD, tilePos, world.getBlockData(tilePos), null, null);
-            world.setBlockTypeNotify(tilePos, Blocks.AIR);
-        }
-    }
-
     @Override
     public ItemStack[] getBreakResult(@NotNull World world, @NotNull EnumDropCause dropCause, int data, @Nullable TileEntity tileEntity) {
         return switch (dropCause) {
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicLayerSnow.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicLayerSnow.java
index a853eafd6..b98471617 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicLayerSnow.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicLayerSnow.java
@@ -20,7 +20,7 @@ import org.joml.primitives.AABBdc;
 
 import java.util.Random;
 
-public class BlockLogicLayerSnow extends BlockLogicLayerBase {
+public class BlockLogicLayerSnow extends BlockLogicLayerSupportable {
 
     public BlockLogicLayerSnow(@NotNull Block<? extends BlockLogicLayerBase> block, @Nullable Block<?> fullBlock, @NotNull Material material) {
         super(block, fullBlock, material);
@@ -42,33 +42,12 @@ public class BlockLogicLayerSnow extends BlockLogicLayerBase {
         world.markBlockNeedsUpdate(tilePos);
     }
 
-    @Override
-    public boolean canPlaceAt(@NotNull World world, @NotNull TilePosc tilePos) {
-        TilePos down = tilePos.down(new TilePos());
-        Block<?> b = world.getBlockType(down);
-        if (!b.isSolidRender() && !(b.getLogic() instanceof BlockLogicLeavesBase)) {
-            return false;
-        } else {
-            Material material = world.getBlockMaterial(down);
-            return material == Materials.LEAVES || material.blocksMotion();
-        }
-    }
-
     @Override
     public @Nullable AABBdc getCollisionAABB(@NotNull WorldSource source, @NotNull TilePosc tilePos) {
         final AABBdc aabb = getBounds();
         return new AABBd(aabb).setMax(aabb.maxX(), Math.max(aabb.maxY() - 2 / 16f, tilePos.y()), aabb.maxZ());
     }
 
-    @Override
-    public void onNeighborChanged(@NotNull World world, @NotNull TilePosc tilePos, final @NotNull Block<?> block) {
-        // Remove if no longer valid
-        if (!canPlaceAt(world, tilePos)) {
-            dropWithCause(world, EnumDropCause.WORLD, tilePos, world.getBlockData(tilePos), null, null);
-            world.setBlockTypeNotify(tilePos, Blocks.AIR);
-        }
-    }
-
     @Override
     public ItemStack[] getBreakResult(@NotNull World world, @NotNull EnumDropCause dropCause, int data, @Nullable TileEntity tileEntity) {
         return switch (dropCause) {
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicLayerSupportable.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicLayerSupportable.java
new file mode 100644
index 000000000..23d242b52
--- /dev/null
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicLayerSupportable.java
@@ -0,0 +1,37 @@
+package net.minecraft.core.block;
+
+import net.minecraft.core.block.material.Material;
+import net.minecraft.core.block.support.FullSupport;
+import net.minecraft.core.block.support.ISupport;
+import net.minecraft.core.block.support.ISupportable;
+import net.minecraft.core.enums.EnumDropCause;
+import net.minecraft.core.util.helper.Side;
+import net.minecraft.core.world.World;
+import net.minecraft.core.world.pos.TilePosc;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+public abstract class BlockLogicLayerSupportable extends BlockLogicLayerBase implements ISupportable {
+	public BlockLogicLayerSupportable(@NotNull Block<? extends BlockLogicLayerBase> block, @Nullable Block<?> fullBlock, @NotNull Material material) {
+        super(block, fullBlock, material);
+    }
+
+    @Override
+    public @NotNull ISupport getSupportConstraint(@NotNull World world, @NotNull TilePosc tilePos, @NotNull Side side) {
+        return FullSupport.INSTANCE;
+    }
+
+    @Override
+    public boolean canPlaceAt(@NotNull World world, @NotNull TilePosc tilePos) {
+        return this.isSupported(world, tilePos, Side.BOTTOM) && super.canPlaceAt(world, tilePos);
+    }
+
+    @Override
+    public void onNeighborChanged(@NotNull World world, @NotNull TilePosc tilePos, final @NotNull Block<?> block) {
+        // Remove if no longer valid
+        if (!this.canPlaceAt(world, tilePos)) {
+            this.dropWithCause(world, EnumDropCause.WORLD, tilePos, world.getBlockData(tilePos), null, null);
+            world.setBlockTypeNotify(tilePos, Blocks.AIR);
+        }
+    }
+}
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicMatcher.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicMatcher.java
index 283f3fa11..389110c9a 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicMatcher.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicMatcher.java
@@ -39,6 +39,7 @@ public class BlockLogicMatcher extends BlockLogicAxisAligned {
 
     @Override
     public void updateTick(@NotNull World world, @NotNull TilePosc tilePos, @NotNull Random rand, boolean isRandomTick) {
+        if (isRandomTick) return;
         updateState(world, tilePos);
     }
 
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicPathDirt.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicPathDirt.java
index ac4241ffa..d89e59c13 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicPathDirt.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicPathDirt.java
@@ -2,6 +2,7 @@ package net.minecraft.core.block;
 
 import net.minecraft.core.block.entity.TileEntity;
 import net.minecraft.core.block.material.Materials;
+import net.minecraft.core.entity.Entity;
 import net.minecraft.core.enums.EnumDropCause;
 import net.minecraft.core.item.ItemStack;
 import net.minecraft.core.block.material.Material;
@@ -37,6 +38,11 @@ public class BlockLogicPathDirt extends BlockLogic {
         return false;
     }
 
+    @Override
+    public boolean suffocatesEntities(@NotNull WorldSource source, @NotNull TilePosc tilePos, @NotNull Class<? extends Entity> entityClass) {
+        return true;
+    }
+
     @Override
     public void onNeighborChanged(@NotNull World world, @NotNull TilePosc tilePos, final @NotNull Block<?> block) {
         super.onNeighborChanged(world, tilePos, block);
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicPermaIce.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicPermaIce.java
new file mode 100644
index 000000000..2c449d54d
--- /dev/null
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicPermaIce.java
@@ -0,0 +1,21 @@
+package net.minecraft.core.block;
+
+import org.jetbrains.annotations.NotNull;
+
+import net.minecraft.core.block.material.Material;
+import net.minecraft.core.entity.Entity;
+import net.minecraft.core.world.WorldSource;
+import net.minecraft.core.world.pos.TilePosc;
+
+public class BlockLogicPermaIce extends BlockLogic {
+
+    public BlockLogicPermaIce(Block<?> block, Material material) {
+        super(block, material);
+        block.friction = 0.98F;
+    }
+
+    @Override
+    public boolean suffocatesEntities(@NotNull WorldSource source, @NotNull TilePosc tilePos, @NotNull Class<? extends Entity> entityClass) {
+        return true;
+    }
+}
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicPressurePlate.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicPressurePlate.java
index 10a3271ae..e0725cb98 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicPressurePlate.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicPressurePlate.java
@@ -88,9 +88,9 @@ public class BlockLogicPressurePlate<T extends Entity> extends BlockLogic implem
 
     @Override
     public void updateTick(@NotNull World world, @NotNull TilePosc tilePos, @NotNull Random rand, boolean isRandomTick) {
-        if (world.isClientSide) {
-            return;
-        }
+        if (world.isClientSide) return;
+        if (isRandomTick) return;
+
         if (isPressed(world.getBlockData(tilePos))) {
             updateState(world, tilePos);
         }
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicRailDetector.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicRailDetector.java
index ebaf81c12..188add707 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicRailDetector.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicRailDetector.java
@@ -44,9 +44,9 @@ public class BlockLogicRailDetector extends BlockLogicRail {
 
     @Override
     public void updateTick(@NotNull World world, @NotNull TilePosc tilePos, @NotNull Random rand, boolean isRandomTick) {
-        if (world.isClientSide) {
-            return;
-        }
+        if (world.isClientSide) return;
+        if (isRandomTick) return;
+
         int meta = world.getBlockData(tilePos);
         if ((meta & MASK_POWERED) != 0) { // If powered
             checkForMinecart(world, tilePos, meta);
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicRepeater.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicRepeater.java
index 7fa8e6d3f..1f8b0e775 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicRepeater.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicRepeater.java
@@ -72,6 +72,8 @@ public class BlockLogicRepeater extends BlockLogic implements ISupportable {
 
     @Override
     public void updateTick(@NotNull World world, @NotNull TilePosc tilePos, @NotNull Random rand, boolean isRandomTick) {
+        if (isRandomTick) return;
+
         int meta = world.getBlockData(tilePos);
         boolean powered = isGettingPower(world, tilePos, meta);
         var side = getSideFromMeta(meta);
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicSeat.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicSeat.java
index 5e0f1cdd4..e2c96f791 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicSeat.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicSeat.java
@@ -26,9 +26,8 @@ public class BlockLogicSeat extends BlockLogic
 
     @Override
     public boolean onInteracted(@NotNull World world, @NotNull TilePosc tilePos, @NotNull Player player, @Nullable Side side, double xHit, double yHit) {
-        if (world.isBlockNormalCube(tilePos.up(new TilePos()))) {
-            return false;
-        }
+        if (world.shouldBlockSuffocateEntities(tilePos.up(new TilePos()), player.getClass())) return false;
+
         if (!world.isClientSide) {
             TileEntitySeat tileEntity = (TileEntitySeat) world.getTileEntity(tilePos);
             if (tileEntity != null && tileEntity.getPassenger() == null) {
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicSlippery.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicSlippery.java
deleted file mode 100644
index 7a8aa2e09..000000000
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicSlippery.java
+++ /dev/null
@@ -1,11 +0,0 @@
-package net.minecraft.core.block;
-
-import net.minecraft.core.block.material.Material;
-
-public class BlockLogicSlippery extends BlockLogic {
-
-    public BlockLogicSlippery(Block<?> block, Material material) {
-        super(block, material);
-        block.friction = 0.98F;
-    }
-}
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicStatue.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicStatue.java
index 9825de3f8..687a4a1fb 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicStatue.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicStatue.java
@@ -5,6 +5,7 @@ import net.minecraft.core.block.entity.TileEntityStatue;
 import net.minecraft.core.block.material.Material;
 import net.minecraft.core.block.support.ISupport;
 import net.minecraft.core.block.support.PartialSupport;
+import net.minecraft.core.entity.Entity;
 import net.minecraft.core.entity.player.Player;
 import net.minecraft.core.enums.EnumDropCause;
 import net.minecraft.core.enums.HumanArmorShape;
@@ -14,6 +15,7 @@ import net.minecraft.core.item.ItemStack;
 import net.minecraft.core.sound.SoundCategory;
 import net.minecraft.core.util.helper.Side;
 import net.minecraft.core.world.World;
+import net.minecraft.core.world.WorldSource;
 import net.minecraft.core.world.pos.TilePos;
 import net.minecraft.core.world.pos.TilePosc;
 import org.jetbrains.annotations.NotNull;
@@ -155,6 +157,11 @@ public class BlockLogicStatue extends BlockLogic {
         return false;
     }
 
+    @Override
+    public boolean pushesEntities(@NotNull WorldSource source, @NotNull TilePosc tilePos, @NotNull Class<? extends Entity> entityClass) {
+        return true;
+    }
+
     @Override
     public boolean isSolidRender() {
         return false;
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicTorchRedstone.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicTorchRedstone.java
index f1b94382d..895b17f39 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicTorchRedstone.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicTorchRedstone.java
@@ -70,6 +70,8 @@ public class BlockLogicTorchRedstone extends BlockLogicTorch {
 
     @Override
     public void updateTick(@NotNull World world, @NotNull TilePosc tilePos, @NotNull Random rand, boolean isRandomTick) {
+        if (isRandomTick) return;
+
         boolean isPowered = hasNeighborSignal(world, tilePos);
         if (this.torchActive) {
             if (isPowered) {
diff --git a/game/core/src/main/java/net/minecraft/core/block/Blocks.java b/game/core/src/main/java/net/minecraft/core/block/Blocks.java
index d0c0e42ea..b196dfd0f 100644
--- a/game/core/src/main/java/net/minecraft/core/block/Blocks.java
+++ b/game/core/src/main/java/net/minecraft/core/block/Blocks.java
@@ -355,7 +355,7 @@ public final class Blocks {
     public static final @NotNull Block<?> GLASS_TINTED = register("glass.tinted", "minecraft:block/glass_tinted", 191, BlockLogicGlassTinted::new)
         .withSound(BlockSounds.GLASS).withHardness(0.5F).withDisabledNeighborNotifyOnMetadataChange()
         .withTags(BlockTags.MINEABLE_BY_PICKAXE);
-    public static final @NotNull Block<?> GLASS_STEEL = register("glass.steel", "minecraft:block/glass_steel", 192, (b) -> new BlockLogicTransparent(b, Materials.GLASS))
+    public static final @NotNull Block<?> GLASS_STEEL = register("glass.steel", "minecraft:block/glass_steel", 192, (b) -> new BlockLogicGlassSteel(b, Materials.GLASS))
         .withSound(BlockSounds.GLASS).withHardness(0.3F).withBlastResistance(2000F)
         .withTags(BlockTags.MINEABLE_BY_PICKAXE, BlockTags.EXTENDS_MOTION_SENSOR_RANGE);
 
@@ -1060,7 +1060,7 @@ public final class Blocks {
     public static final @NotNull Block<?> ICE = register("ice", "minecraft:block/ice", 730, BlockLogicIce::new)
         .withSound(BlockSounds.GLASS).withHardness(0.5F).withLightBlock(3)
         .withTags(BlockTags.SKATEABLE, BlockTags.MINEABLE_BY_PICKAXE);
-    public static final @NotNull Block<?> PERMAICE = register("ice.perma", "minecraft:block/permaice", 731, (b) -> new BlockLogicSlippery(b, Materials.ICE))
+    public static final @NotNull Block<?> PERMAICE = register("ice.perma", "minecraft:block/permaice", 731, (b) -> new BlockLogicPermaIce(b, Materials.ICE))
         .withSound(BlockSounds.GLASS).withHardness(1.5F).withBlastResistance(10F)
         .withTags(BlockTags.SKATEABLE, BlockTags.MINEABLE_BY_PICKAXE);
 
diff --git a/game/core/src/main/java/net/minecraft/core/block/entity/TileEntityTimer.java b/game/core/src/main/java/net/minecraft/core/block/entity/TileEntityTimer.java
index 6c5434e25..323ca7dd3 100644
--- a/game/core/src/main/java/net/minecraft/core/block/entity/TileEntityTimer.java
+++ b/game/core/src/main/java/net/minecraft/core/block/entity/TileEntityTimer.java
@@ -7,6 +7,8 @@ import net.minecraft.core.block.Blocks;
 import net.minecraft.core.util.helper.Axis;
 import net.minecraft.core.util.helper.Side;
 import net.minecraft.core.world.pos.TilePos;
+import net.minecraft.core.world.pos.TilePosc;
+
 import org.jetbrains.annotations.NotNull;
 
 public class TileEntityTimer extends TileEntity {
@@ -49,8 +51,11 @@ public class TileEntityTimer extends TileEntity {
 
             final Side side = BlockLogicTimer.getSideFromMeta(currentMeta);
 
-            this.worldObj.notifyBlocksInCapsuleOfNeighborChange(side, this.tilePos, Blocks.TIMER);
-            this.worldObj.notifyBlocksInCapsuleOfNeighborChange(side.opposite(), this.tilePos, Blocks.TIMER);
+            this.worldObj.notifyBlocksOfNeighborChanges(new TilePosc[] {
+                this.tilePos,
+                this.tilePos.add(side, new TilePos()),
+                this.tilePos.sub(side, new TilePos()),
+            }, Blocks.TIMER);
         }
     }
 }
diff --git a/game/core/src/main/java/net/minecraft/core/block/piston/BlockLogicPistonBase.java b/game/core/src/main/java/net/minecraft/core/block/piston/BlockLogicPistonBase.java
index 596da0a28..0bf60b445 100644
--- a/game/core/src/main/java/net/minecraft/core/block/piston/BlockLogicPistonBase.java
+++ b/game/core/src/main/java/net/minecraft/core/block/piston/BlockLogicPistonBase.java
@@ -12,6 +12,7 @@ import net.minecraft.core.block.support.FullSupport;
 import net.minecraft.core.block.support.ISupport;
 import net.minecraft.core.block.support.PartialSupport;
 import net.minecraft.core.block.tag.BlockTags;
+import net.minecraft.core.entity.Entity;
 import net.minecraft.core.entity.EntityFallingBlock;
 import net.minecraft.core.entity.player.Player;
 import net.minecraft.core.enums.EnumDropCause;
@@ -289,12 +290,14 @@ public class BlockLogicPistonBase extends BlockLogic {
         final int len = LINE_LENGTH.get(lineInfo);
         final boolean shouldCrush = CRUSH_EOL.bool(lineInfo);
         final boolean shouldFling = !shouldCrush && canFling && len == 1;
+
+        @Nullable MovingLine line = null;
         if (shouldFling) {
             flingBlock(world, headPos, dir);
         } else {
             final var tailAction = (shouldCrush) ? this.crushAction : EnumDropCause.WORLD;
             breakTail(tailAction, world, headPos, dir, len);
-            push(world, headPos, dir, len);
+            line = push(world, headPos, dir, len);
         }
 
         final var headData = DIRECTION.set(0, dir.id) | TYPE.getNoShift(data);
@@ -307,11 +310,23 @@ public class BlockLogicPistonBase extends BlockLogic {
         // extension updates base immediately, and head 3 ticks after 
         world.notifyBlocksOfNeighborChange(tilePos, this.block);
 
+        if (line != null) {
+            final var tar = new TilePos();
+            final var src = new TilePos();
+
+            for (int i = len;  i > 0; ) {
+                i--;
+                line.getTargetPos(i, tar);
+                line.getSourcePos(i, src);
+                line.blocks[i].onMoved(world, src, tar, line.movingBlocks[i], i, line);
+            }
+        }
+
         return true;
     }
 
-    private static void push(@NotNull World world, @NotNull TilePosc headPos, @NotNull Direction dir, int len) {
-        if (len <= 0) return;
+    private static @Nullable MovingLine push(@NotNull World world, @NotNull TilePosc headPos, @NotNull Direction dir, int len) {
+        if (len <= 0) return null;
         final TilePos pos1 = new TilePos(), pos2 = new TilePos();
 
         final var line = new MovingLine(len, world, dir, headPos, true);
@@ -347,16 +362,7 @@ public class BlockLogicPistonBase extends BlockLogic {
             }
         }
 
-        /* update data */ {
-            final var tar = dir.offsetScaled(pos1.set(headPos), len);
-            final var src = dir.offsetScaled(pos2.set(headPos), len - 1);
-
-            for (int i = len;  i > 0;  src.sub(dir), tar.sub(dir)) {
-                i--;
-                assert tar != headPos;
-                line.blocks[i].onMoved(world, src, tar, line.movingBlocks[i], i, line);
-            }
-        }
+        return line;
     }
 
 
@@ -538,7 +544,7 @@ public class BlockLogicPistonBase extends BlockLogic {
     }
 
     @Override
-    public boolean renderAsNormalBlockOnCondition(@NotNull WorldSource source, @NotNull TilePosc tilePos) {
+    public boolean pushesEntities(@NotNull WorldSource source, @NotNull TilePosc tilePos, @NotNull Class<? extends Entity> entityClass) {
         int data = getValidatedBaseData(source, tilePos, this);
         return !IS_DETACHED_OR_EXTENDED.bool(data);
     }
diff --git a/game/core/src/main/java/net/minecraft/core/block/piston/BlockLogicPistonMoving.java b/game/core/src/main/java/net/minecraft/core/block/piston/BlockLogicPistonMoving.java
index d5d6fbc35..4a3d1de91 100644
--- a/game/core/src/main/java/net/minecraft/core/block/piston/BlockLogicPistonMoving.java
+++ b/game/core/src/main/java/net/minecraft/core/block/piston/BlockLogicPistonMoving.java
@@ -6,6 +6,7 @@ import net.minecraft.core.block.Block;
 import net.minecraft.core.block.BlockLogic;
 import net.minecraft.core.block.material.Material;
 import net.minecraft.core.block.material.Materials;
+import net.minecraft.core.entity.Entity;
 import net.minecraft.core.entity.player.Player;
 import net.minecraft.core.enums.EnumDropCause;
 import net.minecraft.core.item.ItemStack;
@@ -60,11 +61,11 @@ public class BlockLogicPistonMoving extends BlockLogic {
     }
 
     @Override
-    public boolean renderAsNormalBlockOnCondition(@NotNull WorldSource source, @NotNull TilePosc tilePos) {
+    public boolean pushesEntities(@NotNull WorldSource source, @NotNull TilePosc tilePos, @NotNull Class<? extends Entity> entityClass) {
         if (!(source.getTileEntity(tilePos) instanceof TileEntityMovingPistonBlock moving)) return false;
         if (!moving.isInFinalTick()) return false;
         // TODO: purely data-based api
-        return moving.movingBlock.renderAsNormalBlockOnCondition(source, tilePos);
+        return moving.movingBlock.pushesEntities(source, tilePos, entityClass);
     }
 
     @Override
diff --git a/game/core/src/main/java/net/minecraft/core/entity/Entity.java b/game/core/src/main/java/net/minecraft/core/entity/Entity.java
index 8e7cf0baa..5a6dfade0 100644
--- a/game/core/src/main/java/net/minecraft/core/entity/Entity.java
+++ b/game/core/src/main/java/net/minecraft/core/entity/Entity.java
@@ -1214,7 +1214,7 @@ public abstract class Entity
             int x = MathHelper.floor(this.x + (double) f);
             int y = MathHelper.floor(this.y + (double) getHeadHeight() + (double) f1);
             int z = MathHelper.floor(this.z + (double) f2);
-            if (this.world.isBlockNormalCube(x, y, z)) {
+            if (this.world.shouldBlockSuffocateEntities(new TilePos(x, y, z), this.getClass())) {
                 return true;
             }
         }
@@ -1414,49 +1414,42 @@ public abstract class Entity
 
     protected boolean checkAndPushInTile(double x, double y, double z) {
         workingPos1.set(x, y, z);
-        double depthX = x - (double) workingPos1.x();
-        double depthY = y - (double) workingPos1.y();
-        double depthZ = z - (double) workingPos1.z();
-
-        if (this.world.isBlockNormalCube(workingPos1)) {
-            Direction direction = Direction.NONE;
-            double minDepth = Double.MAX_VALUE;
-            if (depthX < minDepth && !this.world.isBlockNormalCube(workingPos1.west(workingPos2))) {
-                minDepth = depthX;
-                direction = Direction.WEST;
-            }
-            if (1.0D - depthX < minDepth && !this.world.isBlockNormalCube(workingPos1.east(workingPos2))) {
-                minDepth = 1.0D - depthX;
-                direction = Direction.EAST;
-            }
-            if (depthY < minDepth && !this.world.isBlockNormalCube(workingPos1.down(workingPos2))) {
-                minDepth = depthY;
-                direction = Direction.DOWN;
-            }
-            if (1.0D - depthY < minDepth && !this.world.isBlockNormalCube(workingPos1.up(workingPos2))) {
-                minDepth = 1.0D - depthY;
-                direction = Direction.UP;
-            }
-            if (depthZ < minDepth && !this.world.isBlockNormalCube(workingPos1.north(workingPos2))) {
-                minDepth = depthZ;
-                direction = Direction.NORTH;
-            }
-            if (1.0D - depthZ < minDepth && !this.world.isBlockNormalCube(workingPos1.south(workingPos2))) {
-//                minDepth = 1.0D - depthZ;
-                direction = Direction.SOUTH;
-            }
-            float pushOut = this.random.nextFloat() * 0.2F + 0.1F;
-            switch (direction) {
-                case WEST -> this.xd = -pushOut;
-                case EAST -> this.xd = pushOut;
-                case DOWN -> this.yd = -pushOut;
-                case UP -> this.yd = pushOut;
-                case NORTH -> this.zd = -pushOut;
-                case SOUTH -> this.zd = pushOut;
-            }
-            return true;
+        
+        final double depthX, depthY, depthZ;
+        depthX = x - (double) workingPos1.x();
+        depthY = y - (double) workingPos1.y();
+        depthZ = z - (double) workingPos1.z();
+
+        final var entityClass = this.getClass();
+        if (!this.world.shouldBlockPushEntities(workingPos1, entityClass)) return false;
+
+        final float pushOut = this.random.nextFloat() * 0.2F + 0.1F;
+        double minDepth = Double.MAX_VALUE;
+        if (depthX < minDepth && !this.world.shouldBlockPushEntities(workingPos1.west(workingPos2), entityClass)) {
+            minDepth = depthX;
+            this.xd = -pushOut;
         }
-        return false;
+        if (1.0D - depthX < minDepth && !this.world.shouldBlockPushEntities(workingPos1.east(workingPos2), entityClass)) {
+            minDepth = 1.0D - depthX;
+            this.xd = +pushOut;
+        }
+        if (depthY < minDepth && !this.world.shouldBlockPushEntities(workingPos1.down(workingPos2), entityClass)) {
+            minDepth = depthY;
+            this.yd = -pushOut;
+        }
+        if (1.0D - depthY < minDepth && !this.world.shouldBlockPushEntities(workingPos1.up(workingPos2), entityClass)) {
+            minDepth = 1.0D - depthY;
+            this.yd = +pushOut;
+        }
+        if (depthZ < minDepth && !this.world.shouldBlockPushEntities(workingPos1.north(workingPos2), entityClass)) {
+            minDepth = depthZ;
+            this.zd = -pushOut;
+        }
+        if (1.0D - depthZ < minDepth && !this.world.shouldBlockPushEntities(workingPos1.south(workingPos2), entityClass)) {
+            // minDepth = 1.0D - depthZ;
+            this.zd = +pushOut;
+        }
+        return true;
     }
 
     public boolean canRide() {
diff --git a/game/core/src/main/java/net/minecraft/core/entity/player/Player.java b/game/core/src/main/java/net/minecraft/core/entity/player/Player.java
index 0c833f89f..597d3a3df 100644
--- a/game/core/src/main/java/net/minecraft/core/entity/player/Player.java
+++ b/game/core/src/main/java/net/minecraft/core/entity/player/Player.java
@@ -218,8 +218,8 @@ public abstract class Player
     }
 
     // Determines if a block pushes the player out of it
-    protected boolean doesBlockPushOut(int x, int y, int z) {
-        return this.world.isBlockNormalCube(x, y, z);
+    protected boolean doesBlockPushOut(@NotNull TilePosc tilePos) {
+        return this.world.shouldBlockPushEntities(tilePos, this.getClass());
     }
 
     protected boolean boundsClear(final @NotNull AABBdc bounds) {
diff --git a/game/core/src/main/java/net/minecraft/core/entity/vehicle/EntityMinecart.java b/game/core/src/main/java/net/minecraft/core/entity/vehicle/EntityMinecart.java
index 620ebf182..6c3454609 100644
--- a/game/core/src/main/java/net/minecraft/core/entity/vehicle/EntityMinecart.java
+++ b/game/core/src/main/java/net/minecraft/core/entity/vehicle/EntityMinecart.java
@@ -494,15 +494,15 @@ public class EntityMinecart extends Entity implements Container {
                     this.xd += (this.xd / vel) * scalar;
                     this.zd += (this.zd / vel) * scalar;
                 } else if (railDirection == RailDirection.STRAIGHT_EW) {
-                    if (this.world.isBlockNormalCube(tilePos.west(queryPos))) {
+                    if (this.world.canBlockBoostMinecarts(tilePos.west(queryPos))) {
                         this.xd = 0.02D;
-                    } else if (this.world.isBlockNormalCube(tilePos.east(queryPos))) {
+                    } else if (this.world.canBlockBoostMinecarts(tilePos.east(queryPos))) {
                         this.xd = -0.02D;
                     }
                 } else if (railDirection == RailDirection.STRAIGHT_NS) {
-                    if (this.world.isBlockNormalCube(tilePos.north(queryPos))) {
+                    if (this.world.canBlockBoostMinecarts(tilePos.north(queryPos))) {
                         this.zd = 0.02D;
-                    } else if (this.world.isBlockNormalCube(tilePos.south(queryPos))) {
+                    } else if (this.world.canBlockBoostMinecarts(tilePos.south(queryPos))) {
                         this.zd = -0.02D;
                     }
                 }
diff --git a/game/core/src/main/java/net/minecraft/core/item/ItemPlaceable.java b/game/core/src/main/java/net/minecraft/core/item/ItemPlaceable.java
index 652c21498..0d190171a 100644
--- a/game/core/src/main/java/net/minecraft/core/item/ItemPlaceable.java
+++ b/game/core/src/main/java/net/minecraft/core/item/ItemPlaceable.java
@@ -6,6 +6,7 @@ import net.minecraft.core.block.entity.TileEntityActivator;
 import net.minecraft.core.block.tag.BlockTags;
 import net.minecraft.core.entity.player.Player;
 import net.minecraft.core.enums.EnumBlockSoundEffectType;
+import net.minecraft.core.item.block.ItemBlock;
 import net.minecraft.core.util.helper.Direction;
 import net.minecraft.core.util.helper.Side;
 import net.minecraft.core.world.World;
@@ -31,7 +32,7 @@ public class ItemPlaceable extends Item {
         if (selfStack.stackSize <= 0) {
             return false;
         }
-        if (!world.canPlaceInsideBlock(blockPos)) {
+        if (ItemBlock.shouldShift(world, blockPos, this.blockToPlace)) {
             blockPos = blockPos.add(side.direction(), new TilePos());
         }
         if (blockPos.y() < 0 || blockPos.y() >= world.getHeightBlocks()) {
diff --git a/game/core/src/main/java/net/minecraft/core/item/ItemStatue.java b/game/core/src/main/java/net/minecraft/core/item/ItemStatue.java
index 09e183355..6c6cab39d 100644
--- a/game/core/src/main/java/net/minecraft/core/item/ItemStatue.java
+++ b/game/core/src/main/java/net/minecraft/core/item/ItemStatue.java
@@ -36,6 +36,11 @@ public class ItemStatue extends Item {
             return false;
         }
 
+        final var bb = statueBlockBottom.getCollisionAABB(world, blockPos);
+        if (bb != null && !world.checkIfAABBIsClear(bb)) {
+            return false;
+        }
+
         selfStack.consumeItem(player);
         world.setBlockTypeData(blockPos, this.statueBlockBottom, MathHelper.floor((double) (((player.yRot + 180F) * 16F) / 360F) + 0.5D) & 0xf);
         world.setBlockTypeData(blockPos.up(new TilePos()), this.statueBlockTop, MathHelper.floor((double) (((player.yRot + 180F) * 16F) / 360F) + 0.5D) & 0xf);
diff --git a/game/core/src/main/java/net/minecraft/core/item/block/ItemBlock.java b/game/core/src/main/java/net/minecraft/core/item/block/ItemBlock.java
index ce196dd97..deb28011a 100644
--- a/game/core/src/main/java/net/minecraft/core/item/block/ItemBlock.java
+++ b/game/core/src/main/java/net/minecraft/core/item/block/ItemBlock.java
@@ -38,17 +38,29 @@ public class ItemBlock<T extends BlockLogic> extends Item {
         @NotNull ItemStack selfStack, @NotNull World world, @Nullable Player player,
         @NotNull TilePosc blockPos, @NotNull Side side, double xHit, double yHit
     ) {
-        final boolean placeNextToExisting = !world.canPlaceInsideBlock(blockPos) ||
-            (this.block.hasTag(BlockTags.PLACE_OVERWRITES) && this.block == world.getBlockType(blockPos));
-
-        if (placeNextToExisting) blockPos = blockPos.add(side.direction(), new TilePos());
+        if (shouldShift(world, blockPos, this.block)) blockPos = blockPos.add(side.direction(), new TilePos());
         if (!world.canBlockIdBePlacedAt(this.block.id(), blockPos, false, side)) return false;
 
         final int meta = getPlacedData(selfStack, world, player, blockPos, side, xHit, yHit);
-        return this.placeWithMeta(selfStack, world, player, blockPos, meta, side, xHit, yHit);
+        return this.placeDirectly(selfStack, world, player, blockPos, meta, side, xHit, yHit);
+    }
+
+    public static boolean shouldShift(@NotNull World world, @NotNull TilePosc blockPos, @NotNull Block<?> block) {
+        if (!world.canPlaceInsideBlock(blockPos)) return true;
+        return block.hasTag(BlockTags.PLACE_OVERWRITES) && block == world.getBlockType(blockPos);
+    }
+
+    protected final boolean placeWithMeta(
+        @NotNull ItemStack selfStack, @NotNull World world, @Nullable Player player,
+        @NotNull TilePosc blockPos, int meta, @NotNull Side side, double xHit, double yHit
+    ) {
+        if (shouldShift(world, blockPos, this.block)) blockPos = blockPos.add(side.direction(), new TilePos());
+        if (!world.canBlockIdBePlacedAt(this.block.id(), blockPos, false, side)) return false;
+
+        return this.placeDirectly(selfStack, world, player, blockPos, meta, side, xHit, yHit);
     }
 
-    public final boolean placeWithMeta(
+    protected final boolean placeDirectly(
         @NotNull ItemStack selfStack, @NotNull World world, @Nullable Player player,
         @NotNull TilePosc blockPos, int meta, @NotNull Side side, double xHit, double yHit
     ) {
@@ -93,7 +105,7 @@ public class ItemBlock<T extends BlockLogic> extends Item {
         blockPos = new TilePos(blockPos).add(direction);
         @NotNull Block<?> b = world.getBlockType(blockPos);
         if (b == Blocks.AIR || BlockTags.PLACE_OVERWRITES.appliesTo(b)) {
-            onUseOnBlock(selfStack, world, null, blockPos, direction.side(), 0.5, 0.5);
+            this.onUseOnBlock(selfStack, world, null, blockPos, direction.side(), 0.5, 0.5);
         }
     }
 
diff --git a/game/core/src/main/java/net/minecraft/core/item/block/ItemBlockLadder.java b/game/core/src/main/java/net/minecraft/core/item/block/ItemBlockLadder.java
index 4f2dfce00..f791eb4d1 100644
--- a/game/core/src/main/java/net/minecraft/core/item/block/ItemBlockLadder.java
+++ b/game/core/src/main/java/net/minecraft/core/item/block/ItemBlockLadder.java
@@ -24,7 +24,7 @@ public class ItemBlockLadder<T extends BlockLogicLadder> extends ItemBlock<T> {
 
         final Side pside;
         if (player == null || player.isSneaking() || world.getBlockType(bp) != this.block) {
-            if (!world.canPlaceInsideBlock(bp)) bp.add(side.direction());
+            if (shouldShift(world, bp, this.block)) bp.add(side.direction());
             pside = ladder.getSideForPlacement(world, bp, side);
         } else {
             xHit = 0.5;
@@ -36,6 +36,6 @@ public class ItemBlockLadder<T extends BlockLogicLadder> extends ItemBlock<T> {
         }
         final var meta = ladder.getMetaForSide(pside);
         if (!ladder.canExistAt(world, bp, meta)) return false;
-        return super.placeWithMeta(selfStack, world, player, bp, meta, pside, xHit, yHit);
+        return super.placeDirectly(selfStack, world, player, bp, meta, pside, xHit, yHit);
     }
 }
diff --git a/game/core/src/main/java/net/minecraft/core/player/inventory/menu/MenuActivator.java b/game/core/src/main/java/net/minecraft/core/player/inventory/menu/MenuActivator.java
index ac4831969..f389bcbb9 100644
--- a/game/core/src/main/java/net/minecraft/core/player/inventory/menu/MenuActivator.java
+++ b/game/core/src/main/java/net/minecraft/core/player/inventory/menu/MenuActivator.java
@@ -109,7 +109,7 @@ public class MenuActivator extends MenuAbstract {
 
 	@Override
 	public IntList getTargetSlots(@NotNull InventoryAction action, @NotNull Slot slot, int target, Player player) {
-		if(slot.index >= ACTIVATOR_INVENTORY_SIZE && slot.index < INVENTORY_SLOTS_START) {
+		if(slot.index >= ACTIVATOR_SLOTS_START && slot.index < INVENTORY_SLOTS_START) {
 			return getSlots(INVENTORY_SLOTS_START, ContainerInventory.MAIN_INVENTORY_SIZE, false);
 		}else {
 			return getSlots(ACTIVATOR_SLOTS_START, ACTIVATOR_INVENTORY_SIZE, false);
diff --git a/game/core/src/main/java/net/minecraft/core/world/SpawnerMobs.java b/game/core/src/main/java/net/minecraft/core/world/SpawnerMobs.java
index f6634fd5a..1cdfbff11 100644
--- a/game/core/src/main/java/net/minecraft/core/world/SpawnerMobs.java
+++ b/game/core/src/main/java/net/minecraft/core/world/SpawnerMobs.java
@@ -5,6 +5,7 @@ import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet;
 import net.minecraft.core.block.BlockLogicBed;
 import net.minecraft.core.block.material.Materials;
 import net.minecraft.core.data.gamerule.GameRules;
+import net.minecraft.core.entity.Entity;
 import net.minecraft.core.entity.EntityDispatcher;
 import net.minecraft.core.entity.Mob;
 import net.minecraft.core.entity.SpawnListEntry;
@@ -128,7 +129,7 @@ public final class SpawnerMobs {
                 if (entry == null || !spawnerConfig.canMobSpawn(entry.namespaceID)) continue;
 
                 final @NotNull TilePosc mobSpawnPos = getRandomSpawningPointInChunk(world, chunk);
-                if (world.isBlockNormalCube(mobSpawnPos) || world.getBlockMaterial(mobSpawnPos) != creatureType.getSpawnMaterial())
+                if (world.shouldBlockSuffocateEntities(mobSpawnPos, spawnListEntry.entityClass) || world.getBlockMaterial(mobSpawnPos) != creatureType.getSpawnMaterial())
                     continue;
 
                 int countSpawned = 0;
@@ -198,9 +199,9 @@ public final class SpawnerMobs {
 
     private static boolean canCreatureTypeSpawnAtLocation(final @NotNull MobCategory mobCategory, final @NotNull World world, final @NotNull TilePosc tilePos) {
         if (mobCategory.getSpawnMaterial() == Materials.WATER) {
-            return world.getBlockMaterial(tilePos).isLiquid() && !world.isBlockNormalCube(tilePos.up(new TilePos())) && world.getBlockData(tilePos) == 0;
+            return world.getBlockMaterial(tilePos).isLiquid() && !world.shouldBlockSuffocateEntities(tilePos.up(new TilePos()), Entity.class) && world.getBlockData(tilePos) == 0;
         } else {
-            return world.isBlockNormalCube(tilePos.down(new TilePos())) && !world.isBlockNormalCube(tilePos) && !world.getBlockMaterial(tilePos).isLiquid();
+            return world.shouldBlockSuffocateEntities(tilePos.down(new TilePos()), Entity.class) && !world.shouldBlockSuffocateEntities(tilePos, Entity.class) && !world.getBlockMaterial(tilePos).isLiquid();
         }
     }
 
@@ -233,7 +234,7 @@ public final class SpawnerMobs {
 
                 // Ensure we have enough space
                 final @NotNull TilePos spawnPos = new TilePos(initSpawnPos.x(), initSpawnPos.y() - 1, initSpawnPos.z());
-                while (spawnPos.y > 2 && !world.isBlockNormalCube(spawnPos)) {
+                while (spawnPos.y > 2 && !world.shouldBlockSuffocateEntities(spawnPos, Entity.class)) {
                     spawnPos.y--;
                 }
 
@@ -319,7 +320,7 @@ public final class SpawnerMobs {
 
                     // Ensure we have enough space
                     final @NotNull TilePos spawnPos = new TilePos(initSpawnPos.x(), initSpawnPos.y() - 1, initSpawnPos.z());
-                    while (spawnPos.y > 2 && !world.isBlockNormalCube(spawnPos)) {
+                    while (spawnPos.y > 2 && !world.shouldBlockSuffocateEntities(spawnPos, Entity.class)) {
                         spawnPos.y--;
                     }
 
diff --git a/game/core/src/main/java/net/minecraft/core/world/WorldSource.java b/game/core/src/main/java/net/minecraft/core/world/WorldSource.java
index 109828112..966a8eb22 100644
--- a/game/core/src/main/java/net/minecraft/core/world/WorldSource.java
+++ b/game/core/src/main/java/net/minecraft/core/world/WorldSource.java
@@ -4,6 +4,7 @@ import net.minecraft.core.block.Block;
 import net.minecraft.core.block.BlockLogic;
 import net.minecraft.core.block.entity.TileEntity;
 import net.minecraft.core.block.material.Material;
+import net.minecraft.core.entity.Entity;
 import net.minecraft.core.enums.LightLayer;
 import net.minecraft.core.world.biome.Biome;
 import net.minecraft.core.world.pos.TilePos;
@@ -48,8 +49,21 @@ public interface WorldSource {
 
     boolean isBlockOpaqueCube(final @NotNull TilePosc tilePos);
 
+    //TODO: Stop using this to determine block's signal conductivity
     boolean isBlockNormalCube(final @NotNull TilePosc tilePos);
 
+    default boolean shouldBlockSuffocateEntities(final @NotNull TilePosc tilePos, @NotNull Class<? extends Entity> entity) {
+        return this.getBlockType(tilePos).suffocatesEntities(this, tilePos, entity);
+    }
+
+    default boolean shouldBlockPushEntities(final @NotNull TilePosc tilePos, @NotNull Class<? extends Entity> entity) {
+        return this.getBlockType(tilePos).pushesEntities(this, tilePos, entity);
+    }
+
+    default boolean canBlockBoostMinecarts(final @NotNull TilePosc tilePos) {
+        return this.getBlockType(tilePos).canBoostMinecarts(this, tilePos);
+    }
+
     double getBlockTemperature(final @NotNull TilePosc tilePos);
 
     double getBlockHumidity(final @NotNull TilePosc tilePos);
