Silenced a mostly harmless error that can happen when using plugins like crazyenchantments

This commit is contained in:
nossr50 2020-12-01 13:08:33 -08:00
parent dacd846fe7
commit 958fb6f044
12 changed files with 363 additions and 290 deletions

View File

@ -1,3 +1,6 @@
Version 2.1.160
Silenced a harmless "error" related to Rupture/Bleed often produced when using mcMMO and crazy enchantments together
Version 2.1.159
Fixed a memory leak involving renamed mobs
Updated Adventure library (used in our chat code)

View File

@ -2,7 +2,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>com.gmail.nossr50.mcMMO</groupId>
<artifactId>mcMMO</artifactId>
<version>2.1.159</version>
<version>2.1.160-SNAPSHOT</version>
<name>mcMMO</name>
<url>https://github.com/mcMMO-Dev/mcMMO</url>
<scm>

View File

@ -16,6 +16,7 @@ import org.bukkit.entity.Player;
import org.bukkit.event.entity.EntityDamageEvent;
import org.bukkit.inventory.ItemStack;
import org.bukkit.scheduler.BukkitRunnable;
import org.jetbrains.annotations.NotNull;
import java.util.HashMap;
import java.util.Iterator;
@ -23,7 +24,7 @@ import java.util.Map;
import java.util.Map.Entry;
public class BleedTimerTask extends BukkitRunnable {
private static final Map<LivingEntity, BleedContainer> bleedList = new HashMap<>();
private static final @NotNull Map<LivingEntity, BleedContainer> bleedList = new HashMap<>();
private static boolean isIterating = false;
@Override
@ -148,7 +149,7 @@ public class BleedTimerTask extends BukkitRunnable {
isIterating = false;
}
public static BleedContainer copyContainer(BleedContainer container)
public static @NotNull BleedContainer copyContainer(@NotNull BleedContainer container)
{
LivingEntity target = container.target;
LivingEntity source = container.damageSource;
@ -164,7 +165,7 @@ public class BleedTimerTask extends BukkitRunnable {
*
* @param entity LivingEntity to bleed out
*/
public static void bleedOut(LivingEntity entity) {
public static void bleedOut(@NotNull LivingEntity entity) {
/*
* Don't remove anything from the list outside of run()
*/
@ -178,26 +179,36 @@ public class BleedTimerTask extends BukkitRunnable {
* Add a LivingEntity to the bleedList if it is not in it.
*
* @param entity LivingEntity to add
* @param attacker source of the bleed/rupture
* @param ticks Number of bleeding ticks
*/
public static void add(LivingEntity entity, LivingEntity attacker, int ticks, int bleedRank, int toolTier) {
public static void add(@NotNull LivingEntity entity, @NotNull LivingEntity attacker, int ticks, int bleedRank, int toolTier) {
if (!Bukkit.isPrimaryThread()) {
throw new IllegalStateException("Cannot add bleed task async!");
}
if (isIterating) throw new IllegalStateException("Cannot add task while iterating timers!");
if(isIterating) {
//Used to throw an error here, but in reality all we are really doing is preventing concurrency issues from other plugins being naughty and its not really needed
//I'm not really a fan of silent errors, but I'm sick of seeing people using crazy enchantments come in and report this "bug"
return;
}
// if (isIterating) throw new IllegalStateException("Cannot add task while iterating timers!");
if(toolTier < 4)
ticks = Math.max(1, (ticks / 3));
ticks+=1;
BleedContainer newBleedContainer = new BleedContainer(entity, ticks, bleedRank, toolTier, attacker);
bleedList.put(entity, newBleedContainer);
}
public static boolean isBleeding(LivingEntity entity) {
public static boolean isBleedOperationAllowed() {
return !isIterating && Bukkit.isPrimaryThread();
}
public static boolean isBleeding(@NotNull LivingEntity entity) {
return bleedList.containsKey(entity);
}
}

View File

@ -20,6 +20,7 @@ import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import org.bukkit.event.entity.EntityDamageEvent.DamageModifier;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import java.util.Map;
@ -59,26 +60,28 @@ public class SwordsManager extends SkillManager {
*
* @param target The defending entity
*/
public void ruptureCheck(LivingEntity target) {
if (RandomChanceUtil.isActivationSuccessful(SkillActivationType.RANDOM_LINEAR_100_SCALE_WITH_CAP, SubSkillType.SWORDS_RUPTURE, getPlayer(), this.mmoPlayer.getAttackStrength())) {
public void ruptureCheck(@NotNull LivingEntity target) throws IllegalStateException {
if(BleedTimerTask.isBleedOperationAllowed()) {
if (RandomChanceUtil.isActivationSuccessful(SkillActivationType.RANDOM_LINEAR_100_SCALE_WITH_CAP, SubSkillType.SWORDS_RUPTURE, getPlayer(), this.mmoPlayer.getAttackStrength())) {
if (target instanceof Player) {
Player defender = (Player) target;
if (target instanceof Player) {
Player defender = (Player) target;
//Don't start or add to a bleed if they are blocking
if(defender.isBlocking())
return;
//Don't start or add to a bleed if they are blocking
if(defender.isBlocking())
return;
if (NotificationManager.doesPlayerUseNotifications(defender)) {
if(!BleedTimerTask.isBleeding(defender))
NotificationManager.sendPlayerInformation(defender, NotificationType.SUBSKILL_MESSAGE, "Swords.Combat.Bleeding.Started");
if (NotificationManager.doesPlayerUseNotifications(defender)) {
if(!BleedTimerTask.isBleeding(defender))
NotificationManager.sendPlayerInformation(defender, NotificationType.SUBSKILL_MESSAGE, "Swords.Combat.Bleeding.Started");
}
}
}
BleedTimerTask.add(target, getPlayer(), getRuptureBleedTicks(), RankUtils.getRank(getPlayer(), SubSkillType.SWORDS_RUPTURE), getToolTier(getPlayer().getInventory().getItemInMainHand()));
BleedTimerTask.add(target, getPlayer(), getRuptureBleedTicks(), RankUtils.getRank(getPlayer(), SubSkillType.SWORDS_RUPTURE), getToolTier(getPlayer().getInventory().getItemInMainHand()));
if (mmoPlayer.useChatNotifications()) {
NotificationManager.sendPlayerInformation(getPlayer(), NotificationType.SUBSKILL_MESSAGE, "Swords.Combat.Bleeding");
if (mmoPlayer.useChatNotifications()) {
NotificationManager.sendPlayerInformation(getPlayer(), NotificationType.SUBSKILL_MESSAGE, "Swords.Combat.Bleeding");
}
}
}
}

View File

@ -31,6 +31,7 @@ import org.bukkit.Material;
import org.bukkit.attribute.Attribute;
import org.bukkit.entity.*;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.HashMap;
@ -147,7 +148,7 @@ public class TamingManager extends SkillManager {
*
* @param entity The LivingEntity to award XP for
*/
public void awardTamingXP(LivingEntity entity) {
public void awardTamingXP(@NotNull LivingEntity entity) {
applyXpGain(ExperienceConfig.getInstance().getTamingXP(entity.getType()), XPGainReason.PVE);
}
@ -157,7 +158,7 @@ public class TamingManager extends SkillManager {
* @param wolf The wolf using the ability
* @param damage The damage being absorbed by the wolf
*/
public void fastFoodService(Wolf wolf, double damage) {
public void fastFoodService(@NotNull Wolf wolf, double damage) {
if (!RandomChanceUtil.isActivationSuccessful(SkillActivationType.RANDOM_STATIC_CHANCE, SubSkillType.TAMING_FAST_FOOD_SERVICE, getPlayer())) {
return;
}
@ -177,20 +178,23 @@ public class TamingManager extends SkillManager {
* @param target The LivingEntity to apply Gore on
* @param damage The initial damage
*/
public double gore(LivingEntity target, double damage) {
if (!RandomChanceUtil.isActivationSuccessful(SkillActivationType.RANDOM_LINEAR_100_SCALE_WITH_CAP, SubSkillType.TAMING_GORE, getPlayer())) {
return 0;
public double gore(@NotNull LivingEntity target, double damage) {
if(BleedTimerTask.isBleedOperationAllowed()) {
if (!RandomChanceUtil.isActivationSuccessful(SkillActivationType.RANDOM_LINEAR_100_SCALE_WITH_CAP, SubSkillType.TAMING_GORE, getPlayer())) {
return 0;
}
BleedTimerTask.add(target, getPlayer(), Taming.goreBleedTicks, 1, 2);
if (target instanceof Player) {
NotificationManager.sendPlayerInformation((Player)target, NotificationType.SUBSKILL_MESSAGE, "Combat.StruckByGore");
}
NotificationManager.sendPlayerInformation(getPlayer(), NotificationType.SUBSKILL_MESSAGE, "Combat.Gore");
damage = (damage * Taming.goreModifier) - damage;
}
BleedTimerTask.add(target, getPlayer(), Taming.goreBleedTicks, 1, 2);
if (target instanceof Player) {
NotificationManager.sendPlayerInformation((Player)target, NotificationType.SUBSKILL_MESSAGE, "Combat.StruckByGore");
}
NotificationManager.sendPlayerInformation(getPlayer(), NotificationType.SUBSKILL_MESSAGE, "Combat.Gore");
damage = (damage * Taming.goreModifier) - damage;
return damage;
}

View File

@ -1,32 +0,0 @@
//package com.gmail.nossr50.util.compat.layers.attackcooldown;
//
//import com.gmail.nossr50.util.nms.NMSVersion;
//import org.bukkit.entity.Player;
//
//import java.lang.reflect.InvocationTargetException;
//
//public class DummyPlayerAttackCooldownExploitPreventionLayer extends PlayerAttackCooldownExploitPreventionLayer {
// public DummyPlayerAttackCooldownExploitPreventionLayer() {
// super(NMSVersion.UNSUPPORTED);
// }
//
// @Override
// public boolean initializeLayer() {
// return noErrorsOnInitialize;
// }
//
// @Override
// public float getAttackStrength(Player player) throws InvocationTargetException, IllegalAccessException {
// return 1.0F; //Always full strength
// }
//
// @Override
// public float getCooldownValue(Player player) throws InvocationTargetException, IllegalAccessException {
// return 0F;
// }
//
// @Override
// public void resetAttackStrength(Player player) throws InvocationTargetException, IllegalAccessException {
// //Do nothing
// }
//}

View File

@ -0,0 +1,42 @@
package com.gmail.nossr50.util.compat.layers.attackcooldown;
import com.gmail.nossr50.util.nms.NMSVersion;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import java.lang.reflect.InvocationTargetException;
public class DummyPlayerAttackCooldownToolLayer extends PlayerAttackCooldownToolLayer {
public DummyPlayerAttackCooldownToolLayer() {
super(NMSVersion.UNSUPPORTED);
}
@Override
public boolean initializeLayer() {
return noErrorsOnInitialize;
}
@Override
public float getAttackStrength(@NotNull Player player) throws InvocationTargetException, IllegalAccessException {
return 1.0F; //Always full strength
}
@Override
public float getCooldownValue(@NotNull Player player) throws InvocationTargetException, IllegalAccessException {
return 0F;
}
@Override
public void resetAttackStrength(@NotNull Player player) throws InvocationTargetException, IllegalAccessException {
//Do nothing
}
@Override
public int getCooldownFieldValue(@NotNull Player player) throws InvocationTargetException, IllegalAccessException {
return 0;
}
@Override
public void setCooldownFieldValue(@NotNull Player player, int fieldValue) throws InvocationTargetException, IllegalAccessException {
}
}

View File

@ -1,202 +0,0 @@
//package com.gmail.nossr50.util.compat.layers.attackcooldown;
//
//import com.gmail.nossr50.mcMMO;
//import com.gmail.nossr50.util.compat.layers.AbstractNMSCompatibilityLayer;
//import com.gmail.nossr50.util.nms.NMSConstants;
//import com.gmail.nossr50.util.nms.NMSVersion;
//import org.bukkit.entity.Player;
//import org.jetbrains.annotations.NotNull;
//import org.jetbrains.annotations.Nullable;
//
//import java.lang.reflect.InvocationTargetException;
//import java.lang.reflect.Method;
//
///**
// *
// * These classes are a band-aid solution for adding NMS support into 2.1.XXX
// * In 2.2 we are switching to modules and that will clean things up significantly
// *
// */
//public class PlayerAttackCooldownExploitPreventionLayer extends AbstractNMSCompatibilityLayer implements PlayerAttackCooldownMethods{
//
// private final String cbNMSVersionPath;
//
// protected Class<?> craftPlayerClass;
// protected Class<?> entityHumanClass;
//
// protected Method playerAttackCooldownMethod;
// protected Method playerAttackStrengthMethod;
// protected Method resetPlayerAttackCooldownMethod;
// protected Method getHandleMethod;
//
// public PlayerAttackCooldownExploitPreventionLayer(@NotNull NMSVersion nmsVersion) {
// super(nmsVersion);
// mcMMO.p.getLogger().info("Loading Compatibility Layer... (Player Attack Cooldown Exploit Prevention)");
// if(!isCompatibleWithMinecraftVersion()) {
// mcMMO.p.getLogger().severe("this version of mcMMO does not support NMS for this version of Minecraft, try updating mcMMO or updating Minecraft. Not all versions of Minecraft will have NMS support built into mcMMO.");
// cbNMSVersionPath = "";
// } else {
// if(NMSConstants.getCraftBukkitVersionPath(nmsVersion) != null) {
// cbNMSVersionPath = NMSConstants.getCraftBukkitVersionPath(nmsVersion);
// noErrorsOnInitialize = initializeLayer();
//
// if(noErrorsOnInitialize) {
// mcMMO.p.getLogger().info("Successfully Loaded Compatibility Layer! (Player Attack Cooldown Exploit Prevention)");
// }
// } else {
// mcMMO.p.getLogger().info("Failed to load - CL (Player Attack Cooldown Exploit Prevention) Could not find CB NMS path for CL");
// flagErrorsDuringStartup();
// mcMMO.p.getLogger().warning("Could not wire NMS package path for CraftBukkit!");
// cbNMSVersionPath = "";
// }
// }
// }
//
// private boolean isCompatibleWithMinecraftVersion() {
// switch(nmsVersion) {
// case NMS_1_13_2:
// case NMS_1_14_4:
// case NMS_1_15_2:
// case NMS_1_16_1:
// return true;
// default:
// return false;
// }
//
// }
//
// /**
// * Cache all reflection methods/types/classes needed for the NMS of this CompatibilityLayer
// * @param cooldownMethodName the cooldown method name
// * @param attackStrengthMethodName the attack strength method name
// * @param resetAttackCooldownMethodName the reset attack cooldown method name
// * @param getHandleMethodName the get handle method name
// * @return true if NMS was successfully wired
// */
// public boolean wireNMS(@NotNull String cooldownMethodName, @NotNull String attackStrengthMethodName, @NotNull String resetAttackCooldownMethodName, @NotNull String getHandleMethodName) {
// entityHumanClass = initEntityHumanClass();
// craftPlayerClass = initCraftPlayerClass();
//
// try {
// this.playerAttackCooldownMethod = entityHumanClass.getMethod(cooldownMethodName);
// this.playerAttackStrengthMethod = entityHumanClass.getMethod(attackStrengthMethodName, float.class);
// this.resetPlayerAttackCooldownMethod = entityHumanClass.getMethod(resetAttackCooldownMethodName);
// if (craftPlayerClass != null) {
// this.getHandleMethod = craftPlayerClass.getMethod(getHandleMethodName);
// } else {
// return false;
// }
// return true;
// } catch (NoSuchMethodException e) {
// flagErrorsDuringStartup();
// e.printStackTrace();
// return false;
// }
// }
//
// /**
// * Get the cached player attack cooldown method
// * @return the cached player attack cooldown method
// */
// private @Nullable Method getPlayerAttackCooldownMethod() {
// return playerAttackCooldownMethod;
// }
//
// /**
// * Get the cached player attack strength method
// * @return the cached player attack strength method
// */
// private @Nullable Method getPlayerAttackStrengthMethod() {
// return playerAttackStrengthMethod;
// }
//
// /**
// * Get the cached player attack cooldown reset method
// * @return the cached player attack cooldown reset method
// */
// private @Nullable Method getResetPlayerAttackCooldownMethod() {
// return resetPlayerAttackCooldownMethod;
// }
//
// /**
// * Grab the CraftPlayer class type from NMS
// * @return the CraftPlayer class type from NMS
// */
// private @Nullable Class<?> initCraftPlayerClass() {
// try {
// return Class.forName(NMSConstants.getCraftPlayerClassPath(cbNMSVersionPath));
// } catch (ClassNotFoundException e) {
// flagErrorsDuringStartup();
// e.printStackTrace();
// return null;
// }
// }
//
// /**
// * Grab the EntityHuman class type from NMS
// * @return the EntityHuman class type from NMS
// */
// private @Nullable Class<?> initEntityHumanClass() {
// try {
// return Class.forName(NMSConstants.getEntityHumanClassPath(cbNMSVersionPath));
// } catch (ClassNotFoundException e) {
// flagErrorsDuringStartup();
// e.printStackTrace();
// return null;
// }
// }
//
// private void flagErrorsDuringStartup() {
// noErrorsOnInitialize = false;
// }
//
// /**
// * Grabs the attack strength for a player
// * Should be noted that as of today there is no way to capture a players current attack strength in spigot when they attack an entity outside of network packet listening
// * @param player target player
// * @return the float value of the player's attack strength
// */
// @Override
// public float getAttackStrength(Player player) throws InvocationTargetException, IllegalAccessException {
// Object craftPlayer = craftPlayerClass.cast(player);
// Object entityHuman = entityHumanClass.cast(getHandleMethod.invoke(craftPlayer));
//
// return (float) playerAttackStrengthMethod.invoke(entityHuman, 0F); //Add no adjustment ticks
// }
//
// @Override
// public float getCooldownValue(Player player) throws InvocationTargetException, IllegalAccessException {
// Object craftPlayer = craftPlayerClass.cast(player);
// Object entityHuman = entityHumanClass.cast(getHandleMethod.invoke(craftPlayer));
//
// return (float) playerAttackCooldownMethod.invoke(entityHuman); //Add no adjustment ticks
// }
//
// @Override
// public void resetAttackStrength(Player player) throws InvocationTargetException, IllegalAccessException {
// Object craftPlayer = craftPlayerClass.cast(player);
// Object entityHuman = entityHumanClass.cast(getHandleMethod.invoke(craftPlayer));
//
// resetPlayerAttackCooldownMethod.invoke(entityHuman);
// }
//
// @Override
// public boolean initializeLayer() {
// switch(nmsVersion) {
// case NMS_1_12_2:
// return wireNMS("dr", "n", "ds", "getHandle");
// case NMS_1_13_2:
// return wireNMS("dG", "r", "dH", "getHandle");
// case NMS_1_14_4:
// return wireNMS("dY", "s", "dZ", "getHandle");
// case NMS_1_15_2:
// return wireNMS("ex", "s", "ey", "getHandle");
// case NMS_1_16_1:
// return wireNMS("eR", "getAttackCooldown", "resetAttackCooldown", "getHandle");
// default:
// break;
// }
//
// return false;
// }
//}

View File

@ -1,19 +1,24 @@
//package com.gmail.nossr50.util.compat.layers.attackcooldown;
//
//import org.bukkit.entity.Player;
//
//import java.lang.reflect.InvocationTargetException;
//
//public interface PlayerAttackCooldownMethods {
// /**
// * Grabs the attack strength for a player
// * Should be noted that as of today there is no way to capture a players current attack strength in spigot when they attack an entity outside of network packet listening
// * @param player target player
// * @return the float value of the player's attack strength
// */
// float getAttackStrength(Player player) throws InvocationTargetException, IllegalAccessException;
//
// float getCooldownValue(Player player) throws InvocationTargetException, IllegalAccessException;
//
// void resetAttackStrength(Player player) throws InvocationTargetException, IllegalAccessException;
//}
package com.gmail.nossr50.util.compat.layers.attackcooldown;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import java.lang.reflect.InvocationTargetException;
public interface PlayerAttackCooldownMethods {
/**
* Grabs the attack strength for a player
* Should be noted that as of today there is no way to capture a players current attack strength in spigot when they attack an entity outside of network packet listening
* @param player target player
* @return the float value of the player's attack strength
*/
float getAttackStrength(@NotNull Player player) throws InvocationTargetException, IllegalAccessException;
float getCooldownValue(@NotNull Player player) throws InvocationTargetException, IllegalAccessException;
void resetAttackStrength(@NotNull Player player) throws InvocationTargetException, IllegalAccessException;
int getCooldownFieldValue(@NotNull Player player) throws InvocationTargetException, IllegalAccessException;
void setCooldownFieldValue(@NotNull Player player, int fieldValue) throws InvocationTargetException, IllegalAccessException;
}

View File

@ -0,0 +1,237 @@
package com.gmail.nossr50.util.compat.layers.attackcooldown;
import com.gmail.nossr50.mcMMO;
import com.gmail.nossr50.util.compat.layers.AbstractNMSCompatibilityLayer;
import com.gmail.nossr50.util.nms.NMSConstants;
import com.gmail.nossr50.util.nms.NMSVersion;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/**
*
* These classes are a band-aid solution for adding NMS support into 2.1.XXX
* In 2.2 we are switching to modules and that will clean things up significantly
*
*/
public class PlayerAttackCooldownToolLayer extends AbstractNMSCompatibilityLayer implements PlayerAttackCooldownMethods {
private final String cbNMSVersionPath;
protected Class<?> craftPlayerClass;
protected Class<?> entityHumanClass;
protected Class<?> entityLivingClass;
protected Method playerAttackCooldownMethod;
protected Method playerAttackStrengthMethod;
protected Method resetPlayerAttackCooldownMethod;
protected Method setPlayerAttackStrengthMethod;
protected Method getHandleMethod;
protected Field attackCooldownField;
protected String attackStrengthFieldName;
public PlayerAttackCooldownToolLayer(@NotNull NMSVersion nmsVersion) {
super(nmsVersion);
mcMMO.p.getLogger().info("Loading Compatibility Layer... (Player Attack Cooldown Exploit Prevention)");
if(!isCompatibleWithMinecraftVersion(nmsVersion)) {
mcMMO.p.getLogger().severe("this version of mcMMO does not support NMS for this version of Minecraft, try updating mcMMO or updating Minecraft. Not all versions of Minecraft will have NMS support built into mcMMO.");
cbNMSVersionPath = "";
} else {
if(NMSConstants.getCraftBukkitVersionPath(nmsVersion) != null) {
cbNMSVersionPath = NMSConstants.getCraftBukkitVersionPath(nmsVersion);
noErrorsOnInitialize = initializeLayer();
if(noErrorsOnInitialize) {
mcMMO.p.getLogger().info("Successfully Loaded Compatibility Layer! (Player Attack Cooldown Exploit Prevention)");
}
} else {
mcMMO.p.getLogger().info("Failed to load - CL (Player Attack Cooldown Exploit Prevention) Could not find CB NMS path for CL");
flagErrorsDuringStartup();
mcMMO.p.getLogger().warning("Could not wire NMS package path for CraftBukkit!");
cbNMSVersionPath = "";
}
}
}
public static boolean isCompatibleWithMinecraftVersion(@NotNull NMSVersion nmsVersion) {
switch(nmsVersion) {
case NMS_1_13_2:
case NMS_1_14_4:
case NMS_1_15_2:
case NMS_1_16_4:
return true;
default:
return false;
}
}
/**
* Cache all reflection methods/types/classes needed for the NMS of this CompatibilityLayer
* @param cooldownMethodName the cooldown method name
* @param attackStrengthMethodName the attack strength method name
* @param resetAttackCooldownMethodName the reset attack cooldown method name
* @param getHandleMethodName the get handle method name
* @return true if NMS was successfully wired
*/
public boolean wireNMS(@NotNull String cooldownMethodName, @NotNull String attackStrengthMethodName, @NotNull String resetAttackCooldownMethodName, @NotNull String getHandleMethodName, @NotNull String attackStrengthFieldName) {
entityHumanClass = initEntityHumanClass();
if (entityHumanClass != null) {
entityLivingClass = entityHumanClass.getSuperclass();
}
craftPlayerClass = initCraftPlayerClass();
this.attackStrengthFieldName = attackStrengthFieldName;
try {
this.attackCooldownField = entityLivingClass.getDeclaredField(attackStrengthFieldName);
this.attackCooldownField.setAccessible(true);
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
try {
this.playerAttackCooldownMethod = entityHumanClass.getMethod(cooldownMethodName);
this.playerAttackStrengthMethod = entityHumanClass.getMethod(attackStrengthMethodName, float.class);
this.resetPlayerAttackCooldownMethod = entityHumanClass.getMethod(resetAttackCooldownMethodName);
if (craftPlayerClass != null) {
this.getHandleMethod = craftPlayerClass.getMethod(getHandleMethodName);
} else {
return false;
}
return true;
} catch (NoSuchMethodException e) {
flagErrorsDuringStartup();
e.printStackTrace();
return false;
}
}
/**
* Get the cached player attack cooldown method
* @return the cached player attack cooldown method
*/
private @Nullable Method getPlayerAttackCooldownMethod() {
return playerAttackCooldownMethod;
}
/**
* Get the cached player attack strength method
* @return the cached player attack strength method
*/
private @Nullable Method getPlayerAttackStrengthMethod() {
return playerAttackStrengthMethod;
}
/**
* Get the cached player attack cooldown reset method
* @return the cached player attack cooldown reset method
*/
private @Nullable Method getResetPlayerAttackCooldownMethod() {
return resetPlayerAttackCooldownMethod;
}
/**
* Grab the CraftPlayer class type from NMS
* @return the CraftPlayer class type from NMS
*/
private @Nullable Class<?> initCraftPlayerClass() {
try {
return Class.forName(NMSConstants.getCraftPlayerClassPath(cbNMSVersionPath));
} catch (ClassNotFoundException e) {
flagErrorsDuringStartup();
e.printStackTrace();
return null;
}
}
/**
* Grab the EntityHuman class type from NMS
* @return the EntityHuman class type from NMS
*/
private @Nullable Class<?> initEntityHumanClass() {
try {
return Class.forName(NMSConstants.getEntityHumanClassPath(cbNMSVersionPath));
} catch (ClassNotFoundException e) {
flagErrorsDuringStartup();
e.printStackTrace();
return null;
}
}
private void flagErrorsDuringStartup() {
noErrorsOnInitialize = false;
}
/**
* Grabs the attack strength for a player
* Should be noted that as of today there is no way to capture a players current attack strength in spigot when they attack an entity outside of network packet listening
* @param player target player
* @return the float value of the player's attack strength
*/
@Override
public float getAttackStrength(@NotNull Player player) throws InvocationTargetException, IllegalAccessException {
Object craftPlayer = craftPlayerClass.cast(player);
Object entityHuman = entityHumanClass.cast(getHandleMethod.invoke(craftPlayer));
return (float) playerAttackStrengthMethod.invoke(entityHuman, 0F); //Add no adjustment ticks
}
@Override
public float getCooldownValue(@NotNull Player player) throws InvocationTargetException, IllegalAccessException {
Object craftPlayer = craftPlayerClass.cast(player);
Object entityHuman = entityHumanClass.cast(getHandleMethod.invoke(craftPlayer));
return (float) playerAttackCooldownMethod.invoke(entityHuman); //Add no adjustment ticks
}
@Override
public void resetAttackStrength(@NotNull Player player) throws InvocationTargetException, IllegalAccessException {
Object craftPlayer = craftPlayerClass.cast(player);
Object entityHuman = entityHumanClass.cast(getHandleMethod.invoke(craftPlayer));
Object entityLiving = entityLivingClass.cast(entityHuman);
resetPlayerAttackCooldownMethod.invoke(entityLiving);
}
@Override
public int getCooldownFieldValue(@NotNull Player player) throws InvocationTargetException, IllegalAccessException {
Object craftPlayer = craftPlayerClass.cast(player);
Object entityHuman = entityHumanClass.cast(getHandleMethod.invoke(craftPlayer));
Object entityLiving = entityLivingClass.cast(entityHuman);
return attackCooldownField.getInt(entityLiving);
}
@Override
public void setCooldownFieldValue(@NotNull Player player, int fieldValue) throws InvocationTargetException, IllegalAccessException {
Object craftPlayer = craftPlayerClass.cast(player);
Object entityHuman = entityHumanClass.cast(getHandleMethod.invoke(craftPlayer));
attackCooldownField.setInt(entityHuman, fieldValue);
}
@Override
public boolean initializeLayer() {
switch(nmsVersion) {
case NMS_1_12_2:
return wireNMS("dr", "n", "ds", "getHandle", "at");
case NMS_1_13_2:
return wireNMS("dG", "r", "dH", "getHandle", "at");
case NMS_1_14_4:
return wireNMS("dY", "s", "dZ", "getHandle", "at");
case NMS_1_15_2:
return wireNMS("ex", "s", "ey", "getHandle", "at");
case NMS_1_16_4:
return wireNMS("eR", "getAttackCooldown", "resetAttackCooldown", "getHandle", "at");
default:
throw new RuntimeException("Unexpected NMS version support in PlayerAttackCooldown compatibility layer initialization!");
}
}
}

View File

@ -50,6 +50,8 @@ public class NMSConstants {
return "v1_15_R1";
case NMS_1_16_1:
return "v1_16_R1";
case NMS_1_16_4:
return "v1_16_R3";
case UNSUPPORTED:
break;
}

View File

@ -600,7 +600,7 @@ public final class CombatUtils {
return processingNoInvulnDamage;
}
public static void dealNoInvulnerabilityTickDamage(@NotNull LivingEntity target, double damage, Entity attacker) {
public static void dealNoInvulnerabilityTickDamage(@NotNull LivingEntity target, double damage, @Nullable Entity attacker) {
if (target.isDead()) {
return;
}