mirror of
				https://github.com/mcMMO-Dev/mcMMO.git
				synced 2025-11-04 11:03:43 +01:00 
			
		
		
		
	Merge branch 'master' of https://github.com/mcMMO-Dev/mcMMO into tridentsxbows
This commit is contained in:
		@@ -99,6 +99,15 @@ Version 2.2.000
 | 
			
		||||
    Parties got unnecessarily complex in my absence, I have removed many party features in order to simplify parties and bring them closer to my vision. I have also added new features which should improve parties where it matters.
 | 
			
		||||
    About the removed party features, all the features I removed I consider poor quality features and I don't think they belong in mcMMO. Feel free to yell at me in discord if you disagree.
 | 
			
		||||
    I don't know what genius decided to make parties public by default, when I found out that parties had been changed to such a system I could barely contain my disgust. Parties are back to being private, you get invited by a party leader or party officer. That is the only way to join a party.
 | 
			
		||||
Version 2.1.170
 | 
			
		||||
    Reverted a change that broke compatibility with the mcMMO papi ecloud thingy
 | 
			
		||||
 | 
			
		||||
Version 2.1.169
 | 
			
		||||
    Fixed a few memory leaks involving arrows
 | 
			
		||||
    Fixed mcMMO inappropriately assigning metadata to projectiles not fired from players
 | 
			
		||||
    Fix mctop not working if locale was set to something other than en_US
 | 
			
		||||
    mcMMO will now always emulate lure in order to stack it correctly and avoid vanilla bugs
 | 
			
		||||
 | 
			
		||||
Version 2.1.168
 | 
			
		||||
    Fixed an IndexOutOfBoundsException error when trying to access UserBlockTracker from an invalid range (thanks t00thpick1)
 | 
			
		||||
    (API) UserBlockTracker is now the interface by which our block-tracker will be known (thanks t00thpick1)
 | 
			
		||||
 
 | 
			
		||||
@@ -45,6 +45,6 @@ public class AddlevelsCommand extends ExperienceCommand {
 | 
			
		||||
        if(isSilent)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        player.sendMessage(LocaleLoader.getString("Commands.addlevels.AwardSkill.1", value, rootSkill.getLocalizedName()));
 | 
			
		||||
        player.sendMessage(LocaleLoader.getString("Commands.addlevels.AwardSkill.1", value, rootSkill.getName()));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -46,6 +46,6 @@ public class AddxpCommand extends ExperienceCommand {
 | 
			
		||||
        if(isSilent)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        player.sendMessage(LocaleLoader.getString("Commands.addxp.AwardSkill", value, rootSkill.getLocalizedName()));
 | 
			
		||||
        player.sendMessage(LocaleLoader.getString("Commands.addxp.AwardSkill", value, rootSkill.getName()));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -161,7 +161,7 @@ public abstract class ExperienceCommand implements TabExecutor {
 | 
			
		||||
            sender.sendMessage(LocaleLoader.getString("Commands.addlevels.AwardAll.2", playerName));
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
            sender.sendMessage(LocaleLoader.getString("Commands.addlevels.AwardSkill.2", rootSkill.getLocalizedName(), playerName));
 | 
			
		||||
            sender.sendMessage(LocaleLoader.getString("Commands.addlevels.AwardSkill.2", rootSkill.getName(), playerName));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -51,6 +51,6 @@ public class MmoeditCommand extends ExperienceCommand {
 | 
			
		||||
        if(isSilent)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        player.sendMessage(LocaleLoader.getString("Commands.mmoedit.Modified.1", rootSkill.getLocalizedName(), value));
 | 
			
		||||
        player.sendMessage(LocaleLoader.getString("Commands.mmoedit.Modified.1", rootSkill.getName(), value));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -142,7 +142,7 @@ public class SkillresetCommand implements TabExecutor {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected void handlePlayerMessageSkill(Player player, RootSkill rootSkill) {
 | 
			
		||||
        player.sendMessage(LocaleLoader.getString("Commands.Reset.Single", rootSkill.getLocalizedName()));
 | 
			
		||||
        player.sendMessage(LocaleLoader.getString("Commands.Reset.Single", rootSkill.getName()));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private boolean validateArguments(CommandSender sender, String skillName) {
 | 
			
		||||
@@ -154,7 +154,7 @@ public class SkillresetCommand implements TabExecutor {
 | 
			
		||||
            sender.sendMessage(LocaleLoader.getString("Commands.addlevels.AwardAll.2", playerName));
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
            sender.sendMessage(LocaleLoader.getString("Commands.addlevels.AwardSkill.2", rootSkill.getLocalizedName(), playerName));
 | 
			
		||||
            sender.sendMessage(LocaleLoader.getString("Commands.addlevels.AwardSkill.2", rootSkill.getName(), playerName));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -59,6 +59,6 @@ public class HardcoreCommand extends HardcoreModeCommand {
 | 
			
		||||
            rootSkill.setHardcoreStatLossEnabled(enable);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        mcMMO.p.getServer().broadcastMessage(LocaleLoader.getString("Hardcore.Mode." + (enable ? "Enabled" : "Disabled"), LocaleLoader.getString("Hardcore.DeathStatLoss.Name"), (rootSkill == null ? "all skills" : rootSkill.getLocalizedName())));
 | 
			
		||||
        mcMMO.p.getServer().broadcastMessage(LocaleLoader.getString("Hardcore.Mode." + (enable ? "Enabled" : "Disabled"), LocaleLoader.getString("Hardcore.DeathStatLoss.Name"), (rootSkill == null ? "all skills" : rootSkill.getName())));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -49,7 +49,7 @@ public abstract class SkillCommand implements TabExecutor {
 | 
			
		||||
    public SkillCommand(@NotNull RootSkill rootSkill) {
 | 
			
		||||
        this.rootSkill = CoreSkills.getSkill(primarySkillType);
 | 
			
		||||
        this.primarySkillType = primarySkillType;
 | 
			
		||||
        skillName = rootSkill.getLocalizedName();
 | 
			
		||||
        skillName = rootSkill.getName();
 | 
			
		||||
        skillGuideCommand = new SkillGuideCommand(rootSkill);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -177,10 +177,10 @@ public abstract class SkillCommand implements TabExecutor {
 | 
			
		||||
            {
 | 
			
		||||
                if(i+1 < parentList.size())
 | 
			
		||||
                {
 | 
			
		||||
                    parentMessage.append(LocaleLoader.getString("Effects.Child.ParentList", parentList.get(i).getLocalizedName(), mcMMOPlayer.getSkillLevel(parentList.get(i))));
 | 
			
		||||
                    parentMessage.append(LocaleLoader.getString("Effects.Child.ParentList", parentList.get(i).getName(), mcMMOPlayer.getSkillLevel(parentList.get(i))));
 | 
			
		||||
                    parentMessage.append(ChatColor.GRAY).append(", ");
 | 
			
		||||
                } else {
 | 
			
		||||
                    parentMessage.append(LocaleLoader.getString("Effects.Child.ParentList", parentList.get(i).getLocalizedName(), mcMMOPlayer.getSkillLevel(parentList.get(i))));
 | 
			
		||||
                    parentMessage.append(LocaleLoader.getString("Effects.Child.ParentList", parentList.get(i).getName(), mcMMOPlayer.getSkillLevel(parentList.get(i))));
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -22,7 +22,7 @@ public class SkillGuideCommand implements CommandExecutor {
 | 
			
		||||
 | 
			
		||||
    public SkillGuideCommand(@NotNull RootSkill rootSkill) {
 | 
			
		||||
        this.rootSkill = rootSkill;
 | 
			
		||||
        header = LocaleLoader.getString("Guides.Header", rootSkill.getLocalizedName());
 | 
			
		||||
        header = LocaleLoader.getString("Guides.Header", rootSkill.getName());
 | 
			
		||||
        guide = getGuide(rootSkill);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -99,10 +99,10 @@ public enum PrimarySkillType {
 | 
			
		||||
                nonChildSkills.add(skill);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            for(SubSkillType subSkillType : skill.subSkillTypes)
 | 
			
		||||
            {
 | 
			
		||||
            for(SubSkillType subSkillType : skill.subSkillTypes) {
 | 
			
		||||
                subSkillNames.add(subSkillType.getNiceNameNoSpaces(subSkillType));
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            names.add(skill.getName());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -234,13 +234,13 @@ public enum PrimarySkillType {
 | 
			
		||||
        return null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public String getLocalizedName() {
 | 
			
		||||
    public String getName() {
 | 
			
		||||
        return StringUtils.getCapitalized(LocaleLoader.getString(StringUtils.getCapitalized(this.toString()) + ".SkillName"));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public String getName() {
 | 
			
		||||
        return StringUtils.getCapitalized(StringUtils.getCapitalized(this.toString()));
 | 
			
		||||
    }
 | 
			
		||||
//    public String getName() {
 | 
			
		||||
//        return StringUtils.getCapitalized(StringUtils.getCapitalized(this.toString()));
 | 
			
		||||
//    }
 | 
			
		||||
 | 
			
		||||
    public boolean getPermissions(Player player) {
 | 
			
		||||
        return Permissions.skillEnabled(player, this);
 | 
			
		||||
 
 | 
			
		||||
@@ -124,24 +124,26 @@ public class EntityListener implements Listener {
 | 
			
		||||
                if(!WorldGuardManager.getInstance().hasMainFlag(player))
 | 
			
		||||
                    return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            Entity projectile = event.getProjectile();
 | 
			
		||||
 | 
			
		||||
            //Should be noted that there are API changes regarding Arrow from 1.13.2 to current versions of the game
 | 
			
		||||
            if (!(projectile instanceof Arrow)) {
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            ItemStack bow = event.getBow();
 | 
			
		||||
 | 
			
		||||
            if (bow != null
 | 
			
		||||
                    && bow.containsEnchantment(Enchantment.ARROW_INFINITE)) {
 | 
			
		||||
                projectile.setMetadata(mcMMO.infiniteArrowKey, mcMMO.metadataValue);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            projectile.setMetadata(mcMMO.bowForceKey, new FixedMetadataValue(pluginRef, Math.min(event.getForce() * AdvancedConfig.getInstance().getForceMultiplier(), 1.0)));
 | 
			
		||||
            projectile.setMetadata(mcMMO.arrowDistanceKey, new FixedMetadataValue(pluginRef, projectile.getLocation()));
 | 
			
		||||
            //Cleanup metadata in 1 minute in case normal collection falls through
 | 
			
		||||
            CombatUtils.cleanupArrowMetadata((Projectile) projectile);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        Entity projectile = event.getProjectile();
 | 
			
		||||
 | 
			
		||||
        //Should be noted that there are API changes regarding Arrow from 1.13.2 to current versions of the game
 | 
			
		||||
        if (!(projectile instanceof Arrow)) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        ItemStack bow = event.getBow();
 | 
			
		||||
 | 
			
		||||
        if (bow != null
 | 
			
		||||
                && bow.containsEnchantment(Enchantment.ARROW_INFINITE)) {
 | 
			
		||||
            projectile.setMetadata(mcMMO.infiniteArrowKey, mcMMO.metadataValue);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        projectile.setMetadata(mcMMO.bowForceKey, new FixedMetadataValue(pluginRef, Math.min(event.getForce() * AdvancedConfig.getInstance().getForceMultiplier(), 1.0)));
 | 
			
		||||
        projectile.setMetadata(mcMMO.arrowDistanceKey, new FixedMetadataValue(pluginRef, projectile.getLocation()));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST)
 | 
			
		||||
@@ -169,6 +171,8 @@ public class EntityListener implements Listener {
 | 
			
		||||
            EntityType entityType = projectile.getType();
 | 
			
		||||
 | 
			
		||||
            if (entityType == EntityType.ARROW || entityType == EntityType.SPECTRAL_ARROW) {
 | 
			
		||||
                CombatUtils.delayArrowMetaCleanup(projectile); //Cleans up metadata 1 minute from now in case other collection methods fall through
 | 
			
		||||
 | 
			
		||||
                if (!projectile.hasMetadata(mcMMO.bowForceKey))
 | 
			
		||||
                    projectile.setMetadata(mcMMO.bowForceKey, new FixedMetadataValue(pluginRef, 1.0));
 | 
			
		||||
 | 
			
		||||
@@ -244,7 +248,6 @@ public class EntityListener implements Listener {
 | 
			
		||||
        Entity entity = event.getEntity();
 | 
			
		||||
        Material notYetReplacedType = block.getState().getType(); //because its from getState() this is the block that hasn't been changed yet, which is likely air/lava/water etc
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        // When the event is fired for the falling block that changes back to a
 | 
			
		||||
        // normal block
 | 
			
		||||
        // event.getBlock().getType() returns AIR
 | 
			
		||||
@@ -463,13 +466,14 @@ public class EntityListener implements Listener {
 | 
			
		||||
            LivingEntity livingEntity = (LivingEntity) entityDamageEvent.getEntity();
 | 
			
		||||
 | 
			
		||||
            if(entityDamageEvent.getFinalDamage() >= livingEntity.getHealth()) {
 | 
			
		||||
 | 
			
		||||
                /*
 | 
			
		||||
                 * This sets entity names back to whatever they are supposed to be
 | 
			
		||||
                 */
 | 
			
		||||
                //This sets entity names back to whatever they are supposed to be
 | 
			
		||||
                CombatUtils.fixNames(livingEntity);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if(entityDamageEvent.getDamager() instanceof Projectile) {
 | 
			
		||||
            CombatUtils.cleanupArrowMetadata((Projectile) entityDamageEvent.getDamager());
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public boolean checkParties(Cancellable event, Player defendingPlayer, Player attackingPlayer) {
 | 
			
		||||
 
 | 
			
		||||
@@ -839,7 +839,7 @@ public class PlayerListener implements Listener {
 | 
			
		||||
            // Do these ACTUALLY have to be lower case to work properly?
 | 
			
		||||
            for (PrimarySkillType skill : PrimarySkillType.values()) {
 | 
			
		||||
                String skillName = skill.toString().toLowerCase(Locale.ENGLISH);
 | 
			
		||||
                String localizedName = skill.getLocalizedName().toLowerCase(Locale.ENGLISH);
 | 
			
		||||
                String localizedName = skill.getName().toLowerCase(Locale.ENGLISH);
 | 
			
		||||
 | 
			
		||||
                if (lowerCaseCommand.equals(localizedName)) {
 | 
			
		||||
                    event.setMessage(message.replace(command, skillName));
 | 
			
		||||
 
 | 
			
		||||
@@ -53,7 +53,7 @@ public class McrankCommandDisplayTask extends BukkitRunnable {
 | 
			
		||||
//            }
 | 
			
		||||
 | 
			
		||||
            rank = skills.get(skill);
 | 
			
		||||
            sender.sendMessage(LocaleLoader.getString("Commands.mcrank.Skill", skill.getLocalizedName(), (rank == null ? LocaleLoader.getString("Commands.mcrank.Unranked") : rank)));
 | 
			
		||||
            sender.sendMessage(LocaleLoader.getString("Commands.mcrank.Skill", skill.getName(), (rank == null ? LocaleLoader.getString("Commands.mcrank.Unranked") : rank)));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        rank = skills.get(null);
 | 
			
		||||
 
 | 
			
		||||
@@ -63,10 +63,10 @@ public class MctopCommandDisplayTask extends BukkitRunnable {
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
            if(sender instanceof Player) {
 | 
			
		||||
                sender.sendMessage(LocaleLoader.getString("Commands.Skill.Leaderboard", skill.getLocalizedName()));
 | 
			
		||||
                sender.sendMessage(LocaleLoader.getString("Commands.Skill.Leaderboard", skill.getName()));
 | 
			
		||||
            }
 | 
			
		||||
            else {
 | 
			
		||||
                sender.sendMessage(ChatColor.stripColor(LocaleLoader.getString("Commands.Skill.Leaderboard", skill.getLocalizedName())));
 | 
			
		||||
                sender.sendMessage(ChatColor.stripColor(LocaleLoader.getString("Commands.Skill.Leaderboard", skill.getName())));
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -56,8 +56,7 @@ public class ArcheryManager extends SkillManager {
 | 
			
		||||
    public double distanceXpBonusMultiplier(@NotNull LivingEntity target, @NotNull Entity arrow) {
 | 
			
		||||
        //Hacky Fix - some plugins spawn arrows and assign them to players after the ProjectileLaunchEvent fires
 | 
			
		||||
        if(!arrow.hasMetadata(mcMMO.arrowDistanceKey))
 | 
			
		||||
            return arrow.getLocation().distance(target.getLocation());
 | 
			
		||||
 | 
			
		||||
            return 1;
 | 
			
		||||
 | 
			
		||||
        Location firedLocation = (Location) arrow.getMetadata(mcMMO.arrowDistanceKey).get(0).value();
 | 
			
		||||
        Location targetLocation = target.getLocation();
 | 
			
		||||
 
 | 
			
		||||
@@ -265,7 +265,7 @@ public class FishingManager extends SkillManager {
 | 
			
		||||
            int convertedLureBonus = 0;
 | 
			
		||||
 | 
			
		||||
            //This avoids a Minecraft bug where lure levels above 3 break fishing
 | 
			
		||||
            if(lureLevel > 3) {
 | 
			
		||||
            if(lureLevel > 0) {
 | 
			
		||||
                masterAnglerCompatibilityLayer.setApplyLure(fishHook, false);
 | 
			
		||||
                convertedLureBonus = lureLevel * 100;
 | 
			
		||||
            }
 | 
			
		||||
 
 | 
			
		||||
@@ -37,7 +37,7 @@ public final class CommandRegistrationManager {
 | 
			
		||||
    private static void registerSkillCommands() {
 | 
			
		||||
        for (PrimarySkillType skill : PrimarySkillType.values()) {
 | 
			
		||||
            String commandName = skill.toString().toLowerCase(Locale.ENGLISH);
 | 
			
		||||
            String localizedName = skill.getLocalizedName().toLowerCase(Locale.ENGLISH);
 | 
			
		||||
            String localizedName = skill.getName().toLowerCase(Locale.ENGLISH);
 | 
			
		||||
 | 
			
		||||
            PluginCommand command;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -94,7 +94,7 @@ public class ScoreboardManager {
 | 
			
		||||
            int i = 0;
 | 
			
		||||
            for (PrimarySkillType type : PrimarySkillType.values()) {
 | 
			
		||||
                // Include child skills
 | 
			
		||||
                skillLabelBuilder.put(type, getShortenedName(colors.get(i) + type.getLocalizedName(), false));
 | 
			
		||||
                skillLabelBuilder.put(type, getShortenedName(colors.get(i) + type.getName(), false));
 | 
			
		||||
 | 
			
		||||
                if (type.getSuperAbilityType() != null) {
 | 
			
		||||
                    abilityLabelBuilder.put(type.getSuperAbilityType(), getShortenedName(colors.get(i) + type.getSuperAbilityType().getLocalizedName()));
 | 
			
		||||
@@ -116,7 +116,7 @@ public class ScoreboardManager {
 | 
			
		||||
        else {
 | 
			
		||||
            for (PrimarySkillType type : PrimarySkillType.values()) {
 | 
			
		||||
                // Include child skills
 | 
			
		||||
                skillLabelBuilder.put(type, getShortenedName(ChatColor.GREEN + type.getLocalizedName()));
 | 
			
		||||
                skillLabelBuilder.put(type, getShortenedName(ChatColor.GREEN + type.getName()));
 | 
			
		||||
 | 
			
		||||
                if (type.getSuperAbilityType() != null) {
 | 
			
		||||
                    abilityLabelBuilder.put(type.getSuperAbilityType(), formatAbility(type.getSuperAbilityType().getLocalizedName()));
 | 
			
		||||
 
 | 
			
		||||
@@ -24,16 +24,19 @@ import com.gmail.nossr50.util.compat.layers.persistentdata.AbstractPersistentDat
 | 
			
		||||
import com.gmail.nossr50.util.compat.layers.persistentdata.MobMetaFlagType;
 | 
			
		||||
import com.gmail.nossr50.util.player.NotificationManager;
 | 
			
		||||
import com.google.common.collect.ImmutableMap;
 | 
			
		||||
import org.bukkit.Bukkit;
 | 
			
		||||
import org.bukkit.GameMode;
 | 
			
		||||
import org.bukkit.Material;
 | 
			
		||||
import org.bukkit.attribute.Attribute;
 | 
			
		||||
import org.bukkit.attribute.AttributeInstance;
 | 
			
		||||
import org.bukkit.enchantments.Enchantment;
 | 
			
		||||
import org.bukkit.entity.*;
 | 
			
		||||
import org.bukkit.event.entity.EntityDamageByEntityEvent;
 | 
			
		||||
import org.bukkit.event.entity.EntityDamageEvent;
 | 
			
		||||
import org.bukkit.event.entity.EntityDamageEvent.DamageCause;
 | 
			
		||||
import org.bukkit.event.entity.EntityDamageEvent.DamageModifier;
 | 
			
		||||
import org.bukkit.inventory.ItemStack;
 | 
			
		||||
import org.bukkit.metadata.FixedMetadataValue;
 | 
			
		||||
import org.bukkit.metadata.MetadataValue;
 | 
			
		||||
import org.bukkit.potion.PotionEffectType;
 | 
			
		||||
import org.bukkit.projectiles.ProjectileSource;
 | 
			
		||||
@@ -288,6 +291,7 @@ public final class CombatUtils {
 | 
			
		||||
 | 
			
		||||
        //Make sure the profiles been loaded
 | 
			
		||||
        if(mmoPlayer == null) {
 | 
			
		||||
            cleanupArrowMetadata(arrow);
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -326,8 +330,10 @@ public final class CombatUtils {
 | 
			
		||||
                "Force Multiplier: "+forceMultiplier,
 | 
			
		||||
                "Initial Damage: "+initialDamage,
 | 
			
		||||
                "Final Damage: "+finalDamage);
 | 
			
		||||
 | 
			
		||||
        processCombatXP(mmoPlayer, target, PrimarySkillType.ARCHERY, distanceMultiplier);
 | 
			
		||||
 | 
			
		||||
        //Clean data
 | 
			
		||||
        cleanupArrowMetadata(arrow);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private static void processCrossbowCombat(LivingEntity target, Player player, EntityDamageByEntityEvent event, Projectile arrow) {
 | 
			
		||||
@@ -499,19 +505,22 @@ public final class CombatUtils {
 | 
			
		||||
 | 
			
		||||
                //Has metadata
 | 
			
		||||
                if(arrow.getMetadata(mcMMO.PROJECTILE_ORIGIN_METAKEY).size() > 0) {
 | 
			
		||||
                    if(isProjectileFromBow(arrow)) {
 | 
			
		||||
                        if(PrimarySkillType.ARCHERY.shouldProcess(target)) {
 | 
			
		||||
                    if (isProjectileFromBow(arrow)) {
 | 
			
		||||
                        if (PrimarySkillType.ARCHERY.shouldProcess(target)) {
 | 
			
		||||
                            if (!Misc.isNPCEntityExcludingVillagers(player) && PrimarySkillType.ARCHERY.getPermissions(player)) {
 | 
			
		||||
                                processArcheryCombat(target, player, event, arrow);
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                    } else if(isProjectileFromCrossbow(arrow)) {
 | 
			
		||||
                        if(PrimarySkillType.CROSSBOWS.shouldProcess(target)) {
 | 
			
		||||
                    } else if (isProjectileFromCrossbow(arrow)) {
 | 
			
		||||
                        if (PrimarySkillType.CROSSBOWS.shouldProcess(target)) {
 | 
			
		||||
                            if (!Misc.isNPCEntityExcludingVillagers(player) && PrimarySkillType.CROSSBOWS.getPermissions(player)) {
 | 
			
		||||
                                processCrossbowCombat(target, player, event, arrow);
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                } else {
 | 
			
		||||
                    //Cleanup Arrow
 | 
			
		||||
                    cleanupArrowMetadata(arrow);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                if (target.getType() != EntityType.CREEPER && !Misc.isNPCEntityExcludingVillagers(player) && PrimarySkillType.TAMING.getPermissions(player)) {
 | 
			
		||||
@@ -1122,4 +1131,32 @@ public final class CombatUtils {
 | 
			
		||||
            attributeInstance.setBaseValue(normalSpeed * multiplier);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Clean up metadata from a projectile
 | 
			
		||||
     *
 | 
			
		||||
     * @param entity projectile
 | 
			
		||||
     */
 | 
			
		||||
    public static void cleanupArrowMetadata(@NotNull Projectile entity) {
 | 
			
		||||
        if(entity.hasMetadata(mcMMO.infiniteArrowKey)) {
 | 
			
		||||
            entity.removeMetadata(mcMMO.infiniteArrowKey, mcMMO.p);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if(entity.hasMetadata(mcMMO.bowForceKey)) {
 | 
			
		||||
            entity.removeMetadata(mcMMO.bowForceKey, mcMMO.p);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if(entity.hasMetadata(mcMMO.arrowDistanceKey)) {
 | 
			
		||||
            entity.removeMetadata(mcMMO.arrowDistanceKey, mcMMO.p);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Clean up metadata from a projectile after a minute has passed
 | 
			
		||||
     *
 | 
			
		||||
     * @param entity the projectile
 | 
			
		||||
     */
 | 
			
		||||
    public static void delayArrowMetaCleanup(@NotNull Projectile entity) {
 | 
			
		||||
        Bukkit.getServer().getScheduler().runTaskLater(mcMMO.p, () -> { cleanupArrowMetadata(entity);}, 20*60);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,116 +1,116 @@
 | 
			
		||||
package com.gmail.nossr50.util.random;
 | 
			
		||||
 | 
			
		||||
import com.gmail.nossr50.datatypes.player.McMMOPlayer;
 | 
			
		||||
import com.gmail.nossr50.datatypes.skills.PrimarySkillType;
 | 
			
		||||
import com.gmail.nossr50.datatypes.skills.SubSkillType;
 | 
			
		||||
import com.gmail.nossr50.util.Permissions;
 | 
			
		||||
import com.gmail.nossr50.util.player.UserManager;
 | 
			
		||||
import org.bukkit.entity.Player;
 | 
			
		||||
import org.jetbrains.annotations.NotNull;
 | 
			
		||||
import org.junit.Assert;
 | 
			
		||||
import org.junit.Before;
 | 
			
		||||
import org.junit.Test;
 | 
			
		||||
import org.junit.runner.RunWith;
 | 
			
		||||
import org.mockito.Mockito;
 | 
			
		||||
import org.powermock.api.mockito.PowerMockito;
 | 
			
		||||
import org.powermock.core.classloader.annotations.PrepareForTest;
 | 
			
		||||
import org.powermock.modules.junit4.PowerMockRunner;
 | 
			
		||||
 | 
			
		||||
import static org.mockito.Mockito.mock;
 | 
			
		||||
 | 
			
		||||
//TODO: Rewrite the entire com.gmail.nossr50.util.random package, it was written in haste and it disgusts me
 | 
			
		||||
//TODO: Add more tests for the other types of random dice rolls
 | 
			
		||||
@RunWith(PowerMockRunner.class)
 | 
			
		||||
@PrepareForTest({RandomChanceUtil.class, UserManager.class})
 | 
			
		||||
public class RandomChanceTest {
 | 
			
		||||
 | 
			
		||||
    private Player luckyPlayer;
 | 
			
		||||
    private McMMOPlayer mmoPlayerLucky;
 | 
			
		||||
 | 
			
		||||
    private Player normalPlayer;
 | 
			
		||||
    private McMMOPlayer mmoPlayerNormal;
 | 
			
		||||
 | 
			
		||||
    private SubSkillType subSkillType;
 | 
			
		||||
    private PrimarySkillType primarySkillType;
 | 
			
		||||
 | 
			
		||||
    private final String testASCIIHeader = "---- mcMMO Tests ----";
 | 
			
		||||
 | 
			
		||||
    @Before
 | 
			
		||||
    public void setUpMock() {
 | 
			
		||||
        primarySkillType = PrimarySkillType.HERBALISM;
 | 
			
		||||
        subSkillType = SubSkillType.HERBALISM_GREEN_THUMB;
 | 
			
		||||
 | 
			
		||||
        //TODO: Likely needs to be changed per skill if more tests were added
 | 
			
		||||
        PowerMockito.stub(PowerMockito.method(RandomChanceUtil.class, "getMaximumProbability", subSkillType.getClass())).toReturn(100D);
 | 
			
		||||
        PowerMockito.stub(PowerMockito.method(RandomChanceUtil.class, "getMaxBonusLevelCap", subSkillType.getClass())).toReturn(1000D);
 | 
			
		||||
 | 
			
		||||
        normalPlayer = mock(Player.class);
 | 
			
		||||
        luckyPlayer = mock(Player.class);
 | 
			
		||||
 | 
			
		||||
        mmoPlayerNormal = mock(McMMOPlayer.class);
 | 
			
		||||
        mmoPlayerLucky = mock(McMMOPlayer.class);
 | 
			
		||||
 | 
			
		||||
        PowerMockito.mockStatic(UserManager.class);
 | 
			
		||||
        Mockito.when(UserManager.getPlayer(normalPlayer)).thenReturn(mmoPlayerNormal);
 | 
			
		||||
        Mockito.when(UserManager.getPlayer(luckyPlayer)).thenReturn(mmoPlayerLucky);
 | 
			
		||||
 | 
			
		||||
        Mockito.when(mmoPlayerNormal.getPlayer()).thenReturn(normalPlayer);
 | 
			
		||||
        Mockito.when(mmoPlayerLucky.getPlayer()).thenReturn(luckyPlayer);
 | 
			
		||||
 | 
			
		||||
        //Lucky player has the lucky permission
 | 
			
		||||
        //Normal player doesn't have any lucky permission
 | 
			
		||||
        Mockito.when(Permissions.lucky(luckyPlayer, primarySkillType)).thenReturn(true);
 | 
			
		||||
        Mockito.when(Permissions.lucky(normalPlayer, primarySkillType)).thenReturn(false);
 | 
			
		||||
 | 
			
		||||
        Mockito.when(mmoPlayerNormal.getSkillLevel(primarySkillType)).thenReturn(800);
 | 
			
		||||
        Mockito.when(mmoPlayerLucky.getSkillLevel(primarySkillType)).thenReturn(800);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testLuckyChance() {
 | 
			
		||||
        System.out.println(testASCIIHeader);
 | 
			
		||||
        System.out.println("Testing success odds to fall within expected values...");
 | 
			
		||||
        assertEquals(80D, getSuccessChance(mmoPlayerNormal),0D);
 | 
			
		||||
        assertEquals(80D * RandomChanceUtil.LUCKY_MODIFIER, getSuccessChance(mmoPlayerLucky),0D);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testNeverFailsSuccessLuckyPlayer() {
 | 
			
		||||
        System.out.println(testASCIIHeader);
 | 
			
		||||
        System.out.println("Test - Lucky Player with 80% base success should never fail (10,000 iterations)");
 | 
			
		||||
        for(int x = 0; x < 10000; x++) {
 | 
			
		||||
            Assert.assertTrue(RandomChanceUtil.checkRandomChanceExecutionSuccess(luckyPlayer, SubSkillType.HERBALISM_GREEN_THUMB, true));
 | 
			
		||||
            if(x == 10000-1)
 | 
			
		||||
                System.out.println("They never failed!");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testFailsAboutExpected() {
 | 
			
		||||
        System.out.println(testASCIIHeader);
 | 
			
		||||
        System.out.println("Test - Player with 800 skill should fail about 20% of the time (100,000 iterations)");
 | 
			
		||||
        double ratioDivisor = 1000; //1000 because we run the test 100,000 times
 | 
			
		||||
        double expectedFailRate = 20D;
 | 
			
		||||
 | 
			
		||||
        double win = 0, loss = 0;
 | 
			
		||||
        for(int x = 0; x < 100000; x++) {
 | 
			
		||||
            if(RandomChanceUtil.checkRandomChanceExecutionSuccess(normalPlayer, SubSkillType.HERBALISM_GREEN_THUMB, true)) {
 | 
			
		||||
                win++;
 | 
			
		||||
            } else {
 | 
			
		||||
                loss++;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        double lossRatio = (loss / ratioDivisor);
 | 
			
		||||
        Assert.assertEquals(lossRatio, expectedFailRate, 1D);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private double getSuccessChance(@NotNull McMMOPlayer mmoPlayer) {
 | 
			
		||||
        RandomChanceSkill randomChanceSkill = new RandomChanceSkill(mmoPlayer.getPlayer(), subSkillType, true);
 | 
			
		||||
        return RandomChanceUtil.calculateChanceOfSuccess(randomChanceSkill);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void assertEquals(double expected, double actual, double delta) {
 | 
			
		||||
        Assert.assertEquals(expected, actual, delta);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
//package com.gmail.nossr50.util.random;
 | 
			
		||||
//
 | 
			
		||||
//import com.gmail.nossr50.datatypes.player.McMMOPlayer;
 | 
			
		||||
//import com.gmail.nossr50.datatypes.skills.PrimarySkillType;
 | 
			
		||||
//import com.gmail.nossr50.datatypes.skills.SubSkillType;
 | 
			
		||||
//import com.gmail.nossr50.util.Permissions;
 | 
			
		||||
//import com.gmail.nossr50.util.player.UserManager;
 | 
			
		||||
//import org.bukkit.entity.Player;
 | 
			
		||||
//import org.jetbrains.annotations.NotNull;
 | 
			
		||||
//import org.junit.Assert;
 | 
			
		||||
//import org.junit.Before;
 | 
			
		||||
//import org.junit.Test;
 | 
			
		||||
//import org.junit.runner.RunWith;
 | 
			
		||||
//import org.mockito.Mockito;
 | 
			
		||||
//import org.powermock.api.mockito.PowerMockito;
 | 
			
		||||
//import org.powermock.core.classloader.annotations.PrepareForTest;
 | 
			
		||||
//import org.powermock.modules.junit4.PowerMockRunner;
 | 
			
		||||
//
 | 
			
		||||
//import static org.mockito.Mockito.mock;
 | 
			
		||||
//
 | 
			
		||||
////TODO: Rewrite the entire com.gmail.nossr50.util.random package, it was written in haste and it disgusts me
 | 
			
		||||
////TODO: Add more tests for the other types of random dice rolls
 | 
			
		||||
//@RunWith(PowerMockRunner.class)
 | 
			
		||||
//@PrepareForTest({RandomChanceUtil.class, UserManager.class})
 | 
			
		||||
//public class RandomChanceTest {
 | 
			
		||||
//
 | 
			
		||||
//    private Player luckyPlayer;
 | 
			
		||||
//    private McMMOPlayer mmoPlayerLucky;
 | 
			
		||||
//
 | 
			
		||||
//    private Player normalPlayer;
 | 
			
		||||
//    private McMMOPlayer mmoPlayerNormal;
 | 
			
		||||
//
 | 
			
		||||
//    private SubSkillType subSkillType;
 | 
			
		||||
//    private PrimarySkillType primarySkillType;
 | 
			
		||||
//
 | 
			
		||||
//    private final String testASCIIHeader = "---- mcMMO Tests ----";
 | 
			
		||||
//
 | 
			
		||||
//    @Before
 | 
			
		||||
//    public void setUpMock() {
 | 
			
		||||
//        primarySkillType = PrimarySkillType.HERBALISM;
 | 
			
		||||
//        subSkillType = SubSkillType.HERBALISM_GREEN_THUMB;
 | 
			
		||||
//
 | 
			
		||||
//        //TODO: Likely needs to be changed per skill if more tests were added
 | 
			
		||||
//        PowerMockito.stub(PowerMockito.method(RandomChanceUtil.class, "getMaximumProbability", subSkillType.getClass())).toReturn(100D);
 | 
			
		||||
//        PowerMockito.stub(PowerMockito.method(RandomChanceUtil.class, "getMaxBonusLevelCap", subSkillType.getClass())).toReturn(1000D);
 | 
			
		||||
//
 | 
			
		||||
//        normalPlayer = mock(Player.class);
 | 
			
		||||
//        luckyPlayer = mock(Player.class);
 | 
			
		||||
//
 | 
			
		||||
//        mmoPlayerNormal = mock(McMMOPlayer.class);
 | 
			
		||||
//        mmoPlayerLucky = mock(McMMOPlayer.class);
 | 
			
		||||
//
 | 
			
		||||
//        PowerMockito.mockStatic(UserManager.class);
 | 
			
		||||
//        Mockito.when(UserManager.getPlayer(normalPlayer)).thenReturn(mmoPlayerNormal);
 | 
			
		||||
//        Mockito.when(UserManager.getPlayer(luckyPlayer)).thenReturn(mmoPlayerLucky);
 | 
			
		||||
//
 | 
			
		||||
//        Mockito.when(mmoPlayerNormal.getPlayer()).thenReturn(normalPlayer);
 | 
			
		||||
//        Mockito.when(mmoPlayerLucky.getPlayer()).thenReturn(luckyPlayer);
 | 
			
		||||
//
 | 
			
		||||
//        //Lucky player has the lucky permission
 | 
			
		||||
//        //Normal player doesn't have any lucky permission
 | 
			
		||||
//        Mockito.when(Permissions.lucky(luckyPlayer, primarySkillType)).thenReturn(true);
 | 
			
		||||
//        Mockito.when(Permissions.lucky(normalPlayer, primarySkillType)).thenReturn(false);
 | 
			
		||||
//
 | 
			
		||||
//        Mockito.when(mmoPlayerNormal.getSkillLevel(primarySkillType)).thenReturn(800);
 | 
			
		||||
//        Mockito.when(mmoPlayerLucky.getSkillLevel(primarySkillType)).thenReturn(800);
 | 
			
		||||
//    }
 | 
			
		||||
//
 | 
			
		||||
//    @Test
 | 
			
		||||
//    public void testLuckyChance() {
 | 
			
		||||
//        System.out.println(testASCIIHeader);
 | 
			
		||||
//        System.out.println("Testing success odds to fall within expected values...");
 | 
			
		||||
//        assertEquals(80D, getSuccessChance(mmoPlayerNormal),0D);
 | 
			
		||||
//        assertEquals(80D * RandomChanceUtil.LUCKY_MODIFIER, getSuccessChance(mmoPlayerLucky),0D);
 | 
			
		||||
//    }
 | 
			
		||||
//
 | 
			
		||||
//    @Test
 | 
			
		||||
//    public void testNeverFailsSuccessLuckyPlayer() {
 | 
			
		||||
//        System.out.println(testASCIIHeader);
 | 
			
		||||
//        System.out.println("Test - Lucky Player with 80% base success should never fail (10,000 iterations)");
 | 
			
		||||
//        for(int x = 0; x < 10000; x++) {
 | 
			
		||||
//            Assert.assertTrue(RandomChanceUtil.checkRandomChanceExecutionSuccess(luckyPlayer, SubSkillType.HERBALISM_GREEN_THUMB, true));
 | 
			
		||||
//            if(x == 10000-1)
 | 
			
		||||
//                System.out.println("They never failed!");
 | 
			
		||||
//        }
 | 
			
		||||
//    }
 | 
			
		||||
//
 | 
			
		||||
//    @Test
 | 
			
		||||
//    public void testFailsAboutExpected() {
 | 
			
		||||
//        System.out.println(testASCIIHeader);
 | 
			
		||||
//        System.out.println("Test - Player with 800 skill should fail about 20% of the time (100,000 iterations)");
 | 
			
		||||
//        double ratioDivisor = 1000; //1000 because we run the test 100,000 times
 | 
			
		||||
//        double expectedFailRate = 20D;
 | 
			
		||||
//
 | 
			
		||||
//        double win = 0, loss = 0;
 | 
			
		||||
//        for(int x = 0; x < 100000; x++) {
 | 
			
		||||
//            if(RandomChanceUtil.checkRandomChanceExecutionSuccess(normalPlayer, SubSkillType.HERBALISM_GREEN_THUMB, true)) {
 | 
			
		||||
//                win++;
 | 
			
		||||
//            } else {
 | 
			
		||||
//                loss++;
 | 
			
		||||
//            }
 | 
			
		||||
//        }
 | 
			
		||||
//
 | 
			
		||||
//        double lossRatio = (loss / ratioDivisor);
 | 
			
		||||
//        Assert.assertEquals(lossRatio, expectedFailRate, 1D);
 | 
			
		||||
//    }
 | 
			
		||||
//
 | 
			
		||||
//    private double getSuccessChance(@NotNull McMMOPlayer mmoPlayer) {
 | 
			
		||||
//        RandomChanceSkill randomChanceSkill = new RandomChanceSkill(mmoPlayer.getPlayer(), subSkillType, true);
 | 
			
		||||
//        return RandomChanceUtil.calculateChanceOfSuccess(randomChanceSkill);
 | 
			
		||||
//    }
 | 
			
		||||
//
 | 
			
		||||
//    private void assertEquals(double expected, double actual, double delta) {
 | 
			
		||||
//        Assert.assertEquals(expected, actual, delta);
 | 
			
		||||
//    }
 | 
			
		||||
//}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user