Writes a lot of code necessary for the scrapper

Adds the classes necessary for the new scrapper
Partly implements some scrapper functionality
Restructures some classes to reduce code duplication
Moves some classes to make some classes easier to find
Adds a bunch of TODOs where things have an unfinished implementation
This commit is contained in:
Kristian Knarvik 2023-11-14 16:04:48 +01:00
parent 1938a690c6
commit f3f3f66c38
40 changed files with 1788 additions and 594 deletions

16
pom.xml
View File

@ -19,10 +19,6 @@
<!-- Repositories --> <!-- Repositories -->
<repositories> <repositories>
<repository>
<id>knarcraft-repo</id>
<url>https://git.knarcraft.net/api/packages/EpicKnarvik97/maven</url>
</repository>
<repository> <repository>
<id>spigot-repo</id> <id>spigot-repo</id>
<url>https://hub.spigotmc.org/nexus/content/repositories/snapshots/</url> <url>https://hub.spigotmc.org/nexus/content/repositories/snapshots/</url>
@ -39,6 +35,10 @@
<id>papermc</id> <id>papermc</id>
<url>https://repo.papermc.io/repository/maven-public/</url> <url>https://repo.papermc.io/repository/maven-public/</url>
</repository> </repository>
<repository>
<id>knarcraft-repo</id>
<url>https://git.knarcraft.net/api/packages/EpicKnarvik97/maven</url>
</repository>
</repositories> </repositories>
<distributionManagement> <distributionManagement>
<repository> <repository>
@ -69,7 +69,7 @@
<dependency> <dependency>
<groupId>org.spigotmc</groupId> <groupId>org.spigotmc</groupId>
<artifactId>spigot-api</artifactId> <artifactId>spigot-api</artifactId>
<version>1.20.1-R0.1-SNAPSHOT</version> <version>1.20.2-R0.1-SNAPSHOT</version>
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
<dependency> <dependency>
@ -87,7 +87,7 @@
<dependency> <dependency>
<groupId>net.knarcraft</groupId> <groupId>net.knarcraft</groupId>
<artifactId>knarlib</artifactId> <artifactId>knarlib</artifactId>
<version>1.2.3</version> <version>1.2.4</version>
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>
<dependency> <dependency>
@ -98,8 +98,8 @@
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.github.seeseemelk</groupId> <groupId>com.github.seeseemelk</groupId>
<artifactId>MockBukkit-v1.19</artifactId> <artifactId>MockBukkit-v1.20</artifactId>
<version>2.145.0</version> <version>3.9.0</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
</dependencies> </dependencies>

View File

@ -1,13 +1,18 @@
package net.knarcraft.blacksmith; package net.knarcraft.blacksmith;
import net.citizensnpcs.api.CitizensAPI; import net.citizensnpcs.api.CitizensAPI;
import net.knarcraft.blacksmith.command.BlackSmithConfigCommand;
import net.knarcraft.blacksmith.command.BlackSmithConfigTabCompleter;
import net.knarcraft.blacksmith.command.BlackSmithEditCommand;
import net.knarcraft.blacksmith.command.BlackSmithEditTabCompleter;
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.BlackSmithConfigTabCompleter;
import net.knarcraft.blacksmith.command.blacksmith.BlackSmithEditCommand;
import net.knarcraft.blacksmith.command.blacksmith.BlackSmithEditTabCompleter;
import net.knarcraft.blacksmith.command.scrapper.ScrapperConfigCommand;
import net.knarcraft.blacksmith.command.scrapper.ScrapperConfigTabCompleter;
import net.knarcraft.blacksmith.command.scrapper.ScrapperEditCommand;
import net.knarcraft.blacksmith.command.scrapper.ScrapperEditTabCompleter;
import net.knarcraft.blacksmith.config.blacksmith.GlobalBlacksmithSettings; import net.knarcraft.blacksmith.config.blacksmith.GlobalBlacksmithSettings;
import net.knarcraft.blacksmith.config.scrapper.GlobalScrapperSettings;
import net.knarcraft.blacksmith.formatting.BlacksmithTranslatableMessage; import net.knarcraft.blacksmith.formatting.BlacksmithTranslatableMessage;
import net.knarcraft.blacksmith.listener.NPCClickListener; import net.knarcraft.blacksmith.listener.NPCClickListener;
import net.knarcraft.blacksmith.listener.PlayerListener; import net.knarcraft.blacksmith.listener.PlayerListener;
@ -17,12 +22,16 @@ 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;
import net.knarcraft.knarlib.util.UpdateChecker; import net.knarcraft.knarlib.util.UpdateChecker;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.PluginCommand; import org.bukkit.command.PluginCommand;
import org.bukkit.command.TabCompleter;
import org.bukkit.configuration.file.FileConfiguration; import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.plugin.PluginDescriptionFile; import org.bukkit.plugin.PluginDescriptionFile;
import org.bukkit.plugin.PluginManager; import org.bukkit.plugin.PluginManager;
import org.bukkit.plugin.java.JavaPlugin; import org.bukkit.plugin.java.JavaPlugin;
import org.bukkit.plugin.java.JavaPluginLoader; import org.bukkit.plugin.java.JavaPluginLoader;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.File; import java.io.File;
import java.util.logging.Level; import java.util.logging.Level;
@ -33,7 +42,8 @@ import java.util.logging.Level;
public class BlacksmithPlugin extends JavaPlugin { public class BlacksmithPlugin extends JavaPlugin {
private static BlacksmithPlugin instance; private static BlacksmithPlugin instance;
private GlobalBlacksmithSettings config; private GlobalBlacksmithSettings blacksmithConfig;
private GlobalScrapperSettings scrapperConfig;
private static Translator translator; private static Translator translator;
private static StringFormatter stringFormatter; private static StringFormatter stringFormatter;
@ -49,7 +59,8 @@ public class BlacksmithPlugin extends JavaPlugin {
* Constructor required for MockBukkit * Constructor required for MockBukkit
*/ */
@SuppressWarnings("unused") @SuppressWarnings("unused")
protected BlacksmithPlugin(JavaPluginLoader loader, PluginDescriptionFile descriptionFile, File dataFolder, File file) { protected BlacksmithPlugin(@NotNull JavaPluginLoader loader, @NotNull PluginDescriptionFile descriptionFile,
@NotNull File dataFolder, @NotNull File file) {
super(loader, descriptionFile, dataFolder, file); super(loader, descriptionFile, dataFolder, file);
} }
@ -58,17 +69,26 @@ public class BlacksmithPlugin extends JavaPlugin {
* *
* @return <p>An instance of the blacksmith plugin</p> * @return <p>An instance of the blacksmith plugin</p>
*/ */
public static BlacksmithPlugin getInstance() { public static @NotNull BlacksmithPlugin getInstance() {
return instance; return instance;
} }
/** /**
* Gets settings for the blacksmith plugin * Gets settings for the blacksmith plugin's blacksmiths
* *
* @return <p>Settings for the blacksmith plugin</p> * @return <p>Settings for the blacksmith plugin's blacksmith</p>
*/ */
public GlobalBlacksmithSettings getSettings() { public @NotNull GlobalBlacksmithSettings getGlobalBlacksmithSettings() {
return config; return blacksmithConfig;
}
/**
* Gets settings for the blacksmith plugin's scrapper
*
* @return <p>Settings for the blacksmith plugin's scrapper</p>
*/
public @NotNull GlobalScrapperSettings getGlobalScrapperSettings() {
return scrapperConfig;
} }
/** /**
@ -76,8 +96,10 @@ public class BlacksmithPlugin extends JavaPlugin {
*/ */
public void reload() { public void reload() {
this.reloadConfig(); this.reloadConfig();
config.load(); blacksmithConfig.load();
translator.loadLanguages(this.getDataFolder(), "en", this.getConfig().getString("language", "en")); scrapperConfig.load();
translator.loadLanguages(this.getDataFolder(), "en",
this.getConfig().getString("language", "en"));
} }
/** /**
@ -85,7 +107,7 @@ public class BlacksmithPlugin extends JavaPlugin {
* *
* @return <p>The translator to use</p> * @return <p>The translator to use</p>
*/ */
public static Translator getTranslator() { public static @NotNull Translator getTranslator() {
return BlacksmithPlugin.translator; return BlacksmithPlugin.translator;
} }
@ -94,7 +116,7 @@ public class BlacksmithPlugin extends JavaPlugin {
* *
* @return <p>The string formatter to use</p> * @return <p>The string formatter to use</p>
*/ */
public static StringFormatter getStringFormatter() { public static @NotNull StringFormatter getStringFormatter() {
return BlacksmithPlugin.stringFormatter; return BlacksmithPlugin.stringFormatter;
} }
@ -114,23 +136,8 @@ public class BlacksmithPlugin extends JavaPlugin {
this.reloadConfig(); this.reloadConfig();
this.saveConfig(); this.saveConfig();
//Load settings // Initialize custom configuration files
config = new GlobalBlacksmithSettings(this); initializeConfigurations(fileConfiguration);
config.load();
//Prepare the translator
translator = new Translator();
translator.registerMessageCategory(TranslatableTimeUnit.UNIT_SECOND);
translator.registerMessageCategory(BlacksmithTranslatableMessage.ITEM_TYPE_ENCHANTMENT);
translator.loadLanguages(this.getDataFolder(), "en", fileConfiguration.getString("language", "en"));
PluginDescriptionFile description = this.getDescription();
String prefix;
if (description.getPrefix() == null) {
prefix = "Blacksmith";
} else {
prefix = description.getPrefix();
}
BlacksmithPlugin.stringFormatter = new StringFormatter(prefix, translator);
//Set up Vault integration //Set up Vault integration
if (!setUpVault()) { if (!setUpVault()) {
@ -153,6 +160,34 @@ public class BlacksmithPlugin extends JavaPlugin {
() -> this.getDescription().getVersion(), null); () -> this.getDescription().getVersion(), null);
} }
/**
* Initializes custom configuration and translation
*
* @param fileConfiguration <p>The configuration file to get values from</p>
*/
private void initializeConfigurations(@NotNull FileConfiguration fileConfiguration) {
//Load settings
blacksmithConfig = new GlobalBlacksmithSettings(this);
blacksmithConfig.load();
scrapperConfig = new GlobalScrapperSettings(this);
scrapperConfig.load();
//Prepare the translator
translator = new Translator();
translator.registerMessageCategory(TranslatableTimeUnit.UNIT_SECOND);
translator.registerMessageCategory(BlacksmithTranslatableMessage.ITEM_TYPE_ENCHANTMENT);
translator.loadLanguages(this.getDataFolder(), "en",
fileConfiguration.getString("language", "en"));
PluginDescriptionFile description = this.getDescription();
String prefix;
if (description.getPrefix() == null) {
prefix = "Blacksmith";
} else {
prefix = description.getPrefix();
}
BlacksmithPlugin.stringFormatter = new StringFormatter(prefix, translator);
}
/** /**
* Tries to set up Vault * Tries to set up Vault
* *
@ -182,24 +217,28 @@ public class BlacksmithPlugin extends JavaPlugin {
* Registers all commands used by this plugin * Registers all commands used by this plugin
*/ */
private void registerCommands() { private void registerCommands() {
//Register the blacksmith NPC edit main-command registerCommand("blacksmith", new BlackSmithEditCommand(), new BlackSmithEditTabCompleter());
PluginCommand blacksmithCommand = this.getCommand("blacksmith"); registerCommand("blacksmithConfig", new BlackSmithConfigCommand(), new BlackSmithConfigTabCompleter());
if (blacksmithCommand != null) { registerCommand("scrapper", new ScrapperEditCommand(), new ScrapperEditTabCompleter());
blacksmithCommand.setExecutor(new BlackSmithEditCommand()); registerCommand("scrapperConfig", new ScrapperConfigCommand(), new ScrapperConfigTabCompleter());
blacksmithCommand.setTabCompleter(new BlackSmithEditTabCompleter()); registerCommand("preset", new PresetCommand(), new PresetTabCompleter());
} }
//Register the global config edit command /**
PluginCommand blacksmithConfigCommand = this.getCommand("blacksmithConfig"); * Registers a command
if (blacksmithConfigCommand != null) { *
blacksmithConfigCommand.setExecutor(new BlackSmithConfigCommand()); * @param commandName <p>The name of the command</p>
blacksmithConfigCommand.setTabCompleter(new BlackSmithConfigTabCompleter()); * @param executor <p>The executor to bind to the command</p>
* @param tabCompleter <p>The tab completer to bind to the command, or null</p>
*/
private void registerCommand(@NotNull String commandName, @NotNull CommandExecutor executor,
@Nullable TabCompleter tabCompleter) {
PluginCommand command = this.getCommand(commandName);
if (command != null) {
command.setExecutor(executor);
if (tabCompleter != null) {
command.setTabCompleter(tabCompleter);
} }
PluginCommand presetCommand = this.getCommand("preset");
if (presetCommand != null) {
presetCommand.setExecutor(new PresetCommand());
presetCommand.setTabCompleter(new PresetTabCompleter());
} }
} }

View File

@ -24,10 +24,9 @@ public class ReloadCommand implements TabExecutor {
return true; return true;
} }
@Nullable
@Override @Override
public List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, public @Nullable List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command,
@NotNull String[] args) { @NotNull String label, @NotNull String[] args) {
return new ArrayList<>(); return new ArrayList<>();
} }

View File

@ -1,10 +1,11 @@
package net.knarcraft.blacksmith.command; package net.knarcraft.blacksmith.command.blacksmith;
import net.knarcraft.blacksmith.BlacksmithPlugin; import net.knarcraft.blacksmith.BlacksmithPlugin;
import net.knarcraft.blacksmith.command.ReloadCommand;
import net.knarcraft.blacksmith.config.SettingValueType;
import net.knarcraft.blacksmith.config.blacksmith.BlacksmithNPCSetting;
import net.knarcraft.blacksmith.config.blacksmith.GlobalBlacksmithSetting; import net.knarcraft.blacksmith.config.blacksmith.GlobalBlacksmithSetting;
import net.knarcraft.blacksmith.config.blacksmith.GlobalBlacksmithSettings; import net.knarcraft.blacksmith.config.blacksmith.GlobalBlacksmithSettings;
import net.knarcraft.blacksmith.config.blacksmith.BlacksmithNPCSetting;
import net.knarcraft.blacksmith.config.SettingValueType;
import net.knarcraft.blacksmith.formatting.BlacksmithTranslatableMessage; import net.knarcraft.blacksmith.formatting.BlacksmithTranslatableMessage;
import net.knarcraft.blacksmith.formatting.ItemType; import net.knarcraft.blacksmith.formatting.ItemType;
import net.knarcraft.blacksmith.util.InputParsingHelper; import net.knarcraft.blacksmith.util.InputParsingHelper;
@ -17,6 +18,7 @@ import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
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.util.Arrays; import java.util.Arrays;
@ -38,7 +40,7 @@ public class BlackSmithConfigCommand implements CommandExecutor {
if (commandName.equalsIgnoreCase("reload")) { if (commandName.equalsIgnoreCase("reload")) {
return new ReloadCommand().onCommand(sender, command, label, args); return new ReloadCommand().onCommand(sender, command, label, args);
} }
GlobalBlacksmithSettings settings = BlacksmithPlugin.getInstance().getSettings(); GlobalBlacksmithSettings settings = BlacksmithPlugin.getInstance().getGlobalBlacksmithSettings();
//Find which global setting the user has specified, if any //Find which global setting the user has specified, if any
GlobalBlacksmithSetting detectedGlobalBlacksmithSetting = null; GlobalBlacksmithSetting detectedGlobalBlacksmithSetting = null;
@ -93,8 +95,9 @@ public class BlackSmithConfigCommand implements CommandExecutor {
* @param sender <p>The command sender to display any output to</p> * @param sender <p>The command sender to display any output to</p>
* @return <p>True if the value was successfully changed</p> * @return <p>True if the value was successfully changed</p>
*/ */
private boolean changeValue(String[] args, GlobalBlacksmithSetting detectedGlobalBlacksmithSetting, BlacksmithNPCSetting detectedBlacksmithNPCSetting, private boolean changeValue(@NotNull String[] args, @Nullable GlobalBlacksmithSetting detectedGlobalBlacksmithSetting,
GlobalBlacksmithSettings settings, CommandSender sender) { @Nullable BlacksmithNPCSetting detectedBlacksmithNPCSetting,
@NotNull GlobalBlacksmithSettings settings, @NotNull CommandSender sender) {
String newValue = args[1]; String newValue = args[1];
if (detectedGlobalBlacksmithSetting != null) { if (detectedGlobalBlacksmithSetting != null) {
settings.changeValue(detectedGlobalBlacksmithSetting, newValue); settings.changeValue(detectedGlobalBlacksmithSetting, newValue);
@ -124,8 +127,9 @@ public class BlackSmithConfigCommand implements CommandExecutor {
* @param sender <p>The command sender to display any output to</p> * @param sender <p>The command sender to display any output to</p>
* @return <p>True if a settings was successfully displayed</p> * @return <p>True if a settings was successfully displayed</p>
*/ */
private boolean displayCurrentValue(GlobalBlacksmithSetting detectedGlobalBlacksmithSetting, BlacksmithNPCSetting detectedBlacksmithNPCSetting, private boolean displayCurrentValue(@Nullable GlobalBlacksmithSetting detectedGlobalBlacksmithSetting,
GlobalBlacksmithSettings settings, CommandSender sender) { @Nullable BlacksmithNPCSetting detectedBlacksmithNPCSetting,
@NotNull GlobalBlacksmithSettings settings, @NotNull CommandSender sender) {
String settingValue; String settingValue;
String correctCommandName; String correctCommandName;
boolean printRawValue = false; boolean printRawValue = false;
@ -165,8 +169,9 @@ public class BlackSmithConfigCommand implements CommandExecutor {
* @param settings <p>The settings object to query</p> * @param settings <p>The settings object to query</p>
* @return <p>True if the value was successfully displayed</p> * @return <p>True if the value was successfully displayed</p>
*/ */
private boolean displaySpecialCaseValue(String selector, CommandSender sender, GlobalBlacksmithSetting setting, private boolean displaySpecialCaseValue(@NotNull String selector, @NotNull CommandSender sender,
GlobalBlacksmithSettings settings) { @Nullable GlobalBlacksmithSetting setting,
@NotNull GlobalBlacksmithSettings settings) {
if (setting == GlobalBlacksmithSetting.BASE_PRICE || setting == GlobalBlacksmithSetting.PRICE_PER_DURABILITY_POINT) { if (setting == GlobalBlacksmithSetting.BASE_PRICE || setting == GlobalBlacksmithSetting.PRICE_PER_DURABILITY_POINT) {
Material material = InputParsingHelper.matchMaterial(selector); Material material = InputParsingHelper.matchMaterial(selector);
if (material == null) { if (material == null) {
@ -203,7 +208,7 @@ public class BlackSmithConfigCommand implements CommandExecutor {
* @param commandName <p>The command specified</p> * @param commandName <p>The command specified</p>
* @return <p>True if the command is a special case</p> * @return <p>True if the command is a special case</p>
*/ */
private boolean isSpecialCase(String commandName) { private boolean isSpecialCase(@NotNull String commandName) {
return commandName.equalsIgnoreCase(GlobalBlacksmithSetting.BASE_PRICE.getCommandName()) || return commandName.equalsIgnoreCase(GlobalBlacksmithSetting.BASE_PRICE.getCommandName()) ||
commandName.equalsIgnoreCase(GlobalBlacksmithSetting.PRICE_PER_DURABILITY_POINT.getCommandName()) || commandName.equalsIgnoreCase(GlobalBlacksmithSetting.PRICE_PER_DURABILITY_POINT.getCommandName()) ||
commandName.equalsIgnoreCase(GlobalBlacksmithSetting.ENCHANTMENT_COST.getCommandName()); commandName.equalsIgnoreCase(GlobalBlacksmithSetting.ENCHANTMENT_COST.getCommandName());
@ -218,7 +223,9 @@ public class BlackSmithConfigCommand implements CommandExecutor {
* @param sender <p>The command sender to notify if successful</p> * @param sender <p>The command sender to notify if successful</p>
* @return <p>True if already handled as a special case</p> * @return <p>True if already handled as a special case</p>
*/ */
private boolean updateSpecialCase(GlobalBlacksmithSettings settings, GlobalBlacksmithSetting detectedGlobalBlacksmithSetting, String[] args, private boolean updateSpecialCase(@NotNull GlobalBlacksmithSettings settings,
@Nullable GlobalBlacksmithSetting detectedGlobalBlacksmithSetting,
@NotNull String[] args,
CommandSender sender) { CommandSender sender) {
if (InputParsingHelper.isEmpty(args[2])) { if (InputParsingHelper.isEmpty(args[2])) {
args[2] = "-1"; args[2] = "-1";
@ -259,8 +266,10 @@ public class BlackSmithConfigCommand implements CommandExecutor {
* @param sender <p>The command sender to respond to</p> * @param sender <p>The command sender to respond to</p>
* @return <p>True if the input was valid, and the item(s) was/were updated</p> * @return <p>True if the input was valid, and the item(s) was/were updated</p>
*/ */
private boolean updatePriceSpecialCase(GlobalBlacksmithSettings settings, GlobalBlacksmithSetting detectedGlobalBlacksmithSetting, private boolean updatePriceSpecialCase(@NotNull GlobalBlacksmithSettings settings,
String materialName, double newPrice, CommandSender sender) { @NotNull GlobalBlacksmithSetting detectedGlobalBlacksmithSetting,
@NotNull String materialName, double newPrice,
@NotNull CommandSender sender) {
ItemType itemType = ItemType.MATERIAL; ItemType itemType = ItemType.MATERIAL;
String itemChanged; String itemChanged;
//Update base price or price per durability point for an item //Update base price or price per durability point for an item
@ -294,8 +303,9 @@ public class BlackSmithConfigCommand implements CommandExecutor {
* @param materialName <p>The wildcard material name to update cost for</p> * @param materialName <p>The wildcard material name to update cost for</p>
* @param newPrice <p>The new cost for the matched items</p> * @param newPrice <p>The new cost for the matched items</p>
*/ */
private void updateAllMatchedPrices(GlobalBlacksmithSettings settings, GlobalBlacksmithSetting detectedGlobalBlacksmithSetting, private void updateAllMatchedPrices(@NotNull GlobalBlacksmithSettings settings,
String materialName, double newPrice) { @NotNull GlobalBlacksmithSetting detectedGlobalBlacksmithSetting,
@NotNull String materialName, double newPrice) {
String search = InputParsingHelper.regExIfy(materialName); String search = InputParsingHelper.regExIfy(materialName);
for (Material material : ItemHelper.getAllReforgeAbleMaterials()) { for (Material material : ItemHelper.getAllReforgeAbleMaterials()) {
if (!material.name().matches(search)) { if (!material.name().matches(search)) {

View File

@ -1,8 +1,8 @@
package net.knarcraft.blacksmith.command; package net.knarcraft.blacksmith.command.blacksmith;
import net.knarcraft.blacksmith.config.blacksmith.GlobalBlacksmithSetting;
import net.knarcraft.blacksmith.config.blacksmith.BlacksmithNPCSetting;
import net.knarcraft.blacksmith.config.SettingValueType; import net.knarcraft.blacksmith.config.SettingValueType;
import net.knarcraft.blacksmith.config.blacksmith.BlacksmithNPCSetting;
import net.knarcraft.blacksmith.config.blacksmith.GlobalBlacksmithSetting;
import net.knarcraft.blacksmith.util.InputParsingHelper; import net.knarcraft.blacksmith.util.InputParsingHelper;
import org.bukkit.command.Command; import org.bukkit.command.Command;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
@ -66,7 +66,7 @@ public class BlackSmithConfigTabCompleter implements TabCompleter {
* @param args <p>The arguments given by the user</p> * @param args <p>The arguments given by the user</p>
* @return <p>Null if not writing a spaced message</p> * @return <p>Null if not writing a spaced message</p>
*/ */
private List<String> skipCompletionForSpacedMessage(String[] args) { private List<String> skipCompletionForSpacedMessage(@NotNull String[] args) {
if (args.length > 2) { if (args.length > 2) {
BlacksmithNPCSetting blacksmithNpcSetting = null; BlacksmithNPCSetting blacksmithNpcSetting = null;
for (BlacksmithNPCSetting setting : BlacksmithNPCSetting.values()) { for (BlacksmithNPCSetting setting : BlacksmithNPCSetting.values()) {
@ -89,7 +89,8 @@ public class BlackSmithConfigTabCompleter implements TabCompleter {
* @param args <p>The arguments given by the user</p> * @param args <p>The arguments given by the user</p>
* @return <p>The tab-completions to show to the user</p> * @return <p>The tab-completions to show to the user</p>
*/ */
private List<String> getPerTypeTabCompletions(GlobalBlacksmithSetting globalBlacksmithSetting, String[] args) { private List<String> getPerTypeTabCompletions(@NotNull GlobalBlacksmithSetting globalBlacksmithSetting,
@NotNull String[] args) {
//Display possible tab-completions only if a valid enchantment or material is provided //Display possible tab-completions only if a valid enchantment or material is provided
if (((globalBlacksmithSetting == GlobalBlacksmithSetting.BASE_PRICE || if (((globalBlacksmithSetting == GlobalBlacksmithSetting.BASE_PRICE ||
globalBlacksmithSetting == GlobalBlacksmithSetting.PRICE_PER_DURABILITY_POINT) && globalBlacksmithSetting == GlobalBlacksmithSetting.PRICE_PER_DURABILITY_POINT) &&
@ -109,7 +110,7 @@ public class BlackSmithConfigTabCompleter implements TabCompleter {
* @param commandValue <p>The command value used to filter tab-completions</p> * @param commandValue <p>The command value used to filter tab-completions</p>
* @return <p>Some valid options for the command's argument</p> * @return <p>Some valid options for the command's argument</p>
*/ */
private List<String> tabCompleteCommandValues(String commandName, String commandValue) { private List<String> tabCompleteCommandValues(@NotNull String commandName, @NotNull String commandValue) {
if (commandName.equalsIgnoreCase("reload")) { if (commandName.equalsIgnoreCase("reload")) {
return new ArrayList<>(); return new ArrayList<>();
} }
@ -134,9 +135,12 @@ public class BlackSmithConfigTabCompleter implements TabCompleter {
* @param commandValue <p>The command value used to filter between available tab-completions</p> * @param commandValue <p>The command value used to filter between available tab-completions</p>
* @return <p>The available tab-completions</p> * @return <p>The available tab-completions</p>
*/ */
private List<String> getCompletions(GlobalBlacksmithSetting globalBlacksmithSetting, String commandValue) { private List<String> getCompletions(@NotNull GlobalBlacksmithSetting globalBlacksmithSetting,
List<String> returnValues = filterMatchingContains(getTabCompletions(globalBlacksmithSetting.getValueType()), commandValue); @NotNull String commandValue) {
if (globalBlacksmithSetting == GlobalBlacksmithSetting.BASE_PRICE || globalBlacksmithSetting == GlobalBlacksmithSetting.PRICE_PER_DURABILITY_POINT) { List<String> returnValues = filterMatchingContains(
getTabCompletions(globalBlacksmithSetting.getValueType()), commandValue);
if (globalBlacksmithSetting == GlobalBlacksmithSetting.BASE_PRICE ||
globalBlacksmithSetting == GlobalBlacksmithSetting.PRICE_PER_DURABILITY_POINT) {
returnValues.addAll(filterMatchingContains(getTabCompletions(SettingValueType.MATERIAL), commandValue)); returnValues.addAll(filterMatchingContains(getTabCompletions(SettingValueType.MATERIAL), commandValue));
} else if (globalBlacksmithSetting == GlobalBlacksmithSetting.ENCHANTMENT_COST) { } else if (globalBlacksmithSetting == GlobalBlacksmithSetting.ENCHANTMENT_COST) {
returnValues.addAll(filterMatchingContains(getTabCompletions(SettingValueType.ENCHANTMENT), commandValue)); returnValues.addAll(filterMatchingContains(getTabCompletions(SettingValueType.ENCHANTMENT), commandValue));

View File

@ -1,10 +1,10 @@
package net.knarcraft.blacksmith.command; package net.knarcraft.blacksmith.command.blacksmith;
import net.citizensnpcs.api.CitizensAPI; import net.citizensnpcs.api.CitizensAPI;
import net.citizensnpcs.api.npc.NPC; import net.citizensnpcs.api.npc.NPC;
import net.knarcraft.blacksmith.BlacksmithPlugin; import net.knarcraft.blacksmith.BlacksmithPlugin;
import net.knarcraft.blacksmith.config.blacksmith.BlacksmithNPCSetting;
import net.knarcraft.blacksmith.config.SettingValueType; import net.knarcraft.blacksmith.config.SettingValueType;
import net.knarcraft.blacksmith.config.blacksmith.BlacksmithNPCSetting;
import net.knarcraft.blacksmith.formatting.BlacksmithTranslatableMessage; import net.knarcraft.blacksmith.formatting.BlacksmithTranslatableMessage;
import net.knarcraft.blacksmith.trait.BlacksmithTrait; import net.knarcraft.blacksmith.trait.BlacksmithTrait;
import net.knarcraft.blacksmith.util.InputParsingHelper; import net.knarcraft.blacksmith.util.InputParsingHelper;
@ -14,6 +14,7 @@ import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor; import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Arrays; import java.util.Arrays;
@ -64,8 +65,10 @@ public class BlackSmithEditCommand implements CommandExecutor {
* @param sender <p>The command sender to notify about results</p> * @param sender <p>The command sender to notify about results</p>
* @return <p>True if everything went successfully</p> * @return <p>True if everything went successfully</p>
*/ */
private boolean displayOrChangeNPCSetting(BlacksmithTrait blacksmithTrait, BlacksmithNPCSetting blacksmithNpcSetting, String newValue, private boolean displayOrChangeNPCSetting(@NotNull BlacksmithTrait blacksmithTrait,
CommandSender sender) { @NotNull BlacksmithNPCSetting blacksmithNpcSetting,
@Nullable String newValue,
@NotNull CommandSender sender) {
if (newValue == null) { if (newValue == null) {
//Display the current value of the setting //Display the current value of the setting
displayNPCSetting(blacksmithTrait, blacksmithNpcSetting, sender); displayNPCSetting(blacksmithTrait, blacksmithNpcSetting, sender);
@ -99,11 +102,13 @@ public class BlackSmithEditCommand implements CommandExecutor {
* @param blacksmithNpcSetting <p>The NPC setting to see the value of</p> * @param blacksmithNpcSetting <p>The NPC setting to see the value of</p>
* @param sender <p>The command sender to display the value to</p> * @param sender <p>The command sender to display the value to</p>
*/ */
private void displayNPCSetting(BlacksmithTrait blacksmithTrait, BlacksmithNPCSetting blacksmithNpcSetting, CommandSender sender) { private void displayNPCSetting(@NotNull BlacksmithTrait blacksmithTrait,
@NotNull BlacksmithNPCSetting blacksmithNpcSetting, @NotNull CommandSender sender) {
String rawValue = String.valueOf(blacksmithTrait.getSettings().getRawValue(blacksmithNpcSetting)); String rawValue = String.valueOf(blacksmithTrait.getSettings().getRawValue(blacksmithNpcSetting));
if (InputParsingHelper.isEmpty(rawValue)) { if (InputParsingHelper.isEmpty(rawValue)) {
//Display the default value, if no custom value has been specified //Display the default value, if no custom value has been specified
rawValue = String.valueOf(BlacksmithPlugin.getInstance().getSettings().getRawValue(blacksmithNpcSetting)); rawValue = String.valueOf(BlacksmithPlugin.getInstance().getGlobalBlacksmithSettings().getRawValue(
blacksmithNpcSetting));
BlacksmithPlugin.getStringFormatter().displaySuccessMessage(sender, BlacksmithPlugin.getStringFormatter().displaySuccessMessage(sender,
getCurrentValueMessage(blacksmithNpcSetting.getCommandName(), rawValue)); getCurrentValueMessage(blacksmithNpcSetting.getCommandName(), rawValue));
} else { } else {

View File

@ -1,4 +1,4 @@
package net.knarcraft.blacksmith.command; package net.knarcraft.blacksmith.command.blacksmith;
import net.knarcraft.blacksmith.config.blacksmith.BlacksmithNPCSetting; import net.knarcraft.blacksmith.config.blacksmith.BlacksmithNPCSetting;
import net.knarcraft.blacksmith.util.TabCompleteValuesHelper; import net.knarcraft.blacksmith.util.TabCompleteValuesHelper;
@ -17,10 +17,9 @@ import java.util.List;
*/ */
public class BlackSmithEditTabCompleter implements TabCompleter { public class BlackSmithEditTabCompleter implements TabCompleter {
@Nullable
@Override @Override
public List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, public @Nullable List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command,
@NotNull String[] args) { @NotNull String label, @NotNull String[] args) {
if (!sender.hasPermission("blacksmith.edit")) { if (!sender.hasPermission("blacksmith.edit")) {
return new ArrayList<>(); return new ArrayList<>();
} }
@ -48,7 +47,7 @@ public class BlackSmithEditTabCompleter implements TabCompleter {
* @param commandValue <p>The command value used to filter tab-completions</p> * @param commandValue <p>The command value used to filter tab-completions</p>
* @return <p>Some valid options for the command's argument</p> * @return <p>Some valid options for the command's argument</p>
*/ */
private List<String> tabCompleteCommandValues(String commandName, String commandValue) { private @Nullable List<String> tabCompleteCommandValues(@NotNull String commandName, @NotNull String commandValue) {
for (BlacksmithNPCSetting blacksmithNpcSetting : BlacksmithNPCSetting.values()) { for (BlacksmithNPCSetting blacksmithNpcSetting : BlacksmithNPCSetting.values()) {
if (blacksmithNpcSetting.getCommandName().equalsIgnoreCase(commandName)) { if (blacksmithNpcSetting.getCommandName().equalsIgnoreCase(commandName)) {
return TabCompletionHelper.filterMatchingContains(TabCompleteValuesHelper.getTabCompletions( return TabCompletionHelper.filterMatchingContains(TabCompleteValuesHelper.getTabCompletions(

View File

@ -0,0 +1,17 @@
package net.knarcraft.blacksmith.command.scrapper;
import org.apache.commons.lang.NotImplementedException;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.jetbrains.annotations.NotNull;
public class ScrapperConfigCommand implements CommandExecutor {
@Override
public boolean onCommand(@NotNull CommandSender commandSender, @NotNull Command command, @NotNull String s,
@NotNull String[] strings) {
throw new NotImplementedException();
}
}

View File

@ -0,0 +1,20 @@
package net.knarcraft.blacksmith.command.scrapper;
import org.apache.commons.lang.NotImplementedException;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.command.TabCompleter;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
public class ScrapperConfigTabCompleter implements TabCompleter {
@Override
public @Nullable List<String> onTabComplete(@NotNull CommandSender commandSender, @NotNull Command command,
@NotNull String s, @NotNull String[] strings) {
throw new NotImplementedException();
}
}

View File

@ -0,0 +1,15 @@
package net.knarcraft.blacksmith.command.scrapper;
import org.apache.commons.lang.NotImplementedException;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.jetbrains.annotations.NotNull;
public class ScrapperEditCommand implements CommandExecutor {
@Override
public boolean onCommand(@NotNull CommandSender commandSender, @NotNull Command command, @NotNull String s,
@NotNull String[] strings) {
throw new NotImplementedException();
}
}

View File

@ -0,0 +1,18 @@
package net.knarcraft.blacksmith.command.scrapper;
import org.apache.commons.lang.NotImplementedException;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.command.TabCompleter;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
public class ScrapperEditTabCompleter implements TabCompleter {
@Override
public @Nullable List<String> onTabComplete(@NotNull CommandSender commandSender, @NotNull Command command,
@NotNull String s, @NotNull String[] strings) {
throw new NotImplementedException();
}
}

View File

@ -0,0 +1,45 @@
package net.knarcraft.blacksmith.config;
import org.jetbrains.annotations.NotNull;
/**
* An interface describing a global setting
*/
public interface GlobalSetting {
/**
* Gets the full config path for this setting
*
* @return <p>The full config path for this setting</p>
*/
@NotNull String getPath();
/**
* Gets the parent item of the defined path
*
* @return <p>The parent node</p>
*/
@NotNull String getParent();
/**
* Gets the value of this setting
*
* @return <p>The value of this setting</p>
*/
@NotNull Object getDefaultValue();
/**
* The name of the command used to change this setting
*
* @return <p>The name of this setting's command</p>
*/
@NotNull String getCommandName();
/**
* Gets the value type for this setting
*
* @return <p>The value type for this setting</p>
*/
@NotNull SettingValueType getValueType();
}

View File

@ -1,5 +1,7 @@
package net.knarcraft.blacksmith.config; package net.knarcraft.blacksmith.config;
import org.jetbrains.annotations.NotNull;
/** /**
* An interface describing an NPC setting * An interface describing an NPC setting
*/ */
@ -10,34 +12,34 @@ public interface NPCSetting {
* *
* @return <p>The full config path for this setting</p> * @return <p>The full config path for this setting</p>
*/ */
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>
*/ */
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>
*/ */
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>
*/ */
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>
*/ */
SettingValueType getValueType(); @NotNull SettingValueType getValueType();
} }

View File

@ -0,0 +1,40 @@
package net.knarcraft.blacksmith.config;
public interface TraitSettings {
/**
* Gets whether to disable the action cool-down
*
* @return <p>Whether to disable the action cool-down</p>
*/
boolean getDisableCoolDown();
/**
* Gets the message to display when a blacksmith or scrapper is still affected by a cool-down
*
* @return <p>The cool down unexpired message</p>
*/
String getCoolDownUnexpiredMessage();
/**
* Gets the message to display when the blacksmith is busy with another player
*
* @return <p>The busy with player message</p>
*/
String getBusyWithPlayerMessage();
/**
* Gets the message to display when the blacksmith is busy with reforging or salvaging an item
*
* @return <p>The busy working message</p>
*/
String getBusyWorkingMessage();
/**
* Gets the message to display when a blacksmith starts reforging or salvaging an item
*
* @return <p>The start working message</p>
*/
String getStartWorkingMessage();
}

View File

@ -2,6 +2,7 @@ package net.knarcraft.blacksmith.config.blacksmith;
import net.knarcraft.blacksmith.config.NPCSetting; import net.knarcraft.blacksmith.config.NPCSetting;
import net.knarcraft.blacksmith.config.SettingValueType; import net.knarcraft.blacksmith.config.SettingValueType;
import org.jetbrains.annotations.NotNull;
/** /**
* An enum representing all of Blacksmith's settings * An enum representing all of Blacksmith's settings
@ -162,7 +163,7 @@ public enum BlacksmithNPCSetting implements NPCSetting {
* @param commandName <p>The name of the command used to change this setting</p> * @param commandName <p>The name of the command used to change this setting</p>
*/ */
BlacksmithNPCSetting(String path, SettingValueType valueType, Object value, String commandName) { BlacksmithNPCSetting(String path, SettingValueType valueType, Object value, String commandName) {
this.path = "defaults." + path; this.path = "blacksmith.defaults." + path;
this.value = value; this.value = value;
this.valueType = valueType; this.valueType = valueType;
this.childPath = path; this.childPath = path;
@ -170,27 +171,27 @@ public enum BlacksmithNPCSetting implements NPCSetting {
} }
@Override @Override
public String getPath() { public @NotNull String getPath() {
return path; return path;
} }
@Override @Override
public String getChildPath() { public @NotNull String getChildPath() {
return childPath; return childPath;
} }
@Override @Override
public Object getDefaultValue() { public @NotNull Object getDefaultValue() {
return value; return value;
} }
@Override @Override
public String getCommandName() { public @NotNull String getCommandName() {
return commandName; return commandName;
} }
@Override @Override
public SettingValueType getValueType() { public @NotNull SettingValueType getValueType() {
return this.valueType; return this.valueType;
} }

View File

@ -4,6 +4,7 @@ import net.citizensnpcs.api.util.DataKey;
import net.knarcraft.blacksmith.BlacksmithPlugin; import net.knarcraft.blacksmith.BlacksmithPlugin;
import net.knarcraft.blacksmith.config.SettingValueType; import net.knarcraft.blacksmith.config.SettingValueType;
import net.knarcraft.blacksmith.config.SmithPreset; import net.knarcraft.blacksmith.config.SmithPreset;
import net.knarcraft.blacksmith.config.TraitSettings;
import net.knarcraft.blacksmith.util.ConfigHelper; import net.knarcraft.blacksmith.util.ConfigHelper;
import net.knarcraft.blacksmith.util.InputParsingHelper; import net.knarcraft.blacksmith.util.InputParsingHelper;
import net.knarcraft.blacksmith.util.ItemHelper; import net.knarcraft.blacksmith.util.ItemHelper;
@ -22,7 +23,7 @@ import java.util.logging.Level;
/** /**
* A class which keeps track of all Blacksmith settings/config values for one NPC * A class which keeps track of all Blacksmith settings/config values for one NPC
*/ */
public class BlacksmithNPCSettings { public class BlacksmithNPCSettings implements TraitSettings {
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<>();
@ -95,11 +96,7 @@ public class BlacksmithNPCSettings {
return currentValues.get(setting); return currentValues.get(setting);
} }
/** @Override
* Gets the message to display when the blacksmith is busy with another player
*
* @return <p>The busy with player message</p>
*/
public String getBusyWithPlayerMessage() { public String getBusyWithPlayerMessage() {
return asString(BlacksmithNPCSetting.BUSY_WITH_PLAYER_MESSAGE); return asString(BlacksmithNPCSetting.BUSY_WITH_PLAYER_MESSAGE);
} }
@ -109,7 +106,7 @@ public class BlacksmithNPCSettings {
* *
* @return <p>The busy reforging message</p> * @return <p>The busy reforging message</p>
*/ */
public String getBusyReforgingMessage() { public String getBusyWorkingMessage() {
return asString(BlacksmithNPCSetting.BUSY_WITH_REFORGE_MESSAGE); return asString(BlacksmithNPCSetting.BUSY_WITH_REFORGE_MESSAGE);
} }
@ -140,12 +137,8 @@ public class BlacksmithNPCSettings {
return asString(BlacksmithNPCSetting.NOT_DAMAGED_MESSAGE); return asString(BlacksmithNPCSetting.NOT_DAMAGED_MESSAGE);
} }
/** @Override
* Gets the message to display when a blacksmith starts reforging an item public String getStartWorkingMessage() {
*
* @return <p>The start reforge message</p>
*/
public String getStartReforgeMessage() {
return asString(BlacksmithNPCSetting.START_REFORGE_MESSAGE); return asString(BlacksmithNPCSetting.START_REFORGE_MESSAGE);
} }
@ -176,11 +169,7 @@ public class BlacksmithNPCSettings {
return asString(BlacksmithNPCSetting.INSUFFICIENT_FUNDS_MESSAGE); return asString(BlacksmithNPCSetting.INSUFFICIENT_FUNDS_MESSAGE);
} }
/** @Override
* Gets the message to display when a blacksmith is still affected by a cool-down
*
* @return <p>The cool down unexpired message</p>
*/
public String getCoolDownUnexpiredMessage() { public String getCoolDownUnexpiredMessage() {
return asString(BlacksmithNPCSetting.COOL_DOWN_UNEXPIRED_MESSAGE); return asString(BlacksmithNPCSetting.COOL_DOWN_UNEXPIRED_MESSAGE);
} }
@ -305,24 +294,11 @@ public class BlacksmithNPCSettings {
return asString(BlacksmithNPCSetting.BLACKSMITH_TITLE); return asString(BlacksmithNPCSetting.BLACKSMITH_TITLE);
} }
/** @Override
* Gets whether to disable the reforge-cool-down
*
* @return <p>Whether to disable the reforge-cool-down</p>
*/
public boolean getDisableCoolDown() { public boolean getDisableCoolDown() {
return asInt(BlacksmithNPCSetting.REFORGE_COOL_DOWN) <= 0; return asInt(BlacksmithNPCSetting.REFORGE_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(BlacksmithNPCSetting.MAX_REFORGE_DELAY) <= 0;
}
/** /**
* Gets whether this blacksmith is able to repair anvils * Gets whether this blacksmith is able to repair anvils
* *
@ -413,8 +389,10 @@ public class BlacksmithNPCSettings {
*/ */
private void updateEnchantmentBlocklist() { private void updateEnchantmentBlocklist() {
this.enchantmentBlocklist.clear(); this.enchantmentBlocklist.clear();
this.enchantmentBlocklist.addAll(getEnchantmentBlocklist(ConfigHelper.asStringList(getValue( List<String> enchantments = ConfigHelper.asStringList(getValue(BlacksmithNPCSetting.ENCHANTMENT_BLOCKLIST));
BlacksmithNPCSetting.ENCHANTMENT_BLOCKLIST)))); if (enchantments != null) {
this.enchantmentBlocklist.addAll(getEnchantmentBlocklist(enchantments));
}
} }
/** /**
@ -447,8 +425,10 @@ public class BlacksmithNPCSettings {
*/ */
private void updateReforgeAbleItems() { private void updateReforgeAbleItems() {
this.reforgeAbleItems.clear(); this.reforgeAbleItems.clear();
this.reforgeAbleItems.addAll(getReforgeAbleItems(ConfigHelper.asStringList(getValue( List<String> materialStrings = ConfigHelper.asStringList(getValue(BlacksmithNPCSetting.REFORGE_ABLE_ITEMS));
BlacksmithNPCSetting.REFORGE_ABLE_ITEMS)))); if (materialStrings != null) {
this.reforgeAbleItems.addAll(getReforgeAbleItems(materialStrings));
}
} }
/** /**

View File

@ -1,17 +1,22 @@
package net.knarcraft.blacksmith.config.blacksmith; package net.knarcraft.blacksmith.config.blacksmith;
import net.knarcraft.blacksmith.config.GlobalSetting;
import net.knarcraft.blacksmith.config.SettingValueType; import net.knarcraft.blacksmith.config.SettingValueType;
import org.jetbrains.annotations.NotNull;
import java.util.Arrays; import java.util.Arrays;
public enum GlobalBlacksmithSetting { /**
* Settings which are the same for every blacksmith
*/
public enum GlobalBlacksmithSetting implements GlobalSetting {
/** /**
* The base price for repairing, regardless of durability * The base price for repairing, regardless of durability
* *
* <p>This allows specifying a price for each item, by setting basePrice.item_name.</p> * <p>This allows specifying a price for each item, by setting basePrice.item_name.</p>
*/ */
BASE_PRICE("global.basePrice.default", SettingValueType.POSITIVE_DOUBLE, 10.0, "basePrice"), BASE_PRICE("basePrice.default", SettingValueType.POSITIVE_DOUBLE, 10.0, "basePrice"),
/** /**
* The base price for each durability point * The base price for each durability point
@ -20,7 +25,7 @@ public enum GlobalBlacksmithSetting {
* this is the cost each present durability point will add to the cost. This allows specifying a price per * this is the cost each present durability point will add to the cost. This allows specifying a price per
* durability point value for each item, by setting pricePerDurabilityPoint.item_name</p> * durability point value for each item, by setting pricePerDurabilityPoint.item_name</p>
*/ */
PRICE_PER_DURABILITY_POINT("global.pricePerDurabilityPoint.default", SettingValueType.POSITIVE_DOUBLE, PRICE_PER_DURABILITY_POINT("pricePerDurabilityPoint.default", SettingValueType.POSITIVE_DOUBLE,
0.005, "pricePerDurabilityPoint"), 0.005, "pricePerDurabilityPoint"),
/** /**
@ -28,29 +33,29 @@ public enum GlobalBlacksmithSetting {
* *
* <p>This can be specified for each possible enchantment by setting enchantment-cost.enchantment_name</p> * <p>This can be specified for each possible enchantment by setting enchantment-cost.enchantment_name</p>
*/ */
ENCHANTMENT_COST("global.enchantmentCost.default", SettingValueType.POSITIVE_DOUBLE, 5.0, ENCHANTMENT_COST("enchantmentCost.default", SettingValueType.POSITIVE_DOUBLE, 5.0,
"enchantmentCost"), "enchantmentCost"),
/** /**
* Whether the cost should increase for damage taken, as opposed to increase for durability present * Whether the cost should increase for damage taken, as opposed to increase for durability present
*/ */
NATURAL_COST("global.useNaturalCost", SettingValueType.BOOLEAN, true, "useNaturalCost"), NATURAL_COST("useNaturalCost", SettingValueType.BOOLEAN, true, "useNaturalCost"),
/** /**
* Whether to show exact time when displaying the wait time for a reforging or the cool-down * Whether to show exact time when displaying the wait time for a reforging or the cool-down
*/ */
SHOW_EXACT_TIME("global.showExactTime", SettingValueType.BOOLEAN, false, "showExactTime"), SHOW_EXACT_TIME("showExactTime", SettingValueType.BOOLEAN, false, "showExactTime"),
/** /**
* The cost for repairing a chipped anvil * The cost for repairing a chipped anvil
*/ */
ANVIL_CHIPPED_COST("global.chippedAnvilReforgingCost", SettingValueType.POSITIVE_DOUBLE, 10.0, ANVIL_CHIPPED_COST("chippedAnvilReforgingCost", SettingValueType.POSITIVE_DOUBLE, 10.0,
"chippedAnvilReforgingCost"), "chippedAnvilReforgingCost"),
/** /**
* The cost for repairing a damaged anvil * The cost for repairing a damaged anvil
*/ */
ANVIL_DAMAGED_COST("global.damagedAnvilReforgingCost", SettingValueType.POSITIVE_DOUBLE, 20.0, ANVIL_DAMAGED_COST("damagedAnvilReforgingCost", SettingValueType.POSITIVE_DOUBLE, 20.0,
"damagedAnvilReforgingCost"); "damagedAnvilReforgingCost");
private final String path; private final String path;
@ -68,7 +73,7 @@ public enum GlobalBlacksmithSetting {
* @param commandName <p>The name of the command used to change this setting</p> * @param commandName <p>The name of the command used to change this setting</p>
*/ */
GlobalBlacksmithSetting(String path, SettingValueType valueType, Object value, String commandName) { GlobalBlacksmithSetting(String path, SettingValueType valueType, Object value, String commandName) {
this.path = path; this.path = "blacksmith.global." + path;
this.value = value; this.value = value;
this.commandName = commandName; this.commandName = commandName;
this.valueType = valueType; this.valueType = valueType;
@ -76,48 +81,28 @@ public enum GlobalBlacksmithSetting {
this.parent = String.join(".", Arrays.copyOfRange(pathParts, 0, pathParts.length - 1)); this.parent = String.join(".", Arrays.copyOfRange(pathParts, 0, pathParts.length - 1));
} }
/** @Override
* Gets the full config path for this setting public @NotNull String getPath() {
*
* @return <p>The full config path for this setting</p>
*/
public String getPath() {
return path; return path;
} }
/** @Override
* Gets the parent item of the defined path public @NotNull String getParent() {
*
* @return <p>The parent node</p>
*/
public String getParent() {
return parent; return parent;
} }
/** @Override
* Gets the value of this setting public @NotNull Object getDefaultValue() {
*
* @return <p>The value of this setting</p>
*/
public Object getDefaultValue() {
return value; return value;
} }
/** @Override
* The name of the command used to change this setting public @NotNull String getCommandName() {
*
* @return <p>The name of this setting's command</p>
*/
public String getCommandName() {
return commandName; return commandName;
} }
/** @Override
* Gets the value type for this setting public @NotNull SettingValueType getValueType() {
*
* @return <p>The value type for this setting</p>
*/
public SettingValueType getValueType() {
return this.valueType; return this.valueType;
} }

View File

@ -498,8 +498,11 @@ public class GlobalBlacksmithSettings {
*/ */
private void loadReforgeAbleItems() { private void loadReforgeAbleItems() {
defaultReforgeAbleMaterials.clear(); defaultReforgeAbleMaterials.clear();
defaultReforgeAbleMaterials.addAll(BlacksmithNPCSettings.getReforgeAbleItems(ConfigHelper.asStringList( List<String> materialNames = ConfigHelper.asStringList(defaultNPCSettings.get(
defaultNPCSettings.get(BlacksmithNPCSetting.REFORGE_ABLE_ITEMS)))); BlacksmithNPCSetting.REFORGE_ABLE_ITEMS));
if (materialNames != null) {
defaultReforgeAbleMaterials.addAll(BlacksmithNPCSettings.getReforgeAbleItems(materialNames));
}
} }
/** /**
@ -507,8 +510,11 @@ public class GlobalBlacksmithSettings {
*/ */
private void loadEnchantmentBlocklist() { private void loadEnchantmentBlocklist() {
defaultEnchantmentBlocklist.clear(); defaultEnchantmentBlocklist.clear();
defaultEnchantmentBlocklist.addAll(BlacksmithNPCSettings.getEnchantmentBlocklist(ConfigHelper.asStringList( List<String> enchantmentNames = ConfigHelper.asStringList(defaultNPCSettings.get(
defaultNPCSettings.get(BlacksmithNPCSetting.ENCHANTMENT_BLOCKLIST)))); BlacksmithNPCSetting.ENCHANTMENT_BLOCKLIST));
if (enchantmentNames != null) {
defaultEnchantmentBlocklist.addAll(BlacksmithNPCSettings.getEnchantmentBlocklist(enchantmentNames));
}
} }
/** /**

View File

@ -0,0 +1,75 @@
package net.knarcraft.blacksmith.config.scrapper;
import net.knarcraft.blacksmith.config.GlobalSetting;
import net.knarcraft.blacksmith.config.SettingValueType;
import org.jetbrains.annotations.NotNull;
import java.util.Arrays;
/**
* Settings which are the same for every scrapper
*/
public enum GlobalScrapperSetting implements GlobalSetting {
/**
* Whether to display exact time in minutes and seconds when displaying a remaining cool-down
*/
SHOW_EXACT_TIME("scrapper.global.showExactTime", SettingValueType.BOOLEAN, "false",
"showExactTime"),
/**
* Whether to give experience back when salvaging an enchanted item
*/
GIVE_EXPERIENCE("scrapper.global.giveExperience", SettingValueType.BOOLEAN, "true",
"giveExperience"),
;
private final String path;
private final String parent;
private final String commandName;
private final Object value;
private final SettingValueType valueType;
/**
* Instantiates a new setting
*
* @param path <p>The full config path for this setting</p>
* @param valueType <p>The type of value used by this setting</p>
* @param value <p>The default value of this setting</p>
* @param commandName <p>The name of the command used to change this setting</p>
*/
GlobalScrapperSetting(String path, SettingValueType valueType, Object value, String commandName) {
this.path = path;
this.value = value;
this.commandName = commandName;
this.valueType = valueType;
String[] pathParts = path.split("\\.");
this.parent = String.join(".", Arrays.copyOfRange(pathParts, 0, pathParts.length - 1));
}
@Override
public @NotNull String getPath() {
return path;
}
@Override
public @NotNull String getParent() {
return parent;
}
@Override
public @NotNull Object getDefaultValue() {
return value;
}
@Override
public @NotNull String getCommandName() {
return commandName;
}
@Override
public @NotNull SettingValueType getValueType() {
return this.valueType;
}
}

View File

@ -0,0 +1,211 @@
package net.knarcraft.blacksmith.config.scrapper;
import net.citizensnpcs.api.util.DataKey;
import net.citizensnpcs.api.util.YamlStorage;
import net.knarcraft.blacksmith.BlacksmithPlugin;
import net.knarcraft.blacksmith.config.SettingValueType;
import net.knarcraft.blacksmith.util.ConfigHelper;
import java.io.File;
import java.util.HashMap;
import java.util.Map;
public class GlobalScrapperSettings {
private final Map<ScrapperNPCSetting, Object> defaultNPCSettings = new HashMap<>();
private final Map<GlobalScrapperSetting, Object> globalSettings = new HashMap<>();
private final YamlStorage defaultConfig;
/**
* Instantiates a new "Settings"
*
* @param plugin <p>A reference to the blacksmith plugin</p>
*/
public GlobalScrapperSettings(BlacksmithPlugin plugin) {
defaultConfig = new YamlStorage(new File(plugin.getDataFolder() + File.separator + "config.yml"),
"Scrapper Configuration\nWarning: The values under defaults are the values set for a " +
"scrapper upon creation. To change any values for existing NPCs, edit the citizens NPC file.");
}
/**
* Loads all configuration values from the config file
*/
public void load() {
//Load the config from disk
defaultConfig.load();
DataKey root = defaultConfig.getKey("");
//Just in case, clear existing values
defaultNPCSettings.clear();
globalSettings.clear();
//Load/Save NPC default settings
loadDefaultNPCSettings(root);
//Load/Save global settings
loadGlobalSettings(root);
//Save any modified values to disk
defaultConfig.save();
}
/**
* Changes the value of the given setting
*
* @param globalScrapperSetting <p>The global setting to change</p>
* @param newValue <p>The new value of the setting</p>
*/
public void changeValue(GlobalScrapperSetting globalScrapperSetting, Object newValue) {
globalSettings.put(globalScrapperSetting, newValue);
save();
}
/**
* Changes the value of the given setting
*
* @param scrapperNPCSetting <p>The default NPC setting to change</p>
* @param newValue <p>The new value for the setting</p>
*/
public void changeValue(ScrapperNPCSetting scrapperNPCSetting, Object newValue) {
if (scrapperNPCSetting.getValueType() == SettingValueType.STRING_LIST ||
scrapperNPCSetting.getValueType() == SettingValueType.REFORGE_ABLE_ITEMS) {
//Workaround to make sure it's treated as the correct type
defaultNPCSettings.put(scrapperNPCSetting, newValue == null ? null : ConfigHelper.asStringList(newValue));
} else {
defaultNPCSettings.put(scrapperNPCSetting, newValue);
}
save();
}
/**
* Gets the current raw value of the given global setting
*
* @param globalBlacksmithSetting <p>The setting to get</p>
* @return <p>The current raw setting value</p>
*/
public Object getRawValue(GlobalScrapperSetting globalBlacksmithSetting) {
return globalSettings.get(globalBlacksmithSetting);
}
/**
* Gets the current raw value of the given default NPC setting
*
* @param scrapperNPCSetting <p>The setting to get</p>
* @return <p>The current raw setting value</p>
*/
public Object getRawValue(ScrapperNPCSetting scrapperNPCSetting) {
return defaultNPCSettings.get(scrapperNPCSetting);
}
/**
* Gets the current value of the default NPC settings
*
* @return <p>The current value of the default NPC settings</p>
*/
public Map<ScrapperNPCSetting, Object> getDefaultNPCSettings() {
return new HashMap<>(this.defaultNPCSettings);
}
/**
* Gets whether to show exact time for reforging wait-time, and for wait-time between sessions
*
* @return <p>Whether to show exact time</p>
*/
public boolean getShowExactTime() {
return asBoolean(GlobalScrapperSetting.SHOW_EXACT_TIME);
}
/**
* Gets the given value as a boolean
*
* <p>This will throw an exception if used for a non-boolean value</p>
*
* @param setting <p>The setting to get the value of</p>
* @return <p>The value of the given setting as a boolean</p>
*/
public boolean asBoolean(GlobalScrapperSetting setting) {
return ConfigHelper.asBoolean(getValue(setting));
}
/**
* Gets the given value as a double
*
* <p>This will throw an exception if used for a non-double setting</p>
*
* @param setting <p>The setting to get the value of</p>
* @return <p>The value of the given setting as a double</p>
*/
public double asDouble(GlobalScrapperSetting setting) {
return ConfigHelper.asDouble(getValue(setting));
}
/**
* Gets the value of a setting, using the default if not set
*
* @param setting <p>The setting to get the value of</p>
* @return <p>The current value</p>
*/
private Object getValue(GlobalScrapperSetting setting) {
Object value = globalSettings.get(setting);
//If not set in config.yml, use the default value from the enum
if (value == null) {
value = setting.getDefaultValue();
}
return value;
}
/**
* Loads all global settings
*
* @param root <p>The root node of all global settings</p>
*/
private void loadGlobalSettings(DataKey root) {
for (GlobalScrapperSetting globalScrapperSetting : GlobalScrapperSetting.values()) {
if (!root.keyExists(globalScrapperSetting.getPath())) {
//If the setting does not exist in the config file, add it
root.setRaw(globalScrapperSetting.getPath(), globalScrapperSetting.getDefaultValue());
} else {
//Set the setting to the value found in the path
globalSettings.put(globalScrapperSetting, root.getRaw(globalScrapperSetting.getPath()));
}
}
}
/**
* Loads all default NPC settings
*
* @param root <p>The root node of all default NPC settings</p>
*/
private void loadDefaultNPCSettings(DataKey root) {
for (ScrapperNPCSetting setting : ScrapperNPCSetting.values()) {
if (!root.keyExists(setting.getPath())) {
//If the setting does not exist in the config file, add it
root.setRaw(setting.getPath(), setting.getDefaultValue());
} else {
//Set the setting to the value found in the path
defaultNPCSettings.put(setting, root.getRaw(setting.getPath()));
}
}
}
/**
* Saves all current settings to the config file
*/
private void save() {
DataKey root = defaultConfig.getKey("");
//Save all default NPC settings
for (ScrapperNPCSetting setting : ScrapperNPCSetting.values()) {
root.setRaw(setting.getPath(), defaultNPCSettings.get(setting));
}
//Save all normal global settings
for (GlobalScrapperSetting globalBlacksmithSetting : GlobalScrapperSetting.values()) {
root.setRaw(globalBlacksmithSetting.getPath(), globalSettings.get(globalBlacksmithSetting));
}
//Perform the actual save to disk
defaultConfig.save();
}
}

View File

@ -2,6 +2,7 @@ package net.knarcraft.blacksmith.config.scrapper;
import net.knarcraft.blacksmith.config.NPCSetting; import net.knarcraft.blacksmith.config.NPCSetting;
import net.knarcraft.blacksmith.config.SettingValueType; import net.knarcraft.blacksmith.config.SettingValueType;
import org.jetbrains.annotations.NotNull;
public enum ScrapperNPCSetting implements NPCSetting { public enum ScrapperNPCSetting implements NPCSetting {
@ -22,6 +23,21 @@ public enum ScrapperNPCSetting implements NPCSetting {
*/ */
SALVAGE_ABLE_ITEMS("salvageAbleItems", SettingValueType.REFORGE_ABLE_ITEMS, "", "salvageAbleItems"), SALVAGE_ABLE_ITEMS("salvageAbleItems", SettingValueType.REFORGE_ABLE_ITEMS, "", "salvageAbleItems"),
/**
* The maximum amount of seconds a player may need to wait for the reforging to finish
*/
MAX_SALVAGE_DELAY("delaysInSeconds.maximum", SettingValueType.POSITIVE_INTEGER, 30, "maxReforgeDelay"),
/**
* The minimum amount of seconds a player may need to wait for the reforging to finish
*/
MIN_SALVAGE_DELAY("delaysInSeconds.minimum", SettingValueType.POSITIVE_INTEGER, 5, "minReforgeDelay"),
/**
* The setting for number of seconds a player has to wait between each usage of the blacksmith
*/
SALVAGE_COOL_DOWN("delaysInSeconds.reforgeCoolDown", SettingValueType.POSITIVE_INTEGER, 60, "reforgeCoolDown"),
/*----------- /*-----------
| Messages | | Messages |
-----------*/ -----------*/
@ -31,6 +47,50 @@ public enum ScrapperNPCSetting implements NPCSetting {
*/ */
BUSY_WITH_PLAYER_MESSAGE("messages.busyPlayerMessage", SettingValueType.STRING, BUSY_WITH_PLAYER_MESSAGE("messages.busyPlayerMessage", SettingValueType.STRING,
"&cI'm busy at the moment. Come back later!", "busyPlayerMessage"), "&cI'm busy at the moment. Come back later!", "busyPlayerMessage"),
/**
* The message displayed when the scrapper is busy salvaging the player's item
*/
BUSY_WITH_SALVAGE_MESSAGE("messages.busySalvageMessage", SettingValueType.STRING,
"&cI'm working on it. Be patient! I'll finish {time}!", "busySalvageMessage"),
/**
* The message displayed if the player needs to wait for the cool-down to expire
*/
COOL_DOWN_UNEXPIRED_MESSAGE("messages.coolDownUnexpiredMessage", SettingValueType.STRING,
"&cYou've already had your chance! Give me a break! I'll be ready {time}!",
"coolDownUnexpiredMessage"),
/**
* The message displayed if presented with an item that cannot be salvaged by the NPC
*/
CANNOT_SALVAGE_MESSAGE("messages.cannotSalvageMessage", SettingValueType.STRING,
"&cI'm unable to salvage that item", "cannotSalvageMessage"),
/**
* The message displayed if salvaging an item would return in no items
*/
TOO_DAMAGED_FOR_SALVAGE_MESSAGE("messages.tooDamagedForSalvageMessage", SettingValueType.STRING,
"&cThat item is too damaged to be salvaged into anything useful",
"tooDamagedForSalvageMessage"),
/**
* The message displayed if a salvage is successful
*/
SUCCESS_SALVAGE_MESSAGE("messages.successSalvagedMessage", SettingValueType.STRING, "&cThere you go!",
"successSalvagedMessage"),
/**
* The message displayed if a player presents a different item after seeing the price to reforge an item
*/
ITEM_UNEXPECTEDLY_CHANGED_MESSAGE("messages.itemChangedMessage", SettingValueType.STRING,
"&cThat's not the item you wanted to reforge before!", "itemChangedMessage"),
/**
* The message displayed when the scrapper starts salvaging an item
*/
START_SALVAGE_MESSAGE("messages.startSalvageMessage", SettingValueType.STRING,
"&eOk, let's see what I can do...", "startSalvageMessage"),
; ;
private final String path; private final String path;
@ -48,7 +108,7 @@ public enum ScrapperNPCSetting implements NPCSetting {
* @param commandName <p>The name of the command used to change this setting</p> * @param commandName <p>The name of the command used to change this setting</p>
*/ */
ScrapperNPCSetting(String path, SettingValueType valueType, Object value, String commandName) { ScrapperNPCSetting(String path, SettingValueType valueType, Object value, String commandName) {
this.path = "defaults." + path; this.path = "scrapper.defaults." + path;
this.value = value; this.value = value;
this.valueType = valueType; this.valueType = valueType;
this.childPath = path; this.childPath = path;
@ -56,27 +116,27 @@ public enum ScrapperNPCSetting implements NPCSetting {
} }
@Override @Override
public String getPath() { public @NotNull String getPath() {
return path; return path;
} }
@Override @Override
public String getChildPath() { public @NotNull String getChildPath() {
return childPath; return childPath;
} }
@Override @Override
public Object getDefaultValue() { public @NotNull Object getDefaultValue() {
return value; return value;
} }
@Override @Override
public String getCommandName() { public @NotNull String getCommandName() {
return commandName; return commandName;
} }
@Override @Override
public SettingValueType getValueType() { public @NotNull SettingValueType getValueType() {
return this.valueType; return this.valueType;
} }

View File

@ -1,4 +1,239 @@
package net.knarcraft.blacksmith.config.scrapper; package net.knarcraft.blacksmith.config.scrapper;
public class ScrapperNPCSettings { import net.citizensnpcs.api.util.DataKey;
import net.knarcraft.blacksmith.config.SettingValueType;
import net.knarcraft.blacksmith.config.SmithPreset;
import net.knarcraft.blacksmith.config.TraitSettings;
import net.knarcraft.blacksmith.util.ConfigHelper;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class ScrapperNPCSettings implements TraitSettings {
private final Map<ScrapperNPCSetting, Object> currentValues = new HashMap<>();
private final GlobalScrapperSettings globalScrapperSettings;
/**
* Instantiates a new scrapper NPC settings object
*
* @param globalScrapperSettings <p>The global settings object to get default values from</p>
*/
public ScrapperNPCSettings(GlobalScrapperSettings globalScrapperSettings) {
this.globalScrapperSettings = globalScrapperSettings;
}
/**
* Loads variables from the given data key
*
* @param key <p>The data key to load variables from</p>
*/
public void loadVariables(DataKey key) {
for (ScrapperNPCSetting setting : ScrapperNPCSetting.values()) {
if (key.keyExists(setting.getChildPath())) {
currentValues.put(setting, key.getRaw(setting.getChildPath()));
}
}
}
/**
* Saves variables to the given data key
*
* @param key <p>The data key to save variables to</p>
*/
public void saveVariables(DataKey key) {
for (ScrapperNPCSetting setting : ScrapperNPCSetting.values()) {
key.setRaw(setting.getChildPath(), currentValues.get(setting));
}
}
/**
* Changes one setting to the given value
*
* @param setting <p>The setting to change</p>
* @param newValue <p>The new value of the setting</p>
*/
public void changeSetting(ScrapperNPCSetting setting, Object newValue) {
if (setting.getValueType() == SettingValueType.STRING_LIST ||
setting.getValueType() == SettingValueType.REFORGE_ABLE_ITEMS) {
//Workaround to make sure it's treated as the correct type
currentValues.put(setting, newValue == null ? null : ConfigHelper.asStringList(newValue));
} else {
currentValues.put(setting, newValue);
}
}
/**
* Gets the raw current value of a setting
*
* @param setting <p>The setting to get the value of</p>
* @return <p>The current value of the setting</p>
*/
public Object getRawValue(ScrapperNPCSetting setting) {
return currentValues.get(setting);
}
@Override
public String getBusyWithPlayerMessage() {
return asString(ScrapperNPCSetting.BUSY_WITH_PLAYER_MESSAGE);
}
@Override
public String getBusyWorkingMessage() {
return asString(ScrapperNPCSetting.BUSY_WITH_SALVAGE_MESSAGE);
}
@Override
public String getStartWorkingMessage() {
return asString(ScrapperNPCSetting.START_SALVAGE_MESSAGE);
}
/**
* Gets the message to display when a blacksmith has successfully repaired an item
*
* @return <p>The reforge success message</p>
*/
public String getSuccessMessage() {
return asString(ScrapperNPCSetting.SUCCESS_SALVAGE_MESSAGE);
}
@Override
public String getCoolDownUnexpiredMessage() {
return asString(ScrapperNPCSetting.COOL_DOWN_UNEXPIRED_MESSAGE);
}
/**
* The message displayed if a player presents a different item after seeing the price to salvage an item
*/
public String getItemChangedMessage() {
return asString(ScrapperNPCSetting.ITEM_UNEXPECTEDLY_CHANGED_MESSAGE);
}
/**
* Gets the minimum delay used to wait for a salvaging to finish.
*
* @return <p>The minimum salvage delay</p>
*/
public int getMinSalvageDelay() {
return asInt(ScrapperNPCSetting.MIN_SALVAGE_DELAY);
}
/**
* Gets the maximum delay used to wait for a salvaging to finish
*
* @return <p>The maximum salvage delay</p>
*/
public int getMaxSalvageDelay() {
return asInt(ScrapperNPCSetting.MAX_SALVAGE_DELAY);
}
/**
* Gets the cool-down between each salvaging
*
* @return <p>The salvage cool-down</p>
*/
public int getSalvageCoolDown() {
return asInt(ScrapperNPCSetting.SALVAGE_COOL_DOWN);
}
/**
* Gets whether an item should be dropped on the ground instead of being given to the player
*
* @return <p>Whether to drop reforged items on the ground</p>
*/
public boolean getDropItem() {
return asBoolean(ScrapperNPCSetting.DROP_ITEM);
}
@Override
public boolean getDisableCoolDown() {
return asInt(ScrapperNPCSetting.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(ScrapperNPCSetting.MAX_SALVAGE_DELAY) <= 0;
}
/**
* Gets the given value as an integer
*
* <p>This will throw an exception if used for a non-integer setting</p>
*
* @param setting <p>The setting to get the value of</p>
* @return <p>The value of the given setting as an integer</p>
*/
private int asInt(ScrapperNPCSetting setting) {
return ConfigHelper.asInt(getValue(setting));
}
/**
* Gets the string value of the given setting
*
* @param setting <p>The setting to get the value of</p>
* @return <p>The value of the given setting as a string</p>
*/
private String asString(ScrapperNPCSetting setting) {
return getValue(setting).toString();
}
/**
* Gets the boolean value of the given setting
*
* @param setting <p>The setting to get the value of</p>
* @return <p>The value of the given setting as a boolean</p>
*/
private boolean asBoolean(ScrapperNPCSetting setting) {
return ConfigHelper.asBoolean(getValue(setting));
}
/**
* Gets the value of a setting, using the default if not set
*
* @param setting <p>The setting to get the value of</p>
* @return <p>The current value</p>
*/
private Object getValue(ScrapperNPCSetting setting) {
Object value = currentValues.get(setting);
//If not set, use the default value from the config.yml file
if (value == null) {
Map<ScrapperNPCSetting, Object> defaultNPCSettings = globalScrapperSettings.getDefaultNPCSettings();
if (defaultNPCSettings.containsKey(setting)) {
value = defaultNPCSettings.get(setting);
}
}
//If not set in config.yml, use the default value from the enum
if (value == null) {
value = setting.getDefaultValue();
}
return value;
}
/**
* Replaces placeholders in the given reforge-able value
*
* @param stringList <p>The value specified by a user</p>
* @return <p>The value with placeholders replaced</p>
*/
private static List<String> replaceReforgeAblePresets(List<String> stringList) {
List<String> newStrings = new ArrayList<>();
for (String item : stringList) {
if (item == null) {
continue;
}
String replaced = SmithPreset.replacePreset(item);
if (!replaced.equals(item)) {
newStrings.addAll(List.of(replaced.split(",")));
} else {
newStrings.add(item);
}
}
return newStrings;
}
} }

View File

@ -1,11 +1,18 @@
package net.knarcraft.blacksmith.listener; package net.knarcraft.blacksmith.listener;
import net.citizensnpcs.api.event.NPCRightClickEvent;
import net.knarcraft.blacksmith.BlacksmithPlugin; import net.knarcraft.blacksmith.BlacksmithPlugin;
import net.knarcraft.blacksmith.formatting.BlacksmithTranslatableMessage; import net.knarcraft.blacksmith.formatting.BlacksmithTranslatableMessage;
import net.knarcraft.blacksmith.trait.BlacksmithTrait; import net.knarcraft.blacksmith.trait.BlacksmithTrait;
import net.knarcraft.blacksmith.trait.CustomTrait;
import net.knarcraft.blacksmith.trait.ScrapperTrait;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler; import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener; import org.bukkit.event.Listener;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.logging.Level;
/** /**
* A listener for detecting and handling a Blacksmith being right-clicked * A listener for detecting and handling a Blacksmith being right-clicked
@ -13,12 +20,26 @@ import org.bukkit.event.Listener;
public class NPCClickListener implements Listener { public class NPCClickListener implements Listener {
@EventHandler @EventHandler
public void onRightClick(net.citizensnpcs.api.event.NPCRightClickEvent event) { public void onRightClick(@NotNull NPCRightClickEvent event) {
//We only care about blacksmiths //We only care about blacksmiths
if (!event.getNPC().hasTrait(BlacksmithTrait.class)) { if (event.getNPC().hasTrait(BlacksmithTrait.class)) {
handleNPCClick(event, event.getNPC().getTraitNullable(BlacksmithTrait.class));
} else if (event.getNPC().hasTrait(ScrapperTrait.class)) {
handleNPCClick(event, event.getNPC().getTraitNullable(ScrapperTrait.class));
}
}
/**
* Handles a player clicking on a blacksmith or a scrapper NPC
*
* @param event <p>The NPC click event performed</p>
* @param customTrait <p>The NPC's custom trait</p>
*/
private void handleNPCClick(@NotNull NPCRightClickEvent event, @Nullable CustomTrait customTrait) {
if (customTrait == null) {
BlacksmithPlugin.getInstance().getLogger().log(Level.WARNING, "Could not get trait from NPC!");
return; return;
} }
BlacksmithTrait blacksmithTrait = event.getNPC().getTraitNullable(BlacksmithTrait.class);
//Perform any necessary pre-session work //Perform any necessary pre-session work
Player player = event.getClicker(); Player player = event.getClicker();
@ -30,16 +51,16 @@ public class NPCClickListener implements Listener {
return; return;
} }
if (!blacksmithTrait.prepareForSession(player)) { if (!customTrait.prepareForSession(player)) {
return; return;
} }
if (blacksmithTrait.hasSession()) { if (customTrait.hasSession()) {
//Continue the existing session //Continue the existing session
blacksmithTrait.continueSession(player); customTrait.continueSession(player);
} else { } else {
//Start a new session //Start a new session
blacksmithTrait.startSession(player); customTrait.startSession(player);
} }
} }

View File

@ -1,7 +1,9 @@
package net.knarcraft.blacksmith.listener; package net.knarcraft.blacksmith.listener;
import net.citizensnpcs.api.CitizensAPI; import net.citizensnpcs.api.CitizensAPI;
import net.citizensnpcs.api.npc.NPCRegistry;
import net.knarcraft.blacksmith.trait.BlacksmithTrait; import net.knarcraft.blacksmith.trait.BlacksmithTrait;
import net.knarcraft.blacksmith.trait.ScrapperTrait;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.enchantments.EnchantmentTarget; import org.bukkit.enchantments.EnchantmentTarget;
import org.bukkit.entity.Entity; import org.bukkit.entity.Entity;
@ -13,6 +15,8 @@ import org.bukkit.event.block.Action;
import org.bukkit.event.player.PlayerInteractEvent; import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import org.bukkit.util.Vector; import org.bukkit.util.Vector;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class PlayerListener implements Listener { public class PlayerListener implements Listener {
@ -22,19 +26,21 @@ public class PlayerListener implements Listener {
* @param event <p>The triggered event</p> * @param event <p>The triggered event</p>
*/ */
@EventHandler(priority = EventPriority.HIGHEST) @EventHandler(priority = EventPriority.HIGHEST)
public void onClick(PlayerInteractEvent event) { public void onClick(@NotNull PlayerInteractEvent event) {
if (event.getHand() == null || (event.getAction() != Action.RIGHT_CLICK_AIR && event.getAction() != if (event.getHand() == null || (event.getAction() != Action.RIGHT_CLICK_AIR && event.getAction() !=
Action.RIGHT_CLICK_BLOCK)) { Action.RIGHT_CLICK_BLOCK)) {
return; return;
} }
//If the player is not looking at a blacksmith, there is no need to do anything //If the player is not looking at a blacksmith or scrapper, there is no need to do anything
Entity target = getTarget(event.getPlayer(), event.getPlayer().getNearbyEntities(15, 10, 15)); Entity target = getTarget(event.getPlayer(), event.getPlayer().getNearbyEntities(15, 10, 15));
if (!CitizensAPI.getNPCRegistry().isNPC(target) || NPCRegistry registry = CitizensAPI.getNPCRegistry();
!CitizensAPI.getNPCRegistry().getNPC(target).hasTrait(BlacksmithTrait.class)) { if (!registry.isNPC(target) ||
(!registry.getNPC(target).hasTrait(BlacksmithTrait.class) &&
!registry.getNPC(target).hasTrait(ScrapperTrait.class))) {
return; return;
} }
//Block armor equip if interacting with a blacksmith //Block armor equip if interacting with a blacksmith or a scrapper
ItemStack usedItem = event.getPlayer().getInventory().getItem(event.getHand()); ItemStack usedItem = event.getPlayer().getInventory().getItem(event.getHand());
if (usedItem != null && isArmor(usedItem)) { if (usedItem != null && isArmor(usedItem)) {
event.setUseItemInHand(Event.Result.DENY); event.setUseItemInHand(Event.Result.DENY);
@ -47,7 +53,7 @@ public class PlayerListener implements Listener {
* @param item <p>The item to check if is armor or not</p> * @param item <p>The item to check if is armor or not</p>
* @return <p>True if the given item is a type of armor</p> * @return <p>True if the given item is a type of armor</p>
*/ */
public static boolean isArmor(ItemStack item) { public static boolean isArmor(@NotNull ItemStack item) {
return EnchantmentTarget.WEARABLE.includes(item) || item.getType() == Material.ELYTRA; return EnchantmentTarget.WEARABLE.includes(item) || item.getType() == Material.ELYTRA;
} }
@ -59,7 +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>
*/ */
private static <T extends Entity> T getTarget(final Entity entity, final 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;
} }
@ -67,8 +73,10 @@ public class PlayerListener implements Listener {
final double threshold = 1; final double threshold = 1;
for (final T other : entities) { for (final T other : entities) {
final Vector n = other.getLocation().toVector().subtract(entity.getLocation().toVector()); final Vector n = other.getLocation().toVector().subtract(entity.getLocation().toVector());
if (entity.getLocation().getDirection().normalize().crossProduct(n).lengthSquared() < threshold && if (entity.getLocation().getDirection().normalize().crossProduct(n).lengthSquared() < threshold &&
n.normalize().dot(entity.getLocation().getDirection().normalize()) >= 0) { n.normalize().dot(entity.getLocation().getDirection().normalize()) >= 0) {
// Replace if the other entity is nearer, or no target has been found
if (target == null || if (target == null ||
target.getLocation().distanceSquared(entity.getLocation()) > target.getLocation().distanceSquared(entity.getLocation()) >
other.getLocation().distanceSquared(entity.getLocation())) { other.getLocation().distanceSquared(entity.getLocation())) {

View File

@ -10,6 +10,7 @@ import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import org.bukkit.plugin.RegisteredServiceProvider; import org.bukkit.plugin.RegisteredServiceProvider;
import org.bukkit.plugin.ServicesManager; import org.bukkit.plugin.ServicesManager;
import org.jetbrains.annotations.NotNull;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
@ -32,7 +33,7 @@ public class EconomyManager {
* @param logger <p>The logger to use for logging</p> * @param logger <p>The logger to use for logging</p>
* @return <p>True if Vault was successfully set up</p> * @return <p>True if Vault was successfully set up</p>
*/ */
public static boolean setUp(ServicesManager servicesManager, Logger logger) { public static boolean setUp(@NotNull ServicesManager servicesManager, @NotNull Logger logger) {
//If already set up, there is nothing to do //If already set up, there is nothing to do
if (economy != null) { if (economy != null) {
return true; return true;
@ -41,13 +42,13 @@ public class EconomyManager {
} }
/** /**
* Gets whether the given player can pay for re-forging their held item * Gets whether the given player cannot pay for re-forging their held item
* *
* @param player <p>The player holding an item</p> * @param player <p>The player holding an item</p>
* @return <p>Whether the player can pay for the reforge</p> * @return <p>Whether the player cannot pay for the reforge</p>
*/ */
public static boolean canPay(Player player) { public static boolean cannotPayForHeldItemReforge(@NotNull Player player) {
return economy.getBalance(player) - getHeldItemCost(player) >= 0; return !(economy.getBalance(player) - getHeldItemCost(player) >= 0);
} }
/** /**
@ -56,7 +57,7 @@ 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(Player player) { public static String formatCost(@NotNull Player player) {
double cost = getHeldItemCost(player); double cost = getHeldItemCost(player);
return economy.format(cost); return economy.format(cost);
} }
@ -68,7 +69,7 @@ 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(Player player) { public static void withdraw(@NotNull Player player) {
economy.withdrawPlayer(player, getHeldItemCost(player)); economy.withdrawPlayer(player, getHeldItemCost(player));
} }
@ -78,7 +79,7 @@ public class EconomyManager {
* @param player <p>The player to calculate the cost for</p> * @param player <p>The player to calculate the cost for</p>
* @return <p>The calculated cost</p> * @return <p>The calculated cost</p>
*/ */
private static double getHeldItemCost(Player player) { private static double getHeldItemCost(@NotNull Player player) {
return getCost(player.getInventory().getItemInMainHand()); return getCost(player.getInventory().getItemInMainHand());
} }
@ -88,8 +89,8 @@ public class EconomyManager {
* @param item <p>The item to be repaired</p> * @param item <p>The item to be repaired</p>
* @return <p>The cost of the repair</p> * @return <p>The cost of the repair</p>
*/ */
private static double getCost(ItemStack item) { private static double getCost(@NotNull ItemStack item) {
GlobalBlacksmithSettings globalBlacksmithSettings = BlacksmithPlugin.getInstance().getSettings(); GlobalBlacksmithSettings globalBlacksmithSettings = BlacksmithPlugin.getInstance().getGlobalBlacksmithSettings();
Material material = item.getType(); Material material = item.getType();
//Calculate the base price //Calculate the base price
@ -121,8 +122,8 @@ public class EconomyManager {
* @param item <p>The item to calculate enchantment cost for</p> * @param item <p>The item to calculate enchantment cost for</p>
* @return <p>The resulting enchantment cost</p> * @return <p>The resulting enchantment cost</p>
*/ */
private static double getEnchantmentCost(ItemStack item) { private static double getEnchantmentCost(@NotNull ItemStack item) {
GlobalBlacksmithSettings settings = BlacksmithPlugin.getInstance().getSettings(); GlobalBlacksmithSettings settings = BlacksmithPlugin.getInstance().getGlobalBlacksmithSettings();
double price = 0; double price = 0;
for (Enchantment enchantment : item.getEnchantments().keySet()) { for (Enchantment enchantment : item.getEnchantments().keySet()) {
price += settings.getEnchantmentCost(enchantment) * item.getEnchantmentLevel(enchantment); price += settings.getEnchantmentCost(enchantment) * item.getEnchantmentLevel(enchantment);
@ -137,7 +138,7 @@ public class EconomyManager {
* @param logger <p>The logger to use for logging</p> * @param logger <p>The logger to use for logging</p>
* @return <p>True if Vault was successfully set up</p> * @return <p>True if Vault was successfully set up</p>
*/ */
private static boolean setupVault(ServicesManager servicesManager, Logger logger) { private static boolean setupVault(@NotNull ServicesManager servicesManager, @NotNull Logger logger) {
// Setup Vault // Setup Vault
RegisteredServiceProvider<Economy> economyProvider = servicesManager.getRegistration(Economy.class); RegisteredServiceProvider<Economy> economyProvider = servicesManager.getRegistration(Economy.class);
if (economyProvider != null) { if (economyProvider != null) {

View File

@ -1,38 +1,26 @@
package net.knarcraft.blacksmith.trait; package net.knarcraft.blacksmith.trait;
import net.citizensnpcs.api.npc.NPC;
import net.citizensnpcs.api.trait.Trait;
import net.citizensnpcs.api.util.DataKey; import net.citizensnpcs.api.util.DataKey;
import net.knarcraft.blacksmith.BlacksmithPlugin; import net.knarcraft.blacksmith.BlacksmithPlugin;
import net.knarcraft.blacksmith.config.blacksmith.BlacksmithNPCSettings; import net.knarcraft.blacksmith.config.blacksmith.BlacksmithNPCSettings;
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.blacksmith.util.ItemHelper;
import net.knarcraft.knarlib.formatting.StringFormatter; import net.knarcraft.knarlib.formatting.StringFormatter;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.Material; import org.bukkit.Material;
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.jetbrains.annotations.NotNull;
import java.util.Calendar;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.UUID;
import static net.knarcraft.blacksmith.formatting.BlacksmithStringFormatter.sendNPCMessage; import static net.knarcraft.blacksmith.formatting.BlacksmithStringFormatter.sendNPCMessage;
/** /**
* The class representing the Blacksmith NPC trait * The class representing the Blacksmith NPC trait
*/ */
public class BlacksmithTrait extends Trait { public class BlacksmithTrait extends CustomTrait {
private final Map<UUID, Calendar> coolDowns = new HashMap<>();
private ReforgeSession session;
private final BlacksmithNPCSettings config; private final BlacksmithNPCSettings config;
private long _sessionStart = System.currentTimeMillis();
/** /**
* Instantiates a new blacksmith trait * Instantiates a new blacksmith trait
@ -41,7 +29,8 @@ public class BlacksmithTrait extends Trait {
super("blacksmith"); super("blacksmith");
//This should crash if the blacksmith plugin hasn't been properly registered //This should crash if the blacksmith plugin hasn't been properly registered
Bukkit.getServer().getPluginManager().getPlugin("Blacksmith"); Bukkit.getServer().getPluginManager().getPlugin("Blacksmith");
this.config = new BlacksmithNPCSettings(BlacksmithPlugin.getInstance().getSettings()); this.config = new BlacksmithNPCSettings(BlacksmithPlugin.getInstance().getGlobalBlacksmithSettings());
super.setTraitSettings(this.config);
} }
/** /**
@ -49,43 +38,17 @@ public class BlacksmithTrait extends Trait {
* *
* @return <p>The current settings for this NPC</p> * @return <p>The current settings for this NPC</p>
*/ */
public BlacksmithNPCSettings getSettings() { public @NotNull BlacksmithNPCSettings getSettings() {
return config; return config;
} }
/**
* Gets whether this blacksmith is already in a reforging session
*
* @return <p>Whether already in a reforge session</p>
*/
public boolean hasSession() {
return this.session != null;
}
/**
* Adds a cool-down for the given player's next blacksmith reforge
*
* @param playerUUID <p>The ID of the player to add the cool-down for</p>
* @param waitUntil <p>The time when the player can interact again</p>
*/
public void addCoolDown(UUID playerUUID, Calendar waitUntil) {
coolDowns.put(playerUUID, waitUntil);
}
/**
* Unsets the session of this blacksmith, making it ready for another round
*/
public void unsetSession() {
this.session = null;
}
/** /**
* Loads all config values stored in citizens' config file for this NPC * Loads all config values stored in citizens' config file for this NPC
* *
* @param key <p>The data key used for the config root</p> * @param key <p>The data key used for the config root</p>
*/ */
@Override @Override
public void load(DataKey key) { public void load(@NotNull DataKey key) {
config.loadVariables(key); config.loadVariables(key);
} }
@ -95,85 +58,12 @@ public class BlacksmithTrait extends Trait {
* @param key <p>The data key used for the config root</p> * @param key <p>The data key used for the config root</p>
*/ */
@Override @Override
public void save(DataKey key) { public void save(@NotNull DataKey key) {
config.saveVariables(key); config.saveVariables(key);
} }
/** @Override
* Performs necessary work before the session is started or continued public void startSession(@NotNull Player player) {
*
* @param player <p>The player to prepare the session for</p>
* @return <p>True if preparations were successful. False if a session shouldn't be started</p>
*/
public boolean prepareForSession(Player player) {
UUID playerId = player.getUniqueId();
//If cool-down has been disabled after it was set for this player, remove the cool-down
if (config.getDisableCoolDown() && coolDowns.get(playerId) != null) {
coolDowns.remove(playerId);
}
//Deny if permission is missing
if (!player.hasPermission("blacksmith.use")) {
return false;
}
//Deny if on cool-down, or remove cool-down if expired
if (coolDowns.get(playerId) != null) {
Calendar calendar = Calendar.getInstance();
if (!calendar.after(coolDowns.get(playerId))) {
int secondDifference = (int) (coolDowns.get(playerId).getTimeInMillis() - calendar.getTimeInMillis()) / 1000;
boolean exactTime = BlacksmithPlugin.getInstance().getSettings().getShowExactTime();
sendNPCMessage(this.npc, player, StringFormatter.replacePlaceholder(config.getCoolDownUnexpiredMessage(),
"{time}", TimeFormatter.formatTime(exactTime, secondDifference)));
return false;
}
coolDowns.remove(playerId);
}
//If already in a session, but the player has failed to interact, and left the blacksmith, allow a new session
if (session != null) {
if (!session.isRunning() && (System.currentTimeMillis() > _sessionStart + 10 * 1000 ||
this.npc.getEntity().getLocation().distance(session.getPlayer().getLocation()) > 20)) {
session = null;
}
}
return true;
}
/**
* Tries to continue the session for the given player
*
* @param player <p>The player to continue the session for</p>
*/
public void continueSession(Player player) {
//Another player is using the blacksmith
if (!session.isInSession(player)) {
sendNPCMessage(this.npc, player, config.getBusyWithPlayerMessage());
return;
}
//The blacksmith is already reforging for the player
if (session.isRunning()) {
int timeRemaining = (int) ((session.getFinishTime() - System.currentTimeMillis()) / 1000);
boolean showExactTime = BlacksmithPlugin.getInstance().getSettings().getShowExactTime();
sendNPCMessage(this.npc, player, StringFormatter.replacePlaceholder(config.getBusyReforgingMessage(),
"{time}", TimeFormatter.formatTime(showExactTime, timeRemaining)));
return;
}
if (session.endSession()) {
//Quit if the player cannot afford, or has changed their item
session = null;
} else {
//Start reforging for the player
reforge(npc, player);
}
}
/**
* Starts a new session, and prepares to repair the player's item
*
* @param player <p>The player to start the session for</p>
*/
public void startSession(Player player) {
ItemStack hand = player.getInventory().getItemInMainHand(); ItemStack hand = player.getInventory().getItemInMainHand();
//Refuse if not repairable, or if reforge-able items is set, but doesn't include the held item //Refuse if not repairable, or if reforge-able items is set, but doesn't include the held item
List<Material> reforgeAbleItems = config.getReforgeAbleItems(); List<Material> reforgeAbleItems = config.getReforgeAbleItems();
@ -195,7 +85,7 @@ public class BlacksmithTrait extends Trait {
} }
//Start a new reforge session for the player //Start a new reforge session for the player
_sessionStart = System.currentTimeMillis(); currentSessionStartTime = System.currentTimeMillis();
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
@ -205,26 +95,9 @@ public class BlacksmithTrait extends Trait {
itemName)); itemName));
} }
/** @Override
* Starts reforging the player's item protected boolean showExactTime() {
* return BlacksmithPlugin.getInstance().getGlobalBlacksmithSettings().getShowExactTime();
* @param npc <p>The NPC performing the reforge</p>
* @param player <p>The player that initiated the reforge</p>
*/
private void reforge(NPC npc, Player player) {
sendNPCMessage(this.npc, player, config.getStartReforgeMessage());
EconomyManager.withdraw(player);
session.beginReforge();
ItemStack heldItem = player.getInventory().getItemInMainHand();
//Display the item in the NPC's hand
if (npc.getEntity() instanceof Player) {
((Player) npc.getEntity()).getInventory().setItemInMainHand(heldItem);
} else {
Objects.requireNonNull(((LivingEntity) npc.getEntity()).getEquipment()).setItemInMainHand(heldItem);
}
//Remove the item from the player's inventory
player.getInventory().setItemInMainHand(null);
} }
} }

View File

@ -0,0 +1,180 @@
package net.knarcraft.blacksmith.trait;
import net.citizensnpcs.api.npc.NPC;
import net.citizensnpcs.api.trait.Trait;
import net.knarcraft.blacksmith.config.TraitSettings;
import net.knarcraft.blacksmith.formatting.TimeFormatter;
import net.knarcraft.blacksmith.manager.EconomyManager;
import net.knarcraft.knarlib.formatting.StringFormatter;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import java.util.Calendar;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.UUID;
import static net.knarcraft.blacksmith.formatting.BlacksmithStringFormatter.sendNPCMessage;
/**
* A custom trait that utilizes sessions
*/
public abstract class CustomTrait extends Trait {
protected Session session;
protected TraitSettings config;
protected final Map<UUID, Calendar> coolDowns = new HashMap<>();
protected long currentSessionStartTime = System.currentTimeMillis();
/**
* Instantiates a new custom trait
*
* @param name <p>The name of the new trait</p>
*/
protected CustomTrait(String name) {
super(name);
}
/**
* Sets the trait settings object containing this trait's configuration
*
* @param config <p>The trait settings to use</p>
*/
protected void setTraitSettings(TraitSettings config) {
this.config = config;
}
/**
* Starts a new session, and prepares to repair the player's item
*
* @param player <p>The player to start the session for</p>
*/
public abstract void startSession(@NotNull Player player);
/**
* Tries to continue the session for the given player
*
* @param player <p>The player to continue the session for</p>
*/
public void continueSession(@NotNull Player player) {
//Another player is using the blacksmith
if (session.isNotInSession(player)) {
sendNPCMessage(this.npc, player, config.getBusyWithPlayerMessage());
return;
}
//The blacksmith is already reforging for the player
if (session.isRunning()) {
int timeRemaining = (int) ((session.getFinishTime() - System.currentTimeMillis()) / 1000);
boolean showExactTime = showExactTime();
sendNPCMessage(this.npc, player, StringFormatter.replacePlaceholder(config.getBusyWorkingMessage(),
"{time}", TimeFormatter.formatTime(showExactTime, timeRemaining)));
return;
}
if (session.isSessionInvalid()) {
//Quit if the player cannot afford, or has changed their item
session = null;
} else {
//Start reforging for the player
startMainAction(npc, player);
}
}
/**
* Gets whether this blacksmith is already in a reforging session
*
* @return <p>Whether already in a salvage session</p>
*/
public boolean hasSession() {
return this.session != null;
}
/**
* Adds a cool-down for the given player's next blacksmith reforge
*
* @param playerUUID <p>The ID of the player to add the cool-down for</p>
* @param waitUntil <p>The time when the player can interact again</p>
*/
public void addCoolDown(@NotNull UUID playerUUID, @NotNull Calendar waitUntil) {
coolDowns.put(playerUUID, waitUntil);
}
/**
* Unsets the session of this scrapper, making it ready for another round
*/
public void unsetSession() {
this.session = null;
}
/**
* Performs necessary work before the session is started or continued
*
* @param player <p>The player to prepare the session for</p>
* @return <p>True if preparations were successful. False if a session shouldn't be started</p>
*/
public boolean prepareForSession(@NotNull Player player) {
UUID playerId = player.getUniqueId();
//If cool-down has been disabled after it was set for this player, remove the cool-down
if (config.getDisableCoolDown() && coolDowns.get(playerId) != null) {
coolDowns.remove(playerId);
}
//Deny if permission is missing
if (!player.hasPermission("blacksmith.use")) {
return false;
}
//Deny if on cool-down, or remove cool-down if expired
if (coolDowns.get(playerId) != null) {
Calendar calendar = Calendar.getInstance();
if (!calendar.after(coolDowns.get(playerId))) {
int secondDifference = (int) (coolDowns.get(playerId).getTimeInMillis() - calendar.getTimeInMillis()) / 1000;
boolean exactTime = showExactTime();
sendNPCMessage(this.npc, player, StringFormatter.replacePlaceholder(config.getCoolDownUnexpiredMessage(),
"{time}", TimeFormatter.formatTime(exactTime, secondDifference)));
return false;
}
coolDowns.remove(playerId);
}
//If already in a session, but the player has failed to interact, and left the blacksmith, allow a new session
if (session != null && !session.isRunning() && (System.currentTimeMillis() > currentSessionStartTime + 10 * 1000 ||
this.npc.getEntity().getLocation().distance(session.getPlayer().getLocation()) > 20)) {
session = null;
}
return true;
}
/**
* Gets whether to show exact time when displaying the remaining time left
*
* @return <p>Whether to show exact time, or vague words</p>
*/
protected abstract boolean showExactTime();
/**
* Starts reforging the player's item
*
* @param npc <p>The NPC performing the reforge</p>
* @param player <p>The player that initiated the reforge</p>
*/
private void startMainAction(@NotNull NPC npc, @NotNull Player player) {
sendNPCMessage(this.npc, player, config.getStartWorkingMessage());
// TODO: Differentiate between blacksmiths and scrappers when withdrawing money
EconomyManager.withdraw(player);
session.scheduleAction();
ItemStack heldItem = player.getInventory().getItemInMainHand();
//Display the item in the NPC's hand
if (npc.getEntity() instanceof Player) {
((Player) npc.getEntity()).getInventory().setItemInMainHand(heldItem);
} else {
Objects.requireNonNull(((LivingEntity) npc.getEntity()).getEquipment()).setItemInMainHand(heldItem);
}
//Remove the item from the player's inventory
player.getInventory().setItemInMainHand(null);
}
}

View File

@ -11,7 +11,7 @@ import org.bukkit.enchantments.Enchantment;
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.scheduler.BukkitScheduler; import org.jetbrains.annotations.NotNull;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Calendar; import java.util.Calendar;
@ -25,14 +25,11 @@ import static net.knarcraft.blacksmith.formatting.BlacksmithStringFormatter.send
/** /**
* A representation of the session between a player and a blacksmith * A representation of the session between a player and a blacksmith
*/ */
public class ReforgeSession implements Runnable { public class ReforgeSession extends Session implements Runnable {
private final BlacksmithTrait blacksmithTrait; private final BlacksmithTrait blacksmithTrait;
private final Player player;
private final NPC npc; private final NPC npc;
private final ItemStack itemToReforge; private final ItemStack itemToReforge;
private int taskId;
private long finishTime = 0;
private final BlacksmithNPCSettings config; private final BlacksmithNPCSettings config;
private static final String[] enchantments = new String[Enchantment.values().length]; private static final String[] enchantments = new String[Enchantment.values().length];
private static final Random random = new Random(); private static final Random random = new Random();
@ -45,9 +42,10 @@ public class ReforgeSession implements Runnable {
* @param npc <p>The Blacksmith NPC involved in the session</p> * @param npc <p>The Blacksmith 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>
*/ */
ReforgeSession(BlacksmithTrait blacksmithTrait, Player player, NPC npc, BlacksmithNPCSettings config) { ReforgeSession(@NotNull BlacksmithTrait blacksmithTrait, @NotNull Player player, @NotNull NPC npc,
@NotNull BlacksmithNPCSettings config) {
super(player);
this.blacksmithTrait = blacksmithTrait; this.blacksmithTrait = blacksmithTrait;
this.player = player;
this.npc = npc; this.npc = npc;
this.itemToReforge = player.getInventory().getItemInMainHand(); this.itemToReforge = player.getInventory().getItemInMainHand();
this.config = config; this.config = config;
@ -61,13 +59,31 @@ public class ReforgeSession implements Runnable {
} }
} }
/** @Override
* Gets the time in milliseconds when this reforging session will finish public boolean isSessionInvalid() {
* // Prevent player from switching items during session
* @return <p>The time the reforging will finish</p> ItemStack itemInHand = player.getInventory().getItemInMainHand();
*/ if (!itemToReforge.equals(itemInHand)) {
public long getFinishTime() { sendNPCMessage(this.npc, player, config.getItemChangedMessage());
return this.finishTime; return true;
}
// The player is unable to pay
if (EconomyManager.cannotPayForHeldItemReforge(player)) {
sendNPCMessage(this.npc, player, config.getInsufficientFundsMessage());
return true;
}
return false;
}
@Override
protected int getActionDelay() {
if (config.getMaxReforgeDelay() > 0) {
//Finish the reforging after a random delay between the max and min
return new Random().nextInt(config.getMaxReforgeDelay()) + config.getMinReforgeDelay();
} else {
//Finish the salvaging as soon as possible
return 0;
}
} }
/** /**
@ -85,7 +101,22 @@ public class ReforgeSession implements Runnable {
} }
//Give the item back to the player //Give the item back to the player
if (!config.getDisableDelay()) { giveReforgedItem();
//Mark this blacksmith as available
blacksmithTrait.unsetSession();
// Start cool-down
Calendar wait = Calendar.getInstance();
wait.add(Calendar.SECOND, config.getReforgeCoolDown());
blacksmithTrait.addCoolDown(player.getUniqueId(), wait);
}
/**
* Gives the reforged item back to the player
*/
private void giveReforgedItem() {
if (config.getMaxReforgeDelay() > 0) {
//If the player isn't online, or the player cannot fit the item, drop the item to prevent it from disappearing //If the player isn't online, or the player cannot fit the item, drop the item to prevent it from disappearing
if (config.getDropItem() || !player.isOnline() || player.getInventory().firstEmpty() == -1) { if (config.getDropItem() || !player.isOnline() || player.getInventory().firstEmpty() == -1) {
player.getWorld().dropItemNaturally(npc.getEntity().getLocation(), itemToReforge); player.getWorld().dropItemNaturally(npc.getEntity().getLocation(), itemToReforge);
@ -96,14 +127,6 @@ public class ReforgeSession implements Runnable {
//It can be assumed as this happens instantly, that the player still has the item's previous slot selected //It can be assumed as this happens instantly, that the player still has the item's previous slot selected
player.getInventory().setItemInMainHand(itemToReforge); player.getInventory().setItemInMainHand(itemToReforge);
} }
//Mark this blacksmith as available
blacksmithTrait.unsetSession();
// Start cool-down
Calendar wait = Calendar.getInstance();
wait.add(Calendar.SECOND, config.getReforgeCoolDown());
blacksmithTrait.addCoolDown(player.getUniqueId(), wait);
} }
/** /**
@ -225,71 +248,4 @@ public class ReforgeSession implements Runnable {
} }
} }
/**
* Gets whether to end the current session
*
* <p>If the player has switched their item, or the player cannot pay, this returns true.</p>
*
* @return <p>True if the current session should end</p>
*/
public boolean endSession() {
// Prevent player from switching items during session
ItemStack itemInHand = player.getInventory().getItemInMainHand();
if (!itemToReforge.equals(itemInHand)) {
sendNPCMessage(this.npc, player, config.getItemChangedMessage());
return true;
}
// The player is unable to pay
if (!EconomyManager.canPay(player)) {
sendNPCMessage(this.npc, player, config.getInsufficientFundsMessage());
return true;
}
return false;
}
/**
* Gets whether the current session is still running
*
* @return <p>True if the current session is still running</p>
*/
public boolean isRunning() {
return BlacksmithPlugin.getInstance().getServer().getScheduler().isQueued(taskId);
}
/**
* Gets whether the given player is currently in a reforging session
*
* @param other <p>The player to check if is in session</p>
* @return <p>True if the given player is in a reforge session</p>
*/
public boolean isInSession(Player other) {
return player.getName().equals(other.getName());
}
/**
* Begins the actual item reforging
*/
public void beginReforge() {
BukkitScheduler scheduler = BlacksmithPlugin.getInstance().getServer().getScheduler();
int reforgeDelay;
if (!config.getDisableCoolDown()) {
//Finish the reforging after a random delay between the max and min
reforgeDelay = new Random().nextInt(config.getMaxReforgeDelay()) + config.getMinReforgeDelay();
} else {
//Finish the reforging as soon as possible
reforgeDelay = 0;
}
this.finishTime = System.currentTimeMillis() + (reforgeDelay * 1000L);
taskId = scheduler.scheduleSyncDelayedTask(BlacksmithPlugin.getInstance(), this, reforgeDelay * 20L);
}
/**
* Gets the player currently in this reforge session
*
* @return <p>The player currently in this reforge session</p>
*/
public Player getPlayer() {
return player;
}
} }

View File

@ -0,0 +1,128 @@
package net.knarcraft.blacksmith.trait;
import net.citizensnpcs.api.npc.NPC;
import net.knarcraft.blacksmith.BlacksmithPlugin;
import net.knarcraft.blacksmith.config.scrapper.ScrapperNPCSettings;
import net.knarcraft.blacksmith.util.ItemHelper;
import net.knarcraft.blacksmith.util.SalvageHelper;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import java.util.Objects;
import java.util.Random;
import static net.knarcraft.blacksmith.formatting.BlacksmithStringFormatter.sendNPCMessage;
/**
* A representation of the session between a player and a blacksmith
*/
public class SalvageSession extends Session implements Runnable {
private final ScrapperTrait scrapperTrait;
private final NPC npc;
private final ItemStack itemToSalvage;
private final ScrapperNPCSettings config;
private final List<ItemStack> salvage;
private final int enchantmentLevels;
/**
* Instantiates a new session
*
* @param scrapperTrait <p>A reference to the blacksmith trait</p>
* @param player <p>The player initiating the session</p>
* @param npc <p>The Blacksmith NPC involved in the session</p>
* @param config <p>The config to use for the session</p>
*/
SalvageSession(@NotNull ScrapperTrait scrapperTrait, @NotNull Player player, @NotNull NPC npc,
@NotNull ScrapperNPCSettings config) {
super(player);
this.scrapperTrait = scrapperTrait;
this.npc = npc;
this.itemToSalvage = player.getInventory().getItemInMainHand();
this.config = config;
// TODO: Implement the list of items to ignore when calculating salvage
this.salvage = SalvageHelper.getSalvage(BlacksmithPlugin.getInstance().getServer(), this.itemToSalvage,
new ArrayList<>());
this.enchantmentLevels = SalvageHelper.getTotalEnchantmentLevels(this.itemToSalvage);
}
@Override
public boolean isSessionInvalid() {
// Prevent player from switching items during session
ItemStack itemInHand = player.getInventory().getItemInMainHand();
if (!itemToSalvage.equals(itemInHand)) {
sendNPCMessage(this.npc, player, config.getItemChangedMessage());
return true;
}
// TODO: Add economy check
return false;
}
@Override
protected int getActionDelay() {
if (config.getMaxSalvageDelay() > 0) {
//Finish the salvaging after a random delay between the max and min
return new Random().nextInt(config.getMaxSalvageDelay()) + config.getMinSalvageDelay();
} else {
//Finish the salvaging as soon as possible
return 0;
}
}
/**
* Runs the actual salvage which fixes the item and gives it back to the player
*/
@Override
public void run() {
// TODO: Tell the player that the salvaging was successful, or cancel giveSalvage + give the original item back?
// Give the player the result of the salvage
giveSalvage();
//Stop the reforged item from displaying in the blacksmith's hand
if (npc.getEntity() instanceof Player) {
((Player) npc.getEntity()).getInventory().setItemInMainHand(null);
} else {
Objects.requireNonNull(((LivingEntity) npc.getEntity()).getEquipment()).setItemInMainHand(null);
}
//Mark this scrapper as available
scrapperTrait.unsetSession();
// Start cool-down
Calendar wait = Calendar.getInstance();
wait.add(Calendar.SECOND, config.getSalvageCoolDown());
scrapperTrait.addCoolDown(player.getUniqueId(), wait);
}
/**
* Gives the player the calculated salvage
*/
private void giveSalvage() {
// TODO: Find a better calculation than 1 enchantment level = 1 exp level
// Gives the player back some of the XP used on an item
player.giveExpLevels(enchantmentLevels);
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
// disappearing, even if drop item is disabled.
for (ItemStack item : salvage) {
player.getWorld().dropItemNaturally(npc.getEntity().getLocation(), item);
}
} else {
for (ItemStack item : salvage) {
if (ItemHelper.canFitItem(player.getInventory(), item)) {
player.getInventory().addItem(item);
} else {
// If the player cannot fit all the salvage, drop it on the ground
player.getWorld().dropItemNaturally(player.getLocation(), item);
}
}
}
}
}

View File

@ -1,17 +1,80 @@
package net.knarcraft.blacksmith.trait; package net.knarcraft.blacksmith.trait;
import net.citizensnpcs.api.trait.Trait; import net.citizensnpcs.api.util.DataKey;
import net.knarcraft.blacksmith.BlacksmithPlugin;
import net.knarcraft.blacksmith.config.scrapper.ScrapperNPCSettings;
import org.apache.commons.lang.NotImplementedException;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
/** /**
* The class representing a scrapper NPC trait * The class representing a scrapper NPC trait
*/ */
public class ScrapperTrait extends Trait { public class ScrapperTrait extends CustomTrait {
protected ScrapperTrait(String name) {
super(name);
}
//TODO: A scrapper will take items and turn them into the base ingredients //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 //TODO: If an item is enchanted, give an appropriate amount of exp
private final ScrapperNPCSettings config;
/**
* Instantiates a new blacksmith trait
*/
public ScrapperTrait() {
super("scrapper");
//This should crash if the blacksmith plugin hasn't been properly registered
Bukkit.getServer().getPluginManager().getPlugin("Blacksmith");
this.config = new ScrapperNPCSettings(BlacksmithPlugin.getInstance().getGlobalScrapperSettings());
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
*
* @param key <p>The data key used for the config root</p>
*/
@Override
public void load(@NotNull DataKey key) {
config.loadVariables(key);
}
/**
* Saves all config values for this NPC
*
* @param key <p>The data key used for the config root</p>
*/
@Override
public void save(@NotNull DataKey key) {
config.saveVariables(key);
}
/**
* Starts a new session, and prepares to repair the player's item
*
* @param player <p>The player to start the session for</p>
*/
public void startSession(@NotNull Player player) {
// TODO: Need some method to check which items are salvageable by the specific NPC. It should be similar to
// reforge-able items. Optionally, extended mode can be enabled, which supports any recipe?
// TODO: Check if the held item is salvageable, and give appropriate messages
// TODO: Mark the session start
// TODO: Initialize a new session
// TODO: Tell player about the required cost
throw new NotImplementedException();
}
@Override
protected boolean showExactTime() {
return BlacksmithPlugin.getInstance().getGlobalScrapperSettings().getShowExactTime();
}
} }

View File

@ -0,0 +1,95 @@
package net.knarcraft.blacksmith.trait;
import net.knarcraft.blacksmith.BlacksmithPlugin;
import org.bukkit.entity.Player;
import org.bukkit.scheduler.BukkitScheduler;
import org.jetbrains.annotations.NotNull;
/**
* A runnable session for performing a reforging/salvage task
*/
public abstract class Session implements Runnable {
protected final Player player;
protected long finishTime;
protected int taskId;
/**
* Instantiates a new session
*
* @param player <p>The player the session belongs to</p>
*/
public Session(@NotNull Player player) {
this.player = player;
}
/**
* Gets whether the given player is currently in a reforging session
*
* @param other <p>The player to check if is in session</p>
* @return <p>False if the given player is in a reforge session</p>
*/
public boolean isNotInSession(@NotNull Player other) {
return !player.getUniqueId().equals(other.getUniqueId());
}
/**
* Gets the player currently in this reforge session
*
* @return <p>The player currently in this reforge session</p>
*/
public @NotNull Player getPlayer() {
return player;
}
/**
* Gets whether the current session is invalid, and should be ended
*
* <p>If the player has switched their item, the player cannot pay, or some other condition fails,
* this returns true.</p>
*
* @return <p>True if the current session should end</p>
*/
public abstract boolean isSessionInvalid();
/**
* Gets whether the current session is still running
*
* @return <p>True if the current session is still running</p>
*/
public boolean isRunning() {
return BlacksmithPlugin.getInstance().getServer().getScheduler().isQueued(taskId);
}
/**
* Gets the time in milliseconds when this session's action will finish
*
* <p>This returns 0 if the action hasn't been run yet.</p>
*
* @return <p>The timestamp for when the action will finish</p>
*/
public long getFinishTime() {
return this.finishTime;
}
/**
* Schedules this session's main task for after the action delay has passed
*/
public void scheduleAction() {
if (isRunning()) {
throw new IllegalStateException("Session action tried to run twice!");
}
BukkitScheduler scheduler = BlacksmithPlugin.getInstance().getServer().getScheduler();
int actionDelay = getActionDelay();
this.finishTime = System.currentTimeMillis() + (actionDelay * 1000L);
taskId = scheduler.scheduleSyncDelayedTask(BlacksmithPlugin.getInstance(), this, actionDelay * 20L);
}
/**
* Gets the delay for this session's action to finish
*
* @return <p>The delay to wait for this session's action to finish</p>
*/
protected abstract int getActionDelay();
}

View File

@ -1,5 +1,8 @@
package net.knarcraft.blacksmith.util; package net.knarcraft.blacksmith.util;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@ -18,7 +21,7 @@ public final class ConfigHelper {
* @param value <p>The raw string list value</p> * @param value <p>The raw string list value</p>
* @return <p>The value as a string list, or null if not compatible</p> * @return <p>The value as a string list, or null if not compatible</p>
*/ */
public static List<String> asStringList(Object value) { public static @Nullable List<String> asStringList(@Nullable Object value) {
if (value == null) { if (value == null) {
return new ArrayList<>(); return new ArrayList<>();
} }
@ -42,8 +45,10 @@ public final class ConfigHelper {
* *
* @param value <p>The object value to get</p> * @param value <p>The object value to get</p>
* @return <p>The value of the given object as a double</p> * @return <p>The value of the given object as a double</p>
* @throws ClassCastException <p>If a non-double is given as input</p>
* @throws NumberFormatException <p>If a non-double is given as input</p>
*/ */
public static double asDouble(Object value) { public static double asDouble(@NotNull Object value) throws ClassCastException, NumberFormatException {
if (value instanceof String) { if (value instanceof String) {
return Double.parseDouble((String) value); return Double.parseDouble((String) value);
} else if (value instanceof Integer) { } else if (value instanceof Integer) {
@ -60,12 +65,15 @@ public final class ConfigHelper {
* *
* @param value <p>The object value to get</p> * @param value <p>The object value to get</p>
* @return <p>The value of the given object as a boolean</p> * @return <p>The value of the given object as a boolean</p>
* @throws ClassCastException <p>If the given value is not a boolean</p>
*/ */
public static boolean asBoolean(Object value) { public static boolean asBoolean(@NotNull Object value) throws ClassCastException {
if (value instanceof String) { if (value instanceof Boolean booleanValue) {
return booleanValue;
} else if (value instanceof String) {
return Boolean.parseBoolean((String) value); return Boolean.parseBoolean((String) value);
} else { } else {
return (Boolean) value; throw new ClassCastException();
} }
} }
@ -76,8 +84,9 @@ public final class ConfigHelper {
* *
* @param value <p>The object value to get</p> * @param value <p>The object value to get</p>
* @return <p>The value of the given object as an integer</p> * @return <p>The value of the given object as an integer</p>
* @throws ClassCastException <p>If the given value is not an integer</p>
*/ */
public static int asInt(Object value) { public static int asInt(@NotNull Object value) throws ClassCastException {
if (value instanceof String) { if (value instanceof String) {
return Integer.parseInt((String) value); return Integer.parseInt((String) value);
} else { } else {

View File

@ -3,6 +3,8 @@ package net.knarcraft.blacksmith.util;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.NamespacedKey; import org.bukkit.NamespacedKey;
import org.bukkit.enchantments.Enchantment; import org.bukkit.enchantments.Enchantment;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/** /**
* A helper class for parsing input into proper object types * A helper class for parsing input into proper object types
@ -19,7 +21,7 @@ public final class InputParsingHelper {
* @param input <p>The input to check</p> * @param input <p>The input to check</p>
* @return <p>True if the value is empty</p> * @return <p>True if the value is empty</p>
*/ */
public static boolean isEmpty(String input) { public static boolean isEmpty(@Nullable String input) {
return input == null || input.equalsIgnoreCase("null") || input.equals("\"\"") || return input == null || input.equalsIgnoreCase("null") || input.equals("\"\"") ||
input.isBlank() || input.equals("-1"); input.isBlank() || input.equals("-1");
} }
@ -30,7 +32,7 @@ public final class InputParsingHelper {
* @param input <p>The string to match to a material</p> * @param input <p>The string to match to a material</p>
* @return <p>The material matching the string, or null if not found</p> * @return <p>The material matching the string, or null if not found</p>
*/ */
public static Material matchMaterial(String input) { public static @Nullable Material matchMaterial(@NotNull String input) {
return Material.matchMaterial(input.replace("-", "_")); return Material.matchMaterial(input.replace("-", "_"));
} }
@ -40,7 +42,7 @@ public final class InputParsingHelper {
* @param input <p>The string to match to an enchantment</p> * @param input <p>The string to match to an enchantment</p>
* @return <p>The enchantment matching the string, or null if not found</p> * @return <p>The enchantment matching the string, or null if not found</p>
*/ */
public static Enchantment matchEnchantment(String input) { public static @Nullable Enchantment matchEnchantment(@NotNull String input) {
try { try {
return Enchantment.getByKey(NamespacedKey.minecraft( return Enchantment.getByKey(NamespacedKey.minecraft(
input.replace("-", "_").replace(" ", "_").toLowerCase())); input.replace("-", "_").replace(" ", "_").toLowerCase()));
@ -56,7 +58,7 @@ public final class InputParsingHelper {
* @param input <p>The input to RegExIfy</p> * @param input <p>The input to RegExIfy</p>
* @return <p>The converted input</p> * @return <p>The converted input</p>
*/ */
public static String regExIfy(String input) { public static @NotNull String regExIfy(@NotNull String input) {
return input.replace("*", ".*").toUpperCase().replace("-", "_"); return input.replace("*", ".*").toUpperCase().replace("-", "_");
} }

View File

@ -1,9 +1,11 @@
package net.knarcraft.blacksmith.util; package net.knarcraft.blacksmith.util;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
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 java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@ -23,7 +25,7 @@ public final class ItemHelper {
* @param item <p>The item to check</p> * @param item <p>The item to check</p>
* @return <p>True if the item is repairable</p> * @return <p>True if the item is repairable</p>
*/ */
public static boolean isRepairable(ItemStack item) { public static boolean isRepairable(@NotNull ItemStack item) {
return item.getItemMeta() instanceof Damageable && getMaxDurability(item) > 0; return item.getItemMeta() instanceof Damageable && getMaxDurability(item) > 0;
} }
@ -33,7 +35,7 @@ public final class ItemHelper {
* @param itemStack <p>The item to get the durability of</p> * @param itemStack <p>The item to get the durability of</p>
* @return <p>The max durability of the item</p> * @return <p>The max durability of the item</p>
*/ */
public static short getMaxDurability(ItemStack itemStack) { public static short getMaxDurability(@NotNull ItemStack itemStack) {
return itemStack.getType().getMaxDurability(); return itemStack.getType().getMaxDurability();
} }
@ -43,7 +45,7 @@ public final class ItemHelper {
* @param itemStack <p>The item to get the durability of</p> * @param itemStack <p>The item to get the durability of</p>
* @return <p>The durability of the item</p> * @return <p>The durability of the item</p>
*/ */
public static short getDurability(ItemStack itemStack) { public static short getDurability(@NotNull ItemStack itemStack) {
Damageable damageable = (Damageable) itemStack.getItemMeta(); Damageable damageable = (Damageable) itemStack.getItemMeta();
int maxDurability = getMaxDurability(itemStack); int maxDurability = getMaxDurability(itemStack);
if (damageable != null) { if (damageable != null) {
@ -59,7 +61,7 @@ public final class ItemHelper {
* @param itemStack <p>The damage done to the item</p> * @param itemStack <p>The damage done to the item</p>
* @return <p>The damage done to the item</p> * @return <p>The damage done to the item</p>
*/ */
public static short getDamage(ItemStack itemStack) { public static short getDamage(@NotNull ItemStack itemStack) {
Damageable damageable = (Damageable) itemStack.getItemMeta(); Damageable damageable = (Damageable) itemStack.getItemMeta();
if (damageable != null) { if (damageable != null) {
return (short) damageable.getDamage(); return (short) damageable.getDamage();
@ -75,7 +77,7 @@ public final class ItemHelper {
* @param newDamage <p>The new damage done</p> * @param newDamage <p>The new damage done</p>
* @return <p>True if the damage was updated. False if not damageable.</p> * @return <p>True if the damage was updated. False if not damageable.</p>
*/ */
public static boolean updateDamage(ItemStack item, int newDamage) { public static boolean updateDamage(@NotNull ItemStack item, int newDamage) {
ItemMeta meta = item.getItemMeta(); ItemMeta meta = item.getItemMeta();
if (!(meta instanceof Damageable damageable)) { if (!(meta instanceof Damageable damageable)) {
return false; return false;
@ -90,7 +92,7 @@ public final class ItemHelper {
* *
* @return <p>A complete list of reforge-able materials</p> * @return <p>A complete list of reforge-able materials</p>
*/ */
public static List<Material> getAllReforgeAbleMaterials() { public static @NotNull List<Material> getAllReforgeAbleMaterials() {
List<Material> reforgeAbleMaterials = new ArrayList<>(); List<Material> reforgeAbleMaterials = new ArrayList<>();
for (Material material : Material.values()) { for (Material material : Material.values()) {
ItemStack item = new ItemStack(material); ItemStack item = new ItemStack(material);
@ -108,10 +110,49 @@ public final class ItemHelper {
* @param requireDamaged <p>Whether only a damaged anvil should count</p> * @param requireDamaged <p>Whether only a damaged anvil should count</p>
* @return <p>True if the given material is an anvil</p> * @return <p>True if the given material is an anvil</p>
*/ */
public static boolean isAnvil(Material material, boolean requireDamaged) { public static boolean isAnvil(@NotNull Material material, boolean requireDamaged) {
boolean isDamagedAnvil = material == Material.CHIPPED_ANVIL || material == Material.DAMAGED_ANVIL; boolean isDamagedAnvil = material == Material.CHIPPED_ANVIL || material == Material.DAMAGED_ANVIL;
boolean isAnvil = isDamagedAnvil || material == Material.ANVIL; boolean isAnvil = isDamagedAnvil || material == Material.ANVIL;
return (requireDamaged && isDamagedAnvil) || (!requireDamaged && isAnvil); return (requireDamaged && isDamagedAnvil) || (!requireDamaged && isAnvil);
} }
/**
* Checks whether the given inventory is able to fit the given item
*
* @param inventory <p>The inventory to check</p>
* @param item <p>The item to check</p>
* @return <p>True if the inventory can fit the item</p>
*/
public static boolean canFitItem(@NotNull Inventory inventory, @NotNull ItemStack item) {
// If a slot is available, there is no problem
if (inventory.firstEmpty() != -1) {
return true;
}
// If the inventory doesn't contain the correct type of item, stacking is impossible
if (!inventory.contains(item.getType())) {
return false;
}
// Check if the item stack can fit in the inventory if stacked with existing items
int availableSlots = 0;
for (ItemStack itemStack : inventory.getStorageContents()) {
ItemMeta itemMeta = itemStack.getItemMeta();
ItemMeta targetMeta = item.getItemMeta();
// Skip items of a different type, or with metadata that would prevent stacking
if (itemStack.getType() != item.getType() ||
(itemMeta != null && targetMeta != null && !itemMeta.equals(targetMeta))) {
continue;
}
availableSlots += itemStack.getMaxStackSize() - itemStack.getAmount();
if (availableSlots < item.getAmount()) {
return true;
}
}
return false;
}
} }

View File

@ -2,10 +2,13 @@ package net.knarcraft.blacksmith.util;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.Server; import org.bukkit.Server;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.Recipe; import org.bukkit.inventory.Recipe;
import org.bukkit.inventory.ShapedRecipe; import org.bukkit.inventory.ShapedRecipe;
import org.bukkit.inventory.ShapelessRecipe; import org.bukkit.inventory.ShapelessRecipe;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
@ -18,6 +21,20 @@ import java.util.Random;
*/ */
public final class SalvageHelper { public final class SalvageHelper {
/**
* Gets the sum of all enchantment levels for the given item
*
* @param item <p>The item to check</p>
* @return <p>The total amount of enchantment levels on the item</p>
*/
public static int getTotalEnchantmentLevels(@NotNull ItemStack item) {
int expLevels = 0;
for (Enchantment enchantment : item.getEnchantments().keySet()) {
expLevels += item.getEnchantmentLevel(enchantment);
}
return expLevels;
}
/** /**
* Gets the items to return if salvaging the given item stack * Gets the items to return if salvaging the given item stack
* *
@ -28,7 +45,8 @@ public final class SalvageHelper {
* @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>
* @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 List<ItemStack> getSalvage(Server server, ItemStack salvagedItem, List<Material> ignoredSalvage) { public static @Nullable List<ItemStack> getSalvage(@NotNull Server server, @Nullable ItemStack salvagedItem,
@NotNull List<Material> ignoredSalvage) {
if (salvagedItem == null || salvagedItem.getAmount() < 1 || if (salvagedItem == null || salvagedItem.getAmount() < 1 ||
!ItemHelper.isRepairable(salvagedItem)) { !ItemHelper.isRepairable(salvagedItem)) {
return null; return null;
@ -52,8 +70,8 @@ public final class SalvageHelper {
* @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>
* @return <p>A list of items, or null if not a valid type of recipe</p> * @return <p>A list of items, or null if not a valid type of recipe</p>
*/ */
private static List<ItemStack> getRecipeSalvage(Recipe recipe, ItemStack salvagedItem, private static @Nullable List<ItemStack> getRecipeSalvage(@NotNull Recipe recipe, @NotNull ItemStack salvagedItem,
List<Material> ignoredSalvage) { @NotNull List<Material> ignoredSalvage) {
List<ItemStack> ingredients; List<ItemStack> ingredients;
if (recipe instanceof ShapedRecipe shapedRecipe) { if (recipe instanceof ShapedRecipe shapedRecipe) {
ingredients = getIngredients(shapedRecipe); ingredients = getIngredients(shapedRecipe);
@ -67,9 +85,7 @@ public final class SalvageHelper {
ingredients = combineStacks(ingredients); ingredients = combineStacks(ingredients);
//Purge any ignored salvage to only calculate salvage using the remaining items //Purge any ignored salvage to only calculate salvage using the remaining items
if (ignoredSalvage != null) {
ingredients.removeIf((item) -> ignoredSalvage.contains(item.getType())); ingredients.removeIf((item) -> ignoredSalvage.contains(item.getType()));
}
Random random = new Random(); Random random = new Random();
@ -90,7 +106,7 @@ public final class SalvageHelper {
* @param itemsToCopy <p>The items to make a copy of</p> * @param itemsToCopy <p>The items to make a copy of</p>
* @return <p>A copy of the given items</p> * @return <p>A copy of the given items</p>
*/ */
private static List<ItemStack> copyItems(List<ItemStack> itemsToCopy) { private static @NotNull List<ItemStack> copyItems(@NotNull List<ItemStack> itemsToCopy) {
List<ItemStack> copies = new ArrayList<>(itemsToCopy.size()); List<ItemStack> copies = new ArrayList<>(itemsToCopy.size());
for (ItemStack itemStack : itemsToCopy) { for (ItemStack itemStack : itemsToCopy) {
copies.add(new ItemStack(itemStack.getType(), itemStack.getAmount())); copies.add(new ItemStack(itemStack.getType(), itemStack.getAmount()));
@ -106,10 +122,11 @@ public final class SalvageHelper {
* @param random <p>The randomness generator to use</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 List<ItemStack> getSalvage(List<ItemStack> recipeItems, ItemStack salvagedItem, Random random) { private static @NotNull List<ItemStack> getSalvage(@NotNull List<ItemStack> recipeItems,
@NotNull ItemStack salvagedItem, @NotNull Random random) {
double percentageRemaining = (ItemHelper.getDurability(salvagedItem) / double percentageRemaining = (ItemHelper.getDurability(salvagedItem) /
(double) ItemHelper.getMaxDurability(salvagedItem)); (double) ItemHelper.getMaxDurability(salvagedItem));
int totalItems = totalItems(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();
@ -137,7 +154,7 @@ public final class SalvageHelper {
* @param items <p>The items to get the sum of</p> * @param items <p>The items to get the sum of</p>
* @return <p>The total number of items</p> * @return <p>The total number of items</p>
*/ */
private static int totalItems(List<ItemStack> items) { private static int totalItemAmount(@NotNull List<ItemStack> items) {
int sum = 0; int sum = 0;
for (ItemStack itemStack : items) { for (ItemStack itemStack : items) {
sum += itemStack.getAmount(); sum += itemStack.getAmount();
@ -154,7 +171,7 @@ public final class SalvageHelper {
* @param items <p>The items to combine</p> * @param items <p>The items to combine</p>
* @return <p>The given items, but combined</p> * @return <p>The given items, but combined</p>
*/ */
private static List<ItemStack> combineStacks(List<ItemStack> items) { private static @NotNull List<ItemStack> combineStacks(@NotNull List<ItemStack> items) {
Map<Material, Integer> itemAmounts = new HashMap<>(); Map<Material, Integer> itemAmounts = new HashMap<>();
for (ItemStack item : items) { for (ItemStack item : items) {
Material itemType = item.getType(); Material itemType = item.getType();
@ -174,7 +191,7 @@ 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 List<ItemStack> getIngredients(ShapedRecipe shapedRecipe) { private static @NotNull 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

@ -5,6 +5,7 @@ import net.knarcraft.blacksmith.config.SmithPreset;
import net.knarcraft.blacksmith.config.SmithPresetFilter; import net.knarcraft.blacksmith.config.SmithPresetFilter;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.enchantments.Enchantment; import org.bukkit.enchantments.Enchantment;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@ -24,7 +25,7 @@ public final class TabCompleteValuesHelper {
* @param valueType <p>The value type to get possible values for</p> * @param valueType <p>The value type to get possible values for</p>
* @return <p>The values to show the user</p> * @return <p>The values to show the user</p>
*/ */
public static List<String> getTabCompletions(SettingValueType valueType) { public static @NotNull List<String> getTabCompletions(@NotNull SettingValueType valueType) {
return switch (valueType) { return switch (valueType) {
case POSITIVE_INTEGER -> getPositiveIntegers(); case POSITIVE_INTEGER -> getPositiveIntegers();
case BOOLEAN -> getBooleans(); case BOOLEAN -> getBooleans();
@ -43,7 +44,7 @@ public final class TabCompleteValuesHelper {
* *
* @return <p>Some example enchantment block lists</p> * @return <p>Some example enchantment block lists</p>
*/ */
private static List<String> getExampleEnchantmentBlockLists() { private static @NotNull List<String> getExampleEnchantmentBlockLists() {
List<String> exampleBlockLists = new ArrayList<>(); List<String> exampleBlockLists = new ArrayList<>();
exampleBlockLists.add(Enchantment.VANISHING_CURSE.getKey().getKey() + "," + exampleBlockLists.add(Enchantment.VANISHING_CURSE.getKey().getKey() + "," +
Enchantment.BINDING_CURSE.getKey().getKey() + "," + Enchantment.MENDING.getKey().getKey()); Enchantment.BINDING_CURSE.getKey().getKey() + "," + Enchantment.MENDING.getKey().getKey());
@ -58,7 +59,7 @@ public final class TabCompleteValuesHelper {
* *
* @return <p>A complete list of reforge-able material names</p> * @return <p>A complete list of reforge-able material names</p>
*/ */
private static List<String> getAllReforgeAbleMaterialNames() { private static @NotNull List<String> getAllReforgeAbleMaterialNames() {
List<String> reforgeAbleMaterials = new ArrayList<>(); List<String> reforgeAbleMaterials = new ArrayList<>();
for (Material material : ItemHelper.getAllReforgeAbleMaterials()) { for (Material material : ItemHelper.getAllReforgeAbleMaterials()) {
reforgeAbleMaterials.add(material.name()); reforgeAbleMaterials.add(material.name());
@ -80,7 +81,7 @@ public final class TabCompleteValuesHelper {
* *
* @return <p>A complete list of enchantments</p> * @return <p>A complete list of enchantments</p>
*/ */
private static List<String> getAllEnchantments() { private static @NotNull List<String> getAllEnchantments() {
List<String> enchantments = new ArrayList<>(); List<String> enchantments = new ArrayList<>();
for (Enchantment enchantment : Enchantment.values()) { for (Enchantment enchantment : Enchantment.values()) {
enchantments.add(enchantment.getKey().getKey()); enchantments.add(enchantment.getKey().getKey());
@ -93,7 +94,7 @@ public final class TabCompleteValuesHelper {
* *
* @return <p>Some example possible values for reforge-able materials</p> * @return <p>Some example possible values for reforge-able materials</p>
*/ */
private static List<String> getReforgeAbleMaterials() { private static @NotNull List<String> getReforgeAbleMaterials() {
List<String> stringLists = new ArrayList<>(); List<String> stringLists = new ArrayList<>();
for (SmithPreset preset : SmithPreset.values()) { for (SmithPreset preset : SmithPreset.values()) {
stringLists.add("preset:" + preset.name()); stringLists.add("preset:" + preset.name());
@ -114,7 +115,7 @@ public final class TabCompleteValuesHelper {
* *
* @return <p>Some example string values</p> * @return <p>Some example string values</p>
*/ */
private static List<String> getStrings() { private static @NotNull List<String> getStrings() {
List<String> strings = new ArrayList<>(1); List<String> strings = new ArrayList<>(1);
strings.add("&aExample message. Use & for color tags."); strings.add("&aExample message. Use & for color tags.");
return strings; return strings;
@ -125,7 +126,7 @@ public final class TabCompleteValuesHelper {
* *
* @return <p>Some example percentage values</p> * @return <p>Some example percentage values</p>
*/ */
private static List<String> getPercentages() { private static @NotNull List<String> getPercentages() {
List<String> percentages = new ArrayList<>(6); List<String> percentages = new ArrayList<>(6);
percentages.add("0"); percentages.add("0");
percentages.add("10"); percentages.add("10");
@ -141,7 +142,7 @@ public final class TabCompleteValuesHelper {
* *
* @return <p>Some possible positive doubles</p> * @return <p>Some possible positive doubles</p>
*/ */
private static List<String> getPositiveDoubles() { private static @NotNull List<String> getPositiveDoubles() {
List<String> positiveDoubles = new ArrayList<>(4); List<String> positiveDoubles = new ArrayList<>(4);
positiveDoubles.add("0.0"); positiveDoubles.add("0.0");
positiveDoubles.add("0.0001"); positiveDoubles.add("0.0001");
@ -156,7 +157,7 @@ public final class TabCompleteValuesHelper {
* *
* @return <p>Some example positive integers</p> * @return <p>Some example positive integers</p>
*/ */
private static List<String> getPositiveIntegers() { private static @NotNull List<String> getPositiveIntegers() {
List<String> positiveIntegers = new ArrayList<>(6); List<String> positiveIntegers = new ArrayList<>(6);
positiveIntegers.add("0"); positiveIntegers.add("0");
positiveIntegers.add("5"); positiveIntegers.add("5");
@ -173,7 +174,7 @@ public final class TabCompleteValuesHelper {
* *
* @return <p>The possible boolean values</p> * @return <p>The possible boolean values</p>
*/ */
private static List<String> getBooleans() { private static @NotNull List<String> getBooleans() {
List<String> booleans = new ArrayList<>(2); List<String> booleans = new ArrayList<>(2);
booleans.add("True"); booleans.add("True");
booleans.add("False"); booleans.add("False");

View File

@ -6,6 +6,8 @@ import net.knarcraft.blacksmith.formatting.BlacksmithTranslatableMessage;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.bukkit.enchantments.Enchantment; import org.bukkit.enchantments.Enchantment;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List; import java.util.List;
@ -26,7 +28,8 @@ public final class TypeValidationHelper {
* @param sender <p>The command sender to use for printing error messages</p> * @param sender <p>The command sender to use for printing error messages</p>
* @return <p>True if the value is valid</p> * @return <p>True if the value is valid</p>
*/ */
public static boolean isValid(SettingValueType valueType, Object value, CommandSender sender) { public static boolean isValid(@NotNull SettingValueType valueType, @Nullable Object value,
@Nullable CommandSender sender) {
try { try {
return switch (valueType) { return switch (valueType) {
case POSITIVE_DOUBLE -> isPositiveDouble(value, sender); case POSITIVE_DOUBLE -> isPositiveDouble(value, sender);
@ -51,7 +54,7 @@ public final class TypeValidationHelper {
* @param sender <p>The command sender to use for printing error messages</p> * @param sender <p>The command sender to use for printing error messages</p>
* @return <p>True if the value is a material</p> * @return <p>True if the value is a material</p>
*/ */
private static boolean isMaterial(Object value, CommandSender sender) { private static boolean isMaterial(@Nullable Object value, @Nullable CommandSender sender) {
boolean isMaterial = value instanceof Material || (value instanceof String string && boolean isMaterial = value instanceof Material || (value instanceof String string &&
InputParsingHelper.matchMaterial(string) != null); InputParsingHelper.matchMaterial(string) != null);
if (!isMaterial && sender != null) { if (!isMaterial && sender != null) {
@ -68,7 +71,7 @@ public final class TypeValidationHelper {
* @param sender <p>The command sender to use for printing error messages</p> * @param sender <p>The command sender to use for printing error messages</p>
* @return <p>True if the value is an enchantment</p> * @return <p>True if the value is an enchantment</p>
*/ */
private static boolean isEnchantment(Object value, CommandSender sender) { private static boolean isEnchantment(@Nullable Object value, @Nullable CommandSender sender) {
boolean isEnchantment = value instanceof Enchantment || (value instanceof String string && boolean isEnchantment = value instanceof Enchantment || (value instanceof String string &&
InputParsingHelper.matchEnchantment(string) != null); InputParsingHelper.matchEnchantment(string) != null);
if (!isEnchantment && sender != null) { if (!isEnchantment && sender != null) {
@ -85,7 +88,7 @@ public final class TypeValidationHelper {
* @param sender <p>The command sender to use for printing error messages</p> * @param sender <p>The command sender to use for printing error messages</p>
* @return <p>True if the value is a string list</p> * @return <p>True if the value is a string list</p>
*/ */
private static boolean isStringList(Object value, CommandSender sender) { private static boolean isStringList(@Nullable Object value, @Nullable CommandSender sender) {
boolean isStringList = value instanceof String[] || value instanceof List<?> || value instanceof String; boolean isStringList = value instanceof String[] || value instanceof List<?> || value instanceof String;
if (!isStringList && sender != null) { if (!isStringList && sender != null) {
BlacksmithPlugin.getStringFormatter().displayErrorMessage(sender, BlacksmithPlugin.getStringFormatter().displayErrorMessage(sender,
@ -101,9 +104,9 @@ public final class TypeValidationHelper {
* @param sender <p>The command sender to use for printing error messages</p> * @param sender <p>The command sender to use for printing error messages</p>
* @return <p>True if the value is a percentage</p> * @return <p>True if the value is a percentage</p>
*/ */
private static boolean isPercentage(Object value, CommandSender sender) { private static boolean isPercentage(@Nullable Object value, @Nullable CommandSender sender) {
boolean isPercentage = isPositiveInteger(value, null) && ConfigHelper.asInt(value) >= 0 && boolean isPercentage = value != null && isPositiveInteger(value, null) &&
ConfigHelper.asInt(value) <= 100; ConfigHelper.asInt(value) >= 0 && ConfigHelper.asInt(value) <= 100;
if (!isPercentage && sender != null) { if (!isPercentage && sender != null) {
BlacksmithPlugin.getStringFormatter().displayErrorMessage(sender, BlacksmithPlugin.getStringFormatter().displayErrorMessage(sender,
BlacksmithTranslatableMessage.INPUT_PERCENTAGE_REQUIRED); BlacksmithTranslatableMessage.INPUT_PERCENTAGE_REQUIRED);
@ -118,7 +121,7 @@ public final class TypeValidationHelper {
* @param sender <p>The command sender to use for printing error messages</p> * @param sender <p>The command sender to use for printing error messages</p>
* @return <p>True if the value is a non-empty string</p> * @return <p>True if the value is a non-empty string</p>
*/ */
private static boolean isNonEmptyString(Object value, CommandSender sender) { private static boolean isNonEmptyString(@Nullable Object value, @Nullable CommandSender sender) {
boolean isString = value instanceof String string && !string.isBlank(); boolean isString = value instanceof String string && !string.isBlank();
if (!isString && sender != null) { if (!isString && sender != null) {
BlacksmithPlugin.getStringFormatter().displayErrorMessage(sender, BlacksmithPlugin.getStringFormatter().displayErrorMessage(sender,
@ -134,9 +137,9 @@ public final class TypeValidationHelper {
* @param sender <p>The command sender to use for printing error messages</p> * @param sender <p>The command sender to use for printing error messages</p>
* @return <p>True if the value is a positive double</p> * @return <p>True if the value is a positive double</p>
*/ */
private static boolean isPositiveDouble(Object value, CommandSender sender) { private static boolean isPositiveDouble(@Nullable Object value, @Nullable CommandSender sender) {
try { try {
return ConfigHelper.asDouble(value) >= 0.0; return value != null && ConfigHelper.asDouble(value) >= 0.0;
} catch (NumberFormatException | NullPointerException exception) { } catch (NumberFormatException | NullPointerException exception) {
if (sender != null) { if (sender != null) {
BlacksmithPlugin.getStringFormatter().displayErrorMessage(sender, BlacksmithPlugin.getStringFormatter().displayErrorMessage(sender,
@ -153,9 +156,9 @@ public final class TypeValidationHelper {
* @param sender <p>The command sender to use for printing error messages</p> * @param sender <p>The command sender to use for printing error messages</p>
* @return <p>True if the value is a positive integer</p> * @return <p>True if the value is a positive integer</p>
*/ */
private static boolean isPositiveInteger(Object value, CommandSender sender) { private static boolean isPositiveInteger(@Nullable Object value, @Nullable CommandSender sender) {
try { try {
return ConfigHelper.asInt(value) >= 0; return value != null && ConfigHelper.asInt(value) >= 0;
} catch (NumberFormatException | NullPointerException exception) { } catch (NumberFormatException | NullPointerException exception) {
if (sender != null) { if (sender != null) {
BlacksmithPlugin.getStringFormatter().displayErrorMessage(sender, BlacksmithPlugin.getStringFormatter().displayErrorMessage(sender,

View File

@ -137,6 +137,17 @@ scrapper:
# set for each individual NPC, and should not be set here, unless you want to restrict NPCs which have not been set # set for each individual NPC, and should not be set here, unless you want to restrict NPCs which have not been set
# up yet. # up yet.
salvageAbleItems: [ ] salvageAbleItems: [ ]
# All settable delays
delaysInSeconds:
# The maximum time for a salvaging to finish
maximum: 30
# The minimum time for a salvaging to finish
minimum: 5
# The cool-down period between each salvage
salvageCoolDown: 60
messages: messages:
# The message to display when another player is using the scrapper # The message to display when another player is using the scrapper
busyPlayerMessage: "&cI'm busy at the moment. Come back later!" busyPlayerMessage: "&cI'm busy at the moment. Come back later!"

View File

@ -16,7 +16,15 @@ commands:
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 settings description: Used for configuring default blacksmith settings, or global blacksmith settings
scrapper:
permission: blacksmith.edit
usage: /<command> <option> [new value]
description: Used for configuring the selected scrapper NPC
scrapperconfig:
permission: blacksmith.admin
usage: /<command> <option/reload> [new value]
description: Used for configuring default scrapper settings, or global scrapper settings
preset: preset:
permission: blacksmith.preset permission: blacksmith.preset
usage: /<command> <preset>[:filter] usage: /<command> <preset>[:filter]

View File

@ -19,6 +19,7 @@ import java.util.Set;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotEquals; import static org.junit.jupiter.api.Assertions.assertNotEquals;
import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.fail;
/** /**
* A test class to test salvaging * A test class to test salvaging
@ -40,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), null)); assertNull(SalvageHelper.getSalvage(server, new ItemStack(Material.POTATO, 1), new ArrayList<>()));
} }
@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), null)); assertNull(SalvageHelper.getSalvage(server, new ItemStack(Material.IRON_AXE, 0), new ArrayList<>()));
assertNull(SalvageHelper.getSalvage(server, new ItemStack(Material.IRON_SWORD, -1), null)); assertNull(SalvageHelper.getSalvage(server, new ItemStack(Material.IRON_SWORD, -1), new ArrayList<>()));
} }
@Test @Test
@ -57,7 +58,12 @@ 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
assertEquals(expectedSalvage, new HashSet<>(SalvageHelper.getSalvage(server, itemToSalvage, null))); List<ItemStack> salvage = SalvageHelper.getSalvage(server, itemToSalvage, new ArrayList<>());
if (salvage == null) {
fail();
} else {
assertEquals(expectedSalvage, new HashSet<>(salvage));
}
} }
@Test @Test
@ -67,7 +73,12 @@ public class SalvageHelperTest {
expectedSalvage.add(new ItemStack(Material.STICK, 14)); expectedSalvage.add(new ItemStack(Material.STICK, 14));
ItemStack itemToSalvage = new ItemStack(Material.DIAMOND_PICKAXE, 7); ItemStack itemToSalvage = new ItemStack(Material.DIAMOND_PICKAXE, 7);
//Note: Conversion to sets makes sure the order doesn't matter //Note: Conversion to sets makes sure the order doesn't matter
assertEquals(expectedSalvage, new HashSet<>(SalvageHelper.getSalvage(server, itemToSalvage, null))); List<ItemStack> salvage = SalvageHelper.getSalvage(server, itemToSalvage, new ArrayList<>());
if (salvage == null) {
fail();
} else {
assertEquals(expectedSalvage, new HashSet<>(salvage));
}
} }
@Test @Test
@ -82,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, null); List<ItemStack> salvage = SalvageHelper.getSalvage(server, itemToSalvage, new ArrayList<>());
//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