diff --git a/pom.xml b/pom.xml index 3d3839c21..5498b9f71 100644 --- a/pom.xml +++ b/pom.xml @@ -2,7 +2,7 @@ 4.0.0 com.gmail.nossr50.mcMMO mcMMO - 2.2.000-BETA-07-SNAPSHOT + 2.2.000-BETA-08-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 f12610019..e80225d61 100644 --- a/src/main/java/com/gmail/nossr50/listeners/EntityListener.java +++ b/src/main/java/com/gmail/nossr50/listeners/EntityListener.java @@ -152,17 +152,20 @@ public class EntityListener implements Listener { return; } - Projectile projectile = event.getEntity(); - EntityType entityType = projectile.getType(); + if(event.getEntity() instanceof Arrow arrow) { + // Delayed metadata cleanup in case other cleanup hooks fail + CombatUtils.delayArrowMetaCleanup(arrow); - if(projectile instanceof Arrow arrow) { - CombatUtils.delayArrowMetaCleanup(arrow); //Cleans up metadata 1 minute from now in case other collection methods fall through + // If fired from an item with multi-shot, we need to track + if(ItemUtils.doesPlayerHaveEnchantmentInHands(player, "multishot")) { + arrow.setMetadata(MetadataConstants.METADATA_KEY_MULTI_SHOT_ARROW, MetadataConstants.MCMMO_METADATA_VALUE); + } - if(!projectile.hasMetadata(MetadataConstants.METADATA_KEY_BOW_FORCE)) - projectile.setMetadata(MetadataConstants.METADATA_KEY_BOW_FORCE, new FixedMetadataValue(pluginRef, 1.0)); + if(!arrow.hasMetadata(MetadataConstants.METADATA_KEY_BOW_FORCE)) + arrow.setMetadata(MetadataConstants.METADATA_KEY_BOW_FORCE, new FixedMetadataValue(pluginRef, 1.0)); - if(!projectile.hasMetadata(MetadataConstants.METADATA_KEY_ARROW_DISTANCE)) - projectile.setMetadata(MetadataConstants.METADATA_KEY_ARROW_DISTANCE, new FixedMetadataValue(pluginRef, arrow.getLocation())); + if(!arrow.hasMetadata(MetadataConstants.METADATA_KEY_ARROW_DISTANCE)) + arrow.setMetadata(MetadataConstants.METADATA_KEY_ARROW_DISTANCE, new FixedMetadataValue(pluginRef, arrow.getLocation())); //Check both hands if(ItemUtils.doesPlayerHaveEnchantmentInHands(player, "piercing")) { @@ -170,7 +173,7 @@ public class EntityListener implements Listener { } if (ProbabilityUtil.isSkillRNGSuccessful(SubSkillType.ARCHERY_ARROW_RETRIEVAL, player)) { - projectile.setMetadata(MetadataConstants.METADATA_KEY_TRACKED_ARROW, MetadataConstants.MCMMO_METADATA_VALUE); + arrow.setMetadata(MetadataConstants.METADATA_KEY_TRACKED_ARROW, MetadataConstants.MCMMO_METADATA_VALUE); } } } diff --git a/src/main/java/com/gmail/nossr50/skills/crossbows/Crossbows.java b/src/main/java/com/gmail/nossr50/skills/crossbows/Crossbows.java index b09a1510a..216a9485d 100644 --- a/src/main/java/com/gmail/nossr50/skills/crossbows/Crossbows.java +++ b/src/main/java/com/gmail/nossr50/skills/crossbows/Crossbows.java @@ -1,6 +1,7 @@ package com.gmail.nossr50.skills.crossbows; import com.gmail.nossr50.datatypes.player.McMMOPlayer; +import com.gmail.nossr50.util.MetadataConstants; import com.gmail.nossr50.util.player.UserManager; import org.bukkit.entity.Arrow; import org.bukkit.entity.Player; @@ -13,17 +14,29 @@ import static com.gmail.nossr50.util.skills.ProjectileUtils.getNormal; * Util class for crossbows. */ public class Crossbows { + /** + * Process events that may happen from a crossbow hitting an entity. + * + * @param event the projectile hit event + * @param pluginRef the plugin ref + * @param arrow the arrow + */ public static void processCrossbows(ProjectileHitEvent event, Plugin pluginRef, Arrow arrow) { + if (arrow.getShooter() instanceof Player) { + McMMOPlayer mmoPlayer = UserManager.getPlayer((Player) arrow.getShooter()); + if (mmoPlayer == null) + return; + + processTrickShot(event, pluginRef, arrow, mmoPlayer); + } + } + + private static void processTrickShot(ProjectileHitEvent event, Plugin pluginRef, Arrow arrow, McMMOPlayer mmoPlayer) { if(event.getHitBlock() != null && event.getHitBlockFace() != null) { - if (arrow.getShooter() instanceof Player) { - McMMOPlayer mmoPlayer = UserManager.getPlayer((Player) arrow.getShooter()); - if (mmoPlayer != null) { - mmoPlayer.getCrossbowsManager().handleRicochet( - pluginRef, - arrow, - getNormal(event.getHitBlockFace())); - } - } + mmoPlayer.getCrossbowsManager().handleRicochet( + pluginRef, + arrow, + getNormal(event.getHitBlockFace())); } } } diff --git a/src/main/java/com/gmail/nossr50/skills/crossbows/CrossbowsManager.java b/src/main/java/com/gmail/nossr50/skills/crossbows/CrossbowsManager.java index 91826def0..60def74bf 100644 --- a/src/main/java/com/gmail/nossr50/skills/crossbows/CrossbowsManager.java +++ b/src/main/java/com/gmail/nossr50/skills/crossbows/CrossbowsManager.java @@ -8,8 +8,10 @@ import com.gmail.nossr50.skills.SkillManager; import com.gmail.nossr50.util.MetadataConstants; import com.gmail.nossr50.util.Permissions; import com.gmail.nossr50.util.random.ProbabilityUtil; +import com.gmail.nossr50.util.skills.ProjectileUtils; import com.gmail.nossr50.util.skills.RankUtils; import org.bukkit.Location; +import org.bukkit.entity.AbstractArrow; import org.bukkit.entity.Arrow; import org.bukkit.entity.Player; import org.bukkit.metadata.FixedMetadataValue; @@ -18,6 +20,8 @@ import org.bukkit.projectiles.ProjectileSource; import org.bukkit.util.Vector; import org.jetbrains.annotations.NotNull; +import static com.gmail.nossr50.util.skills.CombatUtils.delayArrowMetaCleanup; + public class CrossbowsManager extends SkillManager { public CrossbowsManager(McMMOPlayer mmoPlayer) { super(mmoPlayer, PrimarySkillType.CROSSBOWS); @@ -52,7 +56,6 @@ public class CrossbowsManager extends SkillManager { final Vector reflectedDirection = arrowInBlockVector.subtract(normal.multiply(2 * arrowInBlockVector.dot(normal))); final Vector inverseNormal = normal.multiply(-1); - // check the angle of the arrow against the inverse normal to see if the angle was too shallow // only checks angle on the first bounce if (bounceCount == 0 && arrowInBlockVector.angle(inverseNormal) < Math.PI / 4) { @@ -60,15 +63,24 @@ public class CrossbowsManager extends SkillManager { } // Spawn new arrow with the reflected direction - Arrow arrow = originalArrow.getWorld().spawnArrow(origin, - reflectedDirection, 1, 1); - arrow.setShooter(originalArrowShooter); - arrow.setMetadata(MetadataConstants.METADATA_KEY_BOUNCE_COUNT, + Arrow spawnedArrow = originalArrow.getWorld().spawnArrow(origin, reflectedDirection, 1, 1); + ProjectileUtils.copyArrowMetadata(pluginRef, originalArrow, spawnedArrow); + originalArrow.remove(); + // copy metadata from old arrow + spawnedArrow.setShooter(originalArrowShooter); + spawnedArrow.setMetadata(MetadataConstants.METADATA_KEY_BOUNCE_COUNT, new FixedMetadataValue(pluginRef, bounceCount + 1)); - arrow.setMetadata(MetadataConstants.METADATA_KEY_SPAWNED_ARROW, + spawnedArrow.setMetadata(MetadataConstants.METADATA_KEY_SPAWNED_ARROW, new FixedMetadataValue(pluginRef, originalArrowShooter)); - originalArrow.remove(); + // Don't allow multi-shot or infinite arrows to be picked up + if (spawnedArrow.hasMetadata(MetadataConstants.METADATA_KEY_MULTI_SHOT_ARROW) + || spawnedArrow.hasMetadata(MetadataConstants.METADATA_KEY_INF_ARROW)) { + spawnedArrow.setPickupStatus(AbstractArrow.PickupStatus.DISALLOWED); + } + + // Schedule cleanup of metadata in case metadata cleanup fails + delayArrowMetaCleanup(spawnedArrow); } public int getTrickShotMaxBounceCount() { diff --git a/src/main/java/com/gmail/nossr50/util/MetadataConstants.java b/src/main/java/com/gmail/nossr50/util/MetadataConstants.java index c8fc18a7d..39f9479ce 100644 --- a/src/main/java/com/gmail/nossr50/util/MetadataConstants.java +++ b/src/main/java/com/gmail/nossr50/util/MetadataConstants.java @@ -15,6 +15,7 @@ public class MetadataConstants { */ public static final @NotNull String METADATA_KEY_REPLANT = "mcMMO: Recently Replanted"; public static final @NotNull String METADATA_KEY_SPAWNED_ARROW = "mcMMO: Spawned Arrow"; + public static final @NotNull String METADATA_KEY_MULTI_SHOT_ARROW = "mcMMO: Multi-shot Arrow"; public static final @NotNull String METADATA_KEY_BOUNCE_COUNT = "mcMMO: Arrow Bounce Count"; public static final @NotNull String METADATA_KEY_EXPLOSION_FROM_RUPTURE = "mcMMO: Rupture Explosion"; public static final @NotNull String METADATA_KEY_FISH_HOOK_REF = "mcMMO: Fish Hook Tracker"; diff --git a/src/main/java/com/gmail/nossr50/util/skills/ProjectileUtils.java b/src/main/java/com/gmail/nossr50/util/skills/ProjectileUtils.java index 2c872f417..6427117ae 100644 --- a/src/main/java/com/gmail/nossr50/util/skills/ProjectileUtils.java +++ b/src/main/java/com/gmail/nossr50/util/skills/ProjectileUtils.java @@ -4,6 +4,8 @@ import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.MetadataConstants; import org.bukkit.block.BlockFace; import org.bukkit.entity.Arrow; +import org.bukkit.metadata.FixedMetadataValue; +import org.bukkit.plugin.Plugin; import org.bukkit.util.Vector; import org.jetbrains.annotations.NotNull; @@ -42,5 +44,37 @@ public class ProjectileUtils { if(arrow.hasMetadata(MetadataConstants.METADATA_KEY_SPAWNED_ARROW)) { arrow.removeMetadata(MetadataConstants.METADATA_KEY_SPAWNED_ARROW, mcMMO.p); } + + if(arrow.hasMetadata(MetadataConstants.METADATA_KEY_MULTI_SHOT_ARROW)) { + arrow.removeMetadata(MetadataConstants.METADATA_KEY_MULTI_SHOT_ARROW, mcMMO.p); + } + } + + public static void copyArrowMetadata(@NotNull Plugin pluginRef, @NotNull Arrow arrowToCopy, @NotNull Arrow newArrow) { + if(arrowToCopy.hasMetadata(MetadataConstants.METADATA_KEY_INF_ARROW)) { + newArrow.setMetadata(MetadataConstants.METADATA_KEY_INF_ARROW, + arrowToCopy.getMetadata(MetadataConstants.METADATA_KEY_INF_ARROW).get(0)); + } + + if(arrowToCopy.hasMetadata(MetadataConstants.METADATA_KEY_BOW_FORCE)) { + newArrow.setMetadata(MetadataConstants.METADATA_KEY_BOW_FORCE, + new FixedMetadataValue(pluginRef, + arrowToCopy.getMetadata(MetadataConstants.METADATA_KEY_BOW_FORCE).get(0).asDouble())); + } + + if(arrowToCopy.hasMetadata(MetadataConstants.METADATA_KEY_ARROW_DISTANCE)) { + newArrow.setMetadata(MetadataConstants.METADATA_KEY_ARROW_DISTANCE, + arrowToCopy.getMetadata(MetadataConstants.METADATA_KEY_ARROW_DISTANCE).get(0)); + } + + if(arrowToCopy.hasMetadata(MetadataConstants.METADATA_KEY_SPAWNED_ARROW)) { + newArrow.setMetadata(MetadataConstants.METADATA_KEY_SPAWNED_ARROW, + arrowToCopy.getMetadata(MetadataConstants.METADATA_KEY_SPAWNED_ARROW).get(0)); + } + + if(arrowToCopy.hasMetadata(MetadataConstants.METADATA_KEY_MULTI_SHOT_ARROW)) { + newArrow.setMetadata(MetadataConstants.METADATA_KEY_MULTI_SHOT_ARROW, + arrowToCopy.getMetadata(MetadataConstants.METADATA_KEY_MULTI_SHOT_ARROW).get(0)); + } } }