mirror of
https://github.com/NoCheatPlus/NoCheatPlus.git
synced 2024-12-30 20:37:52 +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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
|
||||
final Location eyes = player.getPlayer().getEyeLocation();
|
||||
@ -63,12 +73,19 @@ public class CheckUtil {
|
||||
private final static double magic = 0.45D;
|
||||
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 SOLID = 2; // 0x00000010
|
||||
|
||||
// All liquids are "nonsolid" too
|
||||
private static final int LIQUID = 4 | NONSOLID; // 0x00000101
|
||||
|
||||
// All ladders are "nonsolid" and "solid" too
|
||||
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 INGROUND = 128;
|
||||
private static final int ONGROUND = 256;
|
||||
// Until I can think of a better way to determine if a block is solid or
|
||||
@ -77,50 +94,78 @@ public class CheckUtil {
|
||||
|
||||
static {
|
||||
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++) {
|
||||
|
||||
// Everything is considered nonsolid at first
|
||||
types[i] = NONSOLID;
|
||||
// Everything unknown is considered nonsolid and solid
|
||||
types[i] = NONSOLID | SOLID;
|
||||
|
||||
if(Block.byId[i] != null) {
|
||||
if(Block.byId[i].material.isSolid()) {
|
||||
// solid blocks like STONE, CAKE, TRAPDOORS
|
||||
// STONE, CAKE, LEAFS, ...
|
||||
types[i] = SOLID;
|
||||
} else if(Block.byId[i].material.isLiquid()) {
|
||||
// WATER, LAVA
|
||||
// WATER, LAVA, ...
|
||||
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.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.DIODE_BLOCK_ON.getId()] |= SOLID | NONSOLID;
|
||||
types[Material.DIODE_BLOCK_OFF.getId()] |= SOLID | NONSOLID;
|
||||
types[Material.WOODEN_DOOR.getId()] |= SOLID | NONSOLID;
|
||||
types[Material.IRON_DOOR_BLOCK.getId()] |= SOLID | NONSOLID;
|
||||
types[Material.PISTON_EXTENSION.getId()] |= SOLID | NONSOLID;
|
||||
types[Material.PISTON_MOVING_PIECE.getId()] |= SOLID | NONSOLID;
|
||||
types[Material.TRAP_DOOR.getId()] |= SOLID | NONSOLID;
|
||||
types[111] |= SOLID | NONSOLID; // Lily pads
|
||||
types[Material.SIGN_POST.getId()] = NONSOLID;
|
||||
|
||||
// doors can be solid or not
|
||||
types[Material.WOODEN_DOOR.getId()] = SOLID | NONSOLID;
|
||||
types[Material.IRON_DOOR_BLOCK.getId()] = SOLID | NONSOLID;
|
||||
|
||||
// pressure plates are so slim, you can consider them
|
||||
// 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
|
||||
* @param values
|
||||
* The coordinates [lowerX, higherX, Y, lowerZ, higherZ] to be
|
||||
* checked
|
||||
* @param l
|
||||
* The precise location that was used for calculation of "values"
|
||||
* @param location
|
||||
* The precise location in the world
|
||||
*
|
||||
* @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 upperX = upperBorder(location.x);
|
||||
@ -129,15 +174,13 @@ public class CheckUtil {
|
||||
final int upperZ = upperBorder(location.z);
|
||||
|
||||
// Check the four borders of the players hitbox for something he could
|
||||
// be standing on
|
||||
// Four seperate corners to check
|
||||
// First border: lowerX, lowerZ
|
||||
// be standing on, and combine the results
|
||||
int result = 0;
|
||||
|
||||
result |= canStand(world, lowerX, Y, lowerZ);
|
||||
result |= canStand(world, upperX, Y, lowerZ);
|
||||
result |= canStand(world, upperX, Y, upperZ);
|
||||
result |= canStand(world, lowerX, Y, upperZ);
|
||||
result |= evaluateSimpleLocation(world, lowerX, Y, lowerZ);
|
||||
result |= evaluateSimpleLocation(world, upperX, Y, lowerZ);
|
||||
result |= evaluateSimpleLocation(world, upperX, Y, upperZ);
|
||||
result |= evaluateSimpleLocation(world, lowerX, Y, upperZ);
|
||||
|
||||
if(!isInGround(result)) {
|
||||
// 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 x
|
||||
* @param y
|
||||
* @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)];
|
||||
final int headIn = types[world.getBlockTypeIdAt(x, y + 1, z)];
|
||||
// First we need to know about the block itself, the block
|
||||
// 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;
|
||||
|
||||
// It's either liquid, or something else
|
||||
if(isLiquid(standingIn) || isLiquid(headIn)) {
|
||||
return LIQUID;
|
||||
if(isNonSolid(top)) {
|
||||
// Simplest (and most likely) case:
|
||||
// Below the player is a solid block
|
||||
if(isSolid(below) && isNonSolid(base)) {
|
||||
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)) {
|
||||
return LADDER;
|
||||
// Special case: Standing on a fence
|
||||
// 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)];
|
||||
|
||||
// Player standing with his feet in a (half) block?
|
||||
if((isSolid(standingIn) || standingOn == FENCE) && isNonSolid(headIn) && standingIn != FENCE) {
|
||||
result = INGROUND;
|
||||
// Special case: Fence
|
||||
// Being a bit above a fence
|
||||
if(below != FENCE && isNonSolid(base) && types[world.getBlockTypeIdAt(x, y - 2, z)] == FENCE) {
|
||||
return ONGROUND;
|
||||
}
|
||||
|
||||
// Player standing on a block?
|
||||
if((isLadder(headIn) || isLadder(standingIn)) || ((isSolid(standingOn) || types[world.getBlockTypeIdAt(x, y - 2, z)] == FENCE) && isNonSolid(standingIn) && standingOn != FENCE)) {
|
||||
result |= ONGROUND;
|
||||
}
|
||||
|
||||
return result;
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static final boolean isSolid(final int value) {
|
||||
@ -206,11 +269,11 @@ public class CheckUtil {
|
||||
}
|
||||
|
||||
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) {
|
||||
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
|
||||
final int fromType = CheckUtil.isLocationOnGround(player.getPlayer().getWorld(), from);
|
||||
final int toType = CheckUtil.isLocationOnGround(player.getPlayer().getWorld(), to);
|
||||
final int fromType = CheckUtil.evaluateLocation(player.getPlayer().getWorld(), from);
|
||||
final int toType = CheckUtil.evaluateLocation(player.getPlayer().getWorld(), to);
|
||||
|
||||
final boolean fromOnGround = CheckUtil.isOnGround(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.entity.EntityDamageByEntityEvent;
|
||||
import org.bukkit.event.entity.EntityDamageEvent;
|
||||
import org.bukkit.event.entity.EntityDamageEvent.DamageCause;
|
||||
import org.bukkit.event.entity.EntityListener;
|
||||
import org.bukkit.event.player.PlayerAnimationEvent;
|
||||
import org.bukkit.event.player.PlayerChatEvent;
|
||||
@ -262,27 +263,54 @@ public abstract class EventManagerImpl implements EventManager {
|
||||
return;
|
||||
|
||||
/**
|
||||
* Some additional limitations - only interested in direct
|
||||
* attacks executed by actual players
|
||||
* Some additional limitations - only interested in
|
||||
* EntityDamageByEntity
|
||||
*
|
||||
*/
|
||||
if(!(event instanceof EntityDamageByEntityEvent))
|
||||
return;
|
||||
|
||||
final EntityDamageByEntityEvent event2 = (EntityDamageByEntityEvent) event;
|
||||
|
||||
// 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)) {
|
||||
/**
|
||||
* Only interested in PROJECTILE and ENTITY_ATTACK
|
||||
*/
|
||||
if(event.getCause() != DamageCause.PROJECTILE && event.getCause() != DamageCause.ENTITY_ATTACK) {
|
||||
return;
|
||||
}
|
||||
|
||||
/** Only now measure time and dispatch event */
|
||||
if(measureTime != null && measureTime.isEnabled()) {
|
||||
final long startTime = System.nanoTime();
|
||||
m.handleEntityDamageByEntityEvent(event2, priority);
|
||||
measureTime.addTime(System.nanoTime() - startTime);
|
||||
} else {
|
||||
m.handleEntityDamageByEntityEvent(event2, priority);
|
||||
|
||||
final EntityDamageByEntityEvent event2 = (EntityDamageByEntityEvent) event;
|
||||
|
||||
if(event2.getCause() == DamageCause.PROJECTILE) {
|
||||
|
||||
// Only handle if attack done by a player indirectly with a
|
||||
// projectile
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -41,25 +41,8 @@ public class FightEventManager extends EventManagerImpl {
|
||||
}
|
||||
|
||||
@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 NoCheatPlayer player = plugin.getPlayer(damager);
|
||||
@ -94,6 +77,22 @@ public class FightEventManager extends EventManagerImpl {
|
||||
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
|
||||
protected void handlePlayerAnimationEvent(final PlayerAnimationEvent event, final Priority priority) {
|
||||
plugin.getPlayer(event.getPlayer()).getData().fight.armswung = true;
|
||||
|
Loading…
Reference in New Issue
Block a user