Skip knock-back for damage events that would not count.

This commit is contained in:
asofold 2014-12-08 01:02:37 +01:00
parent 3739e2a3f5
commit a51965c57d
2 changed files with 209 additions and 193 deletions

View File

@ -513,6 +513,13 @@ public class FightListener extends CheckListener implements JoinLeaveListener{
// Plugin compatibility thing.
damagedData.lastNoDamageTicks = ndt;
}
// Skip events that would not count.
if (ndt >= damagedPlayer.getMaximumNoDamageTicks() / 2) { // TODO: Exact bounds.
final EntityDamageEvent lastDamage = damaged.getLastDamageCause();
if (lastDamage != null && BridgeHealth.getFinalDamage(lastDamage) <= BridgeHealth.getFinalDamage(event)) {
return;
}
}
// Knockback calculation.
switch (event.getCause()) {
case ENTITY_ATTACK:

View File

@ -23,198 +23,207 @@ import fr.neatmonster.nocheatplus.utilities.ReflectionUtil;
*
*/
public class BridgeHealth {
/** For debugging purposes. TODO: Reset on shutdown !? */
private static Set<String> failures = new HashSet<String>();
/**
* This method is meant to be called on API that changed from int to double.<br>
* NOTE: Might get changed to return a Number instance.
* @param obj Object to call the method on.
* @param methodName
* @param RuntimeException with reason Will be thrown if no recovery from present methods is possible. If not null the first call gets logged as "API incompatibility".
* @return
*/
public static final double getDoubleOrInt(final Object obj, final String methodName, final Throwable reason){
if (reason != null){
final String tag = obj.getClass().getName() + "." + methodName;
if (failures.add(tag)){
// New entry.
checkLogEntry(tag);
}
}
final Object o1 = ReflectionUtil.invokeMethodNoArgs(obj, methodName, double.class, int.class);
if (o1 instanceof Number){
return ((Number) o1).doubleValue();
}
else{
String message = "Expect method " + methodName + " in " + obj.getClass() + " with return type double or int, returned instead: " + ((o1 == null ? "null" : o1.getClass().getName()));
if (reason == null){
throw new RuntimeException(message);
}
else{
throw new RuntimeException(message, reason);
}
}
}
/**
* Get the amount of health added with the event.
* @param event
* @return
* @throws RuntimeException, in case of an IncompatibleClassChangeError without success on recovery attempts.
*/
public static double getAmount(final EntityRegainHealthEvent event){
try{
return event.getAmount();
}
catch(IncompatibleClassChangeError e){
return getDoubleOrInt(event, "getAmount", e);
}
}
/**
* Get the damage from an EntityDamageEvent.
* @param event
* @return
* @throws RuntimeException, in case of an IncompatibleClassChangeError without success on recovery attempts.
*/
public static double getDamage(final EntityDamageEvent event){
try{
return event.getDamage();
}
catch(IncompatibleClassChangeError e){
return getDoubleOrInt(event, "getDamage", e);
}
}
/**
* Set the damage from an EntityDamageEvent.
* @param event
* @param damage
* @return
* @throws RuntimeException, in case of an IncompatibleClassChangeError without success on recovery attempts.
*/
public static void setDamage(final EntityDamageEvent event, final double damage){
try{
event.setDamage(damage);
}
catch(IncompatibleClassChangeError e){
invokeVoid(event, "setDamage", (int) Math.round(damage), e);
}
}
/**
* Get the health for an entity (LivingEntity).
* @param entity
* @return
* @throws RuntimeException, in case of an IncompatibleClassChangeError without success on recovery attempts.
*/
public static double getHealth(final LivingEntity entity){
try{
return entity.getHealth();
}
catch(IncompatibleClassChangeError e){
return getDoubleOrInt(entity, "getHealth", e);
}
}
/**
* Get the maximum health for an entity (LivingEntity).
* @param entity
* @return
* @throws RuntimeException, in case of an IncompatibleClassChangeError without success on recovery attempts.
*/
public static double getMaxHealth(final LivingEntity entity){
try{
return entity.getMaxHealth();
}
catch(IncompatibleClassChangeError e){
return getDoubleOrInt(entity, "getMaxHealth", e);
}
}
/**
* Get the last damage for an entity (LivingEntity).
* @param entity
* @return
* @throws RuntimeException, in case of an IncompatibleClassChangeError without success on recovery attempts.
*/
public static double getLastDamage(final LivingEntity entity){
try{
return entity.getLastDamage();
}
catch(IncompatibleClassChangeError e){
return getDoubleOrInt(entity, "getLastDamage", e);
}
}
/**
* Set the health for an entity (LivingEntity).
* @param entity
* @param health
* @return
* @throws RuntimeException, in case of an IncompatibleClassChangeError without success on recovery attempts.
*/
public static void setHealth(final LivingEntity entity, final double health){
try{
entity.setHealth(health);
}
catch(IncompatibleClassChangeError e){
invokeVoid(entity, "setHealth", (int) Math.round(health), e);
}
}
/**
* Damage an entity (LivingEntity).
* @param entity
* @param damage
* @throws RuntimeException, in case of an IncompatibleClassChangeError without success on recovery attempts.
*/
public static void damage(final LivingEntity entity, final double damage){
try{
entity.damage(damage);
}
catch(IncompatibleClassChangeError e){
invokeVoid(entity, "damage", (int) Math.round(damage), e);
}
}
@SuppressWarnings("deprecation")
public static EntityDamageEvent getEntityDamageEvent(final Entity entity, final DamageCause damageCause, final double damage){
try{
return new EntityDamageEvent(entity, damageCause, damage);
}
catch(IncompatibleClassChangeError e){
return new EntityDamageEvent(entity, damageCause, (int) Math.round(damage));
}
}
/**
* Intended for faster compatibility methods for defined scenarios. Transforms any exception to a RuntimeException.
* @param obj
* @param methodName
* @param value
*/
public static void invokeVoid(final Object obj, final String methodName, final int value, final Throwable reason){
if (reason != null){
final String tag = obj.getClass().getName() + "." + methodName;
if (failures.add(tag)){
checkLogEntry(tag);
}
}
try {
obj.getClass().getMethod(methodName, int.class).invoke(obj, value);
} catch (Throwable t) {
throw new RuntimeException("Could not invoke " + methodName + " with one argument (int) on: " + obj.getClass().getName(), reason);
}
}
private static void checkLogEntry(final String tag) {
// New entry.
if (ConfigManager.getConfigFile().getBoolean(ConfPaths.LOGGING_DEBUG)){
StaticLog.logWarning("[NoCheatPlus] API incompatibility detected: " + tag);
}
}
/** For debugging purposes. TODO: Reset on shutdown !? */
private static Set<String> failures = new HashSet<String>();
/**
* This method is meant to be called on API that changed from int to double.<br>
* NOTE: Might get changed to return a Number instance.
* @param obj Object to call the method on.
* @param methodName
* @param RuntimeException with reason Will be thrown if no recovery from present methods is possible. If not null the first call gets logged as "API incompatibility".
* @return
*/
public static final double getDoubleOrInt(final Object obj, final String methodName, final Throwable reason){
if (reason != null){
final String tag = obj.getClass().getName() + "." + methodName;
if (failures.add(tag)){
// New entry.
checkLogEntry(tag);
}
}
final Object o1 = ReflectionUtil.invokeMethodNoArgs(obj, methodName, double.class, int.class);
if (o1 instanceof Number){
return ((Number) o1).doubleValue();
}
else{
String message = "Expect method " + methodName + " in " + obj.getClass() + " with return type double or int, returned instead: " + ((o1 == null ? "null" : o1.getClass().getName()));
if (reason == null){
throw new RuntimeException(message);
}
else{
throw new RuntimeException(message, reason);
}
}
}
/**
* Get the amount of health added with the event.
* @param event
* @return
* @throws RuntimeException, in case of an IncompatibleClassChangeError without success on recovery attempts.
*/
public static double getAmount(final EntityRegainHealthEvent event){
try{
return event.getAmount();
}
catch(IncompatibleClassChangeError e){
return getDoubleOrInt(event, "getAmount", e);
}
}
/**
* Get the damage from an EntityDamageEvent.
* @param event
* @return
* @throws RuntimeException, in case of an IncompatibleClassChangeError without success on recovery attempts.
*/
public static double getDamage(final EntityDamageEvent event){
try{
return event.getDamage();
}
catch(IncompatibleClassChangeError e){
return getDoubleOrInt(event, "getDamage", e);
}
}
public static double getFinalDamage(final EntityDamageEvent event) {
try {
return event.getFinalDamage();
}
catch (Throwable t) {
return getDamage(event);
}
}
/**
* Set the damage from an EntityDamageEvent.
* @param event
* @param damage
* @return
* @throws RuntimeException, in case of an IncompatibleClassChangeError without success on recovery attempts.
*/
public static void setDamage(final EntityDamageEvent event, final double damage){
try{
event.setDamage(damage);
}
catch(IncompatibleClassChangeError e){
invokeVoid(event, "setDamage", (int) Math.round(damage), e);
}
}
/**
* Get the health for an entity (LivingEntity).
* @param entity
* @return
* @throws RuntimeException, in case of an IncompatibleClassChangeError without success on recovery attempts.
*/
public static double getHealth(final LivingEntity entity){
try{
return entity.getHealth();
}
catch(IncompatibleClassChangeError e){
return getDoubleOrInt(entity, "getHealth", e);
}
}
/**
* Get the maximum health for an entity (LivingEntity).
* @param entity
* @return
* @throws RuntimeException, in case of an IncompatibleClassChangeError without success on recovery attempts.
*/
public static double getMaxHealth(final LivingEntity entity){
try{
return entity.getMaxHealth();
}
catch(IncompatibleClassChangeError e){
return getDoubleOrInt(entity, "getMaxHealth", e);
}
}
/**
* Get the last damage for an entity (LivingEntity).
* @param entity
* @return
* @throws RuntimeException, in case of an IncompatibleClassChangeError without success on recovery attempts.
*/
public static double getLastDamage(final LivingEntity entity){
try{
return entity.getLastDamage();
}
catch(IncompatibleClassChangeError e){
return getDoubleOrInt(entity, "getLastDamage", e);
}
}
/**
* Set the health for an entity (LivingEntity).
* @param entity
* @param health
* @return
* @throws RuntimeException, in case of an IncompatibleClassChangeError without success on recovery attempts.
*/
public static void setHealth(final LivingEntity entity, final double health){
try{
entity.setHealth(health);
}
catch(IncompatibleClassChangeError e){
invokeVoid(entity, "setHealth", (int) Math.round(health), e);
}
}
/**
* Damage an entity (LivingEntity).
* @param entity
* @param damage
* @throws RuntimeException, in case of an IncompatibleClassChangeError without success on recovery attempts.
*/
public static void damage(final LivingEntity entity, final double damage){
try{
entity.damage(damage);
}
catch(IncompatibleClassChangeError e){
invokeVoid(entity, "damage", (int) Math.round(damage), e);
}
}
@SuppressWarnings("deprecation")
public static EntityDamageEvent getEntityDamageEvent(final Entity entity, final DamageCause damageCause, final double damage){
try{
return new EntityDamageEvent(entity, damageCause, damage);
}
catch(IncompatibleClassChangeError e){
return new EntityDamageEvent(entity, damageCause, (int) Math.round(damage));
}
}
/**
* Intended for faster compatibility methods for defined scenarios. Transforms any exception to a RuntimeException.
* @param obj
* @param methodName
* @param value
*/
public static void invokeVoid(final Object obj, final String methodName, final int value, final Throwable reason){
if (reason != null){
final String tag = obj.getClass().getName() + "." + methodName;
if (failures.add(tag)){
checkLogEntry(tag);
}
}
try {
obj.getClass().getMethod(methodName, int.class).invoke(obj, value);
} catch (Throwable t) {
throw new RuntimeException("Could not invoke " + methodName + " with one argument (int) on: " + obj.getClass().getName(), reason);
}
}
private static void checkLogEntry(final String tag) {
// New entry.
if (ConfigManager.getConfigFile().getBoolean(ConfPaths.LOGGING_DEBUG)){
StaticLog.logWarning("[NoCheatPlus] API incompatibility detected: " + tag);
}
}
}