More details for last block. Consumed checks. Don't skip item use.

* Store complete event result state for interact.
* Store consumed checks as well.
* Still run the speed check, if only using the item in hand is allowed.
This commit is contained in:
asofold 2017-05-01 01:55:17 +02:00
parent 51d24d1a39
commit d8ab00dfb0
3 changed files with 167 additions and 36 deletions

View File

@ -23,7 +23,9 @@ import java.util.UUID;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.entity.Player;
import org.bukkit.event.Event.Result;
import org.bukkit.event.block.Action;
import org.bukkit.event.player.PlayerInteractEvent;
import fr.neatmonster.nocheatplus.checks.CheckType;
import fr.neatmonster.nocheatplus.checks.access.ACheckData;
@ -96,9 +98,12 @@ public class BlockInteractData extends ACheckData {
private int lastX = Integer.MAX_VALUE;
private int lastY, lastZ;
/** null for air */
public Material lastType = null;
public int lastTick;
public Action lastAction = null;
private Material lastType = null;
private int lastTick;
private Action lastAction = null;
private boolean lastAllowUseBlock = false;
private boolean lastAllowUseItem = false;
private boolean lastIsCancelled = true;
// Data of the reach check.
public double reachDistance;
@ -117,15 +122,28 @@ public class BlockInteractData extends ACheckData {
*/
public int rateLimitSkip = 0;
/**
* Checks that have been run and passed for the block last interacted with
* (rather complete for block-interact checks, to skip subsequent
* block-break/place checks).
*/
private final Set<CheckType> passedChecks = new HashSet<CheckType>();
/**
* Checks that have been run and consume this event, i.e. can't be run again
* (not complete, may contain checks from other check groups).
*/
private final Set<CheckType> consumedChecks = new HashSet<CheckType>();
public BlockInteractData(final BlockInteractConfig config) {
super(config);
}
/**
* Last interacted block.
* Set last interacted block (coordinates, type, tick). Also resets the
* passed checks.
*
* @param block
* @param action
*/
public void setLastBlock(final Block block, final Action action) {
lastX = block.getX();
@ -137,6 +155,8 @@ public class BlockInteractData extends ACheckData {
}
lastTick = TickTask.getTick();
lastAction = action;
resetPassedChecks();
resetConsumedChecks();
}
/**
@ -210,6 +230,36 @@ public class BlockInteractData extends ACheckData {
block.getX(), block.getY(), block.getZ());
}
public boolean getLastAllowUseItem() {
return lastAllowUseItem;
}
public boolean getLastAllowUseBlock() {
return lastAllowUseBlock;
}
public boolean getLastisCancelled() {
return lastIsCancelled;
}
/**
* Get the tick of the last interaction with a block.
*
* @return
*/
public int getLastTick() {
return lastTick;
}
/**
* Get the action of the last interaction with a block.
*
* @return
*/
public Action getLastAction() {
return lastAction;
}
/**
* Resets the last block (and passed checks).
*/
@ -218,7 +268,11 @@ public class BlockInteractData extends ACheckData {
lastAction = null;
lastX = Integer.MAX_VALUE;
lastType = null;
lastAllowUseBlock = false;
lastAllowUseItem = false;
lastIsCancelled = true;
resetPassedChecks();
resetConsumedChecks();
}
/**
@ -228,10 +282,41 @@ public class BlockInteractData extends ACheckData {
passedChecks.clear();
}
/**
* Set the check type to be passed for the last block.
*
* @param checkType
*/
public void addPassedCheck(final CheckType checkType) {
passedChecks.add(checkType);
}
/**
* Check if the last block was set to be consumed by this check type.
*
* @param checkType
* @return
*/
public boolean isConsumedCheck(final CheckType checkType) {
return consumedChecks.contains(checkType);
}
/**
* Reset consumed checks (concern the last block interacted with).
*/
public void resetConsumedChecks() {
consumedChecks.clear();
}
/**
* Set last block to be consumed by the given check type.
*
* @param checkType
*/
public void addConsumedCheck(final CheckType checkType) {
consumedChecks.add(checkType);
}
/**
* Check if this check type was set as passed for the last block.
*
@ -243,10 +328,44 @@ public class BlockInteractData extends ACheckData {
}
/**
* Adjustments, disregarding who/what cancelled the event.
* Adjust to the results of a BlockInteractEvent - only the results, the
* coordinates and action is not updated.
*
* @param event
*/
public void onCancelledBlockInteractEvent() {
resetLastBlock();
public void setPlayerInteractEventResolution(final PlayerInteractEvent event) {
if (event.isCancelled()) {
lastIsCancelled = true;
lastAllowUseItem = event.useItemInHand() == Result.ALLOW;
lastAllowUseBlock = event.useInteractedBlock() == Result.ALLOW;
subsequentCancel ++;
}
else {
lastIsCancelled = false;
lastAllowUseItem = event.useItemInHand() != Result.DENY;
lastAllowUseBlock = event.useInteractedBlock() != Result.DENY;
subsequentCancel = 0;
}
}
/**
* Adjust to the results of a BlockInteractEvent.
*
* @param isCancelled
* @param allowUseItem
* @param allowUseBlock
*/
public void setPlayerInteractEventResolution(final boolean isCancelled,
final boolean allowUseItem, final boolean allowUseBlock) {
this.lastIsCancelled = isCancelled;
this.lastAllowUseBlock = allowUseBlock;
this.lastAllowUseItem = allowUseItem;
if (isCancelled) {
resetLastBlock();
}
else {
}
}
}

View File

@ -107,7 +107,7 @@ public class BlockInteractListener extends CheckListener {
event.setUseInteractedBlock(Result.DENY);
event.setUseItemInHand(Result.DENY);
event.setCancelled(true);
data.onCancelledBlockInteractEvent();
data.resetLastBlock();
if (cancelId >= 0) {
counters.addPrimaryThread(cancelId, 1);
}
@ -117,10 +117,12 @@ public class BlockInteractListener extends CheckListener {
// TODO: Re-arrange for interact spamming. (With ProtocolLib something else is in place as well.)
final Action action = event.getAction();
final Block block = event.getClickedBlock();
final int previousLastTick = data.lastTick;
final int previousLastTick = data.getLastTick();
// TODO: Last block setting: better on monitor !?.
boolean blockChecks = true;
if (block == null) {
data.resetLastBlock();
blockChecks = false;
}
else {
data.setLastBlock(block, action);
@ -147,9 +149,14 @@ public class BlockInteractListener extends CheckListener {
boolean cancelled = false;
if (event.isCancelled() && event.useInteractedBlock() != Result.ALLOW) {
data.subsequentCancel ++;
data.onCancelledBlockInteractEvent();
return;
if (event.useItemInHand() == Result.ALLOW) {
blockChecks = false;
// TODO: Some potential for plugin features...
}
else {
// Can't do more than prevent all (could: set to prevent on highest, if desired).
return;
}
}
final BlockInteractConfig cc = BlockInteractConfig.getConfig(player);
@ -161,12 +168,13 @@ public class BlockInteractListener extends CheckListener {
// TODO: Always run all checks, also for !isBlock ?
// Interaction speed.
if (!cancelled && speed.isEnabled(player) && speed.check(player, data, cc)) {
if (!cancelled && speed.isEnabled(player)
&& speed.check(player, data, cc)) {
cancelled = true;
preventUseItem = true;
}
if (block != null) {
if (blockChecks) {
// First the reach check.
if (!cancelled && reach.isEnabled(player)
&& reach.check(player, loc, block, flyingHandle, data, cc)) {
@ -191,7 +199,6 @@ public class BlockInteractListener extends CheckListener {
onCancelInteract(player, block, face, event, previousLastTick, preventUseItem, data, cc);
}
else {
data.subsequentCancel = 0;
if (flyingHandle.isFlyingQueueFetched()) {
final int flyingIndex = flyingHandle.getFirstIndexWithContentIfFetched();
final Integer cId;
@ -256,19 +263,19 @@ public class BlockInteractListener extends CheckListener {
}
}
}
data.onCancelledBlockInteractEvent();
data.subsequentCancel ++;
}
@EventHandler(ignoreCancelled = false, priority = EventPriority.MONITOR)
public void onPlayerInteractMonitor(final PlayerInteractEvent event) {
// Set event resolution.
final Player player = event.getPlayer();
final BlockInteractData data = BlockInteractData.getData(player);
data.setPlayerInteractEventResolution(event);
// Elytra boost.
if (event.getAction() == Action.RIGHT_CLICK_AIR
&& event.isCancelled() && event.useItemInHand() != Result.DENY) {
final Player player = event.getPlayer();
final ItemStack stack = Bridge1_9.getUsedItem(player, event);
if (stack != null && BridgeMisc.maybeElytraBoost(player, stack.getType())) {
final BlockInteractData data = BlockInteractData.getData(player);
final int power = BridgeMisc.getFireworksPower(stack);
final MovingData mData = MovingData.getData(player);
final int ticks = Math.max((1 + power) * 20, 30);
@ -304,7 +311,7 @@ public class BlockInteractListener extends CheckListener {
final BlockInteractData data, final BlockInteractConfig cc) {
final StringBuilder builder = new StringBuilder(512);
// Rate limit.
if (data.lastTick == previousLastTick && data.subsequentCancel > 0) {
if (data.getLastTick() == previousLastTick && data.subsequentCancel > 0) {
data.rateLimitSkip ++;
return;
}

View File

@ -40,28 +40,33 @@ public class Against extends Check {
public boolean check(final Player player, final Block block, final Material placedMat, final Block blockAgainst, final BlockPlaceData data, final BlockPlaceConfig cc) {
boolean violation = false;
// TODO: Make more precise (workarounds like WATER_LILY, general points).
// TODO: Make more precise (workarounds like WATER_LILY, general points, such as action?).
// Workaround for signs on cactus and similar.
final BlockInteractData bdata = BlockInteractData.getData(player); // TODO: pass as argument.
final Material againstType = blockAgainst.getType();
if (BlockProperties.isAir(againstType)) {
// Attempt to workaround blocks like cactus.
final BlockInteractData bdata = BlockInteractData.getData(player);
if (bdata.matchesLastBlock(TickTask.getTick(), blockAgainst)) {
// Block was placed against something (e.g. cactus), allow it.
// TODO: Later reset can conflict, though it makes sense to reset with placing blocks in general.
// TODO: Reset on leaving the listener rather - why could it conflict?
bdata.resetLastBlock();
return false;
}
if (bdata.isConsumedCheck(this.type)) {
violation = true;
}
if (BlockProperties.isLiquid(againstType)) {
if ((placedMat != Material.WATER_LILY || !BlockProperties.isLiquid(block.getRelative(BlockFace.DOWN).getType())) && !player.hasPermission(Permissions.BLOCKPLACE_AGAINST_LIQUIDS)) {
bdata.addConsumedCheck(this.type);
if (!violation) {
if (BlockProperties.isAir(againstType)) {
// Attempt to workaround blocks like cactus.
if (!bdata.getLastisCancelled() && bdata.matchesLastBlock(TickTask.getTick(), blockAgainst)) {
// Block was placed against something (e.g. cactus), allow it.
// TODO: Later reset can conflict, though it makes sense to reset with placing blocks in general.
// TODO: Reset on leaving the listener rather - why could it conflict?
return false;
}
}
if (BlockProperties.isLiquid(againstType)) {
if ((placedMat != Material.WATER_LILY || !BlockProperties.isLiquid(block.getRelative(BlockFace.DOWN).getType())) && !player.hasPermission(Permissions.BLOCKPLACE_AGAINST_LIQUIDS)) {
violation = true;
}
}
else if (BlockProperties.isAir(againstType) && !player.hasPermission(Permissions.BLOCKPLACE_AGAINST_AIR)) {
violation = true;
}
}
else if (BlockProperties.isAir(againstType) && !player.hasPermission(Permissions.BLOCKPLACE_AGAINST_AIR)) {
violation = true;
}
// Handle violation and return.
if (violation) {
data.againstVL += 1.0;