2023-06-11 07:33:35 +00:00
/ *
* This file is part of Baritone .
*
* Baritone is free software : you can redistribute it and / or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation , either version 3 of the License , or
* ( at your option ) any later version .
*
* Baritone is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU Lesser General Public License for more details .
*
* You should have received a copy of the GNU Lesser General Public License
* along with Baritone . If not , see < https : //www.gnu.org/licenses/>.
* /
2023-06-17 06:55:07 +00:00
package baritone.behavior ;
2023-06-11 07:33:35 +00:00
2023-06-17 06:55:07 +00:00
import baritone.Baritone ;
2023-06-18 05:24:10 +00:00
import baritone.api.behavior.IElytraBehavior ;
2023-06-19 02:25:00 +00:00
import baritone.api.event.events.BlockChangeEvent ;
2023-06-17 04:35:56 +00:00
import baritone.api.event.events.ChunkEvent ;
2023-06-11 07:33:35 +00:00
import baritone.api.event.events.TickEvent ;
2023-06-18 15:57:13 +00:00
import baritone.api.utils.* ;
2023-06-17 07:02:26 +00:00
import baritone.behavior.elytra.NetherPathfinderContext ;
2023-06-17 19:15:57 +00:00
import baritone.behavior.elytra.UnpackedSegment ;
2023-06-11 07:33:35 +00:00
import baritone.utils.BlockStateInterface ;
2023-06-18 05:24:10 +00:00
import baritone.utils.accessor.IEntityFireworkRocket ;
2023-06-11 07:33:35 +00:00
import net.minecraft.block.material.Material ;
2023-06-13 04:43:10 +00:00
import net.minecraft.block.state.IBlockState ;
2023-06-11 07:33:35 +00:00
import net.minecraft.entity.item.EntityFireworkRocket ;
2023-06-18 05:24:10 +00:00
import net.minecraft.init.Items ;
import net.minecraft.item.ItemStack ;
import net.minecraft.nbt.NBTTagCompound ;
2023-06-19 01:06:32 +00:00
import net.minecraft.util.EnumFacing ;
2023-06-11 07:33:35 +00:00
import net.minecraft.util.EnumHand ;
2023-06-18 05:24:10 +00:00
import net.minecraft.util.NonNullList ;
import net.minecraft.util.math.AxisAlignedBB ;
import net.minecraft.util.math.BlockPos ;
import net.minecraft.util.math.MathHelper ;
import net.minecraft.util.math.Vec3d ;
2023-06-17 03:31:53 +00:00
import net.minecraft.world.chunk.Chunk ;
2023-06-11 07:33:35 +00:00
2023-06-13 04:43:10 +00:00
import java.util.* ;
2023-06-17 19:15:57 +00:00
import java.util.concurrent.CompletableFuture ;
import java.util.function.UnaryOperator ;
2023-06-11 07:33:35 +00:00
2023-06-18 05:24:10 +00:00
public final class ElytraBehavior extends Behavior implements IElytraBehavior , Helper {
2023-06-11 07:33:35 +00:00
2023-06-17 07:02:26 +00:00
/ * *
* 2b2t seed
* /
2023-06-17 03:31:53 +00:00
private static final long NETHER_SEED = 146008555100680L ;
2023-06-17 01:38:29 +00:00
// Used exclusively for PathRenderer
2023-06-19 01:06:32 +00:00
public List < Pair < Vec3d , Vec3d > > clearLines ;
public List < Pair < Vec3d , Vec3d > > blockedLines ;
2023-06-17 03:31:53 +00:00
public BlockPos aimPos ;
2023-06-17 01:53:53 +00:00
public List < BetterBlockPos > visiblePath ;
2023-06-17 01:38:29 +00:00
2023-06-17 06:39:21 +00:00
// :sunglasses:
2023-06-17 07:02:26 +00:00
private final NetherPathfinderContext context ;
2023-06-17 19:15:57 +00:00
private final PathManager pathManager ;
2023-06-17 01:38:29 +00:00
private int sinceFirework ;
2023-06-17 00:54:37 +00:00
2023-06-17 06:55:07 +00:00
public ElytraBehavior ( Baritone baritone ) {
2023-06-17 00:54:37 +00:00
super ( baritone ) ;
2023-06-17 07:02:26 +00:00
this . context = new NetherPathfinderContext ( NETHER_SEED ) ;
2023-06-19 01:06:32 +00:00
this . clearLines = new ArrayList < > ( ) ;
this . blockedLines = new ArrayList < > ( ) ;
2023-06-17 01:53:53 +00:00
this . visiblePath = Collections . emptyList ( ) ;
2023-06-17 19:15:57 +00:00
this . pathManager = new PathManager ( ) ;
2023-06-17 00:54:37 +00:00
}
2023-06-17 19:15:57 +00:00
private final class PathManager {
private BlockPos destination ;
private List < BetterBlockPos > path ;
private boolean completePath ;
private int playerNear ;
private boolean recalculating ;
public PathManager ( ) {
// lol imagine initializing fields normally
this . clear ( ) ;
2023-06-17 04:35:56 +00:00
}
2023-06-16 23:59:57 +00:00
2023-06-17 19:15:57 +00:00
public void tick ( ) {
// Recalculate closest path node
this . playerNear = this . calculateNear ( this . playerNear ) ;
2023-06-17 03:31:53 +00:00
2023-06-17 19:15:57 +00:00
// Obstacles are more important than an incomplete path, handle those first.
this . pathfindAroundObstacles ( ) ;
this . attemptNextSegment ( ) ;
2023-06-16 23:59:57 +00:00
}
2023-06-17 19:15:57 +00:00
public void pathToDestination ( BlockPos destination ) {
this . destination = destination ;
2023-06-19 06:09:43 +00:00
final long start = System . nanoTime ( ) ;
2023-06-17 19:15:57 +00:00
this . path0 ( ctx . playerFeet ( ) , destination , UnaryOperator . identity ( ) )
2023-06-18 01:16:26 +00:00
. thenRun ( ( ) - > {
2023-06-19 06:09:43 +00:00
final double distance = this . pathAt ( 0 ) . distanceTo ( this . pathAt ( this . path . size ( ) - 1 ) ) ;
2023-06-17 19:15:57 +00:00
if ( this . completePath ) {
2023-06-19 06:09:43 +00:00
logDirect ( String . format ( " Computed path (%.1f blocks in %.4f seconds) " , distance , ( System . nanoTime ( ) - start ) / 1e9d ) ) ;
2023-06-17 19:15:57 +00:00
} else {
2023-06-19 06:09:43 +00:00
logDirect ( String . format ( " Computed segment (Next %.1f blocks in %.4f seconds) " , distance , ( System . nanoTime ( ) - start ) / 1e9d ) ) ;
2023-06-17 19:15:57 +00:00
}
2023-06-18 01:16:26 +00:00
} )
. whenComplete ( ( result , ex ) - > {
this . recalculating = false ;
if ( ex ! = null ) {
logDirect ( " Failed to compute path to destination " ) ;
}
2023-06-17 19:15:57 +00:00
} ) ;
}
2023-06-19 06:09:43 +00:00
public void pathRecalcSegment ( final int blockedAt , final int upToIncl ) {
2023-06-17 19:15:57 +00:00
if ( this . recalculating ) {
return ;
2023-06-17 04:35:56 +00:00
}
2023-06-17 19:15:57 +00:00
this . recalculating = true ;
final List < BetterBlockPos > after = this . path . subList ( upToIncl , this . path . size ( ) ) ;
final boolean complete = this . completePath ;
2023-06-19 06:09:43 +00:00
final BetterBlockPos blockage = this . path . get ( blockedAt ) ;
final long start = System . nanoTime ( ) ;
2023-06-17 19:15:57 +00:00
this . path0 ( ctx . playerFeet ( ) , this . path . get ( upToIncl ) , segment - > segment . append ( after . stream ( ) , complete ) )
2023-06-18 01:16:26 +00:00
. thenRun ( ( ) - > {
final int recompute = this . path . size ( ) - after . size ( ) - 1 ;
2023-06-19 06:09:43 +00:00
final double distance = this . pathAt ( 0 ) . distanceTo ( this . pathAt ( recompute ) ) ; // in spirit same as ctx.playerFeet().distanceTo(this.path.get(upToIncl)), but, thread safe (those could have changed in the meantime)
logDirect ( String . format ( " Recalculated segment around path blockage near %s %s %s (next %.1f blocks in %.4f seconds) " , SettingsUtil . maybeCensor ( blockage . x ) , SettingsUtil . maybeCensor ( blockage . y ) , SettingsUtil . maybeCensor ( blockage . z ) , distance , ( System . nanoTime ( ) - start ) / 1e9d ) ) ;
2023-06-18 01:16:26 +00:00
} )
. whenComplete ( ( result , ex ) - > {
2023-06-17 19:15:57 +00:00
this . recalculating = false ;
2023-06-18 00:58:19 +00:00
if ( ex ! = null ) {
logDirect ( " Failed to recompute segment " ) ;
}
2023-06-17 19:15:57 +00:00
} ) ;
}
2023-06-17 19:21:32 +00:00
public void pathNextSegment ( final int afterIncl ) {
2023-06-17 19:15:57 +00:00
if ( this . recalculating ) {
2023-06-17 04:35:56 +00:00
return ;
}
2023-06-17 19:15:57 +00:00
this . recalculating = true ;
final List < BetterBlockPos > before = this . path . subList ( 0 , afterIncl + 1 ) ;
2023-06-19 06:09:43 +00:00
final long start = System . nanoTime ( ) ;
2023-06-17 19:15:57 +00:00
this . path0 ( this . path . get ( afterIncl ) , this . destination , segment - > segment . prepend ( before . stream ( ) ) )
2023-06-18 01:16:26 +00:00
. thenRun ( ( ) - > {
2023-06-17 19:15:57 +00:00
final int recompute = this . path . size ( ) - before . size ( ) - 1 ;
2023-06-19 06:09:43 +00:00
final double distance = this . pathAt ( 0 ) . distanceTo ( this . pathAt ( recompute ) ) ;
2023-06-17 19:15:57 +00:00
if ( this . completePath ) {
2023-06-19 06:09:43 +00:00
logDirect ( String . format ( " Computed path (%.1f blocks in %.4f seconds) " , distance , ( System . nanoTime ( ) - start ) / 1e9d ) ) ;
2023-06-17 19:15:57 +00:00
} else {
2023-06-19 06:09:43 +00:00
logDirect ( String . format ( " Computed segment (Next %.1f blocks in %.4f seconds) " , distance , ( System . nanoTime ( ) - start ) / 1e9d ) ) ;
2023-06-17 19:15:57 +00:00
}
2023-06-18 01:16:26 +00:00
} )
. whenComplete ( ( result , ex ) - > {
this . recalculating = false ;
if ( ex ! = null ) {
logDirect ( " Failed to compute next segment " ) ;
}
2023-06-17 19:15:57 +00:00
} ) ;
}
private Vec3d pathAt ( int i ) {
return new Vec3d (
2023-06-19 05:34:22 +00:00
this . path . get ( i ) . x ,
this . path . get ( i ) . y ,
this . path . get ( i ) . z
2023-06-17 19:15:57 +00:00
) ;
}
public void clear ( ) {
this . path = Collections . emptyList ( ) ;
this . playerNear = 0 ;
this . completePath = true ;
2023-06-19 02:46:03 +00:00
this . destination = null ;
2023-06-17 19:15:57 +00:00
}
private void setPath ( final UnpackedSegment segment ) {
this . path = segment . collect ( ) ;
this . removeBacktracks ( ) ;
this . playerNear = 0 ;
this . completePath = segment . isFinished ( ) ;
}
public List < BetterBlockPos > getPath ( ) {
return this . path ;
}
public int getNear ( ) {
return this . playerNear ;
}
// mickey resigned
private CompletableFuture < Void > path0 ( BlockPos src , BlockPos dst , UnaryOperator < UnpackedSegment > operator ) {
return ElytraBehavior . this . context . pathFindAsync ( src , dst )
. thenApply ( UnpackedSegment : : from )
. thenApply ( operator )
. thenAcceptAsync ( this : : setPath , ctx . minecraft ( ) : : addScheduledTask ) ;
}
private void pathfindAroundObstacles ( ) {
if ( this . recalculating ) {
return ;
2023-06-17 04:35:56 +00:00
}
2023-06-17 19:15:57 +00:00
outer :
while ( true ) {
int rangeStartIncl = playerNear ;
int rangeEndExcl = playerNear ;
while ( rangeEndExcl < path . size ( ) & & ctx . world ( ) . isBlockLoaded ( path . get ( rangeEndExcl ) , false ) ) {
rangeEndExcl + + ;
2023-06-17 04:35:56 +00:00
}
2023-06-17 19:15:57 +00:00
if ( rangeStartIncl > = rangeEndExcl ) {
// not loaded yet?
return ;
}
if ( ! passable ( ctx . world ( ) . getBlockState ( path . get ( rangeStartIncl ) ) ) ) {
// we're in a wall
return ; // previous iterations of this function SHOULD have fixed this by now :rage_cat:
}
for ( int i = rangeStartIncl ; i < rangeEndExcl - 1 ; i + + ) {
if ( ! clearView ( pathAt ( i ) , pathAt ( i + 1 ) ) ) {
// obstacle. where do we return to pathing?
// find the next valid segment
2023-06-19 06:09:43 +00:00
this . pathRecalcSegment ( i , rangeEndExcl - 1 ) ;
2023-06-17 19:15:57 +00:00
break outer ;
}
}
break ;
2023-06-17 04:35:56 +00:00
}
}
2023-06-16 23:59:57 +00:00
2023-06-17 19:15:57 +00:00
private void attemptNextSegment ( ) {
if ( this . recalculating ) {
return ;
}
2023-06-17 04:35:56 +00:00
2023-06-17 19:15:57 +00:00
final int last = this . path . size ( ) - 1 ;
if ( ! this . completePath & & ctx . world ( ) . isBlockLoaded ( this . path . get ( last ) , false ) ) {
2023-06-17 19:21:32 +00:00
this . pathNextSegment ( last ) ;
2023-06-17 19:15:57 +00:00
}
}
2023-06-17 06:39:21 +00:00
2023-06-17 19:15:57 +00:00
private int calculateNear ( int index ) {
final BetterBlockPos pos = ctx . playerFeet ( ) ;
for ( int i = index ; i > = Math . max ( index - 1000 , 0 ) ; i - = 10 ) {
if ( path . get ( i ) . distanceSq ( pos ) < path . get ( index ) . distanceSq ( pos ) ) {
index = i ; // intentional: this changes the bound of the loop
}
}
for ( int i = index ; i < Math . min ( index + 1000 , path . size ( ) ) ; i + = 10 ) {
if ( path . get ( i ) . distanceSq ( pos ) < path . get ( index ) . distanceSq ( pos ) ) {
index = i ; // intentional: this changes the bound of the loop
}
}
for ( int i = index ; i > = Math . max ( index - 50 , 0 ) ; i - - ) {
if ( path . get ( i ) . distanceSq ( pos ) < path . get ( index ) . distanceSq ( pos ) ) {
index = i ; // intentional: this changes the bound of the loop
}
}
for ( int i = index ; i < Math . min ( index + 50 , path . size ( ) ) ; i + + ) {
if ( path . get ( i ) . distanceSq ( pos ) < path . get ( index ) . distanceSq ( pos ) ) {
index = i ; // intentional: this changes the bound of the loop
}
}
return index ;
}
2023-06-17 06:39:21 +00:00
2023-06-17 19:15:57 +00:00
private void removeBacktracks ( ) {
Map < BetterBlockPos , Integer > positionFirstSeen = new HashMap < > ( ) ;
for ( int i = 0 ; i < this . path . size ( ) ; i + + ) {
BetterBlockPos pos = this . path . get ( i ) ;
if ( positionFirstSeen . containsKey ( pos ) ) {
int j = positionFirstSeen . get ( pos ) ;
while ( i > j ) {
this . path . remove ( i ) ;
i - - ;
}
2023-06-17 06:39:21 +00:00
} else {
2023-06-17 19:15:57 +00:00
positionFirstSeen . put ( pos , i ) ;
2023-06-17 06:39:21 +00:00
}
2023-06-17 19:15:57 +00:00
}
}
}
@Override
public void onChunkEvent ( ChunkEvent event ) {
2023-06-19 02:25:00 +00:00
if ( event . isPostPopulate ( ) ) {
2023-06-17 19:15:57 +00:00
final Chunk chunk = ctx . world ( ) . getChunk ( event . getX ( ) , event . getZ ( ) ) ;
this . context . queueForPacking ( chunk ) ;
}
}
2023-06-19 02:25:00 +00:00
@Override
public void onBlockChange ( BlockChangeEvent event ) {
event . getAffectedChunks ( ) . stream ( )
. map ( pos - > ctx . world ( ) . getChunk ( pos . x , pos . z ) )
. forEach ( this . context : : queueForPacking ) ;
}
2023-06-19 02:46:03 +00:00
@Override
public void pathTo ( BlockPos destination ) {
2023-06-17 19:15:57 +00:00
this . pathManager . pathToDestination ( destination ) ;
2023-06-11 07:33:35 +00:00
}
2023-06-19 02:46:03 +00:00
@Override
2023-06-16 03:59:01 +00:00
public void cancel ( ) {
2023-06-17 01:53:53 +00:00
this . visiblePath = Collections . emptyList ( ) ;
2023-06-17 19:15:57 +00:00
this . pathManager . clear ( ) ;
2023-06-17 03:31:53 +00:00
this . aimPos = null ;
2023-06-16 03:59:01 +00:00
this . sinceFirework = 0 ;
2023-06-18 05:24:10 +00:00
}
2023-06-19 02:46:03 +00:00
@Override
2023-06-18 05:24:10 +00:00
public boolean isActive ( ) {
2023-06-19 02:46:03 +00:00
return ! this . pathManager . getPath ( ) . isEmpty ( ) ;
2023-06-16 03:59:01 +00:00
}
2023-06-11 07:33:35 +00:00
@Override
public void onTick ( TickEvent event ) {
if ( event . getType ( ) = = TickEvent . Type . OUT ) {
return ;
}
2023-06-19 02:46:03 +00:00
2023-06-19 01:06:32 +00:00
this . clearLines . clear ( ) ;
this . blockedLines . clear ( ) ;
2023-06-17 19:15:57 +00:00
final List < BetterBlockPos > path = this . pathManager . getPath ( ) ;
2023-06-15 07:32:26 +00:00
if ( path . isEmpty ( ) ) {
return ;
}
2023-06-17 01:38:29 +00:00
2023-06-19 00:57:29 +00:00
this . bsi = new BlockStateInterface ( ctx ) ;
2023-06-17 19:15:57 +00:00
this . pathManager . tick ( ) ;
final int playerNear = this . pathManager . getNear ( ) ;
this . visiblePath = path . subList (
2023-06-17 01:53:53 +00:00
Math . max ( playerNear - 30 , 0 ) ,
2023-06-18 03:03:30 +00:00
Math . min ( playerNear + 100 , path . size ( ) )
2023-06-17 01:53:53 +00:00
) ;
2023-06-17 01:38:29 +00:00
if ( ! ctx . player ( ) . isElytraFlying ( ) ) {
return ;
}
2023-06-17 20:35:26 +00:00
baritone . getInputOverrideHandler ( ) . clearAllKeys ( ) ;
2023-06-17 01:38:29 +00:00
if ( ctx . player ( ) . collidedHorizontally ) {
logDirect ( " hbonk " ) ;
}
if ( ctx . player ( ) . collidedVertically ) {
logDirect ( " vbonk " ) ;
}
2023-06-18 05:11:40 +00:00
final Vec3d start = ctx . playerFeetAsVec ( ) ;
final boolean firework = isFireworkActive ( ) ;
2023-06-19 00:57:29 +00:00
BetterBlockPos goingTo = null ;
2023-06-18 18:23:41 +00:00
boolean forceUseFirework = false ;
2023-06-18 05:11:40 +00:00
this . sinceFirework + + ;
2023-06-17 05:39:50 +00:00
outermost :
2023-06-17 01:38:29 +00:00
for ( int relaxation = 0 ; relaxation < 3 ; relaxation + + ) { // try for a strict solution first, then relax more and more (if we're in a corner or near some blocks, it will have to relax its constraints a bit)
int [ ] heights = firework ? new int [ ] { 20 , 10 , 5 , 0 } : new int [ ] { 0 } ; // attempt to gain height, if we can, so as not to waste the boost
int steps = relaxation < 2 ? firework ? 5 : Baritone . settings ( ) . elytraSimulationTicks . value : 3 ;
int lookahead = relaxation = = 0 ? 2 : 3 ; // ideally this would be expressed as a distance in blocks, rather than a number of voxel steps
//int minStep = Math.max(0, playerNear - relaxation);
int minStep = playerNear ;
for ( int i = Math . min ( playerNear + 20 , path . size ( ) - 1 ) ; i > = minStep ; i - - ) {
for ( int dy : heights ) {
2023-06-17 19:15:57 +00:00
Vec3d dest = this . pathManager . pathAt ( i ) . add ( 0 , dy , 0 ) ;
2023-06-17 01:38:29 +00:00
if ( dy ! = 0 ) {
if ( i + lookahead > = path . size ( ) ) {
continue ;
}
if ( start . distanceTo ( dest ) < 40 ) {
2023-06-17 19:15:57 +00:00
if ( ! clearView ( dest , this . pathManager . pathAt ( i + lookahead ) . add ( 0 , dy , 0 ) ) | | ! clearView ( dest , this . pathManager . pathAt ( i + lookahead ) ) ) {
2023-06-17 01:38:29 +00:00
// aka: don't go upwards if doing so would prevent us from being able to see the next position **OR** the modified next position
2023-06-11 19:49:31 +00:00
continue ;
}
2023-06-17 01:38:29 +00:00
} else {
// but if it's far away, allow gaining altitude if we could lose it again by the time we get there
2023-06-17 19:15:57 +00:00
if ( ! clearView ( dest , this . pathManager . pathAt ( i ) ) ) {
2023-06-11 07:33:35 +00:00
continue ;
}
}
}
2023-06-18 00:36:29 +00:00
// 1.0 -> 0.25 -> none
final Double grow = relaxation = = 2 ? null
: relaxation = = 0 ? 1 . 0d : 0 . 25d ;
if ( isClear ( start , dest , grow ) ) {
2023-06-18 18:23:41 +00:00
final float yaw = RotationUtils . calcRotationFromVec3d ( start , dest , ctx . playerRotations ( ) ) . getYaw ( ) ;
final Pair < Float , Boolean > pitch = this . solvePitch ( dest . subtract ( start ) , steps , relaxation , firework ) ;
if ( pitch . first ( ) = = null ) {
2023-06-18 15:57:13 +00:00
baritone . getLookBehavior ( ) . updateTarget ( new Rotation ( yaw , ctx . playerRotations ( ) . getPitch ( ) ) , false ) ;
2023-06-17 01:38:29 +00:00
continue ;
}
2023-06-18 18:23:41 +00:00
forceUseFirework = pitch . second ( ) ;
2023-06-19 01:16:13 +00:00
goingTo = path . get ( i ) ;
2023-06-17 19:15:57 +00:00
this . aimPos = path . get ( i ) . add ( 0 , dy , 0 ) ;
2023-06-18 18:23:41 +00:00
baritone . getLookBehavior ( ) . updateTarget ( new Rotation ( yaw , pitch . first ( ) ) , false ) ;
2023-06-17 05:39:50 +00:00
break outermost ;
2023-06-17 01:38:29 +00:00
}
2023-06-11 07:33:35 +00:00
}
}
2023-06-17 05:39:50 +00:00
if ( relaxation = = 2 ) {
logDirect ( " no pitch solution, probably gonna crash in a few ticks LOL!!! " ) ;
return ;
}
}
2023-06-18 05:11:40 +00:00
final boolean useOnDescend = ! Baritone . settings ( ) . conserveFireworks . value | | ctx . player ( ) . posY < goingTo . y + 5 ;
2023-06-18 05:13:55 +00:00
final double currentSpeed = new Vec3d (
ctx . player ( ) . motionX ,
// ignore y component if we are BOTH below where we want to be AND descending
ctx . player ( ) . posY < goingTo . y ? Math . max ( 0 , ctx . player ( ) . motionY ) : ctx . player ( ) . motionY ,
ctx . player ( ) . motionZ
) . length ( ) ;
2023-06-17 19:15:57 +00:00
2023-06-18 18:23:41 +00:00
if ( forceUseFirework | | ( ! firework
2023-06-17 05:39:50 +00:00
& & sinceFirework > 10
2023-06-18 05:11:40 +00:00
& & useOnDescend
2023-06-17 19:15:57 +00:00
& & ( ctx . player ( ) . posY < goingTo . y - 5 | | start . distanceTo ( new Vec3d ( goingTo . x + 0 . 5 , ctx . player ( ) . posY , goingTo . z + 0 . 5 ) ) > 5 ) // UGH!!!!!!!
2023-06-18 18:23:41 +00:00
& & currentSpeed < Baritone . settings ( ) . elytraFireworkSpeed . value )
2023-06-17 05:39:50 +00:00
) {
2023-06-19 17:32:25 +00:00
// Prioritize boosting fireworks over regular ones
// TODO: Take the minimum boost time into account?
if ( ! baritone . getInventoryBehavior ( ) . throwaway ( true , ElytraBehavior : : isBoostingFireworks ) & &
! baritone . getInventoryBehavior ( ) . throwaway ( true , ElytraBehavior : : isFireworks ) ) {
logDirect ( " no fireworks " ) ;
return ;
2023-06-18 05:24:10 +00:00
}
2023-06-19 06:09:43 +00:00
logDirect ( " attempting to use firework " + ( forceUseFirework ? " takeoff " : " " ) ) ;
2023-06-17 05:39:50 +00:00
ctx . playerController ( ) . processRightClick ( ctx . player ( ) , ctx . world ( ) , EnumHand . MAIN_HAND ) ;
sinceFirework = 0 ;
2023-06-11 07:33:35 +00:00
}
}
2023-06-19 17:32:25 +00:00
private static boolean isFireworks ( final ItemStack itemStack ) {
if ( itemStack . getItem ( ) ! = Items . FIREWORKS ) {
return false ;
2023-06-18 05:24:10 +00:00
}
2023-06-19 17:32:25 +00:00
// If it has NBT data, make sure it won't cause us to explode.
final NBTTagCompound subCompound = itemStack . getSubCompound ( " Fireworks " ) ;
return subCompound = = null | | ! subCompound . hasKey ( " Explosions " ) ;
2023-06-18 05:24:10 +00:00
}
2023-06-19 17:32:25 +00:00
private static boolean isBoostingFireworks ( final ItemStack itemStack ) {
2023-06-18 05:24:10 +00:00
final NBTTagCompound subCompound = itemStack . getSubCompound ( " Fireworks " ) ;
2023-06-19 17:32:25 +00:00
return isFireworks ( itemStack ) & & subCompound ! = null & & subCompound . hasKey ( " Flight " ) ;
2023-06-18 05:24:10 +00:00
}
2023-06-17 01:38:29 +00:00
private boolean isFireworkActive ( ) {
2023-06-17 00:54:37 +00:00
return ctx . world ( ) . loadedEntityList . stream ( )
2023-06-18 05:24:10 +00:00
. filter ( x - > x instanceof EntityFireworkRocket )
. anyMatch ( x - > Objects . equals ( ( ( IEntityFireworkRocket ) x ) . getBoostedEntity ( ) , ctx . player ( ) ) ) ;
2023-06-11 07:33:35 +00:00
}
2023-06-18 00:36:29 +00:00
private boolean isClear ( final Vec3d start , final Vec3d dest , final Double growAmount ) {
if ( ! clearView ( start , dest ) ) {
return false ;
}
if ( growAmount = = null ) {
return true ;
}
final AxisAlignedBB bb = ctx . player ( ) . getEntityBoundingBox ( ) . grow ( growAmount ) ;
2023-06-19 05:34:22 +00:00
if ( Baritone . settings ( ) . experimentalRaytrace . value ) {
final double ox = dest . x - start . x ;
final double oy = dest . y - start . y ;
final double oz = dest . z - start . z ;
2023-06-19 06:09:43 +00:00
final double [ ] src = new double [ ] {
2023-06-19 05:34:22 +00:00
bb . minX , bb . minY , bb . minZ ,
bb . minX , bb . minY , bb . maxZ ,
bb . minX , bb . maxY , bb . minZ ,
bb . minX , bb . maxY , bb . maxZ ,
bb . maxX , bb . minY , bb . minZ ,
bb . maxX , bb . minY , bb . maxZ ,
bb . maxX , bb . maxY , bb . minZ ,
bb . maxX , bb . maxY , bb . maxZ ,
} ;
2023-06-19 06:09:43 +00:00
final double [ ] dst = new double [ ] {
2023-06-19 05:34:22 +00:00
bb . minX + ox , bb . minY + oy , bb . minZ + oz ,
bb . minX + ox , bb . minY + oy , bb . maxZ + oz ,
bb . minX + ox , bb . maxY + oy , bb . minZ + oz ,
bb . minX + ox , bb . maxY + oy , bb . maxZ + oz ,
bb . maxX + ox , bb . minY + oy , bb . minZ + oz ,
bb . maxX + ox , bb . minY + oy , bb . maxZ + oz ,
bb . maxX + ox , bb . maxY + oy , bb . minZ + oz ,
bb . maxX + ox , bb . maxY + oy , bb . maxZ + oz ,
} ;
// Batch together all 8 traces
final boolean [ ] hitOut = new boolean [ 8 ] ;
this . context . raytrace ( src , dst , hitOut ) ;
for ( boolean hit : hitOut ) {
if ( hit ) {
return false ;
}
}
return true ;
}
2023-06-18 03:03:30 +00:00
final Vec3d [ ] corners = new Vec3d [ ] {
2023-06-18 00:36:29 +00:00
new Vec3d ( bb . minX , bb . minY , bb . minZ ) ,
new Vec3d ( bb . minX , bb . minY , bb . maxZ ) ,
new Vec3d ( bb . minX , bb . maxY , bb . minZ ) ,
new Vec3d ( bb . minX , bb . maxY , bb . maxZ ) ,
new Vec3d ( bb . maxX , bb . minY , bb . minZ ) ,
new Vec3d ( bb . maxX , bb . minY , bb . maxZ ) ,
new Vec3d ( bb . maxX , bb . maxY , bb . minZ ) ,
new Vec3d ( bb . maxX , bb . maxY , bb . maxZ ) ,
} ;
for ( final Vec3d corner : corners ) {
if ( ! clearView ( corner , dest . add ( corner . subtract ( start ) ) ) ) {
return false ;
}
}
return true ;
2023-06-11 07:33:35 +00:00
}
private boolean clearView ( Vec3d start , Vec3d dest ) {
2023-06-19 05:34:22 +00:00
boolean clear = ! ( Baritone . settings ( ) . experimentalRaytrace . value
? this . context . raytrace ( start . x , start . y , start . z , dest . x , dest . y , dest . z )
: this . rayTraceBlocks ( start . x , start . y , start . z , dest . x , dest . y , dest . z ) // ox method
) ;
if ( clear ) {
2023-06-19 01:06:32 +00:00
clearLines . add ( new Pair < > ( start , dest ) ) ;
return true ;
} else {
blockedLines . add ( new Pair < > ( start , dest ) ) ;
return false ;
}
2023-06-11 07:33:35 +00:00
}
2023-06-18 18:23:41 +00:00
private Pair < Float , Boolean > solvePitch ( Vec3d goalDirection , int steps , int relaxation , boolean currentlyBoosted ) {
final Float pitch = this . solvePitch ( goalDirection , steps , relaxation = = 2 , currentlyBoosted ) ;
if ( pitch ! = null ) {
return new Pair < > ( pitch , false ) ;
}
if ( Baritone . settings ( ) . experimentalTakeoff . value & & relaxation > 0 ) {
final Float usingFirework = this . solvePitch ( goalDirection , steps , relaxation = = 2 , true ) ;
if ( usingFirework ! = null ) {
return new Pair < > ( usingFirework , true ) ;
}
}
return new Pair < > ( null , false ) ;
}
private Float solvePitch ( Vec3d goalDirection , int steps , boolean desperate , boolean firework ) {
2023-06-11 07:33:35 +00:00
// we are at a certain velocity, but we have a target velocity
// what pitch would get us closest to our target velocity?
// yaw is easy so we only care about pitch
goalDirection = goalDirection . normalize ( ) ;
Rotation good = RotationUtils . calcRotationFromVec3d ( new Vec3d ( 0 , 0 , 0 ) , goalDirection , ctx . playerRotations ( ) ) ; // lazy lol
Float bestPitch = null ;
double bestDot = Double . NEGATIVE_INFINITY ;
Vec3d motion = new Vec3d ( ctx . player ( ) . motionX , ctx . player ( ) . motionY , ctx . player ( ) . motionZ ) ;
2023-06-11 20:57:21 +00:00
float minPitch = desperate ? - 90 : Math . max ( good . getPitch ( ) - Baritone . settings ( ) . elytraPitchRange . value , - 89 ) ;
float maxPitch = desperate ? 90 : Math . min ( good . getPitch ( ) + Baritone . settings ( ) . elytraPitchRange . value , 89 ) ;
2023-06-11 07:33:35 +00:00
outer :
2023-06-11 20:57:21 +00:00
for ( float pitch = minPitch ; pitch < = maxPitch ; pitch + + ) {
2023-06-11 07:33:35 +00:00
Vec3d stepped = motion ;
Vec3d totalMotion = new Vec3d ( 0 , 0 , 0 ) ;
for ( int i = 0 ; i < steps ; i + + ) {
stepped = step ( stepped , pitch , good . getYaw ( ) , firework ) ;
2023-06-11 19:49:31 +00:00
Vec3d actualPositionPrevTick = ctx . playerFeetAsVec ( ) . add ( totalMotion ) ;
2023-06-11 07:33:35 +00:00
totalMotion = totalMotion . add ( stepped ) ;
Vec3d actualPosition = ctx . playerFeetAsVec ( ) . add ( totalMotion ) ;
2023-06-11 19:49:31 +00:00
for ( int x = MathHelper . floor ( Math . min ( actualPosition . x , actualPositionPrevTick . x ) - 0 . 31 ) ; x < = Math . max ( actualPosition . x , actualPositionPrevTick . x ) + 0 . 31 ; x + + ) {
2023-06-18 03:03:30 +00:00
for ( int y = MathHelper . floor ( Math . min ( actualPosition . y , actualPositionPrevTick . y ) - 0 . 2 ) ; y < = Math . max ( actualPosition . y , actualPositionPrevTick . y ) + 1 ; y + + ) {
2023-06-11 19:49:31 +00:00
for ( int z = MathHelper . floor ( Math . min ( actualPosition . z , actualPositionPrevTick . z ) - 0 . 31 ) ; z < = Math . max ( actualPosition . z , actualPositionPrevTick . z ) + 0 . 31 ; z + + ) {
2023-06-19 00:57:29 +00:00
if ( ! this . passable ( x , y , z ) ) {
2023-06-11 19:49:31 +00:00
continue outer ;
}
}
}
2023-06-11 07:33:35 +00:00
}
}
double directionalGoodness = goalDirection . dotProduct ( totalMotion . normalize ( ) ) ;
// tried to incorporate a "speedGoodness" but it kept making it do stupid stuff (aka always losing altitude)
double goodness = directionalGoodness ;
if ( goodness > bestDot ) {
bestDot = goodness ;
bestPitch = pitch ;
}
}
return bestPitch ;
}
2023-06-19 00:57:29 +00:00
private BlockStateInterface bsi ;
public boolean passable ( int x , int y , int z ) {
return passable ( this . bsi . get0 ( x , y , z ) ) ;
}
2023-06-17 07:02:26 +00:00
public static boolean passable ( IBlockState state ) {
2023-06-13 04:43:10 +00:00
return state . getMaterial ( ) = = Material . AIR ;
}
2023-06-17 00:54:37 +00:00
private static Vec3d step ( Vec3d motion , float rotationPitch , float rotationYaw , boolean firework ) {
2023-06-11 07:33:35 +00:00
double motionX = motion . x ;
double motionY = motion . y ;
double motionZ = motion . z ;
2023-06-19 18:17:54 +00:00
float flatZ = MathHelper . cos ( ( - rotationYaw * RotationUtils . DEG_TO_RAD_F ) - ( float ) Math . PI ) ;
float flatX = MathHelper . sin ( ( - rotationYaw * RotationUtils . DEG_TO_RAD_F ) - ( float ) Math . PI ) ;
float pitchBase = - MathHelper . cos ( - rotationPitch * RotationUtils . DEG_TO_RAD_F ) ;
float pitchHeight = MathHelper . sin ( - rotationPitch * RotationUtils . DEG_TO_RAD_F ) ;
2023-06-11 07:33:35 +00:00
Vec3d lookDirection = new Vec3d ( flatX * pitchBase , pitchHeight , flatZ * pitchBase ) ;
2023-06-17 01:38:29 +00:00
2023-06-11 19:49:31 +00:00
if ( firework ) {
2023-06-17 01:38:29 +00:00
// See EntityFireworkRocket
2023-06-11 19:49:31 +00:00
motionX + = lookDirection . x * 0 . 1 + ( lookDirection . x * 1 . 5 - motionX ) * 0 . 5 ;
motionY + = lookDirection . y * 0 . 1 + ( lookDirection . y * 1 . 5 - motionY ) * 0 . 5 ;
motionZ + = lookDirection . z * 0 . 1 + ( lookDirection . z * 1 . 5 - motionZ ) * 0 . 5 ;
}
2023-06-17 01:38:29 +00:00
2023-06-19 18:17:54 +00:00
float pitchRadians = rotationPitch * RotationUtils . DEG_TO_RAD_F ;
2023-06-11 07:33:35 +00:00
double pitchBase2 = Math . sqrt ( lookDirection . x * lookDirection . x + lookDirection . z * lookDirection . z ) ;
double flatMotion = Math . sqrt ( motionX * motionX + motionZ * motionZ ) ;
double thisIsAlwaysOne = lookDirection . length ( ) ;
float pitchBase3 = MathHelper . cos ( pitchRadians ) ;
//System.out.println("always the same lol " + -pitchBase + " " + pitchBase3);
//System.out.println("always the same lol " + Math.abs(pitchBase3) + " " + pitchBase2);
//System.out.println("always 1 lol " + thisIsAlwaysOne);
pitchBase3 = ( float ) ( ( double ) pitchBase3 * ( double ) pitchBase3 * Math . min ( 1 , thisIsAlwaysOne / 0 . 4 ) ) ;
motionY + = - 0 . 08 + ( double ) pitchBase3 * 0 . 06 ;
if ( motionY < 0 & & pitchBase2 > 0 ) {
double speedModifier = motionY * - 0 . 1 * ( double ) pitchBase3 ;
motionY + = speedModifier ;
motionX + = lookDirection . x * speedModifier / pitchBase2 ;
motionZ + = lookDirection . z * speedModifier / pitchBase2 ;
}
if ( pitchRadians < 0 ) { // if you are looking down (below level)
double anotherSpeedModifier = flatMotion * ( double ) ( - MathHelper . sin ( pitchRadians ) ) * 0 . 04 ;
motionY + = anotherSpeedModifier * 3 . 2 ;
motionX - = lookDirection . x * anotherSpeedModifier / pitchBase2 ;
motionZ - = lookDirection . z * anotherSpeedModifier / pitchBase2 ;
}
if ( pitchBase2 > 0 ) { // this is always true unless you are looking literally straight up (let's just say the bot will never do that)
motionX + = ( lookDirection . x / pitchBase2 * flatMotion - motionX ) * 0 . 1 ;
motionZ + = ( lookDirection . z / pitchBase2 * flatMotion - motionZ ) * 0 . 1 ;
}
motionX * = 0 . 99 ;
motionY * = 0 . 98 ;
motionZ * = 0 . 99 ;
//System.out.println(motionX + " " + motionY + " " + motionZ);
2023-06-11 19:49:31 +00:00
2023-06-11 07:33:35 +00:00
return new Vec3d ( motionX , motionY , motionZ ) ;
}
2023-06-19 00:57:29 +00:00
private boolean rayTraceBlocks ( final double startX , final double startY , final double startZ ,
2023-06-18 16:21:01 +00:00
final double endX , final double endY , final double endZ ) {
int voxelCurrX = fastFloor ( startX ) ;
int voxelCurrY = fastFloor ( startY ) ;
int voxelCurrZ = fastFloor ( startZ ) ;
2023-06-19 00:57:29 +00:00
if ( ! this . passable ( voxelCurrX , voxelCurrY , voxelCurrZ ) ) {
2023-06-18 16:21:01 +00:00
return true ;
}
final int voxelEndX = fastFloor ( endX ) ;
final int voxelEndY = fastFloor ( endY ) ;
final int voxelEndZ = fastFloor ( endZ ) ;
double currPosX = startX ;
double currPosY = startY ;
double currPosZ = startZ ;
int steps = 200 ; // TODO: should we lower the max steps?
2023-06-13 05:00:23 +00:00
while ( steps - - > = 0 ) {
2023-06-18 16:21:01 +00:00
if ( voxelCurrX = = voxelEndX & & voxelCurrY = = voxelEndY & & voxelCurrZ = = voxelEndZ ) {
return false ;
2023-06-13 05:00:23 +00:00
}
2023-06-18 16:21:01 +00:00
final double distanceFromStartToEndX = endX - currPosX ;
final double distanceFromStartToEndY = endY - currPosY ;
final double distanceFromStartToEndZ = endZ - currPosZ ;
double nextIntegerX ;
double nextIntegerY ;
double nextIntegerZ ;
// potentially more based branchless impl?
nextIntegerX = voxelCurrX + ( ( voxelCurrX - voxelEndX ) > > > 31 ) ; // if voxelEnd > voxelIn, then voxelIn-voxelEnd will be negative, meaning the sign bit is 1
nextIntegerY = voxelCurrY + ( ( voxelCurrY - voxelEndY ) > > > 31 ) ; // if we do an unsigned right shift by 31, that sign bit becomes the LSB
nextIntegerZ = voxelCurrZ + ( ( voxelCurrZ - voxelEndZ ) > > > 31 ) ; // therefore, this increments nextInteger iff EndX>inX, otherwise it leaves it alone
// remember: don't have to worry about the case when voxelEnd == voxelIn, because nextInteger value wont be used
// these just have to be strictly greater than 1, might as well just go up to the next int
double fracIfSkipX = 2 . 0D ;
double fracIfSkipY = 2 . 0D ;
double fracIfSkipZ = 2 . 0D ;
// reminder to future self: don't "branchlessify" this, it's MUCH slower (pretty obviously, floating point div is much worse than a branch mispredict, but integer increment (like the other two removed branches) are cheap enough to be worth doing either way)
if ( voxelEndX ! = voxelCurrX ) {
fracIfSkipX = ( nextIntegerX - currPosX ) / distanceFromStartToEndX ;
2023-06-13 05:00:23 +00:00
}
2023-06-18 16:21:01 +00:00
if ( voxelEndY ! = voxelCurrY ) {
fracIfSkipY = ( nextIntegerY - currPosY ) / distanceFromStartToEndY ;
2023-06-13 05:00:23 +00:00
}
2023-06-18 16:21:01 +00:00
if ( voxelEndZ ! = voxelCurrZ ) {
fracIfSkipZ = ( nextIntegerZ - currPosZ ) / distanceFromStartToEndZ ;
2023-06-13 05:00:23 +00:00
}
2023-06-18 16:21:01 +00:00
if ( fracIfSkipX < fracIfSkipY & & fracIfSkipX < fracIfSkipZ ) {
// note: voxelEndX == voxelInX is impossible because allowSkip would be set to false in that case, meaning that the elapsed distance would stay at default
currPosX = nextIntegerX ;
currPosY + = distanceFromStartToEndY * fracIfSkipX ;
currPosZ + = distanceFromStartToEndZ * fracIfSkipX ;
// tested: faster to paste this 3 times with only one of the subtractions in each
final int xFloorOffset = ( voxelEndX - voxelCurrX ) > > > 31 ;
voxelCurrX = ( fastFloor ( currPosX ) - xFloorOffset ) ;
voxelCurrY = ( fastFloor ( currPosY ) ) ;
voxelCurrZ = ( fastFloor ( currPosZ ) ) ;
} else if ( fracIfSkipY < fracIfSkipZ ) {
currPosX + = distanceFromStartToEndX * fracIfSkipY ;
currPosY = nextIntegerY ;
currPosZ + = distanceFromStartToEndZ * fracIfSkipY ;
// tested: faster to paste this 3 times with only one of the subtractions in each
final int yFloorOffset = ( voxelEndY - voxelCurrY ) > > > 31 ;
voxelCurrX = ( fastFloor ( currPosX ) ) ;
voxelCurrY = ( fastFloor ( currPosY ) - yFloorOffset ) ;
voxelCurrZ = ( fastFloor ( currPosZ ) ) ;
2023-06-13 05:00:23 +00:00
} else {
2023-06-18 16:21:01 +00:00
currPosX + = distanceFromStartToEndX * fracIfSkipZ ;
currPosY + = distanceFromStartToEndY * fracIfSkipZ ;
currPosZ = nextIntegerZ ;
// tested: faster to paste this 3 times with only one of the subtractions in each
final int zFloorOffset = ( voxelEndZ - voxelCurrZ ) > > > 31 ;
voxelCurrX = ( fastFloor ( currPosX ) ) ;
voxelCurrY = ( fastFloor ( currPosY ) ) ;
voxelCurrZ = ( fastFloor ( currPosZ ) - zFloorOffset ) ;
2023-06-13 05:00:23 +00:00
}
2023-06-18 16:21:01 +00:00
2023-06-19 00:57:29 +00:00
if ( ! this . passable ( voxelCurrX , voxelCurrY , voxelCurrZ ) ) {
2023-06-18 16:21:01 +00:00
return true ;
2023-06-13 05:00:23 +00:00
}
}
2023-06-18 16:21:01 +00:00
return false ;
}
private static final double FLOOR_DOUBLE_D = 1_073_741_824 . 0 ;
private static final int FLOOR_DOUBLE_I = 1_073_741_824 ;
private static int fastFloor ( final double v ) {
return ( ( int ) ( v + FLOOR_DOUBLE_D ) ) - FLOOR_DOUBLE_I ;
}
2023-06-19 01:06:32 +00:00
private boolean rayTraceBlocks ( Vec3d start , Vec3d end ) {
int x1 = MathHelper . floor ( end . x ) ;
int y1 = MathHelper . floor ( end . y ) ;
int z1 = MathHelper . floor ( end . z ) ;
int x2 = MathHelper . floor ( start . x ) ;
int y2 = MathHelper . floor ( start . y ) ;
int z2 = MathHelper . floor ( start . z ) ;
BlockPos blockpos = new BlockPos ( x2 , y2 , z2 ) ;
IBlockState iblockstate = ctx . world ( ) . getBlockState ( blockpos ) ;
if ( ! passable ( iblockstate ) ) {
return true ;
2023-06-18 16:21:01 +00:00
}
2023-06-19 01:06:32 +00:00
int steps = 200 ;
while ( steps - - > = 0 ) {
if ( Double . isNaN ( start . x ) | | Double . isNaN ( start . y ) | | Double . isNaN ( start . z ) ) {
return false ;
}
if ( x2 = = x1 & & y2 = = y1 & & z2 = = z1 ) {
return false ;
}
boolean hitX = true ;
boolean hitY = true ;
boolean hitZ = true ;
double nextX = 999 . 0D ;
double nextY = 999 . 0D ;
double nextZ = 999 . 0D ;
if ( x1 > x2 ) {
nextX = ( double ) x2 + 1 . 0D ;
} else if ( x1 < x2 ) {
nextX = ( double ) x2 + 0 . 0D ;
} else {
hitX = false ;
}
if ( y1 > y2 ) {
nextY = ( double ) y2 + 1 . 0D ;
} else if ( y1 < y2 ) {
nextY = ( double ) y2 + 0 . 0D ;
} else {
hitY = false ;
}
if ( z1 > z2 ) {
nextZ = ( double ) z2 + 1 . 0D ;
} else if ( z1 < z2 ) {
nextZ = ( double ) z2 + 0 . 0D ;
} else {
hitZ = false ;
}
double stepX = 999 . 0D ;
double stepY = 999 . 0D ;
double stepZ = 999 . 0D ;
double dirX = end . x - start . x ;
double dirY = end . y - start . y ;
double dirZ = end . z - start . z ;
if ( hitX ) {
stepX = ( nextX - start . x ) / dirX ;
}
if ( hitY ) {
stepY = ( nextY - start . y ) / dirY ;
}
if ( hitZ ) {
stepZ = ( nextZ - start . z ) / dirZ ;
}
if ( stepX = = - 0 . 0D ) {
stepX = - 1 . 0E - 4D ;
}
if ( stepY = = - 0 . 0D ) {
stepY = - 1 . 0E - 4D ;
}
if ( stepZ = = - 0 . 0D ) {
stepZ = - 1 . 0E - 4D ;
}
EnumFacing dir ;
if ( stepX < stepY & & stepX < stepZ ) {
dir = x1 > x2 ? EnumFacing . WEST : EnumFacing . EAST ;
start = new Vec3d ( nextX , start . y + dirY * stepX , start . z + dirZ * stepX ) ;
} else if ( stepY < stepZ ) {
dir = y1 > y2 ? EnumFacing . DOWN : EnumFacing . UP ;
start = new Vec3d ( start . x + dirX * stepY , nextY , start . z + dirZ * stepY ) ;
} else {
dir = z1 > z2 ? EnumFacing . NORTH : EnumFacing . SOUTH ;
start = new Vec3d ( start . x + dirX * stepZ , start . y + dirY * stepZ , nextZ ) ;
}
x2 = MathHelper . floor ( start . x ) - ( dir = = EnumFacing . EAST ? 1 : 0 ) ;
y2 = MathHelper . floor ( start . y ) - ( dir = = EnumFacing . UP ? 1 : 0 ) ;
z2 = MathHelper . floor ( start . z ) - ( dir = = EnumFacing . SOUTH ? 1 : 0 ) ;
blockpos = new BlockPos ( x2 , y2 , z2 ) ;
IBlockState iblockstate1 = ctx . world ( ) . getBlockState ( blockpos ) ;
if ( ! passable ( iblockstate1 ) ) {
return true ;
}
}
return false ;
2023-06-13 05:00:23 +00:00
}
2023-06-18 05:24:10 +00:00
}