mirror of
https://github.com/NoCheatPlus/NoCheatPlus.git
synced 2025-01-02 22:07:50 +01:00
Updated block properties for movement check (solid, liquid, etc.) +
fix fight checks to really ignore anything besides ENTITY_ATTACK damage types.
This commit is contained in:
parent
37876a946b
commit
031d757265
@ -51,6 +51,16 @@ public class CheckUtil {
|
|||||||
return off;
|
return off;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a player is close enough to a target, based on his eye location
|
||||||
|
*
|
||||||
|
* @param player
|
||||||
|
* @param targetX
|
||||||
|
* @param targetY
|
||||||
|
* @param targetZ
|
||||||
|
* @param limit
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
public static final double reachCheck(final NoCheatPlayer player, final double targetX, final double targetY, final double targetZ, final double limit) {
|
public static final double reachCheck(final NoCheatPlayer player, final double targetX, final double targetY, final double targetZ, final double limit) {
|
||||||
|
|
||||||
final Location eyes = player.getPlayer().getEyeLocation();
|
final Location eyes = player.getPlayer().getEyeLocation();
|
||||||
@ -63,12 +73,19 @@ public class CheckUtil {
|
|||||||
private final static double magic = 0.45D;
|
private final static double magic = 0.45D;
|
||||||
private final static double magic2 = 0.55D;
|
private final static double magic2 = 0.55D;
|
||||||
|
|
||||||
// Block types that may need to be treated specially
|
|
||||||
private static final int NONSOLID = 1; // 0x00000001
|
private static final int NONSOLID = 1; // 0x00000001
|
||||||
private static final int SOLID = 2; // 0x00000010
|
private static final int SOLID = 2; // 0x00000010
|
||||||
|
|
||||||
|
// All liquids are "nonsolid" too
|
||||||
private static final int LIQUID = 4 | NONSOLID; // 0x00000101
|
private static final int LIQUID = 4 | NONSOLID; // 0x00000101
|
||||||
|
|
||||||
|
// All ladders are "nonsolid" and "solid" too
|
||||||
private static final int LADDER = 8 | NONSOLID | SOLID; // 0x00001011
|
private static final int LADDER = 8 | NONSOLID | SOLID; // 0x00001011
|
||||||
|
|
||||||
|
// All fences are solid - fences are treated specially due
|
||||||
|
// to being 1.5 blocks high
|
||||||
private static final int FENCE = 16 | SOLID; // 0x00010000
|
private static final int FENCE = 16 | SOLID; // 0x00010000
|
||||||
|
|
||||||
private static final int INGROUND = 128;
|
private static final int INGROUND = 128;
|
||||||
private static final int ONGROUND = 256;
|
private static final int ONGROUND = 256;
|
||||||
// Until I can think of a better way to determine if a block is solid or
|
// Until I can think of a better way to determine if a block is solid or
|
||||||
@ -77,50 +94,78 @@ public class CheckUtil {
|
|||||||
|
|
||||||
static {
|
static {
|
||||||
types = new int[256];
|
types = new int[256];
|
||||||
// Find and define properties of all blocks
|
|
||||||
|
// Find and define properties of all other blocks
|
||||||
for(int i = 0; i < types.length; i++) {
|
for(int i = 0; i < types.length; i++) {
|
||||||
|
|
||||||
// Everything is considered nonsolid at first
|
// Everything unknown is considered nonsolid and solid
|
||||||
types[i] = NONSOLID;
|
types[i] = NONSOLID | SOLID;
|
||||||
|
|
||||||
if(Block.byId[i] != null) {
|
if(Block.byId[i] != null) {
|
||||||
if(Block.byId[i].material.isSolid()) {
|
if(Block.byId[i].material.isSolid()) {
|
||||||
// solid blocks like STONE, CAKE, TRAPDOORS
|
// STONE, CAKE, LEAFS, ...
|
||||||
types[i] = SOLID;
|
types[i] = SOLID;
|
||||||
} else if(Block.byId[i].material.isLiquid()) {
|
} else if(Block.byId[i].material.isLiquid()) {
|
||||||
// WATER, LAVA
|
// WATER, LAVA, ...
|
||||||
types[i] = LIQUID;
|
types[i] = LIQUID;
|
||||||
|
} else {
|
||||||
|
// AIR, SAPLINGS, ...
|
||||||
|
types[i] = NONSOLID;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Some exceptions
|
// Some exceptions where the above method fails
|
||||||
|
|
||||||
|
// Webs slow down a players fall extremely, so it makes
|
||||||
|
// sense to treat them as optionally solid
|
||||||
|
types[Material.WEB.getId()] = SOLID | NONSOLID;
|
||||||
|
|
||||||
|
// Obvious
|
||||||
types[Material.LADDER.getId()] = LADDER;
|
types[Material.LADDER.getId()] = LADDER;
|
||||||
types[Material.FENCE.getId()] = FENCE;
|
types[Material.FENCE.getId()] = FENCE;
|
||||||
|
types[Material.FENCE_GATE.getId()] = FENCE;
|
||||||
|
|
||||||
|
// These are sometimes solid, sometimes not
|
||||||
|
types[Material.IRON_FENCE.getId()] = SOLID | NONSOLID;
|
||||||
|
types[Material.THIN_GLASS.getId()] = SOLID | NONSOLID;
|
||||||
|
|
||||||
|
// Signs are NOT solid, despite the game claiming they are
|
||||||
types[Material.WALL_SIGN.getId()] = NONSOLID;
|
types[Material.WALL_SIGN.getId()] = NONSOLID;
|
||||||
types[Material.DIODE_BLOCK_ON.getId()] |= SOLID | NONSOLID;
|
types[Material.SIGN_POST.getId()] = NONSOLID;
|
||||||
types[Material.DIODE_BLOCK_OFF.getId()] |= SOLID | NONSOLID;
|
|
||||||
types[Material.WOODEN_DOOR.getId()] |= SOLID | NONSOLID;
|
// doors can be solid or not
|
||||||
types[Material.IRON_DOOR_BLOCK.getId()] |= SOLID | NONSOLID;
|
types[Material.WOODEN_DOOR.getId()] = SOLID | NONSOLID;
|
||||||
types[Material.PISTON_EXTENSION.getId()] |= SOLID | NONSOLID;
|
types[Material.IRON_DOOR_BLOCK.getId()] = SOLID | NONSOLID;
|
||||||
types[Material.PISTON_MOVING_PIECE.getId()] |= SOLID | NONSOLID;
|
|
||||||
types[Material.TRAP_DOOR.getId()] |= SOLID | NONSOLID;
|
// pressure plates are so slim, you can consider them
|
||||||
types[111] |= SOLID | NONSOLID; // Lily pads
|
// nonsolid too
|
||||||
|
types[Material.STONE_PLATE.getId()] = SOLID | NONSOLID;
|
||||||
|
types[Material.WOOD_PLATE.getId()] = SOLID | NONSOLID;
|
||||||
|
|
||||||
|
// Player can stand on and "in" lilipads
|
||||||
|
types[Material.WATER_LILY.getId()] = SOLID | NONSOLID;
|
||||||
|
|
||||||
|
for(int i = 0; i < 256; i++) {
|
||||||
|
if(Block.byId[i] != null) {
|
||||||
|
//System.out.println(Material.getMaterial(i) + (isSolid(types[i]) ? " solid " : "") + (isNonSolid(types[i]) ? " nonsolid " : "") + (isLiquid(types[i]) ? " liquid " : ""));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if certain coordinates are considered "on ground"
|
* Ask NoCheat what it thinks about a certain location.
|
||||||
|
* Is it a place where a player can safely stand, should
|
||||||
|
* it be considered as being inside a liquid etc.
|
||||||
*
|
*
|
||||||
* @param w
|
* @param world
|
||||||
* The world the coordinates belong to
|
* The world the coordinates belong to
|
||||||
* @param values
|
* @param location
|
||||||
* The coordinates [lowerX, higherX, Y, lowerZ, higherZ] to be
|
* The precise location in the world
|
||||||
* checked
|
*
|
||||||
* @param l
|
|
||||||
* The precise location that was used for calculation of "values"
|
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public static final int isLocationOnGround(final World world, final PreciseLocation location) {
|
public static final int evaluateLocation(final World world, final PreciseLocation location) {
|
||||||
|
|
||||||
final int lowerX = lowerBorder(location.x);
|
final int lowerX = lowerBorder(location.x);
|
||||||
final int upperX = upperBorder(location.x);
|
final int upperX = upperBorder(location.x);
|
||||||
@ -129,15 +174,13 @@ public class CheckUtil {
|
|||||||
final int upperZ = upperBorder(location.z);
|
final int upperZ = upperBorder(location.z);
|
||||||
|
|
||||||
// Check the four borders of the players hitbox for something he could
|
// Check the four borders of the players hitbox for something he could
|
||||||
// be standing on
|
// be standing on, and combine the results
|
||||||
// Four seperate corners to check
|
|
||||||
// First border: lowerX, lowerZ
|
|
||||||
int result = 0;
|
int result = 0;
|
||||||
|
|
||||||
result |= canStand(world, lowerX, Y, lowerZ);
|
result |= evaluateSimpleLocation(world, lowerX, Y, lowerZ);
|
||||||
result |= canStand(world, upperX, Y, lowerZ);
|
result |= evaluateSimpleLocation(world, upperX, Y, lowerZ);
|
||||||
result |= canStand(world, upperX, Y, upperZ);
|
result |= evaluateSimpleLocation(world, upperX, Y, upperZ);
|
||||||
result |= canStand(world, lowerX, Y, upperZ);
|
result |= evaluateSimpleLocation(world, lowerX, Y, upperZ);
|
||||||
|
|
||||||
if(!isInGround(result)) {
|
if(!isInGround(result)) {
|
||||||
// Original location: X, Z (allow standing in walls this time)
|
// Original location: X, Z (allow standing in walls this time)
|
||||||
@ -150,43 +193,63 @@ public class CheckUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Potential results are: "LIQUID", "ONGROUND", "INGROUND", mixture or 0
|
* Evaluate a location by only looking at a specific
|
||||||
|
* "column" of the map to find out if that "column"
|
||||||
|
* would allow a player to stand, swim etc. there
|
||||||
*
|
*
|
||||||
* @param world
|
* @param world
|
||||||
* @param x
|
* @param x
|
||||||
* @param y
|
* @param y
|
||||||
* @param z
|
* @param z
|
||||||
* @return
|
* @return Returns INGROUND, ONGROUND, LIQUID, combination of the three or 0
|
||||||
*/
|
*/
|
||||||
private static final int canStand(final World world, final int x, final int y, final int z) {
|
private static final int evaluateSimpleLocation(final World world, final int x, final int y, final int z) {
|
||||||
|
|
||||||
final int standingIn = types[world.getBlockTypeIdAt(x, y, z)];
|
// First we need to know about the block itself, the block
|
||||||
final int headIn = types[world.getBlockTypeIdAt(x, y + 1, z)];
|
// below it and the block above it
|
||||||
|
final int top = types[world.getBlockTypeIdAt(x, y + 1, z)];
|
||||||
|
final int base = types[world.getBlockTypeIdAt(x, y, z)];
|
||||||
|
final int below = types[world.getBlockTypeIdAt(x, y - 1, z)];
|
||||||
|
|
||||||
int result = 0;
|
if(isNonSolid(top)) {
|
||||||
|
// Simplest (and most likely) case:
|
||||||
// It's either liquid, or something else
|
// Below the player is a solid block
|
||||||
if(isLiquid(standingIn) || isLiquid(headIn)) {
|
if(isSolid(below) && isNonSolid(base)) {
|
||||||
return LIQUID;
|
return ONGROUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Next (likely) case:
|
||||||
|
// There is a ladder
|
||||||
|
if(isLadder(base) || isLadder(top)) {
|
||||||
|
return ONGROUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Next (likely) case:
|
||||||
|
// At least the block the player stands
|
||||||
|
// in is solid
|
||||||
|
if(isSolid(base)) {
|
||||||
|
return INGROUND;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Last simple case: Player touches liquid
|
||||||
|
if(isLiquid(base) || isLiquid(top)) {
|
||||||
|
return LIQUID | INGROUND;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(isLadder(standingIn) || isLadder(headIn)) {
|
// Special case: Standing on a fence
|
||||||
return LADDER;
|
// Behave as if there is a block on top of the fence
|
||||||
|
if((below == FENCE) && base != FENCE && isNonSolid(top)) {
|
||||||
|
return INGROUND;
|
||||||
}
|
}
|
||||||
|
|
||||||
final int standingOn = types[world.getBlockTypeIdAt(x, y - 1, z)];
|
// Special case: Fence
|
||||||
|
// Being a bit above a fence
|
||||||
// Player standing with his feet in a (half) block?
|
if(below != FENCE && isNonSolid(base) && types[world.getBlockTypeIdAt(x, y - 2, z)] == FENCE) {
|
||||||
if((isSolid(standingIn) || standingOn == FENCE) && isNonSolid(headIn) && standingIn != FENCE) {
|
return ONGROUND;
|
||||||
result = INGROUND;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Player standing on a block?
|
return 0;
|
||||||
if((isLadder(headIn) || isLadder(standingIn)) || ((isSolid(standingOn) || types[world.getBlockTypeIdAt(x, y - 2, z)] == FENCE) && isNonSolid(standingIn) && standingOn != FENCE)) {
|
|
||||||
result |= ONGROUND;
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final boolean isSolid(final int value) {
|
public static final boolean isSolid(final int value) {
|
||||||
@ -206,11 +269,11 @@ public class CheckUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static final boolean isOnGround(final int fromType) {
|
public static final boolean isOnGround(final int fromType) {
|
||||||
return isLadder(fromType) || (fromType & ONGROUND) == ONGROUND;
|
return (fromType & ONGROUND) == ONGROUND;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final boolean isInGround(final int fromType) {
|
public static final boolean isInGround(final int fromType) {
|
||||||
return isLadder(fromType) || isLiquid(fromType) || (fromType & INGROUND) == INGROUND;
|
return (fromType & INGROUND) == INGROUND;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -53,8 +53,8 @@ public class RunningCheck extends MovingCheck {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// To know if a player "is on ground" is useful
|
// To know if a player "is on ground" is useful
|
||||||
final int fromType = CheckUtil.isLocationOnGround(player.getPlayer().getWorld(), from);
|
final int fromType = CheckUtil.evaluateLocation(player.getPlayer().getWorld(), from);
|
||||||
final int toType = CheckUtil.isLocationOnGround(player.getPlayer().getWorld(), to);
|
final int toType = CheckUtil.evaluateLocation(player.getPlayer().getWorld(), to);
|
||||||
|
|
||||||
final boolean fromOnGround = CheckUtil.isOnGround(fromType);
|
final boolean fromOnGround = CheckUtil.isOnGround(fromType);
|
||||||
final boolean fromInGround = CheckUtil.isInGround(fromType);
|
final boolean fromInGround = CheckUtil.isInGround(fromType);
|
||||||
|
@ -15,6 +15,7 @@ import org.bukkit.event.block.BlockListener;
|
|||||||
import org.bukkit.event.block.BlockPlaceEvent;
|
import org.bukkit.event.block.BlockPlaceEvent;
|
||||||
import org.bukkit.event.entity.EntityDamageByEntityEvent;
|
import org.bukkit.event.entity.EntityDamageByEntityEvent;
|
||||||
import org.bukkit.event.entity.EntityDamageEvent;
|
import org.bukkit.event.entity.EntityDamageEvent;
|
||||||
|
import org.bukkit.event.entity.EntityDamageEvent.DamageCause;
|
||||||
import org.bukkit.event.entity.EntityListener;
|
import org.bukkit.event.entity.EntityListener;
|
||||||
import org.bukkit.event.player.PlayerAnimationEvent;
|
import org.bukkit.event.player.PlayerAnimationEvent;
|
||||||
import org.bukkit.event.player.PlayerChatEvent;
|
import org.bukkit.event.player.PlayerChatEvent;
|
||||||
@ -262,27 +263,54 @@ public abstract class EventManagerImpl implements EventManager {
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Some additional limitations - only interested in direct
|
* Some additional limitations - only interested in
|
||||||
* attacks executed by actual players
|
* EntityDamageByEntity
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
if(!(event instanceof EntityDamageByEntityEvent))
|
if(!(event instanceof EntityDamageByEntityEvent))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
final EntityDamageByEntityEvent event2 = (EntityDamageByEntityEvent) event;
|
/**
|
||||||
|
* Only interested in PROJECTILE and ENTITY_ATTACK
|
||||||
// Only handle if attack done by a player directly or inderictly with a projectile
|
*/
|
||||||
if(!(event2.getDamager() instanceof Player) && !((event2.getDamager() instanceof Projectile) && ((Projectile)event2.getDamager()).getShooter() instanceof Player)) {
|
if(event.getCause() != DamageCause.PROJECTILE && event.getCause() != DamageCause.ENTITY_ATTACK) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Only now measure time and dispatch event */
|
final EntityDamageByEntityEvent event2 = (EntityDamageByEntityEvent) event;
|
||||||
if(measureTime != null && measureTime.isEnabled()) {
|
|
||||||
final long startTime = System.nanoTime();
|
if(event2.getCause() == DamageCause.PROJECTILE) {
|
||||||
m.handleEntityDamageByEntityEvent(event2, priority);
|
|
||||||
measureTime.addTime(System.nanoTime() - startTime);
|
// Only handle if attack done by a player indirectly with a
|
||||||
} else {
|
// projectile
|
||||||
m.handleEntityDamageByEntityEvent(event2, priority);
|
if(!((event2.getDamager() instanceof Projectile) && ((Projectile) event2.getDamager()).getShooter() instanceof Player)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Only now measure time and dispatch event */
|
||||||
|
if(measureTime != null && measureTime.isEnabled()) {
|
||||||
|
final long startTime = System.nanoTime();
|
||||||
|
m.handleProjectileDamageByEntityEvent(event2, priority);
|
||||||
|
measureTime.addTime(System.nanoTime() - startTime);
|
||||||
|
} else {
|
||||||
|
m.handleProjectileDamageByEntityEvent(event2, priority);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Only handle if attack done by a player directly
|
||||||
|
else if(event2.getCause() == DamageCause.ENTITY_ATTACK) {
|
||||||
|
|
||||||
|
if(!(event2.getDamager() instanceof Player)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Only now measure time and dispatch event */
|
||||||
|
if(measureTime != null && measureTime.isEnabled()) {
|
||||||
|
final long startTime = System.nanoTime();
|
||||||
|
m.handleEntityAttackDamageByEntityEvent(event2, priority);
|
||||||
|
measureTime.addTime(System.nanoTime() - startTime);
|
||||||
|
} else {
|
||||||
|
m.handleEntityAttackDamageByEntityEvent(event2, priority);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -380,7 +408,11 @@ public abstract class EventManagerImpl implements EventManager {
|
|||||||
handleEvent(event, priority);
|
handleEvent(event, priority);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void handleEntityDamageByEntityEvent(final EntityDamageByEntityEvent event, final Priority priority) {
|
protected void handleProjectileDamageByEntityEvent(final EntityDamageByEntityEvent event, final Priority priority) {
|
||||||
|
handleEvent(event, priority);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void handleEntityAttackDamageByEntityEvent(final EntityDamageByEntityEvent event, final Priority priority) {
|
||||||
handleEvent(event, priority);
|
handleEvent(event, priority);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -41,25 +41,8 @@ public class FightEventManager extends EventManagerImpl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void handleEntityDamageByEntityEvent(final EntityDamageByEntityEvent event, final Priority priority) {
|
protected void handleEntityAttackDamageByEntityEvent(final EntityDamageByEntityEvent event, final Priority priority) {
|
||||||
|
|
||||||
// Two possibilities: The player attacked directly, or by projectile
|
|
||||||
// We already made sure in the calling method that it is one of those
|
|
||||||
// two
|
|
||||||
if(event.getDamager() instanceof Projectile) {
|
|
||||||
final Player damager = (Player) ((Projectile) event.getDamager()).getShooter();
|
|
||||||
final NoCheatPlayer player = plugin.getPlayer(damager);
|
|
||||||
|
|
||||||
final FightData data = player.getData().fight;
|
|
||||||
|
|
||||||
// Skip the next damage event, because it is with high probability
|
|
||||||
// the same as this one
|
|
||||||
data.skipNext = true;
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Other possibility, the player is the damager directly
|
|
||||||
final Player damager = (Player) event.getDamager();
|
final Player damager = (Player) event.getDamager();
|
||||||
|
|
||||||
final NoCheatPlayer player = plugin.getPlayer(damager);
|
final NoCheatPlayer player = plugin.getPlayer(damager);
|
||||||
@ -94,6 +77,22 @@ public class FightEventManager extends EventManagerImpl {
|
|||||||
event.setCancelled(cancelled);
|
event.setCancelled(cancelled);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void handleProjectileDamageByEntityEvent(final EntityDamageByEntityEvent event, final Priority priority) {
|
||||||
|
|
||||||
|
final Player damager = (Player) ((Projectile) event.getDamager()).getShooter();
|
||||||
|
final NoCheatPlayer player = plugin.getPlayer(damager);
|
||||||
|
|
||||||
|
final FightData data = player.getData().fight;
|
||||||
|
|
||||||
|
// Skip the next damage event, because it is with high probability
|
||||||
|
// the same as this one
|
||||||
|
data.skipNext = true;
|
||||||
|
|
||||||
|
return;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void handlePlayerAnimationEvent(final PlayerAnimationEvent event, final Priority priority) {
|
protected void handlePlayerAnimationEvent(final PlayerAnimationEvent event, final Priority priority) {
|
||||||
plugin.getPlayer(event.getPlayer()).getData().fight.armswung = true;
|
plugin.getPlayer(event.getPlayer()).getData().fight.armswung = true;
|
||||||
|
Loading…
Reference in New Issue
Block a user