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));
+ }
}
}