Crossbow Fixes

This commit is contained in:
nossr50 2024-01-22 13:51:23 -08:00
parent f051edd03d
commit b3b8a12b6d
13 changed files with 76 additions and 112 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-04-SNAPSHOT</version> <version>2.2.000-BETA-07-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

@ -2,20 +2,19 @@ package com.gmail.nossr50.commands.skills;
import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.datatypes.player.McMMOPlayer;
import com.gmail.nossr50.datatypes.skills.PrimarySkillType; import com.gmail.nossr50.datatypes.skills.PrimarySkillType;
import com.gmail.nossr50.datatypes.skills.SubSkillType;
import com.gmail.nossr50.util.player.UserManager; import com.gmail.nossr50.util.player.UserManager;
import com.gmail.nossr50.util.skills.CombatUtils; import com.gmail.nossr50.util.skills.CombatUtils;
import com.gmail.nossr50.util.skills.SkillUtils; import com.gmail.nossr50.util.skills.SkillUtils;
import com.gmail.nossr50.util.text.TextComponentFactory; import com.gmail.nossr50.util.text.TextComponentFactory;
import net.kyori.adventure.text.Component; import net.kyori.adventure.text.Component;
import org.bukkit.ChatColor; import org.bukkit.ChatColor;
import org.bukkit.entity.Cat;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import static com.gmail.nossr50.datatypes.skills.SubSkillType.*; import static com.gmail.nossr50.datatypes.skills.SubSkillType.TRIDENTS_IMPALE;
import static com.gmail.nossr50.datatypes.skills.SubSkillType.TRIDENTS_TRIDENTS_LIMIT_BREAK;
public class TridentsCommand extends SkillCommand { public class TridentsCommand extends SkillCommand {

View File

@ -963,14 +963,14 @@ public class McMMOPlayer implements Identified {
/** /**
* Check to see if an ability can be activated. * Check to see if an ability can be activated.
* *
* @param bowType The type of bow (crossbow, bow) * @param isCrossbow true for crossbow, false for bow
*/ */
public void checkAbilityActivationProjectiles(BowType bowType) { public void checkAbilityActivationProjectiles(boolean isCrossbow) {
PrimarySkillType primarySkillType = bowType == BowType.CROSSBOW ? PrimarySkillType.CROSSBOWS : PrimarySkillType.ARCHERY; PrimarySkillType primarySkillType = isCrossbow ? PrimarySkillType.CROSSBOWS : PrimarySkillType.ARCHERY;
// TODO: Refactor this crappy logic // TODO: Refactor this crappy logic
ToolType tool = bowType == BowType.CROSSBOW ? ToolType.CROSSBOW : ToolType.BOW; ToolType tool = isCrossbow ? ToolType.CROSSBOW : ToolType.BOW;
SuperAbilityType superAbilityType = bowType == BowType.CROSSBOW ? SuperAbilityType.SUPER_SHOTGUN : SuperAbilityType.EXPLOSIVE_SHOT; SuperAbilityType superAbilityType = isCrossbow ? SuperAbilityType.SUPER_SHOTGUN : SuperAbilityType.EXPLOSIVE_SHOT;
SubSkillType subSkillType = superAbilityType.getSubSkillTypeDefinition(); SubSkillType subSkillType = superAbilityType.getSubSkillTypeDefinition();
if (getAbilityMode(superAbilityType) || !superAbilityType.getPermissions(player)) { if (getAbilityMode(superAbilityType) || !superAbilityType.getPermissions(player)) {

View File

@ -26,7 +26,6 @@ import com.gmail.nossr50.util.player.NotificationManager;
import com.gmail.nossr50.util.player.UserManager; import com.gmail.nossr50.util.player.UserManager;
import com.gmail.nossr50.util.random.ProbabilityUtil; import com.gmail.nossr50.util.random.ProbabilityUtil;
import com.gmail.nossr50.util.skills.CombatUtils; import com.gmail.nossr50.util.skills.CombatUtils;
import com.gmail.nossr50.util.skills.ProjectileUtils;
import com.gmail.nossr50.worldguard.WorldGuardManager; import com.gmail.nossr50.worldguard.WorldGuardManager;
import com.gmail.nossr50.worldguard.WorldGuardUtils; import com.gmail.nossr50.worldguard.WorldGuardUtils;
import org.bukkit.ChatColor; import org.bukkit.ChatColor;
@ -105,7 +104,7 @@ public class EntityListener implements Listener {
} }
} }
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = false)
public void onEntityShootBow(EntityShootBowEvent event) { public void onEntityShootBow(EntityShootBowEvent event) {
/* WORLD BLACKLIST CHECK */ /* WORLD BLACKLIST CHECK */
if(WorldBlacklist.isWorldBlacklisted(event.getEntity().getWorld())) if(WorldBlacklist.isWorldBlacklisted(event.getEntity().getWorld()))
@ -113,18 +112,10 @@ public class EntityListener implements Listener {
if(event.getEntity() instanceof Player player) if(event.getEntity() instanceof Player player)
{ {
/* WORLD GUARD MAIN FLAG CHECK */
if(WorldGuardUtils.isWorldGuardLoaded())
{
if(!WorldGuardManager.getInstance().hasMainFlag(player))
return;
}
Entity projectile = event.getProjectile(); Entity projectile = event.getProjectile();
//Should be noted that there are API changes regarding Arrow from 1.13.2 to current versions of the game //Should be noted that there are API changes regarding Arrow from 1.13.2 to current versions of the game
if (!(projectile instanceof Arrow)) { if (!(projectile instanceof Arrow arrow)) {
return; return;
} }
@ -133,20 +124,16 @@ public class EntityListener implements Listener {
if (bow == null) if (bow == null)
return; return;
// determine if bow or crossbow
BowType bowType = ItemUtils.isCrossbow(bow) ? BowType.CROSSBOW : BowType.BOW;
if (bow.containsEnchantment(Enchantment.ARROW_INFINITE)) { if (bow.containsEnchantment(Enchantment.ARROW_INFINITE)) {
projectile.setMetadata(MetadataConstants.METADATA_KEY_INF_ARROW, MetadataConstants.MCMMO_METADATA_VALUE); projectile.setMetadata(MetadataConstants.METADATA_KEY_INF_ARROW, MetadataConstants.MCMMO_METADATA_VALUE);
} }
// Set BowType, Force, and Distance metadata // Set BowType, Force, and Distance metadata
projectile.setMetadata(MetadataConstants.METADATA_KEY_BOW_TYPE, new FixedMetadataValue(pluginRef, bowType));
projectile.setMetadata(MetadataConstants.METADATA_KEY_BOW_FORCE, new FixedMetadataValue(pluginRef, Math.min(event.getForce() * mcMMO.p.getAdvancedConfig().getForceMultiplier(), 1.0))); projectile.setMetadata(MetadataConstants.METADATA_KEY_BOW_FORCE, new FixedMetadataValue(pluginRef, Math.min(event.getForce() * mcMMO.p.getAdvancedConfig().getForceMultiplier(), 1.0)));
projectile.setMetadata(MetadataConstants.METADATA_KEY_ARROW_DISTANCE, new FixedMetadataValue(pluginRef, projectile.getLocation())); projectile.setMetadata(MetadataConstants.METADATA_KEY_ARROW_DISTANCE, new FixedMetadataValue(pluginRef, arrow.getLocation()));
//Cleanup metadata in 1 minute in case normal collection falls through //Cleanup metadata in 1 minute in case normal collection falls through
CombatUtils.delayArrowMetaCleanup((Projectile) projectile); CombatUtils.delayArrowMetaCleanup(arrow);
} }
} }
@ -168,14 +155,14 @@ public class EntityListener implements Listener {
Projectile projectile = event.getEntity(); Projectile projectile = event.getEntity();
EntityType entityType = projectile.getType(); EntityType entityType = projectile.getType();
if(entityType == EntityType.ARROW || entityType == EntityType.SPECTRAL_ARROW) { if(projectile instanceof Arrow arrow) {
CombatUtils.delayArrowMetaCleanup(projectile); //Cleans up metadata 1 minute from now in case other collection methods fall through CombatUtils.delayArrowMetaCleanup(arrow); //Cleans up metadata 1 minute from now in case other collection methods fall through
if(!projectile.hasMetadata(MetadataConstants.METADATA_KEY_BOW_FORCE)) if(!projectile.hasMetadata(MetadataConstants.METADATA_KEY_BOW_FORCE))
projectile.setMetadata(MetadataConstants.METADATA_KEY_BOW_FORCE, new FixedMetadataValue(pluginRef, 1.0)); projectile.setMetadata(MetadataConstants.METADATA_KEY_BOW_FORCE, new FixedMetadataValue(pluginRef, 1.0));
if(!projectile.hasMetadata(MetadataConstants.METADATA_KEY_ARROW_DISTANCE)) if(!projectile.hasMetadata(MetadataConstants.METADATA_KEY_ARROW_DISTANCE))
projectile.setMetadata(MetadataConstants.METADATA_KEY_ARROW_DISTANCE, new FixedMetadataValue(pluginRef, projectile.getLocation())); projectile.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")) {
@ -411,8 +398,8 @@ public class EntityListener implements Listener {
} }
} }
if(entityDamageEvent.getDamager() instanceof Projectile) { if(entityDamageEvent.getDamager() instanceof Arrow arrow) {
ProjectileUtils.cleanupProjectileMetadata((Projectile) entityDamageEvent.getDamager()); CombatUtils.delayArrowMetaCleanup(arrow);
} }
if(entityDamageEvent.getEntity() instanceof Player player && entityDamageEvent.getDamager() instanceof Player) { if(entityDamageEvent.getEntity() instanceof Player player && entityDamageEvent.getDamager() instanceof Player) {
@ -1119,6 +1106,10 @@ public class EntityListener implements Listener {
if (WorldBlacklist.isWorldBlacklisted(event.getEntity().getWorld())) if (WorldBlacklist.isWorldBlacklisted(event.getEntity().getWorld()))
return; return;
Crossbows.processCrossbows(event, pluginRef); if(event.getEntity() instanceof Arrow arrow) {
if(arrow.isShotFromCrossbow()) {
Crossbows.processCrossbows(event, pluginRef, arrow);
}
}
} }
} }

View File

@ -13,14 +13,14 @@ import static com.gmail.nossr50.util.skills.ProjectileUtils.getNormal;
* Util class for crossbows. * Util class for crossbows.
*/ */
public class Crossbows { public class Crossbows {
public static void processCrossbows(ProjectileHitEvent event, Plugin pluginRef) { public static void processCrossbows(ProjectileHitEvent event, Plugin pluginRef, Arrow arrow) {
if(event.getEntity() instanceof Arrow originalArrow && event.getHitBlock() != null && event.getHitBlockFace() != null) { if(event.getHitBlock() != null && event.getHitBlockFace() != null) {
if (originalArrow.getShooter() instanceof Player) { if (arrow.getShooter() instanceof Player) {
McMMOPlayer mmoPlayer = UserManager.getPlayer((Player) originalArrow.getShooter()); McMMOPlayer mmoPlayer = UserManager.getPlayer((Player) arrow.getShooter());
if (mmoPlayer != null) { if (mmoPlayer != null) {
mmoPlayer.getCrossbowsManager().handleRicochet( mmoPlayer.getCrossbowsManager().handleRicochet(
pluginRef, pluginRef,
originalArrow, arrow,
getNormal(event.getHitBlockFace())); getNormal(event.getHitBlockFace()));
} }
} }

View File

@ -5,8 +5,6 @@ import com.gmail.nossr50.datatypes.skills.PrimarySkillType;
import com.gmail.nossr50.datatypes.skills.SubSkillType; import com.gmail.nossr50.datatypes.skills.SubSkillType;
import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.mcMMO;
import com.gmail.nossr50.skills.SkillManager; import com.gmail.nossr50.skills.SkillManager;
import com.gmail.nossr50.skills.archery.Archery;
import com.gmail.nossr50.util.BowType;
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;
@ -25,17 +23,20 @@ public class CrossbowsManager extends SkillManager {
super(mmoPlayer, PrimarySkillType.CROSSBOWS); super(mmoPlayer, PrimarySkillType.CROSSBOWS);
} }
public void handleRicochet(@NotNull Plugin pluginRef, @NotNull Arrow originalArrow, @NotNull Vector hitBlockNormal) { public void handleRicochet(@NotNull Plugin pluginRef, @NotNull Arrow arrow, @NotNull Vector hitBlockNormal) {
if(!arrow.isShotFromCrossbow())
return;
// Check player permission // Check player permission
if (!Permissions.trickShot(mmoPlayer.getPlayer())) { if (!Permissions.trickShot(mmoPlayer.getPlayer())) {
return; return;
} }
// TODO: Add an event for this for plugins to hook into // TODO: Add an event for this for plugins to hook into
spawnReflectedArrow(pluginRef, originalArrow, originalArrow.getLocation(), hitBlockNormal); spawnReflectedArrow(pluginRef, arrow, arrow.getLocation(), hitBlockNormal);
} }
public void spawnReflectedArrow(@NotNull Plugin pluginRef, @NotNull Arrow originalArrow, private void spawnReflectedArrow(@NotNull Plugin pluginRef, @NotNull Arrow originalArrow,
@NotNull Location origin, @NotNull Vector normal) { @NotNull Location origin, @NotNull Vector normal) {
int bounceCount = 0; int bounceCount = 0;
@ -66,8 +67,6 @@ public class CrossbowsManager extends SkillManager {
new FixedMetadataValue(pluginRef, bounceCount + 1)); new FixedMetadataValue(pluginRef, bounceCount + 1));
arrow.setMetadata(MetadataConstants.METADATA_KEY_SPAWNED_ARROW, arrow.setMetadata(MetadataConstants.METADATA_KEY_SPAWNED_ARROW,
new FixedMetadataValue(pluginRef, originalArrowShooter)); new FixedMetadataValue(pluginRef, originalArrowShooter));
arrow.setMetadata(MetadataConstants.METADATA_KEY_BOW_TYPE,
new FixedMetadataValue(pluginRef, BowType.CROSSBOW));
originalArrow.remove(); originalArrow.remove();
} }
@ -89,7 +88,7 @@ public class CrossbowsManager extends SkillManager {
public double poweredShot(double oldDamage) { public double poweredShot(double oldDamage) {
if (ProbabilityUtil.isNonRNGSkillActivationSuccessful(SubSkillType.CROSSBOWS_POWERED_SHOT, getPlayer())) { if (ProbabilityUtil.isNonRNGSkillActivationSuccessful(SubSkillType.CROSSBOWS_POWERED_SHOT, getPlayer())) {
return Archery.getSkillShotBonusDamage(getPlayer(), oldDamage); return getPoweredShotBonusDamage(getPlayer(), oldDamage);
} else { } else {
return oldDamage; return oldDamage;
} }

View File

@ -35,6 +35,7 @@ public class ExcavationManager extends SkillManager {
* @param blockState The {@link BlockState} to check ability activation for * @param blockState The {@link BlockState} to check ability activation for
*/ */
public void excavationBlockCheck(BlockState blockState) { public void excavationBlockCheck(BlockState blockState) {
int xp = Excavation.getBlockXP(blockState);
requireNonNull(blockState, "excavationBlockCheck: blockState cannot be null"); requireNonNull(blockState, "excavationBlockCheck: blockState cannot be null");
if (Permissions.isSubSkillEnabled(getPlayer(), SubSkillType.EXCAVATION_ARCHAEOLOGY)) { if (Permissions.isSubSkillEnabled(getPlayer(), SubSkillType.EXCAVATION_ARCHAEOLOGY)) {
List<ExcavationTreasure> treasures = getTreasures(blockState); List<ExcavationTreasure> treasures = getTreasures(blockState);
@ -51,6 +52,8 @@ public class ExcavationManager extends SkillManager {
} }
} }
} }
applyXpGain(xp, XPGainReason.PVE, XPGainSource.SELF);
} }
@VisibleForTesting @VisibleForTesting
@ -61,16 +64,17 @@ public class ExcavationManager extends SkillManager {
@VisibleForTesting @VisibleForTesting
public void processExcavationBonusesOnBlock(BlockState blockState, ExcavationTreasure treasure, Location location) { public void processExcavationBonusesOnBlock(BlockState blockState, ExcavationTreasure treasure, Location location) {
int xp = Excavation.getBlockXP(blockState);
//Spawn Vanilla XP orbs if a dice roll succeeds //Spawn Vanilla XP orbs if a dice roll succeeds
if(ProbabilityUtil.isStaticSkillRNGSuccessful(PrimarySkillType.EXCAVATION, getPlayer(), getArchaelogyExperienceOrbChance())) { if(ProbabilityUtil.isStaticSkillRNGSuccessful(PrimarySkillType.EXCAVATION, getPlayer(), getArchaelogyExperienceOrbChance())) {
Misc.spawnExperienceOrb(location, getExperienceOrbsReward()); Misc.spawnExperienceOrb(location, getExperienceOrbsReward());
} }
int xp = 0;
xp += treasure.getXp(); xp += treasure.getXp();
Misc.spawnItem(getPlayer(), location, treasure.getDrop(), ItemSpawnReason.EXCAVATION_TREASURE); Misc.spawnItem(getPlayer(), location, treasure.getDrop(), ItemSpawnReason.EXCAVATION_TREASURE);
applyXpGain(xp, XPGainReason.PVE, XPGainSource.SELF); if (xp > 0) {
applyXpGain(xp, XPGainReason.PVE, XPGainSource.SELF);
}
} }
public int getExperienceOrbsReward() { public int getExperienceOrbsReward() {

View File

@ -1,6 +0,0 @@
package com.gmail.nossr50.util;
public enum BowType {
BOW,
CROSSBOW
}

View File

@ -51,17 +51,6 @@ public final class ItemUtils {
return isBow(item) || isCrossbow(item); return isBow(item) || isCrossbow(item);
} }
// TODO: Unit tests
public static BowType getBowType(@NotNull ItemStack item) {
if (isBow(item)) {
return BowType.BOW;
} else if (isCrossbow(item)) {
return BowType.CROSSBOW;
}
throw new IllegalArgumentException(item + " is not a bow or crossbow");
}
// TODO: Unit tests // TODO: Unit tests
public static boolean isTrident(@NotNull ItemStack item) { public static boolean isTrident(@NotNull ItemStack item) {
return mcMMO.getMaterialMapStore().isTrident(item.getType().getKey().getKey()); return mcMMO.getMaterialMapStore().isTrident(item.getType().getKey().getKey());

View File

@ -16,7 +16,6 @@ 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_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_BOW_TYPE = "mcMMO: Bow Type";
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";
public static final @NotNull String METADATA_KEY_DODGE_TRACKER = "mcMMO: Dodge Tracker"; public static final @NotNull String METADATA_KEY_DODGE_TRACKER = "mcMMO: Dodge Tracker";

View File

@ -52,8 +52,10 @@ public final class CombatUtils {
// TODO: Unit tests // TODO: Unit tests
public static void processProjectileSkillSuperAbilityActivation(McMMOPlayer mmoPlayer, ItemStack heldItem) { public static void processProjectileSkillSuperAbilityActivation(McMMOPlayer mmoPlayer, ItemStack heldItem) {
if (heldItem != null && mmoPlayer != null) { if (heldItem != null && mmoPlayer != null) {
if (ItemUtils.isBowOrCrossbow(heldItem)) if (ItemUtils.isBowOrCrossbow(heldItem)) {
mmoPlayer.checkAbilityActivationProjectiles(ItemUtils.getBowType(heldItem)); boolean isCrossbow = ItemUtils.isCrossbow(heldItem);
mmoPlayer.checkAbilityActivationProjectiles(isCrossbow);
}
} }
} }
@ -159,14 +161,14 @@ public final class CombatUtils {
} }
private static void processCrossbowsCombat(@NotNull LivingEntity target, @NotNull Player player, private static void processCrossbowsCombat(@NotNull LivingEntity target, @NotNull Player player,
@NotNull EntityDamageByEntityEvent event, @NotNull Projectile arrow) { @NotNull EntityDamageByEntityEvent event, @NotNull Arrow arrow) {
double initialDamage = event.getDamage(); double initialDamage = event.getDamage();
McMMOPlayer mcMMOPlayer = UserManager.getPlayer(player); McMMOPlayer mcMMOPlayer = UserManager.getPlayer(player);
//Make sure the profiles been loaded //Make sure the profiles been loaded
if(mcMMOPlayer == null) { if(mcMMOPlayer == null) {
ProjectileUtils.cleanupProjectileMetadata(arrow); delayArrowMetaCleanup(arrow);
return; return;
} }
@ -194,7 +196,7 @@ public final class CombatUtils {
"Final Damage: "+boostedDamage); "Final Damage: "+boostedDamage);
//Clean data //Clean data
ProjectileUtils.cleanupProjectileMetadata(arrow); delayArrowMetaCleanup(arrow);
} }
private static void processAxeCombat(@NotNull LivingEntity target, @NotNull Player player, @NotNull EntityDamageByEntityEvent event) { private static void processAxeCombat(@NotNull LivingEntity target, @NotNull Player player, @NotNull EntityDamageByEntityEvent event) {
@ -324,14 +326,15 @@ public final class CombatUtils {
} }
private static void processArcheryCombat(@NotNull LivingEntity target, @NotNull Player player, @NotNull EntityDamageByEntityEvent event, @NotNull Projectile arrow) { private static void processArcheryCombat(@NotNull LivingEntity target, @NotNull Player player,
@NotNull EntityDamageByEntityEvent event, @NotNull Arrow arrow) {
double initialDamage = event.getDamage(); double initialDamage = event.getDamage();
McMMOPlayer mcMMOPlayer = UserManager.getPlayer(player); McMMOPlayer mcMMOPlayer = UserManager.getPlayer(player);
//Make sure the profiles been loaded //Make sure the profiles been loaded
if(mcMMOPlayer == null) { if(mcMMOPlayer == null) {
ProjectileUtils.cleanupProjectileMetadata(arrow); delayArrowMetaCleanup(arrow);
return; return;
} }
@ -372,7 +375,7 @@ public final class CombatUtils {
"Initial Damage: "+initialDamage, "Initial Damage: "+initialDamage,
"Final Damage: "+boostedDamage); "Final Damage: "+boostedDamage);
//Clean data //Clean data
ProjectileUtils.cleanupProjectileMetadata(arrow); delayArrowMetaCleanup(arrow);
} }
/** /**
@ -489,22 +492,20 @@ public final class CombatUtils {
} }
} }
} }
else if (entityType == EntityType.ARROW || entityType == EntityType.SPECTRAL_ARROW) { else if (painSource instanceof Arrow arrow) {
Projectile arrow = (Projectile) painSource;
ProjectileSource projectileSource = arrow.getShooter(); ProjectileSource projectileSource = arrow.getShooter();
boolean isCrossbow = arrow.isShotFromCrossbow();
if (projectileSource instanceof Player player) { if (projectileSource instanceof Player player) {
BowType bowType = getBowTypeFromMetadata(arrow);
if (!Misc.isNPCEntityExcludingVillagers(player)) { if (!Misc.isNPCEntityExcludingVillagers(player)) {
if(bowType == BowType.BOW && mcMMO.p.getSkillTools().canCombatSkillsTrigger(PrimarySkillType.ARCHERY, target)) { if(!isCrossbow && mcMMO.p.getSkillTools().canCombatSkillsTrigger(PrimarySkillType.ARCHERY, target)) {
processArcheryCombat(target, player, event, arrow); processArcheryCombat(target, player, event, arrow);
} else if(bowType == BowType.CROSSBOW && mcMMO.p.getSkillTools().canCombatSkillsTrigger(PrimarySkillType.CROSSBOWS, target)) { } else if(isCrossbow && mcMMO.p.getSkillTools().canCombatSkillsTrigger(PrimarySkillType.CROSSBOWS, target)) {
processCrossbowsCombat(target, player, event, arrow); processCrossbowsCombat(target, player, event, arrow);
} }
} else { } else {
//Cleanup Arrow //Cleanup Arrow
ProjectileUtils.cleanupProjectileMetadata(arrow); delayArrowMetaCleanup(arrow);
} }
if (target.getType() != EntityType.CREEPER if (target.getType() != EntityType.CREEPER
@ -522,18 +523,6 @@ public final class CombatUtils {
} }
} }
private static BowType getBowTypeFromMetadata(Projectile projectile) {
// Return the BowType from the metadata, or default to BOW
if (projectile.hasMetadata(MetadataConstants.METADATA_KEY_BOW_TYPE)) {
List<MetadataValue> metadataValue = projectile.getMetadata(MetadataConstants.METADATA_KEY_BOW_TYPE);
if (!metadataValue.isEmpty()) {
return (BowType) metadataValue.get(0).value();
}
}
throw new IllegalStateException("BowType metadata is empty");
}
/** /**
* This cleans up names from displaying in chat as hearts * This cleans up names from displaying in chat as hearts
* @param entity target entity * @param entity target entity
@ -728,7 +717,7 @@ public final class CombatUtils {
} }
public static boolean hasIgnoreDamageMetadata(@NotNull LivingEntity target) { public static boolean hasIgnoreDamageMetadata(@NotNull LivingEntity target) {
return target.getMetadata(MetadataConstants.METADATA_KEY_CUSTOM_DAMAGE).size() != 0; return target.hasMetadata(MetadataConstants.METADATA_KEY_CUSTOM_DAMAGE);
} }
public static void dealNoInvulnerabilityTickDamageRupture(@NotNull LivingEntity target, double damage, Entity attacker, int toolTier) { public static void dealNoInvulnerabilityTickDamageRupture(@NotNull LivingEntity target, double damage, Entity attacker, int toolTier) {
@ -1040,9 +1029,9 @@ public final class CombatUtils {
/** /**
* Clean up metadata from a projectile after a minute has passed * Clean up metadata from a projectile after a minute has passed
* *
* @param entity the projectile * @param arrow the projectile
*/ */
public static void delayArrowMetaCleanup(@NotNull Projectile entity) { public static void delayArrowMetaCleanup(@NotNull Arrow arrow) {
mcMMO.p.getFoliaLib().getImpl().runLater(() -> ProjectileUtils.cleanupProjectileMetadata(entity), 20*60); mcMMO.p.getFoliaLib().getImpl().runLater(() -> ProjectileUtils.cleanupProjectileMetadata(arrow), 20*120);
} }
} }

View File

@ -3,7 +3,7 @@ package com.gmail.nossr50.util.skills;
import com.gmail.nossr50.mcMMO; 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.Projectile; import org.bukkit.entity.Arrow;
import org.bukkit.util.Vector; import org.bukkit.util.Vector;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
@ -23,28 +23,24 @@ public class ProjectileUtils {
/** /**
* Clean up all possible mcMMO related metadata for a projectile * Clean up all possible mcMMO related metadata for a projectile
* *
* @param entity projectile * @param arrow projectile
*/ */
// TODO: Add test // TODO: Add test
public static void cleanupProjectileMetadata(@NotNull Projectile entity) { public static void cleanupProjectileMetadata(@NotNull Arrow arrow) {
if(entity.hasMetadata(MetadataConstants.METADATA_KEY_INF_ARROW)) { if(arrow.hasMetadata(MetadataConstants.METADATA_KEY_INF_ARROW)) {
entity.removeMetadata(MetadataConstants.METADATA_KEY_INF_ARROW, mcMMO.p); arrow.removeMetadata(MetadataConstants.METADATA_KEY_INF_ARROW, mcMMO.p);
} }
if(entity.hasMetadata(MetadataConstants.METADATA_KEY_BOW_FORCE)) { if(arrow.hasMetadata(MetadataConstants.METADATA_KEY_BOW_FORCE)) {
entity.removeMetadata(MetadataConstants.METADATA_KEY_BOW_FORCE, mcMMO.p); arrow.removeMetadata(MetadataConstants.METADATA_KEY_BOW_FORCE, mcMMO.p);
} }
if(entity.hasMetadata(MetadataConstants.METADATA_KEY_ARROW_DISTANCE)) { if(arrow.hasMetadata(MetadataConstants.METADATA_KEY_ARROW_DISTANCE)) {
entity.removeMetadata(MetadataConstants.METADATA_KEY_ARROW_DISTANCE, mcMMO.p); arrow.removeMetadata(MetadataConstants.METADATA_KEY_ARROW_DISTANCE, mcMMO.p);
} }
if(entity.hasMetadata(MetadataConstants.METADATA_KEY_BOW_TYPE)) { if(arrow.hasMetadata(MetadataConstants.METADATA_KEY_SPAWNED_ARROW)) {
entity.removeMetadata(MetadataConstants.METADATA_KEY_BOW_TYPE, mcMMO.p); arrow.removeMetadata(MetadataConstants.METADATA_KEY_SPAWNED_ARROW, mcMMO.p);
}
if(entity.hasMetadata(MetadataConstants.METADATA_KEY_SPAWNED_ARROW)) {
entity.removeMetadata(MetadataConstants.METADATA_KEY_SPAWNED_ARROW, mcMMO.p);
} }
} }
} }

View File

@ -859,6 +859,8 @@ permissions:
mcmmo.commands.alchemy: true mcmmo.commands.alchemy: true
mcmmo.commands.archery: true mcmmo.commands.archery: true
mcmmo.commands.axes: true mcmmo.commands.axes: true
mcmmo.commands.crossbows: true
mcmmo.commands.tridents: true
mcmmo.commands.excavation: true mcmmo.commands.excavation: true
mcmmo.commands.fishing: true mcmmo.commands.fishing: true
mcmmo.commands.herbalism: true mcmmo.commands.herbalism: true
@ -2212,6 +2214,8 @@ permissions:
mcmmo.skills.taming: true mcmmo.skills.taming: true
mcmmo.skills.unarmed: true mcmmo.skills.unarmed: true
mcmmo.skills.woodcutting: true mcmmo.skills.woodcutting: true
mcmmo.skills.crossbows: true
mcmmo.skills.tridents: true
mcmmo.skills.acrobatics: mcmmo.skills.acrobatics:
description: Allows access to the Acrobatics skill description: Allows access to the Acrobatics skill
children: children: