Implements netherite salvaging #24
All checks were successful
EpicKnarvik97/Blacksmith/pipeline/head This commit looks good

This commit is contained in:
Kristian Knarvik 2024-05-06 21:26:21 +02:00
parent e6047f3866
commit 1d7e8a0732
15 changed files with 430 additions and 209 deletions

View File

@ -119,6 +119,10 @@ repair all items, except diamond armor.
All currently supported presets, and available filters for each preset:
- BLACKSMITH (WEAPON_SMITH + ARMOR_SMITH + TOOL_SMITH)
- GOLD
- IRON
- DIAMOND
- NETHERITE
- WEAPON_SMITH: (RANGED + SWORD + SHIELD)
- BOW (bows and crossbows)
- SWORD (swords)
@ -212,12 +216,14 @@ All currently supported presets, and available filters for each preset:
### Scrapper global-only options
| Key | Value type | Default | Description |
|----------------|------------------------------------------------------------|---------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| basePrice | positive decimal number | 0 | The cost of using a scrapper. |
| showExactTime | true/false | false | If true, scrappers will display exact time remaining in minutes and seconds, instead of vague expressions. |
| giveExperience | true/false | true | If true, each enchantment level on the salvaged item will give one EXP level as salvage. |
| trashSalvage | TARGET_MATERIAL:IGNORED_MATERIAL\[,\*_TARGET2:\*_IGNORED2] | `"*_SHOVEL;*_PICKAXE;*_AXE;*_HOE;*_SWORD;SHIELD;*_BOW:STICK"` | 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`. |
| Key | Value type | Default | Description |
|-----------------------|------------------------------------------------------------|---------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| salvagePrice | positive decimal number | 0 | The cost of using a scrapper to salvage an item. |
| armorTrimSalvagePrice | positive decimal number | 5 | The cost of using a scrapper to remove armor trim from an item. |
| netheriteSalvagePrice | positive decimal number | 15 | The cost of using a scrapper to remove netherite from an item. |
| showExactTime | true/false | false | If true, scrappers will display exact time remaining in minutes and seconds, instead of vague expressions. |
| giveExperience | true/false | true | If true, each enchantment level on the salvaged item will give one EXP level as salvage. |
| trashSalvage | TARGET_MATERIAL:IGNORED_MATERIAL\[,\*_TARGET2:\*_IGNORED2] | `"*_SHOVEL;*_PICKAXE;*_AXE;*_HOE;*_SWORD;SHIELD;*_BOW:STICK"` | 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)
@ -234,28 +240,32 @@ All currently supported presets, and available filters for each preset:
| scrapperTitle | text string | scrapper | The title displayed as part of the message explaining that a scrapper doesn't recognize a player's held item. |
| extendedSalvageEnabled | true/false | false | Whether to enable the extended salvage behavior for this scrapper. As long as it is allowed by salvageAbleItems and it can be crafted in a crafting table, it can be salvaged. This includes things like four planks salvaged into wood. |
| salvageEnchanted | true/false | false | Whether the scrapper is able to salvage enchanted items. This is disabled by default as it's very easy to accidentally salvage heavily enchanted items if one is not careful. |
| salvageArmorTrims | true/false | true | Whether the scrapper is able to salvage armor trims. |
| salvageArmorTrims | true/false | true | Whether the scrapper is able to salvage armor trims from items. |
| salvageNetherite | true/false | true | Whether the scrapper is able to salvage netherite items into diamond items. |
#### Messages
| Message Key | Default | Explanation |
|---------------------------------|-----------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------|
| busyPlayerMessage | &cI'm busy at the moment. Come back later! | The message displayed when the scrapper is serving another player. |
| busySalvageMessage | &cI'm working on it. Be patient! I'll finish {time}! | The message displayed when the scrapper is busy salvaging an item. |
| coolDownUnexpiredMessage | &cYou've already had your chance! Give me a break! I'll be ready {time}! | The message displayed when the player has to wait for the cool-down to expire before using the scrapper again. |
| invalidItemMessage | &cI'm sorry, but I'm a/an {title}, I don't know how to salvage that! | The message displayed when a scrapper is presented an item which it cannot salvage. |
| tooDamagedForSalvageMessage | &cThat item is too damaged to be salvaged into anything useful | The message displayed when a scrapper is presented with an item too damaged to produce salvage. |
| successSalvagedMessage | There you go! | The message displayed when a scrapper successfully repairs an item. |
| failSalvageMessage | &cWhoops! The item broke! Maybe next time? | The message displayed when a scrapper fails to salvage an item. |
| itemChangedMessage | &cThat's not the item you wanted to salvage before! | The message displayed when a player changes their item after being shown the salvage cost. |
| startSalvageMessage | &eOk, let's see what I can do... | The message displayed when a scrapper starts salvaging an item. |
| insufficientFundsMessage | &cYou don't have enough money to salvage an item! | The message displayed when a player is unable to pay for scrapping an item. |
| costMessage | &eIt will cost &a{cost}&e to salvage that item! {yield} &eClick again to salvage! | The message displayed when telling a player about the cost of scrapping an item. |
| fullSalvageMessage | &aI should be able to extract all components from that pristine item.&r | The message displayed as part of costMessage's yield placeholder if all components will be returned. |
| partialSalvageMessage | &cI cannot extract all components from that damaged item.&r | The message displayed as part of costMessage's yield placeholder if only some components will be returned. |
| cannotSalvageEnchantedMessage | &cI'm sorry, but I'm unable to salvage enchanted items! | The message displayed when telling a player that the scrapper cannot salvage enchanted items. |
| cannotSalvageArmorTrimMessage | &cI'm sorry, but I'm unable to salvage armor trims! | The message displayed when telling a player that the scrapper cannot salvage items with armor trim. |
| armorTrimSalvageNotFoundMessage | "&cI'm sorry, but I don't know how to salvage that armor trim!" | The message displayed when telling a player that the scrapper cannot find the correct items to return as armor trim salvage. |
| Message Key | Default | Explanation |
|---------------------------------|-----------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------|
| busyPlayerMessage | &cI'm busy at the moment. Come back later! | The message displayed when the scrapper is serving another player. |
| busySalvageMessage | &cI'm working on it. Be patient! I'll finish {time}! | The message displayed when the scrapper is busy salvaging an item. |
| coolDownUnexpiredMessage | &cYou've already had your chance! Give me a break! I'll be ready {time}! | The message displayed when the player has to wait for the cool-down to expire before using the scrapper again. |
| invalidItemMessage | &cI'm sorry, but I'm a/an {title}, I don't know how to salvage that! | The message displayed when a scrapper is presented an item which it cannot salvage. |
| tooDamagedForSalvageMessage | &cThat item is too damaged to be salvaged into anything useful | The message displayed when a scrapper is presented with an item too damaged to produce salvage. |
| successSalvagedMessage | There you go! | The message displayed when a scrapper successfully repairs an item. |
| failSalvageMessage | &cWhoops! The item broke! Maybe next time? | The message displayed when a scrapper fails to salvage an item. |
| itemChangedMessage | &cThat's not the item you wanted to salvage before! | The message displayed when a player changes their item after being shown the salvage cost. |
| startSalvageMessage | &eOk, let's see what I can do... | The message displayed when a scrapper starts salvaging an item. |
| insufficientFundsMessage | &cYou don't have enough money to salvage an item! | The message displayed when a player is unable to pay for salvaging an item. |
| costMessage | &eIt will cost &a{cost}&e to salvage that &a{item}&e! {yield} &eClick again to salvage! | The message displayed when telling a player about the cost of salvaging an item. |
| costMessageArmorTrim | &eIt will cost &a{cost}&e to salvage that &a{item}&e's armor trim! | The message displayed when telling a player about the cost of salvaging an item's armor trim. |
| costMessageNetherite | &eIt will cost &a{cost}&e to salvage that &a{item}&e into diamond! | The message displayed when telling a player about the cost of salvaging a netherite item into a diamond item. |
| fullSalvageMessage | &aI should be able to extract all components from that pristine item.&r | The message displayed as part of costMessage's yield placeholder if all components will be returned. |
| partialSalvageMessage | &cI cannot extract all components from that damaged item.&r | The message displayed as part of costMessage's yield placeholder if only some components will be returned. |
| cannotSalvageEnchantedMessage | &cI'm sorry, but I'm unable to salvage enchanted items! | The message displayed when telling a player that the scrapper cannot salvage enchanted items. |
| cannotSalvageArmorTrimMessage | &cI'm sorry, but I'm unable to salvage armor trims! | The message displayed when telling a player that the scrapper cannot salvage items with armor trim. |
| armorTrimSalvageNotFoundMessage | &cI'm sorry, but I don't know how to salvage that armor trim! | The message displayed when telling a player that the scrapper cannot find the correct items to return as armor trim salvage. |
| cannotSalvageNetheriteMessage | &cI'm sorry, but I'm unable to salvage netherite items! | The message displayed when telling a player that the scrapper cannot salvage netherite items. |
## Language customization

View File

@ -0,0 +1,23 @@
package net.knarcraft.blacksmith.config;
/**
* A representation of the different ways an item can be salvaged
*/
public enum SalvageMethod {
/**
* Salvaging the item normally by returning the item's crafting recipe
*/
SALVAGE,
/**
* Removing the armor trim from an item
*/
ARMOR_TRIM,
/**
* Un-doing netherite application for an item
*/
NETHERITE,
}

View File

@ -22,7 +22,8 @@ public enum SmithPreset {
/**
* A blacksmith capable of re-forging everything
*/
BLACKSMITH(new SmithPresetFilter[]{}),
BLACKSMITH(new SmithPresetFilter[]{SmithPresetFilter.GOLD, SmithPresetFilter.IRON, SmithPresetFilter.DIAMOND,
SmithPresetFilter.NETHERITE}),
/**
* A blacksmith capable of re-forging all weapons (including shields)

View File

@ -34,7 +34,7 @@ public class GlobalScrapperSettings implements Settings<ScrapperSetting> {
*
* @param instance <p>A reference to the blacksmith plugin</p>
*/
public GlobalScrapperSettings(BlacksmithPlugin instance) {
public GlobalScrapperSettings(@NotNull BlacksmithPlugin instance) {
this.instance = instance;
}
@ -78,7 +78,8 @@ public class GlobalScrapperSettings implements Settings<ScrapperSetting> {
* @param scrapperSetting <p>The setting to get</p>
* @return <p>The current raw setting value</p>
*/
public @NotNull Object getRawValue(@NotNull ScrapperSetting scrapperSetting) {
@NotNull
public Object getRawValue(@NotNull ScrapperSetting scrapperSetting) {
return this.settings.get(scrapperSetting);
}
@ -87,6 +88,7 @@ public class GlobalScrapperSettings implements Settings<ScrapperSetting> {
*
* @return <p>The current value of the default NPC settings</p>
*/
@NotNull
public Map<ScrapperSetting, Object> getDefaultNPCSettings() {
return new HashMap<>(this.settings);
}
@ -108,10 +110,22 @@ public class GlobalScrapperSettings implements Settings<ScrapperSetting> {
* @param setting <p>The setting to get the value of</p>
* @return <p>The value of the given setting as a boolean</p>
*/
public boolean asBoolean(ScrapperSetting setting) {
public boolean asBoolean(@NotNull ScrapperSetting setting) {
return ConfigHelper.asBoolean(getValue(setting));
}
/**
* Gets the given value as a double
*
* <p>This will throw an exception if used for a non-double setting</p>
*
* @param setting <p>The setting to get the value of</p>
* @return <p>The value of the given setting as a double</p>
*/
public double asDouble(@NotNull ScrapperSetting setting) {
return ConfigHelper.asDouble(getValue(setting));
}
/**
* Gets the value of a setting, using the default if not set
*
@ -173,12 +187,30 @@ public class GlobalScrapperSettings implements Settings<ScrapperSetting> {
}
/**
* Gets the cost of using a scrapper
* Gets the cost of using a scrapper to salvage an item
*
* @return <p>The cost of using a scrapper</p>
* @return <p>The cost of using a scrapper to salvage an item</p>
*/
public double getCost() {
return ConfigHelper.asDouble(getValue(ScrapperSetting.USE_COST));
public double getSalvageCost() {
return asDouble(ScrapperSetting.SALVAGE_COST);
}
/**
* Gets the cost of using a scrapper to remove armor trim
*
* @return <p>The cost of using a scrapper to remove armor trim</p>
*/
public double getArmorTrimSalvageCost() {
return asDouble(ScrapperSetting.ARMOR_TRIM_SALVAGE_COST);
}
/**
* Gets the cost of using a scrapper to remove netherite from an item
*
* @return <p>The cost of using a scrapper to remove netherite from an item</p>
*/
public double getNetheriteSalvageCost() {
return asDouble(ScrapperSetting.NETHERITE_SALVAGE_COST);
}
/**

View File

@ -151,6 +151,16 @@ public class ScrapperNPCSettings implements TraitSettings<ScrapperSetting> {
return asString(ScrapperSetting.COST_MESSAGE_ARMOR_TRIM);
}
/**
* Gets the message to use for displaying netherite salvage cost
*
* @return <p>The message to use for displaying netherite salvage cost</p>
*/
@NotNull
public String getNetheriteCostMessage() {
return asString(ScrapperSetting.COST_MESSAGE_NETHERITE);
}
@Override
@NotNull
public String getCoolDownUnexpiredMessage() {
@ -316,6 +326,15 @@ public class ScrapperNPCSettings implements TraitSettings<ScrapperSetting> {
return asBoolean(ScrapperSetting.SALVAGE_ARMOR_TRIMS);
}
/**
* Whether salvage of netherite items is enabled
*
* @return <p>True if this scrapper can salvage netherite items</p>
*/
public boolean salvageNetherite() {
return asBoolean(ScrapperSetting.SALVAGE_NETHERITE);
}
/**
* Gets the title of this scrapper NPC
*
@ -415,4 +434,14 @@ public class ScrapperNPCSettings implements TraitSettings<ScrapperSetting> {
return asString(ScrapperSetting.ARMOR_TRIM_SALVAGE_NOT_FOUND_MESSAGE);
}
/**
* Gets the message to display when explaining that this scrapper is unable to salvage netherite items
*
* @return <p>The message to display when explaining that this scrapper is unable to salvage netherite items</p>
*/
@NotNull
public String getCannotSalvageNetheriteMessage() {
return asString(ScrapperSetting.CANNOT_SALVAGE_NETHERITE_MESSAGE);
}
}

View File

@ -19,7 +19,7 @@ public enum ScrapperSetting implements Setting {
* <p>If set to false, the item will be directly put in the player's inventory instead</p>
*/
DROP_ITEM("dropItem", SettingValueType.BOOLEAN, true, "Whether the " +
"item will drop materials resulting from scrapping on the ground, instead of putting them into the user's" +
"item will drop materials resulting from salvaging on the ground, instead of putting them into the user's" +
" inventory", true, false),
/**
@ -86,6 +86,12 @@ public enum ScrapperSetting implements Setting {
SALVAGE_ARMOR_TRIMS("salvageArmorTrims", SettingValueType.BOOLEAN, true,
"Whether to enable salvaging of armor trims.", true, false),
/**
* The setting for whether the NPC should allow salvaging netherite items to diamond items
*/
SALVAGE_NETHERITE("salvageNetherite", SettingValueType.BOOLEAN, true,
"Whether to enable salvaging of netherite items", true, false),
/*-----------
| Messages |
-----------*/
@ -164,16 +170,23 @@ public enum ScrapperSetting implements Setting {
* The message displayed when displaying the cost of salvaging the held item to the player
*/
COST_MESSAGE("costMessage", SettingValueType.STRING,
"&eIt will cost &a{cost}&e to salvage that item! {yield} Click again to salvage!",
"&eIt will cost &a{cost}&e to salvage that &a{item}&e! {yield} &eClick again to salvage!",
"The message to display when informing a player about the salvaging cost", true, true),
/**
* The message displayed when displaying the cost of salvaging the armor trim of the held item to the player
*/
COST_MESSAGE_ARMOR_TRIM("costMessageArmorTrim", SettingValueType.STRING,
"&eIt will cost &a{cost}&e to salvage that armor trim!",
"&eIt will cost &a{cost}&e to salvage that &a{item}&e's armor trim!",
"The message to display when explaining the shown item's armor trim's salvage cost", true, true),
/**
* The message displayed when displaying the cost of salvaging the netherite of the held item to the player
*/
COST_MESSAGE_NETHERITE("costMessageNetherite", SettingValueType.STRING,
"&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 displayed when explaining that all items will be returned as salvage
*/
@ -209,21 +222,40 @@ public enum ScrapperSetting implements Setting {
"&cI'm sorry, but I don't know how to salvage that armor trim!",
"The message to display if the correct materials to return for the armor trim are unknown", true, true),
/**
* The message displayed when explaining that netherite salvage is disabled
*/
CANNOT_SALVAGE_NETHERITE_MESSAGE("cannotSalvageNetheriteMessage", SettingValueType.STRING,
"&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),
/*------------------
| Global settings |
------------------*/
/**
* The setting for the use cost of using the scrapper
* The setting for the salvage cost
*/
USE_COST("basePrice", SettingValueType.POSITIVE_DOUBLE, 0, "The cost of using a scrapper",
false, false),
SALVAGE_COST("salvagePrice", SettingValueType.POSITIVE_DOUBLE, 0,
"The cost of using a scrapper to salvage an item", false, false),
/**
* The setting for the armor trim salvage cost
*/
ARMOR_TRIM_SALVAGE_COST("armorTrimSalvagePrice", SettingValueType.POSITIVE_DOUBLE, 5,
"The cost of using the scrapper to remove armor trim", false, false),
/**
* The setting for the netherite salvage cost
*/
NETHERITE_SALVAGE_COST("netheriteSalvagePrice", SettingValueType.POSITIVE_DOUBLE, 15,
"The cost of using the scrapper to remove netherite from an item", false, false),
/**
* Whether to display exact time in minutes and seconds when displaying a remaining cool-down
*/
SHOW_EXACT_TIME("showExactTime", SettingValueType.BOOLEAN, "false", "Exact time displays the " +
"exact number of seconds and minutes remaining as part of the scrapping cool-down and scrapping delay " +
"exact number of seconds and minutes remaining as part of the salvaging cool-down and salvaging delay " +
"messages, instead of just vaguely hinting at the remaining time.", false, false),
/**
@ -263,7 +295,7 @@ public enum ScrapperSetting implements Setting {
* @param isPerNPC <p>Whether this setting is per-NPC or global</p>
* @param isMessage <p>Whether this option is for an NPC message</p>
*/
ScrapperSetting(String key, SettingValueType valueType, Object value,
ScrapperSetting(@NotNull String key, @NotNull SettingValueType valueType, @NotNull Object value,
@NotNull String description, boolean isPerNPC, boolean isMessage) {
if (isPerNPC) {
if (isMessage) {
@ -289,32 +321,38 @@ public enum ScrapperSetting implements Setting {
}
@Override
public @NotNull String getPath() {
@NotNull
public String getPath() {
return this.path;
}
@Override
public @NotNull String getChildPath() {
@NotNull
public String getChildPath() {
return this.childPath;
}
@Override
public @NotNull Object getDefaultValue() {
@NotNull
public Object getDefaultValue() {
return this.value;
}
@Override
public @NotNull String getCommandName() {
@NotNull
public String getCommandName() {
return this.commandName;
}
@Override
public @NotNull SettingValueType getValueType() {
@NotNull
public SettingValueType getValueType() {
return this.valueType;
}
@Override
public @NotNull String getDescription() {
@NotNull
public String getDescription() {
return this.description;
}

View File

@ -1,7 +1,9 @@
package net.knarcraft.blacksmith.manager;
import net.knarcraft.blacksmith.BlacksmithPlugin;
import net.knarcraft.blacksmith.config.SalvageMethod;
import net.knarcraft.blacksmith.config.blacksmith.GlobalBlacksmithSettings;
import net.knarcraft.blacksmith.config.scrapper.GlobalScrapperSettings;
import net.knarcraft.blacksmith.util.ItemHelper;
import net.milkbowl.vault.economy.Economy;
import org.bukkit.Material;
@ -54,11 +56,12 @@ public class EconomyManager {
/**
* Gets whether the given player cannot pay for salvaging an item
*
* @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>
* @return <p>Whether the player cannot pay for the salvage</p>
*/
public static boolean cannotPayForSalvage(@NotNull Player player) {
return economy.getBalance(player) - BlacksmithPlugin.getInstance().getGlobalScrapperSettings().getCost() < 0;
public static boolean cannotPayForSalvage(@NotNull Player player, @NotNull SalvageMethod salvageMethod) {
return economy.getBalance(player) - getSalvageCost(salvageMethod) < 0;
}
/**
@ -76,12 +79,27 @@ public class EconomyManager {
/**
* Gets the human-readable cost of salvaging an item
*
* @param salvageMethod <p>The salvage method to get the cost for</p>
* @return <p>The formatted cost</p>
*/
@NotNull
public static String formatScrapperCost() {
double cost = BlacksmithPlugin.getInstance().getGlobalScrapperSettings().getCost();
return economy.format(cost);
public static String formatSalvageCost(@NotNull SalvageMethod salvageMethod) {
return economy.format(getSalvageCost(salvageMethod));
}
/**
* Gets the cost of salvaging using the specified method
*
* @param salvageMethod <p>The salvage method to get cost for</p>
* @return <p>The salvage cost</p>
*/
private static double getSalvageCost(@NotNull SalvageMethod salvageMethod) {
GlobalScrapperSettings settings = BlacksmithPlugin.getInstance().getGlobalScrapperSettings();
return switch (salvageMethod) {
case SALVAGE -> settings.getSalvageCost();
case NETHERITE -> settings.getNetheriteSalvageCost();
case ARMOR_TRIM -> settings.getArmorTrimSalvageCost();
};
}
/**
@ -101,10 +119,11 @@ public class EconomyManager {
/**
* Withdraws the salvaging cost from the given player
*
* @param player <p>The player to withdraw from</p>
* @param player <p>The player to withdraw from</p>
* @param salvageMethod <p>The salvage method to withdraw for</p>
*/
public static void withdrawScrapper(Player player) {
double cost = BlacksmithPlugin.getInstance().getGlobalScrapperSettings().getCost();
public static void withdrawScrapper(@NotNull Player player, @NotNull SalvageMethod salvageMethod) {
double cost = getSalvageCost(salvageMethod);
if (cost > 0) {
economy.withdrawPlayer(player, cost);
}

View File

@ -7,7 +7,7 @@ import net.knarcraft.blacksmith.config.Settings;
import net.knarcraft.blacksmith.config.TraitSettings;
import net.knarcraft.blacksmith.formatting.TimeFormatter;
import net.knarcraft.blacksmith.manager.EconomyManager;
import net.knarcraft.blacksmith.util.ItemHelper;
import net.knarcraft.blacksmith.util.SalvageHelper;
import net.knarcraft.knarlib.formatting.StringFormatter;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
@ -181,8 +181,8 @@ public abstract class CustomTrait<K extends Setting> extends Trait {
if (isBlacksmith) {
EconomyManager.withdrawBlacksmith(player);
} else {
EconomyManager.withdrawScrapper(player);
} else if (this.session instanceof SalvageSession salvageSession) {
EconomyManager.withdrawScrapper(player, salvageSession.salvageMethod);
}
session.scheduleAction();
@ -198,7 +198,7 @@ public abstract class CustomTrait<K extends Setting> extends Trait {
//Remove the item from the player's inventory
if (!isBlacksmith) {
// For scrappers, just reduce the amounts of items, unless the remaining stack is salvaged
int amount = ItemHelper.getRequiredAmountForSalvage(player.getServer(), heldItem);
int amount = SalvageHelper.getRequiredAmountForSalvage(player.getServer(), heldItem);
if (amount != heldItem.getAmount()) {
heldItem.setAmount(heldItem.getAmount() - amount);
playerInventory.setItemInMainHand(heldItem);

View File

@ -69,14 +69,14 @@ public class ReforgeSession extends Session implements Runnable {
@Override
public boolean isSessionInvalid() {
// Prevent player from switching items during session
ItemStack itemInHand = player.getInventory().getItemInMainHand();
ItemStack itemInHand = this.player.getInventory().getItemInMainHand();
if (!itemToReforge.equals(itemInHand)) {
sendNPCMessage(this.npc, player, config.getItemChangedMessage());
sendNPCMessage(this.npc, this.player, this.config.getItemChangedMessage());
return true;
}
// The player is unable to pay
if (EconomyManager.cannotPayForHeldItemReforge(player)) {
sendNPCMessage(this.npc, player, config.getInsufficientFundsMessage());
if (EconomyManager.cannotPayForHeldItemReforge(this.player)) {
sendNPCMessage(this.npc, this.player, this.config.getInsufficientFundsMessage());
return true;
}
return false;
@ -84,9 +84,9 @@ public class ReforgeSession extends Session implements Runnable {
@Override
protected int getActionDelay() {
if (config.getMaxReforgeDelay() > 0) {
if (this.config.getMaxReforgeDelay() > 0) {
//Finish the reforging after a random delay between the max and min
return new Random().nextInt(config.getMaxReforgeDelay()) + config.getMinReforgeDelay();
return new Random().nextInt(this.config.getMaxReforgeDelay()) + this.config.getMinReforgeDelay();
} else {
//Finish the salvaging as soon as possible
return 0;
@ -98,41 +98,41 @@ public class ReforgeSession extends Session implements Runnable {
*/
@Override
public void run() {
sendNPCMessage(this.npc, player, reforgeItem() ? config.getSuccessMessage() : config.getFailMessage());
sendNPCMessage(this.npc, this.player, reforgeItem() ? this.config.getSuccessMessage() : this.config.getFailMessage());
//Stop the reforged item from displaying in the blacksmith's hand
if (npc.getEntity() instanceof Player) {
((Player) npc.getEntity()).getInventory().setItemInMainHand(null);
if (this.npc.getEntity() instanceof Player) {
((Player) this.npc.getEntity()).getInventory().setItemInMainHand(null);
} else {
Objects.requireNonNull(((LivingEntity) npc.getEntity()).getEquipment()).setItemInMainHand(null);
Objects.requireNonNull(((LivingEntity) this.npc.getEntity()).getEquipment()).setItemInMainHand(null);
}
//Give the item back to the player
giveReforgedItem();
//Mark this blacksmith as available
blacksmithTrait.unsetSession();
this.blacksmithTrait.unsetSession();
// Start cool-down
Calendar wait = Calendar.getInstance();
wait.add(Calendar.SECOND, config.getReforgeCoolDown());
blacksmithTrait.addCoolDown(player.getUniqueId(), wait);
wait.add(Calendar.SECOND, this.config.getReforgeCoolDown());
this.blacksmithTrait.addCoolDown(this.player.getUniqueId(), wait);
}
/**
* Gives the reforged item back to the player
*/
private void giveReforgedItem() {
if (config.getMaxReforgeDelay() > 0) {
if (this.config.getMaxReforgeDelay() > 0) {
//If the player isn't online, or the player cannot fit the item, drop the item to prevent it from disappearing
if (config.getDropItem() || !player.isOnline() || player.getInventory().firstEmpty() == -1) {
player.getWorld().dropItemNaturally(npc.getEntity().getLocation(), itemToReforge);
if (this.config.getDropItem() || !this.player.isOnline() || this.player.getInventory().firstEmpty() == -1) {
this.player.getWorld().dropItemNaturally(this.npc.getEntity().getLocation(), this.itemToReforge);
} else {
player.getInventory().addItem(itemToReforge);
this.player.getInventory().addItem(this.itemToReforge);
}
} else {
//It can be assumed as this happens instantly, that the player still has the item's previous slot selected
player.getInventory().setItemInMainHand(itemToReforge);
this.player.getInventory().setItemInMainHand(this.itemToReforge);
}
}
@ -142,7 +142,7 @@ public class ReforgeSession extends Session implements Runnable {
* @return <p>Whether the reforge was successful. False if the blacksmith failed to fully repair the item.</p>
*/
private boolean reforgeItem() {
if (random.nextInt(100) < config.getFailChance()) {
if (random.nextInt(100) < this.config.getFailChance()) {
failReforge();
return false;
} else {
@ -156,18 +156,18 @@ public class ReforgeSession extends Session implements Runnable {
*/
private void succeedReforge() {
// Remove any damage done to the item
updateDamage(itemToReforge, 0);
updateDamage(this.itemToReforge, 0);
//Replace damaged anvils with a normal anvil
if (ItemHelper.isAnvil(itemToReforge.getType(), true)) {
itemToReforge.setType(Material.ANVIL);
if (ItemHelper.isAnvil(this.itemToReforge.getType(), true)) {
this.itemToReforge.setType(Material.ANVIL);
}
//See if a random roll (0-99) is less than extraEnchantmentChance, and add a random enchantment
int roll = random.nextInt(100);
if (roll < config.getExtraEnchantmentChance() &&
itemToReforge.getEnchantments().keySet().size() < config.getMaxEnchantments() &&
!ItemHelper.isAnvil(itemToReforge.getType(), false)) {
if (roll < this.config.getExtraEnchantmentChance() &&
this.itemToReforge.getEnchantments().keySet().size() < this.config.getMaxEnchantments() &&
!ItemHelper.isAnvil(this.itemToReforge.getType(), false)) {
addRandomEnchantment();
}
}
@ -180,12 +180,12 @@ public class ReforgeSession extends Session implements Runnable {
List<Enchantment> usableEnchantments = new ArrayList<>();
for (String enchantmentName : enchantments) {
Enchantment enchantment = InputParsingHelper.matchEnchantment(enchantmentName);
if (enchantment != null && enchantment.canEnchantItem(itemToReforge)) {
if (enchantment != null && enchantment.canEnchantItem(this.itemToReforge)) {
usableEnchantments.add(enchantment);
}
}
//Remove any enchantments in the block list
usableEnchantments.removeAll(blacksmithTrait.getSettings().getEnchantmentBlockList());
usableEnchantments.removeAll(this.blacksmithTrait.getSettings().getEnchantmentBlockList());
//In case all usable enchantments have been blocked, abort
if (usableEnchantments.isEmpty()) {
@ -198,10 +198,10 @@ public class ReforgeSession extends Session implements Runnable {
int randomBound = randomEnchantment.getMaxLevel() + 1;
//A workaround for the random method's bound sometimes being negative
if (randomBound >= 0) {
int existingLevel = itemToReforge.getEnchantmentLevel(randomEnchantment);
int existingLevel = this.itemToReforge.getEnchantmentLevel(randomEnchantment);
/* Add a random enchantment whose level is no lower than the start level, and no lower than the
existing level (to prevent making the item worse) */
itemToReforge.addEnchantment(randomEnchantment, Math.max(Math.max(random.nextInt(randomBound),
this.itemToReforge.addEnchantment(randomEnchantment, Math.max(Math.max(random.nextInt(randomBound),
randomEnchantment.getStartLevel()), existingLevel));
}
}
@ -211,20 +211,20 @@ public class ReforgeSession extends Session implements Runnable {
* The method to run when a blacksmith fails re-forging an item
*/
private void failReforge() {
if (config.getFailRemovesEnchantments()) {
if (this.config.getFailRemovesEnchantments()) {
removeOrDowngradeEnchantments();
}
//Damage the item
short currentItemDurability = ItemHelper.getDurability(itemToReforge);
short currentItemDurability = ItemHelper.getDurability(this.itemToReforge);
short newDurability = (short) (currentItemDurability + (currentItemDurability * random.nextInt(8)));
short maxDurability = itemToReforge.getType().getMaxDurability();
short maxDurability = this.itemToReforge.getType().getMaxDurability();
if (newDurability <= 0) {
newDurability = (short) (maxDurability / 3);
} else if (currentItemDurability + newDurability > maxDurability) {
newDurability = (short) (maxDurability - random.nextInt(maxDurability - 25));
}
updateDamage(itemToReforge, maxDurability - newDurability);
updateDamage(this.itemToReforge, maxDurability - newDurability);
}
/**
@ -232,13 +232,13 @@ public class ReforgeSession extends Session implements Runnable {
*/
private void removeOrDowngradeEnchantments() {
//Remove or downgrade existing enchantments
for (Enchantment enchantment : itemToReforge.getEnchantments().keySet()) {
for (Enchantment enchantment : this.itemToReforge.getEnchantments().keySet()) {
//Completely remove the enchantment, downgrade it, or keep it if lucky and already level 1
if (random.nextBoolean()) {
itemToReforge.removeEnchantment(enchantment);
} else if (itemToReforge.getEnchantmentLevel(enchantment) > 1) {
itemToReforge.removeEnchantment(enchantment);
itemToReforge.addEnchantment(enchantment, 1);
this.itemToReforge.removeEnchantment(enchantment);
} else if (this.itemToReforge.getEnchantmentLevel(enchantment) > 1) {
this.itemToReforge.removeEnchantment(enchantment);
this.itemToReforge.addEnchantment(enchantment, 1);
}
}
}

View File

@ -1,6 +1,7 @@
package net.knarcraft.blacksmith.trait;
import net.citizensnpcs.api.npc.NPC;
import net.knarcraft.blacksmith.config.SalvageMethod;
import net.knarcraft.blacksmith.config.scrapper.ScrapperNPCSettings;
import net.knarcraft.blacksmith.manager.EconomyManager;
import net.knarcraft.blacksmith.util.ItemHelper;
@ -30,6 +31,7 @@ public class SalvageSession extends Session implements Runnable {
private final ScrapperNPCSettings config;
private final List<ItemStack> salvage;
private final int enchantmentLevels;
protected final SalvageMethod salvageMethod;
private static final Random random = new Random();
/**
@ -39,9 +41,11 @@ public class SalvageSession extends Session implements Runnable {
* @param player <p>The player initiating the session</p>
* @param npc <p>The scrapper NPC involved in the session</p>
* @param config <p>The config to use for the session</p>
* @param salvageMethod <p>The salvage method performed in this session</p>
*/
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) {
super(player);
this.scrapperTrait = scrapperTrait;
this.npc = npc;
@ -49,19 +53,20 @@ public class SalvageSession extends Session implements Runnable {
this.config = config;
this.salvage = salvage;
this.enchantmentLevels = SalvageHelper.getTotalEnchantmentLevels(this.itemToSalvage);
this.salvageMethod = salvageMethod;
}
@Override
public boolean isSessionInvalid() {
// Prevent player from switching items during session
ItemStack itemInHand = player.getInventory().getItemInMainHand();
ItemStack itemInHand = this.player.getInventory().getItemInMainHand();
if (!itemToSalvage.equals(itemInHand)) {
sendNPCMessage(this.npc, player, config.getItemChangedMessage());
sendNPCMessage(this.npc, this.player, this.config.getItemChangedMessage());
return true;
}
if (EconomyManager.cannotPayForSalvage(player)) {
sendNPCMessage(this.npc, player, config.getInsufficientFundsMessage());
if (EconomyManager.cannotPayForSalvage(this.player, this.salvageMethod)) {
sendNPCMessage(this.npc, this.player, this.config.getInsufficientFundsMessage());
return true;
}
return false;
@ -69,9 +74,9 @@ public class SalvageSession extends Session implements Runnable {
@Override
protected int getActionDelay() {
if (config.getMaxSalvageDelay() > 0) {
if (this.config.getMaxSalvageDelay() > 0) {
//Finish the salvaging after a random delay between the max and min
return new Random().nextInt(config.getMaxSalvageDelay()) + config.getMinSalvageDelay();
return new Random().nextInt(this.config.getMaxSalvageDelay()) + this.config.getMinSalvageDelay();
} else {
//Finish the salvaging as soon as possible
return 0;
@ -83,22 +88,22 @@ public class SalvageSession extends Session implements Runnable {
*/
@Override
public void run() {
sendNPCMessage(this.npc, player, salvageItem() ? config.getSuccessMessage() : config.getFailMessage());
sendNPCMessage(this.npc, this.player, salvageItem() ? this.config.getSuccessMessage() : this.config.getFailMessage());
//Stop the reforged item from displaying in the scrapper's hand
if (npc.getEntity() instanceof Player) {
((Player) npc.getEntity()).getInventory().setItemInMainHand(null);
if (this.npc.getEntity() instanceof Player) {
((Player) this.npc.getEntity()).getInventory().setItemInMainHand(null);
} else {
Objects.requireNonNull(((LivingEntity) npc.getEntity()).getEquipment()).setItemInMainHand(null);
Objects.requireNonNull(((LivingEntity) this.npc.getEntity()).getEquipment()).setItemInMainHand(null);
}
//Mark this scrapper as available
scrapperTrait.unsetSession();
this.scrapperTrait.unsetSession();
// Start cool-down
Calendar wait = Calendar.getInstance();
wait.add(Calendar.SECOND, config.getSalvageCoolDown());
scrapperTrait.addCoolDown(player.getUniqueId(), wait);
wait.add(Calendar.SECOND, this.config.getSalvageCoolDown());
this.scrapperTrait.addCoolDown(this.player.getUniqueId(), wait);
}
/**
@ -107,7 +112,7 @@ public class SalvageSession extends Session implements Runnable {
* @return <p>True if the salvage was successful. False otherwise.</p>
*/
private boolean salvageItem() {
if (random.nextInt(100) < config.getFailChance()) {
if (random.nextInt(100) < this.config.getFailChance()) {
failSalvage();
return false;
} else {
@ -121,19 +126,19 @@ public class SalvageSession extends Session implements Runnable {
* The method to run when a crapper fails salvaging an item
*/
private void failSalvage() {
if (itemToSalvage.getItemMeta() instanceof Damageable) {
if (this.itemToSalvage.getItemMeta() instanceof Damageable) {
//Damage the item
short currentItemDurability = ItemHelper.getDurability(itemToSalvage);
short currentItemDurability = ItemHelper.getDurability(this.itemToSalvage);
short newDurability = (short) (currentItemDurability + (currentItemDurability * random.nextInt(8)));
short maxDurability = itemToSalvage.getType().getMaxDurability();
short maxDurability = this.itemToSalvage.getType().getMaxDurability();
if (newDurability <= 0) {
newDurability = (short) (maxDurability / 3);
} else if (currentItemDurability + newDurability > maxDurability) {
newDurability = (short) (maxDurability - random.nextInt(maxDurability - 25));
}
updateDamage(itemToSalvage, maxDurability - newDurability);
updateDamage(this.itemToSalvage, maxDurability - newDurability);
} else {
itemToSalvage.setAmount(Math.max(itemToSalvage.getAmount() - 1, 1));
this.itemToSalvage.setAmount(Math.max(this.itemToSalvage.getAmount() - 1, 1));
}
}
@ -143,20 +148,20 @@ public class SalvageSession extends Session implements Runnable {
private void giveSalvage() {
// TODO: Find a better calculation than 1 enchantment level = 1 exp level
// Gives the player back some of the EXP used on an item
player.giveExpLevels(enchantmentLevels);
if (config.getDropItem() || !player.isOnline() || player.getInventory().firstEmpty() == -1) {
this.player.giveExpLevels(this.enchantmentLevels);
if (this.config.getDropItem() || !this.player.isOnline() || this.player.getInventory().firstEmpty() == -1) {
// If the player isn't online, or the player cannot fit the item, drop the item to prevent it from
// disappearing, even if drop item is disabled.
for (ItemStack item : salvage) {
player.getWorld().dropItemNaturally(npc.getEntity().getLocation(), item);
for (ItemStack item : this.salvage) {
this.player.getWorld().dropItemNaturally(this.npc.getEntity().getLocation(), item);
}
} else {
for (ItemStack item : salvage) {
if (ItemHelper.canFitItem(player.getInventory(), item)) {
player.getInventory().addItem(item);
for (ItemStack item : this.salvage) {
if (ItemHelper.canFitItem(this.player.getInventory(), item)) {
this.player.getInventory().addItem(item);
} else {
// If the player cannot fit all the salvage, drop it on the ground
player.getWorld().dropItemNaturally(player.getLocation(), item);
this.player.getWorld().dropItemNaturally(this.player.getLocation(), item);
}
}
}

View File

@ -2,15 +2,18 @@ package net.knarcraft.blacksmith.trait;
import net.citizensnpcs.api.util.DataKey;
import net.knarcraft.blacksmith.BlacksmithPlugin;
import net.knarcraft.blacksmith.config.SalvageMethod;
import net.knarcraft.blacksmith.config.SmithPreset;
import net.knarcraft.blacksmith.config.SmithPresetFilter;
import net.knarcraft.blacksmith.config.scrapper.ScrapperNPCSettings;
import net.knarcraft.blacksmith.config.scrapper.ScrapperSetting;
import net.knarcraft.blacksmith.manager.EconomyManager;
import net.knarcraft.blacksmith.util.ItemHelper;
import net.knarcraft.blacksmith.util.SalvageHelper;
import net.knarcraft.knarlib.formatting.StringFormatter;
import net.knarcraft.knarlib.formatting.StringReplacer;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.Server;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ArmorMeta;
@ -82,7 +85,7 @@ public class ScrapperTrait extends CustomTrait<ScrapperSetting> {
boolean extended = getSettings().extendedSalvageEnabled();
// Check if the item can be salvaged
if (!canBeSalvaged(player.getServer(), itemInHand, salvageAbleItems, extended)) {
if (!canBeSalvaged(itemInHand, salvageAbleItems, extended)) {
sendNPCMessage(this.npc, player, StringFormatter.replacePlaceholder(getSettings().getInvalidItemMessage(),
"{title}", getSettings().getScrapperTitle()));
return;
@ -91,18 +94,35 @@ public class ScrapperTrait extends CustomTrait<ScrapperSetting> {
List<ItemStack> salvage = null;
// Deal with armor trim salvage
boolean salvagingArmorTrim = false;
SalvageMethod salvageMethod = SalvageMethod.SALVAGE;
if (itemInHand.getItemMeta() instanceof ArmorMeta armorMeta && armorMeta.hasTrim()) {
if (!getSettings().salvageArmorTrims()) {
sendNPCMessage(this.npc, player, getSettings().getCannotSalvageArmorTrimMessage());
return;
}
salvage = SalvageHelper.getTrimSalvage(itemInHand, armorMeta);
salvage = SalvageHelper.getArmorTrimSalvage(itemInHand, armorMeta);
if (salvage == null) {
sendNPCMessage(this.npc, player, getSettings().getArmorTrimSalvageNotFoundMessage());
return;
}
salvagingArmorTrim = true;
salvageMethod = SalvageMethod.ARMOR_TRIM;
}
// Remove the netherite ingot from the item
if (salvage == null && SmithPreset.BLACKSMITH.getFilteredMaterials(SmithPresetFilter.NETHERITE).contains(itemInHand.getType())) {
if (!getSettings().salvageNetherite()) {
sendNPCMessage(this.npc, player, getSettings().getCannotSalvageNetheriteMessage());
return;
}
salvage = SalvageHelper.getNetheriteSalvage(itemInHand);
salvageMethod = SalvageMethod.NETHERITE;
}
// As there is no recipe for netherite items, the check needs to be after the netherite salvage check
if (salvageMethod == SalvageMethod.SALVAGE && !SalvageHelper.isSalvageable(player.getServer(), itemInHand)) {
sendNPCMessage(this.npc, player, StringFormatter.replacePlaceholder(getSettings().getInvalidItemMessage(),
"{title}", getSettings().getScrapperTitle()));
}
// Check if the item is enchanted, and whether this blacksmith can salvage it
@ -121,26 +141,53 @@ public class ScrapperTrait extends CustomTrait<ScrapperSetting> {
return;
}
//Start a new scrapper session for the player
startSession(player, salvage, salvageMethod);
// Print the cost to the player
printCostMessage(player, itemInHand, EconomyManager.formatSalvageCost(salvageMethod), salvageMethod);
}
/**
* Prints a message to the given player, explaining the cost of salvaging the held item
*
* @param player <p>The player that interacted with the scrapper</p>
* @param itemInHand <p>The item the player wants to salvage</p>
* @param cost <p>The cost of salvaging the item</p>
* @param salvageMethod <p>The type of salvage performed</p>
*/
private void printCostMessage(@NotNull Player player, @NotNull ItemStack itemInHand, @NotNull String cost,
@NotNull SalvageMethod salvageMethod) {
StringReplacer replacer = new StringReplacer();
replacer.add("{cost}", cost);
replacer.add("{item}", itemInHand.getType().name().toLowerCase().replace('_', ' '));
if (salvageMethod == SalvageMethod.ARMOR_TRIM) {
sendNPCMessage(this.npc, player, replacer.replace(getSettings().getArmorTrimCostMessage()));
} else if (salvageMethod == SalvageMethod.SALVAGE) {
String expectedYield;
if (ItemHelper.getDamage(itemInHand) <= 0) {
expectedYield = getSettings().getFullSalvageMessage();
} else {
expectedYield = getSettings().getPartialSalvageMessage();
}
replacer.add("{yield}", expectedYield);
sendNPCMessage(this.npc, player, replacer.replace(getSettings().getCostMessage()));
} else if (salvageMethod == SalvageMethod.NETHERITE) {
sendNPCMessage(this.npc, player, replacer.replace(getSettings().getNetheriteCostMessage()));
}
}
/**
* Starts a new scrapper session
*
* @param player <p>The player to start the session for</p>
* @param salvage <p>The salvage to return to the player</p>
* @param salvageMethod <p>The type of salvage performed</p>
*/
private void startSession(@NotNull Player player, @NotNull List<ItemStack> salvage,
@NotNull SalvageMethod salvageMethod) {
//Start a new scrapper session for the player
currentSessionStartTime = System.currentTimeMillis();
session = new SalvageSession(this, player, npc, getSettings(), salvage);
//Tell the player the cost of repairing the item
String cost = EconomyManager.formatScrapperCost();
String expectedYield;
if (ItemHelper.getDamage(itemInHand) <= 0) {
expectedYield = getSettings().getFullSalvageMessage();
} else {
expectedYield = getSettings().getPartialSalvageMessage();
}
if (salvagingArmorTrim) {
sendNPCMessage(this.npc, player, StringFormatter.replacePlaceholder(getSettings().getArmorTrimCostMessage(),
"{cost}", cost));
} else {
sendNPCMessage(this.npc, player, StringFormatter.replacePlaceholders(getSettings().getCostMessage(),
List.of("{cost}", "{yield}"), List.of(cost, expectedYield)));
}
session = new SalvageSession(this, player, npc, getSettings(), salvage, salvageMethod);
}
@Override
@ -151,17 +198,14 @@ public class ScrapperTrait extends CustomTrait<ScrapperSetting> {
/**
* Gets whether this scrapper can salvage the given item
*
* @param server <p>The server to get recipes from</p>
* @param item <p>The item to check</p>
* @param salvageAbleItems <p>The items this scrapper can salvage</p>
* @param extended <p>Whether extended salvage is enabled</p>
* @return <p>True if the item can be theoretically salvaged</p>
*/
private boolean canBeSalvaged(@NotNull Server server, @NotNull ItemStack item,
@NotNull List<Material> salvageAbleItems, boolean extended) {
return (extended || ItemHelper.isRepairable(item)) && ItemHelper.isSalvageable(server, item) &&
(salvageAbleItems.isEmpty() || salvageAbleItems.contains(item.getType())) &&
SalvageHelper.hasRecipe(item);
private boolean canBeSalvaged(@NotNull ItemStack item, @NotNull List<Material> salvageAbleItems, boolean extended) {
return (extended || ItemHelper.isRepairable(item)) &&
(salvageAbleItems.isEmpty() || salvageAbleItems.contains(item.getType()));
}
/**

View File

@ -110,6 +110,7 @@ public final class ConfigHelper {
/**
* Changes all configuration values from the old name to the new name
*
* @param dataFolderPath <p>The path to this plugin's data</p>
* @param currentConfiguration <p>The current config to back up</p>
*/
public static void migrateConfig(@NotNull String dataFolderPath, @NotNull FileConfiguration currentConfiguration) {

View File

@ -3,11 +3,8 @@ package net.knarcraft.blacksmith.util;
import net.knarcraft.blacksmith.BlacksmithPlugin;
import net.knarcraft.blacksmith.config.SmithPreset;
import org.bukkit.Material;
import org.bukkit.Server;
import org.bukkit.inventory.CraftingRecipe;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.Recipe;
import org.bukkit.inventory.meta.Damageable;
import org.bukkit.inventory.meta.ItemMeta;
import org.jetbrains.annotations.NotNull;
@ -168,40 +165,6 @@ public final class ItemHelper {
return false;
}
/**
* Checks whether the given item can be salvaged, assuming no restrictions apply
*
* @param server <p>The server to get recipes from</p>
* @param item <p>The item to check</p>
* @return <p>True if the item can be salvaged</p>
*/
public static boolean isSalvageable(@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 CraftingRecipe) && item.getAmount() >= recipe.getResult().getAmount()) {
return true;
}
}
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 CraftingRecipe) {
return recipe.getResult().getAmount();
}
}
return -1;
}
/**
* Gets all materials matching the given material wildcard
*

View File

@ -1,6 +1,5 @@
package net.knarcraft.blacksmith.util;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.Server;
import org.bukkit.enchantments.Enchantment;
@ -43,6 +42,29 @@ public final class SalvageHelper {
trimMaterialToMaterial.put(TrimMaterial.REDSTONE, Material.REDSTONE);
}
/**
* Gets salvage for a given netherite item
*
* @param item <p>The netherite armor/tool to salvage</p>
* @return <p></p>
*/
@Nullable
public static List<ItemStack> getNetheriteSalvage(@NotNull ItemStack item) {
Material newMaterial = Material.matchMaterial(item.getType().name().replace("NETHERITE", "DIAMOND"));
if (newMaterial == null) {
return null;
}
ItemStack clone = item.clone();
clone.setType(newMaterial);
List<ItemStack> salvage = new ArrayList<>();
salvage.add(clone);
salvage.add(new ItemStack(Material.NETHERITE_INGOT, 1));
salvage.add(new ItemStack(Material.NETHERITE_UPGRADE_SMITHING_TEMPLATE, 1));
return salvage;
}
/**
* Gets salvage for the given armor trim
*
@ -51,7 +73,7 @@ public final class SalvageHelper {
* @return <p>The salvage, or null if salvage could not be calculated</p>
*/
@Nullable
public static List<ItemStack> getTrimSalvage(@NotNull ItemStack item, @NotNull ArmorMeta armorMeta) {
public static List<ItemStack> getArmorTrimSalvage(@NotNull ItemStack item, @NotNull ArmorMeta armorMeta) {
ArmorTrim armorTrim = armorMeta.getTrim();
if (armorTrim == null) {
return null;
@ -82,22 +104,41 @@ public final class SalvageHelper {
}
/**
* Gets whether the given item has a valid crafting recipe
* Checks whether the given item can be salvaged, assuming no restrictions apply
*
* @param item <p>The item to check</p>
* @return <p>True if the item has a valid crafting recipe</p>
* @param server <p>The server to get recipes from</p>
* @param item <p>The item to check</p>
* @return <p>True if the item can be salvaged</p>
*/
public static boolean hasRecipe(@NotNull ItemStack item) {
List<Recipe> recipes = Bukkit.getRecipesFor(new ItemStack(item.getType(), item.getAmount()));
public static boolean isSalvageable(@NotNull Server server, @NotNull ItemStack item) {
List<Recipe> recipes = server.getRecipesFor(new ItemStack(item.getType(), item.getAmount()));
for (Recipe recipe : recipes) {
if (recipe instanceof ShapedRecipe || recipe instanceof ShapelessRecipe) {
// Only crafting recipes are allowed.
if ((recipe instanceof ShapedRecipe || recipe instanceof ShapelessRecipe) &&
item.getAmount() >= recipe.getResult().getAmount()) {
return true;
}
}
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
*

View File

@ -116,8 +116,8 @@ blacksmith:
scrapper:
# The settings which apply to all Scrapper NPCs. These can also be changed using the /scrapperConfig command
global:
# Exact time displays the exact number of seconds and minutes remaining as part of the scrapping cool-down and
# scrapping delay messages, instead of just vaguely hinting at the remaining time.
# Exact time displays the exact number of seconds and minutes remaining as part of the salvaging cool-down and
# salvaging delay messages, instead of just vaguely hinting at the remaining time.
showExactTime: false
# Whether enchanted salvaged items should return some amount of exp upon salvage
@ -130,14 +130,20 @@ scrapper:
trashSalvage:
- "*_SHOVEL;*_PICKAXE;*_AXE;*_HOE;*_SWORD;SHIELD;*_BOW:STICK"
# The cost of using the scrapper
basePrice: 0
# The cost of using a scrapper to salvage an item
salvagePrice: 0
# The cost of using the scrapper to remove armor trim
armorTrimSalvagePrice: 5
# The cost of using the scrapper to remove netherite from an item
netheriteSalvagePrice: 15
# 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
defaults:
# Whether the item will drop materials resulting from scrapping on the ground, instead of putting them into the user's inventory
# Whether the item will drop materials resulting from salvaging on the ground, instead of putting them into the user's inventory
dropItem: true
# The chance to fail a salvage, thus destroying the item (0-100)
@ -170,6 +176,9 @@ scrapper:
# Whether to enable salvaging of armor trims
salvageArmorTrims: true
# Whether to enable salvaging of netherite items
salvageNetherite: true
# Default values for messages used by NPCs
messages:
# The message to display when another player is using the scrapper
@ -203,10 +212,13 @@ scrapper:
insufficientFundsMessage: "&cYou don't have enough money to salvage an item!"
# The message to display when explaining the shown item's salvage cost
costMessage: "&eIt will cost &a{cost}&e to salvage that item! {yield} &eClick again to salvage!"
costMessage: "&eIt will cost &a{cost}&e to salvage that &a{item}&e! {yield} &eClick again to salvage!"
# The message to display when explaining the shown item's armor trim's salvage cost
costMessageArmorTrim: "&eIt will cost &a{cost}&e to salvage that armor trim!"
costMessageArmorTrim: "&eIt will cost &a{cost}&e to salvage that &a{item}&e's armor trim!"
# 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!"
# 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"
@ -222,3 +234,6 @@ scrapper:
# The message to display if the correct materials to return for the armor trim are unknown
armorTrimSalvageNotFoundMessage: "&cI'm sorry, but I don't know how to salvage that armor trim!"
# 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!"