diff --git a/pom.xml b/pom.xml index 9f954ed..d2fdcd3 100644 --- a/pom.xml +++ b/pom.xml @@ -35,6 +35,10 @@ vault-repo https://nexus.hc.to/content/repositories/pub_releases + + papermc + https://repo.papermc.io/repository/maven-public/ + @@ -86,6 +90,18 @@ 1.0-SNAPSHOT compile + + org.junit.jupiter + junit-jupiter + 5.9.2 + test + + + com.github.seeseemelk + MockBukkit-v1.19 + 2.144.3 + test + diff --git a/src/main/java/net/knarcraft/blacksmith/BlacksmithPlugin.java b/src/main/java/net/knarcraft/blacksmith/BlacksmithPlugin.java index 669d591..8832c66 100644 --- a/src/main/java/net/knarcraft/blacksmith/BlacksmithPlugin.java +++ b/src/main/java/net/knarcraft/blacksmith/BlacksmithPlugin.java @@ -19,9 +19,12 @@ import net.knarcraft.knarlib.formatting.Translator; import net.knarcraft.knarlib.util.UpdateChecker; import org.bukkit.command.PluginCommand; import org.bukkit.configuration.file.FileConfiguration; +import org.bukkit.plugin.PluginDescriptionFile; import org.bukkit.plugin.PluginManager; import org.bukkit.plugin.java.JavaPlugin; +import org.bukkit.plugin.java.JavaPluginLoader; +import java.io.File; import java.util.logging.Level; /** @@ -34,6 +37,22 @@ public class BlacksmithPlugin extends JavaPlugin { private static Translator translator; private static StringFormatter stringFormatter; + /** + * Constructor required for MockBukkit + */ + @SuppressWarnings("unused") + public BlacksmithPlugin() { + super(); + } + + /** + * Constructor required for MockBukkit + */ + @SuppressWarnings("unused") + protected BlacksmithPlugin(JavaPluginLoader loader, PluginDescriptionFile descriptionFile, File dataFolder, File file) { + super(loader, descriptionFile, dataFolder, file); + } + /** * Gets an instance of the Blacksmith plugin * diff --git a/src/main/java/net/knarcraft/blacksmith/config/NPCSettings.java b/src/main/java/net/knarcraft/blacksmith/config/NPCSettings.java index c42a701..885381e 100644 --- a/src/main/java/net/knarcraft/blacksmith/config/NPCSettings.java +++ b/src/main/java/net/knarcraft/blacksmith/config/NPCSettings.java @@ -2,9 +2,9 @@ package net.knarcraft.blacksmith.config; import net.citizensnpcs.api.util.DataKey; import net.knarcraft.blacksmith.BlacksmithPlugin; -import net.knarcraft.blacksmith.trait.BlacksmithTrait; import net.knarcraft.blacksmith.util.ConfigHelper; import net.knarcraft.blacksmith.util.InputParsingHelper; +import net.knarcraft.blacksmith.util.ItemHelper; import org.bukkit.Material; import org.bukkit.enchantments.Enchantment; import org.bukkit.inventory.ItemStack; @@ -460,7 +460,7 @@ public class NPCSettings { } Material material = InputParsingHelper.matchMaterial(item); - if (material != null && BlacksmithTrait.isRepairable(new ItemStack(material, 1))) { + if (material != null && ItemHelper.isRepairable(new ItemStack(material, 1))) { if (!blacklist) { reforgeAbleItems.add(material); } else { diff --git a/src/main/java/net/knarcraft/blacksmith/trait/BlacksmithTrait.java b/src/main/java/net/knarcraft/blacksmith/trait/BlacksmithTrait.java index 7eb1713..51d8f3a 100644 --- a/src/main/java/net/knarcraft/blacksmith/trait/BlacksmithTrait.java +++ b/src/main/java/net/knarcraft/blacksmith/trait/BlacksmithTrait.java @@ -11,11 +11,9 @@ import net.knarcraft.blacksmith.util.ItemHelper; import net.knarcraft.knarlib.formatting.StringFormatter; import org.bukkit.Bukkit; import org.bukkit.Material; -import org.bukkit.enchantments.EnchantmentTarget; import org.bukkit.entity.LivingEntity; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; -import org.bukkit.inventory.meta.Damageable; import java.util.Calendar; import java.util.HashMap; @@ -180,7 +178,7 @@ public class BlacksmithTrait extends Trait { //Refuse if not repairable, or if reforge-able items is set, but doesn't include the held item List reforgeAbleItems = config.getReforgeAbleItems(); if ((!this.config.getRepairAnvils() || !ItemHelper.isAnvil(hand.getType(), false)) && - (!isRepairable(hand) || (!reforgeAbleItems.isEmpty() && !reforgeAbleItems.contains(hand.getType())))) { + (!ItemHelper.isRepairable(hand) || (!reforgeAbleItems.isEmpty() && !reforgeAbleItems.contains(hand.getType())))) { String invalidMessage = StringFormatter.replacePlaceholder(config.getInvalidItemMessage(), "{title}", config.getBlacksmithTitle()); sendNPCMessage(this.npc, player, invalidMessage); @@ -225,14 +223,4 @@ public class BlacksmithTrait extends Trait { player.getInventory().setItemInMainHand(null); } - /** - * Gets whether the given item is repairable - * - * @param item

The item to check

- * @return

True if the item is repairable

- */ - public static boolean isRepairable(ItemStack item) { - return item.getItemMeta() instanceof Damageable && EnchantmentTarget.BREAKABLE.includes(item); - } - } diff --git a/src/main/java/net/knarcraft/blacksmith/util/ItemHelper.java b/src/main/java/net/knarcraft/blacksmith/util/ItemHelper.java index 4010b30..6d604c4 100644 --- a/src/main/java/net/knarcraft/blacksmith/util/ItemHelper.java +++ b/src/main/java/net/knarcraft/blacksmith/util/ItemHelper.java @@ -17,6 +17,16 @@ public final class ItemHelper { } + /** + * Gets whether the given item is repairable + * + * @param item

The item to check

+ * @return

True if the item is repairable

+ */ + public static boolean isRepairable(ItemStack item) { + return item.getItemMeta() instanceof Damageable && EnchantmentTarget.BREAKABLE.includes(item); + } + /** * Gets the max durability of an item * diff --git a/src/main/java/net/knarcraft/blacksmith/util/SalvageHelper.java b/src/main/java/net/knarcraft/blacksmith/util/SalvageHelper.java index a3ac408..8ba5e83 100644 --- a/src/main/java/net/knarcraft/blacksmith/util/SalvageHelper.java +++ b/src/main/java/net/knarcraft/blacksmith/util/SalvageHelper.java @@ -1,8 +1,7 @@ package net.knarcraft.blacksmith.util; -import net.knarcraft.blacksmith.trait.BlacksmithTrait; -import org.bukkit.Bukkit; import org.bukkit.Material; +import org.bukkit.Server; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.Recipe; import org.bukkit.inventory.ShapedRecipe; @@ -24,17 +23,19 @@ public final class SalvageHelper { * *

Note: Only items craft-able in a crafting table are salvageable. Netherite gear is therefore not salvageable.

* - * @param salvagedItem

The item stack to salvage

+ * @param server

The server to get recipes from

+ * @param salvagedItem

The item stack to salvage

+ * @param ignoredSalvage

Any material which should not be returned as part of the salvage.

* @return

The items to return to the user, or null if not salvageable

*/ - public static List getSalvage(ItemStack salvagedItem) { + public static List getSalvage(Server server, ItemStack salvagedItem, List ignoredSalvage) { if (salvagedItem == null || salvagedItem.getAmount() < 1 || - !BlacksmithTrait.isRepairable(salvagedItem)) { + !ItemHelper.isRepairable(salvagedItem)) { return null; } - for (Recipe recipe : Bukkit.getServer().getRecipesFor(salvagedItem)) { - List salvage = getRecipeSalvage(recipe, salvagedItem); + for (Recipe recipe : server.getRecipesFor(salvagedItem)) { + List salvage = getRecipeSalvage(recipe, salvagedItem, ignoredSalvage); if (salvage != null) { return salvage; } @@ -46,11 +47,13 @@ public final class SalvageHelper { /** * Gets the salvage resulting from the given recipe and the given item * - * @param recipe

The recipe to get salvage for

- * @param salvagedItem

The item to be salvaged

+ * @param recipe

The recipe to get salvage for

+ * @param salvagedItem

The item to be salvaged

+ * @param ignoredSalvage

Any material which should not be returned as part of the salvage.

* @return

A list of items, or null if not a valid type of recipe

*/ - private static List getRecipeSalvage(Recipe recipe, ItemStack salvagedItem) { + private static List getRecipeSalvage(Recipe recipe, ItemStack salvagedItem, + List ignoredSalvage) { List ingredients; if (recipe instanceof ShapedRecipe shapedRecipe) { ingredients = getIngredients(shapedRecipe); @@ -63,6 +66,11 @@ public final class SalvageHelper { //Make things easier by eliminating identical stacks ingredients = combineStacks(ingredients); + //Purge any ignored salvage to only calculate salvage using the remaining items + if (ignoredSalvage != null) { + ingredients.removeIf((item) -> ignoredSalvage.contains(item.getType())); + } + //Make sure to give salvage for all items if a stack > 1 is provided List salvage = new ArrayList<>(); for (int i = 0; i < salvagedItem.getAmount(); i++) { diff --git a/src/test/java/net/knarcraft/blacksmith/CustomServerMock.java b/src/test/java/net/knarcraft/blacksmith/CustomServerMock.java new file mode 100644 index 0000000..32b32fc --- /dev/null +++ b/src/test/java/net/knarcraft/blacksmith/CustomServerMock.java @@ -0,0 +1,31 @@ +package net.knarcraft.blacksmith; + +import be.seeseemelk.mockbukkit.ServerMock; +import org.bukkit.Material; +import org.bukkit.NamespacedKey; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.Recipe; +import org.bukkit.inventory.ShapedRecipe; +import org.jetbrains.annotations.NotNull; + +import java.util.ArrayList; +import java.util.List; + +/** + * A custom server mock specifically for making the SalvageHelperTest work + */ +public class CustomServerMock extends ServerMock { + + public @NotNull List getRecipesFor(@NotNull ItemStack itemStack) { + List validRecipes = new ArrayList<>(); + if (itemStack.getType() == Material.DIAMOND_PICKAXE) { + ShapedRecipe recipe = new ShapedRecipe(NamespacedKey.minecraft("diamond_pickaxe"), itemStack); + recipe.shape("ddd", "asa", "asa"); + recipe.setIngredient('d', Material.DIAMOND); + recipe.setIngredient('s', Material.STICK); + validRecipes.add(recipe); + } + return validRecipes; + } + +} diff --git a/src/test/java/net/knarcraft/blacksmith/util/SalvageHelperTest.java b/src/test/java/net/knarcraft/blacksmith/util/SalvageHelperTest.java new file mode 100644 index 0000000..3bd2391 --- /dev/null +++ b/src/test/java/net/knarcraft/blacksmith/util/SalvageHelperTest.java @@ -0,0 +1,76 @@ +package net.knarcraft.blacksmith.util; + +import be.seeseemelk.mockbukkit.MockBukkit; +import net.knarcraft.blacksmith.CustomServerMock; +import org.bukkit.Material; +import org.bukkit.Server; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.Damageable; +import org.bukkit.inventory.meta.ItemMeta; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertNull; + +/** + * A test class to test salvaging + */ +public class SalvageHelperTest { + + private static Server server; + + @BeforeAll + public static void setUp() { + server = MockBukkit.mock(new CustomServerMock()); + } + + @Test + public void getNullForInvalidItemTest() { + //Assert that a non-reforge-able item will return null + assertNull(SalvageHelper.getSalvage(server, new ItemStack(Material.POTATO, 1), null)); + } + + @Test + public void getNullForLessThanOneItemTest() { + //Assert that 0 or 1 items will return null + assertNull(SalvageHelper.getSalvage(server, new ItemStack(Material.IRON_AXE, 0), null)); + assertNull(SalvageHelper.getSalvage(server, new ItemStack(Material.IRON_SWORD, -1), null)); + } + + @Test + public void getFullSalvageTest() { + Set expectedSalvage = new HashSet<>(); + expectedSalvage.add(new ItemStack(Material.DIAMOND, 3)); + expectedSalvage.add(new ItemStack(Material.STICK, 2)); + ItemStack itemToSalvage = new ItemStack(Material.DIAMOND_PICKAXE, 1); + //Note: Conversion to sets makes sure the order doesn't matter + assertEquals(expectedSalvage, new HashSet<>(SalvageHelper.getSalvage(server, itemToSalvage, null))); + } + + @Test + public void getNonFullSalvageTest() { + List expectedSalvage = new ArrayList<>(); + expectedSalvage.add(new ItemStack(Material.DIAMOND, 3)); + expectedSalvage.add(new ItemStack(Material.STICK, 2)); + ItemStack itemToSalvage = new ItemStack(Material.DIAMOND_PICKAXE, 1); + ItemMeta meta = itemToSalvage.getItemMeta(); + Damageable damageable = (Damageable) meta; + if (damageable != null) { + damageable.setDamage(100); + } + itemToSalvage.setItemMeta(meta); + List salvage = SalvageHelper.getSalvage(server, itemToSalvage, null); + //Assert that some items are given + assertNotEquals(salvage, new ArrayList<>()); + //Assert that a damaged item won't give full salvage + assertNotEquals(expectedSalvage, salvage); + } + +}