From 07f98760289c789c9df2c51c5b82bfbe16a0b7d1 Mon Sep 17 00:00:00 2001 From: direwolf20 <39863894+Direwolf20-MC@users.noreply.github.com> Date: Fri, 13 Sep 2024 16:00:10 -0400 Subject: [PATCH] Fluid Handler for EXP Holder --- .../8202586f691eec5ad0bb88d13a278951d0c130fb | 4 +- .../assets/justdirethings/lang/en_us.json | 2 + .../justdirethings/JustDireThings.java | 16 ++- .../standardbuttons/ToggleButtonFactory.java | 9 ++ .../blockentities/ExperienceHolderBE.java | 26 +++++ .../common/blocks/ExperienceHolder.java | 51 +++++++++ .../ExperienceHolderFluidTank.java | 97 ++++++++++++++++++ .../datagen/JustDireLanguageProvider.java | 2 + .../textures/gui/buttons/pullfluids.png | Bin 0 -> 3267 bytes .../textures/gui/buttons/pushfluids.png | Bin 0 -> 3269 bytes 10 files changed, 201 insertions(+), 6 deletions(-) create mode 100644 src/main/java/com/direwolf20/justdirethings/common/capabilities/ExperienceHolderFluidTank.java create mode 100644 src/main/resources/assets/justdirethings/textures/gui/buttons/pullfluids.png create mode 100644 src/main/resources/assets/justdirethings/textures/gui/buttons/pushfluids.png diff --git a/src/generated/resources/.cache/8202586f691eec5ad0bb88d13a278951d0c130fb b/src/generated/resources/.cache/8202586f691eec5ad0bb88d13a278951d0c130fb index 0413af21..04fab44a 100644 --- a/src/generated/resources/.cache/8202586f691eec5ad0bb88d13a278951d0c130fb +++ b/src/generated/resources/.cache/8202586f691eec5ad0bb88d13a278951d0c130fb @@ -1,2 +1,2 @@ -// 1.21.1 2024-09-13T13:43:18.3815776 Languages: en_us for mod: justdirethings -a4ea5c922b56481d51520c57e5bed3dc238465e4 assets/justdirethings/lang/en_us.json +// 1.21.1 2024-09-13T13:53:01.5331943 Languages: en_us for mod: justdirethings +50598341120df2f850d5821435699dff7b3dcdb3 assets/justdirethings/lang/en_us.json diff --git a/src/generated/resources/assets/justdirethings/lang/en_us.json b/src/generated/resources/assets/justdirethings/lang/en_us.json index 7ec6f9c2..506be149 100644 --- a/src/generated/resources/assets/justdirethings/lang/en_us.json +++ b/src/generated/resources/assets/justdirethings/lang/en_us.json @@ -405,8 +405,10 @@ "justdirethings.screen.paradoxentity": "Revert Entities", "justdirethings.screen.paradoxfluidcost": "Fluid Cost: %s mb", "justdirethings.screen.pickupdelay": "Pickup Delay (Ticks)", + "justdirethings.screen.pullfluids": "Pull Fluids", "justdirethings.screen.pullitems": "Pull Items", "justdirethings.screen.pulse": "Pulse", + "justdirethings.screen.pushfluids": "Push Fluids", "justdirethings.screen.redstone-strong": "Strong Signal", "justdirethings.screen.redstone-weak": "Weak Signal", "justdirethings.screen.remove_favorite": "Remove Favorite", diff --git a/src/main/java/com/direwolf20/justdirethings/JustDireThings.java b/src/main/java/com/direwolf20/justdirethings/JustDireThings.java index 0f823d33..94f6530f 100644 --- a/src/main/java/com/direwolf20/justdirethings/JustDireThings.java +++ b/src/main/java/com/direwolf20/justdirethings/JustDireThings.java @@ -1,16 +1,15 @@ package com.direwolf20.justdirethings; -import com.direwolf20.justdirethings.common.blockentities.EnergyTransmitterBE; -import com.direwolf20.justdirethings.common.blockentities.InventoryHolderBE; -import com.direwolf20.justdirethings.common.blockentities.ParadoxMachineBE; -import com.direwolf20.justdirethings.common.blockentities.PlayerAccessorBE; +import com.direwolf20.justdirethings.common.blockentities.*; import com.direwolf20.justdirethings.common.blockentities.basebe.BaseMachineBE; import com.direwolf20.justdirethings.common.blockentities.basebe.FluidMachineBE; import com.direwolf20.justdirethings.common.blockentities.basebe.PoweredMachineBE; import com.direwolf20.justdirethings.common.capabilities.EnergyStorageItemStackNoReceive; import com.direwolf20.justdirethings.common.capabilities.EnergyStorageItemstack; +import com.direwolf20.justdirethings.common.capabilities.ExperienceHolderFluidTank; import com.direwolf20.justdirethings.common.containers.handlers.PotionCanisterHandler; import com.direwolf20.justdirethings.common.entities.DecoyEntity; +import com.direwolf20.justdirethings.common.fluids.xpfluid.XPFluid; import com.direwolf20.justdirethings.common.items.FluidCanister; import com.direwolf20.justdirethings.common.items.PortalGunV2; import com.direwolf20.justdirethings.common.items.TimeWand; @@ -301,5 +300,14 @@ public boolean canFillFluidType(FluidStack fluid) { }, Registration.ParadoxMachine.get() ); + event.registerBlock(Capabilities.FluidHandler.BLOCK, + (level, pos, state, be, side) -> { + if (be instanceof ExperienceHolderBE experienceHolderBE) { + return new ExperienceHolderFluidTank(experienceHolderBE, fluidstack -> fluidstack.getFluid() instanceof XPFluid); //TODO Tags? + } + return null; + }, + Registration.ExperienceHolder.get() + ); } } diff --git a/src/main/java/com/direwolf20/justdirethings/client/screens/standardbuttons/ToggleButtonFactory.java b/src/main/java/com/direwolf20/justdirethings/client/screens/standardbuttons/ToggleButtonFactory.java index 4d73f350..6987c8c9 100644 --- a/src/main/java/com/direwolf20/justdirethings/client/screens/standardbuttons/ToggleButtonFactory.java +++ b/src/main/java/com/direwolf20/justdirethings/client/screens/standardbuttons/ToggleButtonFactory.java @@ -49,6 +49,15 @@ public static ToggleButton ALLOWLISTBUTTON(int x, int y, boolean startingValue, return new ToggleButton(x, y, STANDARD_WIDTH, STANDARD_HEIGHT, ALLOW_LIST_TEXTURES, startingValue, onPress); } + private static final List PUSH_PULL_FLUIDS_TEXTURES = List.of( + new TextureLocalization(ResourceLocation.fromNamespaceAndPath(JustDireThings.MODID, "textures/gui/buttons/pullfluids.png"), Component.translatable("justdirethings.screen.pullfluids")), + new TextureLocalization(ResourceLocation.fromNamespaceAndPath(JustDireThings.MODID, "textures/gui/buttons/pushfluids.png"), Component.translatable("justdirethings.screen.pushfluids")) + ); + + public static ToggleButton PUSHPULLFLUIDSBUTTON(int x, int y, boolean startingValue, Button.OnPress onPress) { + return new ToggleButton(x, y, STANDARD_WIDTH, STANDARD_HEIGHT, PUSH_PULL_FLUIDS_TEXTURES, startingValue, onPress); + } + private static final ResourceLocation STORE_EXP_BUTTON = ResourceLocation.fromNamespaceAndPath(JustDireThings.MODID, "textures/gui/buttons/add.png"); private static final Component STORE_EXP_BUTTON_LOCALIZATION = Component.translatable("justdirethings.screen.storeexp"); diff --git a/src/main/java/com/direwolf20/justdirethings/common/blockentities/ExperienceHolderBE.java b/src/main/java/com/direwolf20/justdirethings/common/blockentities/ExperienceHolderBE.java index 631f506e..8c467cdf 100644 --- a/src/main/java/com/direwolf20/justdirethings/common/blockentities/ExperienceHolderBE.java +++ b/src/main/java/com/direwolf20/justdirethings/common/blockentities/ExperienceHolderBE.java @@ -24,10 +24,14 @@ import net.minecraft.world.level.block.state.properties.BlockStateProperties; import net.minecraft.world.phys.AABB; import net.minecraft.world.phys.Vec3; +import net.neoforged.neoforge.capabilities.BlockCapabilityCache; +import net.neoforged.neoforge.capabilities.Capabilities; +import net.neoforged.neoforge.fluids.capability.IFluidHandler; import java.util.List; public class ExperienceHolderBE extends BaseMachineBE implements AreaAffectingBE, RedstoneControlledBE { + protected BlockCapabilityCache attachedTank; public FilterData filterData = new FilterData(); public AreaAffectingData areaAffectingData = new AreaAffectingData(getBlockState().getValue(BlockStateProperties.FACING).getOpposite()); public RedstoneControlData redstoneControlData = getDefaultRedstoneData(); @@ -76,6 +80,12 @@ public int addExp(int addition) { } } + public int subExp(int subtraction) { + int amtToRemove = Math.min(exp, subtraction); + this.exp = this.exp - amtToRemove; + return subtraction - amtToRemove; + } + public void storeExp(Player player, int levelChange) { if (levelChange == -1) { // Move all experience from player @@ -235,6 +245,22 @@ private void findTargetPlayer() { } } + private IFluidHandler getAttachedTank() { + if (attachedTank == null) { + assert this.level != null; + BlockState state = level.getBlockState(getBlockPos()); + Direction facing = state.getValue(BlockStateProperties.FACING); + BlockPos inventoryPos = getBlockPos().relative(facing); + attachedTank = BlockCapabilityCache.create( + Capabilities.FluidHandler.BLOCK, // capability to cache + (ServerLevel) this.level, // level + inventoryPos, // target position + facing.getOpposite() // context (The side of the block we're trying to pull/push from?) + ); + } + return attachedTank.getCapability(); + } + @Override public void saveAdditional(CompoundTag tag, HolderLookup.Provider provider) { super.saveAdditional(tag, provider); diff --git a/src/main/java/com/direwolf20/justdirethings/common/blocks/ExperienceHolder.java b/src/main/java/com/direwolf20/justdirethings/common/blocks/ExperienceHolder.java index d59b84ce..cf15e603 100644 --- a/src/main/java/com/direwolf20/justdirethings/common/blocks/ExperienceHolder.java +++ b/src/main/java/com/direwolf20/justdirethings/common/blocks/ExperienceHolder.java @@ -5,10 +5,18 @@ import com.direwolf20.justdirethings.common.containers.ExperienceHolderContainer; import net.minecraft.core.BlockPos; import net.minecraft.network.chat.Component; +import net.minecraft.sounds.SoundEvents; +import net.minecraft.sounds.SoundSource; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.ItemInteractionResult; import net.minecraft.world.SimpleMenuProvider; +import net.minecraft.world.entity.EquipmentSlot; import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.BucketItem; +import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.context.BlockPlaceContext; import net.minecraft.world.level.BlockGetter; +import net.minecraft.world.level.Level; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.SoundType; import net.minecraft.world.level.block.entity.BlockEntity; @@ -16,10 +24,15 @@ import net.minecraft.world.level.block.state.StateDefinition; import net.minecraft.world.level.block.state.properties.BlockStateProperties; import net.minecraft.world.level.block.state.properties.DirectionProperty; +import net.minecraft.world.phys.BlockHitResult; import net.minecraft.world.phys.shapes.BooleanOp; import net.minecraft.world.phys.shapes.CollisionContext; import net.minecraft.world.phys.shapes.Shapes; import net.minecraft.world.phys.shapes.VoxelShape; +import net.neoforged.neoforge.capabilities.Capabilities; +import net.neoforged.neoforge.fluids.FluidStack; +import net.neoforged.neoforge.fluids.capability.IFluidHandler; +import net.neoforged.neoforge.fluids.capability.IFluidHandlerItem; import javax.annotation.Nullable; import java.util.stream.Stream; @@ -114,6 +127,44 @@ public void openMenu(Player player, BlockPos blockPos) { })); } + @Override + protected ItemInteractionResult useItemOn(ItemStack itemStack, BlockState blockState, Level level, BlockPos blockPos, Player player, InteractionHand hand, BlockHitResult blockHitResult) { + if (level.isClientSide) return ItemInteractionResult.PASS_TO_DEFAULT_BLOCK_INTERACTION; + IFluidHandlerItem fluidHandlerItem = itemStack.getCapability(Capabilities.FluidHandler.ITEM); + if (fluidHandlerItem != null) { + IFluidHandler cap = level.getCapability(Capabilities.FluidHandler.BLOCK, blockPos, blockHitResult.getDirection()); + if (cap == null) return ItemInteractionResult.PASS_TO_DEFAULT_BLOCK_INTERACTION; + if (fluidHandlerItem.getFluidInTank(0).getAmount() < fluidHandlerItem.getTankCapacity(0) && !cap.getFluidInTank(0).isEmpty()) { + FluidStack testStack = cap.drain(fluidHandlerItem.getTankCapacity(0), IFluidHandler.FluidAction.SIMULATE); + if (testStack.getAmount() > 0) { + int amtFit = fluidHandlerItem.fill(testStack, IFluidHandler.FluidAction.SIMULATE); + if (amtFit > 0) { + FluidStack extractedStack = cap.drain(amtFit, IFluidHandler.FluidAction.EXECUTE); + fluidHandlerItem.fill(extractedStack, IFluidHandler.FluidAction.EXECUTE); + if (itemStack.getItem() instanceof BucketItem) + player.setItemSlot(hand == InteractionHand.MAIN_HAND ? EquipmentSlot.MAINHAND : EquipmentSlot.OFFHAND, fluidHandlerItem.getContainer()); + level.playSound(null, blockPos, SoundEvents.BUCKET_FILL, SoundSource.BLOCKS, 1F, 1.0F); + return ItemInteractionResult.SUCCESS; + } + } + } else { + FluidStack fluidStack = fluidHandlerItem.getFluidInTank(0); + int insertAmt = cap.fill(fluidStack, IFluidHandler.FluidAction.SIMULATE); + if (insertAmt > 0) { + FluidStack extractedStack = fluidHandlerItem.drain(insertAmt, IFluidHandler.FluidAction.EXECUTE); + if (!extractedStack.isEmpty()) { + cap.fill(extractedStack, IFluidHandler.FluidAction.EXECUTE); + if (itemStack.getItem() instanceof BucketItem) + player.setItemSlot(hand == InteractionHand.MAIN_HAND ? EquipmentSlot.MAINHAND : EquipmentSlot.OFFHAND, fluidHandlerItem.getContainer()); + level.playSound(null, blockPos, SoundEvents.BUCKET_EMPTY, SoundSource.BLOCKS, 1F, 1.0F); + return ItemInteractionResult.SUCCESS; + } + } + } + } + return ItemInteractionResult.PASS_TO_DEFAULT_BLOCK_INTERACTION; + } + @Override public boolean isValidBE(BlockEntity blockEntity) { return blockEntity instanceof ExperienceHolderBE; diff --git a/src/main/java/com/direwolf20/justdirethings/common/capabilities/ExperienceHolderFluidTank.java b/src/main/java/com/direwolf20/justdirethings/common/capabilities/ExperienceHolderFluidTank.java new file mode 100644 index 00000000..e5344a71 --- /dev/null +++ b/src/main/java/com/direwolf20/justdirethings/common/capabilities/ExperienceHolderFluidTank.java @@ -0,0 +1,97 @@ +package com.direwolf20.justdirethings.common.capabilities; + +import com.direwolf20.justdirethings.common.blockentities.ExperienceHolderBE; +import com.direwolf20.justdirethings.setup.Registration; +import net.neoforged.neoforge.fluids.FluidStack; +import net.neoforged.neoforge.fluids.capability.templates.FluidTank; + +import java.util.function.Predicate; + +public class ExperienceHolderFluidTank extends FluidTank { + private final ExperienceHolderBE experienceHolderBE; + + public ExperienceHolderFluidTank(ExperienceHolderBE experienceHolderBE, Predicate validator) { + super(Integer.MAX_VALUE, validator); + this.experienceHolderBE = experienceHolderBE; + fluid = new FluidStack(Registration.XP_FLUID_SOURCE.get(), getFluidAmount()); + } + + public int getFluidAmount() { + // Prevent overflow by capping experienceHolderBE.exp at Integer.MAX_VALUE / 20 + if (experienceHolderBE.exp > Integer.MAX_VALUE / 20) { + return Integer.MAX_VALUE; // If multiplying by 20 would overflow, return max int value + } + + // Safe to multiply without overflow + return Math.min(experienceHolderBE.exp * 20, getCapacity()); + } + + public int getCapacity() { + return Integer.MAX_VALUE; + } + + @Override + public int fill(FluidStack resource, FluidAction action) { + if (resource.isEmpty() || !isFluidValid(resource)) { + return 0; + } + if (action.simulate()) { + if (fluid.isEmpty()) { + return Math.min(capacity, resource.getAmount() - resource.getAmount() % 20); + } + if (!FluidStack.isSameFluidSameComponents(fluid, resource)) { + return 0; + } + return Math.min(capacity - getFluidAmount() - ((capacity - getFluidAmount()) % 20), resource.getAmount() - resource.getAmount() % 20); + } + if (fluid.isEmpty()) { + return resource.getAmount() - insertFluid(resource.getAmount()); + } + if (!FluidStack.isSameFluidSameComponents(fluid, resource)) { + return 0; + } + int filled = resource.getAmount() - insertFluid(resource.getAmount()); + if (filled > 0) + onContentsChanged(); + return filled; + } + + public int insertFluid(int amt) { + int remaining = experienceHolderBE.addExp(amt / 20); + int excessFluid = amt % 20; // Calculate remainder fluid (less than 1 XP) + return (remaining * 20) + excessFluid; + } + + public int extractFluid(int amt) { + int expNeeded = amt / 20; + int unAvailable = experienceHolderBE.subExp(expNeeded); + return (unAvailable * 20) + (amt % 20); + } + + @Override + public FluidStack drain(FluidStack resource, FluidAction action) { + if (resource.isEmpty() || !FluidStack.isSameFluidSameComponents(resource, fluid)) { + return FluidStack.EMPTY; + } + return drain(resource.getAmount(), action); + } + + @Override + public FluidStack drain(int maxDrain, FluidAction action) { + int drained = maxDrain - (maxDrain % 20); //Trim remainder + if (getFluidAmount() < drained) { + drained = getFluidAmount(); + } + FluidStack stack = fluid.copyWithAmount(drained); + if (action.execute() && drained > 0) { + extractFluid(drained); + onContentsChanged(); + } + return stack; + } + + @Override + protected void onContentsChanged() { + experienceHolderBE.markDirtyClient(); + } +} diff --git a/src/main/java/com/direwolf20/justdirethings/datagen/JustDireLanguageProvider.java b/src/main/java/com/direwolf20/justdirethings/datagen/JustDireLanguageProvider.java index 4038e123..7e666b62 100644 --- a/src/main/java/com/direwolf20/justdirethings/datagen/JustDireLanguageProvider.java +++ b/src/main/java/com/direwolf20/justdirethings/datagen/JustDireLanguageProvider.java @@ -529,6 +529,8 @@ protected void addTranslations() { add("justdirethings.screen.targetexp", "Target Level"); add("justdirethings.screen.owneronly", "Owner Only"); add("justdirethings.screen.collectexp", "Collect Experience"); + add("justdirethings.screen.pushfluids", "Push Fluids"); + add("justdirethings.screen.pullfluids", "Pull Fluids"); //Buttons //add("justdirethings.buttons.save", "Save"); diff --git a/src/main/resources/assets/justdirethings/textures/gui/buttons/pullfluids.png b/src/main/resources/assets/justdirethings/textures/gui/buttons/pullfluids.png new file mode 100644 index 0000000000000000000000000000000000000000..c359c6769faf1fa6ad290753bbb89c6675d70eb8 GIT binary patch literal 3267 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 P|A5)4x!RS9mtX$_+zS2~ literal 0 HcmV?d00001