From 5564460d9ba20a7cd1f0b96a1933d78ec9f73be7 Mon Sep 17 00:00:00 2001 From: Jeff Shipley Date: Wed, 16 Oct 2024 23:22:09 -0600 Subject: [PATCH 1/5] Add FluidHandler to teapot --- .../simplytea/fluid/FluidTeapotWrapper.java | 99 +++++++++++++++++++ .../simplytea/item/TeapotItem.java | 93 +++++++++++------ 2 files changed, 160 insertions(+), 32 deletions(-) create mode 100644 src/main/java/knightminer/simplytea/fluid/FluidTeapotWrapper.java diff --git a/src/main/java/knightminer/simplytea/fluid/FluidTeapotWrapper.java b/src/main/java/knightminer/simplytea/fluid/FluidTeapotWrapper.java new file mode 100644 index 0000000..d75f17a --- /dev/null +++ b/src/main/java/knightminer/simplytea/fluid/FluidTeapotWrapper.java @@ -0,0 +1,99 @@ +package knightminer.simplytea.fluid; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import knightminer.simplytea.core.Registration; +import net.minecraft.core.Direction; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.Items; +import net.minecraft.world.level.material.Fluid; +import net.minecraft.world.level.material.Fluids; +import net.minecraftforge.common.Tags; +import net.minecraftforge.common.capabilities.Capability; +import net.minecraftforge.common.capabilities.ForgeCapabilities; +import net.minecraftforge.common.capabilities.ICapabilityProvider; +import net.minecraftforge.common.util.LazyOptional; +import net.minecraftforge.fluids.FluidStack; +import static net.minecraftforge.fluids.FluidType.BUCKET_VOLUME; +import net.minecraftforge.fluids.capability.IFluidHandlerItem; + +public class FluidTeapotWrapper implements IFluidHandlerItem, ICapabilityProvider { + private final LazyOptional holder = LazyOptional.of(() -> this); + + @NotNull + protected ItemStack container; + protected FluidStack fluid = FluidStack.EMPTY; + + public FluidTeapotWrapper(ItemStack container) { + this.container = container; + } + + @Override + public int getTanks() { + return 1; + } + + @Override + public @NotNull FluidStack getFluidInTank(int tank) { + return FluidStack.EMPTY; + } + + @Override + public int getTankCapacity(int tank) { + return BUCKET_VOLUME; + } + + public static boolean isWater(Fluid fluid) { + // Many modded fluids use the WATER tag to give the fluids entity interaction + // Only accept Fluids.WATER and not any other fluid tagged as WATER + return fluid.isSame(Fluids.WATER); + } + + public static boolean isMilk(Fluid fluid) { + // Be more flexible with MILK because if it's tagged as MILK then it should really be milk + return fluid.is(Tags.Fluids.MILK) || fluid.getBucket() == Items.MILK_BUCKET; + } + + @Override + public boolean isFluidValid(int tank, @NotNull FluidStack fluid) { + return isWater(fluid.getFluid()) || isMilk(fluid.getFluid()); + } + + @Override + public int fill(FluidStack resource, FluidAction action) { + if (container.getCount() != 1 || !isFluidValid(0, resource) || resource.getAmount() < BUCKET_VOLUME) { + return 0; + } + + if (action.execute()) { + if (isWater(resource.getFluid())) { + this.container = new ItemStack(Registration.teapot_water); + } else if (isMilk(resource.getFluid())) { + this.container = new ItemStack(Registration.teapot_milk); + } + } + + return BUCKET_VOLUME; + } + + @Override + public @NotNull FluidStack drain(FluidStack resource, FluidAction action) { + return FluidStack.EMPTY; + } + + @Override + public @NotNull FluidStack drain(int maxDrain, FluidAction action) { + return FluidStack.EMPTY; + } + + @Override + public @NotNull ItemStack getContainer() { + return container; + } + + @Override + public @NotNull LazyOptional getCapability(@NotNull Capability capability, @Nullable Direction side) { + return ForgeCapabilities.FLUID_HANDLER_ITEM.orEmpty(capability, holder); + } +} diff --git a/src/main/java/knightminer/simplytea/item/TeapotItem.java b/src/main/java/knightminer/simplytea/item/TeapotItem.java index fecfb36..69659fb 100644 --- a/src/main/java/knightminer/simplytea/item/TeapotItem.java +++ b/src/main/java/knightminer/simplytea/item/TeapotItem.java @@ -1,28 +1,36 @@ package knightminer.simplytea.item; +import org.jetbrains.annotations.Nullable; + import knightminer.simplytea.core.Config; import knightminer.simplytea.core.Registration; +import knightminer.simplytea.fluid.FluidTeapotWrapper; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.sounds.SoundEvent; import net.minecraft.sounds.SoundEvents; -import net.minecraft.tags.FluidTags; import net.minecraft.world.InteractionHand; import net.minecraft.world.InteractionResult; import net.minecraft.world.InteractionResultHolder; import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.entity.animal.Cow; 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.level.ClipContext; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.BucketPickup; import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.material.Fluid; -import net.minecraft.world.level.material.Fluids; import net.minecraft.world.phys.BlockHitResult; import net.minecraft.world.phys.HitResult.Type; +import net.minecraftforge.common.capabilities.ICapabilityProvider; +import net.minecraftforge.fluids.FluidActionResult; +import net.minecraftforge.fluids.FluidType; +import net.minecraftforge.fluids.FluidUtil; +import net.minecraftforge.fluids.capability.IFluidHandler; + +import java.util.Optional; public class TeapotItem extends TooltipItem { public TeapotItem(Properties props) { @@ -33,40 +41,55 @@ public TeapotItem(Properties props) { public InteractionResultHolder use(Level world, Player player, InteractionHand hand) { ItemStack stack = player.getItemInHand(hand); BlockHitResult rayTrace = getPlayerPOVHitResult(world, player, ClipContext.Fluid.SOURCE_ONLY); - if (rayTrace.getType() == Type.BLOCK) { - BlockPos pos = rayTrace.getBlockPos(); - BlockState state = world.getBlockState(pos); - - // we use name for lookup to prevent default fluid conflicts - Fluid fluid = state.getFluidState().getType(); - if(fluid != Fluids.EMPTY) { - // try for water or milk using the config lists - Item item = null; - if (fluid.is(FluidTags.WATER)) { - item = Registration.teapot_water; - } // TODO: milk when mods make a standard + if (rayTrace.getType() != Type.BLOCK) { + return InteractionResultHolder.pass(stack); + } + + BlockPos pos = rayTrace.getBlockPos(); + Direction side = rayTrace.getDirection(); + BlockState state = world.getBlockState(pos); - // if either one is found, update the stack - if(item != null) { - // water is considered infinite unless disabled in the config - if(!Config.SERVER.teapot.infiniteWater()) { - Direction side = rayTrace.getDirection(); - // unable to modify the block, fail - if (!world.mayInteract(player, pos) || !player.mayUseItemAt(pos.relative(side), side, stack) || !(state.getBlock() instanceof BucketPickup)) { - return new InteractionResultHolder<>(InteractionResult.FAIL, stack); - } - ((BucketPickup)state.getBlock()).pickupBlock(world, pos, state); - } + if (!world.mayInteract(player, pos) || !player.mayUseItemAt(pos.relative(side), side, stack)) { + return InteractionResultHolder.fail(stack); + } - stack = ItemUtils.createFilledResult(stack, player, new ItemStack(item)); + ItemStack filledStack = ItemStack.EMPTY; + if (state.getBlock() instanceof BucketPickup bucketPickup) { + // special case for infinite water + if (FluidTeapotWrapper.isWater(state.getFluidState().getType()) && !Config.SERVER.teapot.infiniteWater()) { + filledStack = new ItemStack(Registration.teapot_water); + Optional sound = bucketPickup.getPickupSound(state); + if (sound.isPresent()) { + player.playSound(sound.get(), 1.0f, 1.0f); + } + } + + // should work in most cases + if (filledStack.isEmpty()) { + FluidActionResult actionResult = FluidUtil.tryPickUpFluid(stack, player, world, pos, side); + if (actionResult.isSuccess()) { + filledStack = actionResult.getResult(); + } + } + } - // TODO: fluid sound based on fluid - player.playSound(SoundEvents.BUCKET_FILL, 1.0f, 1.0f); - return new InteractionResultHolder<>(InteractionResult.SUCCESS, stack); + // if pickup block doesn't work, try accessing the fluid handler + if (filledStack.isEmpty()) { + Optional fluidSource = FluidUtil.getFluidHandler(world, pos, side).resolve(); + if (fluidSource.isPresent()) { + FluidActionResult actionResult = FluidUtil.tryFillContainer(stack, fluidSource.get(), FluidType.BUCKET_VOLUME, player, true); + if (actionResult.isSuccess()) { + filledStack = actionResult.getResult(); } } } - return new InteractionResultHolder<>(InteractionResult.FAIL, stack); + + if (!filledStack.isEmpty()) { + ItemStack filledResult = ItemUtils.createFilledResult(stack, player, filledStack); + return InteractionResultHolder.sidedSuccess(filledResult, world.isClientSide()); + } + + return InteractionResultHolder.fail(stack); } @Override @@ -82,4 +105,10 @@ public InteractionResult interactLivingEntity(ItemStack stack, Player player, Li } return InteractionResult.PASS; } + + @Nullable + @Override + public ICapabilityProvider initCapabilities(ItemStack stack, @Nullable CompoundTag nbt) { + return new FluidTeapotWrapper(stack); + } } \ No newline at end of file From 9b3f2848d7874a054ba4bd2eed1e75c56bdae7d2 Mon Sep 17 00:00:00 2001 From: Jeff Shipley Date: Tue, 15 Oct 2024 14:19:56 -0600 Subject: [PATCH 2/5] Allow teapots to be filled from fluid containers, and allow milk pickup. Close #46 --- .../simplytea/core/config/Teapot.java | 9 ++ .../simplytea/item/TeapotItem.java | 119 +++++++++++++----- 2 files changed, 100 insertions(+), 28 deletions(-) diff --git a/src/main/java/knightminer/simplytea/core/config/Teapot.java b/src/main/java/knightminer/simplytea/core/config/Teapot.java index 8420934..0db9af7 100644 --- a/src/main/java/knightminer/simplytea/core/config/Teapot.java +++ b/src/main/java/knightminer/simplytea/core/config/Teapot.java @@ -6,6 +6,7 @@ public class Teapot { private BooleanValue infinite_water; private BooleanValue fill_from_cauldron; + private BooleanValue fill_from_fluid_tank; private BooleanValue milk_cow; public Teapot(ForgeConfigSpec.Builder builder) { builder.comment("Options related to filling the teapot").push("teapot"); @@ -15,6 +16,9 @@ public Teapot(ForgeConfigSpec.Builder builder) { fill_from_cauldron = builder.comment("If true, the teapot can be filled with water from a cauldron") .translation("simplytea.config.teapot.fill_from_cauldron") .define("fill_from_cauldron", true); + fill_from_fluid_tank = builder.comment("If true, the teapot can be filled with water from a fluid tank") + .translation("simplytea.config.teapot.fill_from_fluid_tank") + .define("fill_from_fluid_tank", true); milk_cow = builder.comment("If true, cows can be milked using a teapot to fill it with milk") .translation("simplytea.config.teapot.milk_cow") .define("milk_cow", true); @@ -31,6 +35,11 @@ public boolean fillFromCauldron() { return fill_from_cauldron.get(); } + /** True if teapots can be filled from a fluid tank */ + public boolean fillFromFluidTank() { + return fill_from_fluid_tank.get(); + } + /** True if teapots can be used to milk cows */ public boolean canMilkCows() { return milk_cow.get(); diff --git a/src/main/java/knightminer/simplytea/item/TeapotItem.java b/src/main/java/knightminer/simplytea/item/TeapotItem.java index fecfb36..808035a 100644 --- a/src/main/java/knightminer/simplytea/item/TeapotItem.java +++ b/src/main/java/knightminer/simplytea/item/TeapotItem.java @@ -4,69 +4,132 @@ import knightminer.simplytea.core.Registration; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; +import net.minecraft.sounds.SoundEvent; import net.minecraft.sounds.SoundEvents; -import net.minecraft.tags.FluidTags; import net.minecraft.world.InteractionHand; import net.minecraft.world.InteractionResult; -import net.minecraft.world.InteractionResultHolder; import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.entity.animal.Cow; 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.context.UseOnContext; import net.minecraft.world.level.ClipContext; import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.AbstractCauldronBlock; +import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.BucketPickup; +import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.material.Fluid; +import net.minecraft.world.level.material.FluidState; import net.minecraft.world.level.material.Fluids; import net.minecraft.world.phys.BlockHitResult; import net.minecraft.world.phys.HitResult.Type; +import net.minecraftforge.common.Tags; +import net.minecraftforge.common.capabilities.ForgeCapabilities; +import net.minecraftforge.fluids.FluidActionResult; +import net.minecraftforge.fluids.FluidStack; +import net.minecraftforge.fluids.FluidType; +import net.minecraftforge.fluids.FluidUtil; +import net.minecraftforge.fluids.capability.IFluidHandler; + +import java.util.Optional; public class TeapotItem extends TooltipItem { + public TeapotItem(Properties props) { super(props); } + // using onItemUseFirst() instead of use() because many fluid tanks will consume the interaction before it gets to use() @Override - public InteractionResultHolder use(Level world, Player player, InteractionHand hand) { - ItemStack stack = player.getItemInHand(hand); + public InteractionResult onItemUseFirst(ItemStack stack, UseOnContext context) + { + Level world = context.getLevel(); + if (world.isClientSide) { + return InteractionResult.PASS; + } + + Player player = context.getPlayer(); + // Even though the context already has a blockhitresult, it does not include fluid blocks BlockHitResult rayTrace = getPlayerPOVHitResult(world, player, ClipContext.Fluid.SOURCE_ONLY); if (rayTrace.getType() == Type.BLOCK) { BlockPos pos = rayTrace.getBlockPos(); BlockState state = world.getBlockState(pos); + Block block = state.getBlock(); + Direction side = rayTrace.getDirection(); + + // unable to modify the block + if (!world.mayInteract(player, pos) || !player.mayUseItemAt(pos.relative(side), side, stack)) { + return InteractionResult.PASS; + } + + // cauldron disabled in config + if (block instanceof AbstractCauldronBlock && !Config.SERVER.teapot.fillFromCauldron()) { + return InteractionResult.PASS; + } + + Optional filledItem = Optional.empty(); + Optional pickupSound = Optional.empty(); + FluidState fluidState = state.getFluidState(); + + if (fluidState.isSource()) { + Fluid fluid = fluidState.getType(); + // comparing with WATER fluid instead of WATER fluid tag, because many/most modded fluids are tagged as WATER + // to get water-like interactions even if the fluid is not water + if (fluid.isSame(Fluids.WATER)) { + filledItem = Optional.of(Registration.teapot_water); + pickupSound = ((BucketPickup)block).getPickupSound(state); + if (!Config.SERVER.teapot.infiniteWater()) { + ((BucketPickup)block).pickupBlock(world, pos, state); + } + } else if (fluid.is(Tags.Fluids.MILK)) { + filledItem = Optional.of(Registration.teapot_milk); + pickupSound = ((BucketPickup)block).getPickupSound(state); + ((BucketPickup)block).pickupBlock(world, pos, state); + } + } else if (Config.SERVER.teapot.fillFromFluidTank()) { + BlockEntity entity = world.getBlockEntity(pos); + Optional fluidHandler = Optional.empty(); + if (entity != null) { + fluidHandler = entity.getCapability(ForgeCapabilities.FLUID_HANDLER, side).resolve(); + } + if (fluidHandler.isPresent()) { + FluidActionResult fillResult = FluidUtil.tryFillContainer(new ItemStack(Items.BUCKET), fluidHandler.get(), FluidType.BUCKET_VOLUME, player, false); + FluidStack fluidStack = fillResult.success ? FluidUtil.getFluidContained(fillResult.getResult()).orElseGet(() -> FluidStack.EMPTY) : FluidStack.EMPTY; + + if (fluidStack.isEmpty() || fluidStack.getAmount() != FluidType.BUCKET_VOLUME) { + return InteractionResult.PASS; + } + + // comparing with WATER fluid instead of WATER fluid tag, because many/most modded fluids are tagged as WATER + // to get water-like interactions even if the fluid is not water + if (fluidStack.getFluid().isSame(Fluids.WATER)) { + filledItem = Optional.of(Registration.teapot_water); + } else if (fluidStack.getFluid().is(Tags.Fluids.MILK)) { + filledItem = Optional.of(Registration.teapot_milk); + } - // we use name for lookup to prevent default fluid conflicts - Fluid fluid = state.getFluidState().getType(); - if(fluid != Fluids.EMPTY) { - // try for water or milk using the config lists - Item item = null; - if (fluid.is(FluidTags.WATER)) { - item = Registration.teapot_water; - } // TODO: milk when mods make a standard - - // if either one is found, update the stack - if(item != null) { - // water is considered infinite unless disabled in the config - if(!Config.SERVER.teapot.infiniteWater()) { - Direction side = rayTrace.getDirection(); - // unable to modify the block, fail - if (!world.mayInteract(player, pos) || !player.mayUseItemAt(pos.relative(side), side, stack) || !(state.getBlock() instanceof BucketPickup)) { - return new InteractionResultHolder<>(InteractionResult.FAIL, stack); - } - ((BucketPickup)state.getBlock()).pickupBlock(world, pos, state); + if (filledItem.isPresent()) { + FluidUtil.tryFillContainer(new ItemStack(Items.BUCKET), fluidHandler.get(), FluidType.BUCKET_VOLUME, player, true); } - stack = ItemUtils.createFilledResult(stack, player, new ItemStack(item)); + } + } - // TODO: fluid sound based on fluid - player.playSound(SoundEvents.BUCKET_FILL, 1.0f, 1.0f); - return new InteractionResultHolder<>(InteractionResult.SUCCESS, stack); + if (filledItem.isPresent()) { + if (pickupSound.isPresent()) { + player.playSound(pickupSound.get(), 1.0f, 1.0f); } + player.setItemInHand(context.getHand(), ItemUtils.createFilledResult(stack.copy(), player, new ItemStack(filledItem.get()))); + return InteractionResult.SUCCESS; } } - return new InteractionResultHolder<>(InteractionResult.FAIL, stack); + + return InteractionResult.PASS; } @Override From e642204a819c300582d3465b876e99b10753bfbf Mon Sep 17 00:00:00 2001 From: Jeff Shipley Date: Thu, 17 Oct 2024 00:39:57 -0600 Subject: [PATCH 3/5] Added configurable teapot capacity --- .../simplytea/core/Registration.java | 23 +++++++++++++++++-- .../simplytea/core/config/Teapot.java | 14 ++++++++--- .../simplytea/fluid/FluidTeapotWrapper.java | 8 +++---- .../simplytea/item/TeapotItem.java | 3 +-- 4 files changed, 37 insertions(+), 11 deletions(-) diff --git a/src/main/java/knightminer/simplytea/core/Registration.java b/src/main/java/knightminer/simplytea/core/Registration.java index 6963485..959a33e 100644 --- a/src/main/java/knightminer/simplytea/core/Registration.java +++ b/src/main/java/knightminer/simplytea/core/Registration.java @@ -35,13 +35,18 @@ import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceLocation; import net.minecraft.sounds.SoundEvents; +import net.minecraft.sounds.SoundSource; +import net.minecraft.stats.Stats; import net.minecraft.world.InteractionResult; import net.minecraft.world.effect.MobEffect; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.BlockItem; import net.minecraft.world.item.CreativeModeTab; import net.minecraft.world.item.CreativeModeTabs; import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.ItemUtils; import net.minecraft.world.item.crafting.RecipeSerializer; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Blocks; @@ -53,8 +58,10 @@ import net.minecraft.world.level.block.LayeredCauldronBlock; import net.minecraft.world.level.block.SaplingBlock; import net.minecraft.world.level.block.SoundType; +import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.properties.NoteBlockInstrument; import net.minecraft.world.level.block.state.properties.WoodType; +import net.minecraft.world.level.gameevent.GameEvent; import net.minecraft.world.level.levelgen.feature.ConfiguredFeature; import net.minecraft.world.level.levelgen.feature.Feature; import net.minecraft.world.level.levelgen.feature.configurations.NoneFeatureConfiguration; @@ -265,9 +272,21 @@ static void registerMisc(final FMLCommonSetupEvent event) { RestfulEffect.addConflict(caffeinated); RestfulEffect.addConflict(invigorated); + // Lowers the cauldron by a variable amound depending on configured teapot size + // Based on GLASS_BOTTLE interaction and LayeredCauldronBlock.lowerFillLevel() CauldronInteraction.WATER.put(teapot, (state, level, pos, player, hand, stack) -> { - if (Config.SERVER.teapot.fillFromCauldron()) { - return CauldronInteraction.fillBucket(state, level, pos, player, hand, stack, new ItemStack(teapot_water), s -> s.getValue(LayeredCauldronBlock.LEVEL) == 3, SoundEvents.BUCKET_FILL); + // always consume at least one cauldron level, even for tiny teapots + int teapotLevels = Math.max(1, Math.round(Config.SERVER.teapot.teapotCapacity() / 333.0f)); + if (Config.SERVER.teapot.fillFromCauldron() && state.getValue(LayeredCauldronBlock.LEVEL) >= teapotLevels && !level.isClientSide()) { + player.setItemInHand(hand, ItemUtils.createFilledResult(stack, player, new ItemStack(teapot_water))); + player.awardStat(Stats.USE_CAULDRON); + player.awardStat(Stats.ITEM_USED.get(teapot_water)); + int cauldronLevel = state.getValue(LayeredCauldronBlock.LEVEL) - teapotLevels; + BlockState cauldronstate = cauldronLevel == 0 ? Blocks.CAULDRON.defaultBlockState() : state.setValue(LayeredCauldronBlock.LEVEL, Integer.valueOf(cauldronLevel)); + level.setBlockAndUpdate(pos, cauldronstate); + level.gameEvent(GameEvent.BLOCK_CHANGE, pos, GameEvent.Context.of(cauldronstate)); + level.playSound((Player)null, pos, SoundEvents.BUCKET_FILL, SoundSource.BLOCKS, 1.0F, 1.0F); + level.gameEvent((Entity)null, GameEvent.FLUID_PICKUP, pos); } return InteractionResult.PASS; }); diff --git a/src/main/java/knightminer/simplytea/core/config/Teapot.java b/src/main/java/knightminer/simplytea/core/config/Teapot.java index 0db9af7..6ff217d 100644 --- a/src/main/java/knightminer/simplytea/core/config/Teapot.java +++ b/src/main/java/knightminer/simplytea/core/config/Teapot.java @@ -2,12 +2,15 @@ import net.minecraftforge.common.ForgeConfigSpec; import net.minecraftforge.common.ForgeConfigSpec.BooleanValue; +import net.minecraftforge.common.ForgeConfigSpec.IntValue; +import net.minecraftforge.fluids.FluidType; public class Teapot { private BooleanValue infinite_water; private BooleanValue fill_from_cauldron; private BooleanValue fill_from_fluid_tank; private BooleanValue milk_cow; + private IntValue teapot_capacity; public Teapot(ForgeConfigSpec.Builder builder) { builder.comment("Options related to filling the teapot").push("teapot"); infinite_water = builder.comment("If true, the teapot will not consume water source blocks when filling. It will still consume water from tank and cauldrons.") @@ -16,12 +19,12 @@ public Teapot(ForgeConfigSpec.Builder builder) { fill_from_cauldron = builder.comment("If true, the teapot can be filled with water from a cauldron") .translation("simplytea.config.teapot.fill_from_cauldron") .define("fill_from_cauldron", true); - fill_from_fluid_tank = builder.comment("If true, the teapot can be filled with water from a fluid tank") - .translation("simplytea.config.teapot.fill_from_fluid_tank") - .define("fill_from_fluid_tank", true); milk_cow = builder.comment("If true, cows can be milked using a teapot to fill it with milk") .translation("simplytea.config.teapot.milk_cow") .define("milk_cow", true); + teapot_capacity = builder.comment("Amount of fluid a teapot can contain") + .translation("simplytea.config.teapot.teapot_capacity") + .defineInRange("teapot_capacity", FluidType.BUCKET_VOLUME, 1, FluidType.BUCKET_VOLUME * 256); builder.pop(); } @@ -44,4 +47,9 @@ public boolean fillFromFluidTank() { public boolean canMilkCows() { return milk_cow.get(); } + + /** Amount of fluid a teapot can contain */ + public int teapotCapacity() { + return teapot_capacity.get(); + } } diff --git a/src/main/java/knightminer/simplytea/fluid/FluidTeapotWrapper.java b/src/main/java/knightminer/simplytea/fluid/FluidTeapotWrapper.java index d75f17a..ac3dc66 100644 --- a/src/main/java/knightminer/simplytea/fluid/FluidTeapotWrapper.java +++ b/src/main/java/knightminer/simplytea/fluid/FluidTeapotWrapper.java @@ -3,6 +3,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import knightminer.simplytea.core.Config; import knightminer.simplytea.core.Registration; import net.minecraft.core.Direction; import net.minecraft.world.item.ItemStack; @@ -15,7 +16,6 @@ import net.minecraftforge.common.capabilities.ICapabilityProvider; import net.minecraftforge.common.util.LazyOptional; import net.minecraftforge.fluids.FluidStack; -import static net.minecraftforge.fluids.FluidType.BUCKET_VOLUME; import net.minecraftforge.fluids.capability.IFluidHandlerItem; public class FluidTeapotWrapper implements IFluidHandlerItem, ICapabilityProvider { @@ -41,7 +41,7 @@ public int getTanks() { @Override public int getTankCapacity(int tank) { - return BUCKET_VOLUME; + return Config.SERVER.teapot.teapotCapacity(); } public static boolean isWater(Fluid fluid) { @@ -62,7 +62,7 @@ public boolean isFluidValid(int tank, @NotNull FluidStack fluid) { @Override public int fill(FluidStack resource, FluidAction action) { - if (container.getCount() != 1 || !isFluidValid(0, resource) || resource.getAmount() < BUCKET_VOLUME) { + if (container.getCount() != 1 || !isFluidValid(0, resource) || resource.getAmount() < Config.SERVER.teapot.teapotCapacity()) { return 0; } @@ -74,7 +74,7 @@ public int fill(FluidStack resource, FluidAction action) { } } - return BUCKET_VOLUME; + return Config.SERVER.teapot.teapotCapacity(); } @Override diff --git a/src/main/java/knightminer/simplytea/item/TeapotItem.java b/src/main/java/knightminer/simplytea/item/TeapotItem.java index 69659fb..2e0434b 100644 --- a/src/main/java/knightminer/simplytea/item/TeapotItem.java +++ b/src/main/java/knightminer/simplytea/item/TeapotItem.java @@ -26,7 +26,6 @@ import net.minecraft.world.phys.HitResult.Type; import net.minecraftforge.common.capabilities.ICapabilityProvider; import net.minecraftforge.fluids.FluidActionResult; -import net.minecraftforge.fluids.FluidType; import net.minecraftforge.fluids.FluidUtil; import net.minecraftforge.fluids.capability.IFluidHandler; @@ -77,7 +76,7 @@ public InteractionResultHolder use(Level world, Player player, Intera if (filledStack.isEmpty()) { Optional fluidSource = FluidUtil.getFluidHandler(world, pos, side).resolve(); if (fluidSource.isPresent()) { - FluidActionResult actionResult = FluidUtil.tryFillContainer(stack, fluidSource.get(), FluidType.BUCKET_VOLUME, player, true); + FluidActionResult actionResult = FluidUtil.tryFillContainer(stack, fluidSource.get(), Config.SERVER.teapot.teapotCapacity(), player, true); if (actionResult.isSuccess()) { filledStack = actionResult.getResult(); } From c605e79dbc121edc0b6637f4631e9a6d079c4417 Mon Sep 17 00:00:00 2001 From: Jeff Shipley Date: Fri, 18 Oct 2024 12:08:43 -0600 Subject: [PATCH 4/5] Small cleanup changes for PR --- .../knightminer/simplytea/core/config/Teapot.java | 8 +------- .../simplytea/fluid/FluidTeapotWrapper.java | 2 +- .../java/knightminer/simplytea/item/TeapotItem.java | 13 +------------ 3 files changed, 3 insertions(+), 20 deletions(-) diff --git a/src/main/java/knightminer/simplytea/core/config/Teapot.java b/src/main/java/knightminer/simplytea/core/config/Teapot.java index 6ff217d..11b7244 100644 --- a/src/main/java/knightminer/simplytea/core/config/Teapot.java +++ b/src/main/java/knightminer/simplytea/core/config/Teapot.java @@ -8,7 +8,6 @@ public class Teapot { private BooleanValue infinite_water; private BooleanValue fill_from_cauldron; - private BooleanValue fill_from_fluid_tank; private BooleanValue milk_cow; private IntValue teapot_capacity; public Teapot(ForgeConfigSpec.Builder builder) { @@ -22,7 +21,7 @@ public Teapot(ForgeConfigSpec.Builder builder) { milk_cow = builder.comment("If true, cows can be milked using a teapot to fill it with milk") .translation("simplytea.config.teapot.milk_cow") .define("milk_cow", true); - teapot_capacity = builder.comment("Amount of fluid a teapot can contain") + teapot_capacity = builder.comment("Amount of fluid consumed when filling a teapot from a tank") .translation("simplytea.config.teapot.teapot_capacity") .defineInRange("teapot_capacity", FluidType.BUCKET_VOLUME, 1, FluidType.BUCKET_VOLUME * 256); builder.pop(); @@ -38,11 +37,6 @@ public boolean fillFromCauldron() { return fill_from_cauldron.get(); } - /** True if teapots can be filled from a fluid tank */ - public boolean fillFromFluidTank() { - return fill_from_fluid_tank.get(); - } - /** True if teapots can be used to milk cows */ public boolean canMilkCows() { return milk_cow.get(); diff --git a/src/main/java/knightminer/simplytea/fluid/FluidTeapotWrapper.java b/src/main/java/knightminer/simplytea/fluid/FluidTeapotWrapper.java index ac3dc66..bd32bd0 100644 --- a/src/main/java/knightminer/simplytea/fluid/FluidTeapotWrapper.java +++ b/src/main/java/knightminer/simplytea/fluid/FluidTeapotWrapper.java @@ -47,7 +47,7 @@ public int getTankCapacity(int tank) { public static boolean isWater(Fluid fluid) { // Many modded fluids use the WATER tag to give the fluids entity interaction // Only accept Fluids.WATER and not any other fluid tagged as WATER - return fluid.isSame(Fluids.WATER); + return fluid.isSame(Fluids.WATER) || fluid.isSame(Fluids.FLOWING_WATER); } public static boolean isMilk(Fluid fluid) { diff --git a/src/main/java/knightminer/simplytea/item/TeapotItem.java b/src/main/java/knightminer/simplytea/item/TeapotItem.java index 2e0434b..b65b557 100644 --- a/src/main/java/knightminer/simplytea/item/TeapotItem.java +++ b/src/main/java/knightminer/simplytea/item/TeapotItem.java @@ -63,7 +63,7 @@ public InteractionResultHolder use(Level world, Player player, Intera } } - // should work in most cases + // use teapot like a bucket to get fluid, should work in most cases if (filledStack.isEmpty()) { FluidActionResult actionResult = FluidUtil.tryPickUpFluid(stack, player, world, pos, side); if (actionResult.isSuccess()) { @@ -72,17 +72,6 @@ public InteractionResultHolder use(Level world, Player player, Intera } } - // if pickup block doesn't work, try accessing the fluid handler - if (filledStack.isEmpty()) { - Optional fluidSource = FluidUtil.getFluidHandler(world, pos, side).resolve(); - if (fluidSource.isPresent()) { - FluidActionResult actionResult = FluidUtil.tryFillContainer(stack, fluidSource.get(), Config.SERVER.teapot.teapotCapacity(), player, true); - if (actionResult.isSuccess()) { - filledStack = actionResult.getResult(); - } - } - } - if (!filledStack.isEmpty()) { ItemStack filledResult = ItemUtils.createFilledResult(stack, player, filledStack); return InteractionResultHolder.sidedSuccess(filledResult, world.isClientSide()); From e77cbe376192f596e85da043b7d43c959d9b835d Mon Sep 17 00:00:00 2001 From: jshipley Date: Wed, 30 Oct 2024 19:05:31 -0600 Subject: [PATCH 5/5] Treat water as infinite when infiniteWater config option is set instead of when it's not set --- src/main/java/knightminer/simplytea/item/TeapotItem.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/knightminer/simplytea/item/TeapotItem.java b/src/main/java/knightminer/simplytea/item/TeapotItem.java index b65b557..c87cf86 100644 --- a/src/main/java/knightminer/simplytea/item/TeapotItem.java +++ b/src/main/java/knightminer/simplytea/item/TeapotItem.java @@ -55,7 +55,7 @@ public InteractionResultHolder use(Level world, Player player, Intera ItemStack filledStack = ItemStack.EMPTY; if (state.getBlock() instanceof BucketPickup bucketPickup) { // special case for infinite water - if (FluidTeapotWrapper.isWater(state.getFluidState().getType()) && !Config.SERVER.teapot.infiniteWater()) { + if (FluidTeapotWrapper.isWater(state.getFluidState().getType()) && Config.SERVER.teapot.infiniteWater()) { filledStack = new ItemStack(Registration.teapot_water); Optional sound = bucketPickup.getPickupSound(state); if (sound.isPresent()) { @@ -99,4 +99,4 @@ public InteractionResult interactLivingEntity(ItemStack stack, Player player, Li public ICapabilityProvider initCapabilities(ItemStack stack, @Nullable CompoundTag nbt) { return new FluidTeapotWrapper(stack); } -} \ No newline at end of file +}