mirror of
https://github.com/NoCheatPlus/NoCheatPlus.git
synced 2024-06-26 06:14:42 +02:00
Block change tracking: add flags for use and redstone. (+)
Add block flags: * F_VARIABLE_USE * F_VARIABLE_REDSTONE Add a test to ensure block flags are unique and not 0L. (+) Use individual MiniListener instances. (+) Track right click blocks (use block) and apply, aiming at trap door issues.
This commit is contained in:
parent
4c30b3570e
commit
0a373fb28b
|
@ -15,26 +15,30 @@
|
|||
package fr.neatmonster.nocheatplus.compat.blocks.changetracker;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.BlockFace;
|
||||
import org.bukkit.event.Event.Result;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.block.Action;
|
||||
import org.bukkit.event.block.BlockPistonExtendEvent;
|
||||
import org.bukkit.event.block.BlockPistonRetractEvent;
|
||||
import org.bukkit.event.block.BlockRedstoneEvent;
|
||||
import org.bukkit.event.entity.EntityChangeBlockEvent;
|
||||
import org.bukkit.event.player.PlayerInteractEvent;
|
||||
import org.bukkit.material.Directional;
|
||||
import org.bukkit.material.Door;
|
||||
import org.bukkit.material.MaterialData;
|
||||
|
||||
import fr.neatmonster.nocheatplus.NCPAPIProvider;
|
||||
import fr.neatmonster.nocheatplus.components.NoCheatPlusAPI;
|
||||
import fr.neatmonster.nocheatplus.components.registry.order.RegistrationOrder.RegisterMethodWithOrder;
|
||||
import fr.neatmonster.nocheatplus.event.mini.MiniListener;
|
||||
import fr.neatmonster.nocheatplus.logging.Streams;
|
||||
import fr.neatmonster.nocheatplus.utilities.ReflectionUtil;
|
||||
import fr.neatmonster.nocheatplus.utilities.map.BlockProperties;
|
||||
|
@ -52,7 +56,66 @@ public class BlockChangeListener implements Listener {
|
|||
private final BlockChangeTracker tracker;
|
||||
private final boolean retractHasBlocks;
|
||||
private boolean enabled = true;
|
||||
private final Set<Material> redstoneMaterials = new HashSet<Material>();
|
||||
|
||||
/** Default tag for listeners. */
|
||||
private final String defaultTag = "system.nocheatplus.blockchangetracker";
|
||||
|
||||
/**
|
||||
* NOTE: Using MiniListenerWithOrder (and @Override before @EventHandler)
|
||||
* would make the registry attempt to register with Bukkit for 'Object'.
|
||||
*/
|
||||
private final MiniListener<?>[] miniListeners = new MiniListener<?>[] {
|
||||
new MiniListener<BlockRedstoneEvent>() {
|
||||
@EventHandler(ignoreCancelled = true, priority = EventPriority.MONITOR)
|
||||
@RegisterMethodWithOrder(tag = defaultTag)
|
||||
@Override
|
||||
public void onEvent(BlockRedstoneEvent event) {
|
||||
if (enabled) {
|
||||
onBlockRedstone(event);
|
||||
}
|
||||
}
|
||||
},
|
||||
new MiniListener<EntityChangeBlockEvent>() {
|
||||
@EventHandler(ignoreCancelled = true, priority = EventPriority.MONITOR)
|
||||
@RegisterMethodWithOrder(tag = defaultTag)
|
||||
@Override
|
||||
public void onEvent(EntityChangeBlockEvent event) {
|
||||
if (enabled) {
|
||||
onEntityChangeBlock(event);
|
||||
}
|
||||
}
|
||||
},
|
||||
new MiniListener<BlockPistonExtendEvent>() {
|
||||
@EventHandler(ignoreCancelled = true, priority = EventPriority.MONITOR)
|
||||
@RegisterMethodWithOrder(tag = defaultTag)
|
||||
@Override
|
||||
public void onEvent(BlockPistonExtendEvent event) {
|
||||
if (enabled) {
|
||||
onPistonExtend(event);
|
||||
}
|
||||
}
|
||||
},
|
||||
new MiniListener<BlockPistonRetractEvent>() {
|
||||
@EventHandler(ignoreCancelled = true, priority = EventPriority.MONITOR)
|
||||
@RegisterMethodWithOrder(tag = defaultTag)
|
||||
@Override
|
||||
public void onEvent(BlockPistonRetractEvent event) {
|
||||
if (enabled) {
|
||||
onPistonRetract(event);
|
||||
}
|
||||
}
|
||||
},
|
||||
new MiniListener<PlayerInteractEvent>() {
|
||||
@EventHandler(ignoreCancelled = false, priority = EventPriority.MONITOR)
|
||||
@RegisterMethodWithOrder(tag = defaultTag)
|
||||
@Override
|
||||
public void onEvent(PlayerInteractEvent event) {
|
||||
if (enabled) {
|
||||
onPlayerInteract(event);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
public BlockChangeListener(final BlockChangeTracker tracker) {
|
||||
this.tracker = tracker;
|
||||
|
@ -63,14 +126,16 @@ public class BlockChangeListener implements Listener {
|
|||
else {
|
||||
retractHasBlocks = true;
|
||||
}
|
||||
// TODO: Make an access method to test this/such in BlockProperties!
|
||||
for (Material material : Material.values()) {
|
||||
if (material.isBlock()) {
|
||||
final String name = material.name().toLowerCase();
|
||||
if (name.indexOf("door") >= 0 || name.indexOf("gate") >= 0) {
|
||||
redstoneMaterials.add(material);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Register actual listener(s).
|
||||
*/
|
||||
public void register() {
|
||||
// TODO: Replace 'if (enabled)' by actually unregistering the listeners.
|
||||
final NoCheatPlusAPI api = NCPAPIProvider.getNoCheatPlusAPI();
|
||||
for (final MiniListener<?> listener : miniListeners) {
|
||||
api.addComponent(listener);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -111,21 +176,13 @@ public class BlockChangeListener implements Listener {
|
|||
}
|
||||
}
|
||||
|
||||
@EventHandler(ignoreCancelled = true, priority = EventPriority.MONITOR)
|
||||
public void onPistonExtend(final BlockPistonExtendEvent event) {
|
||||
if (!enabled) {
|
||||
return;
|
||||
}
|
||||
private void onPistonExtend(final BlockPistonExtendEvent event) {
|
||||
final BlockFace direction = event.getDirection();
|
||||
//DebugUtil.debug("EXTEND event=" + event.getDirection() + " piston=" + getDirection(event.getBlock()));
|
||||
tracker.addPistonBlocks(event.getBlock().getRelative(direction), direction, event.getBlocks());
|
||||
}
|
||||
|
||||
@EventHandler(ignoreCancelled = true, priority = EventPriority.MONITOR)
|
||||
public void onPistonRetract(final BlockPistonRetractEvent event) {
|
||||
if (!enabled) {
|
||||
return;
|
||||
}
|
||||
private void onPistonRetract(final BlockPistonRetractEvent event) {
|
||||
final List<Block> blocks;
|
||||
if (retractHasBlocks) {
|
||||
blocks = event.getBlocks();
|
||||
|
@ -170,11 +227,7 @@ public class BlockChangeListener implements Listener {
|
|||
// DebugUtil.debug("BlockPhysics: " + block); // TODO: REMOVE
|
||||
// }
|
||||
|
||||
@EventHandler(ignoreCancelled = true, priority = EventPriority.MONITOR)
|
||||
public void onBlockRedstone(final BlockRedstoneEvent event) {
|
||||
if (!enabled) {
|
||||
return;
|
||||
}
|
||||
private void onBlockRedstone(final BlockRedstoneEvent event) {
|
||||
final int oldCurrent = event.getOldCurrent();
|
||||
final int newCurrent = event.getNewCurrent();
|
||||
if (oldCurrent == newCurrent || oldCurrent > 0 && newCurrent > 0) {
|
||||
|
@ -183,31 +236,15 @@ public class BlockChangeListener implements Listener {
|
|||
// TODO: Fine grained enabling state (pistons, doors, other).
|
||||
final Block block = event.getBlock();
|
||||
// TODO: Abstract method for a block and a set of materials (redstone, interact, ...).
|
||||
if (block == null || !redstoneMaterials.contains(block.getType())) {
|
||||
if (block == null
|
||||
|| (BlockProperties.getBlockFlags(block.getType()) | BlockProperties.F_VARIABLE_REDSTONE) == 0) {
|
||||
return;
|
||||
}
|
||||
addRedstoneBlock(block);
|
||||
}
|
||||
|
||||
private void addRedstoneBlock(final Block block) {
|
||||
final MaterialData materialData = block.getState().getData();
|
||||
if (materialData instanceof Door) {
|
||||
final Door door = (Door) materialData;
|
||||
final Block otherBlock = block.getRelative(door.isTopHalf() ? BlockFace.DOWN : BlockFace.UP);
|
||||
/*
|
||||
* TODO: Double doors... detect those too? Is it still more
|
||||
* efficient than using BlockPhysics with lazy delayed updating
|
||||
* (TickListener...). Hinge corner... possibilities?
|
||||
*/
|
||||
if (redstoneMaterials.contains(otherBlock.getType())) {
|
||||
tracker.addBlocks(block, otherBlock);
|
||||
// DebugUtil.debug("BlockRedstone door: " + block + " / " + otherBlock); // TODO: REMOVE
|
||||
return;
|
||||
}
|
||||
}
|
||||
// Only the single block remains.
|
||||
tracker.addBlocks(block);
|
||||
// DebugUtil.debug("BlockRedstone: " + block); // TODO: REMOVE
|
||||
addSimpleBlock(block, BlockProperties.F_VARIABLE_REDSTONE);
|
||||
}
|
||||
|
||||
// @EventHandler(ignoreCancelled = true, priority = EventPriority.MONITOR)
|
||||
|
@ -223,11 +260,7 @@ public class BlockChangeListener implements Listener {
|
|||
// }
|
||||
// }
|
||||
|
||||
@EventHandler(ignoreCancelled = true, priority = EventPriority.MONITOR)
|
||||
public void onEntityChangeBlock(final EntityChangeBlockEvent event) {
|
||||
if (!enabled) {
|
||||
return;
|
||||
}
|
||||
private void onEntityChangeBlock(final EntityChangeBlockEvent event) {
|
||||
final Block block = event.getBlock();
|
||||
if (block != null) {
|
||||
// TODO: Filters?
|
||||
|
@ -236,4 +269,48 @@ public class BlockChangeListener implements Listener {
|
|||
}
|
||||
}
|
||||
|
||||
private void onPlayerInteract(final PlayerInteractEvent event) {
|
||||
// Check preconditions.
|
||||
final Result result = event.useInteractedBlock();
|
||||
if (event.getAction() == Action.RIGHT_CLICK_BLOCK
|
||||
&& (result == Result.ALLOW
|
||||
|| !event.isCancelled() && result == Result.DEFAULT)) {
|
||||
final Block block = event.getClickedBlock();
|
||||
if (block != null) {
|
||||
final Material type = block.getType();
|
||||
if ((BlockProperties.getBlockFlags(type) | BlockProperties.F_VARIABLE_USE) != 0L) {
|
||||
addSimpleBlock(block, BlockProperties.F_VARIABLE_USE);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a past state for this block, extending for the other block in case of
|
||||
* doors.
|
||||
*
|
||||
* @param block
|
||||
* @param relevantFlags
|
||||
*/
|
||||
private void addSimpleBlock(final Block block, final long relevantFlags) {
|
||||
final MaterialData materialData = block.getState().getData();
|
||||
if (materialData instanceof Door) {
|
||||
final Door door = (Door) materialData;
|
||||
final Block otherBlock = block.getRelative(door.isTopHalf() ? BlockFace.DOWN : BlockFace.UP);
|
||||
/*
|
||||
* TODO: In case of redstone: Double doors... detect those too? Is it still more
|
||||
* efficient than using BlockPhysics with lazy delayed updating
|
||||
* (TickListener...). Hinge corner... possibilities?
|
||||
*/
|
||||
if (otherBlock != null // Top of the map / special case.
|
||||
&& (BlockProperties.getBlockFlags(otherBlock.getType())
|
||||
| relevantFlags) == 0) {
|
||||
tracker.addBlocks(block, otherBlock);
|
||||
return;
|
||||
}
|
||||
}
|
||||
// Only the single block remains.
|
||||
tracker.addBlocks(block);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -658,39 +658,39 @@ public class BlockProperties {
|
|||
protected static final Map<Material, Long> blockFlags = new HashMap<Material, Long>();
|
||||
|
||||
/** Flag position for stairs. */
|
||||
public static final long F_STAIRS = 0x1;
|
||||
public static final long F_STAIRS = 0x1L;
|
||||
|
||||
/** The Constant F_LIQUID. */
|
||||
public static final long F_LIQUID = 0x2;
|
||||
public static final long F_LIQUID = 0x2L;
|
||||
// TODO: maybe remove F_SOLID use (unless for setting F_GROUND on init).
|
||||
/** Minecraft isSolid result. Used for setting ground flag - Subject to change / rename.*/
|
||||
public static final long F_SOLID = 0x4;
|
||||
public static final long F_SOLID = 0x4L;
|
||||
/** Compatibility flag: regard this block as passable always. */
|
||||
public static final long F_IGN_PASSABLE = 0x8;
|
||||
public static final long F_IGN_PASSABLE = 0x8L;
|
||||
|
||||
/** The Constant F_WATER. */
|
||||
public static final long F_WATER = 0x10;
|
||||
public static final long F_WATER = 0x10L;
|
||||
|
||||
/** The Constant F_LAVA. */
|
||||
public static final long F_LAVA = 0x20;
|
||||
public static final long F_LAVA = 0x20L;
|
||||
/** Override bounding box: 1.5 blocks high, like fences.<br>
|
||||
* NOTE: This might have relevance for passable later.
|
||||
*/
|
||||
public static final long F_HEIGHT150 = 0x40;
|
||||
public static final long F_HEIGHT150 = 0x40L;
|
||||
/** The player can stand on these, sneaking or not. */
|
||||
public static final long F_GROUND = 0x80; // TODO:
|
||||
public static final long F_GROUND = 0x80L; // TODO:
|
||||
/** Override bounding box: 1 block height.<br>
|
||||
* NOTE: This should later be ignored by passable, rather.
|
||||
*/
|
||||
public static final long F_HEIGHT100 = 0x100;
|
||||
public static final long F_HEIGHT100 = 0x100L;
|
||||
/** Climbable like ladder and vine (allow to land on without taking damage). */
|
||||
public static final long F_CLIMBABLE = 0x200;
|
||||
public static final long F_CLIMBABLE = 0x200L;
|
||||
/** The block can change shape. This is most likely not 100% accurate... */
|
||||
public static final long F_VARIABLE = 0x400;
|
||||
public static final long F_VARIABLE = 0x400L;
|
||||
// /** The block has full bounds (0..1), inaccurate! */
|
||||
// public static final int F_FULL = 0x800;
|
||||
/** Block has full xz-bounds. */
|
||||
public static final long F_XZ100 = 0x800;
|
||||
public static final long F_XZ100 = 0x800L;
|
||||
|
||||
/**
|
||||
* This flag indicates that everything between the minimum ground height and
|
||||
|
@ -701,105 +701,117 @@ public class BlockProperties {
|
|||
* otherwise colliding blocks
|
||||
* ({@link #isPassableWorkaround(BlockCache, int, int, int, double, double, double, IBlockCacheNode, double, double, double, double)}).
|
||||
*/
|
||||
public static final long F_GROUND_HEIGHT = 0x1000;
|
||||
public static final long F_GROUND_HEIGHT = 0x1000L;
|
||||
|
||||
/**
|
||||
* The height is assumed to decrease from 1.0 with increasing data value from 0 to 0x7, with 0x7 being the lowest.
|
||||
* (repeating till 0x15)). 0x8 means falling/full block. This is meant to model flowing water/lava. <br>
|
||||
* However the hit-box for collision checks will be set to 0.5 height or 1.0 height only.
|
||||
*/
|
||||
public static final long F_HEIGHT_8SIM_DEC = 0x2000;
|
||||
public static final long F_HEIGHT_8SIM_DEC = 0x2000L;
|
||||
|
||||
/**
|
||||
* The height is assumed to increase with data value up to 0x7, repeating up to 0x15.<br>
|
||||
* However the hit-box for collision checks will be set to 0.5 height or 1.0 height only,<br>
|
||||
* as with the 1.4.x snow levels.
|
||||
*/
|
||||
public static final long F_HEIGHT_8SIM_INC = 0x4000;
|
||||
public static final long F_HEIGHT_8SIM_INC = 0x4000L;
|
||||
|
||||
|
||||
/**
|
||||
* The height increases with data value (8 heights).<br>
|
||||
* This is for MC 1.5 snow levels.
|
||||
*/
|
||||
public static final long F_HEIGHT_8_INC = 0x8000;
|
||||
public static final long F_HEIGHT_8_INC = 0x8000L;
|
||||
|
||||
/** All rail types a minecart can move on. */
|
||||
public static final long F_RAILS = 0x10000;
|
||||
public static final long F_RAILS = 0x10000L;
|
||||
|
||||
/** ICE. */
|
||||
public static final long F_ICE = 0x20000;
|
||||
public static final long F_ICE = 0x20000L;
|
||||
|
||||
/** LEAVES. */
|
||||
public static final long F_LEAVES = 0x40000;
|
||||
public static final long F_LEAVES = 0x40000L;
|
||||
|
||||
/** THIN FENCE (glass panes, iron fence). */
|
||||
public static final long F_THIN_FENCE = 0x80000;
|
||||
public static final long F_THIN_FENCE = 0x80000L;
|
||||
|
||||
/** Meta-flag to indicate that the (max.-) edges should mean a collision, can be passed to collidesBlock. */
|
||||
public static final long F_COLLIDE_EDGES = 0x100000;
|
||||
public static final long F_COLLIDE_EDGES = 0x100000L;
|
||||
|
||||
/** Thick fence (default wooden fence). */
|
||||
public static final long F_THICK_FENCE = 0x200000;
|
||||
public static final long F_THICK_FENCE = 0x200000L;
|
||||
|
||||
/** Fence gate style with 0x04 being fully passable. */
|
||||
public static final long F_PASSABLE_X4 = 0x400000;
|
||||
public static final long F_PASSABLE_X4 = 0x400000L;
|
||||
|
||||
// TODO: Separate no fall damage flag ? [-> on ground could return "dominating" flags, or extra flags]
|
||||
/** Like slime block: bounce back 25% of fall height without taking fall damage [TODO: Check/adjust]. */
|
||||
public static final long F_BOUNCE25 = 0x800000;
|
||||
public static final long F_BOUNCE25 = 0x800000L;
|
||||
|
||||
/**
|
||||
* The facing direction is described by the lower 3 data bits in order of
|
||||
* NSWE, starting at and defaulting to 2, which includes invalid states.
|
||||
* Main purpose is ladders, no guarantees on defaults for other blocks yet.
|
||||
*/
|
||||
public static final long F_FACING_LOW3D2_NSWE = 0x1000000;
|
||||
public static final long F_FACING_LOW3D2_NSWE = 0x1000000L;
|
||||
|
||||
/**
|
||||
* The direction the block is attached to is described by the lower 2 bits
|
||||
* in order of SNEW.
|
||||
*/
|
||||
public static final long F_ATTACHED_LOW2_SNEW = 0x2000000;
|
||||
public static final long F_ATTACHED_LOW2_SNEW = 0x2000000L;
|
||||
|
||||
/**
|
||||
* The hacky way to force sfNoLowJump when the block at from has this flag.
|
||||
*/
|
||||
public static final long F_ALLOW_LOWJUMP = 0x4000000;
|
||||
public static final long F_ALLOW_LOWJUMP = 0x4000000L;
|
||||
|
||||
/** One eighth block height (0.125). */
|
||||
public static final long F_HEIGHT8_1 = 0x8000000;
|
||||
public static final long F_HEIGHT8_1 = 0x8000000L;
|
||||
|
||||
/**
|
||||
* Fall distance is divided by 2, if a move goes through this medium
|
||||
* (currently only supports liquid).
|
||||
*/
|
||||
public static final long F_FALLDIST_HALF = 0x10000000;
|
||||
public static final long F_FALLDIST_HALF = 0x10000000L;
|
||||
|
||||
/**
|
||||
* Fall distance is set to zero, if a move goes through this medium
|
||||
* (currently only supports liquid).
|
||||
*/
|
||||
public static final long F_FALLDIST_ZERO = 0x20000000;
|
||||
public static final long F_FALLDIST_ZERO = 0x20000000L;
|
||||
|
||||
/**
|
||||
* Minimum height 15/16 (0.9375 = 1 - 0.0625). <br>
|
||||
* Only applies with F_GROUND_HEIGHT set.
|
||||
*/
|
||||
public static final long F_MIN_HEIGHT16_15 = 0x40000000;
|
||||
public static final long F_MIN_HEIGHT16_15 = 0x40000000L;
|
||||
|
||||
/**
|
||||
* Minimum height 1/16 (0.0625). <br>
|
||||
* Only applies with F_GROUND_HEIGHT set.
|
||||
*/
|
||||
public static final long F_MIN_HEIGHT16_1 = 0x80000000; // TODO: Lily pad min height of MC versions?
|
||||
// TODO: Lily pad min height of MC versions?
|
||||
public static final long F_MIN_HEIGHT16_1 = 0x80000000L;
|
||||
|
||||
/** CARPET. **/
|
||||
public static final long F_CARPET = 0x100000000L;
|
||||
|
||||
|
||||
/** Cobweb like blocks (adhesive). */
|
||||
public static final long F_COBWEB = 0x200000000L;
|
||||
|
||||
/**
|
||||
* Block change tracking: ordinary right click interaction (use) can change
|
||||
* the shape.
|
||||
*/
|
||||
public static final long F_VARIABLE_USE = 0x400000000L;
|
||||
|
||||
/**
|
||||
* Block change tracking: block redstone events can change the shape.
|
||||
*/
|
||||
public static final long F_VARIABLE_REDSTONE = 0x800000000L;
|
||||
|
||||
// TODO: Convenience constants combining all height / minheight flags.
|
||||
|
||||
// TODO: When flags are out, switch to per-block classes :p.
|
||||
|
@ -1084,11 +1096,27 @@ public class BlockProperties {
|
|||
}
|
||||
|
||||
// F_PASSABLE_X4
|
||||
for (final Material mat : new Material[]{
|
||||
for (final Material mat : new Material[] {
|
||||
Material.FENCE_GATE,
|
||||
Material.TRAP_DOOR, // TODO: Players can stand on - still passable past 1.9?
|
||||
}) {
|
||||
setFlag(mat, F_PASSABLE_X4); // TODO: Flag is abused for other checks, need another one.
|
||||
// TODO: PASSABLE_X4 is abused for other checks, need another one?
|
||||
setFlag(mat, F_PASSABLE_X4);
|
||||
}
|
||||
|
||||
// F_VARIABLE_REDSTONE, F_VARIABLE_USE
|
||||
for (Material material : Material.values()) {
|
||||
if (material.isBlock()) {
|
||||
final String name = material.name().toLowerCase();
|
||||
if (name.endsWith("_door")
|
||||
|| name.endsWith("_trapdoor")
|
||||
|| name.endsWith("fence_gate")) {
|
||||
setFlag(material, F_VARIABLE_REDSTONE);
|
||||
if (!name.contains("iron")) {
|
||||
setFlag(material, F_VARIABLE_USE);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// F_FACING_LOW3D2_NSWE
|
||||
|
@ -1408,6 +1436,21 @@ public class BlockProperties {
|
|||
return tags;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all flag names. Results don't start with the 'F_' prefix.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public static Collection<String> getAllFlagNames() {
|
||||
final Set<String> res = new LinkedHashSet<String>();
|
||||
for (final String name : nameFlagMap.keySet()) {
|
||||
if (!name.startsWith("F_")) {
|
||||
res.add(name);
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience method to parse a flag.
|
||||
*
|
||||
|
@ -1953,7 +1996,11 @@ public class BlockProperties {
|
|||
if (blockProps.hardness <= 2
|
||||
&& (blockProps.tool.toolType == ToolType.AXE
|
||||
|| blockProps.tool.toolType == ToolType.SPADE
|
||||
|| (blockProps.hardness < 0.8 && (blockId != Material.NETHERRACK && blockId != Material.SNOW && blockId != Material.SNOW_BLOCK && blockId != Material.STONE_PLATE)))) {
|
||||
|| (blockProps.hardness < 0.8
|
||||
&& (blockId != Material.NETHERRACK
|
||||
&& blockId != Material.SNOW
|
||||
&& blockId != Material.SNOW_BLOCK
|
||||
&& blockId != Material.STONE_PLATE)))) {
|
||||
// Also roughly.
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
package fr.neatmonster.nocheatplus.test;
|
||||
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import fr.neatmonster.nocheatplus.utilities.map.BlockProperties;
|
||||
|
||||
public class TestBlockFlags {
|
||||
|
||||
@Test
|
||||
public void testIfFlagsAreUnique() {
|
||||
final Collection<String> flags = BlockProperties.getAllFlagNames();
|
||||
final Set<Long> occupied = new HashSet<Long>();
|
||||
for (final String name : flags) {
|
||||
final long flag = BlockProperties.parseFlag(name);
|
||||
if (flag == 0L) {
|
||||
fail("Flag '" + name + "' must not be 0L.");
|
||||
}
|
||||
if (occupied.contains(flag)) {
|
||||
fail("Flag '" + flag + "' already is occupied.");
|
||||
}
|
||||
occupied.add(flag);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1185,7 +1185,7 @@ public class NoCheatPlus extends JavaPlugin implements NoCheatPlusAPI {
|
|||
&& config.getBoolean(ConfPaths.COMPATIBILITY_BLOCKS_CHANGETRACKER_PISTONS)) {
|
||||
if (blockChangeListener == null) {
|
||||
blockChangeListener = new BlockChangeListener(blockChangeTracker);
|
||||
this.addComponent(blockChangeListener);
|
||||
blockChangeListener.register();
|
||||
}
|
||||
blockChangeListener.setEnabled(true);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user