@SubscribeEvent public void onLivingUpdateEvent(LivingUpdateEvent event) { Entity entity = event.entityLiving; World world = entity.worldObj; /* * The purpose of the function is to manifest sprint particles * and adjust slipperiness when entity is moving on block, so check * that the conditions are met first. */ if (!isMovingOnGround(entity)) { return; } TEBase TE = getTileEntityAtFeet(entity); if (TE != null) { ItemStack itemStack = getSurfaceItemStack(TE); /* Spawn sprint particles client-side. */ if (world.isRemote && entity.isSprinting() && !entity.isInWater()) { ParticleHelper.spawnTileParticleAt(entity, itemStack); } /* Adjust block slipperiness according to cover. */ Block block = BlockProperties.toBlock(itemStack); if (block instanceof BlockCoverable) { TE.getBlockType().slipperiness = Blocks.dirt.slipperiness; } else { TE.getBlockType().slipperiness = block.slipperiness; } } }
@Override /** Updates the blocks bounds based on its current state. Args: world, x, y, z */ public void setBlockBoundsBasedOnState(IBlockAccess blockAccess, int x, int y, int z) { if (!rayTracing) { TEBase TE = getTileEntity(blockAccess, x, y, z); if (TE != null) { int slopeID = TE.getData(); Slope slope = Slope.slopesList[slopeID]; switch (slope.getPrimaryType()) { case PRISM: case PRISM_1P: case PRISM_2P: case PRISM_3P: case PRISM_4P: if (slope.isPositive) { setBlockBounds(0.0F, 0.0F, 0.0F, 1.0F, 0.5F, 1.0F); } else { setBlockBounds(0.0F, 0.5F, 0.0F, 1.0F, 1.0F, 1.0F); } break; default: setBlockBounds(0.0F, 0.0F, 0.0F, 1.0F, 1.0F, 1.0F); break; } } } }
@Override /** Alters block type. */ protected boolean onHammerRightClick(TEBase TE, EntityPlayer entityPlayer) { int slopeID = TE.getData(); Slope slope = Slope.slopesList[slopeID]; /* Transform slope to next type. */ slopeID = slope.slopeType.onHammerRightClick(slope, slopeID); TE.setData(slopeID); return true; }
@Override /** Alters block direction. */ protected boolean onHammerLeftClick(TEBase TE, EntityPlayer entityPlayer) { int slopeID = TE.getData(); Slope slope = Slope.slopesList[slopeID]; /* Cycle between slope types based on current slope. */ slopeID = slope.slopeType.onHammerLeftClick(slope, slopeID); TE.setData(slopeID); return true; }
@Override /** Checks if the block is a solid face on the given side, used by placement logic. */ public boolean isSideSolid(IBlockAccess blockAccess, int x, int y, int z, ForgeDirection side) { TEBase TE = getTileEntity(blockAccess, x, y, z); if (TE != null) { if (isBlockSolid(blockAccess, x, y, z)) { return Slope.slopesList[TE.getData()].isFaceFull(side); } } return false; }
/** * Gets an {@link ItemStack} that best represents the surface of a Carpenter's Block. * * <p>The top side cover and any overlays are taken into consideration. * * @param TE * @return */ private ItemStack getSurfaceItemStack(TEBase TE) { // Check for top side cover int effectiveSide = TE.hasAttribute(TE.ATTR_COVER[1]) ? 1 : 6; ItemStack itemStack = BlockProperties.getCover(TE, effectiveSide); // Check for overlay on cover if (TE.hasAttribute(TE.ATTR_OVERLAY[effectiveSide])) { Overlay overlay = OverlayHandler.getOverlayType(TE.getAttribute(TE.ATTR_OVERLAY[effectiveSide])); if (OverlayHandler.coversFullSide(overlay, 1)) { itemStack = overlay.getItemStack(); } } return itemStack; }
@Override /** * Ray traces through the blocks collision from start vector to end vector returning a ray trace * hit. Args: world, x, y, z, startVec, endVec */ public MovingObjectPosition collisionRayTrace( World world, int x, int y, int z, Vec3 startVec, Vec3 endVec) { TEBase TE = getTileEntity(world, x, y, z); MovingObjectPosition finalTrace = null; if (TE != null) { Slope slope = Slope.slopesList[TE.getData()]; SlopeUtil slopeUtil = new SlopeUtil(); int numPasses = slopeUtil.getNumPasses(slope); int precision = slopeUtil.getNumBoxesPerPass(slope); rayTracing = true; /* Determine if ray trace is a hit on slope. */ for (int pass = 0; pass < numPasses; ++pass) { for (int slice = 0; slice < precision && finalTrace == null; ++slice) { float[] box = slopeUtil.genBounds(slope, slice, precision, pass); if (box != null) { setBlockBounds(box[0], box[1], box[2], box[3], box[4], box[5]); finalTrace = super.collisionRayTrace(world, x, y, z, startVec, endVec); } } if (slope.type.equals(Type.OBLIQUE_EXT)) { --precision; } } rayTracing = false; /* Determine true face hit since sloped faces are two or more shared faces. */ if (finalTrace != null) { setBlockBounds(0.0F, 0.0F, 0.0F, 1.0F, 1.0F, 1.0F); finalTrace = super.collisionRayTrace(world, x, y, z, startVec, endVec); } } return finalTrace; }
@Override /** Returns whether sides share faces based on sloping property and face shape. */ protected boolean shareFaces( TEBase TE_adj, TEBase TE_src, ForgeDirection side_adj, ForgeDirection side_src) { if (TE_adj.getBlockType() == this) { Slope slope_src = Slope.slopesList[TE_src.getData()]; Slope slope_adj = Slope.slopesList[TE_adj.getData()]; if (!slope_adj.hasSide(side_adj)) { return false; } else if (slope_src.getFaceBias(side_src) == slope_adj.getFaceBias(side_adj)) { return true; } else { return false; } } return super.shareFaces(TE_adj, TE_src, side_adj, side_src); }
@SideOnly(Side.CLIENT) @SubscribeEvent public void onPlaySoundEvent(PlaySoundEvent17 event) { if (event != null && event.name != null && event.name.contains(CarpentersBlocks.MODID)) { if (FMLCommonHandler.instance().getSide() == Side.CLIENT) { World world = FMLClientHandler.instance().getClient().theWorld; int x = MathHelper.floor_double(event.sound.getXPosF()); int y = MathHelper.floor_double(event.sound.getYPosF()); int z = MathHelper.floor_double(event.sound.getZPosF()); // We'll set a default block type to be safe Block block = Blocks.planks; // Grab approximate origin, and gather accurate block type TEBase TE = getApproximateSoundOrigin(world, x, y, z); if (TE != null && TE.hasAttribute(TE.ATTR_COVER[6])) { block = BlockProperties.toBlock(BlockProperties.getCoverSafe(TE, 6)); } if (event.name.startsWith("step.")) { event.result = new PositionedSoundRecord( new ResourceLocation(block.stepSound.getStepResourcePath()), block.stepSound.getVolume() * 0.15F, block.stepSound.getPitch(), x + 0.5F, y + 0.5F, z + 0.5F); } else { // "dig." usually event.result = new PositionedSoundRecord( new ResourceLocation(block.stepSound.getBreakSound()), (block.stepSound.getVolume() + 1.0F) / 2.0F, block.stepSound.getPitch() * 0.8F, x + 0.5F, y + 0.5F, z + 0.5F); } } } }
@Override /** * Adds all intersecting collision boxes to a list. (Be sure to only add boxes to the list if they * intersect the mask.) Parameters: World, X, Y, Z, mask, list, colliding entity */ public void addCollisionBoxesToList( World world, int x, int y, int z, AxisAlignedBB axisAlignedBB, List list, Entity entity) { TEBase TE = getTileEntity(world, x, y, z); if (TE != null) { AxisAlignedBB box = null; Slope slope = Slope.slopesList[TE.getData()]; SlopeUtil slopeUtil = new SlopeUtil(); int precision = slopeUtil.getNumBoxesPerPass(slope); int numPasses = slopeUtil.getNumPasses(slope); for (int pass = 0; pass < numPasses; ++pass) { for (int slice = 0; slice < precision; ++slice) { float[] dim = slopeUtil.genBounds(slope, slice, precision, pass); if (dim != null) { box = AxisAlignedBB.getBoundingBox( x + dim[0], y + dim[1], z + dim[2], x + dim[3], y + dim[4], z + dim[5]); } if (box != null && axisAlignedBB.intersectsWith(box)) { list.add(box); } } if (slope.type.equals(Type.OBLIQUE_EXT)) { --precision; } } } }
@Override public boolean rotateBlock(World world, int x, int y, int z, ForgeDirection axis) { // to correctly support archimedes' ships mod: // if Axis is DOWN, block rotates to the left, north -> west -> south -> east // if Axis is UP, block rotates to the right: north -> east -> south -> west TileEntity tile = world.getTileEntity(x, y, z); if (tile != null && tile instanceof TEBase) { TEBase cbTile = (TEBase) tile; int data = cbTile.getData(); int dataAngle = data % 4; switch (axis) { case UP: { switch (dataAngle) { case 0: { cbTile.setData(data + 3); break; } case 1: { cbTile.setData(data + 1); break; } case 2: { cbTile.setData(data - 2); break; } case 3: { cbTile.setData(data - 2); break; } } break; } case DOWN: { switch (dataAngle) { case 0: { cbTile.setData(data + 2); break; } case 1: { cbTile.setData(data + 2); break; } case 2: { cbTile.setData(data - 1); break; } case 3: { cbTile.setData(data - 3); break; } } break; } default: return false; } return true; } return false; }
@Override /** * Called when the block is placed in the world. Uses cardinal direction to adjust metadata if * player clicks top or bottom face of block. */ public void onBlockPlacedBy( World world, int x, int y, int z, EntityLivingBase entityLiving, ItemStack itemStack) { TEBase TE = getTileEntity(world, x, y, z); if (TE != null) { int slopeID = 0; int metadata = world.getBlockMetadata(x, y, z); boolean isPositive = EventHandler.eventFace > 1 && EventHandler.hitY < 0.5F || EventHandler.eventFace == 1; int corner = getCorner(entityLiving.rotationYaw); ForgeDirection dir = EntityLivingUtil.getFacing(entityLiving).getOpposite(); switch (metadata) { case META_WEDGE: slopeID = getWedgeOrientation( dir, EventHandler.eventFace, EventHandler.hitX, EventHandler.hitY, EventHandler.hitZ); if (!entityLiving.isSneaking()) { slopeID = SlopeTransform.transformWedge(world, slopeID, x, y, z); TE.setData(slopeID); SlopeTransform.transformAdjacentWedges(world, slopeID, x, y, z); } break; case META_OBLIQUE_INT: switch (corner) { case CORNER_SE: slopeID = isPositive ? Slope.ID_OBL_INT_POS_SE : Slope.ID_OBL_INT_NEG_SE; break; case CORNER_NE: slopeID = isPositive ? Slope.ID_OBL_INT_POS_NE : Slope.ID_OBL_INT_NEG_NE; break; case CORNER_NW: slopeID = isPositive ? Slope.ID_OBL_INT_POS_NW : Slope.ID_OBL_INT_NEG_NW; break; case CORNER_SW: slopeID = isPositive ? Slope.ID_OBL_INT_POS_SW : Slope.ID_OBL_INT_NEG_SW; break; } break; case META_OBLIQUE_EXT: switch (corner) { case CORNER_SE: slopeID = isPositive ? Slope.ID_OBL_EXT_POS_SE : Slope.ID_OBL_EXT_NEG_SE; break; case CORNER_NE: slopeID = isPositive ? Slope.ID_OBL_EXT_POS_NE : Slope.ID_OBL_EXT_NEG_NE; break; case CORNER_NW: slopeID = isPositive ? Slope.ID_OBL_EXT_POS_NW : Slope.ID_OBL_EXT_NEG_NW; break; case CORNER_SW: slopeID = isPositive ? Slope.ID_OBL_EXT_POS_SW : Slope.ID_OBL_EXT_NEG_SW; break; } break; case META_PRISM: if (isPositive) { slopeID = Slope.ID_PRISM_POS; if (!entityLiving.isSneaking()) { slopeID = SlopeTransform.transformPrism(world, slopeID, x, y, z); TE.setData(slopeID); SlopeTransform.transformAdjacentPrisms(world, x, y, z); } } else { slopeID = Slope.ID_PRISM_NEG; } break; case META_PRISM_SLOPE: switch (dir) { case NORTH: slopeID = Slope.ID_PRISM_WEDGE_POS_S; break; case SOUTH: slopeID = Slope.ID_PRISM_WEDGE_POS_N; break; case WEST: slopeID = Slope.ID_PRISM_WEDGE_POS_E; break; case EAST: slopeID = Slope.ID_PRISM_WEDGE_POS_W; break; default: { } } break; } TE.setData(slopeID); } super.onBlockPlacedBy(world, x, y, z, entityLiving, itemStack); }