diff --git a/README.md b/README.md index 74de978..1c4bdc0 100644 --- a/README.md +++ b/README.md @@ -59,10 +59,10 @@ annoying: A scrapper will produce salvage for a damage-able item by calculating the amount of items returned based on items in the recipe, and the percentage of durability left on the item. To avoid returning relatively worthless items instead of -valuable items, `ignoredSalvage` can be configured. If the item is fully repaired, the worthless items will be returned -as well, but otherwise, only the valuable items are considered as possible salvage. A scrapper will by default only -salvage damage-able items (same as blacksmiths), but enabling `extendedSalvageEnabled` for a scrapper will allow it to -salvage any crafting table recipe. Note that to salvage for example planks into wood, four wood will be taken. +valuable items, `trashSalvage` can be configured. Trash salvage will only be returned if all non-trash items are +returned as well. A scrapper will by default only salvage damage-able items (same as blacksmiths), but enabling +`extendedSalvageEnabled` for a scrapper will allow it to salvage any crafting table recipe. Note that to salvage for +example planks into wood, four wood will be taken. When an item is salvaged, EXP will be returned based on enchantments on the item. @@ -213,12 +213,12 @@ All currently supported presets, and available filters for each preset: ### Scrapper global-only options -| Key | Value type | Description | -|----------------|----------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| basePrice | positive decimal number | The cost of using a scrapper | -| showExactTime | true/false | If true, scrappers will display exact time remaining in minutes and seconds, instead of vague expressions | -| giveExperience | true/false | If true, each enchantment level on the salvaged item will give one EXP level as salvage | -| ignoredSalvage | TARGET_MATERIAL:IGNORED_MATERIAL | The items that should be ignored when calculating partial salvage. Because receiving just the sticks when salvaging a diamond pickaxe is kind of sad, this allows specifying for example: `*_SHOVEL;*_PICKAXE;*_AXE;*_HOE;*_SWORD:STICK` (the default) for ignoring sticks in salvage for shovels, pickaxes, axes, hoes and swords. A `:` character splits selected items and the ignored salvage. Different item specifications are split by a `;` character. Use `,` to split separate ignored salvages, like: `SHIELD:STICK,BOW_STRING` | +| Key | Value type | Description | +|----------------|------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| basePrice | positive decimal number | The cost of using a scrapper | +| showExactTime | true/false | If true, scrappers will display exact time remaining in minutes and seconds, instead of vague expressions | +| giveExperience | true/false | If true, each enchantment level on the salvaged item will give one EXP level as salvage | +| trashSalvage | TARGET_MATERIAL:IGNORED_MATERIAL\[,\*_TARGET2:\*_IGNORED2] | The items that should be deferred when calculating partial salvage. Because receiving just the sticks when salvaging a diamond pickaxe is kind of sad, this allows specifying for example: `*_SHOVEL;*_PICKAXE;*_AXE;*_HOE;*_SWORD;SHIELD;*_BOW:STICK` (the default) for deferring sticks in salvage for shovels, pickaxes, axes, hoes and swords. A `:` character splits selected items and the trash salvage. Different item specifications are split by a `;` character. Use `,` to split separate trash salvages when using commands, like: `SHIELD:STICK,BOW_STRING` | ### Scrapper per-npc (with default values set in config.yml) diff --git a/src/main/java/net/knarcraft/blacksmith/config/scrapper/GlobalScrapperSettings.java b/src/main/java/net/knarcraft/blacksmith/config/scrapper/GlobalScrapperSettings.java index 80dcce9..cbc518c 100644 --- a/src/main/java/net/knarcraft/blacksmith/config/scrapper/GlobalScrapperSettings.java +++ b/src/main/java/net/knarcraft/blacksmith/config/scrapper/GlobalScrapperSettings.java @@ -25,7 +25,7 @@ public class GlobalScrapperSettings implements Settings { private final Map settings = new HashMap<>(); private final List defaultSalvageableMaterials = new ArrayList<>(); - private final Map> ignoredSalvage = new HashMap<>(); + private final Map> trashSalvage = new HashMap<>(); private final BlacksmithPlugin instance; @@ -144,7 +144,7 @@ public class GlobalScrapperSettings implements Settings { } } loadSalvageAbleItems(); - loadIgnoredSalvage(); + loadTrashSalvage(); } /** @@ -182,17 +182,17 @@ public class GlobalScrapperSettings implements Settings { } /** - * Gets ignored salvage for the given material + * Gets trash salvage for the given material * - *

The ignored salvage should be ignored when calculating item salvage, in order to increase the probability of + *

The trash salvage should be deferred when calculating item salvage, in order to increase the probability of * getting the more expensive materials back.

* - * @param material

The material to get ignored salvage for

- * @return

The ignored salvage

+ * @param material

The material to get trash salvage for

+ * @return

The trash salvage

*/ @Nullable - public Set getIgnoredSalvage(@NotNull Material material) { - return this.ignoredSalvage.get(material); + public Set getTrashSalvage(@NotNull Material material) { + return this.trashSalvage.get(material); } /** @@ -207,40 +207,40 @@ public class GlobalScrapperSettings implements Settings { } /** - * Loads all ignored salvage from the configuration file + * Loads all trash salvage from the configuration file */ - private void loadIgnoredSalvage() { - this.ignoredSalvage.clear(); - List allIgnoredSalvage = ConfigHelper.asStringList(this.settings.get(ScrapperSetting.IGNORED_SALVAGE)); - if (allIgnoredSalvage == null) { + private void loadTrashSalvage() { + this.trashSalvage.clear(); + List allTrashSalvage = ConfigHelper.asStringList(this.settings.get(ScrapperSetting.IGNORED_SALVAGE)); + if (allTrashSalvage == null) { return; } - for (String ignoredSalvageInfo : allIgnoredSalvage) { + for (String trashSalvageInfo : allTrashSalvage) { // Ignore invalid lines - if (!ignoredSalvageInfo.contains(":")) { - BlacksmithPlugin.getInstance().getLogger().log(Level.WARNING, String.format("The ignored salvage " + - "configuration line %s is invalid", ignoredSalvageInfo)); + if (!trashSalvageInfo.contains(":")) { + BlacksmithPlugin.getInstance().getLogger().log(Level.WARNING, String.format("The trash salvage " + + "configuration line %s is invalid", trashSalvageInfo)); continue; } // Parse all material names - String[] data = ignoredSalvageInfo.split(":"); + String[] data = trashSalvageInfo.split(":"); String[] materialStrings = data[0].split(";"); List materials = new ArrayList<>(); for (String materialString : materialStrings) { materials.addAll(ItemHelper.getWildcardMatch(materialString, true)); } - String[] ignoredSalvageStrings = data[1].split(";"); + String[] trashSalvageStrings = data[1].split(";"); List ignored = new ArrayList<>(); - for (String ignoredSalvageString : ignoredSalvageStrings) { - ignored.addAll(ItemHelper.getWildcardMatch(ignoredSalvageString, true)); + for (String trashSalvageString : trashSalvageStrings) { + ignored.addAll(ItemHelper.getWildcardMatch(trashSalvageString, true)); } - // Add the ignored salvage to all the matched materials + // Add the trash salvage to all the matched materials for (Material material : materials) { - ignoredSalvage.computeIfAbsent(material, k -> new HashSet<>()); - ignoredSalvage.get(material).addAll(ignored); + trashSalvage.computeIfAbsent(material, k -> new HashSet<>()); + trashSalvage.get(material).addAll(ignored); } } } diff --git a/src/main/java/net/knarcraft/blacksmith/config/scrapper/ScrapperSetting.java b/src/main/java/net/knarcraft/blacksmith/config/scrapper/ScrapperSetting.java index 3aaa42c..f694b70 100644 --- a/src/main/java/net/knarcraft/blacksmith/config/scrapper/ScrapperSetting.java +++ b/src/main/java/net/knarcraft/blacksmith/config/scrapper/ScrapperSetting.java @@ -194,13 +194,13 @@ public enum ScrapperSetting implements Setting { /** * Which items are ignored when calculating salvage for a given material */ - IGNORED_SALVAGE("ignoredSalvage", SettingValueType.STRING_LIST, - new ArrayList<>(List.of("*_SHOVEL;*_PICKAXE;*_AXE;*_HOE;*_SWORD:STICK")), - "Items ignored during salvage calculation. This follows the format: " + - "\"MATERIAL[,MATERIAL2][,MATERIAL3]:IGNORED\", so the material or materials listed will ignore " + - "the material specified after the \":\" when calculating salvage (* matches any character). This " + - "causes the player to lose some items during salvaging, but can prevent cases where a diamond " + - "pickaxe is salvaged and only sticks are returned.", false, false), + IGNORED_SALVAGE("trashSalvage", SettingValueType.STRING_LIST, + new ArrayList<>(List.of("*_SHOVEL;*_PICKAXE;*_AXE;*_HOE;*_SWORD;SHIELD;*_BOW:STICK")), + "Items treated as trash during salvage calculation. This follows the format: " + + "\"MATERIAL[;MATERIAL2][;MATERIAL3]:TRASH_MATERIAL[;TRASH_MATERIAL2]\", so the material or " + + "materials listed will treat the material specified after the \":\" as trash when calculating " + + "salvage unless all non-trash items can be given as well(* matches any character).", + false, false), ; private final String path; diff --git a/src/main/java/net/knarcraft/blacksmith/trait/ScrapperTrait.java b/src/main/java/net/knarcraft/blacksmith/trait/ScrapperTrait.java index 832f03c..436623a 100644 --- a/src/main/java/net/knarcraft/blacksmith/trait/ScrapperTrait.java +++ b/src/main/java/net/knarcraft/blacksmith/trait/ScrapperTrait.java @@ -144,14 +144,14 @@ public class ScrapperTrait extends CustomTrait { @Nullable private List getSalvage(@NotNull ItemStack item, boolean extended) { // Get the salvage, for the item, but ignore some materials if set, and the item isn't at full durability - Set ignoredSalvage = BlacksmithPlugin.getInstance().getGlobalScrapperSettings().getIgnoredSalvage( + Set trashSalvage = BlacksmithPlugin.getInstance().getGlobalScrapperSettings().getTrashSalvage( item.getType()); // Don't ignore salvage for fully repaired items - if (ignoredSalvage == null || ItemHelper.getDamage(item) == 0) { - ignoredSalvage = new HashSet<>(); + if (trashSalvage == null || ItemHelper.getDamage(item) == 0) { + trashSalvage = new HashSet<>(); } - return SalvageHelper.getSalvage(BlacksmithPlugin.getInstance().getServer(), item, ignoredSalvage, extended); + return SalvageHelper.getSalvage(BlacksmithPlugin.getInstance().getServer(), item, trashSalvage, extended); } } diff --git a/src/main/java/net/knarcraft/blacksmith/util/SalvageHelper.java b/src/main/java/net/knarcraft/blacksmith/util/SalvageHelper.java index 99b511a..4c9bf5b 100644 --- a/src/main/java/net/knarcraft/blacksmith/util/SalvageHelper.java +++ b/src/main/java/net/knarcraft/blacksmith/util/SalvageHelper.java @@ -61,14 +61,14 @@ public final class SalvageHelper { * *

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

* - * @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.

- * @param extended

Whether to enable extended salvage, ignoring the repairable restriction

+ * @param server

The server to get recipes from

+ * @param salvagedItem

The item stack to salvage

+ * @param trashSalvage

Any material treated as trash salvage

+ * @param extended

Whether to enable extended salvage, ignoring the repairable restriction

* @return

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

*/ public static @Nullable List getSalvage(@NotNull Server server, @Nullable ItemStack salvagedItem, - @NotNull Collection ignoredSalvage, boolean extended) { + @NotNull Collection trashSalvage, boolean extended) { if (salvagedItem == null || salvagedItem.getAmount() < 1 || (!extended && !ItemHelper.isRepairable(salvagedItem))) { return null; @@ -76,7 +76,7 @@ public final class SalvageHelper { for (Recipe recipe : server.getRecipesFor(new ItemStack(salvagedItem.getType(), salvagedItem.getAmount()))) { if (recipe instanceof ShapedRecipe || recipe instanceof ShapelessRecipe) { - List salvage = getRecipeSalvage(recipe, salvagedItem, ignoredSalvage); + List salvage = getRecipeSalvage(recipe, salvagedItem, trashSalvage); if (salvage != null && !salvage.isEmpty()) { return salvage; } @@ -89,13 +89,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 ignoredSalvage

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

+ * @param recipe

The recipe to get salvage for

+ * @param salvagedItem

The item to be salvaged

+ * @param trashSalvage

Any material treated as trash salvage

* @return

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

*/ private static @Nullable List getRecipeSalvage(@NotNull Recipe recipe, @NotNull ItemStack salvagedItem, - @NotNull Collection ignoredSalvage) { + @NotNull Collection trashSalvage) { List ingredients; if (recipe instanceof ShapedRecipe shapedRecipe) { ingredients = getIngredients(shapedRecipe); @@ -108,10 +108,7 @@ 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 - ingredients.removeIf((item) -> ignoredSalvage.contains(item.getType())); - - return combineStacks(getSalvage(copyItems(ingredients), salvagedItem)); + return combineStacks(getSalvage(copyItems(ingredients), salvagedItem, trashSalvage)); } /** @@ -135,11 +132,13 @@ public final class SalvageHelper { * * @param recipeItems

All items required for crafting the item to salvage

* @param salvagedItem

The item to be salvaged

+ * @param trashSalvage

The types of materials considered trash for this recipe

* @return

The items to be returned to the user as salvage

*/ @NotNull private static List getSalvage(@NotNull List recipeItems, - @NotNull ItemStack salvagedItem) { + @NotNull ItemStack salvagedItem, + @NotNull Collection trashSalvage) { int durability = ItemHelper.getDurability(salvagedItem); int maxDurability = ItemHelper.getMaxDurability(salvagedItem); @@ -156,16 +155,28 @@ public final class SalvageHelper { int itemsToReturn = (int) Math.floor(percentageRemaining * totalItems); int bound = recipeItems.size(); + List goodItems = copyItems(recipeItems); + goodItems.removeIf((item) -> trashSalvage.contains(item.getType())); + int goodSalvage = totalItemAmount(goodItems); + List salvage = new ArrayList<>(); for (int i = 0; i < itemsToReturn; i++) { + // Pick random item int itemIndex = SalvageHelper.random.nextInt(bound); ItemStack itemStack = recipeItems.get(itemIndex); + // The selected item is trash, so skip it + if (trashSalvage.contains(itemStack.getType()) && i < goodSalvage) { + i--; + continue; + } + //Make sure to never give more of one item than the amount which exists in the recipe if (itemStack.getAmount() <= 0) { i--; continue; } + itemStack.setAmount(itemStack.getAmount() - 1); salvage.add(new ItemStack(itemStack.getType(), 1)); diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index 37e7c4e..eac10e0 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -123,13 +123,12 @@ scrapper: # Whether enchanted salvaged items should return some amount of exp upon salvage giveExperience: true - # Items ignored during salvage calculation. This follows the format: - # "MATERIAL[;MATERIAL2][;MATERIAL3]:IGNORED_MATERIAL[;IGNORED_MATERIAL2]", - # so the material or materials listed will ignore the material specified after the ":" when calculating salvage - # (* matches any character). This causes the player to lose some items during salvaging, but can prevent cases - # where a diamond pickaxe is salvaged and only sticks are returned. - ignoredSalvage: - - "*_SHOVEL;*_PICKAXE;*_AXE;*_HOE;*_SWORD:STICK" + # Items treated as trash during salvage calculation. This follows the format: + # "MATERIAL[;MATERIAL2][;MATERIAL3]:TRASH_MATERIAL[;TRASH_MATERIAL2]", so the material or materials listed will + # treat the material specified after the ":" as trash when calculating salvage unless all non-trash items can be + # given as well(* matches any character). + trashSalvage: + - "*_SHOVEL;*_PICKAXE;*_AXE;*_HOE;*_SWORD;SHIELD;*_BOW:STICK" # The cost of using the scrapper basePrice: 0