Attempt to fix issues with pvp and knockback.

Might disable for older versions of MC
(checks.fight.pvp.knockbackvelocity).
This commit is contained in:
asofold 2014-12-07 23:54:49 +01:00
parent ec997796b8
commit 3c8b255817
5 changed files with 102 additions and 37 deletions

View File

@ -111,6 +111,7 @@ public class FightConfig extends ACheckConfig {
// Special flags:
public final boolean yawRateCheck;
public final boolean cancelDead;
public final boolean knockBackVelocityPvP;
/**
* Instantiates a new fight configuration.
@ -176,6 +177,7 @@ public class FightConfig extends ACheckConfig {
yawRateCheck = data.getBoolean(ConfPaths.FIGHT_YAWRATE_CHECK, true);
cancelDead = data.getBoolean(ConfPaths.FIGHT_CANCELDEAD);
knockBackVelocityPvP = data.getBoolean(ConfPaths.FIGHT_PVP_KNOCKBACKVELOCITY);
}
/* (non-Javadoc)

View File

@ -3,6 +3,7 @@ package fr.neatmonster.nocheatplus.checks.fight;
import java.util.Iterator;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
@ -21,6 +22,7 @@ import org.bukkit.event.player.PlayerItemHeldEvent;
import org.bukkit.event.player.PlayerToggleSprintEvent;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.PlayerInventory;
import org.bukkit.util.Vector;
import fr.neatmonster.nocheatplus.NCPAPIProvider;
import fr.neatmonster.nocheatplus.checks.CheckListener;
@ -39,6 +41,7 @@ import fr.neatmonster.nocheatplus.components.JoinLeaveListener;
import fr.neatmonster.nocheatplus.logging.Streams;
import fr.neatmonster.nocheatplus.permissions.Permissions;
import fr.neatmonster.nocheatplus.stats.Counters;
import fr.neatmonster.nocheatplus.utilities.BlockProperties;
import fr.neatmonster.nocheatplus.utilities.TickTask;
import fr.neatmonster.nocheatplus.utilities.TrigUtil;
import fr.neatmonster.nocheatplus.utilities.build.BuildParameters;
@ -233,7 +236,7 @@ public class FightListener extends CheckListener implements JoinLeaveListener{
// TODO: Permission ?
cancelled = true;
}
if (!cancelled) {
final boolean reachEnabled = reach.isEnabled(player);
final boolean directionEnabled = direction.isEnabled(player);
@ -253,7 +256,7 @@ public class FightListener extends CheckListener implements JoinLeaveListener{
}
}
}
// Check angle with allowed window.
if (angle.isEnabled(player)) {
// TODO: Revise, use own trace.
@ -321,7 +324,7 @@ public class FightListener extends CheckListener implements JoinLeaveListener{
return cancelled;
}
/**
* Quick split-off: Checks using a location trace.
* @param player
@ -338,18 +341,18 @@ public class FightListener extends CheckListener implements JoinLeaveListener{
* @return If to cancel (true) or not (false).
*/
private boolean locationTraceChecks(Player player, Location loc, FightData data, FightConfig cc, Entity damaged, Location damagedLoc, LocationTrace damagedTrace, long tick, boolean reachEnabled, boolean directionEnabled) {
// TODO: Order / splitting off generic stuff.
// TODO: Order / splitting off generic stuff.
boolean cancelled = false;
// (Might pass generic context to factories, for shared + heavy properties.)
final SharedContext sharedContext = new SharedContext(damaged, mcAccess);
final ReachContext reachContext = reachEnabled ? reach.getContext(player, loc, damaged, damagedLoc, data, cc, sharedContext) : null;
final DirectionContext directionContext = directionEnabled ? direction.getContext(player, loc, damaged, damagedLoc, data, cc, sharedContext) : null;
final long traceOldest = tick; // - damagedTrace.getMaxSize(); // TODO: Set by window.
// TODO: Iterating direction, which, static/dynamic choice.
final Iterator<TraceEntry> traceIt = damagedTrace.maxAgeIterator(traceOldest);
boolean violation = true; // No tick with all checks passed.
boolean reachPassed = !reachEnabled; // Passed individually for some tick.
boolean directionPassed = !directionEnabled; // Passed individually for some tick.
@ -399,7 +402,7 @@ public class FightListener extends CheckListener implements JoinLeaveListener{
// TODO: Log exact state, probably record min/max latency (individually).
return cancelled;
}
/**
* Check if a player might return some damage due to the "thorns" enchantment.
* @param player
@ -431,10 +434,12 @@ public class FightListener extends CheckListener implements JoinLeaveListener{
final FightData damagedData = damagedPlayer == null ? null : FightData.getData(damagedPlayer);
final boolean damagedIsDead = damaged.isDead();
if (damagedPlayer != null && !damagedIsDead) {
if (!damagedPlayer.isDead() && godMode.isEnabled(damagedPlayer) && godMode.check(damagedPlayer, BridgeHealth.getDamage(event), damagedData)){
// God mode check.
if (godMode.isEnabled(damagedPlayer) && godMode.check(damagedPlayer, BridgeHealth.getDamage(event), damagedData)){
// It requested to "cancel" the players invulnerability, so set their noDamageTicks to 0.
damagedPlayer.setNoDamageTicks(0);
}
// Adjust buffer for fast heal checks.
if (BridgeHealth.getHealth(damagedPlayer) >= BridgeHealth.getMaxHealth(damagedPlayer)){
// TODO: Might use the same FightData instance for GodMode.
if (damagedData.fastHealBuffer < 0){
@ -500,16 +505,65 @@ public class FightListener extends CheckListener implements JoinLeaveListener{
public void onEntityDamageMonitor(final EntityDamageEvent event) {
final Entity damaged = event.getEntity();
if (damaged instanceof Player){
final Player player = (Player) damaged;
final FightData data = FightData.getData(player);
final int ndt = player.getNoDamageTicks();
if (data.lastDamageTick == TickTask.getTick() && data.lastNoDamageTicks != ndt){
final Player damagedPlayer = (Player) damaged;
final FightData damagedData = FightData.getData(damagedPlayer);
final int ndt = damagedPlayer.getNoDamageTicks();
if (damagedData.lastDamageTick == TickTask.getTick() && damagedData.lastNoDamageTicks != ndt){
// Plugin compatibility thing.
data.lastNoDamageTicks = ndt;
damagedData.lastNoDamageTicks = ndt;
}
// Knockback calculation.
switch (event.getCause()) {
case ENTITY_ATTACK:
if (event instanceof EntityDamageByEntityEvent) {
final Entity entity = ((EntityDamageByEntityEvent) event).getDamager();
if ((entity instanceof Player) && FightConfig.getConfig(damagedPlayer).knockBackVelocityPvP) {
checkKnockBack((Player) entity, damagedPlayer, damagedData);
}
}
default:
break;
}
}
}
/**
* Knockback accounting: Add velocity.
* @param attacker
* @param damagedPlayer
* @param damagedData
*/
private void checkKnockBack(final Player attacker, final Player damagedPlayer, final FightData damagedData) {
double level = 1.0; // Assume "some knock-back" always.
if (attacker.isSprinting()) {
level += 1.0;
}
final ItemStack stack = attacker.getItemInHand();
if (stack != null && stack.getType() != Material.AIR) {
level += (double) stack.getEnchantmentLevel(Enchantment.KNOCKBACK);
}
if (level > 0.0) {
final MovingData mdata = MovingData.getData(damagedPlayer);
final MovingConfig mcc = MovingConfig.getConfig(damagedPlayer);
// Cap the level to something reasonable. TODO: Config.
level = Math.min(20.0, level);
// TODO: How is the direction really calculated?
final Vector dir = attacker.getLocation(useLoc1).getDirection().multiply(0.5 * level);
double vy = dir.getY();
if (BlockProperties.isOnGround(damagedPlayer, damagedPlayer.getLocation(useLoc1), mcc.yOnGround)) {
// (Re-used useLoc1 without need for cleanup.)
vy = 0.365;
}
useLoc1.setWorld(null); // Cleanup.
if (damagedData.debug || mdata.debug) {
NCPAPIProvider.getNoCheatPlusAPI().getLogManager().debug(Streams.TRACE_FILE, damagedPlayer.getName() + " received knockback level: " + level);
}
MovingListener.addVelocity(damagedPlayer, mdata, mcc, dir.getX(), vy, dir.getZ());
}
}
/**
* We listen to death events to prevent a very specific method of doing godmode.
*

View File

@ -1010,57 +1010,64 @@ public class MovingListener extends CheckListener implements TickListener, IRemo
* @param event
* the event
*/
@EventHandler(
ignoreCancelled = true, priority = EventPriority.MONITOR)
@EventHandler(ignoreCancelled = true, priority = EventPriority.MONITOR)
public void onPlayerVelocity(final PlayerVelocityEvent event) {
final Player player = event.getPlayer();
final MovingData data = MovingData.getData(player);
// Ignore velocity if inside of vehicles.
// Ignore players who are in vehicles.
if (player.isInsideVehicle()) {
data.removeAllVelocity();
return;
}
// Process velocity.
final Vector velocity = event.getVelocity();
final MovingConfig cc = MovingConfig.getConfig(player);
addVelocity(player, data, cc, velocity.getX(), velocity.getY(), velocity.getZ());
}
/**
* Add velocity to internal book-keeping.
* @param player
* @param data
* @param cc
* @param vx
* @param vy
* @param vz
*/
public static void addVelocity(final Player player, final MovingData data, final MovingConfig cc, final double vx, final double vy, final double vz) {
final int tick = TickTask.getTick();
data.removeInvalidVelocity(tick - cc.velocityActivationTicks);
final Vector velocity = event.getVelocity();
if (data.debug) {
NCPAPIProvider.getNoCheatPlusAPI().getLogManager().debug(Streams.TRACE_FILE, event.getPlayer().getName() + " new velocity: " + velocity);
NCPAPIProvider.getNoCheatPlusAPI().getLogManager().debug(Streams.TRACE_FILE, player.getName() + " new velocity: " + vx + ", " + vy + ", " + vz);
}
double newVal = velocity.getY();
boolean used = false;
if (newVal >= 0D) { // TODO: Just >, not >=.
if (vy > 0D) {
used = true;
if (data.verticalFreedom <= 0.001 && data.verticalVelocityCounter >= 0) {
data.verticalVelocity = 0;
}
data.verticalVelocity += newVal;
data.verticalVelocity += vy;
data.verticalFreedom += data.verticalVelocity;
data.verticalVelocityCounter = Math.min(100, Math.max(data.verticalVelocityCounter, cc.velocityGraceTicks ) + 1 + (int) Math.round(newVal * 10.0)); // 50;
data.verticalVelocityCounter = Math.min(100, Math.max(data.verticalVelocityCounter, cc.velocityGraceTicks ) + 1 + (int) Math.round(vy * 10.0)); // 50;
data.verticalVelocityUsed = 0;
}
newVal = Math.sqrt(velocity.getX() * velocity.getX() + velocity.getZ() * velocity.getZ());
if (newVal > 0D) {
if (vx != 0.0 && vz != 0.0) {
final double newVal = Math.sqrt(vx * vx + vz * vz);
used = true;
final Velocity vel = new Velocity(tick, newVal, cc.velocityActivationCounter, Math.max(20, 1 + (int) Math.round(newVal * 10.0)));
data.addHorizontalVelocity(vel);
// data.horizontalFreedom += newVal;
// data.horizontalVelocityCounter = Math.min(100, Math.max(data.horizontalVelocityCounter, cc.velocityGraceTicks ) + 1 + (int) Math.round(newVal * 10.0)); // 30;
// data.horizontalVelocityUsed = 0;
}
// Set dirty flag here.
if (used) {
data.sfDirty = true;
data.sfDirty = true; // TODO: Only needed for vertical velocity? Get rid anyway :p.
data.sfNoLowJump = true;
}
// TODO: clear accounting here ?
}
@ -1281,7 +1288,7 @@ public class MovingListener extends CheckListener implements TickListener, IRemo
* @param cc
*/
private void dataOnJoin(Player player, Location loc, MovingData data, MovingConfig cc) {
final int tick = TickTask.getTick();
// Check loaded chunks.
if (cc.loadChunksOnJoin) {
@ -1291,7 +1298,7 @@ public class MovingListener extends CheckListener implements TickListener, IRemo
StaticLog.logInfo("[NoCheatPlus] Player join: Loaded " + loaded + " chunk" + (loaded == 1 ? "" : "s") + " for the world " + loc.getWorld().getName() + " for player: " + player.getName());
}
}
// Correct set-back on join.
if (!data.hasSetBack() || data.hasSetBackWorldChanged(loc)) {
data.clearFlyData();
@ -1304,7 +1311,7 @@ public class MovingListener extends CheckListener implements TickListener, IRemo
// TODO: If to reset positions: relate to previous ones and set-back.
data.resetPositions(loc); // TODO: See above.
}
// Always reset position to this one.
// TODO: more fine grained reset?
data.clearMorePacketsData();

View File

@ -376,7 +376,9 @@ public abstract class ConfPaths {
public static final String FIGHT = CHECKS + "fight.";
public static final String FIGHT_CANCELDEAD = FIGHT + "canceldead";
public static final String FIGHT_TOOLCHANGEPENALTY = FIGHT + "toolchangepenalty";
public static final String FIGHT_TOOLCHANGEPENALTY = FIGHT + "toolchangepenalty";
private static final String FIGHT_PVP = FIGHT + "pvp.";
public static final String FIGHT_PVP_KNOCKBACKVELOCITY = FIGHT_PVP + "knockbackvelocity";
private static final String FIGHT_ANGLE = FIGHT + "angle.";
public static final String FIGHT_ANGLE_CHECK = FIGHT_ANGLE + "active";
@ -645,5 +647,4 @@ public abstract class ConfPaths {
@Deprecated
public static final String BLOCKBREAK_FASTBREAK_DEBUG = "checks.blockbreak.fastbreak.debug";
}

View File

@ -262,6 +262,7 @@ public class DefaultConfig extends ConfigFile {
// FIGHT
set(ConfPaths.FIGHT_CANCELDEAD, true);
set(ConfPaths.FIGHT_TOOLCHANGEPENALTY, 500L);
set(ConfPaths.FIGHT_PVP_KNOCKBACKVELOCITY, true);
set(ConfPaths.FIGHT_YAWRATE_CHECK, true);