Crossbow multi-shot arrows that bounce are no longer pickup-able

This commit is contained in:
nossr50 2024-01-28 15:00:53 -08:00
parent b3b8a12b6d
commit 66a4886ee4
6 changed files with 89 additions and 26 deletions

View File

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

View File

@ -152,17 +152,20 @@ public class EntityListener implements Listener {
return; return;
} }
Projectile projectile = event.getEntity(); if(event.getEntity() instanceof Arrow arrow) {
EntityType entityType = projectile.getType(); // Delayed metadata cleanup in case other cleanup hooks fail
CombatUtils.delayArrowMetaCleanup(arrow);
if(projectile instanceof Arrow arrow) { // If fired from an item with multi-shot, we need to track
CombatUtils.delayArrowMetaCleanup(arrow); //Cleans up metadata 1 minute from now in case other collection methods fall through 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)) if(!arrow.hasMetadata(MetadataConstants.METADATA_KEY_BOW_FORCE))
projectile.setMetadata(MetadataConstants.METADATA_KEY_BOW_FORCE, new FixedMetadataValue(pluginRef, 1.0)); arrow.setMetadata(MetadataConstants.METADATA_KEY_BOW_FORCE, new FixedMetadataValue(pluginRef, 1.0));
if(!projectile.hasMetadata(MetadataConstants.METADATA_KEY_ARROW_DISTANCE)) if(!arrow.hasMetadata(MetadataConstants.METADATA_KEY_ARROW_DISTANCE))
projectile.setMetadata(MetadataConstants.METADATA_KEY_ARROW_DISTANCE, new FixedMetadataValue(pluginRef, arrow.getLocation())); arrow.setMetadata(MetadataConstants.METADATA_KEY_ARROW_DISTANCE, new FixedMetadataValue(pluginRef, arrow.getLocation()));
//Check both hands //Check both hands
if(ItemUtils.doesPlayerHaveEnchantmentInHands(player, "piercing")) { if(ItemUtils.doesPlayerHaveEnchantmentInHands(player, "piercing")) {
@ -170,7 +173,7 @@ public class EntityListener implements Listener {
} }
if (ProbabilityUtil.isSkillRNGSuccessful(SubSkillType.ARCHERY_ARROW_RETRIEVAL, player)) { 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);
} }
} }
} }

View File

@ -1,6 +1,7 @@
package com.gmail.nossr50.skills.crossbows; package com.gmail.nossr50.skills.crossbows;
import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.datatypes.player.McMMOPlayer;
import com.gmail.nossr50.util.MetadataConstants;
import com.gmail.nossr50.util.player.UserManager; import com.gmail.nossr50.util.player.UserManager;
import org.bukkit.entity.Arrow; import org.bukkit.entity.Arrow;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
@ -13,17 +14,29 @@ import static com.gmail.nossr50.util.skills.ProjectileUtils.getNormal;
* Util class for crossbows. * Util class for crossbows.
*/ */
public class 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) { 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(event.getHitBlock() != null && event.getHitBlockFace() != null) {
if (arrow.getShooter() instanceof Player) { mmoPlayer.getCrossbowsManager().handleRicochet(
McMMOPlayer mmoPlayer = UserManager.getPlayer((Player) arrow.getShooter()); pluginRef,
if (mmoPlayer != null) { arrow,
mmoPlayer.getCrossbowsManager().handleRicochet( getNormal(event.getHitBlockFace()));
pluginRef,
arrow,
getNormal(event.getHitBlockFace()));
}
}
} }
} }
} }

View File

@ -8,8 +8,10 @@ import com.gmail.nossr50.skills.SkillManager;
import com.gmail.nossr50.util.MetadataConstants; import com.gmail.nossr50.util.MetadataConstants;
import com.gmail.nossr50.util.Permissions; import com.gmail.nossr50.util.Permissions;
import com.gmail.nossr50.util.random.ProbabilityUtil; import com.gmail.nossr50.util.random.ProbabilityUtil;
import com.gmail.nossr50.util.skills.ProjectileUtils;
import com.gmail.nossr50.util.skills.RankUtils; import com.gmail.nossr50.util.skills.RankUtils;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.entity.AbstractArrow;
import org.bukkit.entity.Arrow; import org.bukkit.entity.Arrow;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.metadata.FixedMetadataValue; import org.bukkit.metadata.FixedMetadataValue;
@ -18,6 +20,8 @@ import org.bukkit.projectiles.ProjectileSource;
import org.bukkit.util.Vector; import org.bukkit.util.Vector;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import static com.gmail.nossr50.util.skills.CombatUtils.delayArrowMetaCleanup;
public class CrossbowsManager extends SkillManager { public class CrossbowsManager extends SkillManager {
public CrossbowsManager(McMMOPlayer mmoPlayer) { public CrossbowsManager(McMMOPlayer mmoPlayer) {
super(mmoPlayer, PrimarySkillType.CROSSBOWS); 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 reflectedDirection = arrowInBlockVector.subtract(normal.multiply(2 * arrowInBlockVector.dot(normal)));
final Vector inverseNormal = normal.multiply(-1); final Vector inverseNormal = normal.multiply(-1);
// check the angle of the arrow against the inverse normal to see if the angle was too shallow // 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 // only checks angle on the first bounce
if (bounceCount == 0 && arrowInBlockVector.angle(inverseNormal) < Math.PI / 4) { 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 // Spawn new arrow with the reflected direction
Arrow arrow = originalArrow.getWorld().spawnArrow(origin, Arrow spawnedArrow = originalArrow.getWorld().spawnArrow(origin, reflectedDirection, 1, 1);
reflectedDirection, 1, 1); ProjectileUtils.copyArrowMetadata(pluginRef, originalArrow, spawnedArrow);
arrow.setShooter(originalArrowShooter); originalArrow.remove();
arrow.setMetadata(MetadataConstants.METADATA_KEY_BOUNCE_COUNT, // copy metadata from old arrow
spawnedArrow.setShooter(originalArrowShooter);
spawnedArrow.setMetadata(MetadataConstants.METADATA_KEY_BOUNCE_COUNT,
new FixedMetadataValue(pluginRef, bounceCount + 1)); new FixedMetadataValue(pluginRef, bounceCount + 1));
arrow.setMetadata(MetadataConstants.METADATA_KEY_SPAWNED_ARROW, spawnedArrow.setMetadata(MetadataConstants.METADATA_KEY_SPAWNED_ARROW,
new FixedMetadataValue(pluginRef, originalArrowShooter)); 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() { public int getTrickShotMaxBounceCount() {

View File

@ -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_REPLANT = "mcMMO: Recently Replanted";
public static final @NotNull String METADATA_KEY_SPAWNED_ARROW = "mcMMO: Spawned Arrow"; 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_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_EXPLOSION_FROM_RUPTURE = "mcMMO: Rupture Explosion";
public static final @NotNull String METADATA_KEY_FISH_HOOK_REF = "mcMMO: Fish Hook Tracker"; public static final @NotNull String METADATA_KEY_FISH_HOOK_REF = "mcMMO: Fish Hook Tracker";

View File

@ -4,6 +4,8 @@ import com.gmail.nossr50.mcMMO;
import com.gmail.nossr50.util.MetadataConstants; import com.gmail.nossr50.util.MetadataConstants;
import org.bukkit.block.BlockFace; import org.bukkit.block.BlockFace;
import org.bukkit.entity.Arrow; import org.bukkit.entity.Arrow;
import org.bukkit.metadata.FixedMetadataValue;
import org.bukkit.plugin.Plugin;
import org.bukkit.util.Vector; import org.bukkit.util.Vector;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
@ -42,5 +44,37 @@ public class ProjectileUtils {
if(arrow.hasMetadata(MetadataConstants.METADATA_KEY_SPAWNED_ARROW)) { if(arrow.hasMetadata(MetadataConstants.METADATA_KEY_SPAWNED_ARROW)) {
arrow.removeMetadata(MetadataConstants.METADATA_KEY_SPAWNED_ARROW, mcMMO.p); 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));
}
} }
} }