Преглед изворни кода

Refactor ricochet code, don't reflect shallow angles

nossr50 пре 1 година
родитељ
комит
76d4b50554

+ 2 - 0
Changelog.txt

@@ -1,4 +1,6 @@
 Version 2.2.000
+    TODO: Trickshot: locale, multiple bounces, does not hurt yourself or allies, reduced damage per bounce?
+    TODO: Add metadata cleanup unit tests
     TODO: Cleanup new arrow metadatas
     TODO: SQL DB update
     TODO: SQL unit tests

+ 1 - 1
src/main/java/com/gmail/nossr50/datatypes/skills/SubSkillType.java

@@ -35,7 +35,7 @@ public enum SubSkillType {
     /* CROSSBOWS */
     CROSSBOWS_SUPER_SHOTGUN(1),
     CROSSBOWS_CROSSBOWS_LIMIT_BREAK(10),
-    CROSSBOWS_TRICK_SHOT(5),
+    CROSSBOWS_TRICK_SHOT(3),
 
     /* Excavation */
     EXCAVATION_ARCHAEOLOGY(8),

+ 7 - 17
src/main/java/com/gmail/nossr50/listeners/EntityListener.java

@@ -15,6 +15,7 @@ import com.gmail.nossr50.metadata.MobMetadataService;
 import com.gmail.nossr50.party.PartyManager;
 import com.gmail.nossr50.runnables.TravelingBlockMetaCleanup;
 import com.gmail.nossr50.skills.archery.Archery;
+import com.gmail.nossr50.skills.crossbows.Crossbows;
 import com.gmail.nossr50.skills.mining.BlastMining;
 import com.gmail.nossr50.skills.mining.MiningManager;
 import com.gmail.nossr50.skills.taming.Taming;
@@ -28,7 +29,10 @@ 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.WorldGuardUtils;
-import org.bukkit.*;
+import org.bukkit.ChatColor;
+import org.bukkit.Material;
+import org.bukkit.NamespacedKey;
+import org.bukkit.OfflinePlayer;
 import org.bukkit.attribute.Attribute;
 import org.bukkit.block.Block;
 import org.bukkit.enchantments.Enchantment;
@@ -48,9 +52,6 @@ import org.bukkit.potion.PotionEffectType;
 import org.bukkit.projectiles.ProjectileSource;
 import org.jetbrains.annotations.NotNull;
 
-import static com.gmail.nossr50.util.skills.ProjectileUtils.getNormal;
-import static com.gmail.nossr50.util.skills.ProjectileUtils.spawnReflectedArrow;
-
 public class EntityListener implements Listener {
     private final mcMMO pluginRef;
     private final @NotNull MobMetadataService mobMetadataService;
@@ -411,7 +412,7 @@ public class EntityListener implements Listener {
         }
 
         if(entityDamageEvent.getDamager() instanceof Projectile) {
-            CombatUtils.cleanupArrowMetadata((Projectile) entityDamageEvent.getDamager());
+            ProjectileUtils.cleanupProjectileMetadata((Projectile) entityDamageEvent.getDamager());
         }
 
         if(entityDamageEvent.getEntity() instanceof Player player && entityDamageEvent.getDamager() instanceof Player) {
@@ -1118,17 +1119,6 @@ public class EntityListener implements Listener {
         if (WorldBlacklist.isWorldBlacklisted(event.getEntity().getWorld()))
             return;
 
-        if(event.getEntity() instanceof Arrow originalArrow && event.getHitBlock() != null && event.getHitBlockFace() != null) {
-            if (originalArrow.getShooter() instanceof Player) {
-                // Avoid infinite spawning of arrows
-                if (originalArrow.hasMetadata(MetadataConstants.METADATA_KEY_SPAWNED_ARROW)) {
-                    return;
-                }
-
-                // Spawn a new arrow shooting in the reflected direction
-                spawnReflectedArrow(pluginRef, originalArrow, originalArrow.getLocation(),
-                        getNormal(event.getHitBlockFace()));
-            }
-        }
+        Crossbows.processCrossbows(event, pluginRef);
     }
 }

+ 35 - 0
src/main/java/com/gmail/nossr50/skills/crossbows/Crossbows.java

@@ -0,0 +1,35 @@
+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;
+import org.bukkit.event.entity.ProjectileHitEvent;
+import org.bukkit.plugin.Plugin;
+
+import static com.gmail.nossr50.util.skills.ProjectileUtils.getNormal;
+
+/**
+ * Util class for crossbows.
+ */
+public class Crossbows {
+    public static void processCrossbows(ProjectileHitEvent event, Plugin pluginRef) {
+        if(event.getEntity() instanceof Arrow originalArrow && event.getHitBlock() != null && event.getHitBlockFace() != null) {
+            if (originalArrow.getShooter() instanceof Player) {
+                // Avoid infinite spawning of arrows
+                if (originalArrow.hasMetadata(MetadataConstants.METADATA_KEY_SPAWNED_ARROW)) {
+                    return;
+                }
+
+                McMMOPlayer mmoPlayer = UserManager.getPlayer((Player) originalArrow.getShooter());
+                if (mmoPlayer != null) {
+                    mmoPlayer.getCrossbowsManager().handleRicochet(
+                            pluginRef,
+                            originalArrow,
+                            getNormal(event.getHitBlockFace()));
+                }
+            }
+        }
+    }
+}

+ 40 - 0
src/main/java/com/gmail/nossr50/skills/crossbows/CrossbowsManager.java

@@ -3,9 +3,49 @@ package com.gmail.nossr50.skills.crossbows;
 import com.gmail.nossr50.datatypes.player.McMMOPlayer;
 import com.gmail.nossr50.datatypes.skills.PrimarySkillType;
 import com.gmail.nossr50.skills.SkillManager;
+import com.gmail.nossr50.util.MetadataConstants;
+import org.bukkit.Location;
+import org.bukkit.entity.Arrow;
+import org.bukkit.metadata.FixedMetadataValue;
+import org.bukkit.plugin.Plugin;
+import org.bukkit.projectiles.ProjectileSource;
+import org.bukkit.util.Vector;
+import org.jetbrains.annotations.NotNull;
 
 public class CrossbowsManager extends SkillManager {
     public CrossbowsManager(McMMOPlayer mmoPlayer) {
         super(mmoPlayer, PrimarySkillType.CROSSBOWS);
     }
+
+    public void handleRicochet(@NotNull Plugin pluginRef, @NotNull Arrow originalArrow, @NotNull Vector hitBlockNormal) {
+        // Reflect arrow in new direction
+        // cleanup metadata on original arrow
+        // TODO: Add an event for this for plugins to hook into
+        spawnReflectedArrow(pluginRef, originalArrow, originalArrow.getLocation(), hitBlockNormal);
+    }
+
+    public void spawnReflectedArrow(@NotNull Plugin pluginRef, @NotNull Arrow originalArrow, @NotNull Location origin, @NotNull Vector normal) {
+        final ProjectileSource originalArrowShooter = originalArrow.getShooter();
+        final Vector arrowInBlockVector = originalArrow.getVelocity();
+        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
+        if (arrowInBlockVector.angle(inverseNormal) < Math.PI / 4) {
+            return;
+        }
+
+        // Spawn new arrow with the reflected direction
+        Arrow arrow = originalArrow.getWorld().spawnArrow(origin,
+                reflectedDirection, 1, 1);
+        arrow.setShooter(originalArrowShooter);
+        arrow.setMetadata(MetadataConstants.METADATA_KEY_SPAWNED_ARROW,
+                new FixedMetadataValue(pluginRef, originalArrowShooter));
+
+        // TODO: This metadata needs to get cleaned up at some point
+        arrow.setMetadata(MetadataConstants.METADATA_KEY_BOW_TYPE,
+                new FixedMetadataValue(pluginRef, originalArrow.getMetadata(
+                        MetadataConstants.METADATA_KEY_BOW_TYPE).get(0)));
+    }
 }

+ 6 - 60
src/main/java/com/gmail/nossr50/util/skills/CombatUtils.java

@@ -161,16 +161,10 @@ public final class CombatUtils {
 
         //Make sure the profiles been loaded
         if(mcMMOPlayer == null) {
-            cleanupArrowMetadata(arrow);
+            ProjectileUtils.cleanupProjectileMetadata(arrow);
             return;
         }
 
-        // CrossbowsManager crossbowsManager = mcMMOPlayer.getCrossbowsManager();
-
-//        if (crossbowsManager.canActivateAbility()) {
-//            mcMMOPlayer.checkAbilityActivation(PrimarySkillType.CROSSBOWS);
-//        }
-
         double boostedDamage = event.getDamage();
 
         if(canUseLimitBreak(player, target, SubSkillType.CROSSBOWS_CROSSBOWS_LIMIT_BREAK)) {
@@ -190,7 +184,7 @@ public final class CombatUtils {
                 "Final Damage: "+boostedDamage);
 
         //Clean data
-        cleanupArrowMetadata(arrow);
+        ProjectileUtils.cleanupProjectileMetadata(arrow);
     }
 
     private static void processAxeCombat(@NotNull LivingEntity target, @NotNull Player player, @NotNull EntityDamageByEntityEvent event) {
@@ -327,7 +321,7 @@ public final class CombatUtils {
 
         //Make sure the profiles been loaded
         if(mcMMOPlayer == null) {
-            cleanupArrowMetadata(arrow);
+            ProjectileUtils.cleanupProjectileMetadata(arrow);
             return;
         }
 
@@ -368,7 +362,7 @@ public final class CombatUtils {
                 "Initial Damage: "+initialDamage,
                 "Final Damage: "+boostedDamage);
         //Clean data
-        cleanupArrowMetadata(arrow);
+        ProjectileUtils.cleanupProjectileMetadata(arrow);
     }
 
     /**
@@ -500,7 +494,7 @@ public final class CombatUtils {
                     }
                 } else {
                     //Cleanup Arrow
-                    cleanupArrowMetadata(arrow);
+                    ProjectileUtils.cleanupProjectileMetadata(arrow);
                 }
 
                 if (target.getType() != EntityType.CREEPER
@@ -733,35 +727,6 @@ public final class CombatUtils {
         }
 
         dealNoInvulnerabilityTickDamage(target, damage, attacker);
-
-//        //IFrame storage
-////        int noDamageTicks = target.getNoDamageTicks();
-//
-////        String debug = "BLEED DMG RESULT: INC DMG:"+damage+", HP-Before:"+target.getHealth()+", HP-After:";
-//
-////        double incDmg = getFakeDamageFinalResult(attacker, target, DamageCause.ENTITY_ATTACK, damage);
-//
-////        double newHealth = Math.max(0, target.getHealth() - incDmg);
-//
-//        //Don't kill things with a stone or wooden weapon
-////        if(toolTier < 3 && newHealth == 0)
-////            return;
-//
-//        target.setMetadata(mcMMO.CUSTOM_DAMAGE_METAKEY, mcMMO.metadataValue);
-//
-//        if(newHealth == 0 && !(target instanceof Player))
-//        {
-//            target.damage(99999, attacker);
-//        }
-//        else
-//        {
-////            Vector beforeRuptureVec = new Vector(target.getVelocity().getX(), target.getVelocity().getY(), target.getVelocity().getZ()); ;
-//            target.damage(damage, attacker);
-////            debug+=target.getHealth();
-//            Bukkit.broadcastMessage(debug);
-////            target.setNoDamageTicks(noDamageTicks); //Do not add additional IFrames
-////            target.setVelocity(beforeRuptureVec);
-//        }
     }
 
     /**
@@ -1062,31 +1027,12 @@ public final class CombatUtils {
         }
     }
 
-    /**
-     * Clean up metadata from a projectile
-     *
-     * @param entity projectile
-     */
-    public static void cleanupArrowMetadata(@NotNull Projectile entity) {
-        if(entity.hasMetadata(MetadataConstants.METADATA_KEY_INF_ARROW)) {
-            entity.removeMetadata(MetadataConstants.METADATA_KEY_INF_ARROW, mcMMO.p);
-        }
-
-        if(entity.hasMetadata(MetadataConstants.METADATA_KEY_BOW_FORCE)) {
-            entity.removeMetadata(MetadataConstants.METADATA_KEY_BOW_FORCE, mcMMO.p);
-        }
-
-        if(entity.hasMetadata(MetadataConstants.METADATA_KEY_ARROW_DISTANCE)) {
-            entity.removeMetadata(MetadataConstants.METADATA_KEY_ARROW_DISTANCE, mcMMO.p);
-        }
-    }
-
     /**
      * Clean up metadata from a projectile after a minute has passed
      *
      * @param entity the projectile
      */
     public static void delayArrowMetaCleanup(@NotNull Projectile entity) {
-        mcMMO.p.getFoliaLib().getImpl().runLater(() -> cleanupArrowMetadata(entity), 20*60);
+        mcMMO.p.getFoliaLib().getImpl().runLater(() -> ProjectileUtils.cleanupProjectileMetadata(entity), 20*60);
     }
 }

+ 28 - 20
src/main/java/com/gmail/nossr50/util/skills/ProjectileUtils.java

@@ -1,13 +1,11 @@
 package com.gmail.nossr50.util.skills;
 
+import com.gmail.nossr50.mcMMO;
 import com.gmail.nossr50.util.MetadataConstants;
-import org.bukkit.Location;
 import org.bukkit.block.BlockFace;
-import org.bukkit.entity.Arrow;
-import org.bukkit.metadata.FixedMetadataValue;
-import org.bukkit.plugin.Plugin;
-import org.bukkit.projectiles.ProjectileSource;
+import org.bukkit.entity.Projectile;
 import org.bukkit.util.Vector;
+import org.jetbrains.annotations.NotNull;
 
 public class ProjectileUtils {
     public static Vector getNormal(BlockFace blockFace) {
@@ -22,21 +20,31 @@ public class ProjectileUtils {
         };
     }
 
-    public static void spawnReflectedArrow(Plugin pluginRef, Arrow originalArrow, Location origin, Vector normal) {
-        // TODO: Add an event for this for plugins to hook into
-        ProjectileSource originalArrowShooter = originalArrow.getShooter();
-        Vector incomingDirection = originalArrow.getVelocity();
-        Vector reflectedDirection = incomingDirection.subtract(normal.multiply(2 * incomingDirection.dot(normal)));
+    /**
+     * Clean up all possible mcMMO related metadata for a projectile
+     *
+     * @param entity projectile
+     */
+    // TODO: Add test
+    public static void cleanupProjectileMetadata(@NotNull Projectile entity) {
+        if(entity.hasMetadata(MetadataConstants.METADATA_KEY_INF_ARROW)) {
+            entity.removeMetadata(MetadataConstants.METADATA_KEY_INF_ARROW, mcMMO.p);
+        }
 
-        // Spawn new arrow with the reflected direction
-        Arrow arrow = originalArrow.getWorld().spawnArrow(origin,
-                reflectedDirection, 1, 1);
-        arrow.setShooter(originalArrowShooter);
-        arrow.setMetadata(MetadataConstants.METADATA_KEY_SPAWNED_ARROW,
-                new FixedMetadataValue(pluginRef, originalArrowShooter));
-        // TODO: This metadata needs to get cleaned up at some point
-        arrow.setMetadata(MetadataConstants.METADATA_KEY_BOW_TYPE,
-                new FixedMetadataValue(pluginRef, originalArrow.getMetadata(
-                        MetadataConstants.METADATA_KEY_BOW_TYPE).get(0)));
+        if(entity.hasMetadata(MetadataConstants.METADATA_KEY_BOW_FORCE)) {
+            entity.removeMetadata(MetadataConstants.METADATA_KEY_BOW_FORCE, mcMMO.p);
+        }
+
+        if(entity.hasMetadata(MetadataConstants.METADATA_KEY_ARROW_DISTANCE)) {
+            entity.removeMetadata(MetadataConstants.METADATA_KEY_ARROW_DISTANCE, mcMMO.p);
+        }
+
+        if(entity.hasMetadata(MetadataConstants.METADATA_KEY_BOW_TYPE)) {
+            entity.removeMetadata(MetadataConstants.METADATA_KEY_BOW_TYPE, mcMMO.p);
+        }
+
+        if(entity.hasMetadata(MetadataConstants.METADATA_KEY_SPAWNED_ARROW)) {
+            entity.removeMetadata(MetadataConstants.METADATA_KEY_SPAWNED_ARROW, mcMMO.p);
+        }
     }
 }