Rewrites a lot of scrapper code to fix actual and potential bugs
	
		
			
	
		
	
	
		
	
		
			All checks were successful
		
		
	
	
		
			
				
	
				EpicKnarvik97/Blacksmith/pipeline/head This commit looks good
				
			
		
		
	
	
				
					
				
			
		
			All checks were successful
		
		
	
	EpicKnarvik97/Blacksmith/pipeline/head This commit looks good
				
			This commit is contained in:
		| @@ -0,0 +1,16 @@ | |||||||
|  | package net.knarcraft.blacksmith.container; | ||||||
|  |  | ||||||
|  | import org.bukkit.inventory.ItemStack; | ||||||
|  | import org.bukkit.inventory.Recipe; | ||||||
|  | import org.jetbrains.annotations.NotNull; | ||||||
|  |  | ||||||
|  | import java.util.List; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * The result of a recipe's salvage | ||||||
|  |  * | ||||||
|  |  * @param recipe  <p>The selected recipe</p> | ||||||
|  |  * @param salvage <p>The resulting salvage</p> | ||||||
|  |  */ | ||||||
|  | public record RecipeResult(@NotNull Recipe recipe, @NotNull List<ItemStack> salvage) { | ||||||
|  | } | ||||||
| @@ -7,6 +7,14 @@ import org.jetbrains.annotations.NotNull; | |||||||
|  |  | ||||||
| import java.util.List; | import java.util.List; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * The result of an attempted salvage | ||||||
|  |  * | ||||||
|  |  * @param salvageMethod  <p>The salvage method used</p> | ||||||
|  |  * @param salvage        <p>The produced salvage</p> | ||||||
|  |  * @param salvageState   <p>The state of the salvage result</p> | ||||||
|  |  * @param requiredAmount <p>The amount of items required for the salvage</p> | ||||||
|  |  */ | ||||||
| public record SalvageResult(@NotNull SalvageMethod salvageMethod, @NotNull List<ItemStack> salvage, | public record SalvageResult(@NotNull SalvageMethod salvageMethod, @NotNull List<ItemStack> salvage, | ||||||
|                             @NotNull SalvageState salvageState) { |                             @NotNull SalvageState salvageState, int requiredAmount) { | ||||||
| } | } | ||||||
|   | |||||||
| @@ -21,7 +21,7 @@ public class NPCClickListener implements Listener { | |||||||
|  |  | ||||||
|     @EventHandler |     @EventHandler | ||||||
|     public void onRightClick(@NotNull NPCRightClickEvent event) { |     public void onRightClick(@NotNull NPCRightClickEvent event) { | ||||||
|         //We only care about blacksmiths |         //We only care about blacksmiths and scrappers | ||||||
|         if (event.getNPC().hasTrait(BlacksmithTrait.class)) { |         if (event.getNPC().hasTrait(BlacksmithTrait.class)) { | ||||||
|             handleNPCClick(event, event.getNPC().getTraitNullable(BlacksmithTrait.class)); |             handleNPCClick(event, event.getNPC().getTraitNullable(BlacksmithTrait.class)); | ||||||
|         } else if (event.getNPC().hasTrait(ScrapperTrait.class)) { |         } else if (event.getNPC().hasTrait(ScrapperTrait.class)) { | ||||||
|   | |||||||
| @@ -7,7 +7,6 @@ import net.knarcraft.blacksmith.config.Settings; | |||||||
| import net.knarcraft.blacksmith.config.TraitSettings; | import net.knarcraft.blacksmith.config.TraitSettings; | ||||||
| import net.knarcraft.blacksmith.formatting.TimeFormatter; | import net.knarcraft.blacksmith.formatting.TimeFormatter; | ||||||
| import net.knarcraft.blacksmith.manager.EconomyManager; | import net.knarcraft.blacksmith.manager.EconomyManager; | ||||||
| import net.knarcraft.blacksmith.util.SalvageHelper; |  | ||||||
| import net.knarcraft.knarlib.formatting.StringFormatter; | import net.knarcraft.knarlib.formatting.StringFormatter; | ||||||
| import org.bukkit.entity.LivingEntity; | import org.bukkit.entity.LivingEntity; | ||||||
| import org.bukkit.entity.Player; | import org.bukkit.entity.Player; | ||||||
| @@ -196,9 +195,9 @@ public abstract class CustomTrait<K extends Setting> extends Trait { | |||||||
|             Objects.requireNonNull(((LivingEntity) npc.getEntity()).getEquipment()).setItemInMainHand(heldItem); |             Objects.requireNonNull(((LivingEntity) npc.getEntity()).getEquipment()).setItemInMainHand(heldItem); | ||||||
|         } |         } | ||||||
|         //Remove the item from the player's inventory |         //Remove the item from the player's inventory | ||||||
|         if (!isBlacksmith) { |         if (this.session instanceof SalvageSession salvageSession) { | ||||||
|             // For scrappers, just reduce the amounts of items, unless the remaining stack is salvaged |             // For scrappers, just reduce the amounts of items, unless the remaining stack is salvaged | ||||||
|             int amount = SalvageHelper.getRequiredAmountForSalvage(player.getServer(), heldItem); |             int amount = salvageSession.getItemsConsumed(); | ||||||
|             if (amount != heldItem.getAmount()) { |             if (amount != heldItem.getAmount()) { | ||||||
|                 heldItem.setAmount(heldItem.getAmount() - amount); |                 heldItem.setAmount(heldItem.getAmount() - amount); | ||||||
|                 playerInventory.setItemInMainHand(heldItem); |                 playerInventory.setItemInMainHand(heldItem); | ||||||
|   | |||||||
| @@ -20,6 +20,7 @@ import java.util.Calendar; | |||||||
| import java.util.List; | import java.util.List; | ||||||
| import java.util.Objects; | import java.util.Objects; | ||||||
| import java.util.Random; | import java.util.Random; | ||||||
|  | import java.util.logging.Level; | ||||||
|  |  | ||||||
| import static net.knarcraft.blacksmith.formatting.BlacksmithStringFormatter.sendNPCMessage; | import static net.knarcraft.blacksmith.formatting.BlacksmithStringFormatter.sendNPCMessage; | ||||||
|  |  | ||||||
| @@ -47,9 +48,9 @@ public class SalvageSession extends Session implements Runnable { | |||||||
|      * @param salvageMethod <p>The salvage method performed in this session</p> |      * @param salvageMethod <p>The salvage method performed in this session</p> | ||||||
|      * @param itemsConsumed <p>The number of items actually consumed, in case a salvaging fails</p> |      * @param itemsConsumed <p>The number of items actually consumed, in case a salvaging fails</p> | ||||||
|      */ |      */ | ||||||
|     SalvageSession(@NotNull ScrapperTrait scrapperTrait, @NotNull Player player, @NotNull NPC npc, |     public SalvageSession(@NotNull ScrapperTrait scrapperTrait, @NotNull Player player, @NotNull NPC npc, | ||||||
|                    @NotNull ScrapperNPCSettings config, @NotNull List<ItemStack> salvage, |                           @NotNull ScrapperNPCSettings config, @NotNull List<ItemStack> salvage, | ||||||
|                    @NotNull SalvageMethod salvageMethod, int itemsConsumed) { |                           @NotNull SalvageMethod salvageMethod, int itemsConsumed) { | ||||||
|         super(player, npc); |         super(player, npc); | ||||||
|         this.scrapperTrait = scrapperTrait; |         this.scrapperTrait = scrapperTrait; | ||||||
|         this.itemToSalvage = player.getInventory().getItemInMainHand().clone(); |         this.itemToSalvage = player.getInventory().getItemInMainHand().clone(); | ||||||
| @@ -110,6 +111,15 @@ public class SalvageSession extends Session implements Runnable { | |||||||
|         this.scrapperTrait.addCoolDown(this.player.getUniqueId(), wait); |         this.scrapperTrait.addCoolDown(this.player.getUniqueId(), wait); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Gets the number of items consumed in order to perform the salvage | ||||||
|  |      * | ||||||
|  |      * @return <p>The number of items consumed as part of this salvage</p> | ||||||
|  |      */ | ||||||
|  |     public int getItemsConsumed() { | ||||||
|  |         return this.itemsConsumed; | ||||||
|  |     } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * Trues to salvage an item, and gives the return item |      * Trues to salvage an item, and gives the return item | ||||||
|      */ |      */ | ||||||
| @@ -156,6 +166,7 @@ public class SalvageSession extends Session implements Runnable { | |||||||
|         // TODO: Find a better calculation than 1 enchantment level = 1 exp level |         // TODO: Find a better calculation than 1 enchantment level = 1 exp level | ||||||
|         // Gives the player back some of the EXP used on an item |         // Gives the player back some of the EXP used on an item | ||||||
|         this.player.giveExpLevels(this.enchantmentLevels); |         this.player.giveExpLevels(this.enchantmentLevels); | ||||||
|  |         BlacksmithPlugin.getInstance().getLogger().log(Level.INFO, "Giving salvage " + this.salvage); | ||||||
|         for (ItemStack item : this.salvage) { |         for (ItemStack item : this.salvage) { | ||||||
|             giveResultingItem(this.config.getMaxSalvageDelay() > 0, this.config.getDropItem(), this.npc, item); |             giveResultingItem(this.config.getMaxSalvageDelay() > 0, this.config.getDropItem(), this.npc, item); | ||||||
|         } |         } | ||||||
|   | |||||||
| @@ -6,6 +6,7 @@ import net.knarcraft.blacksmith.config.SmithPreset; | |||||||
| import net.knarcraft.blacksmith.config.SmithPresetFilter; | import net.knarcraft.blacksmith.config.SmithPresetFilter; | ||||||
| import net.knarcraft.blacksmith.config.scrapper.ScrapperNPCSettings; | import net.knarcraft.blacksmith.config.scrapper.ScrapperNPCSettings; | ||||||
| import net.knarcraft.blacksmith.config.scrapper.ScrapperSetting; | import net.knarcraft.blacksmith.config.scrapper.ScrapperSetting; | ||||||
|  | import net.knarcraft.blacksmith.container.RecipeResult; | ||||||
| import net.knarcraft.blacksmith.container.SalvageResult; | import net.knarcraft.blacksmith.container.SalvageResult; | ||||||
| import net.knarcraft.blacksmith.manager.EconomyManager; | import net.knarcraft.blacksmith.manager.EconomyManager; | ||||||
| import net.knarcraft.blacksmith.property.SalvageMethod; | import net.knarcraft.blacksmith.property.SalvageMethod; | ||||||
| @@ -26,6 +27,7 @@ import java.util.ArrayList; | |||||||
| import java.util.HashSet; | import java.util.HashSet; | ||||||
| import java.util.List; | import java.util.List; | ||||||
| import java.util.Set; | import java.util.Set; | ||||||
|  | import java.util.logging.Level; | ||||||
|  |  | ||||||
| import static net.knarcraft.blacksmith.formatting.BlacksmithStringFormatter.sendNPCMessage; | import static net.knarcraft.blacksmith.formatting.BlacksmithStringFormatter.sendNPCMessage; | ||||||
|  |  | ||||||
| @@ -91,35 +93,57 @@ public class ScrapperTrait extends CustomTrait<ScrapperSetting> { | |||||||
|         if (!canBeSalvaged(itemInHand, salvageAbleItems, extended)) { |         if (!canBeSalvaged(itemInHand, salvageAbleItems, extended)) { | ||||||
|             sendNPCMessage(this.npc, player, StringFormatter.replacePlaceholder(getSettings().getInvalidItemMessage(), |             sendNPCMessage(this.npc, player, StringFormatter.replacePlaceholder(getSettings().getInvalidItemMessage(), | ||||||
|                     "{title}", getSettings().getScrapperTitle())); |                     "{title}", getSettings().getScrapperTitle())); | ||||||
|  |             BlacksmithPlugin.getInstance().getLogger().log(Level.INFO, "Cannot salvage provided item: " + itemInHand); | ||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         List<ItemStack> salvage = null; |         SalvageResult result = getBestResult(player, itemInHand, extended); | ||||||
|         SalvageMethod salvageMethod = null; |  | ||||||
|  |  | ||||||
|         List<SalvageResult> results = List.of(isArmorTrimSalvage(player, itemInHand), |         if (result == null || result.salvage().isEmpty()) { | ||||||
|                 isNetheriteSalvage(player, itemInHand), isNormalSalvage(player, itemInHand, extended)); |  | ||||||
|  |  | ||||||
|         for (SalvageResult result : results) { |  | ||||||
|             if (result.salvageState() == SalvageState.NO_SALVAGE) { |  | ||||||
|                 // No salvage means that the method is correct, but something prevented useful salvage from being returned |  | ||||||
|                 return; |  | ||||||
|             } else if (result.salvageState() == SalvageState.FOUND_SALVAGE) { |  | ||||||
|                 // Successfully found useful salvage |  | ||||||
|                 salvage = result.salvage(); |  | ||||||
|                 salvageMethod = result.salvageMethod(); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|         if (salvage == null || salvage.isEmpty()) { |  | ||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         //Start a new scrapper session for the player |         //Start a new scrapper session for the player | ||||||
|         currentSessionStartTime = System.currentTimeMillis(); |         currentSessionStartTime = System.currentTimeMillis(); | ||||||
|         int itemsConsumed = SalvageHelper.getRequiredAmountForSalvage(player.getServer(), itemInHand); |         session = new SalvageSession(this, player, npc, getSettings(), result.salvage(), | ||||||
|         session = new SalvageSession(this, player, npc, getSettings(), salvage, salvageMethod, itemsConsumed); |                 result.salvageMethod(), result.requiredAmount()); | ||||||
|         // Print the cost to the player |         // Print the cost to the player | ||||||
|         printCostMessage(player, itemInHand, EconomyManager.formatSalvageCost(salvageMethod), salvageMethod); |         printCostMessage(player, itemInHand, EconomyManager.formatSalvageCost(result.salvageMethod()), | ||||||
|  |                 result.salvageMethod()); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Gets the best available salvage result | ||||||
|  |      * | ||||||
|  |      * @param player     <p>The player attempting to salvage an item</p> | ||||||
|  |      * @param itemInHand <p>The item the player is attempting to salvage</p> | ||||||
|  |      * @param extended   <p>Whether extended salvage is enabled</p> | ||||||
|  |      * @return <p>The best result, or null if no valid result exists</p> | ||||||
|  |      */ | ||||||
|  |     @Nullable | ||||||
|  |     private SalvageResult getBestResult(@NotNull Player player, @NotNull ItemStack itemInHand, boolean extended) { | ||||||
|  |         SalvageResult result = isArmorTrimSalvage(player, itemInHand); | ||||||
|  |         if (result.salvageState() == SalvageState.NO_SALVAGE) { | ||||||
|  |             return null; | ||||||
|  |         } else if (result.salvageState() == SalvageState.FOUND_SALVAGE) { | ||||||
|  |             return result; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         result = isNetheriteSalvage(player, itemInHand); | ||||||
|  |         if (result.salvageState() == SalvageState.NO_SALVAGE) { | ||||||
|  |             return null; | ||||||
|  |         } else if (result.salvageState() == SalvageState.FOUND_SALVAGE) { | ||||||
|  |             return result; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         result = isNormalSalvage(player, itemInHand, extended); | ||||||
|  |         if (result.salvageState() == SalvageState.NO_SALVAGE) { | ||||||
|  |             return null; | ||||||
|  |         } else if (result.salvageState() == SalvageState.FOUND_SALVAGE) { | ||||||
|  |             return result; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return null; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
| @@ -130,29 +154,32 @@ public class ScrapperTrait extends CustomTrait<ScrapperSetting> { | |||||||
|      * @param extended   <p>Whether extended salvage is enabled</p> |      * @param extended   <p>Whether extended salvage is enabled</p> | ||||||
|      * @return <p>The result of attempting the salvage</p> |      * @return <p>The result of attempting the salvage</p> | ||||||
|      */ |      */ | ||||||
|  |     @NotNull | ||||||
|     private SalvageResult isNormalSalvage(@NotNull Player player, @NotNull ItemStack itemInHand, boolean extended) { |     private SalvageResult isNormalSalvage(@NotNull Player player, @NotNull ItemStack itemInHand, boolean extended) { | ||||||
|  |  | ||||||
|         // As there is no recipe for netherite items, the check needs to be after the netherite salvage check |         // As there is no recipe for netherite items, the check needs to be after the netherite salvage check | ||||||
|         if (!SalvageHelper.isSalvageable(player.getServer(), itemInHand)) { |         if (!SalvageHelper.isSalvageable(player.getServer(), itemInHand)) { | ||||||
|             sendNPCMessage(this.npc, player, StringFormatter.replacePlaceholder(getSettings().getInvalidItemMessage(), |             sendNPCMessage(this.npc, player, StringFormatter.replacePlaceholder(getSettings().getInvalidItemMessage(), | ||||||
|                     "{title}", getSettings().getScrapperTitle())); |                     "{title}", getSettings().getScrapperTitle())); | ||||||
|             return new SalvageResult(SalvageMethod.SALVAGE, new ArrayList<>(), SalvageState.NO_SALVAGE); |             BlacksmithPlugin.getInstance().getLogger().log(Level.INFO, "Provided with non-salvage-able item " + itemInHand); | ||||||
|  |             return new SalvageResult(SalvageMethod.SALVAGE, new ArrayList<>(), SalvageState.NO_SALVAGE, 0); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         // Check if the item is enchanted, and whether this blacksmith can salvage it |         // Check if the item is enchanted, and whether this blacksmith can salvage it | ||||||
|         if (!itemInHand.getEnchantments().isEmpty() && !getSettings().salvageEnchanted()) { |         if (!itemInHand.getEnchantments().isEmpty() && !getSettings().salvageEnchanted()) { | ||||||
|             sendNPCMessage(this.npc, player, getSettings().getCannotSalvageEnchantedMessage()); |             sendNPCMessage(this.npc, player, getSettings().getCannotSalvageEnchantedMessage()); | ||||||
|             return new SalvageResult(SalvageMethod.SALVAGE, new ArrayList<>(), SalvageState.NO_SALVAGE); |             return new SalvageResult(SalvageMethod.SALVAGE, new ArrayList<>(), SalvageState.NO_SALVAGE, 0); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         // Check if any salvage will be produced |         // Check if any salvage will be produced | ||||||
|         List<ItemStack> salvage = getSalvage(itemInHand, extended); |         RecipeResult recipeResult = getSalvage(itemInHand, extended); | ||||||
|         boolean noUsefulSalvage = salvage == null || salvage.isEmpty(); |         boolean noUsefulSalvage = recipeResult == null || recipeResult.salvage().isEmpty(); | ||||||
|         if (noUsefulSalvage) { |         if (noUsefulSalvage) { | ||||||
|             sendNPCMessage(this.npc, player, getSettings().getTooDamagedMessage()); |             sendNPCMessage(this.npc, player, getSettings().getTooDamagedMessage()); | ||||||
|             return new SalvageResult(SalvageMethod.SALVAGE, new ArrayList<>(), SalvageState.NO_SALVAGE); |             return new SalvageResult(SalvageMethod.SALVAGE, new ArrayList<>(), SalvageState.NO_SALVAGE, 0); | ||||||
|         } else { |         } else { | ||||||
|             return new SalvageResult(SalvageMethod.SALVAGE, salvage, SalvageState.FOUND_SALVAGE); |             return new SalvageResult(SalvageMethod.SALVAGE, recipeResult.salvage(), SalvageState.FOUND_SALVAGE, | ||||||
|  |                     recipeResult.recipe().getResult().getAmount()); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -166,20 +193,20 @@ public class ScrapperTrait extends CustomTrait<ScrapperSetting> { | |||||||
|     @NotNull |     @NotNull | ||||||
|     private SalvageResult isNetheriteSalvage(@NotNull Player player, @NotNull ItemStack itemInHand) { |     private SalvageResult isNetheriteSalvage(@NotNull Player player, @NotNull ItemStack itemInHand) { | ||||||
|         if (!SmithPreset.BLACKSMITH.getFilteredMaterials(SmithPresetFilter.NETHERITE).contains(itemInHand.getType())) { |         if (!SmithPreset.BLACKSMITH.getFilteredMaterials(SmithPresetFilter.NETHERITE).contains(itemInHand.getType())) { | ||||||
|             return new SalvageResult(SalvageMethod.NETHERITE, new ArrayList<>(), SalvageState.INCORRECT_METHOD); |             return new SalvageResult(SalvageMethod.NETHERITE, new ArrayList<>(), SalvageState.INCORRECT_METHOD, 0); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         if (!getSettings().salvageNetherite()) { |         if (!getSettings().salvageNetherite()) { | ||||||
|             sendNPCMessage(this.npc, player, getSettings().getCannotSalvageNetheriteMessage()); |             sendNPCMessage(this.npc, player, getSettings().getCannotSalvageNetheriteMessage()); | ||||||
|             return new SalvageResult(SalvageMethod.NETHERITE, new ArrayList<>(), SalvageState.NO_SALVAGE); |             return new SalvageResult(SalvageMethod.NETHERITE, new ArrayList<>(), SalvageState.NO_SALVAGE, 0); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         List<ItemStack> salvage = SalvageHelper.getNetheriteSalvage(itemInHand); |         List<ItemStack> salvage = SalvageHelper.getNetheriteSalvage(itemInHand); | ||||||
|         if (salvage == null || salvage.isEmpty()) { |         if (salvage == null || salvage.isEmpty()) { | ||||||
|             return new SalvageResult(SalvageMethod.NETHERITE, new ArrayList<>(), SalvageState.NO_SALVAGE); |             return new SalvageResult(SalvageMethod.NETHERITE, new ArrayList<>(), SalvageState.NO_SALVAGE, 0); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         return new SalvageResult(SalvageMethod.NETHERITE, salvage, SalvageState.FOUND_SALVAGE); |         return new SalvageResult(SalvageMethod.NETHERITE, salvage, SalvageState.FOUND_SALVAGE, 1); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
| @@ -192,21 +219,21 @@ public class ScrapperTrait extends CustomTrait<ScrapperSetting> { | |||||||
|     @NotNull |     @NotNull | ||||||
|     private SalvageResult isArmorTrimSalvage(@NotNull Player player, @NotNull ItemStack itemInHand) { |     private SalvageResult isArmorTrimSalvage(@NotNull Player player, @NotNull ItemStack itemInHand) { | ||||||
|         if (!(itemInHand.getItemMeta() instanceof ArmorMeta armorMeta) || !armorMeta.hasTrim()) { |         if (!(itemInHand.getItemMeta() instanceof ArmorMeta armorMeta) || !armorMeta.hasTrim()) { | ||||||
|             return new SalvageResult(SalvageMethod.ARMOR_TRIM, new ArrayList<>(), SalvageState.INCORRECT_METHOD); |             return new SalvageResult(SalvageMethod.ARMOR_TRIM, new ArrayList<>(), SalvageState.INCORRECT_METHOD, 0); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         if (!getSettings().salvageArmorTrims()) { |         if (!getSettings().salvageArmorTrims()) { | ||||||
|             sendNPCMessage(this.npc, player, getSettings().getCannotSalvageArmorTrimMessage()); |             sendNPCMessage(this.npc, player, getSettings().getCannotSalvageArmorTrimMessage()); | ||||||
|             return new SalvageResult(SalvageMethod.ARMOR_TRIM, new ArrayList<>(), SalvageState.NO_SALVAGE); |             return new SalvageResult(SalvageMethod.ARMOR_TRIM, new ArrayList<>(), SalvageState.NO_SALVAGE, 0); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         List<ItemStack> salvage = SalvageHelper.getArmorTrimSalvage(itemInHand, armorMeta); |         List<ItemStack> salvage = SalvageHelper.getArmorTrimSalvage(itemInHand, armorMeta); | ||||||
|         if (salvage == null || salvage.isEmpty()) { |         if (salvage == null || salvage.isEmpty()) { | ||||||
|             sendNPCMessage(this.npc, player, getSettings().getArmorTrimSalvageNotFoundMessage()); |             sendNPCMessage(this.npc, player, getSettings().getArmorTrimSalvageNotFoundMessage()); | ||||||
|             return new SalvageResult(SalvageMethod.ARMOR_TRIM, new ArrayList<>(), SalvageState.NO_SALVAGE); |             return new SalvageResult(SalvageMethod.ARMOR_TRIM, new ArrayList<>(), SalvageState.NO_SALVAGE, 0); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         return new SalvageResult(SalvageMethod.ARMOR_TRIM, salvage, SalvageState.FOUND_SALVAGE); |         return new SalvageResult(SalvageMethod.ARMOR_TRIM, salvage, SalvageState.FOUND_SALVAGE, 1); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
| @@ -264,7 +291,7 @@ public class ScrapperTrait extends CustomTrait<ScrapperSetting> { | |||||||
|      * @return <p>The possible salvage, or null if not salvage-able</p> |      * @return <p>The possible salvage, or null if not salvage-able</p> | ||||||
|      */ |      */ | ||||||
|     @Nullable |     @Nullable | ||||||
|     private List<ItemStack> getSalvage(@NotNull ItemStack item, boolean extended) { |     private RecipeResult 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 |         // Get the salvage, for the item, but ignore some materials if set, and the item isn't at full durability | ||||||
|         Set<Material> trashSalvage = BlacksmithPlugin.getInstance().getGlobalScrapperSettings().getTrashSalvage( |         Set<Material> trashSalvage = BlacksmithPlugin.getInstance().getGlobalScrapperSettings().getTrashSalvage( | ||||||
|                 item.getType()); |                 item.getType()); | ||||||
|   | |||||||
| @@ -1,6 +1,7 @@ | |||||||
| package net.knarcraft.blacksmith.util; | package net.knarcraft.blacksmith.util; | ||||||
|  |  | ||||||
| import org.bukkit.Bukkit; | import net.knarcraft.blacksmith.BlacksmithPlugin; | ||||||
|  | import net.knarcraft.blacksmith.container.RecipeResult; | ||||||
| import org.bukkit.Material; | import org.bukkit.Material; | ||||||
| import org.bukkit.Server; | import org.bukkit.Server; | ||||||
| import org.bukkit.enchantments.Enchantment; | import org.bukkit.enchantments.Enchantment; | ||||||
| @@ -20,6 +21,7 @@ import java.util.HashMap; | |||||||
| import java.util.List; | import java.util.List; | ||||||
| import java.util.Map; | import java.util.Map; | ||||||
| import java.util.Random; | import java.util.Random; | ||||||
|  | import java.util.logging.Level; | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * A helper class for deciding the salvage returned if salvaging an item |  * A helper class for deciding the salvage returned if salvaging an item | ||||||
| @@ -123,23 +125,6 @@ public final class SalvageHelper { | |||||||
|         return false; |         return false; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** |  | ||||||
|      * Gets the amount of an item that's required to salvage that item |  | ||||||
|      * |  | ||||||
|      * @param server <p>The server to get recipes from</p> |  | ||||||
|      * @param item   <p>The item to check</p> |  | ||||||
|      * @return <p>The number of items required for salvage, or -1 if the recipe was not found</p> |  | ||||||
|      */ |  | ||||||
|     public static int getRequiredAmountForSalvage(@NotNull Server server, @NotNull ItemStack item) { |  | ||||||
|         for (Recipe recipe : server.getRecipesFor(new ItemStack(item.getType(), item.getAmount()))) { |  | ||||||
|             // Only crafting recipes are allowed. |  | ||||||
|             if (recipe instanceof ShapedRecipe || recipe instanceof ShapelessRecipe) { |  | ||||||
|                 return recipe.getResult().getAmount(); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|         return 1; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * Gets the sum of all enchantment levels for the given item |      * Gets the sum of all enchantment levels for the given item | ||||||
|      * |      * | ||||||
| @@ -165,28 +150,34 @@ public final class SalvageHelper { | |||||||
|      * @param extended     <p>Whether to enable extended salvage, ignoring the repairable restriction</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> |      * @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, |     public static @Nullable RecipeResult getSalvage(@NotNull Server server, @Nullable ItemStack salvagedItem, | ||||||
|                                                        @NotNull Collection<Material> trashSalvage, boolean extended) { |                                                     @NotNull Collection<Material> trashSalvage, boolean extended) { | ||||||
|         if (salvagedItem == null || salvagedItem.getAmount() < 1 || |         if (salvagedItem == null || salvagedItem.getAmount() < 1 || | ||||||
|                 (!extended && !ItemHelper.isRepairable(salvagedItem))) { |                 (!extended && !ItemHelper.isRepairable(salvagedItem))) { | ||||||
|             return null; |             return null; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         for (Recipe recipe : server.getRecipesFor(new ItemStack(salvagedItem.getType(), salvagedItem.getAmount()))) { |         for (Recipe recipe : server.getRecipesFor(new ItemStack(salvagedItem.getType(), salvagedItem.getAmount()))) { | ||||||
|  |             BlacksmithPlugin.getInstance().getLogger().log(Level.INFO, "Considering recipe: " + recipe.getResult() + " -> " + getRawRecipeSalvage(recipe)); | ||||||
|  |  | ||||||
|             // Only consider crafting table recipes |             // Only consider crafting table recipes | ||||||
|             if (!(recipe instanceof ShapedRecipe) && !(recipe instanceof ShapelessRecipe)) { |             if (!(recipe instanceof ShapedRecipe) && !(recipe instanceof ShapelessRecipe)) { | ||||||
|  |                 BlacksmithPlugin.getInstance().getLogger().log(Level.INFO, "Recipe had invalid type"); | ||||||
|                 continue; |                 continue; | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             // Make sure the player has enough items |             // Make sure the player has enough items | ||||||
|             if (salvagedItem.getAmount() < getRequiredAmountForSalvage(Bukkit.getServer(), salvagedItem)) { |             if (salvagedItem.getAmount() < recipe.getResult().getAmount()) { | ||||||
|  |                 BlacksmithPlugin.getInstance().getLogger().log(Level.INFO, "Too few items for recipe"); | ||||||
|                 continue; |                 continue; | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             // Get actual salvage, as long as any can be produced |             // Get actual salvage, as long as any can be produced | ||||||
|             List<ItemStack> salvage = getRecipeSalvage(recipe, salvagedItem, trashSalvage); |             List<ItemStack> salvage = getRecipeSalvage(recipe, salvagedItem, trashSalvage); | ||||||
|             if (salvage != null && !salvage.isEmpty()) { |             if (salvage != null && !salvage.isEmpty()) { | ||||||
|                 return salvage; |                 BlacksmithPlugin.getInstance().getLogger().log(Level.INFO, "Valid recipe: " + recipe.getResult() + " -> " + getRawRecipeSalvage(recipe)); | ||||||
|  |                 BlacksmithPlugin.getInstance().getLogger().log(Level.INFO, "Actual salvage: " + salvage); | ||||||
|  |                 return new RecipeResult(recipe, salvage); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  |  | ||||||
| @@ -207,7 +198,13 @@ public final class SalvageHelper { | |||||||
|         if (ingredients == null) { |         if (ingredients == null) { | ||||||
|             return null; |             return null; | ||||||
|         } |         } | ||||||
|         return combineStacks(getSalvage(copyItems(ingredients), salvagedItem, trashSalvage)); |         List<ItemStack> copy = copyItems(ingredients); | ||||||
|  |         BlacksmithPlugin.getInstance().getLogger().log(Level.INFO, "Copied salvage: " + copy); | ||||||
|  |         List<ItemStack> salvage = getSalvage(copy, salvagedItem, trashSalvage); | ||||||
|  |         BlacksmithPlugin.getInstance().getLogger().log(Level.INFO, "Combining salvage: " + salvage); | ||||||
|  |         List<ItemStack> combined = combineStacks(salvage); | ||||||
|  |         BlacksmithPlugin.getInstance().getLogger().log(Level.INFO, "Combined : " + combined); | ||||||
|  |         return combined; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
| @@ -247,7 +244,10 @@ public final class SalvageHelper { | |||||||
|             durability = 1; |             durability = 1; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |         BlacksmithPlugin.getInstance().getLogger().log(Level.INFO, "Durability: " + durability + "/" + maxDurability); | ||||||
|  |  | ||||||
|         double percentageRemaining = (double) durability / maxDurability; |         double percentageRemaining = (double) durability / maxDurability; | ||||||
|  |         BlacksmithPlugin.getInstance().getLogger().log(Level.INFO, "Remaining: " + percentageRemaining); | ||||||
|         return pickRandomSalvage(recipeItems, trashSalvage, percentageRemaining); |         return pickRandomSalvage(recipeItems, trashSalvage, percentageRemaining); | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -268,36 +268,47 @@ public final class SalvageHelper { | |||||||
|             percentageRemaining = 1; |             percentageRemaining = 1; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         int totalItems = totalItemAmount(itemsToChooseFrom); |         // If not damaged, just give everything | ||||||
|         //Get the amount of recipe items to be returned |         if (percentageRemaining == 1) { | ||||||
|         int itemsToReturn = (int) Math.floor(percentageRemaining * totalItems); |             BlacksmithPlugin.getInstance().getLogger().log(Level.INFO, "100% Remaining. Copying " + itemsToChooseFrom); | ||||||
|         int bound = itemsToChooseFrom.size(); |             return copyItems(itemsToChooseFrom); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // Split into good items and trash items | ||||||
|         List<ItemStack> goodItems = copyItems(itemsToChooseFrom); |         List<ItemStack> goodItems = copyItems(itemsToChooseFrom); | ||||||
|         goodItems.removeIf((item) -> trashSalvage.contains(item.getType())); |         goodItems.removeIf((item) -> trashSalvage.contains(item.getType())); | ||||||
|         int goodSalvage = totalItemAmount(goodItems); |         List<ItemStack> trashItems = copyItems(itemsToChooseFrom); | ||||||
|  |         trashItems.removeIf((item) -> !trashSalvage.contains(item.getType())); | ||||||
|  |  | ||||||
|         List<ItemStack> salvage = new ArrayList<>(); |         int itemsToReturn = (int) Math.floor(totalItemAmount(itemsToChooseFrom) * percentageRemaining); | ||||||
|         for (int i = 0; i < itemsToReturn; i++) { |         int goodItemAmount = totalItemAmount(goodItems); | ||||||
|             // Pick random item |         int pickedItems = 0; | ||||||
|             int itemIndex = SalvageHelper.random.nextInt(bound); |         List<ItemStack> salvage = new ArrayList<>(itemsToReturn); | ||||||
|             ItemStack itemStack = itemsToChooseFrom.get(itemIndex); |  | ||||||
|  |  | ||||||
|             // The selected item is trash, so skip it |         while (pickedItems < itemsToReturn && pickedItems < goodItemAmount) { | ||||||
|             if (trashSalvage.contains(itemStack.getType()) && i < goodSalvage) { |             int index = SalvageHelper.random.nextInt(goodItems.size()); | ||||||
|                 i--; |             ItemStack itemStack = goodItems.get(index); | ||||||
|  |             if (itemStack.getType().isAir() || itemStack.getAmount() == 0) { | ||||||
|                 continue; |                 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)); |             salvage.add(new ItemStack(itemStack.getType(), 1)); | ||||||
|  |             itemStack.setAmount(itemStack.getAmount() - 1); | ||||||
|  |             pickedItems++; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |         while (pickedItems < itemsToReturn) { | ||||||
|  |             int index = SalvageHelper.random.nextInt(trashItems.size()); | ||||||
|  |             ItemStack itemStack = trashItems.get(index); | ||||||
|  |             if (itemStack.getType().isAir() || itemStack.getAmount() == 0) { | ||||||
|  |                 continue; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             salvage.add(new ItemStack(itemStack.getType(), 1)); | ||||||
|  |             itemStack.setAmount(itemStack.getAmount() - 1); | ||||||
|  |             pickedItems++; | ||||||
|  |         } | ||||||
|  |  | ||||||
|         return salvage; |         return salvage; | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -328,7 +339,7 @@ public final class SalvageHelper { | |||||||
|         Map<Material, Integer> itemAmounts = new HashMap<>(); |         Map<Material, Integer> itemAmounts = new HashMap<>(); | ||||||
|         for (ItemStack item : items) { |         for (ItemStack item : items) { | ||||||
|             Material itemType = item.getType(); |             Material itemType = item.getType(); | ||||||
|             itemAmounts.put(itemType, itemAmounts.getOrDefault(itemType, 0) + 1); |             itemAmounts.put(itemType, itemAmounts.getOrDefault(itemType, 0) + item.getAmount()); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         List<ItemStack> combined = new ArrayList<>(); |         List<ItemStack> combined = new ArrayList<>(); | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user