Finishes the scrapper implementation
Some checks failed
EpicKnarvik97/Blacksmith/pipeline/head There was a failure building this commit

This commit is contained in:
Kristian Knarvik 2024-05-04 01:01:56 +02:00
parent 455db78988
commit 4012e532da
30 changed files with 501 additions and 216 deletions

View File

@ -26,41 +26,57 @@ fee. Costs are highly customizable.
To create a new blacksmith, simply add the blacksmith trait to an NPC by selecting it with `/npc select`, and then using To create a new blacksmith, simply add the blacksmith trait to an NPC by selecting it with `/npc select`, and then using
`/trait add Blacksmith` (See Citizens' documentation for more details). `/trait add Blacksmith` (See Citizens' documentation for more details).
Right-clicking the NPC will tell you if the currently held item is repairable by the blacksmith. If it is, the To create a new scrapper, simply add the scrapper trait to an NPC by selecting it with `/npc select`, and then using
blacksmith should give a price quote. Right-clicking again starts the repair. The item should be given back or dropped `/trait add Scrapper` (See Citizens' documentation for more details).
after a random delay according to the set limits.
While costs are always set globally (no blacksmith can do the same job for cheaper), the blacksmith's messages, Right-clicking the NPC will tell you if the currently held item is repairable by the blacksmith / salvageable by the
cool-down between each reforge, whether the item is dropped or given, the chance of failing or adding an enchantment, scrapper. If it is, the blacksmith / scrapper should give a price quote. Right-clicking again starts the repair /
the maximum number of added enchantments, max and min delays, the length of the cool-down and which items the blacksmith salvage. The item should be given back or dropped after a random delay according to the set limits.
is able to reforge can be changed individually.
While costs are always set globally (no blacksmith or scrapper can do the same job for cheaper), the blacksmith /
scrapper's messages, cool-down between each reforge / salvage, whether the item is dropped or given, the chance of
failing or adding an enchantment, the maximum number of added enchantments, max and min delays, the length of the
cool-down and which items the blacksmith is able to reforge / salvage can be changed individually.
Also note: As a change from the original plugin, unless a value for an NPC has been explicitly set for that NPC, it will Also note: As a change from the original plugin, unless a value for an NPC has been explicitly set for that NPC, it will
mirror the values set in config.yml. This also means that configuration values aren't populated automatically in mirror the values set in config.yml. This also means that configuration values aren't populated automatically in
citizen's NPC save file. While you can manually set the values using the same keys as in config.yml, you should use the citizen's NPC save file. While you can manually set the values using the same keys as in config.yml, you should use the
/blacksmith command when possible. `/blacksmith` or `/scrapper` command when possible.
### Special behavior ### Special behavior
In addition to just being able to repair items, blacksmiths have some random features which can be cool or annoying: In addition to just being able to repair items, blacksmiths / scrappers have some random features which can be cool or
annoying:
- There is a chance that blacksmiths fail to repair an item, leaving it at about the same durability as before. Use - There is a chance that blacksmiths / scrappers fail to repair an item, leaving it at about the same durability as
before (scrappers with `extendedSalvageEnabled` turned on might cause items in a stack to be lost). Use
failReforgeChance to control the chance. Set it to 0 to remove the feature. failReforgeChance to control the chance. Set it to 0 to remove the feature.
- There is a chance a blacksmith may add an enchantment to a reforged item. You can control the probability using - There is a chance a blacksmith may add an enchantment to a reforged item. You can control the probability using
extraEnchantmentChance, and set the maximum number of enchantments using maxEnchantments. EnchantmentBlocklist can be extraEnchantmentChance, and set the maximum number of enchantments using maxEnchantments. EnchantmentBlockList can be
used to block any enchantments you don't want to randomly grant. used to block any enchantments you don't want to randomly grant.
### Scrapper basics
A scrapper will produce salvage for a damage-able item by calculating the amount of items returned based on items in the
recipe, and the percentage of durability left on the item. To avoid returning relatively worthless items instead of
valuable items, `ignoredSalvage` can be configured. If the item is fully repaired, the worthless items will be returned
as well, but otherwise, only the valuable items are considered as possible salvage. A scrapper will by default only
salvage damage-able items (same as blacksmiths), but enabling `extendedSalvageEnabled` for a scrapper will allow it to
salvage any crafting table recipe. Note that to salvage for example planks into wood, four wood will be taken.
When an item is salvaged, EXP will be returned based on enchantments on the item.
## Commands ## Commands
| Command | Arguments | Description | | Command | Arguments | Description |
|-------------------|-------------------------------|----------------------------------------------------------------------------------------------| |-------------------|-------------------------------|----------------------------------------------------------------------------------------------|
| /blacksmith | \<option> \[new-value] | Changes a configuration option for the selected blacksmith (use Citizens' /npc select first) | | /blacksmith | \<option> \[new-value] | Changes a configuration option for the selected blacksmith (use Citizens' /npc select first) |
| /blacksmithconfig | \<reload/option> \[new-value] | Changes a default/global blacksmith configuration value | | /blacksmithConfig | \<reload/option> \[new-value] | Changes a default/global blacksmith configuration value |
| /scrapper | \<option> \[new-value] | Changes a configuration option for the selected scrapper (use Citizens' /npc select first) | | /scrapper | \<option> \[new-value] | Changes a configuration option for the selected scrapper (use Citizens' /npc select first) |
| /scrapperconfig | \<reload/option> \[new-value] | Changes a default/global scrapper configuration value | | /scrapperConfig | \<reload/option> \[new-value] | Changes a default/global scrapper configuration value |
| /preset | \<preset>\[:filter] | Displays all materials included in the given preset, after applying the filter if set | | /preset | \<preset>\[:filter] | Displays all materials included in the given preset, after applying the filter if set |
For /blacksmith, /blacksmithconfig, /scrapper and /scrapperconfig, if a new value isn't specified, a description of the For /blacksmith, /blacksmithConfig, /scrapper and /scrapperConfig, if a new value isn't specified, a description of the
configuration option, and the current value, is displayed instead. configuration option, and the current value, is displayed instead.
For /blacksmith or /scrapper, using -1 or null as the value will clear a custom value, making the NPC use the default For /blacksmith or /scrapper, using -1 or null as the value will clear a custom value, making the NPC use the default
@ -171,15 +187,15 @@ All currently supported presets, and available filters for each preset:
| failReforgeRemovesEnchantments | true/false | Whether a failed reforge should remove or downgrade all enchantments on the item. | | failReforgeRemovesEnchantments | true/false | Whether a failed reforge should remove or downgrade all enchantments on the item. |
| extraEnchantmentChance | 0-100 | The chance of the blacksmith adding an enchantment to an item. | | extraEnchantmentChance | 0-100 | The chance of the blacksmith adding an enchantment to an item. |
| maxEnchantments | 0-10 | The maximum number of different enchantments a blacksmith can add. | | maxEnchantments | 0-10 | The maximum number of different enchantments a blacksmith can add. |
| maxReforgeDelay | 0-3600 | The maximum number of seconds a player needs to wait for an item to be repaired. | | maxReforgeWaitTimeSeconds | 0-3600 | The maximum number of seconds a player needs to wait for an item to be repaired. |
| minReforgeDelay | 0-3600 | The minimum number of seconds a player needs to wait for an item to be repaired. | | minReforgeWaitTimeSeconds | 0-3600 | The minimum number of seconds a player needs to wait for an item to be repaired. |
| reforgeCoolDown | 0-3600 | The cool-down, in seconds, a player has to wait between each time they use one specific blacksmith. | | reforgeCoolDownSeconds | 0-3600 | The cool-down, in seconds, a player has to wait between each time they use one specific blacksmith. |
| reforgeAbleItems | DIAMOND_LEGGINGS,GOLD-pickaxe,bow, etc. | Specifies which items this blacksmith is able to reforge. If set to "" or null, all normally repairable items can be repaired. If set to a list of items, only the items specified can be repaired. Some presets have been included for ease of use. Use a preset by specifying "preset:sword-smith" instead of a material such as "gold-pickaxe". | | reforgeAbleItems | DIAMOND_LEGGINGS,GOLD-pickaxe,bow, etc. | Specifies which items this blacksmith is able to reforge. If set to "" or null, all normally repairable items can be repaired. If set to a list of items, only the items specified can be repaired. Some presets have been included for ease of use. Use a preset by specifying "preset:sword-smith" instead of a material such as "gold-pickaxe". |
| blacksmithTitle | text string | The title displayed as part of the message explaining that a blacksmith doesn't recognize a player's held item | | blacksmithTitle | text string | The title displayed as part of the message explaining that a blacksmith doesn't recognize a player's held item |
| enchantmentBlocklist | string list | A string list of all enchantments a blacksmith should not be allowed to add to items. | | enchantmentBlockList | string list | A string list of all enchantments a blacksmith should not be allowed to add to items. |
| reforgeAnvils | true/false | Whether to allow the blacksmith to reforge anvils. If enabled, chipped and damaged anvils will be replaced with a normal anvil. | | reforgeAnvils | true/false | Whether to allow the blacksmith to reforge anvils. If enabled, chipped and damaged anvils will be replaced with a normal anvil. |
#### Blacksmith per-npc messages (with default values set in config.yml) #### Messages
| Message Key | Explanation | | Message Key | Explanation |
|--------------------------|-----------------------------------------------------------------------------------------------------------------| |--------------------------|-----------------------------------------------------------------------------------------------------------------|
@ -195,6 +211,46 @@ All currently supported presets, and available filters for each preset:
| successMessage | The message displayed when a blacksmith successfully repairs an item | | successMessage | The message displayed when a blacksmith successfully repairs an item |
| notDamagedMessage | The message displayed if a player tries to reforge an item with full durability | | notDamagedMessage | The message displayed if a player tries to reforge an item with full durability |
### Scrapper global-only options
| Key | Value type | Description |
|----------------|----------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| basePrice | positive decimal number | The cost of using a scrapper |
| showExactTime | true/false | If true, scrappers will display exact time remaining in minutes and seconds, instead of vague expressions |
| giveExperience | true/false | If true, each enchantment level on the salvaged item will give one EXP level as salvage |
| ignoredSalvage | TARGET_MATERIAL:IGNORED_MATERIAL | The items that should be ignored when calculating partial salvage. Because receiving just the sticks when salvaging a diamond pickaxe is kind of sad, this allows specifying for example: `*_SHOVEL;*_PICKAXE;*_AXE;*_HOE;*_SWORD:STICK` (the default) for ignoring sticks in salvage for shovels, pickaxes, axes, hoes and swords. A `:` character splits selected items and the ignored salvage. Different item specifications are split by a `;` character. Use `,` to split separate ignored salvages, like: `SHIELD:STICK,BOW_STRING` |
### Scrapper per-npc (with default values set in config.yml)
#### Configuration values
| Key | Value type | Description |
|---------------------------|-----------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| dropItem | true/false | Whether the scrapper should drop the repaired item on the ground (instead of putting it into the player's inventory). |
| failSalvageChance | 0-100 | The chance of the scrapper failing to salvage an item, either further damaging the item, partly repairing the item or causing some items to disappear. |
| salvageAbleItems | DIAMOND_LEGGINGS,GOLD-pickaxe,bow, etc. | Specifies which items this scrapper is able to salvage. If set to "" or null, all normally repairable items can be salvaged. If set to a list of items, only the items specified can be salvaged. Some presets have been included for ease of use. Use a preset by specifying "preset:sword-smith" instead of a material such as "gold-pickaxe". |
| maxSalvageWaitTimeSeconds | 0-3600 | The maximum number of seconds a player needs to wait for an item to be salvaged. |
| minSalvageWaitTimeSeconds | 0-3600 | The minimum number of seconds a player needs to wait for an item to be salvaged. |
| salvageCoolDownSeconds | 0-3600 | The cool-down, in seconds, a player has to wait between each time they use one specific scrapper. |
| scrapperTitle | text string | The title displayed as part of the message explaining that a scrapper doesn't recognize a player's held item |
| extendedSalvageEnabled | true/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. |
#### Messages
| Message Key | Explanation |
|-----------------------------|---------------------------------------------------------------------------------------------------------------|
| busyPlayerMessage | The message displayed when the scrapper is serving another player |
| busySalvageMessage | The message displayed when the scrapper is busy salvaging an item |
| coolDownUnexpiredMessage | The message displayed when the player has to wait for the cool-down to expire before using the scrapper again |
| invalidItemMessage | The message displayed when a scrapper is presented an item which it cannot salvage |
| tooDamagedForSalvageMessage | The message displayed when a scrapper is presented with an item too damaged to produce salvage. |
| successSalvagedMessage | The message displayed when a scrapper successfully repairs an item |
| failSalvageMessage | The message displayed when a scrapper fails to salvage an item |
| itemChangedMessage | The message displayed when a player changes their item after being shown the salvage cost |
| startSalvageMessage | The message displayed when a scrapper starts salvaging an item |
| insufficientFundsMessage | The message displayed when a player is unable to pay for scrapping an item |
| costMessage | The message displayed when telling a player about the cost of scrapping an item |
## Language customization ## Language customization
All strings, even time units, are customizable. If you place a strings.yml file in the plugin folder, it will take All strings, even time units, are customizable. If you place a strings.yml file in the plugin folder, it will take

20
pom.xml
View File

@ -75,7 +75,7 @@
<dependency> <dependency>
<groupId>com.github.MilkBowl</groupId> <groupId>com.github.MilkBowl</groupId>
<artifactId>VaultAPI</artifactId> <artifactId>VaultAPI</artifactId>
<version>1.7</version> <version>1.7.1</version>
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
<dependency> <dependency>
@ -119,7 +119,7 @@
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId> <artifactId>maven-shade-plugin</artifactId>
<version>3.2.4</version> <version>3.3.0</version>
<executions> <executions>
<execution> <execution>
<phase>package</phase> <phase>package</phase>
@ -128,6 +128,16 @@
</goals> </goals>
<configuration> <configuration>
<createDependencyReducedPom>false</createDependencyReducedPom> <createDependencyReducedPom>false</createDependencyReducedPom>
<relocations>
<relocation>
<pattern>net.knarcraft.knarlib</pattern>
<shadedPattern>net.knarcraft.blacksmith.lib.knarlib</shadedPattern>
</relocation>
<relocation>
<pattern>org.jetbrains.annotations</pattern>
<shadedPattern>net.knarcraft.blacksmith.lib.annotations</shadedPattern>
</relocation>
</relocations>
<filters> <filters>
<filter> <filter>
<artifact>net.knarcraft:knarlib</artifact> <artifact>net.knarcraft:knarlib</artifact>
@ -135,6 +145,12 @@
<include>net/knarcraft/knarlib/**</include> <include>net/knarcraft/knarlib/**</include>
</includes> </includes>
</filter> </filter>
<filter>
<artifact>org.jetbrains:annotations</artifact>
<includes>
<include>org/jetbrains/annotations/**</include>
</includes>
</filter>
<filter> <filter>
<excludes> <excludes>
<exclude>*.MF</exclude> <exclude>*.MF</exclude>

View File

@ -1,6 +1,8 @@
package net.knarcraft.blacksmith; package net.knarcraft.blacksmith;
import net.citizensnpcs.api.CitizensAPI; import net.citizensnpcs.api.CitizensAPI;
import net.citizensnpcs.api.trait.TraitFactory;
import net.citizensnpcs.api.trait.TraitInfo;
import net.knarcraft.blacksmith.command.PresetCommand; import net.knarcraft.blacksmith.command.PresetCommand;
import net.knarcraft.blacksmith.command.PresetTabCompleter; import net.knarcraft.blacksmith.command.PresetTabCompleter;
import net.knarcraft.blacksmith.command.blacksmith.BlackSmithConfigCommand; import net.knarcraft.blacksmith.command.blacksmith.BlackSmithConfigCommand;
@ -18,6 +20,7 @@ import net.knarcraft.blacksmith.listener.NPCClickListener;
import net.knarcraft.blacksmith.listener.PlayerListener; import net.knarcraft.blacksmith.listener.PlayerListener;
import net.knarcraft.blacksmith.manager.EconomyManager; import net.knarcraft.blacksmith.manager.EconomyManager;
import net.knarcraft.blacksmith.trait.BlacksmithTrait; import net.knarcraft.blacksmith.trait.BlacksmithTrait;
import net.knarcraft.blacksmith.trait.ScrapperTrait;
import net.knarcraft.knarlib.formatting.StringFormatter; import net.knarcraft.knarlib.formatting.StringFormatter;
import net.knarcraft.knarlib.formatting.TranslatableTimeUnit; import net.knarcraft.knarlib.formatting.TranslatableTimeUnit;
import net.knarcraft.knarlib.formatting.Translator; import net.knarcraft.knarlib.formatting.Translator;
@ -38,6 +41,7 @@ import org.jetbrains.annotations.Nullable;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.util.Arrays;
import java.util.Map; import java.util.Map;
import java.util.logging.Level; import java.util.logging.Level;
@ -154,8 +158,9 @@ public class BlacksmithPlugin extends JavaPlugin {
} }
//Register the blacksmith trait with Citizens //Register the blacksmith trait with Citizens
CitizensAPI.getTraitFactory().registerTrait( TraitFactory traitFactory = CitizensAPI.getTraitFactory();
net.citizensnpcs.api.trait.TraitInfo.create(BlacksmithTrait.class).withName("blacksmith")); traitFactory.registerTrait(TraitInfo.create(BlacksmithTrait.class).withName("blacksmith"));
traitFactory.registerTrait(TraitInfo.create(ScrapperTrait.class).withName("scrapper"));
//Register all commands //Register all commands
registerCommands(); registerCommands();
@ -256,12 +261,12 @@ public class BlacksmithPlugin extends JavaPlugin {
* *
* @param fileConfiguration <p>The config to read from and write to</p> * @param fileConfiguration <p>The config to read from and write to</p>
*/ */
private void migrateConfig(FileConfiguration fileConfiguration) { private void migrateConfig(@NotNull FileConfiguration fileConfiguration) {
//Save the old config just in case something goes wrong //Save the old config just in case something goes wrong
try { try {
fileConfiguration.save(getDataFolder() + "/config.yml.old"); fileConfiguration.save(getDataFolder() + "/config.yml.old");
} catch (IOException e) { } catch (IOException exception) {
e.printStackTrace(); BlacksmithPlugin.getInstance().getLogger().log(Level.SEVERE, Arrays.toString(exception.getStackTrace()));
return; return;
} }
@ -273,8 +278,8 @@ public class BlacksmithPlugin extends JavaPlugin {
migrationFields = FileHelper.readKeyValuePairs(FileHelper.getBufferedReaderFromInputStream(inputStream), migrationFields = FileHelper.readKeyValuePairs(FileHelper.getBufferedReaderFromInputStream(inputStream),
"=", ColorConversion.NORMAL); "=", ColorConversion.NORMAL);
} }
} catch (IOException e) { } catch (IOException exception) {
e.printStackTrace(); BlacksmithPlugin.getInstance().getLogger().log(Level.SEVERE, Arrays.toString(exception.getStackTrace()));
return; return;
} }

View File

@ -131,7 +131,7 @@ public abstract class EditCommand<K extends CustomTrait<L>, L extends Setting> i
} }
settings.changeValue(setting, newValue); settings.changeValue(setting, newValue);
BlacksmithPlugin.getStringFormatter().displaySuccessMessage(sender, BlacksmithPlugin.getStringFormatter().displaySuccessMessage(sender,
getValueChangedMessage(setting.getCommandName(), String.valueOf(newValue))); getValueChangedMessage(setting.getCommandName(), newValue));
//Save the changes immediately to prevent data loss on server crash //Save the changes immediately to prevent data loss on server crash
CitizensAPI.getNPCRegistry().saveToStore(); CitizensAPI.getNPCRegistry().saveToStore();
} }

View File

@ -215,7 +215,7 @@ public class BlackSmithConfigCommand implements CommandExecutor {
private void updateAllMatchedPrices(@NotNull GlobalBlacksmithSettings settings, private void updateAllMatchedPrices(@NotNull GlobalBlacksmithSettings settings,
@NotNull BlacksmithSetting blacksmithSetting, @NotNull BlacksmithSetting blacksmithSetting,
@NotNull String materialName, double newPrice) { @NotNull String materialName, double newPrice) {
List<Material> materials = ItemHelper.getWildcardMatch(materialName); List<Material> materials = ItemHelper.getWildcardMatch(materialName, false);
for (Material material : materials) { for (Material material : materials) {
if (blacksmithSetting == BlacksmithSetting.BASE_PRICE) { if (blacksmithSetting == BlacksmithSetting.BASE_PRICE) {
settings.setBasePrice(material, newPrice); settings.setBasePrice(material, newPrice);

View File

@ -5,6 +5,7 @@ import org.jetbrains.annotations.NotNull;
/** /**
* An interface describing a setting * An interface describing a setting
*/ */
@SuppressWarnings("unused")
public interface Setting { public interface Setting {
/** /**
@ -12,42 +13,48 @@ public interface Setting {
* *
* @return <p>The full config path for this setting</p> * @return <p>The full config path for this setting</p>
*/ */
@NotNull String getPath(); @NotNull
String getPath();
/** /**
* Gets the config path without the root node * Gets the config path without the root node
* *
* @return <p>The config path without the root node</p> * @return <p>The config path without the root node</p>
*/ */
@NotNull String getChildPath(); @NotNull
String getChildPath();
/** /**
* Gets the value of this setting * Gets the value of this setting
* *
* @return <p>The value of this setting</p> * @return <p>The value of this setting</p>
*/ */
@NotNull Object getDefaultValue(); @NotNull
Object getDefaultValue();
/** /**
* The name of the command used to change this setting * The name of the command used to change this setting
* *
* @return <p>The name of this setting's command</p> * @return <p>The name of this setting's command</p>
*/ */
@NotNull String getCommandName(); @NotNull
String getCommandName();
/** /**
* Gets the value type for this setting * Gets the value type for this setting
* *
* @return <p>The value type for this setting</p> * @return <p>The value type for this setting</p>
*/ */
@NotNull SettingValueType getValueType(); @NotNull
SettingValueType getValueType();
/** /**
* Gets the description explaining the usage of this setting * Gets the description explaining the usage of this setting
* *
* @return <p>This setting's description</p> * @return <p>This setting's description</p>
*/ */
@NotNull String getDescription(); @NotNull
String getDescription();
/** /**
* Gets whether this setting can be set per-NPC, or if it's set globally * Gets whether this setting can be set per-NPC, or if it's set globally

View File

@ -1,5 +1,8 @@
package net.knarcraft.blacksmith.config; package net.knarcraft.blacksmith.config;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/** /**
* An interface describing an object for managing settings * An interface describing an object for managing settings
* *
@ -13,7 +16,7 @@ public interface Settings<K extends Setting> {
* @param setting <p>The setting to change</p> * @param setting <p>The setting to change</p>
* @param newValue <p>The new value of the setting</p> * @param newValue <p>The new value of the setting</p>
*/ */
void changeValue(K setting, Object newValue); void changeValue(@NotNull K setting, @Nullable Object newValue);
/** /**
* Gets the current raw value of the given global setting * Gets the current raw value of the given global setting
@ -21,6 +24,6 @@ public interface Settings<K extends Setting> {
* @param setting <p>The setting to get</p> * @param setting <p>The setting to get</p>
* @return <p>The current raw setting value</p> * @return <p>The current raw setting value</p>
*/ */
Object getRawValue(K setting); @NotNull Object getRawValue(@NotNull K setting);
} }

View File

@ -4,6 +4,7 @@ import net.knarcraft.blacksmith.BlacksmithPlugin;
import net.knarcraft.blacksmith.util.ItemHelper; import net.knarcraft.blacksmith.util.ItemHelper;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.Tag; import org.bukkit.Tag;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@ -46,7 +47,7 @@ public enum SmithPreset {
* *
* @param filters <p>The filters applicable to this preset</p> * @param filters <p>The filters applicable to this preset</p>
*/ */
SmithPreset(SmithPresetFilter[] filters) { SmithPreset(@NotNull SmithPresetFilter[] filters) {
this.filters = filters; this.filters = filters;
} }
@ -56,7 +57,7 @@ public enum SmithPreset {
* @param filter <p>The filter to check</p> * @param filter <p>The filter to check</p>
* @return <p>True if the filter is supported</p> * @return <p>True if the filter is supported</p>
*/ */
public boolean supportsFilter(SmithPresetFilter filter) { public boolean supportsFilter(@NotNull SmithPresetFilter filter) {
return List.of(filters).contains(filter); return List.of(filters).contains(filter);
} }
@ -65,6 +66,7 @@ public enum SmithPreset {
* *
* @return <p>The filters supported by this preset</p> * @return <p>The filters supported by this preset</p>
*/ */
@NotNull
public List<SmithPresetFilter> getSupportedFilters() { public List<SmithPresetFilter> getSupportedFilters() {
return List.of(filters); return List.of(filters);
} }
@ -74,6 +76,7 @@ public enum SmithPreset {
* *
* @return <p>All available smith presets</p> * @return <p>All available smith presets</p>
*/ */
@NotNull
public static List<String> getPresetNames() { public static List<String> getPresetNames() {
List<String> presetNames = new ArrayList<>(); List<String> presetNames = new ArrayList<>();
for (SmithPreset preset : SmithPreset.values()) { for (SmithPreset preset : SmithPreset.values()) {
@ -88,7 +91,8 @@ public enum SmithPreset {
* @param possiblePreset <p>The string that might be a preset</p> * @param possiblePreset <p>The string that might be a preset</p>
* @return <p>The string, possibly with the preset replaced</p> * @return <p>The string, possibly with the preset replaced</p>
*/ */
public static String replacePreset(String possiblePreset) { @NotNull
public static String replacePreset(@NotNull String possiblePreset) {
boolean negated = false; boolean negated = false;
String upperCasedPreset = possiblePreset.replace('-', '_').toUpperCase(); String upperCasedPreset = possiblePreset.replace('-', '_').toUpperCase();
@ -143,6 +147,7 @@ public enum SmithPreset {
* @param filter <p>The filter to use for filtering</p> * @param filter <p>The filter to use for filtering</p>
* @return <p>The materials included in this preset, filtered using the given filter</p> * @return <p>The materials included in this preset, filtered using the given filter</p>
*/ */
@NotNull
public List<Material> getFilteredMaterials(SmithPresetFilter filter) { public List<Material> getFilteredMaterials(SmithPresetFilter filter) {
List<Material> materials = new ArrayList<>(this.getMaterials()); List<Material> materials = new ArrayList<>(this.getMaterials());
materials.removeIf((item) -> !filter.isIncluded(item)); materials.removeIf((item) -> !filter.isIncluded(item));
@ -154,6 +159,7 @@ public enum SmithPreset {
* *
* @return <p>All materials in this preset</p> * @return <p>All materials in this preset</p>
*/ */
@NotNull
public List<Material> getMaterials() { public List<Material> getMaterials() {
return switch (this) { return switch (this) {
case BLACKSMITH -> ItemHelper.getAllReforgeAbleMaterials(); case BLACKSMITH -> ItemHelper.getAllReforgeAbleMaterials();
@ -168,6 +174,7 @@ public enum SmithPreset {
* *
* @return <p>All ranged weapon materials</p> * @return <p>All ranged weapon materials</p>
*/ */
@NotNull
private List<Material> getRanged() { private List<Material> getRanged() {
List<Material> ranged = new ArrayList<>(); List<Material> ranged = new ArrayList<>();
ranged.add(Material.TRIDENT); ranged.add(Material.TRIDENT);
@ -181,6 +188,7 @@ public enum SmithPreset {
* *
* @return <p>All tool materials</p> * @return <p>All tool materials</p>
*/ */
@NotNull
private List<Material> getTools() { private List<Material> getTools() {
List<Material> tools = new ArrayList<>(); List<Material> tools = new ArrayList<>();
tools.addAll(Tag.ITEMS_HOES.getValues()); tools.addAll(Tag.ITEMS_HOES.getValues());
@ -198,6 +206,7 @@ public enum SmithPreset {
* *
* @return <p>All weapon materials</p> * @return <p>All weapon materials</p>
*/ */
@NotNull
private List<Material> getWeapons() { private List<Material> getWeapons() {
List<Material> weapons = new ArrayList<>(getSwords()); List<Material> weapons = new ArrayList<>(getSwords());
weapons.addAll(getRanged()); weapons.addAll(getRanged());
@ -210,10 +219,17 @@ public enum SmithPreset {
* *
* @return <p>All sword materials</p> * @return <p>All sword materials</p>
*/ */
@NotNull
private Set<Material> getSwords() { private Set<Material> getSwords() {
return Tag.ITEMS_SWORDS.getValues(); return Tag.ITEMS_SWORDS.getValues();
} }
/**
* Gets all types of armor
*
* @return <p>All armor types</p>
*/
@NotNull
private List<Material> getArmor() { private List<Material> getArmor() {
List<Material> armor = new ArrayList<>(); List<Material> armor = new ArrayList<>();
armor.addAll(getMaterialsEndingWith("HELMET")); armor.addAll(getMaterialsEndingWith("HELMET"));
@ -230,7 +246,8 @@ public enum SmithPreset {
* @param end <p>The string to look for</p> * @param end <p>The string to look for</p>
* @return <p>The resulting materials</p> * @return <p>The resulting materials</p>
*/ */
private List<Material> getMaterialsEndingWith(String end) { @NotNull
private List<Material> getMaterialsEndingWith(@NotNull String end) {
List<Material> matchedMaterials = new ArrayList<>(); List<Material> matchedMaterials = new ArrayList<>();
for (Material material : ItemHelper.getAllReforgeAbleMaterials()) { for (Material material : ItemHelper.getAllReforgeAbleMaterials()) {
if (!material.name().startsWith("LEGACY") && material.name().endsWith(end)) { if (!material.name().startsWith("LEGACY") && material.name().endsWith(end)) {
@ -245,6 +262,7 @@ public enum SmithPreset {
* *
* @return <p>All material names for this smith</p> * @return <p>All material names for this smith</p>
*/ */
@NotNull
private List<String> getMaterialNames() { private List<String> getMaterialNames() {
return getNames(this.getMaterials()); return getNames(this.getMaterials());
} }
@ -255,7 +273,8 @@ public enum SmithPreset {
* @param filter <p>The filter used for filtering materials</p> * @param filter <p>The filter used for filtering materials</p>
* @return <p>All material names for this smith</p> * @return <p>All material names for this smith</p>
*/ */
private List<String> getMaterialNames(SmithPresetFilter filter) { @NotNull
private List<String> getMaterialNames(@NotNull SmithPresetFilter filter) {
return getNames(this.getFilteredMaterials(filter)); return getNames(this.getFilteredMaterials(filter));
} }
@ -265,7 +284,8 @@ public enum SmithPreset {
* @param materials <p>The materials to get the names of</p> * @param materials <p>The materials to get the names of</p>
* @return <p>The names of the materials</p> * @return <p>The names of the materials</p>
*/ */
private List<String> getNames(List<Material> materials) { @NotNull
private List<String> getNames(@NotNull List<Material> materials) {
List<String> items = new ArrayList<>(); List<String> items = new ArrayList<>();
for (Material material : materials) { for (Material material : materials) {
items.add(material.name().toLowerCase().replace("_", "-")); items.add(material.name().toLowerCase().replace("_", "-"));
@ -279,7 +299,8 @@ public enum SmithPreset {
* @param materials <p>The material names to negate</p> * @param materials <p>The material names to negate</p>
* @return <p>The negated material names</p> * @return <p>The negated material names</p>
*/ */
private static List<String> negateMaterials(List<String> materials) { @NotNull
private static List<String> negateMaterials(@NotNull List<String> materials) {
List<String> negatedMaterials = new ArrayList<>(materials.size()); List<String> negatedMaterials = new ArrayList<>(materials.size());
materials.forEach((material) -> { materials.forEach((material) -> {
if (material != null && !material.isBlank()) { if (material != null && !material.isBlank()) {

View File

@ -9,6 +9,8 @@ import net.knarcraft.blacksmith.util.InputParsingHelper;
import net.knarcraft.blacksmith.util.ItemHelper; import net.knarcraft.blacksmith.util.ItemHelper;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.enchantments.Enchantment; import org.bukkit.enchantments.Enchantment;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
@ -22,7 +24,7 @@ import java.util.logging.Level;
public class BlacksmithNPCSettings implements TraitSettings<BlacksmithSetting> { public class BlacksmithNPCSettings implements TraitSettings<BlacksmithSetting> {
private final List<Material> reforgeAbleItems = new ArrayList<>(); private final List<Material> reforgeAbleItems = new ArrayList<>();
private final List<Enchantment> enchantmentBlocklist = new ArrayList<>(); private final List<Enchantment> enchantmentBlockList = new ArrayList<>();
private final Map<BlacksmithSetting, Object> currentValues = new HashMap<>(); private final Map<BlacksmithSetting, Object> currentValues = new HashMap<>();
private final GlobalBlacksmithSettings globalBlacksmithSettings; private final GlobalBlacksmithSettings globalBlacksmithSettings;
@ -46,7 +48,7 @@ public class BlacksmithNPCSettings implements TraitSettings<BlacksmithSetting> {
} }
//Updates the list of reforge-able items/materials //Updates the list of reforge-able items/materials
updateReforgeAbleItems(); updateReforgeAbleItems();
updateEnchantmentBlocklist(); updateEnchantmentBlockList();
} }
/** /**
@ -61,7 +63,7 @@ public class BlacksmithNPCSettings implements TraitSettings<BlacksmithSetting> {
} }
@Override @Override
public void changeValue(BlacksmithSetting setting, Object newValue) { public void changeValue(@NotNull BlacksmithSetting setting, @Nullable Object newValue) {
if (setting.getValueType() == SettingValueType.STRING_LIST || if (setting.getValueType() == SettingValueType.STRING_LIST ||
setting.getValueType() == SettingValueType.REFORGE_ABLE_ITEMS) { setting.getValueType() == SettingValueType.REFORGE_ABLE_ITEMS) {
//Workaround to make sure it's treated as the correct type //Workaround to make sure it's treated as the correct type
@ -72,8 +74,8 @@ public class BlacksmithNPCSettings implements TraitSettings<BlacksmithSetting> {
if (setting == BlacksmithSetting.REFORGE_ABLE_ITEMS) { if (setting == BlacksmithSetting.REFORGE_ABLE_ITEMS) {
updateReforgeAbleItems(); updateReforgeAbleItems();
} }
if (setting == BlacksmithSetting.ENCHANTMENT_BLOCKLIST) { if (setting == BlacksmithSetting.ENCHANTMENT_BLOCK_LIST) {
updateEnchantmentBlocklist(); updateEnchantmentBlockList();
} }
} }
@ -83,7 +85,7 @@ public class BlacksmithNPCSettings implements TraitSettings<BlacksmithSetting> {
* @param setting <p>The setting to get the value of</p> * @param setting <p>The setting to get the value of</p>
* @return <p>The current value of the setting</p> * @return <p>The current value of the setting</p>
*/ */
public Object getRawValue(BlacksmithSetting setting) { public @NotNull Object getRawValue(@NotNull BlacksmithSetting setting) {
return currentValues.get(setting); return currentValues.get(setting);
} }
@ -195,12 +197,12 @@ public class BlacksmithNPCSettings implements TraitSettings<BlacksmithSetting> {
* *
* @return <p>The list of blocked enchantments</p> * @return <p>The list of blocked enchantments</p>
*/ */
public List<Enchantment> getEnchantmentBlocklist() { public List<Enchantment> getEnchantmentBlockList() {
Object currentValue = currentValues.get(BlacksmithSetting.ENCHANTMENT_BLOCKLIST); Object currentValue = currentValues.get(BlacksmithSetting.ENCHANTMENT_BLOCK_LIST);
if (currentValue == null || String.valueOf(currentValue).isEmpty()) { if (currentValue == null || String.valueOf(currentValue).isEmpty()) {
return globalBlacksmithSettings.getEnchantmentBlocklist(); return globalBlacksmithSettings.getEnchantmentBlockList();
} else { } else {
return new ArrayList<>(this.enchantmentBlocklist); return new ArrayList<>(this.enchantmentBlockList);
} }
} }
@ -356,11 +358,11 @@ public class BlacksmithNPCSettings implements TraitSettings<BlacksmithSetting> {
/** /**
* Updates the list of blocked enchantments * Updates the list of blocked enchantments
*/ */
private void updateEnchantmentBlocklist() { private void updateEnchantmentBlockList() {
this.enchantmentBlocklist.clear(); this.enchantmentBlockList.clear();
List<String> enchantments = ConfigHelper.asStringList(getValue(BlacksmithSetting.ENCHANTMENT_BLOCKLIST)); List<String> enchantments = ConfigHelper.asStringList(getValue(BlacksmithSetting.ENCHANTMENT_BLOCK_LIST));
if (enchantments != null) { if (enchantments != null) {
this.enchantmentBlocklist.addAll(getEnchantmentBlocklist(enchantments)); this.enchantmentBlockList.addAll(getEnchantmentBlockList(enchantments));
} }
} }
@ -370,8 +372,8 @@ public class BlacksmithNPCSettings implements TraitSettings<BlacksmithSetting> {
* @param enchantments <p>The enchantment names to block</p> * @param enchantments <p>The enchantment names to block</p>
* @return <p>The enchantments to be blocked</p> * @return <p>The enchantments to be blocked</p>
*/ */
public static List<Enchantment> getEnchantmentBlocklist(List<String> enchantments) { public static List<Enchantment> getEnchantmentBlockList(List<String> enchantments) {
List<Enchantment> enchantmentBlocklist = new ArrayList<>(); List<Enchantment> enchantmentBlockList = new ArrayList<>();
for (String item : enchantments) { for (String item : enchantments) {
if (InputParsingHelper.isEmpty(item)) { if (InputParsingHelper.isEmpty(item)) {
@ -380,13 +382,13 @@ public class BlacksmithNPCSettings implements TraitSettings<BlacksmithSetting> {
Enchantment enchantment = InputParsingHelper.matchEnchantment(item); Enchantment enchantment = InputParsingHelper.matchEnchantment(item);
if (enchantment != null) { if (enchantment != null) {
enchantmentBlocklist.add(enchantment); enchantmentBlockList.add(enchantment);
} else { } else {
BlacksmithPlugin.getInstance().getLogger().log(Level.WARNING, "Unable to verify " + item + BlacksmithPlugin.getInstance().getLogger().log(Level.WARNING, "Unable to verify " + item +
" as a valid enchantment"); " as a valid enchantment");
} }
} }
return enchantmentBlocklist; return enchantmentBlockList;
} }
/** /**

View File

@ -90,7 +90,7 @@ public enum BlacksmithSetting implements Setting {
/** /**
* The setting for the enchantments a blacksmith cannot apply to items * The setting for the enchantments a blacksmith cannot apply to items
*/ */
ENCHANTMENT_BLOCKLIST("enchantmentBlocklist", SettingValueType.STRING_LIST, List.of("binding_curse", ENCHANTMENT_BLOCK_LIST("enchantmentBlockList", SettingValueType.STRING_LIST, List.of("binding_curse",
"mending", "vanishing_curse"), "The enchantments a " + "mending", "vanishing_curse"), "The enchantments a " +
"blacksmith is denied from applying to an item. Disable anything you find too op or annoying.", "blacksmith is denied from applying to an item. Disable anything you find too op or annoying.",
true, false), true, false),

View File

@ -11,6 +11,7 @@ import net.knarcraft.blacksmith.util.ItemHelper;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.enchantments.Enchantment; import org.bukkit.enchantments.Enchantment;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.File; import java.io.File;
import java.util.ArrayList; import java.util.ArrayList;
@ -29,7 +30,7 @@ public class GlobalBlacksmithSettings implements Settings<BlacksmithSetting> {
private final Map<Enchantment, Double> enchantmentCosts = new HashMap<>(); private final Map<Enchantment, Double> enchantmentCosts = new HashMap<>();
private final Map<BlacksmithSetting, Object> settings = new HashMap<>(); private final Map<BlacksmithSetting, Object> settings = new HashMap<>();
private final List<Material> defaultReforgeAbleMaterials = new ArrayList<>(); private final List<Material> defaultReforgeAbleMaterials = new ArrayList<>();
private final List<Enchantment> defaultEnchantmentBlocklist = new ArrayList<>(); private final List<Enchantment> defaultEnchantmentBlockList = new ArrayList<>();
private final YamlStorage defaultConfig; private final YamlStorage defaultConfig;
@ -71,7 +72,7 @@ public class GlobalBlacksmithSettings implements Settings<BlacksmithSetting> {
* @param blacksmithSetting <p>The default NPC setting to change</p> * @param blacksmithSetting <p>The default NPC setting to change</p>
* @param newValue <p>The new value for the setting</p> * @param newValue <p>The new value for the setting</p>
*/ */
public void changeValue(BlacksmithSetting blacksmithSetting, Object newValue) { public void changeValue(@NotNull BlacksmithSetting blacksmithSetting, @Nullable Object newValue) {
if (blacksmithSetting.getValueType() == SettingValueType.STRING_LIST || if (blacksmithSetting.getValueType() == SettingValueType.STRING_LIST ||
blacksmithSetting.getValueType() == SettingValueType.REFORGE_ABLE_ITEMS) { blacksmithSetting.getValueType() == SettingValueType.REFORGE_ABLE_ITEMS) {
//Workaround to make sure it's treated as the correct type //Workaround to make sure it's treated as the correct type
@ -82,8 +83,8 @@ public class GlobalBlacksmithSettings implements Settings<BlacksmithSetting> {
save(); save();
if (blacksmithSetting == BlacksmithSetting.REFORGE_ABLE_ITEMS) { if (blacksmithSetting == BlacksmithSetting.REFORGE_ABLE_ITEMS) {
loadReforgeAbleItems(); loadReforgeAbleItems();
} else if (blacksmithSetting == BlacksmithSetting.ENCHANTMENT_BLOCKLIST) { } else if (blacksmithSetting == BlacksmithSetting.ENCHANTMENT_BLOCK_LIST) {
loadEnchantmentBlocklist(); loadEnchantmentBlockList();
} }
} }
@ -93,7 +94,7 @@ public class GlobalBlacksmithSettings implements Settings<BlacksmithSetting> {
* @param blacksmithSetting <p>The setting to get</p> * @param blacksmithSetting <p>The setting to get</p>
* @return <p>The current raw setting value</p> * @return <p>The current raw setting value</p>
*/ */
public Object getRawValue(BlacksmithSetting blacksmithSetting) { public @NotNull Object getRawValue(@NotNull BlacksmithSetting blacksmithSetting) {
return this.settings.get(blacksmithSetting); return this.settings.get(blacksmithSetting);
} }
@ -248,12 +249,12 @@ public class GlobalBlacksmithSettings implements Settings<BlacksmithSetting> {
} }
/** /**
* Gets the value of enchantmentBlocklist * Gets the value of enchantmentBlockList
* *
* @return <p>The value of enchantmentBlocklist</p> * @return <p>The value of enchantmentBlockList</p>
*/ */
public @NotNull List<Enchantment> getEnchantmentBlocklist() { public @NotNull List<Enchantment> getEnchantmentBlockList() {
return this.defaultEnchantmentBlocklist; return this.defaultEnchantmentBlockList;
} }
/** /**
@ -327,7 +328,7 @@ public class GlobalBlacksmithSettings implements Settings<BlacksmithSetting> {
} }
} }
loadReforgeAbleItems(); loadReforgeAbleItems();
loadEnchantmentBlocklist(); loadEnchantmentBlockList();
//Load all base prices //Load all base prices
loadBasePrices(root); loadBasePrices(root);
@ -467,12 +468,12 @@ public class GlobalBlacksmithSettings implements Settings<BlacksmithSetting> {
/** /**
* Loads the enchantment block list from the current value * Loads the enchantment block list from the current value
*/ */
private void loadEnchantmentBlocklist() { private void loadEnchantmentBlockList() {
this.defaultEnchantmentBlocklist.clear(); this.defaultEnchantmentBlockList.clear();
List<String> enchantmentNames = ConfigHelper.asStringList(settings.get( List<String> enchantmentNames = ConfigHelper.asStringList(settings.get(
BlacksmithSetting.ENCHANTMENT_BLOCKLIST)); BlacksmithSetting.ENCHANTMENT_BLOCK_LIST));
if (enchantmentNames != null) { if (enchantmentNames != null) {
this.defaultEnchantmentBlocklist.addAll(BlacksmithNPCSettings.getEnchantmentBlocklist(enchantmentNames)); this.defaultEnchantmentBlockList.addAll(BlacksmithNPCSettings.getEnchantmentBlockList(enchantmentNames));
} }
} }

View File

@ -86,7 +86,7 @@ public class GlobalScrapperSettings implements Settings<ScrapperSetting> {
* @param scrapperSetting <p>The setting to get</p> * @param scrapperSetting <p>The setting to get</p>
* @return <p>The current raw setting value</p> * @return <p>The current raw setting value</p>
*/ */
public Object getRawValue(ScrapperSetting scrapperSetting) { public @NotNull Object getRawValue(@NotNull ScrapperSetting scrapperSetting) {
return this.settings.get(scrapperSetting); return this.settings.get(scrapperSetting);
} }
@ -104,7 +104,7 @@ public class GlobalScrapperSettings implements Settings<ScrapperSetting> {
* *
* @return <p>Whether to show exact time</p> * @return <p>Whether to show exact time</p>
*/ */
public boolean getShowExactTime() { public boolean showExactTime() {
return asBoolean(ScrapperSetting.SHOW_EXACT_TIME); return asBoolean(ScrapperSetting.SHOW_EXACT_TIME);
} }
@ -173,10 +173,20 @@ public class GlobalScrapperSettings implements Settings<ScrapperSetting> {
* *
* @return <p>The value of salvageAbleItems</p> * @return <p>The value of salvageAbleItems</p>
*/ */
@NotNull
public List<Material> getSalvageAbleItems() { public List<Material> getSalvageAbleItems() {
return this.defaultSalvageableMaterials; return this.defaultSalvageableMaterials;
} }
/**
* Gets the cost of using a scrapper
*
* @return <p>The cost of using a scrapper</p>
*/
public double getCost() {
return ConfigHelper.asDouble(getValue(ScrapperSetting.USE_COST));
}
/** /**
* Gets ignored salvage for the given material * Gets ignored salvage for the given material
* *
@ -186,7 +196,8 @@ public class GlobalScrapperSettings implements Settings<ScrapperSetting> {
* @param material <p>The material to get ignored salvage for</p> * @param material <p>The material to get ignored salvage for</p>
* @return <p>The ignored salvage</p> * @return <p>The ignored salvage</p>
*/ */
public @Nullable Set<Material> getIgnoredSalvage(@NotNull Material material) { @Nullable
public Set<Material> getIgnoredSalvage(@NotNull Material material) {
return this.ignoredSalvage.get(material); return this.ignoredSalvage.get(material);
} }
@ -221,15 +232,15 @@ public class GlobalScrapperSettings implements Settings<ScrapperSetting> {
// Parse all material names // Parse all material names
String[] data = ignoredSalvageInfo.split(":"); String[] data = ignoredSalvageInfo.split(":");
String[] materialStrings = data[0].split(","); String[] materialStrings = data[0].split(";");
List<Material> materials = new ArrayList<>(); List<Material> materials = new ArrayList<>();
for (String materialString : materialStrings) { for (String materialString : materialStrings) {
materials.addAll(ItemHelper.getWildcardMatch(materialString)); materials.addAll(ItemHelper.getWildcardMatch(materialString, true));
} }
String[] ignoredSalvageStrings = data[1].split(","); String[] ignoredSalvageStrings = data[1].split(";");
List<Material> ignored = new ArrayList<>(); List<Material> ignored = new ArrayList<>();
for (String ignoredSalvageString : ignoredSalvageStrings) { for (String ignoredSalvageString : ignoredSalvageStrings) {
ignored.addAll(ItemHelper.getWildcardMatch(ignoredSalvageString)); ignored.addAll(ItemHelper.getWildcardMatch(ignoredSalvageString, true));
} }
// Add the ignored salvage to all the matched materials // Add the ignored salvage to all the matched materials

View File

@ -6,6 +6,8 @@ import net.knarcraft.blacksmith.config.TraitSettings;
import net.knarcraft.blacksmith.util.ConfigHelper; 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.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
@ -57,7 +59,7 @@ public class ScrapperNPCSettings implements TraitSettings<ScrapperSetting> {
* @param setting <p>The setting to change</p> * @param setting <p>The setting to change</p>
* @param newValue <p>The new value of the setting</p> * @param newValue <p>The new value of the setting</p>
*/ */
public void changeValue(ScrapperSetting setting, Object newValue) { public void changeValue(@NotNull ScrapperSetting setting, @Nullable Object newValue) {
if (setting.getValueType() == SettingValueType.STRING_LIST || if (setting.getValueType() == SettingValueType.STRING_LIST ||
setting.getValueType() == SettingValueType.REFORGE_ABLE_ITEMS) { setting.getValueType() == SettingValueType.REFORGE_ABLE_ITEMS) {
//Workaround to make sure it's treated as the correct type //Workaround to make sure it's treated as the correct type
@ -87,21 +89,24 @@ public class ScrapperNPCSettings implements TraitSettings<ScrapperSetting> {
* @param setting <p>The setting to get the value of</p> * @param setting <p>The setting to get the value of</p>
* @return <p>The current value of the setting</p> * @return <p>The current value of the setting</p>
*/ */
public Object getRawValue(ScrapperSetting setting) { public @NotNull Object getRawValue(@NotNull ScrapperSetting setting) {
return currentValues.get(setting); return currentValues.get(setting);
} }
@Override @Override
@NotNull
public String getBusyWithPlayerMessage() { public String getBusyWithPlayerMessage() {
return asString(ScrapperSetting.BUSY_WITH_PLAYER_MESSAGE); return asString(ScrapperSetting.BUSY_WITH_PLAYER_MESSAGE);
} }
@Override @Override
@NotNull
public String getBusyWorkingMessage() { public String getBusyWorkingMessage() {
return asString(ScrapperSetting.BUSY_WITH_SALVAGE_MESSAGE); return asString(ScrapperSetting.BUSY_WITH_SALVAGE_MESSAGE);
} }
@Override @Override
@NotNull
public String getStartWorkingMessage() { public String getStartWorkingMessage() {
return asString(ScrapperSetting.START_SALVAGE_MESSAGE); return asString(ScrapperSetting.START_SALVAGE_MESSAGE);
} }
@ -111,6 +116,7 @@ public class ScrapperNPCSettings implements TraitSettings<ScrapperSetting> {
* *
* @return <p>The salvage success message</p> * @return <p>The salvage success message</p>
*/ */
@NotNull
public String getSuccessMessage() { public String getSuccessMessage() {
return asString(ScrapperSetting.SUCCESS_SALVAGE_MESSAGE); return asString(ScrapperSetting.SUCCESS_SALVAGE_MESSAGE);
} }
@ -120,11 +126,22 @@ public class ScrapperNPCSettings implements TraitSettings<ScrapperSetting> {
* *
* @return <p>The salvage fail message</p> * @return <p>The salvage fail message</p>
*/ */
@NotNull
public String getFailMessage() { public String getFailMessage() {
return asString(ScrapperSetting.FAIL_SALVAGE_MESSAGE); return asString(ScrapperSetting.FAIL_SALVAGE_MESSAGE);
} }
/**
* Gets the message to use for displaying salvage cost
*
* @return <p>The message to use for displaying salvage cost</p>
*/
public String getCostMessage() {
return asString(ScrapperSetting.COST_MESSAGE);
}
@Override @Override
@NotNull
public String getCoolDownUnexpiredMessage() { public String getCoolDownUnexpiredMessage() {
return asString(ScrapperSetting.COOL_DOWN_UNEXPIRED_MESSAGE); return asString(ScrapperSetting.COOL_DOWN_UNEXPIRED_MESSAGE);
} }
@ -132,6 +149,7 @@ public class ScrapperNPCSettings implements TraitSettings<ScrapperSetting> {
/** /**
* The message displayed if a player presents a different item after seeing the price to salvage an item * The message displayed if a player presents a different item after seeing the price to salvage an item
*/ */
@NotNull
public String getItemChangedMessage() { public String getItemChangedMessage() {
return asString(ScrapperSetting.ITEM_UNEXPECTEDLY_CHANGED_MESSAGE); return asString(ScrapperSetting.ITEM_UNEXPECTEDLY_CHANGED_MESSAGE);
} }
@ -177,15 +195,6 @@ public class ScrapperNPCSettings implements TraitSettings<ScrapperSetting> {
return asInt(ScrapperSetting.SALVAGE_COOL_DOWN) <= 0; return asInt(ScrapperSetting.SALVAGE_COOL_DOWN) <= 0;
} }
/**
* Gets whether to disable the delay between starting reforging and the reforging finishing
*
* @return <p>Whether to disable the reforge delay</p>
*/
public boolean getDisableDelay() {
return asInt(ScrapperSetting.MAX_SALVAGE_DELAY) <= 0;
}
/** /**
* Gets the chance of a salvaging to fail * Gets the chance of a salvaging to fail
* *
@ -203,7 +212,7 @@ public class ScrapperNPCSettings implements TraitSettings<ScrapperSetting> {
* @param setting <p>The setting to get the value of</p> * @param setting <p>The setting to get the value of</p>
* @return <p>The value of the given setting as an integer</p> * @return <p>The value of the given setting as an integer</p>
*/ */
private int asInt(ScrapperSetting setting) { private int asInt(@NotNull ScrapperSetting setting) {
return ConfigHelper.asInt(getValue(setting)); return ConfigHelper.asInt(getValue(setting));
} }
@ -213,7 +222,8 @@ public class ScrapperNPCSettings implements TraitSettings<ScrapperSetting> {
* @param setting <p>The setting to get the value of</p> * @param setting <p>The setting to get the value of</p>
* @return <p>The value of the given setting as a string</p> * @return <p>The value of the given setting as a string</p>
*/ */
private String asString(ScrapperSetting setting) { @NotNull
private String asString(@NotNull ScrapperSetting setting) {
return getValue(setting).toString(); return getValue(setting).toString();
} }
@ -223,7 +233,8 @@ public class ScrapperNPCSettings implements TraitSettings<ScrapperSetting> {
* @param setting <p>The setting to get the value of</p> * @param setting <p>The setting to get the value of</p>
* @return <p>The current value</p> * @return <p>The current value</p>
*/ */
private Object getValue(ScrapperSetting setting) { @NotNull
private Object getValue(@NotNull ScrapperSetting setting) {
Object value = currentValues.get(setting); Object value = currentValues.get(setting);
//If not set, use the default value from the config.yml file //If not set, use the default value from the config.yml file
if (value == null) { if (value == null) {
@ -244,6 +255,7 @@ public class ScrapperNPCSettings implements TraitSettings<ScrapperSetting> {
* *
* @return <p>All salvageable items</p> * @return <p>All salvageable items</p>
*/ */
@NotNull
public List<Material> getSalvageAbleItems() { public List<Material> getSalvageAbleItems() {
Object currentValue = currentValues.get(ScrapperSetting.SALVAGE_ABLE_ITEMS); Object currentValue = currentValues.get(ScrapperSetting.SALVAGE_ABLE_ITEMS);
if (currentValue == null || String.valueOf(currentValue).isEmpty()) { if (currentValue == null || String.valueOf(currentValue).isEmpty()) {
@ -257,7 +269,7 @@ public class ScrapperNPCSettings implements TraitSettings<ScrapperSetting> {
* Whether extended salvaging is enabled * Whether extended salvaging is enabled
* *
* <p>When not extended, only repairable items can be salvaged. When extended, any item produced using a crafting * <p>When not extended, only repairable items can be salvaged. When extended, any item produced using a crafting
* recipe or a smithing transformation can be salvaged. This does not include smelting or similar.</p> * recipe can be salvaged. This does not include smelting or similar.</p>
* *
* @return <p>True if extended salvaging is enabled</p> * @return <p>True if extended salvaging is enabled</p>
*/ */
@ -273,6 +285,7 @@ public class ScrapperNPCSettings implements TraitSettings<ScrapperSetting> {
* *
* @return <p>The title of this scrapper NPC</p> * @return <p>The title of this scrapper NPC</p>
*/ */
@NotNull
public String getScrapperTitle() { public String getScrapperTitle() {
return asString(ScrapperSetting.SCRAPPER_TITLE); return asString(ScrapperSetting.SCRAPPER_TITLE);
} }
@ -282,8 +295,19 @@ public class ScrapperNPCSettings implements TraitSettings<ScrapperSetting> {
* *
* @return <p>The message to display</p> * @return <p>The message to display</p>
*/ */
@NotNull
public String getInvalidItemMessage() { public String getInvalidItemMessage() {
return asString(ScrapperSetting.INVALID_ITEM_MESSAGE); return asString(ScrapperSetting.INVALID_ITEM_MESSAGE);
} }
/**
* Gets the message to display if the player is unable to afford an item salvage
*
* @return <p>The message to display</p>
*/
@NotNull
public String getInsufficientFundsMessage() {
return asString(ScrapperSetting.INSUFFICIENT_FUNDS_MESSAGE);
}
} }

View File

@ -140,10 +140,30 @@ public enum ScrapperSetting implements Setting {
START_SALVAGE_MESSAGE("startSalvageMessage", SettingValueType.STRING, "&eOk, let's see what I can do...", START_SALVAGE_MESSAGE("startSalvageMessage", SettingValueType.STRING, "&eOk, let's see what I can do...",
"The message to display once the blacksmith starts re-forging", true, true), "The message to display once the blacksmith starts re-forging", true, true),
/**
* The message displayed if a player is unable to pay the blacksmith
*/
INSUFFICIENT_FUNDS_MESSAGE("insufficientFundsMessage", SettingValueType.STRING,
"&cYou don't have enough money to salvage an item!",
"The message to display when a player cannot pay for the salvaging", true, true),
/**
* The message displayed when displaying the cost of reforging the held item to the player
*/
COST_MESSAGE("costMessage", SettingValueType.STRING,
"&eIt will cost &a{cost}&e to salvage that item! Click again to salvage!",
"The message to display when informing a player about the salvaging cost", true, true),
/*------------------ /*------------------
| Global settings | | Global settings |
------------------*/ ------------------*/
/**
* The setting for the use cost of using the scrapper
*/
USE_COST("basePrice", SettingValueType.POSITIVE_DOUBLE, 0, "The cost of using a scrapper",
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

@ -65,6 +65,7 @@ public class PlayerListener implements Listener {
* @param <T> <p>The type of entity the player is looking at</p> * @param <T> <p>The type of entity the player is looking at</p>
* @return <p>The entity the player is looking at, or null if no such entity exists</p> * @return <p>The entity the player is looking at, or null if no such entity exists</p>
*/ */
@Nullable
private static <T extends Entity> T getTarget(final @Nullable Entity entity, final @NotNull Iterable<T> entities) { private static <T extends Entity> T getTarget(final @Nullable Entity entity, final @NotNull Iterable<T> entities) {
if (entity == null) { if (entity == null) {
return null; return null;

View File

@ -48,7 +48,17 @@ public class EconomyManager {
* @return <p>Whether the player cannot pay for the reforge</p> * @return <p>Whether the player cannot pay for the reforge</p>
*/ */
public static boolean cannotPayForHeldItemReforge(@NotNull Player player) { public static boolean cannotPayForHeldItemReforge(@NotNull Player player) {
return !(economy.getBalance(player) - getHeldItemCost(player) >= 0); return economy.getBalance(player) - getHeldItemCost(player) < 0;
}
/**
* Gets whether the given player cannot pay for salvaging an item
*
* @param player <p>The player holding an item</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;
} }
/** /**
@ -57,11 +67,23 @@ public class EconomyManager {
* @param player <p>The player holding an item</p> * @param player <p>The player holding an item</p>
* @return <p>The formatted cost</p> * @return <p>The formatted cost</p>
*/ */
public static String formatCost(@NotNull Player player) { @NotNull
public static String formatBlacksmithCost(@NotNull Player player) {
double cost = getHeldItemCost(player); double cost = getHeldItemCost(player);
return economy.format(cost); return economy.format(cost);
} }
/**
* Gets the human-readable cost of salvaging an item
*
* @return <p>The formatted cost</p>
*/
@NotNull
public static String formatScrapperCost() {
double cost = BlacksmithPlugin.getInstance().getGlobalScrapperSettings().getCost();
return economy.format(cost);
}
/** /**
* Withdraws the reforging cost from the given player * Withdraws the reforging cost from the given player
* *
@ -69,8 +91,23 @@ public class EconomyManager {
* *
* @param player <p>The player to withdraw from</p> * @param player <p>The player to withdraw from</p>
*/ */
public static void withdraw(@NotNull Player player) { public static void withdrawBlacksmith(@NotNull Player player) {
economy.withdrawPlayer(player, getHeldItemCost(player)); double cost = getHeldItemCost(player);
if (cost > 0) {
economy.withdrawPlayer(player, cost);
}
}
/**
* Withdraws the salvaging cost from the given player
*
* @param player <p>The player to withdraw from</p>
*/
public static void withdrawScrapper(Player player) {
double cost = BlacksmithPlugin.getInstance().getGlobalScrapperSettings().getCost();
if (cost > 0) {
economy.withdrawPlayer(player, cost);
}
} }
/** /**

View File

@ -39,7 +39,8 @@ public class BlacksmithTrait extends CustomTrait<BlacksmithSetting> {
* *
* @return <p>The current settings for this NPC</p> * @return <p>The current settings for this NPC</p>
*/ */
public @NotNull BlacksmithNPCSettings getSettings() { @NotNull
public BlacksmithNPCSettings getSettings() {
return config; return config;
} }
@ -90,7 +91,7 @@ public class BlacksmithTrait extends CustomTrait<BlacksmithSetting> {
session = new ReforgeSession(this, player, npc, config); session = new ReforgeSession(this, player, npc, config);
//Tell the player the cost of repairing the item //Tell the player the cost of repairing the item
String cost = EconomyManager.formatCost(player); String cost = EconomyManager.formatBlacksmithCost(player);
String itemName = hand.getType().name().toLowerCase().replace('_', ' '); String itemName = hand.getType().name().toLowerCase().replace('_', ' ');
sendNPCMessage(this.npc, player, config.getCostMessage().replace("{cost}", cost).replace("{item}", sendNPCMessage(this.npc, player, config.getCostMessage().replace("{cost}", cost).replace("{item}",
itemName)); itemName));

View File

@ -7,10 +7,12 @@ import net.knarcraft.blacksmith.config.Settings;
import net.knarcraft.blacksmith.config.TraitSettings; import net.knarcraft.blacksmith.config.TraitSettings;
import net.knarcraft.blacksmith.formatting.TimeFormatter; import net.knarcraft.blacksmith.formatting.TimeFormatter;
import net.knarcraft.blacksmith.manager.EconomyManager; import net.knarcraft.blacksmith.manager.EconomyManager;
import net.knarcraft.blacksmith.util.ItemHelper;
import net.knarcraft.knarlib.formatting.StringFormatter; import net.knarcraft.knarlib.formatting.StringFormatter;
import org.bukkit.entity.LivingEntity; import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.PlayerInventory;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
@ -174,9 +176,17 @@ public abstract class CustomTrait<K extends Setting> extends Trait {
*/ */
private void startMainAction(@NotNull NPC npc, @NotNull Player player) { private void startMainAction(@NotNull NPC npc, @NotNull Player player) {
sendNPCMessage(this.npc, player, config.getStartWorkingMessage()); sendNPCMessage(this.npc, player, config.getStartWorkingMessage());
// TODO: Differentiate between blacksmiths and scrappers when withdrawing money
EconomyManager.withdraw(player); boolean isBlacksmith = this instanceof BlacksmithTrait;
if (isBlacksmith) {
EconomyManager.withdrawBlacksmith(player);
} else {
EconomyManager.withdrawScrapper(player);
}
session.scheduleAction(); session.scheduleAction();
PlayerInventory playerInventory = player.getInventory();
ItemStack heldItem = player.getInventory().getItemInMainHand(); ItemStack heldItem = player.getInventory().getItemInMainHand();
//Display the item in the NPC's hand //Display the item in the NPC's hand
@ -186,9 +196,16 @@ public abstract class CustomTrait<K extends Setting> extends Trait {
Objects.requireNonNull(((LivingEntity) npc.getEntity()).getEquipment()).setItemInMainHand(heldItem); Objects.requireNonNull(((LivingEntity) npc.getEntity()).getEquipment()).setItemInMainHand(heldItem);
} }
//Remove the item from the player's inventory //Remove the item from the player's inventory
// TODO: For a scrapper with extended salvaging enabled, the item needs to be reduced with the amount specified if (!isBlacksmith) {
// in the recipe, or removed as normal in the case where the player has exactly enough items to run the salvage. // For scrappers, just reduce the amounts of items, unless the remaining stack is salvaged
player.getInventory().setItemInMainHand(null); int amount = ItemHelper.getRequiredAmountForSalvage(player.getServer(), heldItem);
if (amount != heldItem.getAmount()) {
heldItem.setAmount(heldItem.getAmount() - amount);
playerInventory.setItemInMainHand(heldItem);
return;
}
}
playerInventory.setItemInMainHand(null);
} }
} }

View File

@ -178,7 +178,7 @@ public class ReforgeSession extends Session implements Runnable {
} }
} }
//Remove any enchantments in the block list //Remove any enchantments in the block list
usableEnchantments.removeAll(blacksmithTrait.getSettings().getEnchantmentBlocklist()); usableEnchantments.removeAll(blacksmithTrait.getSettings().getEnchantmentBlockList());
//In case all usable enchantments have been blocked, abort //In case all usable enchantments have been blocked, abort
if (usableEnchantments.isEmpty()) { if (usableEnchantments.isEmpty()) {

View File

@ -1,11 +1,10 @@
package net.knarcraft.blacksmith.trait; package net.knarcraft.blacksmith.trait;
import net.citizensnpcs.api.npc.NPC; import net.citizensnpcs.api.npc.NPC;
import net.knarcraft.blacksmith.BlacksmithPlugin;
import net.knarcraft.blacksmith.config.scrapper.ScrapperNPCSettings; import net.knarcraft.blacksmith.config.scrapper.ScrapperNPCSettings;
import net.knarcraft.blacksmith.manager.EconomyManager;
import net.knarcraft.blacksmith.util.ItemHelper; import net.knarcraft.blacksmith.util.ItemHelper;
import net.knarcraft.blacksmith.util.SalvageHelper; import net.knarcraft.blacksmith.util.SalvageHelper;
import org.bukkit.Material;
import org.bukkit.entity.Damageable; import org.bukkit.entity.Damageable;
import org.bukkit.entity.LivingEntity; import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
@ -13,17 +12,15 @@ import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.util.Calendar; import java.util.Calendar;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Objects; import java.util.Objects;
import java.util.Random; import java.util.Random;
import java.util.Set;
import static net.knarcraft.blacksmith.formatting.BlacksmithStringFormatter.sendNPCMessage; import static net.knarcraft.blacksmith.formatting.BlacksmithStringFormatter.sendNPCMessage;
import static net.knarcraft.blacksmith.util.ItemHelper.updateDamage; import static net.knarcraft.blacksmith.util.ItemHelper.updateDamage;
/** /**
* A representation of the session between a player and a blacksmith * A representation of the session between a player and a scrapper
*/ */
public class SalvageSession extends Session implements Runnable { public class SalvageSession extends Session implements Runnable {
@ -38,28 +35,19 @@ public class SalvageSession extends Session implements Runnable {
/** /**
* Instantiates a new session * Instantiates a new session
* *
* @param scrapperTrait <p>A reference to the blacksmith trait</p> * @param scrapperTrait <p>A reference to the scrapper trait</p>
* @param player <p>The player initiating the session</p> * @param player <p>The player initiating the session</p>
* @param npc <p>The Blacksmith NPC involved in 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 config <p>The config to use for the session</p>
*/ */
SalvageSession(@NotNull ScrapperTrait scrapperTrait, @NotNull Player player, @NotNull NPC npc, SalvageSession(@NotNull ScrapperTrait scrapperTrait, @NotNull Player player, @NotNull NPC npc,
@NotNull ScrapperNPCSettings config) { @NotNull ScrapperNPCSettings config, @NotNull List<ItemStack> salvage) {
super(player); super(player);
this.scrapperTrait = scrapperTrait; this.scrapperTrait = scrapperTrait;
this.npc = npc; this.npc = npc;
this.itemToSalvage = player.getInventory().getItemInMainHand(); this.itemToSalvage = player.getInventory().getItemInMainHand();
this.config = config; this.config = config;
this.salvage = salvage;
// Get the salvage, for the item, but ignore some materials if set, and the item isn't at full durability
Set<Material> ignoredSalvage = BlacksmithPlugin.getInstance().getGlobalScrapperSettings().getIgnoredSalvage(
this.itemToSalvage.getType());
if (ignoredSalvage == null || ItemHelper.getDamage(this.itemToSalvage) == 0) {
ignoredSalvage = new HashSet<>();
}
this.salvage = SalvageHelper.getSalvage(BlacksmithPlugin.getInstance().getServer(), this.itemToSalvage,
ignoredSalvage);
this.enchantmentLevels = SalvageHelper.getTotalEnchantmentLevels(this.itemToSalvage); this.enchantmentLevels = SalvageHelper.getTotalEnchantmentLevels(this.itemToSalvage);
} }
@ -71,7 +59,11 @@ public class SalvageSession extends Session implements Runnable {
sendNPCMessage(this.npc, player, config.getItemChangedMessage()); sendNPCMessage(this.npc, player, config.getItemChangedMessage());
return true; return true;
} }
// TODO: Add economy check
if (EconomyManager.cannotPayForSalvage(player)) {
sendNPCMessage(this.npc, player, config.getInsufficientFundsMessage());
return true;
}
return false; return false;
} }
@ -93,7 +85,7 @@ public class SalvageSession extends Session implements Runnable {
public void run() { public void run() {
sendNPCMessage(this.npc, player, salvageItem() ? config.getSuccessMessage() : config.getFailMessage()); sendNPCMessage(this.npc, player, salvageItem() ? config.getSuccessMessage() : config.getFailMessage());
//Stop the reforged item from displaying in the blacksmith's hand //Stop the reforged item from displaying in the scrapper's hand
if (npc.getEntity() instanceof Player) { if (npc.getEntity() instanceof Player) {
((Player) npc.getEntity()).getInventory().setItemInMainHand(null); ((Player) npc.getEntity()).getInventory().setItemInMainHand(null);
} else { } else {
@ -126,10 +118,10 @@ public class SalvageSession extends Session implements Runnable {
} }
/** /**
* The method to run when a blacksmith fails re-forging an item * The method to run when a crapper fails salvaging an item
*/ */
private void failSalvage() { private void failSalvage() {
if (itemToSalvage instanceof Damageable) { if (itemToSalvage.getItemMeta() instanceof Damageable) {
//Damage the item //Damage the item
short currentItemDurability = ItemHelper.getDurability(itemToSalvage); short currentItemDurability = ItemHelper.getDurability(itemToSalvage);
short newDurability = (short) (currentItemDurability + (currentItemDurability * random.nextInt(8))); short newDurability = (short) (currentItemDurability + (currentItemDurability * random.nextInt(8)));
@ -150,7 +142,7 @@ public class SalvageSession extends Session implements Runnable {
*/ */
private void giveSalvage() { private void giveSalvage() {
// TODO: Find a better calculation than 1 enchantment level = 1 exp level // TODO: Find a better calculation than 1 enchantment level = 1 exp level
// Gives the player back some of the XP used on an item // Gives the player back some of the EXP used on an item
player.giveExpLevels(enchantmentLevels); player.giveExpLevels(enchantmentLevels);
if (config.getDropItem() || !player.isOnline() || player.getInventory().firstEmpty() == -1) { if (config.getDropItem() || !player.isOnline() || player.getInventory().firstEmpty() == -1) {
// If the player isn't online, or the player cannot fit the item, drop the item to prevent it from // If the player isn't online, or the player cannot fit the item, drop the item to prevent it from

View File

@ -4,16 +4,21 @@ import net.citizensnpcs.api.util.DataKey;
import net.knarcraft.blacksmith.BlacksmithPlugin; import net.knarcraft.blacksmith.BlacksmithPlugin;
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.manager.EconomyManager;
import net.knarcraft.blacksmith.util.ItemHelper; import net.knarcraft.blacksmith.util.ItemHelper;
import net.knarcraft.blacksmith.util.SalvageHelper;
import net.knarcraft.knarlib.formatting.StringFormatter; import net.knarcraft.knarlib.formatting.StringFormatter;
import org.apache.commons.lang.NotImplementedException;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.Server;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set;
import static net.knarcraft.blacksmith.formatting.BlacksmithStringFormatter.sendNPCMessage; import static net.knarcraft.blacksmith.formatting.BlacksmithStringFormatter.sendNPCMessage;
@ -22,8 +27,6 @@ import static net.knarcraft.blacksmith.formatting.BlacksmithStringFormatter.send
*/ */
public class ScrapperTrait extends CustomTrait<ScrapperSetting> { public class ScrapperTrait extends CustomTrait<ScrapperSetting> {
//TODO: A scrapper will take items and turn them into the base ingredients
//TODO: If an item is enchanted, give an appropriate amount of exp
private final ScrapperNPCSettings config; private final ScrapperNPCSettings config;
/** /**
@ -37,15 +40,6 @@ public class ScrapperTrait extends CustomTrait<ScrapperSetting> {
super.setTraitSettings(this.config); super.setTraitSettings(this.config);
} }
/**
* Gets the current settings for this NPC
*
* @return <p>The current settings for this NPC</p>
*/
public ScrapperNPCSettings getSettings() {
return config;
}
/** /**
* Loads all config values stored in citizens' config file for this NPC * Loads all config values stored in citizens' config file for this NPC
* *
@ -75,25 +69,58 @@ public class ScrapperTrait extends CustomTrait<ScrapperSetting> {
ItemStack itemInHand = player.getInventory().getItemInMainHand(); ItemStack itemInHand = player.getInventory().getItemInMainHand();
List<Material> salvageAbleItems = this.config.getSalvageAbleItems(); List<Material> salvageAbleItems = this.config.getSalvageAbleItems();
boolean extended = this.config.extendedSalvageEnabled(); boolean extended = this.config.extendedSalvageEnabled();
List<ItemStack> salvage = getSalvage(player.getServer(), itemInHand, salvageAbleItems, extended);
// If extended mode is disabled, only allow repairable items to be salvaged // If extended mode is disabled, only allow repairable items to be salvaged
boolean notHoldingSalvageable = !ItemHelper.isSalvageable(player.getServer(), itemInHand) || boolean notHoldingSalvageable = salvage == null || salvage.isEmpty();
(!salvageAbleItems.isEmpty() && !salvageAbleItems.contains(itemInHand.getType())) ||
(!extended && !ItemHelper.isRepairable(itemInHand));
if (notHoldingSalvageable) { if (notHoldingSalvageable) {
String invalidMessage = StringFormatter.replacePlaceholder(config.getInvalidItemMessage(), String invalidMessage = StringFormatter.replacePlaceholder(config.getInvalidItemMessage(),
"{title}", config.getScrapperTitle()); "{title}", config.getScrapperTitle());
sendNPCMessage(this.npc, player, invalidMessage); sendNPCMessage(this.npc, player, invalidMessage);
return; return;
} }
// TODO: Mark the session start
// TODO: Initialize a new session //Start a new scrapper session for the player
// TODO: Tell player about the required cost currentSessionStartTime = System.currentTimeMillis();
throw new NotImplementedException(); session = new SalvageSession(this, player, npc, config, salvage);
//Tell the player the cost of repairing the item
String cost = EconomyManager.formatScrapperCost();
sendNPCMessage(this.npc, player, config.getCostMessage().replace("{cost}", cost));
} }
@Override @Override
protected boolean showExactTime() { protected boolean showExactTime() {
return BlacksmithPlugin.getInstance().getGlobalScrapperSettings().getShowExactTime(); return BlacksmithPlugin.getInstance().getGlobalScrapperSettings().showExactTime();
}
/**
* Gets salvage for an item, if it's salvage-able
*
* @param server <p>The server to get recipes from</p>
* @param item <p>The item to calculate salvage for</p>
* @param salvageAbleItems <p>The items this scrapper can salvage</p>
* @param extended <p>Whether extended salvage is enabled</p>
* @return <p>The possible salvage, or null if not salvage-able</p>
*/
@Nullable
private List<ItemStack> getSalvage(@NotNull Server server, @NotNull ItemStack item,
@NotNull List<Material> salvageAbleItems, boolean extended) {
boolean isSalvageable = (extended || ItemHelper.isRepairable(item)) && ItemHelper.isSalvageable(server, item) &&
(salvageAbleItems.isEmpty() || salvageAbleItems.contains(item.getType()));
if (!isSalvageable) {
return null;
}
// Get the salvage, for the item, but ignore some materials if set, and the item isn't at full durability
Set<Material> ignoredSalvage = BlacksmithPlugin.getInstance().getGlobalScrapperSettings().getIgnoredSalvage(
item.getType());
// Don't ignore salvage for fully repaired items
if (ignoredSalvage == null || ItemHelper.getDamage(item) == 0) {
ignoredSalvage = new HashSet<>();
}
return SalvageHelper.getSalvage(BlacksmithPlugin.getInstance().getServer(), item, ignoredSalvage, extended);
} }
} }

View File

@ -8,7 +8,6 @@ import org.bukkit.inventory.CraftingRecipe;
import org.bukkit.inventory.Inventory; import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.Recipe; import org.bukkit.inventory.Recipe;
import org.bukkit.inventory.SmithingTransformRecipe;
import org.bukkit.inventory.meta.Damageable; import org.bukkit.inventory.meta.Damageable;
import org.bukkit.inventory.meta.ItemMeta; import org.bukkit.inventory.meta.ItemMeta;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
@ -46,7 +45,11 @@ public final class ItemHelper {
* @return <p>The max durability of the item</p> * @return <p>The max durability of the item</p>
*/ */
public static short getMaxDurability(@NotNull ItemStack itemStack) { public static short getMaxDurability(@NotNull ItemStack itemStack) {
if (itemStack.getItemMeta() instanceof Damageable) {
return itemStack.getType().getMaxDurability(); return itemStack.getType().getMaxDurability();
} else {
return 0;
}
} }
/** /**
@ -56,12 +59,11 @@ public final class ItemHelper {
* @return <p>The durability of the item</p> * @return <p>The durability of the item</p>
*/ */
public static short getDurability(@NotNull ItemStack itemStack) { public static short getDurability(@NotNull ItemStack itemStack) {
Damageable damageable = (Damageable) itemStack.getItemMeta(); if (itemStack.getItemMeta() instanceof Damageable damageable) {
int maxDurability = getMaxDurability(itemStack); int maxDurability = getMaxDurability(itemStack);
if (damageable != null) {
return (short) (maxDurability - damageable.getDamage()); return (short) (maxDurability - damageable.getDamage());
} else { } else {
return (short) maxDurability; return 0;
} }
} }
@ -72,8 +74,7 @@ public final class ItemHelper {
* @return <p>The damage done to the item</p> * @return <p>The damage done to the item</p>
*/ */
public static short getDamage(@NotNull ItemStack itemStack) { public static short getDamage(@NotNull ItemStack itemStack) {
Damageable damageable = (Damageable) itemStack.getItemMeta(); if (itemStack.getItemMeta() instanceof Damageable damageable) {
if (damageable != null) {
return (short) damageable.getDamage(); return (short) damageable.getDamage();
} else { } else {
return 0; return 0;
@ -173,26 +174,49 @@ public final class ItemHelper {
* @return <p>True if the item can be salvaged</p> * @return <p>True if the item can be salvaged</p>
*/ */
public static boolean isSalvageable(@NotNull Server server, @NotNull ItemStack item) { public static boolean isSalvageable(@NotNull Server server, @NotNull ItemStack item) {
for (Recipe recipe : server.getRecipesFor(item)) { for (Recipe recipe : server.getRecipesFor(new ItemStack(item.getType(), item.getAmount()))) {
// Only crafting recipes, and smithing transform recipes (diamond -> netherite) are allowed. // Only crafting recipes are allowed.
if (recipe instanceof CraftingRecipe || recipe instanceof SmithingTransformRecipe && if ((recipe instanceof CraftingRecipe) && item.getAmount() >= recipe.getResult().getAmount()) {
item.getAmount() >= recipe.getResult().getAmount()) {
return true; return true;
} }
} }
return false; return false;
} }
/**
* Gets the amount of an item that's required to salvage that item
*
* @param server <p>The server to get recipes from</p>
* @param item <p>The item to check</p>
* @return <p>The number of items required for salvage, or -1 if the recipe was not found</p>
*/
public static int getRequiredAmountForSalvage(@NotNull Server server, @NotNull ItemStack item) {
for (Recipe recipe : server.getRecipesFor(new ItemStack(item.getType(), item.getAmount()))) {
// Only crafting recipes are allowed.
if (recipe instanceof CraftingRecipe) {
return recipe.getResult().getAmount();
}
}
return -1;
}
/** /**
* Gets all materials matching the given material wildcard * Gets all materials matching the given material wildcard
* *
* @param materialName <p>The material name or material wildcard to match</p> * @param materialName <p>The material name or material wildcard to match</p>
* @param extended <p>Whether to use an extended match, allowing any material</p>
* @return <p>The matched material(s)</p> * @return <p>The matched material(s)</p>
*/ */
public static @NotNull List<Material> getWildcardMatch(@NotNull String materialName) { public static @NotNull List<Material> getWildcardMatch(@NotNull String materialName, boolean extended) {
String search = InputParsingHelper.regExIfy(materialName); String search = InputParsingHelper.regExIfy(materialName);
List<Material> materials = new ArrayList<>(); List<Material> materials = new ArrayList<>();
for (Material material : ItemHelper.getAllReforgeAbleMaterials()) { List<Material> all;
if (extended) {
all = List.of(Material.values());
} else {
all = ItemHelper.getAllReforgeAbleMaterials();
}
for (Material material : all) {
if (material.name().matches(search)) { if (material.name().matches(search)) {
materials.add(material); materials.add(material);
} }
@ -249,7 +273,7 @@ public final class ItemHelper {
} }
/** /**
* Replaces smoth presets in the given list of strings * Replaces smith presets in the given list of strings
* *
* @param stringList <p>The value specified by a user</p> * @param stringList <p>The value specified by a user</p>
* @return <p>The value with smith presets replaced</p> * @return <p>The value with smith presets replaced</p>

View File

@ -22,6 +22,8 @@ import java.util.Random;
*/ */
public final class SalvageHelper { public final class SalvageHelper {
private static final Random random = new Random();
/** /**
* Gets the sum of all enchantment levels for the given item * Gets the sum of all enchantment levels for the given item
* *
@ -44,21 +46,24 @@ public final class SalvageHelper {
* @param server <p>The server to get recipes from</p> * @param server <p>The server to get recipes from</p>
* @param salvagedItem <p>The item stack to salvage</p> * @param salvagedItem <p>The item stack to salvage</p>
* @param ignoredSalvage <p>Any material which should not be returned as part of the salvage.</p> * @param ignoredSalvage <p>Any material which should not be returned as part of the salvage.</p>
* @param extended <p>Whether to enable extended salvage, ignoring the repairable restriction</p>
* @return <p>The items to return to the user, or null if not salvageable</p> * @return <p>The items to return to the user, or null if not salvageable</p>
*/ */
public static @Nullable List<ItemStack> getSalvage(@NotNull Server server, @Nullable ItemStack salvagedItem, public static @Nullable List<ItemStack> getSalvage(@NotNull Server server, @Nullable ItemStack salvagedItem,
@NotNull Collection<Material> ignoredSalvage) { @NotNull Collection<Material> ignoredSalvage, boolean extended) {
if (salvagedItem == null || salvagedItem.getAmount() < 1 || if (salvagedItem == null || salvagedItem.getAmount() < 1 ||
!ItemHelper.isRepairable(salvagedItem)) { (!extended && !ItemHelper.isRepairable(salvagedItem))) {
return null; return null;
} }
for (Recipe recipe : server.getRecipesFor(salvagedItem)) { for (Recipe recipe : server.getRecipesFor(new ItemStack(salvagedItem.getType(), salvagedItem.getAmount()))) {
if (recipe instanceof ShapedRecipe || recipe instanceof ShapelessRecipe) {
List<ItemStack> salvage = getRecipeSalvage(recipe, salvagedItem, ignoredSalvage); List<ItemStack> salvage = getRecipeSalvage(recipe, salvagedItem, ignoredSalvage);
if (salvage != null) { if (salvage != null && !salvage.isEmpty()) {
return salvage; return salvage;
} }
} }
}
return null; return null;
} }
@ -88,15 +93,7 @@ public final class SalvageHelper {
//Purge any ignored salvage to only calculate salvage using the remaining items //Purge any ignored salvage to only calculate salvage using the remaining items
ingredients.removeIf((item) -> ignoredSalvage.contains(item.getType())); ingredients.removeIf((item) -> ignoredSalvage.contains(item.getType()));
Random random = new Random(); return combineStacks(getSalvage(copyItems(ingredients), salvagedItem));
//Make sure to give salvage for all items if a stack > 1 is provided
List<ItemStack> allSalvage = new ArrayList<>();
for (int i = 0; i < salvagedItem.getAmount(); i++) {
allSalvage.addAll(getSalvage(copyItems(ingredients), salvagedItem, random));
}
return combineStacks(allSalvage);
} }
/** /**
@ -120,21 +117,30 @@ public final class SalvageHelper {
* *
* @param recipeItems <p>All items required for crafting the item to salvage</p> * @param recipeItems <p>All items required for crafting the item to salvage</p>
* @param salvagedItem <p>The item to be salvaged</p> * @param salvagedItem <p>The item to be salvaged</p>
* @param random <p>The randomness generator to use</p>
* @return <p>The items to be returned to the user as salvage</p> * @return <p>The items to be returned to the user as salvage</p>
*/ */
private static @NotNull List<ItemStack> getSalvage(@NotNull List<ItemStack> recipeItems, @NotNull
@NotNull ItemStack salvagedItem, @NotNull Random random) { private static List<ItemStack> getSalvage(@NotNull List<ItemStack> recipeItems,
double percentageRemaining = (ItemHelper.getDurability(salvagedItem) / @NotNull ItemStack salvagedItem) {
(double) ItemHelper.getMaxDurability(salvagedItem)); int durability = ItemHelper.getDurability(salvagedItem);
int maxDurability = ItemHelper.getMaxDurability(salvagedItem);
// Prevent divide by zero for items that don't have a set max durability
if (maxDurability == 0) {
maxDurability = 1;
durability = 1;
}
double percentageRemaining = (double) durability / maxDurability;
int totalItems = totalItemAmount(recipeItems); int totalItems = totalItemAmount(recipeItems);
//Get the amount of recipe items to be returned //Get the amount of recipe items to be returned
int itemsToReturn = (int) Math.floor(percentageRemaining * totalItems); int itemsToReturn = (int) Math.floor(percentageRemaining * totalItems);
int bound = recipeItems.size(); int bound = recipeItems.size();
List<ItemStack> salvage = new ArrayList<>();
List<ItemStack> salvage = new ArrayList<>();
for (int i = 0; i < itemsToReturn; i++) { for (int i = 0; i < itemsToReturn; i++) {
int itemIndex = random.nextInt(bound); int itemIndex = SalvageHelper.random.nextInt(bound);
ItemStack itemStack = recipeItems.get(itemIndex); ItemStack itemStack = recipeItems.get(itemIndex);
//Make sure to never give more of one item than the amount which exists in the recipe //Make sure to never give more of one item than the amount which exists in the recipe
@ -192,7 +198,8 @@ public final class SalvageHelper {
* @param shapedRecipe <p>The shaped recipe to get ingredients for</p> * @param shapedRecipe <p>The shaped recipe to get ingredients for</p>
* @return <p>The items contained in the recipe</p> * @return <p>The items contained in the recipe</p>
*/ */
private static @NotNull List<ItemStack> getIngredients(@NotNull ShapedRecipe shapedRecipe) { @NotNull
private static List<ItemStack> getIngredients(@NotNull ShapedRecipe shapedRecipe) {
List<ItemStack> ingredients = new ArrayList<>(); List<ItemStack> ingredients = new ArrayList<>();
Map<Character, ItemStack> ingredientMap = shapedRecipe.getIngredientMap(); Map<Character, ItemStack> ingredientMap = shapedRecipe.getIngredientMap();
//The shape is a list of the three rows' strings. Each string contains 3 characters. //The shape is a list of the three rows' strings. Each string contains 3 characters.

View File

@ -6,3 +6,4 @@ scrapper.defaults.delaysInSeconds.salvageCoolDown=scrapper.defaults.salvageCoolD
blacksmith.defaults.delaysInSeconds.minimum=blacksmith.defaults.minReforgeWaitTimeSeconds blacksmith.defaults.delaysInSeconds.minimum=blacksmith.defaults.minReforgeWaitTimeSeconds
blacksmith.defaults.delaysInSeconds.maximum=blacksmith.defaults.maxReforgeWaitTimeSeconds blacksmith.defaults.delaysInSeconds.maximum=blacksmith.defaults.maxReforgeWaitTimeSeconds
blacksmith.defaults.delaysInSeconds.reforgeCoolDown=blacksmith.defaults.reforgeCoolDownSeconds blacksmith.defaults.delaysInSeconds.reforgeCoolDown=blacksmith.defaults.reforgeCoolDownSeconds
blacksmith.defaults.enchantmentBlocklist=blacksmith.defaults.enchantmentBlockList

View File

@ -48,7 +48,7 @@ blacksmith:
reforgeAbleItems: [ ] reforgeAbleItems: [ ]
# The enchantments a blacksmith is denied from applying to an item. Disable anything you find too op or annoying. # The enchantments a blacksmith is denied from applying to an item. Disable anything you find too op or annoying.
enchantmentBlocklist: [ "binding_curse", "mending", "vanishing_curse" ] enchantmentBlockList: [ "binding_curse", "mending", "vanishing_curse" ]
# The chance to fail reforging an item, which only repairs the item a tiny bit or not at all (0-100) # The chance to fail reforging an item, which only repairs the item a tiny bit or not at all (0-100)
failReforgeChance: 10 # Default = 10% failReforgeChance: 10 # Default = 10%
@ -114,7 +114,7 @@ blacksmith:
# Settings for the scrapper trait # Settings for the scrapper trait
scrapper: scrapper:
# The settings which apply to all Scrapper NPCs. These can also be changed using the /scrapperconfig command # The settings which apply to all Scrapper NPCs. These can also be changed using the /scrapperConfig command
global: global:
# Exact time displays the exact number of seconds and minutes remaining as part of the scrapping cool-down and # 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. # scrapping delay messages, instead of just vaguely hinting at the remaining time.
@ -123,12 +123,16 @@ scrapper:
# Whether enchanted salvaged items should return some amount of exp upon salvage # Whether enchanted salvaged items should return some amount of exp upon salvage
giveExperience: true giveExperience: true
# Items ignored during salvage calculation. This follows the format: "MATERIAL[,MATERIAL2][,MATERIAL3]:IGNORED", so # Items ignored during salvage calculation. This follows the format:
# the material or materials listed will ignore the material specified after the ":" when calculating salvage # "MATERIAL[;MATERIAL2][;MATERIAL3]:IGNORED_MATERIAL[;IGNORED_MATERIAL2]",
# so the material or materials listed will ignore the material specified after the ":" when calculating salvage
# (* matches any character). This causes the player to lose some items during salvaging, but can prevent cases # (* matches any character). This causes the player to lose some items during salvaging, but can prevent cases
# where a diamond pickaxe is salvaged and only sticks are returned. # where a diamond pickaxe is salvaged and only sticks are returned.
ignoredSalvage: ignoredSalvage:
- "*_SHOVEL,*_PICKAXE,*_AXE,*_HOE,*_SWORD:STICK" - "*_SHOVEL;*_PICKAXE;*_AXE;*_HOE;*_SWORD:STICK"
# The cost of using the scrapper
basePrice: 0
# 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

View File

@ -13,7 +13,7 @@ commands:
permission: blacksmith.edit permission: blacksmith.edit
usage: /<command> <option> [new value] usage: /<command> <option> [new value]
description: Used for configuring the selected blacksmith NPC description: Used for configuring the selected blacksmith NPC
blacksmithconfig: blacksmithConfig:
permission: blacksmith.admin permission: blacksmith.admin
usage: /<command> <option/reload> [new value] usage: /<command> <option/reload> [new value]
description: Used for configuring default blacksmith settings, or global blacksmith settings description: Used for configuring default blacksmith settings, or global blacksmith settings
@ -21,7 +21,7 @@ commands:
permission: blacksmith.edit permission: blacksmith.edit
usage: /<command> <option> [new value] usage: /<command> <option> [new value]
description: Used for configuring the selected scrapper NPC description: Used for configuring the selected scrapper NPC
scrapperconfig: scrapperConfig:
permission: blacksmith.admin permission: blacksmith.admin
usage: /<command> <option/reload> [new value] usage: /<command> <option/reload> [new value]
description: Used for configuring default scrapper settings, or global scrapper settings description: Used for configuring default scrapper settings, or global scrapper settings

View File

@ -1,5 +1,5 @@
# The english translation of internal strings. To add your own language, copy everything below, and change "en" to your # The english translation of internal strings. To add your own language, copy everything below, and change "en" to your
# own language's code, and change each string. Afterwards, copy this file to Blacksmith's plugin folder, and change the # own language's code, and change each string. Afterward, copy this file to Blacksmith's plugin folder, and change the
# language in config.yml to your language's language code. # language in config.yml to your language's language code.
en: en:
# The format used to display when a setting's value has been changed # The format used to display when a setting's value has been changed

View File

@ -16,7 +16,9 @@ import java.util.List;
*/ */
public class CustomServerMock extends ServerMock { public class CustomServerMock extends ServerMock {
public @NotNull List<Recipe> getRecipesFor(@NotNull ItemStack itemStack) { @Override
@NotNull
public List<Recipe> getRecipesFor(@NotNull ItemStack itemStack) {
List<Recipe> validRecipes = new ArrayList<>(); List<Recipe> validRecipes = new ArrayList<>();
if (itemStack.getType() == Material.DIAMOND_PICKAXE) { if (itemStack.getType() == Material.DIAMOND_PICKAXE) {
ShapedRecipe recipe = new ShapedRecipe(NamespacedKey.minecraft("diamond_pickaxe"), itemStack); ShapedRecipe recipe = new ShapedRecipe(NamespacedKey.minecraft("diamond_pickaxe"), itemStack);
@ -24,6 +26,12 @@ public class CustomServerMock extends ServerMock {
recipe.setIngredient('d', Material.DIAMOND); recipe.setIngredient('d', Material.DIAMOND);
recipe.setIngredient('s', Material.STICK); recipe.setIngredient('s', Material.STICK);
validRecipes.add(recipe); validRecipes.add(recipe);
} else if (itemStack.getType() == Material.TNT) {
ShapedRecipe recipe = new ShapedRecipe(NamespacedKey.minecraft("tnt"), itemStack);
recipe.shape("gsg", "sgs", "gsg");
recipe.setIngredient('g', Material.GUNPOWDER);
recipe.setIngredient('s', Material.SAND);
validRecipes.add(recipe);
} }
return validRecipes; return validRecipes;
} }

View File

@ -86,7 +86,7 @@ public class ItemHelperTest {
@Test @Test
public void getAllReforgeAbleMaterialsTest() { public void getAllReforgeAbleMaterialsTest() {
List<Material> materials = ItemHelper.getAllReforgeAbleMaterials(); List<Material> materials = ItemHelper.getAllReforgeAbleMaterials();
assertTrue(materials.size() > 0); assertFalse(materials.isEmpty());
for (Material material : materials) { for (Material material : materials) {
assertTrue(ItemHelper.getMaxDurability(new ItemStack(material, 1)) > 0); assertTrue(ItemHelper.getMaxDurability(new ItemStack(material, 1)) > 0);

View File

@ -41,14 +41,14 @@ public class SalvageHelperTest {
@Test @Test
public void getNullForInvalidItemTest() { public void getNullForInvalidItemTest() {
//Assert that a non-reforge-able item will return null //Assert that a non-reforge-able item will return null
assertNull(SalvageHelper.getSalvage(server, new ItemStack(Material.POTATO, 1), new ArrayList<>())); assertNull(SalvageHelper.getSalvage(server, new ItemStack(Material.POTATO, 1), new ArrayList<>(), false));
} }
@Test @Test
public void getNullForLessThanOneItemTest() { public void getNullForLessThanOneItemTest() {
//Assert that 0 or 1 items will return null //Assert that 0 or 1 items will return null
assertNull(SalvageHelper.getSalvage(server, new ItemStack(Material.IRON_AXE, 0), new ArrayList<>())); assertNull(SalvageHelper.getSalvage(server, new ItemStack(Material.IRON_AXE, 0), new ArrayList<>(), false));
assertNull(SalvageHelper.getSalvage(server, new ItemStack(Material.IRON_SWORD, -1), new ArrayList<>())); assertNull(SalvageHelper.getSalvage(server, new ItemStack(Material.IRON_SWORD, -1), new ArrayList<>(), false));
} }
@Test @Test
@ -58,7 +58,7 @@ public class SalvageHelperTest {
expectedSalvage.add(new ItemStack(Material.STICK, 2)); expectedSalvage.add(new ItemStack(Material.STICK, 2));
ItemStack itemToSalvage = new ItemStack(Material.DIAMOND_PICKAXE, 1); ItemStack itemToSalvage = new ItemStack(Material.DIAMOND_PICKAXE, 1);
//Note: Conversion to sets makes sure the order doesn't matter //Note: Conversion to sets makes sure the order doesn't matter
List<ItemStack> salvage = SalvageHelper.getSalvage(server, itemToSalvage, new ArrayList<>()); List<ItemStack> salvage = SalvageHelper.getSalvage(server, itemToSalvage, new ArrayList<>(), false);
if (salvage == null) { if (salvage == null) {
fail(); fail();
} else { } else {
@ -67,13 +67,13 @@ public class SalvageHelperTest {
} }
@Test @Test
public void getSeveralFullSalvageTest() { public void getExtendedSalvageTest() {
Set<ItemStack> expectedSalvage = new HashSet<>(); Set<ItemStack> expectedSalvage = new HashSet<>();
expectedSalvage.add(new ItemStack(Material.DIAMOND, 21)); expectedSalvage.add(new ItemStack(Material.GUNPOWDER, 5));
expectedSalvage.add(new ItemStack(Material.STICK, 14)); expectedSalvage.add(new ItemStack(Material.SAND, 4));
ItemStack itemToSalvage = new ItemStack(Material.DIAMOND_PICKAXE, 7); ItemStack itemToSalvage = new ItemStack(Material.TNT, 1);
//Note: Conversion to sets makes sure the order doesn't matter //Note: Conversion to sets makes sure the order doesn't matter
List<ItemStack> salvage = SalvageHelper.getSalvage(server, itemToSalvage, new ArrayList<>()); List<ItemStack> salvage = SalvageHelper.getSalvage(server, itemToSalvage, new ArrayList<>(), true);
if (salvage == null) { if (salvage == null) {
fail(); fail();
} else { } else {
@ -93,7 +93,7 @@ public class SalvageHelperTest {
damageable.setDamage(100); damageable.setDamage(100);
} }
itemToSalvage.setItemMeta(meta); itemToSalvage.setItemMeta(meta);
List<ItemStack> salvage = SalvageHelper.getSalvage(server, itemToSalvage, new ArrayList<>()); List<ItemStack> salvage = SalvageHelper.getSalvage(server, itemToSalvage, new ArrayList<>(), false);
//Assert that some items are given //Assert that some items are given
assertNotEquals(salvage, new ArrayList<>()); assertNotEquals(salvage, new ArrayList<>());
//Assert that a damaged item won't give full salvage //Assert that a damaged item won't give full salvage
@ -113,7 +113,7 @@ public class SalvageHelperTest {
damageable.setDamage(100); damageable.setDamage(100);
} }
itemToSalvage.setItemMeta(meta); itemToSalvage.setItemMeta(meta);
List<ItemStack> salvage = SalvageHelper.getSalvage(server, itemToSalvage, ignoredSalvage); List<ItemStack> salvage = SalvageHelper.getSalvage(server, itemToSalvage, ignoredSalvage, false);
//Assert that some items are given //Assert that some items are given
assertNotEquals(salvage, new ArrayList<>()); assertNotEquals(salvage, new ArrayList<>());
//Assert that a damaged diamond pickaxe with sticks ignored returns 2 diamonds a salvage //Assert that a damaged diamond pickaxe with sticks ignored returns 2 diamonds a salvage