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> pickupTag, + boolean canPlace, + @Nullable String soundPath, + @Nullable BiConsumer 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> 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> pickupTag, String soundPath, BiConsumer 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> 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 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; }