2020-09-09 16:48:43 +02:00
package de.ellpeck.actuallyadditions.common.util ;
2015-04-19 01:50:02 +02:00
2020-09-09 16:48:43 +02:00
import de.ellpeck.actuallyadditions.common.ActuallyAdditions ;
import de.ellpeck.actuallyadditions.common.tile.FilterSettings ;
import de.ellpeck.actuallyadditions.common.util.compat.SlotlessableItemHandlerWrapper ;
2015-05-30 17:47:57 +02:00
import net.minecraft.block.Block ;
2020-10-31 21:42:32 +01:00
import net.minecraft.block.BlockState ;
import net.minecraft.block.Blocks ;
2015-06-28 03:12:32 +02:00
import net.minecraft.block.material.Material ;
2020-10-31 22:01:43 +01:00
import net.minecraft.entity.item.ItemEntity ;
2020-10-31 21:42:32 +01:00
import net.minecraft.entity.player.PlayerEntity ;
import net.minecraft.entity.player.ServerPlayerEntity ;
2015-04-19 01:50:02 +02:00
import net.minecraft.item.ItemStack ;
2020-10-31 21:42:32 +01:00
import net.minecraft.item.Items ;
2020-10-31 22:01:43 +01:00
import net.minecraft.network.play.server.SChangeBlockPacket ;
import net.minecraft.state.properties.BlockStateProperties ;
2015-04-19 01:50:02 +02:00
import net.minecraft.tileentity.TileEntity ;
2020-10-31 21:42:32 +01:00
import net.minecraft.util.Direction ;
import net.minecraft.util.Hand ;
2018-01-29 08:17:31 +01:00
import net.minecraft.util.NonNullList ;
2016-03-18 23:47:22 +01:00
import net.minecraft.util.math.BlockPos ;
import net.minecraft.util.math.MathHelper ;
import net.minecraft.util.math.RayTraceResult ;
import net.minecraft.util.math.Vec3d ;
2015-04-19 01:50:02 +02:00
import net.minecraft.world.World ;
2020-10-31 22:01:43 +01:00
import net.minecraft.world.server.ServerWorld ;
2015-11-22 23:02:59 +01:00
import net.minecraftforge.common.ForgeHooks ;
2015-05-22 17:48:50 +02:00
import net.minecraftforge.common.IPlantable ;
2017-02-04 16:07:58 +01:00
import net.minecraftforge.common.MinecraftForge ;
2016-06-19 20:24:13 +02:00
import net.minecraftforge.common.util.FakePlayer ;
import net.minecraftforge.common.util.FakePlayerFactory ;
2016-11-26 08:58:42 +01:00
import net.minecraftforge.energy.CapabilityEnergy ;
2016-07-06 18:31:29 +02:00
import net.minecraftforge.event.ForgeEventFactory ;
2018-01-29 08:17:31 +01:00
import net.minecraftforge.event.world.BlockEvent.BreakEvent ;
2016-11-19 21:11:17 +01:00
import net.minecraftforge.fluids.FluidStack ;
2016-06-05 12:52:59 +02:00
import net.minecraftforge.fluids.capability.CapabilityFluidHandler ;
2016-06-05 02:16:52 +02:00
import net.minecraftforge.fluids.capability.IFluidHandler ;
2016-07-20 22:14:30 +02:00
import net.minecraftforge.items.IItemHandler ;
2015-06-28 03:12:32 +02:00
2020-10-31 21:42:32 +01:00
import java.util.ArrayList ;
2018-01-29 08:17:31 +01:00
public final class WorldUtil {
2018-06-23 01:39:30 +02:00
public static boolean doItemInteraction ( SlotlessableItemHandlerWrapper extractWrapper , SlotlessableItemHandlerWrapper insertWrapper , int maxExtract ) {
return doItemInteraction ( extractWrapper , insertWrapper , maxExtract , null ) ;
}
public static boolean doItemInteraction ( SlotlessableItemHandlerWrapper extractWrapper , SlotlessableItemHandlerWrapper insertWrapper , int maxExtract , FilterSettings filter ) {
return doItemInteraction ( extractWrapper , insertWrapper , maxExtract , 0 , Integer . MAX_VALUE , 0 , Integer . MAX_VALUE , filter ) ;
}
public static boolean doItemInteraction ( SlotlessableItemHandlerWrapper extractWrapper , SlotlessableItemHandlerWrapper insertWrapper , int maxExtract , int extractSlotStart , int extractSlotEnd , int insertSlotStart , int insertSlotEnd , FilterSettings filter ) {
ItemStack theoreticalExtract = extractItem ( extractWrapper , maxExtract , true , extractSlotStart , extractSlotEnd , filter ) ;
if ( StackUtil . isValid ( theoreticalExtract ) ) {
ItemStack remaining = StackUtil . insertItem ( insertWrapper , theoreticalExtract , false , insertSlotStart , insertSlotEnd ) ;
if ( ! ItemStack . areItemStacksEqual ( remaining , theoreticalExtract ) ) {
int toExtract = theoreticalExtract . getCount ( ) - remaining . getCount ( ) ;
extractItem ( extractWrapper , toExtract , false , extractSlotStart , extractSlotEnd , filter ) ;
return true ;
}
}
return false ;
}
public static ItemStack extractItem ( SlotlessableItemHandlerWrapper extractWrapper , int maxExtract , boolean simulate , int slotStart , int slotEnd , FilterSettings filter ) {
ItemStack extracted = StackUtil . getEmpty ( ) ;
if ( ActuallyAdditions . commonCapsLoaded ) {
Object handler = extractWrapper . getSlotlessHandler ( ) ;
2020-10-31 22:01:43 +01:00
// if (handler instanceof ISlotlessItemHandler) {
// ISlotlessItemHandler slotless = (ISlotlessItemHandler) handler;
//
// if (filter == null || !filter.needsCheck()) {
// extracted = slotless.extractItem(maxExtract, simulate);
// return extracted;
// } else {
// ItemStack would = slotless.extractItem(maxExtract, true);
// if (filter.check(would)) {
// if (simulate) {
// extracted = would;
// } else {
// extracted = slotless.extractItem(maxExtract, false);
// }
// }
// //Leave the possibility to fall back to vanilla when there is a filter
// }
// }
2018-06-23 01:39:30 +02:00
}
if ( ! StackUtil . isValid ( extracted ) ) {
IItemHandler handler = extractWrapper . getNormalHandler ( ) ;
if ( handler ! = null ) {
for ( int i = Math . max ( 0 , slotStart ) ; i < Math . min ( slotEnd , handler . getSlots ( ) ) ; i + + ) {
if ( filter = = null | | ! filter . needsCheck ( ) | | filter . check ( handler . getStackInSlot ( i ) ) ) {
extracted = handler . extractItem ( i , maxExtract , simulate ) ;
if ( StackUtil . isValid ( extracted ) ) {
break ;
}
}
}
}
}
return extracted ;
}
2020-10-31 21:42:32 +01:00
public static void doEnergyInteraction ( TileEntity tileFrom , TileEntity tileTo , Direction sideTo , int maxTransfer ) {
2018-06-23 01:39:30 +02:00
if ( maxTransfer > 0 ) {
2020-10-31 21:42:32 +01:00
Direction opp = sideTo = = null ? null : sideTo . getOpposite ( ) ;
2020-10-31 22:01:43 +01:00
tileFrom . getCapability ( CapabilityEnergy . ENERGY , sideTo ) . ifPresent ( handlerFrom - > tileTo . getCapability ( CapabilityEnergy . ENERGY , opp ) . ifPresent ( handlerTo - > {
2019-02-27 19:53:05 +01:00
int drain = handlerFrom . extractEnergy ( maxTransfer , true ) ;
if ( drain > 0 ) {
int filled = handlerTo . receiveEnergy ( drain , false ) ;
handlerFrom . extractEnergy ( filled , false ) ;
2018-06-23 01:39:30 +02:00
}
2020-10-31 22:01:43 +01:00
} ) ) ;
2018-06-23 01:39:30 +02:00
}
}
2020-10-31 21:42:32 +01:00
public static void doFluidInteraction ( TileEntity tileFrom , TileEntity tileTo , Direction sideTo , int maxTransfer ) {
2018-06-23 01:39:30 +02:00
if ( maxTransfer > 0 ) {
2020-10-31 22:01:43 +01:00
tileFrom . getCapability ( CapabilityFluidHandler . FLUID_HANDLER_CAPABILITY , sideTo ) . ifPresent ( handlerFrom - > tileTo . getCapability ( CapabilityFluidHandler . FLUID_HANDLER_CAPABILITY , sideTo . getOpposite ( ) ) . ifPresent ( handlerTo - > {
FluidStack drain = handlerFrom . drain ( maxTransfer , IFluidHandler . FluidAction . SIMULATE ) ;
int filled = handlerTo . fill ( drain . copy ( ) , IFluidHandler . FluidAction . EXECUTE ) ;
handlerFrom . drain ( filled , IFluidHandler . FluidAction . EXECUTE ) ;
} ) ) ;
2018-06-23 01:39:30 +02:00
}
}
/ * *
* Checks if a given Block with a given Meta is present in given Positions
*
* @param positions The Positions , an array of { x , y , z } arrays containing Positions
* @param block The Block
* @param world The World
* @return Is every block present ?
* /
2020-10-31 22:01:43 +01:00
public static boolean hasBlocksInPlacesGiven ( BlockPos [ ] positions , Block block , World world ) {
2018-06-23 01:39:30 +02:00
for ( BlockPos pos : positions ) {
2020-10-31 22:01:43 +01:00
BlockState state = world . getBlockState ( pos ) ;
if ( ! ( state . getBlock ( ) = = block ) ) { return false ; }
2018-06-23 01:39:30 +02:00
}
return true ;
}
2020-10-31 21:42:32 +01:00
public static ItemStack useItemAtSide ( Direction side , World world , BlockPos pos , ItemStack stack ) {
2020-10-31 22:01:43 +01:00
if ( world instanceof ServerWorld & & StackUtil . isValid ( stack ) & & pos ! = null ) {
2018-06-23 01:39:30 +02:00
BlockPos offsetPos = pos . offset ( side ) ;
2020-10-31 22:01:43 +01:00
BlockState state = world . getBlockState ( offsetPos ) ;
boolean replaceable = state . getMaterial ( ) . isReplaceable ( ) ;
2018-06-23 01:39:30 +02:00
//Redstone
if ( replaceable & & stack . getItem ( ) = = Items . REDSTONE ) {
world . setBlockState ( offsetPos , Blocks . REDSTONE_WIRE . getDefaultState ( ) , 2 ) ;
return StackUtil . shrink ( stack , 1 ) ;
}
//Plants
if ( replaceable & & stack . getItem ( ) instanceof IPlantable ) {
2020-10-31 22:01:43 +01:00
if ( ( ( IPlantable ) stack . getItem ( ) ) . getPlant ( world , offsetPos ) . isValidPosition ( world , offsetPos ) ) {
2018-06-23 01:39:30 +02:00
if ( world . setBlockState ( offsetPos , ( ( IPlantable ) stack . getItem ( ) ) . getPlant ( world , offsetPos ) , 2 ) ) return StackUtil . shrink ( stack , 1 ) ;
}
}
//Everything else
try {
2020-10-31 22:01:43 +01:00
FakePlayer fake = FakePlayerFactory . getMinecraft ( ( ServerWorld ) world ) ;
2019-05-02 09:39:05 +02:00
if ( fake . connection = = null ) fake . connection = new NetHandlerSpaghettiServer ( fake ) ;
2018-06-29 00:24:51 +02:00
ItemStack heldBefore = fake . getHeldItemMainhand ( ) ;
2020-10-31 22:01:43 +01:00
setHandItemWithoutAnnoyingSound ( fake , Hand . MAIN_HAND , stack . copy ( ) ) ;
fake . interactionManager . processRightClick ( fake , world , fake . getHeldItemMainhand ( ) , Hand . MAIN_HAND ) ;
ItemStack result = fake . getHeldItem ( Hand . MAIN_HAND ) ;
setHandItemWithoutAnnoyingSound ( fake , Hand . MAIN_HAND , heldBefore ) ;
2018-06-29 00:24:51 +02:00
return result ;
2018-06-23 01:39:30 +02:00
} catch ( Exception e ) {
2020-10-31 22:01:43 +01:00
ActuallyAdditions . LOGGER . error ( " Something that places Blocks at " + offsetPos . getX ( ) + " , " + offsetPos . getY ( ) + " , " + offsetPos . getZ ( ) + " in World " + world . getDimension ( ) + " threw an Exception! Don't let that happen again! " , e ) ;
2018-06-23 01:39:30 +02:00
}
}
return stack ;
}
2020-10-31 21:42:32 +01:00
public static boolean dropItemAtSide ( Direction side , World world , BlockPos pos , ItemStack stack ) {
2018-06-23 01:39:30 +02:00
BlockPos coords = pos . offset ( side ) ;
if ( world . isBlockLoaded ( coords ) ) {
2020-10-31 22:01:43 +01:00
ItemEntity item = new ItemEntity ( world , coords . getX ( ) + 0 . 5 , coords . getY ( ) + 0 . 5 , coords . getZ ( ) + 0 . 5 , stack ) ;
item . setMotion ( 0 , 0 , 0 ) ;
2018-06-23 01:39:30 +02:00
2020-10-31 22:01:43 +01:00
return world . addEntity ( item ) ;
2018-06-23 01:39:30 +02:00
}
return false ;
}
2020-10-31 21:42:32 +01:00
public static Direction getDirectionBySidesInOrder ( int side ) {
2018-06-23 01:39:30 +02:00
switch ( side ) {
case 0 :
2020-10-31 21:42:32 +01:00
return Direction . UP ;
2018-06-23 01:39:30 +02:00
case 1 :
2020-10-31 21:42:32 +01:00
return Direction . DOWN ;
2018-06-23 01:39:30 +02:00
case 2 :
2020-10-31 21:42:32 +01:00
return Direction . NORTH ;
2018-06-23 01:39:30 +02:00
case 3 :
2020-10-31 21:42:32 +01:00
return Direction . EAST ;
2018-06-23 01:39:30 +02:00
case 4 :
2020-10-31 21:42:32 +01:00
return Direction . SOUTH ;
2018-06-23 01:39:30 +02:00
default :
2020-10-31 21:42:32 +01:00
return Direction . WEST ;
2018-06-23 01:39:30 +02:00
}
}
2020-10-31 22:01:43 +01:00
public static Direction getDirectionByPistonRotation ( BlockState state ) {
return state . get ( BlockStateProperties . FACING ) ;
2018-06-23 01:39:30 +02:00
}
public static ArrayList < Material > getMaterialsAround ( World world , BlockPos pos ) {
2019-02-27 19:53:05 +01:00
ArrayList < Material > blocks = new ArrayList < > ( ) ;
2020-10-31 21:42:32 +01:00
blocks . add ( world . getBlockState ( pos . offset ( Direction . NORTH ) ) . getMaterial ( ) ) ;
blocks . add ( world . getBlockState ( pos . offset ( Direction . EAST ) ) . getMaterial ( ) ) ;
blocks . add ( world . getBlockState ( pos . offset ( Direction . SOUTH ) ) . getMaterial ( ) ) ;
blocks . add ( world . getBlockState ( pos . offset ( Direction . WEST ) ) . getMaterial ( ) ) ;
2018-06-23 01:39:30 +02:00
return blocks ;
}
2020-10-31 22:01:43 +01:00
public static RayTraceResult getNearestPositionWithAir ( World world , PlayerEntity player , int reach ) {
2018-06-23 01:39:30 +02:00
return getMovingObjectPosWithReachDistance ( world , player , reach , false , false , true ) ;
}
2020-10-31 22:01:43 +01:00
// todo: migrate to standard rayTrace
@Deprecated
private static RayTraceResult getMovingObjectPosWithReachDistance ( World world , PlayerEntity player , double distance , boolean p1 , boolean p2 , boolean p3 ) {
2018-06-23 01:39:30 +02:00
float f = player . rotationPitch ;
float f1 = player . rotationYaw ;
2020-10-31 22:01:43 +01:00
double d0 = player . getPosX ( ) ;
double d1 = player . getPosY ( ) + player . getEyeHeight ( ) ;
double d2 = player . getPosZ ( ) ;
2018-06-23 01:39:30 +02:00
Vec3d vec3 = new Vec3d ( d0 , d1 , d2 ) ;
float f2 = MathHelper . cos ( - f1 * 0 . 017453292F - ( float ) Math . PI ) ;
float f3 = MathHelper . sin ( - f1 * 0 . 017453292F - ( float ) Math . PI ) ;
float f4 = - MathHelper . cos ( - f * 0 . 017453292F ) ;
float f5 = MathHelper . sin ( - f * 0 . 017453292F ) ;
float f6 = f3 * f4 ;
float f7 = f2 * f4 ;
2019-02-27 19:53:05 +01:00
Vec3d vec31 = vec3 . add ( f6 * distance , f5 * distance , f7 * distance ) ;
2020-10-31 22:01:43 +01:00
return null ; // world.rayTraceBlocks(vec3, vec31, p1, p2, p3);
2018-06-23 01:39:30 +02:00
}
2020-10-31 21:42:32 +01:00
public static RayTraceResult getNearestBlockWithDefaultReachDistance ( World world , PlayerEntity player ) {
2018-06-23 01:39:30 +02:00
return getNearestBlockWithDefaultReachDistance ( world , player , false , true , false ) ;
}
2020-10-31 22:01:43 +01:00
public static RayTraceResult getNearestBlockWithDefaultReachDistance ( World world , PlayerEntity player , boolean stopOnLiquids , boolean ignoreBlockWithoutBoundingBox , boolean returnLastUncollidableBlock ) {
return getMovingObjectPosWithReachDistance ( world , player , player . getAttribute ( PlayerEntity . REACH_DISTANCE ) . getValue ( ) , stopOnLiquids , ignoreBlockWithoutBoundingBox , returnLastUncollidableBlock ) ;
2018-06-23 01:39:30 +02:00
}
2020-10-31 21:42:32 +01:00
public static void setHandItemWithoutAnnoyingSound ( PlayerEntity player , Hand hand , ItemStack stack ) {
if ( hand = = Hand . MAIN_HAND ) {
2018-06-23 01:39:30 +02:00
player . inventory . mainInventory . set ( player . inventory . currentItem , stack ) ;
2020-10-31 21:42:32 +01:00
} else if ( hand = = Hand . OFF_HAND ) {
2018-06-23 01:39:30 +02:00
player . inventory . offHandInventory . set ( 0 , stack ) ;
}
}
//I think something is up with this, but I'm not entirely certain what.
2019-05-02 09:32:05 +02:00
public static float fireFakeHarvestEventsForDropChance ( TileEntity caller , NonNullList < ItemStack > drops , World world , BlockPos pos ) {
2020-10-31 22:01:43 +01:00
if ( world instanceof ServerWorld ) {
FakePlayer fake = FakePlayerFactory . getMinecraft ( ( ServerWorld ) world ) ;
2019-05-02 09:32:05 +02:00
BlockPos tePos = caller . getPos ( ) ;
fake . setPosition ( tePos . getX ( ) + 0 . 5 , tePos . getY ( ) + 0 . 5 , tePos . getZ ( ) + 0 . 5 ) ;
2020-10-31 22:01:43 +01:00
BlockState state = world . getBlockState ( pos ) ;
2018-06-23 01:39:30 +02:00
BreakEvent event = new BreakEvent ( world , pos , state , fake ) ;
if ( ! MinecraftForge . EVENT_BUS . post ( event ) ) { return ForgeEventFactory . fireBlockHarvesting ( drops , world , pos , state , 0 , 1 , false , fake ) ; }
}
return 0F ;
}
/ * *
* Tries to break a block as if this player had broken it . This is a complex operation .
* @param stack The player ' s current held stack , main hand .
* @param world The player ' s world .
* @param player The player that is breaking this block .
* @param pos The pos to break .
* @return If the break was successful .
* /
2020-10-31 21:42:32 +01:00
public static boolean breakExtraBlock ( ItemStack stack , World world , PlayerEntity player , BlockPos pos ) {
BlockState state = world . getBlockState ( pos ) ;
2018-06-23 01:39:30 +02:00
Block block = state . getBlock ( ) ;
2020-10-31 21:42:32 +01:00
if ( player . isCreative ( ) ) {
if ( block . removedByPlayer ( state , world , pos , player , false , world . getFluidState ( pos ) ) ) {
2018-08-04 04:22:20 +02:00
block . onPlayerDestroy ( world , pos , state ) ;
2018-06-23 01:39:30 +02:00
}
// send update to client
if ( ! world . isRemote ) {
2020-10-31 22:01:43 +01:00
( ( ServerPlayerEntity ) player ) . connection . sendPacket ( new SChangeBlockPacket ( world , pos ) ) ;
2018-06-23 01:39:30 +02:00
}
return true ;
}
// callback to the tool the player uses. Called on both sides. This damages the tool n stuff.
stack . onBlockDestroyed ( world , state , pos , player ) ;
// server sided handling
if ( ! world . isRemote ) {
// send the blockbreak event
2020-10-31 21:42:32 +01:00
int xp = ForgeHooks . onBlockBreakEvent ( world , ( ( ServerPlayerEntity ) player ) . interactionManager . getGameType ( ) , ( ServerPlayerEntity ) player , pos ) ;
2018-06-23 01:39:30 +02:00
if ( xp = = - 1 ) return false ;
TileEntity tileEntity = world . getTileEntity ( pos ) ;
2020-10-31 21:42:32 +01:00
if ( block . removedByPlayer ( state , world , pos , player , true , world . getFluidState ( pos ) ) ) { // boolean is if block can be harvested, checked above
2018-08-04 04:22:20 +02:00
block . onPlayerDestroy ( world , pos , state ) ;
2018-06-23 01:39:30 +02:00
block . harvestBlock ( world , player , pos , state , tileEntity , stack ) ;
block . dropXpOnBlockBreak ( world , pos , xp ) ;
}
// always send block update to client
2020-10-31 22:01:43 +01:00
( ( ServerPlayerEntity ) player ) . connection . sendPacket ( new SChangeBlockPacket ( world , pos ) ) ;
2018-06-23 01:39:30 +02:00
return true ;
}
// client sided handling
else {
// clientside we do a "this block has been clicked on long enough to be broken" call. This should not send any new packets
// the code above, executed on the server, sends a block-updates that give us the correct state of the block we destroy.
// following code can be found in PlayerControllerMP.onPlayerDestroyBlock
world . playEvent ( 2001 , pos , Block . getStateId ( state ) ) ;
2020-10-31 21:42:32 +01:00
if ( block . removedByPlayer ( state , world , pos , player , true , world . getFluidState ( pos ) ) ) {
2018-08-04 04:22:20 +02:00
block . onPlayerDestroy ( world , pos , state ) ;
2018-06-23 01:39:30 +02:00
}
// callback to the tool
stack . onBlockDestroyed ( world , state , pos , player ) ;
// send an update to the server, so we get an update back
ActuallyAdditions . PROXY . sendBreakPacket ( pos ) ;
return true ;
}
}
2015-04-19 01:50:02 +02:00
}