diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicFluid.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicFluid.java
index f64634037..558b84a1c 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicFluid.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicFluid.java
@@ -247,6 +247,19 @@ public abstract class BlockLogicFluid extends BlockLogic {
         return false;
     }
 
+    public static boolean isStillEquivalentToFlowing(Block<?> block1, Block<?> block2) {
+        if (block1 == null || block2 == null) return false;
+        if (block1 == block2) return true;
+
+        if (block1.getLogic() instanceof BlockLogicFluid blockLogic1 &&
+                block2.getLogic() instanceof BlockLogicFluid blockLogic2) {
+
+            return blockLogic1.fluid == blockLogic2.fluid;
+        }
+
+        return false;
+    }
+
     public boolean isFullBlock(@NotNull World world, TilePos tilePos){
         return getFluidHeight(world, tilePos) == 1;
     }
diff --git a/game/core/src/main/java/net/minecraft/core/item/ItemBucket.java b/game/core/src/main/java/net/minecraft/core/item/ItemBucket.java
index e98026c07..8d9bcfeb3 100644
--- a/game/core/src/main/java/net/minecraft/core/item/ItemBucket.java
+++ b/game/core/src/main/java/net/minecraft/core/item/ItemBucket.java
@@ -5,8 +5,8 @@ import net.minecraft.core.block.Block;
 import net.minecraft.core.block.BlockLogicFluid;
 import net.minecraft.core.block.Blocks;
 import net.minecraft.core.block.entity.TileEntityActivator;
-import net.minecraft.core.block.material.Materials;
 import net.minecraft.core.block.tag.BlockTags;
+import net.minecraft.core.data.tag.Tag;
 import net.minecraft.core.entity.animal.MobCow;
 import net.minecraft.core.entity.player.Player;
 import net.minecraft.core.enums.EnumDropCause;
@@ -24,6 +24,7 @@ import org.jetbrains.annotations.Nullable;
 import org.joml.primitives.AABBd;
 
 import java.util.*;
+import java.util.function.BiConsumer;
 
 public abstract class ItemBucket extends ItemFood implements IItemContainer {
 
@@ -33,21 +34,42 @@ public abstract class ItemBucket extends ItemFood implements IItemContainer {
             int healAmount,
             int ticksPerHeal,
             @Nullable Block<?> fluidBlock,
-            boolean canPlace
+            @Nullable Tag<Block<?>> pickupTag,
+            boolean canPlace,
+            @Nullable String soundPath,
+            @Nullable BiConsumer<World, TilePos> placementAction
     ) {
 
+        /**
+         * Constructor for Empty/Placeholder states
+         */
+        public BucketState(String name) {
+            this(name, false, 0, 0, null, null, false, null, null);
+        }
 
         /**
-         * Constructor for Food/Edible Buckets
+         * Constructor for Food/Edible Buckets (Non-placeable)
          */
         public BucketState(String name, int healAmount, int ticksPerHeal) {
-            this(name, true, healAmount, ticksPerHeal, null, false);
+            this(name, true, healAmount, ticksPerHeal, null, null, false, null, null);
+        }
+        /**
+         * Constructor for Fluids
+         */
+        public BucketState(String name, Block<?> fluidBlock, Tag<Block<?>> pickupTag, String soundPath) {
+            this(name, false, 0, 0, fluidBlock, pickupTag, true, soundPath, null);
+        }
+        /**
+         * Constructor for Fluids with custom action
+         */
+        public BucketState(String name, Block<?> fluidBlock, Tag<Block<?>> pickupTag, String soundPath, BiConsumer<World, TilePos> placementAction) {
+            this(name, false, 0, 0, fluidBlock, pickupTag, true, soundPath, placementAction);
         }
         /**
-         * Constructor for Fluid Buckets
+         * Constructor for Edible and Placeable Buckets
          */
-        public BucketState(String name, @Nullable Block<?> fluidBlock, boolean canPlace) {
-            this(name, false, 0, 0, fluidBlock, canPlace);
+        public BucketState(String name, int healAmount, int ticksPerHeal, Block<?> fluidBlock, Tag<Block<?>> pickupTag, String soundPath) {
+            this(name, true, healAmount, ticksPerHeal, fluidBlock, pickupTag, true, soundPath, null);
         }
     }
 
@@ -59,11 +81,36 @@ public abstract class ItemBucket extends ItemFood implements IItemContainer {
     public static final NamespaceID STATE_ICECREAM = new NamespaceID("minecraft", "icecream");
 
     static {
-        registerState(STATE_EMPTY, new BucketState("empty", null, false));
-        registerState(STATE_WATER, new BucketState("water", Blocks.FLUID_WATER_FLOWING, true));
-        registerState(STATE_LAVA, new BucketState("lava", Blocks.FLUID_LAVA_FLOWING, true));
-        registerState(STATE_MILK, new BucketState("milk", 0, 0));
-        registerState(STATE_ICECREAM, new BucketState("icecream", 15, 4));
+        registerState(STATE_EMPTY, new BucketState(
+                "empty"
+        ));
+
+        registerState(STATE_WATER, new BucketState(
+                "water",
+                Blocks.FLUID_WATER_FLOWING,
+                BlockTags.IS_WATER,
+                "liquid.splash"
+        ));
+
+        registerState(STATE_LAVA, new BucketState(
+                "lava",
+                Blocks.FLUID_LAVA_FLOWING,
+                BlockTags.IS_LAVA,
+                "liquid.lavapop",
+                BlockLogicFluid::fizz
+        ));
+
+        registerState(STATE_MILK, new BucketState(
+                "milk",
+                0,
+                0
+        ));
+
+        registerState(STATE_ICECREAM, new BucketState(
+                "icecream",
+                15,
+                4
+        ));
     }
 
     public static NamespaceID registerState(NamespaceID id, BucketState state) {
@@ -100,8 +147,19 @@ public abstract class ItemBucket extends ItemFood implements IItemContainer {
 
     @Nullable
     private NamespaceID getFluidStateAt(World world, TilePosc tilePos) {
-        if (world.getBlockMaterial(tilePos) == Materials.WATER) return STATE_WATER;
-        if (world.getBlockMaterial(tilePos) == Materials.LAVA) return STATE_LAVA;
+        Block<?> blockAtPos = world.getBlockType(tilePos);
+
+        for (Map.Entry<NamespaceID, BucketState> entry : STATE_REGISTRY.entrySet()) {
+            BucketState state = entry.getValue();
+
+            if (state.pickupTag() != null && blockAtPos.hasTag(state.pickupTag())) {
+                return entry.getKey();
+            }
+
+            if (state.fluidBlock() != null && (state.fluidBlock() == blockAtPos || BlockLogicFluid.isStillEquivalentToFlowing(state.fluidBlock(), blockAtPos))) {
+                return entry.getKey();
+            }
+        }
         return null;
     }
 
@@ -131,7 +189,6 @@ public abstract class ItemBucket extends ItemFood implements IItemContainer {
 
         double reachDistance = player.getGamemode().getBlockReachDistance();
         HitResult hitResultFluid = player.rayCast(reachDistance, 1f, true, false, false);
-        HitResult hitResultNoFluid = player.rayCast(reachDistance, 1f, false, false, false);
 
         if (hitResultFluid == null) {
             return handleAirClick(itemStack, world, player);
@@ -152,8 +209,11 @@ public abstract class ItemBucket extends ItemFood implements IItemContainer {
                 }
             }
 
-            if (currentState.canPlace() && hitResultNoFluid instanceof HitResult.Tile hitTileNoFluid) {
-                return tryPlaceFluid(itemStack, world, player, hitTileNoFluid);
+            if (currentState.canPlace()) {
+                HitResult hitResultNoFluid = player.rayCast(reachDistance, 1f, false, false, false);
+                if (hitResultNoFluid instanceof HitResult.Tile hitTileNoFluid) {
+                    return tryPlaceFluid(itemStack, world, player, hitTileNoFluid);
+                }
             }
         }
 
@@ -200,20 +260,22 @@ public abstract class ItemBucket extends ItemFood implements IItemContainer {
             BucketState bucketState = getBucketState(stateId);
 
             if (bucketState.fluidBlock() != null) {
-
-                if(STATE_LAVA.equals(stateId)){
-                    BlockLogicFluid.fizz(world, rayCastPos);
-                    world.playSoundEffect(player, SoundCategory.WORLD_SOUNDS, rayCastPos.x + 0.5F, rayCastPos.y + 0.5F, rayCastPos.z + 0.5F, "liquid.lavapop", 1f, 1f);
+                if (bucketState.soundPath() != null) {
+                    world.playSoundEffect(player, SoundCategory.WORLD_SOUNDS, rayCastPos.x + 0.5F, rayCastPos.y + 0.5F, rayCastPos.z + 0.5F, bucketState.soundPath(), 1f, 1f);
                 }
-                if(STATE_WATER.equals(stateId)){
-                    world.playSoundEffect(player, SoundCategory.WORLD_SOUNDS, rayCastPos.x + 0.5F, rayCastPos.y + 0.5F, rayCastPos.z + 0.5F, "liquid.splash", 0.65f, 1f);
+
+                if (bucketState.placementAction() != null) {
+                    bucketState.placementAction().accept(world, rayCastPos);
                 }
 
                 final Block<?> replacedBlock = world.getBlockType(rayCastPos);
                 final int replacedData = world.getBlockData(rayCastPos);
 
                 world.setBlockTypeNotify(rayCastPos, bucketState.fluidBlock());
-                replacedBlock.dropWithCause(world, EnumDropCause.WORLD, rayCastPos, replacedData, null, null);
+
+                if (!(replacedBlock == Blocks.AIR)) {
+                    replacedBlock.dropWithCause(world, EnumDropCause.WORLD, rayCastPos, replacedData, null, null);
+                }
 
                 player.swingItem();
 
@@ -284,7 +346,8 @@ public abstract class ItemBucket extends ItemFood implements IItemContainer {
 
         player.inventory.insertItem(splitItemStack, true);
         if (splitItemStack.stackSize > 0) {
-            world.dropItem((int) player.x, (int) player.y, (int) player.z, splitItemStack);
+            TilePosc dropPos = new TilePos(player);
+            world.dropItem(dropPos, splitItemStack);
         }
         return itemStack;
     }
@@ -306,10 +369,10 @@ public abstract class ItemBucket extends ItemFood implements IItemContainer {
     public static NamespaceID getState(@NotNull ItemStack stack) {
         CompoundTag tag = stack.getData();
         if (tag.containsKey("State")) {
-            String stateStr = tag.getString("State");
-            if (stateStr.contains(":")) {
+            String stateString = tag.getString("State");
+            if (!stateString.isEmpty()) {
                 try {
-                    return new NamespaceID(stateStr);
+                    return NamespaceID.fromPool(stateString);
                 } catch (HardIllegalArgumentException ignored) {
                 }
             }
@@ -394,13 +457,8 @@ public abstract class ItemBucket extends ItemFood implements IItemContainer {
         boolean isSourceBlock = world.getBlockData(posAhead) == 0;
         if (isSourceBlock) {
             NamespaceID targetStateId = getFluidStateAt(world, posAhead);
-            boolean isRefillScoop = currentStateId.equals(targetStateId) && getCharges(selfStack) < this.maxCharges;
-
-            if (targetStateId != null && (isEmptyScoop || isRefillScoop)) {
-                if (selfStack.stackSize > 1 && !canActivatorAccept(activator, selfStack.getItem(), targetStateId)) {
-                    return;
-                }
-
+            if (targetStateId != null && (isEmptyScoop || (currentStateId.equals(targetStateId) && getCharges(selfStack) < this.maxCharges))) {
+                if (selfStack.stackSize > 1 && !canActivatorAccept(activator, selfStack.getItem(), targetStateId)) return;
                 world.setBlockTypeNotify(posAhead, Blocks.AIR);
                 world.playSoundEffect(null, SoundCategory.WORLD_SOUNDS, posAhead.x + 0.5F, posAhead.y + 0.5F, posAhead.z + 0.5F, "item.pickup", 2.2f, 0.5f);
 
@@ -411,14 +469,8 @@ public abstract class ItemBucket extends ItemFood implements IItemContainer {
 
         if (currentState.canPlace() && currentState.fluidBlock() != null) {
             if (blockAhead.hasTag(BlockTags.PLACE_OVERWRITES) || blockAhead.hasTag(BlockTags.BROKEN_BY_FLUIDS)) {
-
-                if (STATE_LAVA.equals(currentStateId)) {
-                    BlockLogicFluid.fizz(world, posAhead);
-                    world.playSoundEffect(null, SoundCategory.WORLD_SOUNDS, posAhead.x + 0.5F, posAhead.y + 0.5F, posAhead.z + 0.5F, "liquid.lavapop", 1f, 1f);
-                } else if (STATE_WATER.equals(currentStateId)) {
-                    world.playSoundEffect(null, SoundCategory.WORLD_SOUNDS, posAhead.x + 0.5F, posAhead.y + 0.5F, posAhead.z + 0.5F, "liquid.splash", 0.65f, 1f);
-                }
-
+                if (currentState.soundPath() != null) world.playSoundEffect(null, SoundCategory.WORLD_SOUNDS, posAhead.x + 0.5F, posAhead.y + 0.5F, posAhead.z + 0.5F, currentState.soundPath(), 1f, 1f);
+                if (currentState.placementAction() != null) currentState.placementAction().accept(world, posAhead);
                 int replacedData = world.getBlockData(posAhead);
                 world.setBlockTypeNotify(posAhead, currentState.fluidBlock());
                 blockAhead.dropWithCause(world, EnumDropCause.WORLD, posAhead, replacedData, null, null);
@@ -436,7 +488,6 @@ public abstract class ItemBucket extends ItemFood implements IItemContainer {
      * Assumes inventory space has already been verified via canActivatorAccept.
      */
     private void handleActivatorFill(ItemStack selfStack, NamespaceID targetStateId, TileEntityActivator activator) {
-        NamespaceID currentStateId = getState(selfStack);
 
         if (selfStack.stackSize > 1) {
             selfStack.stackSize--;
@@ -460,12 +511,8 @@ public abstract class ItemBucket extends ItemFood implements IItemContainer {
                 }
             }
         } else {
-            if (STATE_EMPTY.equals(currentStateId)) {
-                setState(selfStack, targetStateId);
-                setCharges(selfStack, 1);
-            } else {
-                setCharges(selfStack, getCharges(selfStack) + 1);
-            }
+            if (STATE_EMPTY.equals(getState(selfStack))) { setState(selfStack, targetStateId); setCharges(selfStack, 1); }
+            else { setCharges(selfStack, getCharges(selfStack) + 1); }
         }
     }
 
@@ -475,16 +522,8 @@ public abstract class ItemBucket extends ItemFood implements IItemContainer {
     private boolean canActivatorAccept(TileEntityActivator activator, Item item, NamespaceID targetState) {
         for (int i = 0; i < activator.getContainerSize(); i++) {
             if (activator.locked(i)) continue;
-
-            ItemStack slotStack = activator.getItem(i);
-
-            if (slotStack == null) {
-                return true;
-            }
-
-            if (slotStack.itemID == item.id && getState(slotStack).equals(targetState) && slotStack.stackSize < slotStack.getMaxStackSize()) {
-                return true;
-            }
+            ItemStack slot = activator.getItem(i);
+            if (slot == null || (slot.itemID == item.id && getState(slot).equals(targetState) && slot.stackSize < slot.getMaxStackSize())) return true;
         }
         return false;
     }
