Skip to content

Commit 7dd3cad

Browse files
authored
Implement Bucket Behavior to Cells (#2660)
1 parent 0fe9865 commit 7dd3cad

File tree

4 files changed

+240
-12
lines changed

4 files changed

+240
-12
lines changed

src/main/java/gregtech/api/items/metaitem/stats/IItemBehaviour.java

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ default EnumActionResult onItemUseFirst(EntityPlayer player, World world, BlockP
3838

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

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

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

5656
default void addPropertyOverride(@NotNull Item item) {}
57+
58+
default ActionResult<ItemStack> pass(ItemStack stack) {
59+
return ActionResult.newResult(EnumActionResult.PASS, stack);
60+
}
61+
62+
default ActionResult<ItemStack> success(ItemStack stack) {
63+
return ActionResult.newResult(EnumActionResult.SUCCESS, stack);
64+
}
65+
66+
default ActionResult<ItemStack> fail(ItemStack stack) {
67+
return ActionResult.newResult(EnumActionResult.FAIL, stack);
68+
}
5769
}
Lines changed: 213 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,54 @@
11
package gregtech.api.items.metaitem.stats;
22

3+
import gregtech.api.util.GTUtility;
4+
5+
import net.minecraft.block.Block;
6+
import net.minecraft.block.BlockLiquid;
7+
import net.minecraft.block.material.Material;
8+
import net.minecraft.block.state.IBlockState;
9+
import net.minecraft.client.resources.I18n;
10+
import net.minecraft.entity.item.EntityItem;
11+
import net.minecraft.entity.player.EntityPlayer;
312
import net.minecraft.item.ItemStack;
13+
import net.minecraft.util.ActionResult;
14+
import net.minecraft.util.EnumFacing;
15+
import net.minecraft.util.EnumHand;
16+
import net.minecraft.util.SoundCategory;
17+
import net.minecraft.util.SoundEvent;
18+
import net.minecraft.util.math.BlockPos;
19+
import net.minecraft.util.math.RayTraceResult;
20+
import net.minecraft.util.math.Vec3d;
21+
import net.minecraft.world.World;
22+
import net.minecraftforge.fluids.Fluid;
423
import net.minecraftforge.fluids.FluidStack;
5-
import net.minecraftforge.fluids.capability.CapabilityFluidHandler;
24+
import net.minecraftforge.fluids.FluidUtil;
25+
import net.minecraftforge.fluids.IFluidBlock;
26+
import net.minecraftforge.fluids.capability.IFluidHandler;
627
import net.minecraftforge.fluids.capability.IFluidHandlerItem;
28+
import net.minecraftforge.fluids.capability.wrappers.BlockLiquidWrapper;
29+
import net.minecraftforge.fluids.capability.wrappers.BlockWrapper;
30+
import net.minecraftforge.fluids.capability.wrappers.FluidBlockWrapper;
31+
32+
import org.jetbrains.annotations.NotNull;
33+
import org.jetbrains.annotations.Nullable;
34+
35+
import java.util.List;
36+
37+
public class ItemFluidContainer implements IItemContainerItemProvider, IItemBehaviour {
738

8-
public class ItemFluidContainer implements IItemContainerItemProvider {
39+
private final boolean isBucket;
40+
41+
public ItemFluidContainer(boolean isBucket) {
42+
this.isBucket = isBucket;
43+
}
44+
45+
public ItemFluidContainer() {
46+
this(false);
47+
}
948

1049
@Override
1150
public ItemStack getContainerItem(ItemStack itemStack) {
12-
IFluidHandlerItem handler = itemStack.getCapability(CapabilityFluidHandler.FLUID_HANDLER_ITEM_CAPABILITY, null);
51+
IFluidHandlerItem handler = FluidUtil.getFluidHandler(itemStack);
1352
if (handler != null) {
1453
FluidStack drained = handler.drain(1000, false);
1554
if (drained == null || drained.amount != 1000) return ItemStack.EMPTY;
@@ -18,4 +57,175 @@ public ItemStack getContainerItem(ItemStack itemStack) {
1857
}
1958
return itemStack;
2059
}
60+
61+
@Override
62+
public void addInformation(ItemStack itemStack, List<String> lines) {
63+
if (isBucket) {
64+
lines.add(I18n.format("behaviour.cell_bucket.tooltip"));
65+
}
66+
}
67+
68+
@Override
69+
public ActionResult<ItemStack> onItemRightClick(World world, EntityPlayer player, EnumHand hand) {
70+
ItemStack stack = player.getHeldItem(hand);
71+
if (!isBucket) return pass(stack);
72+
73+
ItemStack cellStack = GTUtility.copy(1, stack);
74+
75+
var cellHandler = FluidUtil.getFluidHandler(cellStack);
76+
if (cellHandler == null) return pass(stack);
77+
78+
var result = rayTrace(world, player, true);
79+
if (result == null || result.typeOfHit != RayTraceResult.Type.BLOCK) {
80+
return pass(stack);
81+
}
82+
83+
var pos = result.getBlockPos();
84+
85+
// can the player modify the clicked block
86+
if (!world.isBlockModifiable(player, pos)) {
87+
return fail(stack);
88+
}
89+
90+
// can player edit
91+
if (!player.canPlayerEdit(pos, result.sideHit, cellStack)) {
92+
return fail(stack);
93+
}
94+
95+
// prioritize filling the cell if there's space, otherwise place fluid
96+
if (fillCell(cellStack, world, pos, result.sideHit, player)) {
97+
addToPlayerInventory(stack, cellHandler.getContainer(), player, hand);
98+
return success(stack);
99+
100+
} else {
101+
result = rayTrace(world, player, false);
102+
if (result == null || result.typeOfHit != RayTraceResult.Type.BLOCK) {
103+
return pass(stack);
104+
}
105+
pos = result.getBlockPos();
106+
107+
if (tryPlace(cellHandler, world, pos.offset(result.sideHit), result.sideHit, player)) {
108+
addToPlayerInventory(stack, cellHandler.getContainer(), player, hand);
109+
return success(stack);
110+
}
111+
}
112+
113+
return pass(stack);
114+
}
115+
116+
private static boolean tryPlace(IFluidHandlerItem cellHandler, World world, BlockPos pos, EnumFacing side,
117+
EntityPlayer player) {
118+
var cellFluid = cellHandler.drain(Fluid.BUCKET_VOLUME, false);
119+
if (cellFluid == null || !cellFluid.getFluid().canBePlacedInWorld())
120+
return false;
121+
122+
IFluidHandler blockHandler = getOrCreate(cellFluid, world, pos, side);
123+
124+
// check that we can place the fluid at the destination
125+
IBlockState destBlockState = world.getBlockState(pos);
126+
Material destMaterial = destBlockState.getMaterial();
127+
boolean isDestNonSolid = !destMaterial.isSolid();
128+
boolean isDestReplaceable = destBlockState.getBlock().isReplaceable(world, pos);
129+
130+
if (!world.isAirBlock(pos) && !isDestNonSolid && !isDestReplaceable) {
131+
// Non-air, solid, unreplacable block. We can't put fluid here.
132+
return false;
133+
}
134+
135+
// check vaporize
136+
if (world.provider.doesWaterVaporize() && cellFluid.getFluid().doesVaporize(cellFluid)) {
137+
cellHandler.drain(Fluid.BUCKET_VOLUME, true);
138+
cellFluid.getFluid().vaporize(player, world, pos, cellFluid);
139+
return true;
140+
}
141+
142+
// fill block
143+
int filled = blockHandler.fill(cellFluid, false);
144+
145+
if (filled != Fluid.BUCKET_VOLUME) return false;
146+
147+
playSound(cellFluid, true, player);
148+
boolean consume = !player.isSpectator() && !player.isCreative();
149+
blockHandler.fill(cellHandler.drain(Fluid.BUCKET_VOLUME, consume), true);
150+
return true;
151+
}
152+
153+
private static boolean fillCell(ItemStack cellStack, World world, BlockPos pos, EnumFacing side,
154+
EntityPlayer player) {
155+
IFluidHandler blockHandler = FluidUtil.getFluidHandler(world, pos, side);
156+
if (blockHandler == null) return false;
157+
158+
IFluidHandlerItem cellHandler = FluidUtil.getFluidHandler(cellStack);
159+
if (cellHandler == null) return false;
160+
161+
FluidStack stack = blockHandler.drain(Fluid.BUCKET_VOLUME, false);
162+
int filled = cellHandler.fill(stack, false);
163+
164+
if (filled != Fluid.BUCKET_VOLUME) return false;
165+
166+
playSound(stack, false, player);
167+
boolean consume = !player.isSpectator() && !player.isCreative();
168+
cellHandler.fill(blockHandler.drain(Fluid.BUCKET_VOLUME, true), consume);
169+
return true;
170+
}
171+
172+
// copied and adapted from Item.java
173+
@Nullable
174+
private static RayTraceResult rayTrace(World worldIn, EntityPlayer player, boolean hitFluids) {
175+
Vec3d lookPos = player.getPositionVector()
176+
.add(0, player.getEyeHeight(), 0);
177+
178+
Vec3d lookOffset = player.getLookVec()
179+
.scale(player.getEntityAttribute(EntityPlayer.REACH_DISTANCE).getAttributeValue());
180+
181+
return worldIn.rayTraceBlocks(lookPos, lookPos.add(lookOffset),
182+
hitFluids, !hitFluids, false);
183+
}
184+
185+
@NotNull
186+
private static IFluidHandler createHandler(FluidStack stack, World world, BlockPos pos) {
187+
Block block = stack.getFluid().getBlock();
188+
if (block instanceof IFluidBlock) {
189+
return new FluidBlockWrapper((IFluidBlock) block, world, pos);
190+
} else if (block instanceof BlockLiquid) {
191+
return new BlockLiquidWrapper((BlockLiquid) block, world, pos);
192+
} else {
193+
return new BlockWrapper(block, world, pos);
194+
}
195+
}
196+
197+
private static IFluidHandler getOrCreate(FluidStack stack, World world, BlockPos pos, EnumFacing side) {
198+
IFluidHandler handler = FluidUtil.getFluidHandler(world, pos, side);
199+
if (handler != null) return handler;
200+
return createHandler(stack, world, pos);
201+
}
202+
203+
private static void addToPlayerInventory(ItemStack playerStack, ItemStack resultStack, EntityPlayer player,
204+
EnumHand hand) {
205+
if (playerStack.getCount() > resultStack.getCount()) {
206+
playerStack.shrink(resultStack.getCount());
207+
if (!player.inventory.addItemStackToInventory(resultStack) && !player.world.isRemote) {
208+
EntityItem dropItem = player.entityDropItem(resultStack, 0);
209+
if (dropItem != null) dropItem.setPickupDelay(0);
210+
}
211+
} else {
212+
player.setHeldItem(hand, resultStack);
213+
}
214+
}
215+
216+
/**
217+
* Play the appropriate fluid interaction sound for the fluid. <br />
218+
* Must be called on server to work correctly
219+
**/
220+
private static void playSound(FluidStack fluid, boolean fill, EntityPlayer player) {
221+
if (fluid == null || player.world.isRemote) return;
222+
SoundEvent soundEvent;
223+
if (fill) {
224+
soundEvent = fluid.getFluid().getFillSound(fluid);
225+
} else {
226+
soundEvent = fluid.getFluid().getEmptySound(fluid);
227+
}
228+
player.world.playSound(null, player.posX, player.posY + 0.5, player.posZ,
229+
soundEvent, SoundCategory.PLAYERS, 1.0F, 1.0F);
230+
}
21231
}

src/main/java/gregtech/common/items/MetaItem1.java

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -191,46 +191,51 @@ public void registerSubItems() {
191191
// Fluid Cells: ID 78-88
192192
FLUID_CELL = addItem(78, "fluid_cell")
193193
.addComponents(new FilteredFluidStats(1000, 1800, true, false, false, false, false),
194-
new ItemFluidContainer())
194+
new ItemFluidContainer(true))
195195
.setCreativeTabs(GTCreativeTabs.TAB_GREGTECH_TOOLS);
196196

197197
FLUID_CELL_UNIVERSAL = addItem(79, "fluid_cell.universal")
198198
.addComponents(new FilteredFluidStats(1000, 1800, true, false, false, false, true),
199-
new ItemFluidContainer())
199+
new ItemFluidContainer(true))
200200
.setCreativeTabs(GTCreativeTabs.TAB_GREGTECH_TOOLS);
201201

202202
FLUID_CELL_LARGE_STEEL = addItem(80, "large_fluid_cell.steel")
203203
.addComponents(new FilteredFluidStats(8000,
204204
Materials.Steel.getProperty(PropertyKey.FLUID_PIPE).getMaxFluidTemperature(), true, false,
205-
false, false, true), new ItemFluidContainer())
205+
false, false, true),
206+
new ItemFluidContainer(true))
206207
.setMaterialInfo(new ItemMaterialInfo(new MaterialStack(Materials.Steel, M * 4))) // ingot * 4
207208
.setCreativeTabs(GTCreativeTabs.TAB_GREGTECH_TOOLS);
208209

209210
FLUID_CELL_LARGE_ALUMINIUM = addItem(81, "large_fluid_cell.aluminium")
210211
.addComponents(new FilteredFluidStats(32000,
211212
Materials.Aluminium.getProperty(PropertyKey.FLUID_PIPE).getMaxFluidTemperature(), true, false,
212-
false, false, true), new ItemFluidContainer())
213+
false, false, true),
214+
new ItemFluidContainer(true))
213215
.setMaterialInfo(new ItemMaterialInfo(new MaterialStack(Materials.Aluminium, M * 4))) // ingot * 4
214216
.setCreativeTabs(GTCreativeTabs.TAB_GREGTECH_TOOLS);
215217

216218
FLUID_CELL_LARGE_STAINLESS_STEEL = addItem(82, "large_fluid_cell.stainless_steel")
217219
.addComponents(new FilteredFluidStats(64000,
218220
Materials.StainlessSteel.getProperty(PropertyKey.FLUID_PIPE).getMaxFluidTemperature(), true,
219-
true, true, false, true), new ItemFluidContainer())
221+
true, true, false, true),
222+
new ItemFluidContainer(true))
220223
.setMaterialInfo(new ItemMaterialInfo(new MaterialStack(Materials.StainlessSteel, M * 6))) // ingot * 6
221224
.setCreativeTabs(GTCreativeTabs.TAB_GREGTECH_TOOLS);
222225

223226
FLUID_CELL_LARGE_TITANIUM = addItem(83, "large_fluid_cell.titanium")
224227
.addComponents(new FilteredFluidStats(128000,
225228
Materials.Titanium.getProperty(PropertyKey.FLUID_PIPE).getMaxFluidTemperature(), true, true,
226-
false, false, true), new ItemFluidContainer())
229+
false, false, true),
230+
new ItemFluidContainer(true))
227231
.setMaterialInfo(new ItemMaterialInfo(new MaterialStack(Materials.Titanium, M * 6))) // ingot * 6
228232
.setCreativeTabs(GTCreativeTabs.TAB_GREGTECH_TOOLS);
229233

230234
FLUID_CELL_LARGE_TUNGSTEN_STEEL = addItem(84, "large_fluid_cell.tungstensteel")
231235
.addComponents(new FilteredFluidStats(512000,
232236
Materials.TungstenSteel.getProperty(PropertyKey.FLUID_PIPE).getMaxFluidTemperature(), true,
233-
true, false, false, true), new ItemFluidContainer())
237+
true, false, false, true),
238+
new ItemFluidContainer(true))
234239
.setMaxStackSize(32)
235240
.setMaterialInfo(new ItemMaterialInfo(new MaterialStack(Materials.TungstenSteel, M * 8))) // ingot * 8
236241
.setCreativeTabs(GTCreativeTabs.TAB_GREGTECH_TOOLS);

src/main/resources/assets/gregtech/lang/en_us.lang

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4784,6 +4784,7 @@ behaviour.softhammer=Activates and Deactivates Machines
47844784
behaviour.hammer=Turns on and off Muffling for Machines (by hitting them)
47854785
behaviour.wrench=Rotates Blocks on Rightclick
47864786
behaviour.boor.by=by %s
4787+
behaviour.cell_bucket.tooltip=Can pickup or place fluids
47874788
behaviour.paintspray.solvent.tooltip=Can remove color from things
47884789
behaviour.paintspray.white.tooltip=Can paint things in White
47894790
behaviour.paintspray.orange.tooltip=Can paint things in Orange

0 commit comments

Comments
 (0)