package game.block; import game.color.Colorizer; import game.entity.Entity; import game.init.Blocks; import game.init.Config; import game.init.FluidRegistry; import game.init.SoundEvent; import game.item.Item; import game.material.Material; import game.properties.IProperty; import game.properties.PropertyInteger; import game.renderer.BlockLayer; import game.renderer.particle.ParticleType; import game.rng.Random; import game.util.ExtMath; import game.world.BlockPos; import game.world.BoundingBox; import game.world.Facing; import game.world.IBlockAccess; import game.world.IWorldAccess; import game.world.State; import game.world.Vec3; import game.world.World; import game.world.WorldClient; import game.world.WorldServer; public abstract class BlockLiquid extends Block { public static final PropertyInteger LEVEL = PropertyInteger.create("level", 0, 15); protected final boolean opaque; protected final int flowRate; public BlockLiquid(Material materialIn, boolean tick, boolean opaque, int rate) { super(materialIn); this.setDefaultState(this.getBaseState().withProperty(LEVEL, Integer.valueOf(0))); this.setBlockBounds(0.0F, 0.0F, 0.0F, 1.0F, 1.0F, 1.0F); if(tick) this.setTickRandomly(); this.opaque = opaque; this.flowRate = rate; } public boolean isPassable(IBlockAccess worldIn, BlockPos pos) { return !this.material.isHotLiquid(); } public int colorMultiplier(IWorldAccess worldIn, BlockPos pos, int renderPass) { return this.material == Material.water ? Colorizer.getWaterColor(worldIn, pos) : 16777215; } /** * Returns the percentage of the liquid block that is air, based on the given flow decay of the liquid */ public static float getLiquidHeightPercent(int meta) { if (meta >= 8) { meta = 0; } return (float)(meta + 1) / 9.0F; } protected int getLevel(IBlockAccess worldIn, BlockPos pos) { return worldIn.getState(pos).getBlock().getMaterial() == this.material ? ((Integer)worldIn.getState(pos).getValue(LEVEL)).intValue() : -1; } protected int getEffectiveFlowDecay(IBlockAccess worldIn, BlockPos pos) { int i = this.getLevel(worldIn, pos); return i >= 8 ? 0 : i; } public boolean isFullCube() { return false; } /** * Used to determine ambient occlusion and culling when rebuilding chunks for render */ public boolean isOpaqueCube() { return false; } public boolean canCollideCheck(State state, boolean hitIfLiquid) { return hitIfLiquid && ((Integer)state.getValue(LEVEL)).intValue() == 0; } /** * Whether this Block is solid on the given Side */ public boolean isBlockSolid(IBlockAccess worldIn, BlockPos pos, Facing side) { Material material = worldIn.getState(pos).getBlock().getMaterial(); return material == this.material ? false : (side == Facing.UP ? true : (material == Material.ice ? false : super.isBlockSolid(worldIn, pos, side))); } public boolean shouldSideBeRendered(IWorldAccess worldIn, BlockPos pos, Facing side) { return worldIn.getState(pos).getBlock().getMaterial() == this.material ? false : (side == Facing.UP ? true : super.shouldSideBeRendered(worldIn, pos, side)); } public boolean shouldRenderSides(IBlockAccess blockAccess, BlockPos pos) { for (int i = -1; i <= 1; ++i) { for (int j = -1; j <= 1; ++j) { State iblockstate = blockAccess.getState(pos.add(i, 0, j)); Block block = iblockstate.getBlock(); Material material = block.getMaterial(); if (material != this.material && !block.isFullBlock()) { return true; } } } return false; } public BoundingBox getCollisionBoundingBox(World worldIn, BlockPos pos, State state) { return null; } /** * The type of render function called. 3 for standard block models, 2 for TESR's, 1 for liquids, -1 is no render */ public int getRenderType() { return 1; } /** * Get the Item that this Block should drop when harvested. */ public Item getItemDropped(State state, Random rand, int fortune) { return null; } /** * Returns the quantity of items to drop on block destruction. */ public int quantityDropped(Random random) { return 0; } protected Vec3 getFlowVector(IBlockAccess worldIn, BlockPos pos) { Vec3 vec3 = new Vec3(0.0D, 0.0D, 0.0D); int i = this.getEffectiveFlowDecay(worldIn, pos); for (Facing enumfacing : Facing.Plane.HORIZONTAL) { BlockPos blockpos = pos.offset(enumfacing); int j = this.getEffectiveFlowDecay(worldIn, blockpos); if (j < 0) { if (!worldIn.getState(blockpos).getBlock().getMaterial().blocksMovement()) { j = this.getEffectiveFlowDecay(worldIn, blockpos.down()); if (j >= 0) { int k = j - (i - 8); vec3 = vec3.addVector((double)((blockpos.getX() - pos.getX()) * k), (double)((blockpos.getY() - pos.getY()) * k), (double)((blockpos.getZ() - pos.getZ()) * k)); } } } else if (j >= 0) { int l = j - i; vec3 = vec3.addVector((double)((blockpos.getX() - pos.getX()) * l), (double)((blockpos.getY() - pos.getY()) * l), (double)((blockpos.getZ() - pos.getZ()) * l)); } } if (((Integer)worldIn.getState(pos).getValue(LEVEL)).intValue() >= 8) { for (Facing enumfacing1 : Facing.Plane.HORIZONTAL) { BlockPos blockpos1 = pos.offset(enumfacing1); if (this.isBlockSolid(worldIn, blockpos1, enumfacing1) || this.isBlockSolid(worldIn, blockpos1.up(), enumfacing1)) { vec3 = vec3.normalize().addVector(0.0D, -6.0D, 0.0D); break; } } } return vec3.normalize(); } public Vec3 modifyAcceleration(World worldIn, BlockPos pos, Entity entityIn, Vec3 motion) { return motion.add(this.getFlowVector(worldIn, pos)); } /** * How many world ticks before ticking */ public int tickRate(World worldIn, BlockPos pos) { return this.flowRate >= 0 ? this.flowRate : (worldIn.isLavaFaster(pos) ? (-this.flowRate / 3) : (-this.flowRate)); } public int getMixedBrightnessForBlock(IWorldAccess worldIn, BlockPos pos) { int i = worldIn.getCombinedLight(pos, 0); int j = worldIn.getCombinedLight(pos.up(), 0); int k = i & 255; int l = j & 255; int i1 = i >> 16 & 255; int j1 = j >> 16 & 255; return (k > l ? k : l) | (i1 > j1 ? i1 : j1) << 16; } public BlockLayer getBlockLayer() { return this.opaque ? BlockLayer.SOLID : BlockLayer.TRANSLUCENT; } public void randomDisplayTick(WorldClient worldIn, BlockPos pos, State state, Random rand) { double d0 = (double)pos.getX(); double d1 = (double)pos.getY(); double d2 = (double)pos.getZ(); if (this.material == Material.water) { int i = ((Integer)state.getValue(LEVEL)).intValue(); if (i > 0 && i < 8) { if (rand.chance(64)) { worldIn.playSound(d0 + 0.5D, d1 + 0.5D, d2 + 0.5D, SoundEvent.WATER, rand.floatv() * 0.25F + 0.75F, rand.floatv() * 1.0F + 0.5F); } } else if (rand.chance(10)) { worldIn.spawnParticle(ParticleType.SUSPENDED, d0 + (double)rand.floatv(), d1 + (double)rand.floatv(), d2 + (double)rand.floatv(), 0.0D, 0.0D, 0.0D); } } if (this.material == Material.lava && worldIn.getState(pos.up()).getBlock().getMaterial() == Material.air && !worldIn.getState(pos.up()).getBlock().isOpaqueCube()) { if (rand.chance(100)) { double d8 = d0 + (double)rand.floatv(); double d4 = d1 + this.maxY; double d6 = d2 + (double)rand.floatv(); worldIn.spawnParticle(ParticleType.LAVA, d8, d4, d6, 0.0D, 0.0D, 0.0D); worldIn.playSound(d8, d4, d6, SoundEvent.LAVA_POP, 0.2F + rand.floatv() * 0.2F, 0.9F + rand.floatv() * 0.15F); } if (rand.chance(200)) { worldIn.playSound(d0, d1, d2, SoundEvent.LAVA, 0.2F + rand.floatv() * 0.2F, 0.9F + rand.floatv() * 0.15F); } } if (rand.chance(10) && worldIn.isBlockSolid(pos.down())) { Material material = worldIn.getState(pos.down(2)).getBlock().getMaterial(); if (!material.blocksMovement() && !material.isLiquid()) { double d3 = d0 + (double)rand.floatv(); double d5 = d1 - 1.05D; double d7 = d2 + (double)rand.floatv(); if (this.material == Material.water) { worldIn.spawnParticle(ParticleType.DRIP_WATER, d3, d5, d7, 0.0D, 0.0D, 0.0D); } else { worldIn.spawnParticle(ParticleType.DRIP_LAVA, d3, d5, d7, 0.0D, 0.0D, 0.0D); } } } } public static double getFlowDirection(IBlockAccess worldIn, BlockPos pos, BlockLiquid block) { Vec3 vec3 = (block instanceof BlockStaticLiquid ? getFlowingBlock((BlockStaticLiquid)block) : block).getFlowVector(worldIn, pos); return vec3.xCoord == 0.0D && vec3.zCoord == 0.0D ? -1000.0D : ExtMath.atan2(vec3.zCoord, vec3.xCoord) - (Math.PI / 2D); } public void onBlockAdded(WorldServer worldIn, BlockPos pos, State state) { this.checkForMixing(worldIn, pos, state); } /** * Called when a neighboring block changes. */ public void onNeighborBlockChange(World worldIn, BlockPos pos, State state, Block neighborBlock) { this.checkForMixing(worldIn, pos, state); } public boolean checkForMixing(World worldIn, BlockPos pos, State state) { if(worldIn.client || !Config.liquidPhysics) return true; if (this.material == Material.lava) { boolean flag = false; for (Facing enumfacing : Facing.values()) { if (enumfacing != Facing.DOWN && worldIn.getState(pos.offset(enumfacing)).getBlock().getMaterial().isColdLiquid()) { flag = true; break; } } if (flag) { Integer integer = (Integer)state.getValue(LEVEL); if (integer.intValue() == 0) { worldIn.setState(pos, Blocks.obsidian.getState()); this.triggerMixEffects(worldIn, pos); return true; } if (integer.intValue() <= 4) { worldIn.setState(pos, Blocks.cobblestone.getState()); this.triggerMixEffects(worldIn, pos); return true; } } } return false; } protected void triggerMixEffects(World worldIn, BlockPos pos) { double d0 = (double)pos.getX(); double d1 = (double)pos.getY(); double d2 = (double)pos.getZ(); worldIn.playSound(SoundEvent.FIZZ, d0 + 0.5D, d1 + 0.5D, d2 + 0.5D, 0.5F, 2.6F + (worldIn.rand.floatv() - worldIn.rand.floatv()) * 0.8F); for (int i = 0; i < 8; ++i) { worldIn.spawnParticle(ParticleType.SMOKE_LARGE, d0 + Math.random(), d1 + 1.2D, d2 + Math.random(), 0.0D, 0.0D, 0.0D); } } /** * Convert the given metadata into a BlockState for this Block */ public State getStateFromMeta(int meta) { return this.getState().withProperty(LEVEL, Integer.valueOf(meta)); } /** * Convert the BlockState into the correct metadata value */ public int getMetaFromState(State state) { return ((Integer)state.getValue(LEVEL)).intValue(); } protected IProperty[] getProperties() { return new IProperty[] {LEVEL}; } public boolean isXrayVisible() { return true; } public static BlockDynamicLiquid getFlowingBlock(BlockStaticLiquid block) { if (block.getMaterial() == Material.water) { return Blocks.flowing_water; } else if (block.getMaterial() == Material.lava) { return Blocks.flowing_lava; } else { return FluidRegistry.getDynamicBlock(block); } } public static BlockStaticLiquid getStaticBlock(BlockDynamicLiquid block) { if (block.getMaterial() == Material.water) { return Blocks.water; } else if (block.getMaterial() == Material.lava) { return Blocks.lava; } else { return FluidRegistry.getStaticBlock(block); } } }