Broken commit implementing a lot of book-splitting code
Some checks failed
EpicKnarvik97/Blacksmith/pipeline/head There was a failure building this commit

This commit is contained in:
Kristian Knarvik 2024-11-27 12:16:57 +01:00
parent 90d3c49c12
commit e3dbeccc14
11 changed files with 438 additions and 13 deletions

View File

@ -7,6 +7,7 @@ import net.knarcraft.blacksmith.util.ConfigHelper;
import net.knarcraft.blacksmith.util.ItemHelper; import net.knarcraft.blacksmith.util.ItemHelper;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.configuration.file.FileConfiguration; import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
@ -212,6 +213,42 @@ public class GlobalScrapperSettings implements Settings<ScrapperSetting> {
return asDouble(ScrapperSetting.NETHERITE_SALVAGE_COST); return asDouble(ScrapperSetting.NETHERITE_SALVAGE_COST);
} }
/**
* Gets the base cost of salvaging an enchanted book
*
* @return <p>The enchanted book salvage base cost</p>
*/
public double getEnchantedBookSalvageCost() {
return asDouble(ScrapperSetting.ENCHANTED_BOOK_SALVAGE_BASE_COST);
}
/**
* Gets the item cost of salvaging an enchanted book
*
* @return <p>The enchanted book salvage cost</p>
*/
public ItemStack getEnchantedBookItemCost() {
return ScrapperSetting.ENCHANTED_BOOK_SALVAGE_ITEM_COST;
}
/**
* Whether to multiply the cost of salvaging enchanted books based on the number of enchantments
*
* @return <p>Whether to multiply the cost of salvaging enchanted books based on the number of enchantments</p>
*/
public boolean multiplyEnchantedBookSalvageCost() {
return asBoolean(ScrapperSetting.ENCHANTED_BOOK_SALVAGE_MULTIPLY);
}
/**
* Whether to require both a monetary and item-based cost when salvaging enchanted books
*
* @return <p>Whether to require both a monetary and item-based cost when salvaging enchanted books</p>
*/
public boolean requireMoneyAndItemForEnchantedBookSalvage() {
return asBoolean(ScrapperSetting.ENCHANTED_BOOK_SALVAGE_REQUIRE_BOTH);
}
/** /**
* Gets trash salvage for the given material * Gets trash salvage for the given material
* *

View File

@ -83,6 +83,15 @@ public class ScrapperNPCSettings implements TraitSettings<ScrapperSetting> {
} }
} }
/**
* Gets whether this scrapper is able to split an enchanted book
*
* @return <p>True if this scrapper is able to split an enchanted book</p>
*/
public boolean splitEnchantedBook() {
return asBoolean(ScrapperSetting.SPLIT_ENCHANTED_BOOK);
}
/** /**
* Gets the raw current value of a setting * Gets the raw current value of a setting
* *
@ -171,6 +180,15 @@ public class ScrapperNPCSettings implements TraitSettings<ScrapperSetting> {
return asString(ScrapperSetting.COST_MESSAGE_NETHERITE); return asString(ScrapperSetting.COST_MESSAGE_NETHERITE);
} }
/**
* Gets the message to use for displaying enchanted book salvage cost
*
* @return <p>The message to use for displaying enchanted book salvage cost</p>
*/
public String getEnchantedBookCostMessage() {
return asString(ScrapperSetting.COST_MESSAGE_ENCHANTED_BOOK);
}
@Override @Override
@NotNull @NotNull
public String getCoolDownUnexpiredMessage() { public String getCoolDownUnexpiredMessage() {
@ -466,4 +484,34 @@ public class ScrapperNPCSettings implements TraitSettings<ScrapperSetting> {
return asString(ScrapperSetting.CANNOT_SALVAGE_NETHERITE_MESSAGE); return asString(ScrapperSetting.CANNOT_SALVAGE_NETHERITE_MESSAGE);
} }
/**
* Gets the message to display when explaining that this scrapper is unable to salvage enchanted books
*
* @return <p>The message to display when explaining that this scrapper is unable to salvage enchanted books</p>
*/
@NotNull
public String getCannotSalvageEnchantedBookMessage() {
return asString(ScrapperSetting.CANNOT_SALVAGE_ENCHANTED_BOOK_MESSAGE);
}
/**
* Gets the message to display when explaining that the scrapper needs to be provided more items for enchanted book salvage
*
* @return <p>The message to display when explaining that the scrapper needs to be provided more items for enchanted book salvage</p>
*/
@NotNull
public String getNotEnoughItemsMessage() {
return asString(ScrapperSetting.NOT_ENOUGH_ITEMS_MESSAGE);
}
/**
* Gets the message to display when explaining that the scrapper cannot salvage an enchanted book with a single enchantment
*
* @return <p>The message to display when explaining that the scrapper cannot salvage an enchanted book with a single enchantment</p>
*/
@NotNull
public String getCannotSplitEnchantedBookFurtherMessage() {
return asString(ScrapperSetting.CANNOT_SPLIT_ENCHANTED_BOOK_FURTHER_MESSAGE);
}
} }

View File

@ -91,6 +91,12 @@ public enum ScrapperSetting implements Setting {
*/ */
SALVAGE_NETHERITE("salvageNetherite", SettingValueType.BOOLEAN, true, SALVAGE_NETHERITE("salvageNetherite", SettingValueType.BOOLEAN, true,
"Whether to enable salvaging of netherite items", true, false), "Whether to enable salvaging of netherite items", true, false),
/**
* The setting for whether the NPC should allow salvaging an enchanted books with several enchantments into several books with one enchantment
*/
SPLIT_ENCHANTED_BOOK("splitEnchantedBook", SettingValueType.BOOLEAN, false, "Whether to enable " +
"splitting of enchanted books", true, false),
/*----------- /*-----------
| Messages | | Messages |
@ -194,6 +200,13 @@ public enum ScrapperSetting implements Setting {
"&eIt will cost &a{cost}&e to salvage that &a{item}&e into diamond!", "&eIt will cost &a{cost}&e to salvage that &a{item}&e into diamond!",
"The message to display when explaining the shown item's netherite salvage cost", true, true), "The message to display when explaining the shown item's netherite salvage cost", true, true),
/**
* The message displayed when displaying the cost of salvaging the player's held enchanted book
*/
COST_MESSAGE_ENCHANTED_BOOK("costMessageEnchantedBook", SettingValueType.STRING,
"&eIt will cost &a{cost}&e to salvage that enchanted book!",
"The message to display when explaining the shown enchanted book's salvage cost", true, true),
/** /**
* The message displayed when explaining that all items will be returned as salvage * The message displayed when explaining that all items will be returned as salvage
*/ */
@ -236,6 +249,27 @@ public enum ScrapperSetting implements Setting {
"&cI'm sorry, but I'm unable to salvage netherite items!", "&cI'm sorry, but I'm unable to salvage netherite items!",
"The message to display when asked to salvage netherite items, and that option is disabled", true, true), "The message to display when asked to salvage netherite items, and that option is disabled", true, true),
/**
* The message displayed when explaining that enchanted book salvage is disabled
*/
CANNOT_SALVAGE_ENCHANTED_BOOK_MESSAGE("cannotSalvageEnchantedBookMessage", SettingValueType.STRING,
"&cI'm sorry, but I'm unable to salvage enchanted books!",
"The message to display when asked to salvage enchanted books, and the option is disabled", true, true),
/**
* The message displayed when explaining that a player needs to provide items to salvage an enchanted book
*/
NOT_ENOUGH_ITEMS_MESSAGE("notEnoughItemsMessage", SettingValueType.STRING,
"&cI'm sorry, but you need to provide enough items for salvaging the enchanted book",
"The message displayed when a player attempts to salvage an enchanted book without providing enough items", true, true),
/**
* The message displayed when explaining that a player cannot salvage an enchanted book containing a single enchantment
*/
CANNOT_SPLIT_ENCHANTED_BOOK_FURTHER_MESSAGE("cannotSplitEnchantedBookFurtherMessage", SettingValueType.STRING,
"&cI'm sorry, but I cannot salvage that enchanted book any further",
"The message displayed when a player attempts to salvage an enchanted book with a single enchantment", true, true),
/** /**
* The message displayed when clicking a scrapper with an empty hand * The message displayed when clicking a scrapper with an empty hand
*/ */
@ -264,6 +298,30 @@ public enum ScrapperSetting implements Setting {
NETHERITE_SALVAGE_COST("netheriteSalvagePrice", SettingValueType.POSITIVE_DOUBLE, 15, NETHERITE_SALVAGE_COST("netheriteSalvagePrice", SettingValueType.POSITIVE_DOUBLE, 15,
"The cost of using the scrapper to remove netherite from an item", false, false), "The cost of using the scrapper to remove netherite from an item", false, false),
/**
* The setting for the enchanted book salvage cost
*/
ENCHANTED_BOOK_SALVAGE_BASE_COST("enchantedBookSalvageBasePrice", SettingValueType.POSITIVE_DOUBLE, 10,
"The per-enchantment cost of splitting an enchanted book", false, false),
/**
* The setting for the enchanted book item cost
*/
ENCHANTED_BOOK_SALVAGE_ITEM_COST("enchantedBookSalvageItemCost", SettingValueType.ITEM_STACK, null,
"The item that needs to be provided in order to salvage an enchanted book", false, false),
/**
* The setting for whether to multiply enchanted book cost
*/
ENCHANTED_BOOK_SALVAGE_MULTIPLY("enchantedBookSalvageMultiplyByEnchantmentNumber", SettingValueType.BOOLEAN,
true, "Whether to multiply the cost of salvaging an enchanted book by the number of enchantments on the book", false, false),
/**
* The setting for whether to require both monetary and item payment for salvaging enchanted books
*/
ENCHANTED_BOOK_SALVAGE_REQUIRE_BOTH("enchantedBookSalvageRequireMoneyAndItem", SettingValueType.BOOLEAN,
true, "Whether salvaging an enchanted book will cost both the configured money amount and the configured item", false, false),
/** /**
* Whether to display exact time in minutes and seconds when displaying a remaining cool-down * Whether to display exact time in minutes and seconds when displaying a remaining cool-down
*/ */

View File

@ -0,0 +1,99 @@
package net.knarcraft.blacksmith.container;
import net.knarcraft.blacksmith.manager.EconomyManager;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.PlayerInventory;
import org.bukkit.inventory.meta.ItemMeta;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
/**
* The cost of performing an action
*
* @param monetaryCost <p>The monetary cost of the action</p>
* @param expCost <p>The experience cost of the action</p>
* @param itemCost <p>The item-based cost of the action</p>
* @param requiredPermissions <p>The permission required for the action</p>
*/
public record ActionCost(double monetaryCost, int expCost, @Nullable ItemStack itemCost,
@NotNull Set<String> requiredPermissions) {
/**
* Checks whether the given player is able to pay this action cost
*
* @param player <p>The player to check</p>
* @return <p>True if the player is able to pay</p>
*/
public boolean canPay(@NotNull Player player) {
for (String permission : requiredPermissions) {
if (!player.hasPermission(permission)) {
return false;
}
}
if (player.getExp() < expCost || !EconomyManager.hasEnough(player, monetaryCost)) {
return false;
}
return itemCost == null || player.getInventory().contains(itemCost);
}
public void takePayment(@NotNull Player player) {
player.giveExp(-expCost);
EconomyManager.withdraw(monetaryCost);
}
/**
* Takes payment for printing a number of books by withdrawing the correct item
*
* @param player <p>The player which needs to pay</p>
* @param item <p>The item to pay</p>
*/
private static void payForBookPrintingItem(Player player, ItemStack item) {
PlayerInventory playerInventory = player.getInventory();
ItemMeta targetMeta = item.getItemMeta();
String displayName = null;
List<String> lore = null;
if (targetMeta != null) {
displayName = targetMeta.hasDisplayName() ? targetMeta.getDisplayName() : null;
lore = targetMeta.hasLore() ? targetMeta.getLore() : null;
}
HashMap<Integer, ? extends ItemStack> itemsOfType = playerInventory.all(item.getType());
int clearedAmount = 0;
for (Map.Entry<Integer, ? extends ItemStack> entry : itemsOfType.entrySet()) {
if (targetMeta == null) {
if (Objects.requireNonNull(entry.getValue()).getAmount() <= item.getAmount() - clearedAmount) {
clearedAmount += entry.getValue().getAmount();
player.getInventory().clear(entry.getKey());
} else {
clearedAmount = item.getAmount();
entry.getValue().setAmount(entry.getValue().getAmount() - (clearedAmount));
}
} else {
// TODO: Only consider item if the name and lore is the same
ItemMeta meta = entry.getValue().getItemMeta();
if (meta == null) {
break;
}
if (displayName != null && (!meta.hasDisplayName() || !meta.getDisplayName().equals(displayName))) {
break;
}
}
if (clearedAmount <= item.getAmount()) {
break;
}
}
}
}

View File

@ -5,6 +5,7 @@ import net.knarcraft.blacksmith.config.blacksmith.GlobalBlacksmithSettings;
import net.knarcraft.blacksmith.config.scrapper.GlobalScrapperSettings; import net.knarcraft.blacksmith.config.scrapper.GlobalScrapperSettings;
import net.knarcraft.blacksmith.property.SalvageMethod; import net.knarcraft.blacksmith.property.SalvageMethod;
import net.knarcraft.blacksmith.util.ItemHelper; import net.knarcraft.blacksmith.util.ItemHelper;
import net.knarcraft.blacksmith.util.SalvageHelper;
import net.milkbowl.vault.economy.Economy; import net.milkbowl.vault.economy.Economy;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.enchantments.Enchantment; import org.bukkit.enchantments.Enchantment;
@ -54,10 +55,11 @@ public class EconomyManager {
* *
* @param player <p>The player holding an item</p> * @param player <p>The player holding an item</p>
* @param salvageMethod <p>The salvage method to check</p> * @param salvageMethod <p>The salvage method to check</p>
* @param item <p>The item to be salvaged</p>
* @return <p>Whether the player cannot pay for the salvage</p> * @return <p>Whether the player cannot pay for the salvage</p>
*/ */
public static boolean cannotPayForSalvage(@NotNull Player player, @NotNull SalvageMethod salvageMethod) { public static boolean cannotPayForSalvage(@NotNull Player player, @NotNull SalvageMethod salvageMethod, @NotNull ItemStack item) {
return economy.getBalance(player) - getSalvageCost(salvageMethod) < 0; return economy.getBalance(player) - getSalvageCost(salvageMethod, item) < 0;
} }
/** /**
@ -76,11 +78,34 @@ public class EconomyManager {
* Gets the human-readable cost of salvaging an item * Gets the human-readable cost of salvaging an item
* *
* @param salvageMethod <p>The salvage method to get the cost for</p> * @param salvageMethod <p>The salvage method to get the cost for</p>
* @param item <p>The item to be salvaged</p>
* @return <p>The formatted cost</p> * @return <p>The formatted cost</p>
*/ */
@NotNull @NotNull
public static String formatSalvageCost(@NotNull SalvageMethod salvageMethod) { public static String formatSalvageCost(@NotNull SalvageMethod salvageMethod, @NotNull ItemStack item) {
return economy.format(getSalvageCost(salvageMethod)); return economy.format(getSalvageCost(salvageMethod, item));
}
/**
* Gets whether the given player has enough money to pay the given cost
*
* @param player <p>The player to check</p>
* @param cost <p>The required cost</p>
* @return <p>True if the player has enough money to cover the cost</p>
*/
public static boolean hasEnough(@NotNull Player player, double cost) {
return economy.getBalance(player) >= cost;
}
/**
* Formats a number as an economy cost
*
* @param cost <p>The cost to format</p>
* @return <p>The formatted cost</p>
*/
@NotNull
public static String format(double cost) {
return economy.format(cost);
} }
/** /**
@ -89,12 +114,13 @@ public class EconomyManager {
* @param salvageMethod <p>The salvage method to get cost for</p> * @param salvageMethod <p>The salvage method to get cost for</p>
* @return <p>The salvage cost</p> * @return <p>The salvage cost</p>
*/ */
private static double getSalvageCost(@NotNull SalvageMethod salvageMethod) { private static double getSalvageCost(@NotNull SalvageMethod salvageMethod, @NotNull ItemStack item) {
GlobalScrapperSettings settings = BlacksmithPlugin.getInstance().getGlobalScrapperSettings(); GlobalScrapperSettings settings = BlacksmithPlugin.getInstance().getGlobalScrapperSettings();
return switch (salvageMethod) { return switch (salvageMethod) {
case SALVAGE, EXTENDED_SALVAGE -> settings.getSalvageCost(); case SALVAGE, EXTENDED_SALVAGE -> settings.getSalvageCost();
case NETHERITE -> settings.getNetheriteSalvageCost(); case NETHERITE -> settings.getNetheriteSalvageCost();
case ARMOR_TRIM -> settings.getArmorTrimSalvageCost(); case ARMOR_TRIM -> settings.getArmorTrimSalvageCost();
case ENCHANTED_BOOK -> getEnchantedBookSalvageCost(item);
}; };
} }
@ -119,7 +145,7 @@ public class EconomyManager {
* @param salvageMethod <p>The salvage method to withdraw for</p> * @param salvageMethod <p>The salvage method to withdraw for</p>
*/ */
public static void withdrawScrapper(@NotNull Player player, @NotNull SalvageMethod salvageMethod) { public static void withdrawScrapper(@NotNull Player player, @NotNull SalvageMethod salvageMethod) {
double cost = getSalvageCost(salvageMethod); double cost = getSalvageCost(salvageMethod, player.getInventory().getItemInMainHand());
if (cost > 0) { if (cost > 0) {
economy.withdrawPlayer(player, cost); economy.withdrawPlayer(player, cost);
} }
@ -183,6 +209,21 @@ public class EconomyManager {
return price; return price;
} }
/**
* Gets the cost of scrapping an enchanted book
*
* @param item <p>The enchanted book to calculate cost for</p>
* @return <p>The cost of scrapping the enchanted book</p>
*/
private static double getEnchantedBookSalvageCost(@NotNull ItemStack item) {
GlobalScrapperSettings settings = BlacksmithPlugin.getInstance().getGlobalScrapperSettings();
double cost = settings.getEnchantedBookSalvageCost();
if (settings.multiplyEnchantedBookSalvageCost()) {
cost *= SalvageHelper.getEnchantmentCount(item) - 1;
}
return SalvageHelper.getEnchantmentCount(item) * cost;
}
/** /**
* Sets up Vault for economy * Sets up Vault for economy
* *

View File

@ -25,4 +25,9 @@ public enum SalvageMethod {
*/ */
NETHERITE, NETHERITE,
/**
* Splitting enchantments of an enchanted book
*/
ENCHANTED_BOOK,
} }

View File

@ -190,10 +190,9 @@ public abstract class CustomTrait<K extends Setting> extends Trait {
} else if (this.session instanceof SalvageSession salvageSession) { } else if (this.session instanceof SalvageSession salvageSession) {
EconomyManager.withdrawScrapper(player, salvageSession.salvageMethod); EconomyManager.withdrawScrapper(player, salvageSession.salvageMethod);
} }
session.scheduleAction();
PlayerInventory playerInventory = player.getInventory(); PlayerInventory playerInventory = player.getInventory();
ItemStack heldItem = player.getInventory().getItemInMainHand(); ItemStack heldItem = player.getInventory().getItemInMainHand();
session.scheduleAction();
//Display the item in the NPC's hand //Display the item in the NPC's hand
Entity entity = npc.getEntity(); Entity entity = npc.getEntity();

View File

@ -70,7 +70,9 @@ public class SalvageSession extends Session implements Runnable {
return true; return true;
} }
if (EconomyManager.cannotPayForSalvage(this.player, this.salvageMethod)) { // TODO: Check item cost. If
if (EconomyManager.cannotPayForSalvage(this.player, this.salvageMethod, this.itemToSalvage)) {
sendNPCMessage(this.npc, this.player, this.config.getInsufficientFundsMessage()); sendNPCMessage(this.npc, this.player, this.config.getInsufficientFundsMessage());
return true; return true;
} }
@ -94,6 +96,7 @@ public class SalvageSession extends Session implements Runnable {
case EXTENDED_SALVAGE -> Material.CRAFTING_TABLE; case EXTENDED_SALVAGE -> Material.CRAFTING_TABLE;
case SALVAGE -> Material.ANVIL; case SALVAGE -> Material.ANVIL;
case NETHERITE, ARMOR_TRIM -> Material.SMITHING_TABLE; case NETHERITE, ARMOR_TRIM -> Material.SMITHING_TABLE;
case ENCHANTED_BOOK -> Material.ENCHANTING_TABLE;
}; };
} }

View File

@ -4,6 +4,7 @@ import net.citizensnpcs.api.util.DataKey;
import net.knarcraft.blacksmith.BlacksmithPlugin; import net.knarcraft.blacksmith.BlacksmithPlugin;
import net.knarcraft.blacksmith.config.SmithPreset; import net.knarcraft.blacksmith.config.SmithPreset;
import net.knarcraft.blacksmith.config.SmithPresetFilter; import net.knarcraft.blacksmith.config.SmithPresetFilter;
import net.knarcraft.blacksmith.config.scrapper.GlobalScrapperSettings;
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.RecipeResult;
@ -20,6 +21,7 @@ import org.bukkit.Material;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ArmorMeta; import org.bukkit.inventory.meta.ArmorMeta;
import org.bukkit.inventory.meta.EnchantmentStorageMeta;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
@ -117,7 +119,7 @@ public class ScrapperTrait extends CustomTrait<ScrapperSetting> {
return; return;
} }
// Print the cost to the player // Print the cost to the player
printCostMessage(player, itemInHand, EconomyManager.formatSalvageCost(result.salvageMethod()), printCostMessage(player, itemInHand, EconomyManager.formatSalvageCost(result.salvageMethod(), itemInHand),
result.salvageMethod()); result.salvageMethod());
} }
@ -145,6 +147,13 @@ public class ScrapperTrait extends CustomTrait<ScrapperSetting> {
return result; return result;
} }
result = isEnchantedBookSalvage(player, itemInHand);
if (result.salvageState() == SalvageState.NO_SALVAGE) {
return null;
} else if (result.salvageState() == SalvageState.FOUND_SALVAGE) {
return result;
}
result = isNormalSalvage(player, itemInHand, extended); result = isNormalSalvage(player, itemInHand, extended);
if (result.salvageState() == SalvageState.NO_SALVAGE) { if (result.salvageState() == SalvageState.NO_SALVAGE) {
return null; return null;
@ -174,7 +183,7 @@ public class ScrapperTrait extends CustomTrait<ScrapperSetting> {
return new SalvageResult(SalvageMethod.SALVAGE, new ArrayList<>(), SalvageState.NO_SALVAGE, 0); 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 scrapper 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, 0); return new SalvageResult(SalvageMethod.SALVAGE, new ArrayList<>(), SalvageState.NO_SALVAGE, 0);
@ -193,6 +202,37 @@ public class ScrapperTrait extends CustomTrait<ScrapperSetting> {
} }
} }
/**
* Gets the result of trying to salvage the item as an enchanted book
*
* @param player <p>The player trying to salvage the item</p>
* @param itemInHand <p>The item to be salvaged</p>
* @return <p>The result of attempting the salvage</p>
*/
private SalvageResult isEnchantedBookSalvage(@NotNull Player player, @NotNull ItemStack itemInHand) {
if (itemInHand.getType() != Material.ENCHANTED_BOOK ||
!(itemInHand.getItemMeta() instanceof EnchantmentStorageMeta)) {
return new SalvageResult(SalvageMethod.ENCHANTED_BOOK, new ArrayList<>(), SalvageState.INCORRECT_METHOD, 0);
}
if (!getSettings().splitEnchantedBook()) {
sendNPCMessage(this.npc, player, getSettings().getCannotSalvageEnchantedBookMessage());
return new SalvageResult(SalvageMethod.ENCHANTED_BOOK, new ArrayList<>(), SalvageState.NO_SALVAGE, 0);
}
if (SalvageHelper.getEnchantmentCount(itemInHand) <= 1) {
sendNPCMessage(this.npc, player, getSettings().getCannotSplitEnchantedBookFurtherMessage());
return new SalvageResult(SalvageMethod.ENCHANTED_BOOK, new ArrayList<>(), SalvageState.NO_SALVAGE, 0);
}
List<ItemStack> salvage = SalvageHelper.getEnchantedBookSalvage(itemInHand);
boolean noUsefulSalvage = salvage == null || salvage.isEmpty();
if (noUsefulSalvage) {
return new SalvageResult(SalvageMethod.ENCHANTED_BOOK, new ArrayList<>(), SalvageState.NO_SALVAGE, 0);
}
return new SalvageResult(SalvageMethod.ENCHANTED_BOOK, salvage, SalvageState.FOUND_SALVAGE, 1);
}
/** /**
* Gets the result of trying to salvage the item as a netherite applied item * Gets the result of trying to salvage the item as a netherite applied item
* *
@ -272,10 +312,30 @@ public class ScrapperTrait extends CustomTrait<ScrapperSetting> {
sendNPCMessage(this.npc, player, replacer.replace(getSettings().getCostMessage())); sendNPCMessage(this.npc, player, replacer.replace(getSettings().getCostMessage()));
} else if (salvageMethod == SalvageMethod.NETHERITE) { } else if (salvageMethod == SalvageMethod.NETHERITE) {
sendNPCMessage(this.npc, player, replacer.replace(getSettings().getNetheriteCostMessage())); sendNPCMessage(this.npc, player, replacer.replace(getSettings().getNetheriteCostMessage()));
} else if (salvageMethod == SalvageMethod.ENCHANTED_BOOK) {
StringReplacer replacer2 = new StringReplacer();
replacer2.add("{cost}", getEnchantedBookCost());
sendNPCMessage(this.npc, player, replacer2.replace(getSettings().getEnchantedBookCostMessage()));
} else { } else {
BlacksmithPlugin.error("Unrecognized salvage method " + salvageMethod); BlacksmithPlugin.error("Unrecognized salvage method " + salvageMethod);
} }
} }
private String getEnchantedBookCost() {
// TODO: If both an item and money is required, print both requirements
// TODO: If only money is required, print the money requirement
// TODO: If an item requirement is set, print the item requirement
GlobalScrapperSettings scrapperSettings = BlacksmithPlugin.getInstance().getGlobalScrapperSettings();
String moneyCost = EconomyManager.format(scrapperSettings.getEnchantedBookSalvageCost());
ItemStack itemCost = scrapperSettings.
if (scrapperSettings.requireMoneyAndItemForEnchantedBookSalvage()) {
// TODO: Print both with a + between them (if item has a special name, use that instead of the material name)
} else {
// TODO: If the item is not null, print it, otherwise print the monetary cost
}
}
@Override @Override
protected boolean showExactTime() { protected boolean showExactTime() {
@ -291,8 +351,8 @@ public class ScrapperTrait extends CustomTrait<ScrapperSetting> {
* @return <p>True if the item can be theoretically salvaged</p> * @return <p>True if the item can be theoretically salvaged</p>
*/ */
private boolean canBeSalvaged(@NotNull ItemStack item, @NotNull List<Material> salvageAbleItems, boolean extended) { private boolean canBeSalvaged(@NotNull ItemStack item, @NotNull List<Material> salvageAbleItems, boolean extended) {
return (extended || ItemHelper.isRepairable(item)) && return item.getType() == Material.ENCHANTED_BOOK || ((extended || ItemHelper.isRepairable(item)) &&
(salvageAbleItems.isEmpty() || salvageAbleItems.contains(item.getType())); (salvageAbleItems.isEmpty() || salvageAbleItems.contains(item.getType())));
} }
/** /**

View File

@ -2,6 +2,7 @@ package net.knarcraft.blacksmith.util;
import net.knarcraft.blacksmith.BlacksmithPlugin; import net.knarcraft.blacksmith.BlacksmithPlugin;
import net.knarcraft.blacksmith.container.RecipeResult; import net.knarcraft.blacksmith.container.RecipeResult;
import org.bukkit.Bukkit;
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;
@ -10,6 +11,8 @@ import org.bukkit.inventory.Recipe;
import org.bukkit.inventory.ShapedRecipe; import org.bukkit.inventory.ShapedRecipe;
import org.bukkit.inventory.ShapelessRecipe; import org.bukkit.inventory.ShapelessRecipe;
import org.bukkit.inventory.meta.ArmorMeta; import org.bukkit.inventory.meta.ArmorMeta;
import org.bukkit.inventory.meta.EnchantmentStorageMeta;
import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.inventory.meta.trim.ArmorTrim; import org.bukkit.inventory.meta.trim.ArmorTrim;
import org.bukkit.inventory.meta.trim.TrimMaterial; import org.bukkit.inventory.meta.trim.TrimMaterial;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
@ -44,6 +47,51 @@ public final class SalvageHelper {
trimMaterialToMaterial.put(TrimMaterial.REDSTONE, Material.REDSTONE); trimMaterialToMaterial.put(TrimMaterial.REDSTONE, Material.REDSTONE);
} }
/**
* Gets salvage for an enchanted book
*
* @param itemStack <p>The enchanted book(s) to salvage</p>
* @return <p>The resulting salvage</p>
* @throws RuntimeException <p>If generated enchanted book metadata is null</p>
*/
@Nullable
public static List<ItemStack> getEnchantedBookSalvage(@NotNull ItemStack itemStack) {
ItemMeta meta = itemStack.getItemMeta();
List<ItemStack> output = new ArrayList<>();
if (!(meta instanceof EnchantmentStorageMeta enchantmentStorageMeta)) {
return null;
}
Map<Enchantment, Integer> enchantmentMap = enchantmentStorageMeta.getStoredEnchants();
for (Map.Entry<Enchantment, Integer> enchantmentEntry : enchantmentMap.entrySet()) {
EnchantmentStorageMeta enchantmentMeta = (EnchantmentStorageMeta) Bukkit.getServer().getItemFactory().getItemMeta(Material.ENCHANTED_BOOK);
if (enchantmentMeta == null) {
throw new RuntimeException("Unable to create enchanted book metadata.");
}
enchantmentMeta.addStoredEnchant(enchantmentEntry.getKey(), enchantmentEntry.getValue(), true);
ItemStack newBook = new ItemStack(Material.ENCHANTED_BOOK, 1);
newBook.setItemMeta(enchantmentMeta);
output.add(newBook);
}
return output;
}
/**
* Gets the number of enchantments applied to an enchanted book
*
* @param itemStack <p>The enchanted book to check</p>
* @return <p>The number of enchantments, or -1 if not an enchanted book</p>
*/
public static int getEnchantmentCount(@NotNull ItemStack itemStack) {
ItemMeta meta = itemStack.getItemMeta();
if (!(meta instanceof EnchantmentStorageMeta enchantmentStorageMeta)) {
return -1;
}
return enchantmentStorageMeta.getStoredEnchants().size();
}
/** /**
* Gets salvage for a given netherite item * Gets salvage for a given netherite item
* *

View File

@ -141,6 +141,18 @@ scrapper:
# The cost of using the scrapper to remove netherite from an item # The cost of using the scrapper to remove netherite from an item
netheriteSalvagePrice: 15 netheriteSalvagePrice: 15
# The per-enchantment cost of splitting an enchanted book
enchantedBookSalvageBasePrice: 10
# The item that needs to be provided to pay for splitting an enchanted book
enchantedBookSalvageItemCost: null
# Whether to multiply the initial cost with the number of enchantments on the book
enchantedBookSalvageMultiplyByEnchantmentNumber: true
# Whether to require both a monetary sum and providing an item in order to pay for salvaging an enchanted book
enchantedBookSalvageRequireMoneyAndItem: false
# The settings which are set to any new scrapper NPC. To change any of these settings for an existing NPC, you must # The settings which are set to any new scrapper NPC. To change any of these settings for an existing NPC, you must
# change the Citizens NPC file, or use the /scrapper command # change the Citizens NPC file, or use the /scrapper command
@ -182,6 +194,9 @@ scrapper:
# Whether to enable salvaging of netherite items # Whether to enable salvaging of netherite items
salvageNetherite: true salvageNetherite: true
# Whether to enable salvaging an enchanted books with several enchantments into several books with one enchantment
splitEnchantedBook: false
# Default values for messages used by NPCs # Default values for messages used by NPCs
messages: messages:
# The message to display when another player is using the scrapper # The message to display when another player is using the scrapper
@ -226,6 +241,9 @@ scrapper:
# The message to display when explaining the shown item's netherite salvage cost # The message to display when explaining the shown item's netherite salvage cost
costMessageNetherite: "&eIt will cost &a{cost}&e to salvage that &a{item}&e into diamond!" costMessageNetherite: "&eIt will cost &a{cost}&e to salvage that &a{item}&e into diamond!"
# The message to display when explaining the shown enchanted book's salvage cost
costMessageEnchantedBook: "&eIt will cost &a{cost}&e to salvage that enchanted book!"
# The yield message to display if trying to salvage a non-damaged item # The yield message to display if trying to salvage a non-damaged item
fullSalvageMessage: "&aI should be able to extract all components from that pristine item.&r" fullSalvageMessage: "&aI should be able to extract all components from that pristine item.&r"
@ -244,5 +262,14 @@ scrapper:
# The message to display when asked to salvage netherite items, and that option is disabled # The message to display when asked to salvage netherite items, and that option is disabled
cannotSalvageNetheriteMessage: "&cI'm sorry, but I'm unable to salvage netherite items!" cannotSalvageNetheriteMessage: "&cI'm sorry, but I'm unable to salvage netherite items!"
# The message displayed when explaining that enchanted book salvage is disabled
cannotSalvageEnchantedBookMessage: "&cI'm sorry, but I'm unable to salvage enchanted books!"
# The message displayed when a player attempts to salvage an enchanted book without providing enough normal books
notEnoughItemsMessage: "&cI'm sorry, but you need to provide {number} {item} to salvage the enchanted book"
# The message displayed when a player attempts to salvage an enchanted book with a single enchantment
cannotSplitEnchantedBookFurtherMessage: "&cI'm sorry, but I cannot salvage that enchanted book any further"
# The message to display when a scrapper is clicked with an empty hand # The message to display when a scrapper is clicked with an empty hand
noItemMessage: "Please present the item you want to salvage" noItemMessage: "Please present the item you want to salvage"