diff --git a/Changelog.txt b/Changelog.txt index b30478c11..a8729e381 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -1,3 +1,7 @@ +Version 2.1.169 + Fixed a few memory leaks involving arrows + Fixed mcMMO inappropriately assigning metadata to projectiles not fired from players + Version 2.1.168 Fixed an IndexOutOfBoundsException error when trying to access UserBlockTracker from an invalid range (thanks t00thpick1) (API) UserBlockTracker is now the interface by which our block-tracker will be known (thanks t00thpick1) diff --git a/pom.xml b/pom.xml index 7063867ce..38b03f6ff 100755 --- a/pom.xml +++ b/pom.xml @@ -2,7 +2,7 @@ 4.0.0 com.gmail.nossr50.mcMMO mcMMO - 2.1.168 + 2.1.169-SNAPSHOT mcMMO https://github.com/mcMMO-Dev/mcMMO diff --git a/src/main/java/com/gmail/nossr50/listeners/EntityListener.java b/src/main/java/com/gmail/nossr50/listeners/EntityListener.java index 13c65f3ec..6fa4d13e4 100644 --- a/src/main/java/com/gmail/nossr50/listeners/EntityListener.java +++ b/src/main/java/com/gmail/nossr50/listeners/EntityListener.java @@ -123,24 +123,26 @@ public class EntityListener implements Listener { if(!WorldGuardManager.getInstance().hasMainFlag(player)) return; } + + Entity projectile = event.getProjectile(); + + //Should be noted that there are API changes regarding Arrow from 1.13.2 to current versions of the game + if (!(projectile instanceof Arrow)) { + return; + } + + ItemStack bow = event.getBow(); + + if (bow != null + && bow.containsEnchantment(Enchantment.ARROW_INFINITE)) { + projectile.setMetadata(mcMMO.infiniteArrowKey, mcMMO.metadataValue); + } + + projectile.setMetadata(mcMMO.bowForceKey, new FixedMetadataValue(pluginRef, Math.min(event.getForce() * AdvancedConfig.getInstance().getForceMultiplier(), 1.0))); + projectile.setMetadata(mcMMO.arrowDistanceKey, new FixedMetadataValue(pluginRef, projectile.getLocation())); + //Cleanup metadata in 1 minute in case normal collection falls through + CombatUtils.cleanupArrowMetadata((Projectile) projectile); } - - Entity projectile = event.getProjectile(); - - //Should be noted that there are API changes regarding Arrow from 1.13.2 to current versions of the game - if (!(projectile instanceof Arrow)) { - return; - } - - ItemStack bow = event.getBow(); - - if (bow != null - && bow.containsEnchantment(Enchantment.ARROW_INFINITE)) { - projectile.setMetadata(mcMMO.infiniteArrowKey, mcMMO.metadataValue); - } - - projectile.setMetadata(mcMMO.bowForceKey, new FixedMetadataValue(pluginRef, Math.min(event.getForce() * AdvancedConfig.getInstance().getForceMultiplier(), 1.0))); - projectile.setMetadata(mcMMO.arrowDistanceKey, new FixedMetadataValue(pluginRef, projectile.getLocation())); } @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) @@ -164,6 +166,8 @@ public class EntityListener implements Listener { EntityType entityType = projectile.getType(); if(entityType == EntityType.ARROW || entityType == EntityType.SPECTRAL_ARROW) { + CombatUtils.delayArrowMetaCleanup(projectile); //Cleans up metadata 1 minute from now in case other collection methods fall through + if(!projectile.hasMetadata(mcMMO.bowForceKey)) projectile.setMetadata(mcMMO.bowForceKey, new FixedMetadataValue(pluginRef, 1.0)); @@ -199,7 +203,6 @@ public class EntityListener implements Listener { Entity entity = event.getEntity(); Material notYetReplacedType = block.getState().getType(); //because its from getState() this is the block that hasn't been changed yet, which is likely air/lava/water etc - // When the event is fired for the falling block that changes back to a // normal block // event.getBlock().getType() returns AIR @@ -418,13 +421,14 @@ public class EntityListener implements Listener { LivingEntity livingEntity = (LivingEntity) entityDamageEvent.getEntity(); if(entityDamageEvent.getFinalDamage() >= livingEntity.getHealth()) { - - /* - * This sets entity names back to whatever they are supposed to be - */ + //This sets entity names back to whatever they are supposed to be CombatUtils.fixNames(livingEntity); - } } + } + + if(entityDamageEvent.getDamager() instanceof Projectile) { + CombatUtils.cleanupArrowMetadata((Projectile) entityDamageEvent.getDamager()); + } } public boolean checkParties(Cancellable event, Player defendingPlayer, Player attackingPlayer) { diff --git a/src/main/java/com/gmail/nossr50/skills/archery/ArcheryManager.java b/src/main/java/com/gmail/nossr50/skills/archery/ArcheryManager.java index fecbc9c8b..8ef8a0e1a 100644 --- a/src/main/java/com/gmail/nossr50/skills/archery/ArcheryManager.java +++ b/src/main/java/com/gmail/nossr50/skills/archery/ArcheryManager.java @@ -55,8 +55,7 @@ public class ArcheryManager extends SkillManager { public double distanceXpBonusMultiplier(LivingEntity target, Entity arrow) { //Hacky Fix - some plugins spawn arrows and assign them to players after the ProjectileLaunchEvent fires if(!arrow.hasMetadata(mcMMO.arrowDistanceKey)) - return arrow.getLocation().distance(target.getLocation()); - + return 1; Location firedLocation = (Location) arrow.getMetadata(mcMMO.arrowDistanceKey).get(0).value(); Location targetLocation = target.getLocation(); diff --git a/src/main/java/com/gmail/nossr50/util/skills/CombatUtils.java b/src/main/java/com/gmail/nossr50/util/skills/CombatUtils.java index 1aaf6395f..716524762 100644 --- a/src/main/java/com/gmail/nossr50/util/skills/CombatUtils.java +++ b/src/main/java/com/gmail/nossr50/util/skills/CombatUtils.java @@ -25,16 +25,19 @@ import com.gmail.nossr50.util.compat.layers.persistentdata.MobMetaFlagType; import com.gmail.nossr50.util.player.NotificationManager; import com.gmail.nossr50.util.player.UserManager; import com.google.common.collect.ImmutableMap; +import org.bukkit.Bukkit; import org.bukkit.GameMode; import org.bukkit.Material; import org.bukkit.attribute.Attribute; import org.bukkit.attribute.AttributeInstance; +import org.bukkit.enchantments.Enchantment; import org.bukkit.entity.*; import org.bukkit.event.entity.EntityDamageByEntityEvent; import org.bukkit.event.entity.EntityDamageEvent; import org.bukkit.event.entity.EntityDamageEvent.DamageCause; import org.bukkit.event.entity.EntityDamageEvent.DamageModifier; import org.bukkit.inventory.ItemStack; +import org.bukkit.metadata.FixedMetadataValue; import org.bukkit.metadata.MetadataValue; import org.bukkit.potion.PotionEffectType; import org.bukkit.projectiles.ProjectileSource; @@ -269,6 +272,7 @@ public final class CombatUtils { //Make sure the profiles been loaded if(mcMMOPlayer == null) { + cleanupArrowMetadata(arrow); return; } @@ -309,6 +313,8 @@ public final class CombatUtils { "Force Multiplier: "+forceMultiplier, "Initial Damage: "+initialDamage, "Final Damage: "+finalDamage); + //Clean data + cleanupArrowMetadata(arrow); } /** @@ -428,6 +434,9 @@ public final class CombatUtils { if (!Misc.isNPCEntityExcludingVillagers(player) && PrimarySkillType.ARCHERY.getPermissions(player)) { processArcheryCombat(target, player, event, arrow); + } else { + //Cleanup Arrow + cleanupArrowMetadata(arrow); } if (target.getType() != EntityType.CREEPER && !Misc.isNPCEntityExcludingVillagers(player) && PrimarySkillType.TAMING.getPermissions(player)) { @@ -1059,4 +1068,32 @@ public final class CombatUtils { attributeInstance.setBaseValue(normalSpeed * multiplier); } } + + /** + * Clean up metadata from a projectile + * + * @param entity projectile + */ + public static void cleanupArrowMetadata(@NotNull Projectile entity) { + if(entity.hasMetadata(mcMMO.infiniteArrowKey)) { + entity.removeMetadata(mcMMO.infiniteArrowKey, mcMMO.p); + } + + if(entity.hasMetadata(mcMMO.bowForceKey)) { + entity.removeMetadata(mcMMO.bowForceKey, mcMMO.p); + } + + if(entity.hasMetadata(mcMMO.arrowDistanceKey)) { + entity.removeMetadata(mcMMO.arrowDistanceKey, mcMMO.p); + } + } + + /** + * Clean up metadata from a projectile after a minute has passed + * + * @param entity the projectile + */ + public static void delayArrowMetaCleanup(@NotNull Projectile entity) { + Bukkit.getServer().getScheduler().runTaskLater(mcMMO.p, () -> { cleanupArrowMetadata(entity);}, 20*60); + } }