Skip to content

Commit

Permalink
Implement Bucket Behavior to Cells (#2660)
Browse files Browse the repository at this point in the history
  • Loading branch information
ghzdude authored Feb 3, 2025
1 parent 0fe9865 commit 7dd3cad
Show file tree
Hide file tree
Showing 4 changed files with 240 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ default EnumActionResult onItemUseFirst(EntityPlayer player, World world, BlockP

default ActionResult<ItemStack> onItemUse(EntityPlayer player, World world, BlockPos pos, EnumHand hand,
EnumFacing facing, float hitX, float hitY, float hitZ) {
return ActionResult.newResult(EnumActionResult.PASS, player.getHeldItem(hand));
return pass(player.getHeldItem(hand));
}

default void addInformation(ItemStack itemStack, List<String> lines) {}
Expand All @@ -50,8 +50,20 @@ default Multimap<String, AttributeModifier> getAttributeModifiers(EntityEquipmen
}

default ActionResult<ItemStack> onItemRightClick(World world, EntityPlayer player, EnumHand hand) {
return ActionResult.newResult(EnumActionResult.PASS, player.getHeldItem(hand));
return pass(player.getHeldItem(hand));
}

default void addPropertyOverride(@NotNull Item item) {}

default ActionResult<ItemStack> pass(ItemStack stack) {
return ActionResult.newResult(EnumActionResult.PASS, stack);
}

default ActionResult<ItemStack> success(ItemStack stack) {
return ActionResult.newResult(EnumActionResult.SUCCESS, stack);
}

default ActionResult<ItemStack> fail(ItemStack stack) {
return ActionResult.newResult(EnumActionResult.FAIL, stack);
}
}
Original file line number Diff line number Diff line change
@@ -1,15 +1,54 @@
package gregtech.api.items.metaitem.stats;

import gregtech.api.util.GTUtility;

import net.minecraft.block.Block;
import net.minecraft.block.BlockLiquid;
import net.minecraft.block.material.Material;
import net.minecraft.block.state.IBlockState;
import net.minecraft.client.resources.I18n;
import net.minecraft.entity.item.EntityItem;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
import net.minecraft.util.ActionResult;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.EnumHand;
import net.minecraft.util.SoundCategory;
import net.minecraft.util.SoundEvent;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.RayTraceResult;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.World;
import net.minecraftforge.fluids.Fluid;
import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.fluids.capability.CapabilityFluidHandler;
import net.minecraftforge.fluids.FluidUtil;
import net.minecraftforge.fluids.IFluidBlock;
import net.minecraftforge.fluids.capability.IFluidHandler;
import net.minecraftforge.fluids.capability.IFluidHandlerItem;
import net.minecraftforge.fluids.capability.wrappers.BlockLiquidWrapper;
import net.minecraftforge.fluids.capability.wrappers.BlockWrapper;
import net.minecraftforge.fluids.capability.wrappers.FluidBlockWrapper;

import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.util.List;

public class ItemFluidContainer implements IItemContainerItemProvider, IItemBehaviour {

public class ItemFluidContainer implements IItemContainerItemProvider {
private final boolean isBucket;

public ItemFluidContainer(boolean isBucket) {
this.isBucket = isBucket;
}

public ItemFluidContainer() {
this(false);
}

@Override
public ItemStack getContainerItem(ItemStack itemStack) {
IFluidHandlerItem handler = itemStack.getCapability(CapabilityFluidHandler.FLUID_HANDLER_ITEM_CAPABILITY, null);
IFluidHandlerItem handler = FluidUtil.getFluidHandler(itemStack);
if (handler != null) {
FluidStack drained = handler.drain(1000, false);
if (drained == null || drained.amount != 1000) return ItemStack.EMPTY;
Expand All @@ -18,4 +57,175 @@ public ItemStack getContainerItem(ItemStack itemStack) {
}
return itemStack;
}

@Override
public void addInformation(ItemStack itemStack, List<String> lines) {
if (isBucket) {
lines.add(I18n.format("behaviour.cell_bucket.tooltip"));
}
}

@Override
public ActionResult<ItemStack> onItemRightClick(World world, EntityPlayer player, EnumHand hand) {
ItemStack stack = player.getHeldItem(hand);
if (!isBucket) return pass(stack);

ItemStack cellStack = GTUtility.copy(1, stack);

var cellHandler = FluidUtil.getFluidHandler(cellStack);
if (cellHandler == null) return pass(stack);

var result = rayTrace(world, player, true);
if (result == null || result.typeOfHit != RayTraceResult.Type.BLOCK) {
return pass(stack);
}

var pos = result.getBlockPos();

// can the player modify the clicked block
if (!world.isBlockModifiable(player, pos)) {
return fail(stack);
}

// can player edit
if (!player.canPlayerEdit(pos, result.sideHit, cellStack)) {
return fail(stack);
}

// prioritize filling the cell if there's space, otherwise place fluid
if (fillCell(cellStack, world, pos, result.sideHit, player)) {
addToPlayerInventory(stack, cellHandler.getContainer(), player, hand);
return success(stack);

} else {
result = rayTrace(world, player, false);
if (result == null || result.typeOfHit != RayTraceResult.Type.BLOCK) {
return pass(stack);
}
pos = result.getBlockPos();

if (tryPlace(cellHandler, world, pos.offset(result.sideHit), result.sideHit, player)) {
addToPlayerInventory(stack, cellHandler.getContainer(), player, hand);
return success(stack);
}
}

return pass(stack);
}

private static boolean tryPlace(IFluidHandlerItem cellHandler, World world, BlockPos pos, EnumFacing side,
EntityPlayer player) {
var cellFluid = cellHandler.drain(Fluid.BUCKET_VOLUME, false);
if (cellFluid == null || !cellFluid.getFluid().canBePlacedInWorld())
return false;

IFluidHandler blockHandler = getOrCreate(cellFluid, world, pos, side);

// check that we can place the fluid at the destination
IBlockState destBlockState = world.getBlockState(pos);
Material destMaterial = destBlockState.getMaterial();
boolean isDestNonSolid = !destMaterial.isSolid();
boolean isDestReplaceable = destBlockState.getBlock().isReplaceable(world, pos);

if (!world.isAirBlock(pos) && !isDestNonSolid && !isDestReplaceable) {
// Non-air, solid, unreplacable block. We can't put fluid here.
return false;
}

// check vaporize
if (world.provider.doesWaterVaporize() && cellFluid.getFluid().doesVaporize(cellFluid)) {
cellHandler.drain(Fluid.BUCKET_VOLUME, true);
cellFluid.getFluid().vaporize(player, world, pos, cellFluid);
return true;
}

// fill block
int filled = blockHandler.fill(cellFluid, false);

if (filled != Fluid.BUCKET_VOLUME) return false;

playSound(cellFluid, true, player);
boolean consume = !player.isSpectator() && !player.isCreative();
blockHandler.fill(cellHandler.drain(Fluid.BUCKET_VOLUME, consume), true);
return true;
}

private static boolean fillCell(ItemStack cellStack, World world, BlockPos pos, EnumFacing side,
EntityPlayer player) {
IFluidHandler blockHandler = FluidUtil.getFluidHandler(world, pos, side);
if (blockHandler == null) return false;

IFluidHandlerItem cellHandler = FluidUtil.getFluidHandler(cellStack);
if (cellHandler == null) return false;

FluidStack stack = blockHandler.drain(Fluid.BUCKET_VOLUME, false);
int filled = cellHandler.fill(stack, false);

if (filled != Fluid.BUCKET_VOLUME) return false;

playSound(stack, false, player);
boolean consume = !player.isSpectator() && !player.isCreative();
cellHandler.fill(blockHandler.drain(Fluid.BUCKET_VOLUME, true), consume);
return true;
}

// copied and adapted from Item.java
@Nullable
private static RayTraceResult rayTrace(World worldIn, EntityPlayer player, boolean hitFluids) {
Vec3d lookPos = player.getPositionVector()
.add(0, player.getEyeHeight(), 0);

Vec3d lookOffset = player.getLookVec()
.scale(player.getEntityAttribute(EntityPlayer.REACH_DISTANCE).getAttributeValue());

return worldIn.rayTraceBlocks(lookPos, lookPos.add(lookOffset),
hitFluids, !hitFluids, false);
}

@NotNull
private static IFluidHandler createHandler(FluidStack stack, World world, BlockPos pos) {
Block block = stack.getFluid().getBlock();
if (block instanceof IFluidBlock) {
return new FluidBlockWrapper((IFluidBlock) block, world, pos);
} else if (block instanceof BlockLiquid) {
return new BlockLiquidWrapper((BlockLiquid) block, world, pos);
} else {
return new BlockWrapper(block, world, pos);
}
}

private static IFluidHandler getOrCreate(FluidStack stack, World world, BlockPos pos, EnumFacing side) {
IFluidHandler handler = FluidUtil.getFluidHandler(world, pos, side);
if (handler != null) return handler;
return createHandler(stack, world, pos);
}

private static void addToPlayerInventory(ItemStack playerStack, ItemStack resultStack, EntityPlayer player,
EnumHand hand) {
if (playerStack.getCount() > resultStack.getCount()) {
playerStack.shrink(resultStack.getCount());
if (!player.inventory.addItemStackToInventory(resultStack) && !player.world.isRemote) {
EntityItem dropItem = player.entityDropItem(resultStack, 0);
if (dropItem != null) dropItem.setPickupDelay(0);
}
} else {
player.setHeldItem(hand, resultStack);
}
}

/**
* Play the appropriate fluid interaction sound for the fluid. <br />
* Must be called on server to work correctly
**/
private static void playSound(FluidStack fluid, boolean fill, EntityPlayer player) {
if (fluid == null || player.world.isRemote) return;
SoundEvent soundEvent;
if (fill) {
soundEvent = fluid.getFluid().getFillSound(fluid);
} else {
soundEvent = fluid.getFluid().getEmptySound(fluid);
}
player.world.playSound(null, player.posX, player.posY + 0.5, player.posZ,
soundEvent, SoundCategory.PLAYERS, 1.0F, 1.0F);
}
}
19 changes: 12 additions & 7 deletions src/main/java/gregtech/common/items/MetaItem1.java
Original file line number Diff line number Diff line change
Expand Up @@ -191,46 +191,51 @@ public void registerSubItems() {
// Fluid Cells: ID 78-88
FLUID_CELL = addItem(78, "fluid_cell")
.addComponents(new FilteredFluidStats(1000, 1800, true, false, false, false, false),
new ItemFluidContainer())
new ItemFluidContainer(true))
.setCreativeTabs(GTCreativeTabs.TAB_GREGTECH_TOOLS);

FLUID_CELL_UNIVERSAL = addItem(79, "fluid_cell.universal")
.addComponents(new FilteredFluidStats(1000, 1800, true, false, false, false, true),
new ItemFluidContainer())
new ItemFluidContainer(true))
.setCreativeTabs(GTCreativeTabs.TAB_GREGTECH_TOOLS);

FLUID_CELL_LARGE_STEEL = addItem(80, "large_fluid_cell.steel")
.addComponents(new FilteredFluidStats(8000,
Materials.Steel.getProperty(PropertyKey.FLUID_PIPE).getMaxFluidTemperature(), true, false,
false, false, true), new ItemFluidContainer())
false, false, true),
new ItemFluidContainer(true))
.setMaterialInfo(new ItemMaterialInfo(new MaterialStack(Materials.Steel, M * 4))) // ingot * 4
.setCreativeTabs(GTCreativeTabs.TAB_GREGTECH_TOOLS);

FLUID_CELL_LARGE_ALUMINIUM = addItem(81, "large_fluid_cell.aluminium")
.addComponents(new FilteredFluidStats(32000,
Materials.Aluminium.getProperty(PropertyKey.FLUID_PIPE).getMaxFluidTemperature(), true, false,
false, false, true), new ItemFluidContainer())
false, false, true),
new ItemFluidContainer(true))
.setMaterialInfo(new ItemMaterialInfo(new MaterialStack(Materials.Aluminium, M * 4))) // ingot * 4
.setCreativeTabs(GTCreativeTabs.TAB_GREGTECH_TOOLS);

FLUID_CELL_LARGE_STAINLESS_STEEL = addItem(82, "large_fluid_cell.stainless_steel")
.addComponents(new FilteredFluidStats(64000,
Materials.StainlessSteel.getProperty(PropertyKey.FLUID_PIPE).getMaxFluidTemperature(), true,
true, true, false, true), new ItemFluidContainer())
true, true, false, true),
new ItemFluidContainer(true))
.setMaterialInfo(new ItemMaterialInfo(new MaterialStack(Materials.StainlessSteel, M * 6))) // ingot * 6
.setCreativeTabs(GTCreativeTabs.TAB_GREGTECH_TOOLS);

FLUID_CELL_LARGE_TITANIUM = addItem(83, "large_fluid_cell.titanium")
.addComponents(new FilteredFluidStats(128000,
Materials.Titanium.getProperty(PropertyKey.FLUID_PIPE).getMaxFluidTemperature(), true, true,
false, false, true), new ItemFluidContainer())
false, false, true),
new ItemFluidContainer(true))
.setMaterialInfo(new ItemMaterialInfo(new MaterialStack(Materials.Titanium, M * 6))) // ingot * 6
.setCreativeTabs(GTCreativeTabs.TAB_GREGTECH_TOOLS);

FLUID_CELL_LARGE_TUNGSTEN_STEEL = addItem(84, "large_fluid_cell.tungstensteel")
.addComponents(new FilteredFluidStats(512000,
Materials.TungstenSteel.getProperty(PropertyKey.FLUID_PIPE).getMaxFluidTemperature(), true,
true, false, false, true), new ItemFluidContainer())
true, false, false, true),
new ItemFluidContainer(true))
.setMaxStackSize(32)
.setMaterialInfo(new ItemMaterialInfo(new MaterialStack(Materials.TungstenSteel, M * 8))) // ingot * 8
.setCreativeTabs(GTCreativeTabs.TAB_GREGTECH_TOOLS);
Expand Down
1 change: 1 addition & 0 deletions src/main/resources/assets/gregtech/lang/en_us.lang
Original file line number Diff line number Diff line change
Expand Up @@ -4784,6 +4784,7 @@ behaviour.softhammer=Activates and Deactivates Machines
behaviour.hammer=Turns on and off Muffling for Machines (by hitting them)
behaviour.wrench=Rotates Blocks on Rightclick
behaviour.boor.by=by %s
behaviour.cell_bucket.tooltip=Can pickup or place fluids
behaviour.paintspray.solvent.tooltip=Can remove color from things
behaviour.paintspray.white.tooltip=Can paint things in White
behaviour.paintspray.orange.tooltip=Can paint things in Orange
Expand Down

0 comments on commit 7dd3cad

Please sign in to comment.