/** * Go through the blocks, checking for valid ones The way this works is: * * <ul> * <li>Adds the current location to the list of valid locations * <li>Checks if the current block is within {@link LiftPlatesConfig#maxLiftSize} * <li>Makes sure the current block is of the same type and data as the central block * <li>If large lifts are not enabled in the configuration, also checks that the block above is * a pressureplate (If any of the previous conditions are not met, the method does not * continue) * <li>Adds the current location to the list of valid locations * <li>Runs the method on {@link LiftUtil#NSEW_FACES}, excluding locations that have already * been visited, with the same sets of valid and visited locations * </ul> * * @param start The origin block * @param current The current block * @param validLocations The list of already travelled and valid locations * @param visited The list of already travelled (not necessarily valid) locations */ private void travelBlocks( Vector3i start, Vector3i current, Set<Vector3i> validLocations, Set<Vector3i> visited, Set<Vector3i> edgeBlocks) { visited.add(current); LiftPlatesConfig config = manager.getPlugin().getConfiguration(); final int maxDist = config.maxLiftSize * config.maxLiftSize; if (start.distanceSquared(current) > maxDist) { // Too far away edgeBlocks.add(current); return; } final World world = manager.getWorld(); if (!world.getBlock(start).equals(world.getBlock(current))) { // Different block type edgeBlocks.add(current); return; } if (!config.recursiveLifts && !LiftUtil.isPressurePlate( world.getBlockType(current.add(0, 1, 0)))) { // Not a pressure plate edgeBlocks.add(current); return; } validLocations.add(current); for (int i = 1; i < config.liftHeight; ++i) { validLocations.add(current.add(0, i, 0)); } for (Direction face : LiftUtil.NSEW_FACES) { Vector3i newLoc = current.add(face.toVector3d().toInt()); if (visited.contains(newLoc)) { continue; } travelBlocks(start, newLoc, validLocations, visited, edgeBlocks); } }
/** * @param sign treated as sign post if it is such, or else assumed to be a wall sign (i.e., if you * ask about a stone block, it's considered a wall sign). * @return the blank side of the sign opposite the text. In the case of a wall sign, the block in * this direction is the block to which the sign is attached. This is also the direction a * player would be facing when reading the sign; see {@link #getFront(Location)}. */ public static Direction getBack(Location sign) { Direction front = getFront(sign); if (front == null) return Direction.NONE; return front.getOpposite(); }
@Override public boolean triggerMechanic(Location block, Sign sign, Human human, Boolean forceState) { if (!SignUtil.getTextRaw(sign, 1).equals("[Door]")) { Direction back = SignUtil.getTextRaw(sign, 1).equals("[Door Up]") ? Direction.UP : Direction.DOWN; Location baseBlock = block.getRelative(back); Location otherSide = getOtherEnd(block, back, maximumLength); if (otherSide == null) { if (human instanceof CommandSource) ((CommandSource) human).sendMessage(Texts.builder("Missing other end!").build()); return true; } Location otherBase = otherSide.getRelative(back.getOpposite()); if (!baseBlock.getBlock().equals(otherBase.getBlock())) { if (human instanceof CommandSource) ((CommandSource) human) .sendMessage(Texts.builder("Both ends must be the same material!").build()); return true; } int leftBlocks = 0, rightBlocks = 0; // Default to 0. Single width bridge is the default. Location left = baseBlock.getRelative(SignUtil.getLeft(block)); Location right = baseBlock.getRelative(SignUtil.getRight(block)); // Calculate left distance Location otherLeft = otherBase.getRelative(SignUtil.getLeft(block)); while (true) { if (leftBlocks >= maximumWidth) break; if (left.getBlock().equals(baseBlock.getBlock()) && otherLeft.getBlock().equals(baseBlock.getBlock())) { leftBlocks++; left = left.getRelative(SignUtil.getLeft(block)); otherLeft = otherLeft.getRelative(SignUtil.getLeft(block)); } else { break; } } // Calculate right distance Location otherRight = otherBase.getRelative(SignUtil.getRight(block)); while (true) { if (rightBlocks >= maximumWidth) break; if (right.getBlock().equals(baseBlock.getBlock()) && otherRight.getBlock().equals(baseBlock.getBlock())) { rightBlocks++; right = right.getRelative(SignUtil.getRight(block)); otherRight = otherRight.getRelative(SignUtil.getRight(block)); } else { break; } } baseBlock = baseBlock.getRelative(back); BlockState type = block.getRelative(back).getBlock(); if (baseBlock.getBlock().equals(type) && (forceState == null || !forceState)) type = BlockTypes.AIR.getDefaultState(); while (baseBlock.getBlockY() != otherSide.getBlockY() + (back == Direction.UP ? -1 : 1)) { baseBlock.setBlock(type); left = baseBlock.getRelative(SignUtil.getLeft(block)); for (int i = 0; i < leftBlocks; i++) { left.setBlock(type); left = left.getRelative(SignUtil.getLeft(block)); } right = baseBlock.getRelative(SignUtil.getRight(block)); for (int i = 0; i < rightBlocks; i++) { right.setBlock(type); right = right.getRelative(SignUtil.getRight(block)); } baseBlock = baseBlock.getRelative(back); } } else { if (human instanceof CommandSource) ((CommandSource) human) .sendMessage(Texts.builder("Door not activatable from here!").build()); return false; } return true; }