1
0
mirror of https://github.com/SquidDev-CC/CC-Tweaked synced 2024-07-04 11:03:22 +00:00
CC-Tweaked/src/main/java/dan200/computercraft/shared/turtle/core/TurtleBrain.java
Daniel Ratcliffe e85cdacbc5 ComputerCraft 1.79 initial upload
Added the complete source code to ComputerCraft 1.79 for Minecraft
1.8.9, plus newly written README and LICENSE files for the open source
release.
2017-05-01 14:32:39 +01:00

1177 lines
36 KiB
Java

/**
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2016. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.shared.turtle.core;
import com.google.common.base.Objects;
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.api.lua.ILuaContext;
import dan200.computercraft.api.lua.LuaException;
import dan200.computercraft.api.peripheral.IPeripheral;
import dan200.computercraft.api.turtle.*;
import dan200.computercraft.shared.computer.core.ComputerFamily;
import dan200.computercraft.shared.computer.core.IComputer;
import dan200.computercraft.shared.computer.core.ServerComputer;
import dan200.computercraft.shared.turtle.blocks.TileTurtle;
import dan200.computercraft.shared.util.Colour;
import dan200.computercraft.shared.util.DirectionUtil;
import dan200.computercraft.shared.util.Holiday;
import dan200.computercraft.shared.util.HolidayUtil;
import net.minecraft.block.Block;
import net.minecraft.block.state.IBlockState;
import net.minecraft.entity.Entity;
import net.minecraft.inventory.IInventory;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.*;
import net.minecraft.world.World;
import net.minecraftforge.common.util.Constants;
import java.lang.ref.WeakReference;
import java.util.*;
public class TurtleBrain implements ITurtleAccess
{
private static int s_nextInstanceID = 0;
private static Map<Integer, WeakReference<TurtleBrain>> s_allClientBrains = new HashMap<Integer, WeakReference<TurtleBrain>>();
public static int assignInstanceID()
{
return s_nextInstanceID++;
}
public static TurtleBrain getClientBrain( int instanceID )
{
if( instanceID >= 0 )
{
WeakReference<TurtleBrain> ref = s_allClientBrains.get( instanceID );
if( ref != null )
{
TurtleBrain brain = ref.get();
if( brain != null )
{
return brain;
}
else
{
s_allClientBrains.remove( instanceID );
}
}
}
return null;
}
public static void setClientBrain( int instanceID, TurtleBrain brain )
{
if( instanceID >= 0 )
{
if( getClientBrain( instanceID ) != brain )
{
s_allClientBrains.put( instanceID, new WeakReference<TurtleBrain>( brain ) );
}
}
}
public static void cleanupBrains()
{
if( s_allClientBrains.size() > 0 )
{
Iterator<Map.Entry<Integer, WeakReference<TurtleBrain>>> it = s_allClientBrains.entrySet().iterator();
while( it.hasNext() )
{
Map.Entry<Integer, WeakReference<TurtleBrain>> entry = it.next();
WeakReference<TurtleBrain> ref = entry.getValue();
if( ref != null )
{
TurtleBrain brain = ref.get();
if( brain == null )
{
it.remove();
}
}
}
}
}
private static final int ANIM_DURATION = 8;
private TileTurtle m_owner;
private LinkedList<TurtleCommandQueueEntry> m_commandQueue;
private int m_commandsIssued;
private Map<TurtleSide, ITurtleUpgrade> m_upgrades;
private Map<TurtleSide, IPeripheral> m_peripherals;
private Map<TurtleSide, NBTTagCompound> m_upgradeNBTData;
private int m_selectedSlot;
private int m_fuelLevel;
private Colour m_colour;
private ResourceLocation m_overlay;
private int m_instanceID;
private EnumFacing m_direction;
private TurtleAnimation m_animation;
private int m_animationProgress;
private int m_lastAnimationProgress;
public TurtleBrain( TileTurtle turtle )
{
m_owner = turtle;
m_commandQueue = new LinkedList<TurtleCommandQueueEntry>();
m_commandsIssued = 0;
m_upgrades = new HashMap<TurtleSide, ITurtleUpgrade>();
m_peripherals = new HashMap<TurtleSide, IPeripheral>();
m_upgradeNBTData = new HashMap<TurtleSide, NBTTagCompound>();
m_selectedSlot = 0;
m_fuelLevel = 0;
m_colour = null;
m_overlay = null;
m_instanceID = -1;
m_direction = EnumFacing.NORTH;
m_animation = TurtleAnimation.None;
m_animationProgress = 0;
m_lastAnimationProgress = 0;
}
public TurtleBrain getFutureSelf()
{
if( getOwner().getWorld().isRemote )
{
TurtleBrain futureSelf = getClientBrain( m_instanceID );
if( futureSelf != null )
{
return futureSelf;
}
}
return this;
}
public void setOwner( TileTurtle owner )
{
m_owner = owner;
}
public TileTurtle getOwner()
{
return m_owner;
}
public ComputerFamily getFamily()
{
return m_owner.getFamily();
}
public void setupComputer( ServerComputer computer )
{
updatePeripherals( computer );
}
public void update()
{
World world = getWorld();
if( !world.isRemote )
{
// Advance movement
updateCommands();
}
// Advance animation
updateAnimation();
// Advance upgrades
if( !m_upgrades.isEmpty() )
{
for( Map.Entry<TurtleSide, ITurtleUpgrade> entry : m_upgrades.entrySet() )
{
entry.getValue().update( this, entry.getKey() );
}
}
}
public void readFromNBT( NBTTagCompound nbttagcompound )
{
// Read state
m_direction = EnumFacing.getFront( nbttagcompound.getInteger( "dir" ) );
m_selectedSlot = nbttagcompound.getInteger( "selectedSlot" );
if( nbttagcompound.hasKey( "fuelLevel" ) )
{
m_fuelLevel = nbttagcompound.getInteger( "fuelLevel" );
}
else
{
m_fuelLevel = 0;
}
// Read colour
if( nbttagcompound.hasKey( "colourIndex" ) )
{
m_colour = Colour.values()[ nbttagcompound.getInteger( "colourIndex" ) ];
}
else
{
m_colour = null;
}
// Read overlay
if( nbttagcompound.hasKey( "overlay_mod" ) )
{
String overlay_mod = nbttagcompound.getString( "overlay_mod" );
if( nbttagcompound.hasKey( "overlay_path" ) )
{
String overlay_path = nbttagcompound.getString( "overlay_path" );
m_overlay = new ResourceLocation( overlay_mod, overlay_path );
}
else
{
m_overlay = null;
}
}
else
{
m_overlay = null;
}
// Read upgrades
// (pre-1.4 turtles will have a "subType" variable, newer things will have "leftUpgrade" and "rightUpgrade")
ITurtleUpgrade leftUpgrade = null;
ITurtleUpgrade rightUpgrade = null;
if( nbttagcompound.hasKey( "subType" ) )
{
// Loading a pre-1.4 world
int subType = nbttagcompound.getInteger( "subType" );
if( (subType & 0x1) > 0 )
{
leftUpgrade = ComputerCraft.Upgrades.diamondPickaxe;
}
if( (subType & 0x2) > 0 )
{
rightUpgrade = ComputerCraft.Upgrades.wirelessModem;
}
}
else
{
// Loading a post-1.4 world
if( nbttagcompound.hasKey( "leftUpgrade" ) )
{
if( nbttagcompound.getTagId( "leftUpgrade" ) == Constants.NBT.TAG_STRING )
{
leftUpgrade = ComputerCraft.getTurtleUpgrade( nbttagcompound.getString( "leftUpgrade" ) );
}
else
{
leftUpgrade = ComputerCraft.getTurtleUpgrade( nbttagcompound.getShort( "leftUpgrade" ) );
}
}
if( nbttagcompound.hasKey( "rightUpgrade" ) )
{
if( nbttagcompound.getTagId( "rightUpgrade" ) == Constants.NBT.TAG_STRING )
{
rightUpgrade = ComputerCraft.getTurtleUpgrade( nbttagcompound.getString( "rightUpgrade" ) );
}
else
{
rightUpgrade = ComputerCraft.getTurtleUpgrade( nbttagcompound.getShort( "rightUpgrade" ) );
}
}
}
setUpgrade( TurtleSide.Left, leftUpgrade );
setUpgrade( TurtleSide.Right, rightUpgrade );
// NBT
m_upgradeNBTData.clear();
if( nbttagcompound.hasKey( "leftUpgradeNBT" ) )
{
m_upgradeNBTData.put( TurtleSide.Left, (NBTTagCompound) nbttagcompound.getCompoundTag( "leftUpgradeNBT" ).copy() );
}
if( nbttagcompound.hasKey( "rightUpgradeNBT" ) )
{
m_upgradeNBTData.put( TurtleSide.Right, (NBTTagCompound) nbttagcompound.getCompoundTag( "rightUpgradeNBT" ).copy() );
}
}
public void writeToNBT( NBTTagCompound nbttagcompound )
{
// Write state
nbttagcompound.setInteger( "dir", m_direction.getIndex() );
nbttagcompound.setInteger( "selectedSlot", m_selectedSlot );
nbttagcompound.setInteger( "fuelLevel", m_fuelLevel );
// Write upgrades
String leftUpgradeID = getUpgradeID( getUpgrade( TurtleSide.Left ) );
if( leftUpgradeID != null )
{
nbttagcompound.setString( "leftUpgrade", leftUpgradeID );
}
String rightUpgradeID = getUpgradeID( getUpgrade( TurtleSide.Right ) );
if( rightUpgradeID != null )
{
nbttagcompound.setString( "rightUpgrade", rightUpgradeID );
}
// Write colour
if( m_colour != null )
{
nbttagcompound.setInteger( "colourIndex", m_colour.ordinal() );
}
// Write overlay
if( m_overlay != null )
{
nbttagcompound.setString( "overlay_mod", m_overlay.getResourceDomain() );
nbttagcompound.setString( "overlay_path", m_overlay.getResourcePath() );
}
// Write NBT
if( m_upgradeNBTData.containsKey( TurtleSide.Left ) )
{
nbttagcompound.setTag( "leftUpgradeNBT", (NBTTagCompound) getUpgradeNBTData( TurtleSide.Left ).copy() );
}
if( m_upgradeNBTData.containsKey( TurtleSide.Right ) )
{
nbttagcompound.setTag( "rightUpgradeNBT", (NBTTagCompound) getUpgradeNBTData( TurtleSide.Right ).copy() );
}
}
private String getUpgradeID( ITurtleUpgrade upgrade )
{
if( upgrade != null )
{
return upgrade.getUpgradeID().toString();
}
return null;
}
public void writeDescription( NBTTagCompound nbttagcompound )
{
// Upgrades
String leftUpgradeID = getUpgradeID( getUpgrade( TurtleSide.Left ) );
if( leftUpgradeID != null )
{
nbttagcompound.setString( "leftUpgrade", leftUpgradeID );
}
String rightUpgradeID = getUpgradeID( getUpgrade( TurtleSide.Right ) );
if( rightUpgradeID != null )
{
nbttagcompound.setString( "rightUpgrade", rightUpgradeID );
}
// NBT
if( m_upgradeNBTData.containsKey( TurtleSide.Left ) )
{
nbttagcompound.setTag( "leftUpgradeNBT", (NBTTagCompound) getUpgradeNBTData( TurtleSide.Left ).copy() );
}
if( m_upgradeNBTData.containsKey( TurtleSide.Right ) )
{
nbttagcompound.setTag( "rightUpgradeNBT", (NBTTagCompound) getUpgradeNBTData( TurtleSide.Right ).copy() );
}
// Colour
if( m_colour != null )
{
nbttagcompound.setInteger( "colourIndex", m_colour.ordinal() );
}
// Overlay
if( m_overlay != null )
{
nbttagcompound.setString( "overlay_mod", m_overlay.getResourceDomain() );
nbttagcompound.setString( "overlay_path", m_overlay.getResourcePath() );
}
// Animation
if( m_instanceID < 0 )
{
m_instanceID = assignInstanceID();
}
nbttagcompound.setInteger( "brainInstanceID", m_instanceID );
nbttagcompound.setInteger( "animation", m_animation.ordinal() );
nbttagcompound.setInteger( "direction", m_direction.getIndex() );
nbttagcompound.setInteger( "fuelLevel", m_fuelLevel );
}
public void readDescription( NBTTagCompound nbttagcompound )
{
// Upgrades
if( nbttagcompound.hasKey( "leftUpgrade" ) )
{
setUpgrade( TurtleSide.Left, ComputerCraft.getTurtleUpgrade( nbttagcompound.getString( "leftUpgrade" ) ) );
}
else
{
setUpgrade( TurtleSide.Left, null );
}
if( nbttagcompound.hasKey( "rightUpgrade" ) )
{
setUpgrade( TurtleSide.Right, ComputerCraft.getTurtleUpgrade( nbttagcompound.getString( "rightUpgrade" ) ) );
}
else
{
setUpgrade( TurtleSide.Right, null );
}
// NBT
m_upgradeNBTData.clear();
if( nbttagcompound.hasKey( "leftUpgradeNBT" ) )
{
m_upgradeNBTData.put( TurtleSide.Left, (NBTTagCompound) nbttagcompound.getCompoundTag( "leftUpgradeNBT" ).copy() );
}
if( nbttagcompound.hasKey( "rightUpgradeNBT" ) )
{
m_upgradeNBTData.put( TurtleSide.Right, (NBTTagCompound)nbttagcompound.getCompoundTag( "rightUpgradeNBT" ).copy() );
}
// Colour
if( nbttagcompound.hasKey( "colourIndex" ) )
{
m_colour = Colour.values()[ nbttagcompound.getInteger( "colourIndex" ) ];
}
else
{
m_colour = null;
}
// Overlay
if( nbttagcompound.hasKey( "overlay_mod" ) && nbttagcompound.hasKey( "overlay_path" ) )
{
String overlay_mod = nbttagcompound.getString( "overlay_mod" );
String overlay_path = nbttagcompound.getString( "overlay_path" );
m_overlay = new ResourceLocation( overlay_mod, overlay_path );
}
else
{
m_overlay = null;
}
// Animation
m_instanceID = nbttagcompound.getInteger( "brainInstanceID" );
setClientBrain( m_instanceID, this );
TurtleAnimation anim = TurtleAnimation.values()[ nbttagcompound.getInteger( "animation" ) ];
if( anim != m_animation &&
anim != TurtleAnimation.Wait &&
anim != TurtleAnimation.ShortWait &&
anim != TurtleAnimation.None )
{
m_animation = TurtleAnimation.values()[ nbttagcompound.getInteger( "animation" ) ];
m_animationProgress = 0;
m_lastAnimationProgress = 0;
}
m_direction = EnumFacing.getFront( nbttagcompound.getInteger( "direction" ) );
m_fuelLevel = nbttagcompound.getInteger( "fuelLevel" );
}
@Override
public World getWorld()
{
return m_owner.getWorld();
}
@Override
public BlockPos getPosition()
{
return m_owner.getPos();
}
@Override
public boolean teleportTo( World world, BlockPos pos )
{
if( world.isRemote || getWorld().isRemote )
{
throw new UnsupportedOperationException();
}
// Cache info about the old turtle (so we don't access this after we delete ourselves)
World oldWorld = getWorld();
BlockPos oldPos = m_owner.getPos();
Block oldBlock = m_owner.getBlock();
if( oldWorld == world && oldPos.equals( pos ) )
{
// Teleporting to the current position is a no-op
return true;
}
// Create a new turtle
if( world.isBlockLoaded( pos ) && world.setBlockState( pos, oldBlock.getDefaultState(), 3 ) )
{
Block block = world.getBlockState( pos ).getBlock();
if( block == oldBlock )
{
TileEntity newTile = world.getTileEntity( pos );
if( newTile != null && newTile instanceof TileTurtle )
{
// Copy the old turtle state into the new turtle
TileTurtle newTurtle = (TileTurtle)newTile;
newTurtle.setWorldObj( world );
newTurtle.setPos( pos );
newTurtle.transferStateFrom( m_owner );
newTurtle.createServerComputer().setWorld( world );
newTurtle.createServerComputer().setPosition( pos );
// Remove the old turtle
oldWorld.setBlockToAir( oldPos );
// Make sure everybody knows about it
newTurtle.updateInput();
newTurtle.updateOutput();
return true;
}
}
// Something went wrong, remove the newly created turtle
world.setBlockToAir( pos );
}
return false;
}
@Override
public Vec3 getVisualPosition( float f )
{
Vec3 offset = getRenderOffset( f );
BlockPos pos = m_owner.getPos();
return new Vec3(
pos.getX() + 0.5 + offset.xCoord,
pos.getY() + 0.5 + offset.yCoord,
pos.getZ() + 0.5 + offset.zCoord
);
}
@Override
public float getVisualYaw( float f )
{
float forward = DirectionUtil.toYawAngle( getDirection() );
float yaw = forward;
switch( m_animation )
{
case TurnLeft:
{
yaw += 90.0f * (1.0f - getAnimationFraction( f ));
if( yaw >= 360.0f )
{
yaw -= 360.0f;
}
break;
}
case TurnRight:
{
yaw += -90.0f * (1.0f - getAnimationFraction( f ));
if( yaw < 0.0f )
{
yaw += 360.0f;
}
break;
}
}
return yaw;
}
@Override
public EnumFacing getDirection()
{
return m_direction;
}
@Override
public void setDirection( EnumFacing dir )
{
if( dir.getAxis() == EnumFacing.Axis.Y )
{
dir = EnumFacing.NORTH;
}
m_direction = dir;
m_owner.updateOutput();
m_owner.updateInput();
m_owner.onTileEntityChange();
}
@Override
public int getSelectedSlot()
{
return m_selectedSlot;
}
@Override
public void setSelectedSlot( int slot )
{
if( getWorld().isRemote )
{
throw new UnsupportedOperationException();
}
if( slot >= 0 && slot < m_owner.getSizeInventory() )
{
m_selectedSlot = slot;
m_owner.onTileEntityChange();
}
}
@Override
public IInventory getInventory()
{
return m_owner;
}
@Override
public boolean isFuelNeeded()
{
return ComputerCraft.turtlesNeedFuel;
}
@Override
public int getFuelLevel()
{
return Math.min( m_fuelLevel, getFuelLimit() );
}
@Override
public void setFuelLevel( int level )
{
m_fuelLevel = Math.min( level, getFuelLimit() );
m_owner.onTileEntityChange();
}
@Override
public int getFuelLimit()
{
if( m_owner.getFamily() == ComputerFamily.Advanced )
{
return ComputerCraft.advancedTurtleFuelLimit;
}
else
{
return ComputerCraft.turtleFuelLimit;
}
}
@Override
public boolean consumeFuel( int fuel )
{
if( getWorld().isRemote )
{
throw new UnsupportedOperationException();
}
if( !isFuelNeeded() )
{
return true;
}
int consumption = Math.max( fuel, 0 );
if( getFuelLevel() >= consumption )
{
setFuelLevel( getFuelLevel() - consumption );
return true;
}
return false;
}
@Override
public void addFuel( int fuel )
{
if( getWorld().isRemote )
{
throw new UnsupportedOperationException();
}
int addition = Math.max( fuel, 0 );
setFuelLevel( getFuelLevel() + addition );
}
private int issueCommand( ITurtleCommand command )
{
m_commandQueue.offer( new TurtleCommandQueueEntry( ++m_commandsIssued, command ) );
return m_commandsIssued;
}
@Override
public Object[] executeCommand( ILuaContext context, ITurtleCommand command ) throws LuaException, InterruptedException
{
if( getWorld().isRemote )
{
throw new UnsupportedOperationException();
}
// Issue command
int commandID = issueCommand( command );
// Wait for response
while( true )
{
Object[] response = context.pullEvent( "turtle_response" );
if( response.length >= 3 && response[ 1 ] instanceof Number && response[ 2 ] instanceof Boolean )
{
if( ( (Number) response[ 1 ] ).intValue() == commandID )
{
Object[] returnValues = new Object[ response.length - 2 ];
for( int i = 0; i < returnValues.length; ++i )
{
returnValues[ i ] = response[ i + 2 ];
}
return returnValues;
}
}
}
}
@Override
public void playAnimation( TurtleAnimation animation )
{
if( getWorld().isRemote )
{
throw new UnsupportedOperationException();
}
m_animation = animation;
if( m_animation == TurtleAnimation.ShortWait )
{
m_animationProgress = ANIM_DURATION / 2;
m_lastAnimationProgress = ANIM_DURATION / 2;
}
else
{
m_animationProgress = 0;
m_lastAnimationProgress = 0;
}
m_owner.updateBlock();
}
@Override
public int getDyeColour()
{
return (m_colour != null) ? m_colour.ordinal() : -1;
}
public ResourceLocation getOverlay()
{
return m_overlay;
}
public void setOverlay( ResourceLocation overlay )
{
if( !Objects.equal(m_overlay, overlay) )
{
m_overlay = overlay;
m_owner.updateBlock();
}
}
@Override
public void setDyeColour( int dyeColour )
{
Colour newColour = null;
if( dyeColour >= 0 && dyeColour < 16 )
{
newColour = Colour.values()[ dyeColour ];
}
if( m_colour != newColour )
{
m_colour = newColour;
m_owner.updateBlock();
}
}
@Override
public ITurtleUpgrade getUpgrade( TurtleSide side )
{
if( m_upgrades.containsKey( side ) )
{
return m_upgrades.get( side );
}
return null;
}
@Override
public void setUpgrade( TurtleSide side, ITurtleUpgrade upgrade )
{
// Remove old upgrade
if( m_upgrades.containsKey( side ) )
{
if( m_upgrades.get( side ) == upgrade )
{
return;
}
m_upgrades.remove( side );
}
else
{
if( upgrade == null )
{
return;
}
}
if( m_upgradeNBTData.containsKey( side ) )
{
m_upgradeNBTData.remove( side );
}
// Set new upgrade
if( upgrade != null )
{
m_upgrades.put( side, upgrade );
}
// Notify clients and create peripherals
if( m_owner.getWorld() != null )
{
updatePeripherals( m_owner.createServerComputer() );
m_owner.updateBlock();
}
}
@Override
public IPeripheral getPeripheral( TurtleSide side )
{
if( m_peripherals.containsKey( side ) )
{
return m_peripherals.get( side );
}
return null;
}
@Override
public NBTTagCompound getUpgradeNBTData( TurtleSide side )
{
if( !m_upgradeNBTData.containsKey( side ) )
{
m_upgradeNBTData.put( side, new NBTTagCompound() );
}
return m_upgradeNBTData.get( side );
}
@Override
public void updateUpgradeNBTData( TurtleSide side )
{
m_owner.updateBlock();
}
public boolean saveBlockChange( BlockPos coordinates, IBlockState previousState )
{
// Overriden by CCEdu
return false;
}
public Vec3 getRenderOffset( float f )
{
switch( m_animation )
{
case MoveForward:
case MoveBack:
case MoveUp:
case MoveDown:
{
// Get direction
EnumFacing dir;
switch( m_animation )
{
case MoveForward:
default:
{
dir = getDirection();
break;
}
case MoveBack:
{
dir = getDirection().getOpposite();
break;
}
case MoveUp:
{
dir = EnumFacing.UP;
break;
}
case MoveDown:
{
dir = EnumFacing.DOWN;
break;
}
}
double distance = -1.0 + (double)getAnimationFraction( f );
return new Vec3(
distance * (double)dir.getFrontOffsetX(),
distance * (double)dir.getFrontOffsetY(),
distance * (double)dir.getFrontOffsetZ()
);
}
default:
{
return new Vec3( 0.0, 0.0, 0.0 );
}
}
}
public float getToolRenderAngle( TurtleSide side, float f )
{
if( (side == TurtleSide.Left && m_animation == TurtleAnimation.SwingLeftTool) ||
(side == TurtleSide.Right && m_animation == TurtleAnimation.SwingRightTool) )
{
return 45.0f * (float)Math.sin( (double) getAnimationFraction( f ) * Math.PI );
}
return 0.0f;
}
private int toDirection( TurtleSide side )
{
switch( side )
{
case Left:
{
return 5;
}
case Right:
default:
{
return 4;
}
}
}
public void updatePeripherals( ServerComputer serverComputer )
{
if( serverComputer == null )
{
// Nothing to do
return;
}
// Update peripherals
for( TurtleSide side : TurtleSide.values() )
{
ITurtleUpgrade upgrade = getUpgrade( side );
IPeripheral peripheral = null;
if( upgrade != null && upgrade.getType() == TurtleUpgradeType.Peripheral )
{
peripheral = upgrade.createPeripheral( this, side );
}
int dir = toDirection( side );
if( peripheral != null )
{
if( !m_peripherals.containsKey( side ) )
{
serverComputer.setPeripheral( dir, peripheral );
serverComputer.setRedstoneInput( dir, 0 );
serverComputer.setBundledRedstoneInput( dir, 0 );
m_peripherals.put( side, peripheral );
}
else if( !m_peripherals.get( side ).equals( peripheral ) )
{
serverComputer.setPeripheral( dir, peripheral );
serverComputer.setRedstoneInput( dir, 0 );
serverComputer.setBundledRedstoneInput( dir, 0 );
m_peripherals.remove( side );
m_peripherals.put( side, peripheral );
}
}
else if( m_peripherals.containsKey( side ) )
{
serverComputer.setPeripheral( dir, null );
m_peripherals.remove( side );
}
}
}
private void updateCommands()
{
if( m_animation == TurtleAnimation.None )
{
// Pull a new command
TurtleCommandQueueEntry nextCommand = null;
if( m_commandQueue.peek() != null )
{
nextCommand = m_commandQueue.remove();
}
if( nextCommand != null )
{
// Execute the command
TurtleCommandResult result = nextCommand.command.execute( this );
// Dispatch the callback
int callbackID = nextCommand.callbackID;
if( callbackID >= 0 )
{
if( result != null && result.isSuccess() )
{
IComputer computer = m_owner.getComputer();
if( computer != null )
{
Object[] results = result.getResults();
if( results != null )
{
Object[] arguments = new Object[ results.length + 2 ];
arguments[0] = callbackID;
arguments[1] = true;
for( int i=0; i<results.length; ++i )
{
arguments[2+i] = results[i];
}
computer.queueEvent( "turtle_response", arguments );
}
else
{
computer.queueEvent( "turtle_response", new Object[] {
callbackID, true
} );
}
}
}
else
{
IComputer computer = m_owner.getComputer();
if( computer != null )
{
computer.queueEvent( "turtle_response", new Object[] {
callbackID, false, ( result != null ) ? result.getErrorMessage() : null
} );
}
}
}
}
}
}
private void updateAnimation()
{
if( m_animation != TurtleAnimation.None )
{
World world = this.getWorld();
if( ComputerCraft.turtlesCanPush )
{
// Advance entity pushing
if( m_animation == TurtleAnimation.MoveForward ||
m_animation == TurtleAnimation.MoveBack ||
m_animation == TurtleAnimation.MoveUp ||
m_animation == TurtleAnimation.MoveDown )
{
BlockPos pos = getPosition();
EnumFacing moveDir;
switch( m_animation )
{
case MoveForward:
default:
{
moveDir = m_direction;
break;
}
case MoveBack:
{
moveDir = m_direction.getOpposite();
break;
}
case MoveUp:
{
moveDir = EnumFacing.UP;
break;
}
case MoveDown:
{
moveDir = EnumFacing.DOWN;
break;
}
}
double minX = pos.getX();
double minY = pos.getY();
double minZ = pos.getZ();
double maxX = minX + 1.0;
double maxY = minY + 1.0;
double maxZ = minZ + 1.0;
float pushFrac = 1.0f - ((float)(m_animationProgress + 1) / (float)ANIM_DURATION);
float push = Math.max( pushFrac + 0.0125f, 0.0f );
if (moveDir.getFrontOffsetX() < 0)
{
minX += (double)((float)moveDir.getFrontOffsetX() * push);
}
else
{
maxX -= (double)((float)moveDir.getFrontOffsetX() * push);
}
if (moveDir.getFrontOffsetY() < 0)
{
minY += (double)((float)moveDir.getFrontOffsetY() * push);
}
else
{
maxY -= (double)((float)moveDir.getFrontOffsetY() * push);
}
if (moveDir.getFrontOffsetZ() < 0)
{
minZ += (double)((float)moveDir.getFrontOffsetZ() * push);
}
else
{
maxZ -= (double)((float)moveDir.getFrontOffsetZ() * push);
}
AxisAlignedBB aabb = new AxisAlignedBB( minX, minY, minZ, maxX, maxY, maxZ );
List list = world.getEntitiesWithinAABBExcludingEntity( (Entity)null, aabb );
if( !list.isEmpty() )
{
double pushStep = 1.0f / (float) ANIM_DURATION;
double pushStepX = (double) moveDir.getFrontOffsetX() * pushStep;
double pushStepY = (double) moveDir.getFrontOffsetY() * pushStep;
double pushStepZ = (double) moveDir.getFrontOffsetZ() * pushStep;
for( int i = 0; i < list.size(); ++i )
{
Entity entity = (Entity) list.get( i );
entity.moveEntity(
pushStepX, pushStepY, pushStepZ
);
}
}
}
}
// Advance valentines day easter egg
if( world.isRemote && m_animation == TurtleAnimation.MoveForward && m_animationProgress == 4 )
{
// Spawn love pfx if valentines day
Holiday currentHoliday = HolidayUtil.getCurrentHoliday();
if( currentHoliday == Holiday.Valentines )
{
Vec3 position = getVisualPosition( 1.0f );
if( position != null )
{
double x = position.xCoord + world.rand.nextGaussian() * 0.1;
double y = position.yCoord + 0.5 + world.rand.nextGaussian() * 0.1;
double z = position.zCoord + world.rand.nextGaussian() * 0.1;
world.spawnParticle(
EnumParticleTypes.HEART, x, y, z,
world.rand.nextGaussian() * 0.02,
world.rand.nextGaussian() * 0.02,
world.rand.nextGaussian() * 0.02
);
}
}
}
// Wait for anim completion
m_lastAnimationProgress = m_animationProgress;
if( ++m_animationProgress >= ANIM_DURATION )
{
m_animation = TurtleAnimation.None;
m_animationProgress = 0;
m_lastAnimationProgress = 0;
}
}
}
private float getAnimationFraction( float f )
{
float next = (float)m_animationProgress / ANIM_DURATION;
float previous = (float)m_lastAnimationProgress / ANIM_DURATION;
return previous + (next - previous) * f;
}
}