package net.minecraft.core.cauldron; import com.mojang.serialization.Codec; import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; import java.util.Map; import java.util.function.Predicate; import net.minecraft.core.BlockPos; import net.minecraft.core.component.DataComponents; import net.minecraft.sounds.SoundEvent; import net.minecraft.sounds.SoundEvents; import net.minecraft.sounds.SoundSource; import net.minecraft.stats.Stats; import net.minecraft.tags.ItemTags; import net.minecraft.world.InteractionHand; import net.minecraft.world.ItemInteractionResult; import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.ItemUtils; import net.minecraft.world.item.Items; import net.minecraft.world.item.alchemy.PotionContents; import net.minecraft.world.item.alchemy.Potions; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.LayeredCauldronBlock; import net.minecraft.world.level.block.ShulkerBoxBlock; import net.minecraft.world.level.block.entity.BannerPatternLayers; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.gameevent.GameEvent; public interface CauldronInteraction { Map INTERACTIONS = new Object2ObjectArrayMap<>(); Codec CODEC = Codec.stringResolver(CauldronInteraction.InteractionMap::name, INTERACTIONS::get); CauldronInteraction.InteractionMap EMPTY = newInteractionMap("empty"); CauldronInteraction.InteractionMap WATER = newInteractionMap("water"); CauldronInteraction.InteractionMap LAVA = newInteractionMap("lava"); CauldronInteraction.InteractionMap POWDER_SNOW = newInteractionMap("powder_snow"); CauldronInteraction FILL_WATER = (blockState, level, blockPos, player, interactionHand, itemStack) -> emptyBucket( level, blockPos, player, interactionHand, itemStack, Blocks.WATER_CAULDRON.defaultBlockState().setValue(LayeredCauldronBlock.LEVEL, 3), SoundEvents.BUCKET_EMPTY ); CauldronInteraction FILL_LAVA = (blockState, level, blockPos, player, interactionHand, itemStack) -> emptyBucket( level, blockPos, player, interactionHand, itemStack, Blocks.LAVA_CAULDRON.defaultBlockState(), SoundEvents.BUCKET_EMPTY_LAVA ); CauldronInteraction FILL_POWDER_SNOW = (blockState, level, blockPos, player, interactionHand, itemStack) -> emptyBucket( level, blockPos, player, interactionHand, itemStack, Blocks.POWDER_SNOW_CAULDRON.defaultBlockState().setValue(LayeredCauldronBlock.LEVEL, 3), SoundEvents.BUCKET_EMPTY_POWDER_SNOW ); CauldronInteraction SHULKER_BOX = (blockState, level, blockPos, player, interactionHand, itemStack) -> { Block block = Block.byItem(itemStack.getItem()); if (!(block instanceof ShulkerBoxBlock)) { return ItemInteractionResult.PASS_TO_DEFAULT_BLOCK_INTERACTION; } else { if (!level.isClientSide) { ItemStack itemStack2 = itemStack.transmuteCopy(Blocks.SHULKER_BOX, 1); player.setItemInHand(interactionHand, ItemUtils.createFilledResult(itemStack, player, itemStack2, false)); player.awardStat(Stats.CLEAN_SHULKER_BOX); LayeredCauldronBlock.lowerFillLevel(blockState, level, blockPos); } return ItemInteractionResult.sidedSuccess(level.isClientSide); } }; CauldronInteraction BANNER = (blockState, level, blockPos, player, interactionHand, itemStack) -> { BannerPatternLayers bannerPatternLayers = itemStack.getOrDefault(DataComponents.BANNER_PATTERNS, BannerPatternLayers.EMPTY); if (bannerPatternLayers.layers().isEmpty()) { return ItemInteractionResult.PASS_TO_DEFAULT_BLOCK_INTERACTION; } else { if (!level.isClientSide) { ItemStack itemStack2 = itemStack.copyWithCount(1); itemStack2.set(DataComponents.BANNER_PATTERNS, bannerPatternLayers.removeLast()); player.setItemInHand(interactionHand, ItemUtils.createFilledResult(itemStack, player, itemStack2, false)); player.awardStat(Stats.CLEAN_BANNER); LayeredCauldronBlock.lowerFillLevel(blockState, level, blockPos); } return ItemInteractionResult.sidedSuccess(level.isClientSide); } }; CauldronInteraction DYED_ITEM = (blockState, level, blockPos, player, interactionHand, itemStack) -> { if (!itemStack.is(ItemTags.DYEABLE)) { return ItemInteractionResult.PASS_TO_DEFAULT_BLOCK_INTERACTION; } else if (!itemStack.has(DataComponents.DYED_COLOR)) { return ItemInteractionResult.PASS_TO_DEFAULT_BLOCK_INTERACTION; } else { if (!level.isClientSide) { itemStack.remove(DataComponents.DYED_COLOR); player.awardStat(Stats.CLEAN_ARMOR); LayeredCauldronBlock.lowerFillLevel(blockState, level, blockPos); } return ItemInteractionResult.sidedSuccess(level.isClientSide); } }; static CauldronInteraction.InteractionMap newInteractionMap(String name) { Object2ObjectOpenHashMap object2ObjectOpenHashMap = new Object2ObjectOpenHashMap<>(); object2ObjectOpenHashMap.defaultReturnValue( (blockState, level, blockPos, player, interactionHand, itemStack) -> ItemInteractionResult.PASS_TO_DEFAULT_BLOCK_INTERACTION ); CauldronInteraction.InteractionMap interactionMap = new CauldronInteraction.InteractionMap(name, object2ObjectOpenHashMap); INTERACTIONS.put(name, interactionMap); return interactionMap; } ItemInteractionResult interact(BlockState blockState, Level level, BlockPos blockPos, Player player, InteractionHand interactionHand, ItemStack itemStack); static void bootStrap() { Map map = EMPTY.map(); addDefaultInteractions(map); map.put(Items.POTION, (CauldronInteraction)(blockState, level, blockPos, player, interactionHand, itemStack) -> { PotionContents potionContents = itemStack.get(DataComponents.POTION_CONTENTS); if (potionContents != null && potionContents.is(Potions.WATER)) { if (!level.isClientSide) { Item item = itemStack.getItem(); player.setItemInHand(interactionHand, ItemUtils.createFilledResult(itemStack, player, new ItemStack(Items.GLASS_BOTTLE))); player.awardStat(Stats.USE_CAULDRON); player.awardStat(Stats.ITEM_USED.get(item)); level.setBlockAndUpdate(blockPos, Blocks.WATER_CAULDRON.defaultBlockState()); level.playSound(null, blockPos, SoundEvents.BOTTLE_EMPTY, SoundSource.BLOCKS, 1.0F, 1.0F); level.gameEvent(null, GameEvent.FLUID_PLACE, blockPos); } return ItemInteractionResult.sidedSuccess(level.isClientSide); } else { return ItemInteractionResult.PASS_TO_DEFAULT_BLOCK_INTERACTION; } }); Map map2 = WATER.map(); addDefaultInteractions(map2); map2.put( Items.BUCKET, (CauldronInteraction)(blockState, level, blockPos, player, interactionHand, itemStack) -> fillBucket( blockState, level, blockPos, player, interactionHand, itemStack, new ItemStack(Items.WATER_BUCKET), blockStatex -> (Integer)blockStatex.getValue(LayeredCauldronBlock.LEVEL) == 3, SoundEvents.BUCKET_FILL ) ); map2.put(Items.GLASS_BOTTLE, (CauldronInteraction)(blockState, level, blockPos, player, interactionHand, itemStack) -> { if (!level.isClientSide) { Item item = itemStack.getItem(); player.setItemInHand(interactionHand, ItemUtils.createFilledResult(itemStack, player, PotionContents.createItemStack(Items.POTION, Potions.WATER))); player.awardStat(Stats.USE_CAULDRON); player.awardStat(Stats.ITEM_USED.get(item)); LayeredCauldronBlock.lowerFillLevel(blockState, level, blockPos); level.playSound(null, blockPos, SoundEvents.BOTTLE_FILL, SoundSource.BLOCKS, 1.0F, 1.0F); level.gameEvent(null, GameEvent.FLUID_PICKUP, blockPos); } return ItemInteractionResult.sidedSuccess(level.isClientSide); }); map2.put(Items.POTION, (CauldronInteraction)(blockState, level, blockPos, player, interactionHand, itemStack) -> { if ((Integer)blockState.getValue(LayeredCauldronBlock.LEVEL) == 3) { return ItemInteractionResult.PASS_TO_DEFAULT_BLOCK_INTERACTION; } else { PotionContents potionContents = itemStack.get(DataComponents.POTION_CONTENTS); if (potionContents != null && potionContents.is(Potions.WATER)) { if (!level.isClientSide) { player.setItemInHand(interactionHand, ItemUtils.createFilledResult(itemStack, player, new ItemStack(Items.GLASS_BOTTLE))); player.awardStat(Stats.USE_CAULDRON); player.awardStat(Stats.ITEM_USED.get(itemStack.getItem())); level.setBlockAndUpdate(blockPos, blockState.cycle(LayeredCauldronBlock.LEVEL)); level.playSound(null, blockPos, SoundEvents.BOTTLE_EMPTY, SoundSource.BLOCKS, 1.0F, 1.0F); level.gameEvent(null, GameEvent.FLUID_PLACE, blockPos); } return ItemInteractionResult.sidedSuccess(level.isClientSide); } else { return ItemInteractionResult.PASS_TO_DEFAULT_BLOCK_INTERACTION; } } }); map2.put(Items.LEATHER_BOOTS, DYED_ITEM); map2.put(Items.LEATHER_LEGGINGS, DYED_ITEM); map2.put(Items.LEATHER_CHESTPLATE, DYED_ITEM); map2.put(Items.LEATHER_HELMET, DYED_ITEM); map2.put(Items.LEATHER_HORSE_ARMOR, DYED_ITEM); map2.put(Items.WOLF_ARMOR, DYED_ITEM); map2.put(Items.WHITE_BANNER, BANNER); map2.put(Items.GRAY_BANNER, BANNER); map2.put(Items.BLACK_BANNER, BANNER); map2.put(Items.BLUE_BANNER, BANNER); map2.put(Items.BROWN_BANNER, BANNER); map2.put(Items.CYAN_BANNER, BANNER); map2.put(Items.GREEN_BANNER, BANNER); map2.put(Items.LIGHT_BLUE_BANNER, BANNER); map2.put(Items.LIGHT_GRAY_BANNER, BANNER); map2.put(Items.LIME_BANNER, BANNER); map2.put(Items.MAGENTA_BANNER, BANNER); map2.put(Items.ORANGE_BANNER, BANNER); map2.put(Items.PINK_BANNER, BANNER); map2.put(Items.PURPLE_BANNER, BANNER); map2.put(Items.RED_BANNER, BANNER); map2.put(Items.YELLOW_BANNER, BANNER); map2.put(Items.WHITE_SHULKER_BOX, SHULKER_BOX); map2.put(Items.GRAY_SHULKER_BOX, SHULKER_BOX); map2.put(Items.BLACK_SHULKER_BOX, SHULKER_BOX); map2.put(Items.BLUE_SHULKER_BOX, SHULKER_BOX); map2.put(Items.BROWN_SHULKER_BOX, SHULKER_BOX); map2.put(Items.CYAN_SHULKER_BOX, SHULKER_BOX); map2.put(Items.GREEN_SHULKER_BOX, SHULKER_BOX); map2.put(Items.LIGHT_BLUE_SHULKER_BOX, SHULKER_BOX); map2.put(Items.LIGHT_GRAY_SHULKER_BOX, SHULKER_BOX); map2.put(Items.LIME_SHULKER_BOX, SHULKER_BOX); map2.put(Items.MAGENTA_SHULKER_BOX, SHULKER_BOX); map2.put(Items.ORANGE_SHULKER_BOX, SHULKER_BOX); map2.put(Items.PINK_SHULKER_BOX, SHULKER_BOX); map2.put(Items.PURPLE_SHULKER_BOX, SHULKER_BOX); map2.put(Items.RED_SHULKER_BOX, SHULKER_BOX); map2.put(Items.YELLOW_SHULKER_BOX, SHULKER_BOX); Map map3 = LAVA.map(); map3.put( Items.BUCKET, (CauldronInteraction)(blockState, level, blockPos, player, interactionHand, itemStack) -> fillBucket( blockState, level, blockPos, player, interactionHand, itemStack, new ItemStack(Items.LAVA_BUCKET), blockStatex -> true, SoundEvents.BUCKET_FILL_LAVA ) ); addDefaultInteractions(map3); Map map4 = POWDER_SNOW.map(); map4.put( Items.BUCKET, (CauldronInteraction)(blockState, level, blockPos, player, interactionHand, itemStack) -> fillBucket( blockState, level, blockPos, player, interactionHand, itemStack, new ItemStack(Items.POWDER_SNOW_BUCKET), blockStatex -> (Integer)blockStatex.getValue(LayeredCauldronBlock.LEVEL) == 3, SoundEvents.BUCKET_FILL_POWDER_SNOW ) ); addDefaultInteractions(map4); } static void addDefaultInteractions(Map interactionsMap) { interactionsMap.put(Items.LAVA_BUCKET, FILL_LAVA); interactionsMap.put(Items.WATER_BUCKET, FILL_WATER); interactionsMap.put(Items.POWDER_SNOW_BUCKET, FILL_POWDER_SNOW); } static ItemInteractionResult fillBucket( BlockState state, Level level, BlockPos pos, Player player, InteractionHand hand, ItemStack emptyStack, ItemStack filledStack, Predicate statePredicate, SoundEvent fillSound ) { if (!statePredicate.test(state)) { return ItemInteractionResult.PASS_TO_DEFAULT_BLOCK_INTERACTION; } else { if (!level.isClientSide) { Item item = emptyStack.getItem(); player.setItemInHand(hand, ItemUtils.createFilledResult(emptyStack, player, filledStack)); player.awardStat(Stats.USE_CAULDRON); player.awardStat(Stats.ITEM_USED.get(item)); level.setBlockAndUpdate(pos, Blocks.CAULDRON.defaultBlockState()); level.playSound(null, pos, fillSound, SoundSource.BLOCKS, 1.0F, 1.0F); level.gameEvent(null, GameEvent.FLUID_PICKUP, pos); } return ItemInteractionResult.sidedSuccess(level.isClientSide); } } static ItemInteractionResult emptyBucket( Level level, BlockPos pos, Player player, InteractionHand hand, ItemStack filledStack, BlockState state, SoundEvent emptySound ) { if (!level.isClientSide) { Item item = filledStack.getItem(); player.setItemInHand(hand, ItemUtils.createFilledResult(filledStack, player, new ItemStack(Items.BUCKET))); player.awardStat(Stats.FILL_CAULDRON); player.awardStat(Stats.ITEM_USED.get(item)); level.setBlockAndUpdate(pos, state); level.playSound(null, pos, emptySound, SoundSource.BLOCKS, 1.0F, 1.0F); level.gameEvent(null, GameEvent.FLUID_PLACE, pos); } return ItemInteractionResult.sidedSuccess(level.isClientSide); } public record InteractionMap(String name, Map map) { } }