Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pr fix connected blocks, nether portal break double logging #51

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -161,20 +161,17 @@ private void relatedBlockCallback(Block block, Consumer<Block> breakCallback, Co
}
}

// Find a list of side-face attached blocks that will detach
ArrayList<Block> detachedBlocks = Utilities.findSideFaceAttachedBlocks(block);
if (detachedBlocks.size() > 0) {
for (final Block b : detachedBlocks) {
breakCallback.accept(b);
}
// Find all attached blocks that will detach when the block is broken
for (final Block b : Utilities.findSideFaceAttachedBlocks(block)) {
breakCallback.accept(b);
}

// Find a list of top-side attached blocks that will detach
detachedBlocks = Utilities.findTopFaceAttachedBlocks(block);
if (detachedBlocks.size() > 0) {
for (final Block b : detachedBlocks) {
breakCallback.accept(b);
}
for (final Block b : Utilities.findTopFaceAttachedBlocks(block)) {
breakCallback.accept(b);
}

for (final Block b : Utilities.findBottomFaceAttachedBlocks(block)) {
breakCallback.accept(b);
}

// Find a list of all hanging entities on this block
Expand Down Expand Up @@ -234,15 +231,6 @@ public void onBlockBreak(final BlockBreakEvent event) {
// check for block relationships
logBlockRelationshipsForBlock(player, block);

// if obsidian, log portal blocks
if (block.getType().equals(Material.OBSIDIAN)) {
final ArrayList<Block> blocks = Utilities.findConnectedBlocksOfType(Material.NETHER_PORTAL, block, null);
if (!blocks.isEmpty()) {
// Only log 1 portal break, we don't need all 8
RecordingQueue.addToQueue(ActionFactory.createBlock("block-break", blocks.get(0), player));
}
}

// Pass to the break alerter
if (!player.hasPermission("prism.alerts.use.break.ignore")
&& !player.hasPermission("prism.alerts.ignore")) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,11 @@ public class TabLibraryHelper {
Tag.FLOWER_POTS)
.append(MaterialTag.ALL_PLANTS);

// Material that will detach from the bottom of a block when that block is broken
protected static final MaterialTag fallsOffBottom = new MaterialTag(
Material.NETHER_PORTAL
);

// Material that will be detached by flowing water/lava
protected static final MaterialTag flowBreaks =
new MaterialTag(
Expand Down
169 changes: 120 additions & 49 deletions Prism/src/main/java/network/darkhelmet/prism/utils/block/Utilities.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,8 @@
import org.bukkit.entity.EntityType;

import javax.annotation.Nonnull;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.EnumMap;
import java.util.Locale;
import java.util.*;
import java.util.function.Predicate;

public class Utilities {

Expand All @@ -39,6 +37,9 @@ public class Utilities {
*/
private static final EnumMap<Material, Material> baseMaterials = new EnumMap<>(Material.class);

public static BlockFace[] CARDINAL_FACES = new BlockFace[] {BlockFace.NORTH, BlockFace.SOUTH, BlockFace.WEST, BlockFace.EAST};
public static BlockFace[] CARDINAL_Y_FACES = new BlockFace[] {BlockFace.UP, BlockFace.DOWN, BlockFace.NORTH, BlockFace.SOUTH, BlockFace.WEST, BlockFace.EAST};

static {
baseMaterials.put(Material.GRASS_BLOCK, Material.DIRT);
baseMaterials.put(Material.MYCELIUM, Material.DIRT);
Expand Down Expand Up @@ -279,29 +280,32 @@ public static ArrayList<Block> findSideFaceAttachedBlocks(final Block block) {
}

/**
* Searches around a block for the first block of the given material.
* Searches around a block in all {@link Utilities#CARDINAL_FACES} directions for the first block of the given material.
*
* @param block the block to search around
* @param m the material of the surrounding block to look for
* @return the first surrounding block of the given material found
*/
@SuppressWarnings("unused")
public static Block findFirstSurroundingBlockOfType(Block block, Material m) {
Block blockToCheck = block.getRelative(BlockFace.EAST);
if (blockToCheck.getType().equals(m)) {
return blockToCheck;
}
blockToCheck = block.getRelative(BlockFace.WEST);
if (blockToCheck.getType().equals(m)) {
return blockToCheck;
}
blockToCheck = block.getRelative(BlockFace.NORTH);
if (blockToCheck.getType().equals(m)) {
return blockToCheck;
}
blockToCheck = block.getRelative(BlockFace.SOUTH);
if (blockToCheck.getType().equals(m)) {
return blockToCheck;
return findFirstSurroundingBlockOfType(block, m, CARDINAL_FACES);
}

/**
* Searches around a block in all specified directions for the first block of the given material.
*
* @param block the block to search around
* @param m the material of the surrounding block to look for
* @param directions the array of directions to search in. See {@link Utilities#CARDINAL_FACES} and {@link Utilities#CARDINAL_Y_FACES}
* @return the first surrounding block of the given material found
*/
@SuppressWarnings("unused")
public static Block findFirstSurroundingBlockOfType(Block block, Material m, BlockFace[] directions) {
for (BlockFace face : directions) {
Block check = block.getRelative(face);
if (check.getType() == m) {
return check;
}
}
return null;
}
Expand All @@ -319,7 +323,7 @@ public static boolean isSideFaceDetachableMaterial(Material m) {
}

/**
* Searches for detachable blocks on the four acceptable sides of a block.
* Searches for detachable blocks on the top of a block.
*
* @param block Block
* @return ArrayList of Blocks
Expand All @@ -333,17 +337,33 @@ public static ArrayList<Block> findTopFaceAttachedBlocks(final Block block) {
detachingBlocks.add(blockToCheck);
if (blockToCheck.getType().equals(Material.CACTUS) || blockToCheck.getType().equals(Material.SUGAR_CANE)) {
// For cactus and sugar cane, we can even have blocks above
ArrayList<Block> additionalBlocks = findTopFaceAttachedBlocks(blockToCheck);
if (!additionalBlocks.isEmpty()) {
detachingBlocks.addAll(additionalBlocks);
}
detachingBlocks.addAll(findTopFaceAttachedBlocks(blockToCheck));
}
}

return detachingBlocks;

}

/**
* Searches for detachable blocks on the bottom of a block.
*
* @param block Block
* @return ArrayList of Blocks
*/
public static ArrayList<Block> findBottomFaceAttachedBlocks(final Block block) {
ArrayList<Block> detachingBlocks = new ArrayList<>();

// Find any block below this block that will detach
Block blockToCheck = block.getRelative(BlockFace.DOWN);
if (Utilities.isBottomFaceDetachableMaterial(blockToCheck.getType())) {
detachingBlocks.add(blockToCheck);
}

return detachingBlocks;

}

/**
* Determine whether or not a block is going to detach from the top of a block.
*
Expand All @@ -355,6 +375,17 @@ public static boolean isTopFaceDetachableMaterial(Material m) {
return TabLibraryHelper.fallsOffTop.isTagged(m);
}

/**
* Determine whether or not a block is going to detach from the top of a block.
*
* @param m the material to check for detaching
* @return boolean - whether a block with a given material will detach from the top of a block.
**/
@SuppressWarnings("WeakerAccess")
public static boolean isBottomFaceDetachableMaterial(Material m) {
return TabLibraryHelper.fallsOffBottom.isTagged(m);
}

/**
* Determine whether or not a block location is filled by a material that means
* an attachable material is now detached.
Expand Down Expand Up @@ -583,40 +614,80 @@ public static boolean materialRequiresSoil(Material m) {
* @param currBlock block
* @param foundLocations List
* @return List
*
* @apiNote Deprecated method. Use {@link #getFuzzyConnectedBlocks(Block, int, Material, int)}
*/
public static ArrayList<Block> findConnectedBlocksOfType(Material type, Block currBlock,
final ArrayList<Location> foundLocations) {
@Deprecated
public static ArrayList<Block> findConnectedBlocksOfType(Material type, Block currBlock, final ArrayList<Location> foundLocations) {
return new ArrayList<Block>(getFuzzyConnectedBlocks(currBlock, 0, type, 8192));
}

ArrayList<Block> foundBlocks = new ArrayList<>();
ArrayList<Location> locations;
if (foundLocations == null) {
locations = new ArrayList<>();
} else {
locations = foundLocations;
}
/**
* Checks & returns all blocks around block if they match the given predicate<br>
* This is done in a "fuzzy" fashion controlled by xFuzz, yFuzz and zFuzz respectively. This allows blocks not directly connected to be added to the results. Set to zero to disable.
* @param block the block to start checking from
* @param fuzz fuzziness of the check
* @param type the type of {@link Block}s to consider connected. Usually {@code block.getType()}
* @param max the maximum number of blocks to compute
* @return A {@link Set} of {@link Block}s that is considered connected by the given {@link Predicate} or an empty {@link Set} if there were no results
*
* @author TauCubed
*/
public static Set<Block> getFuzzyConnectedBlocks(Block block, int fuzz, Material type, int max) {
return getFuzzyConnectedBlocks(block, fuzz, fuzz, fuzz, check -> check.getType() == type, max);
}

locations.add(currBlock.getLocation());

for (int x = -1; x <= 1; x++) {
for (int z = -1; z <= 1; z++) {
for (int y = -1; y <= 1; y++) {
Block newBlock = currBlock.getRelative(x, y, z);
// ensure it matches the type and wasn't already found
if (newBlock.getType() == type && !locations.contains(newBlock.getLocation())) {
foundBlocks.add(newBlock);
ArrayList<Block> additionalBlocks = findConnectedBlocksOfType(type, newBlock, locations);
if (additionalBlocks.size() > 0) {
foundBlocks.addAll(additionalBlocks);
/**
* Checks & returns all blocks around block if they match the given predicate<br>
* This is done in a "fuzzy" fashion controlled by xFuzz, yFuzz and zFuzz respectively. This allows blocks not directly connected to be added to the results. Set to zero to disable.
* @param block the block to start checking from
* @param fuzz fuzziness of the check
* @param check the predicate used to check if the block should be considered "connected"
* @param max fhe maximum number of blocks to compute
* @return A {@link Set} of {@link Block}s that is considered connected by the given {@link Predicate} or an empty {@link Set} if there were no results
*
* @author TauCubed
*/
public static Set<Block> getFuzzyConnectedBlocks(Block block, int fuzz, Predicate<Block> check, int max) {
return getFuzzyConnectedBlocks(block, fuzz, fuzz, fuzz, check, max);
}

/**
* Checks & returns all blocks around block if they match the given predicate<br>
* This is done in a "fuzzy" fashion controlled by xFuzz, yFuzz and zFuzz respectively. This allows blocks not directly connected to be added to the results. Set to zero to disable.
* @param block the block to start checking from
* @param xFuzz X directional fuzziness of the check
* @param yFuzz Y directional fuzziness of the check
* @param zFuzz Z directional fuzziness of the check
* @param check the predicate used to check if the block should be considered "connected"
* @param max the maximum number of blocks to compute
* @return A {@link Set} of {@link Block}s that is considered connected by the given {@link Predicate} or an empty {@link Set} if there were no results
*
* @author TauCubed
*/
public static Set<Block> getFuzzyConnectedBlocks(Block block, int xFuzz, int yFuzz, int zFuzz, Predicate<Block> check, int max) {
Set<Block> results = new HashSet<>();
LinkedList<Block> pending = new LinkedList<>();

// add the first block to search from
pending.add(block);

while ((block = pending.poll()) != null && results.size() < max) {
for (int modX = -xFuzz; modX <= xFuzz; modX++) {
for (int modY = -yFuzz; modY <= yFuzz; modY++) {
for (int modZ = -zFuzz; modZ <= zFuzz; modZ++) {
Block nearby = block.getRelative(modX, modY, modZ);
if (check.test(nearby) && results.add(nearby)) {
pending.add(nearby);
}
}
}
}
}

return foundBlocks;

return results;
}


/**
* Get Block below of same type.
*
Expand Down