11package 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 ;
312import 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 ;
423import 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 ;
627import 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}
0 commit comments