package eiteam.esteemedinnovation.smasher; import eiteam.esteemedinnovation.api.SmasherRegistry; import eiteam.esteemedinnovation.api.steamnet.SteamNetwork; import eiteam.esteemedinnovation.api.tile.SteamTransporterTileEntity; import eiteam.esteemedinnovation.api.wrench.WrenchDisplay; import eiteam.esteemedinnovation.api.wrench.Wrenchable; import eiteam.esteemedinnovation.commons.EsteemedInnovation; import net.minecraft.block.Block; import net.minecraft.block.SoundType; import net.minecraft.block.state.IBlockState; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.GlStateManager; import net.minecraft.client.resources.I18n; import net.minecraft.entity.item.EntityItem; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.init.Blocks; import net.minecraft.init.SoundEvents; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.nbt.NBTTagList; import net.minecraft.network.NetworkManager; import net.minecraft.network.play.server.SPacketUpdateTileEntity; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.*; import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; import net.minecraftforge.client.event.RenderGameOverlayEvent.Post; import java.util.ArrayList; import java.util.Collections; import java.util.List; import static eiteam.esteemedinnovation.smasher.SmasherModule.ROCK_SMASHER; import static eiteam.esteemedinnovation.smasher.SmasherModule.ROCK_SMASHER_DUMMY; public class TileEntitySmasher extends SteamTransporterTileEntity implements Wrenchable, WrenchDisplay { public int spinup = 0; private float extendedLength = 0.0F; private Block smooshingBlock; private int smooshingMeta; public int extendedTicks = 0; private List<ItemStack> smooshedStack; private boolean isActive = false; private boolean isBreaking = false; private boolean shouldStop = false; private boolean running = false; private boolean smashNextRound = false; private boolean blockBreakerMode = false; private boolean hasBeenSet = false; public TileEntitySmasher() { super(EnumFacing.VALUES); } @Override public void readFromNBT(NBTTagCompound access) { super.readFromNBT(access); extendedLength = access.getFloat("extendedLength"); extendedTicks = access.getInteger("extendedTicks"); spinup = access.getInteger("spinup"); blockBreakerMode = access.getBoolean("blockBreakerMode"); hasBeenSet = access.getBoolean("hasBeenSet"); smooshingBlock = Block.getBlockById(access.getInteger("block")); smooshingMeta = access.getInteger("smooshingMeta"); NBTTagList nbttaglist = (NBTTagList) access.getTag("Items"); smooshedStack = new ArrayList<>(); for (int i = 0; i < nbttaglist.tagCount(); ++i) { NBTTagCompound nbttagcompound1 = nbttaglist.getCompoundTagAt(i); smooshedStack.add(ItemStack.loadItemStackFromNBT(nbttagcompound1)); } } @Override public NBTTagCompound writeToNBT(NBTTagCompound access) { super.writeToNBT(access); access.setBoolean("blockBreakerMode", blockBreakerMode); access.setBoolean("hasBeenSet", hasBeenSet); access.setInteger("spinup", spinup); access.setFloat("extendedLength", extendedLength); access.setInteger("extendedTicks", extendedTicks); access.setInteger("block", Block.getIdFromBlock(smooshingBlock)); access.setInteger("smooshingMeta", smooshingMeta); NBTTagList nbttaglist = new NBTTagList(); if (smooshedStack != null) { for (ItemStack aSmooshedStack : smooshedStack) { NBTTagCompound nbttagcompound1 = new NBTTagCompound(); aSmooshedStack.writeToNBT(nbttagcompound1); nbttaglist.appendTag(nbttagcompound1); } } access.setTag("Items", nbttaglist); return access; } @Override public SPacketUpdateTileEntity getUpdatePacket() { NBTTagCompound access = super.getUpdateTag(); access.setInteger("spinup", spinup); access.setFloat("extendedLength", extendedLength); access.setInteger("extendedTicks", extendedTicks); access.setInteger("block", Block.getIdFromBlock(smooshingBlock)); access.setInteger("smooshingMeta", smooshingMeta); access.setBoolean("running", running); access.setBoolean("blockBreakerMode", blockBreakerMode); access.setBoolean("hasBeenSet", hasBeenSet); return new SPacketUpdateTileEntity(pos, 1, access); } private void decodeAndCreateParticles() { if (worldObj.isRemote) { if (extendedTicks > 15) { float xVelocity = 0F; float zVelocity = 0F; double xOffset = 0D; double zOffset = 0D; EnumFacing facing = worldObj.getBlockState(pos).getValue(BlockSmasher.FACING); if (facing.getAxis() == EnumFacing.Axis.X) { xVelocity = 0.05F * -facing.getFrontOffsetX(); xOffset = 0.1D * -facing.getFrontOffsetX(); } else { zVelocity = 0.05F * -facing.getFrontOffsetZ(); zOffset = 0.1D * -facing.getFrontOffsetZ(); } double xParticle = pos.getX() + 0.5D + xOffset; double yParticle = pos.getY() + 1.1D; double zParticle = pos.getZ() + 0.5D + zOffset; worldObj.spawnParticle(EnumParticleTypes.SMOKE_NORMAL, xParticle, yParticle, zParticle, xVelocity, 0.05F, zVelocity); } } } @Override public void onDataPacket(NetworkManager net, SPacketUpdateTileEntity pkt) { super.onDataPacket(net, pkt); NBTTagCompound access = pkt.getNbtCompound(); extendedLength = access.getFloat("extendedLength"); extendedTicks = access.getInteger("extendedTicks"); spinup = access.getInteger("spinup"); smooshingBlock = Block.getBlockById(access.getInteger("block")); smooshingMeta = access.getInteger("smooshingMeta"); running = access.getBoolean("running"); blockBreakerMode = access.getBoolean("blockBreakerMode"); hasBeenSet = access.getBoolean("hasBeenSet"); markForResync(); } @Override public boolean canUpdate(IBlockState target) { return target.getBlock() == ROCK_SMASHER; } @Override public void initialUpdate() { super.initialUpdate(); EnumFacing facing = worldObj.getBlockState(pos).getValue(BlockSmasher.FACING); addSideToGaugeBlacklist(facing); setValidDistributionDirectionsExcluding(facing, EnumFacing.UP); } @Override public void safeUpdate() { if (!worldObj.isRemote) { int[] target = getTarget(1); int x = target[0]; int y = pos.getY(); int z = target[1]; BlockPos soundPos = new BlockPos(pos.getX() + 0.5F, pos.getY() + 0.5F, pos.getZ() + 0.5F); if (spinup == 1) { worldObj.playSound(null, soundPos, EsteemedInnovation.SOUND_HISS, SoundCategory.BLOCKS, SoundType.ANVIL.getVolume(), 0.9F); } if (extendedTicks > 15) { worldObj.playSound(null, soundPos, EsteemedInnovation.SOUND_LEAK, SoundCategory.BLOCKS, 2F, 0.9F); } if (extendedTicks == 5) { float pitch = (0.75F * (float) Math.random() * 0.1F); worldObj.playSound(null, soundPos, SoundEvents.BLOCK_STONE_BREAK, SoundCategory.BLOCKS, 0.5F, pitch); } if (extendedTicks > 0 && extendedTicks < 6 && smooshingBlock != null) { SoundType smooshingSoundType = smooshingBlock.getSoundType(worldObj.getBlockState(soundPos), worldObj, soundPos, null); SoundEvent breakSound = smooshingSoundType.getBreakSound(); worldObj.playSound(null, soundPos, breakSound, SoundCategory.BLOCKS, smooshingSoundType.getVolume(), smooshingSoundType.getPitch()); } //handle state changes if (shouldStop) { spinup = 0; extendedLength = 0; extendedTicks = 0; isActive = false; shouldStop = false; isBreaking = false; running = false; markForResync(); return; } if (!smashNextRound && hasSomethingToSmash() && hasPartner() && getSteamShare() > 1000 && !isActive) { smashNextRound = true; return; } boolean smashThisRound = false; if (smashNextRound) { smashThisRound = true; smashNextRound = false; } if (smashThisRound) { if (hasSomethingToSmash() && !isActive) { decrSteam(1000); running = true; markForResync(); isActive = true; isBreaking = true; } } BlockPos middleBlockPos = new BlockPos(x, y, z); //handle processing if (isActive) { // if we haven't spun up yet, do it. if (isBreaking) { if (!hasSomethingToSmash() && spinup < 40 && isPrimary()) { shouldStop = true; int[] tc = getTarget(2); BlockPos position = new BlockPos(tc[0], y, tc[1]); TileEntitySmasher partner = (TileEntitySmasher) worldObj.getTileEntity(position); if (partner != null) { partner.shouldStop = true; } return; } if (spinup < 41) { // spinup complete. SMAASH! if (spinup == 40) { IBlockState middleBlockState = worldObj.getBlockState(middleBlockPos); Block middleBlock = middleBlockState.getBlock(); if (hasSomethingToSmash()) { spinup++; if (isPrimary()) { smooshingBlock = middleBlock; smooshingMeta = middleBlock.getMetaFromState(middleBlockState); smooshedStack = smooshingBlock.getDrops(worldObj, middleBlockPos, middleBlockState, 0); markForResync(); worldObj.setBlockState(middleBlockPos, ROCK_SMASHER_DUMMY.getDefaultState()); } } else { if (hasPartner()) { int[] pc = getTarget(2); BlockPos partnerPosition = new BlockPos(pc[0], y, pc[1]); TileEntitySmasher partner = (TileEntitySmasher) worldObj.getTileEntity(partnerPosition); //noinspection ConstantConditions if (partner.spinup < 41 || (partner.spinup >= 41 && partner.shouldStop)) { shouldStop = true; } if (shouldStop) { spinup++; return; } } } } spinup++; // if we've spun up, extend } else if (extendedLength < 0.5F && !shouldStop) { extendedLength += 0.1F; if (extendedTicks == 3 && isPrimary() && !worldObj.isRemote) { spawnOutputForSmashedBlock(middleBlockPos); } extendedTicks++; // we're done extending. Time to go inactive and start retracting } else { isBreaking = false; spinup = 0; } } else { // Get back in line! if (extendedLength > 0.0F) { extendedLength -= 0.025F; extendedTicks++; if (extendedLength < 0F) { extendedLength = 0F; } } else { isActive = false; running = false; markForResync(); extendedTicks = 0; if (worldObj.getBlockState(middleBlockPos).getBlock() == ROCK_SMASHER_DUMMY) { worldObj.setBlockToAir(middleBlockPos); } } } // Sync. } else if (worldObj.getBlockState(middleBlockPos).getBlock() == ROCK_SMASHER_DUMMY && isPrimary()) { worldObj.setBlockToAir(middleBlockPos); } } else { if (running) { decodeAndCreateParticles(); if (spinup < 40) { spinup++; } else if (spinup == 40) { int[] tc = getTarget(1); int x = tc[0]; int y = tc[1]; int z = tc[2]; BlockPos targetPosition = new BlockPos(x, y, z); spinup++; if (!worldObj.isAirBlock(targetPosition) && worldObj.getTileEntity(targetPosition) == null) { IBlockState blockState = worldObj.getBlockState(targetPosition); if (blockState.getBlockHardness(worldObj, targetPosition) < 50F && isPrimary()) { smooshingBlock = blockState.getBlock(); smooshingMeta = blockState.getBlock().getMetaFromState(blockState); } } } else if (extendedTicks < 25) { extendedTicks++; } } else { spinup = 0; extendedTicks = 0; } } super.safeUpdate(); } private boolean isPrimary() { return worldObj.getBlockState(pos).getValue(BlockSmasher.FACING).getAxisDirection() == EnumFacing.AxisDirection.NEGATIVE; } private void spawnOutputForSmashedBlock(BlockPos position) { if (smooshedStack != null) { double x = position.getX() + 0.5F; double y = position.getY() + 0.1F; double z = position.getZ() + 0.5F; for (ItemStack stack : smooshedStack) { List<ItemStack> output = SmasherRegistry.getOutput(stack, worldObj); if (output.isEmpty() || blockBreakerMode) { spawnItems(x, y, z, Collections.singletonList(stack)); } else { spawnItems(x, y, z, output); smooshedStack = null; } } } } private void spawnItems(double x, double y, double z, List<ItemStack> items) { for (ItemStack item : items) { EntityItem entityItem = new EntityItem(worldObj, x, y, z, item); worldObj.spawnEntityInWorld(entityItem); } } private boolean hasSomethingToSmash() { int[] target = getTarget(1); int x = target[0]; int y = pos.getY(); int z = target[1]; BlockPos position = new BlockPos(x, y, z); IBlockState blockState = worldObj.getBlockState(position); Block block = blockState.getBlock(); return !worldObj.isAirBlock(position) && block != Blocks.BEDROCK && worldObj.getTileEntity(position) == null && blockState.getBlockHardness(worldObj, position) < 50F; } public boolean hasPartner() { int[] target = getTarget(2); int x = target[0]; int y = pos.getY(); int z = target[1]; int opposite = target[2]; BlockPos partnerPos = new BlockPos(x, y, z); IBlockState partnerState = worldObj.getBlockState(partnerPos); Block partner = partnerState.getBlock(); TileEntity partnerTE = worldObj.getTileEntity(partnerPos); if (partnerTE == null || !(partnerTE instanceof TileEntitySmasher)) { return false; } if (partner == ROCK_SMASHER && ((TileEntitySmasher) partnerTE).getSteamShare() > 100 && partner.getMetaFromState(partnerState) == opposite) { TileEntitySmasher partnerSmasher = (TileEntitySmasher) partnerTE; if (partnerSmasher.blockBreakerMode != blockBreakerMode) { if (hasBeenSet && !partnerSmasher.hasBeenSet) { partnerSmasher.blockBreakerMode = blockBreakerMode; } else if (!hasBeenSet && partnerSmasher.hasBeenSet) { blockBreakerMode = partnerSmasher.blockBreakerMode; } else { blockBreakerMode = partnerSmasher.blockBreakerMode; } hasBeenSet = true; partnerSmasher.hasBeenSet = true; } return true; } return false; } /** * @param distance The distance from the current smasher to check in. For example, getTarget(2) will check * X_Y where X is the current smasher, and Y is the space to check. * @return An array of the X and Z coordinates (no Y because the smasher cannot face up/down) and the opposite * facing horizontal index. */ private int[] getTarget(int distance) { EnumFacing facing = worldObj.getBlockState(pos).getValue(BlockSmasher.FACING); EnumFacing opposite = facing.getOpposite(); BlockPos target = pos.offset(facing, distance); return new int[] { target.getX(), target.getZ(), opposite.getHorizontalIndex() }; } @Override public boolean onWrench(ItemStack stack, EntityPlayer player, World world, BlockPos pos, EnumHand hand, EnumFacing facing, IBlockState state, float hitX, float hitY, float hitZ) { if (player.isSneaking()) { hasBeenSet = true; blockBreakerMode = !blockBreakerMode; int[] target = getTarget(2); int x2 = target[0]; int y2 = this.pos.getY(); int z2 = target[1]; int opposite = target[2]; BlockPos pos2 = new BlockPos(x2, y2, z2); IBlockState state2 = world.getBlockState(pos2); Block block = state2.getBlock(); if (block == ROCK_SMASHER && block.getMetaFromState(state2) == opposite) { TileEntitySmasher smasher = (TileEntitySmasher) world.getTileEntity(pos2); if (smasher != null) { smasher.blockBreakerMode = blockBreakerMode; smasher.hasBeenSet = true; smasher.markForResync(); } } markForResync(); } else { int steam = getSteamShare(); getNetwork().split(this, true); EnumFacing myFacing = worldObj.getBlockState(pos).getValue(BlockSmasher.FACING); setValidDistributionDirectionsExcluding(myFacing, EnumFacing.UP); SteamNetwork.newOrJoin(this); getNetwork().addSteam(steam); } return true; } @Override public void displayWrench(Post event) { GlStateManager.pushMatrix(); int color = Minecraft.getMinecraft().thePlayer.isSneaking() ? 0xC6C6C6 : 0x777777; int x = event.getResolution().getScaledWidth() / 2 - 8; int y = event.getResolution().getScaledHeight() / 2 - 8; String loc = I18n.format("esteemedinnovation.smasher." + blockBreakerMode); Minecraft.getMinecraft().fontRendererObj.drawStringWithShadow(loc, x + 15, y + 13, color); GlStateManager.popMatrix(); } }