Compare commits
6 Commits
master
...
book-split
Author | SHA1 | Date | |
---|---|---|---|
42ca42c571 | |||
7e17122bb2 | |||
b01ccfc537 | |||
e3dbeccc14 | |||
90d3c49c12 | |||
f5bfbfd4f8 |
17
pom.xml
17
pom.xml
@ -65,7 +65,7 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.spigotmc</groupId>
|
<groupId>org.spigotmc</groupId>
|
||||||
<artifactId>spigot-api</artifactId>
|
<artifactId>spigot-api</artifactId>
|
||||||
<version>1.20.6-R0.1-SNAPSHOT</version>
|
<version>1.21.3-R0.1-SNAPSHOT</version>
|
||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
@ -92,6 +92,11 @@
|
|||||||
<version>5.10.2</version>
|
<version>5.10.2</version>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>net.objecthunter</groupId>
|
||||||
|
<artifactId>exp4j</artifactId>
|
||||||
|
<version>0.4.8</version>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<!-- Build information -->
|
<!-- Build information -->
|
||||||
@ -127,6 +132,10 @@
|
|||||||
<pattern>org.jetbrains.annotations</pattern>
|
<pattern>org.jetbrains.annotations</pattern>
|
||||||
<shadedPattern>net.knarcraft.blacksmith.lib.annotations</shadedPattern>
|
<shadedPattern>net.knarcraft.blacksmith.lib.annotations</shadedPattern>
|
||||||
</relocation>
|
</relocation>
|
||||||
|
<relocation>
|
||||||
|
<pattern>net.objecthunter.exp4j</pattern>
|
||||||
|
<shadedPattern>net.knarcraft.blacksmith.lib.exp4j</shadedPattern>
|
||||||
|
</relocation>
|
||||||
</relocations>
|
</relocations>
|
||||||
<filters>
|
<filters>
|
||||||
<filter>
|
<filter>
|
||||||
@ -141,6 +150,12 @@
|
|||||||
<include>org/jetbrains/annotations/**</include>
|
<include>org/jetbrains/annotations/**</include>
|
||||||
</includes>
|
</includes>
|
||||||
</filter>
|
</filter>
|
||||||
|
<filter>
|
||||||
|
<artifact>net.objecthunter:exp4j</artifact>
|
||||||
|
<includes>
|
||||||
|
<include>net/objecthunter/exp4j/**</include>
|
||||||
|
</includes>
|
||||||
|
</filter>
|
||||||
</filters>
|
</filters>
|
||||||
</configuration>
|
</configuration>
|
||||||
</execution>
|
</execution>
|
||||||
|
@ -20,6 +20,7 @@ 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;
|
||||||
import net.knarcraft.blacksmith.manager.EconomyManager;
|
import net.knarcraft.blacksmith.manager.EconomyManager;
|
||||||
|
import net.knarcraft.blacksmith.manager.PlayerUsageManager;
|
||||||
import net.knarcraft.blacksmith.trait.BlacksmithTrait;
|
import net.knarcraft.blacksmith.trait.BlacksmithTrait;
|
||||||
import net.knarcraft.blacksmith.trait.ScrapperTrait;
|
import net.knarcraft.blacksmith.trait.ScrapperTrait;
|
||||||
import net.knarcraft.blacksmith.util.ConfigHelper;
|
import net.knarcraft.blacksmith.util.ConfigHelper;
|
||||||
@ -27,6 +28,7 @@ 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.Bukkit;
|
||||||
import org.bukkit.command.CommandExecutor;
|
import org.bukkit.command.CommandExecutor;
|
||||||
import org.bukkit.command.PluginCommand;
|
import org.bukkit.command.PluginCommand;
|
||||||
import org.bukkit.command.TabCompleter;
|
import org.bukkit.command.TabCompleter;
|
||||||
@ -183,6 +185,10 @@ public class BlacksmithPlugin extends JavaPlugin {
|
|||||||
//Alert about an update in the console
|
//Alert about an update in the console
|
||||||
UpdateChecker.checkForUpdate(this, "https://api.spigotmc.org/legacy/update.php?resource=105938",
|
UpdateChecker.checkForUpdate(this, "https://api.spigotmc.org/legacy/update.php?resource=105938",
|
||||||
() -> this.getDescription().getVersion(), null);
|
() -> this.getDescription().getVersion(), null);
|
||||||
|
|
||||||
|
// Remove expired scrapper usage data
|
||||||
|
Bukkit.getScheduler().scheduleSyncRepeatingTask(this, () -> PlayerUsageManager.removeExpiredData(
|
||||||
|
System.currentTimeMillis() - 3600000), 36000, 36000);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -0,0 +1,86 @@
|
|||||||
|
package net.knarcraft.blacksmith.command;
|
||||||
|
|
||||||
|
import net.knarcraft.blacksmith.BlacksmithPlugin;
|
||||||
|
import net.knarcraft.blacksmith.container.ActionCost;
|
||||||
|
import net.knarcraft.blacksmith.formatting.BlacksmithTranslatableMessage;
|
||||||
|
import org.bukkit.command.Command;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
import org.bukkit.command.TabExecutor;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class CostCommand implements TabExecutor {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onCommand(@NotNull CommandSender commandSender, @NotNull Command command, @NotNull String s, @NotNull String[] arguments) {
|
||||||
|
//TODO: Whenever a cost is specified (not for the per-material and per-enchantment costs), allow either a simple
|
||||||
|
// cost or an ActionCost. When loading costs, first try and parse a double. If not, parse an ActionCost object.
|
||||||
|
// TODO: The command should look like "blacksmithEdit <option> <simple|advanced> <double|economy|item|permission|exp>
|
||||||
|
// <double|blank/null|comma-separated-string|integer>"
|
||||||
|
|
||||||
|
//TODO: Check arguments size
|
||||||
|
if (arguments.length < 2) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionCost actionCost;
|
||||||
|
|
||||||
|
switch (arguments[0]) {
|
||||||
|
case "simple":
|
||||||
|
// TODO: Do something with the cost
|
||||||
|
double cost = parseSimpleCost(commandSender, arguments[1]);
|
||||||
|
break;
|
||||||
|
case "advanced":
|
||||||
|
switch (arguments[1]) {
|
||||||
|
case "economy":
|
||||||
|
// TODO: Expect the next argument to be the cost
|
||||||
|
break;
|
||||||
|
case "item":
|
||||||
|
// TODO: The next argument would either be "null" to clear the value, or "mainHand" to use the item in the player's main hand
|
||||||
|
break;
|
||||||
|
case "permission":
|
||||||
|
// TODO: The next argument will be a comma-separated list of permissions
|
||||||
|
break;
|
||||||
|
case "exp":
|
||||||
|
// TODO: Expect the next argument to be an integer
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable List<String> onTabComplete(@NotNull CommandSender commandSender, @NotNull Command command,
|
||||||
|
@NotNull String s, @NotNull String[] strings) {
|
||||||
|
return List.of();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses a simple double cost
|
||||||
|
*
|
||||||
|
* @param commandSender <p>The command sender to notify of any problems</p>
|
||||||
|
* @param costString <p>The string to parse into a cost</p>
|
||||||
|
* @return <p>The parsed cost</p>
|
||||||
|
* @throws IllegalArgumentException <p>If the specified cost is invalid</p>
|
||||||
|
*/
|
||||||
|
private double parseSimpleCost(@NotNull CommandSender commandSender,
|
||||||
|
@NotNull String costString) throws IllegalArgumentException {
|
||||||
|
try {
|
||||||
|
double cost = Double.parseDouble(costString);
|
||||||
|
if (cost < 0) {
|
||||||
|
throw new NumberFormatException();
|
||||||
|
}
|
||||||
|
return cost;
|
||||||
|
} catch (NumberFormatException exception) {
|
||||||
|
BlacksmithPlugin.getStringFormatter().displayErrorMessage(commandSender,
|
||||||
|
BlacksmithTranslatableMessage.DOUBLE_COST_REQUIRED);
|
||||||
|
throw new IllegalArgumentException("Invalid cost given");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -55,4 +55,9 @@ public enum SettingValueType {
|
|||||||
*/
|
*/
|
||||||
ENCHANTMENT_LIST,
|
ENCHANTMENT_LIST,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Advanced cost, that supports either a simple double, or specifying money cost, permission requirement, exp cost and an item cost
|
||||||
|
*/
|
||||||
|
ADVANCED_COST,
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -212,6 +212,24 @@ public class GlobalScrapperSettings implements Settings<ScrapperSetting> {
|
|||||||
return asDouble(ScrapperSetting.NETHERITE_SALVAGE_COST);
|
return asDouble(ScrapperSetting.NETHERITE_SALVAGE_COST);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the math formula for the increase in salvage cost
|
||||||
|
*
|
||||||
|
* @return <p>The salvage cost increase formula</p>
|
||||||
|
*/
|
||||||
|
public String getSalvageCostIncrease() {
|
||||||
|
return asString(ScrapperSetting.SALVAGE_COST_INCREASE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the math formula for the increase in salvage cooldown
|
||||||
|
*
|
||||||
|
* @return <p>The salvage cooldown increase formula</p>
|
||||||
|
*/
|
||||||
|
public String getSalvageCooldownIncrease() {
|
||||||
|
return asString(ScrapperSetting.SALVAGE_COOLDOWN_INCREASE);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets trash salvage for the given material
|
* Gets trash salvage for the given material
|
||||||
*
|
*
|
||||||
@ -275,4 +293,15 @@ public class GlobalScrapperSettings implements Settings<ScrapperSetting> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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>
|
||||||
|
*/
|
||||||
|
@NotNull
|
||||||
|
private String asString(@NotNull ScrapperSetting setting) {
|
||||||
|
return getValue(setting).toString();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -83,6 +83,15 @@ public class ScrapperNPCSettings implements TraitSettings<ScrapperSetting> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets whether this scrapper is able to split an enchanted book
|
||||||
|
*
|
||||||
|
* @return <p>True if this scrapper is able to split an enchanted book</p>
|
||||||
|
*/
|
||||||
|
public boolean splitEnchantedBook() {
|
||||||
|
return asBoolean(ScrapperSetting.SPLIT_ENCHANTED_BOOK);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the raw current value of a setting
|
* Gets the raw current value of a setting
|
||||||
*
|
*
|
||||||
@ -171,6 +180,15 @@ public class ScrapperNPCSettings implements TraitSettings<ScrapperSetting> {
|
|||||||
return asString(ScrapperSetting.COST_MESSAGE_NETHERITE);
|
return asString(ScrapperSetting.COST_MESSAGE_NETHERITE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the message to use for displaying enchanted book salvage cost
|
||||||
|
*
|
||||||
|
* @return <p>The message to use for displaying enchanted book salvage cost</p>
|
||||||
|
*/
|
||||||
|
public String getEnchantedBookCostMessage() {
|
||||||
|
return asString(ScrapperSetting.COST_MESSAGE_ENCHANTED_BOOK);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@NotNull
|
@NotNull
|
||||||
public String getCoolDownUnexpiredMessage() {
|
public String getCoolDownUnexpiredMessage() {
|
||||||
@ -466,4 +484,24 @@ public class ScrapperNPCSettings implements TraitSettings<ScrapperSetting> {
|
|||||||
return asString(ScrapperSetting.CANNOT_SALVAGE_NETHERITE_MESSAGE);
|
return asString(ScrapperSetting.CANNOT_SALVAGE_NETHERITE_MESSAGE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the message to display when explaining that this scrapper is unable to salvage enchanted books
|
||||||
|
*
|
||||||
|
* @return <p>The message to display when explaining that this scrapper is unable to salvage enchanted books</p>
|
||||||
|
*/
|
||||||
|
@NotNull
|
||||||
|
public String getCannotSalvageEnchantedBookMessage() {
|
||||||
|
return asString(ScrapperSetting.CANNOT_SALVAGE_ENCHANTED_BOOK_MESSAGE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the message to display when explaining that the scrapper cannot salvage an enchanted book with a single enchantment
|
||||||
|
*
|
||||||
|
* @return <p>The message to display when explaining that the scrapper cannot salvage an enchanted book with a single enchantment</p>
|
||||||
|
*/
|
||||||
|
@NotNull
|
||||||
|
public String getCannotSplitEnchantedBookFurtherMessage() {
|
||||||
|
return asString(ScrapperSetting.CANNOT_SPLIT_ENCHANTED_BOOK_FURTHER_MESSAGE);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -92,6 +92,12 @@ public enum ScrapperSetting implements Setting {
|
|||||||
SALVAGE_NETHERITE("salvageNetherite", SettingValueType.BOOLEAN, true,
|
SALVAGE_NETHERITE("salvageNetherite", SettingValueType.BOOLEAN, true,
|
||||||
"Whether to enable salvaging of netherite items", true, false),
|
"Whether to enable salvaging of netherite items", true, false),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The setting for whether the NPC should allow salvaging an enchanted books with several enchantments into several books with one enchantment
|
||||||
|
*/
|
||||||
|
SPLIT_ENCHANTED_BOOK("splitEnchantedBook", SettingValueType.BOOLEAN, false, "Whether to enable " +
|
||||||
|
"splitting of enchanted books", true, false),
|
||||||
|
|
||||||
/*-----------
|
/*-----------
|
||||||
| Messages |
|
| Messages |
|
||||||
-----------*/
|
-----------*/
|
||||||
@ -194,6 +200,13 @@ public enum ScrapperSetting implements Setting {
|
|||||||
"&eIt will cost &a{cost}&e to salvage that &a{item}&e into diamond!",
|
"&eIt will cost &a{cost}&e to salvage that &a{item}&e into diamond!",
|
||||||
"The message to display when explaining the shown item's netherite salvage cost", true, true),
|
"The message to display when explaining the shown item's netherite salvage cost", true, true),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The message displayed when displaying the cost of salvaging the player's held enchanted book
|
||||||
|
*/
|
||||||
|
COST_MESSAGE_ENCHANTED_BOOK("costMessageEnchantedBook", SettingValueType.STRING,
|
||||||
|
"&eIt will cost &a{cost}&e to salvage that enchanted book!",
|
||||||
|
"The message to display when explaining the shown enchanted book's salvage cost", true, true),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The message displayed when explaining that all items will be returned as salvage
|
* The message displayed when explaining that all items will be returned as salvage
|
||||||
*/
|
*/
|
||||||
@ -236,6 +249,20 @@ public enum ScrapperSetting implements Setting {
|
|||||||
"&cI'm sorry, but I'm unable to salvage netherite items!",
|
"&cI'm sorry, but I'm unable to salvage netherite items!",
|
||||||
"The message to display when asked to salvage netherite items, and that option is disabled", true, true),
|
"The message to display when asked to salvage netherite items, and that option is disabled", true, true),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The message displayed when explaining that enchanted book salvage is disabled
|
||||||
|
*/
|
||||||
|
CANNOT_SALVAGE_ENCHANTED_BOOK_MESSAGE("cannotSalvageEnchantedBookMessage", SettingValueType.STRING,
|
||||||
|
"&cI'm sorry, but I'm unable to salvage enchanted books!",
|
||||||
|
"The message to display when asked to salvage enchanted books, and the option is disabled", true, true),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The message displayed when explaining that a player cannot salvage an enchanted book containing a single enchantment
|
||||||
|
*/
|
||||||
|
CANNOT_SPLIT_ENCHANTED_BOOK_FURTHER_MESSAGE("cannotSplitEnchantedBookFurtherMessage", SettingValueType.STRING,
|
||||||
|
"&cI'm sorry, but I cannot salvage that enchanted book any further",
|
||||||
|
"The message displayed when a player attempts to salvage an enchanted book with a single enchantment", true, true),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The message displayed when clicking a scrapper with an empty hand
|
* The message displayed when clicking a scrapper with an empty hand
|
||||||
*/
|
*/
|
||||||
@ -264,6 +291,20 @@ public enum ScrapperSetting implements Setting {
|
|||||||
NETHERITE_SALVAGE_COST("netheriteSalvagePrice", SettingValueType.POSITIVE_DOUBLE, 15,
|
NETHERITE_SALVAGE_COST("netheriteSalvagePrice", SettingValueType.POSITIVE_DOUBLE, 15,
|
||||||
"The cost of using the scrapper to remove netherite from an item", false, false),
|
"The cost of using the scrapper to remove netherite from an item", false, false),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The mathematical formula for increasing salvage cost
|
||||||
|
*/
|
||||||
|
SALVAGE_COST_INCREASE("salvageCostIncrease", SettingValueType.STRING, "{cost}*{timesUsed}",
|
||||||
|
"The mathematical formula for salvage cost increase when continually used within the same hour. " +
|
||||||
|
"This is necessary for some servers where items can be easily farmed. Set to {cost} to disable behavior.", false, false),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The mathematical formula for increasing salvage cooldown
|
||||||
|
*/
|
||||||
|
SALVAGE_COOLDOWN_INCREASE("salvageCooldownIncrease", SettingValueType.STRING, "{cooldown}*{timesUsed}",
|
||||||
|
"The mathematical formula for salvage cooldown increase when continually used within the same hour. " +
|
||||||
|
"This is necessary for some servers where items can be easily farmed. Set to {cooldown} to disable behavior.", false, false),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether to display exact time in minutes and seconds when displaying a remaining cool-down
|
* Whether to display exact time in minutes and seconds when displaying a remaining cool-down
|
||||||
*/
|
*/
|
||||||
|
212
src/main/java/net/knarcraft/blacksmith/container/ActionCost.java
Normal file
212
src/main/java/net/knarcraft/blacksmith/container/ActionCost.java
Normal file
@ -0,0 +1,212 @@
|
|||||||
|
package net.knarcraft.blacksmith.container;
|
||||||
|
|
||||||
|
import net.knarcraft.blacksmith.BlacksmithPlugin;
|
||||||
|
import net.knarcraft.blacksmith.manager.EconomyManager;
|
||||||
|
import org.bukkit.configuration.ConfigurationSection;
|
||||||
|
import org.bukkit.configuration.serialization.ConfigurationSerializable;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
import org.bukkit.inventory.PlayerInventory;
|
||||||
|
import org.bukkit.inventory.meta.ItemMeta;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The cost of performing an action
|
||||||
|
*
|
||||||
|
* @param monetaryCost <p>The monetary cost of the action</p>
|
||||||
|
* @param expCost <p>The experience cost of the action</p>
|
||||||
|
* @param itemCost <p>The item-based cost of the action</p>
|
||||||
|
* @param requiredPermissions <p>The permission required for the action</p>
|
||||||
|
*/
|
||||||
|
public record ActionCost(double monetaryCost, int expCost, @Nullable ItemStack itemCost,
|
||||||
|
@NotNull Set<String> requiredPermissions) implements ConfigurationSerializable {
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
public String displayCost() {
|
||||||
|
StringBuilder builder = new StringBuilder();
|
||||||
|
if (monetaryCost > 0) {
|
||||||
|
builder.append(EconomyManager.format(monetaryCost)).append(", ");
|
||||||
|
}
|
||||||
|
if (expCost > 0) {
|
||||||
|
builder.append(expCost).append("exp, ");
|
||||||
|
}
|
||||||
|
if (itemCost != null) {
|
||||||
|
// TODO: Present name, amount and name + lore
|
||||||
|
builder.append(itemCost);
|
||||||
|
}
|
||||||
|
// TODO: Display required permissions if the player doesn't have them?
|
||||||
|
return builder.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether the given player is able to pay this action cost
|
||||||
|
*
|
||||||
|
* @param player <p>The player to check</p>
|
||||||
|
* @return <p>True if the player is able to pay</p>
|
||||||
|
*/
|
||||||
|
public boolean canPay(@NotNull Player player) {
|
||||||
|
for (String permission : this.requiredPermissions) {
|
||||||
|
if (!player.hasPermission(permission)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (player.getExp() < this.expCost || !EconomyManager.hasEnough(player, this.monetaryCost)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return hasEnoughValidItemsInInventory(player);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Takes exp, money and items from the player, according to this cost
|
||||||
|
*
|
||||||
|
* @param player <p>The player to take the payment from</p>
|
||||||
|
*/
|
||||||
|
public void takePayment(@NotNull Player player) {
|
||||||
|
player.giveExp(-expCost);
|
||||||
|
EconomyManager.withdraw(player, monetaryCost);
|
||||||
|
takeItemCost(player);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether the given player has enough items specified as the item cost
|
||||||
|
*
|
||||||
|
* @param player <p>The player to check</p>
|
||||||
|
* @return <p>True if the player has enough items in their inventory</p>
|
||||||
|
*/
|
||||||
|
private boolean hasEnoughValidItemsInInventory(@NotNull Player player) {
|
||||||
|
if (this.itemCost == null) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int amountInInventory = 0;
|
||||||
|
for (Map.Entry<Integer, Integer> entry : getValidItems(player).entrySet()) {
|
||||||
|
amountInInventory += entry.getValue();
|
||||||
|
}
|
||||||
|
return this.itemCost.getAmount() >= amountInInventory;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets all items in a player's inventory equal to the specified item
|
||||||
|
*
|
||||||
|
* @param player <p>The player to get valid items for</p>
|
||||||
|
* @return <p>All valid items in the format: Inventory id -> Amount</p>
|
||||||
|
*/
|
||||||
|
@NotNull
|
||||||
|
private Map<Integer, Integer> getValidItems(@NotNull Player player) {
|
||||||
|
if (this.itemCost == null) {
|
||||||
|
return new HashMap<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
PlayerInventory playerInventory = player.getInventory();
|
||||||
|
ItemMeta targetMeta = this.itemCost.getItemMeta();
|
||||||
|
String displayName = null;
|
||||||
|
List<String> lore = null;
|
||||||
|
if (targetMeta != null) {
|
||||||
|
displayName = targetMeta.hasDisplayName() ? targetMeta.getDisplayName() : null;
|
||||||
|
lore = targetMeta.hasLore() ? targetMeta.getLore() : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<Integer, Integer> output = new HashMap<>();
|
||||||
|
HashMap<Integer, ? extends ItemStack> itemsOfType = playerInventory.all(this.itemCost.getType());
|
||||||
|
|
||||||
|
for (Map.Entry<Integer, ? extends ItemStack> entry : itemsOfType.entrySet()) {
|
||||||
|
if (targetMeta != null) {
|
||||||
|
// Only consider item if the name and lore is the same
|
||||||
|
ItemMeta meta = entry.getValue().getItemMeta();
|
||||||
|
if (meta == null || (displayName != null && (!meta.hasDisplayName() ||
|
||||||
|
!meta.getDisplayName().equals(displayName)) || lore != null && (!meta.hasLore() ||
|
||||||
|
meta.getLore() == null || !meta.getLore().equals(lore)))) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
output.put(entry.getKey(), (Integer) entry.getValue().getAmount());
|
||||||
|
}
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Takes the amount of items specified as the cost for this action
|
||||||
|
*
|
||||||
|
* @param player <p>The player to take the items from</p>
|
||||||
|
*/
|
||||||
|
private void takeItemCost(@NotNull Player player) {
|
||||||
|
if (this.itemCost == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int clearedAmount = 0;
|
||||||
|
for (Map.Entry<Integer, Integer> entry : getValidItems(player).entrySet()) {
|
||||||
|
int inventory = entry.getKey();
|
||||||
|
int amount = entry.getValue();
|
||||||
|
if (amount <= this.itemCost.getAmount() - clearedAmount) {
|
||||||
|
clearedAmount += amount;
|
||||||
|
player.getInventory().clear(entry.getKey());
|
||||||
|
} else {
|
||||||
|
clearedAmount = this.itemCost.getAmount();
|
||||||
|
ItemStack item = player.getInventory().getItem(inventory);
|
||||||
|
if (item != null) {
|
||||||
|
item.setAmount(amount - clearedAmount);
|
||||||
|
} else {
|
||||||
|
BlacksmithPlugin.error("An item changed after calculating item cost. Was unable to take " +
|
||||||
|
amount + " items");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (clearedAmount >= this.itemCost.getAmount()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads an action cost from a configuration section
|
||||||
|
*
|
||||||
|
* @param configurationSection <p>The configuration section to load from</p>
|
||||||
|
* @param key <p>The key of the cost to load</p>
|
||||||
|
* @return <p>The loaded cost</p>
|
||||||
|
*/
|
||||||
|
private static ActionCost loadActionCost(@NotNull ConfigurationSection configurationSection, @NotNull String key) {
|
||||||
|
double cost = configurationSection.getDouble(key, Double.MIN_VALUE);
|
||||||
|
if (cost != Double.MIN_VALUE) {
|
||||||
|
return new ActionCost(cost, 0, null, Set.of());
|
||||||
|
} else {
|
||||||
|
return (ActionCost) configurationSection.get(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deserializes an action cost
|
||||||
|
*
|
||||||
|
* @param serialized <p>The serialized action cost</p>
|
||||||
|
* @return <p>The deserialized action cost</p>
|
||||||
|
*/
|
||||||
|
@SuppressWarnings({"unused", "unchecked"})
|
||||||
|
public static ActionCost deserialize(Map<String, Object> serialized) {
|
||||||
|
double monetaryCost = (double) serialized.get("monetaryCost");
|
||||||
|
int expCost = (int) serialized.get("expCost");
|
||||||
|
ItemStack itemCost = (ItemStack) serialized.get("itemCost");
|
||||||
|
Set<String> requiredPermissions = (Set<String>) serialized.get("requiredPermissions");
|
||||||
|
return new ActionCost(monetaryCost, expCost, itemCost, requiredPermissions);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull Map<String, Object> serialize() {
|
||||||
|
Map<String, Object> serialized = new HashMap<>();
|
||||||
|
serialized.put("monetaryCost", Optional.of(this.monetaryCost));
|
||||||
|
serialized.put("expCost", Optional.of(this.expCost));
|
||||||
|
serialized.put("itemCost", itemCost);
|
||||||
|
serialized.put("requiredPermissions", this.requiredPermissions);
|
||||||
|
return serialized;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,6 +1,7 @@
|
|||||||
package net.knarcraft.blacksmith.event;
|
package net.knarcraft.blacksmith.event;
|
||||||
|
|
||||||
import net.citizensnpcs.api.npc.NPC;
|
import net.citizensnpcs.api.npc.NPC;
|
||||||
|
import org.bukkit.entity.Entity;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.event.Event;
|
import org.bukkit.event.Event;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
@ -13,15 +14,18 @@ public abstract class AbstractBlacksmithPluginEvent extends Event implements Bla
|
|||||||
|
|
||||||
protected final NPC npc;
|
protected final NPC npc;
|
||||||
protected final Player player;
|
protected final Player player;
|
||||||
|
protected final Entity entity;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Instantiates a new blacksmith plugin event
|
* Instantiates a new blacksmith plugin event
|
||||||
*
|
*
|
||||||
* @param npc <p>The NPC involved in the event</p>
|
* @param npc <p>The NPC involved in the event</p>
|
||||||
|
* @param entity <p>The entity of the NPC</p>
|
||||||
* @param player <p>The player involved in the event</p>
|
* @param player <p>The player involved in the event</p>
|
||||||
*/
|
*/
|
||||||
public AbstractBlacksmithPluginEvent(@NotNull NPC npc, @NotNull Player player) {
|
public AbstractBlacksmithPluginEvent(@NotNull NPC npc, @NotNull Entity entity, @NotNull Player player) {
|
||||||
this.npc = npc;
|
this.npc = npc;
|
||||||
|
this.entity = entity;
|
||||||
this.player = player;
|
this.player = player;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -31,6 +35,12 @@ public abstract class AbstractBlacksmithPluginEvent extends Event implements Bla
|
|||||||
return this.npc;
|
return this.npc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@NotNull
|
||||||
|
public Entity getEntity() {
|
||||||
|
return this.entity;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@NotNull
|
@NotNull
|
||||||
public Player getPlayer() {
|
public Player getPlayer() {
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package net.knarcraft.blacksmith.event;
|
package net.knarcraft.blacksmith.event;
|
||||||
|
|
||||||
import net.citizensnpcs.api.npc.NPC;
|
import net.citizensnpcs.api.npc.NPC;
|
||||||
|
import org.bukkit.entity.Entity;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
@ -18,6 +19,14 @@ public interface BlacksmithPluginEvent {
|
|||||||
@NotNull
|
@NotNull
|
||||||
NPC getNpc();
|
NPC getNpc();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the entity of the NPC
|
||||||
|
*
|
||||||
|
* @return <p>The NPC entity</p>
|
||||||
|
*/
|
||||||
|
@NotNull
|
||||||
|
Entity getEntity();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the player involved in the event
|
* Gets the player involved in the event
|
||||||
*
|
*
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package net.knarcraft.blacksmith.event;
|
package net.knarcraft.blacksmith.event;
|
||||||
|
|
||||||
import net.citizensnpcs.api.npc.NPC;
|
import net.citizensnpcs.api.npc.NPC;
|
||||||
|
import org.bukkit.entity.Entity;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.event.HandlerList;
|
import org.bukkit.event.HandlerList;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
@ -16,9 +17,11 @@ public class BlacksmithReforgeFailEvent extends AbstractBlacksmithPluginEvent im
|
|||||||
* Instantiates a new blacksmith reforge fail event
|
* Instantiates a new blacksmith reforge fail event
|
||||||
*
|
*
|
||||||
* @param npc <p>The NPC involved in the event</p>
|
* @param npc <p>The NPC involved in the event</p>
|
||||||
|
* @param entity <p>The entity of the NPC</p>
|
||||||
|
* @param player <p>The player that initiated the session</p>
|
||||||
*/
|
*/
|
||||||
public BlacksmithReforgeFailEvent(@NotNull NPC npc, @NotNull Player player) {
|
public BlacksmithReforgeFailEvent(@NotNull NPC npc, @NotNull Entity entity, @NotNull Player player) {
|
||||||
super(npc, player);
|
super(npc, entity, player);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -2,6 +2,7 @@ package net.knarcraft.blacksmith.event;
|
|||||||
|
|
||||||
import net.citizensnpcs.api.npc.NPC;
|
import net.citizensnpcs.api.npc.NPC;
|
||||||
import org.bukkit.Material;
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.entity.Entity;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.event.HandlerList;
|
import org.bukkit.event.HandlerList;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
@ -19,13 +20,14 @@ public class BlacksmithReforgeStartEvent extends AbstractBlacksmithPluginEvent i
|
|||||||
* Instantiates a new blacksmith reforge start event
|
* Instantiates a new blacksmith reforge start event
|
||||||
*
|
*
|
||||||
* @param npc <p>The NPC involved in the event</p>
|
* @param npc <p>The NPC involved in the event</p>
|
||||||
|
* @param entity <p>The entity of the NPC</p>
|
||||||
* @param player <p>The player involved in the event</p>
|
* @param player <p>The player involved in the event</p>
|
||||||
* @param durationTicks <p>The duration of the reforge</p>
|
* @param durationTicks <p>The duration of the reforge</p>
|
||||||
* @param craftingStation <p>The appropriate crafting station for this reforging</p>
|
* @param craftingStation <p>The appropriate crafting station for this reforging</p>
|
||||||
*/
|
*/
|
||||||
public BlacksmithReforgeStartEvent(@NotNull NPC npc, @NotNull Player player, long durationTicks,
|
public BlacksmithReforgeStartEvent(@NotNull NPC npc, @NotNull Entity entity, @NotNull Player player, long durationTicks,
|
||||||
@NotNull Material craftingStation) {
|
@NotNull Material craftingStation) {
|
||||||
super(npc, player);
|
super(npc, entity, player);
|
||||||
this.durationTicks = durationTicks;
|
this.durationTicks = durationTicks;
|
||||||
this.craftingStation = craftingStation;
|
this.craftingStation = craftingStation;
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package net.knarcraft.blacksmith.event;
|
package net.knarcraft.blacksmith.event;
|
||||||
|
|
||||||
import net.citizensnpcs.api.npc.NPC;
|
import net.citizensnpcs.api.npc.NPC;
|
||||||
|
import org.bukkit.entity.Entity;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.event.HandlerList;
|
import org.bukkit.event.HandlerList;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
@ -16,10 +17,11 @@ public class BlacksmithReforgeSucceedEvent extends AbstractBlacksmithPluginEvent
|
|||||||
* Instantiates a new blacksmith reforge succeed event
|
* Instantiates a new blacksmith reforge succeed event
|
||||||
*
|
*
|
||||||
* @param npc <p>The NPC involved in the event</p>
|
* @param npc <p>The NPC involved in the event</p>
|
||||||
|
* @param entity <p>The entity of the NPC</p>
|
||||||
* @param player <p>The player involved in the event</p>
|
* @param player <p>The player involved in the event</p>
|
||||||
*/
|
*/
|
||||||
public BlacksmithReforgeSucceedEvent(@NotNull NPC npc, @NotNull Player player) {
|
public BlacksmithReforgeSucceedEvent(@NotNull NPC npc, @NotNull Entity entity, @NotNull Player player) {
|
||||||
super(npc, player);
|
super(npc, entity, player);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -3,6 +3,7 @@ package net.knarcraft.blacksmith.event;
|
|||||||
import net.citizensnpcs.api.npc.NPC;
|
import net.citizensnpcs.api.npc.NPC;
|
||||||
import org.bukkit.Sound;
|
import org.bukkit.Sound;
|
||||||
import org.bukkit.SoundCategory;
|
import org.bukkit.SoundCategory;
|
||||||
|
import org.bukkit.entity.Entity;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.event.Cancellable;
|
import org.bukkit.event.Cancellable;
|
||||||
import org.bukkit.event.HandlerList;
|
import org.bukkit.event.HandlerList;
|
||||||
@ -25,15 +26,16 @@ public class NPCSoundEvent extends AbstractBlacksmithPluginEvent implements Canc
|
|||||||
* Instantiates a new NPC sound event
|
* Instantiates a new NPC sound event
|
||||||
*
|
*
|
||||||
* @param npc <p>The NPC playing the sound</p>
|
* @param npc <p>The NPC playing the sound</p>
|
||||||
|
* @param entity <p>The entity playing the sound</p>
|
||||||
* @param player <p>The player whose interaction triggered the sound</p>
|
* @param player <p>The player whose interaction triggered the sound</p>
|
||||||
* @param soundCategory <p>The category the sound is to play in</p>
|
* @param soundCategory <p>The category the sound is to play in</p>
|
||||||
* @param sound <p>The sound to play</p>
|
* @param sound <p>The sound to play</p>
|
||||||
* @param volume <p>The volume of the played sound</p>
|
* @param volume <p>The volume of the played sound</p>
|
||||||
* @param pitch <p>The pitch of the played sound</p>
|
* @param pitch <p>The pitch of the played sound</p>
|
||||||
*/
|
*/
|
||||||
public NPCSoundEvent(@NotNull NPC npc, @NotNull Player player, @NotNull SoundCategory soundCategory,
|
public NPCSoundEvent(@NotNull NPC npc, @NotNull Entity entity, @NotNull Player player, @NotNull SoundCategory soundCategory,
|
||||||
@NotNull Sound sound, float volume, float pitch) {
|
@NotNull Sound sound, float volume, float pitch) {
|
||||||
super(npc, player);
|
super(npc, entity, player);
|
||||||
this.soundCategory = soundCategory;
|
this.soundCategory = soundCategory;
|
||||||
this.sound = sound;
|
this.sound = sound;
|
||||||
this.volume = volume;
|
this.volume = volume;
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package net.knarcraft.blacksmith.event;
|
package net.knarcraft.blacksmith.event;
|
||||||
|
|
||||||
import net.citizensnpcs.api.npc.NPC;
|
import net.citizensnpcs.api.npc.NPC;
|
||||||
|
import org.bukkit.entity.Entity;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.event.HandlerList;
|
import org.bukkit.event.HandlerList;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
@ -16,10 +17,11 @@ public class ScrapperSalvageFailEvent extends AbstractBlacksmithPluginEvent impl
|
|||||||
* Instantiates a new scrapper salvage fail event
|
* Instantiates a new scrapper salvage fail event
|
||||||
*
|
*
|
||||||
* @param npc <p>The NPC involved in the event</p>
|
* @param npc <p>The NPC involved in the event</p>
|
||||||
|
* @param entity <p>The entity of the NPC</p>
|
||||||
* @param player <p>The player involved in the event</p>
|
* @param player <p>The player involved in the event</p>
|
||||||
*/
|
*/
|
||||||
public ScrapperSalvageFailEvent(@NotNull NPC npc, @NotNull Player player) {
|
public ScrapperSalvageFailEvent(@NotNull NPC npc, @NotNull Entity entity, @NotNull Player player) {
|
||||||
super(npc, player);
|
super(npc, entity, player);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -2,6 +2,7 @@ package net.knarcraft.blacksmith.event;
|
|||||||
|
|
||||||
import net.citizensnpcs.api.npc.NPC;
|
import net.citizensnpcs.api.npc.NPC;
|
||||||
import org.bukkit.Material;
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.entity.Entity;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.event.HandlerList;
|
import org.bukkit.event.HandlerList;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
@ -20,13 +21,14 @@ public class ScrapperSalvageStartEvent extends AbstractBlacksmithPluginEvent imp
|
|||||||
* Instantiates a new scrapper salvage start event
|
* Instantiates a new scrapper salvage start event
|
||||||
*
|
*
|
||||||
* @param npc <p>The NPC involved in the event</p>
|
* @param npc <p>The NPC involved in the event</p>
|
||||||
|
* @param entity <p>The entity of the NPC</p>
|
||||||
* @param player <p>The player involved in the event</p>
|
* @param player <p>The player involved in the event</p>
|
||||||
* @param durationTicks <p>The duration of the salvage</p>
|
* @param durationTicks <p>The duration of the salvage</p>
|
||||||
* @param craftingStation <p>The appropriate crafting station for this salvaging</p>
|
* @param craftingStation <p>The appropriate crafting station for this salvaging</p>
|
||||||
*/
|
*/
|
||||||
public ScrapperSalvageStartEvent(@NotNull NPC npc, @NotNull Player player, long durationTicks,
|
public ScrapperSalvageStartEvent(@NotNull NPC npc, @NotNull Entity entity, @NotNull Player player, long durationTicks,
|
||||||
@NotNull Material craftingStation) {
|
@NotNull Material craftingStation) {
|
||||||
super(npc, player);
|
super(npc, entity, player);
|
||||||
this.durationTicks = durationTicks;
|
this.durationTicks = durationTicks;
|
||||||
this.craftingStation = craftingStation;
|
this.craftingStation = craftingStation;
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package net.knarcraft.blacksmith.event;
|
package net.knarcraft.blacksmith.event;
|
||||||
|
|
||||||
import net.citizensnpcs.api.npc.NPC;
|
import net.citizensnpcs.api.npc.NPC;
|
||||||
|
import org.bukkit.entity.Entity;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.event.HandlerList;
|
import org.bukkit.event.HandlerList;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
@ -16,10 +17,11 @@ public class ScrapperSalvageSucceedEvent extends AbstractBlacksmithPluginEvent i
|
|||||||
* Instantiates a new scrapper salvage succeed event
|
* Instantiates a new scrapper salvage succeed event
|
||||||
*
|
*
|
||||||
* @param npc <p>The NPC involved in the event</p>
|
* @param npc <p>The NPC involved in the event</p>
|
||||||
|
* @param entity <p>The entity of the NPC</p>
|
||||||
* @param player <p>The player involved in the event</p>
|
* @param player <p>The player involved in the event</p>
|
||||||
*/
|
*/
|
||||||
public ScrapperSalvageSucceedEvent(@NotNull NPC npc, @NotNull Player player) {
|
public ScrapperSalvageSucceedEvent(@NotNull NPC npc, @NotNull Entity entity, @NotNull Player player) {
|
||||||
super(npc, player);
|
super(npc, entity, player);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -27,7 +27,8 @@ public final class BlacksmithStringFormatter {
|
|||||||
public static void sendNPCMessage(NPC npc, Player player, String message) {
|
public static void sendNPCMessage(NPC npc, Player player, String message) {
|
||||||
player.sendMessage(BlacksmithPlugin.getStringFormatter().replacePlaceholders(
|
player.sendMessage(BlacksmithPlugin.getStringFormatter().replacePlaceholders(
|
||||||
BlacksmithTranslatableMessage.NPC_TALK_FORMAT, List.of("{npc}", "{message}"),
|
BlacksmithTranslatableMessage.NPC_TALK_FORMAT, List.of("{npc}", "{message}"),
|
||||||
List.of(npc.getName(), ColorHelper.translateColorCodes(message, ColorConversion.RGB))));
|
List.of(ColorHelper.translateColorCodes(npc.getRawName(), ColorConversion.RGB),
|
||||||
|
ColorHelper.translateColorCodes(message, ColorConversion.RGB))));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -143,7 +143,12 @@ public enum BlacksmithTranslatableMessage implements TranslatableMessage {
|
|||||||
/**
|
/**
|
||||||
* The format to use for formatting any message spoken by a blacksmith NPC
|
* The format to use for formatting any message spoken by a blacksmith NPC
|
||||||
*/
|
*/
|
||||||
NPC_TALK_FORMAT;
|
NPC_TALK_FORMAT,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The text to display when explaining that a cost must be a positive double
|
||||||
|
*/
|
||||||
|
DOUBLE_COST_REQUIRED;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the message to display when displaying the raw value of messages
|
* Gets the message to display when displaying the raw value of messages
|
||||||
|
@ -5,7 +5,10 @@ import net.knarcraft.blacksmith.config.blacksmith.GlobalBlacksmithSettings;
|
|||||||
import net.knarcraft.blacksmith.config.scrapper.GlobalScrapperSettings;
|
import net.knarcraft.blacksmith.config.scrapper.GlobalScrapperSettings;
|
||||||
import net.knarcraft.blacksmith.property.SalvageMethod;
|
import net.knarcraft.blacksmith.property.SalvageMethod;
|
||||||
import net.knarcraft.blacksmith.util.ItemHelper;
|
import net.knarcraft.blacksmith.util.ItemHelper;
|
||||||
|
import net.knarcraft.knarlib.formatting.StringReplacer;
|
||||||
import net.milkbowl.vault.economy.Economy;
|
import net.milkbowl.vault.economy.Economy;
|
||||||
|
import net.objecthunter.exp4j.Expression;
|
||||||
|
import net.objecthunter.exp4j.ExpressionBuilder;
|
||||||
import org.bukkit.Material;
|
import org.bukkit.Material;
|
||||||
import org.bukkit.enchantments.Enchantment;
|
import org.bukkit.enchantments.Enchantment;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
@ -54,10 +57,12 @@ public class EconomyManager {
|
|||||||
*
|
*
|
||||||
* @param player <p>The player holding an item</p>
|
* @param player <p>The player holding an item</p>
|
||||||
* @param salvageMethod <p>The salvage method to check</p>
|
* @param salvageMethod <p>The salvage method to check</p>
|
||||||
|
* @param item <p>The item to be salvaged</p>
|
||||||
* @return <p>Whether the player cannot pay for the salvage</p>
|
* @return <p>Whether the player cannot pay for the salvage</p>
|
||||||
*/
|
*/
|
||||||
public static boolean cannotPayForSalvage(@NotNull Player player, @NotNull SalvageMethod salvageMethod) {
|
public static boolean cannotPayForSalvage(@NotNull Player player, @NotNull SalvageMethod salvageMethod, @NotNull ItemStack item) {
|
||||||
return economy.getBalance(player) - getSalvageCost(salvageMethod) < 0;
|
// TODO: Account for advanced cost options
|
||||||
|
return economy.getBalance(player) - getSalvageCost(salvageMethod, item, player) < 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -76,26 +81,61 @@ public class EconomyManager {
|
|||||||
* Gets the human-readable cost of salvaging an item
|
* Gets the human-readable cost of salvaging an item
|
||||||
*
|
*
|
||||||
* @param salvageMethod <p>The salvage method to get the cost for</p>
|
* @param salvageMethod <p>The salvage method to get the cost for</p>
|
||||||
|
* @param item <p>The item to be salvaged</p>
|
||||||
|
* @param player <p>The player to provide the cost to</p>
|
||||||
* @return <p>The formatted cost</p>
|
* @return <p>The formatted cost</p>
|
||||||
*/
|
*/
|
||||||
@NotNull
|
@NotNull
|
||||||
public static String formatSalvageCost(@NotNull SalvageMethod salvageMethod) {
|
public static String formatSalvageCost(@NotNull SalvageMethod salvageMethod, @NotNull ItemStack item,
|
||||||
return economy.format(getSalvageCost(salvageMethod));
|
@NotNull Player player) {
|
||||||
|
return economy.format(getSalvageCost(salvageMethod, item, player));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets whether the given player has enough money to pay the given cost
|
||||||
|
*
|
||||||
|
* @param player <p>The player to check</p>
|
||||||
|
* @param cost <p>The required cost</p>
|
||||||
|
* @return <p>True if the player has enough money to cover the cost</p>
|
||||||
|
*/
|
||||||
|
public static boolean hasEnough(@NotNull Player player, double cost) {
|
||||||
|
return economy.getBalance(player) >= cost;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Formats a number as an economy cost
|
||||||
|
*
|
||||||
|
* @param cost <p>The cost to format</p>
|
||||||
|
* @return <p>The formatted cost</p>
|
||||||
|
*/
|
||||||
|
@NotNull
|
||||||
|
public static String format(double cost) {
|
||||||
|
return economy.format(cost);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the cost of salvaging using the specified method
|
* Gets the cost of salvaging using the specified method
|
||||||
*
|
*
|
||||||
* @param salvageMethod <p>The salvage method to get cost for</p>
|
* @param salvageMethod <p>The salvage method to get cost for</p>
|
||||||
|
* @param item <p>The item to be salvaged</p>
|
||||||
* @return <p>The salvage cost</p>
|
* @return <p>The salvage cost</p>
|
||||||
*/
|
*/
|
||||||
private static double getSalvageCost(@NotNull SalvageMethod salvageMethod) {
|
private static double getSalvageCost(@NotNull SalvageMethod salvageMethod, @NotNull ItemStack item,
|
||||||
|
@NotNull Player player) {
|
||||||
GlobalScrapperSettings settings = BlacksmithPlugin.getInstance().getGlobalScrapperSettings();
|
GlobalScrapperSettings settings = BlacksmithPlugin.getInstance().getGlobalScrapperSettings();
|
||||||
return switch (salvageMethod) {
|
double baseCost = switch (salvageMethod) {
|
||||||
case SALVAGE, EXTENDED_SALVAGE -> settings.getSalvageCost();
|
case SALVAGE, EXTENDED_SALVAGE -> settings.getSalvageCost();
|
||||||
case NETHERITE -> settings.getNetheriteSalvageCost();
|
case NETHERITE -> settings.getNetheriteSalvageCost();
|
||||||
case ARMOR_TRIM -> settings.getArmorTrimSalvageCost();
|
case ARMOR_TRIM -> settings.getArmorTrimSalvageCost();
|
||||||
|
case ENCHANTED_BOOK -> getEnchantedBookSalvageCost(item);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
StringReplacer replacer = new StringReplacer(settings.getSalvageCostIncrease());
|
||||||
|
replacer.add("{cost}", String.valueOf(baseCost));
|
||||||
|
replacer.add("{timesUsed}", String.valueOf(PlayerUsageManager.getUsages(player,
|
||||||
|
System.currentTimeMillis() - 3600000)));
|
||||||
|
Expression expression = new ExpressionBuilder(replacer.replace()).build();
|
||||||
|
return Math.max(expression.evaluate(), baseCost);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -119,12 +159,26 @@ public class EconomyManager {
|
|||||||
* @param salvageMethod <p>The salvage method to withdraw for</p>
|
* @param salvageMethod <p>The salvage method to withdraw for</p>
|
||||||
*/
|
*/
|
||||||
public static void withdrawScrapper(@NotNull Player player, @NotNull SalvageMethod salvageMethod) {
|
public static void withdrawScrapper(@NotNull Player player, @NotNull SalvageMethod salvageMethod) {
|
||||||
double cost = getSalvageCost(salvageMethod);
|
double cost = getSalvageCost(salvageMethod, player.getInventory().getItemInMainHand(), player);
|
||||||
if (cost > 0) {
|
if (cost > 0) {
|
||||||
economy.withdrawPlayer(player, cost);
|
economy.withdrawPlayer(player, cost);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Withdraws money from a player
|
||||||
|
*
|
||||||
|
* @param player <p>The player to withdraw from</p>
|
||||||
|
* @param monetaryCost <p>The cost to withdraw</p>
|
||||||
|
* @throws IllegalArgumentException <p>If a negative cost is given</p>
|
||||||
|
*/
|
||||||
|
public static void withdraw(@NotNull Player player, double monetaryCost) {
|
||||||
|
if (monetaryCost < 0) {
|
||||||
|
throw new IllegalArgumentException("Cannot withdraw a negative amount");
|
||||||
|
}
|
||||||
|
economy.withdrawPlayer(player, monetaryCost);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the cost of the item in the given player's main hand
|
* Gets the cost of the item in the given player's main hand
|
||||||
*
|
*
|
||||||
@ -183,6 +237,24 @@ public class EconomyManager {
|
|||||||
return price;
|
return price;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the cost of scrapping an enchanted book
|
||||||
|
*
|
||||||
|
* @param item <p>The enchanted book to calculate cost for</p>
|
||||||
|
* @return <p>The cost of scrapping the enchanted book</p>
|
||||||
|
*/
|
||||||
|
private static double getEnchantedBookSalvageCost(@NotNull ItemStack item) {
|
||||||
|
// TODO: Properly implement this
|
||||||
|
/*GlobalScrapperSettings settings = BlacksmithPlugin.getInstance().getGlobalScrapperSettings();
|
||||||
|
|
||||||
|
double cost = settings.getEnchantedBookSalvageCost();
|
||||||
|
if (settings.multiplyEnchantedBookSalvageCost()) {
|
||||||
|
cost *= SalvageHelper.getEnchantmentCount(item) - 1;
|
||||||
|
}
|
||||||
|
return SalvageHelper.getEnchantmentCount(item) * cost;*/
|
||||||
|
return 1000000;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets up Vault for economy
|
* Sets up Vault for economy
|
||||||
*
|
*
|
||||||
|
@ -0,0 +1,75 @@
|
|||||||
|
package net.knarcraft.blacksmith.manager;
|
||||||
|
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A manager for keeping track of players using scrappers
|
||||||
|
*/
|
||||||
|
public class PlayerUsageManager {
|
||||||
|
|
||||||
|
private static final Map<Player, Set<Long>> playerUsages = new HashMap<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register that a player has used a scrapper
|
||||||
|
*
|
||||||
|
* @param player <p>The player using a scrapper</p>
|
||||||
|
*/
|
||||||
|
public static void registerUsage(@NotNull Player player) {
|
||||||
|
playerUsages.putIfAbsent(player, new HashSet<>());
|
||||||
|
Set<Long> usages = playerUsages.get(player);
|
||||||
|
usages.add(System.currentTimeMillis());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets how many times the given player has used a scrapper after the given timestamp
|
||||||
|
*
|
||||||
|
* @param player <p>The player to check usages for</p>
|
||||||
|
* @param afterTimestamp <p>The timestamp of when to start looking for usages</p>
|
||||||
|
* @return <p>The number of scrapper uses for the given player</p>
|
||||||
|
*/
|
||||||
|
public static int getUsages(@NotNull Player player, @NotNull Long afterTimestamp) {
|
||||||
|
Set<Long> usages = playerUsages.get(player);
|
||||||
|
if (usages == null) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int uses = 0;
|
||||||
|
Set<Long> expired = new HashSet<>();
|
||||||
|
for (Long usageTime : usages) {
|
||||||
|
if (usageTime < afterTimestamp) {
|
||||||
|
expired.add(usageTime);
|
||||||
|
} else {
|
||||||
|
uses++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove expired data
|
||||||
|
usages.removeAll(expired);
|
||||||
|
|
||||||
|
return uses;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes all expired timestamps
|
||||||
|
*
|
||||||
|
* @param afterTimestamp <p>The timestamp for the earliest time of valid timestamps</p>
|
||||||
|
*/
|
||||||
|
public static void removeExpiredData(@NotNull Long afterTimestamp) {
|
||||||
|
for (Set<Long> usageSet : playerUsages.values()) {
|
||||||
|
Set<Long> expired = new HashSet<>();
|
||||||
|
for (Long item : usageSet) {
|
||||||
|
if (item < afterTimestamp) {
|
||||||
|
expired.add(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
usageSet.removeAll(expired);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -25,4 +25,9 @@ public enum SalvageMethod {
|
|||||||
*/
|
*/
|
||||||
NETHERITE,
|
NETHERITE,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Splitting enchantments of an enchanted book
|
||||||
|
*/
|
||||||
|
ENCHANTED_BOOK,
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -94,7 +94,12 @@ public class BlacksmithTrait extends CustomTrait<BlacksmithSetting> {
|
|||||||
|
|
||||||
//Start a new reforge session for the player
|
//Start a new reforge session for the player
|
||||||
currentSessionStartTime = System.currentTimeMillis();
|
currentSessionStartTime = System.currentTimeMillis();
|
||||||
|
try {
|
||||||
session = new ReforgeSession(this, player, npc, config);
|
session = new ReforgeSession(this, player, npc, config);
|
||||||
|
} catch (IllegalArgumentException exception) {
|
||||||
|
BlacksmithPlugin.error(exception.getMessage());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
//Tell the player the cost of repairing the item
|
//Tell the player the cost of repairing the item
|
||||||
String cost = EconomyManager.formatBlacksmithCost(player);
|
String cost = EconomyManager.formatBlacksmithCost(player);
|
||||||
|
@ -2,14 +2,17 @@ package net.knarcraft.blacksmith.trait;
|
|||||||
|
|
||||||
import net.citizensnpcs.api.npc.NPC;
|
import net.citizensnpcs.api.npc.NPC;
|
||||||
import net.citizensnpcs.api.trait.Trait;
|
import net.citizensnpcs.api.trait.Trait;
|
||||||
|
import net.knarcraft.blacksmith.BlacksmithPlugin;
|
||||||
import net.knarcraft.blacksmith.config.Setting;
|
import net.knarcraft.blacksmith.config.Setting;
|
||||||
import net.knarcraft.blacksmith.config.Settings;
|
import net.knarcraft.blacksmith.config.Settings;
|
||||||
import net.knarcraft.blacksmith.config.TraitSettings;
|
import net.knarcraft.blacksmith.config.TraitSettings;
|
||||||
import net.knarcraft.blacksmith.formatting.TimeFormatter;
|
import net.knarcraft.blacksmith.formatting.TimeFormatter;
|
||||||
import net.knarcraft.blacksmith.manager.EconomyManager;
|
import net.knarcraft.blacksmith.manager.EconomyManager;
|
||||||
import net.knarcraft.knarlib.formatting.StringFormatter;
|
import net.knarcraft.knarlib.formatting.StringFormatter;
|
||||||
|
import org.bukkit.entity.Entity;
|
||||||
import org.bukkit.entity.LivingEntity;
|
import org.bukkit.entity.LivingEntity;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.inventory.EntityEquipment;
|
||||||
import org.bukkit.inventory.ItemStack;
|
import org.bukkit.inventory.ItemStack;
|
||||||
import org.bukkit.inventory.PlayerInventory;
|
import org.bukkit.inventory.PlayerInventory;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
@ -18,7 +21,6 @@ import org.jetbrains.annotations.Nullable;
|
|||||||
import java.util.Calendar;
|
import java.util.Calendar;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
import static net.knarcraft.blacksmith.formatting.BlacksmithStringFormatter.sendNPCMessage;
|
import static net.knarcraft.blacksmith.formatting.BlacksmithStringFormatter.sendNPCMessage;
|
||||||
@ -153,8 +155,13 @@ public abstract class CustomTrait<K extends Setting> extends Trait {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//If already in a session, but the player has failed to interact, and left the blacksmith, allow a new session
|
//If already in a session, but the player has failed to interact, and left the blacksmith, allow a new session
|
||||||
|
Entity entity = npc.getEntity();
|
||||||
|
if (entity == null) {
|
||||||
|
BlacksmithPlugin.error("NPC session could not be started, as the NPC does not have a valid entity");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
if (session != null && !session.isRunning() && (System.currentTimeMillis() > currentSessionStartTime + 10 * 1000 ||
|
if (session != null && !session.isRunning() && (System.currentTimeMillis() > currentSessionStartTime + 10 * 1000 ||
|
||||||
this.npc.getEntity().getLocation().distance(session.getPlayer().getLocation()) > 20)) {
|
entity.getLocation().distance(session.getPlayer().getLocation()) > 20)) {
|
||||||
session = null;
|
session = null;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@ -183,16 +190,21 @@ public abstract class CustomTrait<K extends Setting> extends Trait {
|
|||||||
} else if (this.session instanceof SalvageSession salvageSession) {
|
} else if (this.session instanceof SalvageSession salvageSession) {
|
||||||
EconomyManager.withdrawScrapper(player, salvageSession.salvageMethod);
|
EconomyManager.withdrawScrapper(player, salvageSession.salvageMethod);
|
||||||
}
|
}
|
||||||
|
|
||||||
session.scheduleAction();
|
|
||||||
PlayerInventory playerInventory = player.getInventory();
|
PlayerInventory playerInventory = player.getInventory();
|
||||||
ItemStack heldItem = player.getInventory().getItemInMainHand();
|
ItemStack heldItem = player.getInventory().getItemInMainHand();
|
||||||
|
session.scheduleAction();
|
||||||
|
|
||||||
//Display the item in the NPC's hand
|
//Display the item in the NPC's hand
|
||||||
if (npc.getEntity() instanceof Player) {
|
Entity entity = npc.getEntity();
|
||||||
((Player) npc.getEntity()).getInventory().setItemInMainHand(heldItem);
|
if (entity instanceof Player playerNPC) {
|
||||||
|
playerNPC.getInventory().setItemInMainHand(heldItem);
|
||||||
|
} else if (entity instanceof LivingEntity) {
|
||||||
|
EntityEquipment equipment = ((LivingEntity) entity).getEquipment();
|
||||||
|
if (equipment != null) {
|
||||||
|
((LivingEntity) entity).getEquipment().setItemInMainHand(heldItem);
|
||||||
} else {
|
} else {
|
||||||
Objects.requireNonNull(((LivingEntity) npc.getEntity()).getEquipment()).setItemInMainHand(heldItem);
|
BlacksmithPlugin.warn("Failed to update NPC item, as its equipment was irretrievable.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
//Remove the item from the player's inventory
|
//Remove the item from the player's inventory
|
||||||
if (this.session instanceof SalvageSession salvageSession) {
|
if (this.session instanceof SalvageSession salvageSession) {
|
||||||
|
@ -15,13 +15,13 @@ import org.bukkit.Sound;
|
|||||||
import org.bukkit.enchantments.Enchantment;
|
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.EntityEquipment;
|
||||||
import org.bukkit.inventory.ItemStack;
|
import org.bukkit.inventory.ItemStack;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Calendar;
|
import java.util.Calendar;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
|
|
||||||
import static net.knarcraft.blacksmith.formatting.BlacksmithStringFormatter.sendNPCMessage;
|
import static net.knarcraft.blacksmith.formatting.BlacksmithStringFormatter.sendNPCMessage;
|
||||||
@ -107,10 +107,15 @@ public class ReforgeSession extends Session implements Runnable {
|
|||||||
playSound(success ? Sound.BLOCK_ANVIL_USE : Sound.ENTITY_VILLAGER_NO);
|
playSound(success ? Sound.BLOCK_ANVIL_USE : Sound.ENTITY_VILLAGER_NO);
|
||||||
|
|
||||||
//Stop the reforged item from displaying in the blacksmith's hand
|
//Stop the reforged item from displaying in the blacksmith's hand
|
||||||
if (this.npc.getEntity() instanceof Player) {
|
if (this.entity instanceof Player playerNPC) {
|
||||||
((Player) this.npc.getEntity()).getInventory().setItemInMainHand(null);
|
playerNPC.getInventory().setItemInMainHand(null);
|
||||||
|
} else if (this.entity instanceof LivingEntity) {
|
||||||
|
EntityEquipment equipment = ((LivingEntity) this.entity).getEquipment();
|
||||||
|
if (equipment != null) {
|
||||||
|
equipment.setItemInMainHand(null);
|
||||||
} else {
|
} else {
|
||||||
Objects.requireNonNull(((LivingEntity) this.npc.getEntity()).getEquipment()).setItemInMainHand(null);
|
BlacksmithPlugin.warn("Failed to clear Blacksmith item, as its equipment was irretrievable.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//Give the item back to the player
|
//Give the item back to the player
|
||||||
@ -129,8 +134,7 @@ public class ReforgeSession extends Session implements Runnable {
|
|||||||
* Gives the reforged item back to the player
|
* Gives the reforged item back to the player
|
||||||
*/
|
*/
|
||||||
private void giveReforgedItem() {
|
private void giveReforgedItem() {
|
||||||
giveResultingItem(this.config.getMaxReforgeDelay() > 0, this.config.getDropItem(), this.npc,
|
giveResultingItem(this.config.getMaxReforgeDelay() > 0, this.config.getDropItem(), this.itemToReforge);
|
||||||
this.itemToReforge);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -141,11 +145,11 @@ public class ReforgeSession extends Session implements Runnable {
|
|||||||
private boolean reforgeItem() {
|
private boolean reforgeItem() {
|
||||||
if (random.nextInt(100) < this.config.getFailChance()) {
|
if (random.nextInt(100) < this.config.getFailChance()) {
|
||||||
failReforge();
|
failReforge();
|
||||||
BlacksmithPlugin.getInstance().callEvent(new BlacksmithReforgeFailEvent(this.npc, this.player));
|
BlacksmithPlugin.getInstance().callEvent(new BlacksmithReforgeFailEvent(this.npc, this.entity, this.player));
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
succeedReforge();
|
succeedReforge();
|
||||||
BlacksmithPlugin.getInstance().callEvent(new BlacksmithReforgeSucceedEvent(this.npc, this.player));
|
BlacksmithPlugin.getInstance().callEvent(new BlacksmithReforgeSucceedEvent(this.npc, this.entity, this.player));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,20 +6,24 @@ import net.knarcraft.blacksmith.config.scrapper.ScrapperNPCSettings;
|
|||||||
import net.knarcraft.blacksmith.event.ScrapperSalvageFailEvent;
|
import net.knarcraft.blacksmith.event.ScrapperSalvageFailEvent;
|
||||||
import net.knarcraft.blacksmith.event.ScrapperSalvageSucceedEvent;
|
import net.knarcraft.blacksmith.event.ScrapperSalvageSucceedEvent;
|
||||||
import net.knarcraft.blacksmith.manager.EconomyManager;
|
import net.knarcraft.blacksmith.manager.EconomyManager;
|
||||||
|
import net.knarcraft.blacksmith.manager.PlayerUsageManager;
|
||||||
import net.knarcraft.blacksmith.property.SalvageMethod;
|
import net.knarcraft.blacksmith.property.SalvageMethod;
|
||||||
import net.knarcraft.blacksmith.util.ItemHelper;
|
import net.knarcraft.blacksmith.util.ItemHelper;
|
||||||
import net.knarcraft.blacksmith.util.SalvageHelper;
|
import net.knarcraft.blacksmith.util.SalvageHelper;
|
||||||
|
import net.knarcraft.knarlib.formatting.StringReplacer;
|
||||||
|
import net.objecthunter.exp4j.Expression;
|
||||||
|
import net.objecthunter.exp4j.ExpressionBuilder;
|
||||||
import org.bukkit.Material;
|
import org.bukkit.Material;
|
||||||
import org.bukkit.Sound;
|
import org.bukkit.Sound;
|
||||||
import org.bukkit.entity.LivingEntity;
|
import org.bukkit.entity.LivingEntity;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.inventory.EntityEquipment;
|
||||||
import org.bukkit.inventory.ItemStack;
|
import org.bukkit.inventory.ItemStack;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Calendar;
|
import java.util.Calendar;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
|
|
||||||
import static net.knarcraft.blacksmith.formatting.BlacksmithStringFormatter.sendNPCMessage;
|
import static net.knarcraft.blacksmith.formatting.BlacksmithStringFormatter.sendNPCMessage;
|
||||||
@ -70,7 +74,9 @@ public class SalvageSession extends Session implements Runnable {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (EconomyManager.cannotPayForSalvage(this.player, this.salvageMethod)) {
|
// TODO: Check item cost. If
|
||||||
|
|
||||||
|
if (EconomyManager.cannotPayForSalvage(this.player, this.salvageMethod, this.itemToSalvage)) {
|
||||||
sendNPCMessage(this.npc, this.player, this.config.getInsufficientFundsMessage());
|
sendNPCMessage(this.npc, this.player, this.config.getInsufficientFundsMessage());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -94,6 +100,7 @@ public class SalvageSession extends Session implements Runnable {
|
|||||||
case EXTENDED_SALVAGE -> Material.CRAFTING_TABLE;
|
case EXTENDED_SALVAGE -> Material.CRAFTING_TABLE;
|
||||||
case SALVAGE -> Material.ANVIL;
|
case SALVAGE -> Material.ANVIL;
|
||||||
case NETHERITE, ARMOR_TRIM -> Material.SMITHING_TABLE;
|
case NETHERITE, ARMOR_TRIM -> Material.SMITHING_TABLE;
|
||||||
|
case ENCHANTED_BOOK -> Material.ENCHANTING_TABLE;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -105,10 +112,15 @@ public class SalvageSession extends Session implements Runnable {
|
|||||||
salvageItem();
|
salvageItem();
|
||||||
|
|
||||||
//Stop the reforged item from displaying in the scrapper's hand
|
//Stop the reforged item from displaying in the scrapper's hand
|
||||||
if (this.npc.getEntity() instanceof Player) {
|
if (this.entity instanceof Player playerNPC) {
|
||||||
((Player) this.npc.getEntity()).getInventory().setItemInMainHand(null);
|
playerNPC.getInventory().setItemInMainHand(null);
|
||||||
|
} else if (this.entity instanceof LivingEntity) {
|
||||||
|
EntityEquipment equipment = ((LivingEntity) this.entity).getEquipment();
|
||||||
|
if (equipment != null) {
|
||||||
|
equipment.setItemInMainHand(null);
|
||||||
} else {
|
} else {
|
||||||
Objects.requireNonNull(((LivingEntity) this.npc.getEntity()).getEquipment()).setItemInMainHand(null);
|
BlacksmithPlugin.warn("Failed to clear Scrapper item, as its equipment was irretrievable.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//Mark this scrapper as available
|
//Mark this scrapper as available
|
||||||
@ -116,8 +128,14 @@ public class SalvageSession extends Session implements Runnable {
|
|||||||
|
|
||||||
// Start cool-down
|
// Start cool-down
|
||||||
Calendar wait = Calendar.getInstance();
|
Calendar wait = Calendar.getInstance();
|
||||||
wait.add(Calendar.SECOND, this.config.getSalvageCoolDown());
|
StringReplacer replacer = new StringReplacer(BlacksmithPlugin.getInstance().getGlobalScrapperSettings().getSalvageCooldownIncrease());
|
||||||
|
replacer.add("{cooldown}", String.valueOf(this.config.getSalvageCoolDown()));
|
||||||
|
replacer.add("{timesUsed}", String.valueOf(PlayerUsageManager.getUsages(player, System.currentTimeMillis() - 3600000)));
|
||||||
|
Expression expression = new ExpressionBuilder(replacer.replace()).build();
|
||||||
|
|
||||||
|
wait.add(Calendar.SECOND, Math.max((int) expression.evaluate(), this.config.getSalvageCoolDown()));
|
||||||
this.scrapperTrait.addCoolDown(this.player.getUniqueId(), wait);
|
this.scrapperTrait.addCoolDown(this.player.getUniqueId(), wait);
|
||||||
|
PlayerUsageManager.registerUsage(this.player);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -136,11 +154,11 @@ public class SalvageSession extends Session implements Runnable {
|
|||||||
if (random.nextInt(100) < this.config.getFailChance()) {
|
if (random.nextInt(100) < this.config.getFailChance()) {
|
||||||
playSound(Sound.ENTITY_VILLAGER_NO);
|
playSound(Sound.ENTITY_VILLAGER_NO);
|
||||||
failSalvage();
|
failSalvage();
|
||||||
BlacksmithPlugin.getInstance().callEvent(new ScrapperSalvageFailEvent(this.npc, this.player));
|
BlacksmithPlugin.getInstance().callEvent(new ScrapperSalvageFailEvent(this.npc, this.entity, this.player));
|
||||||
} else {
|
} else {
|
||||||
playSound(Sound.BLOCK_ANVIL_USE);
|
playSound(Sound.BLOCK_ANVIL_USE);
|
||||||
giveSalvage();
|
giveSalvage();
|
||||||
BlacksmithPlugin.getInstance().callEvent(new ScrapperSalvageSucceedEvent(this.npc, this.player));
|
BlacksmithPlugin.getInstance().callEvent(new ScrapperSalvageSucceedEvent(this.npc, this.entity, this.player));
|
||||||
sendNPCMessage(this.npc, this.player, this.config.getSuccessMessage());
|
sendNPCMessage(this.npc, this.player, this.config.getSuccessMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -155,14 +173,13 @@ public class SalvageSession extends Session implements Runnable {
|
|||||||
if (ItemHelper.getMaxDurability(this.itemToSalvage) > 0) {
|
if (ItemHelper.getMaxDurability(this.itemToSalvage) > 0) {
|
||||||
//Damage the item if possible
|
//Damage the item if possible
|
||||||
damageItemRandomly(this.itemToSalvage);
|
damageItemRandomly(this.itemToSalvage);
|
||||||
giveResultingItem(this.config.getMaxSalvageDelay() > 0, this.config.getDropItem(), this.npc,
|
giveResultingItem(this.config.getMaxSalvageDelay() > 0, this.config.getDropItem(), this.itemToSalvage);
|
||||||
this.itemToSalvage);
|
|
||||||
sendNPCMessage(this.npc, this.player, this.config.getFailSalvageMessage());
|
sendNPCMessage(this.npc, this.player, this.config.getFailSalvageMessage());
|
||||||
} else {
|
} else {
|
||||||
// Give half the salvage
|
// Give half the salvage
|
||||||
List<ItemStack> halfSalvage = SalvageHelper.pickRandomSalvage(this.salvage, new ArrayList<>(), 0.5);
|
List<ItemStack> halfSalvage = SalvageHelper.pickRandomSalvage(this.salvage, new ArrayList<>(), 0.5);
|
||||||
for (ItemStack item : halfSalvage) {
|
for (ItemStack item : halfSalvage) {
|
||||||
giveResultingItem(this.config.getMaxSalvageDelay() > 0, this.config.getDropItem(), this.npc, item);
|
giveResultingItem(this.config.getMaxSalvageDelay() > 0, this.config.getDropItem(), item);
|
||||||
}
|
}
|
||||||
sendNPCMessage(this.npc, this.player, this.config.getFailExtendedSalvageMessage());
|
sendNPCMessage(this.npc, this.player, this.config.getFailExtendedSalvageMessage());
|
||||||
}
|
}
|
||||||
@ -177,7 +194,7 @@ public class SalvageSession extends Session implements Runnable {
|
|||||||
this.player.giveExpLevels(this.enchantmentLevels);
|
this.player.giveExpLevels(this.enchantmentLevels);
|
||||||
BlacksmithPlugin.debug("Giving salvage " + this.salvage);
|
BlacksmithPlugin.debug("Giving salvage " + this.salvage);
|
||||||
for (ItemStack item : this.salvage) {
|
for (ItemStack item : this.salvage) {
|
||||||
giveResultingItem(this.config.getMaxSalvageDelay() > 0, this.config.getDropItem(), this.npc, item);
|
giveResultingItem(this.config.getMaxSalvageDelay() > 0, this.config.getDropItem(), item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,6 +4,7 @@ import net.citizensnpcs.api.util.DataKey;
|
|||||||
import net.knarcraft.blacksmith.BlacksmithPlugin;
|
import net.knarcraft.blacksmith.BlacksmithPlugin;
|
||||||
import net.knarcraft.blacksmith.config.SmithPreset;
|
import net.knarcraft.blacksmith.config.SmithPreset;
|
||||||
import net.knarcraft.blacksmith.config.SmithPresetFilter;
|
import net.knarcraft.blacksmith.config.SmithPresetFilter;
|
||||||
|
import net.knarcraft.blacksmith.config.scrapper.GlobalScrapperSettings;
|
||||||
import net.knarcraft.blacksmith.config.scrapper.ScrapperNPCSettings;
|
import net.knarcraft.blacksmith.config.scrapper.ScrapperNPCSettings;
|
||||||
import net.knarcraft.blacksmith.config.scrapper.ScrapperSetting;
|
import net.knarcraft.blacksmith.config.scrapper.ScrapperSetting;
|
||||||
import net.knarcraft.blacksmith.container.RecipeResult;
|
import net.knarcraft.blacksmith.container.RecipeResult;
|
||||||
@ -20,6 +21,7 @@ import org.bukkit.Material;
|
|||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.inventory.ItemStack;
|
import org.bukkit.inventory.ItemStack;
|
||||||
import org.bukkit.inventory.meta.ArmorMeta;
|
import org.bukkit.inventory.meta.ArmorMeta;
|
||||||
|
import org.bukkit.inventory.meta.EnchantmentStorageMeta;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
@ -109,10 +111,15 @@ public class ScrapperTrait extends CustomTrait<ScrapperSetting> {
|
|||||||
|
|
||||||
//Start a new scrapper session for the player
|
//Start a new scrapper session for the player
|
||||||
currentSessionStartTime = System.currentTimeMillis();
|
currentSessionStartTime = System.currentTimeMillis();
|
||||||
|
try {
|
||||||
session = new SalvageSession(this, player, npc, getSettings(), result.salvage(),
|
session = new SalvageSession(this, player, npc, getSettings(), result.salvage(),
|
||||||
result.salvageMethod(), result.requiredAmount());
|
result.salvageMethod(), result.requiredAmount());
|
||||||
|
} catch (IllegalArgumentException exception) {
|
||||||
|
BlacksmithPlugin.error(exception.getMessage());
|
||||||
|
return;
|
||||||
|
}
|
||||||
// Print the cost to the player
|
// Print the cost to the player
|
||||||
printCostMessage(player, itemInHand, EconomyManager.formatSalvageCost(result.salvageMethod()),
|
printCostMessage(player, itemInHand, EconomyManager.formatSalvageCost(result.salvageMethod(), itemInHand, player),
|
||||||
result.salvageMethod());
|
result.salvageMethod());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -140,6 +147,13 @@ public class ScrapperTrait extends CustomTrait<ScrapperSetting> {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
result = isEnchantedBookSalvage(player, itemInHand);
|
||||||
|
if (result.salvageState() == SalvageState.NO_SALVAGE) {
|
||||||
|
return null;
|
||||||
|
} else if (result.salvageState() == SalvageState.FOUND_SALVAGE) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
result = isNormalSalvage(player, itemInHand, extended);
|
result = isNormalSalvage(player, itemInHand, extended);
|
||||||
if (result.salvageState() == SalvageState.NO_SALVAGE) {
|
if (result.salvageState() == SalvageState.NO_SALVAGE) {
|
||||||
return null;
|
return null;
|
||||||
@ -169,7 +183,7 @@ public class ScrapperTrait extends CustomTrait<ScrapperSetting> {
|
|||||||
return new SalvageResult(SalvageMethod.SALVAGE, new ArrayList<>(), SalvageState.NO_SALVAGE, 0);
|
return new SalvageResult(SalvageMethod.SALVAGE, new ArrayList<>(), SalvageState.NO_SALVAGE, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if the item is enchanted, and whether this blacksmith can salvage it
|
// Check if the item is enchanted, and whether this scrapper can salvage it
|
||||||
if (!itemInHand.getEnchantments().isEmpty() && !getSettings().salvageEnchanted()) {
|
if (!itemInHand.getEnchantments().isEmpty() && !getSettings().salvageEnchanted()) {
|
||||||
sendNPCMessage(this.npc, player, getSettings().getCannotSalvageEnchantedMessage());
|
sendNPCMessage(this.npc, player, getSettings().getCannotSalvageEnchantedMessage());
|
||||||
return new SalvageResult(SalvageMethod.SALVAGE, new ArrayList<>(), SalvageState.NO_SALVAGE, 0);
|
return new SalvageResult(SalvageMethod.SALVAGE, new ArrayList<>(), SalvageState.NO_SALVAGE, 0);
|
||||||
@ -188,6 +202,37 @@ public class ScrapperTrait extends CustomTrait<ScrapperSetting> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the result of trying to salvage the item as an enchanted book
|
||||||
|
*
|
||||||
|
* @param player <p>The player trying to salvage the item</p>
|
||||||
|
* @param itemInHand <p>The item to be salvaged</p>
|
||||||
|
* @return <p>The result of attempting the salvage</p>
|
||||||
|
*/
|
||||||
|
private SalvageResult isEnchantedBookSalvage(@NotNull Player player, @NotNull ItemStack itemInHand) {
|
||||||
|
if (itemInHand.getType() != Material.ENCHANTED_BOOK ||
|
||||||
|
!(itemInHand.getItemMeta() instanceof EnchantmentStorageMeta)) {
|
||||||
|
return new SalvageResult(SalvageMethod.ENCHANTED_BOOK, new ArrayList<>(), SalvageState.INCORRECT_METHOD, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!getSettings().splitEnchantedBook()) {
|
||||||
|
sendNPCMessage(this.npc, player, getSettings().getCannotSalvageEnchantedBookMessage());
|
||||||
|
return new SalvageResult(SalvageMethod.ENCHANTED_BOOK, new ArrayList<>(), SalvageState.NO_SALVAGE, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SalvageHelper.getEnchantmentCount(itemInHand) <= 1) {
|
||||||
|
sendNPCMessage(this.npc, player, getSettings().getCannotSplitEnchantedBookFurtherMessage());
|
||||||
|
return new SalvageResult(SalvageMethod.ENCHANTED_BOOK, new ArrayList<>(), SalvageState.NO_SALVAGE, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
List<ItemStack> salvage = SalvageHelper.getEnchantedBookSalvage(itemInHand);
|
||||||
|
boolean noUsefulSalvage = salvage == null || salvage.isEmpty();
|
||||||
|
if (noUsefulSalvage) {
|
||||||
|
return new SalvageResult(SalvageMethod.ENCHANTED_BOOK, new ArrayList<>(), SalvageState.NO_SALVAGE, 0);
|
||||||
|
}
|
||||||
|
return new SalvageResult(SalvageMethod.ENCHANTED_BOOK, salvage, SalvageState.FOUND_SALVAGE, 1);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the result of trying to salvage the item as a netherite applied item
|
* Gets the result of trying to salvage the item as a netherite applied item
|
||||||
*
|
*
|
||||||
@ -267,11 +312,32 @@ public class ScrapperTrait extends CustomTrait<ScrapperSetting> {
|
|||||||
sendNPCMessage(this.npc, player, replacer.replace(getSettings().getCostMessage()));
|
sendNPCMessage(this.npc, player, replacer.replace(getSettings().getCostMessage()));
|
||||||
} else if (salvageMethod == SalvageMethod.NETHERITE) {
|
} else if (salvageMethod == SalvageMethod.NETHERITE) {
|
||||||
sendNPCMessage(this.npc, player, replacer.replace(getSettings().getNetheriteCostMessage()));
|
sendNPCMessage(this.npc, player, replacer.replace(getSettings().getNetheriteCostMessage()));
|
||||||
|
} else if (salvageMethod == SalvageMethod.ENCHANTED_BOOK) {
|
||||||
|
StringReplacer replacer2 = new StringReplacer();
|
||||||
|
replacer2.add("{cost}", getEnchantedBookCost());
|
||||||
|
sendNPCMessage(this.npc, player, replacer2.replace(getSettings().getEnchantedBookCostMessage()));
|
||||||
} else {
|
} else {
|
||||||
BlacksmithPlugin.error("Unrecognized salvage method " + salvageMethod);
|
BlacksmithPlugin.error("Unrecognized salvage method " + salvageMethod);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String getEnchantedBookCost() {
|
||||||
|
// TODO: If both an item and money is required, print both requirements
|
||||||
|
// TODO: If only money is required, print the money requirement
|
||||||
|
// TODO: If an item requirement is set, print the item requirement
|
||||||
|
|
||||||
|
GlobalScrapperSettings scrapperSettings = BlacksmithPlugin.getInstance().getGlobalScrapperSettings();
|
||||||
|
/*String moneyCost = EconomyManager.format(scrapperSettings.getEnchantedBookSalvageCost());
|
||||||
|
//ItemStack itemCost = scrapperSettings.
|
||||||
|
if (scrapperSettings.requireMoneyAndItemForEnchantedBookSalvage()) {
|
||||||
|
// TODO: Print both with a + between them (if item has a special name, use that instead of the material name)
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// TODO: If the item is not null, print it, otherwise print the monetary cost
|
||||||
|
}*/
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean showExactTime() {
|
protected boolean showExactTime() {
|
||||||
return BlacksmithPlugin.getInstance().getGlobalScrapperSettings().showExactTime();
|
return BlacksmithPlugin.getInstance().getGlobalScrapperSettings().showExactTime();
|
||||||
@ -286,8 +352,8 @@ public class ScrapperTrait extends CustomTrait<ScrapperSetting> {
|
|||||||
* @return <p>True if the item can be theoretically salvaged</p>
|
* @return <p>True if the item can be theoretically salvaged</p>
|
||||||
*/
|
*/
|
||||||
private boolean canBeSalvaged(@NotNull ItemStack item, @NotNull List<Material> salvageAbleItems, boolean extended) {
|
private boolean canBeSalvaged(@NotNull ItemStack item, @NotNull List<Material> salvageAbleItems, boolean extended) {
|
||||||
return (extended || ItemHelper.isRepairable(item)) &&
|
return item.getType() == Material.ENCHANTED_BOOK || ((extended || ItemHelper.isRepairable(item)) &&
|
||||||
(salvageAbleItems.isEmpty() || salvageAbleItems.contains(item.getType()));
|
(salvageAbleItems.isEmpty() || salvageAbleItems.contains(item.getType())));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -26,6 +26,7 @@ public abstract class Session implements Runnable {
|
|||||||
protected static final Random random = new Random();
|
protected static final Random random = new Random();
|
||||||
protected final Player player;
|
protected final Player player;
|
||||||
protected final NPC npc;
|
protected final NPC npc;
|
||||||
|
protected final Entity entity;
|
||||||
protected long finishTime;
|
protected long finishTime;
|
||||||
protected int taskId;
|
protected int taskId;
|
||||||
|
|
||||||
@ -38,6 +39,10 @@ public abstract class Session implements Runnable {
|
|||||||
public Session(@NotNull Player player, @NotNull NPC npc) {
|
public Session(@NotNull Player player, @NotNull NPC npc) {
|
||||||
this.player = player;
|
this.player = player;
|
||||||
this.npc = npc;
|
this.npc = npc;
|
||||||
|
this.entity = npc.getEntity();
|
||||||
|
if (entity == null) {
|
||||||
|
throw new IllegalArgumentException("Tried to start session for an NPC without an assigned entity.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -103,9 +108,9 @@ public abstract class Session implements Runnable {
|
|||||||
|
|
||||||
BlacksmithPlugin instance = BlacksmithPlugin.getInstance();
|
BlacksmithPlugin instance = BlacksmithPlugin.getInstance();
|
||||||
if (this instanceof ReforgeSession) {
|
if (this instanceof ReforgeSession) {
|
||||||
instance.callEvent(new BlacksmithReforgeStartEvent(npc, player, actionDelayTicks, getCraftingStation()));
|
instance.callEvent(new BlacksmithReforgeStartEvent(this.npc, this.entity, this.player, actionDelayTicks, getCraftingStation()));
|
||||||
} else if (this instanceof SalvageSession) {
|
} else if (this instanceof SalvageSession) {
|
||||||
instance.callEvent(new ScrapperSalvageStartEvent(npc, player, actionDelayTicks, getCraftingStation()));
|
instance.callEvent(new ScrapperSalvageStartEvent(this.npc, this.entity, this.player, actionDelayTicks, getCraftingStation()));
|
||||||
}
|
}
|
||||||
|
|
||||||
taskId = scheduler.scheduleSyncDelayedTask(BlacksmithPlugin.getInstance(), this, actionDelayTicks);
|
taskId = scheduler.scheduleSyncDelayedTask(BlacksmithPlugin.getInstance(), this, actionDelayTicks);
|
||||||
@ -116,14 +121,13 @@ public abstract class Session implements Runnable {
|
|||||||
*
|
*
|
||||||
* @param hasDelay <p>Whether the session was delayed, or if the item was processed instantly</p>
|
* @param hasDelay <p>Whether the session was delayed, or if the item was processed instantly</p>
|
||||||
* @param dropItem <p>Whether the item should be dropped on the ground</p>
|
* @param dropItem <p>Whether the item should be dropped on the ground</p>
|
||||||
* @param npc <p>The NPC holding the item</p>
|
|
||||||
* @param itemToReturn <p>The item to return to the player</p>
|
* @param itemToReturn <p>The item to return to the player</p>
|
||||||
*/
|
*/
|
||||||
protected void giveResultingItem(boolean hasDelay, boolean dropItem, @NotNull NPC npc, @NotNull ItemStack itemToReturn) {
|
protected void giveResultingItem(boolean hasDelay, boolean dropItem, @NotNull ItemStack itemToReturn) {
|
||||||
if (hasDelay) {
|
if (hasDelay) {
|
||||||
//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 (dropItem || !this.player.isOnline() || !ItemHelper.canFitItem(this.player.getInventory(), itemToReturn)) {
|
if (dropItem || !this.player.isOnline() || !ItemHelper.canFitItem(this.player.getInventory(), itemToReturn)) {
|
||||||
this.player.getWorld().dropItemNaturally(npc.getEntity().getLocation(), itemToReturn);
|
this.player.getWorld().dropItemNaturally(this.entity.getLocation(), itemToReturn);
|
||||||
} else {
|
} else {
|
||||||
this.player.getInventory().addItem(itemToReturn);
|
this.player.getInventory().addItem(itemToReturn);
|
||||||
}
|
}
|
||||||
@ -172,7 +176,7 @@ public abstract class Session implements Runnable {
|
|||||||
* @param sound <p>The sound to play</p>
|
* @param sound <p>The sound to play</p>
|
||||||
*/
|
*/
|
||||||
protected void playSound(Sound sound) {
|
protected void playSound(Sound sound) {
|
||||||
playSound(this.npc.getEntity(), sound);
|
playSound(this.entity, sound);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -187,14 +191,13 @@ public abstract class Session implements Runnable {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
NPCSoundEvent event = new NPCSoundEvent(this.npc, this.player, SoundCategory.AMBIENT, sound, 0.5f, 1.0f);
|
NPCSoundEvent event = new NPCSoundEvent(this.npc, this.entity, this.player, SoundCategory.AMBIENT, sound, 0.5f, 1.0f);
|
||||||
BlacksmithPlugin.getInstance().callEvent(event);
|
BlacksmithPlugin.getInstance().callEvent(event);
|
||||||
if (event.isCancelled()) {
|
if (event.isCancelled()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
world.playSound(event.getNpc().getEntity(), event.getSound(), event.getSoundCategory(), event.getVolume(),
|
world.playSound(event.getEntity(), event.getSound(), event.getSoundCategory(), event.getVolume(), event.getPitch());
|
||||||
event.getPitch());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@ package net.knarcraft.blacksmith.util;
|
|||||||
|
|
||||||
import net.knarcraft.blacksmith.BlacksmithPlugin;
|
import net.knarcraft.blacksmith.BlacksmithPlugin;
|
||||||
import net.knarcraft.blacksmith.container.RecipeResult;
|
import net.knarcraft.blacksmith.container.RecipeResult;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.Material;
|
import org.bukkit.Material;
|
||||||
import org.bukkit.Server;
|
import org.bukkit.Server;
|
||||||
import org.bukkit.enchantments.Enchantment;
|
import org.bukkit.enchantments.Enchantment;
|
||||||
@ -10,6 +11,8 @@ import org.bukkit.inventory.Recipe;
|
|||||||
import org.bukkit.inventory.ShapedRecipe;
|
import org.bukkit.inventory.ShapedRecipe;
|
||||||
import org.bukkit.inventory.ShapelessRecipe;
|
import org.bukkit.inventory.ShapelessRecipe;
|
||||||
import org.bukkit.inventory.meta.ArmorMeta;
|
import org.bukkit.inventory.meta.ArmorMeta;
|
||||||
|
import org.bukkit.inventory.meta.EnchantmentStorageMeta;
|
||||||
|
import org.bukkit.inventory.meta.ItemMeta;
|
||||||
import org.bukkit.inventory.meta.trim.ArmorTrim;
|
import org.bukkit.inventory.meta.trim.ArmorTrim;
|
||||||
import org.bukkit.inventory.meta.trim.TrimMaterial;
|
import org.bukkit.inventory.meta.trim.TrimMaterial;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
@ -44,6 +47,51 @@ public final class SalvageHelper {
|
|||||||
trimMaterialToMaterial.put(TrimMaterial.REDSTONE, Material.REDSTONE);
|
trimMaterialToMaterial.put(TrimMaterial.REDSTONE, Material.REDSTONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets salvage for an enchanted book
|
||||||
|
*
|
||||||
|
* @param itemStack <p>The enchanted book(s) to salvage</p>
|
||||||
|
* @return <p>The resulting salvage</p>
|
||||||
|
* @throws RuntimeException <p>If generated enchanted book metadata is null</p>
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
public static List<ItemStack> getEnchantedBookSalvage(@NotNull ItemStack itemStack) {
|
||||||
|
ItemMeta meta = itemStack.getItemMeta();
|
||||||
|
List<ItemStack> output = new ArrayList<>();
|
||||||
|
|
||||||
|
if (!(meta instanceof EnchantmentStorageMeta enchantmentStorageMeta)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<Enchantment, Integer> enchantmentMap = enchantmentStorageMeta.getStoredEnchants();
|
||||||
|
for (Map.Entry<Enchantment, Integer> enchantmentEntry : enchantmentMap.entrySet()) {
|
||||||
|
EnchantmentStorageMeta enchantmentMeta = (EnchantmentStorageMeta) Bukkit.getServer().getItemFactory().getItemMeta(Material.ENCHANTED_BOOK);
|
||||||
|
if (enchantmentMeta == null) {
|
||||||
|
throw new RuntimeException("Unable to create enchanted book metadata.");
|
||||||
|
}
|
||||||
|
enchantmentMeta.addStoredEnchant(enchantmentEntry.getKey(), enchantmentEntry.getValue(), true);
|
||||||
|
ItemStack newBook = new ItemStack(Material.ENCHANTED_BOOK, 1);
|
||||||
|
newBook.setItemMeta(enchantmentMeta);
|
||||||
|
output.add(newBook);
|
||||||
|
}
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the number of enchantments applied to an enchanted book
|
||||||
|
*
|
||||||
|
* @param itemStack <p>The enchanted book to check</p>
|
||||||
|
* @return <p>The number of enchantments, or -1 if not an enchanted book</p>
|
||||||
|
*/
|
||||||
|
public static int getEnchantmentCount(@NotNull ItemStack itemStack) {
|
||||||
|
ItemMeta meta = itemStack.getItemMeta();
|
||||||
|
if (!(meta instanceof EnchantmentStorageMeta enchantmentStorageMeta)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return enchantmentStorageMeta.getStoredEnchants().size();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets salvage for a given netherite item
|
* Gets salvage for a given netherite item
|
||||||
*
|
*
|
||||||
|
@ -38,6 +38,8 @@ public final class TabCompleteValuesHelper {
|
|||||||
case MATERIAL -> getAllReforgeAbleMaterialNames();
|
case MATERIAL -> getAllReforgeAbleMaterialNames();
|
||||||
case ENCHANTMENT, ENCHANTMENT_LIST -> getAllEnchantments();
|
case ENCHANTMENT, ENCHANTMENT_LIST -> getAllEnchantments();
|
||||||
case STRING_LIST -> List.of("*_SHOVEL,*_PICKAXE,*_AXE,*_HOE,*_SWORD:STICK,SMITHING_TABLE:*_PLANKS");
|
case STRING_LIST -> List.of("*_SHOVEL,*_PICKAXE,*_AXE,*_HOE,*_SWORD:STICK,SMITHING_TABLE:*_PLANKS");
|
||||||
|
// TODO: Change this to something that makes sense
|
||||||
|
case ADVANCED_COST -> List.of();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -36,7 +36,8 @@ public final class TypeValidationHelper {
|
|||||||
case STRING -> isNonEmptyString(value, sender);
|
case STRING -> isNonEmptyString(value, sender);
|
||||||
case POSITIVE_INTEGER -> isPositiveInteger(value, sender);
|
case POSITIVE_INTEGER -> isPositiveInteger(value, sender);
|
||||||
case PERCENTAGE -> isPercentage(value, sender);
|
case PERCENTAGE -> isPercentage(value, sender);
|
||||||
case BOOLEAN -> true;
|
// TODO: Implement proper advanced cost checking
|
||||||
|
case BOOLEAN, ADVANCED_COST -> true;
|
||||||
case REFORGE_ABLE_ITEMS, STRING_LIST -> isStringList(value, sender);
|
case REFORGE_ABLE_ITEMS, STRING_LIST -> isStringList(value, sender);
|
||||||
case MATERIAL -> isMaterial(value, sender);
|
case MATERIAL -> isMaterial(value, sender);
|
||||||
case ENCHANTMENT -> isEnchantment(value, sender);
|
case ENCHANTMENT -> isEnchantment(value, sender);
|
||||||
|
@ -142,6 +142,14 @@ scrapper:
|
|||||||
# The cost of using the scrapper to remove netherite from an item
|
# The cost of using the scrapper to remove netherite from an item
|
||||||
netheriteSalvagePrice: 15
|
netheriteSalvagePrice: 15
|
||||||
|
|
||||||
|
# The mathematical formula for salvage cost increase when continually used within the same hour. This is necessary
|
||||||
|
# for some servers where items can be easily farmed. Set to {cost} to disable behavior.
|
||||||
|
salvageCostIncrease: "{cost}*{timesUsed}"
|
||||||
|
|
||||||
|
# The mathematical formula for salvage cooldown increase when continually used within the same hour. This is
|
||||||
|
# necessary for some servers where items can be easily farmed. Set to {cooldown} to disable behavior.
|
||||||
|
salvageCooldownIncrease: "{cooldown}*{timesUsed}"
|
||||||
|
|
||||||
# The settings which are set to any new scrapper NPC. To change any of these settings for an existing NPC, you must
|
# The settings which are set to any new scrapper NPC. To change any of these settings for an existing NPC, you must
|
||||||
# change the Citizens NPC file, or use the /scrapper command
|
# change the Citizens NPC file, or use the /scrapper command
|
||||||
defaults:
|
defaults:
|
||||||
@ -182,6 +190,9 @@ scrapper:
|
|||||||
# Whether to enable salvaging of netherite items
|
# Whether to enable salvaging of netherite items
|
||||||
salvageNetherite: true
|
salvageNetherite: true
|
||||||
|
|
||||||
|
# Whether to enable salvaging an enchanted books with several enchantments into several books with one enchantment
|
||||||
|
splitEnchantedBook: false
|
||||||
|
|
||||||
# Default values for messages used by NPCs
|
# Default values for messages used by NPCs
|
||||||
messages:
|
messages:
|
||||||
# The message to display when another player is using the scrapper
|
# The message to display when another player is using the scrapper
|
||||||
@ -226,6 +237,9 @@ scrapper:
|
|||||||
# The message to display when explaining the shown item's netherite salvage cost
|
# The message to display when explaining the shown item's netherite salvage cost
|
||||||
costMessageNetherite: "&eIt will cost &a{cost}&e to salvage that &a{item}&e into diamond!"
|
costMessageNetherite: "&eIt will cost &a{cost}&e to salvage that &a{item}&e into diamond!"
|
||||||
|
|
||||||
|
# The message to display when explaining the shown enchanted book's salvage cost
|
||||||
|
costMessageEnchantedBook: "&eIt will cost &a{cost}&e to salvage that enchanted book!"
|
||||||
|
|
||||||
# The yield message to display if trying to salvage a non-damaged item
|
# The yield message to display if trying to salvage a non-damaged item
|
||||||
fullSalvageMessage: "&aI should be able to extract all components from that pristine item.&r"
|
fullSalvageMessage: "&aI should be able to extract all components from that pristine item.&r"
|
||||||
|
|
||||||
@ -244,5 +258,11 @@ scrapper:
|
|||||||
# The message to display when asked to salvage netherite items, and that option is disabled
|
# The message to display when asked to salvage netherite items, and that option is disabled
|
||||||
cannotSalvageNetheriteMessage: "&cI'm sorry, but I'm unable to salvage netherite items!"
|
cannotSalvageNetheriteMessage: "&cI'm sorry, but I'm unable to salvage netherite items!"
|
||||||
|
|
||||||
|
# The message displayed when explaining that enchanted book salvage is disabled
|
||||||
|
cannotSalvageEnchantedBookMessage: "&cI'm sorry, but I'm unable to salvage enchanted books!"
|
||||||
|
|
||||||
|
# The message displayed when a player attempts to salvage an enchanted book with a single enchantment
|
||||||
|
cannotSplitEnchantedBookFurtherMessage: "&cI'm sorry, but I cannot salvage that enchanted book any further"
|
||||||
|
|
||||||
# The message to display when a scrapper is clicked with an empty hand
|
# The message to display when a scrapper is clicked with an empty hand
|
||||||
noItemMessage: "Please present the item you want to salvage"
|
noItemMessage: "Please present the item you want to salvage"
|
@ -43,7 +43,7 @@ en:
|
|||||||
# The format used when displaying any duration remaining
|
# The format used when displaying any duration remaining
|
||||||
DURATION_FORMAT: "in {time} {unit}"
|
DURATION_FORMAT: "in {time} {unit}"
|
||||||
# The format used when NPCs talk to players ({npc} = The NPC's name, {message} is the actual message contents)
|
# The format used when NPCs talk to players ({npc} = The NPC's name, {message} is the actual message contents)
|
||||||
NPC_TALK_FORMAT: "&a[{npc}] -> You:&r {message}"
|
NPC_TALK_FORMAT: "&a[{npc}&r&a] -> You:&r {message}"
|
||||||
# Translation of the duration of less than a second
|
# Translation of the duration of less than a second
|
||||||
UNIT_NOW: "imminently"
|
UNIT_NOW: "imminently"
|
||||||
# Translation of seconds in singular form
|
# Translation of seconds in singular form
|
||||||
@ -90,3 +90,5 @@ en:
|
|||||||
INTERVAL_MORE_THAN_5_MINUTES: "in quite a while"
|
INTERVAL_MORE_THAN_5_MINUTES: "in quite a while"
|
||||||
# The marker shown when displaying values overridden for the selected NPC (not shown if the NPC inherits the default value)
|
# The marker shown when displaying values overridden for the selected NPC (not shown if the NPC inherits the default value)
|
||||||
SETTING_OVERRIDDEN_MARKER: " [NPC]"
|
SETTING_OVERRIDDEN_MARKER: " [NPC]"
|
||||||
|
# The translation of the text displayed when a cost is expected, but a non-number is provided
|
||||||
|
DOUBLE_COST_REQUIRED: "You must supply a numeric (double) cost"
|
Loading…
x
Reference in New Issue
Block a user