private void finalizeSurface(World world, int x, int y, int z) { for (byte px = 0; px < 16; px++) { for (byte pz = 0; pz < 16; pz++) { for (byte py = -1; py < 4; py++) { final Block block = world.getBlock(x + px, y + py, z + pz, world); if (block.isAtSurface()) { final BlockMaterial material = block.getMaterial(); if (material == VanillaMaterials.DIRT) { final BlockMaterial top; final Biome biome = block.getBiomeType(); if (biome instanceof GrassyBiome) { top = ((GrassyBiome) biome).getTopCover(); } else { top = VanillaMaterials.GRASS; } block.setMaterial(top); } else if (material == VanillaMaterials.STATIONARY_WATER && block.translate(0, 1, 0).isMaterial(VanillaMaterials.AIR)) { if (block.getBiomeType() instanceof IcyBiome) { block.setMaterial(VanillaMaterials.ICE); } } } } } } }
@Override public void onUpdate(BlockMaterial oldMaterial, Block block) { super.onUpdate(oldMaterial, block); boolean power = isReceivingPower(block); if (power) { block.setData(HAS_REDSTONE_POWER); } else { block.setData(HAS_NO_REDSTONE_POWER); for (BlockFace face : BlockFaces.BTEWNS) { Block other = block.translate(face); if (other.getMaterial() instanceof RedstoneLamp) { if (other.getData() == HAS_REDSTONE_POWER) { power = true; break; } } } } if (on != power) { if (power) { block.setMaterial(VanillaMaterials.REDSTONE_LAMP_ON); } else { block.setMaterial(VanillaMaterials.REDSTONE_LAMP_OFF); } } }
@Override public boolean onPlacement(Block block, short data, BlockFace against, boolean isClickedBlock) { if (block.getMaterial().equals(this)) { block.setMaterial(this.doubletype).update(); } else { block.setMaterial(this); this.setTop(block, against == BlockFace.TOP); block.update(); } return true; }
@Override public void onUpdate(Block block) { BlockMaterial below = block.translate(BlockFace.BOTTOM).getMaterial(); if (below.getMaterial() == VanillaMaterials.AIR) { block.setMaterial(VanillaMaterials.AIR).update(true); } }
@Override public void onDynamicUpdate(Block block, long updateTime, int data) { if (block.translate(BlockFace.TOP).getLight() < this.getMinimumLightToGrow()) { block.dynamicUpdate(updateTime + getGrowthTime(block), true); return; } int chance = VanillaBlockMaterial.getCropGrowthChance(block) + 1; final Random rand = GenericMath.getRandom(); if (rand.nextInt(chance) == 0) { if (isFullyGrown(block)) { for (int i = 0; i < BlockFaces.NESW.size(); i++) { Block spread = block.translate(BlockFaces.NESW.get(i)); BlockMaterial material = spread.getMaterial(); if (material == VanillaMaterials.AIR) { BlockMaterial belowSpread = spread.translate(BlockFace.BOTTOM).getMaterial(); if (belowSpread.isMaterial( VanillaMaterials.FARMLAND, VanillaMaterials.DIRT, VanillaMaterials.GRASS)) { spread.setMaterial(this.getLastStageMaterial()); break; } } else if (material == getLastStageMaterial()) { break; } } } else { block.addData(1); } } block.dynamicUpdate(updateTime + getGrowthTime(block), true); }
/** * Called when this liquid created a new liquid because it spread * * @param block of the Liquid that got created * @param from where it spread * @return True to notify spreading was allowed, False to deny */ public void onSpread(Block block, int newLevel, BlockFace from) { block.getMaterial().destroy(block); block.setMaterial(this.getFlowingMaterial()); this.setLevel(block, newLevel); if (from == BlockFace.TOP) { this.setFlowingDown(block, true); } }
@Override public void setAttachedFace(Block block, BlockFace attachedFace, Cause<?> cause) { if (attachedFace == BlockFace.BOTTOM) { short data = 0; if (cause instanceof EntityCause) { Entity entity = ((EntityCause) cause).getSource(); float yaw = entity.getTransform().getYaw() * -1.0f; float rotation = (yaw + 180F) * 16F / 360F; data = (short) (rotation + 0.5F); data &= 15; } block.setMaterial(VanillaMaterials.SIGN_POST, data, cause); } else { // get the data for this face short data = (short) (BlockFaces.WESN.indexOf(attachedFace, 0) + 2); block.setMaterial(VanillaMaterials.WALL_SIGN, data, cause); } }
public void fillDownwards(int xx, int yy, int zz, int limit, BlockMaterial material, short data) { short counter = 0; Block block; while (((block = getBlock(xx, yy, zz)).getMaterial().isMaterial(VanillaMaterials.AIR) || block.getMaterial() instanceof Liquid) && counter++ < limit) { block.setMaterial(material, data); yy--; } }
public void attachMaterial(int xx, int yy, int zz, Attachable attachable) { final Block block = getBlock(xx, yy, zz); for (BlockFace face : BlockFaces.BTNSWE) { final Block adjacent = block.translate(face); if (attachable.canAttachTo(adjacent, face.getOpposite())) { block.setMaterial((BlockMaterial) attachable); attachable.setAttachedFace(block, face, null); } } }
@Override public void setAttachedFace(Block block, BlockFace attachedFace) { if (attachedFace == BlockFace.BOTTOM) { Source source = block.getSource(); short data = 0; if (source instanceof Entity) { Vector3 direction = block.getPosition().subtract(((Entity) source).getTransform().getPosition()); float rotation = direction.rotationTo(Vector3.RIGHT).getYaw(); rotation = rotation / 360f * 16f; data = (short) rotation; } block.setMaterial(VanillaMaterials.SIGN_POST, data).queueUpdate(EffectRange.THIS); } else { // get the data for this face short data = (short) (BlockFaces.NSWE.indexOf(attachedFace, 0) + 2); block.setMaterial(VanillaMaterials.WALL_SIGN, data).queueUpdate(EffectRange.THIS); } }
@Override public void onUpdate(BlockMaterial oldMaterial, Block block) { super.onUpdate(oldMaterial, block); if (!block.translate(BlockFace.BOTTOM).getMaterial().isPlacementObstacle()) { // turn this block into a mobile block Entity e = block .getWorld() .createAndSpawnEntity(block.getPosition(), FallingBlock.class, LoadOption.NO_LOAD); e.add(FallingBlock.class).setMaterial(this); block.setMaterial(VanillaMaterials.AIR); } }
@Override public void placeObject(World world, int x, int y, int z) { x -= 8; z -= 8; Biome biome = world.getBiomeType(x, y, z); boolean sandy = biome instanceof SandyBiome; for (byte px = 0; px < 16; px++) { for (byte pz = 0; pz < 16; pz++) { boolean columnHasWater = false; for (byte py = (byte) -holeHeightMap[16 * px + pz]; py < 0; py++) { world.setBlockMaterial(px + x, py + y, pz + z, liquid, (short) 0, world); columnHasWater = true; } if (stoneWalls) { for (byte py = 1; py < 5; py++) { if (isWallBlock(px, py, pz, holeHeightMap)) { world.setBlockMaterial( x + px, y - py, z + pz, VanillaMaterials.STONE, (short) 0, world); } } } for (byte py = 0; py < topHeightMap[16 * px + pz]; py++) { world.setBlockMaterial(px + x, py + y, pz + z, VanillaMaterials.AIR, (short) 0, world); } if (stonyTop) { for (byte py = 1; py < 5; py++) { if (isWallBlock(px, py, pz, topHeightMap)) { final Block block = world.getBlock(px + x, py + y - 1, pz + z, world); if (random.nextBoolean() && block.getMaterial().isOpaque()) { block.setMaterial(VanillaMaterials.STONE); } } } } if (sandy && columnHasWater) { int ty = topHeightMap[16 * px + pz] + y; if (world.getBlockMaterial(x + px, ty, z + pz).equals(VanillaMaterials.SAND)) { world.setBlockMaterial( x + px, ty, z + pz, VanillaMaterials.SANDSTONE, (short) 0, world); } } } } if (biomeAdaptedSurface) { finalizeSurface(world, x, y, z); } }
@Override public void onDynamicUpdate(Block block, long updateTime, int data) { if (willMeltAt(block)) { short dataBlock = block.getData(); if (dataBlock > 0) { block.setData(dataBlock - 1); } else { block.setMaterial(VanillaMaterials.AIR); } } else { // not warm enough to melt the snow and last poll was a long time ago, might as well // skip repeated polls long age = block.getWorld().getAge(); if (age - updateTime > POLL_TIME) { block.dynamicUpdate(age + new Random().nextInt((int) POLL_TIME), true); return; } } block.dynamicUpdate(updateTime + POLL_TIME, true); // TODO : Delay before next check ? }
/** * Let's this liquid flow from the block to the direction given * * @param block to flow from * @param to flow to * @return True if flowing was successful */ public boolean onFlow(Block block, BlockFace to) { int level; if (to == BlockFace.BOTTOM) { level = this.getMaxLevel(); } else { level = this.getLevel(block) - 1; if (level < 0) { return false; } } Block spread = block.getWorld().getBlock(block.getX(), block.getY(), block.getZ(), this).translate(to); BlockMaterial spreadMat = spread.getMaterial(); if (this.isMaterial(spreadMat)) { if (this.isMaximumLevel(spread)) { // If the block above was a non-flowing source, return false to make it spread outwards // If the block above was not a source, return true to stop spreading return !this.isSource(block); } else { // Compare levels if (level > this.getLevel(spread)) { if (spreadMat != this.getFlowingMaterial()) { // Make sure the material is adjusted spread.setMaterial(this.getFlowingMaterial(), spread.getData()); } this.setLevel(spread, level); if (to == BlockFace.BOTTOM) { this.setFlowingDown(spread, true); } // Update blocks around return true; } } } else if (!isLiquidObstacle(spreadMat)) { // Create a new liquid this.onSpread(spread, level, to.getOpposite()); return true; } return false; }
@Override public void populate(Chunk chunk, Random random) { if (chunk.getY() != 4) { return; } final int size = Chunk.BLOCKS.SIZE; final int x = chunk.getBlockX(); final int z = chunk.getBlockZ(); final World world = chunk.getWorld(); final int seed = (int) (world.getSeed() * 73); SHIELD_BASE.setSeed(seed); SHIELD.setSeed(seed); final double[][] noise = WorldGeneratorUtils.fastNoise(SHIELD, size, size, 4, x, 63, z); for (int xx = 0; xx < size; xx++) { for (int zz = 0; zz < size; zz++) { if (noise[xx][zz] > 0.92) { final int y = world.getSurfaceHeight(x + xx, z + zz); for (int yy = 0; yy >= -7; yy--) { if (yy == 0) { final Block block = world.getBlock(x + xx, y + yy, z + zz, world); if (!canReplace(block.getMaterial())) { continue; } block.setMaterial( block.getY() <= NormalGenerator.SEA_LEVEL ? VanillaMaterials.STATIONARY_WATER : VanillaMaterials.AIR); } else { if (canReplace(world.getBlockMaterial(x + xx, y + yy, z + zz))) { world.setBlockMaterial( x + xx, y + yy, z + zz, VanillaMaterials.STONE, (short) 0, world); } } } } } } }
@Override public void onInteractBy(Entity entity, Block block, Action type, BlockFace clickedFace) { super.onInteractBy(entity, block, type, clickedFace); Slot inv = PlayerUtil.getHeldSlot(entity); if (inv != null && inv.get() != null && inv.get().isMaterial(Dye.BONE_MEAL) && type.equals(Action.RIGHT_CLICK)) { if (!PlayerUtil.isCostSuppressed(entity)) { inv.addAmount(-1); } final Random random = GenericMath.getRandom(); // Minecraft does grass growing by Bone Meal as follows. Keep in mind the radius is 8. // - Tall Grass is placed 9/10 times. // - If Tall Grass fails, place Dandelion 2/3 times (within the 1/10 window Tall Grass failed // on) // - If Dandelion fails, place Rose within the 1/3 times window that Dandelion failed (which // is within the 1/10 window Tall Grass failed on). for (int dx = -4; dx < 4; dx++) { for (int dy = -1; dy <= 1; dy++) { for (int dz = -4; dz < 4; dz++) { // Fertilization only occurs 1/3 times. if (random.nextInt(3) != 2) { continue; } // Grass/flowers have lower chance to go to a lower/higher height than the center block // is at. // It incurs another 1/3 times. Only do this when iterating over -1 or 1 on the dy, // otherwise its on the same // plane and we don't care. if (dy != 0) { if (random.nextInt(3) != 2) { continue; } } final Block around = block.translate(dx, dy, dz); // Only spread to Grass blocks if (!around.getMaterial().equals(VanillaMaterials.GRASS)) { continue; } final Block aboveAround = around.translate(BlockFace.TOP); // Make sure the block above the translated one is Air. if (!aboveAround.getMaterial().equals(VanillaMaterials.AIR)) { continue; } if (random.nextInt(10) != 0) { if (VanillaMaterials.TALL_GRASS.canAttachTo(around, BlockFace.TOP)) { aboveAround.setMaterial(VanillaMaterials.TALL_GRASS); } } else if (random.nextInt(3) != 0) { if (VanillaMaterials.DANDELION.canAttachTo(around, BlockFace.TOP)) { aboveAround.setMaterial(VanillaMaterials.DANDELION); } } else { if (VanillaMaterials.ROSE.canAttachTo(around, BlockFace.TOP)) { aboveAround.setMaterial(VanillaMaterials.ROSE); } } } } } } }
@Override public void place() { // rng final Random random = getRandom(); // properties final short lenght = (short) (sections * 5 - 1); // building objects final PieceCuboidBuilder box = new PieceCuboidBuilder(this); final SimpleBlockMaterialPicker picker = new SimpleBlockMaterialPicker(); box.setPicker(picker); // the basic tunnel picker.setOuterInnerMaterials(VanillaMaterials.AIR, VanillaMaterials.AIR); box.setMinMax(0, 0, 0, 2, 1, lenght); box.fill(); box.offsetMinMax(0, 2, 0, 0, 1, 0); box.randomFill(0.8f); // spider webs for spawner if (caveSpiders) { picker.setOuterMaterial(VanillaMaterials.WEB); box.setMinMax(0, 0, 0, 2, 1, lenght); box.randomFill(0.6f); } // decorate sections for (byte section = 0; section < sections; section++) { final short sectionZ = (short) (section * 5 + 2); // fences picker.setOuterMaterial(VanillaMaterials.WOODEN_FENCE); box.setMinMax(0, 0, sectionZ, 0, 1, sectionZ); box.fill(); box.offsetMinMax(2, 0, 0, 2, 0, 0); box.fill(); // ceiling planks picker.setOuterMaterial(VanillaMaterials.PLANK); if (random.nextInt(4) != 0) { box.setMinMax(0, 2, sectionZ, 2, 2, sectionZ); box.fill(); } else { box.setMinMax(0, 2, sectionZ, 0, 2, sectionZ); box.fill(); box.offsetMinMax(2, 0, 0, 2, 0, 0); box.fill(); } // webs and torches setBlockMaterial(0.9f, 0, 2, sectionZ - 1, VanillaMaterials.WEB); setBlockMaterial(0.9f, 2, 2, sectionZ - 1, VanillaMaterials.WEB); setBlockMaterial(0.9f, 0, 2, sectionZ + 1, VanillaMaterials.WEB); setBlockMaterial(0.9f, 2, 2, sectionZ + 1, VanillaMaterials.WEB); setBlockMaterial(0.95f, 0, 2, sectionZ - 2, VanillaMaterials.WEB); setBlockMaterial(0.95f, 2, 2, sectionZ - 2, VanillaMaterials.WEB); setBlockMaterial(0.95f, 0, 2, sectionZ + 2, VanillaMaterials.WEB); setBlockMaterial(0.95f, 2, 2, sectionZ + 2, VanillaMaterials.WEB); attachMaterial(0.95f, 1, 2, sectionZ - 1, VanillaMaterials.TORCH); attachMaterial(0.95f, 1, 2, sectionZ + 1, VanillaMaterials.TORCH); // loot if (random.nextInt(100) == 0) { final LootChestObject chest = new LootChestObject(getRandom()); // TODO: give them proper loot placeObject(2, 0, sectionZ - 1, chest); } if (random.nextInt(100) == 0) { final LootChestObject chest = new LootChestObject(getRandom()); // TODO: give them proper loot placeObject(0, 0, sectionZ + 1, chest); } // spawner if (!caveSpiders || hasSpawner) { continue; } hasSpawner = true; setBlockMaterial(1, 0, sectionZ + random.nextInt(3), VanillaMaterials.MONSTER_SPAWNER); } // bridge gaps for (byte xx = 0; xx <= 2; xx++) { for (byte zz = 0; zz <= lenght; zz++) { final Block block = getBlock(xx, -1, zz); if (block.isMaterial(VanillaMaterials.AIR)) { block.setMaterial(VanillaMaterials.PLANK); } } } // rails if (hasRails) { for (byte zz = 0; zz <= lenght; zz++) { if (getBlockMaterial(1, -1, zz).isOpaque()) { setBlockMaterial(0.3f, 1, 0, zz, VanillaMaterials.RAIL); } } } }
@Override public void onRandomTick(Block block) { if (block.getBlockLight() > 11) { block.setMaterial(VanillaMaterials.AIR); } }
@Override public void onUpdate(BlockMaterial oldMaterial, Block block) { if (block.translate(BlockFace.BOTTOM).isMaterial(VanillaMaterials.AIR)) { block.setMaterial(VanillaMaterials.AIR); } }
private static void placeFrame(Block block, BlockFace facing) { block.setMaterial(VanillaMaterials.END_PORTAL_FRAME); VanillaMaterials.END_PORTAL_FRAME.setFacing(block, facing); }