1
0
mirror of https://github.com/SquidDev-CC/CC-Tweaked synced 2024-06-23 13:43:22 +00:00
CC-Tweaked/src/main/java/dan200/computercraft/shared/turtle/core/TurtleMoveCommand.java
SquidDev f9e13ca67a Update CC: Tweaked to 1.13
Look, I originally had this split into several commits, but lots of
other cleanups got mixed in. I then backported some of the cleanups to
1.12, did other tidy ups there, and eventually the web of merges was
unreadable.

Yes, this is a horrible mess, but it's still nicer than it was. Anyway,
changes:

 - Flatten everything. For instance, there are now three instances of
   BlockComputer, two BlockTurtle, ItemPocketComputer. There's also no
   more BlockPeripheral (thank heavens) - there's separate block classes
   for each peripheral type.

 - Remove pretty much all legacy code. As we're breaking world
   compatibility anyway, we can remove all the code to load worlds from
   1.4 days.
 - The command system is largely rewriten to take advantage of 1.13's
   new system. It's very fancy!

 - WidgetTerminal now uses Minecraft's "GUI listener" system.

 - BREAKING CHANGE: All the codes in keys.lua are different, due to the
   move to LWJGL 3. Hopefully this won't have too much of an impact.

   I don't want to map to the old key codes on the Java side, as there
   always ends up being small but slight inconsistencies. IMO it's
   better to make a clean break - people should be using keys rather
   than hard coding the constants anyway.

 - commands.list now allows fetching sub-commands. The ROM has already
   been updated to allow fancy usage such as commands.time.set("noon").

 - Turtles, modems and cables can be waterlogged.
2019-04-02 20:59:48 +01:00

169 lines
6.2 KiB
Java

/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.shared.turtle.core;
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.api.turtle.ITurtleAccess;
import dan200.computercraft.api.turtle.ITurtleCommand;
import dan200.computercraft.api.turtle.TurtleAnimation;
import dan200.computercraft.api.turtle.TurtleCommandResult;
import dan200.computercraft.api.turtle.event.TurtleBlockEvent;
import dan200.computercraft.shared.TurtlePermissions;
import dan200.computercraft.shared.util.WorldUtil;
import net.minecraft.block.state.IBlockState;
import net.minecraft.entity.Entity;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.shapes.VoxelShape;
import net.minecraft.world.World;
import net.minecraftforge.common.MinecraftForge;
import javax.annotation.Nonnull;
import java.util.List;
public class TurtleMoveCommand implements ITurtleCommand
{
private final MoveDirection m_direction;
public TurtleMoveCommand( MoveDirection direction )
{
m_direction = direction;
}
@Nonnull
@Override
public TurtleCommandResult execute( @Nonnull ITurtleAccess turtle )
{
// Get world direction from direction
EnumFacing direction = m_direction.toWorldDir( turtle );
// Check if we can move
World oldWorld = turtle.getWorld();
BlockPos oldPosition = turtle.getPosition();
BlockPos newPosition = oldPosition.offset( direction );
TurtlePlayer turtlePlayer = TurtlePlaceCommand.createPlayer( turtle, oldPosition, direction );
TurtleCommandResult canEnterResult = canEnter( turtlePlayer, oldWorld, newPosition );
if( !canEnterResult.isSuccess() )
{
return canEnterResult;
}
// Check existing block is air or replaceable
IBlockState state = oldWorld.getBlockState( newPosition );
if( !oldWorld.isAirBlock( newPosition ) &&
!WorldUtil.isLiquidBlock( oldWorld, newPosition ) &&
!state.getMaterial().isReplaceable() )
{
return TurtleCommandResult.failure( "Movement obstructed" );
}
// Check there isn't anything in the way
AxisAlignedBB aabb = getBox( state.getCollisionShape( oldWorld, oldPosition ) );
aabb = aabb.offset(
newPosition.getX(),
newPosition.getY(),
newPosition.getZ()
);
if( !oldWorld.checkNoEntityCollision( null, aabb ) )
{
if( !ComputerCraft.turtlesCanPush || m_direction == MoveDirection.Up || m_direction == MoveDirection.Down )
{
return TurtleCommandResult.failure( "Movement obstructed" );
}
// Check there is space for all the pushable entities to be pushed
List<Entity> list = oldWorld.getEntitiesWithinAABB( Entity.class, aabb, x -> x != null && x.isAlive() && x.preventEntitySpawning );
for( Entity entity : list )
{
AxisAlignedBB entityBB = entity.getBoundingBox();
if( entityBB == null ) entityBB = entity.getCollisionBoundingBox();
if( entityBB == null ) continue;
AxisAlignedBB pushedBB = entityBB.offset(
direction.getXOffset(),
direction.getYOffset(),
direction.getZOffset()
);
if( !oldWorld.checkNoEntityCollision( null, pushedBB ) )
{
return TurtleCommandResult.failure( "Movement obstructed" );
}
}
}
TurtleBlockEvent.Move moveEvent = new TurtleBlockEvent.Move( turtle, turtlePlayer, oldWorld, newPosition );
if( MinecraftForge.EVENT_BUS.post( moveEvent ) )
{
return TurtleCommandResult.failure( moveEvent.getFailureMessage() );
}
// Check fuel level
if( turtle.isFuelNeeded() && turtle.getFuelLevel() < 1 )
{
return TurtleCommandResult.failure( "Out of fuel" );
}
// Move
if( !turtle.teleportTo( oldWorld, newPosition ) ) return TurtleCommandResult.failure( "Movement failed" );
// Consume fuel
turtle.consumeFuel( 1 );
// Animate
switch( m_direction )
{
case Forward:
default:
turtle.playAnimation( TurtleAnimation.MoveForward );
break;
case Back:
turtle.playAnimation( TurtleAnimation.MoveBack );
break;
case Up:
turtle.playAnimation( TurtleAnimation.MoveUp );
break;
case Down:
turtle.playAnimation( TurtleAnimation.MoveDown );
break;
}
return TurtleCommandResult.success();
}
private static TurtleCommandResult canEnter( TurtlePlayer turtlePlayer, World world, BlockPos position )
{
if( World.isOutsideBuildHeight( position ) )
{
return TurtleCommandResult.failure( position.getY() < 0 ? "Too low to move" : "Too high to move" );
}
if( !World.isValid( position ) ) return TurtleCommandResult.failure( "Cannot leave the world" );
// Check spawn protection
if( ComputerCraft.turtlesObeyBlockProtection && !TurtlePermissions.isBlockEnterable( world, position, turtlePlayer ) )
{
return TurtleCommandResult.failure( "Cannot enter protected area" );
}
if( !world.isBlockLoaded( position ) ) return TurtleCommandResult.failure( "Cannot leave loaded world" );
if( !world.getWorldBorder().contains( position ) )
{
return TurtleCommandResult.failure( "Cannot pass the world border" );
}
return TurtleCommandResult.success();
}
private static AxisAlignedBB getBox( VoxelShape shape )
{
return shape.isEmpty() ? EMPTY_BOX : shape.getBoundingBox();
}
private static final AxisAlignedBB EMPTY_BOX = new AxisAlignedBB( 0, 0, 0, 0, 0, 0 );
}