mirror of
https://github.com/SquidDev-CC/CC-Tweaked
synced 2024-06-23 13:43:22 +00:00
![SquidDev](/assets/img/avatar_default.png)
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.
169 lines
6.2 KiB
Java
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 );
|
|
}
|