Bug fixes + a lot of features

This commit is contained in:
GB6 2019-02-19 14:23:20 +01:00
parent a4ced7b7ac
commit 2669b44471
68 changed files with 2655 additions and 1058 deletions

View File

@ -5,7 +5,7 @@
<parent>
<artifactId>EpicEnchants-Parent</artifactId>
<groupId>com.songoda</groupId>
<version>1.0.1-ALPHA</version>
<version>1.0.3-ALPHA</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@ -83,7 +83,7 @@
<dependency>
<groupId>com.github.tr7zw</groupId>
<artifactId>Item-NBT-API</artifactId>
<version>9c5f6575a8</version>
<version>master-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
@ -100,5 +100,12 @@
<version>1.7</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.songoda</groupId>
<artifactId>UltimateBottles</artifactId>
<version>1.0</version>
<scope>provided</scope>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,63 @@
package com.songoda.epicenchants;
import com.songoda.epicenchants.objects.Placeholder;
import org.bukkit.Effect;
import org.bukkit.Sound;
import org.bukkit.command.CommandSender;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.entity.Player;
import static com.songoda.epicenchants.utils.single.GeneralUtils.color;
public class Action {
private FileConfiguration config;
private String prefix;
public void perform(CommandSender sender, String node, Placeholder... placeholders) {
if (config.isString(node)) {
sender.sendMessage(getMessage(node, placeholders));
return;
}
if (!config.isConfigurationSection(node)) {
return;
}
ConfigurationSection section = config.getConfigurationSection(node);
if (section.isString("message")) {
sender.sendMessage(getMessage(node + ".message", placeholders));
}
if (!(sender instanceof Player)) {
return;
}
Player player = (Player) sender;
if (section.isString("sound")) {
player.playSound(player.getLocation(), Sound.valueOf(section.getString("sound").toUpperCase()), 1F, 1F);
}
if (section.isString("effect")) {
player.playEffect(player.getEyeLocation(), Effect.valueOf(section.getString("effect")), 10);
}
}
public String getMessage(String node, Placeholder... placeholders) {
String string = config.getString(node);
for (Placeholder placeholder : placeholders) {
string = string.replace(placeholder.getPlaceholder(), placeholder.getToReplace().toString());
}
return color(string);
}
public void load(FileConfiguration config) {
this.config = config;
this.prefix = config.getString("general.prefix");
}
}

View File

@ -1,47 +1,42 @@
package com.songoda.epicenchants;
import co.aikar.commands.BukkitCommandManager;
import co.aikar.commands.InvalidCommandArgument;
import com.songoda.epicenchants.commands.EnchantCommand;
import com.songoda.epicenchants.enums.GiveType;
import com.songoda.epicenchants.listeners.*;
import com.songoda.epicenchants.managers.EnchantManager;
import com.songoda.epicenchants.managers.FileManager;
import com.songoda.epicenchants.managers.GroupManager;
import com.songoda.epicenchants.managers.InfoManager;
import com.songoda.epicenchants.hooks.HookManager;
import com.songoda.epicenchants.listeners.ArmorListener;
import com.songoda.epicenchants.listeners.EntityListener;
import com.songoda.epicenchants.listeners.PlayerListener;
import com.songoda.epicenchants.listeners.item.*;
import com.songoda.epicenchants.managers.*;
import com.songoda.epicenchants.objects.Enchant;
import com.songoda.epicenchants.utils.EnchantUtils;
import com.songoda.epicenchants.utils.FastInv;
import com.songoda.epicenchants.utils.SpecialItems;
import com.songoda.epicenchants.utils.objects.FastInv;
import lombok.Getter;
import net.milkbowl.vault.economy.Economy;
import org.bukkit.Bukkit;
import org.bukkit.event.Listener;
import org.bukkit.plugin.java.JavaPlugin;
import java.io.File;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.Objects;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import static com.songoda.epicenchants.utils.GeneralUtils.color;
import static com.songoda.epicenchants.utils.single.GeneralUtils.color;
import static org.bukkit.Bukkit.getConsoleSender;
@Getter
public class EpicEnchants extends JavaPlugin {
private BukkitCommandManager commandManager;
private Economy economy;
private EnchantManager enchantManager;
private InfoManager infoManager;
private GroupManager groupManager;
private EnchantUtils enchantUtils;
private FileManager fileManager;
private HookManager hookManager;
private SpecialItems specialItems;
private Locale locale;
private Action action;
private Economy economy;
private EnchantUtils enchantUtils;
@Override
public void onEnable() {
@ -49,10 +44,9 @@ public class EpicEnchants extends JavaPlugin {
getConsoleSender().sendMessage(color("&7" + getDescription().getName() + " " + getDescription().getVersion() + " by &5Songoda <3&7!"));
getConsoleSender().sendMessage(color("&7Action: &aEnabling&7..."));
Locale.init(this);
FastInv.init(this);
this.locale = Locale.getLocale(getConfig().getString("language"));
this.action = new Action();
this.fileManager = new FileManager(this);
this.groupManager = new GroupManager(this);
this.enchantManager = new EnchantManager(this);
@ -60,17 +54,20 @@ public class EpicEnchants extends JavaPlugin {
this.infoManager = new InfoManager(this);
this.specialItems = new SpecialItems(this);
this.economy = getServer().getServicesManager().getRegistration(Economy.class).getProvider();
this.commandManager = new CommandManager(this);
this.hookManager = new HookManager();
fileManager.createFiles();
fileManager.loadFiles();
groupManager.loadGroups();
enchantManager.loadEnchants();
infoManager.loadMenus();
action.load(fileManager.getConfiguration("actions"));
hookManager.setup();
setupCommands();
setupListeners();
if (!enchantManager.getEnchants().isEmpty()) {
getLogger().info("Successfully loaded enchants: " + enchantManager.getEnchants().stream().map(Enchant::getIdentifier).collect(Collectors.joining(", ")));
if (!enchantManager.getValues().isEmpty()) {
getLogger().info("Successfully loaded enchants: " + enchantManager.getValues().stream().map(Enchant::getIdentifier).collect(Collectors.joining(", ")));
}
getConsoleSender().sendMessage(color("&a============================="));
@ -84,28 +81,6 @@ public class EpicEnchants extends JavaPlugin {
getConsoleSender().sendMessage(color("&a============================="));
}
private void setupCommands() {
this.commandManager = new BukkitCommandManager(this);
commandManager.registerDependency(EpicEnchants.class, "instance", this);
commandManager.getCommandCompletions().registerCompletion("enchants", c -> enchantManager.getEnchants().stream().map(Enchant::getIdentifier).collect(Collectors.toList()));
commandManager.getCommandCompletions().registerCompletion("enchantFiles", c -> fileManager.getYmlFiles("enchants").orElse(Collections.emptyList()).stream().map(File::getName).collect(Collectors.toList()));
commandManager.getCommandCompletions().registerCompletion("giveType", c -> Arrays.stream(GiveType.values()).map(s -> s.toString().replace("_", "").toLowerCase()).collect(Collectors.toList()));
commandManager.getCommandCompletions().registerCompletion("levels", c -> IntStream.rangeClosed(1, c.getContextValue(Enchant.class).getMaxLevel()).boxed().map(Objects::toString).collect(Collectors.toList()));
commandManager.getCommandCompletions().registerCompletion("increment", c -> IntStream.rangeClosed(0, 100).filter(i -> i % 10 == 0).boxed().map(Objects::toString).collect(Collectors.toList()));
commandManager.getCommandContexts().registerContext(Enchant.class, c -> enchantManager.getEnchant(c.popFirstArg()).orElseThrow(() -> new InvalidCommandArgument("No enchant exists by that name")));
commandManager.getCommandContexts().registerContext(File.class, c -> enchantManager.getEnchantFile(c.popFirstArg()).orElseThrow(() -> new InvalidCommandArgument("No EnchantFile exists by that name")));
commandManager.getCommandContexts().registerContext(GiveType.class, c -> Arrays.stream(GiveType.values())
.filter(s -> s.toString().toLowerCase().replace("_", "").equalsIgnoreCase(c.popFirstArg()))
.findFirst()
.orElseThrow(() -> new InvalidCommandArgument("No item by that type.")));
commandManager.registerCommand(new EnchantCommand());
}
private void setupListeners() {
EpicEnchants instance = this;
new HashSet<Listener>() {{
@ -114,15 +89,17 @@ public class EpicEnchants extends JavaPlugin {
add(new PlayerListener(instance));
add(new EntityListener(instance));
add(new WhiteScrollListener(instance));
add(new BlackScrollListener(instance));
add(new DustListener(instance));
}}.forEach(listener -> Bukkit.getPluginManager().registerEvents(listener, this));
}
public void reload() {
reloadConfig();
locale.reloadMessages();
fileManager.loadFiles();
enchantManager.loadEnchants();
groupManager.loadGroups();
infoManager.loadMenus();
action.load(fileManager.getConfiguration("actions"));
}
}

View File

@ -1,401 +0,0 @@
package com.songoda.epicenchants;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
import com.songoda.epicenchants.objects.Placeholder;
import org.bukkit.ChatColor;
import org.bukkit.plugin.java.JavaPlugin;
import java.io.*;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
/**
* Assists in the creation of multiple localizations and languages,
* as well as the generation of default .lang files
*
* @author Parker Hawke - 2008Choco
*/
public class Locale {
private static final List<Locale> LOCALES = Lists.newArrayList();
private static final Pattern NODE_PATTERN = Pattern.compile("(\\w+(?:\\.{1}\\w+)*)\\s*=\\s*\"(.*)\"");
private static final String FILE_EXTENSION = ".lang";
private static JavaPlugin plugin;
private static File localeFolder;
private static String defaultLocale;
private final Map<String, String> nodes = new HashMap<>();
private final File file;
private final String name, region;
private Locale(String name, String region) {
if (plugin == null)
throw new IllegalStateException("Cannot generate locales without first initializing the class (Locale#init(JavaPlugin))");
this.name = name.toLowerCase();
this.region = region.toUpperCase();
String fileName = name + "_" + region + FILE_EXTENSION;
this.file = new File(localeFolder, fileName);
if (this.reloadMessages()) return;
plugin.getLogger().info("Loaded locale " + fileName);
}
/**
* Initialize the locale class to generate information and search for localizations.
* This must be called before any other methods in the Locale class can be invoked.
* Note that this will also call {@link #searchForLocales()}, so there is no need to
* invoke it for yourself after the initialization
*
* @param plugin the plugin instance
*/
public static void init(JavaPlugin plugin) {
Locale.plugin = plugin;
if (localeFolder == null) {
localeFolder = new File(plugin.getDataFolder(), "locales/");
}
localeFolder.mkdirs();
Locale.searchForLocales();
Locale.saveDefaultLocale("en_US");
}
/**
* Find all .lang file locales under the "locales" folder
*/
public static void searchForLocales() {
if (!localeFolder.exists()) {
localeFolder.mkdirs();
}
for (File file : localeFolder.listFiles()) {
String name = file.getName();
if (!name.endsWith(".lang")) continue;
String fileName = name.substring(0, name.lastIndexOf('.'));
String[] localeValues = fileName.split("_");
if (localeValues.length != 2) continue;
if (localeExists(localeValues[0] + "_" + localeValues[1])) continue;
LOCALES.add(new Locale(localeValues[0], localeValues[1]));
plugin.getLogger().info("Found and loaded locale \"" + fileName + "\"");
}
}
/**
* Get a locale by its entire proper name (i.e. "en_US")
*
* @param name the full name of the locale
* @return locale of the specified name
*/
public static Locale getLocale(String name) {
for (Locale locale : LOCALES)
if (locale.getLanguageTag().equalsIgnoreCase(name)) return locale;
return null;
}
/**
* Get a locale from the cache by its name (i.e. "en" from "en_US")
*
* @param name the name of the language
* @return locale of the specified language. Null if not cached
*/
public static Locale getLocaleByName(String name) {
for (Locale locale : LOCALES)
if (locale.getName().equalsIgnoreCase(name)) return locale;
return null;
}
/**
* Get a locale from the cache by its region (i.e. "US" from "en_US")
*
* @param region the name of the region
* @return locale of the specified region. Null if not cached
*/
public static Locale getLocaleByRegion(String region) {
for (Locale locale : LOCALES)
if (locale.getRegion().equalsIgnoreCase(region)) return locale;
return null;
}
/**
* Check whether a locale exists and is registered or not
*
* @param name the whole language tag (i.e. "en_US")
* @return true if it exists
*/
public static boolean localeExists(String name) {
for (Locale locale : LOCALES)
if (locale.getLanguageTag().equals(name)) return true;
return false;
}
/**
* Save a default locale file from the project source directory, to the locale folder
*
* @param in file to save
* @param fileName the name of the file to save
* @return true if the operation was successful, false otherwise
*/
public static boolean saveDefaultLocale(InputStream in, String fileName) {
if (!localeFolder.exists()) localeFolder.mkdirs();
if (!fileName.endsWith(FILE_EXTENSION))
fileName = (fileName.lastIndexOf(".") == -1 ? fileName : fileName.substring(0, fileName.lastIndexOf('.'))) + FILE_EXTENSION;
File destinationFile = new File(localeFolder, fileName);
if (destinationFile.exists()) {
return compareFiles(plugin.getResource(fileName), destinationFile);
}
try (OutputStream outputStream = new FileOutputStream(destinationFile)) {
copy(in == null ? plugin.getResource(fileName) : in, outputStream);
fileName = fileName.substring(0, fileName.lastIndexOf('.'));
String[] localeValues = fileName.split("_");
if (localeValues.length != 2) return false;
LOCALES.add(new Locale(localeValues[0], localeValues[1]));
if (defaultLocale == null) defaultLocale = fileName;
return true;
} catch (IOException e) {
return false;
}
}
/**
* Save a default locale file from the project source directory, to the locale folder
*
* @param fileName the name of the file to save
* @return true if the operation was successful, false otherwise
*/
public static boolean saveDefaultLocale(String fileName) {
return saveDefaultLocale(null, fileName);
}
/**
* Clear all current locale data
*/
public static void clearLocaleData() {
for (Locale locale : LOCALES)
locale.nodes.clear();
LOCALES.clear();
}
// Write new changes to existing files, if any at all
private static boolean compareFiles(InputStream defaultFile, File existingFile) {
// Look for default
if (defaultFile == null) {
defaultFile = plugin.getResource(defaultLocale != null ? defaultLocale : "en_US");
if (defaultFile == null) return false; // No default at all
}
boolean changed = false;
List<String> defaultLines, existingLines;
try (BufferedReader defaultReader = new BufferedReader(new InputStreamReader(defaultFile));
BufferedReader existingReader = new BufferedReader(new FileReader(existingFile));
BufferedWriter writer = new BufferedWriter(new FileWriter(existingFile, true))) {
defaultLines = defaultReader.lines().collect(Collectors.toList());
existingLines = existingReader.lines().map(s -> s.split("\\s*=")[0]).collect(Collectors.toList());
for (String defaultValue : defaultLines) {
if (defaultValue.isEmpty() || defaultValue.startsWith("#")) continue;
String key = defaultValue.split("\\s*=")[0];
if (!existingLines.contains(key)) {
if (!changed) {
writer.newLine();
writer.newLine();
writer.write("# New messages for " + plugin.getName() + " v" + plugin.getDescription().getVersion());
}
writer.newLine();
writer.write(defaultValue);
changed = true;
}
}
} catch (IOException e) {
return false;
}
return changed;
}
private static void copy(InputStream input, OutputStream output) {
int n;
byte[] buffer = new byte[1024 * 4];
try {
while ((n = input.read(buffer)) != -1) {
output.write(buffer, 0, n);
}
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* Get a message set for a specific node
*
* @param node the node to get
* @return the message for the specified node
*/
public String getMessage(String node) {
return ChatColor.translateAlternateColorCodes('&', this.getMessageOrDefault(node, node));
}
/**
* Get a message set for a specific node with prefix
*
* @param node the node to get
* @return the message for the specified node
*/
public String getMessageWithPrefix(String node) {
return ChatColor.translateAlternateColorCodes('&', getPrefix() + this.getMessageOrDefault(node, node));
}
/**
* Get a message set for a specific node with prefix
*
* @param node the node to get
* @return the message for the specified node
*/
public String getMessageWithPrefix(String node, Placeholder... placeholders) {
return ChatColor.translateAlternateColorCodes('&', getPrefix() + getMessage(node, placeholders));
}
/**
* Get a message set for a specific node and replace its params with a supplied arguments.
*
* @param node the node to get
* @return the message for the specified node
*/
public String getMessage(String node, Placeholder... placeholders) {
String message = getMessage(node);
for (Placeholder placeholder : placeholders) {
message = message.replace(placeholder.getPlaceholder(), placeholder.getToReplace().toString());
}
return message;
}
/**
* Get a message set for a specific node
*
* @param node the node to get
* @param defaultValue the default value given that a value for the node was not found
* @return the message for the specified node. Default if none found
*/
public String getMessageOrDefault(String node, String defaultValue) {
return this.nodes.getOrDefault(node, defaultValue);
}
/**
* Clear the previous message cache and load new messages directly from file
*
* @return reload messages from file
*/
public boolean reloadMessages() {
if (!this.file.exists()) {
plugin.getLogger().warning("Could not find file for locale " + this.name);
return false;
}
this.nodes.clear(); // Clear previous data (if any)
try (BufferedReader reader = new BufferedReader(new FileReader(file))) {
String line;
for (int lineNumber = 0; (line = reader.readLine()) != null; lineNumber++) {
if (line.isEmpty() || line.startsWith("#") /* Comment */) continue;
Matcher matcher = NODE_PATTERN.matcher(line);
if (!matcher.find()) {
System.err.println("Invalid locale syntax at (line=" + lineNumber + ")");
continue;
}
nodes.put(matcher.group(1), matcher.group(2));
}
} catch (IOException e) {
e.printStackTrace();
return false;
}
return true;
}
/**
* Get the file that represents this locale
*
* @return the locale file (.lang)
*/
public File getFile() {
return file;
}
/**
* Return the entire locale tag (i.e. "en_US")
*
* @return the language tag
*/
public String getLanguageTag() {
return name + "_" + region;
}
/**
* Get an immutable list of all currently loaded locales
*
* @return list of all locales
*/
public static List<Locale> getLocales() {
return ImmutableList.copyOf(LOCALES);
}
/**
* Get the key-value map of nodes to messages
*
* @return node-message map
*/
public Map<String, String> getMessageNodeMap() {
return ImmutableMap.copyOf(nodes);
}
/**
* Get the name of the language that this locale is based on.
* (i.e. "en" for English, or "fr" for French)
*
* @return the name of the language
*/
public String getName() {
return name;
}
public String getPrefix() {
return getMessage("general.nametag.prefix") + " ";
}
/**
* Get the name of the region that this locale is from.
* (i.e. "US" for United States or "CA" for Canada)
*
* @return the name of the region
*/
public String getRegion() {
return region;
}
}

View File

@ -1,22 +1,22 @@
package com.songoda.epicenchants.commands;
import co.aikar.commands.BaseCommand;
import co.aikar.commands.CommandHelp;
import co.aikar.commands.annotation.*;
import com.songoda.epicenchants.EpicEnchants;
import com.songoda.epicenchants.enums.EnchantResult;
import com.songoda.epicenchants.menus.EnchanterMenu;
import com.songoda.epicenchants.menus.TinkererMenu;
import com.songoda.epicenchants.objects.Enchant;
import com.songoda.epicenchants.objects.Group;
import org.apache.commons.lang3.tuple.Pair;
import org.bukkit.Bukkit;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import java.io.File;
import static com.songoda.epicenchants.enums.EnchantResult.BROKEN_FAILURE;
import static com.songoda.epicenchants.objects.Placeholder.of;
import static com.songoda.epicenchants.utils.GeneralUtils.getMessageFromResult;
import static com.songoda.epicenchants.utils.single.GeneralUtils.getMessageFromResult;
@CommandAlias("epicenchants|ee")
public class EnchantCommand extends BaseCommand {
@ -24,38 +24,55 @@ public class EnchantCommand extends BaseCommand {
@Dependency("instance")
private EpicEnchants instance;
@Default
@Subcommand("enchanter")
@Subcommand("%enchanter")
@Description("Opens the Enchanter")
public void onGui(Player player) {
@CommandPermission("epicenchants.enchanter")
public void onEnchanter(Player player) {
new EnchanterMenu(instance, instance.getFileManager().getConfiguration("menus/enchanter-menu"), player).open(player);
}
//ee give book {player} {enchant} {group}
@Subcommand("%tinkerer")
@Description("Opens the Tinkerer")
@CommandPermission("epicenchants.tinkerer")
public void onTinkerer(Player player) {
new TinkererMenu(instance, instance.getFileManager().getConfiguration("menus/tinkerer-menu")).open(player);
}
//ee give book [player] [enchant] <level> <success-rate> <destroy-rate>
@Subcommand("give book")
@CommandCompletion("@players @enchants @levels @increment @increment")
@Description("Give enchant books to players")
@CommandPermission("epicenchants.give")
@CommandPermission("epicenchants.give.book")
public void onGiveBook(CommandSender sender, @Flags("other") Player target, Enchant enchant, @Optional Integer level, @Optional Integer successRate, @Optional Integer destroyRate) {
if (level != null && level > enchant.getMaxLevel()) {
sender.sendMessage(instance.getLocale().getMessageWithPrefix("command.book.maxlevel",
instance.getAction().perform(sender, "command.book.max-level",
of("enchant", enchant.getIdentifier()),
of("max-level", enchant.getMaxLevel())));
of("max-level", enchant.getMaxLevel()));
return;
}
target.getInventory().addItem(enchant.getBookItem().get(enchant, level, successRate, destroyRate));
target.sendMessage(instance.getLocale().getMessageWithPrefix("command.book.received", of("enchant", enchant.getIdentifier())));
sender.sendMessage(instance.getLocale().getMessageWithPrefix("command.book.gave", of("player", target.getName()), of("enchant", enchant.getIdentifier())));
target.getInventory().addItem(enchant.getBook().get(enchant, level, successRate, destroyRate));
instance.getAction().perform(target, "command.book.received", of("enchant", enchant.getIdentifier()));
instance.getAction().perform(sender, "command.book.gave", of("player", target.getName()), of("enchant", enchant.getIdentifier()));
}
//ee give item {player} {giveType} {group}
//ee give item dust [player] [group] <type> <percentage>
@Subcommand("give item dust")
@CommandCompletion("@players @groups @dustTypes @nothing")
@CommandPermission("epicenchants.give.item.dust")
public void onGiveDust(CommandSender sender, @Flags("other") Player target, Group group, @Optional String dustType, @Optional Integer percentage) {
target.getInventory().addItem(instance.getSpecialItems().getDust(group, dustType, percentage));
instance.getAction().perform(target, "command.dust.received", of("group", group.getIdentifier()));
instance.getAction().perform(sender, "command.dust.gave", of("player", target.getName()), of("group", group.getIdentifier()));
}
//ee give item [giveType] [player] <amount> <success-rate>
@Subcommand("give item")
@CommandCompletion("@players @giveType @nothing @nothing")
@Description("Give enchant books to players")
@CommandPermission("epicenchants.give")
@CommandPermission("epicenchants.give.item")
public void onGiveItem(CommandSender sender, @Flags("other") Player target, String giveType, @Optional Integer amount, @Optional Integer successRate) {
String messageKey;
switch (giveType.toLowerCase()) {
case "whitescroll":
target.getInventory().addItem(instance.getSpecialItems().getWhiteScroll(amount));
@ -69,23 +86,28 @@ public class EnchantCommand extends BaseCommand {
return;
}
target.sendMessage(instance.getLocale().getMessageWithPrefix("command." + messageKey + ".received"));
sender.sendMessage(instance.getLocale().getMessageWithPrefix("command." + messageKey + ".gave", of("player", target.getName())));
instance.getAction().perform(target, "command." + messageKey + ".received");
instance.getAction().perform(sender, "command." + messageKey + ".gave", of("player", target.getName()));
}
//ee apply {enchant} {group}
//ee apply [enchant] [level] <success-rate> <destroy-rate>
@Subcommand("apply")
@CommandCompletion("@enchants @nothing")
@Description("Apply enchant to item in hand")
@CommandPermission("epicenchants.apply")
public void onApply(Player player, Enchant enchant, int level, @Optional Integer successRate, @Optional Integer destroyRate) {
if (player.getItemInHand() == null) {
instance.getAction().perform(player, "command.apply.noitem", of("enchant", enchant.getIdentifier()));
return;
}
int slot = player.getInventory().getHeldItemSlot();
ItemStack before = player.getItemInHand();
Pair<ItemStack, EnchantResult> result = instance.getEnchantUtils().apply(before, enchant, level,
successRate == null ? 100 : successRate, destroyRate == null ? 0 : destroyRate);
player.sendMessage(instance.getLocale().getMessageWithPrefix(getMessageFromResult(result.getRight()), of("enchant", enchant.getIdentifier())));
instance.getAction().perform(player, getMessageFromResult(result.getRight()), of("enchant", enchant.getIdentifier()));
if (result.getRight() == BROKEN_FAILURE) {
player.getInventory().clear(slot);
@ -105,27 +127,16 @@ public class EnchantCommand extends BaseCommand {
//ee reload [enchantFileName]
@Subcommand("reload")
@CommandAlias("load")
@Description("Reload all config files, or reload/load specific enchant files")
@Description("Reload all config files.")
@CommandCompletion("@enchantFiles")
@CommandPermission("epicenchants.reload")
public void onReload(CommandSender sender, @Optional File fileName) {
if (fileName == null) {
instance.reload();
sender.sendMessage(instance.getLocale().getMessageWithPrefix("command.reload"));
return;
}
try {
instance.getEnchantManager().loadEnchant(fileName);
} catch (Exception e) {
sender.sendMessage(instance.getLocale().getMessageWithPrefix("command.filereload.failed", of("file-name", fileName.getName())));
Bukkit.getConsoleSender().sendMessage("Something went wrong loading the enchant from file " + fileName.getName());
Bukkit.getConsoleSender().sendMessage("Please check to make sure there are no errors in the file.");
e.printStackTrace();
return;
}
sender.sendMessage(instance.getLocale().getMessageWithPrefix("command.filereload.success", of("file-name", fileName.getName())));
public void onReload(CommandSender sender) {
instance.reload();
instance.getAction().perform(sender, "command.reload");
}
@HelpCommand
public void doHelp(CommandSender sender, CommandHelp help) {
help.showHelp();
}
}

View File

@ -3,7 +3,7 @@ package com.songoda.epicenchants.effect;
import com.songoda.epicenchants.enums.EventType;
import com.songoda.epicenchants.enums.TriggerType;
import com.songoda.epicenchants.objects.LeveledModifier;
import com.songoda.epicenchants.utils.GeneralUtils;
import com.songoda.epicenchants.utils.single.GeneralUtils;
import lombok.Getter;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.entity.LivingEntity;
@ -12,21 +12,17 @@ import org.bukkit.event.Event;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Arrays;
import java.util.function.Consumer;
import static com.songoda.epicenchants.effect.EffectExecutor.Who.OPPONENT;
import static com.songoda.epicenchants.effect.EffectExecutor.Who.WEARER;
import static com.songoda.epicenchants.effect.EffectExecutor.Who.*;
public abstract class EffectExecutor {
@Getter private final ConfigurationSection section;
@Getter private final TriggerType triggerType;
private TriggerType[] allowedEffects;
public EffectExecutor(ConfigurationSection section, TriggerType... allowedEffects) {
public EffectExecutor(ConfigurationSection section) {
this.section = section;
this.triggerType = TriggerType.valueOf(section.getString("trigger"));
this.allowedEffects = allowedEffects;
}
public void testAndRun(@NotNull Player wearer, @Nullable LivingEntity opponent, int level, TriggerType type, Event event, EventType eventType) {
@ -34,10 +30,6 @@ public abstract class EffectExecutor {
return;
}
if (allowedEffects.length != 0 && Arrays.stream(allowedEffects).noneMatch(t -> t == triggerType)) {
throw new IllegalStateException(section.getName() + " cannot be triggered by " + triggerType.toString());
}
if (section.isString("chance") && !GeneralUtils.chance(LeveledModifier.of(section.getString("chance")).get(level, 100))) {
return;
}

View File

@ -0,0 +1,22 @@
package com.songoda.epicenchants.effect.effects;
import com.songoda.epicenchants.effect.EffectExecutor;
import com.songoda.epicenchants.enums.EventType;
import com.songoda.epicenchants.utils.objects.ItemBuilder;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class DropItem extends EffectExecutor {
public DropItem(ConfigurationSection section) {
super(section);
}
@Override
public void execute(@NotNull Player wearer, @Nullable LivingEntity opponent, int level, EventType eventType) {
consume(entity -> entity.getLocation().getWorld().dropItemNaturally(entity.getLocation(),
new ItemBuilder(getSection(), ((Player) entity)).build()), wearer, opponent);
}
}

View File

@ -8,12 +8,10 @@ import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import static com.songoda.epicenchants.enums.EventType.ON;
import static com.songoda.epicenchants.enums.TriggerType.HELD_ITEM;
import static com.songoda.epicenchants.enums.TriggerType.STATIC_EFFECT;
public class Fly extends EffectExecutor {
public Fly(ConfigurationSection section) {
super(section, STATIC_EFFECT, HELD_ITEM);
super(section);
}
@Override

View File

@ -7,7 +7,7 @@ import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import static com.songoda.epicenchants.utils.GeneralUtils.color;
import static com.songoda.epicenchants.utils.single.GeneralUtils.color;
public class Message extends EffectExecutor {
public Message(ConfigurationSection section) {

View File

@ -2,7 +2,8 @@ package com.songoda.epicenchants.effect.effects;
import com.songoda.epicenchants.effect.EffectExecutor;
import com.songoda.epicenchants.enums.EventType;
import com.songoda.epicenchants.utils.Experience;
import com.songoda.epicenchants.objects.LeveledModifier;
import com.songoda.epicenchants.utils.single.Experience;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
@ -18,7 +19,12 @@ public class ModifyExp extends EffectExecutor {
public void execute(@NotNull Player wearer, @Nullable LivingEntity opponent, int level, EventType eventType) {
consume(entity -> {
if (entity instanceof Player) {
Experience.changeExp(((Player) entity), (int) getAmount().get(level, 0));
Player player = (Player) entity;
if (getSection().getString("amount").endsWith("L")) {
player.setLevel((int) (player.getLevel() + LeveledModifier.of(getSection().getString("amount").replace("L", "")).get(level, 0)));
} else {
Experience.changeExp(player, (int) getAmount().get(level, 0));
}
}
}, wearer, opponent);
}

View File

@ -0,0 +1,41 @@
package com.songoda.epicenchants.effect.effects;
import com.songoda.epicenchants.effect.EffectExecutor;
import com.songoda.epicenchants.enums.EventType;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import static com.songoda.epicenchants.utils.single.Experience.*;
public class StealExp extends EffectExecutor {
public StealExp(ConfigurationSection section) {
super(section);
}
@Override
public void execute(@NotNull Player wearer, @Nullable LivingEntity entity, int level, EventType eventType) {
double amount = getAmount().get(level, 0);
if (!(entity instanceof Player)) {
return;
}
Player opponent = (Player) entity;
if (getExp(opponent) - amount <= 0) {
changeExp(opponent, 0);
} else {
changeExp(opponent, (int) -amount);
}
if (getExp(wearer) + amount <= 0) {
changeExp(wearer, 0);
} else {
changeExp(wearer, (int) amount);
}
}
}

View File

@ -47,7 +47,8 @@ public class Throw extends EffectExecutor {
vector = new Vector();
}
if (vector.length() != 0)
if (vector.length() != 0) {
livingEntity.setVelocity(vector);
}
}
}

View File

@ -2,10 +2,9 @@ package com.songoda.epicenchants.effect.effects;
import com.songoda.epicenchants.effect.EffectExecutor;
import com.songoda.epicenchants.enums.EventType;
import com.songoda.epicenchants.objects.LeveledModifier;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import org.bukkit.entity.*;
import org.jetbrains.annotations.NotNull;
public class Tnt extends EffectExecutor {
@ -15,6 +14,11 @@ public class Tnt extends EffectExecutor {
@Override
public void execute(@NotNull Player wearer, LivingEntity opponent, int level, EventType eventType) {
consume(player -> player.getWorld().spawnEntity(player.getLocation(), EntityType.PRIMED_TNT), wearer, opponent);
consume(player -> {
for (int i = 0; i < LeveledModifier.of(getSection().getString("amount")).get(level, 1); i++) {
TNTPrimed tntPrimed = (TNTPrimed) player.getWorld().spawnEntity(player.getLocation(), EntityType.PRIMED_TNT);
tntPrimed.setFuseTicks((int) LeveledModifier.of(getSection().getString("fuse")).get(level, 60));
}
}, wearer, opponent);
}
}

View File

@ -1,5 +1,5 @@
package com.songoda.epicenchants.enums;
public enum EnchantResult {
SUCCESS, FAILURE, BROKEN_FAILURE, CONFLICT, MAXED_OUT, ALREADY_APPLIED
SUCCESS, FAILURE, BROKEN_FAILURE, CONFLICT, MAXED_OUT, ALREADY_APPLIED, PROTECTED
}

View File

@ -1,5 +1,5 @@
package com.songoda.epicenchants.enums;
public enum GiveType {
WHITE_SCROLL, BLACK_SCROLL
WHITE_SCROLL, BLACK_SCROLL, DUST
}

View File

@ -0,0 +1,5 @@
package com.songoda.epicenchants.enums;
public enum ItemType {
BOOK, ENCHANTED, NONE
}

View File

@ -20,6 +20,7 @@ public enum TriggerType {
EXPLOSION_DAMAGE,
FALL_DAMAGE,
FIRE_DAMAGE,
POISON_DAMAGE,
HELD_ITEM,
STATIC_EFFECT,

View File

@ -0,0 +1,9 @@
package com.songoda.epicenchants.hooks;
import org.bukkit.entity.Player;
public interface FactionsHook {
String getRelationToLocation(Player player);
boolean isFriendly(Player player, Player other);
}

View File

@ -0,0 +1,21 @@
package com.songoda.epicenchants.hooks;
import com.songoda.ultimatebottles.UltimateBottles;
import lombok.Getter;
import org.bukkit.Bukkit;
import java.util.Optional;
@Getter
public class HookManager {
private FactionsHook factionsHook;
private UltimateBottles ultimateBottles;
public void setup() {
ultimateBottles = Bukkit.getPluginManager().isPluginEnabled("UltimateBottles") ? (UltimateBottles) Bukkit.getPluginManager().getPlugin("UltimateBottles") : null;
}
public Optional<UltimateBottles> getUltimateBottles() {
return Optional.ofNullable(ultimateBottles);
}
}

View File

@ -1,45 +0,0 @@
package com.songoda.epicenchants.listeners;
import com.songoda.epicenchants.EpicEnchants;
import de.tr7zw.itemnbtapi.NBTItem;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.inventory.InventoryAction;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.event.inventory.InventoryType;
import org.jetbrains.annotations.Nullable;
public class BlackScrollListener {
private final EpicEnchants instance;
public BlackScrollListener(EpicEnchants instance) {
this.instance = instance;
}
@EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST)
public void onInventoryClick(InventoryClickEvent event) {
if (event.getCursor() == null || event.getCurrentItem() == null || event.getAction() != InventoryAction.SWAP_WITH_CURSOR || event.getClickedInventory().getType() == InventoryType.CREATIVE) {
return;
}
@Nullable NBTItem nbtItem = new NBTItem(event.getCursor());
NBTItem toApplyTo = new NBTItem(event.getCurrentItem());
if (nbtItem == null) {
return;
}
if (!nbtItem.getBoolean("black-scroll")) {
return;
}
if (toApplyTo.getCompound("enchants") == null || toApplyTo.getCompound("enchants").getKeys().isEmpty()) {
event.getWhoClicked().sendMessage(instance.getLocale().getMessageWithPrefix("blackscroll.noenchants"));
return;
}
//TODO: Blackscroll
event.getWhoClicked().sendMessage(instance.getLocale().getMessageWithPrefix("blackscroll.success"));
}
}

View File

@ -1,88 +0,0 @@
package com.songoda.epicenchants.listeners;
import com.songoda.epicenchants.EpicEnchants;
import com.songoda.epicenchants.enums.EnchantResult;
import com.songoda.epicenchants.events.EnchantApplyEvent;
import com.songoda.epicenchants.objects.Enchant;
import com.songoda.epicenchants.utils.GeneralUtils;
import de.tr7zw.itemnbtapi.NBTItem;
import org.apache.commons.lang3.tuple.Pair;
import org.bukkit.Bukkit;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.inventory.InventoryAction;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.event.inventory.InventoryType;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.Nullable;
import static com.songoda.epicenchants.enums.EnchantResult.*;
import static com.songoda.epicenchants.objects.Placeholder.of;
public class BookListener implements Listener {
private final EpicEnchants instance;
public BookListener(EpicEnchants instance) {
this.instance = instance;
}
@EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST)
public void onInventoryClick(InventoryClickEvent event) {
if (event.getCursor() == null || event.getCurrentItem() == null || event.getAction() != InventoryAction.SWAP_WITH_CURSOR || event.getClickedInventory().getType() == InventoryType.CREATIVE) {
return;
}
@Nullable NBTItem nbtItem = new NBTItem(event.getCursor());
ItemStack toApplyTo = event.getCurrentItem();
if (nbtItem == null) {
return;
}
if (!nbtItem.getBoolean("book-item")) {
return;
}
Enchant enchant = instance.getEnchantManager().getEnchant(nbtItem.getString("enchant")).orElseThrow(() -> new IllegalStateException("Book without enchant!"));
if (!enchant.getItemWhitelist().contains(toApplyTo.getType())) {
event.getWhoClicked().sendMessage(instance.getLocale().getMessageWithPrefix("enchant.invalidmaterial", of("enchant", enchant.getIdentifier())));
return;
}
int level = nbtItem.getInteger("level");
int successRate = nbtItem.getInteger("success-rate");
int destroyRate = nbtItem.getInteger("destroy-rate");
EnchantApplyEvent enchantEvent = new EnchantApplyEvent(toApplyTo, enchant, level, successRate, destroyRate);
Bukkit.getPluginManager().callEvent(enchantEvent);
if (enchantEvent.isCancelled()) {
return;
}
Pair<ItemStack, EnchantResult> result = instance.getEnchantUtils().apply(toApplyTo, enchant, enchantEvent.getLevel(), enchantEvent.getSuccessRate(), enchantEvent.getDestroyRate());
event.getWhoClicked().sendMessage(instance.getLocale().getMessageWithPrefix(GeneralUtils.getMessageFromResult(result.getRight()),
of("enchant", enchant.getIdentifier())));
event.setCancelled(true);
if (result.getRight() == BROKEN_FAILURE) {
event.getClickedInventory().clear(event.getSlot());
}
if (result.getRight() != CONFLICT && result.getRight() != MAXED_OUT && result.getRight() != ALREADY_APPLIED) {
if (event.getCursor().getAmount() > 1) {
ItemStack toSet = event.getCursor();
toSet.setAmount(toSet.getAmount() - 1);
event.getWhoClicked().setItemOnCursor(toSet);
} else {
event.getWhoClicked().setItemOnCursor(null);
}
}
event.getClickedInventory().setItem(event.getSlot(), result.getLeft());
}
}

View File

@ -3,17 +3,11 @@ package com.songoda.epicenchants.listeners;
import com.songoda.epicenchants.EpicEnchants;
import com.songoda.epicenchants.enums.TriggerType;
import de.tr7zw.itemnbtapi.NBTEntity;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Monster;
import org.bukkit.entity.Player;
import org.bukkit.entity.Projectile;
import org.bukkit.entity.*;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.entity.EntityDamageByEntityEvent;
import org.bukkit.event.entity.EntityDamageEvent;
import org.bukkit.event.entity.EntityDeathEvent;
import org.bukkit.event.entity.EntityTargetLivingEntityEvent;
import org.bukkit.event.entity.*;
import org.bukkit.projectiles.ProjectileSource;
import static com.songoda.epicenchants.enums.TriggerType.*;
@ -110,6 +104,9 @@ public class EntityListener implements Listener {
case ENTITY_EXPLOSION:
instance.getEnchantUtils().handlePlayer(((Player) event.getEntity()), null, event, EXPLOSION_DAMAGE);
break;
case POISON:
instance.getEnchantUtils().handlePlayer(((Player) event.getEntity()), null, event, POISON_DAMAGE);
break;
}
}

View File

@ -1,49 +0,0 @@
package com.songoda.epicenchants.listeners;
import com.songoda.epicenchants.EpicEnchants;
import de.tr7zw.itemnbtapi.NBTItem;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.inventory.InventoryAction;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.event.inventory.InventoryType;
public class WhiteScrollListener implements Listener {
private final EpicEnchants instance;
public WhiteScrollListener(EpicEnchants instance) {
this.instance = instance;
}
@EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST)
public void onInventoryClick(InventoryClickEvent event) {
if (event.getCursor() == null || event.getCurrentItem() == null || event.getAction() != InventoryAction.SWAP_WITH_CURSOR || event.getClickedInventory().getType() == InventoryType.CREATIVE) {
return;
}
NBTItem nbtItem = new NBTItem(event.getCursor());
NBTItem toApplyTo = new NBTItem(event.getCurrentItem());
if (nbtItem == null) {
return;
}
if (!nbtItem.getBoolean("white-scroll")) {
return;
}
if (toApplyTo.hasKey("protected")) {
event.getWhoClicked().sendMessage(instance.getLocale().getMessageWithPrefix("whitescroll.alreadyapplied"));
return;
}
toApplyTo.setBoolean("protected", true);
event.getWhoClicked().sendMessage(instance.getLocale().getMessageWithPrefix("whitescroll.applied"));
//TODO: add lore
event.getWhoClicked().setItemOnCursor(null);
event.getClickedInventory().setItem(event.getSlot(), toApplyTo.getItem());
}
}

View File

@ -0,0 +1,42 @@
package com.songoda.epicenchants.listeners.item;
import com.songoda.epicenchants.EpicEnchants;
import com.songoda.epicenchants.objects.Enchant;
import de.tr7zw.itemnbtapi.NBTCompound;
import de.tr7zw.itemnbtapi.NBTItem;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.inventory.ItemStack;
import static com.songoda.epicenchants.utils.single.GeneralUtils.getRandomElement;
public class BlackScrollListener extends ItemListener {
public BlackScrollListener(EpicEnchants instance) {
super(instance);
}
@Override
void onApply(InventoryClickEvent event, NBTItem cursor, NBTItem current) {
if (!cursor.hasKey("black-scroll") || !cursor.getBoolean("black-scroll")) {
return;
}
event.setCancelled(true);
NBTCompound compound = current.getCompound("enchants");
if (compound == null || compound.getKeys().isEmpty()) {
instance.getAction().perform(event.getWhoClicked(), "blackscroll.noenchants");
return;
}
String id = getRandomElement(compound.getKeys());
int level = compound.getInteger(id);
Enchant enchant = instance.getEnchantManager().getValueUnsafe(id);
ItemStack toSet = instance.getEnchantUtils().removeEnchant(event.getCurrentItem(), enchant);
event.getWhoClicked().getInventory().addItem(enchant.getBook().get(enchant, level, cursor.getInteger("success-rate"), 100));
event.setCurrentItem(toSet);
instance.getAction().perform(event.getWhoClicked(), "blackscroll.success");
useItem(event);
}
}

View File

@ -0,0 +1,91 @@
package com.songoda.epicenchants.listeners.item;
import com.songoda.epicenchants.EpicEnchants;
import com.songoda.epicenchants.enums.EnchantResult;
import com.songoda.epicenchants.events.EnchantApplyEvent;
import com.songoda.epicenchants.objects.Enchant;
import com.songoda.epicenchants.objects.Group;
import com.songoda.epicenchants.utils.single.GeneralUtils;
import de.tr7zw.itemnbtapi.NBTItem;
import org.apache.commons.lang3.tuple.Pair;
import org.bukkit.Bukkit;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.inventory.ItemStack;
import java.util.Optional;
import static com.songoda.epicenchants.enums.EnchantResult.*;
import static com.songoda.epicenchants.objects.Placeholder.of;
public class BookListener extends ItemListener {
public BookListener(EpicEnchants instance) {
super(instance);
}
@Override
void onApply(InventoryClickEvent event, NBTItem cursor, NBTItem current) {
if (!cursor.hasKey("book-item") || !cursor.getBoolean("book-item")) {
return;
}
event.setCancelled(true);
ItemStack toApply = event.getCurrentItem();
Enchant enchant = instance.getEnchantManager().getValue(cursor.getString("enchant")).orElseThrow(() -> new IllegalStateException("Book without enchant!"));
if (!enchant.getItemWhitelist().contains(current.getItem().getType())) {
return;
}
int level = cursor.getInteger("level");
int successRate = cursor.getInteger("success-rate");
int destroyRate = cursor.getInteger("destroy-rate");
EnchantApplyEvent enchantEvent = new EnchantApplyEvent(toApply, enchant, level, successRate, destroyRate);
Bukkit.getPluginManager().callEvent(enchantEvent);
if (enchantEvent.isCancelled()) {
return;
}
Pair<ItemStack, EnchantResult> result = instance.getEnchantUtils().apply(toApply, enchant, enchantEvent.getLevel(), enchantEvent.getSuccessRate(), enchantEvent.getDestroyRate());
instance.getAction().perform(event.getWhoClicked(), GeneralUtils.getMessageFromResult(result.getRight()),
of("enchant", enchant.getIdentifier()));
if (result.getRight() == BROKEN_FAILURE) {
event.getClickedInventory().clear(event.getSlot());
}
if (result.getRight() != CONFLICT && result.getRight() != MAXED_OUT && result.getRight() != ALREADY_APPLIED) {
useItem(event);
}
event.getClickedInventory().setItem(event.getSlot(), result.getLeft());
}
@Override
void onClick(PlayerInteractEvent event, NBTItem clicked) {
if (!clicked.hasKey("mystery-book") || !clicked.getBoolean("mystery-book")) {
return;
}
event.setCancelled(true);
if (event.getPlayer().getInventory().firstEmpty() == -1) {
return;
}
Group group = instance.getGroupManager().getValueUnsafe(clicked.getString("group"));
Optional<Enchant> enchant = instance.getEnchantManager().getRandomEnchant(group);
if (!enchant.isPresent()) {
instance.getAction().perform(event.getPlayer(), "event.purchase.noenchant");
return;
}
useItem(event);
event.getPlayer().getInventory().addItem(enchant.get().getBook().get(enchant.get()));
}
}

View File

@ -0,0 +1,65 @@
package com.songoda.epicenchants.listeners.item;
import com.songoda.epicenchants.EpicEnchants;
import com.songoda.epicenchants.objects.Enchant;
import com.songoda.epicenchants.objects.Group;
import de.tr7zw.itemnbtapi.NBTItem;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.event.player.PlayerInteractEvent;
import java.util.concurrent.ThreadLocalRandom;
public class DustListener extends ItemListener {
public DustListener(EpicEnchants instance) {
super(instance);
}
@Override
void onApply(InventoryClickEvent event, NBTItem cursor, NBTItem current) {
if (!cursor.hasKey("dust") || !cursor.getBoolean("dust")) {
return;
}
if (!current.hasKey("book-item") || !current.getBoolean("book-item")) {
return;
}
Enchant enchant = instance.getEnchantManager().getValue(current.getString("enchant")).orElseThrow(() -> new IllegalStateException("Book without enchant!"));
if (!enchant.getGroup().equals(instance.getGroupManager().getValue(cursor.getString("group")).orElseThrow(() -> new IllegalStateException("Dust without group!")))) {
return;
}
int successRate = current.getInteger("success-rate");
if (successRate == 100) {
return;
}
successRate = successRate + cursor.getInteger("percentage") > 100 ? 100 : successRate + cursor.getInteger("percentage");
event.setCurrentItem(enchant.getBook().get(enchant, current.getInteger("level"), successRate, current.getInteger("destroy-rate")));
event.setCancelled(true);
useItem(event);
}
@Override
void onClick(PlayerInteractEvent event, NBTItem clicked) {
if (!clicked.hasKey("secret-dust") || !clicked.getBoolean("secret-dust")) {
return;
}
event.setCancelled(true);
if (event.getPlayer().getInventory().firstEmpty() == -1) {
return;
}
Group group = instance.getGroupManager().getValueUnsafe(clicked.getString("group"));
int rate = ThreadLocalRandom.current().nextInt(clicked.getInteger("min-rate"), clicked.getInteger("max-rate"));
useItem(event);
event.getPlayer().getInventory().addItem(instance.getSpecialItems().getDust(group, null, rate));
}
}

View File

@ -0,0 +1,78 @@
package com.songoda.epicenchants.listeners.item;
import com.songoda.epicenchants.EpicEnchants;
import de.tr7zw.itemnbtapi.NBTItem;
import org.bukkit.Material;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.block.Action;
import org.bukkit.event.inventory.InventoryAction;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.inventory.EquipmentSlot;
import org.bukkit.inventory.ItemStack;
public abstract class ItemListener implements Listener {
final EpicEnchants instance;
ItemListener(EpicEnchants instance) {
this.instance = instance;
}
abstract void onApply(InventoryClickEvent event, NBTItem cursor, NBTItem current);
void onClick(PlayerInteractEvent event, NBTItem clicked) {
}
@EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST)
public void onInventoryClick(InventoryClickEvent event) {
if (event.getCursor() == null || event.getCurrentItem() == null || event.getAction() != InventoryAction.SWAP_WITH_CURSOR) {
return;
}
onApply(event, new NBTItem(event.getCursor()), new NBTItem(event.getCurrentItem()));
}
@EventHandler(priority = EventPriority.HIGHEST)
public void onPlayerInteract(PlayerInteractEvent event) {
if (event.getAction() == Action.LEFT_CLICK_BLOCK || event.getAction() == Action.LEFT_CLICK_AIR) {
return;
}
if (event.getItem() == null || event.getItem().getType() == Material.AIR) {
return;
}
onClick(event, new NBTItem(event.getItem()));
}
void useItem(InventoryClickEvent event) {
if (event.getCursor().getAmount() > 1) {
ItemStack cursor = event.getCursor();
cursor.setAmount(cursor.getAmount() - 1);
event.getWhoClicked().setItemOnCursor(cursor);
return;
}
event.getWhoClicked().setItemOnCursor(null);
}
void useItem(PlayerInteractEvent event) {
int slot = event.getPlayer().getInventory().getHeldItemSlot();
try {
if (event.getHand() == EquipmentSlot.OFF_HAND) slot = 40;
} catch (Exception ignore) {
}
if (event.getItem().getAmount() > 1) {
ItemStack item = event.getItem();
item.setAmount(item.getAmount() - 1);
event.getPlayer().getInventory().setItem(slot, item);
return;
}
event.getPlayer().getInventory().clear(slot);
}
}

View File

@ -0,0 +1,36 @@
package com.songoda.epicenchants.listeners.item;
import com.songoda.epicenchants.EpicEnchants;
import com.songoda.epicenchants.utils.objects.ItemBuilder;
import de.tr7zw.itemnbtapi.NBTItem;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.inventory.ItemStack;
public class WhiteScrollListener extends ItemListener {
public WhiteScrollListener(EpicEnchants instance) {
super(instance);
}
@Override
void onApply(InventoryClickEvent event, NBTItem cursor, NBTItem current) {
if (!cursor.hasKey("white-scroll") || !cursor.getBoolean("white-scroll")) {
return;
}
event.setCancelled(true);
if (current.hasKey("protected")) {
instance.getAction().perform(event.getWhoClicked(), "white-scroll.already-applied");
return;
}
current.setBoolean("protected", true);
instance.getAction().perform(event.getWhoClicked(), "white-scroll.applied");
ItemStack toSet = new ItemBuilder(current.getItem()).addLore(instance.getSpecialItems().getWhiteScrollLore()).build();
event.getClickedInventory().setItem(event.getSlot(), toSet);
useItem(event);
}
}

View File

@ -0,0 +1,79 @@
package com.songoda.epicenchants.managers;
import co.aikar.commands.BukkitCommandManager;
import co.aikar.commands.InvalidCommandArgument;
import com.songoda.epicenchants.EpicEnchants;
import com.songoda.epicenchants.commands.EnchantCommand;
import com.songoda.epicenchants.enums.GiveType;
import com.songoda.epicenchants.objects.Enchant;
import com.songoda.epicenchants.objects.Group;
import java.io.File;
import java.util.Arrays;
import java.util.Collections;
import java.util.Objects;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
public class CommandManager extends BukkitCommandManager {
public CommandManager(EpicEnchants instance) {
super(instance);
// DEPENDENCIES
registerDependency(EpicEnchants.class, "instance", instance);
// COMPLETIONS
getCommandCompletions().registerCompletion("enchants", c ->
instance.getEnchantManager().getValues().stream().map(Enchant::getIdentifier).collect(Collectors.toList()));
getCommandCompletions().registerCompletion("enchantFiles", c ->
instance.getFileManager().getYmlFiles("enchants").orElse(Collections.emptyList()).stream().map(File::getName).collect(Collectors.toList()));
getCommandCompletions().registerCompletion("giveType", c ->
Arrays.stream(GiveType.values()).map(s -> s.toString().replace("_", "").toLowerCase()).collect(Collectors.toList()));
getCommandCompletions().registerCompletion("levels", c ->
IntStream.rangeClosed(1, c.getContextValue(Enchant.class).getMaxLevel()).boxed().map(Objects::toString).collect(Collectors.toList()));
getCommandCompletions().registerCompletion("increment", c ->
IntStream.rangeClosed(0, 100).filter(i -> i % 10 == 0).boxed().map(Objects::toString).collect(Collectors.toList()));
getCommandCompletions().registerCompletion("groups", c ->
instance.getGroupManager().getValues().stream().map(Group::getIdentifier).collect(Collectors.toList()));
getCommandCompletions().registerCompletion("dustTypes", c ->
instance.getFileManager().getConfiguration("items/dusts.yml").getConfigurationSection("dusts").getKeys(false));
// CONTEXTS
getCommandContexts().registerContext(Enchant.class, c ->
instance.getEnchantManager().getValue(c.popFirstArg()).orElseThrow(() ->
new InvalidCommandArgument("No enchant exists by that name", false)));
getCommandContexts().registerContext(GiveType.class, c -> Arrays.stream(GiveType.values())
.filter(s -> s.toString().toLowerCase().replace("_", "").equalsIgnoreCase(c.popFirstArg()))
.findFirst()
.orElseThrow(() -> new InvalidCommandArgument("No item by that type.", false)));
getCommandContexts().registerContext(Group.class, c -> instance.getGroupManager().getValue(c.popFirstArg()).orElseThrow(() ->
new InvalidCommandArgument("No group exists by that name", false)));
// REPLACEMENTS
getCommandReplacements().addReplacements(
"enchanter", instance.getConfig().getString("commands.enchanter"),
"alchemist", instance.getConfig().getString("commands.alchemist"),
"tinkerer", instance.getConfig().getString("commands.tinkerer")
);
// API
enableUnstableAPI("help");
// COMMANDS
registerCommand(new EnchantCommand());
}
}

View File

@ -7,31 +7,21 @@ import org.bukkit.Bukkit;
import org.bukkit.configuration.file.YamlConfiguration;
import java.io.File;
import java.util.*;
import java.util.Collection;
import java.util.Collections;
import java.util.Optional;
import java.util.stream.Collectors;
import static com.songoda.epicenchants.utils.ConfigParser.parseEnchant;
import static java.io.File.separator;
import static com.songoda.epicenchants.utils.single.ConfigParser.parseEnchant;
public class EnchantManager {
private final Map<String, Enchant> enchantMap;
private final EpicEnchants instance;
public class EnchantManager extends Manager<String, Enchant> {
public EnchantManager(EpicEnchants instance) {
this.instance = instance;
this.enchantMap = new HashMap<>();
}
public Optional<Enchant> getEnchant(String identifier) {
return Optional.ofNullable(enchantMap.get(identifier));
}
public void addEnchant(Enchant enchant) {
enchantMap.put(enchant.getIdentifier(), enchant);
super(instance);
}
public Collection<Enchant> getEnchants(Group group) {
return Collections.unmodifiableCollection(enchantMap.values().stream().filter(s -> s.getGroup().equals(group)).collect(Collectors.toList()));
return Collections.unmodifiableCollection(getValues().stream().filter(s -> s.getGroup().equals(group)).collect(Collectors.toList()));
}
public Optional<Enchant> getRandomEnchant(Group group) {
@ -39,15 +29,6 @@ public class EnchantManager {
return tierList.stream().skip((int) (tierList.size() * Math.random())).findFirst();
}
public Collection<Enchant> getEnchants() {
return Collections.unmodifiableCollection(enchantMap.values());
}
public Enchant getEnchantUnsafe(String identifier) {
return getEnchant(identifier).orElse(null);
}
public void loadEnchants() {
instance.getFileManager().getYmlFiles("enchants").ifPresent(list -> list.forEach(file -> {
try {
@ -61,12 +42,9 @@ public class EnchantManager {
}
public void loadEnchant(File file) throws Exception {
addEnchant(parseEnchant(instance, YamlConfiguration.loadConfiguration(file)));
Enchant enchant = parseEnchant(instance, YamlConfiguration.loadConfiguration(file));
add(enchant.getIdentifier(), enchant);
}
public Optional<File> getEnchantFile(String path) {
File file = new File(instance.getDataFolder() + separator + "enchants" + separator + path);
return file.exists() ? Optional.of(file) : Optional.empty();
}
}

View File

@ -2,6 +2,7 @@ package com.songoda.epicenchants.managers;
import com.songoda.epicenchants.EpicEnchants;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.tuple.Pair;
import org.bukkit.Bukkit;
import org.bukkit.configuration.InvalidConfigurationException;
import org.bukkit.configuration.file.FileConfiguration;
@ -15,27 +16,31 @@ import static java.io.File.separator;
import static java.util.Arrays.asList;
import static org.apache.commons.lang3.tuple.Pair.of;
public class FileManager {
private final EpicEnchants instance;
private final Map<String, FileConfiguration> configurationMap;
public class FileManager extends Manager<String, FileConfiguration> {
private final LinkedHashSet<Pair<String, Boolean>> files = new LinkedHashSet<>(asList(of("menus/main-info-menu.yml", true),
of("menus/enchanter-menu.yml", true),
of("menus/tinkerer-menu.yml", true),
of("menus/groups/simple-menu.yml", false),
of("menus/groups/unique-menu.yml", false),
of("menus/groups/elite-menu.yml", false),
of("menus/groups/ultimate-menu.yml", false),
of("menus/groups/legendary-menu.yml", false),
of("enchants/example-enchant.yml", false),
of("config.yml", true),
of("groups.yml", true),
of("actions.yml", true),
of("items/special-items.yml", true),
of("items/dusts.yml", true)
));
public FileManager(EpicEnchants instance) {
this.instance = instance;
this.configurationMap = new HashMap<>();
super(instance);
}
public void createFiles() {
public void loadFiles() {
Set<String> recentDirs = new HashSet<>();
asList(of("menus/main-info-menu.yml", true),
of("menus/enchanter-menu.yml", true),
of("menus/groups/simple-menu.yml", false),
of("menus/groups/unique-menu.yml", false),
of("menus/groups/elite-menu.yml", false),
of("menus/groups/ultimate-menu.yml", false),
of("menus/groups/legendary-menu.yml", false),
of("enchants/example-enchant.yml", false),
of("config.yml", true),
of("groups.yml", true)).forEach(pair -> {
files.forEach(pair -> {
File file = new File(instance.getDataFolder() + separator + pair.getLeft());
if (!file.exists() && (pair.getRight() || (!file.getParent().equals(instance.getDataFolder().getPath())
@ -57,13 +62,13 @@ public class FileManager {
} catch (IOException | InvalidConfigurationException e) {
e.printStackTrace();
}
configurationMap.put(pair.getLeft().replace(".yml", ""), configuration);
add(pair.getLeft().replace(".yml", ""), configuration);
}
});
}
public FileConfiguration getConfiguration(String key) {
return configurationMap.get(key);
return getValueUnsafe(key);
}
public Optional<List<File>> getYmlFiles(String directory) {

View File

@ -2,34 +2,19 @@ package com.songoda.epicenchants.managers;
import com.songoda.epicenchants.EpicEnchants;
import com.songoda.epicenchants.objects.Group;
import com.songoda.epicenchants.utils.ConfigParser;
import com.songoda.epicenchants.utils.single.ConfigParser;
import org.bukkit.configuration.ConfigurationSection;
import java.util.*;
public class GroupManager {
private final Map<String, Group> groupMap;
private final EpicEnchants instance;
public class GroupManager extends Manager<String, Group> {
public GroupManager(EpicEnchants instance) {
this.instance = instance;
this.groupMap = new HashMap<>();
}
public Optional<Group> getGroup(String identifier) {
return Optional.ofNullable(groupMap.get(identifier));
}
public void addGroup(Group group) {
groupMap.put(group.getIdentifier(), group);
super(instance);
}
public void loadGroups() {
ConfigurationSection config = instance.getFileManager().getConfiguration("groups").getConfigurationSection("groups");
config.getKeys(false).forEach(key -> addGroup(ConfigParser.parseGroup(config.getConfigurationSection(key))));
config.getKeys(false).forEach(key -> {
Group group = ConfigParser.parseGroup(config.getConfigurationSection(key));
add(group.getIdentifier(), group);
});
}
public Collection<Group> getGroups() {
return Collections.unmodifiableCollection(groupMap.values());
}
}
}

View File

@ -31,7 +31,7 @@ public class InfoManager {
instance.getFileManager().getYmlFiles("menus/groups").ifPresent(list -> list.forEach(file -> {
try {
YamlConfiguration config = YamlConfiguration.loadConfiguration(file);
infoMenus.put(instance.getGroupManager().getGroup(config.getString("group"))
infoMenus.put(instance.getGroupManager().getValue(config.getString("group"))
.orElseThrow(() -> new IllegalArgumentException("Invalid group: " + config.getString("group"))), new InfoMenu(instance, config));
} catch (Exception e) {
Bukkit.getConsoleSender().sendMessage("Something went wrong loading the menu from file " + file.getName());

View File

@ -0,0 +1,33 @@
package com.songoda.epicenchants.managers;
import com.songoda.epicenchants.EpicEnchants;
import java.util.*;
public abstract class Manager<K, V> {
final EpicEnchants instance;
private final Map<K, V> map;
public Manager(EpicEnchants instance) {
this.instance = instance;
this.map = new HashMap<>();
}
public Optional<V> getValue(K key) {
return Optional.ofNullable(map.get(key));
}
public void add(K key, V value) {
map.put(key, value);
}
public V getValueUnsafe(K key) {
return getValue(key).orElse(null);
}
public Collection<V> getValues() {
return Collections.unmodifiableCollection(map.values());
}
}

View File

@ -0,0 +1,34 @@
package com.songoda.epicenchants.menus;
import com.songoda.epicenchants.EpicEnchants;
import com.songoda.epicenchants.utils.objects.FastInv;
import com.songoda.epicenchants.utils.objects.ItemBuilder;
import org.bukkit.Material;
import org.bukkit.configuration.file.FileConfiguration;
import static com.songoda.epicenchants.utils.single.GeneralUtils.*;
public class AlchemistMenu extends FastInv {
public AlchemistMenu(EpicEnchants instance, FileConfiguration config) {
super(config.getInt("rows") * 9, color(config.getString("title")));
if (config.isConfigurationSection("fill")) {
fill(new ItemBuilder(config.getConfigurationSection("fill")).build());
}
config.getConfigurationSection("contents").getKeys(false)
.stream()
.map(s -> "contents." + s)
.map(config::getConfigurationSection)
.forEach(section -> {
addItem(getSlots(config.getString("slot")), new ItemBuilder(section).build(), event -> {
if (section.getName().equalsIgnoreCase("left-item") || section.getName().equalsIgnoreCase("right-item")) {
if (getInventory().getItem(event.getSlot()) != null && getInventory().getItem(event.getSlot()).getType() != Material.AIR) {
event.getPlayer().getInventory().addItem(getInventory().getItem(event.getSlot()));
getInventory().clear(event.getSlot());
}
}
});
});
}
}

View File

@ -1,20 +1,16 @@
package com.songoda.epicenchants.menus;
import com.songoda.epicenchants.EpicEnchants;
import com.songoda.epicenchants.objects.Enchant;
import com.songoda.epicenchants.objects.Group;
import com.songoda.epicenchants.utils.FastInv;
import com.songoda.epicenchants.utils.ItemBuilder;
import com.songoda.epicenchants.utils.objects.FastInv;
import com.songoda.epicenchants.utils.objects.ItemBuilder;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import java.util.Optional;
import static com.songoda.epicenchants.objects.Placeholder.of;
import static com.songoda.epicenchants.utils.Experience.changeExp;
import static com.songoda.epicenchants.utils.Experience.getExp;
import static com.songoda.epicenchants.utils.GeneralUtils.color;
import static com.songoda.epicenchants.utils.single.Experience.*;
import static com.songoda.epicenchants.utils.single.GeneralUtils.*;
public class EnchanterMenu extends FastInv {
public EnchanterMenu(EpicEnchants instance, FileConfiguration config, Player player) {
@ -33,7 +29,7 @@ public class EnchanterMenu extends FastInv {
double ecoCost = section.getDouble("eco-cost");
double xpLeft = expCost - player.getLevel() < 0 ? 0 : expCost - player.getLevel();
double ecoLeft = ecoCost - instance.getEconomy().getBalance(player) < 0 ? 0 : ecoCost - instance.getEconomy().getBalance(player);
Group group = instance.getGroupManager().getGroup(section.getString("group").toUpperCase())
Group group = instance.getGroupManager().getValue(section.getString("group").toUpperCase())
.orElseThrow(() -> new IllegalArgumentException("Invalid group set in enchanter: " + section.getString("group")));
ItemStack itemStack = new ItemBuilder(section,
of("exp_cost", expCost),
@ -41,24 +37,17 @@ public class EnchanterMenu extends FastInv {
of("exp_left", xpLeft),
of("eco_left", ecoLeft)).build();
addItem(section.getInt("slot"), itemStack, event -> {
addItem(getSlots(section.getString("slot")), itemStack, event -> {
if (!instance.getEconomy().has((player), ecoCost) || getExp(player) < expCost) {
player.sendMessage(instance.getLocale().getPrefix() + instance.getLocale().getMessage("event.purchase.cannotafford"));
return;
}
Optional<Enchant> enchant = instance.getEnchantManager().getRandomEnchant(group);
if (!enchant.isPresent()) {
player.sendMessage(instance.getLocale().getPrefix() + instance.getLocale().getMessage("event.purchase.noenchant"));
instance.getAction().perform(player, "enchanter.cannot-afford");
return;
}
instance.getEconomy().withdrawPlayer(player, ecoCost);
instance.getAction().perform(player, "event.purchase.success", of("group-name", group.getName()), of("group_color", group.getColor()));
changeExp(player, (int) -expCost);
player.getInventory().addItem(enchant.get().getBookItem().get(enchant.get()));
player.sendMessage(instance.getLocale().getMessageWithPrefix("event.purchase.success", of("group-name", group.getName())));
player.getInventory().addItem(instance.getSpecialItems().getMysteryBook(group));
});
});
}

View File

@ -3,8 +3,8 @@ package com.songoda.epicenchants.menus;
import com.songoda.epicenchants.EpicEnchants;
import com.songoda.epicenchants.objects.Enchant;
import com.songoda.epicenchants.objects.Group;
import com.songoda.epicenchants.utils.FastInv;
import com.songoda.epicenchants.utils.ItemBuilder;
import com.songoda.epicenchants.utils.objects.FastInv;
import com.songoda.epicenchants.utils.objects.ItemBuilder;
import org.apache.commons.lang.StringUtils;
import org.bukkit.configuration.file.FileConfiguration;
@ -13,14 +13,14 @@ import java.util.Set;
import java.util.stream.Collectors;
import static com.songoda.epicenchants.objects.Placeholder.of;
import static com.songoda.epicenchants.utils.GeneralUtils.color;
import static com.songoda.epicenchants.utils.single.GeneralUtils.color;
import static java.util.Arrays.stream;
public class InfoMenu extends FastInv {
public InfoMenu(EpicEnchants instance, FileConfiguration config) {
super(config.getInt("size"), color(config.getString("title")));
Group group = instance.getGroupManager().getGroup(config.getString("group")).orElseThrow(() -> new IllegalArgumentException("Invalid group: " + config.getString("group")));
Group group = instance.getGroupManager().getValue(config.getString("group")).orElseThrow(() -> new IllegalArgumentException("Invalid group: " + config.getString("group")));
String[] split = config.getString("slots").split(",");
Set<Integer> slots = stream(split, 0, split.length)

View File

@ -2,11 +2,11 @@ package com.songoda.epicenchants.menus;
import com.songoda.epicenchants.EpicEnchants;
import com.songoda.epicenchants.objects.Group;
import com.songoda.epicenchants.utils.FastInv;
import com.songoda.epicenchants.utils.ItemBuilder;
import com.songoda.epicenchants.utils.objects.FastInv;
import com.songoda.epicenchants.utils.objects.ItemBuilder;
import org.bukkit.configuration.file.FileConfiguration;
import static com.songoda.epicenchants.utils.GeneralUtils.color;
import static com.songoda.epicenchants.utils.single.GeneralUtils.color;
public class MainInfoMenu extends FastInv {
@ -18,7 +18,7 @@ public class MainInfoMenu extends FastInv {
.map(config::getConfigurationSection)
.forEach(section -> {
addItem(section.getInt("slot"), new ItemBuilder(section).build(), event -> {
Group group = instance.getGroupManager().getGroup(section.getString("group"))
Group group = instance.getGroupManager().getValue(section.getString("group"))
.orElseThrow(() -> new IllegalArgumentException("Invalid group: " + section.getString("group")));
instance.getInfoManager().getMenu(group).ifPresent(menu -> menu.open(event.getPlayer()));
});

View File

@ -0,0 +1,235 @@
package com.songoda.epicenchants.menus;
import com.songoda.epicenchants.EpicEnchants;
import com.songoda.epicenchants.enums.ItemType;
import com.songoda.epicenchants.objects.Enchant;
import com.songoda.epicenchants.utils.objects.FastInv;
import com.songoda.epicenchants.utils.objects.ItemBuilder;
import de.tr7zw.itemnbtapi.NBTCompound;
import de.tr7zw.itemnbtapi.NBTItem;
import org.bukkit.Material;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.event.inventory.InventoryType;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
import static com.songoda.epicenchants.enums.ItemType.*;
import static com.songoda.epicenchants.objects.Placeholder.of;
import static com.songoda.epicenchants.utils.single.GeneralUtils.*;
import static java.util.Arrays.stream;
public class TinkererMenu extends FastInv {
private final Map<Integer, Integer> slotMap;
private final EpicEnchants instance;
private final FileConfiguration config;
public TinkererMenu(EpicEnchants instance, FileConfiguration config) {
super(config.getInt("rows") * 9, color(config.getString("title")));
this.slotMap = getSlotMap(config);
this.instance = instance;
this.config = config;
if (config.isConfigurationSection("fill")) {
fill(new ItemBuilder(config.getConfigurationSection("fill")).build());
}
config.getConfigurationSection("contents").getKeys(false)
.stream()
.map(s -> "contents." + s)
.map(config::getConfigurationSection)
.forEach(section -> {
addItem(getSlots(section.getString("slot")), new ItemBuilder(section).build(), event -> {
if (section.getName().equalsIgnoreCase("accept-left") || section.getName().equalsIgnoreCase("accept-right")) {
slotMap.values().stream().map(slot -> getInventory().getItem(slot)).filter(Objects::nonNull).forEach(event.getPlayer().getInventory()::addItem);
slotMap.keySet().forEach(slot -> getInventory().clear(slot));
event.getPlayer().closeInventory();
instance.getAction().perform(event.getPlayer(), "tinkerer.accepted");
return;
}
if (section.getName().equalsIgnoreCase("deposit-all")) {
int count = (int) stream(event.getPlayer().getInventory().getContents()).filter(i -> isTinkerable(i) != NONE).count();
if (count == 0) {
instance.getAction().perform(event.getPlayer(), "tinkerer.no-items");
return;
}
Inventory inventory = event.getPlayer().getInventory();
int amount = 0;
for (int i = 0; i < inventory.getSize(); i++) {
ItemStack itemStack = inventory.getItem(i);
ItemType itemType = isTinkerable(itemStack);
if (itemType == NONE) {
continue;
}
for (int j = 0; j < itemStack.getAmount(); j++) {
if (!handleItem(itemStack, itemType)) {
continue;
}
amount++;
if (itemStack.getAmount() > 1) {
itemStack.setAmount(itemStack.getAmount() - 1);
inventory.setItem(i, itemStack);
continue;
}
inventory.clear(i);
}
}
instance.getAction().perform(event.getPlayer(), "tinkerer.deposited-all", of("amount", amount));
}
});
});
// Player clicked an item in tinkerer
onClick(event -> {
if (event.getEvent().getClickedInventory() == null) {
return;
}
int slot = event.getSlot();
if (!slotMap.keySet().contains(slot)) {
return;
}
if (getInventory().getItem(slot) != null && getInventory().getItem(slot).getType() != Material.AIR) {
event.getPlayer().getInventory().addItem(getInventory().getItem(slot));
getInventory().clear(slot);
getInventory().clear(slotMap.get(slot));
}
});
// Player clicked his own inv
onClick(event -> {
if (event.getEvent().getClickedInventory() == null || event.getEvent().getClickedInventory().getType() != InventoryType.PLAYER) {
return;
}
ItemStack itemStack = event.getItem();
ItemType itemType = isTinkerable(itemStack);
if (itemType == NONE) {
return;
}
if (handleItem(itemStack, itemType)) {
if (itemStack.getAmount() > 1) {
itemStack.setAmount(itemStack.getAmount() - 1);
return;
}
event.getEvent().getClickedInventory().clear(event.getEvent().getSlot());
}
});
onClose(event -> slotMap.keySet().stream().filter(s -> getInventory().getItem(s) != null).forEach(s -> {
instance.getAction().perform(event.getPlayer(), "tinkerer.cancelled");
event.getPlayer().getInventory().addItem(getInventory().getItem(s));
}));
}
private ItemType isTinkerable(ItemStack itemStack) {
if (itemStack == null || itemStack.getType() == Material.AIR) {
return NONE;
}
NBTItem nbtItem = new NBTItem(itemStack);
if (nbtItem.hasKey("book-item")) {
return BOOK;
}
if (!instance.getHookManager().getUltimateBottles().isPresent()) {
return NONE;
}
if (!itemStack.getEnchantments().isEmpty() || (nbtItem.getCompound("enchants") != null && !nbtItem.getCompound("enchants").getKeys().isEmpty())) {
if (getExpAmount(itemStack) == 0) {
return NONE;
}
return ENCHANTED;
}
return NONE;
}
private boolean handleItem(ItemStack itemStack, ItemType itemType) {
Optional<Map.Entry<Integer, Integer>> emptySlot = slotMap.entrySet().stream().filter(slot -> getInventory().getItem(slot.getKey()) == null || getInventory().getItem(slot.getKey()).getType() == Material.AIR).findFirst();
if (!emptySlot.isPresent()) {
return false;
}
ItemStack finalItemStack = itemStack.clone();
finalItemStack.setAmount(1);
addItem(emptySlot.get().getKey(), finalItemStack);
switch (itemType) {
case BOOK:
getInventory().setItem(emptySlot.get().getValue(), instance.getSpecialItems().getSecretDust(new NBTItem(finalItemStack)));
break;
case ENCHANTED:
getInventory().setItem(emptySlot.get().getValue(), instance.getHookManager().getUltimateBottles().get().createBottle("Tinkerer", getExpAmount(finalItemStack)));
break;
}
return true;
}
private LinkedHashMap<Integer, Integer> getSlotMap(FileConfiguration config) {
return stream(config.getString("slots").split(" ")).map(s -> s.replace(")", "").replace("(", ""))
.collect(Collectors.toMap(
s -> Integer.parseInt(s.split(",")[0]),
s -> Integer.parseInt(s.split(",")[1]),
(u, v) -> {
throw new IllegalStateException(String.format("Duplicate key %s", u));
},
LinkedHashMap::new)
);
}
private int getExpAmount(ItemStack itemStack) {
AtomicInteger total = new AtomicInteger();
ConfigurationSection section = config.getConfigurationSection("exp-table-per-level");
itemStack.getEnchantments().forEach((enchantment, level) -> {
total.addAndGet(section.getInt(enchantment.getName(), section.getInt("DEFAULT")) * level);
});
NBTItem nbtItem = new NBTItem(itemStack);
if (!nbtItem.hasKey("enchants")) {
return total.get();
}
NBTCompound enchantments = nbtItem.getCompound("enchants");
if (enchantments == null) {
return total.get();
}
enchantments.getKeys().forEach(key -> {
Enchant enchant = instance.getEnchantManager().getValueUnsafe(key);
total.addAndGet(section.getInt(enchant.getIdentifier(), enchant.getGroup().getTinkererExp()) * enchantments.getInteger(key));
});
return total.get();
}
}

View File

@ -1,7 +1,7 @@
package com.songoda.epicenchants.objects;
import co.aikar.commands.annotation.Optional;
import com.songoda.epicenchants.utils.ItemBuilder;
import com.songoda.epicenchants.utils.objects.ItemBuilder;
import de.tr7zw.itemnbtapi.NBTItem;
import lombok.Builder;
import org.bukkit.Material;

View File

@ -1,11 +1,13 @@
package com.songoda.epicenchants.objects;
import org.bukkit.Bukkit;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import java.util.Arrays;
public class Condition {
private final String string;
@ -18,15 +20,32 @@ public class Condition {
return new Condition(string);
}
public boolean get(Player player, int level, boolean def) {
public boolean get(Player wearer, LivingEntity attacker, int level, boolean def) {
if (string == null || string.isEmpty()) {
return true;
}
ScriptEngine scriptEngine = new ScriptEngineManager().getEngineByName("JavaScript");
String toValidate = string;
for (Placeholder pair : Arrays.asList(
Placeholder.of("level", level),
Placeholder.of("wearer_health", wearer.getHealth()),
Placeholder.of("attacker_health", attacker.getHealth()),
Placeholder.of("wearer_food", wearer.getFoodLevel()),
Placeholder.of("attacker_food", attacker instanceof Player ? ((Player) attacker).getFoodLevel() : 0),
Placeholder.of("wearer_is_sneaking", wearer.isSneaking()),
Placeholder.of("attacker_is_sneaking", attacker instanceof Player && ((Player) attacker).isSneaking()),
Placeholder.of("world", wearer.getWorld().getName()),
Placeholder.of("players_near", wearer.getNearbyEntities(4, 4, 4).size()),
Placeholder.of("wearer_on_fire", wearer.getFireTicks() != 0),
Placeholder.of("attacker_on_fire", attacker.getFireTicks() != 0)
)) {
toValidate = toValidate.replace(pair.getPlaceholder(), pair.getToReplace().toString());
}
try {
return Boolean.parseBoolean(scriptEngine.eval(string.replace("{level}", "" + level)).toString());
return Boolean.parseBoolean(scriptEngine.eval(toValidate).toString());
} catch (ScriptException | NumberFormatException e) {
Bukkit.getLogger().warning("[EpicEnchants] One of your condition expressions is not properly formatted.");
return def;

View File

@ -28,14 +28,18 @@ public class Enchant {
private Set<String> description;
@Nullable private String format;
@Nullable private BookItem bookItem;
private LeveledModifier modifyDamage;
private Condition condition;
public void onAction(@NotNull Player wearer, @Nullable LivingEntity opponent, Event event, int level, TriggerType triggerType, EventType eventType) {
if (!condition.get(wearer, opponent, level, false)) {
return;
}
effectExecutors.forEach(effect -> effect.testAndRun(wearer, opponent, level, triggerType, event, eventType));
mobs.forEach(mobWrapper -> mobWrapper.trySpawn(wearer, opponent, level, triggerType));
}
public BookItem getBookItem() {
public BookItem getBook() {
return bookItem != null ? bookItem : group.getBookItem();
}

View File

@ -13,4 +13,5 @@ public class Group {
private int slotsUsed;
private BookItem bookItem;
private int destroyRateMin, destroyRateMax, successRateMin, successRateMax;
private int tinkererExp;
}

View File

@ -5,6 +5,9 @@ import com.songoda.epicenchants.enums.EnchantResult;
import com.songoda.epicenchants.enums.EventType;
import com.songoda.epicenchants.enums.TriggerType;
import com.songoda.epicenchants.objects.Enchant;
import com.songoda.epicenchants.utils.objects.ItemBuilder;
import com.songoda.epicenchants.utils.single.GeneralUtils;
import com.songoda.epicenchants.utils.single.RomanNumber;
import de.tr7zw.itemnbtapi.NBTCompound;
import de.tr7zw.itemnbtapi.NBTItem;
import org.apache.commons.lang3.tuple.Pair;
@ -31,13 +34,12 @@ public class EnchantUtils {
}
public Pair<ItemStack, EnchantResult> apply(ItemStack itemStack, Enchant enchant, int level, int successRate, int destroyRate) {
if (!GeneralUtils.chance(successRate)) {
return GeneralUtils.chance(destroyRate) ? Pair.of(new ItemStack(Material.AIR), BROKEN_FAILURE) : Pair.of(itemStack, FAILURE);
}
boolean hasProtection = new NBTItem(itemStack).hasKey("protected");
Map<Enchant, Integer> enchantMap = getEnchants(itemStack);
if (enchantMap.keySet().stream().anyMatch(s -> enchant.getConflict().contains(s.getIdentifier()))) {
if (enchantMap.keySet().stream().anyMatch(s -> enchant.getConflict().contains(s.getIdentifier())) ||
enchant.getConflict().stream().anyMatch(s -> enchantMap.keySet().stream().map(Enchant::getIdentifier).collect(Collectors.toList()).contains(s))) {
return Pair.of(itemStack, CONFLICT);
}
@ -49,9 +51,30 @@ public class EnchantUtils {
return Pair.of(itemStack, ALREADY_APPLIED);
}
if (!GeneralUtils.chance(successRate)) {
if (GeneralUtils.chance(destroyRate)) {
if (hasProtection) {
NBTItem nbtItem = new ItemBuilder(itemStack).removeLore(instance.getSpecialItems().getWhiteScrollLore()).nbt();
nbtItem.removeKey("protected");
return Pair.of(nbtItem.getItem(), PROTECTED);
}
return Pair.of(new ItemStack(Material.AIR), BROKEN_FAILURE);
}
return Pair.of(itemStack, FAILURE);
}
ItemBuilder itemBuilder = new ItemBuilder(itemStack);
if (hasProtection) {
itemBuilder.removeLore(instance.getSpecialItems().getWhiteScrollLore());
}
itemBuilder.removeLore(enchant.getFormat().replace("{level}", "").trim());
itemBuilder.addLore(enchant.getFormat().replace("{level}", "" + level));
itemBuilder.addLore(enchant.getFormat().replace("{level}", "" + (instance.getConfig().getBoolean("roman-numbers") ? RomanNumber.toRoman(level) : level)));
if (hasProtection) {
itemBuilder.addLore(instance.getSpecialItems().getWhiteScrollLore());
}
NBTItem nbtItem = itemBuilder.nbt();
@ -64,18 +87,24 @@ public class EnchantUtils {
}
public Map<Enchant, Integer> getEnchants(ItemStack itemStack) {
if (itemStack == null) {
if (itemStack == null || itemStack.getType() == Material.AIR) {
return Collections.emptyMap();
}
NBTCompound compound = new NBTItem(itemStack).getCompound("enchants");
NBTItem nbtItem = new NBTItem(itemStack);
if (!nbtItem.hasNBTData() || nbtItem.hasKey("enchants")) {
return Collections.emptyMap();
}
NBTCompound compound = nbtItem.getCompound("enchants");
if (compound == null) {
return Collections.emptyMap();
}
return compound.getKeys().stream().filter(key -> instance.getEnchantManager().getEnchantUnsafe(key) != null)
.collect(Collectors.toMap(key -> instance.getEnchantManager().getEnchantUnsafe(key), compound::getInteger));
return compound.getKeys().stream().filter(key -> instance.getEnchantManager().getValueUnsafe(key) != null)
.collect(Collectors.toMap(key -> instance.getEnchantManager().getValueUnsafe(key), compound::getInteger));
}
public void handlePlayer(@NotNull Player player, @Nullable LivingEntity opponent, Event event, TriggerType triggerType) {
@ -91,4 +120,21 @@ public class EnchantUtils {
enchant.onAction(player, opponent, event, level, triggerType, EventType.NONE);
}));
}
public ItemStack removeEnchant(ItemStack itemStack, Enchant enchant) {
if (itemStack == null) {
return null;
}
NBTItem nbtItem = new NBTItem(itemStack);
if (nbtItem.getCompound("enchants") == null || nbtItem.getCompound("enchants").getInteger(enchant.getIdentifier()) == null) {
return itemStack;
}
nbtItem.getCompound("enchants").removeKey(enchant.getIdentifier());
ItemBuilder output = new ItemBuilder(nbtItem.getItem());
output.removeLore(enchant.getFormat().replace("{level}", "").trim());
return output.build();
}
}

View File

@ -1,43 +0,0 @@
package com.songoda.epicenchants.utils;
import com.songoda.epicenchants.enums.EnchantResult;
import org.bukkit.ChatColor;
import java.util.concurrent.ThreadLocalRandom;
public class GeneralUtils {
public static boolean chance(int chance) {
return chance((double) chance);
}
public static boolean chance(double chance) {
return ThreadLocalRandom.current().nextDouble(101) < chance;
}
public static String color(String input) {
return format(input, "", null);
}
public static String format(String input, String placeholder, Object toReplace) {
return ChatColor.translateAlternateColorCodes('&', input).replaceAll(placeholder, toReplace == null ? "" : toReplace.toString());
}
public static String getMessageFromResult(EnchantResult result) {
switch (result) {
case FAILURE:
return "enchant.failure";
case BROKEN_FAILURE:
return "enchant.brokenfailure";
case SUCCESS:
return "enchant.success";
case CONFLICT:
return "enchant.conflict";
case MAXED_OUT:
return "enchant.maxedout";
case ALREADY_APPLIED:
return "enchant.alreadyapplied";
}
return "";
}
}

View File

@ -1,12 +1,18 @@
package com.songoda.epicenchants.utils;
import com.songoda.epicenchants.EpicEnchants;
import com.songoda.epicenchants.objects.Group;
import com.songoda.epicenchants.utils.objects.ItemBuilder;
import de.tr7zw.itemnbtapi.NBTItem;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.Nullable;
import java.util.concurrent.ThreadLocalRandom;
import static com.songoda.epicenchants.objects.Placeholder.of;
import static com.songoda.epicenchants.utils.single.GeneralUtils.color;
public class SpecialItems {
private final EpicEnchants instance;
@ -16,7 +22,7 @@ public class SpecialItems {
}
public ItemStack getWhiteScroll(Integer amount) {
NBTItem nbtItem = new ItemBuilder(instance.getFileManager().getConfiguration("special-items").getConfigurationSection("white-scroll")).nbt();
NBTItem nbtItem = new ItemBuilder(instance.getFileManager().getConfiguration("items/special-items").getConfigurationSection("white-scroll")).nbt();
nbtItem.setBoolean("white-scroll", true);
ItemStack itemStack = nbtItem.getItem();
@ -28,11 +34,11 @@ public class SpecialItems {
}
public ItemStack getBlackScroll(Integer amount, Integer chance) {
int percentage = chance == null ? ThreadLocalRandom.current().nextInt(instance.getConfig().getInt("rates.black-scroll-min"), instance.getConfig().getInt("rates.black-scroll-max") + 1) : chance;
NBTItem nbtItem = new ItemBuilder(instance.getFileManager().getConfiguration("special-items").getConfigurationSection("black-scroll"), of("percentage", percentage)).nbt();
int successRate = chance == null ? ThreadLocalRandom.current().nextInt(instance.getConfig().getInt("rates.black-scroll-min"), instance.getConfig().getInt("rates.black-scroll-max") + 1) : chance;
NBTItem nbtItem = new ItemBuilder(instance.getFileManager().getConfiguration("items/special-items").getConfigurationSection("black-scroll"), of("success-rate", successRate)).nbt();
nbtItem.setBoolean("black-scroll", true);
nbtItem.setInteger("percentage", percentage);
nbtItem.setInteger("success-rate", successRate);
ItemStack itemStack = nbtItem.getItem();
@ -42,4 +48,79 @@ public class SpecialItems {
return itemStack;
}
public ItemStack getMysteryBook(Group group) {
NBTItem nbtItem = new ItemBuilder(instance.getFileManager().getConfiguration("items/special-items").getConfigurationSection("mystery-book"),
of("group-color", group.getColor()),
of("group-name", group.getName())).nbt();
nbtItem.setBoolean("mystery-book", true);
nbtItem.setString("group", group.getIdentifier());
return nbtItem.getItem();
}
public ItemStack getSecretDust(NBTItem book) {
Group group = instance.getEnchantManager().getValueUnsafe(book.getString("enchant")).getGroup();
return getSecretDust(group, (int) Math.floor(book.getInteger("success-rate") / 10.0));
}
public ItemStack getSecretDust(Group group, int max) {
NBTItem nbtItem = new ItemBuilder(instance.getFileManager().getConfiguration("items/dusts").getConfigurationSection("secret-dust"),
of("group-color", group.getColor()),
of("group-name", group.getName()),
of("max-rate", max),
of("min-rate", 0)).nbt();
nbtItem.setBoolean("secret-dust", true);
nbtItem.setString("group", group.getIdentifier());
nbtItem.setInteger("max-rate", max);
nbtItem.setInteger("min-rate", 1);
return nbtItem.getItem();
}
public ItemStack getDust(Group group, @Nullable String type, @Nullable Integer percentage) {
FileConfiguration dustConfig = instance.getFileManager().getConfiguration("items/dusts");
int random = ThreadLocalRandom.current().nextInt(101);
int counter = 0;
if (type == null) {
for (String s : dustConfig.getConfigurationSection("dusts").getKeys(false)) {
int chance = dustConfig.getConfigurationSection("dusts." + s).getInt("chance");
if (random < (chance + counter) && random >= counter) {
type = s;
}
counter += chance;
}
}
ConfigurationSection config = dustConfig.getConfigurationSection("dusts." + (type == null ? "mystery" : type));
if (config.isInt("min-rate") && config.isInt("max-rate")) {
int minRate = config.getInt("min-rate");
int maxRate = config.getInt("max-rate");
percentage = ThreadLocalRandom.current().nextInt(minRate, maxRate + 1);
} else if (percentage == null) {
percentage = ThreadLocalRandom.current().nextInt(0, 10);
}
NBTItem nbtItem = new ItemBuilder(config,
of("group-color", group.getColor()),
of("group-name", group.getName()),
of("percentage", percentage)).nbt();
if (type != null && type.equalsIgnoreCase("mystery")) {
return nbtItem.getItem();
}
nbtItem.setBoolean("dust", true);
nbtItem.setInteger("percentage", percentage);
nbtItem.setString("group", group.getIdentifier());
return nbtItem.getItem();
}
public String getWhiteScrollLore() {
return color(instance.getFileManager().getConfiguration("special-items").getConfigurationSection("white-scroll").getString("format"));
}
}

View File

@ -1,4 +1,4 @@
package com.songoda.epicenchants.utils;
package com.songoda.epicenchants.utils.objects;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
@ -12,10 +12,7 @@ import org.bukkit.inventory.ItemStack;
import org.bukkit.plugin.Plugin;
import org.bukkit.scheduler.BukkitTask;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.*;
/**
* A fast API to easily create advanced GUI.
@ -99,61 +96,58 @@ public class FastInv implements InventoryHolder {
}
}
private static Listener getListener() {
return new Listener() {
public static class FastInvClickEvent extends FastInvEvent {
private final InventoryClickEvent event;
private final InventoryAction action;
private final ClickType clickType;
private final ItemStack item;
private final int slot;
@EventHandler
public void onClick(InventoryClickEvent event) {
if (event.getInventory().getHolder() instanceof FastInv && event.getWhoClicked() instanceof Player) {
int slot = event.getRawSlot();
FastInv inv = (FastInv) event.getInventory().getHolder();
private FastInvClickEvent(Player player, FastInv inventory, InventoryClickEvent event, int slot, ItemStack item,
boolean cancelled, InventoryAction action, ClickType clickType) {
super(player, inventory, cancelled);
this.event = event;
this.slot = slot;
this.item = item;
this.action = action;
this.clickType = clickType;
}
FastInvClickEvent clickEvent = new FastInvClickEvent((Player) event.getWhoClicked(), inv, slot,
event.getCurrentItem(), true, event.getAction(), event.getClick());
/**
* @return The action of the event
*/
public InventoryAction getAction() {
return this.action;
}
if (inv.itemListeners.containsKey(slot)) {
inv.itemListeners.get(slot).onClick(clickEvent);
}
/**
* @return The click type
*/
public ClickType getClickType() {
return this.clickType;
}
inv.clickListeners.forEach(listener -> listener.onClick(clickEvent));
/**
* Get the clicked {@link ItemStack}
*
* @return The clicked item
*/
public ItemStack getItem() {
return this.item;
}
if (clickEvent.isCancelled()) {
event.setCancelled(true);
}
}
}
/**
* Get the number of the clicked slot
*
* @return The slot number
*/
public int getSlot() {
return this.slot;
}
@EventHandler
public void onClose(InventoryCloseEvent event) {
if (event.getInventory().getHolder() instanceof FastInv && event.getPlayer() instanceof Player) {
Player player = (Player) event.getPlayer();
FastInv inv = (FastInv) event.getInventory().getHolder();
FastInvCloseEvent closeEvent = new FastInvCloseEvent(player, inv, false);
inv.closeListeners.forEach(listener -> listener.onClose(closeEvent));
Bukkit.getScheduler().runTask(plugin, () -> {
// Tiny delay to prevent errors.
if (closeEvent.isCancelled() && player.isOnline()) {
player.openInventory(inv.getInventory());
} else if (inv.getInventory().getViewers().isEmpty() && inv.cancelTasksOnClose) {
inv.cancelTasks();
}
});
}
}
@EventHandler
public void onDisable(PluginDisableEvent event) {
if (event.getPlugin().equals(plugin)) {
for (Player player : Bukkit.getOnlinePlayers()) {
if (player.getOpenInventory().getTopInventory().getHolder() instanceof FastInv) {
player.closeInventory();
}
}
}
}
};
public InventoryClickEvent getEvent() {
return event;
}
}
/**
@ -420,7 +414,6 @@ public class FastInv implements InventoryHolder {
}
public static abstract class FastInvEvent {
private boolean cancelled;
private final FastInv inventory;
private final Player player;
@ -468,53 +461,61 @@ public class FastInv implements InventoryHolder {
}
}
public static class FastInvClickEvent extends FastInvEvent {
private static Listener getListener() {
return new Listener() {
private final InventoryAction action;
private final ClickType clickType;
private final ItemStack item;
private final int slot;
@EventHandler
public void onClick(InventoryClickEvent event) {
if (event.getInventory().getHolder() instanceof FastInv && event.getWhoClicked() instanceof Player) {
int slot = event.getRawSlot();
FastInv inv = (FastInv) event.getInventory().getHolder();
private FastInvClickEvent(Player player, FastInv inventory, int slot, ItemStack item,
boolean cancelled, InventoryAction action, ClickType clickType) {
super(player, inventory, cancelled);
this.slot = slot;
this.item = item;
this.action = action;
this.clickType = clickType;
}
FastInvClickEvent clickEvent = new FastInvClickEvent((Player) event.getWhoClicked(), inv, event, slot,
event.getCurrentItem(), true, event.getAction(), event.getClick());
/**
* @return The action of the event
*/
public InventoryAction getAction() {
return this.action;
}
if (inv.itemListeners.containsKey(slot)) {
inv.itemListeners.get(slot).onClick(clickEvent);
}
/**
* @return The click type
*/
public ClickType getClickType() {
return this.clickType;
}
inv.clickListeners.forEach(listener -> listener.onClick(clickEvent));
/**
* Get the clicked {@link ItemStack}
*
* @return The clicked item
*/
public ItemStack getItem() {
return this.item;
}
if (clickEvent.isCancelled()) {
event.setCancelled(true);
}
}
}
/**
* Get the number of the clicked slot
*
* @return The slot number
*/
public int getSlot() {
return this.slot;
}
@EventHandler
public void onClose(InventoryCloseEvent event) {
if (event.getInventory().getHolder() instanceof FastInv && event.getPlayer() instanceof Player) {
Player player = (Player) event.getPlayer();
FastInv inv = (FastInv) event.getInventory().getHolder();
FastInvCloseEvent closeEvent = new FastInvCloseEvent(player, inv, false);
inv.closeListeners.forEach(listener -> listener.onClose(closeEvent));
Bukkit.getScheduler().runTask(plugin, () -> {
// Tiny delay to prevent errors.
if (closeEvent.isCancelled() && player.isOnline()) {
player.openInventory(inv.getInventory());
} else if (inv.getInventory().getViewers().isEmpty() && inv.cancelTasksOnClose) {
inv.cancelTasks();
}
});
}
}
@EventHandler
public void onDisable(PluginDisableEvent event) {
if (event.getPlugin().equals(plugin)) {
for (Player player : Bukkit.getOnlinePlayers()) {
if (player.getOpenInventory().getTopInventory().getHolder() instanceof FastInv) {
player.closeInventory();
}
}
}
}
};
}
public static class FastInvCloseEvent extends FastInvEvent {

View File

@ -1,11 +1,15 @@
package com.songoda.epicenchants.utils;
package com.songoda.epicenchants.utils.objects;
import com.songoda.epicenchants.objects.Placeholder;
import com.songoda.epicenchants.utils.single.ConfigParser;
import com.songoda.epicenchants.utils.single.GeneralUtils;
import com.songoda.epicenchants.utils.single.XMaterial;
import com.songoda.epicenchants.wrappers.EnchantmentWrapper;
import de.tr7zw.itemnbtapi.NBTItem;
import org.bukkit.Material;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemFlag;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
@ -14,7 +18,7 @@ import org.bukkit.inventory.meta.SkullMeta;
import java.util.*;
import java.util.stream.Collectors;
import static com.songoda.epicenchants.utils.GeneralUtils.color;
import static com.songoda.epicenchants.utils.single.GeneralUtils.color;
public class ItemBuilder {
@ -41,8 +45,16 @@ public class ItemBuilder {
this(new ItemStack(material, amount, data));
}
public ItemBuilder(ConfigurationSection section, Player player, Placeholder... placeholders) {
this(section, placeholders);
if (item.getType() == Material.LEGACY_SKULL_ITEM) {
((SkullMeta) item.getItemMeta()).setOwningPlayer(player);
}
}
public ItemBuilder(ConfigurationSection section, Placeholder... placeholders) {
this(Material.valueOf(section.getString("material")), (byte) (section.contains("data") ? section.getInt("data") : 0));
this(XMaterial.requestXMaterial(section.getString("material"), (byte) (section.contains("data") ? section.getInt("data") : 0)).parseItem());
if (section.contains("enchants")) {
section.getStringList("enchants").stream()
@ -147,6 +159,23 @@ public class ItemBuilder {
return this;
}
public ItemBuilder removeLore(int index) {
if (!meta.hasLore()) {
return this;
}
List<String> lore = meta.getLore();
if (index >= lore.size()) {
return this;
}
lore.remove(index);
meta.setLore(lore);
return this;
}
public ItemBuilder addLore(String... lore) {
return addLore(Arrays.asList(lore));
}

View File

@ -1,12 +1,10 @@
package com.songoda.epicenchants.utils;
package com.songoda.epicenchants.utils.single;
import com.songoda.epicenchants.EpicEnchants;
import com.songoda.epicenchants.effect.EffectManager;
import com.songoda.epicenchants.enums.TriggerType;
import com.songoda.epicenchants.objects.BookItem;
import com.songoda.epicenchants.objects.Enchant;
import com.songoda.epicenchants.objects.Group;
import com.songoda.epicenchants.objects.LeveledModifier;
import com.songoda.epicenchants.objects.*;
import com.songoda.epicenchants.utils.objects.ItemBuilder;
import com.songoda.epicenchants.wrappers.EnchantmentWrapper;
import com.songoda.epicenchants.wrappers.MobWrapper;
import org.bukkit.Material;
@ -20,18 +18,19 @@ import java.util.HashSet;
import java.util.Objects;
import java.util.stream.Collectors;
import static com.songoda.epicenchants.utils.GeneralUtils.color;
import static com.songoda.epicenchants.utils.single.GeneralUtils.color;
public class ConfigParser {
public static Enchant parseEnchant(EpicEnchants instance, FileConfiguration config) {
return Enchant.builder()
.identifier(config.getString("identifier"))
.group(instance.getGroupManager().getGroup(config.getString("group").toUpperCase()).orElseThrow(() -> new IllegalArgumentException("Invalid group: " + config.getString("group"))))
.group(instance.getGroupManager().getValue(config.getString("group").toUpperCase()).orElseThrow(() -> new IllegalArgumentException("Invalid group: " + config.getString("group"))))
.maxLevel(config.getInt("max-level"))
.format(color(config.getString("applied-format")))
.bookItem(parseBookItem(config.getConfigurationSection("book-item")))
.itemWhitelist((config.isList("item-whitelist") ? config.getStringList("item-whitelist").stream().map(Material::valueOf).collect(Collectors.toSet()) : Collections.emptySet()))
.conflict(config.isList("conflicting-enchants") ? new HashSet<>(config.getStringList("conflicting-enchants")) : Collections.emptySet())
.condition(Condition.of(config.getString("condition")))
.mobs(config.isConfigurationSection("mobs") ? config.getConfigurationSection("mobs").getKeys(false).stream()
.map(s -> "mobs." + s)
.map(config::getConfigurationSection)
@ -89,6 +88,7 @@ public class ConfigParser {
.color(section.getString("group-color"))
.bookItem(parseBookItem(section.getConfigurationSection("book-item")))
.slotsUsed(section.getInt("slots-used"))
.tinkererExp(section.getInt("tinkerer-exp-per-level"))
.destroyRateMin(section.getInt("rates.destroy-min"))
.destroyRateMax(section.getInt("rates.destroy-max"))
.successRateMin(section.getInt("rates.success-min"))

View File

@ -1,4 +1,4 @@
package com.songoda.epicenchants.utils;
package com.songoda.epicenchants.utils.single;
import org.bukkit.entity.Player;

View File

@ -0,0 +1,52 @@
package com.songoda.epicenchants.utils.single;
import com.songoda.epicenchants.enums.EnchantResult;
import org.apache.commons.lang.StringUtils;
import org.bukkit.ChatColor;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ThreadLocalRandom;
import java.util.stream.Collectors;
public class GeneralUtils {
public static boolean chance(int chance) {
return chance((double) chance);
}
public static boolean chance(double chance) {
return ThreadLocalRandom.current().nextDouble(101) < chance;
}
public static String color(String input) {
return format(input, "", null);
}
public static String format(String input, String placeholder, Object toReplace) {
return ChatColor.translateAlternateColorCodes('&', input).replaceAll(placeholder, toReplace == null ? "" : toReplace.toString());
}
public static String getMessageFromResult(EnchantResult result) {
return "enchant." + result.toString().toLowerCase().replace("_", "");
}
public static <X> X getRandomElement(Set<X> set) {
int item = ThreadLocalRandom.current().nextInt(set.size());
int i = 0;
for (X obj : set) {
if (i == item)
return obj;
i++;
}
return null;
}
public static int[] getSlots(String string) {
return Arrays.stream(string.split(",")).filter(StringUtils::isNumeric).mapToInt(Integer::parseInt).toArray();
}
public static List<Integer> getSlotsList(String string) {
return Arrays.stream(string.split(",")).filter(StringUtils::isNumeric).mapToInt(Integer::parseInt).boxed().collect(Collectors.toList());
}
}

View File

@ -0,0 +1,30 @@
package com.songoda.epicenchants.utils.single;
import java.util.TreeMap;
public class RomanNumber {
private final static TreeMap<Integer, String> map = new TreeMap<Integer, String>() {{
put(1000, "M");
put(900, "CM");
put(500, "D");
put(400, "CD");
put(100, "C");
put(90, "XC");
put(50, "L");
put(40, "XL");
put(10, "X");
put(9, "IX");
put(5, "V");
put(4, "IV");
put(1, "I");
}};
public static String toRoman(int number) {
int l = map.floorKey(number);
if (number == l) {
return map.get(number);
}
return map.get(l) + toRoman(number - l);
}
}

File diff suppressed because it is too large Load Diff

View File

@ -2,12 +2,9 @@ package com.songoda.epicenchants.wrappers;
import com.songoda.epicenchants.enums.TriggerType;
import com.songoda.epicenchants.objects.LeveledModifier;
import com.songoda.epicenchants.utils.GeneralUtils;
import com.songoda.epicenchants.utils.ItemBuilder;
import de.tr7zw.itemnbtapi.NBTEntity;
import de.tr7zw.itemnbtapi.NBTList;
import de.tr7zw.itemnbtapi.NBTListCompound;
import de.tr7zw.itemnbtapi.NBTType;
import com.songoda.epicenchants.utils.objects.ItemBuilder;
import com.songoda.epicenchants.utils.single.GeneralUtils;
import de.tr7zw.itemnbtapi.*;
import lombok.Builder;
import org.bukkit.Location;
import org.bukkit.entity.*;

View File

@ -0,0 +1,37 @@
general:
prefix: "&8[&6EpicEnchants&8]"
no-permission: "&cYou do not have permission to do that."
command:
book:
received: "&7You have been given a &6{enchant} &7book."
gave: "&7You gave {player} a &6{enchant} &7book."
max-level: "&cThe max level for {enchant} is {max-level}."
white-scroll:
received: "&7You have been given a whitescroll."
gave: "&7You gave {player} a whitescroll."
reload: "&6Configuration files reload"
enchanter:
cannot-afford: "&cYou cannot afford this purchase."
success: "&7Purchased {group_color}{group_name} &7book."
tinkerer:
open: "&eTrading with the tinkerer."
cancelled: "&cCancelled."
accepted: "&aAccepted"
no-items: "&c&l(!) &r&cThe tinkerer is not interested in any of your items!"
deposited-all: "&a&l(!) &r&aDeposited {amount} items."
enchants:
invalid-material: "&cYou can not apply &6{enchant} &cto that item."
broken-failure: "&6{enchant} &cfailed to apply and broke your item..."
success: "&aYou have success fully applied &6{enchant}."
conflict: "&cYou cannot apply this enchant as it conflicts with another enchant."
maxed-out: "&cYou already have that enchant maxed on this item."
already-applied: "&cYou already have that enchant with that level applied on this item."
protected: "&aYour book would have broken your item, luckily it was protected!"

View File

@ -1 +1,13 @@
language: "en_US"
language: "en_US"
roman-numbers: true
rates:
black-scroll-min: 20
black-scroll-max: 100
commands:
enchanter: "enchanter"
alchemist: "alchemist"
tinkerer: "tinkerer"

View File

@ -1,38 +0,0 @@
#General
general.nametag.prefix= "&8[&6EpicEnchants&8]"
#Command
command.book.received= "&7You have been given a &6{enchant} &7book."
command.book.gave= "&7You gave {player} a &6{enchant} &7book."
command.book.maxlevel= "&cThe max level for {enchant} is {max-level}."
command.whitescroll;.received= "&7You have been given a whitescroll."
command.whitescroll.gave= "&7You gave {player} a whitescroll."
command.blackscroll.received= "&7You have been given a blackscroll."
command.blackscroll.gave= "&7You gave {player} a blackscroll."
command.reload= "&6Configuration files reload"
command.filereload.success= "&6{file-name} has been successfully reloaded."
command.filereload.failed= "&c{file-name} failed to be reloaded. &7Please check console for errors."
#Event
event.general.nopermission= "&cYou do not have permission to do that."
event.purchase.noenchant= "&cThere is no enchant available for &6{group-name}&7."
event.purchase.cannotafford= "&cYou cannot afford this purchase."
event.purchase.success= "&7You successfully purchased a &6{group-name} &7Book."
#Enchant
enchant.invalidmaterial= "&cYou can not apply &6{enchant} &cto that item."
enchant.failure= "&cYou failed to apply &6{enchant}."
enchant.brokenfailure= "&6{enchant} &cfailed to apply and broke your item..."
enchant.success= "&aYou have success fully applied &6{enchant}."
enchant.conflict= "&cYou cannot apply this enchant as it conflicts with another enchant."
enchant.maxedout= "&cYou already have that enchant maxed on this item."
enchant.alreadyapplied= "&cYou already have that enchant with that level applied on this item."
#Item
whitescroll.applied="&aThis item is now protected."
whitescroll.alreadyapplied= "&cThis item is already protected."
blackscroll.success= "&aYou have successfully extracted an enchant from this item."
blackscroll.noenchants= "&cThis item has no enchants to extract"

View File

@ -1,8 +1,9 @@
groups:
SIMPLE:
group-color: "&7"
group-color: "&f"
group-name: "Simple"
group-format: "{group_color} {enchant} {level}"
tinkerer-exp-per-level: 100
rates:
destroy-min: 10
destroy-max: 100
@ -10,15 +11,15 @@ groups:
success-max: 80
book-item:
material: BOOK
display-name: "&7{enchant} {level}"
display-name: "{group_color}{enchant} {level}"
lore:
- "&7Drag on to item to enchant"
- "&7Destroy Rate &c{destroy_rate}"
- "&7Success Rate &a{success_rate}"
- "&a{success_rate}% Success Rate"
- "&c{destroy_rate}% Destroy Rate"
UNIQUE:
group-color: "&a"
group-name: "Unique"
group-format: "{group_color}{enchant} {level}"
tinkerer-exp-per-level: 200
rates:
destroy-min: 10
destroy-max: 100
@ -28,13 +29,13 @@ groups:
material: BOOK
display-name: "{group_color}{enchant} {level}"
lore:
- "&7Drag on to item to enchant"
- "&7Destroy Rate &c{destroy_rate}"
- "&7Success Rate &a{success_rate}"
- "&a{success_rate}% Success Rate"
- "&c{destroy_rate}% Destroy Rate"
ELITE:
group-color: "&b"
group-name: "Elite"
group-format: "{group_color}{enchant} {level}"
tinkerer-exp-per-level: 300
rates:
destroy-min: 10
destroy-max: 100
@ -44,12 +45,12 @@ groups:
material: BOOK
display-name: "{group_color}{enchant} {level}"
lore:
- "&7Drag on to item to enchant"
- "&7Destroy Rate &c{destroy_rate}"
- "&7Success Rate &a{success_rate}"
- "&a{success_rate}% Success Rate"
- "&c{destroy_rate}% Destroy Rate"
ULTIMATE:
group-color: "&e"
group-name: "Ultimate"
tinkerer-exp-per-level: 600
group-format: "{group_color}{enchant} {level}"
rates:
destroy-min: 10
@ -60,13 +61,13 @@ groups:
material: BOOK
display-name: "{group_color}{enchant} {level}"
lore:
- "&7Drag on to item to enchant"
- "&cDestroy Rate {destroy_rate}"
- "&aSuccess Rate {success_rate}"
- "&a{success_rate}% Success Rate"
- "&c{destroy_rate}% Destroy Rate"
LEGENDARY:
group-color: "&6"
group-name: "Legendary"
group-format: "{group_color}{enchant} {level}"
tinkerer-exp-per-level: 1000
rates:
destroy-min: 10
destroy-max: 100
@ -76,6 +77,5 @@ groups:
material: BOOK
display-name: "{group_color}{enchant} {level}"
lore:
- "&7Drag on to item to enchant"
- "&cDestroy Rate {destroy_rate}"
- "&aSuccess Rate {success_rate}"
- "&a{success_rate}% Success Rate"
- "&c{destroy_rate}% Destroy Rate"

View File

@ -0,0 +1,39 @@
secret-dust:
material: FIREBALL
display-name: "{group-color}{group-name} Secret Dust &7(Right click)"
lore:
- "&aSuccess: +{min-rate}-{max-rate}%"
- "&7Contains &bMagic&7, &ePrimal&7 or &fMystery &7dust."
- "&7An unidentified satchel of dust."
dusts:
mystery:
chance: 50
material: SULPHUR
display-name: "&fMystery Dust"
lore:
- "&7The failed bi-product of"
- "&7Mystery and Primal dust."
magic:
chance: 40
material: SUGAR
display-name: "{group-color}{group-name} Magic Dust"
lore:
- "&a+{percentage}% success"
- "&7Apply to a &l{group-color}{group-name} Enchantment Book"
- "&7to increase its success rate by &l{group-color}{percentage}%"
- ""
- "&7Place dust on enchantment book."
primal:
chance: 10
min-rate: 10
max-rate: 30
material: GLOWSTONE_DUST
display-name: "&l{group-color}{group-name} Primal Dust"
lore:
- "&a&l+{percentage}% SUCCESS"
- "&fApply to a &l{group-color}{group-name} Enchantment Book"
- "&fto increase its success rate by &l{group-color}{percentage}%"
- ""
- "&fPlace dust on enchantment book."

View File

@ -0,0 +1,24 @@
white-scroll:
material: MAP
display-name: "&e&lWhite Scroll"
format: "&7&lPROTECTED"
lore:
- "&7Prevents an item from being destroyed"
- "&7due to a failed Enchantment Book."
- "&ePlace scroll on item to apply."
black-scroll:
material: INK_SACK
display-name: "&f&lBlack Scroll"
lore:
- "&7Removes a random enchantment"
- "&7from an item and converts"
- "&7it into a {success-rate} success book."
- "&fPlace scroll on item to extract."
mystery-book:
material: BOOK
display-name: "{group-color}{group-name} Enchantment &7(Right click)"
lore:
- "&7Examine to receive a random"
- "{group-color}{group-name} &7enchantment book."

View File

@ -21,5 +21,4 @@ contents:
group: SIMPLE
exp-cost: 20
eco-cost: 2000
row: 1
column: 5
slot: 4

View File

@ -0,0 +1,41 @@
title: "Tinkerer"
rows: 6
player-slots: "1,2,3,9,10,11,12,18,19,20,21,27,28,29,30,36,37,38,39,45,46,47,48"
tinkerer-slots: "5,6,7,14,15,16,17,23,24,25,26,32,33,34,35,41,42,43,44,50,51,52,53"
slots: "(1,5) (2,6) (3,7) (9,14)
(10,15) (11,16) (12,17) (18,23)
(19,24) (20,25) (21,26) (27,32)
(28,33) (29,34) (30,35) (36,41)
(37,42) (38,43) (39,44) (45,50)
(46,51) (47,52) (48,53)"
contents:
1:
material: "STAINED_GLASS_PANE"
display-name: " "
slot: "4,13,22,31,40"
accept-left:
material: "STAINED_GLASS_PANE"
data: 4
display-name: "&eClick to accept trade"
slot: 0
accept-right:
material: "STAINED_GLASS_PANE"
data: 4
display-name: "&eClick to accept trade"
slot: 8
deposit-all:
material: "STAINED_GLASS_PANE"
data: 4
display-name: "&l&eDeposit All"
lore:
- "&7Click to deposit all tinkerable items."
slot: "49"
exp-table-per-level:
DEFAULT: 10
DEPTH_STRIDER: 20
ExampleEnchant: 50

View File

@ -4,4 +4,5 @@ main: com.songoda.epicenchants.EpicEnchants
authors: [GB6]
website: https://songoda.com/
depend: [Vault]
softdepend: [UltimateBottles]
api-version: 1.13

View File

@ -1,16 +0,0 @@
white-scroll:
material: EMPTY_MAP
display-name: "&e&lWhite Scroll"
lore:
- "&7Prevents an item from being destroyed"
- "&7due to a failed Enchantment Book."
- "&ePlace scroll on item to apply."
black-scroll:
material: INK_SAC
display-name: "&f&lBlack Scroll"
lore:
- "&7Removes a random enchantment"
- "&7from an item and converts"
- "&7it into a {percentage} success book."
- "&fPlace scroll on item to extract."

View File

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>hooks</artifactId>
<groupId>com.songoda</groupId>
<version>1.0.3-ALPHA</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>FactionsUUID</artifactId>
</project>

View File

@ -0,0 +1,4 @@
package com.songoda.epicenchants.hooks;
public class FactionsUUIDHook {
}

21
hooks/pom.xml Normal file
View File

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>EpicEnchants-Parent</artifactId>
<groupId>com.songoda</groupId>
<version>1.0.3-ALPHA</version>
</parent>
<packaging>pom</packaging>
<modules>
<module>FactionsUUID</module>
</modules>
<modelVersion>4.0.0</modelVersion>
<artifactId>hooks</artifactId>
</project>

View File

@ -7,9 +7,10 @@
<groupId>com.songoda</groupId>
<artifactId>EpicEnchants-Parent</artifactId>
<packaging>pom</packaging>
<version>1.0.1-ALPHA</version>
<version>1.0.3-ALPHA</version>
<modules>
<module>core</module>
<module>hooks</module>
</modules>
<repositories>