@Override
 public void onPlacedBy(
     EntityPlayer player, ItemStack is, EnumFacing side, float hitX, float hitY, float hitZ) {
   super.onPlacedBy(player, is, side, hitX, hitY, hitZ);
   NBTTagCompound tag = null;
   if (is.hasTagCompound()) {
     tag = is.getTagCompound();
     try {
       putData(new DataInNBT(tag));
     } catch (IOException e) {
       e.printStackTrace();
     }
   } else {
     addLump();
   }
   EnumFacing placement = SpaceUtil.determineFlatOrientation(player);
   if (tag == null || !tag.hasKey("front")) {
     front = placement;
     setRotation((byte) 0);
   } else if (placement.getDirectionVec().getY() == 0 && placement != null) {
     front = SpaceUtil.getOrientation(tag.getByte("front"));
     if (front == null || front.getDirectionVec().getY() != 0) {
       setRotation((byte) 0);
       front = placement;
     } else {
       EnumFacing f = placement;
       byte r = 0;
       for (byte i = 0; i < 4; i++) {
         if (f == front) {
           r = i;
           break;
         }
         f = SpaceUtil.rotate(f, EnumFacing.UP);
       }
       setRotation(r);
     }
   }
 }
 @Override
 public MovingObjectPosition collisionRayTrace(Vec3 startVec, Vec3 endVec) {
   Block block = new Block(Material.rock);
   // It's possible for the startVec to be embedded in a lump (causing it
   // to hit the opposite side), so we must move it farther away
   Vec3 d = startVec.subtract(endVec);
   double scale = 5.2; // Diagonal of a 3³. (Was initially using incrScale = 2)
   // This isn't quite right; the dVector would properly be normalized here
   // & rescaled to the max diameter. But we can survive without it.
   // Unnormalized length of dVector is 6m in surviavl mode IIRC. This'll
   // be way longer than it needs to be.
   // Why is it + instead of -? Hmm.
   startVec = startVec.add(SpaceUtil.scale(d, scale));
   MovingObjectPosition shortest = null;
   for (int i = 0; i < parts.size(); i++) {
     ClayLump lump = parts.get(i);
     lump.toRotatedBlockBounds(this, block);
     MovingObjectPosition mop = block.collisionRayTrace(worldObj, pos, startVec, endVec);
     if (mop != null) {
       mop.subHit = i;
       if (shortest == null) {
         shortest = mop;
       } else {
         Vec3 s = shortest.hitVec;
         Vec3 m = mop.hitVec;
         s = new Vec3(s.xCoord, s.yCoord, s.zCoord);
         m = new Vec3(m.xCoord, m.yCoord, m.zCoord);
         startVec = startVec.subtract(s).subtract(m);
         if (m.lengthVector() < s.lengthVector()) {
           shortest = mop;
         }
       }
     }
   }
   return shortest;
   // return super.collisionRayTrace(w, pos, startVec, endVec);
 }
 @Override
 public boolean handleMessageFromServer(Enum messageType, ByteBuf input) throws IOException {
   if (super.handleMessageFromServer(messageType, input)) {
     return true;
   }
   if (messageType.equals(factorization.net.StandardMessageType.Description)) {
     readStateChange(input);
     front = SpaceUtil.getOrientation(input.readByte());
     setRotation(input.readByte());
     parts.clear();
     ArrayList<Object> args = new ArrayList();
     while (true) {
       try {
         parts.add(new ClayLump().read(input));
       } catch (IOException e) {
         break;
       }
     }
     shouldRenderTesr = getState() == ClayState.WET;
   } else if (messageType.equals(GreenwareMessage.SculptMove)) {
     updateLump(input.readInt(), new ClayLump().read(input));
   } else if (messageType.equals(GreenwareMessage.SculptNew)) {
     addLump();
   } else if (messageType.equals(GreenwareMessage.SculptRemove)) {
     removeLump(input.readInt());
   } else if (messageType.equals(GreenwareMessage.SculptState)) {
     readStateChange(input);
   } else {
     return false;
   }
   cache_dirty = true;
   if (renderEfficient()) {
     getCoord().redraw();
   }
   return true;
 }