diff --git a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelDispatcher.java b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelDispatcher.java
index e184b6351..b65bbd6c7 100644
--- a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelDispatcher.java
+++ b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelDispatcher.java
@@ -424,23 +424,17 @@ public final class BlockModelDispatcher
             loadDataModel("minecraft:block/piston/head"),
             loadDataModel("minecraft:block/piston_sticky/head"),
             loadDataModel("minecraft:block/piston_steel/head"),
-            // loadDataModel("minecraft:block/piston/head_half"),
-            // loadDataModel("minecraft:block/piston_sticky/head_half"),
-            // loadDataModel("minecraft:block/piston_steel/head_half"),
-            loadDataModel("minecraft:block/piston/head_short"),
-            loadDataModel("minecraft:block/piston_sticky/head_short"),
-            loadDataModel("minecraft:block/piston_steel/head_short")
+            loadDataModel("minecraft:block/piston/head_half"),
+            loadDataModel("minecraft:block/piston_sticky/head_half"),
+            loadDataModel("minecraft:block/piston_steel/head_half")
         ));
         addDispatch(new BlockModelGenericPistonHead<>(Blocks.PISTON_HEAD_STEEL,
             loadDataModel("minecraft:block/piston/head"),
             loadDataModel("minecraft:block/piston_sticky/head"),
             loadDataModel("minecraft:block/piston_steel/head"),
-            // loadDataModel("minecraft:block/piston/head_half"),
-            // loadDataModel("minecraft:block/piston_sticky/head_half"),
-            // loadDataModel("minecraft:block/piston_steel/head_half"),
-            loadDataModel("minecraft:block/piston/head_short"),
-            loadDataModel("minecraft:block/piston_sticky/head_short"),
-            loadDataModel("minecraft:block/piston_steel/head_short")
+            loadDataModel("minecraft:block/piston/head_half"),
+            loadDataModel("minecraft:block/piston_sticky/head_half"),
+            loadDataModel("minecraft:block/piston_steel/head_half")
         ));
 
         addDispatch(new BlockModelGeneric<>(Blocks.NOTEBLOCK, loadDataModel("minecraft:block/noteblock")));
diff --git a/game/client/src/main/java/net/minecraft/client/render/block/model/generic/BlockModelGenericPiston.java b/game/client/src/main/java/net/minecraft/client/render/block/model/generic/BlockModelGenericPiston.java
index cd622adc5..b1bc6e2c9 100644
--- a/game/client/src/main/java/net/minecraft/client/render/block/model/generic/BlockModelGenericPiston.java
+++ b/game/client/src/main/java/net/minecraft/client/render/block/model/generic/BlockModelGenericPiston.java
@@ -46,7 +46,7 @@ public class BlockModelGenericPiston<T extends BlockLogic> extends BlockModelGen
 
     @Override
     public @NotNull StaticBlockModel getModelFromData(int data) {
-        return (/*noCulling || */PistonCommon.IS_DETACHED_OR_EXTENDED.bool(data)) 
+        return (/*noCulling || */PistonCommon.IS_EXTENDED.bool(data)) 
             ? this.extended 
             : super.getModelFromData(data);
     }
diff --git a/game/client/src/main/java/net/minecraft/client/render/block/model/generic/BlockModelGenericPistonHead.java b/game/client/src/main/java/net/minecraft/client/render/block/model/generic/BlockModelGenericPistonHead.java
index 4373c7aa8..eea0337af 100644
--- a/game/client/src/main/java/net/minecraft/client/render/block/model/generic/BlockModelGenericPistonHead.java
+++ b/game/client/src/main/java/net/minecraft/client/render/block/model/generic/BlockModelGenericPistonHead.java
@@ -14,26 +14,21 @@ import org.useless.dragonfly.models.block.StaticBlockModel;
 public class BlockModelGenericPistonHead<T extends BlockLogic> extends BlockModelGenericVeryRotatable<T> {
 
     public final @NotNull StaticBlockModel[] normal;
-    public final @NotNull StaticBlockModel[] schort;
-    // // it seems like the short versions are good enough for hiding the shaft while extending
-    // // should we delete the block model assets as well?
-    // public final @NotNull StaticBlockModel[] half;
+    public final @NotNull StaticBlockModel[] half;
 
     public BlockModelGenericPistonHead(
         @NotNull Block<T> block, 
         @NotNull BlockModelData piston, @NotNull BlockModelData sticky, @NotNull BlockModelData steel, 
-        // @NotNull BlockModelData pistonHalf, @NotNull BlockModelData stickyHalf, @NotNull BlockModelData steelHalf,
-        @NotNull BlockModelData pistonShort, @NotNull BlockModelData stickyShort, @NotNull BlockModelData steelShort
+        @NotNull BlockModelData pistonHalf, @NotNull BlockModelData stickyHalf, @NotNull BlockModelData steelHalf
     ) {
         super(block, piston);
         this.normal = new StaticBlockModel[] { piston.asModel(), sticky.asModel(), steel.asModel() };
-        // this.half = new StaticBlockModel[] { pistonHalf.asModel(), stickyHalf.asModel(), steelHalf.asModel() };
-        this.schort = new StaticBlockModel[] { pistonShort.asModel(), stickyShort.asModel(), steelShort.asModel() };
+        this.half = new StaticBlockModel[] { pistonHalf.asModel(), stickyHalf.asModel(), steelHalf.asModel() };
     }
 
     public void renderPistonHeadNoCulling(@NotNull TessellatorGeneral tessellator, @NotNull WorldSource worldSource, int meta, @NotNull TilePos tilePos, boolean flag) {
         final var type = PistonCommon.TYPE.get(meta);
-        final var model = (flag) ? normal[type] : schort[type];
+        final var model = (flag) ? normal[type] : half[type];
 
         final var dir = Direction.fromId(PistonCommon.DIRECTION.get(meta));
         final int rx, ry, rz;
@@ -54,8 +49,6 @@ public class BlockModelGenericPistonHead<T extends BlockLogic> extends BlockMode
     public @NotNull StaticBlockModel getModelFromData(int data) {
         int type = PistonCommon.TYPE.get(data);
         if (type >= 3) type = 0;
-        return PistonCommon.IS_DETACHED.bool(data)
-            ? schort[type]
-            : normal[type];
+        return normal[type];
     }
 }
diff --git a/game/client/src/main/java/net/minecraft/client/render/entity/MobRendererSheep.java b/game/client/src/main/java/net/minecraft/client/render/entity/MobRendererSheep.java
index b44444a7a..12666c4b0 100644
--- a/game/client/src/main/java/net/minecraft/client/render/entity/MobRendererSheep.java
+++ b/game/client/src/main/java/net/minecraft/client/render/entity/MobRendererSheep.java
@@ -1,6 +1,7 @@
 package net.minecraft.client.render.entity;
 
 import net.minecraft.client.render.renderer.GLRenderer;
+import net.minecraft.client.util.helper.Colors;
 import net.minecraft.core.entity.animal.MobSheep;
 import net.minecraft.core.util.helper.MathHelper;
 import org.jetbrains.annotations.NotNull;
@@ -20,14 +21,16 @@ public class MobRendererSheep extends MobRenderer<MobSheep> {
         switch (layer) {
             case 1: {
                 final int colorIndex = entity.getFleeceColor().blockMeta;
-                GLRenderer.setColor3f(brightness * MobSheep.FLEECE_COLOR_TABLE[colorIndex][0], brightness * MobSheep.FLEECE_COLOR_TABLE[colorIndex][1], brightness * MobSheep.FLEECE_COLOR_TABLE[colorIndex][2]);
+                final var color = Colors.allSheepColors[colorIndex];
+                GLRenderer.setColor3f(brightness * color.getRed()/255f, brightness * color.getGreen()/255f, brightness * color.getBlue()/255f);
                 model = getModel("main");
                 bindTexture("/assets/minecraft/textures/entity/sheep/wool_overlay.png");
                 break;
             }
             case 2: {
                 final int colorIndex = entity.getFleeceColor().blockMeta;
-                GLRenderer.setColor3f(brightness * MobSheep.FLEECE_COLOR_TABLE[colorIndex][0], brightness * MobSheep.FLEECE_COLOR_TABLE[colorIndex][1], brightness * MobSheep.FLEECE_COLOR_TABLE[colorIndex][2]);
+                final var color = Colors.allSheepColors[colorIndex];
+                GLRenderer.setColor3f(brightness * color.getRed()/255f, brightness * color.getGreen()/255f, brightness * color.getBlue()/255f);
                 model = getModel("wool");
                 bindTexture("/assets/minecraft/textures/entity/sheep/wool_overlay.png");
                 break;
diff --git a/game/client/src/main/java/net/minecraft/client/render/item/model/ItemModel.java b/game/client/src/main/java/net/minecraft/client/render/item/model/ItemModel.java
index f3b62f45c..3cdcd3e69 100644
--- a/game/client/src/main/java/net/minecraft/client/render/item/model/ItemModel.java
+++ b/game/client/src/main/java/net/minecraft/client/render/item/model/ItemModel.java
@@ -44,6 +44,8 @@ public abstract class ItemModel {
     }
 
     public void renderItemEntity(@NotNull TessellatorGeneral tessellator, @NotNull ItemStack itemStack, boolean items3d, int clusterSize, int ticks, float yaw, byte lightIndex, float partialTick) {
+        GLRenderer.pushFrame();
+        GLRenderer.setShader(Shaders.ITEM);
         GLRenderer.enableState(State.BLEND);
         if (items3d) {
             GLRenderer.modelM4f().rotateY(Math.toRadians(yaw));
@@ -52,6 +54,7 @@ public abstract class ItemModel {
         }
         render(tessellator, null, itemStack, DisplayPos.GROUND, items3d, clusterSize, lightIndex, partialTick, false);
         GLRenderer.disableState(State.BLEND);
+        GLRenderer.popFrame();
     }
 
     public void renderFirstPerson(@NotNull TessellatorGeneral tessellator, @NotNull ItemRenderer itemRenderer, @NotNull Player player, @NotNull ItemStack itemStack, byte lightIndex, float partialTick) {
diff --git a/game/client/src/main/java/net/minecraft/client/render/item/model/ItemModelStandard.java b/game/client/src/main/java/net/minecraft/client/render/item/model/ItemModelStandard.java
index 919fe5085..7a975a202 100644
--- a/game/client/src/main/java/net/minecraft/client/render/item/model/ItemModelStandard.java
+++ b/game/client/src/main/java/net/minecraft/client/render/item/model/ItemModelStandard.java
@@ -41,7 +41,7 @@ public class ItemModelStandard extends ItemModel{
     public static final DisplayPos DEFAULT_ITEM_FIRST_PERSON_LEFT_HAND = new DisplayPos(1.13f/16f, 3.2f/16f, 1.13f/16f, 0, -90, 25, 0.68f, 0.68f, 0.68f);
     public static final DisplayPos DEFAULT_ITEM_FIXED = new DisplayPos(0, 0, 0, 0, 180, 0, 1, 1, 1);
 
-    protected boolean itemfullBright = false;
+    protected boolean itemfullBright = false; // TODO this is probably redundant with the emissive textures now
 
     public ItemModelStandard(final @NotNull Item item) {
         this(item, true);
diff --git a/game/client/src/main/java/net/minecraft/client/render/shader/framebuffer/FrameBufferTexture.java b/game/client/src/main/java/net/minecraft/client/render/shader/framebuffer/FrameBufferTexture.java
index 8462482f1..76233aab6 100644
--- a/game/client/src/main/java/net/minecraft/client/render/shader/framebuffer/FrameBufferTexture.java
+++ b/game/client/src/main/java/net/minecraft/client/render/shader/framebuffer/FrameBufferTexture.java
@@ -19,7 +19,7 @@ public abstract class FrameBufferTexture implements FrameBufferAttachment {
     public FrameBufferTexture(final int format, final int attachment, final @NotNull Vector2ic size, final int samples, final @Nullable Consumer<@NotNull Parameters> parametersConsumer) {
         this.id = GLAllocation.generateTexture();
         this.attachment = attachment;
-        this.size = new Vector2i(size);
+        this.size = new Vector2i(Math.max(size.x(), 1), Math.max(size.y(), 1));
 
         this.whileBound(() -> {
             this.init(format, size, samples);
diff --git a/game/client/src/main/java/net/minecraft/client/render/shader/framebuffer/RenderBuffer.java b/game/client/src/main/java/net/minecraft/client/render/shader/framebuffer/RenderBuffer.java
index 8897a32d7..d7625122b 100644
--- a/game/client/src/main/java/net/minecraft/client/render/shader/framebuffer/RenderBuffer.java
+++ b/game/client/src/main/java/net/minecraft/client/render/shader/framebuffer/RenderBuffer.java
@@ -1,6 +1,7 @@
 package net.minecraft.client.render.shader.framebuffer;
 
 import org.jetbrains.annotations.NotNull;
+import org.joml.Vector2i;
 import org.joml.Vector2ic;
 import org.lwjgl.opengl.GL41;
 
@@ -14,7 +15,7 @@ public abstract class RenderBuffer implements FrameBufferAttachment {
     public RenderBuffer(final int format, final int attachment, final @NotNull Vector2ic size, final int samples) {
         this.id = GL41.glGenRenderbuffers();
         this.attachment = attachment;
-        this.size = size;
+        this.size = new Vector2i(Math.max(size.x(), 1), Math.max(size.y(), 1));
 
         this.whileBound(() -> {
             this.init(format, size, samples);
diff --git a/game/client/src/main/java/net/minecraft/client/util/helper/Colors.java b/game/client/src/main/java/net/minecraft/client/util/helper/Colors.java
index d8eadb4c5..1a74730c8 100644
--- a/game/client/src/main/java/net/minecraft/client/util/helper/Colors.java
+++ b/game/client/src/main/java/net/minecraft/client/util/helper/Colors.java
@@ -15,35 +15,38 @@ public abstract class Colors {
 	private static Minecraft mc = Minecraft.getMinecraft();
 	
 	public static final Color[] allChatColors = new Color[16];
-	public static final Color[] allPlankColors = new Color[16];
-	public static final Color[] allLampColors = new Color[16];
+//	public static final Color[] allPlankColors = new Color[16];
+//	public static final Color[] allLampColors = new Color[16];
 	public static final Color[] allFlagColors = new Color[16];
 	public static final Color[] allSignColors = new Color[16];
 	public static final Color[] allRedstoneColors = new Color[16];
-	public static final Color[] allConduitColors = new Color[16];
+//	public static final Color[] allConduitColors = new Color[16];
 	public static final Color[] allPortalColors = new Color[16];
+	public static final Color[] allSheepColors = new Color[16];
 
 	public static void loadDummyColors() {
 		Color white = new Color().setRGB(255, 255, 255);
 		Arrays.fill(allChatColors, white);
-		Arrays.fill(allPlankColors, white);
-		Arrays.fill(allLampColors, white);
+//		Arrays.fill(allPlankColors, white);
+//		Arrays.fill(allLampColors, white);
 		Arrays.fill(allFlagColors, white);
 		Arrays.fill(allSignColors, white);
 		Arrays.fill(allRedstoneColors, white);
-		Arrays.fill(allConduitColors, white);
+//		Arrays.fill(allConduitColors, white);
 		Arrays.fill(allPortalColors, white);
+		Arrays.fill(allSheepColors, white);
 	}
 
 	public static void loadColors() {
 		fillColorArray("/assets/minecraft/textures/misc/colors_chat.png", allChatColors);
-		fillColorArray("/assets/minecraft/textures/misc/colors_planks.png", allPlankColors);
+//		fillColorArray("/assets/minecraft/textures/misc/colors_planks.png", allPlankColors);
 		fillColorArray("/assets/minecraft/textures/misc/colors_signs.png", allSignColors);
-		fillColorArray("/assets/minecraft/textures/misc/colors_lamps.png", allLampColors);
+//		fillColorArray("/assets/minecraft/textures/misc/colors_lamps.png", allLampColors);
 		fillColorArray("/assets/minecraft/textures/misc/colors_flag.png", allFlagColors);
 		fillColorArray("/assets/minecraft/textures/misc/colors_redstone.png", allRedstoneColors);
-		fillColorArray("/assets/minecraft/textures/misc/colors_conduit.png", allConduitColors);
+//		fillColorArray("/assets/minecraft/textures/misc/colors_conduit.png", allConduitColors);
 		fillColorArray("/assets/minecraft/textures/misc/colors_portal.png", allPortalColors);
+		fillColorArray("/assets/minecraft/textures/misc/colors_sheep.png", allSheepColors);
 	}
 	
 	public static void fillColorArray(String path, Color[] colors) {
diff --git a/game/client/src/main/java/org/useless/dragonfly/models/block/mojang/StaticBlockModelMojang.java b/game/client/src/main/java/org/useless/dragonfly/models/block/mojang/StaticBlockModelMojang.java
index 5daf67d85..30f3cdd43 100644
--- a/game/client/src/main/java/org/useless/dragonfly/models/block/mojang/StaticBlockModelMojang.java
+++ b/game/client/src/main/java/org/useless/dragonfly/models/block/mojang/StaticBlockModelMojang.java
@@ -233,7 +233,10 @@ public class StaticBlockModelMojang implements StaticBlockModel {
                 }
 
                 final boolean useAO = this.compiled.data.ambientOcclusion && GameSettings.AMBIENT_OCCLUSION.value && element.shade;
-                final boolean isFullCube = depth <= FULL_CUBE_THRESHOLD && element.shade;
+                // TODO hardcodeing slightly rotated elements to not be full cubes,
+                //  this fixes some more major shading issues but keeps in some more minor ones
+                //  the depth, topP, botP, lefP, rigP need reworking to account for rotations -Useless
+                final boolean isFullCube = depth <= FULL_CUBE_THRESHOLD && (element.sourceElement.rotation == null || element.sourceElement.rotation.angle % 90 == 0);
 
                 final float r;
                 final float g;
diff --git a/game/client/src/main/resources/assets/minecraft/models/block/piston/head.json b/game/client/src/main/resources/assets/minecraft/models/block/piston/head.json
index f866f84d0..64224752b 100644
--- a/game/client/src/main/resources/assets/minecraft/models/block/piston/head.json
+++ b/game/client/src/main/resources/assets/minecraft/models/block/piston/head.json
@@ -1,17 +1,11 @@
 {
 	"format_version": "1.21.6",
 	"credit": "Made with Blockbench",
+	"parent": "block/piston_templates/head",
 	"textures": {
 		"face": "block/piston/face",
 		"head": "block/piston/head",
-		"shaft": "block/piston/shaft",
-		"overlay": "#face",
-		"particle_up": "#head",
-		"particle_down": "#head",
-		"particle_north": "#face",
-		"particle_south": "#face",
-		"particle_west": "#head",
-		"particle_east": "#head"
+		"shaft": "block/piston/shaft"
 	},
 	"elements": [
 		{
diff --git a/game/client/src/main/resources/assets/minecraft/models/block/piston/head_half.json b/game/client/src/main/resources/assets/minecraft/models/block/piston/head_half.json
index e41f71cc2..fcae2a1bd 100644
--- a/game/client/src/main/resources/assets/minecraft/models/block/piston/head_half.json
+++ b/game/client/src/main/resources/assets/minecraft/models/block/piston/head_half.json
@@ -1,17 +1,11 @@
 {
 	"format_version": "1.21.6",
 	"credit": "Made with Blockbench",
+	"parent": "block/piston_templates/head",
 	"textures": {
 		"face": "block/piston/face",
 		"head": "block/piston/head",
-		"shaft": "block/piston/shaft",
-		"overlay": "#face",
-		"particle_up": "#head",
-		"particle_down": "#head",
-		"particle_north": "#face",
-		"particle_south": "#face",
-		"particle_west": "#head",
-		"particle_east": "#head"
+		"shaft": "block/piston/shaft"
 	},
 	"elements": [
 		{
diff --git a/game/client/src/main/resources/assets/minecraft/models/block/piston/head_short.json b/game/client/src/main/resources/assets/minecraft/models/block/piston/head_short.json
deleted file mode 100644
index 0681ef1dc..000000000
--- a/game/client/src/main/resources/assets/minecraft/models/block/piston/head_short.json
+++ /dev/null
@@ -1,43 +0,0 @@
-{
-	"format_version": "1.21.6",
-	"credit": "Made with Blockbench",
-	"textures": {
-		"face": "block/piston/face",
-		"head": "block/piston/head",
-		"shaft": "block/piston/shaft",
-		"shaft_end": "block/piston/shaft_end",
-		"overlay": "#face",
-		"particle_up": "#head",
-		"particle_down": "#head",
-		"particle_north": "#face",
-		"particle_south": "#face",
-		"particle_west": "#head",
-		"particle_east": "#head"
-	},
-	"elements": [
-		{
-			"from": [0, 0, 0],
-			"to": [16, 16, 4],
-			"faces": {
-				"north": {"uv": [0, 0, 16, 16], "texture": "#face", "cullface": "north"},
-				"east": {"uv": [0, 0, 16, 4], "rotation": 90, "texture": "#head"},
-				"south": {"uv": [0, 0, 16, 16], "texture": "#face"},
-				"west": {"uv": [0, 0, 16, 4], "rotation": 270, "texture": "#head", "cullface": "west"},
-				"up": {"uv": [0, 0, 16, 4], "texture": "#head", "cullface": "up"},
-				"down": {"uv": [0, 0, 16, 4], "rotation": 180, "texture": "#head", "cullface": "down"}
-			}
-		},
-		{
-			"from": [6, 6, 4],
-			"to": [10, 10, 16],
-			"rotation": {"angle": 0, "axis": "y", "origin": [6, 6, 6]},
-			"faces": {
-				"east": {"uv": [6, 0, 10, 12], "rotation": 90, "texture": "#shaft"},
-				"west": {"uv": [10, 4, 6, 16], "rotation": 90, "texture": "#shaft"},
-				"up": {"uv": [6, 0, 10, 12], "texture": "#shaft"},
-				"down": {"uv": [10, 4, 6, 16], "texture": "#shaft"},
-				"south": {"uv": [6, 6, 10, 10], "texture": "#shaft_end"}
-			}
-		}
-	]
-}
\ No newline at end of file
diff --git a/game/client/src/main/resources/assets/minecraft/models/block/piston_steel/head.json b/game/client/src/main/resources/assets/minecraft/models/block/piston_steel/head.json
index 3e703ebfa..9acc359b2 100644
--- a/game/client/src/main/resources/assets/minecraft/models/block/piston_steel/head.json
+++ b/game/client/src/main/resources/assets/minecraft/models/block/piston_steel/head.json
@@ -1,17 +1,11 @@
 {
 	"format_version": "1.21.6",
 	"credit": "Made with Blockbench",
+	"parent": "block/piston_templates/head",
 	"textures": {
 		"face": "block/piston_steel/face",
 		"head": "block/piston_steel/head",
-		"shaft": "block/piston_steel/shaft",
-		"overlay": "#face",
-		"particle_up": "#head",
-		"particle_down": "#head",
-		"particle_north": "#face",
-		"particle_south": "#face",
-		"particle_west": "#head",
-		"particle_east": "#head"
+		"shaft": "block/piston_steel/shaft"
 	},
 	"elements": [
 		{
diff --git a/game/client/src/main/resources/assets/minecraft/models/block/piston_steel/head_half.json b/game/client/src/main/resources/assets/minecraft/models/block/piston_steel/head_half.json
index 702cd8bbc..9000e854c 100644
--- a/game/client/src/main/resources/assets/minecraft/models/block/piston_steel/head_half.json
+++ b/game/client/src/main/resources/assets/minecraft/models/block/piston_steel/head_half.json
@@ -1,17 +1,11 @@
 {
 	"format_version": "1.21.6",
 	"credit": "Made with Blockbench",
+	"parent": "block/piston_templates/head",
 	"textures": {
 		"face": "block/piston_steel/face",
 		"head": "block/piston_steel/head",
-		"shaft": "block/piston_steel/shaft",
-		"overlay": "#face",
-		"particle_up": "#head",
-		"particle_down": "#head",
-		"particle_north": "#face",
-		"particle_south": "#face",
-		"particle_west": "#head",
-		"particle_east": "#head"
+		"shaft": "block/piston_steel/shaft"
 	},
 	"elements": [
 		{
diff --git a/game/client/src/main/resources/assets/minecraft/models/block/piston_steel/head_short.json b/game/client/src/main/resources/assets/minecraft/models/block/piston_steel/head_short.json
deleted file mode 100644
index 4da8264d4..000000000
--- a/game/client/src/main/resources/assets/minecraft/models/block/piston_steel/head_short.json
+++ /dev/null
@@ -1,42 +0,0 @@
-{
-	"format_version": "1.21.6",
-	"credit": "Made with Blockbench",
-	"textures": {
-		"face": "block/piston_steel/face",
-		"head": "block/piston_steel/head",
-		"shaft": "block/piston_steel/shaft",
-		"overlay": "#face",
-		"particle_up": "#head",
-		"particle_down": "#head",
-		"particle_north": "#face",
-		"particle_south": "#face",
-		"particle_west": "#head",
-		"particle_east": "#head"
-	},
-	"elements": [
-		{
-			"from": [0, 0, 0],
-			"to": [16, 16, 6],
-			"faces": {
-				"north": {"uv": [0, 0, 16, 16], "texture": "#face", "cullface": "north"},
-				"east": {"uv": [0, 0, 16, 6], "rotation": 90, "texture": "#head"},
-				"south": {"uv": [0, 0, 16, 16], "texture": "#face"},
-				"west": {"uv": [0, 0, 16, 6], "rotation": 270, "texture": "#head", "cullface": "west"},
-				"up": {"uv": [0, 0, 16, 6], "texture": "#head", "cullface": "up"},
-				"down": {"uv": [0, 0, 16, 6], "rotation": 180, "texture": "#head", "cullface": "down"}
-			}
-		},
-		{
-			"from": [4, 4, 6],
-			"to": [12, 12, 16],
-			"rotation": {"angle": 0, "axis": "y", "origin": [6, 6, 6]},
-			"faces": {
-				"east": {"uv": [4, 0, 12, 12], "rotation": 90, "texture": "#shaft"},
-				"west": {"uv": [12, 4, 4, 16], "rotation": 90, "texture": "#shaft"},
-				"up": {"uv": [4, 0, 12, 12], "texture": "#shaft"},
-				"down": {"uv": [12, 4, 4, 16], "texture": "#shaft"},
-				"south": {"uv": [4, 4, 12, 12], "texture": "#shaft"}
-			}
-		}
-	]
-}
\ No newline at end of file
diff --git a/game/client/src/main/resources/assets/minecraft/models/block/piston_sticky/head.json b/game/client/src/main/resources/assets/minecraft/models/block/piston_sticky/head.json
index 123f7756c..6afe927b9 100644
--- a/game/client/src/main/resources/assets/minecraft/models/block/piston_sticky/head.json
+++ b/game/client/src/main/resources/assets/minecraft/models/block/piston_sticky/head.json
@@ -1,18 +1,12 @@
 {
 	"format_version": "1.21.6",
 	"credit": "Made with Blockbench",
+	"parent": "block/piston_templates/head",
 	"textures": {
 		"face": "block/piston_sticky/face",
 		"back": "block/piston/face",
 		"head": "block/piston_sticky/head",
-		"shaft": "block/piston/shaft",
-		"overlay": "#face",
-		"particle_up": "#head",
-		"particle_down": "#head",
-		"particle_north": "#face",
-		"particle_south": "#back",
-		"particle_west": "#head",
-		"particle_east": "#head"
+		"shaft": "block/piston/shaft"
 	},
 	"elements": [
 		{
diff --git a/game/client/src/main/resources/assets/minecraft/models/block/piston_sticky/head_half.json b/game/client/src/main/resources/assets/minecraft/models/block/piston_sticky/head_half.json
index d37ae4c46..8484f9b5d 100644
--- a/game/client/src/main/resources/assets/minecraft/models/block/piston_sticky/head_half.json
+++ b/game/client/src/main/resources/assets/minecraft/models/block/piston_sticky/head_half.json
@@ -1,18 +1,12 @@
 {
 	"format_version": "1.21.6",
 	"credit": "Made with Blockbench",
+	"parent": "block/piston_templates/head",
 	"textures": {
 		"face": "block/piston_sticky/face",
 		"back": "block/piston/face",
 		"head": "block/piston_sticky/head",
-		"shaft": "block/piston/shaft",
-		"overlay": "#face",
-		"particle_up": "#head",
-		"particle_down": "#head",
-		"particle_north": "#face",
-		"particle_south": "#back",
-		"particle_west": "#head",
-		"particle_east": "#head"
+		"shaft": "block/piston/shaft"
 	},
 	"elements": [
 		{
diff --git a/game/client/src/main/resources/assets/minecraft/models/block/piston_sticky/head_short.json b/game/client/src/main/resources/assets/minecraft/models/block/piston_sticky/head_short.json
deleted file mode 100644
index bcb6ee0a7..000000000
--- a/game/client/src/main/resources/assets/minecraft/models/block/piston_sticky/head_short.json
+++ /dev/null
@@ -1,44 +0,0 @@
-{
-	"format_version": "1.21.6",
-	"credit": "Made with Blockbench",
-	"textures": {
-		"face": "block/piston_sticky/face",
-		"back": "block/piston/face",
-		"head": "block/piston_sticky/head",
-		"shaft": "block/piston/shaft",
-		"shaft_end": "block/piston/shaft_end",
-		"overlay": "#face",
-		"particle_up": "#head",
-		"particle_down": "#head",
-		"particle_north": "#face",
-		"particle_south": "#back",
-		"particle_west": "#head",
-		"particle_east": "#head"
-	},
-	"elements": [
-		{
-			"from": [0, 0, 0],
-			"to": [16, 16, 4],
-			"faces": {
-				"north": {"uv": [0, 0, 16, 16], "texture": "#face", "cullface": "north"},
-				"east": {"uv": [0, 0, 16, 4], "rotation": 90, "texture": "#head"},
-				"south": {"uv": [0, 0, 16, 16], "texture": "#back"},
-				"west": {"uv": [0, 0, 16, 4], "rotation": 270, "texture": "#head", "cullface": "west"},
-				"up": {"uv": [0, 0, 16, 4], "texture": "#head", "cullface": "up"},
-				"down": {"uv": [0, 0, 16, 4], "rotation": 180, "texture": "#head", "cullface": "down"}
-			}
-		},
-		{
-			"from": [6, 6, 4],
-			"to": [10, 10, 16],
-			"rotation": {"angle": 0, "axis": "y", "origin": [6, 6, 6]},
-			"faces": {
-				"east": {"uv": [6, 0, 10, 12], "rotation": 90, "texture": "#shaft"},
-				"west": {"uv": [10, 4, 6, 16], "rotation": 90, "texture": "#shaft"},
-				"up": {"uv": [6, 0, 10, 12], "texture": "#shaft"},
-				"down": {"uv": [10, 4, 6, 16], "texture": "#shaft"},
-				"south": {"uv": [6, 6, 10, 10], "texture": "#shaft_end"}
-			}
-		}
-	]
-}
\ No newline at end of file
diff --git a/game/client/src/main/resources/assets/minecraft/models/block/piston_templates/head.json b/game/client/src/main/resources/assets/minecraft/models/block/piston_templates/head.json
new file mode 100644
index 000000000..e535e4fe3
--- /dev/null
+++ b/game/client/src/main/resources/assets/minecraft/models/block/piston_templates/head.json
@@ -0,0 +1,24 @@
+{
+	"format_version": "1.21.6",
+	"ambientocclusion": false,
+    "parent": "block/block",
+	"display": {
+		"firstperson_righthand": {
+			"rotation": [0, 135, 0],
+			"scale": [0.4, 0.4, 0.4]
+		},
+		"firstperson_lefthand": {
+			"rotation": [0, 135, 0],
+			"scale": [0.4, 0.4, 0.4]
+		}
+	},
+	"textures": {
+		"overlay": "#face",
+		"particle_up": "#head",
+		"particle_down": "#head",
+		"particle_north": "#face",
+		"particle_south": "#face",
+		"particle_west": "#head",
+		"particle_east": "#head"
+	}
+}
\ No newline at end of file
diff --git a/game/client/src/main/resources/assets/minecraft/models/entity/models.json b/game/client/src/main/resources/assets/minecraft/models/entity/models.json
index 84f8e7338..b8466d0b9 100644
--- a/game/client/src/main/resources/assets/minecraft/models/entity/models.json
+++ b/game/client/src/main/resources/assets/minecraft/models/entity/models.json
@@ -39,6 +39,9 @@
         },
         "49f6ea39-30b2-4441-b07c-7bfe0beeb61e": {
             "main": "geometry.player.base.shign"
+        },
+        "badff6b8-7ac7-4385-b11b-1e3d6a3649a0": {
+            "main": "geometry.player.base.silvy"
         }
     },
     "renderers": {
diff --git a/game/client/src/main/resources/assets/minecraft/models/entity/secret.geo.json b/game/client/src/main/resources/assets/minecraft/models/entity/secret.geo.json
index 59f692ed1..a762e4241 100644
--- a/game/client/src/main/resources/assets/minecraft/models/entity/secret.geo.json
+++ b/game/client/src/main/resources/assets/minecraft/models/entity/secret.geo.json
@@ -1341,6 +1341,238 @@
 					"rotation": [90, 0, 0]
 				}
 			]
+		},
+		{
+			"description": {
+				"identifier": "geometry.player.base.silvy",
+				"texture_width": 64,
+				"texture_height": 64,
+				"visible_bounds_width": 4,
+				"visible_bounds_height": 4,
+				"visible_bounds_offset": [0, 2, 0]
+			},
+			"bones": [
+				{
+					"name": "waist",
+					"pivot": [0, 12, 0]
+				},
+				{
+					"name": "body",
+					"parent": "waist",
+					"pivot": [0, 24, 0]
+				},
+				{
+					"name": "torso",
+					"parent": "body",
+					"pivot": [0, 24, 0],
+					"cubes": [
+						{"origin": [-4, 12, -2], "size": [8, 12, 4], "uv": [16, 16]}
+					]
+				},
+				{
+					"name": "rightArm",
+					"parent": "torso",
+					"pivot": [-5, 22, 0],
+					"cubes": [
+						{"origin": [-7, 12, -2], "size": [3, 12, 4], "uv": [40, 16]}
+					]
+				},
+				{
+					"name": "rightSleeve",
+					"parent": "rightArm",
+					"pivot": [-6, 18, 0],
+					"cubes": [
+						{"origin": [-7, 12, -2], "size": [3, 12, 4], "inflate": 0.25, "uv": [40, 32]}
+					]
+				},
+				{
+					"name": "rightItem",
+					"parent": "rightArm",
+					"pivot": [-5.5, 12, -2],
+					"rotation": [90, 0, 0]
+				},
+				{
+					"name": "leftArm",
+					"parent": "torso",
+					"pivot": [5, 22, 0],
+					"cubes": [
+						{"origin": [4, 12, -2], "size": [3, 12, 4], "uv": [32, 48]}
+					]
+				},
+				{
+					"name": "leftSleeve",
+					"parent": "leftArm",
+					"pivot": [5, 18, 0],
+					"cubes": [
+						{"origin": [4, 12, -2], "size": [3, 12, 4], "inflate": 0.25, "uv": [48, 48]}
+					]
+				},
+				{
+					"name": "leftItem",
+					"parent": "leftArm",
+					"pivot": [5.5, 12, -2],
+					"rotation": [-90, 180, 0]
+				},
+				{
+					"name": "cape",
+					"parent": "torso",
+					"pivot": [0, 24, 2.5]
+				},
+				{
+					"name": "bone2",
+					"parent": "torso",
+					"pivot": [0, 24, 0],
+					"cubes": [
+						{
+							"origin": [-6, 13.25, 2],
+							"size": [12, 19, 0],
+							"pivot": [0, 13.25, 2],
+							"rotation": [-91.74942, 34.96182, -93.05099],
+							"uv": {
+								"north": {"uv": [32, 36], "uv_size": [8, 12]},
+								"south": {"uv": [40, 36], "uv_size": [-8, 12]}
+							}
+						},
+						{
+							"origin": [-6, 13.25, 2],
+							"size": [12, 19, 0],
+							"pivot": [0, 13.25, 2],
+							"rotation": [-55.02563, 1.43364, -2.04831],
+							"uv": {
+								"north": {"uv": [32, 36], "uv_size": [8, 12]},
+								"south": {"uv": [40, 36], "uv_size": [-8, 12]}
+							}
+						}
+					]
+				},
+				{
+					"name": "jacket",
+					"parent": "torso",
+					"pivot": [0, 18, 0],
+					"cubes": [
+						{"origin": [-4, 12, -2], "size": [8, 12, 4], "inflate": 0.25, "uv": [16, 32]}
+					]
+				},
+				{
+					"name": "head",
+					"parent": "body",
+					"pivot": [0, 24, 0],
+					"cubes": [
+						{"origin": [-4, 24, -4], "size": [8, 8, 8], "uv": [0, 0]}
+					]
+				},
+				{
+					"name": "bone",
+					"parent": "head",
+					"pivot": [0, 24, 0],
+					"cubes": [
+						{
+							"origin": [-11, 30, -4],
+							"size": [8, 12, 0],
+							"pivot": [-3, 30, -3],
+							"rotation": [0, -45, 0],
+							"uv": {
+								"north": {"uv": [56, 16], "uv_size": [8, 12]},
+								"south": {"uv": [64, 16], "uv_size": [-8, 12]}
+							}
+						},
+						{
+							"origin": [-9.75, 30, -4.25],
+							"size": [8, 12, 0],
+							"pivot": [0.25, 30, -3.25],
+							"rotation": [0, -140, 0],
+							"uv": {
+								"north": {"uv": [56, 16], "uv_size": [8, 12]},
+								"south": {"uv": [64, 16], "uv_size": [-8, 12]}
+							}
+						},
+						{
+							"origin": [-4.25, 15.5, 4],
+							"size": [4, 14, 0],
+							"pivot": [-2.25, 29.5, 4],
+							"rotation": [7.38443, -0.75155, 27.48436],
+							"uv": {
+								"north": {"uv": [60, 28], "uv_size": [4, 14]},
+								"south": {"uv": [60, 28], "uv_size": [-4, 14]}
+							}
+						},
+						{
+							"origin": [0, 15.5, 4],
+							"size": [4, 14, 0],
+							"pivot": [2, 29.5, 4],
+							"rotation": [7.38443, 0.75155, -27.48436],
+							"uv": {
+								"north": {"uv": [60, 28], "uv_size": [4, 14]},
+								"south": {"uv": [60, 28], "uv_size": [-4, 14]}
+							}
+						}
+					]
+				},
+				{
+					"name": "hat",
+					"parent": "head",
+					"pivot": [0, 28, 0],
+					"cubes": [
+						{"origin": [-4, 24, -4], "size": [8, 8, 8], "inflate": 0.25, "uv": [32, 0]}
+					]
+				},
+				{
+					"name": "rightLeg",
+					"parent": "body",
+					"pivot": [-1.9, 12, 0],
+					"cubes": [
+						{"origin": [-4, 0, -2], "size": [4, 12, 4], "uv": [0, 16]}
+					]
+				},
+				{
+					"name": "rightPant",
+					"parent": "rightLeg",
+					"pivot": [-2, 6, 0],
+					"cubes": [
+						{"origin": [-4, 0, -2], "size": [4, 12, 4], "inflate": 0.25, "uv": [0, 32]}
+					]
+				},
+				{
+					"name": "leftLeg",
+					"parent": "body",
+					"pivot": [1.9, 12, 0],
+					"cubes": [
+						{"origin": [0, 0, -2], "size": [4, 12, 4], "uv": [16, 48]}
+					]
+				},
+				{
+					"name": "leftPant",
+					"parent": "leftLeg",
+					"pivot": [2, 6, 0],
+					"cubes": [
+						{"origin": [0, 0, -2], "size": [4, 12, 4], "inflate": 0.25, "uv": [0, 48]}
+					]
+				}
+			],
+			"item_display_transforms": {
+				"thirdperson_righthand": {
+					"rotation": [-68, 0, 92],
+					"translation": [0, -1.5, 0],
+					"scale": [1, 1, 1],
+					"rotation_pivot": [0, 0, 0],
+					"scale_pivot": [0, 0, 0]
+				},
+				"gui": {
+					"rotation": [34, 40, 0],
+					"translation": [-0.75, 2.25, 0],
+					"scale": [0.95, 0.95, 0.95],
+					"rotation_pivot": [0, 0, 0],
+					"scale_pivot": [0, 0, 0],
+					"fit_to_frame": false
+				},
+				"head": {
+					"rotation": [19, 0, 0],
+					"translation": [-2.75, 16.75, 4.25],
+					"scale": [2.6, 2.6, 2.6],
+					"rotation_pivot": [0, 0, 0],
+					"scale_pivot": [0, 0, 0]
+				}
+			}
 		}
 	]
 }
\ No newline at end of file
diff --git a/game/client/src/main/resources/assets/minecraft/textures/block/matcher/front0.emiss.png b/game/client/src/main/resources/assets/minecraft/textures/block/matcher/front0.emiss.png
new file mode 100644
index 000000000..8e5dad90c
Binary files /dev/null and b/game/client/src/main/resources/assets/minecraft/textures/block/matcher/front0.emiss.png differ
diff --git a/game/client/src/main/resources/assets/minecraft/textures/block/matcher/front_overlay0.png.mcmeta b/game/client/src/main/resources/assets/minecraft/textures/block/matcher/front0.emiss.png.mcmeta
similarity index 100%
rename from game/client/src/main/resources/assets/minecraft/textures/block/matcher/front_overlay0.png.mcmeta
rename to game/client/src/main/resources/assets/minecraft/textures/block/matcher/front0.emiss.png.mcmeta
diff --git a/game/client/src/main/resources/assets/minecraft/textures/block/matcher/front1.emiss.png b/game/client/src/main/resources/assets/minecraft/textures/block/matcher/front1.emiss.png
new file mode 100644
index 000000000..a3627c320
Binary files /dev/null and b/game/client/src/main/resources/assets/minecraft/textures/block/matcher/front1.emiss.png differ
diff --git a/game/client/src/main/resources/assets/minecraft/textures/block/matcher/front_overlay1.png.mcmeta b/game/client/src/main/resources/assets/minecraft/textures/block/matcher/front1.emiss.png.mcmeta
similarity index 100%
rename from game/client/src/main/resources/assets/minecraft/textures/block/matcher/front_overlay1.png.mcmeta
rename to game/client/src/main/resources/assets/minecraft/textures/block/matcher/front1.emiss.png.mcmeta
diff --git a/game/client/src/main/resources/assets/minecraft/textures/block/matcher/front2.emiss.png b/game/client/src/main/resources/assets/minecraft/textures/block/matcher/front2.emiss.png
new file mode 100644
index 000000000..077b7fabc
Binary files /dev/null and b/game/client/src/main/resources/assets/minecraft/textures/block/matcher/front2.emiss.png differ
diff --git a/game/client/src/main/resources/assets/minecraft/textures/block/matcher/front_overlay2.png.mcmeta b/game/client/src/main/resources/assets/minecraft/textures/block/matcher/front2.emiss.png.mcmeta
similarity index 100%
rename from game/client/src/main/resources/assets/minecraft/textures/block/matcher/front_overlay2.png.mcmeta
rename to game/client/src/main/resources/assets/minecraft/textures/block/matcher/front2.emiss.png.mcmeta
diff --git a/game/client/src/main/resources/assets/minecraft/textures/block/matcher/front3.emiss.png b/game/client/src/main/resources/assets/minecraft/textures/block/matcher/front3.emiss.png
new file mode 100644
index 000000000..8e980e188
Binary files /dev/null and b/game/client/src/main/resources/assets/minecraft/textures/block/matcher/front3.emiss.png differ
diff --git a/game/client/src/main/resources/assets/minecraft/textures/block/matcher/front_overlay3.png.mcmeta b/game/client/src/main/resources/assets/minecraft/textures/block/matcher/front3.emiss.png.mcmeta
similarity index 100%
rename from game/client/src/main/resources/assets/minecraft/textures/block/matcher/front_overlay3.png.mcmeta
rename to game/client/src/main/resources/assets/minecraft/textures/block/matcher/front3.emiss.png.mcmeta
diff --git a/game/client/src/main/resources/assets/minecraft/textures/block/matcher/front_overlay0.png b/game/client/src/main/resources/assets/minecraft/textures/block/matcher/front_overlay0.png
deleted file mode 100644
index 7b76571a3..000000000
Binary files a/game/client/src/main/resources/assets/minecraft/textures/block/matcher/front_overlay0.png and /dev/null differ
diff --git a/game/client/src/main/resources/assets/minecraft/textures/block/matcher/front_overlay1.png b/game/client/src/main/resources/assets/minecraft/textures/block/matcher/front_overlay1.png
deleted file mode 100644
index 897ab8fcc..000000000
Binary files a/game/client/src/main/resources/assets/minecraft/textures/block/matcher/front_overlay1.png and /dev/null differ
diff --git a/game/client/src/main/resources/assets/minecraft/textures/block/matcher/front_overlay2.png b/game/client/src/main/resources/assets/minecraft/textures/block/matcher/front_overlay2.png
deleted file mode 100644
index 90df1efad..000000000
Binary files a/game/client/src/main/resources/assets/minecraft/textures/block/matcher/front_overlay2.png and /dev/null differ
diff --git a/game/client/src/main/resources/assets/minecraft/textures/block/matcher/front_overlay3.png b/game/client/src/main/resources/assets/minecraft/textures/block/matcher/front_overlay3.png
deleted file mode 100644
index d8b6bacfa..000000000
Binary files a/game/client/src/main/resources/assets/minecraft/textures/block/matcher/front_overlay3.png and /dev/null differ
diff --git a/game/client/src/main/resources/assets/minecraft/textures/misc/colors_sheep.png b/game/client/src/main/resources/assets/minecraft/textures/misc/colors_sheep.png
new file mode 100644
index 000000000..68fd4c791
Binary files /dev/null and b/game/client/src/main/resources/assets/minecraft/textures/misc/colors_sheep.png differ
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 226d3e3a2..c82bba4ed 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
@@ -63,9 +63,9 @@ public class BlockLogicActivator
             final double pz = direction.offsetZ() * 0.6D + 0.5D;
 
             if (itemStack == null) {
-                final @Nullable Block<?> block = world.getBlockType(tilePos.add(direction, new TilePos()));
+                final Block<?> block = world.getBlockType(tilePos.add(direction, new TilePos()));
 
-                if (block != null) {
+                if (block != Blocks.AIR) {
                     block.onActivatorInteracted(world, tilePos.add(direction, new TilePos()), activator, direction);
                 } else {
                     world.playSoundEffect(null, SoundCategory.WORLD_SOUNDS, tilePos.x(), tilePos.y(), tilePos.z(), "tile.activator.click", 1, 1);
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 907e57760..7d1b75589 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
@@ -44,6 +44,7 @@ public final class Blocks {
 
     public static final @NotNull Block<?> AIR = register("air", "minecraft:block/air", 0, (b) -> new BlockLogicAir(b))
         .withTags(BlockTags.PLACE_OVERWRITES, BlockTags.NOT_IN_CREATIVE_MENU);
+
     public static final @NotNull Block<?> STONE = register("stone", "minecraft:block/stone", 1, (b) -> new BlockLogicStone(b, Blocks.COBBLE_STONE, Materials.STONE))
         .withSound(BlockSounds.STONE).withHardness(1.5F).withBlastResistance(10F)
         .withTags(BlockTags.CAVES_CUT_THROUGH, BlockTags.MINEABLE_BY_PICKAXE, BlockTags.CHAINLINK_FENCES_CONNECT);
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 931f38e8d..28a8042b0 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
@@ -85,21 +85,12 @@ public class BlockLogicPistonBase extends BlockLogic {
         
         final boolean powered = hasNeighborSignal(world, tilePos, Direction.fromId(DIRECTION.get(data)));
         final boolean extended = IS_EXTENDED.bool(data);
-        final boolean detached = IS_DETACHED.bool(data);
         final var dir = Direction.fromId(DIRECTION.get(data));
         
         if (powered == extended) return false;
 
-        int event = (!detached) ? EVENT_EXTEND : EVENT_DETACH_EXTEND;
-        event |= (powered) ? 0 : 1;
-
-        final int lineInfo;
-        if (detached) {
-            lineInfo = 0;
-        } else {
-            lineInfo = (powered) ? testPushLine(world, tilePos, dir) : testPullLine(world, tilePos, dir);
-        }
-
+        final int event = EVENT_EXTEND | ((powered) ? 0 : 1);
+        final int lineInfo = (powered) ? testPushLine(world, tilePos, dir) : testPullLine(world, tilePos, dir);
         assert (lineInfo & ~0xFF) == 0;
 
         if (LINE_OBSTRUCTED.bool(lineInfo)) return false;
@@ -122,11 +113,6 @@ public class BlockLogicPistonBase extends BlockLogic {
         switch (index & ~1) {
         default:
             return;
-        case EVENT_DETACH:
-            break;
-        case EVENT_DETACH_EXTEND:
-            world.setBlockDataNotify(tilePos, IS_EXTENDED.set(data, isOut ? 1 : 0));
-            break;
         case EVENT_EXTEND:
             if (isOut) {
                 if (!this.extend(world, tilePos, data, eventData)) return;
@@ -150,18 +136,6 @@ public class BlockLogicPistonBase extends BlockLogic {
         default: 
             assert false;
             return;
-        case EVENT_DETACH:
-            this.emitParticles(world, tilePos, Direction.fromId(DIRECTION.get(data)));
-            sound = (isOut) ? "tile.piston.detached" : "tile.piston.attached";
-            volumn = 0.5F;
-            pitch  = 0.6F;
-            break;
-        case EVENT_DETACH_EXTEND:
-            this.emitParticles(world, tilePos, Direction.fromId(DIRECTION.get(data)));
-            sound = (isOut) ? "tile.piston.detached.out" : "tile.piston.detached.in";
-            volumn = 0.2F;
-            pitch  = 0.5F;
-            break;
         case EVENT_EXTEND:
             sound = (isOut) ? "tile.piston.out" : "tile.piston.in";
             volumn = 0.5F;
@@ -187,37 +161,6 @@ public class BlockLogicPistonBase extends BlockLogic {
         return false;
     }
 
-    private void emitParticles(@NotNull World world, @NotNull TilePosc pos, @NotNull Direction direction) {
-        final var random = world.rand;
-
-        var thickness = HEAD_BLOCK_MAP[this.typeId].getLogic().headThickness;
-
-        final double dx,dy,dz;
-        dx = direction.offsetX();
-        dy = direction.offsetY();
-        dz = direction.offsetZ();
-        
-        final double ox,oy,oz;
-        ox = pos.x() + 0.5 + dx * (0.5-thickness);
-        oy = pos.y() + 0.5 + dy * (0.5-thickness);
-        oz = pos.z() + 0.5 + dz * (0.5-thickness);
-
-        for (int i = 0; i < 8; i++) {
-            final double v = random.nextDouble() * 0x1p-5;
-
-            final double x,y,z;
-            x = ox + random.nextDouble() * 0x1p-2 * dx + random.nextDouble() * 0x1p-4 * (dy + dz);
-            y = oy + random.nextDouble() * 0x1p-2 * dy + random.nextDouble() * 0x1p-4 * (dx + dz);
-            z = oz + random.nextDouble() * 0x1p-2 * dz + random.nextDouble() * 0x1p-4 * (dx + dy);
-
-            final double vx,vy,vz;
-            vx = dx * v + random.nextGaussian() * 0x1p-7;
-            vy = dy * v + random.nextGaussian() * 0x1p-7;
-            vz = dz * v + random.nextGaussian() * 0x1p-7;
-            world.spawnParticle("smoke", x,y,z, vx, vy, vz, 0, 16.0, false);
-        }
-    }
-
     // Piston tests:
     // =================
 
@@ -290,14 +233,7 @@ public class BlockLogicPistonBase extends BlockLogic {
             return switch (block.getPistonPushReaction(world, tilePos)) {
                 case Material.PISTON_DESTROY_ON_PUSH -> BREAKS;
                 case Material.PISTON_CANT_PUSH -> OBSTRUCTED;
-                default -> {
-                    // hardcoded. I don't want premature abstraction until we do sticky blocks for real
-                    if (block != Blocks.PISTON_HEAD) yield PUSHES;
-                    final var data = world.getBlockData(tilePos);
-                    if (TYPE.get(data) != TYPE_STICKY) yield PUSHES;
-                    if (DIRECTION.get(data) != direction.id) yield PUSHES;
-                    yield PULLS;
-                }
+                default -> PUSHES;
             };
         }
     }
@@ -476,7 +412,6 @@ public class BlockLogicPistonBase extends BlockLogic {
         meta |= TYPE.set(meta, this.typeId);
         meta |= NEW_FORMAT_SIGNATURE.mask;
 
-        meta |= IS_DETACHED_OR_EXTENDED.setNoShift(meta, itemStack.getMetadata());
         final var dir = (player != null)
             ? player.getPlacementDirection(side).opposite().id
             : side.id;
@@ -501,7 +436,7 @@ public class BlockLogicPistonBase extends BlockLogic {
     @Override
     public @NotNull AABBdc getBoundsFromState(@NotNull WorldSource source, @NotNull TilePosc tilePos) {
         int data = getValidatedBaseData(source, tilePos, this);
-        if (!IS_DETACHED_OR_EXTENDED.bool(data)) return this.bounds;
+        if (!IS_EXTENDED.bool(data)) return this.bounds;
 
         final var dir = Direction.fromId(DIRECTION.get(data));
         final var thickness = HEAD_BLOCK_MAP[this.typeId].getLogic().headThickness;
@@ -516,7 +451,7 @@ public class BlockLogicPistonBase extends BlockLogic {
     @Override
     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);
+        return !IS_EXTENDED.bool(data);
     }
 
     private static final ISupport[] SUPPORT_LUT;
@@ -544,7 +479,7 @@ public class BlockLogicPistonBase extends BlockLogic {
         final int data = getValidatedBaseData(world, tilePos, this);
         final int dir = Direction.fromId(DIRECTION.get(data)).id; // ensures < 6
 
-        return (!IS_DETACHED_OR_EXTENDED.bool(data))
+        return (!IS_EXTENDED.bool(data))
             ? FullSupport.INSTANCE
             : SUPPORT_LUT[side.id * 6 + dir];
     }
@@ -567,7 +502,6 @@ public class BlockLogicPistonBase extends BlockLogic {
     @Override
     public void onRemoved(@NotNull World world, @NotNull TilePosc tilePos, int data) {
         data = fixLegacyBaseData(world, tilePos, this, data);
-        if (IS_DETACHED.bool(data)) return;
 
         final var dir = Direction.fromId(DIRECTION.get(data));
         final var hpos = new TilePos(tilePos).add(dir);
@@ -587,32 +521,4 @@ public class BlockLogicPistonBase extends BlockLogic {
             world.setBlockTypeNotify(hpos, Blocks.AIR);
         }
     }
-
-    @Override
-    public @NotNull ItemStack @Nullable [] getBreakResult(
-        @NotNull World world, @NotNull EnumDropCause dropCause,
-        int data, @Nullable TileEntity tileEntity
-    ) {
-        class ctx {
-            static final ItemStack[] buf = new ItemStack[1];
-        }
-
-//        data = validateBaseData(data, this);
-//        data = DIRECTION.set(data, 0) & IS_EXTENDED.set(data, 0);
-
-        ctx.buf[0] = new ItemStack(this.block, 1, /*data*/0); // Setting the item to just have metadata 0, the item doesn't really need to know the blocks metadata to work and it just complicates recipe logic when the metadata is there -Useless
-        return ctx.buf;
-    }
-
-    @Override
-    public @NotNull String getLanguageKey(int data) {
-        interface ctx {
-            String[] KEYMAP = {
-                BASE_BLOCK_MAP[TYPE_NORMAL].getKey() + ".detached",
-                BASE_BLOCK_MAP[TYPE_STICKY].getKey() + ".detached",
-                BASE_BLOCK_MAP[TYPE_STEEL].getKey() + ".detached",
-            }; 
-        }
-        return (IS_DETACHED.bool(data)) ? ctx.KEYMAP[this.typeId] : this.block.getKey();
-    }
 }
diff --git a/game/core/src/main/java/net/minecraft/core/block/piston/BlockLogicPistonHead.java b/game/core/src/main/java/net/minecraft/core/block/piston/BlockLogicPistonHead.java
index e16017c0c..e6b2c4d44 100644
--- a/game/core/src/main/java/net/minecraft/core/block/piston/BlockLogicPistonHead.java
+++ b/game/core/src/main/java/net/minecraft/core/block/piston/BlockLogicPistonHead.java
@@ -11,16 +11,12 @@ import net.minecraft.core.block.material.Materials;
 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.entity.Entity;
 import net.minecraft.core.entity.player.Player;
 import net.minecraft.core.enums.EnumDropCause;
 import net.minecraft.core.item.Item;
 import net.minecraft.core.item.ItemStack;
-import net.minecraft.core.item.Items;
 import net.minecraft.core.util.helper.Direction;
 import net.minecraft.core.util.helper.Side;
-import net.minecraft.core.world.ICarriable;
-import net.minecraft.core.world.ICarrySource;
 import net.minecraft.core.world.World;
 import net.minecraft.core.world.WorldSource;
 import net.minecraft.core.world.pos.TilePos;
@@ -33,7 +29,7 @@ import org.joml.primitives.AABBdc;
 
 import static net.minecraft.core.block.piston.PistonCommon.*;
 
-public class BlockLogicPistonHead extends BlockLogic implements ICarrySource {
+public class BlockLogicPistonHead extends BlockLogic {
 
     // "Good lord. This really is our most NSFW update" -- Jonk
     // "Daaayyymmnn boy! He thick boy! That's a thick ass boy, DAYMN!" -- Melon
@@ -73,12 +69,7 @@ public class BlockLogicPistonHead extends BlockLogic implements ICarrySource {
     public boolean canPlaceAt(@NotNull World world, @NotNull TilePosc tilePos) {
         return false;
     }
-    
-    @Override
-    public boolean canPlaceOnSide(@NotNull World world, @NotNull TilePosc tilePos, @NotNull Side side) {
-        return false;
-    }
-    
+
     @Override
     public void getCollisionAABBs(@NotNull World world, @NotNull TilePosc tilePos, @NotNull AABBdc aabb, @NotNull List<@NotNull AABBdc> aabbList) {
         final var halvedShaft = shaftThickness / 2;
@@ -102,19 +93,6 @@ public class BlockLogicPistonHead extends BlockLogic implements ICarrySource {
         addIntersectingBoundingBox(aabb, new AABBd(smin, smax).translate(pos), aabbList);
     }
 
-    @Override
-    public @NotNull AABBdc getSelectionAABB(@NotNull WorldSource source, @NotNull TilePosc tilePos) {
-        final Vector3d min = new Vector3d(0), max = new Vector3d(1);
-        // if (!isBaseless(source.getBlockData(tilePos))) {
-        //     final int i = getDirectionFromMeta(source.getBlockData(tilePos)).getId();
-        //     final int j = (i/2 + 1) % 3;
-        //     final boolean n = (i & 1) == 0;
-        //     if (n) max.setComponent(j, 1 + headThickness);
-        //       else min.setComponent(j, 0 - headThickness);
-        // }
-        return new AABBd(min, max).translate(new Vector3d(tilePos.vec()));
-    }
-
     @Override
     public @NotNull AABBdc getBoundsFromState(@NotNull WorldSource source, @NotNull TilePosc tilePos) {
         final Vector3d min = new Vector3d(0), max = new Vector3d(1);
@@ -132,63 +110,36 @@ public class BlockLogicPistonHead extends BlockLogic implements ICarrySource {
     @Override
     public void onNeighborChanged(@NotNull World world, @NotNull TilePosc tilePos, final @NotNull Block<?> block) {
         final var data = getValidatedHeadData(world, tilePos);
-        if (IS_DETACHED.bool(data)) return;
 
         final var bpos = new TilePos(tilePos).sub(Direction.fromId(DIRECTION.get(data)));
-        if (!(world.getBlockType(bpos).getLogic() instanceof BlockLogicPistonBase)) return;
+        if (!(world.getBlockType(bpos).getLogic() instanceof BlockLogicPistonBase)) {
+            world.setBlockTypeNotify(tilePos, Blocks.AIR);
+            return;
+        }
         int bdat = fixLegacyBaseData(world, bpos);
-        if (PAIR_COMPARISON.get(data ^ bdat) != 0) return;
+        if (PAIR_COMPARISON.get(data ^ bdat) != 0) {
+            world.setBlockTypeNotify(tilePos, Blocks.AIR);
+            return;
+        }
 
         world.getBlockType(bpos).onNeighborChanged(world, bpos, block);
     }
 
     @Override
     public int getPistonPushReaction(@NotNull World world, @NotNull TilePosc tilePos) {
-        return (IS_DETACHED.bool(getValidatedHeadData(world, tilePos)))
-            ? Material.PISTON_PUSHABLE 
-            : Material.PISTON_CANT_PUSH;
+        return Material.PISTON_CANT_PUSH;
     }
 
     @Override
     public void onRemoved(@NotNull World world, @NotNull TilePosc tilePos, int data) {
         data = validateHeadData(data);
-        if (IS_DETACHED.bool(data)) return;
 
         final var bpos = new TilePos(tilePos).sub(Direction.fromId(DIRECTION.get(data)));
         if (!(world.getBlockType(bpos).getLogic() instanceof BlockLogicPistonBase)) return;
         int bdat = fixLegacyBaseData(world, bpos);
         if (PAIR_COMPARISON.get(data ^ bdat) != 0) return;
-        bdat = IS_DETACHED.set(bdat, 1);
-        if (TYPE.get(bdat) == TYPE_STICKY) {
-            bdat = TYPE.set(bdat, TYPE_NORMAL);
-            world.setBlockTypeData(bpos, Blocks.PISTON_BASE, bdat);
-        } else {
-            world.setBlockData(bpos, bdat);
-        }
-        world.markBlockDirty(bpos);
-        world.triggerEvent(bpos, EVENT_DETACH, 0);
-    }
-
-    @Override
-    public void onDestroyedByPlayer(
-        @NotNull World world, @NotNull TilePosc tilePos, @NotNull Side side, int data,
-        @NotNull Player player, @Nullable Item item
-    ) {
-        data = validateHeadData(data);
-        if (IS_DETACHED.bool(data)) return;
-        
-        final var bpos = new TilePos(tilePos).sub(Direction.fromId(DIRECTION.get(data)));
-        if (!(world.getBlockType(bpos).getLogic() instanceof BlockLogicPistonBase)) return;
-        int bdat = fixLegacyBaseData(world, bpos);
-        bdat = IS_DETACHED.set(bdat, 0);
-        if (PAIR_COMPARISON.get(data ^ bdat) != 0) return;
-        
-        final var b = world.getBlockType(bpos).getLogic();
-        world.setBlockTypeNotify(bpos, Blocks.AIR); // onRemoved
-        
-        if (player.gamemode.hasItemDrops()) {
-            b.dropWithCause(world, EnumDropCause.WORLD, bpos, bdat, null, null);
-        }
+        final var b = world.getBlockType(bpos);
+        world.setBlockTypeNotify(bpos, Blocks.AIR);
     }
 
     @Override
@@ -197,40 +148,8 @@ public class BlockLogicPistonHead extends BlockLogic implements ICarrySource {
         int data, @Nullable TileEntity tileEntity
     ) {
         // handle middle click pick block properly
-        if (dropCause == EnumDropCause.PICK_BLOCK) {
-            if (IS_DETACHED.bool(data)) return null;
-            
-            // we assume head is attached to an actual matching base without performing tilepos lookup
-            int baseData = IS_EXTENDED.set(data, 1);
-            return BASE_BLOCK_MAP[TYPE.get(data)].getBreakResult(world, dropCause, baseData, null);
-        }
-
-        return this.getBreakResult(world, dropCause, data, tileEntity);
-    }
-    
-    @Override
-    public @NotNull ItemStack @Nullable [] getBreakResult(
-        @NotNull World world, @NotNull EnumDropCause dropCause,
-        int data, @Nullable TileEntity tileEntity
-    ) {
-        class Result { final static ItemStack[][] LUT = {
-            { new ItemStack(Blocks.PLANKS_OAK, 3) },
-            { new ItemStack(Blocks.PLANKS_OAK, 3), new ItemStack(Items.SLIMEBALL) },
-            { new ItemStack(Items.INGOT_STEEL_CRUDE, 3) },
-        }; }
-        
-        if (dropCause == EnumDropCause.PICK_BLOCK) return null;
-        if (!IS_DETACHED.bool(data)) return null;
-        return Result.LUT[TYPE.get(data)];
-    }
-
-    @Override
-    public @NotNull ICarriable pickup(@NotNull World world, @NotNull Entity holder, @NotNull TilePosc tilePos) {
-        final var hdat = getValidatedHeadData(world, tilePos);
-        
-        world.setBlockType(tilePos, Blocks.AIR); // onRemoved
-        world.notifyBlockChange(tilePos, this.block);
-
-        return new CarriedPistonHead((byte)TYPE.get(hdat));
+        // we assume head is attached to an actual matching base without performing tilepos lookup
+        final int baseData = IS_EXTENDED.set(data, 1);
+        return BASE_BLOCK_MAP[TYPE.get(data)].getBreakResult(world, dropCause, baseData, null);
     }
 }
diff --git a/game/core/src/main/java/net/minecraft/core/block/piston/CarriedPistonHead.java b/game/core/src/main/java/net/minecraft/core/block/piston/CarriedPistonHead.java
deleted file mode 100644
index 51abfd297..000000000
--- a/game/core/src/main/java/net/minecraft/core/block/piston/CarriedPistonHead.java
+++ /dev/null
@@ -1,119 +0,0 @@
-package net.minecraft.core.block.piston;
-
-import org.jetbrains.annotations.NotNull;
-
-import com.mojang.nbt.tags.CompoundTag;
-
-import net.minecraft.core.block.Block;
-import net.minecraft.core.block.motion.ICarriedBlock;
-import net.minecraft.core.entity.Entity;
-import net.minecraft.core.entity.Mob;
-import net.minecraft.core.enums.EnumDropCause;
-import net.minecraft.core.enums.PlacementMode;
-import net.minecraft.core.util.helper.Direction;
-import net.minecraft.core.util.helper.MathHelper;
-import net.minecraft.core.util.helper.Side;
-import net.minecraft.core.world.ICarriable;
-import net.minecraft.core.world.World;
-import net.minecraft.core.world.pos.TilePos;
-
-import static net.minecraft.core.block.piston.PistonCommon.*;
-
-public class CarriedPistonHead implements ICarriable, ICarriedBlock {
-    private @NotNull byte type;
-
-    public CarriedPistonHead(byte type) {
-        this.type = type;
-    }
-
-	@Override
-    public @NotNull Block<? extends BlockLogicPistonHead> block() {
-        return PistonCommon.HEAD_BLOCK_MAP[type];
-    }
-
-    @Override
-    public int metadata() {
-        return metadata(Direction.UP.id);
-    }
-    
-    private int metadata(int dir) {
-        int d = 0;
-        d = IS_DETACHED.set(d, 1);
-        d = TYPE.set(d, this.type);
-        d = DIRECTION.set(d, dir);
-        d = validateHeadData(d);
-        return d;
-    }
-
-    @Override
-    public boolean tryPlace(World world, Entity holder, int blockX, int blockY, int blockZ,
-        Side side, double xPlaced, double yPlaced
-    ) {
-        final var hpos = new TilePos(blockX, blockY, blockZ).add(side.direction());
-        if (!world.canPlaceInsideBlock(hpos)) return false;
-
-        final int dir = (holder instanceof Mob mob)
-            ? mob.getPlacementDirection(side.opposite(), PlacementMode.SIDE).opposite().id
-            : Direction.UP.id;
-
-        int hdat = metadata(dir);
-        world.setBlockType(hpos, block());
-
-        sync_base: {
-            final var bpos = new TilePos();
-            int bdat = headGetBase(hdat, bpos, world, hpos);
-            if (bdat == DATA_INVALID) break sync_base;
-            if (!IS_DETACHED_OR_EXTENDED.bool(bdat)) break sync_base;
-            if (PAIR_COMPARISON.get(hdat ^ bdat) != 0) break sync_base;
-
-            hdat = IS_DETACHED.set(hdat, 0);
-            bdat = IS_DETACHED.set(bdat, 0);
-            bdat = IS_EXTENDED.set(hdat, 1);
-
-            if (IS_STEEL.bool(hdat)) {
-                world.setBlockData(bpos, bdat);
-            } else {
-                bdat = TYPE.setNoShift(bdat, hdat);
-                world.setBlockTypeDataRaw(bpos, BASE_BLOCK_MAP[TYPE.get(hdat)], bdat);
-            }
-            world.triggerEvent(bpos, EVENT_ATTACH, 0);
-        }
-
-        world.setBlockDataNotify(hpos, hdat);
-        return true;
-    }
-
-    @Override
-    public void drop(World world, Entity holder) {
-        if (world.isClientSide) return;
-        if (ICarriable.tryPlaceAroundHolder(this, world, holder)) return;
-
-        final int holderX = MathHelper.floor(holder.x);
-        final int holderY = MathHelper.floor(holder.y);
-        final int holderZ = MathHelper.floor(holder.z);
-
-        this.block().dropWithCause(
-            world, EnumDropCause.WORLD, new TilePos(holderX, holderY, holderZ),
-            this.metadata(), null, null);
-    }
-
-    @Override
-    public void writeToNBT(CompoundTag tag) {
-        tag.putByte("head_type", type);
-        tag.putString("type", TYPE_PISTON_HEAD);
-    }
-
-    @Override
-    public void readFromNBT(CompoundTag tag) {
-        type = tag.getByte("head_type");
-    }
-
-    public static CarriedPistonHead createAndLoad(CompoundTag tag) {
-        final var carriedBlock = new CarriedPistonHead((byte)0);
-        carriedBlock.readFromNBT(tag);
-        return carriedBlock;
-    }
-
-    @Override
-    public void heldTick(World world, Entity holder) {}
-}
diff --git a/game/core/src/main/java/net/minecraft/core/block/piston/PistonCommon.java b/game/core/src/main/java/net/minecraft/core/block/piston/PistonCommon.java
index 51bd8ecf2..5c49d260f 100644
--- a/game/core/src/main/java/net/minecraft/core/block/piston/PistonCommon.java
+++ b/game/core/src/main/java/net/minecraft/core/block/piston/PistonCommon.java
@@ -23,20 +23,15 @@ public abstract class PistonCommon {
 
     public static final PackedField DIRECTION   = new PackedField(0, 3);
     public static final PackedField TYPE        = new PackedField(3, 2);
-    public static final PackedField IS_DETACHED = new PackedField(5, 1);
     public static final PackedField IS_EXTENDED = new PackedField(6, 1);
     
     public static final PackedField NEW_FORMAT_SIGNATURE = new PackedField(7, 1);
 
     public static final PackedField IS_STICKY   = new PackedField(3, 1);
     public static final PackedField IS_STEEL    = new PackedField(4, 1);
-
-    public static final PackedField IS_DETACHED_OR_EXTENDED = new PackedField(
-        IS_DETACHED.mask | IS_EXTENDED.mask
-    );
     
     public static final PackedField PAIR_COMPARISON = new PackedField(
-        DIRECTION.mask | IS_DETACHED.mask | IS_STEEL.mask
+        DIRECTION.mask | TYPE.mask
     );
 
     // TODO using type id is poorly extensible,
@@ -52,11 +47,8 @@ public abstract class PistonCommon {
      */ 
     public static final byte EVENT_EXTEND         = 0b00_0; 
     public static final byte EVENT_RETRACT        = 0b00_1;
-    public static final byte EVENT_DETACH         = 0b01_0;
-    public static final byte EVENT_ATTACH         = 0b01_1;
-    public static final byte EVENT_DETACH_EXTEND  = 0b10_0;
-    public static final byte EVENT_DETACH_RETRACT = 0b10_1;
 
+    @SuppressWarnings("unchecked")
     public static final @NotNull Block<? extends BlockLogicPistonBase>[] 
     BASE_BLOCK_MAP = (Block<BlockLogicPistonBase>[]) new Block[] {
         Blocks.PISTON_BASE,
@@ -64,6 +56,7 @@ public abstract class PistonCommon {
         Blocks.PISTON_BASE_STEEL,
     };
     
+    @SuppressWarnings("unchecked")
     public static final @NotNull Block<? extends BlockLogicPistonHead>[]
     HEAD_BLOCK_MAP = (Block<BlockLogicPistonHead>[]) new Block[] {
         Blocks.PISTON_HEAD,
@@ -86,7 +79,7 @@ public abstract class PistonCommon {
         if (baseDir == Direction.NONE) return DIRECTION.set(baseData, 0);
 
         // old data format should not have set those bits
-        if (!IS_DETACHED_OR_EXTENDED.bool(baseData)) set_extended_if_head_matches: {
+        if (!IS_EXTENDED.bool(baseData)) set_extended_if_head_matches: {
             final var headPos = new TilePos(basePos).add(baseDir);
             final var headBlock = world.getBlockType(headPos);
             final var headData = world.getBlockData(headPos);
@@ -103,8 +96,6 @@ public abstract class PistonCommon {
                 break set_extended_if_head_matches;
             } 
 
-            // old head data format should not have set this bit
-            if (IS_DETACHED.bool(headData)) break set_extended_if_head_matches;
             if (DIRECTION.get(headData) != baseDir.id) break set_extended_if_head_matches;
 
             if (TYPE.get(headData) != base.typeId) break set_extended_if_head_matches;
@@ -186,19 +177,4 @@ public abstract class PistonCommon {
         public final boolean isExtending;
         public final boolean isSourcePiston;
     }
-
-    public static @NotNull ItemStack baseItem(int type, boolean isExteneded, boolean isDetached) {
-        int data = 0;
-        data |= TYPE.set(data, type);
-        data |= IS_EXTENDED.set(data, isExteneded ? 1 : 0);
-        data |= IS_DETACHED.set(data, isDetached ? 1 : 0);
-        return new ItemStack(BASE_BLOCK_MAP[type], 1, data);
-    }
-
-    public static @NotNull ItemStack headItem(int type, boolean isDetached) {
-        int data = 0;
-        data |= TYPE.set(data, type);
-        data |= IS_DETACHED.set(data, isDetached ? 1 : 0);
-        return new ItemStack(BASE_BLOCK_MAP[type], 1, data);
-    }
 }
diff --git a/game/core/src/main/java/net/minecraft/core/entity/animal/MobSheep.java b/game/core/src/main/java/net/minecraft/core/entity/animal/MobSheep.java
index 67875bb6c..5f7e9dc72 100644
--- a/game/core/src/main/java/net/minecraft/core/entity/animal/MobSheep.java
+++ b/game/core/src/main/java/net/minecraft/core/entity/animal/MobSheep.java
@@ -280,25 +280,6 @@ public class MobSheep
         return random.nextInt(500) != 0 ? DyeColor.WHITE : DyeColor.PINK;
     }
 
-    public static final float[][] FLEECE_COLOR_TABLE = {
-        {  1.0F,  1.0F,  1.0F  }, // White
-        {  0.95F, 0.7F,  0.2F  }, // Orange
-        {  0.9F,  0.5F,  0.85F }, // Magenta
-        {  0.6F,  0.7F,  0.95F }, // Light Blue
-        {  0.9F,  0.9F,  0.2F  }, // Yellow
-        {  0.5F,  0.8F,  0.1F  }, // Lime
-        {  0.95F, 0.7F,  0.8F  }, // Pink
-        {  0.3F,  0.3F,  0.3F  }, // Grey
-        {  0.6F,  0.6F,  0.6F  }, // Silver
-        {  0.3F,  0.6F,  0.7F  }, // Cyan
-        {  0.7F,  0.4F,  0.9F  }, // Purple
-        {  0.2F,  0.4F,  0.8F  }, // Blue
-        {  0.5F,  0.4F,  0.3F  }, // Brown
-        {  0.4F,  0.5F,  0.2F  }, // Green
-        {  0.8F,  0.3F,  0.3F  }, // Red
-        {  0.1F,  0.1F,  0.1F  }  // Black
-    };
-
     @Override
     public boolean isFavouriteItem(ItemStack itemStack)
     {
@@ -311,4 +292,5 @@ public class MobSheep
     public void setGrowthTimer(int growthTimer){
         this.growthTimer = growthTimer;
     }
+
 }
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 b28e6ac3a..3e6016425 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
@@ -1586,7 +1586,7 @@ public abstract class Player
                     addStat(StatList.distanceByMinecartStat, i);
                     if (this.startMinecartRidingPoint == null) {
                         this.startMinecartRidingPoint = new TilePos(this);
-                    } else if (this.startMinecartRidingPoint.distanceSquared(this) >= 1000D) {
+                    } else if (this.startMinecartRidingPoint.distance(this) >= 1000D) {
                         addStat(Achievements.ON_A_RAIL, 1);
                     }
                 } else if (this.vehicle instanceof EntityBoat) {
diff --git a/game/core/src/main/java/net/minecraft/core/item/ItemSlimeball.java b/game/core/src/main/java/net/minecraft/core/item/ItemSlimeball.java
index e3bfa5d83..0dd485631 100644
--- a/game/core/src/main/java/net/minecraft/core/item/ItemSlimeball.java
+++ b/game/core/src/main/java/net/minecraft/core/item/ItemSlimeball.java
@@ -12,8 +12,6 @@ import net.minecraft.core.world.pos.TilePosc;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
-import static net.minecraft.core.block.piston.PistonCommon.IS_DETACHED;
-
 import java.util.Random;
 
 public class ItemSlimeball extends Item {
@@ -44,14 +42,14 @@ public class ItemSlimeball extends Item {
         }
         
         data = PistonCommon.TYPE.set(data, PistonCommon.TYPE_STICKY);
-        assert selfStack.consumeItem(player);
+        selfStack.consumeItem(player);
 
         final var baseBlock = PistonCommon.BASE_BLOCK_MAP[PistonCommon.TYPE_STICKY];
         final var headBlock = PistonCommon.HEAD_BLOCK_MAP[PistonCommon.TYPE_STICKY];
 
         final var newBlock = (isBase) ? baseBlock : headBlock;
 
-        if (isBase || IS_DETACHED.bool(data)) {
+        if (isBase) {
             world.setBlockTypeDataNotify(blockPos, newBlock, data);
             return true;
         }
@@ -61,9 +59,7 @@ public class ItemSlimeball extends Item {
         final TilePos bpos = new TilePos();
         int bdat = PistonCommon.headGetBase(data, bpos, world, blockPos);
         
-        final boolean isExtendedButNotDetached  = 
-            PistonCommon.IS_DETACHED_OR_EXTENDED.get(bdat) == PistonCommon.IS_EXTENDED.mask;
-        if (!isExtendedButNotDetached) {
+        if (!PistonCommon.IS_EXTENDED.bool(bdat)) {
             world.setBlockTypeDataNotify(blockPos, newBlock, data);
             return true;
         }
diff --git a/game/core/src/main/java/net/minecraft/core/world/ICarriable.java b/game/core/src/main/java/net/minecraft/core/world/ICarriable.java
index d1b45581e..e9f689fd5 100644
--- a/game/core/src/main/java/net/minecraft/core/world/ICarriable.java
+++ b/game/core/src/main/java/net/minecraft/core/world/ICarriable.java
@@ -3,7 +3,7 @@ package net.minecraft.core.world;
 import com.mojang.logging.LogUtils;
 import com.mojang.nbt.tags.CompoundTag;
 import net.minecraft.core.block.motion.CarriedBlock;
-import net.minecraft.core.block.piston.CarriedPistonHead;
+import net.minecraft.core.block.piston.BlockLogicPistonHead;
 import net.minecraft.core.entity.Entity;
 import net.minecraft.core.enums.EnumDropCause;
 import net.minecraft.core.util.helper.MathHelper;
@@ -61,16 +61,12 @@ public interface ICarriable {
     void readFromNBT(CompoundTag tag);
 
     static final String TYPE_BLOCK = "block";
-    static final String TYPE_PISTON_HEAD = "block/piston_head";
 
     static ICarriable createAndLoadCarriable(Entity holder, CompoundTag tag) {
         String type = tag.getString("type");
         if (type.equalsIgnoreCase(TYPE_BLOCK)) {
             return CarriedBlock.createAndLoadCarriedBlock(holder, tag);
         }
-        if (type.equalsIgnoreCase(TYPE_PISTON_HEAD)) {
-            return CarriedPistonHead.createAndLoad(tag);
-        }
         LOGGER.warn("Could not identify carriable for type {}!", type);
         return null;
     }
diff --git a/game/core/src/main/java/net/minecraft/core/world/noise/ImprovedPerlinNoise.java b/game/core/src/main/java/net/minecraft/core/world/noise/ImprovedPerlinNoise.java
index e4bbccfef..ea7b5748a 100644
--- a/game/core/src/main/java/net/minecraft/core/world/noise/ImprovedPerlinNoise.java
+++ b/game/core/src/main/java/net/minecraft/core/world/noise/ImprovedPerlinNoise.java
@@ -40,7 +40,7 @@ public class ImprovedPerlinNoise
     }
 
     public enum LegacyNoiseType {
-        DEFAULT(true, true, false),
+        DEFAULT(true, true, true),
         ALPHA(false, false, true),
         BETA(true, false, true);
 
diff --git a/util/datagen/build.gradle.kts b/util/datagen/build.gradle.kts
index 49736ad3d..e416c8b22 100644
--- a/util/datagen/build.gradle.kts
+++ b/util/datagen/build.gradle.kts
@@ -14,6 +14,7 @@ dependencies {
     implementation(libs.brigadier)
     implementation(libs.gson)
     implementation(libs.jetbrains.annotations)
+    implementation(libs.fastutil)
 }
 
 val output by configurations.creating
diff --git a/util/datagen/src/main/java/net/minecraft/datagen/SmeltingGenerator.java b/util/datagen/src/main/java/net/minecraft/datagen/SmeltingGenerator.java
index ef1a9abbe..ce7c50a54 100644
--- a/util/datagen/src/main/java/net/minecraft/datagen/SmeltingGenerator.java
+++ b/util/datagen/src/main/java/net/minecraft/datagen/SmeltingGenerator.java
@@ -1,12 +1,14 @@
 package net.minecraft.datagen;
 
+import it.unimi.dsi.fastutil.ints.Int2IntArrayMap;
+import net.minecraft.core.block.*;
 import net.minecraft.core.data.registry.Registries;
 import net.minecraft.core.data.registry.recipe.RecipeSymbol;
 import net.minecraft.datagen.recipeBuilders.RecipeBuilder;
-import net.minecraft.core.block.Blocks;
 import net.minecraft.core.item.ItemStack;
 import net.minecraft.core.item.Items;
 import net.minecraft.core.util.helper.DyeColor;
+import org.jetbrains.annotations.NotNull;
 
 public class SmeltingGenerator {
     public static void generate() {
@@ -54,6 +56,32 @@ public class SmeltingGenerator {
         blastRecipe("iron_ingot_and_charcoal_to_crude_steel", Items.INGOT_IRON.getDefaultStack(), new ItemStack(Items.COAL, 1, 1), Items.INGOT_STEEL_CRUDE.getDefaultStack());
 
         blastRecipe("log_to_scorched_log", "minecraft:logs", Blocks.BLOCK_ASH.getDefaultStack(), Blocks.LOG_SCORCHED.getDefaultStack());
+
+        addOreConversions(BlockLogicOreCoal.variantMap);
+        addOreConversions(BlockLogicOreIron.variantMap);
+        addOreConversions(BlockLogicOreGold.variantMap);
+        addOreConversions(BlockLogicOreLapis.variantMap);
+        addOreConversions(BlockLogicOreRedstone.variantMap);
+        addOreConversions(BlockLogicOreDiamond.variantMap);
+        addOreConversions(BlockLogicOreNetherCoal.variantMap);
+    }
+
+    private static void addOreConversions(Int2IntArrayMap variantMap) {
+        for (int fromParentId : variantMap.keySet()) {
+            for (int toParentId : variantMap.keySet()) {
+                if (fromParentId == toParentId) continue;
+
+                final Block<?> toParent = Blocks.getBlock(toParentId);
+
+                final Block<?> fromChild = Blocks.getBlock(variantMap.get(fromParentId));
+                final Block<?> toChild = Blocks.getBlock(variantMap.get(toParentId));
+
+                blastRecipe(
+                    String.format("%s_to_%s", fromChild.getKey(), toChild.getKey()),
+                    toParent.getDefaultStack(), fromChild.getDefaultStack(), toChild.getDefaultStack()
+                );
+            }
+        }
     }
 
     private static void furnaceRecipe(String id, ItemStack input, ItemStack output) {
diff --git a/util/datagen/src/main/java/net/minecraft/datagen/WorkbenchGenerator.java b/util/datagen/src/main/java/net/minecraft/datagen/WorkbenchGenerator.java
index 48a5ae1e5..0b36bb940 100644
--- a/util/datagen/src/main/java/net/minecraft/datagen/WorkbenchGenerator.java
+++ b/util/datagen/src/main/java/net/minecraft/datagen/WorkbenchGenerator.java
@@ -1283,15 +1283,18 @@ class WorkbenchGenerator {
             .addInput('#', "minecraft:cobblestones")
             .addInput('I', Items.INGOT_IRON)
             .addInput('R', Items.DUST_REDSTONE)
-            .create("piston", new ItemStack(Blocks.PISTON_BASE));
+            .create("piston", Blocks.PISTON_BASE.getDefaultStack());
 
         RecipeBuilder.Shaped(CORE_NAMESPACE)
             .setShape(
                 "XXX",
-                " B ")
-            .addInput('X', "minecraft:planks")
-            .addInput('B', PistonCommon.baseItem(PistonCommon.TYPE_NORMAL, false, true))
-            .create("piston_reattach", new ItemStack(Blocks.PISTON_BASE));
+                "#I#",
+                "#R#")
+            .addInput('X', Items.INGOT_STEEL_CRUDE)
+            .addInput('#', "minecraft:stones")
+            .addInput('I', Items.INGOT_STEEL)
+            .addInput('R', Items.DUST_REDSTONE)
+            .create("steel_piston", Blocks.PISTON_BASE_STEEL.getDefaultStack());
 
         RecipeBuilder.Shaped(CORE_NAMESPACE)
             .setShape(
@@ -1301,35 +1304,6 @@ class WorkbenchGenerator {
             .addInput('P', Blocks.PISTON_BASE)
             .create("sticky_piston", Blocks.PISTON_BASE_STICKY.getDefaultStack());
 
-        RecipeBuilder.Shaped(CORE_NAMESPACE)
-            .setShape(
-                " S ",
-                "XXX",
-                " B ")
-            .addInput('S', Items.SLIMEBALL)
-            .addInput('X', "minecraft:planks")
-            .addInput('B', PistonCommon.baseItem(PistonCommon.TYPE_STICKY, false, true))
-            .create("sticky_piston_reattach", Blocks.PISTON_BASE_STICKY.getDefaultStack());
-        
-        RecipeBuilder.Shaped(CORE_NAMESPACE)
-        .setShape(
-            "XXX",
-            "#I#",
-            "#R#")
-            .addInput('X', Items.INGOT_STEEL_CRUDE)
-            .addInput('#', "minecraft:stones")
-            .addInput('I', Items.INGOT_STEEL)
-            .addInput('R', Items.DUST_REDSTONE)
-            .create("steel_piston", Blocks.PISTON_BASE_STEEL.getDefaultStack());
-            
-        RecipeBuilder.Shaped(CORE_NAMESPACE)
-            .setShape(
-                "XXX",
-                " B ")
-            .addInput('X', Items.INGOT_STEEL_CRUDE)
-            .addInput('B', PistonCommon.baseItem(PistonCommon.TYPE_STEEL, false, true))
-            .create("steel_piston_reattach", Blocks.PISTON_BASE_STEEL.getDefaultStack());
-
         RecipeBuilder.Shaped(CORE_NAMESPACE)
             .setShape(
                 "X#X",
