Changes ignored salvage into trash salvage according to #22

This commit is contained in:
Kristian Knarvik 2024-05-05 18:02:12 +02:00
parent c71d664a79
commit 21d55563b7
6 changed files with 77 additions and 67 deletions

View File

@ -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)

View File

@ -25,7 +25,7 @@ public class GlobalScrapperSettings implements Settings<ScrapperSetting> {
private final Map<ScrapperSetting, Object> settings = new HashMap<>();
private final List<Material> defaultSalvageableMaterials = new ArrayList<>();
private final Map<Material, Set<Material>> ignoredSalvage = new HashMap<>();
private final Map<Material, Set<Material>> trashSalvage = new HashMap<>();
private final BlacksmithPlugin instance;
@ -144,7 +144,7 @@ public class GlobalScrapperSettings implements Settings<ScrapperSetting> {
}
}
loadSalvageAbleItems();
loadIgnoredSalvage();
loadTrashSalvage();
}
/**
@ -182,17 +182,17 @@ public class GlobalScrapperSettings implements Settings<ScrapperSetting> {
}
/**
* Gets ignored salvage for the given material
* Gets trash salvage for the given material
*
* <p>The ignored salvage should be ignored when calculating item salvage, in order to increase the probability of
* <p>The trash salvage should be deferred when calculating item salvage, in order to increase the probability of
* getting the more expensive materials back.</p>
*
* @param material <p>The material to get ignored salvage for</p>
* @return <p>The ignored salvage</p>
* @param material <p>The material to get trash salvage for</p>
* @return <p>The trash salvage</p>
*/
@Nullable
public Set<Material> getIgnoredSalvage(@NotNull Material material) {
return this.ignoredSalvage.get(material);
public Set<Material> getTrashSalvage(@NotNull Material material) {
return this.trashSalvage.get(material);
}
/**
@ -207,40 +207,40 @@ public class GlobalScrapperSettings implements Settings<ScrapperSetting> {
}
/**
* Loads all ignored salvage from the configuration file
* Loads all trash salvage from the configuration file
*/
private void loadIgnoredSalvage() {
this.ignoredSalvage.clear();
List<String> allIgnoredSalvage = ConfigHelper.asStringList(this.settings.get(ScrapperSetting.IGNORED_SALVAGE));
if (allIgnoredSalvage == null) {
private void loadTrashSalvage() {
this.trashSalvage.clear();
List<String> 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<Material> materials = new ArrayList<>();
for (String materialString : materialStrings) {
materials.addAll(ItemHelper.getWildcardMatch(materialString, true));
}
String[] ignoredSalvageStrings = data[1].split(";");
String[] trashSalvageStrings = data[1].split(";");
List<Material> 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);
}
}
}

View File

@ -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;

View File

@ -144,14 +144,14 @@ public class ScrapperTrait extends CustomTrait<ScrapperSetting> {
@Nullable
private List<ItemStack> 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<Material> ignoredSalvage = BlacksmithPlugin.getInstance().getGlobalScrapperSettings().getIgnoredSalvage(
Set<Material> 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);
}
}

View File

@ -61,14 +61,14 @@ public final class SalvageHelper {
*
* <p>Note: Only items craft-able in a crafting table are salvageable. Netherite gear is therefore not salvageable.</p>
*
* @param server <p>The server to get recipes from</p>
* @param salvagedItem <p>The item stack to salvage</p>
* @param ignoredSalvage <p>Any material which should not be returned as part of the salvage.</p>
* @param extended <p>Whether to enable extended salvage, ignoring the repairable restriction</p>
* @param server <p>The server to get recipes from</p>
* @param salvagedItem <p>The item stack to salvage</p>
* @param trashSalvage <p>Any material treated as trash salvage</p>
* @param extended <p>Whether to enable extended salvage, ignoring the repairable restriction</p>
* @return <p>The items to return to the user, or null if not salvageable</p>
*/
public static @Nullable List<ItemStack> getSalvage(@NotNull Server server, @Nullable ItemStack salvagedItem,
@NotNull Collection<Material> ignoredSalvage, boolean extended) {
@NotNull Collection<Material> 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<ItemStack> salvage = getRecipeSalvage(recipe, salvagedItem, ignoredSalvage);
List<ItemStack> 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 <p>The recipe to get salvage for</p>
* @param salvagedItem <p>The item to be salvaged</p>
* @param ignoredSalvage <p>Any material which should not be returned as part of the salvage.</p>
* @param recipe <p>The recipe to get salvage for</p>
* @param salvagedItem <p>The item to be salvaged</p>
* @param trashSalvage <p>Any material treated as trash salvage</p>
* @return <p>A list of items, or null if not a valid type of recipe</p>
*/
private static @Nullable List<ItemStack> getRecipeSalvage(@NotNull Recipe recipe, @NotNull ItemStack salvagedItem,
@NotNull Collection<Material> ignoredSalvage) {
@NotNull Collection<Material> trashSalvage) {
List<ItemStack> 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 <p>All items required for crafting the item to salvage</p>
* @param salvagedItem <p>The item to be salvaged</p>
* @param trashSalvage <p>The types of materials considered trash for this recipe</p>
* @return <p>The items to be returned to the user as salvage</p>
*/
@NotNull
private static List<ItemStack> getSalvage(@NotNull List<ItemStack> recipeItems,
@NotNull ItemStack salvagedItem) {
@NotNull ItemStack salvagedItem,
@NotNull Collection<Material> 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<ItemStack> goodItems = copyItems(recipeItems);
goodItems.removeIf((item) -> trashSalvage.contains(item.getType()));
int goodSalvage = totalItemAmount(goodItems);
List<ItemStack> 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));

View File

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